drm pull for 5.6-rc1
uapi: - dma-buf heaps added (and fixed) - command line add support for panel oreientation - command line allow overriding penguin count drm: - mipi dsi definition updates - lockdep annotations for dma_resv - remove dma-buf kmap/kunmap support - constify fb_ops in all fbdev drivers - MST fix for daisy chained hotplug- - CTA-861-G modes with VIC >= 193 added - fix drm_panel_of_backlight export - LVDS decoder support - more device based logging support - scanline alighment for dumb buffers - MST DSC helpers scheduler: - documentation fixes - job distribution improvements panel: - Logic PD type 28 panel support - Jimax8729d MIPI-DSI - igenic JZ4770 - generic DSI devicetree bindings - sony acx424AKP panel - Leadtek LTK500HD1829 - xinpeng XPP055C272 - AUO B116XAK01 - GiantPlus GPM940B0 - BOE NV140FHM-N49 - Satoz SAT050AT40H12R2 - Sharp LS020B1DD01D panels. ttm: - use blocking WW lock i915: - hw/uapi state separation - Lock annotation improvements - selftest improvements - ICL/TGL DSI VDSC support - VBT parsing improvments - Display refactoring - DSI updates + fixes - HDCP 2.2 for CFL - CML PCI ID fixes - GLK+ fbc fix - PSR fixes - GEN/GT refactor improvments - DP MST fixes - switch context id alloc to xarray - workaround updates - LMEM debugfs support - tiled monitor fixes - ICL+ clock gating programming removed - DP MST disable sequence fixed - LMEM discontiguous object maps - prefaulting for discontiguous objects - use LMEM for dumb buffers if possible - add LMEM mmap support amdgpu: - enable sync object timelines for vulkan - MST atomic routines - enable MST DSC support - add DMCUB display microengine support - DC OEM i2c support - Renoir DC fixes - Initial HDCP 2.x support - BACO support for Arcturus - Use BACO for runtime PM power save - gfxoff on navi10 - gfx10 golden updates and fixes - DCN support on POWER - GFXOFF for raven1 refresh - MM engine idle handlers cleanup - 10bpc EDP panel fixes - renoir watermark fixes - SR-IOV fixes - Arcturus VCN fixes - GDDR6 training fixes - freesync fixes - Pollock support amdkfd: - unify more codepath with amdgpu - use KIQ to setup HIQ rather than MMIO radeon: - fix vma fault handler race - PPC DMA fix - register check fixes for r100/r200 nouveau: - mmap_sem vs dma_resv fix - rewrite the ACR secure boot code for Turing - TU10x graphics engine support (TU11x pending) - Page kind mapping for turing - 10-bit LUT support - GP10B Tegra fixes - HD audio regression fix hisilicon/hibmc: - use generic fbdev code and helpers rockchip: - dsi/px30 support virtio: - fb damage support - static some functions vc4: - use dma_resv lock wrappers msm: - use dma_resv lock wrappers - sc7180 display + DSI support - a618 support - UBWC support improvements vmwgfx: - updates + new logging uapi exynos: - enable/disable callback cleanups etnaviv: - use dma_resv lock wrappers atmel-hlcdc: - clock fixes mediatek: - cmdq support - non-smooth cursor fixes - ctm property support sun4i: - suspend support - A64 mipi dsi support rcar-du: - Color management module support - LVDS encoder dual-link support - R8A77980 support analogic: - add support for an6345 ast: - atomic modeset support - primary plane garbage fix arcgpu: - fixes for fourcc handling tegra: - minor fixes and improvments mcde: - vblank support meson: - OSD1 plane AFBC commit gma500: - add pageflip support - reomve global drm_dev komeda: - tweak debugfs output - d32 support - runtime PM suppotr udl: - use generic shmem helpers - cleanup and fixes -----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJeMm6RAAoJEAx081l5xIa+vN8P/0j4jEOv+KIinAhoH+LG3EpD m2TUuu5OQIoBrcCoWOgFBk3wqYpw6PdMBdkXh+5sE5lfeBynp8oC3Bin+QsHJE05 eGBpZtHe+70MQb0Eha+Aic0hchvBKzRnq6i0MYSIHn6afs76dLmF8knTjycxrvV5 Xu1Z3WDmjzqgWF9ja5JCD6fby11seP5RrwObYKVikO35QQyJJwGSGKgu5rq/pByK /n0PCnCOINuL0Lz6J9qexdh/0/XYFQilRC31GJNlKbDSFuECF0GOEzEE/xUBW/pI dLh2YwIIygm18Gar9PgvMwXJn3BfzQ0qEJsf+HlQeNw9iLgbHpp2AsTxHTE87OGe R/y85taW3jGjPsNOKZOeLpvg/Ro8l8ZipLApvDCG2O22DThg/cd6NDjZxl1FJfRH acDG/JdgPo5MbdRAH/cM1WuFS9gEM+0BeSQ5gCjtPakF+X4Vz+ABFDLMRJoaejkJ q8DG32TQXELQx0RMghsqK7YCWGfl+2alA1u9w6TgJh9Rq4iVckvpDeqAZnK1Adkc 87g957Tl0n6FA4wJj/t5jrceiLRMJAm/rBK+R3GZNfWrgx4bHbCmb4fZDZsrFzph nbAjNJ5kOchrFCaRR47ULby6+Q14MAFbkWq4Crfu4YDdzUkTPpep6pi2GIe8w0rV P0hdYOYJf6LUda0utuQX =oFrI -----END PGP SIGNATURE----- Merge tag 'drm-next-2020-01-30' of git://anongit.freedesktop.org/drm/drm Pull drm updates from Davbe Airlie: "This is the main pull request for graphics for 5.6. Usual selection of changes all over. I've got one outstanding vmwgfx pull that touches mm so kept it separate until after all of this lands. I'll try and get it to you soon after this, but it might be early next week (nothing wrong with code, just my schedule is messy) This also hits a lot of fbdev drivers with some cleanups. Other notables: - vulkan timeline semaphore support added to syncobjs - nouveau turing secureboot/graphics support - Displayport MST display stream compression support Detailed summary: uapi: - dma-buf heaps added (and fixed) - command line add support for panel oreientation - command line allow overriding penguin count drm: - mipi dsi definition updates - lockdep annotations for dma_resv - remove dma-buf kmap/kunmap support - constify fb_ops in all fbdev drivers - MST fix for daisy chained hotplug- - CTA-861-G modes with VIC >= 193 added - fix drm_panel_of_backlight export - LVDS decoder support - more device based logging support - scanline alighment for dumb buffers - MST DSC helpers scheduler: - documentation fixes - job distribution improvements panel: - Logic PD type 28 panel support - Jimax8729d MIPI-DSI - igenic JZ4770 - generic DSI devicetree bindings - sony acx424AKP panel - Leadtek LTK500HD1829 - xinpeng XPP055C272 - AUO B116XAK01 - GiantPlus GPM940B0 - BOE NV140FHM-N49 - Satoz SAT050AT40H12R2 - Sharp LS020B1DD01D panels. ttm: - use blocking WW lock i915: - hw/uapi state separation - Lock annotation improvements - selftest improvements - ICL/TGL DSI VDSC support - VBT parsing improvments - Display refactoring - DSI updates + fixes - HDCP 2.2 for CFL - CML PCI ID fixes - GLK+ fbc fix - PSR fixes - GEN/GT refactor improvments - DP MST fixes - switch context id alloc to xarray - workaround updates - LMEM debugfs support - tiled monitor fixes - ICL+ clock gating programming removed - DP MST disable sequence fixed - LMEM discontiguous object maps - prefaulting for discontiguous objects - use LMEM for dumb buffers if possible - add LMEM mmap support amdgpu: - enable sync object timelines for vulkan - MST atomic routines - enable MST DSC support - add DMCUB display microengine support - DC OEM i2c support - Renoir DC fixes - Initial HDCP 2.x support - BACO support for Arcturus - Use BACO for runtime PM power save - gfxoff on navi10 - gfx10 golden updates and fixes - DCN support on POWER - GFXOFF for raven1 refresh - MM engine idle handlers cleanup - 10bpc EDP panel fixes - renoir watermark fixes - SR-IOV fixes - Arcturus VCN fixes - GDDR6 training fixes - freesync fixes - Pollock support amdkfd: - unify more codepath with amdgpu - use KIQ to setup HIQ rather than MMIO radeon: - fix vma fault handler race - PPC DMA fix - register check fixes for r100/r200 nouveau: - mmap_sem vs dma_resv fix - rewrite the ACR secure boot code for Turing - TU10x graphics engine support (TU11x pending) - Page kind mapping for turing - 10-bit LUT support - GP10B Tegra fixes - HD audio regression fix hisilicon/hibmc: - use generic fbdev code and helpers rockchip: - dsi/px30 support virtio: - fb damage support - static some functions vc4: - use dma_resv lock wrappers msm: - use dma_resv lock wrappers - sc7180 display + DSI support - a618 support - UBWC support improvements vmwgfx: - updates + new logging uapi exynos: - enable/disable callback cleanups etnaviv: - use dma_resv lock wrappers atmel-hlcdc: - clock fixes mediatek: - cmdq support - non-smooth cursor fixes - ctm property support sun4i: - suspend support - A64 mipi dsi support rcar-du: - Color management module support - LVDS encoder dual-link support - R8A77980 support analogic: - add support for an6345 ast: - atomic modeset support - primary plane garbage fix arcgpu: - fixes for fourcc handling tegra: - minor fixes and improvments mcde: - vblank support meson: - OSD1 plane AFBC commit gma500: - add pageflip support - reomve global drm_dev komeda: - tweak debugfs output - d32 support - runtime PM suppotr udl: - use generic shmem helpers - cleanup and fixes" * tag 'drm-next-2020-01-30' of git://anongit.freedesktop.org/drm/drm: (1998 commits) drm/nouveau/fb/gp102-: allow module to load even when scrubber binary is missing drm/nouveau/acr: return error when registering LSF if ACR not supported drm/nouveau/disp/gv100-: not all channel types support reporting error codes drm/nouveau/disp/nv50-: prevent oops when no channel method map provided drm/nouveau: support synchronous pushbuf submission drm/nouveau: signal pending fences when channel has been killed drm/nouveau: reject attempts to submit to dead channels drm/nouveau: zero vma pointer even if we only unreference it rather than free drm/nouveau: Add HD-audio component notifier support drm/nouveau: fix build error without CONFIG_IOMMU_API drm/nouveau/kms/nv04: remove set but not used variable 'width' drm/nouveau/kms/nv50: remove set but not unused variable 'nv_connector' drm/nouveau/mmu: fix comptag memory leak drm/nouveau/gr/gp10b: Use gp100_grctx and gp100_gr_zbc drm/nouveau/pmu/gm20b,gp10b: Fix Falcon bootstrapping drm/exynos: Rename Exynos to lowercase drm/exynos: change callback names drm/mst: Don't do atomic checks over disabled managers drm/amdgpu: add the lost mutex_init back drm/amd/display: skip opp blank or unblank if test pattern enabled ...
This commit is contained in:
commit
9f68e3655a
|
@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
|
@ -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>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
@ -1050,43 +1030,6 @@ int dma_buf_end_cpu_access(struct dma_buf *dmabuf,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(dma_buf_end_cpu_access);
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
|
@ -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
|
|
@ -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");
|
|
@ -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,
|
||||
};
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -543,12 +543,6 @@ void amdgpu_gfx_off_ctrl(struct amdgpu_device *adev, bool enable)
|
|||
if (!(adev->pm.pp_feature & PP_GFXOFF_MASK))
|
||||
return;
|
||||
|
||||
if (!is_support_sw_smu(adev) &&
|
||||
(!adev->powerplay.pp_funcs ||
|
||||
!adev->powerplay.pp_funcs->set_powergating_by_smu))
|
||||
return;
|
||||
|
||||
|
||||
mutex_lock(&adev->gfx.gfx_off_mutex);
|
||||
|
||||
if (!enable)
|
||||
|
@ -641,7 +635,7 @@ int amdgpu_gfx_process_ras_data_cb(struct amdgpu_device *adev,
|
|||
kgd2kfd_set_sram_ecc_flag(adev->kfd.dev);
|
||||
if (adev->gfx.funcs->query_ras_error_count)
|
||||
adev->gfx.funcs->query_ras_error_count(adev, err_data);
|
||||
amdgpu_ras_reset_gpu(adev, 0);
|
||||
amdgpu_ras_reset_gpu(adev);
|
||||
}
|
||||
return AMDGPU_RAS_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -76,11 +76,15 @@ struct kiq_pm4_funcs {
|
|||
struct amdgpu_ring *ring,
|
||||
u64 addr,
|
||||
u64 seq);
|
||||
void (*kiq_invalidate_tlbs)(struct amdgpu_ring *kiq_ring,
|
||||
uint16_t pasid, uint32_t flush_type,
|
||||
bool all_hub);
|
||||
/* Packet sizes */
|
||||
int set_resources_size;
|
||||
int map_queues_size;
|
||||
int unmap_queues_size;
|
||||
int query_status_size;
|
||||
int invalidate_tlbs_size;
|
||||
};
|
||||
|
||||
struct amdgpu_kiq {
|
||||
|
@ -269,8 +273,12 @@ struct amdgpu_gfx {
|
|||
bool me_fw_write_wait;
|
||||
bool cp_fw_write_wait;
|
||||
struct amdgpu_ring gfx_ring[AMDGPU_MAX_GFX_RINGS];
|
||||
struct drm_gpu_scheduler *gfx_sched[AMDGPU_MAX_GFX_RINGS];
|
||||
uint32_t num_gfx_sched;
|
||||
unsigned num_gfx_rings;
|
||||
struct amdgpu_ring compute_ring[AMDGPU_MAX_COMPUTE_RINGS];
|
||||
struct drm_gpu_scheduler *compute_sched[AMDGPU_MAX_COMPUTE_RINGS];
|
||||
uint32_t num_compute_sched;
|
||||
unsigned num_compute_rings;
|
||||
struct amdgpu_irq_src eop_irq;
|
||||
struct amdgpu_irq_src priv_reg_irq;
|
||||
|
|
|
@ -223,7 +223,7 @@ void amdgpu_gmc_agp_location(struct amdgpu_device *adev, struct amdgpu_gmc *mc)
|
|||
u64 size_af, size_bf;
|
||||
|
||||
if (amdgpu_sriov_vf(adev)) {
|
||||
mc->agp_start = 0xffffffff;
|
||||
mc->agp_start = 0xffffffffffff;
|
||||
mc->agp_end = 0x0;
|
||||
mc->agp_size = 0;
|
||||
|
||||
|
@ -333,3 +333,43 @@ void amdgpu_gmc_ras_fini(struct amdgpu_device *adev)
|
|||
amdgpu_mmhub_ras_fini(adev);
|
||||
amdgpu_xgmi_ras_fini(adev);
|
||||
}
|
||||
|
||||
/*
|
||||
* The latest engine allocation on gfx9/10 is:
|
||||
* Engine 2, 3: firmware
|
||||
* Engine 0, 1, 4~16: amdgpu ring,
|
||||
* subject to change when ring number changes
|
||||
* Engine 17: Gart flushes
|
||||
*/
|
||||
#define GFXHUB_FREE_VM_INV_ENGS_BITMAP 0x1FFF3
|
||||
#define MMHUB_FREE_VM_INV_ENGS_BITMAP 0x1FFF3
|
||||
|
||||
int amdgpu_gmc_allocate_vm_inv_eng(struct amdgpu_device *adev)
|
||||
{
|
||||
struct amdgpu_ring *ring;
|
||||
unsigned vm_inv_engs[AMDGPU_MAX_VMHUBS] =
|
||||
{GFXHUB_FREE_VM_INV_ENGS_BITMAP, MMHUB_FREE_VM_INV_ENGS_BITMAP,
|
||||
GFXHUB_FREE_VM_INV_ENGS_BITMAP};
|
||||
unsigned i;
|
||||
unsigned vmhub, inv_eng;
|
||||
|
||||
for (i = 0; i < adev->num_rings; ++i) {
|
||||
ring = adev->rings[i];
|
||||
vmhub = ring->funcs->vmhub;
|
||||
|
||||
inv_eng = ffs(vm_inv_engs[vmhub]);
|
||||
if (!inv_eng) {
|
||||
dev_err(adev->dev, "no VM inv eng for ring %s\n",
|
||||
ring->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ring->vm_inv_eng = inv_eng - 1;
|
||||
vm_inv_engs[vmhub] &= ~(1 << ring->vm_inv_eng);
|
||||
|
||||
dev_info(adev->dev, "ring %s uses VM inv eng %u on hub %u\n",
|
||||
ring->name, ring->vm_inv_eng, ring->funcs->vmhub);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -60,6 +60,11 @@
|
|||
*/
|
||||
#define AMDGPU_GMC_FAULT_TIMEOUT 5000ULL
|
||||
|
||||
/*
|
||||
* Default stolen memory size, 1024 * 768 * 4
|
||||
*/
|
||||
#define AMDGPU_STOLEN_BIST_TRAINING_DEFAULT_SIZE 0x300000ULL
|
||||
|
||||
struct firmware;
|
||||
|
||||
/*
|
||||
|
@ -92,6 +97,9 @@ struct amdgpu_gmc_funcs {
|
|||
/* flush the vm tlb via mmio */
|
||||
void (*flush_gpu_tlb)(struct amdgpu_device *adev, uint32_t vmid,
|
||||
uint32_t vmhub, uint32_t flush_type);
|
||||
/* flush the vm tlb via pasid */
|
||||
int (*flush_gpu_tlb_pasid)(struct amdgpu_device *adev, uint16_t pasid,
|
||||
uint32_t flush_type, bool all_hub);
|
||||
/* flush the vm tlb via ring */
|
||||
uint64_t (*emit_flush_gpu_tlb)(struct amdgpu_ring *ring, unsigned vmid,
|
||||
uint64_t pd_addr);
|
||||
|
@ -216,6 +224,9 @@ struct amdgpu_gmc {
|
|||
};
|
||||
|
||||
#define amdgpu_gmc_flush_gpu_tlb(adev, vmid, vmhub, type) ((adev)->gmc.gmc_funcs->flush_gpu_tlb((adev), (vmid), (vmhub), (type)))
|
||||
#define amdgpu_gmc_flush_gpu_tlb_pasid(adev, pasid, type, allhub) \
|
||||
((adev)->gmc.gmc_funcs->flush_gpu_tlb_pasid \
|
||||
((adev), (pasid), (type), (allhub)))
|
||||
#define amdgpu_gmc_emit_flush_gpu_tlb(r, vmid, addr) (r)->adev->gmc.gmc_funcs->emit_flush_gpu_tlb((r), (vmid), (addr))
|
||||
#define amdgpu_gmc_emit_pasid_mapping(r, vmid, pasid) (r)->adev->gmc.gmc_funcs->emit_pasid_mapping((r), (vmid), (pasid))
|
||||
#define amdgpu_gmc_map_mtype(adev, flags) (adev)->gmc.gmc_funcs->map_mtype((adev),(flags))
|
||||
|
@ -267,5 +278,6 @@ bool amdgpu_gmc_filter_faults(struct amdgpu_device *adev, uint64_t addr,
|
|||
uint16_t pasid, uint64_t timestamp);
|
||||
int amdgpu_gmc_ras_late_init(struct amdgpu_device *adev);
|
||||
void amdgpu_gmc_ras_fini(struct amdgpu_device *adev);
|
||||
int amdgpu_gmc_allocate_vm_inv_eng(struct amdgpu_device *adev);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -206,7 +206,7 @@ static int amdgpu_vmid_grab_idle(struct amdgpu_vm *vm,
|
|||
int r;
|
||||
|
||||
if (ring->vmid_wait && !dma_fence_is_signaled(ring->vmid_wait))
|
||||
return amdgpu_sync_fence(adev, sync, ring->vmid_wait, false);
|
||||
return amdgpu_sync_fence(sync, ring->vmid_wait, false);
|
||||
|
||||
fences = kmalloc_array(sizeof(void *), id_mgr->num_ids, GFP_KERNEL);
|
||||
if (!fences)
|
||||
|
@ -241,7 +241,7 @@ static int amdgpu_vmid_grab_idle(struct amdgpu_vm *vm,
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
r = amdgpu_sync_fence(adev, sync, &array->base, false);
|
||||
r = amdgpu_sync_fence(sync, &array->base, false);
|
||||
dma_fence_put(ring->vmid_wait);
|
||||
ring->vmid_wait = &array->base;
|
||||
return r;
|
||||
|
@ -294,7 +294,7 @@ static int amdgpu_vmid_grab_reserved(struct amdgpu_vm *vm,
|
|||
tmp = amdgpu_sync_peek_fence(&(*id)->active, ring);
|
||||
if (tmp) {
|
||||
*id = NULL;
|
||||
r = amdgpu_sync_fence(adev, sync, tmp, false);
|
||||
r = amdgpu_sync_fence(sync, tmp, false);
|
||||
return r;
|
||||
}
|
||||
needs_flush = true;
|
||||
|
@ -303,7 +303,7 @@ static int amdgpu_vmid_grab_reserved(struct amdgpu_vm *vm,
|
|||
/* Good we can use this VMID. Remember this submission as
|
||||
* user of the VMID.
|
||||
*/
|
||||
r = amdgpu_sync_fence(ring->adev, &(*id)->active, fence, false);
|
||||
r = amdgpu_sync_fence(&(*id)->active, fence, false);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
|
@ -375,7 +375,7 @@ static int amdgpu_vmid_grab_used(struct amdgpu_vm *vm,
|
|||
/* Good, we can use this VMID. Remember this submission as
|
||||
* user of the VMID.
|
||||
*/
|
||||
r = amdgpu_sync_fence(ring->adev, &(*id)->active, fence, false);
|
||||
r = amdgpu_sync_fence(&(*id)->active, fence, false);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
|
@ -435,8 +435,7 @@ int amdgpu_vmid_grab(struct amdgpu_vm *vm, struct amdgpu_ring *ring,
|
|||
id = idle;
|
||||
|
||||
/* Remember this submission as user of the VMID */
|
||||
r = amdgpu_sync_fence(ring->adev, &id->active,
|
||||
fence, false);
|
||||
r = amdgpu_sync_fence(&id->active, fence, false);
|
||||
if (r)
|
||||
goto error;
|
||||
|
||||
|
|
|
@ -66,7 +66,6 @@ int amdgpu_ih_ring_init(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih,
|
|||
if (ih->ring == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
memset((void *)ih->ring, 0, ih->ring_size + 8);
|
||||
ih->gpu_addr = dma_addr;
|
||||
ih->wptr_addr = dma_addr + ih->ring_size;
|
||||
ih->wptr_cpu = &ih->ring[ih->ring_size / 4];
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue