mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 03:15:31 +09:00
Merge 9f68e3655a ("Merge tag 'drm-next-2020-01-30' of git://anongit.freedesktop.org/drm/drm") into android-mainline
Huge DRM/dma-buf merge point. Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: I4cdf5053c210758aea54e28a0d15e9b32a2d906f
This commit is contained in:
@@ -189,7 +189,8 @@ Description:
|
||||
Access: Read
|
||||
Valid values: "Unknown", "Good", "Overheat", "Dead",
|
||||
"Over voltage", "Unspecified failure", "Cold",
|
||||
"Watchdog timer expire", "Safety timer expire"
|
||||
"Watchdog timer expire", "Safety timer expire",
|
||||
"Over current"
|
||||
|
||||
What: /sys/class/power_supply/<supply_name>/precharge_current
|
||||
Date: June 2017
|
||||
|
||||
@@ -0,0 +1,291 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/allwinner,sun4i-a10-display-backend.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Allwinner A10 Display Engine Backend Device Tree Bindings
|
||||
|
||||
maintainers:
|
||||
- Chen-Yu Tsai <wens@csie.org>
|
||||
- Maxime Ripard <mripard@kernel.org>
|
||||
|
||||
description: |
|
||||
The display engine backend exposes layers and sprites to the system.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- allwinner,sun4i-a10-display-backend
|
||||
- allwinner,sun5i-a13-display-backend
|
||||
- allwinner,sun6i-a31-display-backend
|
||||
- allwinner,sun7i-a20-display-backend
|
||||
- allwinner,sun8i-a23-display-backend
|
||||
- allwinner,sun8i-a33-display-backend
|
||||
- allwinner,sun9i-a80-display-backend
|
||||
|
||||
reg:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
items:
|
||||
- description: Display Backend registers
|
||||
- description: SAT registers
|
||||
|
||||
reg-names:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
items:
|
||||
- const: be
|
||||
- const: sat
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
minItems: 3
|
||||
maxItems: 4
|
||||
items:
|
||||
- description: The backend interface clock
|
||||
- description: The backend module clock
|
||||
- description: The backend DRAM clock
|
||||
- description: The SAT clock
|
||||
|
||||
clock-names:
|
||||
minItems: 3
|
||||
maxItems: 4
|
||||
items:
|
||||
- const: ahb
|
||||
- const: mod
|
||||
- const: ram
|
||||
- const: sat
|
||||
|
||||
resets:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
items:
|
||||
- description: The Backend reset line
|
||||
- description: The SAT reset line
|
||||
|
||||
reset-names:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
items:
|
||||
- const: be
|
||||
- const: sat
|
||||
|
||||
# FIXME: This should be made required eventually once every SoC will
|
||||
# have the MBUS declared.
|
||||
interconnects:
|
||||
maxItems: 1
|
||||
|
||||
# FIXME: This should be made required eventually once every SoC will
|
||||
# have the MBUS declared.
|
||||
interconnect-names:
|
||||
const: dma-mem
|
||||
|
||||
ports:
|
||||
type: object
|
||||
description: |
|
||||
A ports node with endpoint definitions as defined in
|
||||
Documentation/devicetree/bindings/media/video-interfaces.txt.
|
||||
|
||||
properties:
|
||||
"#address-cells":
|
||||
const: 1
|
||||
|
||||
"#size-cells":
|
||||
const: 0
|
||||
|
||||
port@0:
|
||||
type: object
|
||||
description: |
|
||||
Input endpoints of the controller.
|
||||
|
||||
port@1:
|
||||
type: object
|
||||
description: |
|
||||
Output endpoints of the controller.
|
||||
|
||||
required:
|
||||
- "#address-cells"
|
||||
- "#size-cells"
|
||||
- port@0
|
||||
- port@1
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- clock-names
|
||||
- resets
|
||||
- ports
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: allwinner,sun8i-a33-display-backend
|
||||
|
||||
then:
|
||||
properties:
|
||||
reg:
|
||||
minItems: 2
|
||||
|
||||
reg-names:
|
||||
minItems: 2
|
||||
|
||||
clocks:
|
||||
minItems: 4
|
||||
|
||||
clock-names:
|
||||
minItems: 4
|
||||
|
||||
resets:
|
||||
minItems: 2
|
||||
|
||||
reset-names:
|
||||
minItems: 2
|
||||
|
||||
required:
|
||||
- reg-names
|
||||
- reset-names
|
||||
|
||||
else:
|
||||
properties:
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
reg-names:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 3
|
||||
|
||||
clock-names:
|
||||
maxItems: 3
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
reset-names:
|
||||
maxItems: 1
|
||||
|
||||
examples:
|
||||
- |
|
||||
/*
|
||||
* This comes from the clock/sun4i-a10-ccu.h and
|
||||
* reset/sun4i-a10-ccu.h headers, but we can't include them since
|
||||
* it would trigger a bunch of warnings for redefinitions of
|
||||
* symbols with the other example.
|
||||
*/
|
||||
|
||||
#define CLK_AHB_DE_BE0 42
|
||||
#define CLK_DRAM_DE_BE0 140
|
||||
#define CLK_DE_BE0 144
|
||||
#define RST_DE_BE0 5
|
||||
|
||||
display-backend@1e60000 {
|
||||
compatible = "allwinner,sun4i-a10-display-backend";
|
||||
reg = <0x01e60000 0x10000>;
|
||||
interrupts = <47>;
|
||||
clocks = <&ccu CLK_AHB_DE_BE0>, <&ccu CLK_DE_BE0>,
|
||||
<&ccu CLK_DRAM_DE_BE0>;
|
||||
clock-names = "ahb", "mod",
|
||||
"ram";
|
||||
resets = <&ccu RST_DE_BE0>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0>;
|
||||
|
||||
endpoint@0 {
|
||||
reg = <0>;
|
||||
remote-endpoint = <&fe0_out_be0>;
|
||||
};
|
||||
|
||||
endpoint@1 {
|
||||
reg = <1>;
|
||||
remote-endpoint = <&fe1_out_be0>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <1>;
|
||||
|
||||
endpoint@0 {
|
||||
reg = <0>;
|
||||
remote-endpoint = <&tcon0_in_be0>;
|
||||
};
|
||||
|
||||
endpoint@1 {
|
||||
reg = <1>;
|
||||
remote-endpoint = <&tcon1_in_be0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
/*
|
||||
* This comes from the clock/sun8i-a23-a33-ccu.h and
|
||||
* reset/sun8i-a23-a33-ccu.h headers, but we can't include them
|
||||
* since it would trigger a bunch of warnings for redefinitions of
|
||||
* symbols with the other example.
|
||||
*/
|
||||
|
||||
#define CLK_BUS_DE_BE 40
|
||||
#define CLK_BUS_SAT 46
|
||||
#define CLK_DRAM_DE_BE 84
|
||||
#define CLK_DE_BE 85
|
||||
#define RST_BUS_DE_BE 21
|
||||
#define RST_BUS_SAT 27
|
||||
|
||||
display-backend@1e60000 {
|
||||
compatible = "allwinner,sun8i-a33-display-backend";
|
||||
reg = <0x01e60000 0x10000>, <0x01e80000 0x1000>;
|
||||
reg-names = "be", "sat";
|
||||
interrupts = <GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&ccu CLK_BUS_DE_BE>, <&ccu CLK_DE_BE>,
|
||||
<&ccu CLK_DRAM_DE_BE>, <&ccu CLK_BUS_SAT>;
|
||||
clock-names = "ahb", "mod",
|
||||
"ram", "sat";
|
||||
resets = <&ccu RST_BUS_DE_BE>, <&ccu RST_BUS_SAT>;
|
||||
reset-names = "be", "sat";
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
|
||||
endpoint {
|
||||
remote-endpoint = <&fe0_out_be0>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
|
||||
endpoint {
|
||||
remote-endpoint = <&drc0_in_be0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
@@ -0,0 +1,114 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/allwinner,sun4i-a10-display-engine.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Allwinner A10 Display Engine Pipeline Device Tree Bindings
|
||||
|
||||
maintainers:
|
||||
- Chen-Yu Tsai <wens@csie.org>
|
||||
- Maxime Ripard <mripard@kernel.org>
|
||||
|
||||
description: |
|
||||
The display engine pipeline (and its entry point, since it can be
|
||||
either directly the backend or the frontend) is represented as an
|
||||
extra node.
|
||||
|
||||
The Allwinner A10 Display pipeline is composed of several components
|
||||
that are going to be documented below:
|
||||
|
||||
For all connections between components up to the TCONs in the
|
||||
display pipeline, when there are multiple components of the same
|
||||
type at the same depth, the local endpoint ID must be the same as
|
||||
the remote component's index. For example, if the remote endpoint is
|
||||
Frontend 1, then the local endpoint ID must be 1.
|
||||
|
||||
Frontend 0 [0] ------- [0] Backend 0 [0] ------- [0] TCON 0
|
||||
[1] -- -- [1] [1] -- -- [1]
|
||||
\ / \ /
|
||||
X X
|
||||
/ \ / \
|
||||
[0] -- -- [0] [0] -- -- [0]
|
||||
Frontend 1 [1] ------- [1] Backend 1 [1] ------- [1] TCON 1
|
||||
|
||||
For a two pipeline system such as the one depicted above, the lines
|
||||
represent the connections between the components, while the numbers
|
||||
within the square brackets corresponds to the ID of the local endpoint.
|
||||
|
||||
The same rule also applies to DE 2.0 mixer-TCON connections:
|
||||
|
||||
Mixer 0 [0] ----------- [0] TCON 0
|
||||
[1] ---- ---- [1]
|
||||
\ /
|
||||
X
|
||||
/ \
|
||||
[0] ---- ---- [0]
|
||||
Mixer 1 [1] ----------- [1] TCON 1
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- allwinner,sun4i-a10-display-engine
|
||||
- allwinner,sun5i-a10s-display-engine
|
||||
- allwinner,sun5i-a13-display-engine
|
||||
- allwinner,sun6i-a31-display-engine
|
||||
- allwinner,sun6i-a31s-display-engine
|
||||
- allwinner,sun7i-a20-display-engine
|
||||
- allwinner,sun8i-a23-display-engine
|
||||
- allwinner,sun8i-a33-display-engine
|
||||
- allwinner,sun8i-a83t-display-engine
|
||||
- allwinner,sun8i-h3-display-engine
|
||||
- allwinner,sun8i-r40-display-engine
|
||||
- allwinner,sun8i-v3s-display-engine
|
||||
- allwinner,sun9i-a80-display-engine
|
||||
- allwinner,sun50i-a64-display-engine
|
||||
- allwinner,sun50i-h6-display-engine
|
||||
|
||||
allwinner,pipelines:
|
||||
allOf:
|
||||
- $ref: /schemas/types.yaml#/definitions/phandle-array
|
||||
- minItems: 1
|
||||
maxItems: 2
|
||||
description: |
|
||||
Available display engine frontends (DE 1.0) or mixers (DE
|
||||
2.0/3.0) available.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- allwinner,pipelines
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- allwinner,sun4i-a10-display-engine
|
||||
- allwinner,sun6i-a31-display-engine
|
||||
- allwinner,sun6i-a31s-display-engine
|
||||
- allwinner,sun7i-a20-display-engine
|
||||
- allwinner,sun8i-a83t-display-engine
|
||||
- allwinner,sun8i-r40-display-engine
|
||||
- allwinner,sun9i-a80-display-engine
|
||||
- allwinner,sun50i-a64-display-engine
|
||||
|
||||
then:
|
||||
properties:
|
||||
allwinner,pipelines:
|
||||
minItems: 2
|
||||
|
||||
else:
|
||||
properties:
|
||||
allwinner,pipelines:
|
||||
maxItems: 1
|
||||
|
||||
examples:
|
||||
- |
|
||||
de: display-engine {
|
||||
compatible = "allwinner,sun4i-a10-display-engine";
|
||||
allwinner,pipelines = <&fe0>, <&fe1>;
|
||||
};
|
||||
|
||||
...
|
||||
@@ -0,0 +1,138 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/allwinner,sun4i-a10-display-frontend.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Allwinner A10 Display Engine Frontend Device Tree Bindings
|
||||
|
||||
maintainers:
|
||||
- Chen-Yu Tsai <wens@csie.org>
|
||||
- Maxime Ripard <mripard@kernel.org>
|
||||
|
||||
description: |
|
||||
The display engine frontend does formats conversion, scaling,
|
||||
deinterlacing and color space conversion.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- allwinner,sun4i-a10-display-frontend
|
||||
- allwinner,sun5i-a13-display-frontend
|
||||
- allwinner,sun6i-a31-display-frontend
|
||||
- allwinner,sun7i-a20-display-frontend
|
||||
- allwinner,sun8i-a23-display-frontend
|
||||
- allwinner,sun8i-a33-display-frontend
|
||||
- allwinner,sun9i-a80-display-frontend
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: The frontend interface clock
|
||||
- description: The frontend module clock
|
||||
- description: The frontend DRAM clock
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: ahb
|
||||
- const: mod
|
||||
- const: ram
|
||||
|
||||
# FIXME: This should be made required eventually once every SoC will
|
||||
# have the MBUS declared.
|
||||
interconnects:
|
||||
maxItems: 1
|
||||
|
||||
# FIXME: This should be made required eventually once every SoC will
|
||||
# have the MBUS declared.
|
||||
interconnect-names:
|
||||
const: dma-mem
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
ports:
|
||||
type: object
|
||||
description: |
|
||||
A ports node with endpoint definitions as defined in
|
||||
Documentation/devicetree/bindings/media/video-interfaces.txt.
|
||||
|
||||
properties:
|
||||
"#address-cells":
|
||||
const: 1
|
||||
|
||||
"#size-cells":
|
||||
const: 0
|
||||
|
||||
port@0:
|
||||
type: object
|
||||
description: |
|
||||
Input endpoints of the controller.
|
||||
|
||||
port@1:
|
||||
type: object
|
||||
description: |
|
||||
Output endpoints of the controller.
|
||||
|
||||
required:
|
||||
- "#address-cells"
|
||||
- "#size-cells"
|
||||
- port@1
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- clock-names
|
||||
- resets
|
||||
- ports
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/sun4i-a10-ccu.h>
|
||||
#include <dt-bindings/reset/sun4i-a10-ccu.h>
|
||||
|
||||
fe0: display-frontend@1e00000 {
|
||||
compatible = "allwinner,sun4i-a10-display-frontend";
|
||||
reg = <0x01e00000 0x20000>;
|
||||
interrupts = <47>;
|
||||
clocks = <&ccu CLK_AHB_DE_FE0>, <&ccu CLK_DE_FE0>,
|
||||
<&ccu CLK_DRAM_DE_FE0>;
|
||||
clock-names = "ahb", "mod",
|
||||
"ram";
|
||||
resets = <&ccu RST_DE_FE0>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
fe0_out: port@1 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <1>;
|
||||
|
||||
fe0_out_be0: endpoint@0 {
|
||||
reg = <0>;
|
||||
remote-endpoint = <&be0_in_fe0>;
|
||||
};
|
||||
|
||||
fe0_out_be1: endpoint@1 {
|
||||
reg = <1>;
|
||||
remote-endpoint = <&be1_in_fe0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
...
|
||||
@@ -0,0 +1,183 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/allwinner,sun4i-a10-hdmi.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Allwinner A10 HDMI Controller Device Tree Bindings
|
||||
|
||||
description: |
|
||||
The HDMI Encoder supports the HDMI video and audio outputs, and does
|
||||
CEC. It is one end of the pipeline.
|
||||
|
||||
maintainers:
|
||||
- Chen-Yu Tsai <wens@csie.org>
|
||||
- Maxime Ripard <mripard@kernel.org>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- const: allwinner,sun4i-a10-hdmi
|
||||
- const: allwinner,sun5i-a10s-hdmi
|
||||
- const: allwinner,sun6i-a31-hdmi
|
||||
- items:
|
||||
- const: allwinner,sun7i-a20-hdmi
|
||||
- const: allwinner,sun5i-a10s-hdmi
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
oneOf:
|
||||
- items:
|
||||
- description: The HDMI interface clock
|
||||
- description: The HDMI module clock
|
||||
- description: The first video PLL
|
||||
- description: The second video PLL
|
||||
|
||||
- items:
|
||||
- description: The HDMI interface clock
|
||||
- description: The HDMI module clock
|
||||
- description: The HDMI DDC clock
|
||||
- description: The first video PLL
|
||||
- description: The second video PLL
|
||||
|
||||
clock-names:
|
||||
oneOf:
|
||||
- items:
|
||||
- const: ahb
|
||||
- const: mod
|
||||
- const: pll-0
|
||||
- const: pll-1
|
||||
|
||||
- items:
|
||||
- const: ahb
|
||||
- const: mod
|
||||
- const: ddc
|
||||
- const: pll-0
|
||||
- const: pll-1
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
dmas:
|
||||
items:
|
||||
- description: DDC Transmission DMA Channel
|
||||
- description: DDC Reception DMA Channel
|
||||
- description: Audio Transmission DMA Channel
|
||||
|
||||
dma-names:
|
||||
items:
|
||||
- const: ddc-tx
|
||||
- const: ddc-rx
|
||||
- const: audio-tx
|
||||
|
||||
ports:
|
||||
type: object
|
||||
description: |
|
||||
A ports node with endpoint definitions as defined in
|
||||
Documentation/devicetree/bindings/media/video-interfaces.txt.
|
||||
|
||||
properties:
|
||||
"#address-cells":
|
||||
const: 1
|
||||
|
||||
"#size-cells":
|
||||
const: 0
|
||||
|
||||
port@0:
|
||||
type: object
|
||||
description: |
|
||||
Input endpoints of the controller.
|
||||
|
||||
port@1:
|
||||
type: object
|
||||
description: |
|
||||
Output endpoints of the controller. Usually an HDMI
|
||||
connector.
|
||||
|
||||
required:
|
||||
- "#address-cells"
|
||||
- "#size-cells"
|
||||
- port@0
|
||||
- port@1
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- clock-names
|
||||
- dmas
|
||||
- dma-names
|
||||
|
||||
if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: allwinner,sun6i-a31-hdmi
|
||||
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 5
|
||||
|
||||
clock-names:
|
||||
minItems: 5
|
||||
|
||||
required:
|
||||
- resets
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/sun4i-a10-ccu.h>
|
||||
#include <dt-bindings/dma/sun4i-a10.h>
|
||||
#include <dt-bindings/reset/sun4i-a10-ccu.h>
|
||||
|
||||
hdmi: hdmi@1c16000 {
|
||||
compatible = "allwinner,sun4i-a10-hdmi";
|
||||
reg = <0x01c16000 0x1000>;
|
||||
interrupts = <58>;
|
||||
clocks = <&ccu CLK_AHB_HDMI0>, <&ccu CLK_HDMI>,
|
||||
<&ccu CLK_PLL_VIDEO0_2X>,
|
||||
<&ccu CLK_PLL_VIDEO1_2X>;
|
||||
clock-names = "ahb", "mod", "pll-0", "pll-1";
|
||||
dmas = <&dma SUN4I_DMA_NORMAL 16>,
|
||||
<&dma SUN4I_DMA_NORMAL 16>,
|
||||
<&dma SUN4I_DMA_DEDICATED 24>;
|
||||
dma-names = "ddc-tx", "ddc-rx", "audio-tx";
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
hdmi_in: port@0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0>;
|
||||
|
||||
hdmi_in_tcon0: endpoint@0 {
|
||||
reg = <0>;
|
||||
remote-endpoint = <&tcon0_out_hdmi>;
|
||||
};
|
||||
|
||||
hdmi_in_tcon1: endpoint@1 {
|
||||
reg = <1>;
|
||||
remote-endpoint = <&tcon1_out_hdmi>;
|
||||
};
|
||||
};
|
||||
|
||||
hdmi_out: port@1 {
|
||||
reg = <1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
@@ -0,0 +1,676 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/allwinner,sun4i-a10-tcon.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Allwinner A10 Timings Controller (TCON) Device Tree Bindings
|
||||
|
||||
maintainers:
|
||||
- Chen-Yu Tsai <wens@csie.org>
|
||||
- Maxime Ripard <mripard@kernel.org>
|
||||
|
||||
description: |
|
||||
The TCON acts as a timing controller for RGB, LVDS and TV
|
||||
interfaces.
|
||||
|
||||
properties:
|
||||
"#clock-cells":
|
||||
const: 0
|
||||
|
||||
compatible:
|
||||
oneOf:
|
||||
- const: allwinner,sun4i-a10-tcon
|
||||
- const: allwinner,sun5i-a13-tcon
|
||||
- const: allwinner,sun6i-a31-tcon
|
||||
- const: allwinner,sun6i-a31s-tcon
|
||||
- const: allwinner,sun7i-a20-tcon
|
||||
- const: allwinner,sun8i-a23-tcon
|
||||
- const: allwinner,sun8i-a33-tcon
|
||||
- const: allwinner,sun8i-a83t-tcon-lcd
|
||||
- const: allwinner,sun8i-a83t-tcon-tv
|
||||
- const: allwinner,sun8i-r40-tcon-tv
|
||||
- const: allwinner,sun8i-v3s-tcon
|
||||
- const: allwinner,sun9i-a80-tcon-lcd
|
||||
- const: allwinner,sun9i-a80-tcon-tv
|
||||
|
||||
- items:
|
||||
- enum:
|
||||
- allwinner,sun50i-a64-tcon-lcd
|
||||
- const: allwinner,sun8i-a83t-tcon-lcd
|
||||
|
||||
- items:
|
||||
- enum:
|
||||
- allwinner,sun8i-h3-tcon-tv
|
||||
- allwinner,sun50i-a64-tcon-tv
|
||||
- allwinner,sun50i-h6-tcon-tv
|
||||
- const: allwinner,sun8i-a83t-tcon-tv
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
minItems: 1
|
||||
maxItems: 4
|
||||
|
||||
clock-names:
|
||||
minItems: 1
|
||||
maxItems: 4
|
||||
|
||||
clock-output-names:
|
||||
allOf:
|
||||
- $ref: /schemas/types.yaml#/definitions/string-array
|
||||
- maxItems: 1
|
||||
description:
|
||||
Name of the LCD pixel clock created.
|
||||
|
||||
dmas:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
anyOf:
|
||||
- items:
|
||||
- description: TCON Reset Line
|
||||
|
||||
- items:
|
||||
- description: TCON Reset Line
|
||||
- description: TCON LVDS Reset Line
|
||||
|
||||
- items:
|
||||
- description: TCON Reset Line
|
||||
- description: TCON eDP Reset Line
|
||||
|
||||
- items:
|
||||
- description: TCON Reset Line
|
||||
- description: TCON eDP Reset Line
|
||||
- description: TCON LVDS Reset Line
|
||||
|
||||
reset-names:
|
||||
oneOf:
|
||||
- const: lcd
|
||||
|
||||
- items:
|
||||
- const: lcd
|
||||
- const: lvds
|
||||
|
||||
- items:
|
||||
- const: lcd
|
||||
- const: edp
|
||||
|
||||
- items:
|
||||
- const: lcd
|
||||
- const: edp
|
||||
- const: lvds
|
||||
|
||||
ports:
|
||||
type: object
|
||||
description: |
|
||||
A ports node with endpoint definitions as defined in
|
||||
Documentation/devicetree/bindings/media/video-interfaces.txt.
|
||||
|
||||
properties:
|
||||
"#address-cells":
|
||||
const: 1
|
||||
|
||||
"#size-cells":
|
||||
const: 0
|
||||
|
||||
port@0:
|
||||
type: object
|
||||
description: |
|
||||
Input endpoints of the controller.
|
||||
|
||||
port@1:
|
||||
type: object
|
||||
description: |
|
||||
Output endpoints of the controller.
|
||||
|
||||
patternProperties:
|
||||
"^endpoint(@[0-9])$":
|
||||
type: object
|
||||
|
||||
properties:
|
||||
allwinner,tcon-channel:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
TCON can have 1 or 2 channels, usually with the
|
||||
first channel being used for the panels interfaces
|
||||
(RGB, LVDS, etc.), and the second being used for the
|
||||
outputs that require another controller (TV Encoder,
|
||||
HDMI, etc.).
|
||||
|
||||
If that property is present, specifies the TCON
|
||||
channel the endpoint is associated to. If that
|
||||
property is not present, the endpoint number will be
|
||||
used as the channel number.
|
||||
|
||||
unevaluatedProperties: true
|
||||
|
||||
required:
|
||||
- "#address-cells"
|
||||
- "#size-cells"
|
||||
- port@0
|
||||
- port@1
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- clock-names
|
||||
- resets
|
||||
- ports
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- allwinner,sun4i-a10-tcon
|
||||
- allwinner,sun5i-a13-tcon
|
||||
- allwinner,sun7i-a20-tcon
|
||||
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 3
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: ahb
|
||||
- const: tcon-ch0
|
||||
- const: tcon-ch1
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- allwinner,sun6i-a31-tcon
|
||||
- allwinner,sun6i-a31s-tcon
|
||||
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 4
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: ahb
|
||||
- const: tcon-ch0
|
||||
- const: tcon-ch1
|
||||
- const: lvds-alt
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- allwinner,sun8i-a23-tcon
|
||||
- allwinner,sun8i-a33-tcon
|
||||
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 3
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: ahb
|
||||
- const: tcon-ch0
|
||||
- const: lvds-alt
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- allwinner,sun8i-a83t-tcon-lcd
|
||||
- allwinner,sun8i-v3s-tcon
|
||||
- allwinner,sun9i-a80-tcon-lcd
|
||||
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 2
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: ahb
|
||||
- const: tcon-ch0
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- allwinner,sun8i-a83t-tcon-tv
|
||||
- allwinner,sun8i-r40-tcon-tv
|
||||
- allwinner,sun9i-a80-tcon-tv
|
||||
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 2
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: ahb
|
||||
- const: tcon-ch1
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- allwinner,sun5i-a13-tcon
|
||||
- allwinner,sun6i-a31-tcon
|
||||
- allwinner,sun6i-a31s-tcon
|
||||
- allwinner,sun7i-a20-tcon
|
||||
- allwinner,sun8i-a23-tcon
|
||||
- allwinner,sun8i-a33-tcon
|
||||
- allwinner,sun8i-v3s-tcon
|
||||
- allwinner,sun9i-a80-tcon-lcd
|
||||
- allwinner,sun4i-a10-tcon
|
||||
- allwinner,sun8i-a83t-tcon-lcd
|
||||
|
||||
then:
|
||||
required:
|
||||
- "#clock-cells"
|
||||
- clock-output-names
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- allwinner,sun6i-a31-tcon
|
||||
- allwinner,sun6i-a31s-tcon
|
||||
- allwinner,sun8i-a23-tcon
|
||||
- allwinner,sun8i-a33-tcon
|
||||
- allwinner,sun8i-a83t-tcon-lcd
|
||||
|
||||
then:
|
||||
properties:
|
||||
resets:
|
||||
minItems: 2
|
||||
|
||||
reset-names:
|
||||
items:
|
||||
- const: lcd
|
||||
- const: lvds
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- allwinner,sun9i-a80-tcon-lcd
|
||||
|
||||
then:
|
||||
properties:
|
||||
resets:
|
||||
minItems: 3
|
||||
|
||||
reset-names:
|
||||
items:
|
||||
- const: lcd
|
||||
- const: edp
|
||||
- const: lvds
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- allwinner,sun9i-a80-tcon-tv
|
||||
|
||||
then:
|
||||
properties:
|
||||
resets:
|
||||
minItems: 2
|
||||
|
||||
reset-names:
|
||||
items:
|
||||
- const: lcd
|
||||
- const: edp
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- allwinner,sun4i-a10-tcon
|
||||
- allwinner,sun5i-a13-tcon
|
||||
- allwinner,sun6i-a31-tcon
|
||||
- allwinner,sun6i-a31s-tcon
|
||||
- allwinner,sun7i-a20-tcon
|
||||
- allwinner,sun8i-a23-tcon
|
||||
- allwinner,sun8i-a33-tcon
|
||||
|
||||
then:
|
||||
required:
|
||||
- dmas
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/dma/sun4i-a10.h>
|
||||
|
||||
/*
|
||||
* This comes from the clock/sun4i-a10-ccu.h and
|
||||
* reset/sun4i-a10-ccu.h headers, but we can't include them since
|
||||
* it would trigger a bunch of warnings for redefinitions of
|
||||
* symbols with the other example.
|
||||
*/
|
||||
|
||||
#define CLK_AHB_LCD0 56
|
||||
#define CLK_TCON0_CH0 149
|
||||
#define CLK_TCON0_CH1 155
|
||||
#define RST_TCON0 11
|
||||
|
||||
lcd-controller@1c0c000 {
|
||||
compatible = "allwinner,sun4i-a10-tcon";
|
||||
reg = <0x01c0c000 0x1000>;
|
||||
interrupts = <44>;
|
||||
resets = <&ccu RST_TCON0>;
|
||||
reset-names = "lcd";
|
||||
clocks = <&ccu CLK_AHB_LCD0>,
|
||||
<&ccu CLK_TCON0_CH0>,
|
||||
<&ccu CLK_TCON0_CH1>;
|
||||
clock-names = "ahb",
|
||||
"tcon-ch0",
|
||||
"tcon-ch1";
|
||||
clock-output-names = "tcon0-pixel-clock";
|
||||
#clock-cells = <0>;
|
||||
dmas = <&dma SUN4I_DMA_DEDICATED 14>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0>;
|
||||
|
||||
endpoint@0 {
|
||||
reg = <0>;
|
||||
remote-endpoint = <&be0_out_tcon0>;
|
||||
};
|
||||
|
||||
endpoint@1 {
|
||||
reg = <1>;
|
||||
remote-endpoint = <&be1_out_tcon0>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <1>;
|
||||
|
||||
endpoint@1 {
|
||||
reg = <1>;
|
||||
remote-endpoint = <&hdmi_in_tcon0>;
|
||||
allwinner,tcon-channel = <1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
#undef CLK_AHB_LCD0
|
||||
#undef CLK_TCON0_CH0
|
||||
#undef CLK_TCON0_CH1
|
||||
#undef RST_TCON0
|
||||
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
/*
|
||||
* This comes from the clock/sun6i-a31-ccu.h and
|
||||
* reset/sun6i-a31-ccu.h headers, but we can't include them since
|
||||
* it would trigger a bunch of warnings for redefinitions of
|
||||
* symbols with the other example.
|
||||
*/
|
||||
|
||||
#define CLK_PLL_MIPI 15
|
||||
#define CLK_AHB1_LCD0 47
|
||||
#define CLK_LCD0_CH0 127
|
||||
#define CLK_LCD0_CH1 129
|
||||
#define RST_AHB1_LCD0 27
|
||||
#define RST_AHB1_LVDS 41
|
||||
|
||||
lcd-controller@1c0c000 {
|
||||
compatible = "allwinner,sun6i-a31-tcon";
|
||||
reg = <0x01c0c000 0x1000>;
|
||||
interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&dma 11>;
|
||||
resets = <&ccu RST_AHB1_LCD0>, <&ccu RST_AHB1_LVDS>;
|
||||
reset-names = "lcd", "lvds";
|
||||
clocks = <&ccu CLK_AHB1_LCD0>,
|
||||
<&ccu CLK_LCD0_CH0>,
|
||||
<&ccu CLK_LCD0_CH1>,
|
||||
<&ccu CLK_PLL_MIPI>;
|
||||
clock-names = "ahb",
|
||||
"tcon-ch0",
|
||||
"tcon-ch1",
|
||||
"lvds-alt";
|
||||
clock-output-names = "tcon0-pixel-clock";
|
||||
#clock-cells = <0>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0>;
|
||||
|
||||
endpoint@0 {
|
||||
reg = <0>;
|
||||
remote-endpoint = <&drc0_out_tcon0>;
|
||||
};
|
||||
|
||||
endpoint@1 {
|
||||
reg = <1>;
|
||||
remote-endpoint = <&drc1_out_tcon0>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <1>;
|
||||
|
||||
endpoint@1 {
|
||||
reg = <1>;
|
||||
remote-endpoint = <&hdmi_in_tcon0>;
|
||||
allwinner,tcon-channel = <1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
#undef CLK_PLL_MIPI
|
||||
#undef CLK_AHB1_LCD0
|
||||
#undef CLK_LCD0_CH0
|
||||
#undef CLK_LCD0_CH1
|
||||
#undef RST_AHB1_LCD0
|
||||
#undef RST_AHB1_LVDS
|
||||
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
/*
|
||||
* This comes from the clock/sun9i-a80-ccu.h and
|
||||
* reset/sun9i-a80-ccu.h headers, but we can't include them since
|
||||
* it would trigger a bunch of warnings for redefinitions of
|
||||
* symbols with the other example.
|
||||
*/
|
||||
|
||||
#define CLK_BUS_LCD0 102
|
||||
#define CLK_LCD0 58
|
||||
#define RST_BUS_LCD0 22
|
||||
#define RST_BUS_EDP 24
|
||||
#define RST_BUS_LVDS 25
|
||||
|
||||
lcd-controller@3c00000 {
|
||||
compatible = "allwinner,sun9i-a80-tcon-lcd";
|
||||
reg = <0x03c00000 0x10000>;
|
||||
interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&ccu CLK_BUS_LCD0>, <&ccu CLK_LCD0>;
|
||||
clock-names = "ahb", "tcon-ch0";
|
||||
resets = <&ccu RST_BUS_LCD0>, <&ccu RST_BUS_EDP>, <&ccu RST_BUS_LVDS>;
|
||||
reset-names = "lcd", "edp", "lvds";
|
||||
clock-output-names = "tcon0-pixel-clock";
|
||||
#clock-cells = <0>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
|
||||
endpoint {
|
||||
remote-endpoint = <&drc0_out_tcon0>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
#undef CLK_BUS_TCON0
|
||||
#undef CLK_TCON0
|
||||
#undef RST_BUS_TCON0
|
||||
#undef RST_BUS_EDP
|
||||
#undef RST_BUS_LVDS
|
||||
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
/*
|
||||
* This comes from the clock/sun8i-a83t-ccu.h and
|
||||
* reset/sun8i-a83t-ccu.h headers, but we can't include them since
|
||||
* it would trigger a bunch of warnings for redefinitions of
|
||||
* symbols with the other example.
|
||||
*/
|
||||
|
||||
#define CLK_BUS_TCON0 36
|
||||
#define CLK_TCON0 85
|
||||
#define RST_BUS_TCON0 22
|
||||
#define RST_BUS_LVDS 31
|
||||
|
||||
lcd-controller@1c0c000 {
|
||||
compatible = "allwinner,sun8i-a83t-tcon-lcd";
|
||||
reg = <0x01c0c000 0x1000>;
|
||||
interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&ccu CLK_BUS_TCON0>, <&ccu CLK_TCON0>;
|
||||
clock-names = "ahb", "tcon-ch0";
|
||||
clock-output-names = "tcon-pixel-clock";
|
||||
#clock-cells = <0>;
|
||||
resets = <&ccu RST_BUS_TCON0>, <&ccu RST_BUS_LVDS>;
|
||||
reset-names = "lcd", "lvds";
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0>;
|
||||
|
||||
endpoint@0 {
|
||||
reg = <0>;
|
||||
remote-endpoint = <&mixer0_out_tcon0>;
|
||||
};
|
||||
|
||||
endpoint@1 {
|
||||
reg = <1>;
|
||||
remote-endpoint = <&mixer1_out_tcon0>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
#undef CLK_BUS_TCON0
|
||||
#undef CLK_TCON0
|
||||
#undef RST_BUS_TCON0
|
||||
#undef RST_BUS_LVDS
|
||||
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
/*
|
||||
* This comes from the clock/sun8i-r40-ccu.h and
|
||||
* reset/sun8i-r40-ccu.h headers, but we can't include them since
|
||||
* it would trigger a bunch of warnings for redefinitions of
|
||||
* symbols with the other example.
|
||||
*/
|
||||
|
||||
#define CLK_BUS_TCON_TV0 73
|
||||
#define RST_BUS_TCON_TV0 49
|
||||
|
||||
tcon_tv0: lcd-controller@1c73000 {
|
||||
compatible = "allwinner,sun8i-r40-tcon-tv";
|
||||
reg = <0x01c73000 0x1000>;
|
||||
interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&ccu CLK_BUS_TCON_TV0>, <&tcon_top 0>;
|
||||
clock-names = "ahb", "tcon-ch1";
|
||||
resets = <&ccu RST_BUS_TCON_TV0>;
|
||||
reset-names = "lcd";
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0>;
|
||||
|
||||
endpoint@0 {
|
||||
reg = <0>;
|
||||
remote-endpoint = <&tcon_top_mixer0_out_tcon_tv0>;
|
||||
};
|
||||
|
||||
endpoint@1 {
|
||||
reg = <1>;
|
||||
remote-endpoint = <&tcon_top_mixer1_out_tcon_tv0>;
|
||||
};
|
||||
};
|
||||
|
||||
tcon_tv0_out: port@1 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <1>;
|
||||
|
||||
endpoint@1 {
|
||||
reg = <1>;
|
||||
remote-endpoint = <&tcon_top_hdmi_in_tcon_tv0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
#undef CLK_BUS_TCON_TV0
|
||||
#undef RST_BUS_TCON_TV0
|
||||
|
||||
...
|
||||
@@ -0,0 +1,62 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/allwinner,sun4i-a10-tv-encoder.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Allwinner A10 TV Encoder Device Tree Bindings
|
||||
|
||||
maintainers:
|
||||
- Chen-Yu Tsai <wens@csie.org>
|
||||
- Maxime Ripard <mripard@kernel.org>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: allwinner,sun4i-a10-tv-encoder
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
port:
|
||||
type: object
|
||||
description:
|
||||
A port node with endpoint definitions as defined in
|
||||
Documentation/devicetree/bindings/media/video-interfaces.txt. The
|
||||
first port should be the input endpoint, usually coming from the
|
||||
associated TCON.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- resets
|
||||
- port
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
tve0: tv-encoder@1c0a000 {
|
||||
compatible = "allwinner,sun4i-a10-tv-encoder";
|
||||
reg = <0x01c0a000 0x1000>;
|
||||
clocks = <&ahb_gates 34>;
|
||||
resets = <&tcon_ch0_clk 0>;
|
||||
|
||||
port {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
tve0_in_tcon0: endpoint@0 {
|
||||
reg = <0>;
|
||||
remote-endpoint = <&tcon0_out_tve0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
@@ -0,0 +1,138 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/allwinner,sun6i-a31-drc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Allwinner A31 Dynamic Range Controller Device Tree Bindings
|
||||
|
||||
maintainers:
|
||||
- Chen-Yu Tsai <wens@csie.org>
|
||||
- Maxime Ripard <mripard@kernel.org>
|
||||
|
||||
description: |
|
||||
The DRC (Dynamic Range Controller) allows to dynamically adjust
|
||||
pixel brightness/contrast based on histogram measurements for LCD
|
||||
content adaptive backlight control.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- allwinner,sun6i-a31-drc
|
||||
- allwinner,sun6i-a31s-drc
|
||||
- allwinner,sun8i-a23-drc
|
||||
- allwinner,sun8i-a33-drc
|
||||
- allwinner,sun9i-a80-drc
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: The DRC interface clock
|
||||
- description: The DRC module clock
|
||||
- description: The DRC DRAM clock
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: ahb
|
||||
- const: mod
|
||||
- const: ram
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
ports:
|
||||
type: object
|
||||
description: |
|
||||
A ports node with endpoint definitions as defined in
|
||||
Documentation/devicetree/bindings/media/video-interfaces.txt.
|
||||
|
||||
properties:
|
||||
"#address-cells":
|
||||
const: 1
|
||||
|
||||
"#size-cells":
|
||||
const: 0
|
||||
|
||||
port@0:
|
||||
type: object
|
||||
description: |
|
||||
Input endpoints of the controller.
|
||||
|
||||
port@1:
|
||||
type: object
|
||||
description: |
|
||||
Output endpoints of the controller.
|
||||
|
||||
required:
|
||||
- "#address-cells"
|
||||
- "#size-cells"
|
||||
- port@0
|
||||
- port@1
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- clock-names
|
||||
- resets
|
||||
- ports
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
#include <dt-bindings/clock/sun6i-a31-ccu.h>
|
||||
#include <dt-bindings/reset/sun6i-a31-ccu.h>
|
||||
|
||||
drc0: drc@1e70000 {
|
||||
compatible = "allwinner,sun6i-a31-drc";
|
||||
reg = <0x01e70000 0x10000>;
|
||||
interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&ccu CLK_AHB1_DRC0>, <&ccu CLK_IEP_DRC0>,
|
||||
<&ccu CLK_DRAM_DRC0>;
|
||||
clock-names = "ahb", "mod",
|
||||
"ram";
|
||||
resets = <&ccu RST_AHB1_DRC0>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
drc0_in: port@0 {
|
||||
reg = <0>;
|
||||
|
||||
drc0_in_be0: endpoint {
|
||||
remote-endpoint = <&be0_out_drc0>;
|
||||
};
|
||||
};
|
||||
|
||||
drc0_out: port@1 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <1>;
|
||||
|
||||
drc0_out_tcon0: endpoint@0 {
|
||||
reg = <0>;
|
||||
remote-endpoint = <&tcon0_in_drc0>;
|
||||
};
|
||||
|
||||
drc0_out_tcon1: endpoint@1 {
|
||||
reg = <1>;
|
||||
remote-endpoint = <&tcon1_in_drc0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
...
|
||||
@@ -15,7 +15,9 @@ properties:
|
||||
"#size-cells": true
|
||||
|
||||
compatible:
|
||||
const: allwinner,sun6i-a31-mipi-dsi
|
||||
enum:
|
||||
- allwinner,sun6i-a31-mipi-dsi
|
||||
- allwinner,sun50i-a64-mipi-dsi
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
@@ -24,6 +26,8 @@ properties:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
items:
|
||||
- description: Bus Clock
|
||||
- description: Module Clock
|
||||
@@ -63,13 +67,38 @@ required:
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- clock-names
|
||||
- phys
|
||||
- phy-names
|
||||
- resets
|
||||
- vcc-dsi-supply
|
||||
- port
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: allwinner,sun6i-a31-mipi-dsi
|
||||
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 2
|
||||
|
||||
required:
|
||||
- clock-names
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: allwinner,sun50i-a64-mipi-dsi
|
||||
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 1
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/allwinner,sun8i-a83t-de2-mixer.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Allwinner Display Engine 2.0 Mixer Device Tree Bindings
|
||||
|
||||
maintainers:
|
||||
- Chen-Yu Tsai <wens@csie.org>
|
||||
- Maxime Ripard <mripard@kernel.org>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- allwinner,sun8i-a83t-de2-mixer-0
|
||||
- allwinner,sun8i-a83t-de2-mixer-1
|
||||
- allwinner,sun8i-h3-de2-mixer-0
|
||||
- allwinner,sun8i-r40-de2-mixer-0
|
||||
- allwinner,sun8i-r40-de2-mixer-1
|
||||
- allwinner,sun8i-v3s-de2-mixer
|
||||
- allwinner,sun50i-a64-de2-mixer-0
|
||||
- allwinner,sun50i-a64-de2-mixer-1
|
||||
- allwinner,sun50i-h6-de3-mixer-0
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: The mixer interface clock
|
||||
- description: The mixer module clock
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: bus
|
||||
- const: mod
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
ports:
|
||||
type: object
|
||||
description: |
|
||||
A ports node with endpoint definitions as defined in
|
||||
Documentation/devicetree/bindings/media/video-interfaces.txt.
|
||||
|
||||
properties:
|
||||
"#address-cells":
|
||||
const: 1
|
||||
|
||||
"#size-cells":
|
||||
const: 0
|
||||
|
||||
port@0:
|
||||
type: object
|
||||
description: |
|
||||
Input endpoints of the controller.
|
||||
|
||||
port@1:
|
||||
type: object
|
||||
description: |
|
||||
Output endpoints of the controller.
|
||||
|
||||
required:
|
||||
- "#address-cells"
|
||||
- "#size-cells"
|
||||
- port@1
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- resets
|
||||
- ports
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/sun8i-de2.h>
|
||||
#include <dt-bindings/reset/sun8i-de2.h>
|
||||
|
||||
mixer0: mixer@1100000 {
|
||||
compatible = "allwinner,sun8i-a83t-de2-mixer-0";
|
||||
reg = <0x01100000 0x100000>;
|
||||
clocks = <&display_clocks CLK_BUS_MIXER0>,
|
||||
<&display_clocks CLK_MIXER0>;
|
||||
clock-names = "bus",
|
||||
"mod";
|
||||
resets = <&display_clocks RST_MIXER0>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
mixer0_out: port@1 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <1>;
|
||||
|
||||
mixer0_out_tcon0: endpoint@0 {
|
||||
reg = <0>;
|
||||
remote-endpoint = <&tcon0_in_mixer0>;
|
||||
};
|
||||
|
||||
mixer0_out_tcon1: endpoint@1 {
|
||||
reg = <1>;
|
||||
remote-endpoint = <&tcon1_in_mixer0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
@@ -0,0 +1,273 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/allwinner,sun8i-a83t-dw-hdmi.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Allwinner A83t DWC HDMI TX Encoder Device Tree Bindings
|
||||
|
||||
description: |
|
||||
The HDMI transmitter is a Synopsys DesignWare HDMI 1.4 TX controller
|
||||
IP with Allwinner\'s own PHY IP. It supports audio and video outputs
|
||||
and CEC.
|
||||
|
||||
These DT bindings follow the Synopsys DWC HDMI TX bindings defined
|
||||
in Documentation/devicetree/bindings/display/bridge/dw_hdmi.txt with
|
||||
the following device-specific properties.
|
||||
|
||||
maintainers:
|
||||
- Chen-Yu Tsai <wens@csie.org>
|
||||
- Maxime Ripard <mripard@kernel.org>
|
||||
|
||||
properties:
|
||||
"#phy-cells":
|
||||
const: 0
|
||||
|
||||
compatible:
|
||||
oneOf:
|
||||
- const: allwinner,sun8i-a83t-dw-hdmi
|
||||
- const: allwinner,sun50i-h6-dw-hdmi
|
||||
|
||||
- items:
|
||||
- enum:
|
||||
- allwinner,sun8i-h3-dw-hdmi
|
||||
- allwinner,sun8i-r40-dw-hdmi
|
||||
- allwinner,sun50i-a64-dw-hdmi
|
||||
- const: allwinner,sun8i-a83t-dw-hdmi
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
reg-io-width:
|
||||
const: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
minItems: 3
|
||||
maxItems: 6
|
||||
items:
|
||||
- description: Bus Clock
|
||||
- description: Register Clock
|
||||
- description: TMDS Clock
|
||||
- description: HDMI CEC Clock
|
||||
- description: HDCP Clock
|
||||
- description: HDCP Bus Clock
|
||||
|
||||
clock-names:
|
||||
minItems: 3
|
||||
maxItems: 6
|
||||
items:
|
||||
- const: iahb
|
||||
- const: isfr
|
||||
- const: tmds
|
||||
- const: cec
|
||||
- const: hdcp
|
||||
- const: hdcp-bus
|
||||
|
||||
resets:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
items:
|
||||
- description: HDMI Controller Reset
|
||||
- description: HDCP Reset
|
||||
|
||||
reset-names:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
items:
|
||||
- const: ctrl
|
||||
- const: hdcp
|
||||
|
||||
phys:
|
||||
maxItems: 1
|
||||
description:
|
||||
Phandle to the DWC HDMI PHY.
|
||||
|
||||
phy-names:
|
||||
const: phy
|
||||
|
||||
hvcc-supply:
|
||||
description:
|
||||
The VCC power supply of the controller
|
||||
|
||||
ports:
|
||||
type: object
|
||||
description: |
|
||||
A ports node with endpoint definitions as defined in
|
||||
Documentation/devicetree/bindings/media/video-interfaces.txt.
|
||||
|
||||
properties:
|
||||
"#address-cells":
|
||||
const: 1
|
||||
|
||||
"#size-cells":
|
||||
const: 0
|
||||
|
||||
port@0:
|
||||
type: object
|
||||
description: |
|
||||
Input endpoints of the controller. Usually the associated
|
||||
TCON.
|
||||
|
||||
port@1:
|
||||
type: object
|
||||
description: |
|
||||
Output endpoints of the controller. Usually an HDMI
|
||||
connector.
|
||||
|
||||
required:
|
||||
- "#address-cells"
|
||||
- "#size-cells"
|
||||
- port@0
|
||||
- port@1
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- reg-io-width
|
||||
- interrupts
|
||||
- clocks
|
||||
- clock-names
|
||||
- resets
|
||||
- reset-names
|
||||
- phys
|
||||
- phy-names
|
||||
- ports
|
||||
|
||||
if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- allwinner,sun50i-h6-dw-hdmi
|
||||
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 6
|
||||
|
||||
clock-names:
|
||||
minItems: 6
|
||||
|
||||
resets:
|
||||
minItems: 2
|
||||
|
||||
reset-names:
|
||||
minItems: 2
|
||||
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
/*
|
||||
* This comes from the clock/sun8i-a83t-ccu.h and
|
||||
* reset/sun8i-a83t-ccu.h headers, but we can't include them since
|
||||
* it would trigger a bunch of warnings for redefinitions of
|
||||
* symbols with the other example.
|
||||
*/
|
||||
#define CLK_BUS_HDMI 39
|
||||
#define CLK_HDMI 93
|
||||
#define CLK_HDMI_SLOW 94
|
||||
#define RST_BUS_HDMI1 26
|
||||
|
||||
hdmi@1ee0000 {
|
||||
compatible = "allwinner,sun8i-a83t-dw-hdmi";
|
||||
reg = <0x01ee0000 0x10000>;
|
||||
reg-io-width = <1>;
|
||||
interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&ccu CLK_BUS_HDMI>, <&ccu CLK_HDMI_SLOW>,
|
||||
<&ccu CLK_HDMI>;
|
||||
clock-names = "iahb", "isfr", "tmds";
|
||||
resets = <&ccu RST_BUS_HDMI1>;
|
||||
reset-names = "ctrl";
|
||||
phys = <&hdmi_phy>;
|
||||
phy-names = "phy";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&hdmi_pins>;
|
||||
status = "disabled";
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
|
||||
endpoint {
|
||||
remote-endpoint = <&tcon1_out_hdmi>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
/* Cleanup after ourselves */
|
||||
#undef CLK_BUS_HDMI
|
||||
#undef CLK_HDMI
|
||||
#undef CLK_HDMI_SLOW
|
||||
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
/*
|
||||
* This comes from the clock/sun50i-h6-ccu.h and
|
||||
* reset/sun50i-h6-ccu.h headers, but we can't include them since
|
||||
* it would trigger a bunch of warnings for redefinitions of
|
||||
* symbols with the other example.
|
||||
*/
|
||||
#define CLK_BUS_HDMI 126
|
||||
#define CLK_BUS_HDCP 137
|
||||
#define CLK_HDMI 123
|
||||
#define CLK_HDMI_SLOW 124
|
||||
#define CLK_HDMI_CEC 125
|
||||
#define CLK_HDCP 136
|
||||
#define RST_BUS_HDMI_SUB 57
|
||||
#define RST_BUS_HDCP 62
|
||||
|
||||
hdmi@6000000 {
|
||||
compatible = "allwinner,sun50i-h6-dw-hdmi";
|
||||
reg = <0x06000000 0x10000>;
|
||||
reg-io-width = <1>;
|
||||
interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&ccu CLK_BUS_HDMI>, <&ccu CLK_HDMI_SLOW>,
|
||||
<&ccu CLK_HDMI>, <&ccu CLK_HDMI_CEC>,
|
||||
<&ccu CLK_HDCP>, <&ccu CLK_BUS_HDCP>;
|
||||
clock-names = "iahb", "isfr", "tmds", "cec", "hdcp",
|
||||
"hdcp-bus";
|
||||
resets = <&ccu RST_BUS_HDMI_SUB>, <&ccu RST_BUS_HDCP>;
|
||||
reset-names = "ctrl", "hdcp";
|
||||
phys = <&hdmi_phy>;
|
||||
phy-names = "phy";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&hdmi_pins>;
|
||||
status = "disabled";
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
|
||||
endpoint {
|
||||
remote-endpoint = <&tcon_top_hdmi_out_hdmi>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
@@ -0,0 +1,117 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/allwinner,sun8i-a83t-hdmi-phy.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Allwinner A83t HDMI PHY Device Tree Bindings
|
||||
|
||||
maintainers:
|
||||
- Chen-Yu Tsai <wens@csie.org>
|
||||
- Maxime Ripard <mripard@kernel.org>
|
||||
|
||||
properties:
|
||||
"#phy-cells":
|
||||
const: 0
|
||||
|
||||
compatible:
|
||||
enum:
|
||||
- allwinner,sun8i-a83t-hdmi-phy
|
||||
- allwinner,sun8i-h3-hdmi-phy
|
||||
- allwinner,sun8i-r40-hdmi-phy
|
||||
- allwinner,sun50i-a64-hdmi-phy
|
||||
- allwinner,sun50i-h6-hdmi-phy
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 4
|
||||
items:
|
||||
- description: Bus Clock
|
||||
- description: Module Clock
|
||||
- description: Parent of the PHY clock
|
||||
- description: Second possible parent of the PHY clock
|
||||
|
||||
clock-names:
|
||||
minItems: 2
|
||||
maxItems: 4
|
||||
items:
|
||||
- const: bus
|
||||
- const: mod
|
||||
- const: pll-0
|
||||
- const: pll-1
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
reset-names:
|
||||
const: phy
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- resets
|
||||
- reset-names
|
||||
|
||||
if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- allwinner,sun8i-r40-hdmi-phy
|
||||
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 4
|
||||
|
||||
clock-names:
|
||||
minItems: 4
|
||||
|
||||
else:
|
||||
if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- allwinner,sun8i-h3-hdmi-phy
|
||||
- allwinner,sun50i-a64-hdmi-phy
|
||||
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 3
|
||||
|
||||
clock-names:
|
||||
minItems: 3
|
||||
|
||||
else:
|
||||
properties:
|
||||
clocks:
|
||||
maxItems: 2
|
||||
|
||||
clock-names:
|
||||
maxItems: 2
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/sun8i-a83t-ccu.h>
|
||||
#include <dt-bindings/reset/sun8i-a83t-ccu.h>
|
||||
|
||||
hdmi_phy: hdmi-phy@1ef0000 {
|
||||
compatible = "allwinner,sun8i-a83t-hdmi-phy";
|
||||
reg = <0x01ef0000 0x10000>;
|
||||
clocks = <&ccu CLK_BUS_HDMI>, <&ccu CLK_HDMI_SLOW>;
|
||||
clock-names = "bus", "mod";
|
||||
resets = <&ccu RST_BUS_HDMI0>;
|
||||
reset-names = "phy";
|
||||
#phy-cells = <0>;
|
||||
};
|
||||
|
||||
...
|
||||
@@ -0,0 +1,382 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/allwinner,sun8i-r40-tcon-top.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Allwinner R40 TCON TOP Device Tree Bindings
|
||||
|
||||
maintainers:
|
||||
- Chen-Yu Tsai <wens@csie.org>
|
||||
- Maxime Ripard <mripard@kernel.org>
|
||||
|
||||
description: |
|
||||
TCON TOPs main purpose is to configure whole display pipeline. It
|
||||
determines relationships between mixers and TCONs, selects source
|
||||
TCON for HDMI, muxes LCD and TV encoder GPIO output, selects TV
|
||||
encoder clock source and contains additional TV TCON and DSI gates.
|
||||
|
||||
It allows display pipeline to be configured in very different ways:
|
||||
|
||||
/ LCD0/LVDS0
|
||||
/ [0] TCON-LCD0
|
||||
| \ MIPI DSI
|
||||
mixer0 |
|
||||
\ / [1] TCON-LCD1 - LCD1/LVDS1
|
||||
TCON-TOP
|
||||
/ \ [2] TCON-TV0 [0] - TVE0/RGB
|
||||
mixer1 | \
|
||||
| TCON-TOP - HDMI
|
||||
| /
|
||||
\ [3] TCON-TV1 [1] - TVE1/RGB
|
||||
|
||||
Note that both TCON TOP references same physical unit. Both mixers
|
||||
can be connected to any TCON. Not all TCON TOP variants support all
|
||||
features.
|
||||
|
||||
properties:
|
||||
"#clock-cells":
|
||||
const: 1
|
||||
|
||||
compatible:
|
||||
enum:
|
||||
- allwinner,sun8i-r40-tcon-top
|
||||
- allwinner,sun50i-h6-tcon-top
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 6
|
||||
items:
|
||||
- description: The TCON TOP interface clock
|
||||
- description: The TCON TOP TV0 clock
|
||||
- description: The TCON TOP TVE0 clock
|
||||
- description: The TCON TOP TV1 clock
|
||||
- description: The TCON TOP TVE1 clock
|
||||
- description: The TCON TOP MIPI DSI clock
|
||||
|
||||
clock-names:
|
||||
minItems: 2
|
||||
maxItems: 6
|
||||
items:
|
||||
- const: bus
|
||||
- const: tcon-tv0
|
||||
- const: tve0
|
||||
- const: tcon-tv1
|
||||
- const: tve1
|
||||
- const: dsi
|
||||
|
||||
clock-output-names:
|
||||
minItems: 1
|
||||
maxItems: 3
|
||||
description: >
|
||||
The first item is the name of the clock created for the TV0
|
||||
channel, the second item is the name of the TCON TV1 channel
|
||||
clock and the third one is the name of the DSI channel clock.
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
ports:
|
||||
type: object
|
||||
description: |
|
||||
A ports node with endpoint definitions as defined in
|
||||
Documentation/devicetree/bindings/media/video-interfaces.txt.
|
||||
All ports should have only one endpoint connected to
|
||||
remote endpoint.
|
||||
|
||||
properties:
|
||||
"#address-cells":
|
||||
const: 1
|
||||
|
||||
"#size-cells":
|
||||
const: 0
|
||||
|
||||
port@0:
|
||||
type: object
|
||||
description: |
|
||||
Input endpoint for Mixer 0 mux.
|
||||
|
||||
port@1:
|
||||
type: object
|
||||
description: |
|
||||
Output endpoint for Mixer 0 mux
|
||||
|
||||
properties:
|
||||
"#address-cells":
|
||||
const: 1
|
||||
|
||||
"#size-cells":
|
||||
const: 0
|
||||
|
||||
reg: true
|
||||
|
||||
patternProperties:
|
||||
"^endpoint@[0-9]$":
|
||||
type: object
|
||||
|
||||
properties:
|
||||
reg:
|
||||
description: |
|
||||
ID of the target TCON
|
||||
|
||||
required:
|
||||
- reg
|
||||
|
||||
required:
|
||||
- "#address-cells"
|
||||
- "#size-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
port@2:
|
||||
type: object
|
||||
description: |
|
||||
Input endpoint for Mixer 1 mux.
|
||||
|
||||
port@3:
|
||||
type: object
|
||||
description: |
|
||||
Output endpoint for Mixer 1 mux
|
||||
|
||||
properties:
|
||||
"#address-cells":
|
||||
const: 1
|
||||
|
||||
"#size-cells":
|
||||
const: 0
|
||||
|
||||
reg: true
|
||||
|
||||
patternProperties:
|
||||
"^endpoint@[0-9]$":
|
||||
type: object
|
||||
|
||||
properties:
|
||||
reg:
|
||||
description: |
|
||||
ID of the target TCON
|
||||
|
||||
required:
|
||||
- reg
|
||||
|
||||
required:
|
||||
- "#address-cells"
|
||||
- "#size-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
port@4:
|
||||
type: object
|
||||
description: |
|
||||
Input endpoint for HDMI mux.
|
||||
|
||||
properties:
|
||||
"#address-cells":
|
||||
const: 1
|
||||
|
||||
"#size-cells":
|
||||
const: 0
|
||||
|
||||
reg: true
|
||||
|
||||
patternProperties:
|
||||
"^endpoint@[0-9]$":
|
||||
type: object
|
||||
|
||||
properties:
|
||||
reg:
|
||||
description: |
|
||||
ID of the target TCON
|
||||
|
||||
required:
|
||||
- reg
|
||||
|
||||
required:
|
||||
- "#address-cells"
|
||||
- "#size-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
port@5:
|
||||
type: object
|
||||
description: |
|
||||
Output endpoint for HDMI mux
|
||||
|
||||
required:
|
||||
- "#address-cells"
|
||||
- "#size-cells"
|
||||
- port@0
|
||||
- port@1
|
||||
- port@4
|
||||
- port@5
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- "#clock-cells"
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- clock-output-names
|
||||
- resets
|
||||
- ports
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: allwinner,sun50i-h6-tcon-top
|
||||
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
maxItems: 2
|
||||
|
||||
clock-output-names:
|
||||
maxItems: 1
|
||||
|
||||
else:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 6
|
||||
|
||||
clock-output-names:
|
||||
minItems: 3
|
||||
|
||||
ports:
|
||||
required:
|
||||
- port@2
|
||||
- port@3
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
#include <dt-bindings/clock/sun8i-r40-ccu.h>
|
||||
#include <dt-bindings/reset/sun8i-r40-ccu.h>
|
||||
|
||||
tcon_top: tcon-top@1c70000 {
|
||||
compatible = "allwinner,sun8i-r40-tcon-top";
|
||||
reg = <0x01c70000 0x1000>;
|
||||
clocks = <&ccu CLK_BUS_TCON_TOP>,
|
||||
<&ccu CLK_TCON_TV0>,
|
||||
<&ccu CLK_TVE0>,
|
||||
<&ccu CLK_TCON_TV1>,
|
||||
<&ccu CLK_TVE1>,
|
||||
<&ccu CLK_DSI_DPHY>;
|
||||
clock-names = "bus",
|
||||
"tcon-tv0",
|
||||
"tve0",
|
||||
"tcon-tv1",
|
||||
"tve1",
|
||||
"dsi";
|
||||
clock-output-names = "tcon-top-tv0",
|
||||
"tcon-top-tv1",
|
||||
"tcon-top-dsi";
|
||||
resets = <&ccu RST_BUS_TCON_TOP>;
|
||||
#clock-cells = <1>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
tcon_top_mixer0_in: port@0 {
|
||||
reg = <0>;
|
||||
|
||||
tcon_top_mixer0_in_mixer0: endpoint {
|
||||
remote-endpoint = <&mixer0_out_tcon_top>;
|
||||
};
|
||||
};
|
||||
|
||||
tcon_top_mixer0_out: port@1 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <1>;
|
||||
|
||||
tcon_top_mixer0_out_tcon_lcd0: endpoint@0 {
|
||||
reg = <0>;
|
||||
};
|
||||
|
||||
tcon_top_mixer0_out_tcon_lcd1: endpoint@1 {
|
||||
reg = <1>;
|
||||
};
|
||||
|
||||
tcon_top_mixer0_out_tcon_tv0: endpoint@2 {
|
||||
reg = <2>;
|
||||
remote-endpoint = <&tcon_tv0_in_tcon_top_mixer0>;
|
||||
};
|
||||
|
||||
tcon_top_mixer0_out_tcon_tv1: endpoint@3 {
|
||||
reg = <3>;
|
||||
remote-endpoint = <&tcon_tv1_in_tcon_top_mixer0>;
|
||||
};
|
||||
};
|
||||
|
||||
tcon_top_mixer1_in: port@2 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <2>;
|
||||
|
||||
tcon_top_mixer1_in_mixer1: endpoint@1 {
|
||||
reg = <1>;
|
||||
remote-endpoint = <&mixer1_out_tcon_top>;
|
||||
};
|
||||
};
|
||||
|
||||
tcon_top_mixer1_out: port@3 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <3>;
|
||||
|
||||
tcon_top_mixer1_out_tcon_lcd0: endpoint@0 {
|
||||
reg = <0>;
|
||||
};
|
||||
|
||||
tcon_top_mixer1_out_tcon_lcd1: endpoint@1 {
|
||||
reg = <1>;
|
||||
};
|
||||
|
||||
tcon_top_mixer1_out_tcon_tv0: endpoint@2 {
|
||||
reg = <2>;
|
||||
remote-endpoint = <&tcon_tv0_in_tcon_top_mixer1>;
|
||||
};
|
||||
|
||||
tcon_top_mixer1_out_tcon_tv1: endpoint@3 {
|
||||
reg = <3>;
|
||||
remote-endpoint = <&tcon_tv1_in_tcon_top_mixer1>;
|
||||
};
|
||||
};
|
||||
|
||||
tcon_top_hdmi_in: port@4 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <4>;
|
||||
|
||||
tcon_top_hdmi_in_tcon_tv0: endpoint@0 {
|
||||
reg = <0>;
|
||||
remote-endpoint = <&tcon_tv0_out_tcon_top>;
|
||||
};
|
||||
|
||||
tcon_top_hdmi_in_tcon_tv1: endpoint@1 {
|
||||
reg = <1>;
|
||||
remote-endpoint = <&tcon_tv1_out_tcon_top>;
|
||||
};
|
||||
};
|
||||
|
||||
tcon_top_hdmi_out: port@5 {
|
||||
reg = <5>;
|
||||
|
||||
tcon_top_hdmi_out_hdmi: endpoint {
|
||||
remote-endpoint = <&hdmi_in_tcon_top>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
@@ -0,0 +1,133 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/allwinner,sun9i-a80-deu.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Allwinner A80 Detail Enhancement Unit Device Tree Bindings
|
||||
|
||||
maintainers:
|
||||
- Chen-Yu Tsai <wens@csie.org>
|
||||
- Maxime Ripard <mripard@kernel.org>
|
||||
|
||||
description: |
|
||||
The DEU (Detail Enhancement Unit), found in the Allwinner A80 SoC,
|
||||
can sharpen the display content in both luma and chroma channels.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: allwinner,sun9i-a80-deu
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: The DEU interface clock
|
||||
- description: The DEU module clock
|
||||
- description: The DEU DRAM clock
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: ahb
|
||||
- const: mod
|
||||
- const: ram
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
ports:
|
||||
type: object
|
||||
description: |
|
||||
A ports node with endpoint definitions as defined in
|
||||
Documentation/devicetree/bindings/media/video-interfaces.txt.
|
||||
|
||||
properties:
|
||||
"#address-cells":
|
||||
const: 1
|
||||
|
||||
"#size-cells":
|
||||
const: 0
|
||||
|
||||
port@0:
|
||||
type: object
|
||||
description: |
|
||||
Input endpoints of the controller.
|
||||
|
||||
port@1:
|
||||
type: object
|
||||
description: |
|
||||
Output endpoints of the controller.
|
||||
|
||||
required:
|
||||
- "#address-cells"
|
||||
- "#size-cells"
|
||||
- port@0
|
||||
- port@1
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- clock-names
|
||||
- resets
|
||||
- ports
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
#include <dt-bindings/clock/sun9i-a80-de.h>
|
||||
#include <dt-bindings/reset/sun9i-a80-de.h>
|
||||
|
||||
deu0: deu@3300000 {
|
||||
compatible = "allwinner,sun9i-a80-deu";
|
||||
reg = <0x03300000 0x40000>;
|
||||
interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&de_clocks CLK_BUS_DEU0>,
|
||||
<&de_clocks CLK_IEP_DEU0>,
|
||||
<&de_clocks CLK_DRAM_DEU0>;
|
||||
clock-names = "ahb",
|
||||
"mod",
|
||||
"ram";
|
||||
resets = <&de_clocks RST_DEU0>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
deu0_in: port@0 {
|
||||
reg = <0>;
|
||||
|
||||
deu0_in_fe0: endpoint {
|
||||
remote-endpoint = <&fe0_out_deu0>;
|
||||
};
|
||||
};
|
||||
|
||||
deu0_out: port@1 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <1>;
|
||||
|
||||
deu0_out_be0: endpoint@0 {
|
||||
reg = <0>;
|
||||
remote-endpoint = <&be0_in_deu0>;
|
||||
};
|
||||
|
||||
deu0_out_be1: endpoint@1 {
|
||||
reg = <1>;
|
||||
remote-endpoint = <&be1_in_deu0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
131
Documentation/devicetree/bindings/display/bridge/lvds-codec.yaml
Normal file
131
Documentation/devicetree/bindings/display/bridge/lvds-codec.yaml
Normal file
@@ -0,0 +1,131 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/bridge/lvds-codec.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Transparent LVDS encoders and decoders
|
||||
|
||||
maintainers:
|
||||
- Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
|
||||
|
||||
description: |
|
||||
This binding supports transparent LVDS encoders and decoders that don't
|
||||
require any configuration.
|
||||
|
||||
LVDS is a physical layer specification defined in ANSI/TIA/EIA-644-A. Multiple
|
||||
incompatible data link layers have been used over time to transmit image data
|
||||
to LVDS panels. This binding targets devices compatible with the following
|
||||
specifications only.
|
||||
|
||||
[JEIDA] "Digital Interface Standards for Monitor", JEIDA-59-1999, February
|
||||
1999 (Version 1.0), Japan Electronic Industry Development Association (JEIDA)
|
||||
[LDI] "Open LVDS Display Interface", May 1999 (Version 0.95), National
|
||||
Semiconductor
|
||||
[VESA] "VESA Notebook Panel Standard", October 2007 (Version 1.0), Video
|
||||
Electronics Standards Association (VESA)
|
||||
|
||||
Those devices have been marketed under the FPD-Link and FlatLink brand names
|
||||
among others.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- items:
|
||||
- enum:
|
||||
- ti,ds90c185 # For the TI DS90C185 FPD-Link Serializer
|
||||
- ti,ds90c187 # For the TI DS90C187 FPD-Link Serializer
|
||||
- ti,sn75lvds83 # For the TI SN75LVDS83 FlatLink transmitter
|
||||
- const: lvds-encoder # Generic LVDS encoder compatible fallback
|
||||
- items:
|
||||
- enum:
|
||||
- ti,ds90cf384a # For the DS90CF384A FPD-Link LVDS Receiver
|
||||
- const: lvds-decoder # Generic LVDS decoders compatible fallback
|
||||
- enum:
|
||||
- thine,thc63lvdm83d # For the THC63LVDM83D LVDS serializer
|
||||
|
||||
ports:
|
||||
type: object
|
||||
description: |
|
||||
This device has two video ports. Their connections are modeled using the
|
||||
OF graph bindings specified in Documentation/devicetree/bindings/graph.txt
|
||||
properties:
|
||||
port@0:
|
||||
type: object
|
||||
description: |
|
||||
For LVDS encoders, port 0 is the parallel input
|
||||
For LVDS decoders, port 0 is the LVDS input
|
||||
|
||||
port@1:
|
||||
type: object
|
||||
description: |
|
||||
For LVDS encoders, port 1 is the LVDS output
|
||||
For LVDS decoders, port 1 is the parallel output
|
||||
|
||||
required:
|
||||
- port@0
|
||||
- port@1
|
||||
|
||||
powerdown-gpios:
|
||||
description:
|
||||
The GPIO used to control the power down line of this device.
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- ports
|
||||
|
||||
examples:
|
||||
- |
|
||||
lvds-encoder {
|
||||
compatible = "ti,ds90c185", "lvds-encoder";
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
|
||||
lvds_enc_in: endpoint {
|
||||
remote-endpoint = <&display_out_rgb>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
|
||||
lvds_enc_out: endpoint {
|
||||
remote-endpoint = <&lvds_panel_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
- |
|
||||
lvds-decoder {
|
||||
compatible = "ti,ds90cf384a", "lvds-decoder";
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
|
||||
lvds_dec_in: endpoint {
|
||||
remote-endpoint = <&display_out_lvds>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
|
||||
lvds_dec_out: endpoint {
|
||||
remote-endpoint = <&rgb_panel_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
@@ -1,66 +0,0 @@
|
||||
Parallel to LVDS Encoder
|
||||
------------------------
|
||||
|
||||
This binding supports the parallel to LVDS encoders that don't require any
|
||||
configuration.
|
||||
|
||||
LVDS is a physical layer specification defined in ANSI/TIA/EIA-644-A. Multiple
|
||||
incompatible data link layers have been used over time to transmit image data
|
||||
to LVDS panels. This binding targets devices compatible with the following
|
||||
specifications only.
|
||||
|
||||
[JEIDA] "Digital Interface Standards for Monitor", JEIDA-59-1999, February
|
||||
1999 (Version 1.0), Japan Electronic Industry Development Association (JEIDA)
|
||||
[LDI] "Open LVDS Display Interface", May 1999 (Version 0.95), National
|
||||
Semiconductor
|
||||
[VESA] "VESA Notebook Panel Standard", October 2007 (Version 1.0), Video
|
||||
Electronics Standards Association (VESA)
|
||||
|
||||
Those devices have been marketed under the FPD-Link and FlatLink brand names
|
||||
among others.
|
||||
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: Must be "lvds-encoder"
|
||||
|
||||
Any encoder compatible with this generic binding, but with additional
|
||||
properties not listed here, must list a device specific compatible first
|
||||
followed by this generic compatible.
|
||||
|
||||
Required nodes:
|
||||
|
||||
This device has two video ports. Their connections are modeled using the OF
|
||||
graph bindings specified in Documentation/devicetree/bindings/graph.txt.
|
||||
|
||||
- Video port 0 for parallel input
|
||||
- Video port 1 for LVDS output
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
lvds-encoder {
|
||||
compatible = "lvds-encoder";
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
|
||||
lvds_enc_in: endpoint {
|
||||
remote-endpoint = <&display_out_rgb>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
|
||||
lvds_enc_out: endpoint {
|
||||
remote-endpoint = <&lvds_panel_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -1,50 +0,0 @@
|
||||
THine Electronics THC63LVDM83D LVDS serializer
|
||||
----------------------------------------------
|
||||
|
||||
The THC63LVDM83D is an LVDS serializer designed to support pixel data
|
||||
transmission between a host and a flat panel.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: Should be "thine,thc63lvdm83d"
|
||||
|
||||
Optional properties:
|
||||
|
||||
- powerdown-gpios: Power down control GPIO (the /PWDN pin, active low).
|
||||
|
||||
Required nodes:
|
||||
|
||||
The THC63LVDM83D has two video ports. Their connections are modeled using the
|
||||
OFgraph bindings specified in Documentation/devicetree/bindings/graph.txt.
|
||||
|
||||
- Video port 0 for CMOS/TTL input
|
||||
- Video port 1 for LVDS output
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
lvds_enc: encoder@0 {
|
||||
compatible = "thine,thc63lvdm83d";
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
|
||||
lvds_enc_in: endpoint@0 {
|
||||
remote-endpoint = <&rgb_out>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
|
||||
lvds_enc_out: endpoint@0 {
|
||||
remote-endpoint = <&panel_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -1,55 +0,0 @@
|
||||
Texas Instruments FPD-Link (LVDS) Serializer
|
||||
--------------------------------------------
|
||||
|
||||
The DS90C185 and DS90C187 are low-power serializers for portable
|
||||
battery-powered applications that reduces the size of the RGB
|
||||
interface between the host GPU and the display.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: Should be
|
||||
"ti,ds90c185", "lvds-encoder" for the TI DS90C185 FPD-Link Serializer
|
||||
"ti,ds90c187", "lvds-encoder" for the TI DS90C187 FPD-Link Serializer
|
||||
|
||||
Optional properties:
|
||||
|
||||
- powerdown-gpios: Power down control GPIO (the PDB pin, active-low)
|
||||
|
||||
Required nodes:
|
||||
|
||||
The devices have two video ports. Their connections are modeled using the OF
|
||||
graph bindings specified in Documentation/devicetree/bindings/graph.txt.
|
||||
|
||||
- Video port 0 for parallel input
|
||||
- Video port 1 for LVDS output
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
lvds-encoder {
|
||||
compatible = "ti,ds90c185", "lvds-encoder";
|
||||
|
||||
powerdown-gpios = <&gpio 17 GPIO_ACTIVE_LOW>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
|
||||
lvds_enc_in: endpoint {
|
||||
remote-endpoint = <&lcdc_out_rgb>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
|
||||
lvds_enc_out: endpoint {
|
||||
remote-endpoint = <&lvds_panel_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,91 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/dsi-controller.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Common Properties for DSI Display Panels
|
||||
|
||||
maintainers:
|
||||
- Linus Walleij <linus.walleij@linaro.org>
|
||||
|
||||
description: |
|
||||
This document defines device tree properties common to DSI, Display
|
||||
Serial Interface controllers and attached panels. It doesn't constitute
|
||||
a device tree binding specification by itself but is meant to be referenced
|
||||
by device tree bindings.
|
||||
|
||||
When referenced from panel device tree bindings the properties defined in
|
||||
this document are defined as follows. The panel device tree bindings are
|
||||
responsible for defining whether each property is required or optional.
|
||||
|
||||
Notice: this binding concerns DSI panels connected directly to a master
|
||||
without any intermediate port graph to the panel. Each DSI master
|
||||
can control one to four virtual channels to one panel. Each virtual
|
||||
channel should have a node "panel" for their virtual channel with their
|
||||
reg-property set to the virtual channel number, usually there is just
|
||||
one virtual channel, number 0.
|
||||
|
||||
properties:
|
||||
$nodename:
|
||||
pattern: "^dsi-controller(@.*)?$"
|
||||
|
||||
"#address-cells":
|
||||
const: 1
|
||||
|
||||
"#size-cells":
|
||||
const: 0
|
||||
|
||||
patternProperties:
|
||||
"^panel@[0-3]$":
|
||||
description: Panels connected to the DSI link
|
||||
type: object
|
||||
|
||||
properties:
|
||||
reg:
|
||||
minimum: 0
|
||||
maximum: 3
|
||||
description:
|
||||
The virtual channel number of a DSI peripheral. Must be in the range
|
||||
from 0 to 3, as DSI uses a 2-bit addressing scheme. Some DSI
|
||||
peripherals respond to more than a single virtual channel. In that
|
||||
case the reg property can take multiple entries, one for each virtual
|
||||
channel that the peripheral responds to.
|
||||
|
||||
clock-master:
|
||||
type: boolean
|
||||
description:
|
||||
Should be enabled if the host is being used in conjunction with
|
||||
another DSI host to drive the same peripheral. Hardware supporting
|
||||
such a configuration generally requires the data on both the busses
|
||||
to be driven by the same clock. Only the DSI host instance
|
||||
controlling this clock should contain this property.
|
||||
|
||||
enforce-video-mode:
|
||||
type: boolean
|
||||
description:
|
||||
The best option is usually to run a panel in command mode, as this
|
||||
gives better control over the panel hardware. However for different
|
||||
reasons like broken hardware, missing features or testing, it may be
|
||||
useful to be able to force a command mode-capable panel into video
|
||||
mode.
|
||||
|
||||
required:
|
||||
- reg
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
dsi-controller@a0351000 {
|
||||
reg = <0xa0351000 0x1000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
panel@0 {
|
||||
compatible = "sony,acx424akp";
|
||||
reg = <0>;
|
||||
vddi-supply = <&ab8500_ldo_aux1_reg>;
|
||||
reset-gpios = <&gpio2 1 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
@@ -4,6 +4,7 @@ Required properties:
|
||||
- compatible: one of:
|
||||
* ingenic,jz4740-lcd
|
||||
* ingenic,jz4725b-lcd
|
||||
* ingenic,jz4770-lcd
|
||||
- reg: LCD registers location and length
|
||||
- clocks: LCD pixclock and device clock specifiers.
|
||||
The device clock is only required on the JZ4740.
|
||||
|
||||
@@ -8,7 +8,7 @@ The DPU display controller is found in SDM845 SoC.
|
||||
|
||||
MDSS:
|
||||
Required properties:
|
||||
- compatible: "qcom,sdm845-mdss"
|
||||
- compatible: "qcom,sdm845-mdss", "qcom,sc7180-mdss"
|
||||
- reg: physical base address and length of contoller's registers.
|
||||
- reg-names: register region names. The following region is required:
|
||||
* "mdss"
|
||||
@@ -41,7 +41,7 @@ Optional properties:
|
||||
|
||||
MDP:
|
||||
Required properties:
|
||||
- compatible: "qcom,sdm845-dpu"
|
||||
- compatible: "qcom,sdm845-dpu", "qcom,sc7180-dpu"
|
||||
- reg: physical base address and length of controller's registers.
|
||||
- reg-names : register region names. The following region is required:
|
||||
* "mdp"
|
||||
|
||||
@@ -23,13 +23,18 @@ Required properties:
|
||||
- iommus: optional phandle to an adreno iommu instance
|
||||
- operating-points-v2: optional phandle to the OPP operating points
|
||||
- interconnects: optional phandle to an interconnect provider. See
|
||||
../interconnect/interconnect.txt for details.
|
||||
../interconnect/interconnect.txt for details. Some A3xx and all A4xx platforms
|
||||
will have two paths; all others will have one path.
|
||||
- interconnect-names: The names of the interconnect paths that correspond to the
|
||||
interconnects property. Values must be gfx-mem and ocmem.
|
||||
- qcom,gmu: For GMU attached devices a phandle to the GMU device that will
|
||||
control the power for the GPU. Applicable targets:
|
||||
- qcom,adreno-630.2
|
||||
- zap-shader: For a5xx and a6xx devices this node contains a memory-region that
|
||||
points to reserved memory to store the zap shader that can be used to help
|
||||
bring the GPU out of secure mode.
|
||||
- firmware-name: optional property of the 'zap-shader' node, listing the
|
||||
relative path of the device specific zap firmware.
|
||||
|
||||
Example 3xx/4xx/a5xx:
|
||||
|
||||
@@ -76,11 +81,13 @@ Example a6xx (with GMU):
|
||||
operating-points-v2 = <&gpu_opp_table>;
|
||||
|
||||
interconnects = <&rsc_hlos MASTER_GFX3D &rsc_hlos SLAVE_EBI1>;
|
||||
interconnect-names = "gfx-mem";
|
||||
|
||||
qcom,gmu = <&gmu>;
|
||||
|
||||
zap-shader {
|
||||
memory-region = <&zap_shader_region>;
|
||||
firmware-name = "qcom/LENOVO/81JL/qcdxkmsuc850.mbn"
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/panel/ampire,am-480272h3tmqw-t01h.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Ampire AM-480272H3TMQW-T01H 4.3" WQVGA TFT LCD panel
|
||||
|
||||
maintainers:
|
||||
- Yannick Fertre <yannick.fertre@st.com>
|
||||
- Thierry Reding <treding@nvidia.com>
|
||||
|
||||
allOf:
|
||||
- $ref: panel-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: ampire,am-480272h3tmqw-t01h
|
||||
|
||||
power-supply: true
|
||||
enable-gpios: true
|
||||
backlight: true
|
||||
port: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
panel_rgb: panel {
|
||||
compatible = "ampire,am-480272h3tmqw-t01h";
|
||||
enable-gpios = <&gpioa 8 1>;
|
||||
port {
|
||||
panel_in_rgb: endpoint {
|
||||
remote-endpoint = <&controller_out_rgb>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
@@ -1,7 +0,0 @@
|
||||
Ampire AM-800480R3TMQW-A1H 7.0" WVGA TFT LCD panel
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "ampire,am800480r3tmqwa1h"
|
||||
|
||||
This binding is compatible with the simple-panel binding, which is specified
|
||||
in simple-panel.txt in this directory.
|
||||
@@ -1,12 +0,0 @@
|
||||
GiantPlus 3.0" (320x240 pixels) 24-bit TFT LCD panel
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "giantplus,gpm940b0"
|
||||
- power-supply: as specified in the base binding
|
||||
|
||||
Optional properties:
|
||||
- backlight: as specified in the base binding
|
||||
- enable-gpios: as specified in the base binding
|
||||
|
||||
This binding is compatible with the simple-panel binding, which is specified
|
||||
in simple-panel.txt in this directory.
|
||||
@@ -0,0 +1,49 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/panel/leadtek,ltk500hd1829.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Leadtek LTK500HD1829 5.0in 720x1280 DSI panel
|
||||
|
||||
maintainers:
|
||||
- Heiko Stuebner <heiko.stuebner@theobroma-systems.com>
|
||||
|
||||
allOf:
|
||||
- $ref: panel-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: leadtek,ltk500hd1829
|
||||
reg: true
|
||||
backlight: true
|
||||
reset-gpios: true
|
||||
iovcc-supply:
|
||||
description: regulator that supplies the iovcc voltage
|
||||
vcc-supply:
|
||||
description: regulator that supplies the vcc voltage
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- backlight
|
||||
- iovcc-supply
|
||||
- vcc-supply
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
dsi@ff450000 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
panel@0 {
|
||||
compatible = "leadtek,ltk500hd1829";
|
||||
reg = <0>;
|
||||
backlight = <&backlight>;
|
||||
iovcc-supply = <&vcc_1v8>;
|
||||
vcc-supply = <&vcc_2v8>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
@@ -0,0 +1,42 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/panel/logicpd,type28.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Logic PD Type 28 4.3" WQVGA TFT LCD panel
|
||||
|
||||
maintainers:
|
||||
- Adam Ford <aford173@gmail.com>
|
||||
|
||||
allOf:
|
||||
- $ref: panel-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: logicpd,type28
|
||||
|
||||
power-supply: true
|
||||
enable-gpios: true
|
||||
backlight: true
|
||||
port: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
lcd0: display {
|
||||
compatible = "logicpd,type28";
|
||||
enable-gpios = <&gpio5 27 0>;
|
||||
backlight = <&backlight>;
|
||||
port {
|
||||
lcd_in: endpoint {
|
||||
remote-endpoint = <&dpi_out>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
@@ -0,0 +1,69 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/panel/panel-simple.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Simple panels with one power supply
|
||||
|
||||
maintainers:
|
||||
- Thierry Reding <thierry.reding@gmail.com>
|
||||
- Sam Ravnborg <sam@ravnborg.org>
|
||||
|
||||
description: |
|
||||
This binding file is a collection of the simple (dumb) panels that
|
||||
requires only a single power-supply.
|
||||
There are optionally a backlight and an enable GPIO.
|
||||
The panel may use an OF graph binding for the association to the display,
|
||||
or it may be a direct child node of the display.
|
||||
|
||||
If the panel is more advanced a dedicated binding file is required.
|
||||
|
||||
allOf:
|
||||
- $ref: panel-common.yaml#
|
||||
|
||||
properties:
|
||||
|
||||
compatible:
|
||||
enum:
|
||||
# compatible must be listed in alphabetical order, ordered by compatible.
|
||||
# The description in the comment is mandatory for each compatible.
|
||||
|
||||
# Ampire AM-480272H3TMQW-T01H 4.3" WQVGA TFT LCD panel
|
||||
- ampire,am-480272h3tmqw-t01h
|
||||
# Ampire AM-800480R3TMQW-A1H 7.0" WVGA TFT LCD panel
|
||||
- ampire,am800480r3tmqwa1h
|
||||
# AUO B116XAK01 eDP TFT LCD panel
|
||||
- auo,b116xa01
|
||||
# BOE NV140FHM-N49 14.0" FHD a-Si FT panel
|
||||
- boe,nv140fhmn49
|
||||
# GiantPlus GPM940B0 3.0" QVGA TFT LCD panel
|
||||
- giantplus,gpm940b0
|
||||
# Satoz SAT050AT40H12R2 5.0" WVGA TFT LCD panel
|
||||
- satoz,sat050at40h12r2
|
||||
# Sharp LS020B1DD01D 2.0" HQVGA TFT LCD panel
|
||||
- sharp,ls020b1dd01d
|
||||
|
||||
backlight: true
|
||||
enable-gpios: true
|
||||
port: true
|
||||
power-supply: true
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- power-supply
|
||||
|
||||
examples:
|
||||
- |
|
||||
panel_rgb: panel-rgb {
|
||||
compatible = "ampire,am-480272h3tmqw-t01h";
|
||||
power-supply = <&vcc_lcd_reg>;
|
||||
|
||||
port {
|
||||
panel_in_rgb: endpoint {
|
||||
remote-endpoint = <<dc_out_rgb>;
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -1,12 +0,0 @@
|
||||
Sharp 2.0" (240x160 pixels) 16-bit TFT LCD panel
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "sharp,ls020b1dd01d"
|
||||
- power-supply: as specified in the base binding
|
||||
|
||||
Optional properties:
|
||||
- backlight: as specified in the base binding
|
||||
- enable-gpios: as specified in the base binding
|
||||
|
||||
This binding is compatible with the simple-panel binding, which is specified
|
||||
in simple-panel.txt in this directory.
|
||||
@@ -0,0 +1,49 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/panel/sony,acx424akp.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Sony ACX424AKP 4" 480x864 AMOLED panel
|
||||
|
||||
maintainers:
|
||||
- Linus Walleij <linus.walleij@linaro.org>
|
||||
|
||||
allOf:
|
||||
- $ref: panel-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: sony,acx424akp
|
||||
reg: true
|
||||
reset-gpios: true
|
||||
vddi-supply:
|
||||
description: regulator that supplies the vddi voltage
|
||||
enforce-video-mode: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- reset-gpios
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
dsi-controller@a0351000 {
|
||||
compatible = "ste,mcde-dsi";
|
||||
reg = <0xa0351000 0x1000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
panel@0 {
|
||||
compatible = "sony,acx424akp";
|
||||
reg = <0>;
|
||||
vddi-supply = <&foo>;
|
||||
reset-gpios = <&foo_gpio 0 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
@@ -0,0 +1,49 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/panel/xinpeng,xpp055c272.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Xinpeng XPP055C272 5.5in 720x1280 DSI panel
|
||||
|
||||
maintainers:
|
||||
- Heiko Stuebner <heiko.stuebner@theobroma-systems.com>
|
||||
|
||||
allOf:
|
||||
- $ref: panel-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: xinpeng,xpp055c272
|
||||
reg: true
|
||||
backlight: true
|
||||
reset-gpios: true
|
||||
iovcc-supply:
|
||||
description: regulator that supplies the iovcc voltage
|
||||
vci-supply:
|
||||
description: regulator that supplies the vci voltage
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- backlight
|
||||
- iovcc-supply
|
||||
- vci-supply
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
dsi@ff450000 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
panel@0 {
|
||||
compatible = "xinpeng,xpp055c272";
|
||||
reg = <0>;
|
||||
backlight = <&backlight>;
|
||||
iovcc-supply = <&vcc_1v8>;
|
||||
vci-supply = <&vcc3v3_lcd>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
67
Documentation/devicetree/bindings/display/renesas,cmm.yaml
Normal file
67
Documentation/devicetree/bindings/display/renesas,cmm.yaml
Normal file
@@ -0,0 +1,67 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/renesas,cmm.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Renesas R-Car Color Management Module (CMM)
|
||||
|
||||
maintainers:
|
||||
- Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
||||
- Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
|
||||
- Jacopo Mondi <jacopo+renesas@jmondi.org>
|
||||
|
||||
description: |+
|
||||
Renesas R-Car color management module connected to R-Car DU video channels.
|
||||
It provides image enhancement functions such as 1-D look-up tables (LUT),
|
||||
3-D look-up tables (CLU), 1D-histogram generation (HGO), and color
|
||||
space conversion (CSC).
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- items:
|
||||
- enum:
|
||||
- renesas,r8a7795-cmm
|
||||
- renesas,r8a7796-cmm
|
||||
- renesas,r8a77965-cmm
|
||||
- renesas,r8a77990-cmm
|
||||
- renesas,r8a77995-cmm
|
||||
- const: renesas,rcar-gen3-cmm
|
||||
- items:
|
||||
- const: renesas,rcar-gen2-cmm
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- resets
|
||||
- power-domains
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/r8a7796-cpg-mssr.h>
|
||||
#include <dt-bindings/power/r8a7796-sysc.h>
|
||||
|
||||
cmm0: cmm@fea40000 {
|
||||
compatible = "renesas,r8a7796-cmm",
|
||||
"renesas,rcar-gen3-cmm";
|
||||
reg = <0 0xfea40000 0 0x1000>;
|
||||
power-domains = <&sysc R8A7796_PD_ALWAYS_ON>;
|
||||
clocks = <&cpg CPG_MOD 711>;
|
||||
resets = <&cpg 711>;
|
||||
};
|
||||
@@ -41,10 +41,14 @@ Required Properties:
|
||||
supplied they must be named "dclkin.x" with "x" being the input clock
|
||||
numerical index.
|
||||
|
||||
- vsps: A list of phandle and channel index tuples to the VSPs that handle
|
||||
the memory interfaces for the DU channels. The phandle identifies the VSP
|
||||
instance that serves the DU channel, and the channel index identifies the
|
||||
LIF instance in that VSP.
|
||||
- renesas,cmms: A list of phandles to the CMM instances present in the SoC,
|
||||
one for each available DU channel. The property shall not be specified for
|
||||
SoCs that do not provide any CMM (such as V3M and V3H).
|
||||
|
||||
- renesas,vsps: A list of phandle and channel index tuples to the VSPs that
|
||||
handle the memory interfaces for the DU channels. The phandle identifies the
|
||||
VSP instance that serves the DU channel, and the channel index identifies
|
||||
the LIF instance in that VSP.
|
||||
|
||||
Required nodes:
|
||||
|
||||
@@ -92,7 +96,8 @@ Example: R8A7795 (R-Car H3) ES2.0 DU
|
||||
<&cpg CPG_MOD 722>,
|
||||
<&cpg CPG_MOD 721>;
|
||||
clock-names = "du.0", "du.1", "du.2", "du.3";
|
||||
vsps = <&vspd0 0>, <&vspd1 0>, <&vspd2 0>, <&vspd0 1>;
|
||||
renesas,cmms = <&cmm0>, <&cmm1>, <&cmm2>, <&cmm3>;
|
||||
renesas,vsps = <&vspd0 0>, <&vspd1 0>, <&vspd2 0>, <&vspd0 1>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
|
||||
@@ -4,13 +4,16 @@ Rockchip specific extensions to the Synopsys Designware MIPI DSI
|
||||
Required properties:
|
||||
- #address-cells: Should be <1>.
|
||||
- #size-cells: Should be <0>.
|
||||
- compatible: "rockchip,rk3288-mipi-dsi", "snps,dw-mipi-dsi".
|
||||
"rockchip,rk3399-mipi-dsi", "snps,dw-mipi-dsi".
|
||||
- compatible: one of
|
||||
"rockchip,px30-mipi-dsi", "snps,dw-mipi-dsi"
|
||||
"rockchip,rk3288-mipi-dsi", "snps,dw-mipi-dsi"
|
||||
"rockchip,rk3399-mipi-dsi", "snps,dw-mipi-dsi"
|
||||
- reg: Represent the physical address range of the controller.
|
||||
- interrupts: Represent the controller's interrupt to the CPU(s).
|
||||
- clocks, clock-names: Phandles to the controller's pll reference
|
||||
clock(ref) and APB clock(pclk). For RK3399, a phy config clock
|
||||
(phy_cfg) and a grf clock(grf) are required. As described in [1].
|
||||
clock(ref) when using an internal dphy and APB clock(pclk).
|
||||
For RK3399, a phy config clock (phy_cfg) and a grf clock(grf)
|
||||
are required. As described in [1].
|
||||
- rockchip,grf: this soc should set GRF regs to mux vopl/vopb.
|
||||
- ports: contain a port node with endpoint definitions as defined in [2].
|
||||
For vopb,set the reg = <0> and set the reg = <1> for vopl.
|
||||
@@ -18,6 +21,8 @@ Required properties:
|
||||
- video port 1 for either a panel or subsequent encoder
|
||||
|
||||
Optional properties:
|
||||
- phys: from general PHY binding: the phandle for the PHY device.
|
||||
- phy-names: Should be "dphy" if phys references an external phy.
|
||||
- power-domains: a phandle to mipi dsi power domain node.
|
||||
- resets: list of phandle + reset specifier pairs, as described in [3].
|
||||
- reset-names: string reset name, must be "apb".
|
||||
|
||||
@@ -4,6 +4,7 @@ Rockchip RK3288 LVDS interface
|
||||
Required properties:
|
||||
- compatible: matching the soc type, one of
|
||||
- "rockchip,rk3288-lvds";
|
||||
- "rockchip,px30-lvds";
|
||||
|
||||
- reg: physical base address of the controller and length
|
||||
of memory mapped region.
|
||||
@@ -18,6 +19,9 @@ Required properties:
|
||||
- rockchip,grf: phandle to the general register files syscon
|
||||
- rockchip,output: "rgb", "lvds" or "duallvds", This describes the output interface
|
||||
|
||||
- phys: LVDS/DSI DPHY (px30 only)
|
||||
- phy-names: name of the PHY, must be "dphy" (px30 only)
|
||||
|
||||
Optional properties:
|
||||
- pinctrl-names: must contain a "lcdc" entry.
|
||||
- pinctrl-0: pin control group to be used for this controller.
|
||||
|
||||
@@ -1,637 +0,0 @@
|
||||
Allwinner A10 Display Pipeline
|
||||
==============================
|
||||
|
||||
The Allwinner A10 Display pipeline is composed of several components
|
||||
that are going to be documented below:
|
||||
|
||||
For all connections between components up to the TCONs in the display
|
||||
pipeline, when there are multiple components of the same type at the
|
||||
same depth, the local endpoint ID must be the same as the remote
|
||||
component's index. For example, if the remote endpoint is Frontend 1,
|
||||
then the local endpoint ID must be 1.
|
||||
|
||||
Frontend 0 [0] ------- [0] Backend 0 [0] ------- [0] TCON 0
|
||||
[1] -- -- [1] [1] -- -- [1]
|
||||
\ / \ /
|
||||
X X
|
||||
/ \ / \
|
||||
[0] -- -- [0] [0] -- -- [0]
|
||||
Frontend 1 [1] ------- [1] Backend 1 [1] ------- [1] TCON 1
|
||||
|
||||
For a two pipeline system such as the one depicted above, the lines
|
||||
represent the connections between the components, while the numbers
|
||||
within the square brackets corresponds to the ID of the local endpoint.
|
||||
|
||||
The same rule also applies to DE 2.0 mixer-TCON connections:
|
||||
|
||||
Mixer 0 [0] ----------- [0] TCON 0
|
||||
[1] ---- ---- [1]
|
||||
\ /
|
||||
X
|
||||
/ \
|
||||
[0] ---- ---- [0]
|
||||
Mixer 1 [1] ----------- [1] TCON 1
|
||||
|
||||
HDMI Encoder
|
||||
------------
|
||||
|
||||
The HDMI Encoder supports the HDMI video and audio outputs, and does
|
||||
CEC. It is one end of the pipeline.
|
||||
|
||||
Required properties:
|
||||
- compatible: value must be one of:
|
||||
* allwinner,sun4i-a10-hdmi
|
||||
* allwinner,sun5i-a10s-hdmi
|
||||
* allwinner,sun6i-a31-hdmi
|
||||
- reg: base address and size of memory-mapped region
|
||||
- interrupts: interrupt associated to this IP
|
||||
- clocks: phandles to the clocks feeding the HDMI encoder
|
||||
* ahb: the HDMI interface clock
|
||||
* mod: the HDMI module clock
|
||||
* ddc: the HDMI ddc clock (A31 only)
|
||||
* pll-0: the first video PLL
|
||||
* pll-1: the second video PLL
|
||||
- clock-names: the clock names mentioned above
|
||||
- resets: phandle to the reset control for the HDMI encoder (A31 only)
|
||||
- dmas: phandles to the DMA channels used by the HDMI encoder
|
||||
* ddc-tx: The channel for DDC transmission
|
||||
* ddc-rx: The channel for DDC reception
|
||||
* audio-tx: The channel used for audio transmission
|
||||
- dma-names: the channel names mentioned above
|
||||
|
||||
- ports: A ports node with endpoint definitions as defined in
|
||||
Documentation/devicetree/bindings/media/video-interfaces.txt. The
|
||||
first port should be the input endpoint. The second should be the
|
||||
output, usually to an HDMI connector.
|
||||
|
||||
DWC HDMI TX Encoder
|
||||
-------------------
|
||||
|
||||
The HDMI transmitter is a Synopsys DesignWare HDMI 1.4 TX controller IP
|
||||
with Allwinner's own PHY IP. It supports audio and video outputs and CEC.
|
||||
|
||||
These DT bindings follow the Synopsys DWC HDMI TX bindings defined in
|
||||
Documentation/devicetree/bindings/display/bridge/dw_hdmi.txt with the
|
||||
following device-specific properties.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: value must be one of:
|
||||
* "allwinner,sun8i-a83t-dw-hdmi"
|
||||
* "allwinner,sun50i-a64-dw-hdmi", "allwinner,sun8i-a83t-dw-hdmi"
|
||||
* "allwinner,sun50i-h6-dw-hdmi"
|
||||
- reg: base address and size of memory-mapped region
|
||||
- reg-io-width: See dw_hdmi.txt. Shall be 1.
|
||||
- interrupts: HDMI interrupt number
|
||||
- clocks: phandles to the clocks feeding the HDMI encoder
|
||||
* iahb: the HDMI bus clock
|
||||
* isfr: the HDMI register clock
|
||||
* tmds: TMDS clock
|
||||
* cec: HDMI CEC clock (H6 only)
|
||||
* hdcp: HDCP clock (H6 only)
|
||||
* hdcp-bus: HDCP bus clock (H6 only)
|
||||
- clock-names: the clock names mentioned above
|
||||
- resets:
|
||||
* ctrl: HDMI controller reset
|
||||
* hdcp: HDCP reset (H6 only)
|
||||
- reset-names: reset names mentioned above
|
||||
- phys: phandle to the DWC HDMI PHY
|
||||
- phy-names: must be "phy"
|
||||
|
||||
- ports: A ports node with endpoint definitions as defined in
|
||||
Documentation/devicetree/bindings/media/video-interfaces.txt. The
|
||||
first port should be the input endpoint. The second should be the
|
||||
output, usually to an HDMI connector.
|
||||
|
||||
Optional properties:
|
||||
- hvcc-supply: the VCC power supply of the controller
|
||||
|
||||
DWC HDMI PHY
|
||||
------------
|
||||
|
||||
Required properties:
|
||||
- compatible: value must be one of:
|
||||
* allwinner,sun8i-a83t-hdmi-phy
|
||||
* allwinner,sun8i-h3-hdmi-phy
|
||||
* allwinner,sun8i-r40-hdmi-phy
|
||||
* allwinner,sun50i-a64-hdmi-phy
|
||||
* allwinner,sun50i-h6-hdmi-phy
|
||||
- reg: base address and size of memory-mapped region
|
||||
- clocks: phandles to the clocks feeding the HDMI PHY
|
||||
* bus: the HDMI PHY interface clock
|
||||
* mod: the HDMI PHY module clock
|
||||
- clock-names: the clock names mentioned above
|
||||
- resets: phandle to the reset controller driving the PHY
|
||||
- reset-names: must be "phy"
|
||||
|
||||
H3, A64 and R40 HDMI PHY require additional clocks:
|
||||
- pll-0: parent of phy clock
|
||||
- pll-1: second possible phy clock parent (A64/R40 only)
|
||||
|
||||
TV Encoder
|
||||
----------
|
||||
|
||||
The TV Encoder supports the composite and VGA output. It is one end of
|
||||
the pipeline.
|
||||
|
||||
Required properties:
|
||||
- compatible: value should be "allwinner,sun4i-a10-tv-encoder".
|
||||
- reg: base address and size of memory-mapped region
|
||||
- clocks: the clocks driving the TV encoder
|
||||
- resets: phandle to the reset controller driving the encoder
|
||||
|
||||
- ports: A ports node with endpoint definitions as defined in
|
||||
Documentation/devicetree/bindings/media/video-interfaces.txt. The
|
||||
first port should be the input endpoint.
|
||||
|
||||
TCON
|
||||
----
|
||||
|
||||
The TCON acts as a timing controller for RGB, LVDS and TV interfaces.
|
||||
|
||||
Required properties:
|
||||
- compatible: value must be either:
|
||||
* allwinner,sun4i-a10-tcon
|
||||
* allwinner,sun5i-a13-tcon
|
||||
* allwinner,sun6i-a31-tcon
|
||||
* allwinner,sun6i-a31s-tcon
|
||||
* allwinner,sun7i-a20-tcon
|
||||
* allwinner,sun8i-a23-tcon
|
||||
* allwinner,sun8i-a33-tcon
|
||||
* allwinner,sun8i-a83t-tcon-lcd
|
||||
* allwinner,sun8i-a83t-tcon-tv
|
||||
* allwinner,sun8i-r40-tcon-tv
|
||||
* allwinner,sun8i-v3s-tcon
|
||||
* allwinner,sun9i-a80-tcon-lcd
|
||||
* allwinner,sun9i-a80-tcon-tv
|
||||
* "allwinner,sun50i-a64-tcon-lcd", "allwinner,sun8i-a83t-tcon-lcd"
|
||||
* "allwinner,sun50i-a64-tcon-tv", "allwinner,sun8i-a83t-tcon-tv"
|
||||
* allwinner,sun50i-h6-tcon-tv, allwinner,sun8i-r40-tcon-tv
|
||||
- reg: base address and size of memory-mapped region
|
||||
- interrupts: interrupt associated to this IP
|
||||
- clocks: phandles to the clocks feeding the TCON.
|
||||
- 'ahb': the interface clocks
|
||||
- 'tcon-ch0': The clock driving the TCON channel 0, if supported
|
||||
- resets: phandles to the reset controllers driving the encoder
|
||||
- "lcd": the reset line for the TCON
|
||||
- "edp": the reset line for the eDP block (A80 only)
|
||||
|
||||
- clock-names: the clock names mentioned above
|
||||
- reset-names: the reset names mentioned above
|
||||
- clock-output-names: Name of the pixel clock created, if TCON supports
|
||||
channel 0.
|
||||
|
||||
- ports: A ports node with endpoint definitions as defined in
|
||||
Documentation/devicetree/bindings/media/video-interfaces.txt. The
|
||||
first port should be the input endpoint, the second one the output
|
||||
|
||||
The output may have multiple endpoints. TCON can have 1 or 2 channels,
|
||||
usually with the first channel being used for the panels interfaces
|
||||
(RGB, LVDS, etc.), and the second being used for the outputs that
|
||||
require another controller (TV Encoder, HDMI, etc.). The endpoints
|
||||
will take an extra property, allwinner,tcon-channel, to specify the
|
||||
channel the endpoint is associated to. If that property is not
|
||||
present, the endpoint number will be used as the channel number.
|
||||
|
||||
For TCONs with channel 0, there is one more clock required:
|
||||
- 'tcon-ch0': The clock driving the TCON channel 0
|
||||
For TCONs with channel 1, there is one more clock required:
|
||||
- 'tcon-ch1': The clock driving the TCON channel 1
|
||||
|
||||
When TCON support LVDS (all TCONs except TV TCONs on A83T, R40 and those found
|
||||
in A13, H3, H5 and V3s SoCs), you need one more reset line:
|
||||
- 'lvds': The reset line driving the LVDS logic
|
||||
|
||||
And on the A23, A31, A31s and A33, you need one more clock line:
|
||||
- 'lvds-alt': An alternative clock source, separate from the TCON channel 0
|
||||
clock, that can be used to drive the LVDS clock
|
||||
|
||||
TCON TOP
|
||||
--------
|
||||
|
||||
TCON TOPs main purpose is to configure whole display pipeline. It determines
|
||||
relationships between mixers and TCONs, selects source TCON for HDMI, muxes
|
||||
LCD and TV encoder GPIO output, selects TV encoder clock source and contains
|
||||
additional TV TCON and DSI gates.
|
||||
|
||||
It allows display pipeline to be configured in very different ways:
|
||||
|
||||
/ LCD0/LVDS0
|
||||
/ [0] TCON-LCD0
|
||||
| \ MIPI DSI
|
||||
mixer0 |
|
||||
\ / [1] TCON-LCD1 - LCD1/LVDS1
|
||||
TCON-TOP
|
||||
/ \ [2] TCON-TV0 [0] - TVE0/RGB
|
||||
mixer1 | \
|
||||
| TCON-TOP - HDMI
|
||||
| /
|
||||
\ [3] TCON-TV1 [1] - TVE1/RGB
|
||||
|
||||
Note that both TCON TOP references same physical unit. Both mixers can be
|
||||
connected to any TCON. Not all TCON TOP variants support all features.
|
||||
|
||||
Required properties:
|
||||
- compatible: value must be one of:
|
||||
* allwinner,sun8i-r40-tcon-top
|
||||
* allwinner,sun50i-h6-tcon-top
|
||||
- reg: base address and size of the memory-mapped region.
|
||||
- clocks: phandle to the clocks feeding the TCON TOP
|
||||
* bus: TCON TOP interface clock
|
||||
* tcon-tv0: TCON TV0 clock
|
||||
* tve0: TVE0 clock (R40 only)
|
||||
* tcon-tv1: TCON TV1 clock (R40 only)
|
||||
* tve1: TVE0 clock (R40 only)
|
||||
* dsi: MIPI DSI clock (R40 only)
|
||||
- clock-names: clock name mentioned above
|
||||
- resets: phandle to the reset line driving the TCON TOP
|
||||
- #clock-cells : must contain 1
|
||||
- clock-output-names: Names of clocks created for TCON TV0 channel clock,
|
||||
TCON TV1 channel clock (R40 only) and DSI channel clock (R40 only), in
|
||||
that order.
|
||||
|
||||
- ports: A ports node with endpoint definitions as defined in
|
||||
Documentation/devicetree/bindings/media/video-interfaces.txt. 6 ports should
|
||||
be defined:
|
||||
* port 0 is input for mixer0 mux
|
||||
* port 1 is output for mixer0 mux
|
||||
* port 2 is input for mixer1 mux
|
||||
* port 3 is output for mixer1 mux
|
||||
* port 4 is input for HDMI mux
|
||||
* port 5 is output for HDMI mux
|
||||
All output endpoints for mixer muxes and input endpoints for HDMI mux should
|
||||
have reg property with the id of the target TCON, as shown in above graph
|
||||
(0-3 for mixer muxes and 0-1 for HDMI mux). All ports should have only one
|
||||
endpoint connected to remote endpoint.
|
||||
|
||||
DRC
|
||||
---
|
||||
|
||||
The DRC (Dynamic Range Controller), found in the latest Allwinner SoCs
|
||||
(A31, A23, A33, A80), allows to dynamically adjust pixel
|
||||
brightness/contrast based on histogram measurements for LCD content
|
||||
adaptive backlight control.
|
||||
|
||||
|
||||
Required properties:
|
||||
- compatible: value must be one of:
|
||||
* allwinner,sun6i-a31-drc
|
||||
* allwinner,sun6i-a31s-drc
|
||||
* allwinner,sun8i-a23-drc
|
||||
* allwinner,sun8i-a33-drc
|
||||
* allwinner,sun9i-a80-drc
|
||||
- reg: base address and size of the memory-mapped region.
|
||||
- interrupts: interrupt associated to this IP
|
||||
- clocks: phandles to the clocks feeding the DRC
|
||||
* ahb: the DRC interface clock
|
||||
* mod: the DRC module clock
|
||||
* ram: the DRC DRAM clock
|
||||
- clock-names: the clock names mentioned above
|
||||
- resets: phandles to the reset line driving the DRC
|
||||
|
||||
- ports: A ports node with endpoint definitions as defined in
|
||||
Documentation/devicetree/bindings/media/video-interfaces.txt. The
|
||||
first port should be the input endpoints, the second one the outputs
|
||||
|
||||
Display Engine Backend
|
||||
----------------------
|
||||
|
||||
The display engine backend exposes layers and sprites to the
|
||||
system.
|
||||
|
||||
Required properties:
|
||||
- compatible: value must be one of:
|
||||
* allwinner,sun4i-a10-display-backend
|
||||
* allwinner,sun5i-a13-display-backend
|
||||
* allwinner,sun6i-a31-display-backend
|
||||
* allwinner,sun7i-a20-display-backend
|
||||
* allwinner,sun8i-a23-display-backend
|
||||
* allwinner,sun8i-a33-display-backend
|
||||
* allwinner,sun9i-a80-display-backend
|
||||
- reg: base address and size of the memory-mapped region.
|
||||
- interrupts: interrupt associated to this IP
|
||||
- clocks: phandles to the clocks feeding the frontend and backend
|
||||
* ahb: the backend interface clock
|
||||
* mod: the backend module clock
|
||||
* ram: the backend DRAM clock
|
||||
- clock-names: the clock names mentioned above
|
||||
- resets: phandles to the reset controllers driving the backend
|
||||
|
||||
- ports: A ports node with endpoint definitions as defined in
|
||||
Documentation/devicetree/bindings/media/video-interfaces.txt. The
|
||||
first port should be the input endpoints, the second one the output
|
||||
|
||||
On the A33, some additional properties are required:
|
||||
- reg needs to have an additional region corresponding to the SAT
|
||||
- reg-names need to be set, with "be" and "sat"
|
||||
- clocks and clock-names need to have a phandle to the SAT bus
|
||||
clocks, whose name will be "sat"
|
||||
- resets and reset-names need to have a phandle to the SAT bus
|
||||
resets, whose name will be "sat"
|
||||
|
||||
DEU
|
||||
---
|
||||
|
||||
The DEU (Detail Enhancement Unit), found in the Allwinner A80 SoC,
|
||||
can sharpen the display content in both luma and chroma channels.
|
||||
|
||||
Required properties:
|
||||
- compatible: value must be one of:
|
||||
* allwinner,sun9i-a80-deu
|
||||
- reg: base address and size of the memory-mapped region.
|
||||
- interrupts: interrupt associated to this IP
|
||||
- clocks: phandles to the clocks feeding the DEU
|
||||
* ahb: the DEU interface clock
|
||||
* mod: the DEU module clock
|
||||
* ram: the DEU DRAM clock
|
||||
- clock-names: the clock names mentioned above
|
||||
- resets: phandles to the reset line driving the DEU
|
||||
|
||||
- ports: A ports node with endpoint definitions as defined in
|
||||
Documentation/devicetree/bindings/media/video-interfaces.txt. The
|
||||
first port should be the input endpoints, the second one the outputs
|
||||
|
||||
Display Engine Frontend
|
||||
-----------------------
|
||||
|
||||
The display engine frontend does formats conversion, scaling,
|
||||
deinterlacing and color space conversion.
|
||||
|
||||
Required properties:
|
||||
- compatible: value must be one of:
|
||||
* allwinner,sun4i-a10-display-frontend
|
||||
* allwinner,sun5i-a13-display-frontend
|
||||
* allwinner,sun6i-a31-display-frontend
|
||||
* allwinner,sun7i-a20-display-frontend
|
||||
* allwinner,sun8i-a23-display-frontend
|
||||
* allwinner,sun8i-a33-display-frontend
|
||||
* allwinner,sun9i-a80-display-frontend
|
||||
- reg: base address and size of the memory-mapped region.
|
||||
- interrupts: interrupt associated to this IP
|
||||
- clocks: phandles to the clocks feeding the frontend and backend
|
||||
* ahb: the backend interface clock
|
||||
* mod: the backend module clock
|
||||
* ram: the backend DRAM clock
|
||||
- clock-names: the clock names mentioned above
|
||||
- resets: phandles to the reset controllers driving the backend
|
||||
|
||||
- ports: A ports node with endpoint definitions as defined in
|
||||
Documentation/devicetree/bindings/media/video-interfaces.txt. The
|
||||
first port should be the input endpoints, the second one the outputs
|
||||
|
||||
Display Engine 2.0 Mixer
|
||||
------------------------
|
||||
|
||||
The DE2 mixer have many functionalities, currently only layer blending is
|
||||
supported.
|
||||
|
||||
Required properties:
|
||||
- compatible: value must be one of:
|
||||
* allwinner,sun8i-a83t-de2-mixer-0
|
||||
* allwinner,sun8i-a83t-de2-mixer-1
|
||||
* allwinner,sun8i-h3-de2-mixer-0
|
||||
* allwinner,sun8i-r40-de2-mixer-0
|
||||
* allwinner,sun8i-r40-de2-mixer-1
|
||||
* allwinner,sun8i-v3s-de2-mixer
|
||||
* allwinner,sun50i-a64-de2-mixer-0
|
||||
* allwinner,sun50i-a64-de2-mixer-1
|
||||
* allwinner,sun50i-h6-de3-mixer-0
|
||||
- reg: base address and size of the memory-mapped region.
|
||||
- clocks: phandles to the clocks feeding the mixer
|
||||
* bus: the mixer interface clock
|
||||
* mod: the mixer module clock
|
||||
- clock-names: the clock names mentioned above
|
||||
- resets: phandles to the reset controllers driving the mixer
|
||||
|
||||
- ports: A ports node with endpoint definitions as defined in
|
||||
Documentation/devicetree/bindings/media/video-interfaces.txt. The
|
||||
first port should be the input endpoints, the second one the output
|
||||
|
||||
|
||||
Display Engine Pipeline
|
||||
-----------------------
|
||||
|
||||
The display engine pipeline (and its entry point, since it can be
|
||||
either directly the backend or the frontend) is represented as an
|
||||
extra node.
|
||||
|
||||
Required properties:
|
||||
- compatible: value must be one of:
|
||||
* allwinner,sun4i-a10-display-engine
|
||||
* allwinner,sun5i-a10s-display-engine
|
||||
* allwinner,sun5i-a13-display-engine
|
||||
* allwinner,sun6i-a31-display-engine
|
||||
* allwinner,sun6i-a31s-display-engine
|
||||
* allwinner,sun7i-a20-display-engine
|
||||
* allwinner,sun8i-a23-display-engine
|
||||
* allwinner,sun8i-a33-display-engine
|
||||
* allwinner,sun8i-a83t-display-engine
|
||||
* allwinner,sun8i-h3-display-engine
|
||||
* allwinner,sun8i-r40-display-engine
|
||||
* allwinner,sun8i-v3s-display-engine
|
||||
* allwinner,sun9i-a80-display-engine
|
||||
* allwinner,sun50i-a64-display-engine
|
||||
* allwinner,sun50i-h6-display-engine
|
||||
|
||||
- allwinner,pipelines: list of phandle to the display engine
|
||||
frontends (DE 1.0) or mixers (DE 2.0/3.0) available.
|
||||
|
||||
Example:
|
||||
|
||||
panel: panel {
|
||||
compatible = "olimex,lcd-olinuxino-43-ts";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
panel_input: endpoint {
|
||||
remote-endpoint = <&tcon0_out_panel>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
connector {
|
||||
compatible = "hdmi-connector";
|
||||
type = "a";
|
||||
|
||||
port {
|
||||
hdmi_con_in: endpoint {
|
||||
remote-endpoint = <&hdmi_out_con>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
hdmi: hdmi@1c16000 {
|
||||
compatible = "allwinner,sun5i-a10s-hdmi";
|
||||
reg = <0x01c16000 0x1000>;
|
||||
interrupts = <58>;
|
||||
clocks = <&ccu CLK_AHB_HDMI>, <&ccu CLK_HDMI>,
|
||||
<&ccu CLK_PLL_VIDEO0_2X>,
|
||||
<&ccu CLK_PLL_VIDEO1_2X>;
|
||||
clock-names = "ahb", "mod", "pll-0", "pll-1";
|
||||
dmas = <&dma SUN4I_DMA_NORMAL 16>,
|
||||
<&dma SUN4I_DMA_NORMAL 16>,
|
||||
<&dma SUN4I_DMA_DEDICATED 24>;
|
||||
dma-names = "ddc-tx", "ddc-rx", "audio-tx";
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0>;
|
||||
|
||||
hdmi_in_tcon0: endpoint {
|
||||
remote-endpoint = <&tcon0_out_hdmi>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <1>;
|
||||
|
||||
hdmi_out_con: endpoint {
|
||||
remote-endpoint = <&hdmi_con_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
tve0: tv-encoder@1c0a000 {
|
||||
compatible = "allwinner,sun4i-a10-tv-encoder";
|
||||
reg = <0x01c0a000 0x1000>;
|
||||
clocks = <&ahb_gates 34>;
|
||||
resets = <&tcon_ch0_clk 0>;
|
||||
|
||||
port {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
tve0_in_tcon0: endpoint@0 {
|
||||
reg = <0>;
|
||||
remote-endpoint = <&tcon0_out_tve0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
tcon0: lcd-controller@1c0c000 {
|
||||
compatible = "allwinner,sun5i-a13-tcon";
|
||||
reg = <0x01c0c000 0x1000>;
|
||||
interrupts = <44>;
|
||||
resets = <&tcon_ch0_clk 1>;
|
||||
reset-names = "lcd";
|
||||
clocks = <&ahb_gates 36>,
|
||||
<&tcon_ch0_clk>,
|
||||
<&tcon_ch1_clk>;
|
||||
clock-names = "ahb",
|
||||
"tcon-ch0",
|
||||
"tcon-ch1";
|
||||
clock-output-names = "tcon-pixel-clock";
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
tcon0_in: port@0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0>;
|
||||
|
||||
tcon0_in_be0: endpoint@0 {
|
||||
reg = <0>;
|
||||
remote-endpoint = <&be0_out_tcon0>;
|
||||
};
|
||||
};
|
||||
|
||||
tcon0_out: port@1 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <1>;
|
||||
|
||||
tcon0_out_panel: endpoint@0 {
|
||||
reg = <0>;
|
||||
remote-endpoint = <&panel_input>;
|
||||
};
|
||||
|
||||
tcon0_out_tve0: endpoint@1 {
|
||||
reg = <1>;
|
||||
remote-endpoint = <&tve0_in_tcon0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
fe0: display-frontend@1e00000 {
|
||||
compatible = "allwinner,sun5i-a13-display-frontend";
|
||||
reg = <0x01e00000 0x20000>;
|
||||
interrupts = <47>;
|
||||
clocks = <&ahb_gates 46>, <&de_fe_clk>,
|
||||
<&dram_gates 25>;
|
||||
clock-names = "ahb", "mod",
|
||||
"ram";
|
||||
resets = <&de_fe_clk>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
fe0_out: port@1 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <1>;
|
||||
|
||||
fe0_out_be0: endpoint {
|
||||
remote-endpoint = <&be0_in_fe0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
be0: display-backend@1e60000 {
|
||||
compatible = "allwinner,sun5i-a13-display-backend";
|
||||
reg = <0x01e60000 0x10000>;
|
||||
interrupts = <47>;
|
||||
clocks = <&ahb_gates 44>, <&de_be_clk>,
|
||||
<&dram_gates 26>;
|
||||
clock-names = "ahb", "mod",
|
||||
"ram";
|
||||
resets = <&de_be_clk>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
be0_in: port@0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0>;
|
||||
|
||||
be0_in_fe0: endpoint@0 {
|
||||
reg = <0>;
|
||||
remote-endpoint = <&fe0_out_be0>;
|
||||
};
|
||||
};
|
||||
|
||||
be0_out: port@1 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <1>;
|
||||
|
||||
be0_out_tcon0: endpoint@0 {
|
||||
reg = <0>;
|
||||
remote-endpoint = <&tcon0_in_be0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
display-engine {
|
||||
compatible = "allwinner,sun5i-a13-display-engine";
|
||||
allwinner,pipelines = <&fe0>;
|
||||
};
|
||||
@@ -1,21 +0,0 @@
|
||||
Device-Tree bindings for tilcdc DRM TFP410 output driver
|
||||
|
||||
Required properties:
|
||||
- compatible: value should be "ti,tilcdc,tfp410".
|
||||
- i2c: the phandle for the i2c device to use for DDC
|
||||
|
||||
Recommended properties:
|
||||
- pinctrl-names, pinctrl-0: the pincontrol settings to configure
|
||||
muxing properly for pins that connect to TFP410 device
|
||||
- powerdn-gpio: the powerdown GPIO, pulled low to power down the
|
||||
TFP410 device (for DPMS_OFF)
|
||||
|
||||
Example:
|
||||
|
||||
dvicape {
|
||||
compatible = "ti,tilcdc,tfp410";
|
||||
i2c = <&i2c2>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&bone_dvi_cape_dvi_00A1_pins>;
|
||||
powerdn-gpio = <&gpio2 31 0>;
|
||||
};
|
||||
@@ -15,7 +15,11 @@ properties:
|
||||
const: 0
|
||||
|
||||
compatible:
|
||||
const: allwinner,sun6i-a31-mipi-dphy
|
||||
oneOf:
|
||||
- const: allwinner,sun6i-a31-mipi-dphy
|
||||
- items:
|
||||
- const: allwinner,sun50i-a64-mipi-dphy
|
||||
- const: allwinner,sun6i-a31-mipi-dphy
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
@@ -35,6 +35,10 @@ Optional Properties:
|
||||
for each of the battery capacity lookup table. The first temperature value
|
||||
specifies the OCV table 0, and the second temperature value specifies the
|
||||
OCV table 1, and so on.
|
||||
- resistance-temp-table: An array providing the temperature in degree Celsius
|
||||
and corresponding battery internal resistance percent, which is used to look
|
||||
up the resistance percent according to current temperature to get a accurate
|
||||
batterty internal resistance in different temperatures.
|
||||
|
||||
Battery properties are named, where possible, for the corresponding
|
||||
elements in enum power_supply_property, defined in
|
||||
@@ -61,6 +65,7 @@ Example:
|
||||
ocv-capacity-table-0 = <4185000 100>, <4113000 95>, <4066000 90>, ...;
|
||||
ocv-capacity-table-1 = <4200000 100>, <4185000 95>, <4113000 90>, ...;
|
||||
ocv-capacity-table-2 = <4250000 100>, <4200000 95>, <4185000 90>, ...;
|
||||
resistance-temp-table = <20 100>, <10 90>, <0 80>, <(-10) 60>;
|
||||
};
|
||||
|
||||
charger: charger@11 {
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
Binding for TI bq25890 Li-Ion Charger
|
||||
|
||||
This driver will support the bq25896 and the bq25890. There are other ICs
|
||||
in the same family but those have not been tested.
|
||||
This driver will support the bq25892, the bq25896 and the bq25890. There are
|
||||
other ICs in the same family but those have not been tested.
|
||||
|
||||
Required properties:
|
||||
- compatible: Should contain one of the following:
|
||||
* "ti,bq25890"
|
||||
* "ti,bq25892"
|
||||
* "ti,bq25895"
|
||||
* "ti,bq25896"
|
||||
- reg: integer, i2c address of the device.
|
||||
- ti,battery-regulation-voltage: integer, maximum charging voltage (in uV);
|
||||
- ti,charge-current: integer, maximum charging current (in uA);
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
max17040_battery
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
Required properties :
|
||||
- compatible : "maxim,max17040" or "maxim,max77836-battery"
|
||||
- reg: i2c slave address
|
||||
|
||||
Optional properties :
|
||||
- maxim,alert-low-soc-level : The alert threshold that sets the state of
|
||||
charge level (%) where an interrupt is
|
||||
generated. Can be configured from 1 up to 32
|
||||
(%). If skipped the power up default value of
|
||||
4 (%) will be used.
|
||||
- interrupts : Interrupt line see Documentation/devicetree/
|
||||
bindings/interrupt-controller/interrupts.txt
|
||||
- wakeup-source : This device has wakeup capabilities. Use this
|
||||
property to use alert low SOC level interrupt
|
||||
as wake up source.
|
||||
|
||||
Optional properties support interrupt functionality for alert low state of
|
||||
charge level, present in some ICs in the same family, and should be used with
|
||||
compatible "maxim,max77836-battery".
|
||||
|
||||
Example:
|
||||
|
||||
battery-fuel-gauge@36 {
|
||||
compatible = "maxim,max77836-battery";
|
||||
reg = <0x36>;
|
||||
maxim,alert-low-soc-level = <10>;
|
||||
interrupt-parent = <&gpio7>;
|
||||
interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
|
||||
wakeup-source;
|
||||
};
|
||||
@@ -2,7 +2,11 @@ max17042_battery
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
Required properties :
|
||||
- compatible : "maxim,max17042"
|
||||
- compatible : one of the following
|
||||
* "maxim,max17042"
|
||||
* "maxim,max17047"
|
||||
* "maxim,max17050"
|
||||
* "maxim,max17055"
|
||||
|
||||
Optional properties :
|
||||
- maxim,rsns-microohm : Resistance of rsns resistor in micro Ohms
|
||||
|
||||
@@ -13,6 +13,8 @@ Required properties:
|
||||
- io-channel-names: Should be "bat-temp" or "charge-vol".
|
||||
- nvmem-cells: A phandle to the calibration cells provided by eFuse device.
|
||||
- nvmem-cell-names: Should be "fgu_calib".
|
||||
- sprd,calib-resistance-micro-ohms: Specify the real resistance of coulomb counter
|
||||
chip in micro Ohms.
|
||||
- monitored-battery: Phandle of battery characteristics devicetree node.
|
||||
See Documentation/devicetree/bindings/power/supply/battery.txt
|
||||
|
||||
@@ -52,5 +54,6 @@ Example:
|
||||
nvmem-cells = <&fgu_calib>;
|
||||
nvmem-cell-names = "fgu_calib";
|
||||
monitored-battery = <&bat>;
|
||||
sprd,calib-resistance-micro-ohms = <21500>;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -521,6 +521,8 @@ patternProperties:
|
||||
description: Lantiq Semiconductor
|
||||
"^lattice,.*":
|
||||
description: Lattice Semiconductor
|
||||
"^leadtek,.*":
|
||||
description: Shenzhen Leadtek Technology Co., Ltd.
|
||||
"^leez,.*":
|
||||
description: Leez
|
||||
"^lego,.*":
|
||||
@@ -835,6 +837,8 @@ patternProperties:
|
||||
description: Sancloud Ltd
|
||||
"^sandisk,.*":
|
||||
description: Sandisk Corporation
|
||||
"^satoz,.*":
|
||||
description: Satoz International Co., Ltd
|
||||
"^sbs,.*":
|
||||
description: Smart Battery System
|
||||
"^schindler,.*":
|
||||
@@ -1072,6 +1076,8 @@ patternProperties:
|
||||
description: Extreme Engineering Solutions (X-ES)
|
||||
"^xillybus,.*":
|
||||
description: Xillybus Ltd.
|
||||
"^xinpeng,.*":
|
||||
description: Shenzhen Xinpeng Technology Co., Ltd
|
||||
"^xlnx,.*":
|
||||
description: Xilinx
|
||||
"^xunlong,.*":
|
||||
|
||||
@@ -127,7 +127,7 @@ C. Boot options
|
||||
is typically located on the same video card. Thus, the consoles that
|
||||
are controlled by the VGA console will be garbled.
|
||||
|
||||
4. fbcon=rotate:<n>
|
||||
5. fbcon=rotate:<n>
|
||||
|
||||
This option changes the orientation angle of the console display. The
|
||||
value 'n' accepts the following:
|
||||
@@ -152,21 +152,21 @@ C. Boot options
|
||||
Actually, the underlying fb driver is totally ignorant of console
|
||||
rotation.
|
||||
|
||||
5. fbcon=margin:<color>
|
||||
6. fbcon=margin:<color>
|
||||
|
||||
This option specifies the color of the margins. The margins are the
|
||||
leftover area at the right and the bottom of the screen that are not
|
||||
used by text. By default, this area will be black. The 'color' value
|
||||
is an integer number that depends on the framebuffer driver being used.
|
||||
|
||||
6. fbcon=nodefer
|
||||
7. fbcon=nodefer
|
||||
|
||||
If the kernel is compiled with deferred fbcon takeover support, normally
|
||||
the framebuffer contents, left in place by the firmware/bootloader, will
|
||||
be preserved until there actually is some text is output to the console.
|
||||
This option causes fbcon to bind immediately to the fbdev device.
|
||||
|
||||
7. fbcon=logo-pos:<location>
|
||||
8. fbcon=logo-pos:<location>
|
||||
|
||||
The only possible 'location' is 'center' (without quotes), and when
|
||||
given, the bootup logo is moved from the default top-left corner
|
||||
@@ -174,6 +174,11 @@ C. Boot options
|
||||
displayed due to multiple CPUs, the collected line of logos is moved
|
||||
as a whole.
|
||||
|
||||
9. fbcon=logo-count:<n>
|
||||
|
||||
The value 'n' overrides the number of bootup logos. 0 disables the
|
||||
logo, and -1 gives the default which is the number of online CPUs.
|
||||
|
||||
C. Attaching, Detaching and Unloading
|
||||
|
||||
Before going on to how to attach, detach and unload the framebuffer console, an
|
||||
|
||||
@@ -65,6 +65,9 @@ Valid options are::
|
||||
- reflect_y (boolean): Perform an axial symmetry on the Y axis
|
||||
- rotate (integer): Rotate the initial framebuffer by x
|
||||
degrees. Valid values are 0, 90, 180 and 270.
|
||||
- panel_orientation, one of "normal", "upside_down", "left_side_up", or
|
||||
"right_side_up". For KMS drivers only, this sets the "panel orientation"
|
||||
property on the kms connector as hint for kms users.
|
||||
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
@@ -24,9 +24,9 @@ Driver Initialization
|
||||
At the core of every DRM driver is a :c:type:`struct drm_driver
|
||||
<drm_driver>` structure. Drivers typically statically initialize
|
||||
a drm_driver structure, and then pass it to
|
||||
:c:func:`drm_dev_alloc()` to allocate a device instance. After the
|
||||
drm_dev_alloc() to allocate a device instance. After the
|
||||
device instance is fully initialized it can be registered (which makes
|
||||
it accessible from userspace) using :c:func:`drm_dev_register()`.
|
||||
it accessible from userspace) using drm_dev_register().
|
||||
|
||||
The :c:type:`struct drm_driver <drm_driver>` structure
|
||||
contains static information that describes the driver and features it
|
||||
|
||||
@@ -3,7 +3,7 @@ Kernel Mode Setting (KMS)
|
||||
=========================
|
||||
|
||||
Drivers must initialize the mode setting core by calling
|
||||
:c:func:`drm_mode_config_init()` on the DRM device. The function
|
||||
drm_mode_config_init() on the DRM device. The function
|
||||
initializes the :c:type:`struct drm_device <drm_device>`
|
||||
mode_config field and never fails. Once done, mode configuration must
|
||||
be setup by initializing the following fields.
|
||||
@@ -181,8 +181,7 @@ Setting`_). The somewhat surprising part here is that properties are not
|
||||
directly instantiated on each object, but free-standing mode objects themselves,
|
||||
represented by :c:type:`struct drm_property <drm_property>`, which only specify
|
||||
the type and value range of a property. Any given property can be attached
|
||||
multiple times to different objects using :c:func:`drm_object_attach_property()
|
||||
<drm_object_attach_property>`.
|
||||
multiple times to different objects using drm_object_attach_property().
|
||||
|
||||
.. kernel-doc:: include/drm/drm_mode_object.h
|
||||
:internal:
|
||||
@@ -260,7 +259,8 @@ Taken all together there's two consequences for the atomic design:
|
||||
drm_connector_state <drm_connector_state>` for connectors. These are the only
|
||||
objects with userspace-visible and settable state. For internal state drivers
|
||||
can subclass these structures through embeddeding, or add entirely new state
|
||||
structures for their globally shared hardware functions.
|
||||
structures for their globally shared hardware functions, see :c:type:`struct
|
||||
drm_private_state<drm_private_state>`.
|
||||
|
||||
- An atomic update is assembled and validated as an entirely free-standing pile
|
||||
of structures within the :c:type:`drm_atomic_state <drm_atomic_state>`
|
||||
@@ -269,6 +269,14 @@ Taken all together there's two consequences for the atomic design:
|
||||
to the driver and modeset objects. This way rolling back an update boils down
|
||||
to releasing memory and unreferencing objects like framebuffers.
|
||||
|
||||
Locking of atomic state structures is internally using :c:type:`struct
|
||||
drm_modeset_lock <drm_modeset_lock>`. As a general rule the locking shouldn't be
|
||||
exposed to drivers, instead the right locks should be automatically acquired by
|
||||
any function that duplicates or peeks into a state, like e.g.
|
||||
drm_atomic_get_crtc_state(). Locking only protects the software data
|
||||
structure, ordering of committing state changes to hardware is sequenced using
|
||||
:c:type:`struct drm_crtc_commit <drm_crtc_commit>`.
|
||||
|
||||
Read on in this chapter, and also in :ref:`drm_atomic_helper` for more detailed
|
||||
coverage of specific topics.
|
||||
|
||||
@@ -479,6 +487,9 @@ Color Management Properties
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_color_mgmt.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: include/drm/drm_color_mgmt.h
|
||||
:internal:
|
||||
|
||||
Tile Group Property
|
||||
-------------------
|
||||
|
||||
|
||||
@@ -149,19 +149,19 @@ struct :c:type:`struct drm_gem_object <drm_gem_object>`.
|
||||
To create a GEM object, a driver allocates memory for an instance of its
|
||||
specific GEM object type and initializes the embedded struct
|
||||
:c:type:`struct drm_gem_object <drm_gem_object>` with a call
|
||||
to :c:func:`drm_gem_object_init()`. The function takes a pointer
|
||||
to drm_gem_object_init(). The function takes a pointer
|
||||
to the DRM device, a pointer to the GEM object and the buffer object
|
||||
size in bytes.
|
||||
|
||||
GEM uses shmem to allocate anonymous pageable memory.
|
||||
:c:func:`drm_gem_object_init()` will create an shmfs file of the
|
||||
drm_gem_object_init() will create an shmfs file of the
|
||||
requested size and store it into the struct :c:type:`struct
|
||||
drm_gem_object <drm_gem_object>` filp field. The memory is
|
||||
used as either main storage for the object when the graphics hardware
|
||||
uses system memory directly or as a backing store otherwise.
|
||||
|
||||
Drivers are responsible for the actual physical pages allocation by
|
||||
calling :c:func:`shmem_read_mapping_page_gfp()` for each page.
|
||||
calling shmem_read_mapping_page_gfp() for each page.
|
||||
Note that they can decide to allocate pages when initializing the GEM
|
||||
object, or to delay allocation until the memory is needed (for instance
|
||||
when a page fault occurs as a result of a userspace memory access or
|
||||
@@ -170,20 +170,18 @@ when the driver needs to start a DMA transfer involving the memory).
|
||||
Anonymous pageable memory allocation is not always desired, for instance
|
||||
when the hardware requires physically contiguous system memory as is
|
||||
often the case in embedded devices. Drivers can create GEM objects with
|
||||
no shmfs backing (called private GEM objects) by initializing them with
|
||||
a call to :c:func:`drm_gem_private_object_init()` instead of
|
||||
:c:func:`drm_gem_object_init()`. Storage for private GEM objects
|
||||
must be managed by drivers.
|
||||
no shmfs backing (called private GEM objects) by initializing them with a call
|
||||
to drm_gem_private_object_init() instead of drm_gem_object_init(). Storage for
|
||||
private GEM objects must be managed by drivers.
|
||||
|
||||
GEM Objects Lifetime
|
||||
--------------------
|
||||
|
||||
All GEM objects are reference-counted by the GEM core. References can be
|
||||
acquired and release by :c:func:`calling drm_gem_object_get()` and
|
||||
:c:func:`drm_gem_object_put()` respectively. The caller must hold the
|
||||
:c:type:`struct drm_device <drm_device>` struct_mutex lock when calling
|
||||
:c:func:`drm_gem_object_get()`. As a convenience, GEM provides
|
||||
:c:func:`drm_gem_object_put_unlocked()` functions that can be called without
|
||||
acquired and release by calling drm_gem_object_get() and drm_gem_object_put()
|
||||
respectively. The caller must hold the :c:type:`struct drm_device <drm_device>`
|
||||
struct_mutex lock when calling drm_gem_object_get(). As a convenience, GEM
|
||||
provides drm_gem_object_put_unlocked() functions that can be called without
|
||||
holding the lock.
|
||||
|
||||
When the last reference to a GEM object is released the GEM core calls
|
||||
@@ -194,7 +192,7 @@ free the GEM object and all associated resources.
|
||||
void (\*gem_free_object) (struct drm_gem_object \*obj); Drivers are
|
||||
responsible for freeing all GEM object resources. This includes the
|
||||
resources created by the GEM core, which need to be released with
|
||||
:c:func:`drm_gem_object_release()`.
|
||||
drm_gem_object_release().
|
||||
|
||||
GEM Objects Naming
|
||||
------------------
|
||||
@@ -210,13 +208,11 @@ to the GEM object in other standard or driver-specific ioctls. Closing a
|
||||
DRM file handle frees all its GEM handles and dereferences the
|
||||
associated GEM objects.
|
||||
|
||||
To create a handle for a GEM object drivers call
|
||||
:c:func:`drm_gem_handle_create()`. The function takes a pointer
|
||||
to the DRM file and the GEM object and returns a locally unique handle.
|
||||
When the handle is no longer needed drivers delete it with a call to
|
||||
:c:func:`drm_gem_handle_delete()`. Finally the GEM object
|
||||
associated with a handle can be retrieved by a call to
|
||||
:c:func:`drm_gem_object_lookup()`.
|
||||
To create a handle for a GEM object drivers call drm_gem_handle_create(). The
|
||||
function takes a pointer to the DRM file and the GEM object and returns a
|
||||
locally unique handle. When the handle is no longer needed drivers delete it
|
||||
with a call to drm_gem_handle_delete(). Finally the GEM object associated with a
|
||||
handle can be retrieved by a call to drm_gem_object_lookup().
|
||||
|
||||
Handles don't take ownership of GEM objects, they only take a reference
|
||||
to the object that will be dropped when the handle is destroyed. To
|
||||
@@ -258,7 +254,7 @@ The mmap system call can't be used directly to map GEM objects, as they
|
||||
don't have their own file handle. Two alternative methods currently
|
||||
co-exist to map GEM objects to userspace. The first method uses a
|
||||
driver-specific ioctl to perform the mapping operation, calling
|
||||
:c:func:`do_mmap()` under the hood. This is often considered
|
||||
do_mmap() under the hood. This is often considered
|
||||
dubious, seems to be discouraged for new GEM-enabled drivers, and will
|
||||
thus not be described here.
|
||||
|
||||
@@ -267,23 +263,22 @@ The second method uses the mmap system call on the DRM file handle. void
|
||||
offset); DRM identifies the GEM object to be mapped by a fake offset
|
||||
passed through the mmap offset argument. Prior to being mapped, a GEM
|
||||
object must thus be associated with a fake offset. To do so, drivers
|
||||
must call :c:func:`drm_gem_create_mmap_offset()` on the object.
|
||||
must call drm_gem_create_mmap_offset() on the object.
|
||||
|
||||
Once allocated, the fake offset value must be passed to the application
|
||||
in a driver-specific way and can then be used as the mmap offset
|
||||
argument.
|
||||
|
||||
The GEM core provides a helper method :c:func:`drm_gem_mmap()` to
|
||||
The GEM core provides a helper method drm_gem_mmap() to
|
||||
handle object mapping. The method can be set directly as the mmap file
|
||||
operation handler. It will look up the GEM object based on the offset
|
||||
value and set the VMA operations to the :c:type:`struct drm_driver
|
||||
<drm_driver>` gem_vm_ops field. Note that
|
||||
:c:func:`drm_gem_mmap()` doesn't map memory to userspace, but
|
||||
relies on the driver-provided fault handler to map pages individually.
|
||||
<drm_driver>` gem_vm_ops field. Note that drm_gem_mmap() doesn't map memory to
|
||||
userspace, but relies on the driver-provided fault handler to map pages
|
||||
individually.
|
||||
|
||||
To use :c:func:`drm_gem_mmap()`, drivers must fill the struct
|
||||
:c:type:`struct drm_driver <drm_driver>` gem_vm_ops field
|
||||
with a pointer to VM operations.
|
||||
To use drm_gem_mmap(), drivers must fill the struct :c:type:`struct drm_driver
|
||||
<drm_driver>` gem_vm_ops field with a pointer to VM operations.
|
||||
|
||||
The VM operations is a :c:type:`struct vm_operations_struct <vm_operations_struct>`
|
||||
made up of several fields, the more interesting ones being:
|
||||
@@ -298,9 +293,8 @@ made up of several fields, the more interesting ones being:
|
||||
|
||||
|
||||
The open and close operations must update the GEM object reference
|
||||
count. Drivers can use the :c:func:`drm_gem_vm_open()` and
|
||||
:c:func:`drm_gem_vm_close()` helper functions directly as open
|
||||
and close handlers.
|
||||
count. Drivers can use the drm_gem_vm_open() and drm_gem_vm_close() helper
|
||||
functions directly as open and close handlers.
|
||||
|
||||
The fault operation handler is responsible for mapping individual pages
|
||||
to userspace when a page fault occurs. Depending on the memory
|
||||
@@ -312,12 +306,12 @@ Drivers that want to map the GEM object upfront instead of handling page
|
||||
faults can implement their own mmap file operation handler.
|
||||
|
||||
For platforms without MMU the GEM core provides a helper method
|
||||
:c:func:`drm_gem_cma_get_unmapped_area`. The mmap() routines will call
|
||||
this to get a proposed address for the mapping.
|
||||
drm_gem_cma_get_unmapped_area(). The mmap() routines will call this to get a
|
||||
proposed address for the mapping.
|
||||
|
||||
To use :c:func:`drm_gem_cma_get_unmapped_area`, drivers must fill the
|
||||
struct :c:type:`struct file_operations <file_operations>` get_unmapped_area
|
||||
field with a pointer on :c:func:`drm_gem_cma_get_unmapped_area`.
|
||||
To use drm_gem_cma_get_unmapped_area(), drivers must fill the struct
|
||||
:c:type:`struct file_operations <file_operations>` get_unmapped_area field with
|
||||
a pointer on drm_gem_cma_get_unmapped_area().
|
||||
|
||||
More detailed information about get_unmapped_area can be found in
|
||||
Documentation/nommu-mmap.txt
|
||||
|
||||
@@ -254,36 +254,45 @@ Validating changes with IGT
|
||||
There's a collection of tests that aims to cover the whole functionality of
|
||||
DRM drivers and that can be used to check that changes to DRM drivers or the
|
||||
core don't regress existing functionality. This test suite is called IGT and
|
||||
its code can be found in https://cgit.freedesktop.org/drm/igt-gpu-tools/.
|
||||
its code and instructions to build and run can be found in
|
||||
https://gitlab.freedesktop.org/drm/igt-gpu-tools/.
|
||||
|
||||
To build IGT, start by installing its build dependencies. In Debian-based
|
||||
systems::
|
||||
Using VKMS to test DRM API
|
||||
--------------------------
|
||||
|
||||
# apt-get build-dep intel-gpu-tools
|
||||
VKMS is a software-only model of a KMS driver that is useful for testing
|
||||
and for running compositors. VKMS aims to enable a virtual display without
|
||||
the need for a hardware display capability. These characteristics made VKMS
|
||||
a perfect tool for validating the DRM core behavior and also support the
|
||||
compositor developer. VKMS makes it possible to test DRM functions in a
|
||||
virtual machine without display, simplifying the validation of some of the
|
||||
core changes.
|
||||
|
||||
And in Fedora-based systems::
|
||||
To Validate changes in DRM API with VKMS, start setting the kernel: make
|
||||
sure to enable VKMS module; compile the kernel with the VKMS enabled and
|
||||
install it in the target machine. VKMS can be run in a Virtual Machine
|
||||
(QEMU, virtme or similar). It's recommended the use of KVM with the minimum
|
||||
of 1GB of RAM and four cores.
|
||||
|
||||
# dnf builddep intel-gpu-tools
|
||||
It's possible to run the IGT-tests in a VM in two ways:
|
||||
|
||||
Then clone the repository::
|
||||
1. Use IGT inside a VM
|
||||
2. Use IGT from the host machine and write the results in a shared directory.
|
||||
|
||||
$ git clone git://anongit.freedesktop.org/drm/igt-gpu-tools
|
||||
As follow, there is an example of using a VM with a shared directory with
|
||||
the host machine to run igt-tests. As an example it's used virtme::
|
||||
|
||||
Configure the build system and start the build::
|
||||
$ virtme-run --rwdir /path/for/shared_dir --kdir=path/for/kernel/directory --mods=auto
|
||||
|
||||
$ cd igt-gpu-tools && ./autogen.sh && make -j6
|
||||
Run the igt-tests in the guest machine, as example it's ran the 'kms_flip'
|
||||
tests::
|
||||
|
||||
Download the piglit dependency::
|
||||
$ /path/for/igt-gpu-tools/scripts/run-tests.sh -p -s -t "kms_flip.*" -v
|
||||
|
||||
$ ./scripts/run-tests.sh -d
|
||||
|
||||
And run the tests::
|
||||
|
||||
$ ./scripts/run-tests.sh -t kms -t core -s
|
||||
|
||||
run-tests.sh is a wrapper around piglit that will execute the tests matching
|
||||
the -t options. A report in HTML format will be available in
|
||||
./results/html/index.html. Results can be compared with piglit.
|
||||
In this example, instead of build the igt_runner, Piglit is used
|
||||
(-p option); it's created html summary of the tests results and it's saved
|
||||
in the folder "igt-gpu-tools/results"; it's executed only the igt-tests
|
||||
matching the -t option.
|
||||
|
||||
Display CRC Support
|
||||
-------------------
|
||||
|
||||
@@ -466,9 +466,6 @@ GuC-based command submission
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
|
||||
:doc: GuC-based command submission
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
|
||||
:internal:
|
||||
|
||||
HuC
|
||||
---
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/gt/uc/intel_huc.c
|
||||
|
||||
@@ -142,14 +142,14 @@ Contact: Daniel Vetter, respective driver maintainers
|
||||
|
||||
Level: Advanced
|
||||
|
||||
Convert instances of dev_info/dev_err/dev_warn to their DRM_DEV_* equivalent
|
||||
----------------------------------------------------------------------------
|
||||
Convert logging to drm_* functions with drm_device paramater
|
||||
------------------------------------------------------------
|
||||
|
||||
For drivers which could have multiple instances, it is necessary to
|
||||
differentiate between which is which in the logs. Since DRM_INFO/WARN/ERROR
|
||||
don't do this, drivers used dev_info/warn/err to make this differentiation. We
|
||||
now have DRM_DEV_* variants of the drm print macros, so we can start to convert
|
||||
those drivers back to using drm-formwatted specific log messages.
|
||||
now have drm_* variants of the drm print functions, so we can start to convert
|
||||
those drivers back to using drm-formatted specific log messages.
|
||||
|
||||
Before you start this conversion please contact the relevant maintainers to make
|
||||
sure your work will be merged - not everyone agrees that the DRM dmesg macros
|
||||
@@ -171,26 +171,43 @@ Contact: Maintainer of the driver you plan to convert
|
||||
|
||||
Level: Intermediate
|
||||
|
||||
Convert drivers to use drm_fb_helper_fbdev_setup/teardown()
|
||||
-----------------------------------------------------------
|
||||
Convert drivers to use drm_fbdev_generic_setup()
|
||||
------------------------------------------------
|
||||
|
||||
Most drivers can use drm_fb_helper_fbdev_setup() except maybe:
|
||||
|
||||
- amdgpu which has special logic to decide whether to call
|
||||
drm_helper_disable_unused_functions()
|
||||
|
||||
- armada which isn't atomic and doesn't call
|
||||
drm_helper_disable_unused_functions()
|
||||
|
||||
- i915 which calls drm_fb_helper_initial_config() in a worker
|
||||
|
||||
Drivers that use drm_framebuffer_remove() to clean up the fbdev framebuffer can
|
||||
probably use drm_fb_helper_fbdev_teardown().
|
||||
Most drivers can use drm_fbdev_generic_setup(). Driver have to implement
|
||||
atomic modesetting and GEM vmap support. Current generic fbdev emulation
|
||||
expects the framebuffer in system memory (or system-like memory).
|
||||
|
||||
Contact: Maintainer of the driver you plan to convert
|
||||
|
||||
Level: Intermediate
|
||||
|
||||
drm_framebuffer_funcs and drm_mode_config_funcs.fb_create cleanup
|
||||
-----------------------------------------------------------------
|
||||
|
||||
A lot more drivers could be switched over to the drm_gem_framebuffer helpers.
|
||||
Various hold-ups:
|
||||
|
||||
- Need to switch over to the generic dirty tracking code using
|
||||
drm_atomic_helper_dirtyfb first (e.g. qxl).
|
||||
|
||||
- Need to switch to drm_fbdev_generic_setup(), otherwise a lot of the custom fb
|
||||
setup code can't be deleted.
|
||||
|
||||
- Many drivers wrap drm_gem_fb_create() only to check for valid formats. For
|
||||
atomic drivers we could check for valid formats by calling
|
||||
drm_plane_check_pixel_format() against all planes, and pass if any plane
|
||||
supports the format. For non-atomic that's not possible since like the format
|
||||
list for the primary plane is fake and we'd therefor reject valid formats.
|
||||
|
||||
- Many drivers subclass drm_framebuffer, we'd need a embedding compatible
|
||||
version of the varios drm_gem_fb_create functions. Maybe called
|
||||
drm_gem_fb_create/_with_dirty/_with_funcs as needed.
|
||||
|
||||
Contact: Daniel Vetter
|
||||
|
||||
Level: Intermediate
|
||||
|
||||
Clean up mmap forwarding
|
||||
------------------------
|
||||
|
||||
@@ -328,8 +345,8 @@ drm_fb_helper tasks
|
||||
these igt tests need to be fixed: kms_fbcon_fbt@psr and
|
||||
kms_fbcon_fbt@psr-suspend.
|
||||
|
||||
- The max connector argument for drm_fb_helper_init() and
|
||||
drm_fb_helper_fbdev_setup() isn't used anymore and can be removed.
|
||||
- The max connector argument for drm_fb_helper_init() isn't used anymore and
|
||||
can be removed.
|
||||
|
||||
- The helper doesn't keep an array of connectors anymore so these can be
|
||||
removed: drm_fb_helper_single_add_all_connectors(),
|
||||
@@ -351,6 +368,23 @@ connector register/unregister fixes
|
||||
|
||||
Level: Intermediate
|
||||
|
||||
Remove load/unload callbacks from all non-DRIVER_LEGACY drivers
|
||||
---------------------------------------------------------------
|
||||
|
||||
The load/unload callbacks in struct &drm_driver are very much midlayers, plus
|
||||
for historical reasons they get the ordering wrong (and we can't fix that)
|
||||
between setting up the &drm_driver structure and calling drm_dev_register().
|
||||
|
||||
- Rework drivers to no longer use the load/unload callbacks, directly coding the
|
||||
load/unload sequence into the driver's probe function.
|
||||
|
||||
- Once all non-DRIVER_LEGACY drivers are converted, disallow the load/unload
|
||||
callbacks for all modern drivers.
|
||||
|
||||
Contact: Daniel Vetter
|
||||
|
||||
Level: Intermediate
|
||||
|
||||
Core refactorings
|
||||
=================
|
||||
|
||||
|
||||
31
MAINTAINERS
31
MAINTAINERS
@@ -5025,6 +5025,24 @@ F: Documentation/driver-api/dma-buf.rst
|
||||
K: dma_(buf|fence|resv)
|
||||
T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
|
||||
DMA-BUF HEAPS FRAMEWORK
|
||||
M: Sumit Semwal <sumit.semwal@linaro.org>
|
||||
R: Andrew F. Davis <afd@ti.com>
|
||||
R: Benjamin Gaignard <benjamin.gaignard@linaro.org>
|
||||
R: Liam Mark <lmark@codeaurora.org>
|
||||
R: Laura Abbott <labbott@redhat.com>
|
||||
R: Brian Starkey <Brian.Starkey@arm.com>
|
||||
R: John Stultz <john.stultz@linaro.org>
|
||||
S: Maintained
|
||||
L: linux-media@vger.kernel.org
|
||||
L: dri-devel@lists.freedesktop.org
|
||||
L: linaro-mm-sig@lists.linaro.org (moderated for non-subscribers)
|
||||
F: include/uapi/linux/dma-heap.h
|
||||
F: include/linux/dma-heap.h
|
||||
F: drivers/dma-buf/dma-heap.c
|
||||
F: drivers/dma-buf/heaps/*
|
||||
T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
|
||||
DMA GENERIC OFFLOAD ENGINE SUBSYSTEM
|
||||
M: Vinod Koul <vkoul@kernel.org>
|
||||
L: dmaengine@vger.kernel.org
|
||||
@@ -5230,6 +5248,12 @@ T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
S: Maintained
|
||||
F: drivers/gpu/drm/bochs/
|
||||
|
||||
DRM DRIVER FOR BOE HIMAX8279D PANELS
|
||||
M: Jerry Han <hanxu5@huaqin.corp-partner.google.com>
|
||||
S: Maintained
|
||||
F: drivers/gpu/drm/panel/panel-boe-himax8279d.c
|
||||
F: Documentation/devicetree/bindings/display/panel/boe,himax8279d.txt
|
||||
|
||||
DRM DRIVER FOR FARADAY TVE200 TV ENCODER
|
||||
M: Linus Walleij <linus.walleij@linaro.org>
|
||||
T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
@@ -5385,6 +5409,12 @@ S: Maintained
|
||||
F: drivers/gpu/drm/tiny/st7735r.c
|
||||
F: Documentation/devicetree/bindings/display/sitronix,st7735r.txt
|
||||
|
||||
DRM DRIVER FOR SONY ACX424AKP PANELS
|
||||
M: Linus Walleij <linus.walleij@linaro.org>
|
||||
T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
S: Maintained
|
||||
F: drivers/gpu/drm/panel/panel-sony-acx424akp.c
|
||||
|
||||
DRM DRIVER FOR ST-ERICSSON MCDE
|
||||
M: Linus Walleij <linus.walleij@linaro.org>
|
||||
T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
@@ -5457,7 +5487,6 @@ F: include/linux/vga*
|
||||
DRM DRIVERS AND MISC GPU PATCHES
|
||||
M: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
|
||||
M: Maxime Ripard <mripard@kernel.org>
|
||||
M: Sean Paul <sean@poorly.run>
|
||||
W: https://01.org/linuxgraphics/gfx-docs/maintainer-tools/drm-misc.html
|
||||
S: Maintained
|
||||
T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
|
||||
@@ -6,21 +6,31 @@
|
||||
* Author: Sathyanarayanan Kuppuswamy <sathyanarayanan.kuppuswamy@intel.com>
|
||||
*/
|
||||
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/platform_data/tc35876x.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <asm/intel-mid.h>
|
||||
|
||||
static struct gpiod_lookup_table tc35876x_gpio_table = {
|
||||
.dev_id = "i2c_disp_brig",
|
||||
.table = {
|
||||
GPIO_LOOKUP("0000:00:0c.0", -1, "bridge-reset", GPIO_ACTIVE_HIGH),
|
||||
GPIO_LOOKUP("0000:00:0c.0", -1, "bl-en", GPIO_ACTIVE_HIGH),
|
||||
GPIO_LOOKUP("0000:00:0c.0", -1, "vadd", GPIO_ACTIVE_HIGH),
|
||||
{ },
|
||||
},
|
||||
};
|
||||
|
||||
/*tc35876x DSI_LVDS bridge chip and panel platform data*/
|
||||
static void *tc35876x_platform_data(void *data)
|
||||
{
|
||||
static struct tc35876x_platform_data pdata;
|
||||
struct gpiod_lookup_table *table = &tc35876x_gpio_table;
|
||||
struct gpiod_lookup *lookup = table->table;
|
||||
|
||||
/* gpio pins set to -1 will not be used by the driver */
|
||||
pdata.gpio_bridge_reset = get_gpio_by_name("LCMB_RXEN");
|
||||
pdata.gpio_panel_bl_en = get_gpio_by_name("6S6P_BL_EN");
|
||||
pdata.gpio_panel_vadd = get_gpio_by_name("EN_VREG_LCD_V3P3");
|
||||
lookup[0].chip_hwnum = get_gpio_by_name("LCMB_RXEN");
|
||||
lookup[1].chip_hwnum = get_gpio_by_name("6S6P_BL_EN");
|
||||
lookup[2].chip_hwnum = get_gpio_by_name("EN_VREG_LCD_V3P3");
|
||||
gpiod_add_lookup_table(table);
|
||||
|
||||
return &pdata;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const struct devs_id tc35876x_dev_id __initconst = {
|
||||
|
||||
@@ -69,10 +69,6 @@ ACPI_MODULE_NAME("acpi_lpss");
|
||||
#define LPSS_SAVE_CTX BIT(4)
|
||||
#define LPSS_NO_D3_DELAY BIT(5)
|
||||
|
||||
/* Crystal Cove PMIC shares same ACPI ID between different platforms */
|
||||
#define BYT_CRC_HRV 2
|
||||
#define CHT_CRC_HRV 3
|
||||
|
||||
struct lpss_private_data;
|
||||
|
||||
struct lpss_device_desc {
|
||||
@@ -158,7 +154,7 @@ static void lpss_deassert_reset(struct lpss_private_data *pdata)
|
||||
*/
|
||||
static struct pwm_lookup byt_pwm_lookup[] = {
|
||||
PWM_LOOKUP_WITH_MODULE("80860F09:00", 0, "0000:00:02.0",
|
||||
"pwm_backlight", 0, PWM_POLARITY_NORMAL,
|
||||
"pwm_soc_backlight", 0, PWM_POLARITY_NORMAL,
|
||||
"pwm-lpss-platform"),
|
||||
};
|
||||
|
||||
@@ -170,8 +166,7 @@ static void byt_pwm_setup(struct lpss_private_data *pdata)
|
||||
if (!adev->pnp.unique_id || strcmp(adev->pnp.unique_id, "1"))
|
||||
return;
|
||||
|
||||
if (!acpi_dev_present("INT33FD", NULL, BYT_CRC_HRV))
|
||||
pwm_add_table(byt_pwm_lookup, ARRAY_SIZE(byt_pwm_lookup));
|
||||
pwm_add_table(byt_pwm_lookup, ARRAY_SIZE(byt_pwm_lookup));
|
||||
}
|
||||
|
||||
#define LPSS_I2C_ENABLE 0x6c
|
||||
@@ -204,7 +199,7 @@ static void byt_i2c_setup(struct lpss_private_data *pdata)
|
||||
/* BSW PWM used for backlight control by the i915 driver */
|
||||
static struct pwm_lookup bsw_pwm_lookup[] = {
|
||||
PWM_LOOKUP_WITH_MODULE("80862288:00", 0, "0000:00:02.0",
|
||||
"pwm_backlight", 0, PWM_POLARITY_NORMAL,
|
||||
"pwm_soc_backlight", 0, PWM_POLARITY_NORMAL,
|
||||
"pwm-lpss-platform"),
|
||||
};
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ static int cfag12864bfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
|
||||
return vm_map_pages_zero(vma, &pages, 1);
|
||||
}
|
||||
|
||||
static struct fb_ops cfag12864bfb_ops = {
|
||||
static const struct fb_ops cfag12864bfb_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.fb_read = fb_sys_read,
|
||||
.fb_write = fb_sys_write,
|
||||
|
||||
@@ -228,7 +228,7 @@ static int ht16k33_mmap(struct fb_info *info, struct vm_area_struct *vma)
|
||||
return vm_map_pages_zero(vma, &pages, 1);
|
||||
}
|
||||
|
||||
static struct fb_ops ht16k33_fb_ops = {
|
||||
static const struct fb_ops ht16k33_fb_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.fb_read = fb_sys_read,
|
||||
.fb_write = fb_sys_write,
|
||||
|
||||
@@ -44,4 +44,15 @@ config DMABUF_SELFTESTS
|
||||
default n
|
||||
depends on DMA_SHARED_BUFFER
|
||||
|
||||
menuconfig DMABUF_HEAPS
|
||||
bool "DMA-BUF Userland Memory Heaps"
|
||||
select DMA_SHARED_BUFFER
|
||||
help
|
||||
Choose this option to enable the DMA-BUF userland memory heaps.
|
||||
This options creates per heap chardevs in /dev/dma_heap/ which
|
||||
allows userspace to allocate dma-bufs that can be shared
|
||||
between drivers.
|
||||
|
||||
source "drivers/dma-buf/heaps/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
obj-y := dma-buf.o dma-fence.o dma-fence-array.o dma-fence-chain.o \
|
||||
dma-resv.o seqno-fence.o
|
||||
obj-$(CONFIG_DMABUF_HEAPS) += dma-heap.o
|
||||
obj-$(CONFIG_DMABUF_HEAPS) += heaps/
|
||||
obj-$(CONFIG_SYNC_FILE) += sync_file.o
|
||||
obj-$(CONFIG_SW_SYNC) += sw_sync.o sync_debug.o
|
||||
obj-$(CONFIG_UDMABUF) += udmabuf.o
|
||||
|
||||
@@ -878,29 +878,9 @@ EXPORT_SYMBOL_GPL(dma_buf_unmap_attachment);
|
||||
* with calls to dma_buf_begin_cpu_access() and dma_buf_end_cpu_access()
|
||||
* access.
|
||||
*
|
||||
* To support dma_buf objects residing in highmem cpu access is page-based
|
||||
* using an api similar to kmap. Accessing a dma_buf is done in aligned chunks
|
||||
* of PAGE_SIZE size. Before accessing a chunk it needs to be mapped, which
|
||||
* returns a pointer in kernel virtual address space. Afterwards the chunk
|
||||
* needs to be unmapped again. There is no limit on how often a given chunk
|
||||
* can be mapped and unmapped, i.e. the importer does not need to call
|
||||
* begin_cpu_access again before mapping the same chunk again.
|
||||
*
|
||||
* Interfaces::
|
||||
* void \*dma_buf_kmap(struct dma_buf \*, unsigned long);
|
||||
* void dma_buf_kunmap(struct dma_buf \*, unsigned long, void \*);
|
||||
*
|
||||
* Implementing the functions is optional for exporters and for importers all
|
||||
* the restrictions of using kmap apply.
|
||||
*
|
||||
* dma_buf kmap calls outside of the range specified in begin_cpu_access are
|
||||
* undefined. If the range is not PAGE_SIZE aligned, kmap needs to succeed on
|
||||
* the partial chunks at the beginning and end but may return stale or bogus
|
||||
* data outside of the range (in these partial chunks).
|
||||
*
|
||||
* For some cases the overhead of kmap can be too high, a vmap interface
|
||||
* is introduced. This interface should be used very carefully, as vmalloc
|
||||
* space is a limited resources on many architectures.
|
||||
* Since for most kernel internal dma-buf accesses need the entire buffer, a
|
||||
* vmap interface is introduced. Note that on very old 32-bit architectures
|
||||
* vmalloc space might be limited and result in vmap calls failing.
|
||||
*
|
||||
* Interfaces::
|
||||
* void \*dma_buf_vmap(struct dma_buf \*dmabuf)
|
||||
@@ -1090,44 +1070,6 @@ int dma_buf_end_cpu_access_partial(struct dma_buf *dmabuf,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dma_buf_end_cpu_access_partial);
|
||||
|
||||
/**
|
||||
* dma_buf_kmap - Map a page of the buffer object into kernel address space. The
|
||||
* same restrictions as for kmap and friends apply.
|
||||
* @dmabuf: [in] buffer to map page from.
|
||||
* @page_num: [in] page in PAGE_SIZE units to map.
|
||||
*
|
||||
* This call must always succeed, any necessary preparations that might fail
|
||||
* need to be done in begin_cpu_access.
|
||||
*/
|
||||
void *dma_buf_kmap(struct dma_buf *dmabuf, unsigned long page_num)
|
||||
{
|
||||
WARN_ON(!dmabuf);
|
||||
|
||||
if (!dmabuf->ops->map)
|
||||
return NULL;
|
||||
return dmabuf->ops->map(dmabuf, page_num);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dma_buf_kmap);
|
||||
|
||||
/**
|
||||
* dma_buf_kunmap - Unmap a page obtained by dma_buf_kmap.
|
||||
* @dmabuf: [in] buffer to unmap page from.
|
||||
* @page_num: [in] page in PAGE_SIZE units to unmap.
|
||||
* @vaddr: [in] kernel space pointer obtained from dma_buf_kmap.
|
||||
*
|
||||
* This call must always succeed.
|
||||
*/
|
||||
void dma_buf_kunmap(struct dma_buf *dmabuf, unsigned long page_num,
|
||||
void *vaddr)
|
||||
{
|
||||
WARN_ON(!dmabuf);
|
||||
|
||||
if (dmabuf->ops->unmap)
|
||||
dmabuf->ops->unmap(dmabuf, page_num, vaddr);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dma_buf_kunmap);
|
||||
|
||||
|
||||
/**
|
||||
* dma_buf_mmap - Setup up a userspace mmap with the given vma
|
||||
* @dmabuf: [in] buffer that should back the vma
|
||||
|
||||
298
drivers/dma-buf/dma-heap.c
Normal file
298
drivers/dma-buf/dma-heap.c
Normal file
@@ -0,0 +1,298 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Framework for userspace DMA-BUF allocations
|
||||
*
|
||||
* Copyright (C) 2011 Google, Inc.
|
||||
* Copyright (C) 2019 Linaro Ltd.
|
||||
*/
|
||||
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/dma-buf.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/xarray.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/dma-heap.h>
|
||||
#include <uapi/linux/dma-heap.h>
|
||||
|
||||
#define DEVNAME "dma_heap"
|
||||
|
||||
#define NUM_HEAP_MINORS 128
|
||||
|
||||
/**
|
||||
* struct dma_heap - represents a dmabuf heap in the system
|
||||
* @name: used for debugging/device-node name
|
||||
* @ops: ops struct for this heap
|
||||
* @heap_devt heap device node
|
||||
* @list list head connecting to list of heaps
|
||||
* @heap_cdev heap char device
|
||||
*
|
||||
* Represents a heap of memory from which buffers can be made.
|
||||
*/
|
||||
struct dma_heap {
|
||||
const char *name;
|
||||
const struct dma_heap_ops *ops;
|
||||
void *priv;
|
||||
dev_t heap_devt;
|
||||
struct list_head list;
|
||||
struct cdev heap_cdev;
|
||||
};
|
||||
|
||||
static LIST_HEAD(heap_list);
|
||||
static DEFINE_MUTEX(heap_list_lock);
|
||||
static dev_t dma_heap_devt;
|
||||
static struct class *dma_heap_class;
|
||||
static DEFINE_XARRAY_ALLOC(dma_heap_minors);
|
||||
|
||||
static int dma_heap_buffer_alloc(struct dma_heap *heap, size_t len,
|
||||
unsigned int fd_flags,
|
||||
unsigned int heap_flags)
|
||||
{
|
||||
/*
|
||||
* Allocations from all heaps have to begin
|
||||
* and end on page boundaries.
|
||||
*/
|
||||
len = PAGE_ALIGN(len);
|
||||
if (!len)
|
||||
return -EINVAL;
|
||||
|
||||
return heap->ops->allocate(heap, len, fd_flags, heap_flags);
|
||||
}
|
||||
|
||||
static int dma_heap_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct dma_heap *heap;
|
||||
|
||||
heap = xa_load(&dma_heap_minors, iminor(inode));
|
||||
if (!heap) {
|
||||
pr_err("dma_heap: minor %d unknown.\n", iminor(inode));
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* instance data as context */
|
||||
file->private_data = heap;
|
||||
nonseekable_open(inode, file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long dma_heap_ioctl_allocate(struct file *file, void *data)
|
||||
{
|
||||
struct dma_heap_allocation_data *heap_allocation = data;
|
||||
struct dma_heap *heap = file->private_data;
|
||||
int fd;
|
||||
|
||||
if (heap_allocation->fd)
|
||||
return -EINVAL;
|
||||
|
||||
if (heap_allocation->fd_flags & ~DMA_HEAP_VALID_FD_FLAGS)
|
||||
return -EINVAL;
|
||||
|
||||
if (heap_allocation->heap_flags & ~DMA_HEAP_VALID_HEAP_FLAGS)
|
||||
return -EINVAL;
|
||||
|
||||
fd = dma_heap_buffer_alloc(heap, heap_allocation->len,
|
||||
heap_allocation->fd_flags,
|
||||
heap_allocation->heap_flags);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
heap_allocation->fd = fd;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int dma_heap_ioctl_cmds[] = {
|
||||
DMA_HEAP_IOCTL_ALLOC,
|
||||
};
|
||||
|
||||
static long dma_heap_ioctl(struct file *file, unsigned int ucmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
char stack_kdata[128];
|
||||
char *kdata = stack_kdata;
|
||||
unsigned int kcmd;
|
||||
unsigned int in_size, out_size, drv_size, ksize;
|
||||
int nr = _IOC_NR(ucmd);
|
||||
int ret = 0;
|
||||
|
||||
if (nr >= ARRAY_SIZE(dma_heap_ioctl_cmds))
|
||||
return -EINVAL;
|
||||
|
||||
/* Get the kernel ioctl cmd that matches */
|
||||
kcmd = dma_heap_ioctl_cmds[nr];
|
||||
|
||||
/* Figure out the delta between user cmd size and kernel cmd size */
|
||||
drv_size = _IOC_SIZE(kcmd);
|
||||
out_size = _IOC_SIZE(ucmd);
|
||||
in_size = out_size;
|
||||
if ((ucmd & kcmd & IOC_IN) == 0)
|
||||
in_size = 0;
|
||||
if ((ucmd & kcmd & IOC_OUT) == 0)
|
||||
out_size = 0;
|
||||
ksize = max(max(in_size, out_size), drv_size);
|
||||
|
||||
/* If necessary, allocate buffer for ioctl argument */
|
||||
if (ksize > sizeof(stack_kdata)) {
|
||||
kdata = kmalloc(ksize, GFP_KERNEL);
|
||||
if (!kdata)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (copy_from_user(kdata, (void __user *)arg, in_size) != 0) {
|
||||
ret = -EFAULT;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* zero out any difference between the kernel/user structure size */
|
||||
if (ksize > in_size)
|
||||
memset(kdata + in_size, 0, ksize - in_size);
|
||||
|
||||
switch (kcmd) {
|
||||
case DMA_HEAP_IOCTL_ALLOC:
|
||||
ret = dma_heap_ioctl_allocate(file, kdata);
|
||||
break;
|
||||
default:
|
||||
ret = -ENOTTY;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (copy_to_user((void __user *)arg, kdata, out_size) != 0)
|
||||
ret = -EFAULT;
|
||||
err:
|
||||
if (kdata != stack_kdata)
|
||||
kfree(kdata);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations dma_heap_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = dma_heap_open,
|
||||
.unlocked_ioctl = dma_heap_ioctl,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = dma_heap_ioctl,
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* dma_heap_get_drvdata() - get per-subdriver data for the heap
|
||||
* @heap: DMA-Heap to retrieve private data for
|
||||
*
|
||||
* Returns:
|
||||
* The per-subdriver data for the heap.
|
||||
*/
|
||||
void *dma_heap_get_drvdata(struct dma_heap *heap)
|
||||
{
|
||||
return heap->priv;
|
||||
}
|
||||
|
||||
struct dma_heap *dma_heap_add(const struct dma_heap_export_info *exp_info)
|
||||
{
|
||||
struct dma_heap *heap, *h, *err_ret;
|
||||
struct device *dev_ret;
|
||||
unsigned int minor;
|
||||
int ret;
|
||||
|
||||
if (!exp_info->name || !strcmp(exp_info->name, "")) {
|
||||
pr_err("dma_heap: Cannot add heap without a name\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
if (!exp_info->ops || !exp_info->ops->allocate) {
|
||||
pr_err("dma_heap: Cannot add heap with invalid ops struct\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
/* check the name is unique */
|
||||
mutex_lock(&heap_list_lock);
|
||||
list_for_each_entry(h, &heap_list, list) {
|
||||
if (!strcmp(h->name, exp_info->name)) {
|
||||
mutex_unlock(&heap_list_lock);
|
||||
pr_err("dma_heap: Already registered heap named %s\n",
|
||||
exp_info->name);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&heap_list_lock);
|
||||
|
||||
heap = kzalloc(sizeof(*heap), GFP_KERNEL);
|
||||
if (!heap)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
heap->name = exp_info->name;
|
||||
heap->ops = exp_info->ops;
|
||||
heap->priv = exp_info->priv;
|
||||
|
||||
/* Find unused minor number */
|
||||
ret = xa_alloc(&dma_heap_minors, &minor, heap,
|
||||
XA_LIMIT(0, NUM_HEAP_MINORS - 1), GFP_KERNEL);
|
||||
if (ret < 0) {
|
||||
pr_err("dma_heap: Unable to get minor number for heap\n");
|
||||
err_ret = ERR_PTR(ret);
|
||||
goto err0;
|
||||
}
|
||||
|
||||
/* Create device */
|
||||
heap->heap_devt = MKDEV(MAJOR(dma_heap_devt), minor);
|
||||
|
||||
cdev_init(&heap->heap_cdev, &dma_heap_fops);
|
||||
ret = cdev_add(&heap->heap_cdev, heap->heap_devt, 1);
|
||||
if (ret < 0) {
|
||||
pr_err("dma_heap: Unable to add char device\n");
|
||||
err_ret = ERR_PTR(ret);
|
||||
goto err1;
|
||||
}
|
||||
|
||||
dev_ret = device_create(dma_heap_class,
|
||||
NULL,
|
||||
heap->heap_devt,
|
||||
NULL,
|
||||
heap->name);
|
||||
if (IS_ERR(dev_ret)) {
|
||||
pr_err("dma_heap: Unable to create device\n");
|
||||
err_ret = ERR_CAST(dev_ret);
|
||||
goto err2;
|
||||
}
|
||||
/* Add heap to the list */
|
||||
mutex_lock(&heap_list_lock);
|
||||
list_add(&heap->list, &heap_list);
|
||||
mutex_unlock(&heap_list_lock);
|
||||
|
||||
return heap;
|
||||
|
||||
err2:
|
||||
cdev_del(&heap->heap_cdev);
|
||||
err1:
|
||||
xa_erase(&dma_heap_minors, minor);
|
||||
err0:
|
||||
kfree(heap);
|
||||
return err_ret;
|
||||
}
|
||||
|
||||
static char *dma_heap_devnode(struct device *dev, umode_t *mode)
|
||||
{
|
||||
return kasprintf(GFP_KERNEL, "dma_heap/%s", dev_name(dev));
|
||||
}
|
||||
|
||||
static int dma_heap_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = alloc_chrdev_region(&dma_heap_devt, 0, NUM_HEAP_MINORS, DEVNAME);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dma_heap_class = class_create(THIS_MODULE, DEVNAME);
|
||||
if (IS_ERR(dma_heap_class)) {
|
||||
unregister_chrdev_region(dma_heap_devt, NUM_HEAP_MINORS);
|
||||
return PTR_ERR(dma_heap_class);
|
||||
}
|
||||
dma_heap_class->devnode = dma_heap_devnode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
subsys_initcall(dma_heap_init);
|
||||
@@ -34,6 +34,7 @@
|
||||
|
||||
#include <linux/dma-resv.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/sched/mm.h>
|
||||
|
||||
/**
|
||||
* DOC: Reservation Object Overview
|
||||
@@ -95,6 +96,37 @@ static void dma_resv_list_free(struct dma_resv_list *list)
|
||||
kfree_rcu(list, rcu);
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_LOCKDEP)
|
||||
static int __init dma_resv_lockdep(void)
|
||||
{
|
||||
struct mm_struct *mm = mm_alloc();
|
||||
struct ww_acquire_ctx ctx;
|
||||
struct dma_resv obj;
|
||||
int ret;
|
||||
|
||||
if (!mm)
|
||||
return -ENOMEM;
|
||||
|
||||
dma_resv_init(&obj);
|
||||
|
||||
down_read(&mm->mmap_sem);
|
||||
ww_acquire_init(&ctx, &reservation_ww_class);
|
||||
ret = dma_resv_lock(&obj, &ctx);
|
||||
if (ret == -EDEADLK)
|
||||
dma_resv_lock_slow(&obj, &ctx);
|
||||
fs_reclaim_acquire(GFP_KERNEL);
|
||||
fs_reclaim_release(GFP_KERNEL);
|
||||
ww_mutex_unlock(&obj.lock);
|
||||
ww_acquire_fini(&ctx);
|
||||
up_read(&mm->mmap_sem);
|
||||
|
||||
mmput(mm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
subsys_initcall(dma_resv_lockdep);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* dma_resv_init - initialize a reservation object
|
||||
* @obj: the reservation object
|
||||
|
||||
14
drivers/dma-buf/heaps/Kconfig
Normal file
14
drivers/dma-buf/heaps/Kconfig
Normal file
@@ -0,0 +1,14 @@
|
||||
config DMABUF_HEAPS_SYSTEM
|
||||
bool "DMA-BUF System Heap"
|
||||
depends on DMABUF_HEAPS
|
||||
help
|
||||
Choose this option to enable the system dmabuf heap. The system heap
|
||||
is backed by pages from the buddy allocator. If in doubt, say Y.
|
||||
|
||||
config DMABUF_HEAPS_CMA
|
||||
bool "DMA-BUF CMA Heap"
|
||||
depends on DMABUF_HEAPS && DMA_CMA
|
||||
help
|
||||
Choose this option to enable dma-buf CMA heap. This heap is backed
|
||||
by the Contiguous Memory Allocator (CMA). If your system has these
|
||||
regions, you should say Y here.
|
||||
4
drivers/dma-buf/heaps/Makefile
Normal file
4
drivers/dma-buf/heaps/Makefile
Normal file
@@ -0,0 +1,4 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
obj-y += heap-helpers.o
|
||||
obj-$(CONFIG_DMABUF_HEAPS_SYSTEM) += system_heap.o
|
||||
obj-$(CONFIG_DMABUF_HEAPS_CMA) += cma_heap.o
|
||||
177
drivers/dma-buf/heaps/cma_heap.c
Normal file
177
drivers/dma-buf/heaps/cma_heap.c
Normal file
@@ -0,0 +1,177 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* DMABUF CMA heap exporter
|
||||
*
|
||||
* Copyright (C) 2012, 2019 Linaro Ltd.
|
||||
* Author: <benjamin.gaignard@linaro.org> for ST-Ericsson.
|
||||
*/
|
||||
|
||||
#include <linux/cma.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/dma-buf.h>
|
||||
#include <linux/dma-heap.h>
|
||||
#include <linux/dma-contiguous.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/sched/signal.h>
|
||||
|
||||
#include "heap-helpers.h"
|
||||
|
||||
struct cma_heap {
|
||||
struct dma_heap *heap;
|
||||
struct cma *cma;
|
||||
};
|
||||
|
||||
static void cma_heap_free(struct heap_helper_buffer *buffer)
|
||||
{
|
||||
struct cma_heap *cma_heap = dma_heap_get_drvdata(buffer->heap);
|
||||
unsigned long nr_pages = buffer->pagecount;
|
||||
struct page *cma_pages = buffer->priv_virt;
|
||||
|
||||
/* free page list */
|
||||
kfree(buffer->pages);
|
||||
/* release memory */
|
||||
cma_release(cma_heap->cma, cma_pages, nr_pages);
|
||||
kfree(buffer);
|
||||
}
|
||||
|
||||
/* dmabuf heap CMA operations functions */
|
||||
static int cma_heap_allocate(struct dma_heap *heap,
|
||||
unsigned long len,
|
||||
unsigned long fd_flags,
|
||||
unsigned long heap_flags)
|
||||
{
|
||||
struct cma_heap *cma_heap = dma_heap_get_drvdata(heap);
|
||||
struct heap_helper_buffer *helper_buffer;
|
||||
struct page *cma_pages;
|
||||
size_t size = PAGE_ALIGN(len);
|
||||
unsigned long nr_pages = size >> PAGE_SHIFT;
|
||||
unsigned long align = get_order(size);
|
||||
struct dma_buf *dmabuf;
|
||||
int ret = -ENOMEM;
|
||||
pgoff_t pg;
|
||||
|
||||
if (align > CONFIG_CMA_ALIGNMENT)
|
||||
align = CONFIG_CMA_ALIGNMENT;
|
||||
|
||||
helper_buffer = kzalloc(sizeof(*helper_buffer), GFP_KERNEL);
|
||||
if (!helper_buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
init_heap_helper_buffer(helper_buffer, cma_heap_free);
|
||||
helper_buffer->heap = heap;
|
||||
helper_buffer->size = len;
|
||||
|
||||
cma_pages = cma_alloc(cma_heap->cma, nr_pages, align, false);
|
||||
if (!cma_pages)
|
||||
goto free_buf;
|
||||
|
||||
if (PageHighMem(cma_pages)) {
|
||||
unsigned long nr_clear_pages = nr_pages;
|
||||
struct page *page = cma_pages;
|
||||
|
||||
while (nr_clear_pages > 0) {
|
||||
void *vaddr = kmap_atomic(page);
|
||||
|
||||
memset(vaddr, 0, PAGE_SIZE);
|
||||
kunmap_atomic(vaddr);
|
||||
/*
|
||||
* Avoid wasting time zeroing memory if the process
|
||||
* has been killed by by SIGKILL
|
||||
*/
|
||||
if (fatal_signal_pending(current))
|
||||
goto free_cma;
|
||||
|
||||
page++;
|
||||
nr_clear_pages--;
|
||||
}
|
||||
} else {
|
||||
memset(page_address(cma_pages), 0, size);
|
||||
}
|
||||
|
||||
helper_buffer->pagecount = nr_pages;
|
||||
helper_buffer->pages = kmalloc_array(helper_buffer->pagecount,
|
||||
sizeof(*helper_buffer->pages),
|
||||
GFP_KERNEL);
|
||||
if (!helper_buffer->pages) {
|
||||
ret = -ENOMEM;
|
||||
goto free_cma;
|
||||
}
|
||||
|
||||
for (pg = 0; pg < helper_buffer->pagecount; pg++)
|
||||
helper_buffer->pages[pg] = &cma_pages[pg];
|
||||
|
||||
/* create the dmabuf */
|
||||
dmabuf = heap_helper_export_dmabuf(helper_buffer, fd_flags);
|
||||
if (IS_ERR(dmabuf)) {
|
||||
ret = PTR_ERR(dmabuf);
|
||||
goto free_pages;
|
||||
}
|
||||
|
||||
helper_buffer->dmabuf = dmabuf;
|
||||
helper_buffer->priv_virt = cma_pages;
|
||||
|
||||
ret = dma_buf_fd(dmabuf, fd_flags);
|
||||
if (ret < 0) {
|
||||
dma_buf_put(dmabuf);
|
||||
/* just return, as put will call release and that will free */
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
free_pages:
|
||||
kfree(helper_buffer->pages);
|
||||
free_cma:
|
||||
cma_release(cma_heap->cma, cma_pages, nr_pages);
|
||||
free_buf:
|
||||
kfree(helper_buffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct dma_heap_ops cma_heap_ops = {
|
||||
.allocate = cma_heap_allocate,
|
||||
};
|
||||
|
||||
static int __add_cma_heap(struct cma *cma, void *data)
|
||||
{
|
||||
struct cma_heap *cma_heap;
|
||||
struct dma_heap_export_info exp_info;
|
||||
|
||||
cma_heap = kzalloc(sizeof(*cma_heap), GFP_KERNEL);
|
||||
if (!cma_heap)
|
||||
return -ENOMEM;
|
||||
cma_heap->cma = cma;
|
||||
|
||||
exp_info.name = cma_get_name(cma);
|
||||
exp_info.ops = &cma_heap_ops;
|
||||
exp_info.priv = cma_heap;
|
||||
|
||||
cma_heap->heap = dma_heap_add(&exp_info);
|
||||
if (IS_ERR(cma_heap->heap)) {
|
||||
int ret = PTR_ERR(cma_heap->heap);
|
||||
|
||||
kfree(cma_heap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_default_cma_heap(void)
|
||||
{
|
||||
struct cma *default_cma = dev_get_cma_area(NULL);
|
||||
int ret = 0;
|
||||
|
||||
if (default_cma)
|
||||
ret = __add_cma_heap(default_cma, NULL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
module_init(add_default_cma_heap);
|
||||
MODULE_DESCRIPTION("DMA-BUF CMA Heap");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
271
drivers/dma-buf/heaps/heap-helpers.c
Normal file
271
drivers/dma-buf/heaps/heap-helpers.c
Normal file
@@ -0,0 +1,271 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <linux/device.h>
|
||||
#include <linux/dma-buf.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <uapi/linux/dma-heap.h>
|
||||
|
||||
#include "heap-helpers.h"
|
||||
|
||||
void init_heap_helper_buffer(struct heap_helper_buffer *buffer,
|
||||
void (*free)(struct heap_helper_buffer *))
|
||||
{
|
||||
buffer->priv_virt = NULL;
|
||||
mutex_init(&buffer->lock);
|
||||
buffer->vmap_cnt = 0;
|
||||
buffer->vaddr = NULL;
|
||||
buffer->pagecount = 0;
|
||||
buffer->pages = NULL;
|
||||
INIT_LIST_HEAD(&buffer->attachments);
|
||||
buffer->free = free;
|
||||
}
|
||||
|
||||
struct dma_buf *heap_helper_export_dmabuf(struct heap_helper_buffer *buffer,
|
||||
int fd_flags)
|
||||
{
|
||||
DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
|
||||
|
||||
exp_info.ops = &heap_helper_ops;
|
||||
exp_info.size = buffer->size;
|
||||
exp_info.flags = fd_flags;
|
||||
exp_info.priv = buffer;
|
||||
|
||||
return dma_buf_export(&exp_info);
|
||||
}
|
||||
|
||||
static void *dma_heap_map_kernel(struct heap_helper_buffer *buffer)
|
||||
{
|
||||
void *vaddr;
|
||||
|
||||
vaddr = vmap(buffer->pages, buffer->pagecount, VM_MAP, PAGE_KERNEL);
|
||||
if (!vaddr)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
return vaddr;
|
||||
}
|
||||
|
||||
static void dma_heap_buffer_destroy(struct heap_helper_buffer *buffer)
|
||||
{
|
||||
if (buffer->vmap_cnt > 0) {
|
||||
WARN(1, "%s: buffer still mapped in the kernel\n", __func__);
|
||||
vunmap(buffer->vaddr);
|
||||
}
|
||||
|
||||
buffer->free(buffer);
|
||||
}
|
||||
|
||||
static void *dma_heap_buffer_vmap_get(struct heap_helper_buffer *buffer)
|
||||
{
|
||||
void *vaddr;
|
||||
|
||||
if (buffer->vmap_cnt) {
|
||||
buffer->vmap_cnt++;
|
||||
return buffer->vaddr;
|
||||
}
|
||||
vaddr = dma_heap_map_kernel(buffer);
|
||||
if (IS_ERR(vaddr))
|
||||
return vaddr;
|
||||
buffer->vaddr = vaddr;
|
||||
buffer->vmap_cnt++;
|
||||
return vaddr;
|
||||
}
|
||||
|
||||
static void dma_heap_buffer_vmap_put(struct heap_helper_buffer *buffer)
|
||||
{
|
||||
if (!--buffer->vmap_cnt) {
|
||||
vunmap(buffer->vaddr);
|
||||
buffer->vaddr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
struct dma_heaps_attachment {
|
||||
struct device *dev;
|
||||
struct sg_table table;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
static int dma_heap_attach(struct dma_buf *dmabuf,
|
||||
struct dma_buf_attachment *attachment)
|
||||
{
|
||||
struct dma_heaps_attachment *a;
|
||||
struct heap_helper_buffer *buffer = dmabuf->priv;
|
||||
int ret;
|
||||
|
||||
a = kzalloc(sizeof(*a), GFP_KERNEL);
|
||||
if (!a)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = sg_alloc_table_from_pages(&a->table, buffer->pages,
|
||||
buffer->pagecount, 0,
|
||||
buffer->pagecount << PAGE_SHIFT,
|
||||
GFP_KERNEL);
|
||||
if (ret) {
|
||||
kfree(a);
|
||||
return ret;
|
||||
}
|
||||
|
||||
a->dev = attachment->dev;
|
||||
INIT_LIST_HEAD(&a->list);
|
||||
|
||||
attachment->priv = a;
|
||||
|
||||
mutex_lock(&buffer->lock);
|
||||
list_add(&a->list, &buffer->attachments);
|
||||
mutex_unlock(&buffer->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dma_heap_detach(struct dma_buf *dmabuf,
|
||||
struct dma_buf_attachment *attachment)
|
||||
{
|
||||
struct dma_heaps_attachment *a = attachment->priv;
|
||||
struct heap_helper_buffer *buffer = dmabuf->priv;
|
||||
|
||||
mutex_lock(&buffer->lock);
|
||||
list_del(&a->list);
|
||||
mutex_unlock(&buffer->lock);
|
||||
|
||||
sg_free_table(&a->table);
|
||||
kfree(a);
|
||||
}
|
||||
|
||||
static
|
||||
struct sg_table *dma_heap_map_dma_buf(struct dma_buf_attachment *attachment,
|
||||
enum dma_data_direction direction)
|
||||
{
|
||||
struct dma_heaps_attachment *a = attachment->priv;
|
||||
struct sg_table *table;
|
||||
|
||||
table = &a->table;
|
||||
|
||||
if (!dma_map_sg(attachment->dev, table->sgl, table->nents,
|
||||
direction))
|
||||
table = ERR_PTR(-ENOMEM);
|
||||
return table;
|
||||
}
|
||||
|
||||
static void dma_heap_unmap_dma_buf(struct dma_buf_attachment *attachment,
|
||||
struct sg_table *table,
|
||||
enum dma_data_direction direction)
|
||||
{
|
||||
dma_unmap_sg(attachment->dev, table->sgl, table->nents, direction);
|
||||
}
|
||||
|
||||
static vm_fault_t dma_heap_vm_fault(struct vm_fault *vmf)
|
||||
{
|
||||
struct vm_area_struct *vma = vmf->vma;
|
||||
struct heap_helper_buffer *buffer = vma->vm_private_data;
|
||||
|
||||
if (vmf->pgoff > buffer->pagecount)
|
||||
return VM_FAULT_SIGBUS;
|
||||
|
||||
vmf->page = buffer->pages[vmf->pgoff];
|
||||
get_page(vmf->page);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct vm_operations_struct dma_heap_vm_ops = {
|
||||
.fault = dma_heap_vm_fault,
|
||||
};
|
||||
|
||||
static int dma_heap_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
|
||||
{
|
||||
struct heap_helper_buffer *buffer = dmabuf->priv;
|
||||
|
||||
if ((vma->vm_flags & (VM_SHARED | VM_MAYSHARE)) == 0)
|
||||
return -EINVAL;
|
||||
|
||||
vma->vm_ops = &dma_heap_vm_ops;
|
||||
vma->vm_private_data = buffer;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dma_heap_dma_buf_release(struct dma_buf *dmabuf)
|
||||
{
|
||||
struct heap_helper_buffer *buffer = dmabuf->priv;
|
||||
|
||||
dma_heap_buffer_destroy(buffer);
|
||||
}
|
||||
|
||||
static int dma_heap_dma_buf_begin_cpu_access(struct dma_buf *dmabuf,
|
||||
enum dma_data_direction direction)
|
||||
{
|
||||
struct heap_helper_buffer *buffer = dmabuf->priv;
|
||||
struct dma_heaps_attachment *a;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&buffer->lock);
|
||||
|
||||
if (buffer->vmap_cnt)
|
||||
invalidate_kernel_vmap_range(buffer->vaddr, buffer->size);
|
||||
|
||||
list_for_each_entry(a, &buffer->attachments, list) {
|
||||
dma_sync_sg_for_cpu(a->dev, a->table.sgl, a->table.nents,
|
||||
direction);
|
||||
}
|
||||
mutex_unlock(&buffer->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dma_heap_dma_buf_end_cpu_access(struct dma_buf *dmabuf,
|
||||
enum dma_data_direction direction)
|
||||
{
|
||||
struct heap_helper_buffer *buffer = dmabuf->priv;
|
||||
struct dma_heaps_attachment *a;
|
||||
|
||||
mutex_lock(&buffer->lock);
|
||||
|
||||
if (buffer->vmap_cnt)
|
||||
flush_kernel_vmap_range(buffer->vaddr, buffer->size);
|
||||
|
||||
list_for_each_entry(a, &buffer->attachments, list) {
|
||||
dma_sync_sg_for_device(a->dev, a->table.sgl, a->table.nents,
|
||||
direction);
|
||||
}
|
||||
mutex_unlock(&buffer->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *dma_heap_dma_buf_vmap(struct dma_buf *dmabuf)
|
||||
{
|
||||
struct heap_helper_buffer *buffer = dmabuf->priv;
|
||||
void *vaddr;
|
||||
|
||||
mutex_lock(&buffer->lock);
|
||||
vaddr = dma_heap_buffer_vmap_get(buffer);
|
||||
mutex_unlock(&buffer->lock);
|
||||
|
||||
return vaddr;
|
||||
}
|
||||
|
||||
static void dma_heap_dma_buf_vunmap(struct dma_buf *dmabuf, void *vaddr)
|
||||
{
|
||||
struct heap_helper_buffer *buffer = dmabuf->priv;
|
||||
|
||||
mutex_lock(&buffer->lock);
|
||||
dma_heap_buffer_vmap_put(buffer);
|
||||
mutex_unlock(&buffer->lock);
|
||||
}
|
||||
|
||||
const struct dma_buf_ops heap_helper_ops = {
|
||||
.map_dma_buf = dma_heap_map_dma_buf,
|
||||
.unmap_dma_buf = dma_heap_unmap_dma_buf,
|
||||
.mmap = dma_heap_mmap,
|
||||
.release = dma_heap_dma_buf_release,
|
||||
.attach = dma_heap_attach,
|
||||
.detach = dma_heap_detach,
|
||||
.begin_cpu_access = dma_heap_dma_buf_begin_cpu_access,
|
||||
.end_cpu_access = dma_heap_dma_buf_end_cpu_access,
|
||||
.vmap = dma_heap_dma_buf_vmap,
|
||||
.vunmap = dma_heap_dma_buf_vunmap,
|
||||
};
|
||||
53
drivers/dma-buf/heaps/heap-helpers.h
Normal file
53
drivers/dma-buf/heaps/heap-helpers.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* DMABUF Heaps helper code
|
||||
*
|
||||
* Copyright (C) 2011 Google, Inc.
|
||||
* Copyright (C) 2019 Linaro Ltd.
|
||||
*/
|
||||
|
||||
#ifndef _HEAP_HELPERS_H
|
||||
#define _HEAP_HELPERS_H
|
||||
|
||||
#include <linux/dma-heap.h>
|
||||
#include <linux/list.h>
|
||||
|
||||
/**
|
||||
* struct heap_helper_buffer - helper buffer metadata
|
||||
* @heap: back pointer to the heap the buffer came from
|
||||
* @dmabuf: backing dma-buf for this buffer
|
||||
* @size: size of the buffer
|
||||
* @priv_virt pointer to heap specific private value
|
||||
* @lock mutext to protect the data in this structure
|
||||
* @vmap_cnt count of vmap references on the buffer
|
||||
* @vaddr vmap'ed virtual address
|
||||
* @pagecount number of pages in the buffer
|
||||
* @pages list of page pointers
|
||||
* @attachments list of device attachments
|
||||
*
|
||||
* @free heap callback to free the buffer
|
||||
*/
|
||||
struct heap_helper_buffer {
|
||||
struct dma_heap *heap;
|
||||
struct dma_buf *dmabuf;
|
||||
size_t size;
|
||||
|
||||
void *priv_virt;
|
||||
struct mutex lock;
|
||||
int vmap_cnt;
|
||||
void *vaddr;
|
||||
pgoff_t pagecount;
|
||||
struct page **pages;
|
||||
struct list_head attachments;
|
||||
|
||||
void (*free)(struct heap_helper_buffer *buffer);
|
||||
};
|
||||
|
||||
void init_heap_helper_buffer(struct heap_helper_buffer *buffer,
|
||||
void (*free)(struct heap_helper_buffer *));
|
||||
|
||||
struct dma_buf *heap_helper_export_dmabuf(struct heap_helper_buffer *buffer,
|
||||
int fd_flags);
|
||||
|
||||
extern const struct dma_buf_ops heap_helper_ops;
|
||||
#endif /* _HEAP_HELPERS_H */
|
||||
123
drivers/dma-buf/heaps/system_heap.c
Normal file
123
drivers/dma-buf/heaps/system_heap.c
Normal file
@@ -0,0 +1,123 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* DMABUF System heap exporter
|
||||
*
|
||||
* Copyright (C) 2011 Google, Inc.
|
||||
* Copyright (C) 2019 Linaro Ltd.
|
||||
*/
|
||||
|
||||
#include <linux/dma-buf.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/dma-heap.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sched/signal.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
#include "heap-helpers.h"
|
||||
|
||||
struct dma_heap *sys_heap;
|
||||
|
||||
static void system_heap_free(struct heap_helper_buffer *buffer)
|
||||
{
|
||||
pgoff_t pg;
|
||||
|
||||
for (pg = 0; pg < buffer->pagecount; pg++)
|
||||
__free_page(buffer->pages[pg]);
|
||||
kfree(buffer->pages);
|
||||
kfree(buffer);
|
||||
}
|
||||
|
||||
static int system_heap_allocate(struct dma_heap *heap,
|
||||
unsigned long len,
|
||||
unsigned long fd_flags,
|
||||
unsigned long heap_flags)
|
||||
{
|
||||
struct heap_helper_buffer *helper_buffer;
|
||||
struct dma_buf *dmabuf;
|
||||
int ret = -ENOMEM;
|
||||
pgoff_t pg;
|
||||
|
||||
helper_buffer = kzalloc(sizeof(*helper_buffer), GFP_KERNEL);
|
||||
if (!helper_buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
init_heap_helper_buffer(helper_buffer, system_heap_free);
|
||||
helper_buffer->heap = heap;
|
||||
helper_buffer->size = len;
|
||||
|
||||
helper_buffer->pagecount = len / PAGE_SIZE;
|
||||
helper_buffer->pages = kmalloc_array(helper_buffer->pagecount,
|
||||
sizeof(*helper_buffer->pages),
|
||||
GFP_KERNEL);
|
||||
if (!helper_buffer->pages) {
|
||||
ret = -ENOMEM;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
for (pg = 0; pg < helper_buffer->pagecount; pg++) {
|
||||
/*
|
||||
* Avoid trying to allocate memory if the process
|
||||
* has been killed by by SIGKILL
|
||||
*/
|
||||
if (fatal_signal_pending(current))
|
||||
goto err1;
|
||||
|
||||
helper_buffer->pages[pg] = alloc_page(GFP_KERNEL | __GFP_ZERO);
|
||||
if (!helper_buffer->pages[pg])
|
||||
goto err1;
|
||||
}
|
||||
|
||||
/* create the dmabuf */
|
||||
dmabuf = heap_helper_export_dmabuf(helper_buffer, fd_flags);
|
||||
if (IS_ERR(dmabuf)) {
|
||||
ret = PTR_ERR(dmabuf);
|
||||
goto err1;
|
||||
}
|
||||
|
||||
helper_buffer->dmabuf = dmabuf;
|
||||
|
||||
ret = dma_buf_fd(dmabuf, fd_flags);
|
||||
if (ret < 0) {
|
||||
dma_buf_put(dmabuf);
|
||||
/* just return, as put will call release and that will free */
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
err1:
|
||||
while (pg > 0)
|
||||
__free_page(helper_buffer->pages[--pg]);
|
||||
kfree(helper_buffer->pages);
|
||||
err0:
|
||||
kfree(helper_buffer);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct dma_heap_ops system_heap_ops = {
|
||||
.allocate = system_heap_allocate,
|
||||
};
|
||||
|
||||
static int system_heap_create(void)
|
||||
{
|
||||
struct dma_heap_export_info exp_info;
|
||||
int ret = 0;
|
||||
|
||||
exp_info.name = "system";
|
||||
exp_info.ops = &system_heap_ops;
|
||||
exp_info.priv = NULL;
|
||||
|
||||
sys_heap = dma_heap_add(&exp_info);
|
||||
if (IS_ERR(sys_heap))
|
||||
ret = PTR_ERR(sys_heap);
|
||||
|
||||
return ret;
|
||||
}
|
||||
module_init(system_heap_create);
|
||||
MODULE_LICENSE("GPL v2");
|
||||
@@ -18,6 +18,8 @@ static const size_t size_limit_mb = 64; /* total dmabuf size, in megabytes */
|
||||
struct udmabuf {
|
||||
pgoff_t pagecount;
|
||||
struct page **pages;
|
||||
struct sg_table *sg;
|
||||
struct miscdevice *device;
|
||||
};
|
||||
|
||||
static vm_fault_t udmabuf_vm_fault(struct vm_fault *vmf)
|
||||
@@ -46,10 +48,10 @@ static int mmap_udmabuf(struct dma_buf *buf, struct vm_area_struct *vma)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct sg_table *map_udmabuf(struct dma_buf_attachment *at,
|
||||
enum dma_data_direction direction)
|
||||
static struct sg_table *get_sg_table(struct device *dev, struct dma_buf *buf,
|
||||
enum dma_data_direction direction)
|
||||
{
|
||||
struct udmabuf *ubuf = at->dmabuf->priv;
|
||||
struct udmabuf *ubuf = buf->priv;
|
||||
struct sg_table *sg;
|
||||
int ret;
|
||||
|
||||
@@ -61,7 +63,7 @@ static struct sg_table *map_udmabuf(struct dma_buf_attachment *at,
|
||||
GFP_KERNEL);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
if (!dma_map_sg(at->dev, sg->sgl, sg->nents, direction)) {
|
||||
if (!dma_map_sg(dev, sg->sgl, sg->nents, direction)) {
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
@@ -73,54 +75,89 @@ err:
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
static void put_sg_table(struct device *dev, struct sg_table *sg,
|
||||
enum dma_data_direction direction)
|
||||
{
|
||||
dma_unmap_sg(dev, sg->sgl, sg->nents, direction);
|
||||
sg_free_table(sg);
|
||||
kfree(sg);
|
||||
}
|
||||
|
||||
static struct sg_table *map_udmabuf(struct dma_buf_attachment *at,
|
||||
enum dma_data_direction direction)
|
||||
{
|
||||
return get_sg_table(at->dev, at->dmabuf, direction);
|
||||
}
|
||||
|
||||
static void unmap_udmabuf(struct dma_buf_attachment *at,
|
||||
struct sg_table *sg,
|
||||
enum dma_data_direction direction)
|
||||
{
|
||||
dma_unmap_sg(at->dev, sg->sgl, sg->nents, direction);
|
||||
sg_free_table(sg);
|
||||
kfree(sg);
|
||||
return put_sg_table(at->dev, sg, direction);
|
||||
}
|
||||
|
||||
static void release_udmabuf(struct dma_buf *buf)
|
||||
{
|
||||
struct udmabuf *ubuf = buf->priv;
|
||||
struct device *dev = ubuf->device->this_device;
|
||||
pgoff_t pg;
|
||||
|
||||
if (ubuf->sg)
|
||||
put_sg_table(dev, ubuf->sg, DMA_BIDIRECTIONAL);
|
||||
|
||||
for (pg = 0; pg < ubuf->pagecount; pg++)
|
||||
put_page(ubuf->pages[pg]);
|
||||
kfree(ubuf->pages);
|
||||
kfree(ubuf);
|
||||
}
|
||||
|
||||
static void *kmap_udmabuf(struct dma_buf *buf, unsigned long page_num)
|
||||
static int begin_cpu_udmabuf(struct dma_buf *buf,
|
||||
enum dma_data_direction direction)
|
||||
{
|
||||
struct udmabuf *ubuf = buf->priv;
|
||||
struct page *page = ubuf->pages[page_num];
|
||||
struct device *dev = ubuf->device->this_device;
|
||||
|
||||
return kmap(page);
|
||||
if (!ubuf->sg) {
|
||||
ubuf->sg = get_sg_table(dev, buf, direction);
|
||||
if (IS_ERR(ubuf->sg))
|
||||
return PTR_ERR(ubuf->sg);
|
||||
} else {
|
||||
dma_sync_sg_for_cpu(dev, ubuf->sg->sgl, ubuf->sg->nents,
|
||||
direction);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void kunmap_udmabuf(struct dma_buf *buf, unsigned long page_num,
|
||||
void *vaddr)
|
||||
static int end_cpu_udmabuf(struct dma_buf *buf,
|
||||
enum dma_data_direction direction)
|
||||
{
|
||||
kunmap(vaddr);
|
||||
struct udmabuf *ubuf = buf->priv;
|
||||
struct device *dev = ubuf->device->this_device;
|
||||
|
||||
if (!ubuf->sg)
|
||||
return -EINVAL;
|
||||
|
||||
dma_sync_sg_for_device(dev, ubuf->sg->sgl, ubuf->sg->nents, direction);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dma_buf_ops udmabuf_ops = {
|
||||
.map_dma_buf = map_udmabuf,
|
||||
.unmap_dma_buf = unmap_udmabuf,
|
||||
.release = release_udmabuf,
|
||||
.map = kmap_udmabuf,
|
||||
.unmap = kunmap_udmabuf,
|
||||
.mmap = mmap_udmabuf,
|
||||
.cache_sgt_mapping = true,
|
||||
.map_dma_buf = map_udmabuf,
|
||||
.unmap_dma_buf = unmap_udmabuf,
|
||||
.release = release_udmabuf,
|
||||
.mmap = mmap_udmabuf,
|
||||
.begin_cpu_access = begin_cpu_udmabuf,
|
||||
.end_cpu_access = end_cpu_udmabuf,
|
||||
};
|
||||
|
||||
#define SEALS_WANTED (F_SEAL_SHRINK)
|
||||
#define SEALS_DENIED (F_SEAL_WRITE)
|
||||
|
||||
static long udmabuf_create(const struct udmabuf_create_list *head,
|
||||
const struct udmabuf_create_item *list)
|
||||
static long udmabuf_create(struct miscdevice *device,
|
||||
struct udmabuf_create_list *head,
|
||||
struct udmabuf_create_item *list)
|
||||
{
|
||||
DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
|
||||
struct file *memfd = NULL;
|
||||
@@ -187,6 +224,7 @@ static long udmabuf_create(const struct udmabuf_create_list *head,
|
||||
exp_info.priv = ubuf;
|
||||
exp_info.flags = O_RDWR;
|
||||
|
||||
ubuf->device = device;
|
||||
buf = dma_buf_export(&exp_info);
|
||||
if (IS_ERR(buf)) {
|
||||
ret = PTR_ERR(buf);
|
||||
@@ -224,7 +262,7 @@ static long udmabuf_ioctl_create(struct file *filp, unsigned long arg)
|
||||
list.offset = create.offset;
|
||||
list.size = create.size;
|
||||
|
||||
return udmabuf_create(&head, &list);
|
||||
return udmabuf_create(filp->private_data, &head, &list);
|
||||
}
|
||||
|
||||
static long udmabuf_ioctl_create_list(struct file *filp, unsigned long arg)
|
||||
@@ -243,7 +281,7 @@ static long udmabuf_ioctl_create_list(struct file *filp, unsigned long arg)
|
||||
if (IS_ERR(list))
|
||||
return PTR_ERR(list);
|
||||
|
||||
ret = udmabuf_create(&head, list);
|
||||
ret = udmabuf_create(filp->private_data, &head, list);
|
||||
kfree(list);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -54,6 +54,9 @@ config DRM_DEBUG_MM
|
||||
|
||||
If in doubt, say "N".
|
||||
|
||||
config DRM_EXPORT_FOR_TESTS
|
||||
bool
|
||||
|
||||
config DRM_DEBUG_SELFTEST
|
||||
tristate "kselftests for DRM"
|
||||
depends on DRM
|
||||
@@ -61,6 +64,7 @@ config DRM_DEBUG_SELFTEST
|
||||
select PRIME_NUMBERS
|
||||
select DRM_LIB_RANDOM
|
||||
select DRM_KMS_HELPER
|
||||
select DRM_EXPORT_FOR_TESTS if m
|
||||
default n
|
||||
help
|
||||
This option provides kernel modules that can be used to run
|
||||
@@ -164,6 +168,7 @@ config DRM_LOAD_EDID_FIRMWARE
|
||||
|
||||
config DRM_DP_CEC
|
||||
bool "Enable DisplayPort CEC-Tunneling-over-AUX HDMI support"
|
||||
depends on DRM
|
||||
select CEC_CORE
|
||||
help
|
||||
Choose this option if you want to enable HDMI CEC support for
|
||||
@@ -294,9 +299,6 @@ config DRM_VKMS
|
||||
|
||||
If M is selected the module will be called vkms.
|
||||
|
||||
config DRM_ATI_PCIGART
|
||||
bool
|
||||
|
||||
source "drivers/gpu/drm/exynos/Kconfig"
|
||||
|
||||
source "drivers/gpu/drm/rockchip/Kconfig"
|
||||
@@ -393,7 +395,6 @@ menuconfig DRM_LEGACY
|
||||
bool "Enable legacy drivers (DANGEROUS)"
|
||||
depends on DRM && MMU
|
||||
select DRM_VM
|
||||
select DRM_ATI_PCIGART if PCI
|
||||
help
|
||||
Enable legacy DRI1 drivers. Those drivers expose unsafe and dangerous
|
||||
APIs to user-space, which can be used to circumvent access
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
drm-y := drm_auth.o drm_cache.o \
|
||||
drm_file.o drm_gem.o drm_ioctl.o drm_irq.o \
|
||||
drm_memory.o drm_drv.o drm_pci.o \
|
||||
drm_memory.o drm_drv.o \
|
||||
drm_sysfs.o drm_hashtab.o drm_mm.o \
|
||||
drm_crtc.o drm_fourcc.o drm_modes.o drm_edid.o \
|
||||
drm_encoder_slave.o \
|
||||
@@ -25,10 +25,10 @@ drm-$(CONFIG_DRM_VM) += drm_vm.o
|
||||
drm-$(CONFIG_COMPAT) += drm_ioc32.o
|
||||
drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
|
||||
drm-$(CONFIG_DRM_GEM_SHMEM_HELPER) += drm_gem_shmem_helper.o
|
||||
drm-$(CONFIG_DRM_ATI_PCIGART) += ati_pcigart.o
|
||||
drm-$(CONFIG_DRM_PANEL) += drm_panel.o
|
||||
drm-$(CONFIG_OF) += drm_of.o
|
||||
drm-$(CONFIG_AGP) += drm_agpsupport.o
|
||||
drm-$(CONFIG_PCI) += drm_pci.o
|
||||
drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o
|
||||
drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
|
||||
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
menu "ACP (Audio CoProcessor) Configuration"
|
||||
|
||||
config DRM_AMD_ACP
|
||||
bool "Enable AMD Audio CoProcessor IP support"
|
||||
depends on DRM_AMDGPU
|
||||
select MFD_CORE
|
||||
select PM_GENERIC_DOMAINS if PM
|
||||
help
|
||||
bool "Enable AMD Audio CoProcessor IP support"
|
||||
depends on DRM_AMDGPU
|
||||
select MFD_CORE
|
||||
select PM_GENERIC_DOMAINS if PM
|
||||
help
|
||||
Choose this option to enable ACP IP support for AMD SOCs.
|
||||
This adds the ACP (Audio CoProcessor) IP driver and wires
|
||||
it up into the amdgpu driver. The ACP block provides the DMA
|
||||
|
||||
@@ -147,12 +147,16 @@ amdgpu-y += \
|
||||
vce_v3_0.o \
|
||||
vce_v4_0.o
|
||||
|
||||
# add VCN block
|
||||
# add VCN and JPEG block
|
||||
amdgpu-y += \
|
||||
amdgpu_vcn.o \
|
||||
vcn_v1_0.o \
|
||||
vcn_v2_0.o \
|
||||
vcn_v2_5.o
|
||||
vcn_v2_5.o \
|
||||
amdgpu_jpeg.o \
|
||||
jpeg_v1_0.o \
|
||||
jpeg_v2_0.o \
|
||||
jpeg_v2_5.o
|
||||
|
||||
# add ATHUB block
|
||||
amdgpu-y += \
|
||||
|
||||
@@ -69,6 +69,7 @@
|
||||
#include "amdgpu_uvd.h"
|
||||
#include "amdgpu_vce.h"
|
||||
#include "amdgpu_vcn.h"
|
||||
#include "amdgpu_jpeg.h"
|
||||
#include "amdgpu_mn.h"
|
||||
#include "amdgpu_gmc.h"
|
||||
#include "amdgpu_gfx.h"
|
||||
@@ -89,6 +90,7 @@
|
||||
#include "amdgpu_mes.h"
|
||||
#include "amdgpu_umc.h"
|
||||
#include "amdgpu_mmhub.h"
|
||||
#include "amdgpu_df.h"
|
||||
|
||||
#define MAX_GPU_INSTANCE 16
|
||||
|
||||
@@ -588,6 +590,8 @@ struct amdgpu_asic_funcs {
|
||||
bool (*need_reset_on_init)(struct amdgpu_device *adev);
|
||||
/* PCIe replay counter */
|
||||
uint64_t (*get_pcie_replay_count)(struct amdgpu_device *adev);
|
||||
/* device supports BACO */
|
||||
bool (*supports_baco)(struct amdgpu_device *adev);
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -633,9 +637,8 @@ struct amdgpu_fw_vram_usage {
|
||||
struct amdgpu_bo *reserved_bo;
|
||||
void *va;
|
||||
|
||||
/* Offset on the top of VRAM, used as c2p write buffer.
|
||||
/* GDDR6 training support flag.
|
||||
*/
|
||||
u64 mem_train_fb_loc;
|
||||
bool mem_train_support;
|
||||
};
|
||||
|
||||
@@ -662,29 +665,6 @@ struct amdgpu_mmio_remap {
|
||||
resource_size_t bus_addr;
|
||||
};
|
||||
|
||||
struct amdgpu_df_funcs {
|
||||
void (*sw_init)(struct amdgpu_device *adev);
|
||||
void (*sw_fini)(struct amdgpu_device *adev);
|
||||
void (*enable_broadcast_mode)(struct amdgpu_device *adev,
|
||||
bool enable);
|
||||
u32 (*get_fb_channel_number)(struct amdgpu_device *adev);
|
||||
u32 (*get_hbm_channel_number)(struct amdgpu_device *adev);
|
||||
void (*update_medium_grain_clock_gating)(struct amdgpu_device *adev,
|
||||
bool enable);
|
||||
void (*get_clockgating_state)(struct amdgpu_device *adev,
|
||||
u32 *flags);
|
||||
void (*enable_ecc_force_par_wr_rmw)(struct amdgpu_device *adev,
|
||||
bool enable);
|
||||
int (*pmc_start)(struct amdgpu_device *adev, uint64_t config,
|
||||
int is_enable);
|
||||
int (*pmc_stop)(struct amdgpu_device *adev, uint64_t config,
|
||||
int is_disable);
|
||||
void (*pmc_get_count)(struct amdgpu_device *adev, uint64_t config,
|
||||
uint64_t *count);
|
||||
uint64_t (*get_fica)(struct amdgpu_device *adev, uint32_t ficaa_val);
|
||||
void (*set_fica)(struct amdgpu_device *adev, uint32_t ficaa_val,
|
||||
uint32_t ficadl_val, uint32_t ficadh_val);
|
||||
};
|
||||
/* Define the HW IP blocks will be used in driver , add more if necessary */
|
||||
enum amd_hw_ip_block_type {
|
||||
GC_HWIP = 1,
|
||||
@@ -704,6 +684,7 @@ enum amd_hw_ip_block_type {
|
||||
MP1_HWIP,
|
||||
UVD_HWIP,
|
||||
VCN_HWIP = UVD_HWIP,
|
||||
JPEG_HWIP = VCN_HWIP,
|
||||
VCE_HWIP,
|
||||
DF_HWIP,
|
||||
DCE_HWIP,
|
||||
@@ -899,6 +880,9 @@ struct amdgpu_device {
|
||||
/* vcn */
|
||||
struct amdgpu_vcn vcn;
|
||||
|
||||
/* jpeg */
|
||||
struct amdgpu_jpeg jpeg;
|
||||
|
||||
/* firmwares */
|
||||
struct amdgpu_firmware firmware;
|
||||
|
||||
@@ -924,6 +908,9 @@ struct amdgpu_device {
|
||||
bool enable_mes;
|
||||
struct amdgpu_mes mes;
|
||||
|
||||
/* df */
|
||||
struct amdgpu_df df;
|
||||
|
||||
struct amdgpu_ip_block ip_blocks[AMDGPU_MAX_IP_NUM];
|
||||
int num_ip_blocks;
|
||||
struct mutex mn_lock;
|
||||
@@ -937,8 +924,6 @@ struct amdgpu_device {
|
||||
/* soc15 register offset based on ip, instance and segment */
|
||||
uint32_t *reg_offset[MAX_HWIP][HWIP_MAX_INSTANCE];
|
||||
|
||||
const struct amdgpu_df_funcs *df_funcs;
|
||||
|
||||
/* delayed work_func for deferring clockgating during resume */
|
||||
struct delayed_work delayed_init_work;
|
||||
|
||||
@@ -982,6 +967,11 @@ struct amdgpu_device {
|
||||
|
||||
/* device pstate */
|
||||
int pstate;
|
||||
/* enable runtime pm on the device */
|
||||
bool runpm;
|
||||
|
||||
bool pm_sysfs_en;
|
||||
bool ucode_sysfs_en;
|
||||
};
|
||||
|
||||
static inline struct amdgpu_device *amdgpu_ttm_adev(struct ttm_bo_device *bdev)
|
||||
@@ -1117,6 +1107,8 @@ int emu_soc_asic_init(struct amdgpu_device *adev);
|
||||
#define amdgpu_asic_get_pcie_usage(adev, cnt0, cnt1) ((adev)->asic_funcs->get_pcie_usage((adev), (cnt0), (cnt1)))
|
||||
#define amdgpu_asic_need_reset_on_init(adev) (adev)->asic_funcs->need_reset_on_init((adev))
|
||||
#define amdgpu_asic_get_pcie_replay_count(adev) ((adev)->asic_funcs->get_pcie_replay_count((adev)))
|
||||
#define amdgpu_asic_supports_baco(adev) (adev)->asic_funcs->supports_baco((adev))
|
||||
|
||||
#define amdgpu_inc_vram_lost(adev) atomic_inc(&((adev)->vram_lost_counter));
|
||||
|
||||
/* Common functions */
|
||||
@@ -1133,9 +1125,12 @@ void amdgpu_device_program_register_sequence(struct amdgpu_device *adev,
|
||||
const u32 *registers,
|
||||
const u32 array_size);
|
||||
|
||||
bool amdgpu_device_is_px(struct drm_device *dev);
|
||||
bool amdgpu_device_supports_boco(struct drm_device *dev);
|
||||
bool amdgpu_device_supports_baco(struct drm_device *dev);
|
||||
bool amdgpu_device_is_peer_accessible(struct amdgpu_device *adev,
|
||||
struct amdgpu_device *peer_adev);
|
||||
int amdgpu_device_baco_enter(struct drm_device *dev);
|
||||
int amdgpu_device_baco_exit(struct drm_device *dev);
|
||||
|
||||
/* atpx handler */
|
||||
#if defined(CONFIG_VGA_SWITCHEROO)
|
||||
@@ -1173,8 +1168,8 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv);
|
||||
void amdgpu_driver_postclose_kms(struct drm_device *dev,
|
||||
struct drm_file *file_priv);
|
||||
int amdgpu_device_ip_suspend(struct amdgpu_device *adev);
|
||||
int amdgpu_device_suspend(struct drm_device *dev, bool suspend, bool fbcon);
|
||||
int amdgpu_device_resume(struct drm_device *dev, bool resume, bool fbcon);
|
||||
int amdgpu_device_suspend(struct drm_device *dev, bool fbcon);
|
||||
int amdgpu_device_resume(struct drm_device *dev, bool fbcon);
|
||||
u32 amdgpu_get_vblank_counter_kms(struct drm_device *dev, unsigned int pipe);
|
||||
int amdgpu_enable_vblank_kms(struct drm_device *dev, unsigned int pipe);
|
||||
void amdgpu_disable_vblank_kms(struct drm_device *dev, unsigned int pipe);
|
||||
|
||||
@@ -613,15 +613,9 @@ void amdgpu_amdkfd_set_compute_idle(struct kgd_dev *kgd, bool idle)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)kgd;
|
||||
|
||||
if (is_support_sw_smu(adev))
|
||||
smu_switch_power_profile(&adev->smu,
|
||||
PP_SMC_POWER_PROFILE_COMPUTE,
|
||||
!idle);
|
||||
else if (adev->powerplay.pp_funcs &&
|
||||
adev->powerplay.pp_funcs->switch_power_profile)
|
||||
amdgpu_dpm_switch_power_profile(adev,
|
||||
PP_SMC_POWER_PROFILE_COMPUTE,
|
||||
!idle);
|
||||
amdgpu_dpm_switch_power_profile(adev,
|
||||
PP_SMC_POWER_PROFILE_COMPUTE,
|
||||
!idle);
|
||||
}
|
||||
|
||||
bool amdgpu_amdkfd_is_kfd_vmid(struct amdgpu_device *adev, u32 vmid)
|
||||
@@ -634,6 +628,38 @@ bool amdgpu_amdkfd_is_kfd_vmid(struct amdgpu_device *adev, u32 vmid)
|
||||
return false;
|
||||
}
|
||||
|
||||
int amdgpu_amdkfd_flush_gpu_tlb_vmid(struct kgd_dev *kgd, uint16_t vmid)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)kgd;
|
||||
|
||||
if (adev->family == AMDGPU_FAMILY_AI) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < adev->num_vmhubs; i++)
|
||||
amdgpu_gmc_flush_gpu_tlb(adev, vmid, i, 0);
|
||||
} else {
|
||||
amdgpu_gmc_flush_gpu_tlb(adev, vmid, AMDGPU_GFXHUB_0, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int amdgpu_amdkfd_flush_gpu_tlb_pasid(struct kgd_dev *kgd, uint16_t pasid)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)kgd;
|
||||
uint32_t flush_type = 0;
|
||||
bool all_hub = false;
|
||||
|
||||
if (adev->gmc.xgmi.num_physical_nodes &&
|
||||
adev->asic_type == CHIP_VEGA20)
|
||||
flush_type = 2;
|
||||
|
||||
if (adev->family == AMDGPU_FAMILY_AI)
|
||||
all_hub = true;
|
||||
|
||||
return amdgpu_gmc_flush_gpu_tlb_pasid(adev, pasid, flush_type, all_hub);
|
||||
}
|
||||
|
||||
bool amdgpu_amdkfd_have_atomics_support(struct kgd_dev *kgd)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)kgd;
|
||||
|
||||
@@ -136,6 +136,8 @@ int amdgpu_amdkfd_submit_ib(struct kgd_dev *kgd, enum kgd_engine_type engine,
|
||||
uint32_t *ib_cmd, uint32_t ib_len);
|
||||
void amdgpu_amdkfd_set_compute_idle(struct kgd_dev *kgd, bool idle);
|
||||
bool amdgpu_amdkfd_have_atomics_support(struct kgd_dev *kgd);
|
||||
int amdgpu_amdkfd_flush_gpu_tlb_vmid(struct kgd_dev *kgd, uint16_t vmid);
|
||||
int amdgpu_amdkfd_flush_gpu_tlb_pasid(struct kgd_dev *kgd, uint16_t pasid);
|
||||
|
||||
bool amdgpu_amdkfd_is_kfd_vmid(struct amdgpu_device *adev, u32 vmid);
|
||||
|
||||
|
||||
@@ -46,6 +46,8 @@
|
||||
#include "soc15.h"
|
||||
#include "soc15d.h"
|
||||
#include "amdgpu_amdkfd_gfx_v9.h"
|
||||
#include "gfxhub_v1_0.h"
|
||||
#include "mmhub_v9_4.h"
|
||||
|
||||
#define HQD_N_REGS 56
|
||||
#define DUMP_REG(addr) do { \
|
||||
@@ -69,32 +71,56 @@ static uint32_t get_sdma_rlc_reg_offset(struct amdgpu_device *adev,
|
||||
unsigned int engine_id,
|
||||
unsigned int queue_id)
|
||||
{
|
||||
uint32_t sdma_engine_reg_base[8] = {
|
||||
SOC15_REG_OFFSET(SDMA0, 0,
|
||||
mmSDMA0_RLC0_RB_CNTL) - mmSDMA0_RLC0_RB_CNTL,
|
||||
SOC15_REG_OFFSET(SDMA1, 0,
|
||||
mmSDMA1_RLC0_RB_CNTL) - mmSDMA1_RLC0_RB_CNTL,
|
||||
SOC15_REG_OFFSET(SDMA2, 0,
|
||||
mmSDMA2_RLC0_RB_CNTL) - mmSDMA2_RLC0_RB_CNTL,
|
||||
SOC15_REG_OFFSET(SDMA3, 0,
|
||||
mmSDMA3_RLC0_RB_CNTL) - mmSDMA3_RLC0_RB_CNTL,
|
||||
SOC15_REG_OFFSET(SDMA4, 0,
|
||||
mmSDMA4_RLC0_RB_CNTL) - mmSDMA4_RLC0_RB_CNTL,
|
||||
SOC15_REG_OFFSET(SDMA5, 0,
|
||||
mmSDMA5_RLC0_RB_CNTL) - mmSDMA5_RLC0_RB_CNTL,
|
||||
SOC15_REG_OFFSET(SDMA6, 0,
|
||||
mmSDMA6_RLC0_RB_CNTL) - mmSDMA6_RLC0_RB_CNTL,
|
||||
SOC15_REG_OFFSET(SDMA7, 0,
|
||||
mmSDMA7_RLC0_RB_CNTL) - mmSDMA7_RLC0_RB_CNTL
|
||||
};
|
||||
uint32_t sdma_engine_reg_base = 0;
|
||||
uint32_t sdma_rlc_reg_offset;
|
||||
|
||||
uint32_t retval = sdma_engine_reg_base[engine_id]
|
||||
switch (engine_id) {
|
||||
default:
|
||||
dev_warn(adev->dev,
|
||||
"Invalid sdma engine id (%d), using engine id 0\n",
|
||||
engine_id);
|
||||
/* fall through */
|
||||
case 0:
|
||||
sdma_engine_reg_base = SOC15_REG_OFFSET(SDMA0, 0,
|
||||
mmSDMA0_RLC0_RB_CNTL) - mmSDMA0_RLC0_RB_CNTL;
|
||||
break;
|
||||
case 1:
|
||||
sdma_engine_reg_base = SOC15_REG_OFFSET(SDMA1, 0,
|
||||
mmSDMA1_RLC0_RB_CNTL) - mmSDMA1_RLC0_RB_CNTL;
|
||||
break;
|
||||
case 2:
|
||||
sdma_engine_reg_base = SOC15_REG_OFFSET(SDMA2, 0,
|
||||
mmSDMA2_RLC0_RB_CNTL) - mmSDMA2_RLC0_RB_CNTL;
|
||||
break;
|
||||
case 3:
|
||||
sdma_engine_reg_base = SOC15_REG_OFFSET(SDMA3, 0,
|
||||
mmSDMA3_RLC0_RB_CNTL) - mmSDMA3_RLC0_RB_CNTL;
|
||||
break;
|
||||
case 4:
|
||||
sdma_engine_reg_base = SOC15_REG_OFFSET(SDMA4, 0,
|
||||
mmSDMA4_RLC0_RB_CNTL) - mmSDMA4_RLC0_RB_CNTL;
|
||||
break;
|
||||
case 5:
|
||||
sdma_engine_reg_base = SOC15_REG_OFFSET(SDMA5, 0,
|
||||
mmSDMA5_RLC0_RB_CNTL) - mmSDMA5_RLC0_RB_CNTL;
|
||||
break;
|
||||
case 6:
|
||||
sdma_engine_reg_base = SOC15_REG_OFFSET(SDMA6, 0,
|
||||
mmSDMA6_RLC0_RB_CNTL) - mmSDMA6_RLC0_RB_CNTL;
|
||||
break;
|
||||
case 7:
|
||||
sdma_engine_reg_base = SOC15_REG_OFFSET(SDMA7, 0,
|
||||
mmSDMA7_RLC0_RB_CNTL) - mmSDMA7_RLC0_RB_CNTL;
|
||||
break;
|
||||
}
|
||||
|
||||
sdma_rlc_reg_offset = sdma_engine_reg_base
|
||||
+ queue_id * (mmSDMA0_RLC1_RB_CNTL - mmSDMA0_RLC0_RB_CNTL);
|
||||
|
||||
pr_debug("RLC register offset for SDMA%d RLC%d: 0x%x\n", engine_id,
|
||||
queue_id, retval);
|
||||
queue_id, sdma_rlc_reg_offset);
|
||||
|
||||
return retval;
|
||||
return sdma_rlc_reg_offset;
|
||||
}
|
||||
|
||||
static int kgd_hqd_sdma_load(struct kgd_dev *kgd, void *mqd,
|
||||
@@ -258,11 +284,28 @@ static int kgd_hqd_sdma_destroy(struct kgd_dev *kgd, void *mqd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void kgd_set_vm_context_page_table_base(struct kgd_dev *kgd, uint32_t vmid,
|
||||
uint64_t page_table_base)
|
||||
{
|
||||
struct amdgpu_device *adev = get_amdgpu_device(kgd);
|
||||
|
||||
if (!amdgpu_amdkfd_is_kfd_vmid(adev, vmid)) {
|
||||
pr_err("trying to set page table base for wrong VMID %u\n",
|
||||
vmid);
|
||||
return;
|
||||
}
|
||||
|
||||
mmhub_v9_4_setup_vm_pt_regs(adev, vmid, page_table_base);
|
||||
|
||||
gfxhub_v1_0_setup_vm_pt_regs(adev, vmid, page_table_base);
|
||||
}
|
||||
|
||||
const struct kfd2kgd_calls arcturus_kfd2kgd = {
|
||||
.program_sh_mem_settings = kgd_gfx_v9_program_sh_mem_settings,
|
||||
.set_pasid_vmid_mapping = kgd_gfx_v9_set_pasid_vmid_mapping,
|
||||
.init_interrupts = kgd_gfx_v9_init_interrupts,
|
||||
.hqd_load = kgd_gfx_v9_hqd_load,
|
||||
.hiq_mqd_load = kgd_gfx_v9_hiq_mqd_load,
|
||||
.hqd_sdma_load = kgd_hqd_sdma_load,
|
||||
.hqd_dump = kgd_gfx_v9_hqd_dump,
|
||||
.hqd_sdma_dump = kgd_hqd_sdma_dump,
|
||||
@@ -277,8 +320,6 @@ const struct kfd2kgd_calls arcturus_kfd2kgd = {
|
||||
.get_atc_vmid_pasid_mapping_info =
|
||||
kgd_gfx_v9_get_atc_vmid_pasid_mapping_info,
|
||||
.get_tile_config = kgd_gfx_v9_get_tile_config,
|
||||
.set_vm_context_page_table_base = kgd_gfx_v9_set_vm_context_page_table_base,
|
||||
.invalidate_tlbs = kgd_gfx_v9_invalidate_tlbs,
|
||||
.invalidate_tlbs_vmid = kgd_gfx_v9_invalidate_tlbs_vmid,
|
||||
.set_vm_context_page_table_base = kgd_set_vm_context_page_table_base,
|
||||
.get_hive_id = amdgpu_amdkfd_get_hive_id,
|
||||
};
|
||||
|
||||
@@ -107,13 +107,13 @@ static void acquire_queue(struct kgd_dev *kgd, uint32_t pipe_id,
|
||||
lock_srbm(kgd, mec, pipe, queue_id, 0);
|
||||
}
|
||||
|
||||
static uint32_t get_queue_mask(struct amdgpu_device *adev,
|
||||
static uint64_t get_queue_mask(struct amdgpu_device *adev,
|
||||
uint32_t pipe_id, uint32_t queue_id)
|
||||
{
|
||||
unsigned int bit = (pipe_id * adev->gfx.mec.num_queue_per_pipe +
|
||||
queue_id) & 31;
|
||||
unsigned int bit = pipe_id * adev->gfx.mec.num_queue_per_pipe +
|
||||
queue_id;
|
||||
|
||||
return ((uint32_t)1) << bit;
|
||||
return 1ull << bit;
|
||||
}
|
||||
|
||||
static void release_queue(struct kgd_dev *kgd)
|
||||
@@ -268,21 +268,6 @@ static int kgd_hqd_load(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id,
|
||||
pr_debug("Load hqd of pipe %d queue %d\n", pipe_id, queue_id);
|
||||
acquire_queue(kgd, pipe_id, queue_id);
|
||||
|
||||
/* HIQ is set during driver init period with vmid set to 0*/
|
||||
if (m->cp_hqd_vmid == 0) {
|
||||
uint32_t value, mec, pipe;
|
||||
|
||||
mec = (pipe_id / adev->gfx.mec.num_pipe_per_mec) + 1;
|
||||
pipe = (pipe_id % adev->gfx.mec.num_pipe_per_mec);
|
||||
|
||||
pr_debug("kfd: set HIQ, mec:%d, pipe:%d, queue:%d.\n",
|
||||
mec, pipe, queue_id);
|
||||
value = RREG32(SOC15_REG_OFFSET(GC, 0, mmRLC_CP_SCHEDULERS));
|
||||
value = REG_SET_FIELD(value, RLC_CP_SCHEDULERS, scheduler1,
|
||||
((mec << 5) | (pipe << 3) | queue_id | 0x80));
|
||||
WREG32(SOC15_REG_OFFSET(GC, 0, mmRLC_CP_SCHEDULERS), value);
|
||||
}
|
||||
|
||||
/* HQD registers extend from CP_MQD_BASE_ADDR to CP_HQD_EOP_WPTR_MEM. */
|
||||
mqd_hqd = &m->cp_mqd_base_addr_lo;
|
||||
hqd_base = SOC15_REG_OFFSET(GC, 0, mmCP_MQD_BASE_ADDR);
|
||||
@@ -332,9 +317,10 @@ static int kgd_hqd_load(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id,
|
||||
lower_32_bits((uint64_t)wptr));
|
||||
WREG32(SOC15_REG_OFFSET(GC, 0, mmCP_HQD_PQ_WPTR_POLL_ADDR_HI),
|
||||
upper_32_bits((uint64_t)wptr));
|
||||
pr_debug("%s setting CP_PQ_WPTR_POLL_CNTL1 to %x\n", __func__, get_queue_mask(adev, pipe_id, queue_id));
|
||||
pr_debug("%s setting CP_PQ_WPTR_POLL_CNTL1 to %x\n", __func__,
|
||||
(uint32_t)get_queue_mask(adev, pipe_id, queue_id));
|
||||
WREG32(SOC15_REG_OFFSET(GC, 0, mmCP_PQ_WPTR_POLL_CNTL1),
|
||||
get_queue_mask(adev, pipe_id, queue_id));
|
||||
(uint32_t)get_queue_mask(adev, pipe_id, queue_id));
|
||||
}
|
||||
|
||||
/* Start the EOP fetcher */
|
||||
@@ -350,6 +336,59 @@ static int kgd_hqd_load(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kgd_hiq_mqd_load(struct kgd_dev *kgd, void *mqd,
|
||||
uint32_t pipe_id, uint32_t queue_id,
|
||||
uint32_t doorbell_off)
|
||||
{
|
||||
struct amdgpu_device *adev = get_amdgpu_device(kgd);
|
||||
struct amdgpu_ring *kiq_ring = &adev->gfx.kiq.ring;
|
||||
struct v10_compute_mqd *m;
|
||||
uint32_t mec, pipe;
|
||||
int r;
|
||||
|
||||
m = get_mqd(mqd);
|
||||
|
||||
acquire_queue(kgd, pipe_id, queue_id);
|
||||
|
||||
mec = (pipe_id / adev->gfx.mec.num_pipe_per_mec) + 1;
|
||||
pipe = (pipe_id % adev->gfx.mec.num_pipe_per_mec);
|
||||
|
||||
pr_debug("kfd: set HIQ, mec:%d, pipe:%d, queue:%d.\n",
|
||||
mec, pipe, queue_id);
|
||||
|
||||
spin_lock(&adev->gfx.kiq.ring_lock);
|
||||
r = amdgpu_ring_alloc(kiq_ring, 7);
|
||||
if (r) {
|
||||
pr_err("Failed to alloc KIQ (%d).\n", r);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
amdgpu_ring_write(kiq_ring, PACKET3(PACKET3_MAP_QUEUES, 5));
|
||||
amdgpu_ring_write(kiq_ring,
|
||||
PACKET3_MAP_QUEUES_QUEUE_SEL(0) | /* Queue_Sel */
|
||||
PACKET3_MAP_QUEUES_VMID(m->cp_hqd_vmid) | /* VMID */
|
||||
PACKET3_MAP_QUEUES_QUEUE(queue_id) |
|
||||
PACKET3_MAP_QUEUES_PIPE(pipe) |
|
||||
PACKET3_MAP_QUEUES_ME((mec - 1)) |
|
||||
PACKET3_MAP_QUEUES_QUEUE_TYPE(0) | /*queue_type: normal compute queue */
|
||||
PACKET3_MAP_QUEUES_ALLOC_FORMAT(0) | /* alloc format: all_on_one_pipe */
|
||||
PACKET3_MAP_QUEUES_ENGINE_SEL(1) | /* engine_sel: hiq */
|
||||
PACKET3_MAP_QUEUES_NUM_QUEUES(1)); /* num_queues: must be 1 */
|
||||
amdgpu_ring_write(kiq_ring,
|
||||
PACKET3_MAP_QUEUES_DOORBELL_OFFSET(doorbell_off));
|
||||
amdgpu_ring_write(kiq_ring, m->cp_mqd_base_addr_lo);
|
||||
amdgpu_ring_write(kiq_ring, m->cp_mqd_base_addr_hi);
|
||||
amdgpu_ring_write(kiq_ring, m->cp_hqd_pq_wptr_poll_addr_lo);
|
||||
amdgpu_ring_write(kiq_ring, m->cp_hqd_pq_wptr_poll_addr_hi);
|
||||
amdgpu_ring_commit(kiq_ring);
|
||||
|
||||
out_unlock:
|
||||
spin_unlock(&adev->gfx.kiq.ring_lock);
|
||||
release_queue(kgd);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int kgd_hqd_dump(struct kgd_dev *kgd,
|
||||
uint32_t pipe_id, uint32_t queue_id,
|
||||
uint32_t (**dump)[2], uint32_t *n_regs)
|
||||
@@ -686,71 +725,6 @@ static bool get_atc_vmid_pasid_mapping_info(struct kgd_dev *kgd,
|
||||
return !!(value & ATC_VMID0_PASID_MAPPING__VALID_MASK);
|
||||
}
|
||||
|
||||
static int invalidate_tlbs_with_kiq(struct amdgpu_device *adev, uint16_t pasid)
|
||||
{
|
||||
signed long r;
|
||||
uint32_t seq;
|
||||
struct amdgpu_ring *ring = &adev->gfx.kiq.ring;
|
||||
|
||||
spin_lock(&adev->gfx.kiq.ring_lock);
|
||||
amdgpu_ring_alloc(ring, 12); /* fence + invalidate_tlbs package*/
|
||||
amdgpu_ring_write(ring, PACKET3(PACKET3_INVALIDATE_TLBS, 0));
|
||||
amdgpu_ring_write(ring,
|
||||
PACKET3_INVALIDATE_TLBS_DST_SEL(1) |
|
||||
PACKET3_INVALIDATE_TLBS_PASID(pasid));
|
||||
amdgpu_fence_emit_polling(ring, &seq);
|
||||
amdgpu_ring_commit(ring);
|
||||
spin_unlock(&adev->gfx.kiq.ring_lock);
|
||||
|
||||
r = amdgpu_fence_wait_polling(ring, seq, adev->usec_timeout);
|
||||
if (r < 1) {
|
||||
DRM_ERROR("wait for kiq fence error: %ld.\n", r);
|
||||
return -ETIME;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int invalidate_tlbs(struct kgd_dev *kgd, uint16_t pasid)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *) kgd;
|
||||
int vmid;
|
||||
uint16_t queried_pasid;
|
||||
bool ret;
|
||||
struct amdgpu_ring *ring = &adev->gfx.kiq.ring;
|
||||
|
||||
if (amdgpu_emu_mode == 0 && ring->sched.ready)
|
||||
return invalidate_tlbs_with_kiq(adev, pasid);
|
||||
|
||||
for (vmid = 0; vmid < 16; vmid++) {
|
||||
if (!amdgpu_amdkfd_is_kfd_vmid(adev, vmid))
|
||||
continue;
|
||||
|
||||
ret = get_atc_vmid_pasid_mapping_info(kgd, vmid,
|
||||
&queried_pasid);
|
||||
if (ret && queried_pasid == pasid) {
|
||||
amdgpu_gmc_flush_gpu_tlb(adev, vmid,
|
||||
AMDGPU_GFXHUB_0, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int invalidate_tlbs_vmid(struct kgd_dev *kgd, uint16_t vmid)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *) kgd;
|
||||
|
||||
if (!amdgpu_amdkfd_is_kfd_vmid(adev, vmid)) {
|
||||
pr_err("non kfd vmid %d\n", vmid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
amdgpu_gmc_flush_gpu_tlb(adev, vmid, AMDGPU_GFXHUB_0, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kgd_address_watch_disable(struct kgd_dev *kgd)
|
||||
{
|
||||
return 0;
|
||||
@@ -817,6 +791,7 @@ const struct kfd2kgd_calls gfx_v10_kfd2kgd = {
|
||||
.set_pasid_vmid_mapping = kgd_set_pasid_vmid_mapping,
|
||||
.init_interrupts = kgd_init_interrupts,
|
||||
.hqd_load = kgd_hqd_load,
|
||||
.hiq_mqd_load = kgd_hiq_mqd_load,
|
||||
.hqd_sdma_load = kgd_hqd_sdma_load,
|
||||
.hqd_dump = kgd_hqd_dump,
|
||||
.hqd_sdma_dump = kgd_hqd_sdma_dump,
|
||||
@@ -832,7 +807,5 @@ const struct kfd2kgd_calls gfx_v10_kfd2kgd = {
|
||||
get_atc_vmid_pasid_mapping_info,
|
||||
.get_tile_config = amdgpu_amdkfd_get_tile_config,
|
||||
.set_vm_context_page_table_base = set_vm_context_page_table_base,
|
||||
.invalidate_tlbs = invalidate_tlbs,
|
||||
.invalidate_tlbs_vmid = invalidate_tlbs_vmid,
|
||||
.get_hive_id = amdgpu_amdkfd_get_hive_id,
|
||||
};
|
||||
|
||||
@@ -696,45 +696,6 @@ static void set_vm_context_page_table_base(struct kgd_dev *kgd, uint32_t vmid,
|
||||
lower_32_bits(page_table_base));
|
||||
}
|
||||
|
||||
static int invalidate_tlbs(struct kgd_dev *kgd, uint16_t pasid)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *) kgd;
|
||||
int vmid;
|
||||
unsigned int tmp;
|
||||
|
||||
if (adev->in_gpu_reset)
|
||||
return -EIO;
|
||||
|
||||
for (vmid = 0; vmid < 16; vmid++) {
|
||||
if (!amdgpu_amdkfd_is_kfd_vmid(adev, vmid))
|
||||
continue;
|
||||
|
||||
tmp = RREG32(mmATC_VMID0_PASID_MAPPING + vmid);
|
||||
if ((tmp & ATC_VMID0_PASID_MAPPING__VALID_MASK) &&
|
||||
(tmp & ATC_VMID0_PASID_MAPPING__PASID_MASK) == pasid) {
|
||||
WREG32(mmVM_INVALIDATE_REQUEST, 1 << vmid);
|
||||
RREG32(mmVM_INVALIDATE_RESPONSE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int invalidate_tlbs_vmid(struct kgd_dev *kgd, uint16_t vmid)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *) kgd;
|
||||
|
||||
if (!amdgpu_amdkfd_is_kfd_vmid(adev, vmid)) {
|
||||
pr_err("non kfd vmid\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
WREG32(mmVM_INVALIDATE_REQUEST, 1 << vmid);
|
||||
RREG32(mmVM_INVALIDATE_RESPONSE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* read_vmid_from_vmfault_reg - read vmid from register
|
||||
*
|
||||
@@ -771,7 +732,5 @@ const struct kfd2kgd_calls gfx_v7_kfd2kgd = {
|
||||
.set_scratch_backing_va = set_scratch_backing_va,
|
||||
.get_tile_config = get_tile_config,
|
||||
.set_vm_context_page_table_base = set_vm_context_page_table_base,
|
||||
.invalidate_tlbs = invalidate_tlbs,
|
||||
.invalidate_tlbs_vmid = invalidate_tlbs_vmid,
|
||||
.read_vmid_from_vmfault_reg = read_vmid_from_vmfault_reg,
|
||||
};
|
||||
|
||||
@@ -657,45 +657,6 @@ static void set_vm_context_page_table_base(struct kgd_dev *kgd, uint32_t vmid,
|
||||
lower_32_bits(page_table_base));
|
||||
}
|
||||
|
||||
static int invalidate_tlbs(struct kgd_dev *kgd, uint16_t pasid)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *) kgd;
|
||||
int vmid;
|
||||
unsigned int tmp;
|
||||
|
||||
if (adev->in_gpu_reset)
|
||||
return -EIO;
|
||||
|
||||
for (vmid = 0; vmid < 16; vmid++) {
|
||||
if (!amdgpu_amdkfd_is_kfd_vmid(adev, vmid))
|
||||
continue;
|
||||
|
||||
tmp = RREG32(mmATC_VMID0_PASID_MAPPING + vmid);
|
||||
if ((tmp & ATC_VMID0_PASID_MAPPING__VALID_MASK) &&
|
||||
(tmp & ATC_VMID0_PASID_MAPPING__PASID_MASK) == pasid) {
|
||||
WREG32(mmVM_INVALIDATE_REQUEST, 1 << vmid);
|
||||
RREG32(mmVM_INVALIDATE_RESPONSE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int invalidate_tlbs_vmid(struct kgd_dev *kgd, uint16_t vmid)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *) kgd;
|
||||
|
||||
if (!amdgpu_amdkfd_is_kfd_vmid(adev, vmid)) {
|
||||
pr_err("non kfd vmid %d\n", vmid);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
WREG32(mmVM_INVALIDATE_REQUEST, 1 << vmid);
|
||||
RREG32(mmVM_INVALIDATE_RESPONSE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct kfd2kgd_calls gfx_v8_kfd2kgd = {
|
||||
.program_sh_mem_settings = kgd_program_sh_mem_settings,
|
||||
.set_pasid_vmid_mapping = kgd_set_pasid_vmid_mapping,
|
||||
@@ -717,6 +678,4 @@ const struct kfd2kgd_calls gfx_v8_kfd2kgd = {
|
||||
.set_scratch_backing_va = set_scratch_backing_va,
|
||||
.get_tile_config = get_tile_config,
|
||||
.set_vm_context_page_table_base = set_vm_context_page_table_base,
|
||||
.invalidate_tlbs = invalidate_tlbs,
|
||||
.invalidate_tlbs_vmid = invalidate_tlbs_vmid,
|
||||
};
|
||||
|
||||
@@ -40,7 +40,6 @@
|
||||
#include "soc15d.h"
|
||||
#include "mmhub_v1_0.h"
|
||||
#include "gfxhub_v1_0.h"
|
||||
#include "gmc_v9_0.h"
|
||||
|
||||
|
||||
enum hqd_dequeue_request_type {
|
||||
@@ -104,13 +103,13 @@ static void acquire_queue(struct kgd_dev *kgd, uint32_t pipe_id,
|
||||
lock_srbm(kgd, mec, pipe, queue_id, 0);
|
||||
}
|
||||
|
||||
static uint32_t get_queue_mask(struct amdgpu_device *adev,
|
||||
static uint64_t get_queue_mask(struct amdgpu_device *adev,
|
||||
uint32_t pipe_id, uint32_t queue_id)
|
||||
{
|
||||
unsigned int bit = (pipe_id * adev->gfx.mec.num_queue_per_pipe +
|
||||
queue_id) & 31;
|
||||
unsigned int bit = pipe_id * adev->gfx.mec.num_queue_per_pipe +
|
||||
queue_id;
|
||||
|
||||
return ((uint32_t)1) << bit;
|
||||
return 1ull << bit;
|
||||
}
|
||||
|
||||
static void release_queue(struct kgd_dev *kgd)
|
||||
@@ -259,21 +258,6 @@ int kgd_gfx_v9_hqd_load(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id,
|
||||
|
||||
acquire_queue(kgd, pipe_id, queue_id);
|
||||
|
||||
/* HIQ is set during driver init period with vmid set to 0*/
|
||||
if (m->cp_hqd_vmid == 0) {
|
||||
uint32_t value, mec, pipe;
|
||||
|
||||
mec = (pipe_id / adev->gfx.mec.num_pipe_per_mec) + 1;
|
||||
pipe = (pipe_id % adev->gfx.mec.num_pipe_per_mec);
|
||||
|
||||
pr_debug("kfd: set HIQ, mec:%d, pipe:%d, queue:%d.\n",
|
||||
mec, pipe, queue_id);
|
||||
value = RREG32(SOC15_REG_OFFSET(GC, 0, mmRLC_CP_SCHEDULERS));
|
||||
value = REG_SET_FIELD(value, RLC_CP_SCHEDULERS, scheduler1,
|
||||
((mec << 5) | (pipe << 3) | queue_id | 0x80));
|
||||
WREG32_RLC(SOC15_REG_OFFSET(GC, 0, mmRLC_CP_SCHEDULERS), value);
|
||||
}
|
||||
|
||||
/* HQD registers extend from CP_MQD_BASE_ADDR to CP_HQD_EOP_WPTR_MEM. */
|
||||
mqd_hqd = &m->cp_mqd_base_addr_lo;
|
||||
hqd_base = SOC15_REG_OFFSET(GC, 0, mmCP_MQD_BASE_ADDR);
|
||||
@@ -324,7 +308,7 @@ int kgd_gfx_v9_hqd_load(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id,
|
||||
WREG32_RLC(SOC15_REG_OFFSET(GC, 0, mmCP_HQD_PQ_WPTR_POLL_ADDR_HI),
|
||||
upper_32_bits((uintptr_t)wptr));
|
||||
WREG32(SOC15_REG_OFFSET(GC, 0, mmCP_PQ_WPTR_POLL_CNTL1),
|
||||
get_queue_mask(adev, pipe_id, queue_id));
|
||||
(uint32_t)get_queue_mask(adev, pipe_id, queue_id));
|
||||
}
|
||||
|
||||
/* Start the EOP fetcher */
|
||||
@@ -340,6 +324,59 @@ int kgd_gfx_v9_hqd_load(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kgd_gfx_v9_hiq_mqd_load(struct kgd_dev *kgd, void *mqd,
|
||||
uint32_t pipe_id, uint32_t queue_id,
|
||||
uint32_t doorbell_off)
|
||||
{
|
||||
struct amdgpu_device *adev = get_amdgpu_device(kgd);
|
||||
struct amdgpu_ring *kiq_ring = &adev->gfx.kiq.ring;
|
||||
struct v9_mqd *m;
|
||||
uint32_t mec, pipe;
|
||||
int r;
|
||||
|
||||
m = get_mqd(mqd);
|
||||
|
||||
acquire_queue(kgd, pipe_id, queue_id);
|
||||
|
||||
mec = (pipe_id / adev->gfx.mec.num_pipe_per_mec) + 1;
|
||||
pipe = (pipe_id % adev->gfx.mec.num_pipe_per_mec);
|
||||
|
||||
pr_debug("kfd: set HIQ, mec:%d, pipe:%d, queue:%d.\n",
|
||||
mec, pipe, queue_id);
|
||||
|
||||
spin_lock(&adev->gfx.kiq.ring_lock);
|
||||
r = amdgpu_ring_alloc(kiq_ring, 7);
|
||||
if (r) {
|
||||
pr_err("Failed to alloc KIQ (%d).\n", r);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
amdgpu_ring_write(kiq_ring, PACKET3(PACKET3_MAP_QUEUES, 5));
|
||||
amdgpu_ring_write(kiq_ring,
|
||||
PACKET3_MAP_QUEUES_QUEUE_SEL(0) | /* Queue_Sel */
|
||||
PACKET3_MAP_QUEUES_VMID(m->cp_hqd_vmid) | /* VMID */
|
||||
PACKET3_MAP_QUEUES_QUEUE(queue_id) |
|
||||
PACKET3_MAP_QUEUES_PIPE(pipe) |
|
||||
PACKET3_MAP_QUEUES_ME((mec - 1)) |
|
||||
PACKET3_MAP_QUEUES_QUEUE_TYPE(0) | /*queue_type: normal compute queue */
|
||||
PACKET3_MAP_QUEUES_ALLOC_FORMAT(0) | /* alloc format: all_on_one_pipe */
|
||||
PACKET3_MAP_QUEUES_ENGINE_SEL(1) | /* engine_sel: hiq */
|
||||
PACKET3_MAP_QUEUES_NUM_QUEUES(1)); /* num_queues: must be 1 */
|
||||
amdgpu_ring_write(kiq_ring,
|
||||
PACKET3_MAP_QUEUES_DOORBELL_OFFSET(doorbell_off));
|
||||
amdgpu_ring_write(kiq_ring, m->cp_mqd_base_addr_lo);
|
||||
amdgpu_ring_write(kiq_ring, m->cp_mqd_base_addr_hi);
|
||||
amdgpu_ring_write(kiq_ring, m->cp_hqd_pq_wptr_poll_addr_lo);
|
||||
amdgpu_ring_write(kiq_ring, m->cp_hqd_pq_wptr_poll_addr_hi);
|
||||
amdgpu_ring_commit(kiq_ring);
|
||||
|
||||
out_unlock:
|
||||
spin_unlock(&adev->gfx.kiq.ring_lock);
|
||||
release_queue(kgd);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int kgd_gfx_v9_hqd_dump(struct kgd_dev *kgd,
|
||||
uint32_t pipe_id, uint32_t queue_id,
|
||||
uint32_t (**dump)[2], uint32_t *n_regs)
|
||||
@@ -618,100 +655,6 @@ bool kgd_gfx_v9_get_atc_vmid_pasid_mapping_info(struct kgd_dev *kgd,
|
||||
return !!(value & ATC_VMID0_PASID_MAPPING__VALID_MASK);
|
||||
}
|
||||
|
||||
static int invalidate_tlbs_with_kiq(struct amdgpu_device *adev, uint16_t pasid,
|
||||
uint32_t flush_type)
|
||||
{
|
||||
signed long r;
|
||||
uint32_t seq;
|
||||
struct amdgpu_ring *ring = &adev->gfx.kiq.ring;
|
||||
|
||||
spin_lock(&adev->gfx.kiq.ring_lock);
|
||||
amdgpu_ring_alloc(ring, 12); /* fence + invalidate_tlbs package*/
|
||||
amdgpu_ring_write(ring, PACKET3(PACKET3_INVALIDATE_TLBS, 0));
|
||||
amdgpu_ring_write(ring,
|
||||
PACKET3_INVALIDATE_TLBS_DST_SEL(1) |
|
||||
PACKET3_INVALIDATE_TLBS_ALL_HUB(1) |
|
||||
PACKET3_INVALIDATE_TLBS_PASID(pasid) |
|
||||
PACKET3_INVALIDATE_TLBS_FLUSH_TYPE(flush_type));
|
||||
amdgpu_fence_emit_polling(ring, &seq);
|
||||
amdgpu_ring_commit(ring);
|
||||
spin_unlock(&adev->gfx.kiq.ring_lock);
|
||||
|
||||
r = amdgpu_fence_wait_polling(ring, seq, adev->usec_timeout);
|
||||
if (r < 1) {
|
||||
DRM_ERROR("wait for kiq fence error: %ld.\n", r);
|
||||
return -ETIME;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kgd_gfx_v9_invalidate_tlbs(struct kgd_dev *kgd, uint16_t pasid)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *) kgd;
|
||||
int vmid, i;
|
||||
uint16_t queried_pasid;
|
||||
bool ret;
|
||||
struct amdgpu_ring *ring = &adev->gfx.kiq.ring;
|
||||
uint32_t flush_type = 0;
|
||||
|
||||
if (adev->in_gpu_reset)
|
||||
return -EIO;
|
||||
if (adev->gmc.xgmi.num_physical_nodes &&
|
||||
adev->asic_type == CHIP_VEGA20)
|
||||
flush_type = 2;
|
||||
|
||||
if (ring->sched.ready)
|
||||
return invalidate_tlbs_with_kiq(adev, pasid, flush_type);
|
||||
|
||||
for (vmid = 0; vmid < 16; vmid++) {
|
||||
if (!amdgpu_amdkfd_is_kfd_vmid(adev, vmid))
|
||||
continue;
|
||||
|
||||
ret = kgd_gfx_v9_get_atc_vmid_pasid_mapping_info(kgd, vmid,
|
||||
&queried_pasid);
|
||||
if (ret && queried_pasid == pasid) {
|
||||
for (i = 0; i < adev->num_vmhubs; i++)
|
||||
amdgpu_gmc_flush_gpu_tlb(adev, vmid,
|
||||
i, flush_type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kgd_gfx_v9_invalidate_tlbs_vmid(struct kgd_dev *kgd, uint16_t vmid)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *) kgd;
|
||||
int i;
|
||||
|
||||
if (!amdgpu_amdkfd_is_kfd_vmid(adev, vmid)) {
|
||||
pr_err("non kfd vmid %d\n", vmid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Use legacy mode tlb invalidation.
|
||||
*
|
||||
* Currently on Raven the code below is broken for anything but
|
||||
* legacy mode due to a MMHUB power gating problem. A workaround
|
||||
* is for MMHUB to wait until the condition PER_VMID_INVALIDATE_REQ
|
||||
* == PER_VMID_INVALIDATE_ACK instead of simply waiting for the ack
|
||||
* bit.
|
||||
*
|
||||
* TODO 1: agree on the right set of invalidation registers for
|
||||
* KFD use. Use the last one for now. Invalidate both GC and
|
||||
* MMHUB.
|
||||
*
|
||||
* TODO 2: support range-based invalidation, requires kfg2kgd
|
||||
* interface change
|
||||
*/
|
||||
for (i = 0; i < adev->num_vmhubs; i++)
|
||||
amdgpu_gmc_flush_gpu_tlb(adev, vmid, i, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kgd_gfx_v9_address_watch_disable(struct kgd_dev *kgd)
|
||||
{
|
||||
return 0;
|
||||
@@ -758,8 +701,8 @@ uint32_t kgd_gfx_v9_address_watch_get_offset(struct kgd_dev *kgd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kgd_gfx_v9_set_vm_context_page_table_base(struct kgd_dev *kgd, uint32_t vmid,
|
||||
uint64_t page_table_base)
|
||||
static void kgd_gfx_v9_set_vm_context_page_table_base(struct kgd_dev *kgd,
|
||||
uint32_t vmid, uint64_t page_table_base)
|
||||
{
|
||||
struct amdgpu_device *adev = get_amdgpu_device(kgd);
|
||||
|
||||
@@ -769,16 +712,7 @@ void kgd_gfx_v9_set_vm_context_page_table_base(struct kgd_dev *kgd, uint32_t vmi
|
||||
return;
|
||||
}
|
||||
|
||||
/* TODO: take advantage of per-process address space size. For
|
||||
* now, all processes share the same address space size, like
|
||||
* on GFX8 and older.
|
||||
*/
|
||||
if (adev->asic_type == CHIP_ARCTURUS) {
|
||||
/* Two MMHUBs */
|
||||
mmhub_v9_4_setup_vm_pt_regs(adev, 0, vmid, page_table_base);
|
||||
mmhub_v9_4_setup_vm_pt_regs(adev, 1, vmid, page_table_base);
|
||||
} else
|
||||
mmhub_v1_0_setup_vm_pt_regs(adev, vmid, page_table_base);
|
||||
mmhub_v1_0_setup_vm_pt_regs(adev, vmid, page_table_base);
|
||||
|
||||
gfxhub_v1_0_setup_vm_pt_regs(adev, vmid, page_table_base);
|
||||
}
|
||||
@@ -788,6 +722,7 @@ const struct kfd2kgd_calls gfx_v9_kfd2kgd = {
|
||||
.set_pasid_vmid_mapping = kgd_gfx_v9_set_pasid_vmid_mapping,
|
||||
.init_interrupts = kgd_gfx_v9_init_interrupts,
|
||||
.hqd_load = kgd_gfx_v9_hqd_load,
|
||||
.hiq_mqd_load = kgd_gfx_v9_hiq_mqd_load,
|
||||
.hqd_sdma_load = kgd_hqd_sdma_load,
|
||||
.hqd_dump = kgd_gfx_v9_hqd_dump,
|
||||
.hqd_sdma_dump = kgd_hqd_sdma_dump,
|
||||
@@ -803,7 +738,5 @@ const struct kfd2kgd_calls gfx_v9_kfd2kgd = {
|
||||
kgd_gfx_v9_get_atc_vmid_pasid_mapping_info,
|
||||
.get_tile_config = kgd_gfx_v9_get_tile_config,
|
||||
.set_vm_context_page_table_base = kgd_gfx_v9_set_vm_context_page_table_base,
|
||||
.invalidate_tlbs = kgd_gfx_v9_invalidate_tlbs,
|
||||
.invalidate_tlbs_vmid = kgd_gfx_v9_invalidate_tlbs_vmid,
|
||||
.get_hive_id = amdgpu_amdkfd_get_hive_id,
|
||||
};
|
||||
|
||||
@@ -33,6 +33,9 @@ int kgd_gfx_v9_hqd_load(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id,
|
||||
uint32_t queue_id, uint32_t __user *wptr,
|
||||
uint32_t wptr_shift, uint32_t wptr_mask,
|
||||
struct mm_struct *mm);
|
||||
int kgd_gfx_v9_hiq_mqd_load(struct kgd_dev *kgd, void *mqd,
|
||||
uint32_t pipe_id, uint32_t queue_id,
|
||||
uint32_t doorbell_off);
|
||||
int kgd_gfx_v9_hqd_dump(struct kgd_dev *kgd,
|
||||
uint32_t pipe_id, uint32_t queue_id,
|
||||
uint32_t (**dump)[2], uint32_t *n_regs);
|
||||
@@ -57,9 +60,5 @@ uint32_t kgd_gfx_v9_address_watch_get_offset(struct kgd_dev *kgd,
|
||||
|
||||
bool kgd_gfx_v9_get_atc_vmid_pasid_mapping_info(struct kgd_dev *kgd,
|
||||
uint8_t vmid, uint16_t *p_pasid);
|
||||
void kgd_gfx_v9_set_vm_context_page_table_base(struct kgd_dev *kgd, uint32_t vmid,
|
||||
uint64_t page_table_base);
|
||||
int kgd_gfx_v9_invalidate_tlbs(struct kgd_dev *kgd, uint16_t pasid);
|
||||
int kgd_gfx_v9_invalidate_tlbs_vmid(struct kgd_dev *kgd, uint16_t vmid);
|
||||
int kgd_gfx_v9_get_tile_config(struct kgd_dev *kgd,
|
||||
struct tile_config *config);
|
||||
|
||||
@@ -85,7 +85,7 @@ static bool check_if_add_bo_to_vm(struct amdgpu_vm *avm,
|
||||
}
|
||||
|
||||
/* Set memory usage limits. Current, limits are
|
||||
* System (TTM + userptr) memory - 3/4th System RAM
|
||||
* System (TTM + userptr) memory - 15/16th System RAM
|
||||
* TTM memory - 3/8th System RAM
|
||||
*/
|
||||
void amdgpu_amdkfd_gpuvm_init_mem_limits(void)
|
||||
@@ -98,7 +98,7 @@ void amdgpu_amdkfd_gpuvm_init_mem_limits(void)
|
||||
mem *= si.mem_unit;
|
||||
|
||||
spin_lock_init(&kfd_mem_limit.mem_limit_lock);
|
||||
kfd_mem_limit.max_system_mem_limit = (mem >> 1) + (mem >> 2);
|
||||
kfd_mem_limit.max_system_mem_limit = mem - (mem >> 4);
|
||||
kfd_mem_limit.max_ttm_mem_limit = (mem >> 1) - (mem >> 3);
|
||||
pr_debug("Kernel memory limit %lluM, TTM limit %lluM\n",
|
||||
(kfd_mem_limit.max_system_mem_limit >> 20),
|
||||
@@ -358,7 +358,7 @@ static int vm_update_pds(struct amdgpu_vm *vm, struct amdgpu_sync *sync)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return amdgpu_sync_fence(NULL, sync, vm->last_update, false);
|
||||
return amdgpu_sync_fence(sync, vm->last_update, false);
|
||||
}
|
||||
|
||||
static uint64_t get_pte_flags(struct amdgpu_device *adev, struct kgd_mem *mem)
|
||||
@@ -750,7 +750,7 @@ static int unmap_bo_from_gpuvm(struct amdgpu_device *adev,
|
||||
|
||||
amdgpu_vm_clear_freed(adev, vm, &bo_va->last_pt_update);
|
||||
|
||||
amdgpu_sync_fence(NULL, sync, bo_va->last_pt_update, false);
|
||||
amdgpu_sync_fence(sync, bo_va->last_pt_update, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -769,7 +769,7 @@ static int update_gpuvm_pte(struct amdgpu_device *adev,
|
||||
return ret;
|
||||
}
|
||||
|
||||
return amdgpu_sync_fence(NULL, sync, bo_va->last_pt_update, false);
|
||||
return amdgpu_sync_fence(sync, bo_va->last_pt_update, false);
|
||||
}
|
||||
|
||||
static int map_bo_to_gpuvm(struct amdgpu_device *adev,
|
||||
@@ -1674,10 +1674,10 @@ int amdgpu_amdkfd_evict_userptr(struct kgd_mem *mem,
|
||||
struct mm_struct *mm)
|
||||
{
|
||||
struct amdkfd_process_info *process_info = mem->process_info;
|
||||
int invalid, evicted_bos;
|
||||
int evicted_bos;
|
||||
int r = 0;
|
||||
|
||||
invalid = atomic_inc_return(&mem->invalid);
|
||||
atomic_inc(&mem->invalid);
|
||||
evicted_bos = atomic_inc_return(&process_info->evicted_bos);
|
||||
if (evicted_bos == 1) {
|
||||
/* First eviction, stop the queues */
|
||||
@@ -2048,7 +2048,7 @@ int amdgpu_amdkfd_gpuvm_restore_process_bos(void *info, struct dma_fence **ef)
|
||||
pr_debug("Memory eviction: Validate BOs failed. Try again\n");
|
||||
goto validate_map_fail;
|
||||
}
|
||||
ret = amdgpu_sync_fence(NULL, &sync_obj, bo->tbo.moving, false);
|
||||
ret = amdgpu_sync_fence(&sync_obj, bo->tbo.moving, false);
|
||||
if (ret) {
|
||||
pr_debug("Memory eviction: Sync BO fence failed. Try again\n");
|
||||
goto validate_map_fail;
|
||||
|
||||
@@ -338,17 +338,9 @@ bool amdgpu_atombios_get_connector_info_from_object_table(struct amdgpu_device *
|
||||
path_size += le16_to_cpu(path->usSize);
|
||||
|
||||
if (device_support & le16_to_cpu(path->usDeviceTag)) {
|
||||
uint8_t con_obj_id, con_obj_num, con_obj_type;
|
||||
|
||||
con_obj_id =
|
||||
uint8_t con_obj_id =
|
||||
(le16_to_cpu(path->usConnObjectId) & OBJECT_ID_MASK)
|
||||
>> OBJECT_ID_SHIFT;
|
||||
con_obj_num =
|
||||
(le16_to_cpu(path->usConnObjectId) & ENUM_ID_MASK)
|
||||
>> ENUM_ID_SHIFT;
|
||||
con_obj_type =
|
||||
(le16_to_cpu(path->usConnObjectId) &
|
||||
OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT;
|
||||
|
||||
/* Skip TV/CV support */
|
||||
if ((le16_to_cpu(path->usDeviceTag) ==
|
||||
@@ -373,15 +365,7 @@ bool amdgpu_atombios_get_connector_info_from_object_table(struct amdgpu_device *
|
||||
router.ddc_valid = false;
|
||||
router.cd_valid = false;
|
||||
for (j = 0; j < ((le16_to_cpu(path->usSize) - 8) / 2); j++) {
|
||||
uint8_t grph_obj_id, grph_obj_num, grph_obj_type;
|
||||
|
||||
grph_obj_id =
|
||||
(le16_to_cpu(path->usGraphicObjIds[j]) &
|
||||
OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
|
||||
grph_obj_num =
|
||||
(le16_to_cpu(path->usGraphicObjIds[j]) &
|
||||
ENUM_ID_MASK) >> ENUM_ID_SHIFT;
|
||||
grph_obj_type =
|
||||
uint8_t grph_obj_type =
|
||||
(le16_to_cpu(path->usGraphicObjIds[j]) &
|
||||
OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT;
|
||||
|
||||
@@ -2038,7 +2022,7 @@ int amdgpu_atombios_init(struct amdgpu_device *adev)
|
||||
if (adev->is_atom_fw) {
|
||||
amdgpu_atomfirmware_scratch_regs_init(adev);
|
||||
amdgpu_atomfirmware_allocate_fb_scratch(adev);
|
||||
ret = amdgpu_atomfirmware_get_mem_train_fb_loc(adev);
|
||||
ret = amdgpu_atomfirmware_get_mem_train_info(adev);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to get mem train fb location.\n");
|
||||
return ret;
|
||||
|
||||
@@ -525,16 +525,12 @@ static int gddr6_mem_train_support(struct amdgpu_device *adev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int amdgpu_atomfirmware_get_mem_train_fb_loc(struct amdgpu_device *adev)
|
||||
int amdgpu_atomfirmware_get_mem_train_info(struct amdgpu_device *adev)
|
||||
{
|
||||
struct atom_context *ctx = adev->mode_info.atom_context;
|
||||
unsigned char *bios = ctx->bios;
|
||||
struct vram_reserve_block *reserved_block;
|
||||
int index, block_number;
|
||||
int index;
|
||||
uint8_t frev, crev;
|
||||
uint16_t data_offset, size;
|
||||
uint32_t start_address_in_kb;
|
||||
uint64_t offset;
|
||||
int ret;
|
||||
|
||||
adev->fw_vram_usage.mem_train_support = false;
|
||||
@@ -569,32 +565,6 @@ int amdgpu_atomfirmware_get_mem_train_fb_loc(struct amdgpu_device *adev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
reserved_block = (struct vram_reserve_block *)
|
||||
(bios + data_offset + sizeof(struct atom_common_table_header));
|
||||
block_number = ((unsigned int)size - sizeof(struct atom_common_table_header))
|
||||
/ sizeof(struct vram_reserve_block);
|
||||
reserved_block += (block_number > 0) ? block_number-1 : 0;
|
||||
DRM_DEBUG("block_number:0x%04x, last block: 0x%08xkb sz, %dkb fw, %dkb drv.\n",
|
||||
block_number,
|
||||
le32_to_cpu(reserved_block->start_address_in_kb),
|
||||
le16_to_cpu(reserved_block->used_by_firmware_in_kb),
|
||||
le16_to_cpu(reserved_block->used_by_driver_in_kb));
|
||||
if (reserved_block->used_by_firmware_in_kb > 0) {
|
||||
start_address_in_kb = le32_to_cpu(reserved_block->start_address_in_kb);
|
||||
offset = (uint64_t)start_address_in_kb * ONE_KiB;
|
||||
if ((offset & (ONE_MiB - 1)) < (4 * ONE_KiB + 1) ) {
|
||||
offset -= ONE_MiB;
|
||||
}
|
||||
|
||||
offset &= ~(ONE_MiB - 1);
|
||||
adev->fw_vram_usage.mem_train_fb_loc = offset;
|
||||
adev->fw_vram_usage.mem_train_support = true;
|
||||
DRM_DEBUG("mem_train_fb_loc:0x%09llx.\n", offset);
|
||||
ret = 0;
|
||||
} else {
|
||||
DRM_ERROR("used_by_firmware_in_kb is 0!\n");
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
adev->fw_vram_usage.mem_train_support = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ void amdgpu_atomfirmware_scratch_regs_init(struct amdgpu_device *adev);
|
||||
int amdgpu_atomfirmware_allocate_fb_scratch(struct amdgpu_device *adev);
|
||||
int amdgpu_atomfirmware_get_vram_info(struct amdgpu_device *adev,
|
||||
int *vram_width, int *vram_type, int *vram_vendor);
|
||||
int amdgpu_atomfirmware_get_mem_train_fb_loc(struct amdgpu_device *adev);
|
||||
int amdgpu_atomfirmware_get_mem_train_info(struct amdgpu_device *adev);
|
||||
int amdgpu_atomfirmware_get_clock_info(struct amdgpu_device *adev);
|
||||
int amdgpu_atomfirmware_get_gfx_info(struct amdgpu_device *adev);
|
||||
bool amdgpu_atomfirmware_mem_ecc_supported(struct amdgpu_device *adev);
|
||||
|
||||
@@ -795,29 +795,23 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p)
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = amdgpu_sync_fence(adev, &p->job->sync,
|
||||
fpriv->prt_va->last_pt_update, false);
|
||||
r = amdgpu_sync_vm_fence(&p->job->sync, fpriv->prt_va->last_pt_update);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (amdgpu_mcbp || amdgpu_sriov_vf(adev)) {
|
||||
struct dma_fence *f;
|
||||
|
||||
bo_va = fpriv->csa_va;
|
||||
BUG_ON(!bo_va);
|
||||
r = amdgpu_vm_bo_update(adev, bo_va, false);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
f = bo_va->last_pt_update;
|
||||
r = amdgpu_sync_fence(adev, &p->job->sync, f, false);
|
||||
r = amdgpu_sync_vm_fence(&p->job->sync, bo_va->last_pt_update);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
amdgpu_bo_list_for_each_entry(e, p->bo_list) {
|
||||
struct dma_fence *f;
|
||||
|
||||
/* ignore duplicates */
|
||||
bo = ttm_to_amdgpu_bo(e->tv.bo);
|
||||
if (!bo)
|
||||
@@ -831,8 +825,7 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p)
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
f = bo_va->last_pt_update;
|
||||
r = amdgpu_sync_fence(adev, &p->job->sync, f, false);
|
||||
r = amdgpu_sync_vm_fence(&p->job->sync, bo_va->last_pt_update);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
@@ -845,7 +838,7 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p)
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = amdgpu_sync_fence(adev, &p->job->sync, vm->last_update, false);
|
||||
r = amdgpu_sync_vm_fence(&p->job->sync, vm->last_update);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
@@ -916,6 +909,11 @@ static int amdgpu_cs_ib_fill(struct amdgpu_device *adev,
|
||||
if (parser->entity && parser->entity != entity)
|
||||
return -EINVAL;
|
||||
|
||||
/* Return if there is no run queue associated with this entity.
|
||||
* Possibly because of disabled HW IP*/
|
||||
if (entity->rq == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
parser->entity = entity;
|
||||
|
||||
ring = to_amdgpu_ring(entity->rq->sched);
|
||||
@@ -987,7 +985,7 @@ static int amdgpu_cs_process_fence_dep(struct amdgpu_cs_parser *p,
|
||||
dma_fence_put(old);
|
||||
}
|
||||
|
||||
r = amdgpu_sync_fence(p->adev, &p->job->sync, fence, true);
|
||||
r = amdgpu_sync_fence(&p->job->sync, fence, true);
|
||||
dma_fence_put(fence);
|
||||
if (r)
|
||||
return r;
|
||||
@@ -1009,7 +1007,7 @@ static int amdgpu_syncobj_lookup_and_add_to_sync(struct amdgpu_cs_parser *p,
|
||||
return r;
|
||||
}
|
||||
|
||||
r = amdgpu_sync_fence(p->adev, &p->job->sync, fence, true);
|
||||
r = amdgpu_sync_fence(&p->job->sync, fence, true);
|
||||
dma_fence_put(fence);
|
||||
|
||||
return r;
|
||||
@@ -1236,7 +1234,6 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p,
|
||||
goto error_abort;
|
||||
}
|
||||
|
||||
job->owner = p->filp;
|
||||
p->fence = dma_fence_get(&job->base.s_fence->finished);
|
||||
|
||||
amdgpu_ctx_add_fence(p->ctx, entity, p->fence, &seq);
|
||||
|
||||
@@ -74,7 +74,7 @@ static int amdgpu_ctx_init(struct amdgpu_device *adev,
|
||||
struct amdgpu_ctx *ctx)
|
||||
{
|
||||
unsigned num_entities = amdgpu_ctx_total_num_entities();
|
||||
unsigned i, j, k;
|
||||
unsigned i, j;
|
||||
int r;
|
||||
|
||||
if (priority < 0 || priority >= DRM_SCHED_PRIORITY_MAX)
|
||||
@@ -121,72 +121,57 @@ static int amdgpu_ctx_init(struct amdgpu_device *adev,
|
||||
ctx->override_priority = DRM_SCHED_PRIORITY_UNSET;
|
||||
|
||||
for (i = 0; i < AMDGPU_HW_IP_NUM; ++i) {
|
||||
struct amdgpu_ring *rings[AMDGPU_MAX_RINGS];
|
||||
struct drm_sched_rq *rqs[AMDGPU_MAX_RINGS];
|
||||
unsigned num_rings = 0;
|
||||
unsigned num_rqs = 0;
|
||||
struct drm_gpu_scheduler **scheds;
|
||||
struct drm_gpu_scheduler *sched;
|
||||
unsigned num_scheds = 0;
|
||||
|
||||
switch (i) {
|
||||
case AMDGPU_HW_IP_GFX:
|
||||
rings[0] = &adev->gfx.gfx_ring[0];
|
||||
num_rings = 1;
|
||||
sched = &adev->gfx.gfx_ring[0].sched;
|
||||
scheds = &sched;
|
||||
num_scheds = 1;
|
||||
break;
|
||||
case AMDGPU_HW_IP_COMPUTE:
|
||||
for (j = 0; j < adev->gfx.num_compute_rings; ++j)
|
||||
rings[j] = &adev->gfx.compute_ring[j];
|
||||
num_rings = adev->gfx.num_compute_rings;
|
||||
scheds = adev->gfx.compute_sched;
|
||||
num_scheds = adev->gfx.num_compute_sched;
|
||||
break;
|
||||
case AMDGPU_HW_IP_DMA:
|
||||
for (j = 0; j < adev->sdma.num_instances; ++j)
|
||||
rings[j] = &adev->sdma.instance[j].ring;
|
||||
num_rings = adev->sdma.num_instances;
|
||||
scheds = adev->sdma.sdma_sched;
|
||||
num_scheds = adev->sdma.num_sdma_sched;
|
||||
break;
|
||||
case AMDGPU_HW_IP_UVD:
|
||||
rings[0] = &adev->uvd.inst[0].ring;
|
||||
num_rings = 1;
|
||||
sched = &adev->uvd.inst[0].ring.sched;
|
||||
scheds = &sched;
|
||||
num_scheds = 1;
|
||||
break;
|
||||
case AMDGPU_HW_IP_VCE:
|
||||
rings[0] = &adev->vce.ring[0];
|
||||
num_rings = 1;
|
||||
sched = &adev->vce.ring[0].sched;
|
||||
scheds = &sched;
|
||||
num_scheds = 1;
|
||||
break;
|
||||
case AMDGPU_HW_IP_UVD_ENC:
|
||||
rings[0] = &adev->uvd.inst[0].ring_enc[0];
|
||||
num_rings = 1;
|
||||
sched = &adev->uvd.inst[0].ring_enc[0].sched;
|
||||
scheds = &sched;
|
||||
num_scheds = 1;
|
||||
break;
|
||||
case AMDGPU_HW_IP_VCN_DEC:
|
||||
for (j = 0; j < adev->vcn.num_vcn_inst; ++j) {
|
||||
if (adev->vcn.harvest_config & (1 << j))
|
||||
continue;
|
||||
rings[num_rings++] = &adev->vcn.inst[j].ring_dec;
|
||||
}
|
||||
scheds = adev->vcn.vcn_dec_sched;
|
||||
num_scheds = adev->vcn.num_vcn_dec_sched;
|
||||
break;
|
||||
case AMDGPU_HW_IP_VCN_ENC:
|
||||
for (j = 0; j < adev->vcn.num_vcn_inst; ++j) {
|
||||
if (adev->vcn.harvest_config & (1 << j))
|
||||
continue;
|
||||
for (k = 0; k < adev->vcn.num_enc_rings; ++k)
|
||||
rings[num_rings++] = &adev->vcn.inst[j].ring_enc[k];
|
||||
}
|
||||
scheds = adev->vcn.vcn_enc_sched;
|
||||
num_scheds = adev->vcn.num_vcn_enc_sched;
|
||||
break;
|
||||
case AMDGPU_HW_IP_VCN_JPEG:
|
||||
for (j = 0; j < adev->vcn.num_vcn_inst; ++j) {
|
||||
if (adev->vcn.harvest_config & (1 << j))
|
||||
continue;
|
||||
rings[num_rings++] = &adev->vcn.inst[j].ring_jpeg;
|
||||
}
|
||||
scheds = adev->jpeg.jpeg_sched;
|
||||
num_scheds = adev->jpeg.num_jpeg_sched;
|
||||
break;
|
||||
}
|
||||
|
||||
for (j = 0; j < num_rings; ++j) {
|
||||
if (!rings[j]->adev)
|
||||
continue;
|
||||
|
||||
rqs[num_rqs++] = &rings[j]->sched.sched_rq[priority];
|
||||
}
|
||||
|
||||
for (j = 0; j < amdgpu_ctx_num_entities[i]; ++j)
|
||||
r = drm_sched_entity_init(&ctx->entities[i][j].entity,
|
||||
rqs, num_rqs, &ctx->guilty);
|
||||
priority, scheds,
|
||||
num_scheds, &ctx->guilty);
|
||||
if (r)
|
||||
goto error_cleanup_entities;
|
||||
}
|
||||
@@ -627,3 +612,45 @@ void amdgpu_ctx_mgr_fini(struct amdgpu_ctx_mgr *mgr)
|
||||
idr_destroy(&mgr->ctx_handles);
|
||||
mutex_destroy(&mgr->lock);
|
||||
}
|
||||
|
||||
void amdgpu_ctx_init_sched(struct amdgpu_device *adev)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < adev->gfx.num_gfx_rings; i++) {
|
||||
adev->gfx.gfx_sched[i] = &adev->gfx.gfx_ring[i].sched;
|
||||
adev->gfx.num_gfx_sched++;
|
||||
}
|
||||
|
||||
for (i = 0; i < adev->gfx.num_compute_rings; i++) {
|
||||
adev->gfx.compute_sched[i] = &adev->gfx.compute_ring[i].sched;
|
||||
adev->gfx.num_compute_sched++;
|
||||
}
|
||||
|
||||
for (i = 0; i < adev->sdma.num_instances; i++) {
|
||||
adev->sdma.sdma_sched[i] = &adev->sdma.instance[i].ring.sched;
|
||||
adev->sdma.num_sdma_sched++;
|
||||
}
|
||||
|
||||
for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
|
||||
if (adev->vcn.harvest_config & (1 << i))
|
||||
continue;
|
||||
adev->vcn.vcn_dec_sched[adev->vcn.num_vcn_dec_sched++] =
|
||||
&adev->vcn.inst[i].ring_dec.sched;
|
||||
}
|
||||
|
||||
for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
|
||||
if (adev->vcn.harvest_config & (1 << i))
|
||||
continue;
|
||||
for (j = 0; j < adev->vcn.num_enc_rings; ++j)
|
||||
adev->vcn.vcn_enc_sched[adev->vcn.num_vcn_enc_sched++] =
|
||||
&adev->vcn.inst[i].ring_enc[j].sched;
|
||||
}
|
||||
|
||||
for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) {
|
||||
if (adev->jpeg.harvest_config & (1 << i))
|
||||
continue;
|
||||
adev->jpeg.jpeg_sched[adev->jpeg.num_jpeg_sched++] =
|
||||
&adev->jpeg.inst[i].ring_dec.sched;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,4 +87,7 @@ void amdgpu_ctx_mgr_entity_fini(struct amdgpu_ctx_mgr *mgr);
|
||||
long amdgpu_ctx_mgr_entity_flush(struct amdgpu_ctx_mgr *mgr, long timeout);
|
||||
void amdgpu_ctx_mgr_fini(struct amdgpu_ctx_mgr *mgr);
|
||||
|
||||
void amdgpu_ctx_init_sched(struct amdgpu_device *adev);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include <drm/drm_debugfs.h>
|
||||
|
||||
@@ -129,7 +130,7 @@ static int amdgpu_debugfs_process_reg_op(bool read, struct file *f,
|
||||
sh_bank = 0xFFFFFFFF;
|
||||
if (instance_bank == 0x3FF)
|
||||
instance_bank = 0xFFFFFFFF;
|
||||
use_bank = 1;
|
||||
use_bank = true;
|
||||
} else if (*pos & (1ULL << 61)) {
|
||||
|
||||
me = (*pos & GENMASK_ULL(33, 24)) >> 24;
|
||||
@@ -137,17 +138,24 @@ static int amdgpu_debugfs_process_reg_op(bool read, struct file *f,
|
||||
queue = (*pos & GENMASK_ULL(53, 44)) >> 44;
|
||||
vmid = (*pos & GENMASK_ULL(58, 54)) >> 54;
|
||||
|
||||
use_ring = 1;
|
||||
use_ring = true;
|
||||
} else {
|
||||
use_bank = use_ring = 0;
|
||||
use_bank = use_ring = false;
|
||||
}
|
||||
|
||||
*pos &= (1UL << 22) - 1;
|
||||
|
||||
r = pm_runtime_get_sync(adev->ddev->dev);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (use_bank) {
|
||||
if ((sh_bank != 0xFFFFFFFF && sh_bank >= adev->gfx.config.max_sh_per_se) ||
|
||||
(se_bank != 0xFFFFFFFF && se_bank >= adev->gfx.config.max_shader_engines))
|
||||
(se_bank != 0xFFFFFFFF && se_bank >= adev->gfx.config.max_shader_engines)) {
|
||||
pm_runtime_mark_last_busy(adev->ddev->dev);
|
||||
pm_runtime_put_autosuspend(adev->ddev->dev);
|
||||
return -EINVAL;
|
||||
}
|
||||
mutex_lock(&adev->grbm_idx_mutex);
|
||||
amdgpu_gfx_select_se_sh(adev, se_bank,
|
||||
sh_bank, instance_bank);
|
||||
@@ -193,6 +201,9 @@ end:
|
||||
if (pm_pg_lock)
|
||||
mutex_unlock(&adev->pm.mutex);
|
||||
|
||||
pm_runtime_mark_last_busy(adev->ddev->dev);
|
||||
pm_runtime_put_autosuspend(adev->ddev->dev);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -237,13 +248,20 @@ static ssize_t amdgpu_debugfs_regs_pcie_read(struct file *f, char __user *buf,
|
||||
if (size & 0x3 || *pos & 0x3)
|
||||
return -EINVAL;
|
||||
|
||||
r = pm_runtime_get_sync(adev->ddev->dev);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
while (size) {
|
||||
uint32_t value;
|
||||
|
||||
value = RREG32_PCIE(*pos >> 2);
|
||||
r = put_user(value, (uint32_t *)buf);
|
||||
if (r)
|
||||
if (r) {
|
||||
pm_runtime_mark_last_busy(adev->ddev->dev);
|
||||
pm_runtime_put_autosuspend(adev->ddev->dev);
|
||||
return r;
|
||||
}
|
||||
|
||||
result += 4;
|
||||
buf += 4;
|
||||
@@ -251,6 +269,9 @@ static ssize_t amdgpu_debugfs_regs_pcie_read(struct file *f, char __user *buf,
|
||||
size -= 4;
|
||||
}
|
||||
|
||||
pm_runtime_mark_last_busy(adev->ddev->dev);
|
||||
pm_runtime_put_autosuspend(adev->ddev->dev);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -276,12 +297,19 @@ static ssize_t amdgpu_debugfs_regs_pcie_write(struct file *f, const char __user
|
||||
if (size & 0x3 || *pos & 0x3)
|
||||
return -EINVAL;
|
||||
|
||||
r = pm_runtime_get_sync(adev->ddev->dev);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
while (size) {
|
||||
uint32_t value;
|
||||
|
||||
r = get_user(value, (uint32_t *)buf);
|
||||
if (r)
|
||||
if (r) {
|
||||
pm_runtime_mark_last_busy(adev->ddev->dev);
|
||||
pm_runtime_put_autosuspend(adev->ddev->dev);
|
||||
return r;
|
||||
}
|
||||
|
||||
WREG32_PCIE(*pos >> 2, value);
|
||||
|
||||
@@ -291,6 +319,9 @@ static ssize_t amdgpu_debugfs_regs_pcie_write(struct file *f, const char __user
|
||||
size -= 4;
|
||||
}
|
||||
|
||||
pm_runtime_mark_last_busy(adev->ddev->dev);
|
||||
pm_runtime_put_autosuspend(adev->ddev->dev);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -316,13 +347,20 @@ static ssize_t amdgpu_debugfs_regs_didt_read(struct file *f, char __user *buf,
|
||||
if (size & 0x3 || *pos & 0x3)
|
||||
return -EINVAL;
|
||||
|
||||
r = pm_runtime_get_sync(adev->ddev->dev);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
while (size) {
|
||||
uint32_t value;
|
||||
|
||||
value = RREG32_DIDT(*pos >> 2);
|
||||
r = put_user(value, (uint32_t *)buf);
|
||||
if (r)
|
||||
if (r) {
|
||||
pm_runtime_mark_last_busy(adev->ddev->dev);
|
||||
pm_runtime_put_autosuspend(adev->ddev->dev);
|
||||
return r;
|
||||
}
|
||||
|
||||
result += 4;
|
||||
buf += 4;
|
||||
@@ -330,6 +368,9 @@ static ssize_t amdgpu_debugfs_regs_didt_read(struct file *f, char __user *buf,
|
||||
size -= 4;
|
||||
}
|
||||
|
||||
pm_runtime_mark_last_busy(adev->ddev->dev);
|
||||
pm_runtime_put_autosuspend(adev->ddev->dev);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -355,12 +396,19 @@ static ssize_t amdgpu_debugfs_regs_didt_write(struct file *f, const char __user
|
||||
if (size & 0x3 || *pos & 0x3)
|
||||
return -EINVAL;
|
||||
|
||||
r = pm_runtime_get_sync(adev->ddev->dev);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
while (size) {
|
||||
uint32_t value;
|
||||
|
||||
r = get_user(value, (uint32_t *)buf);
|
||||
if (r)
|
||||
if (r) {
|
||||
pm_runtime_mark_last_busy(adev->ddev->dev);
|
||||
pm_runtime_put_autosuspend(adev->ddev->dev);
|
||||
return r;
|
||||
}
|
||||
|
||||
WREG32_DIDT(*pos >> 2, value);
|
||||
|
||||
@@ -370,6 +418,9 @@ static ssize_t amdgpu_debugfs_regs_didt_write(struct file *f, const char __user
|
||||
size -= 4;
|
||||
}
|
||||
|
||||
pm_runtime_mark_last_busy(adev->ddev->dev);
|
||||
pm_runtime_put_autosuspend(adev->ddev->dev);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -395,13 +446,20 @@ static ssize_t amdgpu_debugfs_regs_smc_read(struct file *f, char __user *buf,
|
||||
if (size & 0x3 || *pos & 0x3)
|
||||
return -EINVAL;
|
||||
|
||||
r = pm_runtime_get_sync(adev->ddev->dev);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
while (size) {
|
||||
uint32_t value;
|
||||
|
||||
value = RREG32_SMC(*pos);
|
||||
r = put_user(value, (uint32_t *)buf);
|
||||
if (r)
|
||||
if (r) {
|
||||
pm_runtime_mark_last_busy(adev->ddev->dev);
|
||||
pm_runtime_put_autosuspend(adev->ddev->dev);
|
||||
return r;
|
||||
}
|
||||
|
||||
result += 4;
|
||||
buf += 4;
|
||||
@@ -409,6 +467,9 @@ static ssize_t amdgpu_debugfs_regs_smc_read(struct file *f, char __user *buf,
|
||||
size -= 4;
|
||||
}
|
||||
|
||||
pm_runtime_mark_last_busy(adev->ddev->dev);
|
||||
pm_runtime_put_autosuspend(adev->ddev->dev);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -434,12 +495,19 @@ static ssize_t amdgpu_debugfs_regs_smc_write(struct file *f, const char __user *
|
||||
if (size & 0x3 || *pos & 0x3)
|
||||
return -EINVAL;
|
||||
|
||||
r = pm_runtime_get_sync(adev->ddev->dev);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
while (size) {
|
||||
uint32_t value;
|
||||
|
||||
r = get_user(value, (uint32_t *)buf);
|
||||
if (r)
|
||||
if (r) {
|
||||
pm_runtime_mark_last_busy(adev->ddev->dev);
|
||||
pm_runtime_put_autosuspend(adev->ddev->dev);
|
||||
return r;
|
||||
}
|
||||
|
||||
WREG32_SMC(*pos, value);
|
||||
|
||||
@@ -449,6 +517,9 @@ static ssize_t amdgpu_debugfs_regs_smc_write(struct file *f, const char __user *
|
||||
size -= 4;
|
||||
}
|
||||
|
||||
pm_runtime_mark_last_busy(adev->ddev->dev);
|
||||
pm_runtime_put_autosuspend(adev->ddev->dev);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -572,7 +643,16 @@ static ssize_t amdgpu_debugfs_sensor_read(struct file *f, char __user *buf,
|
||||
idx = *pos >> 2;
|
||||
|
||||
valuesize = sizeof(values);
|
||||
|
||||
r = pm_runtime_get_sync(adev->ddev->dev);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = amdgpu_dpm_read_sensor(adev, idx, &values[0], &valuesize);
|
||||
|
||||
pm_runtime_mark_last_busy(adev->ddev->dev);
|
||||
pm_runtime_put_autosuspend(adev->ddev->dev);
|
||||
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
@@ -633,6 +713,10 @@ static ssize_t amdgpu_debugfs_wave_read(struct file *f, char __user *buf,
|
||||
wave = (*pos & GENMASK_ULL(36, 31)) >> 31;
|
||||
simd = (*pos & GENMASK_ULL(44, 37)) >> 37;
|
||||
|
||||
r = pm_runtime_get_sync(adev->ddev->dev);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* switch to the specific se/sh/cu */
|
||||
mutex_lock(&adev->grbm_idx_mutex);
|
||||
amdgpu_gfx_select_se_sh(adev, se, sh, cu);
|
||||
@@ -644,6 +728,9 @@ static ssize_t amdgpu_debugfs_wave_read(struct file *f, char __user *buf,
|
||||
amdgpu_gfx_select_se_sh(adev, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF);
|
||||
mutex_unlock(&adev->grbm_idx_mutex);
|
||||
|
||||
pm_runtime_mark_last_busy(adev->ddev->dev);
|
||||
pm_runtime_put_autosuspend(adev->ddev->dev);
|
||||
|
||||
if (!x)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -711,6 +798,10 @@ static ssize_t amdgpu_debugfs_gpr_read(struct file *f, char __user *buf,
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
r = pm_runtime_get_sync(adev->ddev->dev);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* switch to the specific se/sh/cu */
|
||||
mutex_lock(&adev->grbm_idx_mutex);
|
||||
amdgpu_gfx_select_se_sh(adev, se, sh, cu);
|
||||
@@ -726,6 +817,9 @@ static ssize_t amdgpu_debugfs_gpr_read(struct file *f, char __user *buf,
|
||||
amdgpu_gfx_select_se_sh(adev, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF);
|
||||
mutex_unlock(&adev->grbm_idx_mutex);
|
||||
|
||||
pm_runtime_mark_last_busy(adev->ddev->dev);
|
||||
pm_runtime_put_autosuspend(adev->ddev->dev);
|
||||
|
||||
while (size) {
|
||||
uint32_t value;
|
||||
|
||||
@@ -859,6 +953,10 @@ static int amdgpu_debugfs_test_ib(struct seq_file *m, void *data)
|
||||
struct amdgpu_device *adev = dev->dev_private;
|
||||
int r = 0, i;
|
||||
|
||||
r = pm_runtime_get_sync(dev->dev);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Avoid accidently unparking the sched thread during GPU reset */
|
||||
mutex_lock(&adev->lock_reset);
|
||||
|
||||
@@ -889,6 +987,9 @@ static int amdgpu_debugfs_test_ib(struct seq_file *m, void *data)
|
||||
|
||||
mutex_unlock(&adev->lock_reset);
|
||||
|
||||
pm_runtime_mark_last_busy(dev->dev);
|
||||
pm_runtime_put_autosuspend(dev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -907,8 +1008,17 @@ static int amdgpu_debugfs_evict_vram(struct seq_file *m, void *data)
|
||||
struct drm_info_node *node = (struct drm_info_node *)m->private;
|
||||
struct drm_device *dev = node->minor->dev;
|
||||
struct amdgpu_device *adev = dev->dev_private;
|
||||
int r;
|
||||
|
||||
r = pm_runtime_get_sync(dev->dev);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
seq_printf(m, "(%d)\n", amdgpu_bo_evict_vram(adev));
|
||||
|
||||
pm_runtime_mark_last_busy(dev->dev);
|
||||
pm_runtime_put_autosuspend(dev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -917,8 +1027,17 @@ static int amdgpu_debugfs_evict_gtt(struct seq_file *m, void *data)
|
||||
struct drm_info_node *node = (struct drm_info_node *)m->private;
|
||||
struct drm_device *dev = node->minor->dev;
|
||||
struct amdgpu_device *adev = dev->dev_private;
|
||||
int r;
|
||||
|
||||
r = pm_runtime_get_sync(dev->dev);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
seq_printf(m, "(%d)\n", ttm_bo_evict_mm(&adev->mman.bdev, TTM_PL_TT));
|
||||
|
||||
pm_runtime_mark_last_busy(dev->dev);
|
||||
pm_runtime_put_autosuspend(dev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -66,6 +66,7 @@
|
||||
#include "amdgpu_pmu.h"
|
||||
|
||||
#include <linux/suspend.h>
|
||||
#include <drm/task_barrier.h>
|
||||
|
||||
MODULE_FIRMWARE("amdgpu/vega10_gpu_info.bin");
|
||||
MODULE_FIRMWARE("amdgpu/vega12_gpu_info.bin");
|
||||
@@ -137,14 +138,14 @@ static DEVICE_ATTR(pcie_replay_count, S_IRUGO,
|
||||
static void amdgpu_device_get_pcie_info(struct amdgpu_device *adev);
|
||||
|
||||
/**
|
||||
* amdgpu_device_is_px - Is the device is a dGPU with HG/PX power control
|
||||
* amdgpu_device_supports_boco - Is the device a dGPU with HG/PX power control
|
||||
*
|
||||
* @dev: drm_device pointer
|
||||
*
|
||||
* Returns true if the device is a dGPU with HG/PX power control,
|
||||
* otherwise return false.
|
||||
*/
|
||||
bool amdgpu_device_is_px(struct drm_device *dev)
|
||||
bool amdgpu_device_supports_boco(struct drm_device *dev)
|
||||
{
|
||||
struct amdgpu_device *adev = dev->dev_private;
|
||||
|
||||
@@ -153,6 +154,21 @@ bool amdgpu_device_is_px(struct drm_device *dev)
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_device_supports_baco - Does the device support BACO
|
||||
*
|
||||
* @dev: drm_device pointer
|
||||
*
|
||||
* Returns true if the device supporte BACO,
|
||||
* otherwise return false.
|
||||
*/
|
||||
bool amdgpu_device_supports_baco(struct drm_device *dev)
|
||||
{
|
||||
struct amdgpu_device *adev = dev->dev_private;
|
||||
|
||||
return amdgpu_asic_supports_baco(adev);
|
||||
}
|
||||
|
||||
/**
|
||||
* VRAM access helper functions.
|
||||
*
|
||||
@@ -1016,8 +1032,6 @@ def_value:
|
||||
*/
|
||||
static int amdgpu_device_check_arguments(struct amdgpu_device *adev)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (amdgpu_sched_jobs < 4) {
|
||||
dev_warn(adev->dev, "sched jobs (%d) must be at least 4\n",
|
||||
amdgpu_sched_jobs);
|
||||
@@ -1057,7 +1071,7 @@ static int amdgpu_device_check_arguments(struct amdgpu_device *adev)
|
||||
|
||||
adev->firmware.load_type = amdgpu_ucode_get_load_type(adev, amdgpu_fw_load_type);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1072,8 +1086,9 @@ static int amdgpu_device_check_arguments(struct amdgpu_device *adev)
|
||||
static void amdgpu_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_state state)
|
||||
{
|
||||
struct drm_device *dev = pci_get_drvdata(pdev);
|
||||
int r;
|
||||
|
||||
if (amdgpu_device_is_px(dev) && state == VGA_SWITCHEROO_OFF)
|
||||
if (amdgpu_device_supports_boco(dev) && state == VGA_SWITCHEROO_OFF)
|
||||
return;
|
||||
|
||||
if (state == VGA_SWITCHEROO_ON) {
|
||||
@@ -1081,7 +1096,12 @@ static void amdgpu_switcheroo_set_state(struct pci_dev *pdev, enum vga_switchero
|
||||
/* don't suspend or resume card normally */
|
||||
dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
|
||||
|
||||
amdgpu_device_resume(dev, true, true);
|
||||
pci_set_power_state(dev->pdev, PCI_D0);
|
||||
pci_restore_state(dev->pdev);
|
||||
r = pci_enable_device(dev->pdev);
|
||||
if (r)
|
||||
DRM_WARN("pci_enable_device failed (%d)\n", r);
|
||||
amdgpu_device_resume(dev, true);
|
||||
|
||||
dev->switch_power_state = DRM_SWITCH_POWER_ON;
|
||||
drm_kms_helper_poll_enable(dev);
|
||||
@@ -1089,7 +1109,11 @@ static void amdgpu_switcheroo_set_state(struct pci_dev *pdev, enum vga_switchero
|
||||
pr_info("amdgpu: switched off\n");
|
||||
drm_kms_helper_poll_disable(dev);
|
||||
dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
|
||||
amdgpu_device_suspend(dev, true, true);
|
||||
amdgpu_device_suspend(dev, true);
|
||||
pci_save_state(dev->pdev);
|
||||
/* Shut down the device */
|
||||
pci_disable_device(dev->pdev);
|
||||
pci_set_power_state(dev->pdev, PCI_D3cold);
|
||||
dev->switch_power_state = DRM_SWITCH_POWER_OFF;
|
||||
}
|
||||
}
|
||||
@@ -1527,7 +1551,6 @@ static int amdgpu_device_parse_gpu_info_fw(struct amdgpu_device *adev)
|
||||
}
|
||||
|
||||
parse_soc_bounding_box:
|
||||
#ifdef CONFIG_DRM_AMD_DC_DCN2_0
|
||||
/*
|
||||
* soc bounding box info is not integrated in disocovery table,
|
||||
* we always need to parse it from gpu info firmware.
|
||||
@@ -1538,7 +1561,6 @@ parse_soc_bounding_box:
|
||||
le32_to_cpu(hdr->header.ucode_array_offset_bytes));
|
||||
adev->dm.soc_bounding_box = &gpu_info_fw->soc_bounding_box;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -1787,7 +1809,8 @@ static int amdgpu_device_fw_loading(struct amdgpu_device *adev)
|
||||
}
|
||||
}
|
||||
|
||||
r = amdgpu_pm_load_smu_firmware(adev, &smu_version);
|
||||
if (!amdgpu_sriov_vf(adev) || adev->asic_type == CHIP_TONGA)
|
||||
r = amdgpu_pm_load_smu_firmware(adev, &smu_version);
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -1854,6 +1877,9 @@ static int amdgpu_device_ip_init(struct amdgpu_device *adev)
|
||||
}
|
||||
}
|
||||
|
||||
if (amdgpu_sriov_vf(adev))
|
||||
amdgpu_virt_init_data_exchange(adev);
|
||||
|
||||
r = amdgpu_ib_pool_init(adev);
|
||||
if (r) {
|
||||
dev_err(adev->dev, "IB initialization failed (%d).\n", r);
|
||||
@@ -1895,11 +1921,8 @@ static int amdgpu_device_ip_init(struct amdgpu_device *adev)
|
||||
amdgpu_amdkfd_device_init(adev);
|
||||
|
||||
init_failed:
|
||||
if (amdgpu_sriov_vf(adev)) {
|
||||
if (!r)
|
||||
amdgpu_virt_init_data_exchange(adev);
|
||||
if (amdgpu_sriov_vf(adev))
|
||||
amdgpu_virt_release_full_gpu(adev, true);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -1938,6 +1961,7 @@ static bool amdgpu_device_check_vram_lost(struct amdgpu_device *adev)
|
||||
* amdgpu_device_set_cg_state - set clockgating for amdgpu device
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
* @state: clockgating state (gate or ungate)
|
||||
*
|
||||
* The list of all the hardware IPs that make up the asic is walked and the
|
||||
* set_clockgating_state callbacks are run.
|
||||
@@ -1962,6 +1986,7 @@ static int amdgpu_device_set_cg_state(struct amdgpu_device *adev,
|
||||
if (adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_UVD &&
|
||||
adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_VCE &&
|
||||
adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_VCN &&
|
||||
adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_JPEG &&
|
||||
adev->ip_blocks[i].version->funcs->set_clockgating_state) {
|
||||
/* enable clockgating to save power */
|
||||
r = adev->ip_blocks[i].version->funcs->set_clockgating_state((void *)adev,
|
||||
@@ -1992,6 +2017,7 @@ static int amdgpu_device_set_pg_state(struct amdgpu_device *adev, enum amd_power
|
||||
if (adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_UVD &&
|
||||
adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_VCE &&
|
||||
adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_VCN &&
|
||||
adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_JPEG &&
|
||||
adev->ip_blocks[i].version->funcs->set_powergating_state) {
|
||||
/* enable powergating to save power */
|
||||
r = adev->ip_blocks[i].version->funcs->set_powergating_state((void *)adev,
|
||||
@@ -2319,14 +2345,7 @@ static int amdgpu_device_ip_suspend_phase2(struct amdgpu_device *adev)
|
||||
adev->ip_blocks[i].status.hw = false;
|
||||
/* handle putting the SMC in the appropriate state */
|
||||
if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_SMC) {
|
||||
if (is_support_sw_smu(adev)) {
|
||||
r = smu_set_mp1_state(&adev->smu, adev->mp1_state);
|
||||
} else if (adev->powerplay.pp_funcs &&
|
||||
adev->powerplay.pp_funcs->set_mp1_state) {
|
||||
r = adev->powerplay.pp_funcs->set_mp1_state(
|
||||
adev->powerplay.pp_handle,
|
||||
adev->mp1_state);
|
||||
}
|
||||
r = amdgpu_dpm_set_mp1_state(adev, adev->mp1_state);
|
||||
if (r) {
|
||||
DRM_ERROR("SMC failed to set mp1 state %d, %d\n",
|
||||
adev->mp1_state, r);
|
||||
@@ -2413,7 +2432,8 @@ static int amdgpu_device_ip_reinit_late_sriov(struct amdgpu_device *adev)
|
||||
AMD_IP_BLOCK_TYPE_GFX,
|
||||
AMD_IP_BLOCK_TYPE_SDMA,
|
||||
AMD_IP_BLOCK_TYPE_UVD,
|
||||
AMD_IP_BLOCK_TYPE_VCE
|
||||
AMD_IP_BLOCK_TYPE_VCE,
|
||||
AMD_IP_BLOCK_TYPE_VCN
|
||||
};
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ip_order); i++) {
|
||||
@@ -2428,7 +2448,11 @@ static int amdgpu_device_ip_reinit_late_sriov(struct amdgpu_device *adev)
|
||||
block->status.hw)
|
||||
continue;
|
||||
|
||||
r = block->version->funcs->hw_init(adev);
|
||||
if (block->version->type == AMD_IP_BLOCK_TYPE_SMC)
|
||||
r = block->version->funcs->resume(adev);
|
||||
else
|
||||
r = block->version->funcs->hw_init(adev);
|
||||
|
||||
DRM_INFO("RE-INIT-late: %s %s\n", block->version->funcs->name, r?"failed":"succeeded");
|
||||
if (r)
|
||||
return r;
|
||||
@@ -2600,20 +2624,19 @@ bool amdgpu_device_asic_has_dc_support(enum amd_asic_type asic_type)
|
||||
case CHIP_VEGA10:
|
||||
case CHIP_VEGA12:
|
||||
case CHIP_VEGA20:
|
||||
#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
|
||||
#if defined(CONFIG_DRM_AMD_DC_DCN)
|
||||
case CHIP_RAVEN:
|
||||
#endif
|
||||
#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
|
||||
case CHIP_NAVI10:
|
||||
case CHIP_NAVI14:
|
||||
case CHIP_NAVI12:
|
||||
#endif
|
||||
#if defined(CONFIG_DRM_AMD_DC_DCN2_1)
|
||||
case CHIP_RENOIR:
|
||||
#endif
|
||||
return amdgpu_dc != 0;
|
||||
#endif
|
||||
default:
|
||||
if (amdgpu_dc > 0)
|
||||
DRM_INFO("Display Core has been requested via kernel parameter "
|
||||
"but isn't supported by ASIC, ignoring\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -2638,8 +2661,38 @@ static void amdgpu_device_xgmi_reset_func(struct work_struct *__work)
|
||||
{
|
||||
struct amdgpu_device *adev =
|
||||
container_of(__work, struct amdgpu_device, xgmi_reset_work);
|
||||
struct amdgpu_hive_info *hive = amdgpu_get_xgmi_hive(adev, 0);
|
||||
|
||||
adev->asic_reset_res = amdgpu_asic_reset(adev);
|
||||
/* It's a bug to not have a hive within this function */
|
||||
if (WARN_ON(!hive))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Use task barrier to synchronize all xgmi reset works across the
|
||||
* hive. task_barrier_enter and task_barrier_exit will block
|
||||
* until all the threads running the xgmi reset works reach
|
||||
* those points. task_barrier_full will do both blocks.
|
||||
*/
|
||||
if (amdgpu_asic_reset_method(adev) == AMD_RESET_METHOD_BACO) {
|
||||
|
||||
task_barrier_enter(&hive->tb);
|
||||
adev->asic_reset_res = amdgpu_device_baco_enter(adev->ddev);
|
||||
|
||||
if (adev->asic_reset_res)
|
||||
goto fail;
|
||||
|
||||
task_barrier_exit(&hive->tb);
|
||||
adev->asic_reset_res = amdgpu_device_baco_exit(adev->ddev);
|
||||
|
||||
if (adev->asic_reset_res)
|
||||
goto fail;
|
||||
} else {
|
||||
|
||||
task_barrier_full(&hive->tb);
|
||||
adev->asic_reset_res = amdgpu_asic_reset(adev);
|
||||
}
|
||||
|
||||
fail:
|
||||
if (adev->asic_reset_res)
|
||||
DRM_WARN("ASIC reset failed with error, %d for drm dev, %s",
|
||||
adev->asic_reset_res, adev->ddev->unique);
|
||||
@@ -2731,7 +2784,7 @@ int amdgpu_device_init(struct amdgpu_device *adev,
|
||||
uint32_t flags)
|
||||
{
|
||||
int r, i;
|
||||
bool runtime = false;
|
||||
bool boco = false;
|
||||
u32 max_MBps;
|
||||
|
||||
adev->shutdown = false;
|
||||
@@ -2754,7 +2807,7 @@ int amdgpu_device_init(struct amdgpu_device *adev,
|
||||
adev->mman.buffer_funcs = NULL;
|
||||
adev->mman.buffer_funcs_ring = NULL;
|
||||
adev->vm_manager.vm_pte_funcs = NULL;
|
||||
adev->vm_manager.vm_pte_num_rqs = 0;
|
||||
adev->vm_manager.vm_pte_num_scheds = 0;
|
||||
adev->gmc.gmc_funcs = NULL;
|
||||
adev->fence_context = dma_fence_context_alloc(AMDGPU_MAX_RINGS);
|
||||
bitmap_zero(adev->gfx.pipe_reserve_bitmap, AMDGPU_MAX_COMPUTE_QUEUES);
|
||||
@@ -2794,9 +2847,8 @@ int amdgpu_device_init(struct amdgpu_device *adev,
|
||||
mutex_init(&adev->virt.vf_errors.lock);
|
||||
hash_init(adev->mn_hash);
|
||||
mutex_init(&adev->lock_reset);
|
||||
mutex_init(&adev->notifier_lock);
|
||||
mutex_init(&adev->virt.dpm_mutex);
|
||||
mutex_init(&adev->psp.mutex);
|
||||
mutex_init(&adev->notifier_lock);
|
||||
|
||||
r = amdgpu_device_check_arguments(adev);
|
||||
if (r)
|
||||
@@ -2902,12 +2954,15 @@ int amdgpu_device_init(struct amdgpu_device *adev,
|
||||
* ignore it */
|
||||
vga_client_register(adev->pdev, adev, NULL, amdgpu_device_vga_set_decode);
|
||||
|
||||
if (amdgpu_device_is_px(ddev))
|
||||
runtime = true;
|
||||
if (!pci_is_thunderbolt_attached(adev->pdev))
|
||||
if (amdgpu_device_supports_boco(ddev))
|
||||
boco = true;
|
||||
if (amdgpu_has_atpx() &&
|
||||
(amdgpu_is_atpx_hybrid() ||
|
||||
amdgpu_has_atpx_dgpu_power_cntl()) &&
|
||||
!pci_is_thunderbolt_attached(adev->pdev))
|
||||
vga_switcheroo_register_client(adev->pdev,
|
||||
&amdgpu_switcheroo_ops, runtime);
|
||||
if (runtime)
|
||||
&amdgpu_switcheroo_ops, boco);
|
||||
if (boco)
|
||||
vga_switcheroo_init_domain_pm_ops(adev->dev, &adev->vga_pm_domain);
|
||||
|
||||
if (amdgpu_emu_mode == 1) {
|
||||
@@ -2994,11 +3049,17 @@ fence_driver_init:
|
||||
}
|
||||
dev_err(adev->dev, "amdgpu_device_ip_init failed\n");
|
||||
amdgpu_vf_error_put(adev, AMDGIM_ERROR_VF_AMDGPU_INIT_FAIL, 0, 0);
|
||||
if (amdgpu_virt_request_full_gpu(adev, false))
|
||||
amdgpu_virt_release_full_gpu(adev, false);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
DRM_DEBUG("SE %d, SH per SE %d, CU per SH %d, active_cu_number %d\n",
|
||||
adev->gfx.config.max_shader_engines,
|
||||
adev->gfx.config.max_sh_per_se,
|
||||
adev->gfx.config.max_cu_per_sh,
|
||||
adev->gfx.cu_info.number);
|
||||
|
||||
amdgpu_ctx_init_sched(adev);
|
||||
|
||||
adev->accel_working = true;
|
||||
|
||||
amdgpu_vm_check_compute_bug(adev);
|
||||
@@ -3013,16 +3074,19 @@ fence_driver_init:
|
||||
|
||||
amdgpu_fbdev_init(adev);
|
||||
|
||||
if (amdgpu_sriov_vf(adev) && amdgim_is_hwperf(adev))
|
||||
amdgpu_pm_virt_sysfs_init(adev);
|
||||
|
||||
r = amdgpu_pm_sysfs_init(adev);
|
||||
if (r)
|
||||
if (r) {
|
||||
adev->pm_sysfs_en = false;
|
||||
DRM_ERROR("registering pm debugfs failed (%d).\n", r);
|
||||
} else
|
||||
adev->pm_sysfs_en = true;
|
||||
|
||||
r = amdgpu_ucode_sysfs_init(adev);
|
||||
if (r)
|
||||
if (r) {
|
||||
adev->ucode_sysfs_en = false;
|
||||
DRM_ERROR("Creating firmware sysfs failed (%d).\n", r);
|
||||
} else
|
||||
adev->ucode_sysfs_en = true;
|
||||
|
||||
r = amdgpu_debugfs_gem_init(adev);
|
||||
if (r)
|
||||
@@ -3091,7 +3155,7 @@ fence_driver_init:
|
||||
|
||||
failed:
|
||||
amdgpu_vf_error_trans_all(adev);
|
||||
if (runtime)
|
||||
if (boco)
|
||||
vga_switcheroo_fini_domain_pm_ops(adev->dev);
|
||||
|
||||
return r;
|
||||
@@ -3122,7 +3186,8 @@ void amdgpu_device_fini(struct amdgpu_device *adev)
|
||||
drm_atomic_helper_shutdown(adev->ddev);
|
||||
}
|
||||
amdgpu_fence_driver_fini(adev);
|
||||
amdgpu_pm_sysfs_fini(adev);
|
||||
if (adev->pm_sysfs_en)
|
||||
amdgpu_pm_sysfs_fini(adev);
|
||||
amdgpu_fbdev_fini(adev);
|
||||
r = amdgpu_device_ip_fini(adev);
|
||||
if (adev->firmware.gpu_info_fw) {
|
||||
@@ -3139,9 +3204,12 @@ void amdgpu_device_fini(struct amdgpu_device *adev)
|
||||
|
||||
kfree(adev->bios);
|
||||
adev->bios = NULL;
|
||||
if (!pci_is_thunderbolt_attached(adev->pdev))
|
||||
if (amdgpu_has_atpx() &&
|
||||
(amdgpu_is_atpx_hybrid() ||
|
||||
amdgpu_has_atpx_dgpu_power_cntl()) &&
|
||||
!pci_is_thunderbolt_attached(adev->pdev))
|
||||
vga_switcheroo_unregister_client(adev->pdev);
|
||||
if (adev->flags & AMD_IS_PX)
|
||||
if (amdgpu_device_supports_boco(adev->ddev))
|
||||
vga_switcheroo_fini_domain_pm_ops(adev->dev);
|
||||
vga_client_register(adev->pdev, NULL, NULL, NULL);
|
||||
if (adev->rio_mem)
|
||||
@@ -3150,12 +3218,11 @@ void amdgpu_device_fini(struct amdgpu_device *adev)
|
||||
iounmap(adev->rmmio);
|
||||
adev->rmmio = NULL;
|
||||
amdgpu_device_doorbell_fini(adev);
|
||||
if (amdgpu_sriov_vf(adev) && amdgim_is_hwperf(adev))
|
||||
amdgpu_pm_virt_sysfs_fini(adev);
|
||||
|
||||
amdgpu_debugfs_regs_cleanup(adev);
|
||||
device_remove_file(adev->dev, &dev_attr_pcie_replay_count);
|
||||
amdgpu_ucode_sysfs_fini(adev);
|
||||
if (adev->ucode_sysfs_en)
|
||||
amdgpu_ucode_sysfs_fini(adev);
|
||||
if (IS_ENABLED(CONFIG_PERF_EVENTS))
|
||||
amdgpu_pmu_fini(adev);
|
||||
amdgpu_debugfs_preempt_cleanup(adev);
|
||||
@@ -3178,7 +3245,7 @@ void amdgpu_device_fini(struct amdgpu_device *adev)
|
||||
* Returns 0 for success or an error on failure.
|
||||
* Called at driver suspend.
|
||||
*/
|
||||
int amdgpu_device_suspend(struct drm_device *dev, bool suspend, bool fbcon)
|
||||
int amdgpu_device_suspend(struct drm_device *dev, bool fbcon)
|
||||
{
|
||||
struct amdgpu_device *adev;
|
||||
struct drm_crtc *crtc;
|
||||
@@ -3261,13 +3328,6 @@ int amdgpu_device_suspend(struct drm_device *dev, bool suspend, bool fbcon)
|
||||
*/
|
||||
amdgpu_bo_evict_vram(adev);
|
||||
|
||||
if (suspend) {
|
||||
pci_save_state(dev->pdev);
|
||||
/* Shut down the device */
|
||||
pci_disable_device(dev->pdev);
|
||||
pci_set_power_state(dev->pdev, PCI_D3hot);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3282,7 +3342,7 @@ int amdgpu_device_suspend(struct drm_device *dev, bool suspend, bool fbcon)
|
||||
* Returns 0 for success or an error on failure.
|
||||
* Called at driver resume.
|
||||
*/
|
||||
int amdgpu_device_resume(struct drm_device *dev, bool resume, bool fbcon)
|
||||
int amdgpu_device_resume(struct drm_device *dev, bool fbcon)
|
||||
{
|
||||
struct drm_connector *connector;
|
||||
struct drm_connector_list_iter iter;
|
||||
@@ -3293,14 +3353,6 @@ int amdgpu_device_resume(struct drm_device *dev, bool resume, bool fbcon)
|
||||
if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
|
||||
return 0;
|
||||
|
||||
if (resume) {
|
||||
pci_set_power_state(dev->pdev, PCI_D0);
|
||||
pci_restore_state(dev->pdev);
|
||||
r = pci_enable_device(dev->pdev);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
/* post card */
|
||||
if (amdgpu_device_need_post(adev)) {
|
||||
r = amdgpu_atom_asic_init(adev->mode_info.atom_context);
|
||||
@@ -3639,13 +3691,12 @@ static int amdgpu_device_reset_sriov(struct amdgpu_device *adev,
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
amdgpu_amdkfd_pre_reset(adev);
|
||||
|
||||
/* Resume IP prior to SMC */
|
||||
r = amdgpu_device_ip_reinit_early_sriov(adev);
|
||||
if (r)
|
||||
goto error;
|
||||
|
||||
amdgpu_virt_init_data_exchange(adev);
|
||||
/* we need recover gart prior to run SMC/CP/SDMA resume */
|
||||
amdgpu_gtt_mgr_recover(&adev->mman.bdev.man[TTM_PL_TT]);
|
||||
|
||||
@@ -3663,7 +3714,6 @@ static int amdgpu_device_reset_sriov(struct amdgpu_device *adev,
|
||||
amdgpu_amdkfd_post_reset(adev);
|
||||
|
||||
error:
|
||||
amdgpu_virt_init_data_exchange(adev);
|
||||
amdgpu_virt_release_full_gpu(adev, true);
|
||||
if (!r && adev->virt.gim_feature & AMDGIM_FEATURE_GIM_FLR_VRAMLOST) {
|
||||
amdgpu_inc_vram_lost(adev);
|
||||
@@ -3709,6 +3759,7 @@ bool amdgpu_device_should_recover_gpu(struct amdgpu_device *adev)
|
||||
case CHIP_VEGA10:
|
||||
case CHIP_VEGA12:
|
||||
case CHIP_RAVEN:
|
||||
case CHIP_ARCTURUS:
|
||||
break;
|
||||
default:
|
||||
goto disabled;
|
||||
@@ -3785,7 +3836,7 @@ static int amdgpu_do_asic_reset(struct amdgpu_hive_info *hive,
|
||||
list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) {
|
||||
/* For XGMI run all resets in parallel to speed up the process */
|
||||
if (tmp_adev->gmc.xgmi.num_physical_nodes > 1) {
|
||||
if (!queue_work(system_highpri_wq, &tmp_adev->xgmi_reset_work))
|
||||
if (!queue_work(system_unbound_wq, &tmp_adev->xgmi_reset_work))
|
||||
r = -EALREADY;
|
||||
} else
|
||||
r = amdgpu_asic_reset(tmp_adev);
|
||||
@@ -3797,7 +3848,7 @@ static int amdgpu_do_asic_reset(struct amdgpu_hive_info *hive,
|
||||
}
|
||||
}
|
||||
|
||||
/* For XGMI wait for all PSP resets to complete before proceed */
|
||||
/* For XGMI wait for all resets to complete before proceed */
|
||||
if (!r) {
|
||||
list_for_each_entry(tmp_adev, device_list_handle,
|
||||
gmc.xgmi.head) {
|
||||
@@ -3811,6 +3862,8 @@ static int amdgpu_do_asic_reset(struct amdgpu_hive_info *hive,
|
||||
}
|
||||
}
|
||||
|
||||
if (!r && amdgpu_ras_intr_triggered())
|
||||
amdgpu_ras_intr_cleared();
|
||||
|
||||
list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) {
|
||||
if (need_full_reset) {
|
||||
@@ -3899,7 +3952,7 @@ static bool amdgpu_device_lock_adev(struct amdgpu_device *adev, bool trylock)
|
||||
mutex_lock(&adev->lock_reset);
|
||||
|
||||
atomic_inc(&adev->gpu_reset_counter);
|
||||
adev->in_gpu_reset = 1;
|
||||
adev->in_gpu_reset = true;
|
||||
switch (amdgpu_asic_reset_method(adev)) {
|
||||
case AMD_RESET_METHOD_MODE1:
|
||||
adev->mp1_state = PP_MP1_STATE_SHUTDOWN;
|
||||
@@ -3919,7 +3972,7 @@ static void amdgpu_device_unlock_adev(struct amdgpu_device *adev)
|
||||
{
|
||||
amdgpu_vf_error_trans_all(adev);
|
||||
adev->mp1_state = PP_MP1_STATE_NONE;
|
||||
adev->in_gpu_reset = 0;
|
||||
adev->in_gpu_reset = false;
|
||||
mutex_unlock(&adev->lock_reset);
|
||||
}
|
||||
|
||||
@@ -3943,12 +3996,15 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
|
||||
struct amdgpu_device *tmp_adev = NULL;
|
||||
int i, r = 0;
|
||||
bool in_ras_intr = amdgpu_ras_intr_triggered();
|
||||
bool use_baco =
|
||||
(amdgpu_asic_reset_method(adev) == AMD_RESET_METHOD_BACO) ?
|
||||
true : false;
|
||||
|
||||
/*
|
||||
* Flush RAM to disk so that after reboot
|
||||
* the user can read log and see why the system rebooted.
|
||||
*/
|
||||
if (in_ras_intr && amdgpu_ras_get_context(adev)->reboot) {
|
||||
if (in_ras_intr && !use_baco && amdgpu_ras_get_context(adev)->reboot) {
|
||||
|
||||
DRM_WARN("Emergency reboot.");
|
||||
|
||||
@@ -3959,7 +4015,8 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
|
||||
need_full_reset = job_signaled = false;
|
||||
INIT_LIST_HEAD(&device_list);
|
||||
|
||||
dev_info(adev->dev, "GPU %s begin!\n", in_ras_intr ? "jobs stop":"reset");
|
||||
dev_info(adev->dev, "GPU %s begin!\n",
|
||||
(in_ras_intr && !use_baco) ? "jobs stop":"reset");
|
||||
|
||||
cancel_delayed_work_sync(&adev->delayed_init_work);
|
||||
|
||||
@@ -4026,7 +4083,8 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
|
||||
amdgpu_unregister_gpu_instance(tmp_adev);
|
||||
|
||||
/* disable ras on ALL IPs */
|
||||
if (!in_ras_intr && amdgpu_device_ip_need_full_reset(tmp_adev))
|
||||
if (!(in_ras_intr && !use_baco) &&
|
||||
amdgpu_device_ip_need_full_reset(tmp_adev))
|
||||
amdgpu_ras_suspend(tmp_adev);
|
||||
|
||||
for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
|
||||
@@ -4037,13 +4095,13 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
|
||||
|
||||
drm_sched_stop(&ring->sched, job ? &job->base : NULL);
|
||||
|
||||
if (in_ras_intr)
|
||||
if (in_ras_intr && !use_baco)
|
||||
amdgpu_job_stop_all_jobs_on_sched(&ring->sched);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (in_ras_intr)
|
||||
if (in_ras_intr && !use_baco)
|
||||
goto skip_sched_resume;
|
||||
|
||||
/*
|
||||
@@ -4136,7 +4194,7 @@ skip_hw_reset:
|
||||
skip_sched_resume:
|
||||
list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) {
|
||||
/*unlock kfd: SRIOV would do it separately */
|
||||
if (!in_ras_intr && !amdgpu_sriov_vf(tmp_adev))
|
||||
if (!(in_ras_intr && !use_baco) && !amdgpu_sriov_vf(tmp_adev))
|
||||
amdgpu_amdkfd_post_reset(tmp_adev);
|
||||
amdgpu_device_unlock_adev(tmp_adev);
|
||||
}
|
||||
@@ -4285,3 +4343,35 @@ static void amdgpu_device_get_pcie_info(struct amdgpu_device *adev)
|
||||
}
|
||||
}
|
||||
|
||||
int amdgpu_device_baco_enter(struct drm_device *dev)
|
||||
{
|
||||
struct amdgpu_device *adev = dev->dev_private;
|
||||
struct amdgpu_ras *ras = amdgpu_ras_get_context(adev);
|
||||
|
||||
if (!amdgpu_device_supports_baco(adev->ddev))
|
||||
return -ENOTSUPP;
|
||||
|
||||
if (ras && ras->supported)
|
||||
adev->nbio.funcs->enable_doorbell_interrupt(adev, false);
|
||||
|
||||
return amdgpu_dpm_baco_enter(adev);
|
||||
}
|
||||
|
||||
int amdgpu_device_baco_exit(struct drm_device *dev)
|
||||
{
|
||||
struct amdgpu_device *adev = dev->dev_private;
|
||||
struct amdgpu_ras *ras = amdgpu_ras_get_context(adev);
|
||||
int ret = 0;
|
||||
|
||||
if (!amdgpu_device_supports_baco(adev->ddev))
|
||||
return -ENOTSUPP;
|
||||
|
||||
ret = amdgpu_dpm_baco_exit(adev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (ras && ras->supported)
|
||||
adev->nbio.funcs->enable_doorbell_interrupt(adev, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
62
drivers/gpu/drm/amd/amdgpu/amdgpu_df.h
Normal file
62
drivers/gpu/drm/amd/amdgpu/amdgpu_df.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2020 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __AMDGPU_DF_H__
|
||||
#define __AMDGPU_DF_H__
|
||||
|
||||
struct amdgpu_df_hash_status {
|
||||
bool hash_64k;
|
||||
bool hash_2m;
|
||||
bool hash_1g;
|
||||
};
|
||||
|
||||
struct amdgpu_df_funcs {
|
||||
void (*sw_init)(struct amdgpu_device *adev);
|
||||
void (*sw_fini)(struct amdgpu_device *adev);
|
||||
void (*enable_broadcast_mode)(struct amdgpu_device *adev,
|
||||
bool enable);
|
||||
u32 (*get_fb_channel_number)(struct amdgpu_device *adev);
|
||||
u32 (*get_hbm_channel_number)(struct amdgpu_device *adev);
|
||||
void (*update_medium_grain_clock_gating)(struct amdgpu_device *adev,
|
||||
bool enable);
|
||||
void (*get_clockgating_state)(struct amdgpu_device *adev,
|
||||
u32 *flags);
|
||||
void (*enable_ecc_force_par_wr_rmw)(struct amdgpu_device *adev,
|
||||
bool enable);
|
||||
int (*pmc_start)(struct amdgpu_device *adev, uint64_t config,
|
||||
int is_enable);
|
||||
int (*pmc_stop)(struct amdgpu_device *adev, uint64_t config,
|
||||
int is_disable);
|
||||
void (*pmc_get_count)(struct amdgpu_device *adev, uint64_t config,
|
||||
uint64_t *count);
|
||||
uint64_t (*get_fica)(struct amdgpu_device *adev, uint32_t ficaa_val);
|
||||
void (*set_fica)(struct amdgpu_device *adev, uint32_t ficaa_val,
|
||||
uint32_t ficadl_val, uint32_t ficadh_val);
|
||||
};
|
||||
|
||||
struct amdgpu_df {
|
||||
struct amdgpu_df_hash_status hash_status;
|
||||
const struct amdgpu_df_funcs *funcs;
|
||||
};
|
||||
|
||||
#endif /* __AMDGPU_DF_H__ */
|
||||
@@ -513,13 +513,23 @@ uint32_t amdgpu_display_supported_domains(struct amdgpu_device *adev,
|
||||
* will not allow USWC mappings.
|
||||
* Also, don't allow GTT domain if the BO doens't have USWC falg set.
|
||||
*/
|
||||
if (adev->asic_type >= CHIP_CARRIZO &&
|
||||
adev->asic_type < CHIP_RAVEN &&
|
||||
(adev->flags & AMD_IS_APU) &&
|
||||
(bo_flags & AMDGPU_GEM_CREATE_CPU_GTT_USWC) &&
|
||||
if ((bo_flags & AMDGPU_GEM_CREATE_CPU_GTT_USWC) &&
|
||||
amdgpu_bo_support_uswc(bo_flags) &&
|
||||
amdgpu_device_asic_has_dc_support(adev->asic_type))
|
||||
domain |= AMDGPU_GEM_DOMAIN_GTT;
|
||||
amdgpu_device_asic_has_dc_support(adev->asic_type)) {
|
||||
switch (adev->asic_type) {
|
||||
case CHIP_CARRIZO:
|
||||
case CHIP_STONEY:
|
||||
domain |= AMDGPU_GEM_DOMAIN_GTT;
|
||||
break;
|
||||
case CHIP_RAVEN:
|
||||
/* enable S/G on PCO and RV2 */
|
||||
if (adev->rev_id >= 0x8 || adev->pdev->device == 0x15d8)
|
||||
domain |= AMDGPU_GEM_DOMAIN_GTT;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return domain;
|
||||
@@ -690,7 +700,6 @@ bool amdgpu_display_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
|
||||
struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
|
||||
struct amdgpu_encoder *amdgpu_encoder;
|
||||
struct drm_connector *connector;
|
||||
struct amdgpu_connector *amdgpu_connector;
|
||||
u32 src_v = 1, dst_v = 1;
|
||||
u32 src_h = 1, dst_h = 1;
|
||||
|
||||
@@ -702,7 +711,6 @@ bool amdgpu_display_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
|
||||
continue;
|
||||
amdgpu_encoder = to_amdgpu_encoder(encoder);
|
||||
connector = amdgpu_get_connector_for_encoder(encoder);
|
||||
amdgpu_connector = to_amdgpu_connector(connector);
|
||||
|
||||
/* set scaling */
|
||||
if (amdgpu_encoder->rmx_type == RMX_OFF)
|
||||
|
||||
@@ -360,10 +360,8 @@ struct dma_buf *amdgpu_gem_prime_export(struct drm_gem_object *gobj,
|
||||
return ERR_PTR(-EPERM);
|
||||
|
||||
buf = drm_gem_prime_export(gobj, flags);
|
||||
if (!IS_ERR(buf)) {
|
||||
buf->file->f_mapping = gobj->dev->anon_inode->i_mapping;
|
||||
if (!IS_ERR(buf))
|
||||
buf->ops = &amdgpu_dmabuf_ops;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -946,20 +946,63 @@ int amdgpu_dpm_set_powergating_by_smu(struct amdgpu_device *adev, uint32_t block
|
||||
bool swsmu = is_support_sw_smu(adev);
|
||||
|
||||
switch (block_type) {
|
||||
case AMD_IP_BLOCK_TYPE_GFX:
|
||||
case AMD_IP_BLOCK_TYPE_UVD:
|
||||
case AMD_IP_BLOCK_TYPE_VCN:
|
||||
case AMD_IP_BLOCK_TYPE_VCE:
|
||||
if (swsmu) {
|
||||
ret = smu_dpm_set_power_gate(&adev->smu, block_type, gate);
|
||||
} else if (adev->powerplay.pp_funcs &&
|
||||
adev->powerplay.pp_funcs->set_powergating_by_smu) {
|
||||
/*
|
||||
* TODO: need a better lock mechanism
|
||||
*
|
||||
* Here adev->pm.mutex lock protection is enforced on
|
||||
* UVD and VCE cases only. Since for other cases, there
|
||||
* may be already lock protection in amdgpu_pm.c.
|
||||
* This is a quick fix for the deadlock issue below.
|
||||
* NFO: task ocltst:2028 blocked for more than 120 seconds.
|
||||
* Tainted: G OE 5.0.0-37-generic #40~18.04.1-Ubuntu
|
||||
* echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
|
||||
* cltst D 0 2028 2026 0x00000000
|
||||
* all Trace:
|
||||
* __schedule+0x2c0/0x870
|
||||
* schedule+0x2c/0x70
|
||||
* schedule_preempt_disabled+0xe/0x10
|
||||
* __mutex_lock.isra.9+0x26d/0x4e0
|
||||
* __mutex_lock_slowpath+0x13/0x20
|
||||
* ? __mutex_lock_slowpath+0x13/0x20
|
||||
* mutex_lock+0x2f/0x40
|
||||
* amdgpu_dpm_set_powergating_by_smu+0x64/0xe0 [amdgpu]
|
||||
* gfx_v8_0_enable_gfx_static_mg_power_gating+0x3c/0x70 [amdgpu]
|
||||
* gfx_v8_0_set_powergating_state+0x66/0x260 [amdgpu]
|
||||
* amdgpu_device_ip_set_powergating_state+0x62/0xb0 [amdgpu]
|
||||
* pp_dpm_force_performance_level+0xe7/0x100 [amdgpu]
|
||||
* amdgpu_set_dpm_forced_performance_level+0x129/0x330 [amdgpu]
|
||||
*/
|
||||
mutex_lock(&adev->pm.mutex);
|
||||
ret = ((adev)->powerplay.pp_funcs->set_powergating_by_smu(
|
||||
(adev)->powerplay.pp_handle, block_type, gate));
|
||||
mutex_unlock(&adev->pm.mutex);
|
||||
}
|
||||
break;
|
||||
case AMD_IP_BLOCK_TYPE_GFX:
|
||||
case AMD_IP_BLOCK_TYPE_VCN:
|
||||
case AMD_IP_BLOCK_TYPE_SDMA:
|
||||
if (swsmu)
|
||||
ret = smu_dpm_set_power_gate(&adev->smu, block_type, gate);
|
||||
else
|
||||
else if (adev->powerplay.pp_funcs &&
|
||||
adev->powerplay.pp_funcs->set_powergating_by_smu)
|
||||
ret = ((adev)->powerplay.pp_funcs->set_powergating_by_smu(
|
||||
(adev)->powerplay.pp_handle, block_type, gate));
|
||||
break;
|
||||
case AMD_IP_BLOCK_TYPE_JPEG:
|
||||
if (swsmu)
|
||||
ret = smu_dpm_set_power_gate(&adev->smu, block_type, gate);
|
||||
break;
|
||||
case AMD_IP_BLOCK_TYPE_GMC:
|
||||
case AMD_IP_BLOCK_TYPE_ACP:
|
||||
ret = ((adev)->powerplay.pp_funcs->set_powergating_by_smu(
|
||||
if (adev->powerplay.pp_funcs &&
|
||||
adev->powerplay.pp_funcs->set_powergating_by_smu)
|
||||
ret = ((adev)->powerplay.pp_funcs->set_powergating_by_smu(
|
||||
(adev)->powerplay.pp_handle, block_type, gate));
|
||||
break;
|
||||
default:
|
||||
@@ -968,3 +1011,163 @@ int amdgpu_dpm_set_powergating_by_smu(struct amdgpu_device *adev, uint32_t block
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int amdgpu_dpm_baco_enter(struct amdgpu_device *adev)
|
||||
{
|
||||
const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
|
||||
void *pp_handle = adev->powerplay.pp_handle;
|
||||
struct smu_context *smu = &adev->smu;
|
||||
int ret = 0;
|
||||
|
||||
if (is_support_sw_smu(adev)) {
|
||||
ret = smu_baco_enter(smu);
|
||||
} else {
|
||||
if (!pp_funcs || !pp_funcs->set_asic_baco_state)
|
||||
return -ENOENT;
|
||||
|
||||
/* enter BACO state */
|
||||
ret = pp_funcs->set_asic_baco_state(pp_handle, 1);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int amdgpu_dpm_baco_exit(struct amdgpu_device *adev)
|
||||
{
|
||||
const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
|
||||
void *pp_handle = adev->powerplay.pp_handle;
|
||||
struct smu_context *smu = &adev->smu;
|
||||
int ret = 0;
|
||||
|
||||
if (is_support_sw_smu(adev)) {
|
||||
ret = smu_baco_exit(smu);
|
||||
} else {
|
||||
if (!pp_funcs || !pp_funcs->set_asic_baco_state)
|
||||
return -ENOENT;
|
||||
|
||||
/* exit BACO state */
|
||||
ret = pp_funcs->set_asic_baco_state(pp_handle, 0);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int amdgpu_dpm_set_mp1_state(struct amdgpu_device *adev,
|
||||
enum pp_mp1_state mp1_state)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (is_support_sw_smu(adev)) {
|
||||
ret = smu_set_mp1_state(&adev->smu, mp1_state);
|
||||
} else if (adev->powerplay.pp_funcs &&
|
||||
adev->powerplay.pp_funcs->set_mp1_state) {
|
||||
ret = adev->powerplay.pp_funcs->set_mp1_state(
|
||||
adev->powerplay.pp_handle,
|
||||
mp1_state);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool amdgpu_dpm_is_baco_supported(struct amdgpu_device *adev)
|
||||
{
|
||||
const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
|
||||
void *pp_handle = adev->powerplay.pp_handle;
|
||||
struct smu_context *smu = &adev->smu;
|
||||
bool baco_cap;
|
||||
|
||||
if (is_support_sw_smu(adev)) {
|
||||
return smu_baco_is_support(smu);
|
||||
} else {
|
||||
if (!pp_funcs || !pp_funcs->get_asic_baco_capability)
|
||||
return false;
|
||||
|
||||
if (pp_funcs->get_asic_baco_capability(pp_handle, &baco_cap))
|
||||
return false;
|
||||
|
||||
return baco_cap ? true : false;
|
||||
}
|
||||
}
|
||||
|
||||
int amdgpu_dpm_mode2_reset(struct amdgpu_device *adev)
|
||||
{
|
||||
const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
|
||||
void *pp_handle = adev->powerplay.pp_handle;
|
||||
struct smu_context *smu = &adev->smu;
|
||||
|
||||
if (is_support_sw_smu(adev)) {
|
||||
return smu_mode2_reset(smu);
|
||||
} else {
|
||||
if (!pp_funcs || !pp_funcs->asic_reset_mode_2)
|
||||
return -ENOENT;
|
||||
|
||||
return pp_funcs->asic_reset_mode_2(pp_handle);
|
||||
}
|
||||
}
|
||||
|
||||
int amdgpu_dpm_baco_reset(struct amdgpu_device *adev)
|
||||
{
|
||||
const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
|
||||
void *pp_handle = adev->powerplay.pp_handle;
|
||||
struct smu_context *smu = &adev->smu;
|
||||
int ret = 0;
|
||||
|
||||
dev_info(adev->dev, "GPU BACO reset\n");
|
||||
|
||||
if (is_support_sw_smu(adev)) {
|
||||
ret = smu_baco_enter(smu);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = smu_baco_exit(smu);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
if (!pp_funcs
|
||||
|| !pp_funcs->set_asic_baco_state)
|
||||
return -ENOENT;
|
||||
|
||||
/* enter BACO state */
|
||||
ret = pp_funcs->set_asic_baco_state(pp_handle, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* exit BACO state */
|
||||
ret = pp_funcs->set_asic_baco_state(pp_handle, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int amdgpu_dpm_switch_power_profile(struct amdgpu_device *adev,
|
||||
enum PP_SMC_POWER_PROFILE type,
|
||||
bool en)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (is_support_sw_smu(adev))
|
||||
ret = smu_switch_power_profile(&adev->smu, type, en);
|
||||
else if (adev->powerplay.pp_funcs &&
|
||||
adev->powerplay.pp_funcs->switch_power_profile)
|
||||
ret = adev->powerplay.pp_funcs->switch_power_profile(
|
||||
adev->powerplay.pp_handle, type, en);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int amdgpu_dpm_set_xgmi_pstate(struct amdgpu_device *adev,
|
||||
uint32_t pstate)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (is_support_sw_smu_xgmi(adev))
|
||||
ret = smu_set_xgmi_pstate(&adev->smu, pstate);
|
||||
else if (adev->powerplay.pp_funcs &&
|
||||
adev->powerplay.pp_funcs->set_xgmi_pstate)
|
||||
ret = adev->powerplay.pp_funcs->set_xgmi_pstate(adev->powerplay.pp_handle,
|
||||
pstate);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -341,10 +341,6 @@ enum amdgpu_pcie_gen {
|
||||
((adev)->powerplay.pp_funcs->reset_power_profile_state(\
|
||||
(adev)->powerplay.pp_handle, request))
|
||||
|
||||
#define amdgpu_dpm_switch_power_profile(adev, type, en) \
|
||||
((adev)->powerplay.pp_funcs->switch_power_profile(\
|
||||
(adev)->powerplay.pp_handle, type, en))
|
||||
|
||||
#define amdgpu_dpm_set_clockgating_by_smu(adev, msg_id) \
|
||||
((adev)->powerplay.pp_funcs->set_clockgating_by_smu(\
|
||||
(adev)->powerplay.pp_handle, msg_id))
|
||||
@@ -517,4 +513,24 @@ extern int amdgpu_dpm_get_sclk(struct amdgpu_device *adev, bool low);
|
||||
|
||||
extern int amdgpu_dpm_get_mclk(struct amdgpu_device *adev, bool low);
|
||||
|
||||
int amdgpu_dpm_set_xgmi_pstate(struct amdgpu_device *adev,
|
||||
uint32_t pstate);
|
||||
|
||||
int amdgpu_dpm_switch_power_profile(struct amdgpu_device *adev,
|
||||
enum PP_SMC_POWER_PROFILE type,
|
||||
bool en);
|
||||
|
||||
int amdgpu_dpm_baco_reset(struct amdgpu_device *adev);
|
||||
|
||||
int amdgpu_dpm_mode2_reset(struct amdgpu_device *adev);
|
||||
|
||||
bool amdgpu_dpm_is_baco_supported(struct amdgpu_device *adev);
|
||||
|
||||
int amdgpu_dpm_set_mp1_state(struct amdgpu_device *adev,
|
||||
enum pp_mp1_state mp1_state);
|
||||
|
||||
int amdgpu_dpm_baco_exit(struct amdgpu_device *adev);
|
||||
|
||||
int amdgpu_dpm_baco_enter(struct amdgpu_device *adev);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1147,7 +1147,7 @@ static int amdgpu_pmops_suspend(struct device *dev)
|
||||
{
|
||||
struct drm_device *drm_dev = dev_get_drvdata(dev);
|
||||
|
||||
return amdgpu_device_suspend(drm_dev, true, true);
|
||||
return amdgpu_device_suspend(drm_dev, true);
|
||||
}
|
||||
|
||||
static int amdgpu_pmops_resume(struct device *dev)
|
||||
@@ -1155,13 +1155,14 @@ static int amdgpu_pmops_resume(struct device *dev)
|
||||
struct drm_device *drm_dev = dev_get_drvdata(dev);
|
||||
|
||||
/* GPU comes up enabled by the bios on resume */
|
||||
if (amdgpu_device_is_px(drm_dev)) {
|
||||
if (amdgpu_device_supports_boco(drm_dev) ||
|
||||
amdgpu_device_supports_baco(drm_dev)) {
|
||||
pm_runtime_disable(dev);
|
||||
pm_runtime_set_active(dev);
|
||||
pm_runtime_enable(dev);
|
||||
}
|
||||
|
||||
return amdgpu_device_resume(drm_dev, true, true);
|
||||
return amdgpu_device_resume(drm_dev, true);
|
||||
}
|
||||
|
||||
static int amdgpu_pmops_freeze(struct device *dev)
|
||||
@@ -1170,7 +1171,7 @@ static int amdgpu_pmops_freeze(struct device *dev)
|
||||
struct amdgpu_device *adev = drm_dev->dev_private;
|
||||
int r;
|
||||
|
||||
r = amdgpu_device_suspend(drm_dev, false, true);
|
||||
r = amdgpu_device_suspend(drm_dev, true);
|
||||
if (r)
|
||||
return r;
|
||||
return amdgpu_asic_reset(adev);
|
||||
@@ -1180,46 +1181,66 @@ static int amdgpu_pmops_thaw(struct device *dev)
|
||||
{
|
||||
struct drm_device *drm_dev = dev_get_drvdata(dev);
|
||||
|
||||
return amdgpu_device_resume(drm_dev, false, true);
|
||||
return amdgpu_device_resume(drm_dev, true);
|
||||
}
|
||||
|
||||
static int amdgpu_pmops_poweroff(struct device *dev)
|
||||
{
|
||||
struct drm_device *drm_dev = dev_get_drvdata(dev);
|
||||
|
||||
return amdgpu_device_suspend(drm_dev, true, true);
|
||||
return amdgpu_device_suspend(drm_dev, true);
|
||||
}
|
||||
|
||||
static int amdgpu_pmops_restore(struct device *dev)
|
||||
{
|
||||
struct drm_device *drm_dev = dev_get_drvdata(dev);
|
||||
|
||||
return amdgpu_device_resume(drm_dev, false, true);
|
||||
return amdgpu_device_resume(drm_dev, true);
|
||||
}
|
||||
|
||||
static int amdgpu_pmops_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct drm_device *drm_dev = pci_get_drvdata(pdev);
|
||||
int ret;
|
||||
struct amdgpu_device *adev = drm_dev->dev_private;
|
||||
int ret, i;
|
||||
|
||||
if (!amdgpu_device_is_px(drm_dev)) {
|
||||
if (!adev->runpm) {
|
||||
pm_runtime_forbid(dev);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
|
||||
/* wait for all rings to drain before suspending */
|
||||
for (i = 0; i < AMDGPU_MAX_RINGS; i++) {
|
||||
struct amdgpu_ring *ring = adev->rings[i];
|
||||
if (ring && ring->sched.ready) {
|
||||
ret = amdgpu_fence_wait_empty(ring);
|
||||
if (ret)
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
|
||||
if (amdgpu_device_supports_boco(drm_dev))
|
||||
drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
|
||||
drm_kms_helper_poll_disable(drm_dev);
|
||||
|
||||
ret = amdgpu_device_suspend(drm_dev, false, false);
|
||||
pci_save_state(pdev);
|
||||
pci_disable_device(pdev);
|
||||
pci_ignore_hotplug(pdev);
|
||||
if (amdgpu_is_atpx_hybrid())
|
||||
pci_set_power_state(pdev, PCI_D3cold);
|
||||
else if (!amdgpu_has_atpx_dgpu_power_cntl())
|
||||
pci_set_power_state(pdev, PCI_D3hot);
|
||||
drm_dev->switch_power_state = DRM_SWITCH_POWER_DYNAMIC_OFF;
|
||||
ret = amdgpu_device_suspend(drm_dev, false);
|
||||
if (amdgpu_device_supports_boco(drm_dev)) {
|
||||
/* Only need to handle PCI state in the driver for ATPX
|
||||
* PCI core handles it for _PR3.
|
||||
*/
|
||||
if (amdgpu_is_atpx_hybrid()) {
|
||||
pci_ignore_hotplug(pdev);
|
||||
} else {
|
||||
pci_save_state(pdev);
|
||||
pci_disable_device(pdev);
|
||||
pci_ignore_hotplug(pdev);
|
||||
pci_set_power_state(pdev, PCI_D3cold);
|
||||
}
|
||||
drm_dev->switch_power_state = DRM_SWITCH_POWER_DYNAMIC_OFF;
|
||||
} else if (amdgpu_device_supports_baco(drm_dev)) {
|
||||
amdgpu_device_baco_enter(drm_dev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1228,34 +1249,45 @@ static int amdgpu_pmops_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct drm_device *drm_dev = pci_get_drvdata(pdev);
|
||||
struct amdgpu_device *adev = drm_dev->dev_private;
|
||||
int ret;
|
||||
|
||||
if (!amdgpu_device_is_px(drm_dev))
|
||||
if (!adev->runpm)
|
||||
return -EINVAL;
|
||||
|
||||
drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
|
||||
if (amdgpu_device_supports_boco(drm_dev)) {
|
||||
drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
|
||||
|
||||
if (amdgpu_is_atpx_hybrid() ||
|
||||
!amdgpu_has_atpx_dgpu_power_cntl())
|
||||
pci_set_power_state(pdev, PCI_D0);
|
||||
pci_restore_state(pdev);
|
||||
ret = pci_enable_device(pdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
pci_set_master(pdev);
|
||||
|
||||
ret = amdgpu_device_resume(drm_dev, false, false);
|
||||
/* Only need to handle PCI state in the driver for ATPX
|
||||
* PCI core handles it for _PR3.
|
||||
*/
|
||||
if (amdgpu_is_atpx_hybrid()) {
|
||||
pci_set_master(pdev);
|
||||
} else {
|
||||
pci_set_power_state(pdev, PCI_D0);
|
||||
pci_restore_state(pdev);
|
||||
ret = pci_enable_device(pdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
pci_set_master(pdev);
|
||||
}
|
||||
} else if (amdgpu_device_supports_baco(drm_dev)) {
|
||||
amdgpu_device_baco_exit(drm_dev);
|
||||
}
|
||||
ret = amdgpu_device_resume(drm_dev, false);
|
||||
drm_kms_helper_poll_enable(drm_dev);
|
||||
drm_dev->switch_power_state = DRM_SWITCH_POWER_ON;
|
||||
if (amdgpu_device_supports_boco(drm_dev))
|
||||
drm_dev->switch_power_state = DRM_SWITCH_POWER_ON;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amdgpu_pmops_runtime_idle(struct device *dev)
|
||||
{
|
||||
struct drm_device *drm_dev = dev_get_drvdata(dev);
|
||||
struct amdgpu_device *adev = drm_dev->dev_private;
|
||||
struct drm_crtc *crtc;
|
||||
|
||||
if (!amdgpu_device_is_px(drm_dev)) {
|
||||
if (!adev->runpm) {
|
||||
pm_runtime_forbid(dev);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ amdgpufb_release(struct fb_info *info, int user)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct fb_ops amdgpufb_ops = {
|
||||
static const struct fb_ops amdgpufb_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
DRM_FB_HELPER_DEFAULT_OPS,
|
||||
.fb_open = amdgpufb_open,
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <linux/kref.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include <drm/drm_debugfs.h>
|
||||
|
||||
@@ -154,7 +155,7 @@ int amdgpu_fence_emit(struct amdgpu_ring *ring, struct dma_fence **f,
|
||||
seq);
|
||||
amdgpu_ring_emit_fence(ring, ring->fence_drv.gpu_addr,
|
||||
seq, flags | AMDGPU_FENCE_FLAG_INT);
|
||||
|
||||
pm_runtime_get_noresume(adev->ddev->dev);
|
||||
ptr = &ring->fence_drv.fences[seq & ring->fence_drv.num_fences_mask];
|
||||
if (unlikely(rcu_dereference_protected(*ptr, 1))) {
|
||||
struct dma_fence *old;
|
||||
@@ -234,6 +235,7 @@ static void amdgpu_fence_schedule_fallback(struct amdgpu_ring *ring)
|
||||
bool amdgpu_fence_process(struct amdgpu_ring *ring)
|
||||
{
|
||||
struct amdgpu_fence_driver *drv = &ring->fence_drv;
|
||||
struct amdgpu_device *adev = ring->adev;
|
||||
uint32_t seq, last_seq;
|
||||
int r;
|
||||
|
||||
@@ -274,6 +276,8 @@ bool amdgpu_fence_process(struct amdgpu_ring *ring)
|
||||
BUG();
|
||||
|
||||
dma_fence_put(fence);
|
||||
pm_runtime_mark_last_busy(adev->ddev->dev);
|
||||
pm_runtime_put_autosuspend(adev->ddev->dev);
|
||||
} while (last_seq != seq);
|
||||
|
||||
return true;
|
||||
@@ -737,10 +741,18 @@ static int amdgpu_debugfs_gpu_recover(struct seq_file *m, void *data)
|
||||
struct drm_info_node *node = (struct drm_info_node *) m->private;
|
||||
struct drm_device *dev = node->minor->dev;
|
||||
struct amdgpu_device *adev = dev->dev_private;
|
||||
int r;
|
||||
|
||||
r = pm_runtime_get_sync(dev->dev);
|
||||
if (r < 0)
|
||||
return 0;
|
||||
|
||||
seq_printf(m, "gpu recover\n");
|
||||
amdgpu_device_gpu_recover(adev, NULL);
|
||||
|
||||
pm_runtime_mark_last_busy(dev->dev);
|
||||
pm_runtime_put_autosuspend(dev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -302,6 +302,7 @@ int amdgpu_gart_map(struct amdgpu_device *adev, uint64_t offset,
|
||||
* @pages: number of pages to bind
|
||||
* @pagelist: pages to bind
|
||||
* @dma_addr: DMA addresses of pages
|
||||
* @flags: page table entry flags
|
||||
*
|
||||
* Binds the requested pages to the gart page table
|
||||
* (all asics).
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user