Merge tag 'drm-misc-next-2025-06-12' of https://gitlab.freedesktop.org/drm/misc/kernel into drm-next

drm-misc-next for 6.17:

UAPI Changes:

Cross-subsystem Changes:

Core Changes:
 - atomic-helpers: Tune the enable / disable sequence
 - bridge: Add destroy hook
 - color management: Add helpers for hardware gamma LUT handling
 - HDMI: Add CEC handling, YUV420 output support
 - sched: tracing improvements

Driver Changes:
 - hyperv: Move out of simple-kms, drm_panic support
 - i915: drm_panel_follower support
 - imx: Add IMX8qxq Display Controller Support
 - lima: Add Rockchip RK3528 GPU Support
 - nouveau: fence handling cleanup
 - panfrost: Add BO labeling, 64-bit registers access
 - qaic: Add RAS Support
 - rz-du: Add RZ/V2H(P) Support, MIPI-DSI DCS Support
 - sun4i: Add H616 Support
 - tidss: Add TI AM62L Support
 - vkms: YUV and R* formats support

 - bridges:
   - Switched to reference counted drm_bridge allocations

 - panels:
   - Switched to reference counted drm_panel allocations
   - Add support for fwnode-based panel lookup
   - himax-hx8394: Support for Huiling hl055fhv028c
   - ilitek-ili9881c: Support for 7" Raspberry Pi 720x1280
   - panel-edp: Support for KDC KD116N3730A05, N160JCE-ELL CMN,
   - panel-simple: Support for AUO P238HAN01
   - st7701: Support for Winstar wf40eswaa6mnn0
   - visionox-rm69299: Support for rm69299-shift
   - New panels: Renesas R61307, Renesas R69328

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

From: Maxime Ripard <mripard@redhat.com>
Link: https://lore.kernel.org/r/20250612-coucal-of-impossible-cleaning-a5eecf@houat
This commit is contained in:
Dave Airlie
2025-06-18 08:09:27 +10:00
381 changed files with 15331 additions and 2785 deletions

View File

@@ -0,0 +1,18 @@
What: /sys/bus/pci/drivers/qaic/XXXX:XX:XX.X/ce_count
Date: May 2025
KernelVersion: 6.17
Contact: dri-devel@lists.freedesktop.org
Description: Number of correctable errors received from device since driver is loaded.
What: /sys/bus/pci/drivers/qaic/XXXX:XX:XX.X/ue_count
Date: May 2025
KernelVersion: 6.17
Contact: dri-devel@lists.freedesktop.org
Description: Number of uncorrectable errors received from device since driver is loaded.
What: /sys/bus/pci/drivers/qaic/XXXX:XX:XX.X/ue_nonfatal_count
Date: May 2025
KernelVersion: 6.17
Contact: dri-devel@lists.freedesktop.org
Description: Number of uncorrectable non-fatal errors received from device since driver
is loaded.

View File

@@ -24,9 +24,11 @@ properties:
- allwinner,sun50i-a64-de2-mixer-0
- allwinner,sun50i-a64-de2-mixer-1
- allwinner,sun50i-h6-de3-mixer-0
- allwinner,sun50i-h616-de33-mixer-0
reg:
maxItems: 1
reg: true
reg-names: true
clocks:
items:
@@ -61,6 +63,34 @@ properties:
required:
- port@1
allOf:
- if:
properties:
compatible:
contains:
enum:
- allwinner,sun50i-h616-de33-mixer-0
then:
properties:
reg:
description: |
Registers for controlling individual layers of the display
engine (layers), global control (top), and display blending
control (display). Names are from Allwinner BSP kernel.
maxItems: 3
reg-names:
items:
- const: layers
- const: top
- const: display
required:
- reg-names
else:
properties:
reg:
maxItems: 1
required:
- compatible
- reg

View File

@@ -0,0 +1,57 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/imx/fsl,imx8qxp-dc-axi-performance-counter.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Freescale i.MX8qxp Display Controller AXI Performance Counter
description: |
Performance counters are provided to allow measurement of average bandwidth
and latency during operation. The following features are supported:
* Manual and timer controlled measurement mode.
* Measurement counters:
- GLOBAL_COUNTER for overall measurement time
- BUSY_COUNTER for number of data bus busy cycles
- DATA_COUNTER for number of data transfer cycles
- TRANSFER_COUNTER for number of transfers
- ADDRBUSY_COUNTER for number of address bus busy cycles
- LATENCY_COUNTER for average latency
* Counter overflow detection.
* Outstanding Transfer Counters (OTC) which are used for latency measurement
have to run immediately after reset, but can be disabled by software when
there is no need for latency measurement.
maintainers:
- Liu Ying <victor.liu@nxp.com>
properties:
compatible:
const: fsl,imx8qxp-dc-axi-performance-counter
reg:
maxItems: 1
clocks:
maxItems: 1
required:
- compatible
- reg
- clocks
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/imx8-lpcg.h>
pmu@5618f000 {
compatible = "fsl,imx8qxp-dc-axi-performance-counter";
reg = <0x5618f000 0x90>;
clocks = <&dc0_lpcg IMX_LPCG_CLK_5>;
};

View File

@@ -0,0 +1,204 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/imx/fsl,imx8qxp-dc-blit-engine.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Freescale i.MX8qxp Display Controller Blit Engine
description: |
A blit operation (block based image transfer) reads up to 3 source images
from memory and computes one destination image from it, which is written
back to memory. The following basic operations are supported:
* Buffer Fill
Fills a buffer with constant color
* Buffer Copy
Copies one source to a destination buffer.
* Image Blend
Combines two source images by a blending equation and writes result to
destination (which can be one of the sources).
* Image Rop2/3
Combines up to three source images by a logical equation (raster operation)
and writes result to destination (which can be one of the sources).
* Image Flip
Mirrors the source image in horizontal and/or vertical direction.
* Format Convert
Convert between the supported color and buffer formats.
* Color Transform
Modify colors by linear or non-linear transformations.
* Image Scale
Changes size of the source image.
* Image Rotate
Rotates the source image by any angle.
* Image Filter
Performs an FIR filter operation on the source image.
* Image Warp
Performs a re-sampling of the source image with any pattern. The sample
point positions are read from a compressed coordinate buffer.
* Buffer Pack
Writes an image with color components stored in up to three different
buffers (planar formats) into a single buffer (packed format).
* Chroma Resample
Converts between different YUV formats that differ in chroma sampling rate
(4:4:4, 4:2:2, 4:2:0).
maintainers:
- Liu Ying <victor.liu@nxp.com>
properties:
compatible:
const: fsl,imx8qxp-dc-blit-engine
reg:
maxItems: 2
reg-names:
items:
- const: pec
- const: cfg
"#address-cells":
const: 1
"#size-cells":
const: 1
ranges: true
patternProperties:
"^blitblend@[0-9a-f]+$":
type: object
additionalProperties: true
properties:
compatible:
const: fsl,imx8qxp-dc-blitblend
"^clut@[0-9a-f]+$":
type: object
additionalProperties: true
properties:
compatible:
const: fsl,imx8qxp-dc-clut
"^fetchdecode@[0-9a-f]+$":
type: object
additionalProperties: true
properties:
compatible:
const: fsl,imx8qxp-dc-fetchdecode
"^fetcheco@[0-9a-f]+$":
type: object
additionalProperties: true
properties:
compatible:
const: fsl,imx8qxp-dc-fetcheco
"^fetchwarp@[0-9a-f]+$":
type: object
additionalProperties: true
properties:
compatible:
const: fsl,imx8qxp-dc-fetchwarp
"^filter@[0-9a-f]+$":
type: object
additionalProperties: true
properties:
compatible:
const: fsl,imx8qxp-dc-filter
"^hscaler@[0-9a-f]+$":
type: object
additionalProperties: true
properties:
compatible:
const: fsl,imx8qxp-dc-hscaler
"^matrix@[0-9a-f]+$":
type: object
additionalProperties: true
properties:
compatible:
const: fsl,imx8qxp-dc-matrix
"^rop@[0-9a-f]+$":
type: object
additionalProperties: true
properties:
compatible:
const: fsl,imx8qxp-dc-rop
"^store@[0-9a-f]+$":
type: object
additionalProperties: true
properties:
compatible:
const: fsl,imx8qxp-dc-store
"^vscaler@[0-9a-f]+$":
type: object
additionalProperties: true
properties:
compatible:
const: fsl,imx8qxp-dc-vscaler
required:
- compatible
- reg
- reg-names
- "#address-cells"
- "#size-cells"
- ranges
additionalProperties: false
examples:
- |
blit-engine@56180820 {
compatible = "fsl,imx8qxp-dc-blit-engine";
reg = <0x56180820 0x13c>, <0x56181000 0x3400>;
reg-names = "pec", "cfg";
#address-cells = <1>;
#size-cells = <1>;
ranges;
fetchdecode@56180820 {
compatible = "fsl,imx8qxp-dc-fetchdecode";
reg = <0x56180820 0x10>, <0x56181000 0x404>;
reg-names = "pec", "cfg";
};
store@56180940 {
compatible = "fsl,imx8qxp-dc-store";
reg = <0x56180940 0x1c>, <0x56184000 0x5c>;
reg-names = "pec", "cfg";
interrupt-parent = <&dc0_intc>;
interrupts = <0>, <1>, <2>;
interrupt-names = "shdload", "framecomplete", "seqcomplete";
};
};

View File

@@ -0,0 +1,41 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/imx/fsl,imx8qxp-dc-blitblend.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Freescale i.MX8qxp Display Controller Blit Blend Unit
description:
Combines two input frames to a single output frame, all frames having the
same dimension.
maintainers:
- Liu Ying <victor.liu@nxp.com>
properties:
compatible:
const: fsl,imx8qxp-dc-blitblend
reg:
maxItems: 2
reg-names:
items:
- const: pec
- const: cfg
required:
- compatible
- reg
- reg-names
additionalProperties: false
examples:
- |
blitblend@56180920 {
compatible = "fsl,imx8qxp-dc-blitblend";
reg = <0x56180920 0x10>, <0x56183c00 0x3c>;
reg-names = "pec", "cfg";
};

View File

@@ -0,0 +1,44 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/imx/fsl,imx8qxp-dc-clut.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Freescale i.MX8qxp Display Controller Color Lookup Table
description: |
The unit implements 3 look-up tables with 256 x 10 bit entries each. These
can be used for different kinds of applications. From 10-bit input values
only upper 8 bits are used.
The unit supports color lookup, index lookup, dithering and alpha masking.
maintainers:
- Liu Ying <victor.liu@nxp.com>
properties:
compatible:
const: fsl,imx8qxp-dc-clut
reg:
maxItems: 2
reg-names:
items:
- const: pec
- const: cfg
required:
- compatible
- reg
- reg-names
additionalProperties: false
examples:
- |
clut@56180880 {
compatible = "fsl,imx8qxp-dc-clut";
reg = <0x56180880 0x10>, <0x56182400 0x404>;
reg-names = "pec", "cfg";
};

View File

@@ -0,0 +1,67 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/imx/fsl,imx8qxp-dc-command-sequencer.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Freescale i.MX8qxp Display Controller Command Sequencer
description: |
The Command Sequencer is designed to autonomously process command lists.
By that it can load setups into the DC configuration and synchronize to
hardware events. This releases a system's CPU from workload, because it
does not need to wait for certain events. Also it simplifies SW architecture,
because no interrupt handlers are required. Setups are read via AXI bus,
while write access to configuration registers occurs directly via an internal
bus. This saves bandwidth for the AXI interconnect and improves the system
architecture in terms of safety aspects.
maintainers:
- Liu Ying <victor.liu@nxp.com>
properties:
compatible:
const: fsl,imx8qxp-dc-command-sequencer
reg:
maxItems: 1
clocks:
maxItems: 1
interrupts:
maxItems: 5
interrupt-names:
items:
- const: error
- const: sw0
- const: sw1
- const: sw2
- const: sw3
sram:
$ref: /schemas/types.yaml#/definitions/phandle
description: phandle pointing to the mmio-sram device node
required:
- compatible
- reg
- clocks
- interrupts
- interrupt-names
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/imx8-lpcg.h>
command-sequencer@56180400 {
compatible = "fsl,imx8qxp-dc-command-sequencer";
reg = <0x56180400 0x1a4>;
clocks = <&dc0_lpcg IMX_LPCG_CLK_5>;
interrupt-parent = <&dc0_intc>;
interrupts = <36>, <37>, <38>, <39>, <40>;
interrupt-names = "error", "sw0", "sw1", "sw2", "sw3";
};

View File

@@ -0,0 +1,44 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/imx/fsl,imx8qxp-dc-constframe.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Freescale i.MX8qxp Display Controller Constant Frame
description: |
The Constant Frame unit is used instead of a Fetch unit where generation of
constant color frames only is sufficient. This is the case for the background
planes of content and safety streams in a Display Controller.
The color can be setup to any RGBA value.
maintainers:
- Liu Ying <victor.liu@nxp.com>
properties:
compatible:
const: fsl,imx8qxp-dc-constframe
reg:
maxItems: 2
reg-names:
items:
- const: pec
- const: cfg
required:
- compatible
- reg
- reg-names
additionalProperties: false
examples:
- |
constframe@56180960 {
compatible = "fsl,imx8qxp-dc-constframe";
reg = <0x56180960 0xc>, <0x56184400 0x20>;
reg-names = "pec", "cfg";
};

View File

@@ -0,0 +1,152 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/imx/fsl,imx8qxp-dc-display-engine.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Freescale i.MX8qxp Display Controller Display Engine
description:
All Processing Units that operate in a display clock domain. Pixel pipeline
is driven by a video timing and cannot be stalled. Implements all display
specific processing.
maintainers:
- Liu Ying <victor.liu@nxp.com>
properties:
compatible:
const: fsl,imx8qxp-dc-display-engine
reg:
maxItems: 2
reg-names:
items:
- const: top
- const: cfg
resets:
maxItems: 1
interrupts:
maxItems: 3
interrupt-names:
items:
- const: shdload
- const: framecomplete
- const: seqcomplete
power-domains:
maxItems: 1
"#address-cells":
const: 1
"#size-cells":
const: 1
ranges: true
patternProperties:
"^dither@[0-9a-f]+$":
type: object
additionalProperties: true
properties:
compatible:
const: fsl,imx8qxp-dc-dither
"^framegen@[0-9a-f]+$":
type: object
additionalProperties: true
properties:
compatible:
const: fsl,imx8qxp-dc-framegen
"^gammacor@[0-9a-f]+$":
type: object
additionalProperties: true
properties:
compatible:
const: fsl,imx8qxp-dc-gammacor
"^matrix@[0-9a-f]+$":
type: object
additionalProperties: true
properties:
compatible:
const: fsl,imx8qxp-dc-matrix
"^signature@[0-9a-f]+$":
type: object
additionalProperties: true
properties:
compatible:
const: fsl,imx8qxp-dc-signature
"^tcon@[0-9a-f]+$":
type: object
additionalProperties: true
properties:
compatible:
const: fsl,imx8qxp-dc-tcon
required:
- compatible
- reg
- reg-names
- interrupts
- interrupt-names
- power-domains
- "#address-cells"
- "#size-cells"
- ranges
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/imx8-lpcg.h>
#include <dt-bindings/firmware/imx/rsrc.h>
display-engine@5618b400 {
compatible = "fsl,imx8qxp-dc-display-engine";
reg = <0x5618b400 0x14>, <0x5618b800 0x1c00>;
reg-names = "top", "cfg";
interrupt-parent = <&dc0_intc>;
interrupts = <15>, <16>, <17>;
interrupt-names = "shdload", "framecomplete", "seqcomplete";
power-domains = <&pd IMX_SC_R_DC_0_PLL_0>;
#address-cells = <1>;
#size-cells = <1>;
ranges;
framegen@5618b800 {
compatible = "fsl,imx8qxp-dc-framegen";
reg = <0x5618b800 0x98>;
clocks = <&dc0_disp_lpcg IMX_LPCG_CLK_0>;
interrupt-parent = <&dc0_intc>;
interrupts = <18>, <19>, <20>, <21>, <41>, <42>, <43>, <44>;
interrupt-names = "int0", "int1", "int2", "int3",
"primsync_on", "primsync_off",
"secsync_on", "secsync_off";
};
tcon@5618c800 {
compatible = "fsl,imx8qxp-dc-tcon";
reg = <0x5618c800 0x588>;
port {
dc0_disp0_dc0_pixel_combiner_ch0: endpoint {
remote-endpoint = <&dc0_pixel_combiner_ch0_dc0_disp0>;
};
};
};
};

View File

@@ -0,0 +1,45 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/imx/fsl,imx8qxp-dc-dither.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Freescale i.MX8qxp Display Controller Dither Unit
description: |
The unit can increase the physical color resolution of a display from 5, 6, 7
or 8 bits per RGB channel to a virtual resolution of 10 bits. The physical
resolution can be set individually for each channel.
The resolution is increased by mixing the two physical colors that are nearest
to the virtual color code in a variable ratio either by time (temporal
dithering) or by position (spatial dithering).
An optimized algorithm for temporal dithering minimizes noise artifacts on the
output image.
The dither operation can be individually enabled or disabled for each pixel
using the alpha input bit.
maintainers:
- Liu Ying <victor.liu@nxp.com>
properties:
compatible:
const: fsl,imx8qxp-dc-dither
reg:
maxItems: 1
required:
- compatible
- reg
additionalProperties: false
examples:
- |
dither@5618c400 {
compatible = "fsl,imx8qxp-dc-dither";
reg = <0x5618c400 0x14>;
};

View File

@@ -0,0 +1,72 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/imx/fsl,imx8qxp-dc-extdst.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Freescale i.MX8qxp Display Controller External Destination Interface
description: |
The External Destination unit is the interface between the internal pixel
processing pipeline of the Pixel Engine, which is 30-bit RGB plus 8-bit Alpha,
and a Display Engine.
It comprises the following built-in Gamma apply function.
+------X-----------------------+
| | ExtDst Unit |
| V |
| +-------+ |
| | Gamma | |
| +-------+ |
| | |
| V +
+------X-----------------------+
The output format is 24-bit RGB plus 1-bit Alpha. Conversion from 10 to 8
bits is done by LSBit truncation. Alpha output bit is 1 for input 255, 0
otherwise.
maintainers:
- Liu Ying <victor.liu@nxp.com>
properties:
compatible:
const: fsl,imx8qxp-dc-extdst
reg:
maxItems: 2
reg-names:
items:
- const: pec
- const: cfg
interrupts:
maxItems: 3
interrupt-names:
items:
- const: shdload
- const: framecomplete
- const: seqcomplete
required:
- compatible
- reg
- reg-names
- interrupts
- interrupt-names
additionalProperties: false
examples:
- |
extdst@56180980 {
compatible = "fsl,imx8qxp-dc-extdst";
reg = <0x56180980 0x1c>, <0x56184800 0x28>;
reg-names = "pec", "cfg";
interrupt-parent = <&dc0_intc>;
interrupts = <3>, <4>, <5>;
interrupt-names = "shdload", "framecomplete", "seqcomplete";
};

View File

@@ -0,0 +1,141 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/imx/fsl,imx8qxp-dc-fetchunit.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Freescale i.MX8qxp Display Controller Fetch Unit
description: |
The Fetch Unit is the interface between the AXI bus for source buffer access
and the internal pixel processing pipeline, which is 30-bit RGB plus 8-bit
Alpha.
It is used to generate foreground planes in Display Controllers and source
planes in Blit Engines, and comprises the following built-in functions to
convert a wide range of frame buffer types.
+---------X-----------------------------------------+
| | Fetch Unit |
| V |
| +---------+ |
| | | |
| | Decode | Decompression [Decode] |
| | | |
| +---------+ |
| | |
| V |
| +---------+ |
| | Clip & | Clip Window [All] |
| | Overlay | Plane composition [Layer, Warp] |
| | | |
| +---------+ |
| | |
| V |
| +---------+ |
| | Re- | Flip/Rotate/Repl./Drop [All] |
X--> | sample | Perspective/Affine warping [Persp] |
| | | | Arbitrary warping [Warp, Persp] |
| | +---------+ |
| | | |
| | V |
| | +---------+ |
| | | | |
| | | Palette | Color Palette [Layer, Decode] |
| | | | |
| | +---------+ |
| | | |
| | V |
| | +---------+ |
| | | Extract | Raw to RGBA/YUV [All] |
| | | & | Bit width expansion [All] |
| | | Expand | |
| | +---------+ |
| | | |
| | V |
| | +---------+ |
| | | | Planar to packed |
| |->| Combine | [Decode, Warp, Persp] |
| | | | |
| | +---------+ |
| | | |
| | V |
| | +---------+ |
| | | | YUV422 to YUV444 |
| | | Chroma | [Decode, Persp] |
| | | | |
| | +---------+ |
| | | |
| | V |
| | +---------+ |
| | | | YUV to RGB |
| | | Color | [Warp, Persp, Decode, Layer] |
| | | | |
| | +---------+ |
| | | |
| | V |
| | +---------+ |
| | | | Gamma removal |
| | | Gamma | [Warp, Persp, Decode, Layer] |
| | | | |
| | +---------+ |
| | | |
| | V |
| | +---------+ |
| | | | Alpla multiply, RGB pre-multiply |
| ->| Multiply| [Warp, Persp, Decode, Layer] |
| | | |
| --------- |
| | |
| V |
| +---------+ |
| | | Bilinear filter |
| | Filter | [Warp, Persp] |
| | | |
| +---------+ |
| | |
| V |
+---------X-----------------------------------------+
Note that different derivatives of the Fetch Unit exist. Each implements a
specific subset only of the pipeline stages shown above. Restrictions for the
units are specified in [square brackets].
maintainers:
- Liu Ying <victor.liu@nxp.com>
properties:
compatible:
enum:
- fsl,imx8qxp-dc-fetchdecode
- fsl,imx8qxp-dc-fetcheco
- fsl,imx8qxp-dc-fetchlayer
- fsl,imx8qxp-dc-fetchwarp
reg:
maxItems: 2
reg-names:
items:
- const: pec
- const: cfg
fsl,prg:
$ref: /schemas/types.yaml#/definitions/phandle
description:
Optional Prefetch Resolve Gasket associated with the Fetch Unit.
required:
- compatible
- reg
- reg-names
additionalProperties: false
examples:
- |
fetchlayer@56180ac0 {
compatible = "fsl,imx8qxp-dc-fetchlayer";
reg = <0x56180ac0 0xc>, <0x56188400 0x404>;
reg-names = "pec", "cfg";
};

View File

@@ -0,0 +1,43 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/imx/fsl,imx8qxp-dc-filter.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Freescale i.MX8qxp Display Controller Filter Unit
description: |
5x5 FIR filter with 25 programmable coefficients.
Typical applications are image blurring, sharpening or support for edge
detection algorithms.
maintainers:
- Liu Ying <victor.liu@nxp.com>
properties:
compatible:
const: fsl,imx8qxp-dc-filter
reg:
maxItems: 2
reg-names:
items:
- const: pec
- const: cfg
required:
- compatible
- reg
- reg-names
additionalProperties: false
examples:
- |
filter@56180900 {
compatible = "fsl,imx8qxp-dc-filter";
reg = <0x56180900 0x10>, <0x56183800 0x30>;
reg-names = "pec", "cfg";
};

View File

@@ -0,0 +1,64 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/imx/fsl,imx8qxp-dc-framegen.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Freescale i.MX8qxp Display Controller Frame Generator
description:
The Frame Generator (FrameGen) module generates a programmable video timing
and optionally allows to synchronize the generated video timing to external
synchronization signals.
maintainers:
- Liu Ying <victor.liu@nxp.com>
properties:
compatible:
const: fsl,imx8qxp-dc-framegen
reg:
maxItems: 1
clocks:
maxItems: 1
interrupts:
maxItems: 8
interrupt-names:
items:
- const: int0
- const: int1
- const: int2
- const: int3
- const: primsync_on
- const: primsync_off
- const: secsync_on
- const: secsync_off
required:
- compatible
- reg
- clocks
- interrupts
- interrupt-names
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/imx8-lpcg.h>
#include <dt-bindings/firmware/imx/rsrc.h>
framegen@5618b800 {
compatible = "fsl,imx8qxp-dc-framegen";
reg = <0x5618b800 0x98>;
clocks = <&dc0_disp_lpcg IMX_LPCG_CLK_0>;
interrupt-parent = <&dc0_intc>;
interrupts = <18>, <19>, <20>, <21>, <41>, <42>, <43>, <44>;
interrupt-names = "int0", "int1", "int2", "int3",
"primsync_on", "primsync_off",
"secsync_on", "secsync_off";
};

View File

@@ -0,0 +1,32 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/imx/fsl,imx8qxp-dc-gammacor.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Freescale i.MX8qxp Display Controller Gamma Correction Unit
description: The unit supports non-linear color transformation.
maintainers:
- Liu Ying <victor.liu@nxp.com>
properties:
compatible:
const: fsl,imx8qxp-dc-gammacor
reg:
maxItems: 1
required:
- compatible
- reg
additionalProperties: false
examples:
- |
gammacor@5618c000 {
compatible = "fsl,imx8qxp-dc-gammacor";
reg = <0x5618c000 0x20>;
};

View File

@@ -0,0 +1,39 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/imx/fsl,imx8qxp-dc-layerblend.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Freescale i.MX8qxp Display Controller Layer Blend Unit
description: Combines two input frames to a single output frame.
maintainers:
- Liu Ying <victor.liu@nxp.com>
properties:
compatible:
const: fsl,imx8qxp-dc-layerblend
reg:
maxItems: 2
reg-names:
items:
- const: pec
- const: cfg
required:
- compatible
- reg
- reg-names
additionalProperties: false
examples:
- |
layerblend@56180ba0 {
compatible = "fsl,imx8qxp-dc-layerblend";
reg = <0x56180ba0 0x10>, <0x5618a400 0x20>;
reg-names = "pec", "cfg";
};

View File

@@ -0,0 +1,44 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/imx/fsl,imx8qxp-dc-matrix.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Freescale i.MX8qxp Display Controller Color Matrix
description:
The unit supports linear color transformation, alpha pre-multiply and
alpha masking.
maintainers:
- Liu Ying <victor.liu@nxp.com>
properties:
compatible:
const: fsl,imx8qxp-dc-matrix
reg:
minItems: 1
maxItems: 2
reg-names:
oneOf:
- const: cfg # matrix in display engine
- items: # matrix in pixel engine
- const: pec
- const: cfg
required:
- compatible
- reg
- reg-names
additionalProperties: false
examples:
- |
matrix@5618bc00 {
compatible = "fsl,imx8qxp-dc-matrix";
reg = <0x5618bc00 0x3c>;
reg-names = "cfg";
};

View File

@@ -0,0 +1,250 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/imx/fsl,imx8qxp-dc-pixel-engine.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Freescale i.MX8qxp Display Controller Pixel Engine
description:
All Processing Units that operate in the AXI bus clock domain. Pixel
pipelines have the ability to stall when a destination is busy. Implements
all communication to memory resources and most of the image processing
functions. Interconnection of Processing Units is re-configurable.
maintainers:
- Liu Ying <victor.liu@nxp.com>
properties:
compatible:
const: fsl,imx8qxp-dc-pixel-engine
reg:
maxItems: 1
clocks:
maxItems: 1
"#address-cells":
const: 1
"#size-cells":
const: 1
ranges: true
patternProperties:
"^blit-engine@[0-9a-f]+$":
type: object
additionalProperties: true
properties:
compatible:
const: fsl,imx8qxp-dc-blit-engine
"^constframe@[0-9a-f]+$":
type: object
additionalProperties: true
properties:
compatible:
const: fsl,imx8qxp-dc-constframe
"^extdst@[0-9a-f]+$":
type: object
additionalProperties: true
properties:
compatible:
const: fsl,imx8qxp-dc-extdst
"^fetchdecode@[0-9a-f]+$":
type: object
additionalProperties: true
properties:
compatible:
const: fsl,imx8qxp-dc-fetchdecode
"^fetcheco@[0-9a-f]+$":
type: object
additionalProperties: true
properties:
compatible:
const: fsl,imx8qxp-dc-fetcheco
"^fetchlayer@[0-9a-f]+$":
type: object
additionalProperties: true
properties:
compatible:
const: fsl,imx8qxp-dc-fetchlayer
"^fetchwarp@[0-9a-f]+$":
type: object
additionalProperties: true
properties:
compatible:
const: fsl,imx8qxp-dc-fetchwarp
"^hscaler@[0-9a-f]+$":
type: object
additionalProperties: true
properties:
compatible:
const: fsl,imx8qxp-dc-hscaler
"^layerblend@[0-9a-f]+$":
type: object
additionalProperties: true
properties:
compatible:
const: fsl,imx8qxp-dc-layerblend
"^matrix@[0-9a-f]+$":
type: object
additionalProperties: true
properties:
compatible:
const: fsl,imx8qxp-dc-matrix
"^safety@[0-9a-f]+$":
type: object
additionalProperties: true
properties:
compatible:
const: fsl,imx8qxp-dc-safety
"^vscaler@[0-9a-f]+$":
type: object
additionalProperties: true
properties:
compatible:
const: fsl,imx8qxp-dc-vscaler
required:
- compatible
- reg
- clocks
- "#address-cells"
- "#size-cells"
- ranges
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/imx8-lpcg.h>
pixel-engine@56180800 {
compatible = "fsl,imx8qxp-dc-pixel-engine";
reg = <0x56180800 0xac00>;
clocks = <&dc0_lpcg IMX_LPCG_CLK_5>;
#address-cells = <1>;
#size-cells = <1>;
ranges;
constframe@56180960 {
compatible = "fsl,imx8qxp-dc-constframe";
reg = <0x56180960 0xc>, <0x56184400 0x20>;
reg-names = "pec", "cfg";
};
extdst@56180980 {
compatible = "fsl,imx8qxp-dc-extdst";
reg = <0x56180980 0x1c>, <0x56184800 0x28>;
reg-names = "pec", "cfg";
interrupt-parent = <&dc0_intc>;
interrupts = <3>, <4>, <5>;
interrupt-names = "shdload", "framecomplete", "seqcomplete";
};
constframe@561809a0 {
compatible = "fsl,imx8qxp-dc-constframe";
reg = <0x561809a0 0xc>, <0x56184c00 0x20>;
reg-names = "pec", "cfg";
};
extdst@561809c0 {
compatible = "fsl,imx8qxp-dc-extdst";
reg = <0x561809c0 0x1c>, <0x56185000 0x28>;
reg-names = "pec", "cfg";
interrupt-parent = <&dc0_intc>;
interrupts = <6>, <7>, <8>;
interrupt-names = "shdload", "framecomplete", "seqcomplete";
};
constframe@561809e0 {
compatible = "fsl,imx8qxp-dc-constframe";
reg = <0x561809e0 0xc>, <0x56185400 0x20>;
reg-names = "pec", "cfg";
};
extdst@56180a00 {
compatible = "fsl,imx8qxp-dc-extdst";
reg = <0x56180a00 0x1c>, <0x56185800 0x28>;
reg-names = "pec", "cfg";
interrupt-parent = <&dc0_intc>;
interrupts = <9>, <10>, <11>;
interrupt-names = "shdload", "framecomplete", "seqcomplete";
};
constframe@56180a20 {
compatible = "fsl,imx8qxp-dc-constframe";
reg = <0x56180a20 0xc>, <0x56185c00 0x20>;
reg-names = "pec", "cfg";
};
extdst@56180a40 {
compatible = "fsl,imx8qxp-dc-extdst";
reg = <0x56180a40 0x1c>, <0x56186000 0x28>;
reg-names = "pec", "cfg";
interrupt-parent = <&dc0_intc>;
interrupts = <12>, <13>, <14>;
interrupt-names = "shdload", "framecomplete", "seqcomplete";
};
fetchwarp@56180a60 {
compatible = "fsl,imx8qxp-dc-fetchwarp";
reg = <0x56180a60 0x10>, <0x56186400 0x190>;
reg-names = "pec", "cfg";
};
fetchlayer@56180ac0 {
compatible = "fsl,imx8qxp-dc-fetchlayer";
reg = <0x56180ac0 0xc>, <0x56188400 0x404>;
reg-names = "pec", "cfg";
};
layerblend@56180ba0 {
compatible = "fsl,imx8qxp-dc-layerblend";
reg = <0x56180ba0 0x10>, <0x5618a400 0x20>;
reg-names = "pec", "cfg";
};
layerblend@56180bc0 {
compatible = "fsl,imx8qxp-dc-layerblend";
reg = <0x56180bc0 0x10>, <0x5618a800 0x20>;
reg-names = "pec", "cfg";
};
layerblend@56180be0 {
compatible = "fsl,imx8qxp-dc-layerblend";
reg = <0x56180be0 0x10>, <0x5618ac00 0x20>;
reg-names = "pec", "cfg";
};
layerblend@56180c00 {
compatible = "fsl,imx8qxp-dc-layerblend";
reg = <0x56180c00 0x10>, <0x5618b000 0x20>;
reg-names = "pec", "cfg";
};
};

View File

@@ -0,0 +1,43 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/imx/fsl,imx8qxp-dc-rop.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Freescale i.MX8qxp Display Controller Raster Operation Unit
description: |
The unit can combine up to three input frames to a single output frame, all
having the same dimension.
The unit supports logic operations, arithmetic operations and packing.
maintainers:
- Liu Ying <victor.liu@nxp.com>
properties:
compatible:
const: fsl,imx8qxp-dc-rop
reg:
maxItems: 2
reg-names:
items:
- const: pec
- const: cfg
required:
- compatible
- reg
- reg-names
additionalProperties: false
examples:
- |
rop@56180860 {
compatible = "fsl,imx8qxp-dc-rop";
reg = <0x56180860 0x10>, <0x56182000 0x20>;
reg-names = "pec", "cfg";
};

View File

@@ -0,0 +1,34 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/imx/fsl,imx8qxp-dc-safety.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Freescale i.MX8qxp Display Controller Safety Unit
description:
The unit allows corresponding processing units to be configured in a path
leading to multiple endpoints.
maintainers:
- Liu Ying <victor.liu@nxp.com>
properties:
compatible:
const: fsl,imx8qxp-dc-safety
reg:
maxItems: 1
required:
- compatible
- reg
additionalProperties: false
examples:
- |
safety@56180800 {
compatible = "fsl,imx8qxp-dc-safety";
reg = <0x56180800 0x1c>;
};

View File

@@ -0,0 +1,83 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/imx/fsl,imx8qxp-dc-scaling-engine.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Freescale i.MX8qxp Display Controller Scaling Engine
description: |
The unit can change the dimension of the input frame by nearest or linear
re-sampling with 1/32 sub pixel precision.
Internally it consist of two independent blocks for horizontal and vertical
scaling. The sequence of both operations is arbitrary.
Any frame dimensions between 1 and 16384 pixels in width and height are
supported, except that the vertical scaler has a frame width maximum
depending of the system's functional limitations.
In general all scale factors are supported inside the supported frame
dimensions. In range of scale factors 1/16..16 the filtered output colors
are LSBit precise (e.g. DC ripple free).
+-----------+
| Line |
| Buffer |
+-----------+
^
|
V
|\ +-----------+
------+ | | |
| | +-->| Vertical |----
| ----+ | | Scaler | |
| | |/ +-----------+ |
| | |
| | |
| | | |\
| ------------- -------------+-----+ |
Input --+ X | +--> Output
| ------------- -------------+-----+ |
| | | |/
| | |
| | |\ +-----------+ |
| ----+ | | | |
| | +-->| Horizontal|----
------+ | | Scaler |
|/ +-----------+
The unit supports downscaling, upscaling, sub pixel translation and bob
de-interlacing.
maintainers:
- Liu Ying <victor.liu@nxp.com>
properties:
compatible:
enum:
- fsl,imx8qxp-dc-hscaler
- fsl,imx8qxp-dc-vscaler
reg:
maxItems: 2
reg-names:
items:
- const: pec
- const: cfg
required:
- compatible
- reg
- reg-names
additionalProperties: false
examples:
- |
hscaler@561808c0 {
compatible = "fsl,imx8qxp-dc-hscaler";
reg = <0x561808c0 0x10>, <0x56183000 0x18>;
reg-names = "pec", "cfg";
};

View File

@@ -0,0 +1,53 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/imx/fsl,imx8qxp-dc-signature.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Freescale i.MX8qxp Display Controller Signature Unit
description: |
In order to control the correctness of display output, signature values can
be computed for each frame and compared against reference values. In case of
a mismatch (signature violation) a HW event can be triggered, for example a
SW interrupt.
This unit supports signature computation, reference check, evaluation windows,
alpha masking and panic modes.
maintainers:
- Liu Ying <victor.liu@nxp.com>
properties:
compatible:
const: fsl,imx8qxp-dc-signature
reg:
maxItems: 1
interrupts:
maxItems: 3
interrupt-names:
items:
- const: shdload
- const: valid
- const: error
required:
- compatible
- reg
- interrupts
- interrupt-names
additionalProperties: false
examples:
- |
signature@5618d000 {
compatible = "fsl,imx8qxp-dc-signature";
reg = <0x5618d000 0x140>;
interrupt-parent = <&dc0_intc>;
interrupts = <22>, <23>, <24>;
interrupt-names = "shdload", "valid", "error";
};

View File

@@ -0,0 +1,96 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/imx/fsl,imx8qxp-dc-store.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Freescale i.MX8qxp Display Controller Store Unit
description: |
The Store unit is the interface between the internal pixel processing
pipeline, which is 30-bit RGB plus 8-bit Alpha, and the AXI bus for
destination buffer access. It is used for the destination of Blit Engines.
It comprises a set of built-in functions to generate a wide range of buffer
formats. Note, that these are exactly inverse to corresponding functions in
the Fetch Unit.
+------X-------------------------+
| | Store Unit |
| V |
| +-------+ |
| | Gamma | Gamma apply |
| +-------+ |
| | |
| V |
| +-------+ |
| | Color | RGB to YUV |
| +-------+ |
| | |
| V |
| +-------+ |
| | Chroma| YUV444 to 422 |
| +-------+ |
| | |
| V |
| +-------+ |
| | Reduce| Bit width reduction |
| | | dithering |
| +-------+ |
| | |
| V |
| +-------+ |
| | Pack | RGBA/YUV to RAW |
| | Encode| or Compression |
| +-------+ |
| | |
| V |
+------X-------------------------+
maintainers:
- Liu Ying <victor.liu@nxp.com>
properties:
compatible:
const: fsl,imx8qxp-dc-store
reg:
maxItems: 2
reg-names:
items:
- const: pec
- const: cfg
interrupts:
maxItems: 3
interrupt-names:
items:
- const: shdload
- const: framecomplete
- const: seqcomplete
fsl,lts:
$ref: /schemas/types.yaml#/definitions/phandle
description:
Optional Linear Tile Store associated with the Store Unit.
required:
- compatible
- reg
- reg-names
- interrupts
- interrupt-names
additionalProperties: false
examples:
- |
store@56180940 {
compatible = "fsl,imx8qxp-dc-store";
reg = <0x56180940 0x1c>, <0x56184000 0x5c>;
reg-names = "pec", "cfg";
interrupt-parent = <&dc0_intc>;
interrupts = <0>, <1>, <2>;
interrupt-names = "shdload", "framecomplete", "seqcomplete";
};

View File

@@ -0,0 +1,45 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/imx/fsl,imx8qxp-dc-tcon.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Freescale i.MX8qxp Display Controller Timing Controller
description:
The TCon can generate a wide range of customized synchronization signals and
does the mapping of the color bits to the output.
maintainers:
- Liu Ying <victor.liu@nxp.com>
properties:
compatible:
const: fsl,imx8qxp-dc-tcon
reg:
maxItems: 1
port:
$ref: /schemas/graph.yaml#/properties/port
description: video output
required:
- compatible
- reg
- port
additionalProperties: false
examples:
- |
tcon@5618c800 {
compatible = "fsl,imx8qxp-dc-tcon";
reg = <0x5618c800 0x588>;
port {
dc0_disp0_dc0_pixel_combiner_ch0: endpoint {
remote-endpoint = <&dc0_pixel_combiner_ch0_dc0_disp0>;
};
};
};

View File

@@ -0,0 +1,236 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/imx/fsl,imx8qxp-dc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Freescale i.MX8qxp Display Controller
description: |
The Freescale i.MX8qxp Display Controller(DC) is comprised of three main
components that include a blit engine for 2D graphics accelerations, display
controller for display output processing, as well as a command sequencer.
Display buffers Source buffers
(AXI read master) (AXI read master)
| .......... | | | |
+---------------------------+------------+------------------+-+-+------+
| Display Controller (DC) | .......... | | | | |
| | | | | | |
| @@@@@@@@@@@ +----------+------------+------------+ | | | |
A | | Command | | V V | | | | |
X <-+->| Sequencer | | @@@@@@@@@@@@@@@@@@@@@@@@@@@@ | V V V |
I | | (AXI CLK) | | | | | @@@@@@@@@@ |
| @@@@@@@@@@@ | | Pixel Engine | | | | |
| | | | (AXI CLK) | | | | |
| V | @@@@@@@@@@@@@@@@@@@@@@@@@@@@ | | | |
A | *********** | | | | | | | Blit | |
H <-+->| Configure | | V V V V | | Engine | |
B | | (CFG CLK) | | 00000000000 11111111111 | | (AXI CLK)| |
| *********** | | Display | | Display | | | | |
| | | Engine | | Engine | | | | |
| | | (Disp CLK)| | (Disp CLK)| | | | |
| @@@@@@@@@@@ | 00000000000 11111111111 | @@@@@@@@@@ |
I | | Common | | | | | | |
R <-+--| Control | | | Display | | | |
Q | | (AXI CLK) | | | Controller | | | |
| @@@@@@@@@@@ +------------------------------------+ | |
| | | ^ | |
+--------------------------+----------------+-------+---------+--------+
^ | | | |
| V V | V
Clocks & Resets Display Display Panic Destination
Output0 Output1 Control buffer
(AXI write master)
maintainers:
- Liu Ying <victor.liu@nxp.com>
properties:
compatible:
const: fsl,imx8qxp-dc
reg:
maxItems: 1
clocks:
maxItems: 1
resets:
maxItems: 2
reset-names:
items:
- const: axi
- const: cfg
power-domains:
maxItems: 1
"#address-cells":
const: 1
"#size-cells":
const: 1
ranges: true
patternProperties:
"^command-sequencer@[0-9a-f]+$":
type: object
additionalProperties: true
properties:
compatible:
const: fsl,imx8qxp-dc-command-sequencer
"^display-engine@[0-9a-f]+$":
type: object
additionalProperties: true
properties:
compatible:
const: fsl,imx8qxp-dc-display-engine
"^interrupt-controller@[0-9a-f]+$":
type: object
additionalProperties: true
properties:
compatible:
const: fsl,imx8qxp-dc-intc
"^pixel-engine@[0-9a-f]+$":
type: object
additionalProperties: true
properties:
compatible:
const: fsl,imx8qxp-dc-pixel-engine
"^pmu@[0-9a-f]+$":
type: object
additionalProperties: true
properties:
compatible:
const: fsl,imx8qxp-dc-axi-performance-counter
required:
- compatible
- reg
- clocks
- power-domains
- "#address-cells"
- "#size-cells"
- ranges
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/imx8-lpcg.h>
#include <dt-bindings/firmware/imx/rsrc.h>
display-controller@56180000 {
compatible = "fsl,imx8qxp-dc";
reg = <0x56180000 0x40000>;
clocks = <&dc0_lpcg IMX_LPCG_CLK_4>;
power-domains = <&pd IMX_SC_R_DC_0>;
#address-cells = <1>;
#size-cells = <1>;
ranges;
interrupt-controller@56180040 {
compatible = "fsl,imx8qxp-dc-intc";
reg = <0x56180040 0x60>;
clocks = <&dc0_lpcg IMX_LPCG_CLK_5>;
interrupt-controller;
interrupt-parent = <&dc0_irqsteer>;
#interrupt-cells = <1>;
interrupts = <448>, <449>, <450>, <64>,
<65>, <66>, <67>, <68>,
<69>, <70>, <193>, <194>,
<195>, <196>, <197>, <72>,
<73>, <74>, <75>, <76>,
<77>, <78>, <79>, <80>,
<81>, <199>, <200>, <201>,
<202>, <203>, <204>, <205>,
<206>, <207>, <208>, <5>,
<0>, <1>, <2>, <3>,
<4>, <82>, <83>, <84>,
<85>, <209>, <210>, <211>,
<212>;
interrupt-names = "store9_shdload",
"store9_framecomplete",
"store9_seqcomplete",
"extdst0_shdload",
"extdst0_framecomplete",
"extdst0_seqcomplete",
"extdst4_shdload",
"extdst4_framecomplete",
"extdst4_seqcomplete",
"extdst1_shdload",
"extdst1_framecomplete",
"extdst1_seqcomplete",
"extdst5_shdload",
"extdst5_framecomplete",
"extdst5_seqcomplete",
"disengcfg_shdload0",
"disengcfg_framecomplete0",
"disengcfg_seqcomplete0",
"framegen0_int0",
"framegen0_int1",
"framegen0_int2",
"framegen0_int3",
"sig0_shdload",
"sig0_valid",
"sig0_error",
"disengcfg_shdload1",
"disengcfg_framecomplete1",
"disengcfg_seqcomplete1",
"framegen1_int0",
"framegen1_int1",
"framegen1_int2",
"framegen1_int3",
"sig1_shdload",
"sig1_valid",
"sig1_error",
"reserved",
"cmdseq_error",
"comctrl_sw0",
"comctrl_sw1",
"comctrl_sw2",
"comctrl_sw3",
"framegen0_primsync_on",
"framegen0_primsync_off",
"framegen0_secsync_on",
"framegen0_secsync_off",
"framegen1_primsync_on",
"framegen1_primsync_off",
"framegen1_secsync_on",
"framegen1_secsync_off";
};
pixel-engine@56180800 {
compatible = "fsl,imx8qxp-dc-pixel-engine";
reg = <0x56180800 0xac00>;
clocks = <&dc0_lpcg IMX_LPCG_CLK_5>;
#address-cells = <1>;
#size-cells = <1>;
ranges;
};
display-engine@5618b400 {
compatible = "fsl,imx8qxp-dc-display-engine";
reg = <0x5618b400 0x14>, <0x5618b800 0x1c00>;
reg-names = "top", "cfg";
interrupt-parent = <&dc0_intc>;
interrupts = <15>, <16>, <17>;
interrupt-names = "shdload", "framecomplete", "seqcomplete";
power-domains = <&pd IMX_SC_R_DC_0_PLL_0>;
#address-cells = <1>;
#size-cells = <1>;
ranges;
};
};

View File

@@ -17,12 +17,17 @@ description:
properties:
compatible:
items:
- enum:
- hannstar,hsd060bhw4
- microchip,ac40t08a-mipi-panel
- powkiddy,x55-panel
- const: himax,hx8394
oneOf:
- items:
- enum:
- hannstar,hsd060bhw4
- microchip,ac40t08a-mipi-panel
- powkiddy,x55-panel
- const: himax,hx8394
- items:
- enum:
- huiling,hl055fhav028c
- const: himax,hx8399c
reg:
maxItems: 1

View File

@@ -19,6 +19,7 @@ properties:
- ampire,am8001280g
- bananapi,lhr050h41
- feixin,k101-im2byl02
- raspberrypi,dsi-7inch
- startek,kd050hdfia020
- tdo,tl050hdv35
- wanchanglong,w552946aba

View File

@@ -57,6 +57,8 @@ properties:
- auo,g121ean01
# AU Optronics Corporation 15.6" (1366x768) TFT LCD panel
- auo,g156xtn01
# AU Optronics Corporation 23.8" FHD (1920x1080) TFT LCD panel
- auo,p238han01
# AU Optronics Corporation 31.5" FHD (1920x1080) TFT LCD panel
- auo,p320hvn03
# AU Optronics Corporation 21.5" FHD (1920x1080) color TFT LCD panel

View File

@@ -0,0 +1,94 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/panel/renesas,r61307.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Renesas R61307 based DSI Display Panel
maintainers:
- Svyatoslav Ryhel <clamor95@gmail.com>
description:
The Renesas R61307 is a generic DSI Panel IC used to control LCD panels.
allOf:
- $ref: panel-common.yaml#
properties:
compatible:
items:
- enum:
# KOE/HITACHI TX13D100VM0EAA 5.0" XGA TFT LCD panel
- hit,tx13d100vm0eaa
- koe,tx13d100vm0eaa
- const: renesas,r61307
reg:
maxItems: 1
vcc-supply:
description: Regulator for main power supply.
iovcc-supply:
description: Regulator for 1.8V IO power supply.
backlight: true
renesas,gamma:
$ref: /schemas/types.yaml#/definitions/uint32
description:
0 - disabled
1-3 - gamma setting A presets
enum: [0, 1, 2, 3]
renesas,column-inversion:
type: boolean
description: switch between line and column inversion. The line
inversion is set by default.
renesas,contrast:
type: boolean
description: digital contrast adjustment
reset-gpios: true
port: true
required:
- compatible
- port
- backlight
additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
dsi {
#address-cells = <1>;
#size-cells = <0>;
panel@1 {
compatible = "koe,tx13d100vm0eaa", "renesas,r61307";
reg = <1>;
reset-gpios = <&gpio 176 GPIO_ACTIVE_LOW>;
renesas,gamma = <3>;
renesas,column-inversion;
renesas,contrast;
vcc-supply = <&vcc_3v0_lcd>;
iovcc-supply = <&iovcc_1v8_lcd>;
backlight = <&backlight>;
port {
panel_in: endpoint {
remote-endpoint = <&dsi_out>;
};
};
};
};
...

View File

@@ -0,0 +1,73 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/panel/renesas,r69328.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Renesas R69328 based DSI Display Panel
maintainers:
- Svyatoslav Ryhel <clamor95@gmail.com>
description:
The Renesas R69328 is a generic DSI Panel IC used to control LCD panels.
allOf:
- $ref: panel-common.yaml#
properties:
compatible:
items:
- enum:
# JDI DX12D100VM0EAA 4.7" WXGA TFT LCD panel
- jdi,dx12d100vm0eaa
- const: renesas,r69328
reg:
maxItems: 1
vdd-supply:
description: Regulator for main power supply.
vddio-supply:
description: Regulator for 1.8V IO power supply.
backlight: true
reset-gpios: true
port: true
required:
- compatible
- port
- backlight
additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
dsi {
#address-cells = <1>;
#size-cells = <0>;
panel@1 {
compatible = "jdi,dx12d100vm0eaa", "renesas,r69328";
reg = <1>;
reset-gpios = <&gpio 176 GPIO_ACTIVE_LOW>;
vdd-supply = <&vdd_3v0_lcd>;
vddio-supply = <&vdd_1v8_io>;
backlight = <&backlight>;
port {
panel_in: endpoint {
remote-endpoint = <&dsi_out>;
};
};
};
};
...

View File

@@ -29,6 +29,7 @@ properties:
- densitron,dmt028vghmcmi-1a
- elida,kd50t048a
- techstar,ts8550b
- winstar,wf40eswaa6mnn0
- const: sitronix,st7701
reg:

View File

@@ -18,7 +18,9 @@ allOf:
properties:
compatible:
const: visionox,rm69299-1080p-display
enum:
- visionox,rm69299-1080p-display
- visionox,rm69299-shift
reg:
maxItems: 1

View File

@@ -20,6 +20,7 @@ properties:
- enum:
- renesas,r9a07g043u-du # RZ/G2UL
- renesas,r9a07g044-du # RZ/G2{L,LC}
- renesas,r9a09g057-du # RZ/V2H(P)
- items:
- enum:
- renesas,r9a07g054-du # RZ/V2L
@@ -101,7 +102,12 @@ allOf:
required:
- port@0
else:
- if:
properties:
compatible:
contains:
const: renesas,r9a07g044-du
then:
properties:
ports:
properties:
@@ -113,6 +119,21 @@ allOf:
required:
- port@0
- port@1
- if:
properties:
compatible:
contains:
const: renesas,r9a09g057-du
then:
properties:
ports:
properties:
port@0:
description: DSI
port@1: false
required:
- port@0
examples:
# RZ/G2L DU

View File

@@ -12,18 +12,25 @@ maintainers:
- Tomi Valkeinen <tomi.valkeinen@ti.com>
description: |
The AM625 and AM65x TI Keystone Display SubSystem with two output
The AM625 and AM65x TI Keystone Display SubSystem has two output
ports and two video planes. In AM65x DSS, the first video port
supports 1 OLDI TX and in AM625 DSS, the first video port output is
internally routed to 2 OLDI TXes. The second video port supports DPI
format. The first plane is full video plane with all features and the
second is a "lite plane" without scaling support.
The AM62L display subsystem has a single output port which supports DPI
format but it only supports single video "lite plane" which does not support
scaling. The output port is routed to SoC boundary via DPI interface and same
DPI signals are also routed internally to DSI Tx controller present within the
SoC. Due to clocking limitations only one of the interface i.e. either DSI or
DPI can be used at once.
properties:
compatible:
enum:
- ti,am625-dss
- ti,am62a7-dss
- ti,am62l-dss
- ti,am65x-dss
reg:
@@ -91,6 +98,8 @@ properties:
For AM625 DSS, the internal DPI output port node from video
port 1.
For AM62A7 DSS, the port is tied off inside the SoC.
For AM62L DSS, the DSS DPI output port node from video port 1
or DSI Tx controller node connected to video port 1.
port@1:
$ref: /schemas/graph.yaml#/properties/port
@@ -123,6 +132,16 @@ allOf:
ports:
properties:
port@0: false
- if:
properties:
compatible:
contains:
const: ti,am62l-dss
then:
properties:
ports:
properties:
port@1: false
required:
- compatible

View File

@@ -47,6 +47,7 @@ properties:
- hisilicon,hi6220-mali
- mediatek,mt7623-mali
- rockchip,rk3328-mali
- rockchip,rk3528-mali
- const: arm,mali-450
# "arm,mali-300"
@@ -148,6 +149,7 @@ allOf:
- rockchip,rk3188-mali
- rockchip,rk3228-mali
- rockchip,rk3328-mali
- rockchip,rk3528-mali
then:
required:
- resets

View File

@@ -0,0 +1,318 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/interrupt-controller/fsl,imx8qxp-dc-intc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Freescale i.MX8qxp Display Controller interrupt controller
description: |
The Display Controller has a built-in interrupt controller with the following
features for all relevant HW events:
* Enable bit (mask)
* Status bit (set by an HW event)
* Preset bit (can be used by SW to set status)
* Clear bit (used by SW to reset the status)
Each interrupt can be connected as IRQ (maskable) and/or NMI (non-maskable).
Alternatively the un-masked trigger signals for all HW events are provided,
allowing it to use a global interrupt controller instead.
Each interrupt can be protected against SW running in user mode. In that case,
only privileged AHB access can control the interrupt status.
maintainers:
- Liu Ying <victor.liu@nxp.com>
properties:
compatible:
const: fsl,imx8qxp-dc-intc
reg:
maxItems: 1
clocks:
maxItems: 1
interrupt-controller: true
"#interrupt-cells":
const: 1
interrupts:
items:
- description: store9 shadow load interrupt(blit engine)
- description: store9 frame complete interrupt(blit engine)
- description: store9 sequence complete interrupt(blit engine)
- description:
extdst0 shadow load interrupt
(display controller, content stream 0)
- description:
extdst0 frame complete interrupt
(display controller, content stream 0)
- description:
extdst0 sequence complete interrupt
(display controller, content stream 0)
- description:
extdst4 shadow load interrupt
(display controller, safety stream 0)
- description:
extdst4 frame complete interrupt
(display controller, safety stream 0)
- description:
extdst4 sequence complete interrupt
(display controller, safety stream 0)
- description:
extdst1 shadow load interrupt
(display controller, content stream 1)
- description:
extdst1 frame complete interrupt
(display controller, content stream 1)
- description:
extdst1 sequence complete interrupt
(display controller, content stream 1)
- description:
extdst5 shadow load interrupt
(display controller, safety stream 1)
- description:
extdst5 frame complete interrupt
(display controller, safety stream 1)
- description:
extdst5 sequence complete interrupt
(display controller, safety stream 1)
- description:
disengcfg0 shadow load interrupt
(display controller, display stream 0)
- description:
disengcfg0 frame complete interrupt
(display controller, display stream 0)
- description:
disengcfg0 sequence complete interrupt
(display controller, display stream 0)
- description:
framegen0 programmable interrupt0
(display controller, display stream 0)
- description:
framegen0 programmable interrupt1
(display controller, display stream 0)
- description:
framegen0 programmable interrupt2
(display controller, display stream 0)
- description:
framegen0 programmable interrupt3
(display controller, display stream 0)
- description:
signature0 shadow load interrupt
(display controller, display stream 0)
- description:
signature0 measurement valid interrupt
(display controller, display stream 0)
- description:
signature0 error condition interrupt
(display controller, display stream 0)
- description:
disengcfg1 shadow load interrupt
(display controller, display stream 1)
- description:
disengcfg1 frame complete interrupt
(display controller, display stream 1)
- description:
disengcfg1 sequence complete interrupt
(display controller, display stream 1)
- description:
framegen1 programmable interrupt0
(display controller, display stream 1)
- description:
framegen1 programmable interrupt1
(display controller, display stream 1)
- description:
framegen1 programmable interrupt2
(display controller, display stream 1)
- description:
framegen1 programmable interrupt3
(display controller, display stream 1)
- description:
signature1 shadow load interrupt
(display controller, display stream 1)
- description:
signature1 measurement valid interrupt
(display controller, display stream 1)
- description:
signature1 error condition interrupt
(display controller, display stream 1)
- description: reserved
- description:
command sequencer error condition interrupt(command sequencer)
- description:
common control software interrupt0(common control)
- description:
common control software interrupt1(common control)
- description:
common control software interrupt2(common control)
- description:
common control software interrupt3(common control)
- description:
framegen0 synchronization status activated interrupt
(display controller, safety stream 0)
- description:
framegen0 synchronization status deactivated interrupt
(display controller, safety stream 0)
- description:
framegen0 synchronization status activated interrupt
(display controller, content stream 0)
- description:
framegen0 synchronization status deactivated interrupt
(display controller, content stream 0)
- description:
framegen1 synchronization status activated interrupt
(display controller, safety stream 1)
- description:
framegen1 synchronization status deactivated interrupt
(display controller, safety stream 1)
- description:
framegen1 synchronization status activated interrupt
(display controller, content stream 1)
- description:
framegen1 synchronization status deactivated interrupt
(display controller, content stream 1)
minItems: 49
interrupt-names:
items:
- const: store9_shdload
- const: store9_framecomplete
- const: store9_seqcomplete
- const: extdst0_shdload
- const: extdst0_framecomplete
- const: extdst0_seqcomplete
- const: extdst4_shdload
- const: extdst4_framecomplete
- const: extdst4_seqcomplete
- const: extdst1_shdload
- const: extdst1_framecomplete
- const: extdst1_seqcomplete
- const: extdst5_shdload
- const: extdst5_framecomplete
- const: extdst5_seqcomplete
- const: disengcfg_shdload0
- const: disengcfg_framecomplete0
- const: disengcfg_seqcomplete0
- const: framegen0_int0
- const: framegen0_int1
- const: framegen0_int2
- const: framegen0_int3
- const: sig0_shdload
- const: sig0_valid
- const: sig0_error
- const: disengcfg_shdload1
- const: disengcfg_framecomplete1
- const: disengcfg_seqcomplete1
- const: framegen1_int0
- const: framegen1_int1
- const: framegen1_int2
- const: framegen1_int3
- const: sig1_shdload
- const: sig1_valid
- const: sig1_error
- const: reserved
- const: cmdseq_error
- const: comctrl_sw0
- const: comctrl_sw1
- const: comctrl_sw2
- const: comctrl_sw3
- const: framegen0_primsync_on
- const: framegen0_primsync_off
- const: framegen0_secsync_on
- const: framegen0_secsync_off
- const: framegen1_primsync_on
- const: framegen1_primsync_off
- const: framegen1_secsync_on
- const: framegen1_secsync_off
minItems: 49
required:
- compatible
- reg
- clocks
- interrupt-controller
- "#interrupt-cells"
- interrupts
- interrupt-names
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/imx8-lpcg.h>
interrupt-controller@56180040 {
compatible = "fsl,imx8qxp-dc-intc";
reg = <0x56180040 0x60>;
clocks = <&dc0_lpcg IMX_LPCG_CLK_5>;
interrupt-controller;
interrupt-parent = <&dc0_irqsteer>;
#interrupt-cells = <1>;
interrupts = <448>, <449>, <450>, <64>,
<65>, <66>, <67>, <68>,
<69>, <70>, <193>, <194>,
<195>, <196>, <197>, <72>,
<73>, <74>, <75>, <76>,
<77>, <78>, <79>, <80>,
<81>, <199>, <200>, <201>,
<202>, <203>, <204>, <205>,
<206>, <207>, <208>, <5>,
<0>, <1>, <2>, <3>,
<4>, <82>, <83>, <84>,
<85>, <209>, <210>, <211>,
<212>;
interrupt-names = "store9_shdload",
"store9_framecomplete",
"store9_seqcomplete",
"extdst0_shdload",
"extdst0_framecomplete",
"extdst0_seqcomplete",
"extdst4_shdload",
"extdst4_framecomplete",
"extdst4_seqcomplete",
"extdst1_shdload",
"extdst1_framecomplete",
"extdst1_seqcomplete",
"extdst5_shdload",
"extdst5_framecomplete",
"extdst5_seqcomplete",
"disengcfg_shdload0",
"disengcfg_framecomplete0",
"disengcfg_seqcomplete0",
"framegen0_int0",
"framegen0_int1",
"framegen0_int2",
"framegen0_int3",
"sig0_shdload",
"sig0_valid",
"sig0_error",
"disengcfg_shdload1",
"disengcfg_framecomplete1",
"disengcfg_seqcomplete1",
"framegen1_int0",
"framegen1_int1",
"framegen1_int2",
"framegen1_int3",
"sig1_shdload",
"sig1_valid",
"sig1_error",
"reserved",
"cmdseq_error",
"comctrl_sw0",
"comctrl_sw1",
"comctrl_sw2",
"comctrl_sw3",
"framegen0_primsync_on",
"framegen0_primsync_off",
"framegen0_secsync_on",
"framegen0_secsync_off",
"framegen1_primsync_on",
"framegen1_primsync_off",
"framegen1_secsync_on",
"framegen1_secsync_off";
};

View File

@@ -672,6 +672,8 @@ patternProperties:
description: Huawei Technologies Co., Ltd.
"^hugsun,.*":
description: Shenzhen Hugsun Technology Co. Ltd.
"^huiling,.*":
description: Shenzhen Huiling Information Technology Co., Ltd.
"^hwacom,.*":
description: HwaCom Systems Inc.
"^hxt,.*":

View File

@@ -693,3 +693,22 @@ dma-buf interoperability
Please see Documentation/userspace-api/dma-buf-alloc-exchange.rst for
information on how dma-buf is integrated and exposed within DRM.
Trace events
============
See Documentation/trace/tracepoints.rst for information about using
Linux Kernel Tracepoints.
In the DRM subsystem, some events are considered stable uAPI to avoid
breaking tools (e.g.: GPUVis, umr) relying on them. Stable means that fields
cannot be removed, nor their formatting updated. Adding new fields is
possible, under the normal uAPI requirements.
Stable uAPI events
------------------
From ``drivers/gpu/drm/scheduler/gpu_scheduler_trace.h``
.. kernel-doc:: drivers/gpu/drm/scheduler/gpu_scheduler_trace.h
:doc: uAPI trace events

View File

@@ -515,6 +515,21 @@ Contact: Douglas Anderson <dianders@chromium.org>
Level: Starter
Remove devm_drm_put_bridge()
----------------------------
Due to how the panel bridge handles the drm_bridge object lifetime, special
care must be taken to dispose of the drm_bridge object when the
panel_bridge is removed. This is currently managed using
devm_drm_put_bridge(), but that is an unsafe, temporary workaround. To fix
that, the DRM panel lifetime needs to be reworked. After the rework is
done, remove devm_drm_put_bridge() and the TODO in
drm_panel_bridge_remove().
Contact: Maxime Ripard <mripard@kernel.org>,
Luca Ceresoli <luca.ceresoli@bootlin.com>
Level: Intermediate
Core refactorings
=================

View File

@@ -89,6 +89,17 @@ You can also run subtests if you do not want to run the entire test::
sudo ./build/tests/kms_flip --run-subtest basic-plain-flip --device "sys:/sys/devices/platform/vkms"
sudo IGT_DEVICE="sys:/sys/devices/platform/vkms" ./build/tests/kms_flip --run-subtest basic-plain-flip
Testing With KUnit
==================
KUnit (Kernel unit testing framework) provides a common framework for unit tests
within the Linux kernel.
More information in ../dev-tools/kunit/index.rst .
To run the VKMS KUnit tests::
tools/testing/kunit/kunit.py run --kunitconfig=drivers/gpu/drm/vkms/tests
TODO
====
@@ -122,8 +133,8 @@ There's lots of plane features we could add support for:
- Scaling.
- Additional buffer formats, especially YUV formats for video like NV12.
Low/high bpp RGB formats would also be interesting.
- Additional buffer formats. Low/high bpp RGB formats would be interesting
[Good to get started].
- Async updates (currently only possible on cursor plane using the legacy
cursor api).

View File

@@ -8064,6 +8064,14 @@ F: Documentation/devicetree/bindings/display/imx/
F: drivers/gpu/drm/imx/ipuv3/
F: drivers/gpu/ipu-v3/
DRM DRIVERS FOR FREESCALE IMX8 DISPLAY CONTROLLER
M: Liu Ying <victor.liu@nxp.com>
L: dri-devel@lists.freedesktop.org
S: Maintained
T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
F: Documentation/devicetree/bindings/display/imx/fsl,imx8qxp-dc*.yaml
F: drivers/gpu/drm/imx/dc/
DRM DRIVERS FOR FREESCALE IMX BRIDGE
M: Liu Ying <victor.liu@nxp.com>
L: dri-devel@lists.freedesktop.org
@@ -8307,9 +8315,17 @@ T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
F: drivers/gpu/drm/scheduler/
F: include/drm/gpu_scheduler.h
DRM LOG
M: Jocelyn Falempe <jfalempe@redhat.com>
M: Javier Martinez Canillas <javierm@redhat.com>
L: dri-devel@lists.freedesktop.org
S: Supported
T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
F: drivers/gpu/drm/clients/drm_log.c
DRM PANEL DRIVERS
M: Neil Armstrong <neil.armstrong@linaro.org>
R: Jessica Zhang <quic_jesszhan@quicinc.com>
R: Jessica Zhang <jessica.zhang@oss.qualcomm.com>
L: dri-devel@lists.freedesktop.org
S: Maintained
T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
@@ -8318,6 +8334,26 @@ F: drivers/gpu/drm/drm_panel.c
F: drivers/gpu/drm/panel/
F: include/drm/drm_panel.h
DRM PANIC
M: Jocelyn Falempe <jfalempe@redhat.com>
M: Javier Martinez Canillas <javierm@redhat.com>
L: dri-devel@lists.freedesktop.org
S: Supported
T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
F: drivers/gpu/drm/drm_draw.c
F: drivers/gpu/drm/drm_draw_internal.h
F: drivers/gpu/drm/drm_panic*.c
F: include/drm/drm_panic*
DRM PANIC QR CODE
M: Jocelyn Falempe <jfalempe@redhat.com>
M: Javier Martinez Canillas <javierm@redhat.com>
L: dri-devel@lists.freedesktop.org
L: rust-for-linux@vger.kernel.org
S: Supported
T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
F: drivers/gpu/drm/drm_panic_qr.rs
DRM PRIVACY-SCREEN CLASS
M: Hans de Goede <hdegoede@redhat.com>
L: dri-devel@lists.freedesktop.org
@@ -20365,6 +20401,7 @@ L: linux-arm-msm@vger.kernel.org
L: dri-devel@lists.freedesktop.org
S: Supported
T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
F: Documentation/ABI/testing/sysfs-driver-qaic
F: Documentation/accel/qaic/
F: drivers/accel/qaic/
F: include/uapi/drm/qaic_accel.h

View File

@@ -848,7 +848,8 @@ int aie2_cmd_submit(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job *job,
goto up_sem;
}
ret = drm_sched_job_init(&job->base, &hwctx->priv->entity, 1, hwctx);
ret = drm_sched_job_init(&job->base, &hwctx->priv->entity, 1, hwctx,
hwctx->client->filp->client_id);
if (ret) {
XDNA_ERR(xdna, "DRM job init failed, ret %d", ret);
goto free_chain;

View File

@@ -1066,28 +1066,11 @@ static bool is_pci_link_healthy(struct hl_device *hdev)
return (device_id == hdev->pdev->device);
}
static void stringify_time_of_last_heartbeat(struct hl_device *hdev, char *time_str, size_t size,
bool is_pq_hb)
{
time64_t seconds = is_pq_hb ? hdev->heartbeat_debug_info.last_pq_heartbeat_ts
: hdev->heartbeat_debug_info.last_eq_heartbeat_ts;
struct tm tm;
if (!seconds)
return;
time64_to_tm(seconds, 0, &tm);
snprintf(time_str, size, "%ld-%02d-%02d %02d:%02d:%02d (UTC)",
tm.tm_year + 1900, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
}
static bool hl_device_eq_heartbeat_received(struct hl_device *hdev)
{
struct eq_heartbeat_debug_info *heartbeat_debug_info = &hdev->heartbeat_debug_info;
u32 cpu_q_id = heartbeat_debug_info->cpu_queue_id, pq_pi_mask = (HL_QUEUE_LENGTH << 1) - 1;
struct asic_fixed_properties *prop = &hdev->asic_prop;
char pq_time_str[64] = "N/A", eq_time_str[64] = "N/A";
if (!prop->cpucp_info.eq_health_check_supported)
return true;
@@ -1095,17 +1078,15 @@ static bool hl_device_eq_heartbeat_received(struct hl_device *hdev)
if (!hdev->eq_heartbeat_received) {
dev_err(hdev->dev, "EQ heartbeat event was not received!\n");
stringify_time_of_last_heartbeat(hdev, pq_time_str, sizeof(pq_time_str), true);
stringify_time_of_last_heartbeat(hdev, eq_time_str, sizeof(eq_time_str), false);
dev_err(hdev->dev,
"EQ: {CI %u, HB counter %u, last HB time: %s}, PQ: {PI: %u, CI: %u (%u), last HB time: %s}\n",
"EQ: {CI %u, HB counter %u, last HB time: %ptTs}, PQ: {PI: %u, CI: %u (%u), last HB time: %ptTs}\n",
hdev->event_queue.ci,
heartbeat_debug_info->heartbeat_event_counter,
eq_time_str,
&hdev->heartbeat_debug_info.last_eq_heartbeat_ts,
hdev->kernel_queues[cpu_q_id].pi,
atomic_read(&hdev->kernel_queues[cpu_q_id].ci),
atomic_read(&hdev->kernel_queues[cpu_q_id].ci) & pq_pi_mask,
pq_time_str);
&hdev->heartbeat_debug_info.last_pq_heartbeat_ts);
hl_eq_dump(hdev, &hdev->event_queue);

View File

@@ -165,6 +165,7 @@ struct ivpu_device {
int boot;
int jsm;
int tdr;
int inference;
int autosuspend;
int d0i3_entry_msg;
int state_dump_msg;

View File

@@ -94,12 +94,14 @@ static void timeouts_init(struct ivpu_device *vdev)
vdev->timeout.boot = -1;
vdev->timeout.jsm = -1;
vdev->timeout.tdr = -1;
vdev->timeout.inference = -1;
vdev->timeout.autosuspend = -1;
vdev->timeout.d0i3_entry_msg = -1;
} else if (ivpu_is_fpga(vdev)) {
vdev->timeout.boot = 50;
vdev->timeout.jsm = 15000;
vdev->timeout.tdr = 30000;
vdev->timeout.inference = 900000;
vdev->timeout.autosuspend = -1;
vdev->timeout.d0i3_entry_msg = 500;
vdev->timeout.state_dump_msg = 10000;
@@ -107,6 +109,7 @@ static void timeouts_init(struct ivpu_device *vdev)
vdev->timeout.boot = 50;
vdev->timeout.jsm = 500;
vdev->timeout.tdr = 10000;
vdev->timeout.inference = 300000;
vdev->timeout.autosuspend = 100;
vdev->timeout.d0i3_entry_msg = 100;
vdev->timeout.state_dump_msg = 10;
@@ -114,6 +117,7 @@ static void timeouts_init(struct ivpu_device *vdev)
vdev->timeout.boot = 1000;
vdev->timeout.jsm = 500;
vdev->timeout.tdr = 2000;
vdev->timeout.inference = 60000;
if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX)
vdev->timeout.autosuspend = 10;
else

View File

@@ -33,8 +33,11 @@ static unsigned long ivpu_tdr_timeout_ms;
module_param_named(tdr_timeout_ms, ivpu_tdr_timeout_ms, ulong, 0644);
MODULE_PARM_DESC(tdr_timeout_ms, "Timeout for device hang detection, in milliseconds, 0 - default");
static unsigned long ivpu_inference_timeout_ms;
module_param_named(inference_timeout_ms, ivpu_inference_timeout_ms, ulong, 0644);
MODULE_PARM_DESC(inference_timeout_ms, "Inference maximum duration, in milliseconds, 0 - default");
#define PM_RESCHEDULE_LIMIT 5
#define PM_TDR_HEARTBEAT_LIMIT 30
static void ivpu_pm_prepare_cold_boot(struct ivpu_device *vdev)
{
@@ -191,6 +194,10 @@ static void ivpu_job_timeout_work(struct work_struct *work)
{
struct ivpu_pm_info *pm = container_of(work, struct ivpu_pm_info, job_timeout_work.work);
struct ivpu_device *vdev = pm->vdev;
unsigned long timeout_ms = ivpu_tdr_timeout_ms ? ivpu_tdr_timeout_ms : vdev->timeout.tdr;
unsigned long inference_timeout_ms = ivpu_inference_timeout_ms ? ivpu_inference_timeout_ms :
vdev->timeout.inference;
u64 inference_max_retries;
u64 heartbeat;
if (ivpu_jsm_get_heartbeat(vdev, 0, &heartbeat) || heartbeat <= vdev->fw->last_heartbeat) {
@@ -198,8 +205,10 @@ static void ivpu_job_timeout_work(struct work_struct *work)
goto recovery;
}
if (atomic_fetch_inc(&vdev->job_timeout_counter) > PM_TDR_HEARTBEAT_LIMIT) {
ivpu_err(vdev, "Job timeout detected, heartbeat limit exceeded\n");
inference_max_retries = DIV_ROUND_UP(inference_timeout_ms, timeout_ms);
if (atomic_fetch_inc(&vdev->job_timeout_counter) >= inference_max_retries) {
ivpu_err(vdev, "Job timeout detected, heartbeat limit (%lld) exceeded\n",
inference_max_retries);
goto recovery;
}

View File

@@ -10,6 +10,7 @@ qaic-y := \
qaic_control.o \
qaic_data.o \
qaic_drv.o \
qaic_ras.o \
qaic_timesync.o \
sahara.o

View File

@@ -167,6 +167,14 @@ struct qaic_device {
struct workqueue_struct *bootlog_wq;
/* Synchronizes access of pages in MHI bootlog device */
struct mutex bootlog_mutex;
/* MHI RAS channel device */
struct mhi_device *ras_ch;
/* Correctable error count */
unsigned int ce_count;
/* Un-correctable error count */
unsigned int ue_count;
/* Un-correctable non-fatal error count */
unsigned int ue_nf_count;
};
struct qaic_drm_device {
@@ -213,8 +221,6 @@ struct qaic_bo {
bool sliced;
/* Request ID of this BO if it is queued for execution */
u16 req_id;
/* Handle assigned to this BO */
u32 handle;
/* Wait on this for completion of DMA transfer of this BO */
struct completion xfer_done;
/*

View File

@@ -731,7 +731,6 @@ int qaic_create_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *fi
if (ret)
goto free_bo;
bo->handle = args->handle;
drm_gem_object_put(obj);
srcu_read_unlock(&qdev->dev_lock, qdev_rcu_id);
srcu_read_unlock(&usr->qddev_lock, usr_rcu_id);

View File

@@ -29,6 +29,7 @@
#include "mhi_controller.h"
#include "qaic.h"
#include "qaic_debugfs.h"
#include "qaic_ras.h"
#include "qaic_timesync.h"
#include "sahara.h"
@@ -695,6 +696,10 @@ static int __init qaic_init(void)
if (ret)
pr_debug("qaic: qaic_bootlog_register failed %d\n", ret);
ret = qaic_ras_register();
if (ret)
pr_debug("qaic: qaic_ras_register failed %d\n", ret);
return 0;
free_mhi:
@@ -722,6 +727,7 @@ static void __exit qaic_exit(void)
* reinitializing the link_up state after the cleanup is done.
*/
link_up = true;
qaic_ras_unregister();
qaic_bootlog_unregister();
qaic_timesync_deinit();
sahara_unregister();

View File

@@ -0,0 +1,642 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. */
/* Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. */
/* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */
#include <asm/byteorder.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/mhi.h>
#include "qaic.h"
#include "qaic_ras.h"
#define MAGIC 0x55AA
#define VERSION 0x2
#define HDR_SZ 12
#define NUM_TEMP_LVL 3
#define POWER_BREAK BIT(0)
enum msg_type {
MSG_PUSH, /* async push from device */
MSG_REQ, /* sync request to device */
MSG_RESP, /* sync response from device */
};
enum err_type {
CE, /* correctable error */
UE, /* uncorrectable error */
UE_NF, /* uncorrectable error that is non-fatal, expect a disruption */
ERR_TYPE_MAX,
};
static const char * const err_type_str[] = {
[CE] = "Correctable",
[UE] = "Uncorrectable",
[UE_NF] = "Uncorrectable Non-Fatal",
};
static const char * const err_class_str[] = {
[CE] = "Warning",
[UE] = "Fatal",
[UE_NF] = "Warning",
};
enum err_source {
SOC_MEM,
PCIE,
DDR,
SYS_BUS1,
SYS_BUS2,
NSP_MEM,
TSENS,
};
static const char * const err_src_str[TSENS + 1] = {
[SOC_MEM] = "SoC Memory",
[PCIE] = "PCIE",
[DDR] = "DDR",
[SYS_BUS1] = "System Bus source 1",
[SYS_BUS2] = "System Bus source 2",
[NSP_MEM] = "NSP Memory",
[TSENS] = "Temperature Sensors",
};
struct ras_data {
/* header start */
/* Magic number to validate the message */
u16 magic;
/* RAS version number */
u16 ver;
u32 seq_num;
/* RAS message type */
u8 type;
u8 id;
/* Size of RAS message without the header in byte */
u16 len;
/* header end */
s32 result;
/*
* Error source
* 0 : SoC Memory
* 1 : PCIE
* 2 : DDR
* 3 : System Bus source 1
* 4 : System Bus source 2
* 5 : NSP Memory
* 6 : Temperature Sensors
*/
u32 source;
/*
* Stores the error type, there are three types of error in RAS
* 0 : correctable error (CE)
* 1 : uncorrectable error (UE)
* 2 : uncorrectable error that is non-fatal (UE_NF)
*/
u32 err_type;
u32 err_threshold;
u32 ce_count;
u32 ue_count;
u32 intr_num;
/* Data specific to error source */
u8 syndrome[64];
} __packed;
struct soc_mem_syndrome {
u64 error_address[8];
} __packed;
struct nsp_mem_syndrome {
u32 error_address[8];
u8 nsp_id;
} __packed;
struct ddr_syndrome {
u32 count;
u32 irq_status;
u32 data_31_0[2];
u32 data_63_32[2];
u32 data_95_64[2];
u32 data_127_96[2];
u32 addr_lsb;
u16 addr_msb;
u16 parity_bits;
u16 instance;
u16 err_type;
} __packed;
struct tsens_syndrome {
u32 threshold_type;
s32 temp;
} __packed;
struct sysbus1_syndrome {
u32 slave;
u32 err_type;
u16 addr[8];
u8 instance;
} __packed;
struct sysbus2_syndrome {
u32 lsb3;
u32 msb3;
u32 lsb2;
u32 msb2;
u32 ext_id;
u16 path;
u16 op_type;
u16 len;
u16 redirect;
u8 valid;
u8 word_error;
u8 non_secure;
u8 opc;
u8 error_code;
u8 trans_type;
u8 addr_space;
u8 instance;
} __packed;
struct pcie_syndrome {
/* CE info */
u32 bad_tlp;
u32 bad_dllp;
u32 replay_rollover;
u32 replay_timeout;
u32 rx_err;
u32 internal_ce_count;
/* UE_NF info */
u32 fc_timeout;
u32 poison_tlp;
u32 ecrc_err;
u32 unsupported_req;
u32 completer_abort;
u32 completion_timeout;
/* UE info */
u32 addr;
u8 index;
/*
* Flag to indicate specific event of PCIe
* BIT(0): Power break (low power)
* BIT(1) to BIT(7): Reserved
*/
u8 flag;
} __packed;
static const char * const threshold_type_str[NUM_TEMP_LVL] = {
[0] = "lower",
[1] = "upper",
[2] = "critical",
};
static void ras_msg_to_cpu(struct ras_data *msg)
{
struct sysbus1_syndrome *sysbus1_syndrome = (struct sysbus1_syndrome *)&msg->syndrome[0];
struct sysbus2_syndrome *sysbus2_syndrome = (struct sysbus2_syndrome *)&msg->syndrome[0];
struct soc_mem_syndrome *soc_syndrome = (struct soc_mem_syndrome *)&msg->syndrome[0];
struct nsp_mem_syndrome *nsp_syndrome = (struct nsp_mem_syndrome *)&msg->syndrome[0];
struct tsens_syndrome *tsens_syndrome = (struct tsens_syndrome *)&msg->syndrome[0];
struct pcie_syndrome *pcie_syndrome = (struct pcie_syndrome *)&msg->syndrome[0];
struct ddr_syndrome *ddr_syndrome = (struct ddr_syndrome *)&msg->syndrome[0];
int i;
le16_to_cpus(&msg->magic);
le16_to_cpus(&msg->ver);
le32_to_cpus(&msg->seq_num);
le16_to_cpus(&msg->len);
le32_to_cpus(&msg->result);
le32_to_cpus(&msg->source);
le32_to_cpus(&msg->err_type);
le32_to_cpus(&msg->err_threshold);
le32_to_cpus(&msg->ce_count);
le32_to_cpus(&msg->ue_count);
le32_to_cpus(&msg->intr_num);
switch (msg->source) {
case SOC_MEM:
for (i = 0; i < 8; i++)
le64_to_cpus(&soc_syndrome->error_address[i]);
break;
case PCIE:
le32_to_cpus(&pcie_syndrome->bad_tlp);
le32_to_cpus(&pcie_syndrome->bad_dllp);
le32_to_cpus(&pcie_syndrome->replay_rollover);
le32_to_cpus(&pcie_syndrome->replay_timeout);
le32_to_cpus(&pcie_syndrome->rx_err);
le32_to_cpus(&pcie_syndrome->internal_ce_count);
le32_to_cpus(&pcie_syndrome->fc_timeout);
le32_to_cpus(&pcie_syndrome->poison_tlp);
le32_to_cpus(&pcie_syndrome->ecrc_err);
le32_to_cpus(&pcie_syndrome->unsupported_req);
le32_to_cpus(&pcie_syndrome->completer_abort);
le32_to_cpus(&pcie_syndrome->completion_timeout);
le32_to_cpus(&pcie_syndrome->addr);
break;
case DDR:
le16_to_cpus(&ddr_syndrome->instance);
le16_to_cpus(&ddr_syndrome->err_type);
le32_to_cpus(&ddr_syndrome->count);
le32_to_cpus(&ddr_syndrome->irq_status);
le32_to_cpus(&ddr_syndrome->data_31_0[0]);
le32_to_cpus(&ddr_syndrome->data_31_0[1]);
le32_to_cpus(&ddr_syndrome->data_63_32[0]);
le32_to_cpus(&ddr_syndrome->data_63_32[1]);
le32_to_cpus(&ddr_syndrome->data_95_64[0]);
le32_to_cpus(&ddr_syndrome->data_95_64[1]);
le32_to_cpus(&ddr_syndrome->data_127_96[0]);
le32_to_cpus(&ddr_syndrome->data_127_96[1]);
le16_to_cpus(&ddr_syndrome->parity_bits);
le16_to_cpus(&ddr_syndrome->addr_msb);
le32_to_cpus(&ddr_syndrome->addr_lsb);
break;
case SYS_BUS1:
le32_to_cpus(&sysbus1_syndrome->slave);
le32_to_cpus(&sysbus1_syndrome->err_type);
for (i = 0; i < 8; i++)
le16_to_cpus(&sysbus1_syndrome->addr[i]);
break;
case SYS_BUS2:
le16_to_cpus(&sysbus2_syndrome->op_type);
le16_to_cpus(&sysbus2_syndrome->len);
le16_to_cpus(&sysbus2_syndrome->redirect);
le16_to_cpus(&sysbus2_syndrome->path);
le32_to_cpus(&sysbus2_syndrome->ext_id);
le32_to_cpus(&sysbus2_syndrome->lsb2);
le32_to_cpus(&sysbus2_syndrome->msb2);
le32_to_cpus(&sysbus2_syndrome->lsb3);
le32_to_cpus(&sysbus2_syndrome->msb3);
break;
case NSP_MEM:
for (i = 0; i < 8; i++)
le32_to_cpus(&nsp_syndrome->error_address[i]);
break;
case TSENS:
le32_to_cpus(&tsens_syndrome->threshold_type);
le32_to_cpus(&tsens_syndrome->temp);
break;
}
}
static void decode_ras_msg(struct qaic_device *qdev, struct ras_data *msg)
{
struct sysbus1_syndrome *sysbus1_syndrome = (struct sysbus1_syndrome *)&msg->syndrome[0];
struct sysbus2_syndrome *sysbus2_syndrome = (struct sysbus2_syndrome *)&msg->syndrome[0];
struct soc_mem_syndrome *soc_syndrome = (struct soc_mem_syndrome *)&msg->syndrome[0];
struct nsp_mem_syndrome *nsp_syndrome = (struct nsp_mem_syndrome *)&msg->syndrome[0];
struct tsens_syndrome *tsens_syndrome = (struct tsens_syndrome *)&msg->syndrome[0];
struct pcie_syndrome *pcie_syndrome = (struct pcie_syndrome *)&msg->syndrome[0];
struct ddr_syndrome *ddr_syndrome = (struct ddr_syndrome *)&msg->syndrome[0];
char *class;
char *level;
if (msg->magic != MAGIC) {
pci_warn(qdev->pdev, "Dropping RAS message with invalid magic %x\n", msg->magic);
return;
}
if (!msg->ver || msg->ver > VERSION) {
pci_warn(qdev->pdev, "Dropping RAS message with invalid version %d\n", msg->ver);
return;
}
if (msg->type != MSG_PUSH) {
pci_warn(qdev->pdev, "Dropping non-PUSH RAS message\n");
return;
}
if (msg->len != sizeof(*msg) - HDR_SZ) {
pci_warn(qdev->pdev, "Dropping RAS message with invalid len %d\n", msg->len);
return;
}
if (msg->err_type >= ERR_TYPE_MAX) {
pci_warn(qdev->pdev, "Dropping RAS message with err type %d\n", msg->err_type);
return;
}
if (msg->err_type == UE)
level = KERN_ERR;
else
level = KERN_WARNING;
switch (msg->source) {
case SOC_MEM:
dev_printk(level, &qdev->pdev->dev, "RAS event.\nClass:%s\nDescription:%s %s %s\nError Threshold for this report %d\nSyndrome:\n 0x%llx\n 0x%llx\n 0x%llx\n 0x%llx\n 0x%llx\n 0x%llx\n 0x%llx\n 0x%llx\n",
err_class_str[msg->err_type],
err_type_str[msg->err_type],
"error from",
err_src_str[msg->source],
msg->err_threshold,
soc_syndrome->error_address[0],
soc_syndrome->error_address[1],
soc_syndrome->error_address[2],
soc_syndrome->error_address[3],
soc_syndrome->error_address[4],
soc_syndrome->error_address[5],
soc_syndrome->error_address[6],
soc_syndrome->error_address[7]);
break;
case PCIE:
dev_printk(level, &qdev->pdev->dev, "RAS event.\nClass:%s\nDescription:%s %s %s\nError Threshold for this report %d\n",
err_class_str[msg->err_type],
err_type_str[msg->err_type],
"error from",
err_src_str[msg->source],
msg->err_threshold);
switch (msg->err_type) {
case CE:
/*
* Modeled after AER prints. This continues the dev_printk() from a few
* lines up. We reduce duplication of code, but also avoid re-printing the
* PCI device info so that the end result looks uniform to the log user.
*/
printk(KERN_WARNING pr_fmt("Syndrome:\n Bad TLP count %d\n Bad DLLP count %d\n Replay Rollover count %d\n Replay Timeout count %d\n Recv Error count %d\n Internal CE count %d\n"),
pcie_syndrome->bad_tlp,
pcie_syndrome->bad_dllp,
pcie_syndrome->replay_rollover,
pcie_syndrome->replay_timeout,
pcie_syndrome->rx_err,
pcie_syndrome->internal_ce_count);
if (msg->ver > 0x1)
pr_warn(" Power break %s\n",
pcie_syndrome->flag & POWER_BREAK ? "ON" : "OFF");
break;
case UE:
printk(KERN_ERR pr_fmt("Syndrome:\n Index %d\n Address 0x%x\n"),
pcie_syndrome->index, pcie_syndrome->addr);
break;
case UE_NF:
printk(KERN_WARNING pr_fmt("Syndrome:\n FC timeout count %d\n Poisoned TLP count %d\n ECRC error count %d\n Unsupported request count %d\n Completer abort count %d\n Completion timeout count %d\n"),
pcie_syndrome->fc_timeout,
pcie_syndrome->poison_tlp,
pcie_syndrome->ecrc_err,
pcie_syndrome->unsupported_req,
pcie_syndrome->completer_abort,
pcie_syndrome->completion_timeout);
break;
default:
break;
}
break;
case DDR:
dev_printk(level, &qdev->pdev->dev, "RAS event.\nClass:%s\nDescription:%s %s %s\nError Threshold for this report %d\nSyndrome:\n Instance %d\n Count %d\n Data 31_0 0x%x 0x%x\n Data 63_32 0x%x 0x%x\n Data 95_64 0x%x 0x%x\n Data 127_96 0x%x 0x%x\n Parity bits 0x%x\n Address msb 0x%x\n Address lsb 0x%x\n",
err_class_str[msg->err_type],
err_type_str[msg->err_type],
"error from",
err_src_str[msg->source],
msg->err_threshold,
ddr_syndrome->instance,
ddr_syndrome->count,
ddr_syndrome->data_31_0[1],
ddr_syndrome->data_31_0[0],
ddr_syndrome->data_63_32[1],
ddr_syndrome->data_63_32[0],
ddr_syndrome->data_95_64[1],
ddr_syndrome->data_95_64[0],
ddr_syndrome->data_127_96[1],
ddr_syndrome->data_127_96[0],
ddr_syndrome->parity_bits,
ddr_syndrome->addr_msb,
ddr_syndrome->addr_lsb);
break;
case SYS_BUS1:
dev_printk(level, &qdev->pdev->dev, "RAS event.\nClass:%s\nDescription:%s %s %s\nError Threshold for this report %d\nSyndrome:\n instance %d\n %s\n err_type %d\n address0 0x%x\n address1 0x%x\n address2 0x%x\n address3 0x%x\n address4 0x%x\n address5 0x%x\n address6 0x%x\n address7 0x%x\n",
err_class_str[msg->err_type],
err_type_str[msg->err_type],
"error from",
err_src_str[msg->source],
msg->err_threshold,
sysbus1_syndrome->instance,
sysbus1_syndrome->slave ? "Slave" : "Master",
sysbus1_syndrome->err_type,
sysbus1_syndrome->addr[0],
sysbus1_syndrome->addr[1],
sysbus1_syndrome->addr[2],
sysbus1_syndrome->addr[3],
sysbus1_syndrome->addr[4],
sysbus1_syndrome->addr[5],
sysbus1_syndrome->addr[6],
sysbus1_syndrome->addr[7]);
break;
case SYS_BUS2:
dev_printk(level, &qdev->pdev->dev, "RAS event.\nClass:%s\nDescription:%s %s %s\nError Threshold for this report %d\nSyndrome:\n instance %d\n valid %d\n word error %d\n non-secure %d\n opc %d\n error code %d\n transaction type %d\n address space %d\n operation type %d\n len %d\n redirect %d\n path %d\n ext_id %d\n lsb2 %d\n msb2 %d\n lsb3 %d\n msb3 %d\n",
err_class_str[msg->err_type],
err_type_str[msg->err_type],
"error from",
err_src_str[msg->source],
msg->err_threshold,
sysbus2_syndrome->instance,
sysbus2_syndrome->valid,
sysbus2_syndrome->word_error,
sysbus2_syndrome->non_secure,
sysbus2_syndrome->opc,
sysbus2_syndrome->error_code,
sysbus2_syndrome->trans_type,
sysbus2_syndrome->addr_space,
sysbus2_syndrome->op_type,
sysbus2_syndrome->len,
sysbus2_syndrome->redirect,
sysbus2_syndrome->path,
sysbus2_syndrome->ext_id,
sysbus2_syndrome->lsb2,
sysbus2_syndrome->msb2,
sysbus2_syndrome->lsb3,
sysbus2_syndrome->msb3);
break;
case NSP_MEM:
dev_printk(level, &qdev->pdev->dev, "RAS event.\nClass:%s\nDescription:%s %s %s\nError Threshold for this report %d\nSyndrome:\n NSP ID %d\n 0x%x\n 0x%x\n 0x%x\n 0x%x\n 0x%x\n 0x%x\n 0x%x\n 0x%x\n",
err_class_str[msg->err_type],
err_type_str[msg->err_type],
"error from",
err_src_str[msg->source],
msg->err_threshold,
nsp_syndrome->nsp_id,
nsp_syndrome->error_address[0],
nsp_syndrome->error_address[1],
nsp_syndrome->error_address[2],
nsp_syndrome->error_address[3],
nsp_syndrome->error_address[4],
nsp_syndrome->error_address[5],
nsp_syndrome->error_address[6],
nsp_syndrome->error_address[7]);
break;
case TSENS:
if (tsens_syndrome->threshold_type >= NUM_TEMP_LVL) {
pci_warn(qdev->pdev, "Dropping RAS message with invalid temp threshold %d\n",
tsens_syndrome->threshold_type);
break;
}
if (msg->err_type)
class = "Fatal";
else if (tsens_syndrome->threshold_type)
class = "Critical";
else
class = "Warning";
dev_printk(level, &qdev->pdev->dev, "RAS event.\nClass:%s\nDescription:%s %s %s\nError Threshold for this report %d\nSyndrome:\n %s threshold\n %d deg C\n",
class,
err_type_str[msg->err_type],
"error from",
err_src_str[msg->source],
msg->err_threshold,
threshold_type_str[tsens_syndrome->threshold_type],
tsens_syndrome->temp);
break;
}
/* Uncorrectable errors are fatal */
if (msg->err_type == UE)
mhi_soc_reset(qdev->mhi_cntrl);
switch (msg->err_type) {
case CE:
if (qdev->ce_count != UINT_MAX)
qdev->ce_count++;
break;
case UE:
if (qdev->ce_count != UINT_MAX)
qdev->ue_count++;
break;
case UE_NF:
if (qdev->ce_count != UINT_MAX)
qdev->ue_nf_count++;
break;
default:
/* not possible */
break;
}
}
static ssize_t ce_count_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct qaic_device *qdev = pci_get_drvdata(to_pci_dev(dev));
return snprintf(buf, PAGE_SIZE, "%d\n", qdev->ce_count);
}
static ssize_t ue_count_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct qaic_device *qdev = pci_get_drvdata(to_pci_dev(dev));
return snprintf(buf, PAGE_SIZE, "%d\n", qdev->ue_count);
}
static ssize_t ue_nonfatal_count_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct qaic_device *qdev = pci_get_drvdata(to_pci_dev(dev));
return snprintf(buf, PAGE_SIZE, "%d\n", qdev->ue_nf_count);
}
static DEVICE_ATTR_RO(ce_count);
static DEVICE_ATTR_RO(ue_count);
static DEVICE_ATTR_RO(ue_nonfatal_count);
static struct attribute *ras_attrs[] = {
&dev_attr_ce_count.attr,
&dev_attr_ue_count.attr,
&dev_attr_ue_nonfatal_count.attr,
NULL,
};
static struct attribute_group ras_group = {
.attrs = ras_attrs,
};
static int qaic_ras_mhi_probe(struct mhi_device *mhi_dev, const struct mhi_device_id *id)
{
struct qaic_device *qdev = pci_get_drvdata(to_pci_dev(mhi_dev->mhi_cntrl->cntrl_dev));
struct ras_data *resp;
int ret;
ret = mhi_prepare_for_transfer(mhi_dev);
if (ret)
return ret;
resp = kzalloc(sizeof(*resp), GFP_KERNEL);
if (!resp) {
mhi_unprepare_from_transfer(mhi_dev);
return -ENOMEM;
}
ret = mhi_queue_buf(mhi_dev, DMA_FROM_DEVICE, resp, sizeof(*resp), MHI_EOT);
if (ret) {
kfree(resp);
mhi_unprepare_from_transfer(mhi_dev);
return ret;
}
ret = device_add_group(&qdev->pdev->dev, &ras_group);
if (ret) {
mhi_unprepare_from_transfer(mhi_dev);
pci_dbg(qdev->pdev, "ras add sysfs failed %d\n", ret);
return ret;
}
dev_set_drvdata(&mhi_dev->dev, qdev);
qdev->ras_ch = mhi_dev;
return ret;
}
static void qaic_ras_mhi_remove(struct mhi_device *mhi_dev)
{
struct qaic_device *qdev;
qdev = dev_get_drvdata(&mhi_dev->dev);
qdev->ras_ch = NULL;
device_remove_group(&qdev->pdev->dev, &ras_group);
mhi_unprepare_from_transfer(mhi_dev);
}
static void qaic_ras_mhi_ul_xfer_cb(struct mhi_device *mhi_dev, struct mhi_result *mhi_result) {}
static void qaic_ras_mhi_dl_xfer_cb(struct mhi_device *mhi_dev, struct mhi_result *mhi_result)
{
struct qaic_device *qdev = dev_get_drvdata(&mhi_dev->dev);
struct ras_data *msg = mhi_result->buf_addr;
int ret;
if (mhi_result->transaction_status) {
kfree(msg);
return;
}
ras_msg_to_cpu(msg);
decode_ras_msg(qdev, msg);
ret = mhi_queue_buf(qdev->ras_ch, DMA_FROM_DEVICE, msg, sizeof(*msg), MHI_EOT);
if (ret) {
dev_err(&mhi_dev->dev, "Cannot requeue RAS recv buf %d\n", ret);
kfree(msg);
}
}
static const struct mhi_device_id qaic_ras_mhi_match_table[] = {
{ .chan = "QAIC_STATUS", },
{},
};
static struct mhi_driver qaic_ras_mhi_driver = {
.id_table = qaic_ras_mhi_match_table,
.remove = qaic_ras_mhi_remove,
.probe = qaic_ras_mhi_probe,
.ul_xfer_cb = qaic_ras_mhi_ul_xfer_cb,
.dl_xfer_cb = qaic_ras_mhi_dl_xfer_cb,
.driver = {
.name = "qaic_ras",
},
};
int qaic_ras_register(void)
{
return mhi_driver_register(&qaic_ras_mhi_driver);
}
void qaic_ras_unregister(void)
{
mhi_driver_unregister(&qaic_ras_mhi_driver);
}

View File

@@ -0,0 +1,10 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright (c) 2020, The Linux Foundation. All rights reserved. */
#ifndef __QAIC_RAS_H__
#define __QAIC_RAS_H__
int qaic_ras_register(void);
void qaic_ras_unregister(void);
#endif /* __QAIC_RAS_H__ */

View File

@@ -36,7 +36,6 @@ config UDMABUF
depends on DMA_SHARED_BUFFER
depends on MEMFD_CREATE || COMPILE_TEST
depends on MMU
select VMAP_PFN
help
A driver to let userspace turn memfd regions into dma-bufs.
Qemu can use this to create host dmabufs for guest framebuffers.

View File

@@ -218,7 +218,6 @@ static void dma_fence_chain_set_deadline(struct dma_fence *fence,
}
const struct dma_fence_ops dma_fence_chain_ops = {
.use_64bit_seqno = true,
.get_driver_name = dma_fence_chain_get_driver_name,
.get_timeline_name = dma_fence_chain_get_timeline_name,
.enable_signaling = dma_fence_chain_enable_signaling,
@@ -252,7 +251,7 @@ void dma_fence_chain_init(struct dma_fence_chain *chain,
chain->prev_seqno = 0;
/* Try to reuse the context of the previous chain node. */
if (prev_chain && __dma_fence_is_later(seqno, prev->seqno, prev->ops)) {
if (prev_chain && __dma_fence_is_later(prev, seqno, prev->seqno)) {
context = prev->context;
chain->prev_seqno = prev->seqno;
} else {
@@ -262,8 +261,8 @@ void dma_fence_chain_init(struct dma_fence_chain *chain,
seqno = max(prev->seqno, seqno);
}
dma_fence_init(&chain->base, &dma_fence_chain_ops,
&chain->lock, context, seqno);
dma_fence_init64(&chain->base, &dma_fence_chain_ops, &chain->lock,
context, seqno);
/*
* Chaining dma_fence_chain container together is only allowed through

View File

@@ -538,8 +538,8 @@ void dma_fence_release(struct kref *kref)
if (WARN(!list_empty(&fence->cb_list) &&
!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags),
"Fence %s:%s:%llx:%llx released with pending signals!\n",
fence->ops->get_driver_name(fence),
fence->ops->get_timeline_name(fence),
dma_fence_driver_name(fence),
dma_fence_timeline_name(fence),
fence->context, fence->seqno)) {
unsigned long flags;
@@ -983,12 +983,32 @@ EXPORT_SYMBOL(dma_fence_set_deadline);
void dma_fence_describe(struct dma_fence *fence, struct seq_file *seq)
{
seq_printf(seq, "%s %s seq %llu %ssignalled\n",
fence->ops->get_driver_name(fence),
fence->ops->get_timeline_name(fence), fence->seqno,
dma_fence_driver_name(fence),
dma_fence_timeline_name(fence),
fence->seqno,
dma_fence_is_signaled(fence) ? "" : "un");
}
EXPORT_SYMBOL(dma_fence_describe);
static void
__dma_fence_init(struct dma_fence *fence, const struct dma_fence_ops *ops,
spinlock_t *lock, u64 context, u64 seqno, unsigned long flags)
{
BUG_ON(!lock);
BUG_ON(!ops || !ops->get_driver_name || !ops->get_timeline_name);
kref_init(&fence->refcount);
fence->ops = ops;
INIT_LIST_HEAD(&fence->cb_list);
fence->lock = lock;
fence->context = context;
fence->seqno = seqno;
fence->flags = flags;
fence->error = 0;
trace_dma_fence_init(fence);
}
/**
* dma_fence_init - Initialize a custom fence.
* @fence: the fence to initialize
@@ -1008,18 +1028,30 @@ void
dma_fence_init(struct dma_fence *fence, const struct dma_fence_ops *ops,
spinlock_t *lock, u64 context, u64 seqno)
{
BUG_ON(!lock);
BUG_ON(!ops || !ops->get_driver_name || !ops->get_timeline_name);
kref_init(&fence->refcount);
fence->ops = ops;
INIT_LIST_HEAD(&fence->cb_list);
fence->lock = lock;
fence->context = context;
fence->seqno = seqno;
fence->flags = 0UL;
fence->error = 0;
trace_dma_fence_init(fence);
__dma_fence_init(fence, ops, lock, context, seqno, 0UL);
}
EXPORT_SYMBOL(dma_fence_init);
/**
* dma_fence_init64 - Initialize a custom fence with 64-bit seqno support.
* @fence: the fence to initialize
* @ops: the dma_fence_ops for operations on this fence
* @lock: the irqsafe spinlock to use for locking this fence
* @context: the execution context this fence is run on
* @seqno: a linear increasing sequence number for this context
*
* Initializes an allocated fence, the caller doesn't have to keep its
* refcount after committing with this fence, but it will need to hold a
* refcount again if &dma_fence_ops.enable_signaling gets called.
*
* Context and seqno are used for easy comparison between fences, allowing
* to check which fence is later by simply using dma_fence_later().
*/
void
dma_fence_init64(struct dma_fence *fence, const struct dma_fence_ops *ops,
spinlock_t *lock, u64 context, u64 seqno)
{
__dma_fence_init(fence, ops, lock, context, seqno,
BIT(DMA_FENCE_FLAG_SEQNO64_BIT));
}
EXPORT_SYMBOL(dma_fence_init64);

View File

@@ -170,7 +170,7 @@ static bool timeline_fence_signaled(struct dma_fence *fence)
{
struct sync_timeline *parent = dma_fence_parent(fence);
return !__dma_fence_is_later(fence->seqno, parent->value, fence->ops);
return !__dma_fence_is_later(fence, fence->seqno, parent->value);
}
static void timeline_fence_set_deadline(struct dma_fence *fence, ktime_t deadline)

View File

@@ -137,8 +137,8 @@ char *sync_file_get_name(struct sync_file *sync_file, char *buf, int len)
struct dma_fence *fence = sync_file->fence;
snprintf(buf, len, "%s-%s%llu-%lld",
fence->ops->get_driver_name(fence),
fence->ops->get_timeline_name(fence),
dma_fence_driver_name(fence),
dma_fence_timeline_name(fence),
fence->context,
fence->seqno);
}
@@ -262,9 +262,9 @@ static long sync_file_ioctl_merge(struct sync_file *sync_file,
static int sync_fill_fence_info(struct dma_fence *fence,
struct sync_fence_info *info)
{
strscpy(info->obj_name, fence->ops->get_timeline_name(fence),
strscpy(info->obj_name, dma_fence_timeline_name(fence),
sizeof(info->obj_name));
strscpy(info->driver_name, fence->ops->get_driver_name(fence),
strscpy(info->driver_name, dma_fence_driver_name(fence),
sizeof(info->driver_name));
info->status = dma_fence_get_status(fence);

View File

@@ -109,29 +109,22 @@ static int mmap_udmabuf(struct dma_buf *buf, struct vm_area_struct *vma)
static int vmap_udmabuf(struct dma_buf *buf, struct iosys_map *map)
{
struct udmabuf *ubuf = buf->priv;
unsigned long *pfns;
struct page **pages;
void *vaddr;
pgoff_t pg;
dma_resv_assert_held(buf->resv);
/**
* HVO may free tail pages, so just use pfn to map each folio
* into vmalloc area.
*/
pfns = kvmalloc_array(ubuf->pagecount, sizeof(*pfns), GFP_KERNEL);
if (!pfns)
pages = kvmalloc_array(ubuf->pagecount, sizeof(*pages), GFP_KERNEL);
if (!pages)
return -ENOMEM;
for (pg = 0; pg < ubuf->pagecount; pg++) {
unsigned long pfn = folio_pfn(ubuf->folios[pg]);
for (pg = 0; pg < ubuf->pagecount; pg++)
pages[pg] = folio_page(ubuf->folios[pg],
ubuf->offsets[pg] >> PAGE_SHIFT);
pfn += ubuf->offsets[pg] >> PAGE_SHIFT;
pfns[pg] = pfn;
}
vaddr = vmap_pfn(pfns, ubuf->pagecount, PAGE_KERNEL);
kvfree(pfns);
vaddr = vm_map_ram(pages, ubuf->pagecount, -1);
kvfree(pages);
if (!vaddr)
return -EINVAL;

View File

@@ -229,9 +229,10 @@ static int adp_mipi_probe(struct platform_device *pdev)
{
struct adp_mipi_drv_private *adp;
adp = devm_kzalloc(&pdev->dev, sizeof(*adp), GFP_KERNEL);
if (!adp)
return -ENOMEM;
adp = devm_drm_bridge_alloc(&pdev->dev, struct adp_mipi_drv_private,
bridge, &adp_dsi_bridge_funcs);
if (IS_ERR(adp))
return PTR_ERR(adp);
adp->mipi = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(adp->mipi)) {
@@ -241,7 +242,6 @@ static int adp_mipi_probe(struct platform_device *pdev)
adp->dsi.dev = &pdev->dev;
adp->dsi.ops = &adp_dsi_host_ops;
adp->bridge.funcs = &adp_dsi_bridge_funcs;
adp->bridge.of_node = pdev->dev.of_node;
adp->bridge.type = DRM_MODE_CONNECTOR_DSI;
dev_set_drvdata(&pdev->dev, adp);

View File

@@ -642,7 +642,7 @@ int amdgpu_amdkfd_submit_ib(struct amdgpu_device *adev,
goto err;
}
ret = amdgpu_job_alloc(adev, NULL, NULL, NULL, 1, &job);
ret = amdgpu_job_alloc(adev, NULL, NULL, NULL, 1, &job, 0);
if (ret)
goto err;

View File

@@ -293,7 +293,8 @@ static int amdgpu_cs_pass1(struct amdgpu_cs_parser *p,
for (i = 0; i < p->gang_size; ++i) {
ret = amdgpu_job_alloc(p->adev, vm, p->entities[i], vm,
num_ibs[i], &p->jobs[i]);
num_ibs[i], &p->jobs[i],
p->filp->client_id);
if (ret)
goto free_all_kdata;
switch (p->adev->enforce_isolation[fpriv->xcp_id]) {

View File

@@ -143,7 +143,6 @@ static bool amdgpu_eviction_fence_enable_signaling(struct dma_fence *f)
}
static const struct dma_fence_ops amdgpu_eviction_fence_ops = {
.use_64bit_seqno = true,
.get_driver_name = amdgpu_eviction_fence_get_driver_name,
.get_timeline_name = amdgpu_eviction_fence_get_timeline_name,
.enable_signaling = amdgpu_eviction_fence_enable_signaling,
@@ -169,9 +168,9 @@ amdgpu_eviction_fence_create(struct amdgpu_eviction_fence_mgr *evf_mgr)
ev_fence->evf_mgr = evf_mgr;
get_task_comm(ev_fence->timeline_name, current);
spin_lock_init(&ev_fence->lock);
dma_fence_init(&ev_fence->base, &amdgpu_eviction_fence_ops,
&ev_fence->lock, evf_mgr->ev_fence_ctx,
atomic_inc_return(&evf_mgr->ev_fence_seq));
dma_fence_init64(&ev_fence->base, &amdgpu_eviction_fence_ops,
&ev_fence->lock, evf_mgr->ev_fence_ctx,
atomic_inc_return(&evf_mgr->ev_fence_seq));
return ev_fence;
}

View File

@@ -204,7 +204,8 @@ static enum drm_gpu_sched_stat amdgpu_job_timedout(struct drm_sched_job *s_job)
int amdgpu_job_alloc(struct amdgpu_device *adev, struct amdgpu_vm *vm,
struct drm_sched_entity *entity, void *owner,
unsigned int num_ibs, struct amdgpu_job **job)
unsigned int num_ibs, struct amdgpu_job **job,
u64 drm_client_id)
{
if (num_ibs == 0)
return -EINVAL;
@@ -222,7 +223,8 @@ int amdgpu_job_alloc(struct amdgpu_device *adev, struct amdgpu_vm *vm,
if (!entity)
return 0;
return drm_sched_job_init(&(*job)->base, entity, 1, owner);
return drm_sched_job_init(&(*job)->base, entity, 1, owner,
drm_client_id);
}
int amdgpu_job_alloc_with_ib(struct amdgpu_device *adev,
@@ -232,7 +234,7 @@ int amdgpu_job_alloc_with_ib(struct amdgpu_device *adev,
{
int r;
r = amdgpu_job_alloc(adev, NULL, entity, owner, 1, job);
r = amdgpu_job_alloc(adev, NULL, entity, owner, 1, job, 0);
if (r)
return r;

View File

@@ -91,7 +91,8 @@ static inline struct amdgpu_ring *amdgpu_job_ring(struct amdgpu_job *job)
int amdgpu_job_alloc(struct amdgpu_device *adev, struct amdgpu_vm *vm,
struct drm_sched_entity *entity, void *owner,
unsigned int num_ibs, struct amdgpu_job **job);
unsigned int num_ibs, struct amdgpu_job **job,
u64 drm_client_id);
int amdgpu_job_alloc_with_ib(struct amdgpu_device *adev,
struct drm_sched_entity *entity, void *owner,
size_t size, enum amdgpu_ib_pool_type pool_type,

View File

@@ -167,25 +167,23 @@ TRACE_EVENT(amdgpu_cs_ioctl,
TP_PROTO(struct amdgpu_job *job),
TP_ARGS(job),
TP_STRUCT__entry(
__field(uint64_t, sched_job_id)
__string(timeline, AMDGPU_JOB_GET_TIMELINE_NAME(job))
__field(unsigned int, context)
__field(unsigned int, seqno)
__field(u64, context)
__field(u64, seqno)
__field(struct dma_fence *, fence)
__string(ring, to_amdgpu_ring(job->base.sched)->name)
__field(u32, num_ibs)
),
TP_fast_assign(
__entry->sched_job_id = job->base.id;
__assign_str(timeline);
__entry->context = job->base.s_fence->finished.context;
__entry->seqno = job->base.s_fence->finished.seqno;
__assign_str(ring);
__entry->num_ibs = job->num_ibs;
),
TP_printk("sched_job=%llu, timeline=%s, context=%u, seqno=%u, ring_name=%s, num_ibs=%u",
__entry->sched_job_id, __get_str(timeline), __entry->context,
TP_printk("timeline=%s, fence=%llu:%llu, ring_name=%s, num_ibs=%u",
__get_str(timeline), __entry->context,
__entry->seqno, __get_str(ring), __entry->num_ibs)
);
@@ -193,24 +191,22 @@ TRACE_EVENT(amdgpu_sched_run_job,
TP_PROTO(struct amdgpu_job *job),
TP_ARGS(job),
TP_STRUCT__entry(
__field(uint64_t, sched_job_id)
__string(timeline, AMDGPU_JOB_GET_TIMELINE_NAME(job))
__field(unsigned int, context)
__field(unsigned int, seqno)
__field(u64, context)
__field(u64, seqno)
__string(ring, to_amdgpu_ring(job->base.sched)->name)
__field(u32, num_ibs)
),
TP_fast_assign(
__entry->sched_job_id = job->base.id;
__assign_str(timeline);
__entry->context = job->base.s_fence->finished.context;
__entry->seqno = job->base.s_fence->finished.seqno;
__assign_str(ring);
__entry->num_ibs = job->num_ibs;
),
TP_printk("sched_job=%llu, timeline=%s, context=%u, seqno=%u, ring_name=%s, num_ibs=%u",
__entry->sched_job_id, __get_str(timeline), __entry->context,
TP_printk("timeline=%s, fence=%llu:%llu, ring_name=%s, num_ibs=%u",
__get_str(timeline), __entry->context,
__entry->seqno, __get_str(ring), __entry->num_ibs)
);
@@ -551,23 +547,19 @@ TRACE_EVENT(amdgpu_ib_pipe_sync,
TP_ARGS(sched_job, fence),
TP_STRUCT__entry(
__string(ring, sched_job->base.sched->name)
__field(uint64_t, id)
__field(struct dma_fence *, fence)
__field(uint64_t, ctx)
__field(unsigned, seqno)
__field(u64, ctx)
__field(u64, seqno)
),
TP_fast_assign(
__assign_str(ring);
__entry->id = sched_job->base.id;
__entry->fence = fence;
__entry->ctx = fence->context;
__entry->seqno = fence->seqno;
),
TP_printk("job ring=%s, id=%llu, need pipe sync to fence=%p, context=%llu, seq=%u",
__get_str(ring), __entry->id,
__entry->fence, __entry->ctx,
__entry->seqno)
TP_printk("job ring=%s need pipe sync to fence=%llu:%llu",
__get_str(ring), __entry->ctx, __entry->seqno)
);
TRACE_EVENT(amdgpu_reset_reg_dumps,

View File

@@ -239,8 +239,8 @@ static int amdgpu_userq_fence_create(struct amdgpu_usermode_queue *userq,
fence = &userq_fence->base;
userq_fence->fence_drv = fence_drv;
dma_fence_init(fence, &amdgpu_userq_fence_ops, &userq_fence->lock,
fence_drv->context, seq);
dma_fence_init64(fence, &amdgpu_userq_fence_ops, &userq_fence->lock,
fence_drv->context, seq);
amdgpu_userq_fence_driver_get(fence_drv);
dma_fence_get(fence);
@@ -334,7 +334,6 @@ static void amdgpu_userq_fence_release(struct dma_fence *f)
}
static const struct dma_fence_ops amdgpu_userq_fence_ops = {
.use_64bit_seqno = true,
.get_driver_name = amdgpu_userq_fence_get_driver_name,
.get_timeline_name = amdgpu_userq_fence_get_timeline_name,
.signaled = amdgpu_userq_fence_signaled,

View File

@@ -71,7 +71,6 @@ static void amdgpu_tlb_fence_work(struct work_struct *work)
}
static const struct dma_fence_ops amdgpu_tlb_fence_ops = {
.use_64bit_seqno = true,
.get_driver_name = amdgpu_tlb_fence_get_driver_name,
.get_timeline_name = amdgpu_tlb_fence_get_timeline_name
};
@@ -101,8 +100,8 @@ void amdgpu_vm_tlb_fence_create(struct amdgpu_device *adev, struct amdgpu_vm *vm
INIT_WORK(&f->work, amdgpu_tlb_fence_work);
spin_lock_init(&f->lock);
dma_fence_init(&f->base, &amdgpu_tlb_fence_ops, &f->lock,
vm->tlb_fence_context, atomic64_read(&vm->tlb_seq));
dma_fence_init64(&f->base, &amdgpu_tlb_fence_ops, &f->lock,
vm->tlb_fence_context, atomic64_read(&vm->tlb_seq));
/* TODO: We probably need a separate wq here */
dma_fence_get(&f->base);

View File

@@ -11,8 +11,8 @@
#include <linux/clk.h>
#include <linux/of_graph.h>
#include <linux/platform_data/simplefb.h>
#include <video/pixel_format.h>
#include <video/videomode.h>
#include <drm/drm_atomic.h>
@@ -73,7 +73,17 @@ static const struct drm_crtc_funcs hdlcd_crtc_funcs = {
.disable_vblank = hdlcd_crtc_disable_vblank,
};
static struct simplefb_format supported_formats[] = SIMPLEFB_FORMATS;
static const struct {
u32 fourcc;
struct pixel_format pixel;
} supported_formats[] = {
{ DRM_FORMAT_RGB565, PIXEL_FORMAT_RGB565 },
{ DRM_FORMAT_XRGB1555, PIXEL_FORMAT_XRGB1555 },
{ DRM_FORMAT_RGB888, PIXEL_FORMAT_RGB888 },
{ DRM_FORMAT_XRGB8888, PIXEL_FORMAT_XRGB8888 },
{ DRM_FORMAT_XBGR8888, PIXEL_FORMAT_XBGR8888 },
{ DRM_FORMAT_XRGB2101010, PIXEL_FORMAT_XRGB2101010},
};
/*
* Setup the HDLCD registers for decoding the pixels out of the framebuffer
@@ -83,15 +93,12 @@ static int hdlcd_set_pxl_fmt(struct drm_crtc *crtc)
unsigned int btpp;
struct hdlcd_drm_private *hdlcd = crtc_to_hdlcd_priv(crtc);
const struct drm_framebuffer *fb = crtc->primary->state->fb;
uint32_t pixel_format;
struct simplefb_format *format = NULL;
const struct pixel_format *format = NULL;
int i;
pixel_format = fb->format->format;
for (i = 0; i < ARRAY_SIZE(supported_formats); i++) {
if (supported_formats[i].fourcc == pixel_format)
format = &supported_formats[i];
if (supported_formats[i].fourcc == fb->format->format)
format = &supported_formats[i].pixel;
}
if (WARN_ON(!format))

View File

@@ -64,7 +64,7 @@ static const struct drm_driver ast_driver = {
.minor = DRIVER_MINOR,
.patchlevel = DRIVER_PATCHLEVEL,
DRM_GEM_SHMEM_DRIVER_OPS,
DRM_GEM_SHMEM_DRIVER_OPS_NO_MAP_SGT,
DRM_FBDEV_SHMEM_DRIVER_OPS,
};

View File

@@ -34,6 +34,7 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_color_mgmt.h>
#include <drm/drm_crtc.h>
#include <drm/drm_damage_helper.h>
#include <drm/drm_format_helper.h>
@@ -71,31 +72,44 @@ static unsigned long ast_fb_vram_size(struct ast_device *ast)
return cursor_offset - offset;
}
static inline void ast_load_palette_index(struct ast_device *ast,
u8 index, u8 red, u8 green,
u8 blue)
static void ast_set_gamma_lut(struct drm_crtc *crtc, unsigned int index,
u16 red, u16 green, u16 blue)
{
ast_io_write8(ast, AST_IO_VGADWR, index);
struct drm_device *dev = crtc->dev;
struct ast_device *ast = to_ast_device(dev);
u8 i8 = index & 0xff;
u8 r8 = red >> 8;
u8 g8 = green >> 8;
u8 b8 = blue >> 8;
if (drm_WARN_ON_ONCE(dev, index != i8))
return; /* driver bug */
ast_io_write8(ast, AST_IO_VGADWR, i8);
ast_io_read8(ast, AST_IO_VGASRI);
ast_io_write8(ast, AST_IO_VGAPDR, red);
ast_io_write8(ast, AST_IO_VGAPDR, r8);
ast_io_read8(ast, AST_IO_VGASRI);
ast_io_write8(ast, AST_IO_VGAPDR, green);
ast_io_write8(ast, AST_IO_VGAPDR, g8);
ast_io_read8(ast, AST_IO_VGASRI);
ast_io_write8(ast, AST_IO_VGAPDR, blue);
ast_io_write8(ast, AST_IO_VGAPDR, b8);
ast_io_read8(ast, AST_IO_VGASRI);
}
static void ast_crtc_set_gamma_linear(struct ast_device *ast,
const struct drm_format_info *format)
static void ast_crtc_fill_gamma(struct ast_device *ast,
const struct drm_format_info *format)
{
int i;
struct drm_crtc *crtc = &ast->crtc;
switch (format->format) {
case DRM_FORMAT_C8: /* In this case, gamma table is used as color palette */
case DRM_FORMAT_C8:
/* gamma table is used as color palette */
drm_crtc_fill_palette_8(crtc, ast_set_gamma_lut);
break;
case DRM_FORMAT_RGB565:
/* also uses 8-bit gamma ramp on low-color modes */
fallthrough;
case DRM_FORMAT_XRGB8888:
for (i = 0; i < AST_LUT_SIZE; i++)
ast_load_palette_index(ast, i, i, i, i);
drm_crtc_fill_gamma_888(crtc, ast_set_gamma_lut);
break;
default:
drm_warn_once(&ast->base, "Unsupported format %p4cc for gamma correction\n",
@@ -104,21 +118,22 @@ static void ast_crtc_set_gamma_linear(struct ast_device *ast,
}
}
static void ast_crtc_set_gamma(struct ast_device *ast,
const struct drm_format_info *format,
struct drm_color_lut *lut)
static void ast_crtc_load_gamma(struct ast_device *ast,
const struct drm_format_info *format,
struct drm_color_lut *lut)
{
int i;
struct drm_crtc *crtc = &ast->crtc;
switch (format->format) {
case DRM_FORMAT_C8: /* In this case, gamma table is used as color palette */
case DRM_FORMAT_C8:
/* gamma table is used as color palette */
drm_crtc_load_palette_8(crtc, lut, ast_set_gamma_lut);
break;
case DRM_FORMAT_RGB565:
/* also uses 8-bit gamma ramp on low-color modes */
fallthrough;
case DRM_FORMAT_XRGB8888:
for (i = 0; i < AST_LUT_SIZE; i++)
ast_load_palette_index(ast, i,
lut[i].red >> 8,
lut[i].green >> 8,
lut[i].blue >> 8);
drm_crtc_load_gamma_888(crtc, lut, ast_set_gamma_lut);
break;
default:
drm_warn_once(&ast->base, "Unsupported format %p4cc for gamma correction\n",
@@ -811,11 +826,11 @@ ast_crtc_helper_atomic_flush(struct drm_crtc *crtc,
*/
if (crtc_state->enable && crtc_state->color_mgmt_changed) {
if (crtc_state->gamma_lut)
ast_crtc_set_gamma(ast,
ast_crtc_state->format,
crtc_state->gamma_lut->data);
ast_crtc_load_gamma(ast,
ast_crtc_state->format,
crtc_state->gamma_lut->data);
else
ast_crtc_set_gamma_linear(ast, ast_crtc_state->format);
ast_crtc_fill_gamma(ast, ast_crtc_state->format);
}
}

View File

@@ -5,6 +5,9 @@ config DRM_I2C_ADV7511
select DRM_KMS_HELPER
select REGMAP_I2C
select DRM_MIPI_DSI
select DRM_DISPLAY_HELPER
select DRM_BRIDGE_CONNECTOR
select DRM_DISPLAY_HDMI_STATE_HELPER
help
Support for the Analog Devices ADV7511(W)/13/33/35 HDMI encoders.
@@ -19,7 +22,7 @@ config DRM_I2C_ADV7511_AUDIO
config DRM_I2C_ADV7511_CEC
bool "ADV7511/33/35 HDMI CEC driver"
depends on DRM_I2C_ADV7511
select CEC_CORE
select DRM_DISPLAY_HDMI_CEC_HELPER
default y
help
When selected the HDMI transmitter will support the CEC feature.

View File

@@ -313,16 +313,11 @@ enum adv7511_csc_scaling {
* @csc_enable: Whether to enable color space conversion
* @csc_scaling_factor: Color space conversion scaling factor
* @csc_coefficents: Color space conversion coefficents
* @hdmi_mode: Whether to use HDMI or DVI output mode
* @avi_infoframe: HDMI infoframe
*/
struct adv7511_video_config {
bool csc_enable;
enum adv7511_csc_scaling csc_scaling_factor;
const uint16_t *csc_coefficents;
bool hdmi_mode;
struct hdmi_avi_infoframe avi_infoframe;
};
enum adv7511_type {
@@ -337,6 +332,7 @@ struct adv7511_chip_info {
enum adv7511_type type;
unsigned int max_mode_clock_khz;
unsigned int max_lane_freq_khz;
const char *name;
const char * const *supply_names;
unsigned int num_supplies;
unsigned int reg_cec_offset;
@@ -371,7 +367,7 @@ struct adv7511 {
struct work_struct hpd_work;
struct drm_bridge bridge;
struct drm_connector connector;
struct drm_connector *cec_connector;
bool embedded_sync;
enum adv7511_sync_polarity vsync_polarity;
@@ -389,9 +385,7 @@ struct adv7511 {
bool use_timing_gen;
const struct adv7511_chip_info *info;
struct platform_device *audio_pdev;
struct cec_adapter *cec_adap;
u8 cec_addr[ADV7511_MAX_ADDRS];
u8 cec_valid_addrs;
bool cec_enabled_adap;
@@ -399,20 +393,29 @@ struct adv7511 {
u32 cec_clk_freq;
};
static inline struct adv7511 *bridge_to_adv7511(struct drm_bridge *bridge)
{
return container_of(bridge, struct adv7511, bridge);
}
#ifdef CONFIG_DRM_I2C_ADV7511_CEC
int adv7511_cec_init(struct device *dev, struct adv7511 *adv7511);
int adv7511_cec_init(struct drm_connector *connector,
struct drm_bridge *bridge);
int adv7511_cec_enable(struct drm_bridge *bridge, bool enable);
int adv7511_cec_log_addr(struct drm_bridge *bridge, u8 addr);
int adv7511_cec_transmit(struct drm_bridge *bridge, u8 attempts,
u32 signal_free_time, struct cec_msg *msg);
int adv7511_cec_irq_process(struct adv7511 *adv7511, unsigned int irq1);
#else
static inline int adv7511_cec_init(struct device *dev, struct adv7511 *adv7511)
{
regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL,
ADV7511_CEC_CTRL_POWER_DOWN);
return 0;
}
#define adv7511_cec_init NULL
#define adv7511_cec_enable NULL
#define adv7511_cec_log_addr NULL
#define adv7511_cec_transmit NULL
#endif
void adv7533_dsi_power_on(struct adv7511 *adv);
void adv7533_dsi_power_off(struct adv7511 *adv);
void adv7533_dsi_config_timing_gen(struct adv7511 *adv);
enum drm_mode_status adv7533_mode_valid(struct adv7511 *adv,
const struct drm_display_mode *mode);
int adv7533_patch_registers(struct adv7511 *adv);
@@ -421,16 +424,18 @@ int adv7533_attach_dsi(struct adv7511 *adv);
int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv);
#ifdef CONFIG_DRM_I2C_ADV7511_AUDIO
int adv7511_audio_init(struct device *dev, struct adv7511 *adv7511);
void adv7511_audio_exit(struct adv7511 *adv7511);
int adv7511_hdmi_audio_startup(struct drm_connector *connector,
struct drm_bridge *bridge);
void adv7511_hdmi_audio_shutdown(struct drm_connector *connector,
struct drm_bridge *bridge);
int adv7511_hdmi_audio_prepare(struct drm_connector *connector,
struct drm_bridge *bridge,
struct hdmi_codec_daifmt *fmt,
struct hdmi_codec_params *hparms);
#else /*CONFIG_DRM_I2C_ADV7511_AUDIO */
static inline int adv7511_audio_init(struct device *dev, struct adv7511 *adv7511)
{
return 0;
}
static inline void adv7511_audio_exit(struct adv7511 *adv7511)
{
}
#define adv7511_hdmi_audio_startup NULL
#define adv7511_hdmi_audio_shutdown NULL
#define adv7511_hdmi_audio_prepare NULL
#endif /* CONFIG_DRM_I2C_ADV7511_AUDIO */
#endif /* __DRM_I2C_ADV7511_H__ */

View File

@@ -55,11 +55,12 @@ static int adv7511_update_cts_n(struct adv7511 *adv7511)
return 0;
}
static int adv7511_hdmi_hw_params(struct device *dev, void *data,
struct hdmi_codec_daifmt *fmt,
struct hdmi_codec_params *hparms)
int adv7511_hdmi_audio_prepare(struct drm_connector *connector,
struct drm_bridge *bridge,
struct hdmi_codec_daifmt *fmt,
struct hdmi_codec_params *hparms)
{
struct adv7511 *adv7511 = dev_get_drvdata(dev);
struct adv7511 *adv7511 = bridge_to_adv7511(bridge);
unsigned int audio_source, i2s_format = 0;
unsigned int invert_clock;
unsigned int rate;
@@ -167,9 +168,10 @@ static int adv7511_hdmi_hw_params(struct device *dev, void *data,
return 0;
}
static int audio_startup(struct device *dev, void *data)
int adv7511_hdmi_audio_startup(struct drm_connector *connector,
struct drm_bridge *bridge)
{
struct adv7511 *adv7511 = dev_get_drvdata(dev);
struct adv7511 *adv7511 = bridge_to_adv7511(bridge);
regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CONFIG,
BIT(7), 0);
@@ -204,69 +206,12 @@ static int audio_startup(struct device *dev, void *data)
return 0;
}
static void audio_shutdown(struct device *dev, void *data)
void adv7511_hdmi_audio_shutdown(struct drm_connector *connector,
struct drm_bridge *bridge)
{
struct adv7511 *adv7511 = dev_get_drvdata(dev);
struct adv7511 *adv7511 = bridge_to_adv7511(bridge);
if (adv7511->audio_source == ADV7511_AUDIO_SOURCE_SPDIF)
regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CONFIG,
BIT(7), 0);
}
static int adv7511_hdmi_i2s_get_dai_id(struct snd_soc_component *component,
struct device_node *endpoint,
void *data)
{
struct of_endpoint of_ep;
int ret;
ret = of_graph_parse_endpoint(endpoint, &of_ep);
if (ret < 0)
return ret;
/*
* HDMI sound should be located as reg = <2>
* Then, it is sound port 0
*/
if (of_ep.port == 2)
return 0;
return -EINVAL;
}
static const struct hdmi_codec_ops adv7511_codec_ops = {
.hw_params = adv7511_hdmi_hw_params,
.audio_shutdown = audio_shutdown,
.audio_startup = audio_startup,
.get_dai_id = adv7511_hdmi_i2s_get_dai_id,
};
static const struct hdmi_codec_pdata codec_data = {
.ops = &adv7511_codec_ops,
.i2s_formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |
SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE),
.max_i2s_channels = 2,
.i2s = 1,
.no_i2s_capture = 1,
.spdif = 1,
.no_spdif_capture = 1,
};
int adv7511_audio_init(struct device *dev, struct adv7511 *adv7511)
{
adv7511->audio_pdev = platform_device_register_data(dev,
HDMI_CODEC_DRV_NAME,
PLATFORM_DEVID_AUTO,
&codec_data,
sizeof(codec_data));
return PTR_ERR_OR_ZERO(adv7511->audio_pdev);
}
void adv7511_audio_exit(struct adv7511 *adv7511)
{
if (adv7511->audio_pdev) {
platform_device_unregister(adv7511->audio_pdev);
adv7511->audio_pdev = NULL;
}
}

View File

@@ -12,6 +12,8 @@
#include <media/cec.h>
#include <drm/display/drm_hdmi_cec_helper.h>
#include "adv7511.h"
static const u8 ADV7511_REG_CEC_RX_FRAME_HDR[] = {
@@ -44,8 +46,8 @@ static void adv_cec_tx_raw_status(struct adv7511 *adv7511, u8 tx_raw_status)
return;
if (tx_raw_status & ADV7511_INT1_CEC_TX_ARBIT_LOST) {
cec_transmit_attempt_done(adv7511->cec_adap,
CEC_TX_STATUS_ARB_LOST);
drm_connector_hdmi_cec_transmit_attempt_done(adv7511->cec_connector,
CEC_TX_STATUS_ARB_LOST);
return;
}
if (tx_raw_status & ADV7511_INT1_CEC_TX_RETRY_TIMEOUT) {
@@ -72,12 +74,14 @@ static void adv_cec_tx_raw_status(struct adv7511 *adv7511, u8 tx_raw_status)
if (low_drive_cnt)
status |= CEC_TX_STATUS_LOW_DRIVE;
}
cec_transmit_done(adv7511->cec_adap, status,
0, nack_cnt, low_drive_cnt, err_cnt);
drm_connector_hdmi_cec_transmit_done(adv7511->cec_connector, status,
0, nack_cnt, low_drive_cnt,
err_cnt);
return;
}
if (tx_raw_status & ADV7511_INT1_CEC_TX_READY) {
cec_transmit_attempt_done(adv7511->cec_adap, CEC_TX_STATUS_OK);
drm_connector_hdmi_cec_transmit_attempt_done(adv7511->cec_connector,
CEC_TX_STATUS_OK);
return;
}
}
@@ -116,7 +120,7 @@ static void adv7511_cec_rx(struct adv7511 *adv7511, int rx_buf)
regmap_update_bits(adv7511->regmap_cec,
ADV7511_REG_CEC_RX_BUFFERS + offset, BIT(rx_buf), 0);
cec_received_msg(adv7511->cec_adap, &msg);
drm_connector_hdmi_cec_received_msg(adv7511->cec_connector, &msg);
}
int adv7511_cec_irq_process(struct adv7511 *adv7511, unsigned int irq1)
@@ -179,9 +183,9 @@ int adv7511_cec_irq_process(struct adv7511 *adv7511, unsigned int irq1)
return IRQ_HANDLED;
}
static int adv7511_cec_adap_enable(struct cec_adapter *adap, bool enable)
int adv7511_cec_enable(struct drm_bridge *bridge, bool enable)
{
struct adv7511 *adv7511 = cec_get_drvdata(adap);
struct adv7511 *adv7511 = bridge_to_adv7511(bridge);
unsigned int offset = adv7511->info->reg_cec_offset;
if (adv7511->i2c_cec == NULL)
@@ -225,9 +229,9 @@ static int adv7511_cec_adap_enable(struct cec_adapter *adap, bool enable)
return 0;
}
static int adv7511_cec_adap_log_addr(struct cec_adapter *adap, u8 addr)
int adv7511_cec_log_addr(struct drm_bridge *bridge, u8 addr)
{
struct adv7511 *adv7511 = cec_get_drvdata(adap);
struct adv7511 *adv7511 = bridge_to_adv7511(bridge);
unsigned int offset = adv7511->info->reg_cec_offset;
unsigned int i, free_idx = ADV7511_MAX_ADDRS;
@@ -293,10 +297,10 @@ static int adv7511_cec_adap_log_addr(struct cec_adapter *adap, u8 addr)
return 0;
}
static int adv7511_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
u32 signal_free_time, struct cec_msg *msg)
int adv7511_cec_transmit(struct drm_bridge *bridge, u8 attempts,
u32 signal_free_time, struct cec_msg *msg)
{
struct adv7511 *adv7511 = cec_get_drvdata(adap);
struct adv7511 *adv7511 = bridge_to_adv7511(bridge);
unsigned int offset = adv7511->info->reg_cec_offset;
u8 len = msg->len;
unsigned int i;
@@ -328,12 +332,6 @@ static int adv7511_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
return 0;
}
static const struct cec_adap_ops adv7511_cec_adap_ops = {
.adap_enable = adv7511_cec_adap_enable,
.adap_log_addr = adv7511_cec_adap_log_addr,
.adap_transmit = adv7511_cec_adap_transmit,
};
static int adv7511_cec_parse_dt(struct device *dev, struct adv7511 *adv7511)
{
adv7511->cec_clk = devm_clk_get(dev, "cec");
@@ -348,20 +346,18 @@ static int adv7511_cec_parse_dt(struct device *dev, struct adv7511 *adv7511)
return 0;
}
int adv7511_cec_init(struct device *dev, struct adv7511 *adv7511)
int adv7511_cec_init(struct drm_connector *connector,
struct drm_bridge *bridge)
{
struct adv7511 *adv7511 = bridge_to_adv7511(bridge);
struct device *dev = &adv7511->i2c_main->dev;
unsigned int offset = adv7511->info->reg_cec_offset;
int ret = adv7511_cec_parse_dt(dev, adv7511);
if (ret)
goto err_cec_parse_dt;
adv7511->cec_adap = cec_allocate_adapter(&adv7511_cec_adap_ops,
adv7511, dev_name(dev), CEC_CAP_DEFAULTS, ADV7511_MAX_ADDRS);
if (IS_ERR(adv7511->cec_adap)) {
ret = PTR_ERR(adv7511->cec_adap);
goto err_cec_alloc;
}
adv7511->cec_connector = connector;
regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL, 0);
/* cec soft reset */
@@ -378,17 +374,8 @@ int adv7511_cec_init(struct device *dev, struct adv7511 *adv7511)
ADV7511_REG_CEC_CLK_DIV + offset,
((adv7511->cec_clk_freq / 750000) - 1) << 2);
ret = cec_register_adapter(adv7511->cec_adap, dev);
if (ret)
goto err_cec_register;
return 0;
err_cec_register:
cec_delete_adapter(adv7511->cec_adap);
adv7511->cec_adap = NULL;
err_cec_alloc:
dev_info(dev, "Initializing CEC failed with error %d, disabling CEC\n",
ret);
err_cec_parse_dt:
regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL,
ADV7511_CEC_CTRL_POWER_DOWN);

View File

@@ -12,14 +12,17 @@
#include <linux/of.h>
#include <linux/slab.h>
#include <media/cec.h>
#include <sound/pcm.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge_connector.h>
#include <drm/drm_edid.h>
#include <drm/drm_of.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <drm/display/drm_hdmi_helper.h>
#include <drm/display/drm_hdmi_state_helper.h>
#include "adv7511.h"
@@ -203,62 +206,37 @@ static const uint16_t adv7511_csc_ycbcr_to_rgb[] = {
static void adv7511_set_config_csc(struct adv7511 *adv7511,
struct drm_connector *connector,
bool rgb, bool hdmi_mode)
bool rgb)
{
struct adv7511_video_config config;
bool output_format_422, output_format_ycbcr;
unsigned int mode;
uint8_t infoframe[17];
config.hdmi_mode = hdmi_mode;
hdmi_avi_infoframe_init(&config.avi_infoframe);
config.avi_infoframe.scan_mode = HDMI_SCAN_MODE_UNDERSCAN;
if (rgb) {
config.csc_enable = false;
config.avi_infoframe.colorspace = HDMI_COLORSPACE_RGB;
output_format_422 = false;
output_format_ycbcr = false;
} else {
config.csc_scaling_factor = ADV7511_CSC_SCALING_4;
config.csc_coefficents = adv7511_csc_ycbcr_to_rgb;
if ((connector->display_info.color_formats &
DRM_COLOR_FORMAT_YCBCR422) &&
config.hdmi_mode) {
connector->display_info.is_hdmi) {
config.csc_enable = false;
config.avi_infoframe.colorspace =
HDMI_COLORSPACE_YUV422;
} else {
config.csc_enable = true;
config.avi_infoframe.colorspace = HDMI_COLORSPACE_RGB;
}
}
if (config.hdmi_mode) {
mode = ADV7511_HDMI_CFG_MODE_HDMI;
switch (config.avi_infoframe.colorspace) {
case HDMI_COLORSPACE_YUV444:
output_format_422 = false;
output_format_ycbcr = true;
break;
case HDMI_COLORSPACE_YUV422:
output_format_422 = true;
output_format_ycbcr = true;
break;
default:
} else {
config.csc_enable = true;
output_format_422 = false;
output_format_ycbcr = false;
break;
}
} else {
mode = ADV7511_HDMI_CFG_MODE_DVI;
output_format_422 = false;
output_format_ycbcr = false;
}
adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_AVI_INFOFRAME);
if (connector->display_info.is_hdmi)
mode = ADV7511_HDMI_CFG_MODE_HDMI;
else
mode = ADV7511_HDMI_CFG_MODE_DVI;
adv7511_set_colormap(adv7511, config.csc_enable,
config.csc_coefficents,
@@ -269,15 +247,6 @@ static void adv7511_set_config_csc(struct adv7511 *adv7511,
regmap_update_bits(adv7511->regmap, ADV7511_REG_HDCP_HDMI_CFG,
ADV7511_HDMI_CFG_MODE_MASK, mode);
hdmi_avi_infoframe_pack(&config.avi_infoframe, infoframe,
sizeof(infoframe));
/* The AVI infoframe id is not configurable */
regmap_bulk_write(adv7511->regmap, ADV7511_REG_AVI_INFOFRAME_VERSION,
infoframe + 1, sizeof(infoframe) - 1);
adv7511_packet_enable(adv7511, ADV7511_PACKET_ENABLE_AVI_INFOFRAME);
}
static void adv7511_set_link_config(struct adv7511 *adv7511,
@@ -446,22 +415,16 @@ static void adv7511_hpd_work(struct work_struct *work)
* restore its state.
*/
if (status == connector_status_connected &&
adv7511->connector.status == connector_status_disconnected &&
adv7511->status == connector_status_disconnected &&
adv7511->powered) {
regcache_mark_dirty(adv7511->regmap);
adv7511_power_on(adv7511);
}
if (adv7511->connector.status != status) {
adv7511->connector.status = status;
if (adv7511->status != status) {
adv7511->status = status;
if (adv7511->connector.dev) {
if (status == connector_status_disconnected)
cec_phys_addr_invalidate(adv7511->cec_adap);
drm_kms_helper_hotplug_event(adv7511->connector.dev);
} else {
drm_bridge_hpd_notify(&adv7511->bridge, status);
}
drm_bridge_hpd_notify(&adv7511->bridge, status);
}
}
@@ -636,45 +599,11 @@ static const struct drm_edid *adv7511_edid_read(struct adv7511 *adv7511,
if (!adv7511->powered)
__adv7511_power_off(adv7511);
if (drm_edid) {
/*
* FIXME: The CEC physical address should be set using
* cec_s_phys_addr(adap,
* connector->display_info.source_physical_address, false) from
* a path that has read the EDID and called
* drm_edid_connector_update().
*/
const struct edid *edid = drm_edid_raw(drm_edid);
adv7511_set_config_csc(adv7511, connector, adv7511->rgb,
drm_detect_hdmi_monitor(edid));
cec_s_phys_addr_from_edid(adv7511->cec_adap, edid);
} else {
cec_s_phys_addr_from_edid(adv7511->cec_adap, NULL);
}
return drm_edid;
}
static int adv7511_get_modes(struct adv7511 *adv7511,
struct drm_connector *connector)
{
const struct drm_edid *drm_edid;
unsigned int count;
drm_edid = adv7511_edid_read(adv7511, connector);
drm_edid_connector_update(connector, drm_edid);
count = drm_edid_connector_add_modes(connector);
drm_edid_free(drm_edid);
return count;
}
static enum drm_connector_status
adv7511_detect(struct adv7511 *adv7511, struct drm_connector *connector)
adv7511_detect(struct adv7511 *adv7511)
{
enum drm_connector_status status;
unsigned int val;
@@ -699,8 +628,6 @@ adv7511_detect(struct adv7511 *adv7511, struct drm_connector *connector)
if (status == connector_status_connected && hpd && adv7511->powered) {
regcache_mark_dirty(adv7511->regmap);
adv7511_power_on(adv7511);
if (connector)
adv7511_get_modes(adv7511, connector);
if (adv7511->status == connector_status_connected)
status = connector_status_disconnected;
} else {
@@ -719,17 +646,7 @@ adv7511_detect(struct adv7511 *adv7511, struct drm_connector *connector)
return status;
}
static enum drm_mode_status adv7511_mode_valid(struct adv7511 *adv7511,
const struct drm_display_mode *mode)
{
if (mode->clock > 165000)
return MODE_CLOCK_HIGH;
return MODE_OK;
}
static void adv7511_mode_set(struct adv7511 *adv7511,
const struct drm_display_mode *mode,
const struct drm_display_mode *adj_mode)
{
unsigned int low_refresh_rate;
@@ -800,11 +717,11 @@ static void adv7511_mode_set(struct adv7511 *adv7511,
vsync_polarity = 1;
}
if (drm_mode_vrefresh(mode) <= 24)
if (drm_mode_vrefresh(adj_mode) <= 24)
low_refresh_rate = ADV7511_LOW_REFRESH_RATE_24HZ;
else if (drm_mode_vrefresh(mode) <= 25)
else if (drm_mode_vrefresh(adj_mode) <= 25)
low_refresh_rate = ADV7511_LOW_REFRESH_RATE_25HZ;
else if (drm_mode_vrefresh(mode) <= 30)
else if (drm_mode_vrefresh(adj_mode) <= 30)
low_refresh_rate = ADV7511_LOW_REFRESH_RATE_30HZ;
else
low_refresh_rate = ADV7511_LOW_REFRESH_RATE_NONE;
@@ -821,82 +738,30 @@ static void adv7511_mode_set(struct adv7511 *adv7511,
drm_mode_copy(&adv7511->curr_mode, adj_mode);
/* Update horizontal/vertical porch params */
if (adv7511->info->has_dsi && adv7511->use_timing_gen)
adv7533_dsi_config_timing_gen(adv7511);
/*
* TODO Test first order 4:2:2 to 4:4:4 up conversion method, which is
* supposed to give better results.
*/
adv7511->f_tmds = mode->clock;
adv7511->f_tmds = adj_mode->clock;
}
/* -----------------------------------------------------------------------------
* DRM Connector Operations
*/
static struct adv7511 *connector_to_adv7511(struct drm_connector *connector)
{
return container_of(connector, struct adv7511, connector);
}
static int adv7511_connector_get_modes(struct drm_connector *connector)
{
struct adv7511 *adv = connector_to_adv7511(connector);
return adv7511_get_modes(adv, connector);
}
static enum drm_mode_status
adv7511_connector_mode_valid(struct drm_connector *connector,
const struct drm_display_mode *mode)
{
struct adv7511 *adv = connector_to_adv7511(connector);
return adv7511_mode_valid(adv, mode);
}
static struct drm_connector_helper_funcs adv7511_connector_helper_funcs = {
.get_modes = adv7511_connector_get_modes,
.mode_valid = adv7511_connector_mode_valid,
};
static enum drm_connector_status
adv7511_connector_detect(struct drm_connector *connector, bool force)
{
struct adv7511 *adv = connector_to_adv7511(connector);
return adv7511_detect(adv, connector);
}
static const struct drm_connector_funcs adv7511_connector_funcs = {
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = adv7511_connector_detect,
.destroy = drm_connector_cleanup,
.reset = drm_atomic_helper_connector_reset,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
static int adv7511_connector_init(struct adv7511 *adv)
{
struct drm_bridge *bridge = &adv->bridge;
int ret;
struct drm_connector *connector;
if (adv->i2c_main->irq)
adv->connector.polled = DRM_CONNECTOR_POLL_HPD;
else
adv->connector.polled = DRM_CONNECTOR_POLL_CONNECT |
DRM_CONNECTOR_POLL_DISCONNECT;
ret = drm_connector_init(bridge->dev, &adv->connector,
&adv7511_connector_funcs,
DRM_MODE_CONNECTOR_HDMIA);
if (ret < 0) {
connector = drm_bridge_connector_init(bridge->dev, bridge->encoder);
if (IS_ERR(connector)) {
DRM_ERROR("Failed to initialize connector with drm\n");
return ret;
return PTR_ERR(connector);
}
drm_connector_helper_add(&adv->connector,
&adv7511_connector_helper_funcs);
drm_connector_attach_encoder(&adv->connector, bridge->encoder);
drm_connector_attach_encoder(connector, bridge->encoder);
return 0;
}
@@ -905,7 +770,7 @@ static int adv7511_connector_init(struct adv7511 *adv)
* DRM Bridge Operations
*/
static struct adv7511 *bridge_to_adv7511(struct drm_bridge *bridge)
static const struct adv7511 *bridge_to_adv7511_const(const struct drm_bridge *bridge)
{
return container_of(bridge, struct adv7511, bridge);
}
@@ -914,8 +779,29 @@ static void adv7511_bridge_atomic_enable(struct drm_bridge *bridge,
struct drm_atomic_state *state)
{
struct adv7511 *adv = bridge_to_adv7511(bridge);
struct drm_connector *connector;
struct drm_connector_state *conn_state;
struct drm_crtc_state *crtc_state;
adv7511_power_on(adv);
connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder);
if (WARN_ON(!connector))
return;
conn_state = drm_atomic_get_new_connector_state(state, connector);
if (WARN_ON(!conn_state))
return;
crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
if (WARN_ON(!crtc_state))
return;
adv7511_set_config_csc(adv, connector, adv->rgb);
adv7511_mode_set(adv, &crtc_state->adjusted_mode);
drm_atomic_helper_connector_hdmi_update_infoframes(connector, state);
}
static void adv7511_bridge_atomic_disable(struct drm_bridge *bridge,
@@ -926,13 +812,17 @@ static void adv7511_bridge_atomic_disable(struct drm_bridge *bridge,
adv7511_power_off(adv);
}
static void adv7511_bridge_mode_set(struct drm_bridge *bridge,
const struct drm_display_mode *mode,
const struct drm_display_mode *adj_mode)
static enum drm_mode_status
adv7511_bridge_hdmi_tmds_char_rate_valid(const struct drm_bridge *bridge,
const struct drm_display_mode *mode,
unsigned long long tmds_rate)
{
struct adv7511 *adv = bridge_to_adv7511(bridge);
const struct adv7511 *adv = bridge_to_adv7511_const(bridge);
adv7511_mode_set(adv, mode, adj_mode);
if (tmds_rate > 1000ULL * adv->info->max_mode_clock_khz)
return MODE_CLOCK_HIGH;
return MODE_OK;
}
static enum drm_mode_status adv7511_bridge_mode_valid(struct drm_bridge *bridge,
@@ -941,10 +831,10 @@ static enum drm_mode_status adv7511_bridge_mode_valid(struct drm_bridge *bridge,
{
struct adv7511 *adv = bridge_to_adv7511(bridge);
if (adv->info->has_dsi)
return adv7533_mode_valid(adv, mode);
else
return adv7511_mode_valid(adv, mode);
if (!adv->info->has_dsi)
return MODE_OK;
return adv7533_mode_valid(adv, mode);
}
static int adv7511_bridge_attach(struct drm_bridge *bridge,
@@ -978,7 +868,7 @@ static enum drm_connector_status adv7511_bridge_detect(struct drm_bridge *bridge
{
struct adv7511 *adv = bridge_to_adv7511(bridge);
return adv7511_detect(adv, NULL);
return adv7511_detect(adv);
}
static const struct drm_edid *adv7511_bridge_edid_read(struct drm_bridge *bridge,
@@ -989,28 +879,71 @@ static const struct drm_edid *adv7511_bridge_edid_read(struct drm_bridge *bridge
return adv7511_edid_read(adv, connector);
}
static void adv7511_bridge_hpd_notify(struct drm_bridge *bridge,
enum drm_connector_status status)
static int adv7511_bridge_hdmi_clear_infoframe(struct drm_bridge *bridge,
enum hdmi_infoframe_type type)
{
struct adv7511 *adv = bridge_to_adv7511(bridge);
struct adv7511 *adv7511 = bridge_to_adv7511(bridge);
if (status == connector_status_disconnected)
cec_phys_addr_invalidate(adv->cec_adap);
switch (type) {
case HDMI_INFOFRAME_TYPE_AVI:
adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_AVI_INFOFRAME);
break;
default:
drm_dbg_driver(adv7511->bridge.dev, "Unsupported HDMI InfoFrame %x\n", type);
break;
}
return 0;
}
static int adv7511_bridge_hdmi_write_infoframe(struct drm_bridge *bridge,
enum hdmi_infoframe_type type,
const u8 *buffer, size_t len)
{
struct adv7511 *adv7511 = bridge_to_adv7511(bridge);
adv7511_bridge_hdmi_clear_infoframe(bridge, type);
switch (type) {
case HDMI_INFOFRAME_TYPE_AVI:
/* The AVI infoframe id is not configurable */
regmap_bulk_write(adv7511->regmap, ADV7511_REG_AVI_INFOFRAME_VERSION,
buffer + 1, len - 1);
adv7511_packet_enable(adv7511, ADV7511_PACKET_ENABLE_AVI_INFOFRAME);
break;
default:
drm_dbg_driver(adv7511->bridge.dev, "Unsupported HDMI InfoFrame %x\n", type);
break;
}
return 0;
}
static const struct drm_bridge_funcs adv7511_bridge_funcs = {
.mode_set = adv7511_bridge_mode_set,
.mode_valid = adv7511_bridge_mode_valid,
.attach = adv7511_bridge_attach,
.detect = adv7511_bridge_detect,
.edid_read = adv7511_bridge_edid_read,
.hpd_notify = adv7511_bridge_hpd_notify,
.atomic_enable = adv7511_bridge_atomic_enable,
.atomic_disable = adv7511_bridge_atomic_disable,
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
.atomic_reset = drm_atomic_helper_bridge_reset,
.hdmi_tmds_char_rate_valid = adv7511_bridge_hdmi_tmds_char_rate_valid,
.hdmi_clear_infoframe = adv7511_bridge_hdmi_clear_infoframe,
.hdmi_write_infoframe = adv7511_bridge_hdmi_write_infoframe,
.hdmi_audio_startup = adv7511_hdmi_audio_startup,
.hdmi_audio_prepare = adv7511_hdmi_audio_prepare,
.hdmi_audio_shutdown = adv7511_hdmi_audio_shutdown,
.hdmi_cec_init = adv7511_cec_init,
.hdmi_cec_enable = adv7511_cec_enable,
.hdmi_cec_log_addr = adv7511_cec_log_addr,
.hdmi_cec_transmit = adv7511_cec_transmit,
};
/* -----------------------------------------------------------------------------
@@ -1224,9 +1157,10 @@ static int adv7511_probe(struct i2c_client *i2c)
if (!dev->of_node)
return -EINVAL;
adv7511 = devm_kzalloc(dev, sizeof(*adv7511), GFP_KERNEL);
if (!adv7511)
return -ENOMEM;
adv7511 = devm_drm_bridge_alloc(dev, struct adv7511, bridge,
&adv7511_bridge_funcs);
if (IS_ERR(adv7511))
return PTR_ERR(adv7511);
adv7511->i2c_main = i2c;
adv7511->powered = false;
@@ -1323,22 +1257,43 @@ static int adv7511_probe(struct i2c_client *i2c)
if (adv7511->info->link_config)
adv7511_set_link_config(adv7511, &link_config);
ret = adv7511_cec_init(dev, adv7511);
if (ret)
goto err_unregister_cec;
regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL,
ADV7511_CEC_CTRL_POWER_DOWN);
adv7511->bridge.funcs = &adv7511_bridge_funcs;
adv7511->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID;
adv7511->bridge.ops = DRM_BRIDGE_OP_DETECT |
DRM_BRIDGE_OP_EDID |
DRM_BRIDGE_OP_HDMI |
DRM_BRIDGE_OP_HDMI_AUDIO |
DRM_BRIDGE_OP_HDMI_CEC_ADAPTER;
if (adv7511->i2c_main->irq)
adv7511->bridge.ops |= DRM_BRIDGE_OP_HPD;
adv7511->bridge.vendor = "Analog";
adv7511->bridge.product = adv7511->info->name;
#ifdef CONFIG_DRM_I2C_ADV7511_AUDIO
adv7511->bridge.hdmi_audio_dev = dev;
adv7511->bridge.hdmi_audio_max_i2s_playback_channels = 2;
adv7511->bridge.hdmi_audio_i2s_formats = (SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S20_3LE |
SNDRV_PCM_FMTBIT_S24_3LE |
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE),
adv7511->bridge.hdmi_audio_spdif_playback = 1;
adv7511->bridge.hdmi_audio_dai_port = 2;
#endif
#ifdef CONFIG_DRM_I2C_ADV7511_CEC
adv7511->bridge.hdmi_cec_dev = dev;
adv7511->bridge.hdmi_cec_adapter_name = dev_name(dev);
adv7511->bridge.hdmi_cec_available_las = ADV7511_MAX_ADDRS;
#endif
adv7511->bridge.of_node = dev->of_node;
adv7511->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
drm_bridge_add(&adv7511->bridge);
adv7511_audio_init(dev, adv7511);
if (i2c->irq) {
init_waitqueue_head(&adv7511->wq);
@@ -1360,10 +1315,7 @@ static int adv7511_probe(struct i2c_client *i2c)
return 0;
err_unregister_audio:
adv7511_audio_exit(adv7511);
drm_bridge_remove(&adv7511->bridge);
err_unregister_cec:
cec_unregister_adapter(adv7511->cec_adap);
i2c_unregister_device(adv7511->i2c_cec);
clk_disable_unprepare(adv7511->cec_clk);
err_i2c_unregister_packet:
@@ -1388,9 +1340,6 @@ static void adv7511_remove(struct i2c_client *i2c)
drm_bridge_remove(&adv7511->bridge);
adv7511_audio_exit(adv7511);
cec_unregister_adapter(adv7511->cec_adap);
i2c_unregister_device(adv7511->i2c_cec);
clk_disable_unprepare(adv7511->cec_clk);
@@ -1400,6 +1349,8 @@ static void adv7511_remove(struct i2c_client *i2c)
static const struct adv7511_chip_info adv7511_chip_info = {
.type = ADV7511,
.name = "ADV7511",
.max_mode_clock_khz = 165000,
.supply_names = adv7511_supply_names,
.num_supplies = ARRAY_SIZE(adv7511_supply_names),
.link_config = true,
@@ -1407,6 +1358,7 @@ static const struct adv7511_chip_info adv7511_chip_info = {
static const struct adv7511_chip_info adv7533_chip_info = {
.type = ADV7533,
.name = "ADV7533",
.max_mode_clock_khz = 80000,
.max_lane_freq_khz = 800000,
.supply_names = adv7533_supply_names,
@@ -1417,6 +1369,7 @@ static const struct adv7511_chip_info adv7533_chip_info = {
static const struct adv7511_chip_info adv7535_chip_info = {
.type = ADV7535,
.name = "ADV7535",
.max_mode_clock_khz = 148500,
.max_lane_freq_khz = 891000,
.supply_names = adv7533_supply_names,

View File

@@ -24,7 +24,7 @@ static const struct reg_sequence adv7533_cec_fixed_registers[] = {
{ 0x05, 0xc8 },
};
static void adv7511_dsi_config_timing_gen(struct adv7511 *adv)
void adv7533_dsi_config_timing_gen(struct adv7511 *adv)
{
struct mipi_dsi_device *dsi = adv->dsi;
struct drm_display_mode *mode = &adv->curr_mode;
@@ -67,9 +67,6 @@ void adv7533_dsi_power_on(struct adv7511 *adv)
{
struct mipi_dsi_device *dsi = adv->dsi;
if (adv->use_timing_gen)
adv7511_dsi_config_timing_gen(adv);
/* set number of dsi lanes */
regmap_write(adv->regmap_cec, 0x1c, dsi->lanes << 4);
@@ -106,10 +103,6 @@ enum drm_mode_status adv7533_mode_valid(struct adv7511 *adv,
struct mipi_dsi_device *dsi = adv->dsi;
u8 bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
/* Check max clock for either 7533 or 7535 */
if (mode->clock > adv->info->max_mode_clock_khz)
return MODE_CLOCK_HIGH;
/* Check max clock for each lane */
if (mode->clock * bpp > adv->info->max_lane_freq_khz * adv->num_dsi_lanes)
return MODE_CLOCK_HIGH;

View File

@@ -1193,9 +1193,10 @@ static int anx78xx_i2c_probe(struct i2c_client *client)
bool found = false;
int err;
anx78xx = devm_kzalloc(&client->dev, sizeof(*anx78xx), GFP_KERNEL);
if (!anx78xx)
return -ENOMEM;
anx78xx = devm_drm_bridge_alloc(&client->dev, struct anx78xx, bridge,
&anx78xx_bridge_funcs);
if (IS_ERR(anx78xx))
return PTR_ERR(anx78xx);
pdata = &anx78xx->pdata;
@@ -1306,8 +1307,6 @@ static int anx78xx_i2c_probe(struct i2c_client *client)
goto err_poweroff;
}
anx78xx->bridge.funcs = &anx78xx_bridge_funcs;
drm_bridge_add(&anx78xx->bridge);
/* If cable is pulled out, just poweroff and wait for HPD event */

View File

@@ -2596,7 +2596,6 @@ static int anx7625_link_bridge(struct drm_dp_aux *aux)
return ret;
}
platform->bridge.funcs = &anx7625_bridge_funcs;
platform->bridge.of_node = dev->of_node;
if (!anx7625_of_panel_on_aux_bus(dev))
platform->bridge.ops |= DRM_BRIDGE_OP_EDID;
@@ -2630,10 +2629,10 @@ static int anx7625_i2c_probe(struct i2c_client *client)
return -ENODEV;
}
platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
if (!platform) {
platform = devm_drm_bridge_alloc(dev, struct anx7625_data, bridge, &anx7625_bridge_funcs);
if (IS_ERR(platform)) {
DRM_DEV_ERROR(dev, "fail to allocate driver data\n");
return -ENOMEM;
return PTR_ERR(platform);
}
pdata = &platform->pdata;

View File

@@ -109,9 +109,10 @@ static int drm_aux_bridge_probe(struct auxiliary_device *auxdev,
{
struct drm_aux_bridge_data *data;
data = devm_kzalloc(&auxdev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data = devm_drm_bridge_alloc(&auxdev->dev, struct drm_aux_bridge_data,
bridge, &drm_aux_bridge_funcs);
if (IS_ERR(data))
return PTR_ERR(data);
data->dev = &auxdev->dev;
data->next_bridge = devm_drm_of_get_bridge(&auxdev->dev, auxdev->dev.of_node, 0, 0);
@@ -119,7 +120,6 @@ static int drm_aux_bridge_probe(struct auxiliary_device *auxdev,
return dev_err_probe(&auxdev->dev, PTR_ERR(data->next_bridge),
"failed to acquire drm_bridge\n");
data->bridge.funcs = &drm_aux_bridge_funcs;
data->bridge.of_node = data->dev->of_node;
/* passthrough data, allow everything */

View File

@@ -171,12 +171,13 @@ static int drm_aux_hpd_bridge_probe(struct auxiliary_device *auxdev,
{
struct drm_aux_hpd_bridge_data *data;
data = devm_kzalloc(&auxdev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data = devm_drm_bridge_alloc(&auxdev->dev,
struct drm_aux_hpd_bridge_data, bridge,
&drm_aux_hpd_bridge_funcs);
if (IS_ERR(data))
return PTR_ERR(data);
data->dev = &auxdev->dev;
data->bridge.funcs = &drm_aux_hpd_bridge_funcs;
data->bridge.of_node = dev_get_platdata(data->dev);
data->bridge.ops = DRM_BRIDGE_OP_HPD;
data->bridge.type = id->driver_data;

View File

@@ -670,13 +670,28 @@ cdns_dsi_bridge_mode_valid(struct drm_bridge *bridge,
return MODE_OK;
}
static void cdns_dsi_bridge_atomic_disable(struct drm_bridge *bridge,
struct drm_atomic_state *state)
static void cdns_dsi_bridge_atomic_post_disable(struct drm_bridge *bridge,
struct drm_atomic_state *state)
{
struct cdns_dsi_input *input = bridge_to_cdns_dsi_input(bridge);
struct cdns_dsi *dsi = input_to_dsi(input);
u32 val;
/*
* The cdns-dsi controller needs to be disabled after it's DPI source
* has stopped streaming. If this is not followed, there is a brief
* window before DPI source is disabled and after cdns-dsi controller
* has been disabled where the DPI stream is still on, but the cdns-dsi
* controller is not ready anymore to accept the incoming signals. This
* is one of the reasons why a shift in pixel colors is observed on
* displays that have cdns-dsi as one of the bridges.
*
* To mitigate this, disable this bridge from the bridge post_disable()
* hook, instead of the bridge _disable() hook. The bridge post_disable()
* hook gets called after the CRTC disable, where often many DPI sources
* disable their streams.
*/
val = readl(dsi->regs + MCTL_MAIN_DATA_CTL);
val &= ~(IF_VID_SELECT_MASK | IF_VID_MODE | VID_EN | HOST_EOT_GEN |
DISP_EOT_GEN);
@@ -688,15 +703,6 @@ static void cdns_dsi_bridge_atomic_disable(struct drm_bridge *bridge,
if (dsi->platform_ops && dsi->platform_ops->disable)
dsi->platform_ops->disable(dsi);
pm_runtime_put(dsi->base.dev);
}
static void cdns_dsi_bridge_atomic_post_disable(struct drm_bridge *bridge,
struct drm_atomic_state *state)
{
struct cdns_dsi_input *input = bridge_to_cdns_dsi_input(bridge);
struct cdns_dsi *dsi = input_to_dsi(input);
dsi->phy_initialized = false;
dsi->link_initialized = false;
phy_power_off(dsi->dphy);
@@ -774,8 +780,8 @@ static void cdns_dsi_init_link(struct cdns_dsi *dsi)
dsi->link_initialized = true;
}
static void cdns_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
struct drm_atomic_state *state)
static void cdns_dsi_bridge_atomic_pre_enable(struct drm_bridge *bridge,
struct drm_atomic_state *state)
{
struct cdns_dsi_input *input = bridge_to_cdns_dsi_input(bridge);
struct cdns_dsi *dsi = input_to_dsi(input);
@@ -792,6 +798,21 @@ static void cdns_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
u32 tmp, reg_wakeup, div, status;
int nlanes;
/*
* The cdns-dsi controller needs to be enabled before it's DPI source
* has begun streaming. If this is not followed, there is a brief window
* after DPI source enable and before cdns-dsi controller enable where
* the DPI stream is on, but the cdns-dsi controller is not ready to
* accept the incoming signals. This is one of the reasons why a shift
* in pixel colors is observed on displays that have cdns-dsi as one of
* the bridges.
*
* To mitigate this, enable this bridge from the bridge pre_enable()
* hook, instead of the bridge _enable() hook. The bridge pre_enable()
* hook gets called before the CRTC enable, where often many DPI sources
* enable their streams.
*/
if (WARN_ON(pm_runtime_get_sync(dsi->base.dev) < 0))
return;
@@ -811,8 +832,8 @@ static void cdns_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
mode = &crtc_state->adjusted_mode;
nlanes = output->dev->lanes;
cdns_dsi_hs_init(dsi);
cdns_dsi_init_link(dsi);
cdns_dsi_hs_init(dsi);
/*
* Now that the DSI Link and DSI Phy are initialized,
@@ -941,19 +962,6 @@ static void cdns_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
writel(tmp, dsi->regs + MCTL_MAIN_EN);
}
static void cdns_dsi_bridge_atomic_pre_enable(struct drm_bridge *bridge,
struct drm_atomic_state *state)
{
struct cdns_dsi_input *input = bridge_to_cdns_dsi_input(bridge);
struct cdns_dsi *dsi = input_to_dsi(input);
if (WARN_ON(pm_runtime_get_sync(dsi->base.dev) < 0))
return;
cdns_dsi_init_link(dsi);
cdns_dsi_hs_init(dsi);
}
static u32 *cdns_dsi_bridge_get_input_bus_fmts(struct drm_bridge *bridge,
struct drm_bridge_state *bridge_state,
struct drm_crtc_state *crtc_state,
@@ -1048,9 +1056,7 @@ cdns_dsi_bridge_atomic_reset(struct drm_bridge *bridge)
static const struct drm_bridge_funcs cdns_dsi_bridge_funcs = {
.attach = cdns_dsi_bridge_attach,
.mode_valid = cdns_dsi_bridge_mode_valid,
.atomic_disable = cdns_dsi_bridge_atomic_disable,
.atomic_pre_enable = cdns_dsi_bridge_atomic_pre_enable,
.atomic_enable = cdns_dsi_bridge_atomic_enable,
.atomic_post_disable = cdns_dsi_bridge_atomic_post_disable,
.atomic_check = cdns_dsi_bridge_atomic_check,
.atomic_reset = cdns_dsi_bridge_atomic_reset,
@@ -1289,9 +1295,10 @@ static int cdns_dsi_drm_probe(struct platform_device *pdev)
int ret, irq;
u32 val;
dsi = devm_kzalloc(&pdev->dev, sizeof(*dsi), GFP_KERNEL);
if (!dsi)
return -ENOMEM;
dsi = devm_drm_bridge_alloc(&pdev->dev, struct cdns_dsi, input.bridge,
&cdns_dsi_bridge_funcs);
if (IS_ERR(dsi))
return PTR_ERR(dsi);
platform_set_drvdata(pdev, dsi);
@@ -1349,7 +1356,6 @@ static int cdns_dsi_drm_probe(struct platform_device *pdev)
* CDNS_DPI_INPUT.
*/
input->id = CDNS_DPI_INPUT;
input->bridge.funcs = &cdns_dsi_bridge_funcs;
input->bridge.of_node = pdev->dev.of_node;
/* Mask all interrupts before registering the IRQ handler. */

View File

@@ -2389,9 +2389,10 @@ static int cdns_mhdp_probe(struct platform_device *pdev)
int ret;
int irq;
mhdp = devm_kzalloc(dev, sizeof(*mhdp), GFP_KERNEL);
if (!mhdp)
return -ENOMEM;
mhdp = devm_drm_bridge_alloc(dev, struct cdns_mhdp_device, bridge,
&cdns_mhdp_bridge_funcs);
if (IS_ERR(mhdp))
return PTR_ERR(mhdp);
clk = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(clk)) {
@@ -2481,7 +2482,6 @@ static int cdns_mhdp_probe(struct platform_device *pdev)
mhdp->display_fmt.bpc = 8;
mhdp->bridge.of_node = pdev->dev.of_node;
mhdp->bridge.funcs = &cdns_mhdp_bridge_funcs;
mhdp->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID |
DRM_BRIDGE_OP_HPD;
mhdp->bridge.type = DRM_MODE_CONNECTOR_DisplayPort;

View File

@@ -691,9 +691,10 @@ static int chipone_common_probe(struct device *dev, struct chipone **icnr)
struct chipone *icn;
int ret;
icn = devm_kzalloc(dev, sizeof(struct chipone), GFP_KERNEL);
if (!icn)
return -ENOMEM;
icn = devm_drm_bridge_alloc(dev, struct chipone, bridge,
&chipone_bridge_funcs);
if (IS_ERR(icn))
return PTR_ERR(icn);
icn->dev = dev;
@@ -701,7 +702,6 @@ static int chipone_common_probe(struct device *dev, struct chipone **icnr)
if (ret)
return ret;
icn->bridge.funcs = &chipone_bridge_funcs;
icn->bridge.type = DRM_MODE_CONNECTOR_DPI;
icn->bridge.of_node = dev->of_node;

View File

@@ -536,9 +536,10 @@ static int ch7033_probe(struct i2c_client *client)
unsigned int val;
int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv = devm_drm_bridge_alloc(dev, struct ch7033_priv, bridge,
&ch7033_bridge_funcs);
if (IS_ERR(priv))
return PTR_ERR(priv);
dev_set_drvdata(dev, priv);
@@ -575,7 +576,6 @@ static int ch7033_probe(struct i2c_client *client)
}
INIT_LIST_HEAD(&priv->bridge.list);
priv->bridge.funcs = &ch7033_bridge_funcs;
priv->bridge.of_node = dev->of_node;
drm_bridge_add(&priv->bridge);

View File

@@ -103,9 +103,10 @@ static int cros_ec_anx7688_bridge_probe(struct i2c_client *client)
u8 buffer[4];
int ret;
anx7688 = devm_kzalloc(dev, sizeof(*anx7688), GFP_KERNEL);
if (!anx7688)
return -ENOMEM;
anx7688 = devm_drm_bridge_alloc(dev, struct cros_ec_anx7688, bridge,
&cros_ec_anx7688_bridge_funcs);
if (IS_ERR(anx7688))
return PTR_ERR(anx7688);
anx7688->client = client;
i2c_set_clientdata(client, anx7688);
@@ -153,7 +154,6 @@ static int cros_ec_anx7688_bridge_probe(struct i2c_client *client)
DRM_WARN("Old ANX7688 FW version (0x%04x), not filtering\n",
fw_version);
anx7688->bridge.funcs = &cros_ec_anx7688_bridge_funcs;
drm_bridge_add(&anx7688->bridge);
return 0;

View File

@@ -298,16 +298,15 @@ static int fsl_ldb_probe(struct platform_device *pdev)
struct fsl_ldb *fsl_ldb;
int dual_link;
fsl_ldb = devm_kzalloc(dev, sizeof(*fsl_ldb), GFP_KERNEL);
if (!fsl_ldb)
return -ENOMEM;
fsl_ldb = devm_drm_bridge_alloc(dev, struct fsl_ldb, bridge, &funcs);
if (IS_ERR(fsl_ldb))
return PTR_ERR(fsl_ldb);
fsl_ldb->devdata = of_device_get_match_data(dev);
if (!fsl_ldb->devdata)
return -EINVAL;
fsl_ldb->dev = &pdev->dev;
fsl_ldb->bridge.funcs = &funcs;
fsl_ldb->bridge.of_node = dev->of_node;
fsl_ldb->clk = devm_clk_get(dev, "ldb");

View File

@@ -59,9 +59,10 @@ struct drm_bridge *devm_imx_drm_legacy_bridge(struct device *dev,
struct imx_legacy_bridge *imx_bridge;
int ret;
imx_bridge = devm_kzalloc(dev, sizeof(*imx_bridge), GFP_KERNEL);
if (!imx_bridge)
return ERR_PTR(-ENOMEM);
imx_bridge = devm_drm_bridge_alloc(dev, struct imx_legacy_bridge,
base, &imx_legacy_bridge_funcs);
if (IS_ERR(imx_bridge))
return ERR_CAST(imx_bridge);
ret = of_get_drm_display_mode(np,
&imx_bridge->mode,
@@ -72,7 +73,6 @@ struct drm_bridge *devm_imx_drm_legacy_bridge(struct device *dev,
imx_bridge->mode.type |= DRM_MODE_TYPE_DRIVER;
imx_bridge->base.funcs = &imx_legacy_bridge_funcs;
imx_bridge->base.of_node = np;
imx_bridge->base.ops = DRM_BRIDGE_OP_MODES;
imx_bridge->base.type = type;

View File

@@ -140,9 +140,10 @@ static int imx8mp_hdmi_pvi_probe(struct platform_device *pdev)
struct device_node *remote;
struct imx8mp_hdmi_pvi *pvi;
pvi = devm_kzalloc(&pdev->dev, sizeof(*pvi), GFP_KERNEL);
if (!pvi)
return -ENOMEM;
pvi = devm_drm_bridge_alloc(&pdev->dev, struct imx8mp_hdmi_pvi,
bridge, &imx_hdmi_pvi_bridge_funcs);
if (IS_ERR(pvi))
return PTR_ERR(pvi);
platform_set_drvdata(pdev, pvi);
pvi->dev = &pdev->dev;
@@ -166,7 +167,6 @@ static int imx8mp_hdmi_pvi_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
/* Register the bridge. */
pvi->bridge.funcs = &imx_hdmi_pvi_bridge_funcs;
pvi->bridge.of_node = pdev->dev.of_node;
pvi->bridge.timings = pvi->next_bridge->timings;

View File

@@ -63,12 +63,11 @@ struct imx8qxp_pc_channel {
struct drm_bridge *next_bridge;
struct imx8qxp_pc *pc;
unsigned int stream_id;
bool is_available;
};
struct imx8qxp_pc {
struct device *dev;
struct imx8qxp_pc_channel ch[2];
struct imx8qxp_pc_channel *ch[2];
struct clk *clk_apb;
void __iomem *base;
};
@@ -307,7 +306,14 @@ static int imx8qxp_pc_bridge_probe(struct platform_device *pdev)
goto free_child;
}
ch = &pc->ch[i];
ch = devm_drm_bridge_alloc(dev, struct imx8qxp_pc_channel, bridge,
&imx8qxp_pc_bridge_funcs);
if (IS_ERR(ch)) {
ret = PTR_ERR(ch);
goto free_child;
}
pc->ch[i] = ch;
ch->pc = pc;
ch->stream_id = i;
@@ -333,9 +339,7 @@ static int imx8qxp_pc_bridge_probe(struct platform_device *pdev)
of_node_put(remote);
ch->bridge.driver_private = ch;
ch->bridge.funcs = &imx8qxp_pc_bridge_funcs;
ch->bridge.of_node = child;
ch->is_available = true;
drm_bridge_add(&ch->bridge);
}
@@ -345,8 +349,8 @@ static int imx8qxp_pc_bridge_probe(struct platform_device *pdev)
free_child:
of_node_put(child);
if (i == 1 && pc->ch[0].next_bridge)
drm_bridge_remove(&pc->ch[0].bridge);
if (i == 1 && pc->ch[0]->next_bridge)
drm_bridge_remove(&pc->ch[0]->bridge);
pm_runtime_disable(dev);
return ret;
@@ -359,13 +363,10 @@ static void imx8qxp_pc_bridge_remove(struct platform_device *pdev)
int i;
for (i = 0; i < 2; i++) {
ch = &pc->ch[i];
ch = pc->ch[i];
if (!ch->is_available)
continue;
drm_bridge_remove(&ch->bridge);
ch->is_available = false;
if (ch)
drm_bridge_remove(&ch->bridge);
}
pm_runtime_disable(&pdev->dev);

View File

@@ -327,9 +327,10 @@ static int imx8qxp_pixel_link_bridge_probe(struct platform_device *pdev)
struct device_node *np = dev->of_node;
int ret;
pl = devm_kzalloc(dev, sizeof(*pl), GFP_KERNEL);
if (!pl)
return -ENOMEM;
pl = devm_drm_bridge_alloc(dev, struct imx8qxp_pixel_link, bridge,
&imx8qxp_pixel_link_bridge_funcs);
if (IS_ERR(pl))
return PTR_ERR(pl);
ret = imx_scu_get_handle(&pl->ipc_handle);
if (ret) {
@@ -384,7 +385,6 @@ static int imx8qxp_pixel_link_bridge_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, pl);
pl->bridge.driver_private = pl;
pl->bridge.funcs = &imx8qxp_pixel_link_bridge_funcs;
pl->bridge.of_node = np;
drm_bridge_add(&pl->bridge);

View File

@@ -392,9 +392,10 @@ static int imx8qxp_pxl2dpi_bridge_probe(struct platform_device *pdev)
struct device_node *np = dev->of_node;
int ret;
p2d = devm_kzalloc(dev, sizeof(*p2d), GFP_KERNEL);
if (!p2d)
return -ENOMEM;
p2d = devm_drm_bridge_alloc(dev, struct imx8qxp_pxl2dpi, bridge,
&imx8qxp_pxl2dpi_bridge_funcs);
if (IS_ERR(p2d))
return PTR_ERR(p2d);
p2d->regmap = syscon_node_to_regmap(np->parent);
if (IS_ERR(p2d->regmap)) {
@@ -441,7 +442,6 @@ static int imx8qxp_pxl2dpi_bridge_probe(struct platform_device *pdev)
pm_runtime_enable(dev);
p2d->bridge.driver_private = p2d;
p2d->bridge.funcs = &imx8qxp_pxl2dpi_bridge_funcs;
p2d->bridge.of_node = np;
drm_bridge_add(&p2d->bridge);

View File

@@ -816,9 +816,10 @@ static int it6263_probe(struct i2c_client *client)
struct it6263 *it;
int ret;
it = devm_kzalloc(dev, sizeof(*it), GFP_KERNEL);
if (!it)
return -ENOMEM;
it = devm_drm_bridge_alloc(dev, struct it6263, bridge,
&it6263_bridge_funcs);
if (IS_ERR(it))
return PTR_ERR(it);
it->dev = dev;
it->hdmi_i2c = client;
@@ -866,7 +867,6 @@ static int it6263_probe(struct i2c_client *client)
i2c_set_clientdata(client, it);
it->bridge.funcs = &it6263_bridge_funcs;
it->bridge.of_node = dev->of_node;
/* IT6263 chip doesn't support HPD interrupt. */
it->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID |

View File

@@ -3583,9 +3583,10 @@ static int it6505_i2c_probe(struct i2c_client *client)
struct extcon_dev *extcon;
int err;
it6505 = devm_kzalloc(&client->dev, sizeof(*it6505), GFP_KERNEL);
if (!it6505)
return -ENOMEM;
it6505 = devm_drm_bridge_alloc(&client->dev, struct it6505, bridge,
&it6505_bridge_funcs);
if (IS_ERR(it6505))
return PTR_ERR(it6505);
mutex_init(&it6505->extcon_lock);
mutex_init(&it6505->mode_lock);
@@ -3660,7 +3661,6 @@ static int it6505_i2c_probe(struct i2c_client *client)
it6505->aux.transfer = it6505_aux_transfer;
drm_dp_aux_init(&it6505->aux);
it6505->bridge.funcs = &it6505_bridge_funcs;
it6505->bridge.type = DRM_MODE_CONNECTOR_DisplayPort;
it6505->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID |
DRM_BRIDGE_OP_HPD;

View File

@@ -1516,9 +1516,10 @@ static int it66121_probe(struct i2c_client *client)
return -ENXIO;
}
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
ctx = devm_drm_bridge_alloc(dev, struct it66121_ctx, bridge,
&it66121_bridge_funcs);
if (IS_ERR(ctx))
return PTR_ERR(ctx);
ep = of_graph_get_endpoint_by_regs(dev->of_node, 0, 0);
if (!ep)
@@ -1577,7 +1578,6 @@ static int it66121_probe(struct i2c_client *client)
return -ENODEV;
}
ctx->bridge.funcs = &it66121_bridge_funcs;
ctx->bridge.of_node = dev->of_node;
ctx->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
ctx->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID;

View File

@@ -761,9 +761,10 @@ static int lt8912_probe(struct i2c_client *client)
int ret = 0;
struct device *dev = &client->dev;
lt = devm_kzalloc(dev, sizeof(struct lt8912), GFP_KERNEL);
if (!lt)
return -ENOMEM;
lt = devm_drm_bridge_alloc(dev, struct lt8912, bridge,
&lt8912_bridge_funcs);
if (IS_ERR(lt))
return PTR_ERR(lt);
lt->dev = dev;
lt->i2c_client[0] = client;
@@ -778,7 +779,6 @@ static int lt8912_probe(struct i2c_client *client)
i2c_set_clientdata(client, lt);
lt->bridge.funcs = &lt8912_bridge_funcs;
lt->bridge.of_node = dev->of_node;
lt->bridge.ops = (DRM_BRIDGE_OP_EDID |
DRM_BRIDGE_OP_DETECT);

View File

@@ -727,9 +727,9 @@ static int lt9211_probe(struct i2c_client *client)
struct lt9211 *ctx;
int ret;
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
ctx = devm_drm_bridge_alloc(dev, struct lt9211, bridge, &lt9211_funcs);
if (IS_ERR(ctx))
return PTR_ERR(ctx);
ctx->dev = dev;
@@ -755,7 +755,6 @@ static int lt9211_probe(struct i2c_client *client)
dev_set_drvdata(dev, ctx);
i2c_set_clientdata(client, ctx);
ctx->bridge.funcs = &lt9211_funcs;
ctx->bridge.of_node = dev->of_node;
drm_bridge_add(&ctx->bridge);

View File

@@ -1072,9 +1072,10 @@ static int lt9611_probe(struct i2c_client *client)
return -ENODEV;
}
lt9611 = devm_kzalloc(dev, sizeof(*lt9611), GFP_KERNEL);
if (!lt9611)
return -ENOMEM;
lt9611 = devm_drm_bridge_alloc(dev, struct lt9611, bridge,
&lt9611_bridge_funcs);
if (IS_ERR(lt9611))
return PTR_ERR(lt9611);
lt9611->dev = dev;
lt9611->client = client;
@@ -1127,7 +1128,6 @@ static int lt9611_probe(struct i2c_client *client)
/* Disable Audio InfoFrame, enabled by default */
regmap_update_bits(lt9611->regmap, 0x843d, LT9611_INFOFRAME_AUDIO, 0);
lt9611->bridge.funcs = &lt9611_bridge_funcs;
lt9611->bridge.of_node = client->dev.of_node;
lt9611->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID |
DRM_BRIDGE_OP_HPD | DRM_BRIDGE_OP_MODES |

View File

@@ -118,9 +118,10 @@ static int lvds_codec_probe(struct platform_device *pdev)
u32 val;
int ret;
lvds_codec = devm_kzalloc(dev, sizeof(*lvds_codec), GFP_KERNEL);
if (!lvds_codec)
return -ENOMEM;
lvds_codec = devm_drm_bridge_alloc(dev, struct lvds_codec, bridge,
&funcs);
if (IS_ERR(lvds_codec))
return PTR_ERR(lvds_codec);
lvds_codec->dev = &pdev->dev;
lvds_codec->connector_type = (uintptr_t)of_device_get_match_data(dev);
@@ -156,8 +157,6 @@ static int lvds_codec_probe(struct platform_device *pdev)
if (IS_ERR(lvds_codec->panel_bridge))
return PTR_ERR(lvds_codec->panel_bridge);
lvds_codec->bridge.funcs = &funcs;
/*
* Decoder input LVDS format is a property of the decoder chip or even
* its strapping. Handle data-mapping the same way lvds-panel does. In

View File

@@ -225,13 +225,11 @@ static int ge_b850v3_lvds_init(struct device *dev)
if (ge_b850v3_lvds_ptr)
goto success;
ge_b850v3_lvds_ptr = devm_kzalloc(dev,
sizeof(*ge_b850v3_lvds_ptr),
GFP_KERNEL);
if (!ge_b850v3_lvds_ptr) {
ge_b850v3_lvds_ptr = devm_drm_bridge_alloc(dev, struct ge_b850v3_lvds, bridge,
&ge_b850v3_lvds_funcs);
if (IS_ERR(ge_b850v3_lvds_ptr)) {
mutex_unlock(&ge_b850v3_lvds_dev_mutex);
return -ENOMEM;
return PTR_ERR(ge_b850v3_lvds_ptr);
}
success:
@@ -264,7 +262,6 @@ static int ge_b850v3_register(void)
struct device *dev = &stdp4028_i2c->dev;
/* drm bridge initialization */
ge_b850v3_lvds_ptr->bridge.funcs = &ge_b850v3_lvds_funcs;
ge_b850v3_lvds_ptr->bridge.ops = DRM_BRIDGE_OP_DETECT |
DRM_BRIDGE_OP_EDID;
ge_b850v3_lvds_ptr->bridge.type = DRM_MODE_CONNECTOR_DisplayPort;

View File

@@ -157,9 +157,10 @@ static int mchp_lvds_probe(struct platform_device *pdev)
if (!dev->of_node)
return -ENODEV;
lvds = devm_kzalloc(&pdev->dev, sizeof(*lvds), GFP_KERNEL);
if (!lvds)
return -ENOMEM;
lvds = devm_drm_bridge_alloc(&pdev->dev, struct mchp_lvds, bridge,
&mchp_lvds_bridge_funcs);
if (IS_ERR(lvds))
return PTR_ERR(lvds);
lvds->dev = dev;
@@ -192,7 +193,6 @@ static int mchp_lvds_probe(struct platform_device *pdev)
lvds->bridge.of_node = dev->of_node;
lvds->bridge.type = DRM_MODE_CONNECTOR_LVDS;
lvds->bridge.funcs = &mchp_lvds_bridge_funcs;
dev_set_drvdata(dev, lvds);
ret = devm_pm_runtime_enable(dev);

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