mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-17 09:43:59 +08:00
drm main pull for 5.4-rc1
-----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJdgfi4AAoJEAx081l5xIa+uYQP/3lbB75F60oSb0Y17uOtAwrS /ZMKZ3/EXcCw42JuYTbz17EiQSajkJcOC+tNRo22nlg4d9R0x3/kXwA7O/eu5RWI 8Qi1rfrMZ6LotQXBfc4nVlHvyocsYc/GVNfsCboUCLwU/aNwnrufS9jeEsvWd2Vt iIn/okeQ7mTyB/3Dm4RFIAexE21+d5is6YTs45xUnDLhWzXYLU7VnHt5S5kXurEI cmVA7C1EAqV+GAwkeFWFx/jBpBRKqvTPa8EpOu7cQL01x7KwU2cQeNdOyBF6Uf8a cNKFI7jZZmu/mFp+YqU33ZIZxbLELm5PN1sz4ZvoIT8BJAQf1VmZg+GG87AvQCUz zbWKrbHGVy/c+sohUmvCOQvmzca/7rZutFyaCOx2mEdrheRZMWQI/w2C03VfkNFS vPpXrKXaWbVezHwF6x9PemRxvOPvLkeKAgSVuAfK0DhT5kEldqdzFzI7UO9MYfyX j+HOUIRP/pseshUV6YbnAe9MS3T4zb5P+Qd1zRTGgo8R9/l1AmVHyrkbH1hGNjY0 mECHucCOh/VsyPAdg1XADJHqMg9081prySK8hNV6oazwSHdC38GdajuOmdyO3azQ OpJZDQd0eP4fHPMU6F5HSzLOO/wYuAie8gWVSZ3ylDxDPIKfqcjVo+4bxJ8sbmpI akj6BoMX7we0fjhlbdit =5CRH -----END PGP SIGNATURE----- Merge tag 'drm-next-2019-09-18' of git://anongit.freedesktop.org/drm/drm Pull drm updates from Dave Airlie: "This is the main pull request for 5.4-rc1 merge window. I don't think there is anything outstanding so next week should just be fixes, but we'll see if I missed anything. I landed some fixes earlier in the week but got delayed writing summary and sending it out, due to a mix of sick kid and jetlag! There are some fixes pending, but I'd rather get the main merge out of the way instead of delaying it longer. It's also pretty large in commit count and new amd header file size. The largest thing is four new amdgpu products (navi12/14, arcturus and renoir APU support). Otherwise it's pretty much lots of work across the board, i915 has started landing tigerlake support, lots of icelake fixes and lots of locking reworking for future gpu support, lots of header file rework (drmP.h is nearly gone), some old legacy hacks (DRM_WAIT_ON) have been put into the places they are needed. uapi: - content protection type property for HDCP core: - rework include dependencies - lots of drmP.h removals - link rate calculation robustness fix - make fb helper map only when required - add connector->DDC adapter link - DRM_WAIT_ON removed - drop DRM_AUTH usage from drivers dma-buf: - reservation object fence helper dma-fence: - shrink dma_fence struct - merge signal functions - store timestamps in dma_fence - selftests ttm: - embed drm_get_object struct into ttm_buffer_object - release_notify callback bridges: - sii902x - audio graph card support - tc358767 - aux data handling rework - ti-snd64dsi86 - debugfs support, DSI mode flags support panels: - Support for GiantPlus GPM940B0, Sharp LQ070Y3DG3B, Ortustech COM37H3M, Novatek NT39016, Sharp LS020B1DD01D, Raydium RM67191, Boe Himax8279d, Sharp LD-D5116Z01B - TI nspire, NEC NL8048HL11, LG Philips LB035Q02, Sharp LS037V7DW01, Sony ACX565AKM, Toppoly TD028TTEC1 Toppoly TD043MTEA1 i915: - Initial tigerlake platform support - Locking simplification work, general all over refactoring. - Selftests - HDCP debug info improvements - DSI properties - Icelake display PLL fixes, colorspace fixes, bandwidth fixes, DSI suspend/resume - GuC fixes - Perf fixes - ElkhartLake enablement - DP MST fixes - GVT - command parser enhancements amdgpu: - add wipe memory on release flag for buffer creation - Navi12/14 support (may be marked experimental) - Arcturus support - Renoir APU support - mclk DPM for Navi - DC display fixes - Raven scatter/gather support - RAS support for GFX - Navi12 + Arcturus power features - GPU reset for Picasso - smu11 i2c controller support amdkfd: - navi12/14 support - Arcturus support radeon: - kexec fix nouveau: - improved display color management - detect lack of GPU power cables vmwgfx: - evicition priority support - remove unused security feature msm: - msm8998 display support - better async commit support for cursor updates etnaviv: - per-process address space support - performance counter fixes - softpin support mcde: - DCS transfers fix exynos: - drmP.h cleanup lima: - reduce logging kirin: - misc clenaups komeda: - dual-link support - DT memory regions hisilicon: - misc fixes imx: - IPUv3 image converter fixes - 32-bit RGB V4L2 pixel format support ingenic: - more support for panel related cases mgag200: - cursor support fix panfrost: - export GPU features register to userspace - gpu heap allocations - per-fd address space support pl111: - CLD pads wiring support removed from DT rockchip: - rework to use DRM PSR helpers - fix bug in VOP_WIN_GET macro - DSI DT binding rework sun4i: - improve support for color encoding and range - DDC enabled GPIO tinydrm: - rework SPI support - improve MIPI-DBI support - moved to drm/tiny vkms: - rework CRC tracking dw-hdmi: - get_eld and i2s improvements gm12u320: - misc fixes meson: - global code cleanup - vpu feature detect omap: - alpha/pixel blend mode properties rcar-du: - misc fixes" * tag 'drm-next-2019-09-18' of git://anongit.freedesktop.org/drm/drm: (2112 commits) drm/nouveau/bar/gm20b: Avoid BAR1 teardown during init drm/nouveau: Fix ordering between TTM and GEM release drm/nouveau/prime: Extend DMA reservation object lock drm/nouveau: Fix fallout from reservation object rework drm/nouveau/kms/nv50-: Don't create MSTMs for eDP connectors drm/i915: Use NOEVICT for first pass on attemping to pin a GGTT mmap drm/i915: to make vgpu ppgtt notificaiton as atomic operation drm/i915: Flush the existing fence before GGTT read/write drm/i915: Hold irq-off for the entire fake lock period drm/i915/gvt: update RING_START reg of vGPU when the context is submitted to i915 drm/i915/gvt: update vgpu workload head pointer correctly drm/mcde: Fix DSI transfers drm/msm: Use the correct dma_sync calls harder drm/msm: remove unlikely() from WARN_ON() conditions drm/msm/dsi: Fix return value check for clk_get_parent drm/msm: add atomic traces drm/msm/dpu: async commit support drm/msm: async commit support drm/msm: split power control from prepare/complete_commit drm/msm: add kms->flush_commit() ...
This commit is contained in:
commit
574cc45397
@ -1,119 +0,0 @@
|
||||
Amlogic specific extensions to the Synopsys Designware HDMI Controller
|
||||
======================================================================
|
||||
|
||||
The Amlogic Meson Synopsys Designware Integration is composed of :
|
||||
- A Synopsys DesignWare HDMI Controller IP
|
||||
- A TOP control block controlling the Clocks and PHY
|
||||
- A custom HDMI PHY in order to convert video to TMDS signal
|
||||
___________________________________
|
||||
| HDMI TOP |<= HPD
|
||||
|___________________________________|
|
||||
| | |
|
||||
| Synopsys HDMI | HDMI PHY |=> TMDS
|
||||
| Controller |________________|
|
||||
|___________________________________|<=> DDC
|
||||
|
||||
The HDMI TOP block only supports HPD sensing.
|
||||
The Synopsys HDMI Controller interrupt is routed through the
|
||||
TOP Block interrupt.
|
||||
Communication to the TOP Block and the Synopsys HDMI Controller is done
|
||||
via a pair of dedicated addr+read/write registers.
|
||||
The HDMI PHY is configured by registers in the HHI register block.
|
||||
|
||||
Pixel data arrives in 4:4:4 format from the VENC block and the VPU HDMI mux
|
||||
selects either the ENCI encoder for the 576i or 480i formats or the ENCP
|
||||
encoder for all the other formats including interlaced HD formats.
|
||||
|
||||
The VENC uses a DVI encoder on top of the ENCI or ENCP encoders to generate
|
||||
DVI timings for the HDMI controller.
|
||||
|
||||
Amlogic Meson GXBB, GXL and GXM SoCs families embeds the Synopsys DesignWare
|
||||
HDMI TX IP version 2.01a with HDCP and I2C & S/PDIF
|
||||
audio source interfaces.
|
||||
|
||||
Required properties:
|
||||
- compatible: value should be different for each SoC family as :
|
||||
- GXBB (S905) : "amlogic,meson-gxbb-dw-hdmi"
|
||||
- GXL (S905X, S905D) : "amlogic,meson-gxl-dw-hdmi"
|
||||
- GXM (S912) : "amlogic,meson-gxm-dw-hdmi"
|
||||
followed by the common "amlogic,meson-gx-dw-hdmi"
|
||||
- G12A (S905X2, S905Y2, S905D2) : "amlogic,meson-g12a-dw-hdmi"
|
||||
- reg: Physical base address and length of the controller's registers.
|
||||
- interrupts: The HDMI interrupt number
|
||||
- clocks, clock-names : must have the phandles to the HDMI iahb and isfr clocks,
|
||||
and the Amlogic Meson venci clocks as described in
|
||||
Documentation/devicetree/bindings/clock/clock-bindings.txt,
|
||||
the clocks are soc specific, the clock-names should be "iahb", "isfr", "venci"
|
||||
- resets, resets-names: must have the phandles to the HDMI apb, glue and phy
|
||||
resets as described in :
|
||||
Documentation/devicetree/bindings/reset/reset.txt,
|
||||
the reset-names should be "hdmitx_apb", "hdmitx", "hdmitx_phy"
|
||||
|
||||
Optional properties:
|
||||
- hdmi-supply: Optional phandle to an external 5V regulator to power the HDMI
|
||||
logic, as described in the file ../regulator/regulator.txt
|
||||
|
||||
Required nodes:
|
||||
|
||||
The connections to the HDMI ports are modeled using the OF graph
|
||||
bindings specified in Documentation/devicetree/bindings/graph.txt.
|
||||
|
||||
The following table lists for each supported model the port number
|
||||
corresponding to each HDMI output and input.
|
||||
|
||||
Port 0 Port 1
|
||||
-----------------------------------------
|
||||
S905 (GXBB) VENC Input TMDS Output
|
||||
S905X (GXL) VENC Input TMDS Output
|
||||
S905D (GXL) VENC Input TMDS Output
|
||||
S912 (GXM) VENC Input TMDS Output
|
||||
S905X2 (G12A) VENC Input TMDS Output
|
||||
S905Y2 (G12A) VENC Input TMDS Output
|
||||
S905D2 (G12A) VENC Input TMDS Output
|
||||
|
||||
Example:
|
||||
|
||||
hdmi-connector {
|
||||
compatible = "hdmi-connector";
|
||||
type = "a";
|
||||
|
||||
port {
|
||||
hdmi_connector_in: endpoint {
|
||||
remote-endpoint = <&hdmi_tx_tmds_out>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
hdmi_tx: hdmi-tx@c883a000 {
|
||||
compatible = "amlogic,meson-gxbb-dw-hdmi", "amlogic,meson-gx-dw-hdmi";
|
||||
reg = <0x0 0xc883a000 0x0 0x1c>;
|
||||
interrupts = <GIC_SPI 57 IRQ_TYPE_EDGE_RISING>;
|
||||
resets = <&reset RESET_HDMITX_CAPB3>,
|
||||
<&reset RESET_HDMI_SYSTEM_RESET>,
|
||||
<&reset RESET_HDMI_TX>;
|
||||
reset-names = "hdmitx_apb", "hdmitx", "hdmitx_phy";
|
||||
clocks = <&clkc CLKID_HDMI_PCLK>,
|
||||
<&clkc CLKID_CLK81>,
|
||||
<&clkc CLKID_GCLK_VENCI_INT0>;
|
||||
clock-names = "isfr", "iahb", "venci";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
/* VPU VENC Input */
|
||||
hdmi_tx_venc_port: port@0 {
|
||||
reg = <0>;
|
||||
|
||||
hdmi_tx_in: endpoint {
|
||||
remote-endpoint = <&hdmi_tx_out>;
|
||||
};
|
||||
};
|
||||
|
||||
/* TMDS Output */
|
||||
hdmi_tx_tmds_port: port@1 {
|
||||
reg = <1>;
|
||||
|
||||
hdmi_tx_tmds_out: endpoint {
|
||||
remote-endpoint = <&hdmi_connector_in>;
|
||||
};
|
||||
};
|
||||
};
|
@ -0,0 +1,150 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
# Copyright 2019 BayLibre, SAS
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/display/amlogic,meson-dw-hdmi.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
|
||||
title: Amlogic specific extensions to the Synopsys Designware HDMI Controller
|
||||
|
||||
maintainers:
|
||||
- Neil Armstrong <narmstrong@baylibre.com>
|
||||
|
||||
description: |
|
||||
The Amlogic Meson Synopsys Designware Integration is composed of
|
||||
- A Synopsys DesignWare HDMI Controller IP
|
||||
- A TOP control block controlling the Clocks and PHY
|
||||
- A custom HDMI PHY in order to convert video to TMDS signal
|
||||
___________________________________
|
||||
| HDMI TOP |<= HPD
|
||||
|___________________________________|
|
||||
| | |
|
||||
| Synopsys HDMI | HDMI PHY |=> TMDS
|
||||
| Controller |________________|
|
||||
|___________________________________|<=> DDC
|
||||
|
||||
The HDMI TOP block only supports HPD sensing.
|
||||
The Synopsys HDMI Controller interrupt is routed through the
|
||||
TOP Block interrupt.
|
||||
Communication to the TOP Block and the Synopsys HDMI Controller is done
|
||||
via a pair of dedicated addr+read/write registers.
|
||||
The HDMI PHY is configured by registers in the HHI register block.
|
||||
|
||||
Pixel data arrives in "4:4:4" format from the VENC block and the VPU HDMI mux
|
||||
selects either the ENCI encoder for the 576i or 480i formats or the ENCP
|
||||
encoder for all the other formats including interlaced HD formats.
|
||||
|
||||
The VENC uses a DVI encoder on top of the ENCI or ENCP encoders to generate
|
||||
DVI timings for the HDMI controller.
|
||||
|
||||
Amlogic Meson GXBB, GXL and GXM SoCs families embeds the Synopsys DesignWare
|
||||
HDMI TX IP version 2.01a with HDCP and I2C & S/PDIF
|
||||
audio source interfaces.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- items:
|
||||
- enum:
|
||||
- amlogic,meson-gxbb-dw-hdmi # GXBB (S905)
|
||||
- amlogic,meson-gxl-dw-hdmi # GXL (S905X, S905D)
|
||||
- amlogic,meson-gxm-dw-hdmi # GXM (S912)
|
||||
- const: amlogic,meson-gx-dw-hdmi
|
||||
- enum:
|
||||
- amlogic,meson-g12a-dw-hdmi # G12A (S905X2, S905Y2, S905D2)
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
minItems: 3
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: isfr
|
||||
- const: iahb
|
||||
- const: venci
|
||||
|
||||
resets:
|
||||
minItems: 3
|
||||
|
||||
reset-names:
|
||||
items:
|
||||
- const: hdmitx_apb
|
||||
- const: hdmitx
|
||||
- const: hdmitx_phy
|
||||
|
||||
hdmi-supply:
|
||||
description: phandle to an external 5V regulator to power the HDMI logic
|
||||
allOf:
|
||||
- $ref: /schemas/types.yaml#/definitions/phandle
|
||||
|
||||
port@0:
|
||||
type: object
|
||||
description:
|
||||
A port node pointing to the VENC Input port node.
|
||||
|
||||
port@1:
|
||||
type: object
|
||||
description:
|
||||
A port node pointing to the TMDS Output port node.
|
||||
|
||||
"#address-cells":
|
||||
const: 1
|
||||
|
||||
"#size-cells":
|
||||
const: 0
|
||||
|
||||
"#sound-dai-cells":
|
||||
const: 0
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- clock-names
|
||||
- resets
|
||||
- reset-names
|
||||
- port@0
|
||||
- port@1
|
||||
- "#address-cells"
|
||||
- "#size-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
hdmi_tx: hdmi-tx@c883a000 {
|
||||
compatible = "amlogic,meson-gxbb-dw-hdmi", "amlogic,meson-gx-dw-hdmi";
|
||||
reg = <0xc883a000 0x1c>;
|
||||
interrupts = <57>;
|
||||
resets = <&reset_apb>, <&reset_hdmitx>, <&reset_hdmitx_phy>;
|
||||
reset-names = "hdmitx_apb", "hdmitx", "hdmitx_phy";
|
||||
clocks = <&clk_isfr>, <&clk_iahb>, <&clk_venci>;
|
||||
clock-names = "isfr", "iahb", "venci";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
/* VPU VENC Input */
|
||||
hdmi_tx_venc_port: port@0 {
|
||||
reg = <0>;
|
||||
|
||||
hdmi_tx_in: endpoint {
|
||||
remote-endpoint = <&hdmi_tx_out>;
|
||||
};
|
||||
};
|
||||
|
||||
/* TMDS Output */
|
||||
hdmi_tx_tmds_port: port@1 {
|
||||
reg = <1>;
|
||||
|
||||
hdmi_tx_tmds_out: endpoint {
|
||||
remote-endpoint = <&hdmi_connector_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -1,121 +0,0 @@
|
||||
Amlogic Meson Display Controller
|
||||
================================
|
||||
|
||||
The Amlogic Meson Display controller is composed of several components
|
||||
that are going to be documented below:
|
||||
|
||||
DMC|---------------VPU (Video Processing Unit)----------------|------HHI------|
|
||||
| vd1 _______ _____________ _________________ | |
|
||||
D |-------| |----| | | | | HDMI PLL |
|
||||
D | vd2 | VIU | | Video Post | | Video Encoders |<---|-----VCLK |
|
||||
R |-------| |----| Processing | | | | |
|
||||
| osd2 | | | |---| Enci ----------|----|-----VDAC------|
|
||||
R |-------| CSC |----| Scalers | | Encp ----------|----|----HDMI-TX----|
|
||||
A | osd1 | | | Blenders | | Encl ----------|----|---------------|
|
||||
M |-------|______|----|____________| |________________| | |
|
||||
___|__________________________________________________________|_______________|
|
||||
|
||||
|
||||
VIU: Video Input Unit
|
||||
---------------------
|
||||
|
||||
The Video Input Unit is in charge of the pixel scanout from the DDR memory.
|
||||
It fetches the frames addresses, stride and parameters from the "Canvas" memory.
|
||||
This part is also in charge of the CSC (Colorspace Conversion).
|
||||
It can handle 2 OSD Planes and 2 Video Planes.
|
||||
|
||||
VPP: Video Post Processing
|
||||
--------------------------
|
||||
|
||||
The Video Post Processing is in charge of the scaling and blending of the
|
||||
various planes into a single pixel stream.
|
||||
There is a special "pre-blending" used by the video planes with a dedicated
|
||||
scaler and a "post-blending" to merge with the OSD Planes.
|
||||
The OSD planes also have a dedicated scaler for one of the OSD.
|
||||
|
||||
VENC: Video Encoders
|
||||
--------------------
|
||||
|
||||
The VENC is composed of the multiple pixel encoders :
|
||||
- ENCI : Interlace Video encoder for CVBS and Interlace HDMI
|
||||
- ENCP : Progressive Video Encoder for HDMI
|
||||
- ENCL : LCD LVDS Encoder
|
||||
The VENC Unit gets a Pixel Clocks (VCLK) from a dedicated HDMI PLL and clock
|
||||
tree and provides the scanout clock to the VPP and VIU.
|
||||
The ENCI is connected to a single VDAC for Composite Output.
|
||||
The ENCI and ENCP are connected to an on-chip HDMI Transceiver.
|
||||
|
||||
Device Tree Bindings:
|
||||
---------------------
|
||||
|
||||
VPU: Video Processing Unit
|
||||
--------------------------
|
||||
|
||||
Required properties:
|
||||
- compatible: value should be different for each SoC family as :
|
||||
- GXBB (S905) : "amlogic,meson-gxbb-vpu"
|
||||
- GXL (S905X, S905D) : "amlogic,meson-gxl-vpu"
|
||||
- GXM (S912) : "amlogic,meson-gxm-vpu"
|
||||
followed by the common "amlogic,meson-gx-vpu"
|
||||
- G12A (S905X2, S905Y2, S905D2) : "amlogic,meson-g12a-vpu"
|
||||
- reg: base address and size of he following memory-mapped regions :
|
||||
- vpu
|
||||
- hhi
|
||||
- reg-names: should contain the names of the previous memory regions
|
||||
- interrupts: should contain the VENC Vsync interrupt number
|
||||
- amlogic,canvas: phandle to canvas provider node as described in the file
|
||||
../soc/amlogic/amlogic,canvas.txt
|
||||
|
||||
Optional properties:
|
||||
- power-domains: Optional phandle to associated power domain as described in
|
||||
the file ../power/power_domain.txt
|
||||
|
||||
Required nodes:
|
||||
|
||||
The connections to the VPU output video ports are modeled using the OF graph
|
||||
bindings specified in Documentation/devicetree/bindings/graph.txt.
|
||||
|
||||
The following table lists for each supported model the port number
|
||||
corresponding to each VPU output.
|
||||
|
||||
Port 0 Port 1
|
||||
-----------------------------------------
|
||||
S905 (GXBB) CVBS VDAC HDMI-TX
|
||||
S905X (GXL) CVBS VDAC HDMI-TX
|
||||
S905D (GXL) CVBS VDAC HDMI-TX
|
||||
S912 (GXM) CVBS VDAC HDMI-TX
|
||||
S905X2 (G12A) CVBS VDAC HDMI-TX
|
||||
S905Y2 (G12A) CVBS VDAC HDMI-TX
|
||||
S905D2 (G12A) CVBS VDAC HDMI-TX
|
||||
|
||||
Example:
|
||||
|
||||
tv-connector {
|
||||
compatible = "composite-video-connector";
|
||||
|
||||
port {
|
||||
tv_connector_in: endpoint {
|
||||
remote-endpoint = <&cvbs_vdac_out>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
vpu: vpu@d0100000 {
|
||||
compatible = "amlogic,meson-gxbb-vpu";
|
||||
reg = <0x0 0xd0100000 0x0 0x100000>,
|
||||
<0x0 0xc883c000 0x0 0x1000>,
|
||||
<0x0 0xc8838000 0x0 0x1000>;
|
||||
reg-names = "vpu", "hhi", "dmc";
|
||||
interrupts = <GIC_SPI 3 IRQ_TYPE_EDGE_RISING>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
/* CVBS VDAC output port */
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
|
||||
cvbs_vdac_out: endpoint {
|
||||
remote-endpoint = <&tv_connector_in>;
|
||||
};
|
||||
};
|
||||
};
|
137
Documentation/devicetree/bindings/display/amlogic,meson-vpu.yaml
Normal file
137
Documentation/devicetree/bindings/display/amlogic,meson-vpu.yaml
Normal file
@ -0,0 +1,137 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
# Copyright 2019 BayLibre, SAS
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/display/amlogic,meson-vpu.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
|
||||
title: Amlogic Meson Display Controller
|
||||
|
||||
maintainers:
|
||||
- Neil Armstrong <narmstrong@baylibre.com>
|
||||
|
||||
description: |
|
||||
The Amlogic Meson Display controller is composed of several components
|
||||
that are going to be documented below
|
||||
|
||||
DMC|---------------VPU (Video Processing Unit)----------------|------HHI------|
|
||||
| vd1 _______ _____________ _________________ | |
|
||||
D |-------| |----| | | | | HDMI PLL |
|
||||
D | vd2 | VIU | | Video Post | | Video Encoders |<---|-----VCLK |
|
||||
R |-------| |----| Processing | | | | |
|
||||
| osd2 | | | |---| Enci ----------|----|-----VDAC------|
|
||||
R |-------| CSC |----| Scalers | | Encp ----------|----|----HDMI-TX----|
|
||||
A | osd1 | | | Blenders | | Encl ----------|----|---------------|
|
||||
M |-------|______|----|____________| |________________| | |
|
||||
___|__________________________________________________________|_______________|
|
||||
|
||||
|
||||
VIU: Video Input Unit
|
||||
---------------------
|
||||
|
||||
The Video Input Unit is in charge of the pixel scanout from the DDR memory.
|
||||
It fetches the frames addresses, stride and parameters from the "Canvas" memory.
|
||||
This part is also in charge of the CSC (Colorspace Conversion).
|
||||
It can handle 2 OSD Planes and 2 Video Planes.
|
||||
|
||||
VPP: Video Post Processing
|
||||
--------------------------
|
||||
|
||||
The Video Post Processing is in charge of the scaling and blending of the
|
||||
various planes into a single pixel stream.
|
||||
There is a special "pre-blending" used by the video planes with a dedicated
|
||||
scaler and a "post-blending" to merge with the OSD Planes.
|
||||
The OSD planes also have a dedicated scaler for one of the OSD.
|
||||
|
||||
VENC: Video Encoders
|
||||
--------------------
|
||||
|
||||
The VENC is composed of the multiple pixel encoders
|
||||
- ENCI : Interlace Video encoder for CVBS and Interlace HDMI
|
||||
- ENCP : Progressive Video Encoder for HDMI
|
||||
- ENCL : LCD LVDS Encoder
|
||||
The VENC Unit gets a Pixel Clocks (VCLK) from a dedicated HDMI PLL and clock
|
||||
tree and provides the scanout clock to the VPP and VIU.
|
||||
The ENCI is connected to a single VDAC for Composite Output.
|
||||
The ENCI and ENCP are connected to an on-chip HDMI Transceiver.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- items:
|
||||
- enum:
|
||||
- amlogic,meson-gxbb-vpu # GXBB (S905)
|
||||
- amlogic,meson-gxl-vpu # GXL (S905X, S905D)
|
||||
- amlogic,meson-gxm-vpu # GXM (S912)
|
||||
- const: amlogic,meson-gx-vpu
|
||||
- enum:
|
||||
- amlogic,meson-g12a-vpu # G12A (S905X2, S905Y2, S905D2)
|
||||
|
||||
reg:
|
||||
maxItems: 2
|
||||
|
||||
reg-names:
|
||||
items:
|
||||
- const: vpu
|
||||
- const: hhi
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
description: phandle to the associated power domain
|
||||
|
||||
port@0:
|
||||
type: object
|
||||
description:
|
||||
A port node pointing to the CVBS VDAC port node.
|
||||
|
||||
port@1:
|
||||
type: object
|
||||
description:
|
||||
A port node pointing to the HDMI-TX port node.
|
||||
|
||||
"#address-cells":
|
||||
const: 1
|
||||
|
||||
"#size-cells":
|
||||
const: 0
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- port@0
|
||||
- port@1
|
||||
- "#address-cells"
|
||||
- "#size-cells"
|
||||
|
||||
examples:
|
||||
- |
|
||||
vpu: vpu@d0100000 {
|
||||
compatible = "amlogic,meson-gxbb-vpu", "amlogic,meson-gx-vpu";
|
||||
reg = <0xd0100000 0x100000>, <0xc883c000 0x1000>;
|
||||
reg-names = "vpu", "hhi";
|
||||
interrupts = <3>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
/* CVBS VDAC output port */
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
|
||||
cvbs_vdac_out: endpoint {
|
||||
remote-endpoint = <&tv_connector_in>;
|
||||
};
|
||||
};
|
||||
|
||||
/* HDMI TX output port */
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
|
||||
hdmi_tx_out: endpoint {
|
||||
remote-endpoint = <&hdmi_tx_in>;
|
||||
};
|
||||
};
|
||||
};
|
@ -39,9 +39,11 @@ Required sub-nodes:
|
||||
|
||||
- port: describes LCD panel signals, following the common binding
|
||||
for video transmitter interfaces; see
|
||||
Documentation/devicetree/bindings/media/video-interfaces.txt;
|
||||
when it is a TFT panel, the port's endpoint must define the
|
||||
following property:
|
||||
Documentation/devicetree/bindings/media/video-interfaces.txt
|
||||
|
||||
Deprecated properties:
|
||||
The port's endbpoint subnode had this, now deprecated property
|
||||
in the past. Drivers should be able to survive without it:
|
||||
|
||||
- arm,pl11x,tft-r0g0b0-pads: an array of three 32-bit values,
|
||||
defining the way CLD pads are wired up; first value
|
||||
@ -80,7 +82,6 @@ Example:
|
||||
port {
|
||||
clcd_pads: endpoint {
|
||||
remote-endpoint = <&clcd_panel>;
|
||||
arm,pl11x,tft-r0g0b0-pads = <0 8 16>;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -26,9 +26,8 @@ Optional properties:
|
||||
- clocks: phandle and clock specifier for each clock listed in
|
||||
the clock-names property
|
||||
- clock-names: "mclk"
|
||||
Describes SII902x MCLK input. MCLK is used to produce
|
||||
HDMI audio CTS values. This property is required if
|
||||
"#sound-dai-cells"-property is present. This property follows
|
||||
Describes SII902x MCLK input. MCLK can be used to produce
|
||||
HDMI audio CTS values. This property follows
|
||||
Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||
consumer binding.
|
||||
|
||||
|
@ -9,6 +9,7 @@ Optional properties:
|
||||
- label: a symbolic name for the connector
|
||||
- hpd-gpios: HPD GPIO number
|
||||
- ddc-i2c-bus: phandle link to the I2C controller used for DDC EDID probing
|
||||
- ddc-en-gpios: signal to enable DDC bus
|
||||
|
||||
Required nodes:
|
||||
- Video port for HDMI input
|
||||
|
@ -1,26 +0,0 @@
|
||||
Ampire AM-480272H3TMQW-T01H 4.3" WQVGA TFT LCD panel
|
||||
|
||||
This binding is compatible with the simple-panel binding, which is specified
|
||||
in simple-panel.txt in this directory.
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "ampire,am-480272h3tmqw-t01h"
|
||||
|
||||
Optional properties:
|
||||
- power-supply: regulator to provide the supply voltage
|
||||
- enable-gpios: GPIO pin to enable or disable the panel
|
||||
- backlight: phandle of the backlight device attached to the panel
|
||||
|
||||
Optional nodes:
|
||||
- Video port for RGB input.
|
||||
|
||||
Example:
|
||||
panel_rgb: panel-rgb {
|
||||
compatible = "ampire,am-480272h3tmqw-t01h";
|
||||
enable-gpios = <&gpioa 8 1>;
|
||||
port {
|
||||
panel_in_rgb: endpoint {
|
||||
remote-endpoint = <&controller_out_rgb>;
|
||||
};
|
||||
};
|
||||
};
|
@ -0,0 +1,42 @@
|
||||
# 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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
@ -10,7 +10,7 @@ Required properties:
|
||||
- compatible: should be "arm,versatile-tft-panel"
|
||||
|
||||
Required subnodes:
|
||||
- port: see display/panel/panel-common.txt, graph.txt
|
||||
- port: see display/panel/panel-common.yaml, graph.txt
|
||||
|
||||
|
||||
Example:
|
||||
|
@ -1,9 +0,0 @@
|
||||
Armadeus ST0700 Adapt. A Santek ST0700I5Y-RBSLW 7.0" WVGA (800x480) TFT with
|
||||
an adapter board.
|
||||
|
||||
Required properties:
|
||||
- compatible: "armadeus,st0700-adapt"
|
||||
- power-supply: see panel-common.txt
|
||||
|
||||
Optional properties:
|
||||
- backlight: see panel-common.txt
|
@ -0,0 +1,33 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/panel/armadeus,st0700-adapt.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Armadeus ST0700 Adapter
|
||||
|
||||
description:
|
||||
A Santek ST0700I5Y-RBSLW 7.0" WVGA (800x480) TFT with an adapter board.
|
||||
|
||||
maintainers:
|
||||
- '"Sébastien Szymanski" <sebastien.szymanski@armadeus.com>'
|
||||
- Thierry Reding <thierry.reding@gmail.com>
|
||||
|
||||
allOf:
|
||||
- $ref: panel-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: armadeus,st0700-adapt
|
||||
|
||||
power-supply: true
|
||||
backlight: true
|
||||
port: true
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- power-supply
|
||||
|
||||
...
|
@ -1,12 +0,0 @@
|
||||
Banana Pi 7" (S070WV20-CT16) TFT LCD Panel
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "bananapi,s070wv20-ct16"
|
||||
- power-supply: see ./panel-common.txt
|
||||
|
||||
Optional properties:
|
||||
- enable-gpios: see ./simple-panel.txt
|
||||
- backlight: see ./simple-panel.txt
|
||||
|
||||
This binding is compatible with the simple-panel binding, which is specified
|
||||
in ./simple-panel.txt.
|
@ -0,0 +1,31 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/panel/bananapi,s070wv20-ct16.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Banana Pi 7" (S070WV20-CT16) TFT LCD Panel
|
||||
|
||||
maintainers:
|
||||
- Chen-Yu Tsai <wens@csie.org>
|
||||
- Thierry Reding <thierry.reding@gmail.com>
|
||||
|
||||
allOf:
|
||||
- $ref: panel-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: bananapi,s070wv20-ct16
|
||||
|
||||
power-supply: true
|
||||
backlight: true
|
||||
enable-gpios: true
|
||||
port: true
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- power-supply
|
||||
|
||||
...
|
@ -0,0 +1,24 @@
|
||||
Boe Himax8279d 1200x1920 TFT LCD panel
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "boe,himax8279d8p" and one of: "boe,himax8279d10p"
|
||||
- reg: DSI virtual channel of the peripheral
|
||||
- enable-gpios: panel enable gpio
|
||||
- pp33-gpios: a GPIO phandle for the 3.3v pin that provides the supply voltage
|
||||
- pp18-gpios: a GPIO phandle for the 1.8v pin that provides the supply voltage
|
||||
|
||||
Optional properties:
|
||||
- backlight: phandle of the backlight device attached to the panel
|
||||
|
||||
Example:
|
||||
|
||||
&mipi_dsi {
|
||||
panel {
|
||||
compatible = "boe,himax8279d8p", "boe,himax8279d10p";
|
||||
reg = <0>;
|
||||
backlight = <&backlight>;
|
||||
enable-gpios = <&gpio 45 GPIO_ACTIVE_HIGH>;
|
||||
pp33-gpios = <&gpio 35 GPIO_ACTIVE_HIGH>;
|
||||
pp18-gpios = <&gpio 36 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
};
|
@ -1,13 +0,0 @@
|
||||
DLC Display Co. DLC0700YZG-1 7.0" WSVGA TFT LCD panel
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "dlc,dlc0700yzg-1"
|
||||
- power-supply: See simple-panel.txt
|
||||
|
||||
Optional properties:
|
||||
- reset-gpios: See panel-common.txt
|
||||
- enable-gpios: See simple-panel.txt
|
||||
- backlight: See simple-panel.txt
|
||||
|
||||
This binding is compatible with the simple-panel binding, which is specified
|
||||
in simple-panel.txt in this directory.
|
@ -0,0 +1,31 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/panel/dlc,dlc0700yzg-1.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: DLC Display Co. DLC0700YZG-1 7.0" WSVGA TFT LCD panel
|
||||
|
||||
maintainers:
|
||||
- Philipp Zabel <p.zabel@pengutronix.de>
|
||||
- Thierry Reding <thierry.reding@gmail.com>
|
||||
|
||||
allOf:
|
||||
- $ref: panel-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: dlc,dlc0700yzg-1
|
||||
|
||||
reset-gpios: true
|
||||
enable-gpios: true
|
||||
backlight: true
|
||||
port: true
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- power-supply
|
||||
|
||||
...
|
@ -40,7 +40,7 @@ simple-panel.txt
|
||||
| Identifier | compatbile | description |
|
||||
+=================+=====================+=====================================+
|
||||
| ETM0700G0DH6 | edt,etm070080dh6 | WVGA TFT Display with capacitive |
|
||||
| | | Touchscreen |
|
||||
| | edt,etm0700g0dh6 | Touchscreen |
|
||||
+-----------------+---------------------+-------------------------------------+
|
||||
| ETM0700G0BDH6 | edt,etm070080bdh6 | Same as ETM0700G0DH6 but with |
|
||||
| | | inverted pixel clock. |
|
||||
|
@ -0,0 +1,12 @@
|
||||
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.
|
@ -1,7 +0,0 @@
|
||||
Innolux Corporation 10.1" EE101IA-01D WXGA (1280x800) LVDS panel
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "innolux,ee101ia-01d"
|
||||
|
||||
This binding is compatible with the lvds-panel binding, which is specified
|
||||
in panel-lvds.txt in this directory.
|
@ -0,0 +1,31 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/panel/innolux,ee101ia-01d.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Innolux Corporation 10.1" EE101IA-01D WXGA (1280x800) LVDS panel
|
||||
|
||||
maintainers:
|
||||
- Heiko Stuebner <heiko.stuebner@bq.com>
|
||||
- Thierry Reding <thierry.reding@gmail.com>
|
||||
|
||||
allOf:
|
||||
- $ref: lvds.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: innolux,ee101ia-01d
|
||||
- {} # panel-lvds, but not listed here to avoid false select
|
||||
|
||||
backlight: true
|
||||
enable-gpios: true
|
||||
power-supply: true
|
||||
width-mm: true
|
||||
height-mm: true
|
||||
panel-timing: true
|
||||
port: true
|
||||
|
||||
additionalProperties: false
|
||||
...
|
@ -0,0 +1,42 @@
|
||||
King Display KD035G6-54NT 3.5" (320x240 pixels) 24-bit TFT LCD panel
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "kingdisplay,kd035g6-54nt"
|
||||
- power-supply: See panel-common.txt
|
||||
- reset-gpios: See panel-common.txt
|
||||
|
||||
Optional properties:
|
||||
- backlight: see panel-common.txt
|
||||
|
||||
The generic bindings for the SPI slaves documented in [1] also apply.
|
||||
|
||||
The device node can contain one 'port' child node with one child
|
||||
'endpoint' node, according to the bindings defined in [2]. This
|
||||
node should describe panel's video bus.
|
||||
|
||||
[1]: Documentation/devicetree/bindings/spi/spi-bus.txt
|
||||
[2]: Documentation/devicetree/bindings/graph.txt
|
||||
|
||||
Example:
|
||||
|
||||
&spi {
|
||||
panel@0 {
|
||||
compatible = "kingdisplay,kd035g6-54nt";
|
||||
reg = <0>;
|
||||
|
||||
spi-max-frequency = <3125000>;
|
||||
spi-3wire;
|
||||
spi-cs-high;
|
||||
|
||||
reset-gpios = <&gpe 2 GPIO_ACTIVE_LOW>;
|
||||
|
||||
backlight = <&backlight>;
|
||||
power-supply = <&ldo6>;
|
||||
|
||||
port {
|
||||
panel_input: endpoint {
|
||||
remote-endpoint = <&panel_output>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
107
Documentation/devicetree/bindings/display/panel/lvds.yaml
Normal file
107
Documentation/devicetree/bindings/display/panel/lvds.yaml
Normal file
@ -0,0 +1,107 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/panel/lvds.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: LVDS Display Panel
|
||||
|
||||
maintainers:
|
||||
- Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
|
||||
- Thierry Reding <thierry.reding@gmail.com>
|
||||
|
||||
description: |+
|
||||
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 bindings supports display panels compatible with the
|
||||
following specifications.
|
||||
|
||||
[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)
|
||||
|
||||
Device compatible with those specifications have been marketed under the
|
||||
FPD-Link and FlatLink brands.
|
||||
|
||||
allOf:
|
||||
- $ref: panel-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: panel-lvds
|
||||
description:
|
||||
Shall contain "panel-lvds" in addition to a mandatory panel-specific
|
||||
compatible string defined in individual panel bindings. The "panel-lvds"
|
||||
value shall never be used on its own.
|
||||
|
||||
data-mapping:
|
||||
enum:
|
||||
- jeida-18
|
||||
- jeida-24
|
||||
- vesa-24
|
||||
description: |
|
||||
The color signals mapping order.
|
||||
|
||||
LVDS data mappings are defined as follows.
|
||||
|
||||
- "jeida-18" - 18-bit data mapping compatible with the [JEIDA], [LDI] and
|
||||
[VESA] specifications. Data are transferred as follows on 3 LVDS lanes.
|
||||
|
||||
Slot 0 1 2 3 4 5 6
|
||||
________________ _________________
|
||||
Clock \_______________________/
|
||||
______ ______ ______ ______ ______ ______ ______
|
||||
DATA0 ><__G0__><__R5__><__R4__><__R3__><__R2__><__R1__><__R0__><
|
||||
DATA1 ><__B1__><__B0__><__G5__><__G4__><__G3__><__G2__><__G1__><
|
||||
DATA2 ><_CTL2_><_CTL1_><_CTL0_><__B5__><__B4__><__B3__><__B2__><
|
||||
|
||||
- "jeida-24" - 24-bit data mapping compatible with the [DSIM] and [LDI]
|
||||
specifications. Data are transferred as follows on 4 LVDS lanes.
|
||||
|
||||
Slot 0 1 2 3 4 5 6
|
||||
________________ _________________
|
||||
Clock \_______________________/
|
||||
______ ______ ______ ______ ______ ______ ______
|
||||
DATA0 ><__G2__><__R7__><__R6__><__R5__><__R4__><__R3__><__R2__><
|
||||
DATA1 ><__B3__><__B2__><__G7__><__G6__><__G5__><__G4__><__G3__><
|
||||
DATA2 ><_CTL2_><_CTL1_><_CTL0_><__B7__><__B6__><__B5__><__B4__><
|
||||
DATA3 ><_CTL3_><__B1__><__B0__><__G1__><__G0__><__R1__><__R0__><
|
||||
|
||||
- "vesa-24" - 24-bit data mapping compatible with the [VESA] specification.
|
||||
Data are transferred as follows on 4 LVDS lanes.
|
||||
|
||||
Slot 0 1 2 3 4 5 6
|
||||
________________ _________________
|
||||
Clock \_______________________/
|
||||
______ ______ ______ ______ ______ ______ ______
|
||||
DATA0 ><__G0__><__R5__><__R4__><__R3__><__R2__><__R1__><__R0__><
|
||||
DATA1 ><__B1__><__B0__><__G5__><__G4__><__G3__><__G2__><__G1__><
|
||||
DATA2 ><_CTL2_><_CTL1_><_CTL0_><__B5__><__B4__><__B3__><__B2__><
|
||||
DATA3 ><_CTL3_><__B7__><__B6__><__G7__><__G6__><__R7__><__R6__><
|
||||
|
||||
Control signals are mapped as follows.
|
||||
|
||||
CTL0: HSync
|
||||
CTL1: VSync
|
||||
CTL2: Data Enable
|
||||
CTL3: 0
|
||||
|
||||
data-mirror:
|
||||
type: boolean
|
||||
description:
|
||||
If set, reverse the bit order described in the data mappings below on all
|
||||
data lanes, transmitting bits for slots 6 to 0 instead of 0 to 6.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- data-mapping
|
||||
- width-mm
|
||||
- height-mm
|
||||
- panel-timing
|
||||
- port
|
||||
|
||||
...
|
@ -1,47 +0,0 @@
|
||||
Mitsubishi AA204XD12 LVDS Display Panel
|
||||
=======================================
|
||||
|
||||
The AA104XD12 is a 10.4" XGA TFT-LCD display panel.
|
||||
|
||||
These DT bindings follow the LVDS panel bindings defined in panel-lvds.txt
|
||||
with the following device-specific properties.
|
||||
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: Shall contain "mitsubishi,aa121td01" and "panel-lvds", in that
|
||||
order.
|
||||
- vcc-supply: Reference to the regulator powering the panel VCC pins.
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
panel {
|
||||
compatible = "mitsubishi,aa104xd12", "panel-lvds";
|
||||
vcc-supply = <&vcc_3v3>;
|
||||
|
||||
width-mm = <210>;
|
||||
height-mm = <158>;
|
||||
|
||||
data-mapping = "jeida-24";
|
||||
|
||||
panel-timing {
|
||||
/* 1024x768 @65Hz */
|
||||
clock-frequency = <65000000>;
|
||||
hactive = <1024>;
|
||||
vactive = <768>;
|
||||
hsync-len = <136>;
|
||||
hfront-porch = <20>;
|
||||
hback-porch = <160>;
|
||||
vfront-porch = <3>;
|
||||
vback-porch = <29>;
|
||||
vsync-len = <6>;
|
||||
};
|
||||
|
||||
port {
|
||||
panel_in: endpoint {
|
||||
remote-endpoint = <&lvds_encoder>;
|
||||
};
|
||||
};
|
||||
};
|
@ -0,0 +1,75 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/panel/mitsubishi,aa104xd12.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Mitsubishi AA104XD12 10.4" XGA LVDS Display Panel
|
||||
|
||||
maintainers:
|
||||
- Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
||||
- Thierry Reding <thierry.reding@gmail.com>
|
||||
|
||||
allOf:
|
||||
- $ref: lvds.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: mitsubishi,aa104xd12
|
||||
- {} # panel-lvds, but not listed here to avoid false select
|
||||
|
||||
vcc-supply:
|
||||
description: Reference to the regulator powering the panel VCC pins.
|
||||
|
||||
data-mapping:
|
||||
const: jeida-24
|
||||
|
||||
width-mm:
|
||||
const: 210
|
||||
|
||||
height-mm:
|
||||
const: 158
|
||||
|
||||
panel-timing: true
|
||||
port: true
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- vcc-supply
|
||||
|
||||
examples:
|
||||
- |+
|
||||
|
||||
panel {
|
||||
compatible = "mitsubishi,aa104xd12", "panel-lvds";
|
||||
vcc-supply = <&vcc_3v3>;
|
||||
|
||||
width-mm = <210>;
|
||||
height-mm = <158>;
|
||||
|
||||
data-mapping = "jeida-24";
|
||||
|
||||
panel-timing {
|
||||
/* 1024x768 @65Hz */
|
||||
clock-frequency = <65000000>;
|
||||
hactive = <1024>;
|
||||
vactive = <768>;
|
||||
hsync-len = <136>;
|
||||
hfront-porch = <20>;
|
||||
hback-porch = <160>;
|
||||
vfront-porch = <3>;
|
||||
vback-porch = <29>;
|
||||
vsync-len = <6>;
|
||||
};
|
||||
|
||||
port {
|
||||
panel_in: endpoint {
|
||||
remote-endpoint = <&lvds_encoder>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
@ -1,47 +0,0 @@
|
||||
Mitsubishi AA121TD01 LVDS Display Panel
|
||||
=======================================
|
||||
|
||||
The AA121TD01 is a 12.1" WXGA TFT-LCD display panel.
|
||||
|
||||
These DT bindings follow the LVDS panel bindings defined in panel-lvds.txt
|
||||
with the following device-specific properties.
|
||||
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: Shall contain "mitsubishi,aa121td01" and "panel-lvds", in that
|
||||
order.
|
||||
- vcc-supply: Reference to the regulator powering the panel VCC pins.
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
panel {
|
||||
compatible = "mitsubishi,aa121td01", "panel-lvds";
|
||||
vcc-supply = <&vcc_3v3>;
|
||||
|
||||
width-mm = <261>;
|
||||
height-mm = <163>;
|
||||
|
||||
data-mapping = "jeida-24";
|
||||
|
||||
panel-timing {
|
||||
/* 1280x800 @60Hz */
|
||||
clock-frequency = <71000000>;
|
||||
hactive = <1280>;
|
||||
vactive = <800>;
|
||||
hsync-len = <70>;
|
||||
hfront-porch = <20>;
|
||||
hback-porch = <70>;
|
||||
vsync-len = <5>;
|
||||
vfront-porch = <3>;
|
||||
vback-porch = <15>;
|
||||
};
|
||||
|
||||
port {
|
||||
panel_in: endpoint {
|
||||
remote-endpoint = <&lvds_encoder>;
|
||||
};
|
||||
};
|
||||
};
|
@ -0,0 +1,74 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/panel/mitsubishi,aa121td01.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Mitsubishi AA121TD01 12.1" WXGA LVDS Display Panel
|
||||
|
||||
maintainers:
|
||||
- Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
||||
- Thierry Reding <thierry.reding@gmail.com>
|
||||
|
||||
allOf:
|
||||
- $ref: lvds.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: mitsubishi,aa121td01
|
||||
- {} # panel-lvds, but not listed here to avoid false select
|
||||
|
||||
vcc-supply:
|
||||
description: Reference to the regulator powering the panel VCC pins.
|
||||
|
||||
data-mapping:
|
||||
const: jeida-24
|
||||
|
||||
width-mm:
|
||||
const: 261
|
||||
|
||||
height-mm:
|
||||
const: 163
|
||||
|
||||
panel-timing: true
|
||||
port: true
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- vcc-supply
|
||||
|
||||
examples:
|
||||
- |+
|
||||
panel {
|
||||
compatible = "mitsubishi,aa121td01", "panel-lvds";
|
||||
vcc-supply = <&vcc_3v3>;
|
||||
|
||||
width-mm = <261>;
|
||||
height-mm = <163>;
|
||||
|
||||
data-mapping = "jeida-24";
|
||||
|
||||
panel-timing {
|
||||
/* 1280x800 @60Hz */
|
||||
clock-frequency = <71000000>;
|
||||
hactive = <1280>;
|
||||
vactive = <800>;
|
||||
hsync-len = <70>;
|
||||
hfront-porch = <20>;
|
||||
hback-porch = <70>;
|
||||
vsync-len = <5>;
|
||||
vfront-porch = <3>;
|
||||
vback-porch = <15>;
|
||||
};
|
||||
|
||||
port {
|
||||
panel_in: endpoint {
|
||||
remote-endpoint = <&lvds_encoder>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
@ -0,0 +1,62 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/panel/nec,nl8048hl11.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: NEC NL8048HL11 4.1" WVGA TFT LCD panel
|
||||
|
||||
description:
|
||||
The NEC NL8048HL11 is a 4.1" WVGA TFT LCD panel with a 24-bit RGB parallel
|
||||
data interface and an SPI control interface.
|
||||
|
||||
maintainers:
|
||||
- Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
||||
|
||||
allOf:
|
||||
- $ref: panel-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: nec,nl8048hl11
|
||||
|
||||
label: true
|
||||
port: true
|
||||
reg: true
|
||||
reset-gpios: true
|
||||
|
||||
spi-max-frequency:
|
||||
maximum: 10000000
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- reset-gpios
|
||||
- port
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
spi0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
lcd_panel: panel@0 {
|
||||
compatible = "nec,nl8048hl11";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <10000000>;
|
||||
|
||||
reset-gpios = <&gpio7 7 GPIO_ACTIVE_LOW>;
|
||||
|
||||
port {
|
||||
lcd_in: endpoint {
|
||||
remote-endpoint = <&dpi_out>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
@ -0,0 +1,12 @@
|
||||
OrtusTech COM37H3M05DTC Blanview 3.7" VGA portrait TFT-LCD panel
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "ortustech,com37h3m05dtc"
|
||||
|
||||
Optional properties:
|
||||
- enable-gpios: GPIO pin to enable or disable the panel
|
||||
- backlight: phandle of the backlight device attached to the panel
|
||||
- power-supply: phandle of the regulator that provides the supply voltage
|
||||
|
||||
This binding is compatible with the simple-panel binding, which is specified
|
||||
in simple-panel.txt in this directory.
|
@ -0,0 +1,12 @@
|
||||
OrtusTech COM37H3M99DTC Blanview 3.7" VGA portrait TFT-LCD panel
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "ortustech,com37h3m99dtc"
|
||||
|
||||
Optional properties:
|
||||
- enable-gpios: GPIO pin to enable or disable the panel
|
||||
- backlight: phandle of the backlight device attached to the panel
|
||||
- power-supply: phandle of the regulator that provides the supply voltage
|
||||
|
||||
This binding is compatible with the simple-panel binding, which is specified
|
||||
in simple-panel.txt in this directory.
|
@ -1,101 +0,0 @@
|
||||
Common Properties for Display Panel
|
||||
===================================
|
||||
|
||||
This document defines device tree properties common to several classes of
|
||||
display panels. It doesn't constitue 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.
|
||||
|
||||
|
||||
Descriptive Properties
|
||||
----------------------
|
||||
|
||||
- width-mm,
|
||||
- height-mm: The width-mm and height-mm specify the width and height of the
|
||||
physical area where images are displayed. These properties are expressed in
|
||||
millimeters and rounded to the closest unit.
|
||||
|
||||
- label: The label property specifies a symbolic name for the panel as a
|
||||
string suitable for use by humans. It typically contains a name inscribed on
|
||||
the system (e.g. as an affixed label) or specified in the system's
|
||||
documentation (e.g. in the user's manual).
|
||||
|
||||
If no such name exists, and unless the property is mandatory according to
|
||||
device tree bindings, it shall rather be omitted than constructed of
|
||||
non-descriptive information. For instance an LCD panel in a system that
|
||||
contains a single panel shall not be labelled "LCD" if that name is not
|
||||
inscribed on the system or used in a descriptive fashion in system
|
||||
documentation.
|
||||
|
||||
|
||||
Display Timings
|
||||
---------------
|
||||
|
||||
- panel-timing: Most display panels are restricted to a single resolution and
|
||||
require specific display timings. The panel-timing subnode expresses those
|
||||
timings as specified in the timing subnode section of the display timing
|
||||
bindings defined in
|
||||
Documentation/devicetree/bindings/display/panel/display-timing.txt.
|
||||
|
||||
|
||||
Connectivity
|
||||
------------
|
||||
|
||||
- ports: Panels receive video data through one or multiple connections. While
|
||||
the nature of those connections is specific to the panel type, the
|
||||
connectivity is expressed in a standard fashion using ports as specified in
|
||||
the device graph bindings defined in
|
||||
Documentation/devicetree/bindings/graph.txt.
|
||||
|
||||
- ddc-i2c-bus: Some panels expose EDID information through an I2C-compatible
|
||||
bus such as DDC2 or E-DDC. For such panels the ddc-i2c-bus contains a
|
||||
phandle to the system I2C controller connected to that bus.
|
||||
|
||||
|
||||
Control I/Os
|
||||
------------
|
||||
|
||||
Many display panels can be controlled through pins driven by GPIOs. The nature
|
||||
and timing of those control signals are device-specific and left for panel
|
||||
device tree bindings to specify. The following GPIO specifiers can however be
|
||||
used for panels that implement compatible control signals.
|
||||
|
||||
- enable-gpios: Specifier for a GPIO connected to the panel enable control
|
||||
signal. The enable signal is active high and enables operation of the panel.
|
||||
This property can also be used for panels implementing an active low power
|
||||
down signal, which is a negated version of the enable signal. Active low
|
||||
enable signals (or active high power down signals) can be supported by
|
||||
inverting the GPIO specifier polarity flag.
|
||||
|
||||
Note that the enable signal control panel operation only and must not be
|
||||
confused with a backlight enable signal.
|
||||
|
||||
- reset-gpios: Specifier for a GPIO coonnected to the panel reset control
|
||||
signal. The reset signal is active low and resets the panel internal logic
|
||||
while active. Active high reset signals can be supported by inverting the
|
||||
GPIO specifier polarity flag.
|
||||
|
||||
Power
|
||||
-----
|
||||
|
||||
- power-supply: display panels require power to be supplied. While several
|
||||
panels need more than one power supply with panel-specific constraints
|
||||
governing the order and timings of the power supplies, in many cases a single
|
||||
power supply is sufficient, either because the panel has a single power rail,
|
||||
or because all its power rails can be driven by the same supply. In that case
|
||||
the power-supply property specifies the supply powering the panel as a phandle
|
||||
to a regulator.
|
||||
|
||||
Backlight
|
||||
---------
|
||||
|
||||
Most display panels include a backlight. Some of them also include a backlight
|
||||
controller exposed through a control bus such as I2C or DSI. Others expose
|
||||
backlight control through GPIO, PWM or other signals connected to an external
|
||||
backlight controller.
|
||||
|
||||
- backlight: For panels whose backlight is controlled by an external backlight
|
||||
controller, this property contains a phandle that references the controller.
|
@ -0,0 +1,149 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/panel/panel-common.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Common Properties for Display Panels
|
||||
|
||||
maintainers:
|
||||
- Thierry Reding <thierry.reding@gmail.com>
|
||||
- Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
|
||||
|
||||
description: |
|
||||
This document defines device tree properties common to several classes of
|
||||
display panels. It doesn't constitue 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.
|
||||
|
||||
properties:
|
||||
# Descriptive Properties
|
||||
width-mm:
|
||||
description:
|
||||
Specifies the width of the physical area where images are displayed. This
|
||||
property is expressed in millimeters and rounded to the closest unit.
|
||||
|
||||
height-mm:
|
||||
description:
|
||||
Specifies the height of the physical area where images are displayed. This
|
||||
property is expressed in millimeters and rounded to the closest unit.
|
||||
|
||||
label:
|
||||
description: |
|
||||
The label property specifies a symbolic name for the panel as a
|
||||
string suitable for use by humans. It typically contains a name inscribed
|
||||
on the system (e.g. as an affixed label) or specified in the system's
|
||||
documentation (e.g. in the user's manual).
|
||||
|
||||
If no such name exists, and unless the property is mandatory according to
|
||||
device tree bindings, it shall rather be omitted than constructed of
|
||||
non-descriptive information. For instance an LCD panel in a system that
|
||||
contains a single panel shall not be labelled "LCD" if that name is not
|
||||
inscribed on the system or used in a descriptive fashion in system
|
||||
documentation.
|
||||
|
||||
rotation:
|
||||
description:
|
||||
Display rotation in degrees counter clockwise (0,90,180,270)
|
||||
allOf:
|
||||
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||
- enum: [ 0, 90, 180, 270 ]
|
||||
|
||||
# Display Timings
|
||||
panel-timing:
|
||||
type: object
|
||||
description:
|
||||
Most display panels are restricted to a single resolution and
|
||||
require specific display timings. The panel-timing subnode expresses those
|
||||
timings as specified in the timing subnode section of the display timing
|
||||
bindings defined in
|
||||
Documentation/devicetree/bindings/display/panel/display-timing.txt.
|
||||
|
||||
# Connectivity
|
||||
port:
|
||||
type: object
|
||||
|
||||
ports:
|
||||
type: object
|
||||
description:
|
||||
Panels receive video data through one or multiple connections. While
|
||||
the nature of those connections is specific to the panel type, the
|
||||
connectivity is expressed in a standard fashion using ports as specified
|
||||
in the device graph bindings defined in
|
||||
Documentation/devicetree/bindings/graph.txt.
|
||||
|
||||
ddc-i2c-bus:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
Some panels expose EDID information through an I2C-compatible
|
||||
bus such as DDC2 or E-DDC. For such panels the ddc-i2c-bus contains a
|
||||
phandle to the system I2C controller connected to that bus.
|
||||
|
||||
no-hpd:
|
||||
type: boolean
|
||||
description:
|
||||
This panel is supposed to communicate that it's ready via HPD
|
||||
(hot plug detect) signal, but the signal isn't hooked up so we should
|
||||
hardcode the max delay from the panel spec when powering up the panel.
|
||||
|
||||
# Control I/Os
|
||||
|
||||
# Many display panels can be controlled through pins driven by GPIOs. The nature
|
||||
# and timing of those control signals are device-specific and left for panel
|
||||
# device tree bindings to specify. The following GPIO specifiers can however be
|
||||
# used for panels that implement compatible control signals.
|
||||
|
||||
enable-gpios:
|
||||
maxItems: 1
|
||||
description: |
|
||||
Specifier for a GPIO connected to the panel enable control signal. The
|
||||
enable signal is active high and enables operation of the panel. This
|
||||
property can also be used for panels implementing an active low power down
|
||||
signal, which is a negated version of the enable signal. Active low enable
|
||||
signals (or active high power down signals) can be supported by inverting
|
||||
the GPIO specifier polarity flag.
|
||||
|
||||
Note that the enable signal control panel operation only and must not be
|
||||
confused with a backlight enable signal.
|
||||
|
||||
reset-gpios:
|
||||
maxItems: 1
|
||||
description:
|
||||
Specifier for a GPIO connected to the panel reset control signal.
|
||||
The reset signal is active low and resets the panel internal logic
|
||||
while active. Active high reset signals can be supported by inverting the
|
||||
GPIO specifier polarity flag.
|
||||
|
||||
# Power
|
||||
power-supply:
|
||||
description:
|
||||
Display panels require power to be supplied. While several panels need
|
||||
more than one power supply with panel-specific constraints governing the
|
||||
order and timings of the power supplies, in many cases a single power
|
||||
supply is sufficient, either because the panel has a single power rail, or
|
||||
because all its power rails can be driven by the same supply. In that case
|
||||
the power-supply property specifies the supply powering the panel as a
|
||||
phandle to a regulator.
|
||||
|
||||
# Backlight
|
||||
|
||||
# Most display panels include a backlight. Some of them also include a backlight
|
||||
# controller exposed through a control bus such as I2C or DSI. Others expose
|
||||
# backlight control through GPIO, PWM or other signals connected to an external
|
||||
# backlight controller.
|
||||
|
||||
backlight:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
For panels whose backlight is controlled by an external backlight
|
||||
controller, this property contains a phandle that references the
|
||||
controller.
|
||||
|
||||
dependencies:
|
||||
width-mm: [ height-mm ]
|
||||
height-mm: [ width-mm ]
|
||||
|
||||
...
|
@ -1,121 +0,0 @@
|
||||
LVDS Display Panel
|
||||
==================
|
||||
|
||||
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 bindings supports display panels compatible with the
|
||||
following specifications.
|
||||
|
||||
[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)
|
||||
|
||||
Device compatible with those specifications have been marketed under the
|
||||
FPD-Link and FlatLink brands.
|
||||
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: Shall contain "panel-lvds" in addition to a mandatory
|
||||
panel-specific compatible string defined in individual panel bindings. The
|
||||
"panel-lvds" value shall never be used on its own.
|
||||
- width-mm: See panel-common.txt.
|
||||
- height-mm: See panel-common.txt.
|
||||
- data-mapping: The color signals mapping order, "jeida-18", "jeida-24"
|
||||
or "vesa-24".
|
||||
|
||||
Optional properties:
|
||||
|
||||
- label: See panel-common.txt.
|
||||
- gpios: See panel-common.txt.
|
||||
- backlight: See panel-common.txt.
|
||||
- power-supply: See panel-common.txt.
|
||||
- data-mirror: If set, reverse the bit order described in the data mappings
|
||||
below on all data lanes, transmitting bits for slots 6 to 0 instead of
|
||||
0 to 6.
|
||||
|
||||
Required nodes:
|
||||
|
||||
- panel-timing: See panel-common.txt.
|
||||
- ports: See panel-common.txt. These bindings require a single port subnode
|
||||
corresponding to the panel LVDS input.
|
||||
|
||||
|
||||
LVDS data mappings are defined as follows.
|
||||
|
||||
- "jeida-18" - 18-bit data mapping compatible with the [JEIDA], [LDI] and
|
||||
[VESA] specifications. Data are transferred as follows on 3 LVDS lanes.
|
||||
|
||||
Slot 0 1 2 3 4 5 6
|
||||
________________ _________________
|
||||
Clock \_______________________/
|
||||
______ ______ ______ ______ ______ ______ ______
|
||||
DATA0 ><__G0__><__R5__><__R4__><__R3__><__R2__><__R1__><__R0__><
|
||||
DATA1 ><__B1__><__B0__><__G5__><__G4__><__G3__><__G2__><__G1__><
|
||||
DATA2 ><_CTL2_><_CTL1_><_CTL0_><__B5__><__B4__><__B3__><__B2__><
|
||||
|
||||
- "jeida-24" - 24-bit data mapping compatible with the [DSIM] and [LDI]
|
||||
specifications. Data are transferred as follows on 4 LVDS lanes.
|
||||
|
||||
Slot 0 1 2 3 4 5 6
|
||||
________________ _________________
|
||||
Clock \_______________________/
|
||||
______ ______ ______ ______ ______ ______ ______
|
||||
DATA0 ><__G2__><__R7__><__R6__><__R5__><__R4__><__R3__><__R2__><
|
||||
DATA1 ><__B3__><__B2__><__G7__><__G6__><__G5__><__G4__><__G3__><
|
||||
DATA2 ><_CTL2_><_CTL1_><_CTL0_><__B7__><__B6__><__B5__><__B4__><
|
||||
DATA3 ><_CTL3_><__B1__><__B0__><__G1__><__G0__><__R1__><__R0__><
|
||||
|
||||
- "vesa-24" - 24-bit data mapping compatible with the [VESA] specification.
|
||||
Data are transferred as follows on 4 LVDS lanes.
|
||||
|
||||
Slot 0 1 2 3 4 5 6
|
||||
________________ _________________
|
||||
Clock \_______________________/
|
||||
______ ______ ______ ______ ______ ______ ______
|
||||
DATA0 ><__G0__><__R5__><__R4__><__R3__><__R2__><__R1__><__R0__><
|
||||
DATA1 ><__B1__><__B0__><__G5__><__G4__><__G3__><__G2__><__G1__><
|
||||
DATA2 ><_CTL2_><_CTL1_><_CTL0_><__B5__><__B4__><__B3__><__B2__><
|
||||
DATA3 ><_CTL3_><__B7__><__B6__><__G7__><__G6__><__R7__><__R6__><
|
||||
|
||||
Control signals are mapped as follows.
|
||||
|
||||
CTL0: HSync
|
||||
CTL1: VSync
|
||||
CTL2: Data Enable
|
||||
CTL3: 0
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
panel {
|
||||
compatible = "mitsubishi,aa121td01", "panel-lvds";
|
||||
|
||||
width-mm = <261>;
|
||||
height-mm = <163>;
|
||||
|
||||
data-mapping = "jeida-24";
|
||||
|
||||
panel-timing {
|
||||
/* 1280x800 @60Hz */
|
||||
clock-frequency = <71000000>;
|
||||
hactive = <1280>;
|
||||
vactive = <800>;
|
||||
hsync-len = <70>;
|
||||
hfront-porch = <20>;
|
||||
hback-porch = <70>;
|
||||
vsync-len = <5>;
|
||||
vfront-porch = <3>;
|
||||
vback-porch = <15>;
|
||||
};
|
||||
|
||||
port {
|
||||
panel_in: endpoint {
|
||||
remote-endpoint = <&lvds_encoder>;
|
||||
};
|
||||
};
|
||||
};
|
@ -1,4 +0,0 @@
|
||||
Common display properties
|
||||
-------------------------
|
||||
|
||||
- rotation: Display rotation in degrees counter clockwise (0,90,180,270)
|
@ -1,14 +0,0 @@
|
||||
PDA 91-00156-A0 5.0" WVGA TFT LCD panel
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "pda,91-00156-a0"
|
||||
- power-supply: this panel requires a single power supply. A phandle to a
|
||||
regulator needs to be specified here. Compatible with panel-common binding which
|
||||
is specified in the panel-common.txt in this directory.
|
||||
- backlight: this panel's backlight is controlled by an external backlight
|
||||
controller. A phandle to this controller needs to be specified here.
|
||||
Compatible with panel-common binding which is specified in the panel-common.txt
|
||||
in this directory.
|
||||
|
||||
This binding is compatible with the simple-panel binding, which is specified
|
||||
in simple-panel.txt in this directory.
|
@ -0,0 +1,31 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/panel/pda,91-00156-a0.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: PDA 91-00156-A0 5.0" WVGA TFT LCD panel
|
||||
|
||||
maintainers:
|
||||
- Cristian Birsan <cristian.birsan@microchip.com>
|
||||
- Thierry Reding <thierry.reding@gmail.com>
|
||||
|
||||
allOf:
|
||||
- $ref: panel-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: pda,91-00156-a0
|
||||
|
||||
power-supply: true
|
||||
backlight: true
|
||||
port: true
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- power-supply
|
||||
- backlight
|
||||
|
||||
...
|
@ -1,49 +0,0 @@
|
||||
This binding covers the official 7" (800x480) Raspberry Pi touchscreen
|
||||
panel.
|
||||
|
||||
This DSI panel contains:
|
||||
|
||||
- TC358762 DSI->DPI bridge
|
||||
- Atmel microcontroller on I2C for power sequencing the DSI bridge and
|
||||
controlling backlight
|
||||
- Touchscreen controller on I2C for touch input
|
||||
|
||||
and this binding covers the DSI display parts but not its touch input.
|
||||
|
||||
Required properties:
|
||||
- compatible: Must be "raspberrypi,7inch-touchscreen-panel"
|
||||
- reg: Must be "45"
|
||||
- port: See panel-common.txt
|
||||
|
||||
Example:
|
||||
|
||||
dsi1: dsi@7e700000 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
<...>
|
||||
|
||||
port {
|
||||
dsi_out_port: endpoint {
|
||||
remote-endpoint = <&panel_dsi_port>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
i2c_dsi: i2c {
|
||||
compatible = "i2c-gpio";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
gpios = <&gpio 28 0
|
||||
&gpio 29 0>;
|
||||
|
||||
lcd@45 {
|
||||
compatible = "raspberrypi,7inch-touchscreen-panel";
|
||||
reg = <0x45>;
|
||||
|
||||
port {
|
||||
panel_dsi_port: endpoint {
|
||||
remote-endpoint = <&dsi_out_port>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
@ -0,0 +1,71 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/panel/raspberrypi,7inch-touchscreen.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: The official 7" (800x480) Raspberry Pi touchscreen
|
||||
|
||||
maintainers:
|
||||
- Eric Anholt <eric@anholt.net>
|
||||
- Thierry Reding <thierry.reding@gmail.com>
|
||||
|
||||
description: |+
|
||||
This DSI panel contains:
|
||||
|
||||
- TC358762 DSI->DPI bridge
|
||||
- Atmel microcontroller on I2C for power sequencing the DSI bridge and
|
||||
controlling backlight
|
||||
- Touchscreen controller on I2C for touch input
|
||||
|
||||
and this binding covers the DSI display parts but not its touch input.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: raspberrypi,7inch-touchscreen-panel
|
||||
|
||||
reg:
|
||||
const: 0x45
|
||||
|
||||
port: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- port
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |+
|
||||
dsi1: dsi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port {
|
||||
dsi_out_port: endpoint {
|
||||
remote-endpoint = <&panel_dsi_port>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
i2c_dsi: i2c {
|
||||
compatible = "i2c-gpio";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
scl-gpios = <&gpio 28 0>;
|
||||
sda-gpios = <&gpio 29 0>;
|
||||
|
||||
lcd@45 {
|
||||
compatible = "raspberrypi,7inch-touchscreen-panel";
|
||||
reg = <0x45>;
|
||||
|
||||
port {
|
||||
panel_dsi_port: endpoint {
|
||||
remote-endpoint = <&dsi_out_port>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
@ -0,0 +1,41 @@
|
||||
Raydium RM67171 OLED LCD panel with MIPI-DSI protocol
|
||||
|
||||
Required properties:
|
||||
- compatible: "raydium,rm67191"
|
||||
- reg: virtual channel for MIPI-DSI protocol
|
||||
must be <0>
|
||||
- dsi-lanes: number of DSI lanes to be used
|
||||
must be <3> or <4>
|
||||
- port: input port node with endpoint definition as
|
||||
defined in Documentation/devicetree/bindings/graph.txt;
|
||||
the input port should be connected to a MIPI-DSI device
|
||||
driver
|
||||
|
||||
Optional properties:
|
||||
- reset-gpios: a GPIO spec for the RST_B GPIO pin
|
||||
- v3p3-supply: phandle to 3.3V regulator that powers the VDD_3V3 pin
|
||||
- v1p8-supply: phandle to 1.8V regulator that powers the VDD_1V8 pin
|
||||
- width-mm: see panel-common.txt
|
||||
- height-mm: see panel-common.txt
|
||||
- video-mode: 0 - burst-mode
|
||||
1 - non-burst with sync event
|
||||
2 - non-burst with sync pulse
|
||||
|
||||
Example:
|
||||
|
||||
panel@0 {
|
||||
compatible = "raydium,rm67191";
|
||||
reg = <0>;
|
||||
pinctrl-0 = <&pinctrl_mipi_dsi_0_1_en>;
|
||||
pinctrl-names = "default";
|
||||
reset-gpios = <&gpio1 7 GPIO_ACTIVE_LOW>;
|
||||
dsi-lanes = <4>;
|
||||
width-mm = <68>;
|
||||
height-mm = <121>;
|
||||
|
||||
port {
|
||||
panel_in: endpoint {
|
||||
remote-endpoint = <&mipi_out>;
|
||||
};
|
||||
};
|
||||
};
|
@ -5,6 +5,9 @@ Required properties:
|
||||
- reg: DSI virtual channel of the peripheral
|
||||
- reset-gpios: panel reset gpio
|
||||
- backlight: phandle of the backlight device attached to the panel
|
||||
- vcc-supply: phandle of the regulator that provides the vcc supply voltage.
|
||||
- iovcc-supply: phandle of the regulator that provides the iovcc supply
|
||||
voltage.
|
||||
|
||||
Example:
|
||||
|
||||
@ -14,5 +17,7 @@ Example:
|
||||
reg = <0>;
|
||||
backlight = <&backlight>;
|
||||
reset-gpios = <&gpio3 13 GPIO_ACTIVE_LOW>;
|
||||
vcc-supply = <®_2v8_p>;
|
||||
iovcc-supply = <®_1v8_p>;
|
||||
};
|
||||
};
|
||||
|
@ -1,41 +0,0 @@
|
||||
Solomon Goldentek Display GKTW70SDAE4SE LVDS Display Panel
|
||||
==========================================================
|
||||
|
||||
The GKTW70SDAE4SE is a 7" WVGA TFT-LCD display panel.
|
||||
|
||||
These DT bindings follow the LVDS panel bindings defined in panel-lvds.txt
|
||||
with the following device-specific properties.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: Shall contain "sgd,gktw70sdae4se" and "panel-lvds", in that order.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
panel {
|
||||
compatible = "sgd,gktw70sdae4se", "panel-lvds";
|
||||
|
||||
width-mm = <153>;
|
||||
height-mm = <86>;
|
||||
|
||||
data-mapping = "jeida-18";
|
||||
|
||||
panel-timing {
|
||||
clock-frequency = <32000000>;
|
||||
hactive = <800>;
|
||||
vactive = <480>;
|
||||
hback-porch = <39>;
|
||||
hfront-porch = <39>;
|
||||
vback-porch = <29>;
|
||||
vfront-porch = <13>;
|
||||
hsync-len = <47>;
|
||||
vsync-len = <2>;
|
||||
};
|
||||
|
||||
port {
|
||||
panel_in: endpoint {
|
||||
remote-endpoint = <&lvds_encoder>;
|
||||
};
|
||||
};
|
||||
};
|
@ -0,0 +1,68 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/panel/sgd,gktw70sdae4se.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Solomon Goldentek Display GKTW70SDAE4SE 7" WVGA LVDS Display Panel
|
||||
|
||||
maintainers:
|
||||
- Neil Armstrong <narmstrong@baylibre.com>
|
||||
- Thierry Reding <thierry.reding@gmail.com>
|
||||
|
||||
allOf:
|
||||
- $ref: lvds.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: sgd,gktw70sdae4se
|
||||
- {} # panel-lvds, but not listed here to avoid false select
|
||||
|
||||
data-mapping:
|
||||
const: jeida-18
|
||||
|
||||
width-mm:
|
||||
const: 153
|
||||
|
||||
height-mm:
|
||||
const: 86
|
||||
|
||||
panel-timing: true
|
||||
port: true
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
||||
examples:
|
||||
- |+
|
||||
panel {
|
||||
compatible = "sgd,gktw70sdae4se", "panel-lvds";
|
||||
|
||||
width-mm = <153>;
|
||||
height-mm = <86>;
|
||||
|
||||
data-mapping = "jeida-18";
|
||||
|
||||
panel-timing {
|
||||
clock-frequency = <32000000>;
|
||||
hactive = <800>;
|
||||
vactive = <480>;
|
||||
hback-porch = <39>;
|
||||
hfront-porch = <39>;
|
||||
vback-porch = <29>;
|
||||
vfront-porch = <13>;
|
||||
hsync-len = <47>;
|
||||
vsync-len = <2>;
|
||||
};
|
||||
|
||||
port {
|
||||
panel_in: endpoint {
|
||||
remote-endpoint = <&lvds_encoder>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
@ -0,0 +1,26 @@
|
||||
Sharp LD-D5116Z01B 12.3" WUXGA+ eDP panel
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "sharp,ld-d5116z01b"
|
||||
- power-supply: regulator to provide the VCC supply voltage (3.3 volts)
|
||||
|
||||
This binding is compatible with the simple-panel binding.
|
||||
|
||||
The device node can contain one 'port' child node with one child
|
||||
'endpoint' node, according to the bindings defined in [1]. This
|
||||
node should describe panel's video bus.
|
||||
|
||||
[1]: Documentation/devicetree/bindings/media/video-interfaces.txt
|
||||
|
||||
Example:
|
||||
|
||||
panel: panel {
|
||||
compatible = "sharp,ld-d5116z01b";
|
||||
power-supply = <&vlcd_3v3>;
|
||||
|
||||
port {
|
||||
panel_ep: endpoint {
|
||||
remote-endpoint = <&bridge_out_ep>;
|
||||
};
|
||||
};
|
||||
};
|
@ -0,0 +1,12 @@
|
||||
Sharp LQ070Y3DG3B 7.0" WVGA landscape TFT LCD panel
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "sharp,lq070y3dg3b"
|
||||
|
||||
Optional properties:
|
||||
- enable-gpios: GPIO pin to enable or disable the panel
|
||||
- backlight: phandle of the backlight device attached to the panel
|
||||
- power-supply: phandle of the regulator that provides the supply voltage
|
||||
|
||||
This binding is compatible with the simple-panel binding, which is specified
|
||||
in simple-panel.txt in this directory.
|
@ -0,0 +1,12 @@
|
||||
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.
|
@ -1,28 +1 @@
|
||||
Simple display panel
|
||||
====================
|
||||
|
||||
panel node
|
||||
----------
|
||||
|
||||
Required properties:
|
||||
- power-supply: See panel-common.txt
|
||||
|
||||
Optional properties:
|
||||
- ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
|
||||
- enable-gpios: GPIO pin to enable or disable the panel
|
||||
- backlight: phandle of the backlight device attached to the panel
|
||||
- no-hpd: This panel is supposed to communicate that it's ready via HPD
|
||||
(hot plug detect) signal, but the signal isn't hooked up so we should
|
||||
hardcode the max delay from the panel spec when powering up the panel.
|
||||
|
||||
Example:
|
||||
|
||||
panel: panel {
|
||||
compatible = "cptt,claa101wb01";
|
||||
ddc-i2c-bus = <&panelddc>;
|
||||
|
||||
power-supply = <&vdd_pnl_reg>;
|
||||
enable-gpios = <&gpio 90 0>;
|
||||
|
||||
backlight = <&backlight>;
|
||||
};
|
||||
See panel-common.yaml in this directory.
|
||||
|
@ -1,15 +0,0 @@
|
||||
TFC S9700RTWV43TR-01B 7" Three Five Corp 800x480 LCD panel with
|
||||
resistive touch
|
||||
|
||||
The panel is found on TI AM335x-evm.
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "tfc,s9700rtwv43tr-01b"
|
||||
- power-supply: See panel-common.txt
|
||||
|
||||
Optional properties:
|
||||
- enable-gpios: GPIO pin to enable or disable the panel, if there is one
|
||||
- backlight: phandle of the backlight device attached to the panel
|
||||
|
||||
This binding is compatible with the simple-panel binding, which is specified
|
||||
in simple-panel.txt in this directory.
|
@ -0,0 +1,33 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/panel/tfc,s9700rtwv43tr-01b.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: TFC S9700RTWV43TR-01B 7" Three Five Corp 800x480 LCD panel with resistive touch
|
||||
|
||||
maintainers:
|
||||
- Jyri Sarha <jsarha@ti.com>
|
||||
- Thierry Reding <thierry.reding@gmail.com>
|
||||
|
||||
description: |+
|
||||
The panel is found on TI AM335x-evm.
|
||||
|
||||
allOf:
|
||||
- $ref: panel-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: tfc,s9700rtwv43tr-01b
|
||||
|
||||
enable-gpios: true
|
||||
backlight: true
|
||||
port: true
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- power-supply
|
||||
|
||||
...
|
@ -0,0 +1,36 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/panel/ti,nspire.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Texas Instruments NSPIRE Display Panels
|
||||
|
||||
maintainers:
|
||||
- Linus Walleij <linus.walleij@linaro.org>
|
||||
|
||||
allOf:
|
||||
- $ref: panel-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- ti,nspire-cx-lcd-panel
|
||||
- ti,nspire-classic-lcd-panel
|
||||
port: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
panel {
|
||||
compatible = "ti,nspire-cx-lcd-panel";
|
||||
port {
|
||||
panel_in: endpoint {
|
||||
remote-endpoint = <&pads>;
|
||||
};
|
||||
};
|
||||
};
|
@ -1,70 +0,0 @@
|
||||
TPO TPG110 Panel
|
||||
================
|
||||
|
||||
This panel driver is a component that acts as an intermediary
|
||||
between an RGB output and a variety of panels. The panel
|
||||
driver is strapped up in electronics to the desired resolution
|
||||
and other properties, and has a control interface over 3WIRE
|
||||
SPI. By talking to the TPG110 over SPI, the strapped properties
|
||||
can be discovered and the hardware is therefore mostly
|
||||
self-describing.
|
||||
|
||||
+--------+
|
||||
SPI -> | TPO | -> physical display
|
||||
RGB -> | TPG110 |
|
||||
+--------+
|
||||
|
||||
If some electrical strap or alternate resolution is desired,
|
||||
this can be set up by taking software control of the display
|
||||
over the SPI interface. The interface can also adjust
|
||||
for properties of the display such as gamma correction and
|
||||
certain electrical driving levels.
|
||||
|
||||
The TPG110 does not know the physical dimensions of the panel
|
||||
connected, so this needs to be specified in the device tree.
|
||||
|
||||
It requires a GPIO line for control of its reset line.
|
||||
|
||||
The serial protocol has line names that resemble I2C but the
|
||||
protocol is not I2C but 3WIRE SPI.
|
||||
|
||||
Required properties:
|
||||
- compatible : one of:
|
||||
"ste,nomadik-nhk15-display", "tpo,tpg110"
|
||||
"tpo,tpg110"
|
||||
- grestb-gpios : panel reset GPIO
|
||||
- width-mm : see display/panel/panel-common.txt
|
||||
- height-mm : see display/panel/panel-common.txt
|
||||
|
||||
The device needs to be a child of an SPI bus, see
|
||||
spi/spi-bus.txt. The SPI child must set the following
|
||||
properties:
|
||||
- spi-3wire
|
||||
- spi-max-frequency = <3000000>;
|
||||
as these are characteristics of this device.
|
||||
|
||||
The device node can contain one 'port' child node with one child
|
||||
'endpoint' node, according to the bindings defined in
|
||||
media/video-interfaces.txt. This node should describe panel's video bus.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
panel: display@0 {
|
||||
compatible = "tpo,tpg110";
|
||||
reg = <0>;
|
||||
spi-3wire;
|
||||
/* 320 ns min period ~= 3 MHz */
|
||||
spi-max-frequency = <3000000>;
|
||||
/* Width and height from data sheet */
|
||||
width-mm = <116>;
|
||||
height-mm = <87>;
|
||||
grestb-gpios = <&foo_gpio 5 GPIO_ACTIVE_LOW>;
|
||||
backlight = <&bl>;
|
||||
|
||||
port {
|
||||
nomadik_clcd_panel: endpoint {
|
||||
remote-endpoint = <&foo>;
|
||||
};
|
||||
};
|
||||
};
|
101
Documentation/devicetree/bindings/display/panel/tpo,tpg110.yaml
Normal file
101
Documentation/devicetree/bindings/display/panel/tpo,tpg110.yaml
Normal file
@ -0,0 +1,101 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/panel/tpo,tpg110.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: TPO TPG110 Panel
|
||||
|
||||
maintainers:
|
||||
- Linus Walleij <linus.walleij@linaro.org>
|
||||
- Thierry Reding <thierry.reding@gmail.com>
|
||||
|
||||
description: |+
|
||||
This panel driver is a component that acts as an intermediary
|
||||
between an RGB output and a variety of panels. The panel
|
||||
driver is strapped up in electronics to the desired resolution
|
||||
and other properties, and has a control interface over 3WIRE
|
||||
SPI. By talking to the TPG110 over SPI, the strapped properties
|
||||
can be discovered and the hardware is therefore mostly
|
||||
self-describing.
|
||||
|
||||
+--------+
|
||||
SPI -> | TPO | -> physical display
|
||||
RGB -> | TPG110 |
|
||||
+--------+
|
||||
|
||||
If some electrical strap or alternate resolution is desired,
|
||||
this can be set up by taking software control of the display
|
||||
over the SPI interface. The interface can also adjust
|
||||
for properties of the display such as gamma correction and
|
||||
certain electrical driving levels.
|
||||
|
||||
The TPG110 does not know the physical dimensions of the panel
|
||||
connected, so this needs to be specified in the device tree.
|
||||
|
||||
It requires a GPIO line for control of its reset line.
|
||||
|
||||
The serial protocol has line names that resemble I2C but the
|
||||
protocol is not I2C but 3WIRE SPI.
|
||||
|
||||
|
||||
allOf:
|
||||
- $ref: panel-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- items:
|
||||
- enum:
|
||||
- ste,nomadik-nhk15-display
|
||||
- const: tpo,tpg110
|
||||
- const: tpo,tpg110
|
||||
|
||||
reg: true
|
||||
|
||||
grestb-gpios:
|
||||
maxItems: 1
|
||||
description: panel reset GPIO
|
||||
|
||||
spi-3wire: true
|
||||
|
||||
spi-max-frequency:
|
||||
const: 3000000
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- grestb-gpios
|
||||
- width-mm
|
||||
- height-mm
|
||||
- spi-3wire
|
||||
- spi-max-frequency
|
||||
- port
|
||||
|
||||
examples:
|
||||
- |+
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
panel: display@0 {
|
||||
compatible = "tpo,tpg110";
|
||||
reg = <0>;
|
||||
spi-3wire;
|
||||
/* 320 ns min period ~= 3 MHz */
|
||||
spi-max-frequency = <3000000>;
|
||||
/* Width and height from data sheet */
|
||||
width-mm = <116>;
|
||||
height-mm = <87>;
|
||||
grestb-gpios = <&foo_gpio 5 1>;
|
||||
backlight = <&bl>;
|
||||
|
||||
port {
|
||||
nomadik_clcd_panel: endpoint {
|
||||
remote-endpoint = <&foo>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
@ -14,6 +14,8 @@ Required properties:
|
||||
- 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.
|
||||
- video port 0 for the VOP input, the remote endpoint maybe vopb or vopl
|
||||
- video port 1 for either a panel or subsequent encoder
|
||||
|
||||
Optional properties:
|
||||
- power-domains: a phandle to mipi dsi power domain node.
|
||||
@ -40,11 +42,12 @@ Example:
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <1>;
|
||||
|
||||
mipi_in: port {
|
||||
mipi_in: port@0 {
|
||||
reg = <0>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
mipi_in_vopb: endpoint@0 {
|
||||
reg = <0>;
|
||||
remote-endpoint = <&vopb_out_mipi>;
|
||||
@ -54,6 +57,16 @@ Example:
|
||||
remote-endpoint = <&vopl_out_mipi>;
|
||||
};
|
||||
};
|
||||
|
||||
mipi_out: port@1 {
|
||||
reg = <1>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
mipi_out_panel: endpoint {
|
||||
remote-endpoint = <&panel_in_mipi>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
panel {
|
||||
@ -64,5 +77,11 @@ Example:
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&lcd_en>;
|
||||
backlight = <&backlight>;
|
||||
|
||||
port {
|
||||
panel_in_mipi: endpoint {
|
||||
remote-endpoint = <&mipi_out_panel>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -32,17 +32,6 @@ Their connections are modeled using the OF graph bindings specified in
|
||||
- video port 0 for the VOP input, the remote endpoint maybe vopb or vopl
|
||||
- video port 1 for either a panel or subsequent encoder
|
||||
|
||||
the lvds panel described by
|
||||
Documentation/devicetree/bindings/display/panel/simple-panel.txt
|
||||
|
||||
Panel required properties:
|
||||
- ports for remote LVDS output
|
||||
|
||||
Panel optional properties:
|
||||
- data-mapping: should be "vesa-24","jeida-24" or "jeida-18".
|
||||
This describes decribed by:
|
||||
Documentation/devicetree/bindings/display/panel/panel-lvds.txt
|
||||
|
||||
Example:
|
||||
|
||||
lvds_panel: lvds-panel {
|
||||
|
@ -27,6 +27,15 @@ Optional properties:
|
||||
- solomon,prechargep2: Length of precharge period (phase 2) in clock cycles.
|
||||
This needs to be the higher, the higher the capacitance
|
||||
of the OLED's pixels is
|
||||
- solomon,dclk-div: Clock divisor 1 to 16
|
||||
- solomon,dclk-frq: Clock frequency 0 to 15, higher value means higher
|
||||
frequency
|
||||
- solomon,lookup-table: 8 bit value array of current drive pulse widths for
|
||||
BANK0, and colors A, B, and C. Each value in range
|
||||
of 31 to 63 for pulse widths of 32 to 64. Color D
|
||||
is always width 64.
|
||||
- solomon,area-color-enable: Display uses color mode
|
||||
- solomon,low-power. Display runs in low power mode
|
||||
|
||||
[0]: Documentation/devicetree/bindings/pwm/pwm.txt
|
||||
|
||||
@ -46,4 +55,5 @@ ssd1306: oled@3c {
|
||||
solomon,com-lrremap;
|
||||
solomon,com-invdir;
|
||||
solomon,com-offset = <32>;
|
||||
solomon,lookup-table = /bits/ 8 <0x3f 0x3f 0x3f 0x3f>;
|
||||
};
|
||||
|
@ -521,6 +521,8 @@ patternProperties:
|
||||
description: Lenovo Group Ltd.
|
||||
"^lg,.*":
|
||||
description: LG Corporation
|
||||
"^lgphilips,.*":
|
||||
description: LG Display
|
||||
"^libretech,.*":
|
||||
description: Shenzhen Libre Technology Co., Ltd
|
||||
"^licheepi,.*":
|
||||
@ -951,6 +953,9 @@ patternProperties:
|
||||
description: Tecon Microprocessor Technologies, LLC.
|
||||
"^topeet,.*":
|
||||
description: Topeet
|
||||
"^toppoly,.*":
|
||||
description: TPO (deprecated, use tpo)
|
||||
deprecated: true
|
||||
"^toradex,.*":
|
||||
description: Toradex AG
|
||||
"^toshiba,.*":
|
||||
|
@ -11,7 +11,6 @@ GPU Driver Documentation
|
||||
meson
|
||||
pl111
|
||||
tegra
|
||||
tinydrm
|
||||
tve200
|
||||
v3d
|
||||
vc4
|
||||
|
@ -263,6 +263,18 @@ the MST topology helpers easier to understand
|
||||
drm_dp_mst_topology_put_port
|
||||
drm_dp_mst_get_mstb_malloc drm_dp_mst_put_mstb_malloc
|
||||
|
||||
MIPI DBI Helper Functions Reference
|
||||
===================================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_mipi_dbi.c
|
||||
:doc: overview
|
||||
|
||||
.. kernel-doc:: include/drm/drm_mipi_dbi.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_mipi_dbi.c
|
||||
:export:
|
||||
|
||||
MIPI DSI Helper Functions Reference
|
||||
===================================
|
||||
|
||||
|
@ -433,43 +433,11 @@ PRIME is the cross device buffer sharing framework in drm, originally
|
||||
created for the OPTIMUS range of multi-gpu platforms. To userspace PRIME
|
||||
buffers are dma-buf based file descriptors.
|
||||
|
||||
Overview and Driver Interface
|
||||
-----------------------------
|
||||
Overview and Lifetime Rules
|
||||
---------------------------
|
||||
|
||||
Similar to GEM global names, PRIME file descriptors are also used to
|
||||
share buffer objects across processes. They offer additional security:
|
||||
as file descriptors must be explicitly sent over UNIX domain sockets to
|
||||
be shared between applications, they can't be guessed like the globally
|
||||
unique GEM names.
|
||||
|
||||
Drivers that support the PRIME API must set the DRIVER_PRIME bit in the
|
||||
struct :c:type:`struct drm_driver <drm_driver>`
|
||||
driver_features field, and implement the prime_handle_to_fd and
|
||||
prime_fd_to_handle operations.
|
||||
|
||||
int (\*prime_handle_to_fd)(struct drm_device \*dev, struct drm_file
|
||||
\*file_priv, uint32_t handle, uint32_t flags, int \*prime_fd); int
|
||||
(\*prime_fd_to_handle)(struct drm_device \*dev, struct drm_file
|
||||
\*file_priv, int prime_fd, uint32_t \*handle); Those two operations
|
||||
convert a handle to a PRIME file descriptor and vice versa. Drivers must
|
||||
use the kernel dma-buf buffer sharing framework to manage the PRIME file
|
||||
descriptors. Similar to the mode setting API PRIME is agnostic to the
|
||||
underlying buffer object manager, as long as handles are 32bit unsigned
|
||||
integers.
|
||||
|
||||
While non-GEM drivers must implement the operations themselves, GEM
|
||||
drivers must use the :c:func:`drm_gem_prime_handle_to_fd()` and
|
||||
:c:func:`drm_gem_prime_fd_to_handle()` helper functions. Those
|
||||
helpers rely on the driver gem_prime_export and gem_prime_import
|
||||
operations to create a dma-buf instance from a GEM object (dma-buf
|
||||
exporter role) and to create a GEM object from a dma-buf instance
|
||||
(dma-buf importer role).
|
||||
|
||||
struct dma_buf \* (\*gem_prime_export)(struct drm_device \*dev,
|
||||
struct drm_gem_object \*obj, int flags); struct drm_gem_object \*
|
||||
(\*gem_prime_import)(struct drm_device \*dev, struct dma_buf
|
||||
\*dma_buf); These two operations are mandatory for GEM drivers that
|
||||
support PRIME.
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_prime.c
|
||||
:doc: overview and lifetime rules
|
||||
|
||||
PRIME Helper Functions
|
||||
----------------------
|
||||
|
@ -91,9 +91,6 @@ Frontbuffer Tracking
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_frontbuffer.c
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/i915_gem.c
|
||||
:functions: i915_gem_track_fb
|
||||
|
||||
Display FIFO Underrun Reporting
|
||||
-------------------------------
|
||||
|
||||
@ -430,31 +427,31 @@ WOPCM Layout
|
||||
GuC
|
||||
===
|
||||
|
||||
Firmware Layout
|
||||
-------------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/gt/uc/intel_uc_fw_abi.h
|
||||
:doc: Firmware Layout
|
||||
|
||||
GuC-specific firmware loader
|
||||
----------------------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/intel_guc_fw.c
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c
|
||||
:internal:
|
||||
|
||||
GuC-based command submission
|
||||
----------------------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/intel_guc_submission.c
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
|
||||
:doc: GuC-based command submission
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/intel_guc_submission.c
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
|
||||
:internal:
|
||||
|
||||
GuC Firmware Layout
|
||||
-------------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/intel_guc_fwif.h
|
||||
:doc: GuC Firmware Layout
|
||||
|
||||
GuC Address Space
|
||||
-----------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/intel_guc.c
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/gt/uc/intel_guc.c
|
||||
:doc: GuC Address Space
|
||||
|
||||
Tracing
|
||||
|
@ -51,6 +51,22 @@ and "FIXME" where the interface could be cleaned up.
|
||||
|
||||
Also read the :ref:`guidelines for the kernel documentation at large <doc_guide>`.
|
||||
|
||||
Documentation Requirements for kAPI
|
||||
-----------------------------------
|
||||
|
||||
All kernel APIs exported to other modules must be documented, including their
|
||||
datastructures and at least a short introductory section explaining the overall
|
||||
concepts. Documentation should be put into the code itself as kerneldoc comments
|
||||
as much as reasonable.
|
||||
|
||||
Do not blindly document everything, but document only what's relevant for driver
|
||||
authors: Internal functions of drm.ko and definitely static functions should not
|
||||
have formal kerneldoc comments. Use normal C comments if you feel like a comment
|
||||
is warranted. You may use kerneldoc syntax in the comment, but it shall not
|
||||
start with a /** kerneldoc marker. Similar for data structures, annotate
|
||||
anything entirely private with ``/* private: */`` comments as per the
|
||||
documentation guide.
|
||||
|
||||
Getting Started
|
||||
===============
|
||||
|
||||
|
@ -1,30 +0,0 @@
|
||||
============================
|
||||
drm/tinydrm Tiny DRM drivers
|
||||
============================
|
||||
|
||||
tinydrm is a collection of DRM drivers that are so small they can fit in a
|
||||
single source file.
|
||||
|
||||
Helpers
|
||||
=======
|
||||
|
||||
.. kernel-doc:: include/drm/tinydrm/tinydrm-helpers.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/tinydrm/core/tinydrm-helpers.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/tinydrm/core/tinydrm-pipe.c
|
||||
:export:
|
||||
|
||||
MIPI DBI Compatible Controllers
|
||||
===============================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/tinydrm/mipi-dbi.c
|
||||
:doc: overview
|
||||
|
||||
.. kernel-doc:: include/drm/tinydrm/mipi-dbi.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/tinydrm/mipi-dbi.c
|
||||
:export:
|
@ -162,7 +162,7 @@ Clean up mmap forwarding
|
||||
|
||||
A lot of drivers forward gem mmap calls to dma-buf mmap for imported buffers.
|
||||
And also a lot of them forward dma-buf mmap to the gem mmap implementations.
|
||||
Would be great to refactor this all into a set of small common helpers.
|
||||
There's drm_gem_prime_mmap() for this now, but still needs to be rolled out.
|
||||
|
||||
Contact: Daniel Vetter
|
||||
|
||||
@ -196,15 +196,6 @@ Might be good to also have some igt testcases for this.
|
||||
|
||||
Contact: Daniel Vetter, Noralf Tronnes
|
||||
|
||||
Remove the ->gem_prime_res_obj callback
|
||||
--------------------------------------------
|
||||
|
||||
The ->gem_prime_res_obj callback can be removed from drivers by using the
|
||||
reservation_object in the drm_gem_object. It may also be possible to use the
|
||||
generic drm_gem_reservation_object_wait helper for waiting for a bo.
|
||||
|
||||
Contact: Daniel Vetter
|
||||
|
||||
idr_init_base()
|
||||
---------------
|
||||
|
||||
@ -215,22 +206,13 @@ efficient.
|
||||
|
||||
Contact: Daniel Vetter
|
||||
|
||||
Defaults for .gem_prime_import and export
|
||||
-----------------------------------------
|
||||
|
||||
Most drivers don't need to set drm_driver->gem_prime_import and
|
||||
->gem_prime_export now that drm_gem_prime_import() and drm_gem_prime_export()
|
||||
are the default.
|
||||
|
||||
struct drm_gem_object_funcs
|
||||
---------------------------
|
||||
|
||||
GEM objects can now have a function table instead of having the callbacks on the
|
||||
DRM driver struct. This is now the preferred way and drivers can be moved over.
|
||||
|
||||
DRM_GEM_CMA_VMAP_DRIVER_OPS, DRM_GEM_SHMEM_DRIVER_OPS already support this, but
|
||||
DRM_GEM_VRAM_DRIVER_PRIME does not yet and needs to be aligned with the previous
|
||||
two. We also need a 2nd version of the CMA define that doesn't require the
|
||||
We also need a 2nd version of the CMA define that doesn't require the
|
||||
vmapping to be present (different hook for prime importing). Plus this needs to
|
||||
be rolled out to all drivers using their own implementations, too.
|
||||
|
||||
@ -317,19 +299,6 @@ In the end no .c file should need to include ``drmP.h`` anymore.
|
||||
|
||||
Contact: Daniel Vetter
|
||||
|
||||
Add missing kerneldoc for exported functions
|
||||
--------------------------------------------
|
||||
|
||||
The DRM reference documentation is still lacking kerneldoc in a few areas. The
|
||||
task would be to clean up interfaces like moving functions around between
|
||||
files to better group them and improving the interfaces like dropping return
|
||||
values for functions that never fail. Then write kerneldoc for all exported
|
||||
functions and an overview section and integrate it all into the drm book.
|
||||
|
||||
See https://dri.freedesktop.org/docs/drm/ for what's there already.
|
||||
|
||||
Contact: Daniel Vetter
|
||||
|
||||
Make panic handling work
|
||||
------------------------
|
||||
|
||||
@ -393,6 +362,9 @@ There's a bunch of issues with it:
|
||||
this (together with the drm_minor->drm_device move) would allow us to remove
|
||||
debugfs_init.
|
||||
|
||||
- Drop the return code and error checking from all debugfs functions. Greg KH is
|
||||
working on this already.
|
||||
|
||||
Contact: Daniel Vetter
|
||||
|
||||
KMS cleanups
|
||||
@ -440,39 +412,22 @@ fit the available time.
|
||||
|
||||
Contact: Daniel Vetter
|
||||
|
||||
Backlight Refactoring
|
||||
---------------------
|
||||
|
||||
Backlight drivers have a triple enable/disable state, which is a bit overkill.
|
||||
Plan to fix this:
|
||||
|
||||
1. Roll out backlight_enable() and backlight_disable() helpers everywhere. This
|
||||
has started already.
|
||||
2. In all, only look at one of the three status bits set by the above helpers.
|
||||
3. Remove the other two status bits.
|
||||
|
||||
Contact: Daniel Vetter
|
||||
|
||||
Driver Specific
|
||||
===============
|
||||
|
||||
tinydrm
|
||||
-------
|
||||
|
||||
Tinydrm is the helper driver for really simple fb drivers. The goal is to make
|
||||
those drivers as simple as possible, so lots of room for refactoring:
|
||||
|
||||
- backlight helpers, probably best to put them into a new drm_backlight.c.
|
||||
This is because drivers/video is de-facto unmaintained. We could also
|
||||
move drivers/video/backlight to drivers/gpu/backlight and take it all
|
||||
over within drm-misc, but that's more work. Backlight helpers require a fair
|
||||
bit of reworking and refactoring. A simple example is the enabling of a backlight.
|
||||
Tinydrm has helpers for this. It would be good if other drivers can also use the
|
||||
helper. However, there are various cases we need to consider i.e different
|
||||
drivers seem to have different ways of enabling/disabling a backlight.
|
||||
We also need to consider the backlight drivers (like gpio_backlight). The situation
|
||||
is further complicated by the fact that the backlight is tied to fbdev
|
||||
via fb_notifier_callback() which has complicated logic. For further details, refer
|
||||
to the following discussion thread:
|
||||
https://groups.google.com/forum/#!topic/outreachy-kernel/8rBe30lwtdA
|
||||
|
||||
- spi helpers, probably best put into spi core/helper code. Thierry said
|
||||
the spi maintainer is fast&reactive, so shouldn't be a big issue.
|
||||
|
||||
- extract the mipi-dbi helper (well, the non-tinydrm specific parts at
|
||||
least) into a separate helper, like we have for mipi-dsi already. Or follow
|
||||
one of the ideas for having a shared dsi/dbi helper, abstracting away the
|
||||
transport details more.
|
||||
|
||||
Contact: Noralf Trønnes, Daniel Vetter
|
||||
|
||||
AMD DC Display Driver
|
||||
---------------------
|
||||
|
||||
|
@ -1313,6 +1313,113 @@ The following tables list existing packed RGB formats.
|
||||
- g\ :sub:`6`
|
||||
- g\ :sub:`5`
|
||||
- g\ :sub:`4`
|
||||
* .. _MEDIA-BUS-FMT-RGB888-3X8:
|
||||
|
||||
- MEDIA_BUS_FMT_RGB888_3X8
|
||||
- 0x101c
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
- r\ :sub:`7`
|
||||
- r\ :sub:`6`
|
||||
- r\ :sub:`5`
|
||||
- r\ :sub:`4`
|
||||
- r\ :sub:`3`
|
||||
- r\ :sub:`2`
|
||||
- r\ :sub:`1`
|
||||
- r\ :sub:`0`
|
||||
* -
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
- g\ :sub:`7`
|
||||
- g\ :sub:`6`
|
||||
- g\ :sub:`5`
|
||||
- g\ :sub:`4`
|
||||
- g\ :sub:`3`
|
||||
- g\ :sub:`2`
|
||||
- g\ :sub:`1`
|
||||
- g\ :sub:`0`
|
||||
* -
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
- b\ :sub:`7`
|
||||
- b\ :sub:`6`
|
||||
- b\ :sub:`5`
|
||||
- b\ :sub:`4`
|
||||
- b\ :sub:`3`
|
||||
- b\ :sub:`2`
|
||||
- b\ :sub:`1`
|
||||
- b\ :sub:`0`
|
||||
* .. _MEDIA-BUS-FMT-ARGB888-1X32:
|
||||
|
||||
- MEDIA_BUS_FMT_ARGB888_1X32
|
||||
|
62
MAINTAINERS
62
MAINTAINERS
@ -834,17 +834,11 @@ F: drivers/iommu/amd_iommu*.[ch]
|
||||
F: include/linux/amd-iommu.h
|
||||
|
||||
AMD KFD
|
||||
M: Oded Gabbay <oded.gabbay@gmail.com>
|
||||
L: dri-devel@lists.freedesktop.org
|
||||
T: git git://people.freedesktop.org/~gabbayo/linux.git
|
||||
M: Felix Kuehling <Felix.Kuehling@amd.com>
|
||||
L: amd-gfx@lists.freedesktop.org
|
||||
T: git git://people.freedesktop.org/~agd5f/linux
|
||||
S: Supported
|
||||
F: drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
|
||||
F: drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
|
||||
F: drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c
|
||||
F: drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c
|
||||
F: drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c
|
||||
F: drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_fence.c
|
||||
F: drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
|
||||
F: drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd*.[ch]
|
||||
F: drivers/gpu/drm/amd/amdkfd/
|
||||
F: drivers/gpu/drm/amd/include/cik_structs.h
|
||||
F: drivers/gpu/drm/amd/include/kgd_kfd_interface.h
|
||||
@ -5144,17 +5138,24 @@ S: Maintained
|
||||
F: drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c
|
||||
F: Documentation/devicetree/bindings/display/panel/feiyang,fy07024di26a30d.txt
|
||||
|
||||
DRM DRIVER FOR GRAIN MEDIA GM12U320 PROJECTORS
|
||||
M: Hans de Goede <hdegoede@redhat.com>
|
||||
T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
S: Maintained
|
||||
F: drivers/gpu/drm/tiny/gm12u320.c
|
||||
|
||||
DRM DRIVER FOR ILITEK ILI9225 PANELS
|
||||
M: David Lechner <david@lechnology.com>
|
||||
T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
S: Maintained
|
||||
F: drivers/gpu/drm/tinydrm/ili9225.c
|
||||
F: drivers/gpu/drm/tiny/ili9225.c
|
||||
F: Documentation/devicetree/bindings/display/ilitek,ili9225.txt
|
||||
|
||||
DRM DRIVER FOR HX8357D PANELS
|
||||
M: Eric Anholt <eric@anholt.net>
|
||||
T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
S: Maintained
|
||||
F: drivers/gpu/drm/tinydrm/hx8357d.c
|
||||
F: drivers/gpu/drm/tiny/hx8357d.c
|
||||
F: Documentation/devicetree/bindings/display/himax,hx8357d.txt
|
||||
|
||||
DRM DRIVER FOR INTEL I810 VIDEO CARDS
|
||||
@ -5174,8 +5175,9 @@ F: drivers/gpu/drm/mgag200/
|
||||
|
||||
DRM DRIVER FOR MI0283QT
|
||||
M: Noralf Trønnes <noralf@tronnes.org>
|
||||
T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
S: Maintained
|
||||
F: drivers/gpu/drm/tinydrm/mi0283qt.c
|
||||
F: drivers/gpu/drm/tiny/mi0283qt.c
|
||||
F: Documentation/devicetree/bindings/display/multi-inno,mi0283qt.txt
|
||||
|
||||
DRM DRIVER FOR MSM ADRENO GPU
|
||||
@ -5207,8 +5209,9 @@ F: Documentation/devicetree/bindings/display/panel/olimex,lcd-olinuxino.txt
|
||||
|
||||
DRM DRIVER FOR PERVASIVE DISPLAYS REPAPER PANELS
|
||||
M: Noralf Trønnes <noralf@tronnes.org>
|
||||
T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
S: Maintained
|
||||
F: drivers/gpu/drm/tinydrm/repaper.c
|
||||
F: drivers/gpu/drm/tiny/repaper.c
|
||||
F: Documentation/devicetree/bindings/display/repaper.txt
|
||||
|
||||
DRM DRIVER FOR QEMU'S CIRRUS DEVICE
|
||||
@ -5230,6 +5233,12 @@ S: Maintained
|
||||
F: drivers/gpu/drm/qxl/
|
||||
F: include/uapi/drm/qxl_drm.h
|
||||
|
||||
DRM DRIVER FOR RAYDIUM RM67191 PANELS
|
||||
M: Robert Chiras <robert.chiras@nxp.com>
|
||||
S: Maintained
|
||||
F: drivers/gpu/drm/panel/panel-raydium-rm67191.c
|
||||
F: Documentation/devicetree/bindings/display/panel/raydium,rm67191.txt
|
||||
|
||||
DRM DRIVER FOR RAGE 128 VIDEO CARDS
|
||||
S: Orphan / Obsolete
|
||||
F: drivers/gpu/drm/r128/
|
||||
@ -5237,6 +5246,7 @@ F: include/uapi/drm/r128_drm.h
|
||||
|
||||
DRM DRIVER FOR ROCKTECH JH057N00900 PANELS
|
||||
M: Guido Günther <agx@sigxcpu.org>
|
||||
R: Purism Kernel Team <kernel@puri.sm>
|
||||
S: Maintained
|
||||
F: drivers/gpu/drm/panel/panel-rocktech-jh057n00900.c
|
||||
F: Documentation/devicetree/bindings/display/panel/rocktech,jh057n00900.txt
|
||||
@ -5259,14 +5269,16 @@ F: Documentation/devicetree/bindings/display/panel/sitronix,st7701.txt
|
||||
|
||||
DRM DRIVER FOR SITRONIX ST7586 PANELS
|
||||
M: David Lechner <david@lechnology.com>
|
||||
T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
S: Maintained
|
||||
F: drivers/gpu/drm/tinydrm/st7586.c
|
||||
F: drivers/gpu/drm/tiny/st7586.c
|
||||
F: Documentation/devicetree/bindings/display/sitronix,st7586.txt
|
||||
|
||||
DRM DRIVER FOR SITRONIX ST7735R PANELS
|
||||
M: David Lechner <david@lechnology.com>
|
||||
T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
S: Maintained
|
||||
F: drivers/gpu/drm/tinydrm/st7735r.c
|
||||
F: drivers/gpu/drm/tiny/st7735r.c
|
||||
F: Documentation/devicetree/bindings/display/sitronix,st7735r.txt
|
||||
|
||||
DRM DRIVER FOR ST-ERICSSON MCDE
|
||||
@ -5285,7 +5297,7 @@ M: Linus Walleij <linus.walleij@linaro.org>
|
||||
T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
S: Maintained
|
||||
F: drivers/gpu/drm/panel/panel-tpo-tpg110.c
|
||||
F: Documentation/devicetree/bindings/display/panel/tpo,tpg110.txt
|
||||
F: Documentation/devicetree/bindings/display/panel/tpo,tpg110.yaml
|
||||
|
||||
DRM DRIVER FOR USB DISPLAYLINK VIDEO ADAPTERS
|
||||
M: Dave Airlie <airlied@redhat.com>
|
||||
@ -5367,12 +5379,13 @@ L: linux-amlogic@lists.infradead.org
|
||||
W: http://linux-meson.com/
|
||||
S: Supported
|
||||
F: drivers/gpu/drm/meson/
|
||||
F: Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt
|
||||
F: Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt
|
||||
F: Documentation/devicetree/bindings/display/amlogic,meson-vpu.yaml
|
||||
F: Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.yaml
|
||||
F: Documentation/gpu/meson.rst
|
||||
T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
|
||||
DRM DRIVERS FOR ATMEL HLCDC
|
||||
M: Sam Ravnborg <sam@ravnborg.org>
|
||||
M: Boris Brezillon <bbrezillon@kernel.org>
|
||||
L: dri-devel@lists.freedesktop.org
|
||||
S: Supported
|
||||
@ -5382,7 +5395,10 @@ T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
|
||||
DRM DRIVERS FOR BRIDGE CHIPS
|
||||
M: Andrzej Hajda <a.hajda@samsung.com>
|
||||
M: Neil Armstrong <narmstrong@baylibre.com>
|
||||
R: Laurent Pinchart <Laurent.pinchart@ideasonboard.com>
|
||||
R: Jonas Karlman <jonas@kwiboo.se>
|
||||
R: Jernej Skrabec <jernej.skrabec@siol.net>
|
||||
S: Maintained
|
||||
T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
F: drivers/gpu/drm/bridge/
|
||||
@ -5570,14 +5586,6 @@ F: drivers/gpu/drm/panel/
|
||||
F: include/drm/drm_panel.h
|
||||
F: Documentation/devicetree/bindings/display/panel/
|
||||
|
||||
DRM TINYDRM DRIVERS
|
||||
M: Noralf Trønnes <noralf@tronnes.org>
|
||||
W: https://github.com/notro/tinydrm/wiki/Development
|
||||
T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
S: Maintained
|
||||
F: drivers/gpu/drm/tinydrm/
|
||||
F: include/drm/tinydrm/
|
||||
|
||||
DRM DRIVERS FOR XEN
|
||||
M: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
|
||||
T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
|
@ -549,6 +549,7 @@ static const struct pci_device_id intel_early_ids[] __initconst = {
|
||||
INTEL_CNL_IDS(&gen9_early_ops),
|
||||
INTEL_ICL_11_IDS(&gen11_early_ops),
|
||||
INTEL_EHL_IDS(&gen11_early_ops),
|
||||
INTEL_TGL_12_IDS(&gen11_early_ops),
|
||||
};
|
||||
|
||||
struct resource intel_graphics_stolen_res __ro_after_init = DEFINE_RES_MEM(0, 0);
|
||||
|
@ -39,4 +39,9 @@ config UDMABUF
|
||||
A driver to let userspace turn memfd regions into dma-bufs.
|
||||
Qemu can use this to create host dmabufs for guest framebuffers.
|
||||
|
||||
config DMABUF_SELFTESTS
|
||||
tristate "Selftests for the dma-buf interfaces"
|
||||
default n
|
||||
depends on DMA_SHARED_BUFFER
|
||||
|
||||
endmenu
|
||||
|
@ -1,6 +1,12 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
obj-y := dma-buf.o dma-fence.o dma-fence-array.o dma-fence-chain.o \
|
||||
reservation.o seqno-fence.o
|
||||
dma-resv.o seqno-fence.o
|
||||
obj-$(CONFIG_SYNC_FILE) += sync_file.o
|
||||
obj-$(CONFIG_SW_SYNC) += sw_sync.o sync_debug.o
|
||||
obj-$(CONFIG_UDMABUF) += udmabuf.o
|
||||
|
||||
dmabuf_selftests-y := \
|
||||
selftest.o \
|
||||
st-dma-fence.o
|
||||
|
||||
obj-$(CONFIG_DMABUF_SELFTESTS) += dmabuf_selftests.o
|
||||
|
@ -21,7 +21,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/reservation.h>
|
||||
#include <linux/dma-resv.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/mount.h>
|
||||
#include <linux/pseudo_fs.h>
|
||||
@ -104,8 +104,8 @@ static int dma_buf_release(struct inode *inode, struct file *file)
|
||||
list_del(&dmabuf->list_node);
|
||||
mutex_unlock(&db_list.lock);
|
||||
|
||||
if (dmabuf->resv == (struct reservation_object *)&dmabuf[1])
|
||||
reservation_object_fini(dmabuf->resv);
|
||||
if (dmabuf->resv == (struct dma_resv *)&dmabuf[1])
|
||||
dma_resv_fini(dmabuf->resv);
|
||||
|
||||
module_put(dmabuf->owner);
|
||||
kfree(dmabuf);
|
||||
@ -165,7 +165,7 @@ static loff_t dma_buf_llseek(struct file *file, loff_t offset, int whence)
|
||||
* To support cross-device and cross-driver synchronization of buffer access
|
||||
* implicit fences (represented internally in the kernel with &struct fence) can
|
||||
* be attached to a &dma_buf. The glue for that and a few related things are
|
||||
* provided in the &reservation_object structure.
|
||||
* provided in the &dma_resv structure.
|
||||
*
|
||||
* Userspace can query the state of these implicitly tracked fences using poll()
|
||||
* and related system calls:
|
||||
@ -195,8 +195,8 @@ static void dma_buf_poll_cb(struct dma_fence *fence, struct dma_fence_cb *cb)
|
||||
static __poll_t dma_buf_poll(struct file *file, poll_table *poll)
|
||||
{
|
||||
struct dma_buf *dmabuf;
|
||||
struct reservation_object *resv;
|
||||
struct reservation_object_list *fobj;
|
||||
struct dma_resv *resv;
|
||||
struct dma_resv_list *fobj;
|
||||
struct dma_fence *fence_excl;
|
||||
__poll_t events;
|
||||
unsigned shared_count, seq;
|
||||
@ -506,13 +506,13 @@ err_alloc_file:
|
||||
struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info)
|
||||
{
|
||||
struct dma_buf *dmabuf;
|
||||
struct reservation_object *resv = exp_info->resv;
|
||||
struct dma_resv *resv = exp_info->resv;
|
||||
struct file *file;
|
||||
size_t alloc_size = sizeof(struct dma_buf);
|
||||
int ret;
|
||||
|
||||
if (!exp_info->resv)
|
||||
alloc_size += sizeof(struct reservation_object);
|
||||
alloc_size += sizeof(struct dma_resv);
|
||||
else
|
||||
/* prevent &dma_buf[1] == dma_buf->resv */
|
||||
alloc_size += 1;
|
||||
@ -544,8 +544,8 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info)
|
||||
dmabuf->cb_excl.active = dmabuf->cb_shared.active = 0;
|
||||
|
||||
if (!resv) {
|
||||
resv = (struct reservation_object *)&dmabuf[1];
|
||||
reservation_object_init(resv);
|
||||
resv = (struct dma_resv *)&dmabuf[1];
|
||||
dma_resv_init(resv);
|
||||
}
|
||||
dmabuf->resv = resv;
|
||||
|
||||
@ -909,11 +909,11 @@ static int __dma_buf_begin_cpu_access(struct dma_buf *dmabuf,
|
||||
{
|
||||
bool write = (direction == DMA_BIDIRECTIONAL ||
|
||||
direction == DMA_TO_DEVICE);
|
||||
struct reservation_object *resv = dmabuf->resv;
|
||||
struct dma_resv *resv = dmabuf->resv;
|
||||
long ret;
|
||||
|
||||
/* Wait on any implicit rendering fences */
|
||||
ret = reservation_object_wait_timeout_rcu(resv, write, true,
|
||||
ret = dma_resv_wait_timeout_rcu(resv, write, true,
|
||||
MAX_SCHEDULE_TIMEOUT);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@ -1154,8 +1154,8 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused)
|
||||
int ret;
|
||||
struct dma_buf *buf_obj;
|
||||
struct dma_buf_attachment *attach_obj;
|
||||
struct reservation_object *robj;
|
||||
struct reservation_object_list *fobj;
|
||||
struct dma_resv *robj;
|
||||
struct dma_resv_list *fobj;
|
||||
struct dma_fence *fence;
|
||||
unsigned seq;
|
||||
int count = 0, attach_count, shared_count, i;
|
||||
|
@ -13,6 +13,8 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/dma-fence-array.h>
|
||||
|
||||
#define PENDING_ERROR 1
|
||||
|
||||
static const char *dma_fence_array_get_driver_name(struct dma_fence *fence)
|
||||
{
|
||||
return "dma_fence_array";
|
||||
@ -23,10 +25,29 @@ static const char *dma_fence_array_get_timeline_name(struct dma_fence *fence)
|
||||
return "unbound";
|
||||
}
|
||||
|
||||
static void dma_fence_array_set_pending_error(struct dma_fence_array *array,
|
||||
int error)
|
||||
{
|
||||
/*
|
||||
* Propagate the first error reported by any of our fences, but only
|
||||
* before we ourselves are signaled.
|
||||
*/
|
||||
if (error)
|
||||
cmpxchg(&array->base.error, PENDING_ERROR, error);
|
||||
}
|
||||
|
||||
static void dma_fence_array_clear_pending_error(struct dma_fence_array *array)
|
||||
{
|
||||
/* Clear the error flag if not actually set. */
|
||||
cmpxchg(&array->base.error, PENDING_ERROR, 0);
|
||||
}
|
||||
|
||||
static void irq_dma_fence_array_work(struct irq_work *wrk)
|
||||
{
|
||||
struct dma_fence_array *array = container_of(wrk, typeof(*array), work);
|
||||
|
||||
dma_fence_array_clear_pending_error(array);
|
||||
|
||||
dma_fence_signal(&array->base);
|
||||
dma_fence_put(&array->base);
|
||||
}
|
||||
@ -38,6 +59,8 @@ static void dma_fence_array_cb_func(struct dma_fence *f,
|
||||
container_of(cb, struct dma_fence_array_cb, cb);
|
||||
struct dma_fence_array *array = array_cb->array;
|
||||
|
||||
dma_fence_array_set_pending_error(array, f->error);
|
||||
|
||||
if (atomic_dec_and_test(&array->num_pending))
|
||||
irq_work_queue(&array->work);
|
||||
else
|
||||
@ -63,9 +86,14 @@ static bool dma_fence_array_enable_signaling(struct dma_fence *fence)
|
||||
dma_fence_get(&array->base);
|
||||
if (dma_fence_add_callback(array->fences[i], &cb[i].cb,
|
||||
dma_fence_array_cb_func)) {
|
||||
int error = array->fences[i]->error;
|
||||
|
||||
dma_fence_array_set_pending_error(array, error);
|
||||
dma_fence_put(&array->base);
|
||||
if (atomic_dec_and_test(&array->num_pending))
|
||||
if (atomic_dec_and_test(&array->num_pending)) {
|
||||
dma_fence_array_clear_pending_error(array);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -142,6 +170,8 @@ struct dma_fence_array *dma_fence_array_create(int num_fences,
|
||||
atomic_set(&array->num_pending, signal_on_any ? 1 : num_fences);
|
||||
array->fences = fences;
|
||||
|
||||
array->base.error = PENDING_ERROR;
|
||||
|
||||
return array;
|
||||
}
|
||||
EXPORT_SYMBOL(dma_fence_array_create);
|
||||
|
@ -178,8 +178,30 @@ static bool dma_fence_chain_signaled(struct dma_fence *fence)
|
||||
static void dma_fence_chain_release(struct dma_fence *fence)
|
||||
{
|
||||
struct dma_fence_chain *chain = to_dma_fence_chain(fence);
|
||||
struct dma_fence *prev;
|
||||
|
||||
/* Manually unlink the chain as much as possible to avoid recursion
|
||||
* and potential stack overflow.
|
||||
*/
|
||||
while ((prev = rcu_dereference_protected(chain->prev, true))) {
|
||||
struct dma_fence_chain *prev_chain;
|
||||
|
||||
if (kref_read(&prev->refcount) > 1)
|
||||
break;
|
||||
|
||||
prev_chain = to_dma_fence_chain(prev);
|
||||
if (!prev_chain)
|
||||
break;
|
||||
|
||||
/* No need for atomic operations since we hold the last
|
||||
* reference to prev_chain.
|
||||
*/
|
||||
chain->prev = prev_chain->prev;
|
||||
RCU_INIT_POINTER(prev_chain->prev, NULL);
|
||||
dma_fence_put(prev);
|
||||
}
|
||||
dma_fence_put(prev);
|
||||
|
||||
dma_fence_put(rcu_dereference_protected(chain->prev, true));
|
||||
dma_fence_put(chain->fence);
|
||||
dma_fence_free(fence);
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ static atomic64_t dma_fence_context_counter = ATOMIC64_INIT(1);
|
||||
*
|
||||
* - Then there's also implicit fencing, where the synchronization points are
|
||||
* implicitly passed around as part of shared &dma_buf instances. Such
|
||||
* implicit fences are stored in &struct reservation_object through the
|
||||
* implicit fences are stored in &struct dma_resv through the
|
||||
* &dma_buf.resv pointer.
|
||||
*/
|
||||
|
||||
@ -129,31 +129,27 @@ EXPORT_SYMBOL(dma_fence_context_alloc);
|
||||
int dma_fence_signal_locked(struct dma_fence *fence)
|
||||
{
|
||||
struct dma_fence_cb *cur, *tmp;
|
||||
int ret = 0;
|
||||
struct list_head cb_list;
|
||||
|
||||
lockdep_assert_held(fence->lock);
|
||||
|
||||
if (WARN_ON(!fence))
|
||||
if (unlikely(test_and_set_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
|
||||
&fence->flags)))
|
||||
return -EINVAL;
|
||||
|
||||
if (test_and_set_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) {
|
||||
ret = -EINVAL;
|
||||
/* Stash the cb_list before replacing it with the timestamp */
|
||||
list_replace(&fence->cb_list, &cb_list);
|
||||
|
||||
/*
|
||||
* we might have raced with the unlocked dma_fence_signal,
|
||||
* still run through all callbacks
|
||||
*/
|
||||
} else {
|
||||
fence->timestamp = ktime_get();
|
||||
set_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags);
|
||||
trace_dma_fence_signaled(fence);
|
||||
}
|
||||
fence->timestamp = ktime_get();
|
||||
set_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags);
|
||||
trace_dma_fence_signaled(fence);
|
||||
|
||||
list_for_each_entry_safe(cur, tmp, &fence->cb_list, node) {
|
||||
list_del_init(&cur->node);
|
||||
list_for_each_entry_safe(cur, tmp, &cb_list, node) {
|
||||
INIT_LIST_HEAD(&cur->node);
|
||||
cur->func(fence, cur);
|
||||
}
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(dma_fence_signal_locked);
|
||||
|
||||
@ -173,28 +169,16 @@ EXPORT_SYMBOL(dma_fence_signal_locked);
|
||||
int dma_fence_signal(struct dma_fence *fence)
|
||||
{
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
if (!fence)
|
||||
return -EINVAL;
|
||||
|
||||
if (test_and_set_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags))
|
||||
return -EINVAL;
|
||||
spin_lock_irqsave(fence->lock, flags);
|
||||
ret = dma_fence_signal_locked(fence);
|
||||
spin_unlock_irqrestore(fence->lock, flags);
|
||||
|
||||
fence->timestamp = ktime_get();
|
||||
set_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags);
|
||||
trace_dma_fence_signaled(fence);
|
||||
|
||||
if (test_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT, &fence->flags)) {
|
||||
struct dma_fence_cb *cur, *tmp;
|
||||
|
||||
spin_lock_irqsave(fence->lock, flags);
|
||||
list_for_each_entry_safe(cur, tmp, &fence->cb_list, node) {
|
||||
list_del_init(&cur->node);
|
||||
cur->func(fence, cur);
|
||||
}
|
||||
spin_unlock_irqrestore(fence->lock, flags);
|
||||
}
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(dma_fence_signal);
|
||||
|
||||
@ -248,7 +232,8 @@ void dma_fence_release(struct kref *kref)
|
||||
|
||||
trace_dma_fence_destroy(fence);
|
||||
|
||||
if (WARN(!list_empty(&fence->cb_list),
|
||||
if (WARN(!list_empty(&fence->cb_list) &&
|
||||
!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags),
|
||||
"Fence %s:%s:%llx:%llx released with pending signals!\n",
|
||||
fence->ops->get_driver_name(fence),
|
||||
fence->ops->get_timeline_name(fence),
|
||||
|
@ -32,7 +32,7 @@
|
||||
* Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
|
||||
*/
|
||||
|
||||
#include <linux/reservation.h>
|
||||
#include <linux/dma-resv.h>
|
||||
#include <linux/export.h>
|
||||
|
||||
/**
|
||||
@ -56,26 +56,103 @@ const char reservation_seqcount_string[] = "reservation_seqcount";
|
||||
EXPORT_SYMBOL(reservation_seqcount_string);
|
||||
|
||||
/**
|
||||
* reservation_object_reserve_shared - Reserve space to add shared fences to
|
||||
* a reservation_object.
|
||||
* dma_resv_list_alloc - allocate fence list
|
||||
* @shared_max: number of fences we need space for
|
||||
*
|
||||
* Allocate a new dma_resv_list and make sure to correctly initialize
|
||||
* shared_max.
|
||||
*/
|
||||
static struct dma_resv_list *dma_resv_list_alloc(unsigned int shared_max)
|
||||
{
|
||||
struct dma_resv_list *list;
|
||||
|
||||
list = kmalloc(offsetof(typeof(*list), shared[shared_max]), GFP_KERNEL);
|
||||
if (!list)
|
||||
return NULL;
|
||||
|
||||
list->shared_max = (ksize(list) - offsetof(typeof(*list), shared)) /
|
||||
sizeof(*list->shared);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* dma_resv_list_free - free fence list
|
||||
* @list: list to free
|
||||
*
|
||||
* Free a dma_resv_list and make sure to drop all references.
|
||||
*/
|
||||
static void dma_resv_list_free(struct dma_resv_list *list)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if (!list)
|
||||
return;
|
||||
|
||||
for (i = 0; i < list->shared_count; ++i)
|
||||
dma_fence_put(rcu_dereference_protected(list->shared[i], true));
|
||||
|
||||
kfree_rcu(list, rcu);
|
||||
}
|
||||
|
||||
/**
|
||||
* dma_resv_init - initialize a reservation object
|
||||
* @obj: the reservation object
|
||||
*/
|
||||
void dma_resv_init(struct dma_resv *obj)
|
||||
{
|
||||
ww_mutex_init(&obj->lock, &reservation_ww_class);
|
||||
|
||||
__seqcount_init(&obj->seq, reservation_seqcount_string,
|
||||
&reservation_seqcount_class);
|
||||
RCU_INIT_POINTER(obj->fence, NULL);
|
||||
RCU_INIT_POINTER(obj->fence_excl, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL(dma_resv_init);
|
||||
|
||||
/**
|
||||
* dma_resv_fini - destroys a reservation object
|
||||
* @obj: the reservation object
|
||||
*/
|
||||
void dma_resv_fini(struct dma_resv *obj)
|
||||
{
|
||||
struct dma_resv_list *fobj;
|
||||
struct dma_fence *excl;
|
||||
|
||||
/*
|
||||
* This object should be dead and all references must have
|
||||
* been released to it, so no need to be protected with rcu.
|
||||
*/
|
||||
excl = rcu_dereference_protected(obj->fence_excl, 1);
|
||||
if (excl)
|
||||
dma_fence_put(excl);
|
||||
|
||||
fobj = rcu_dereference_protected(obj->fence, 1);
|
||||
dma_resv_list_free(fobj);
|
||||
ww_mutex_destroy(&obj->lock);
|
||||
}
|
||||
EXPORT_SYMBOL(dma_resv_fini);
|
||||
|
||||
/**
|
||||
* dma_resv_reserve_shared - Reserve space to add shared fences to
|
||||
* a dma_resv.
|
||||
* @obj: reservation object
|
||||
* @num_fences: number of fences we want to add
|
||||
*
|
||||
* Should be called before reservation_object_add_shared_fence(). Must
|
||||
* Should be called before dma_resv_add_shared_fence(). Must
|
||||
* be called with obj->lock held.
|
||||
*
|
||||
* RETURNS
|
||||
* Zero for success, or -errno
|
||||
*/
|
||||
int reservation_object_reserve_shared(struct reservation_object *obj,
|
||||
unsigned int num_fences)
|
||||
int dma_resv_reserve_shared(struct dma_resv *obj, unsigned int num_fences)
|
||||
{
|
||||
struct reservation_object_list *old, *new;
|
||||
struct dma_resv_list *old, *new;
|
||||
unsigned int i, j, k, max;
|
||||
|
||||
reservation_object_assert_held(obj);
|
||||
dma_resv_assert_held(obj);
|
||||
|
||||
old = reservation_object_get_list(obj);
|
||||
old = dma_resv_get_list(obj);
|
||||
|
||||
if (old && old->shared_max) {
|
||||
if ((old->shared_count + num_fences) <= old->shared_max)
|
||||
@ -87,7 +164,7 @@ int reservation_object_reserve_shared(struct reservation_object *obj,
|
||||
max = 4;
|
||||
}
|
||||
|
||||
new = kmalloc(offsetof(typeof(*new), shared[max]), GFP_KERNEL);
|
||||
new = dma_resv_list_alloc(max);
|
||||
if (!new)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -101,79 +178,76 @@ int reservation_object_reserve_shared(struct reservation_object *obj,
|
||||
struct dma_fence *fence;
|
||||
|
||||
fence = rcu_dereference_protected(old->shared[i],
|
||||
reservation_object_held(obj));
|
||||
dma_resv_held(obj));
|
||||
if (dma_fence_is_signaled(fence))
|
||||
RCU_INIT_POINTER(new->shared[--k], fence);
|
||||
else
|
||||
RCU_INIT_POINTER(new->shared[j++], fence);
|
||||
}
|
||||
new->shared_count = j;
|
||||
new->shared_max = max;
|
||||
|
||||
preempt_disable();
|
||||
write_seqcount_begin(&obj->seq);
|
||||
/*
|
||||
* RCU_INIT_POINTER can be used here,
|
||||
* seqcount provides the necessary barriers
|
||||
* We are not changing the effective set of fences here so can
|
||||
* merely update the pointer to the new array; both existing
|
||||
* readers and new readers will see exactly the same set of
|
||||
* active (unsignaled) shared fences. Individual fences and the
|
||||
* old array are protected by RCU and so will not vanish under
|
||||
* the gaze of the rcu_read_lock() readers.
|
||||
*/
|
||||
RCU_INIT_POINTER(obj->fence, new);
|
||||
write_seqcount_end(&obj->seq);
|
||||
preempt_enable();
|
||||
rcu_assign_pointer(obj->fence, new);
|
||||
|
||||
if (!old)
|
||||
return 0;
|
||||
|
||||
/* Drop the references to the signaled fences */
|
||||
for (i = k; i < new->shared_max; ++i) {
|
||||
for (i = k; i < max; ++i) {
|
||||
struct dma_fence *fence;
|
||||
|
||||
fence = rcu_dereference_protected(new->shared[i],
|
||||
reservation_object_held(obj));
|
||||
dma_resv_held(obj));
|
||||
dma_fence_put(fence);
|
||||
}
|
||||
kfree_rcu(old, rcu);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(reservation_object_reserve_shared);
|
||||
EXPORT_SYMBOL(dma_resv_reserve_shared);
|
||||
|
||||
/**
|
||||
* reservation_object_add_shared_fence - Add a fence to a shared slot
|
||||
* dma_resv_add_shared_fence - Add a fence to a shared slot
|
||||
* @obj: the reservation object
|
||||
* @fence: the shared fence to add
|
||||
*
|
||||
* Add a fence to a shared slot, obj->lock must be held, and
|
||||
* reservation_object_reserve_shared() has been called.
|
||||
* dma_resv_reserve_shared() has been called.
|
||||
*/
|
||||
void reservation_object_add_shared_fence(struct reservation_object *obj,
|
||||
struct dma_fence *fence)
|
||||
void dma_resv_add_shared_fence(struct dma_resv *obj, struct dma_fence *fence)
|
||||
{
|
||||
struct reservation_object_list *fobj;
|
||||
struct dma_resv_list *fobj;
|
||||
struct dma_fence *old;
|
||||
unsigned int i, count;
|
||||
|
||||
dma_fence_get(fence);
|
||||
|
||||
reservation_object_assert_held(obj);
|
||||
dma_resv_assert_held(obj);
|
||||
|
||||
fobj = reservation_object_get_list(obj);
|
||||
fobj = dma_resv_get_list(obj);
|
||||
count = fobj->shared_count;
|
||||
|
||||
preempt_disable();
|
||||
write_seqcount_begin(&obj->seq);
|
||||
|
||||
for (i = 0; i < count; ++i) {
|
||||
struct dma_fence *old_fence;
|
||||
|
||||
old_fence = rcu_dereference_protected(fobj->shared[i],
|
||||
reservation_object_held(obj));
|
||||
if (old_fence->context == fence->context ||
|
||||
dma_fence_is_signaled(old_fence)) {
|
||||
dma_fence_put(old_fence);
|
||||
old = rcu_dereference_protected(fobj->shared[i],
|
||||
dma_resv_held(obj));
|
||||
if (old->context == fence->context ||
|
||||
dma_fence_is_signaled(old))
|
||||
goto replace;
|
||||
}
|
||||
}
|
||||
|
||||
BUG_ON(fobj->shared_count >= fobj->shared_max);
|
||||
old = NULL;
|
||||
count++;
|
||||
|
||||
replace:
|
||||
@ -183,26 +257,26 @@ replace:
|
||||
|
||||
write_seqcount_end(&obj->seq);
|
||||
preempt_enable();
|
||||
dma_fence_put(old);
|
||||
}
|
||||
EXPORT_SYMBOL(reservation_object_add_shared_fence);
|
||||
EXPORT_SYMBOL(dma_resv_add_shared_fence);
|
||||
|
||||
/**
|
||||
* reservation_object_add_excl_fence - Add an exclusive fence.
|
||||
* dma_resv_add_excl_fence - Add an exclusive fence.
|
||||
* @obj: the reservation object
|
||||
* @fence: the shared fence to add
|
||||
*
|
||||
* Add a fence to the exclusive slot. The obj->lock must be held.
|
||||
*/
|
||||
void reservation_object_add_excl_fence(struct reservation_object *obj,
|
||||
struct dma_fence *fence)
|
||||
void dma_resv_add_excl_fence(struct dma_resv *obj, struct dma_fence *fence)
|
||||
{
|
||||
struct dma_fence *old_fence = reservation_object_get_excl(obj);
|
||||
struct reservation_object_list *old;
|
||||
struct dma_fence *old_fence = dma_resv_get_excl(obj);
|
||||
struct dma_resv_list *old;
|
||||
u32 i = 0;
|
||||
|
||||
reservation_object_assert_held(obj);
|
||||
dma_resv_assert_held(obj);
|
||||
|
||||
old = reservation_object_get_list(obj);
|
||||
old = dma_resv_get_list(obj);
|
||||
if (old)
|
||||
i = old->shared_count;
|
||||
|
||||
@ -221,28 +295,26 @@ void reservation_object_add_excl_fence(struct reservation_object *obj,
|
||||
/* inplace update, no shared fences */
|
||||
while (i--)
|
||||
dma_fence_put(rcu_dereference_protected(old->shared[i],
|
||||
reservation_object_held(obj)));
|
||||
dma_resv_held(obj)));
|
||||
|
||||
dma_fence_put(old_fence);
|
||||
}
|
||||
EXPORT_SYMBOL(reservation_object_add_excl_fence);
|
||||
EXPORT_SYMBOL(dma_resv_add_excl_fence);
|
||||
|
||||
/**
|
||||
* reservation_object_copy_fences - Copy all fences from src to dst.
|
||||
* dma_resv_copy_fences - Copy all fences from src to dst.
|
||||
* @dst: the destination reservation object
|
||||
* @src: the source reservation object
|
||||
*
|
||||
* Copy all fences from src to dst. dst-lock must be held.
|
||||
*/
|
||||
int reservation_object_copy_fences(struct reservation_object *dst,
|
||||
struct reservation_object *src)
|
||||
int dma_resv_copy_fences(struct dma_resv *dst, struct dma_resv *src)
|
||||
{
|
||||
struct reservation_object_list *src_list, *dst_list;
|
||||
struct dma_resv_list *src_list, *dst_list;
|
||||
struct dma_fence *old, *new;
|
||||
size_t size;
|
||||
unsigned i;
|
||||
|
||||
reservation_object_assert_held(dst);
|
||||
dma_resv_assert_held(dst);
|
||||
|
||||
rcu_read_lock();
|
||||
src_list = rcu_dereference(src->fence);
|
||||
@ -251,10 +323,9 @@ retry:
|
||||
if (src_list) {
|
||||
unsigned shared_count = src_list->shared_count;
|
||||
|
||||
size = offsetof(typeof(*src_list), shared[shared_count]);
|
||||
rcu_read_unlock();
|
||||
|
||||
dst_list = kmalloc(size, GFP_KERNEL);
|
||||
dst_list = dma_resv_list_alloc(shared_count);
|
||||
if (!dst_list)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -266,7 +337,6 @@ retry:
|
||||
}
|
||||
|
||||
dst_list->shared_count = 0;
|
||||
dst_list->shared_max = shared_count;
|
||||
for (i = 0; i < src_list->shared_count; ++i) {
|
||||
struct dma_fence *fence;
|
||||
|
||||
@ -276,7 +346,7 @@ retry:
|
||||
continue;
|
||||
|
||||
if (!dma_fence_get_rcu(fence)) {
|
||||
kfree(dst_list);
|
||||
dma_resv_list_free(dst_list);
|
||||
src_list = rcu_dereference(src->fence);
|
||||
goto retry;
|
||||
}
|
||||
@ -295,8 +365,8 @@ retry:
|
||||
new = dma_fence_get_rcu_safe(&src->fence_excl);
|
||||
rcu_read_unlock();
|
||||
|
||||
src_list = reservation_object_get_list(dst);
|
||||
old = reservation_object_get_excl(dst);
|
||||
src_list = dma_resv_get_list(dst);
|
||||
old = dma_resv_get_excl(dst);
|
||||
|
||||
preempt_disable();
|
||||
write_seqcount_begin(&dst->seq);
|
||||
@ -306,16 +376,15 @@ retry:
|
||||
write_seqcount_end(&dst->seq);
|
||||
preempt_enable();
|
||||
|
||||
if (src_list)
|
||||
kfree_rcu(src_list, rcu);
|
||||
dma_resv_list_free(src_list);
|
||||
dma_fence_put(old);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(reservation_object_copy_fences);
|
||||
EXPORT_SYMBOL(dma_resv_copy_fences);
|
||||
|
||||
/**
|
||||
* reservation_object_get_fences_rcu - Get an object's shared and exclusive
|
||||
* dma_resv_get_fences_rcu - Get an object's shared and exclusive
|
||||
* fences without update side lock held
|
||||
* @obj: the reservation object
|
||||
* @pfence_excl: the returned exclusive fence (or NULL)
|
||||
@ -327,10 +396,10 @@ EXPORT_SYMBOL(reservation_object_copy_fences);
|
||||
* exclusive fence is not specified the fence is put into the array of the
|
||||
* shared fences as well. Returns either zero or -ENOMEM.
|
||||
*/
|
||||
int reservation_object_get_fences_rcu(struct reservation_object *obj,
|
||||
struct dma_fence **pfence_excl,
|
||||
unsigned *pshared_count,
|
||||
struct dma_fence ***pshared)
|
||||
int dma_resv_get_fences_rcu(struct dma_resv *obj,
|
||||
struct dma_fence **pfence_excl,
|
||||
unsigned *pshared_count,
|
||||
struct dma_fence ***pshared)
|
||||
{
|
||||
struct dma_fence **shared = NULL;
|
||||
struct dma_fence *fence_excl;
|
||||
@ -338,7 +407,7 @@ int reservation_object_get_fences_rcu(struct reservation_object *obj,
|
||||
int ret = 1;
|
||||
|
||||
do {
|
||||
struct reservation_object_list *fobj;
|
||||
struct dma_resv_list *fobj;
|
||||
unsigned int i, seq;
|
||||
size_t sz = 0;
|
||||
|
||||
@ -385,13 +454,6 @@ int reservation_object_get_fences_rcu(struct reservation_object *obj,
|
||||
if (!dma_fence_get_rcu(shared[i]))
|
||||
break;
|
||||
}
|
||||
|
||||
if (!pfence_excl && fence_excl) {
|
||||
shared[i] = fence_excl;
|
||||
fence_excl = NULL;
|
||||
++i;
|
||||
++shared_count;
|
||||
}
|
||||
}
|
||||
|
||||
if (i != shared_count || read_seqcount_retry(&obj->seq, seq)) {
|
||||
@ -406,6 +468,11 @@ unlock:
|
||||
rcu_read_unlock();
|
||||
} while (ret);
|
||||
|
||||
if (pfence_excl)
|
||||
*pfence_excl = fence_excl;
|
||||
else if (fence_excl)
|
||||
shared[++shared_count] = fence_excl;
|
||||
|
||||
if (!shared_count) {
|
||||
kfree(shared);
|
||||
shared = NULL;
|
||||
@ -413,15 +480,12 @@ unlock:
|
||||
|
||||
*pshared_count = shared_count;
|
||||
*pshared = shared;
|
||||
if (pfence_excl)
|
||||
*pfence_excl = fence_excl;
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(reservation_object_get_fences_rcu);
|
||||
EXPORT_SYMBOL_GPL(dma_resv_get_fences_rcu);
|
||||
|
||||
/**
|
||||
* reservation_object_wait_timeout_rcu - Wait on reservation's objects
|
||||
* dma_resv_wait_timeout_rcu - Wait on reservation's objects
|
||||
* shared and/or exclusive fences.
|
||||
* @obj: the reservation object
|
||||
* @wait_all: if true, wait on all fences, else wait on just exclusive fence
|
||||
@ -432,9 +496,9 @@ EXPORT_SYMBOL_GPL(reservation_object_get_fences_rcu);
|
||||
* Returns -ERESTARTSYS if interrupted, 0 if the wait timed out, or
|
||||
* greater than zer on success.
|
||||
*/
|
||||
long reservation_object_wait_timeout_rcu(struct reservation_object *obj,
|
||||
bool wait_all, bool intr,
|
||||
unsigned long timeout)
|
||||
long dma_resv_wait_timeout_rcu(struct dma_resv *obj,
|
||||
bool wait_all, bool intr,
|
||||
unsigned long timeout)
|
||||
{
|
||||
struct dma_fence *fence;
|
||||
unsigned seq, shared_count;
|
||||
@ -462,8 +526,7 @@ retry:
|
||||
}
|
||||
|
||||
if (wait_all) {
|
||||
struct reservation_object_list *fobj =
|
||||
rcu_dereference(obj->fence);
|
||||
struct dma_resv_list *fobj = rcu_dereference(obj->fence);
|
||||
|
||||
if (fobj)
|
||||
shared_count = fobj->shared_count;
|
||||
@ -506,11 +569,10 @@ unlock_retry:
|
||||
rcu_read_unlock();
|
||||
goto retry;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(reservation_object_wait_timeout_rcu);
|
||||
EXPORT_SYMBOL_GPL(dma_resv_wait_timeout_rcu);
|
||||
|
||||
|
||||
static inline int
|
||||
reservation_object_test_signaled_single(struct dma_fence *passed_fence)
|
||||
static inline int dma_resv_test_signaled_single(struct dma_fence *passed_fence)
|
||||
{
|
||||
struct dma_fence *fence, *lfence = passed_fence;
|
||||
int ret = 1;
|
||||
@ -527,7 +589,7 @@ reservation_object_test_signaled_single(struct dma_fence *passed_fence)
|
||||
}
|
||||
|
||||
/**
|
||||
* reservation_object_test_signaled_rcu - Test if a reservation object's
|
||||
* dma_resv_test_signaled_rcu - Test if a reservation object's
|
||||
* fences have been signaled.
|
||||
* @obj: the reservation object
|
||||
* @test_all: if true, test all fences, otherwise only test the exclusive
|
||||
@ -536,8 +598,7 @@ reservation_object_test_signaled_single(struct dma_fence *passed_fence)
|
||||
* RETURNS
|
||||
* true if all fences signaled, else false
|
||||
*/
|
||||
bool reservation_object_test_signaled_rcu(struct reservation_object *obj,
|
||||
bool test_all)
|
||||
bool dma_resv_test_signaled_rcu(struct dma_resv *obj, bool test_all)
|
||||
{
|
||||
unsigned seq, shared_count;
|
||||
int ret;
|
||||
@ -551,8 +612,7 @@ retry:
|
||||
if (test_all) {
|
||||
unsigned i;
|
||||
|
||||
struct reservation_object_list *fobj =
|
||||
rcu_dereference(obj->fence);
|
||||
struct dma_resv_list *fobj = rcu_dereference(obj->fence);
|
||||
|
||||
if (fobj)
|
||||
shared_count = fobj->shared_count;
|
||||
@ -560,7 +620,7 @@ retry:
|
||||
for (i = 0; i < shared_count; ++i) {
|
||||
struct dma_fence *fence = rcu_dereference(fobj->shared[i]);
|
||||
|
||||
ret = reservation_object_test_signaled_single(fence);
|
||||
ret = dma_resv_test_signaled_single(fence);
|
||||
if (ret < 0)
|
||||
goto retry;
|
||||
else if (!ret)
|
||||
@ -575,8 +635,7 @@ retry:
|
||||
struct dma_fence *fence_excl = rcu_dereference(obj->fence_excl);
|
||||
|
||||
if (fence_excl) {
|
||||
ret = reservation_object_test_signaled_single(
|
||||
fence_excl);
|
||||
ret = dma_resv_test_signaled_single(fence_excl);
|
||||
if (ret < 0)
|
||||
goto retry;
|
||||
|
||||
@ -588,4 +647,4 @@ retry:
|
||||
rcu_read_unlock();
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(reservation_object_test_signaled_rcu);
|
||||
EXPORT_SYMBOL_GPL(dma_resv_test_signaled_rcu);
|
167
drivers/dma-buf/selftest.c
Normal file
167
drivers/dma-buf/selftest.c
Normal file
@ -0,0 +1,167 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
/*
|
||||
* Copyright © 2019 Intel Corporation
|
||||
*/
|
||||
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/sched/signal.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "selftest.h"
|
||||
|
||||
enum {
|
||||
#define selftest(n, func) __idx_##n,
|
||||
#include "selftests.h"
|
||||
#undef selftest
|
||||
};
|
||||
|
||||
#define selftest(n, f) [__idx_##n] = { .name = #n, .func = f },
|
||||
static struct selftest {
|
||||
bool enabled;
|
||||
const char *name;
|
||||
int (*func)(void);
|
||||
} selftests[] = {
|
||||
#include "selftests.h"
|
||||
};
|
||||
#undef selftest
|
||||
|
||||
/* Embed the line number into the parameter name so that we can order tests */
|
||||
#define param(n) __PASTE(igt__, __PASTE(__PASTE(__LINE__, __), n))
|
||||
#define selftest_0(n, func, id) \
|
||||
module_param_named(id, selftests[__idx_##n].enabled, bool, 0400);
|
||||
#define selftest(n, func) selftest_0(n, func, param(n))
|
||||
#include "selftests.h"
|
||||
#undef selftest
|
||||
|
||||
int __sanitycheck__(void)
|
||||
{
|
||||
pr_debug("Hello World!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *__st_filter;
|
||||
|
||||
static bool apply_subtest_filter(const char *caller, const char *name)
|
||||
{
|
||||
char *filter, *sep, *tok;
|
||||
bool result = true;
|
||||
|
||||
filter = kstrdup(__st_filter, GFP_KERNEL);
|
||||
for (sep = filter; (tok = strsep(&sep, ","));) {
|
||||
bool allow = true;
|
||||
char *sl;
|
||||
|
||||
if (*tok == '!') {
|
||||
allow = false;
|
||||
tok++;
|
||||
}
|
||||
|
||||
if (*tok == '\0')
|
||||
continue;
|
||||
|
||||
sl = strchr(tok, '/');
|
||||
if (sl) {
|
||||
*sl++ = '\0';
|
||||
if (strcmp(tok, caller)) {
|
||||
if (allow)
|
||||
result = false;
|
||||
continue;
|
||||
}
|
||||
tok = sl;
|
||||
}
|
||||
|
||||
if (strcmp(tok, name)) {
|
||||
if (allow)
|
||||
result = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
result = allow;
|
||||
break;
|
||||
}
|
||||
kfree(filter);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int
|
||||
__subtests(const char *caller, const struct subtest *st, int count, void *data)
|
||||
{
|
||||
int err;
|
||||
|
||||
for (; count--; st++) {
|
||||
cond_resched();
|
||||
if (signal_pending(current))
|
||||
return -EINTR;
|
||||
|
||||
if (!apply_subtest_filter(caller, st->name))
|
||||
continue;
|
||||
|
||||
pr_info("dma-buf: Running %s/%s\n", caller, st->name);
|
||||
|
||||
err = st->func(data);
|
||||
if (err && err != -EINTR) {
|
||||
pr_err("dma-buf/%s: %s failed with error %d\n",
|
||||
caller, st->name, err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void set_default_test_all(struct selftest *st, unsigned long count)
|
||||
{
|
||||
unsigned long i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
if (st[i].enabled)
|
||||
return;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
st[i].enabled = true;
|
||||
}
|
||||
|
||||
static int run_selftests(struct selftest *st, unsigned long count)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
set_default_test_all(st, count);
|
||||
|
||||
/* Tests are listed in natural order in selftests.h */
|
||||
for (; count--; st++) {
|
||||
if (!st->enabled)
|
||||
continue;
|
||||
|
||||
pr_info("dma-buf: Running %s\n", st->name);
|
||||
err = st->func();
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
|
||||
if (WARN(err > 0 || err == -ENOTTY,
|
||||
"%s returned %d, conflicting with selftest's magic values!\n",
|
||||
st->name, err))
|
||||
err = -1;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __init st_init(void)
|
||||
{
|
||||
return run_selftests(selftests, ARRAY_SIZE(selftests));
|
||||
}
|
||||
|
||||
static void __exit st_exit(void)
|
||||
{
|
||||
}
|
||||
|
||||
module_param_named(st_filter, __st_filter, charp, 0400);
|
||||
module_init(st_init);
|
||||
module_exit(st_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Self-test harness for dma-buf");
|
||||
MODULE_LICENSE("GPL and additional rights");
|
30
drivers/dma-buf/selftest.h
Normal file
30
drivers/dma-buf/selftest.h
Normal file
@ -0,0 +1,30 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
/*
|
||||
* Copyright © 2019 Intel Corporation
|
||||
*/
|
||||
|
||||
#ifndef __SELFTEST_H__
|
||||
#define __SELFTEST_H__
|
||||
|
||||
#include <linux/compiler.h>
|
||||
|
||||
#define selftest(name, func) int func(void);
|
||||
#include "selftests.h"
|
||||
#undef selftest
|
||||
|
||||
struct subtest {
|
||||
int (*func)(void *data);
|
||||
const char *name;
|
||||
};
|
||||
|
||||
int __subtests(const char *caller,
|
||||
const struct subtest *st,
|
||||
int count,
|
||||
void *data);
|
||||
#define subtests(T, data) \
|
||||
__subtests(__func__, T, ARRAY_SIZE(T), data)
|
||||
|
||||
#define SUBTEST(x) { x, #x }
|
||||
|
||||
#endif /* __SELFTEST_H__ */
|
13
drivers/dma-buf/selftests.h
Normal file
13
drivers/dma-buf/selftests.h
Normal file
@ -0,0 +1,13 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/* List each unit test as selftest(name, function)
|
||||
*
|
||||
* The name is used as both an enum and expanded as subtest__name to create
|
||||
* a module parameter. It must be unique and legal for a C identifier.
|
||||
*
|
||||
* The function should be of type int function(void). It may be conditionally
|
||||
* compiled using #if IS_ENABLED(DRM_I915_SELFTEST).
|
||||
*
|
||||
* Tests are executed in order by igt/dmabuf_selftest
|
||||
*/
|
||||
selftest(sanitycheck, __sanitycheck__) /* keep first (igt selfcheck) */
|
||||
selftest(dma_fence, dma_fence)
|
574
drivers/dma-buf/st-dma-fence.c
Normal file
574
drivers/dma-buf/st-dma-fence.c
Normal file
@ -0,0 +1,574 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
/*
|
||||
* Copyright © 2019 Intel Corporation
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dma-fence.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/sched/signal.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include "selftest.h"
|
||||
|
||||
static struct kmem_cache *slab_fences;
|
||||
|
||||
static struct mock_fence {
|
||||
struct dma_fence base;
|
||||
struct spinlock lock;
|
||||
} *to_mock_fence(struct dma_fence *f) {
|
||||
return container_of(f, struct mock_fence, base);
|
||||
}
|
||||
|
||||
static const char *mock_name(struct dma_fence *f)
|
||||
{
|
||||
return "mock";
|
||||
}
|
||||
|
||||
static void mock_fence_release(struct dma_fence *f)
|
||||
{
|
||||
kmem_cache_free(slab_fences, to_mock_fence(f));
|
||||
}
|
||||
|
||||
struct wait_cb {
|
||||
struct dma_fence_cb cb;
|
||||
struct task_struct *task;
|
||||
};
|
||||
|
||||
static void mock_wakeup(struct dma_fence *f, struct dma_fence_cb *cb)
|
||||
{
|
||||
wake_up_process(container_of(cb, struct wait_cb, cb)->task);
|
||||
}
|
||||
|
||||
static long mock_wait(struct dma_fence *f, bool intr, long timeout)
|
||||
{
|
||||
const int state = intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE;
|
||||
struct wait_cb cb = { .task = current };
|
||||
|
||||
if (dma_fence_add_callback(f, &cb.cb, mock_wakeup))
|
||||
return timeout;
|
||||
|
||||
while (timeout) {
|
||||
set_current_state(state);
|
||||
|
||||
if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &f->flags))
|
||||
break;
|
||||
|
||||
if (signal_pending_state(state, current))
|
||||
break;
|
||||
|
||||
timeout = schedule_timeout(timeout);
|
||||
}
|
||||
__set_current_state(TASK_RUNNING);
|
||||
|
||||
if (!dma_fence_remove_callback(f, &cb.cb))
|
||||
return timeout;
|
||||
|
||||
if (signal_pending_state(state, current))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
return -ETIME;
|
||||
}
|
||||
|
||||
static const struct dma_fence_ops mock_ops = {
|
||||
.get_driver_name = mock_name,
|
||||
.get_timeline_name = mock_name,
|
||||
.wait = mock_wait,
|
||||
.release = mock_fence_release,
|
||||
};
|
||||
|
||||
static struct dma_fence *mock_fence(void)
|
||||
{
|
||||
struct mock_fence *f;
|
||||
|
||||
f = kmem_cache_alloc(slab_fences, GFP_KERNEL);
|
||||
if (!f)
|
||||
return NULL;
|
||||
|
||||
spin_lock_init(&f->lock);
|
||||
dma_fence_init(&f->base, &mock_ops, &f->lock, 0, 0);
|
||||
|
||||
return &f->base;
|
||||
}
|
||||
|
||||
static int sanitycheck(void *arg)
|
||||
{
|
||||
struct dma_fence *f;
|
||||
|
||||
f = mock_fence();
|
||||
if (!f)
|
||||
return -ENOMEM;
|
||||
|
||||
dma_fence_signal(f);
|
||||
dma_fence_put(f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_signaling(void *arg)
|
||||
{
|
||||
struct dma_fence *f;
|
||||
int err = -EINVAL;
|
||||
|
||||
f = mock_fence();
|
||||
if (!f)
|
||||
return -ENOMEM;
|
||||
|
||||
if (dma_fence_is_signaled(f)) {
|
||||
pr_err("Fence unexpectedly signaled on creation\n");
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
if (dma_fence_signal(f)) {
|
||||
pr_err("Fence reported being already signaled\n");
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
if (!dma_fence_is_signaled(f)) {
|
||||
pr_err("Fence not reporting signaled\n");
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
if (!dma_fence_signal(f)) {
|
||||
pr_err("Fence reported not being already signaled\n");
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
err = 0;
|
||||
err_free:
|
||||
dma_fence_put(f);
|
||||
return err;
|
||||
}
|
||||
|
||||
struct simple_cb {
|
||||
struct dma_fence_cb cb;
|
||||
bool seen;
|
||||
};
|
||||
|
||||
static void simple_callback(struct dma_fence *f, struct dma_fence_cb *cb)
|
||||
{
|
||||
smp_store_mb(container_of(cb, struct simple_cb, cb)->seen, true);
|
||||
}
|
||||
|
||||
static int test_add_callback(void *arg)
|
||||
{
|
||||
struct simple_cb cb = {};
|
||||
struct dma_fence *f;
|
||||
int err = -EINVAL;
|
||||
|
||||
f = mock_fence();
|
||||
if (!f)
|
||||
return -ENOMEM;
|
||||
|
||||
if (dma_fence_add_callback(f, &cb.cb, simple_callback)) {
|
||||
pr_err("Failed to add callback, fence already signaled!\n");
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
dma_fence_signal(f);
|
||||
if (!cb.seen) {
|
||||
pr_err("Callback failed!\n");
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
err = 0;
|
||||
err_free:
|
||||
dma_fence_put(f);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int test_late_add_callback(void *arg)
|
||||
{
|
||||
struct simple_cb cb = {};
|
||||
struct dma_fence *f;
|
||||
int err = -EINVAL;
|
||||
|
||||
f = mock_fence();
|
||||
if (!f)
|
||||
return -ENOMEM;
|
||||
|
||||
dma_fence_signal(f);
|
||||
|
||||
if (!dma_fence_add_callback(f, &cb.cb, simple_callback)) {
|
||||
pr_err("Added callback, but fence was already signaled!\n");
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
dma_fence_signal(f);
|
||||
if (cb.seen) {
|
||||
pr_err("Callback called after failed attachment !\n");
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
err = 0;
|
||||
err_free:
|
||||
dma_fence_put(f);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int test_rm_callback(void *arg)
|
||||
{
|
||||
struct simple_cb cb = {};
|
||||
struct dma_fence *f;
|
||||
int err = -EINVAL;
|
||||
|
||||
f = mock_fence();
|
||||
if (!f)
|
||||
return -ENOMEM;
|
||||
|
||||
if (dma_fence_add_callback(f, &cb.cb, simple_callback)) {
|
||||
pr_err("Failed to add callback, fence already signaled!\n");
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
if (!dma_fence_remove_callback(f, &cb.cb)) {
|
||||
pr_err("Failed to remove callback!\n");
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
dma_fence_signal(f);
|
||||
if (cb.seen) {
|
||||
pr_err("Callback still signaled after removal!\n");
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
err = 0;
|
||||
err_free:
|
||||
dma_fence_put(f);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int test_late_rm_callback(void *arg)
|
||||
{
|
||||
struct simple_cb cb = {};
|
||||
struct dma_fence *f;
|
||||
int err = -EINVAL;
|
||||
|
||||
f = mock_fence();
|
||||
if (!f)
|
||||
return -ENOMEM;
|
||||
|
||||
if (dma_fence_add_callback(f, &cb.cb, simple_callback)) {
|
||||
pr_err("Failed to add callback, fence already signaled!\n");
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
dma_fence_signal(f);
|
||||
if (!cb.seen) {
|
||||
pr_err("Callback failed!\n");
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
if (dma_fence_remove_callback(f, &cb.cb)) {
|
||||
pr_err("Callback removal succeed after being executed!\n");
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
err = 0;
|
||||
err_free:
|
||||
dma_fence_put(f);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int test_status(void *arg)
|
||||
{
|
||||
struct dma_fence *f;
|
||||
int err = -EINVAL;
|
||||
|
||||
f = mock_fence();
|
||||
if (!f)
|
||||
return -ENOMEM;
|
||||
|
||||
if (dma_fence_get_status(f)) {
|
||||
pr_err("Fence unexpectedly has signaled status on creation\n");
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
dma_fence_signal(f);
|
||||
if (!dma_fence_get_status(f)) {
|
||||
pr_err("Fence not reporting signaled status\n");
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
err = 0;
|
||||
err_free:
|
||||
dma_fence_put(f);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int test_error(void *arg)
|
||||
{
|
||||
struct dma_fence *f;
|
||||
int err = -EINVAL;
|
||||
|
||||
f = mock_fence();
|
||||
if (!f)
|
||||
return -ENOMEM;
|
||||
|
||||
dma_fence_set_error(f, -EIO);
|
||||
|
||||
if (dma_fence_get_status(f)) {
|
||||
pr_err("Fence unexpectedly has error status before signal\n");
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
dma_fence_signal(f);
|
||||
if (dma_fence_get_status(f) != -EIO) {
|
||||
pr_err("Fence not reporting error status, got %d\n",
|
||||
dma_fence_get_status(f));
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
err = 0;
|
||||
err_free:
|
||||
dma_fence_put(f);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int test_wait(void *arg)
|
||||
{
|
||||
struct dma_fence *f;
|
||||
int err = -EINVAL;
|
||||
|
||||
f = mock_fence();
|
||||
if (!f)
|
||||
return -ENOMEM;
|
||||
|
||||
if (dma_fence_wait_timeout(f, false, 0) != -ETIME) {
|
||||
pr_err("Wait reported complete before being signaled\n");
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
dma_fence_signal(f);
|
||||
|
||||
if (dma_fence_wait_timeout(f, false, 0) != 0) {
|
||||
pr_err("Wait reported incomplete after being signaled\n");
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
err = 0;
|
||||
err_free:
|
||||
dma_fence_signal(f);
|
||||
dma_fence_put(f);
|
||||
return err;
|
||||
}
|
||||
|
||||
struct wait_timer {
|
||||
struct timer_list timer;
|
||||
struct dma_fence *f;
|
||||
};
|
||||
|
||||
static void wait_timer(struct timer_list *timer)
|
||||
{
|
||||
struct wait_timer *wt = from_timer(wt, timer, timer);
|
||||
|
||||
dma_fence_signal(wt->f);
|
||||
}
|
||||
|
||||
static int test_wait_timeout(void *arg)
|
||||
{
|
||||
struct wait_timer wt;
|
||||
int err = -EINVAL;
|
||||
|
||||
timer_setup_on_stack(&wt.timer, wait_timer, 0);
|
||||
|
||||
wt.f = mock_fence();
|
||||
if (!wt.f)
|
||||
return -ENOMEM;
|
||||
|
||||
if (dma_fence_wait_timeout(wt.f, false, 1) != -ETIME) {
|
||||
pr_err("Wait reported complete before being signaled\n");
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
mod_timer(&wt.timer, jiffies + 1);
|
||||
|
||||
if (dma_fence_wait_timeout(wt.f, false, 2) == -ETIME) {
|
||||
if (timer_pending(&wt.timer)) {
|
||||
pr_notice("Timer did not fire within the jiffie!\n");
|
||||
err = 0; /* not our fault! */
|
||||
} else {
|
||||
pr_err("Wait reported incomplete after timeout\n");
|
||||
}
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
err = 0;
|
||||
err_free:
|
||||
del_timer_sync(&wt.timer);
|
||||
destroy_timer_on_stack(&wt.timer);
|
||||
dma_fence_signal(wt.f);
|
||||
dma_fence_put(wt.f);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int test_stub(void *arg)
|
||||
{
|
||||
struct dma_fence *f[64];
|
||||
int err = -EINVAL;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(f); i++) {
|
||||
f[i] = dma_fence_get_stub();
|
||||
if (!dma_fence_is_signaled(f[i])) {
|
||||
pr_err("Obtained unsignaled stub fence!\n");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
err = 0;
|
||||
err:
|
||||
while (i--)
|
||||
dma_fence_put(f[i]);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Now off to the races! */
|
||||
|
||||
struct race_thread {
|
||||
struct dma_fence __rcu **fences;
|
||||
struct task_struct *task;
|
||||
bool before;
|
||||
int id;
|
||||
};
|
||||
|
||||
static void __wait_for_callbacks(struct dma_fence *f)
|
||||
{
|
||||
spin_lock_irq(f->lock);
|
||||
spin_unlock_irq(f->lock);
|
||||
}
|
||||
|
||||
static int thread_signal_callback(void *arg)
|
||||
{
|
||||
const struct race_thread *t = arg;
|
||||
unsigned long pass = 0;
|
||||
unsigned long miss = 0;
|
||||
int err = 0;
|
||||
|
||||
while (!err && !kthread_should_stop()) {
|
||||
struct dma_fence *f1, *f2;
|
||||
struct simple_cb cb;
|
||||
|
||||
f1 = mock_fence();
|
||||
if (!f1) {
|
||||
err = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
|
||||
rcu_assign_pointer(t->fences[t->id], f1);
|
||||
smp_wmb();
|
||||
|
||||
rcu_read_lock();
|
||||
do {
|
||||
f2 = dma_fence_get_rcu_safe(&t->fences[!t->id]);
|
||||
} while (!f2 && !kthread_should_stop());
|
||||
rcu_read_unlock();
|
||||
|
||||
if (t->before)
|
||||
dma_fence_signal(f1);
|
||||
|
||||
smp_store_mb(cb.seen, false);
|
||||
if (!f2 || dma_fence_add_callback(f2, &cb.cb, simple_callback))
|
||||
miss++, cb.seen = true;
|
||||
|
||||
if (!t->before)
|
||||
dma_fence_signal(f1);
|
||||
|
||||
if (!cb.seen) {
|
||||
dma_fence_wait(f2, false);
|
||||
__wait_for_callbacks(f2);
|
||||
}
|
||||
|
||||
if (!READ_ONCE(cb.seen)) {
|
||||
pr_err("Callback not seen on thread %d, pass %lu (%lu misses), signaling %s add_callback; fence signaled? %s\n",
|
||||
t->id, pass, miss,
|
||||
t->before ? "before" : "after",
|
||||
dma_fence_is_signaled(f2) ? "yes" : "no");
|
||||
err = -EINVAL;
|
||||
}
|
||||
|
||||
dma_fence_put(f2);
|
||||
|
||||
rcu_assign_pointer(t->fences[t->id], NULL);
|
||||
smp_wmb();
|
||||
|
||||
dma_fence_put(f1);
|
||||
|
||||
pass++;
|
||||
}
|
||||
|
||||
pr_info("%s[%d] completed %lu passes, %lu misses\n",
|
||||
__func__, t->id, pass, miss);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int race_signal_callback(void *arg)
|
||||
{
|
||||
struct dma_fence __rcu *f[2] = {};
|
||||
int ret = 0;
|
||||
int pass;
|
||||
|
||||
for (pass = 0; !ret && pass <= 1; pass++) {
|
||||
struct race_thread t[2];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(t); i++) {
|
||||
t[i].fences = f;
|
||||
t[i].id = i;
|
||||
t[i].before = pass;
|
||||
t[i].task = kthread_run(thread_signal_callback, &t[i],
|
||||
"dma-fence:%d", i);
|
||||
get_task_struct(t[i].task);
|
||||
}
|
||||
|
||||
msleep(50);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(t); i++) {
|
||||
int err;
|
||||
|
||||
err = kthread_stop(t[i].task);
|
||||
if (err && !ret)
|
||||
ret = err;
|
||||
|
||||
put_task_struct(t[i].task);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dma_fence(void)
|
||||
{
|
||||
static const struct subtest tests[] = {
|
||||
SUBTEST(sanitycheck),
|
||||
SUBTEST(test_signaling),
|
||||
SUBTEST(test_add_callback),
|
||||
SUBTEST(test_late_add_callback),
|
||||
SUBTEST(test_rm_callback),
|
||||
SUBTEST(test_late_rm_callback),
|
||||
SUBTEST(test_status),
|
||||
SUBTEST(test_error),
|
||||
SUBTEST(test_wait),
|
||||
SUBTEST(test_wait_timeout),
|
||||
SUBTEST(test_stub),
|
||||
SUBTEST(race_signal_callback),
|
||||
};
|
||||
int ret;
|
||||
|
||||
pr_info("sizeof(dma_fence)=%zu\n", sizeof(struct dma_fence));
|
||||
|
||||
slab_fences = KMEM_CACHE(mock_fence,
|
||||
SLAB_TYPESAFE_BY_RCU |
|
||||
SLAB_HWCACHE_ALIGN);
|
||||
if (!slab_fences)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = subtests(tests, NULL);
|
||||
|
||||
kmem_cache_destroy(slab_fences);
|
||||
|
||||
return ret;
|
||||
}
|
@ -132,17 +132,14 @@ static void timeline_fence_release(struct dma_fence *fence)
|
||||
{
|
||||
struct sync_pt *pt = dma_fence_to_sync_pt(fence);
|
||||
struct sync_timeline *parent = dma_fence_parent(fence);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(fence->lock, flags);
|
||||
if (!list_empty(&pt->link)) {
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(fence->lock, flags);
|
||||
if (!list_empty(&pt->link)) {
|
||||
list_del(&pt->link);
|
||||
rb_erase(&pt->node, &parent->pt_tree);
|
||||
}
|
||||
spin_unlock_irqrestore(fence->lock, flags);
|
||||
list_del(&pt->link);
|
||||
rb_erase(&pt->node, &parent->pt_tree);
|
||||
}
|
||||
spin_unlock_irqrestore(fence->lock, flags);
|
||||
|
||||
sync_timeline_put(parent);
|
||||
dma_fence_free(fence);
|
||||
@ -265,7 +262,8 @@ static struct sync_pt *sync_pt_create(struct sync_timeline *obj,
|
||||
p = &parent->rb_left;
|
||||
} else {
|
||||
if (dma_fence_get_rcu(&other->base)) {
|
||||
dma_fence_put(&pt->base);
|
||||
sync_timeline_put(obj);
|
||||
kfree(pt);
|
||||
pt = other;
|
||||
goto unlock;
|
||||
}
|
||||
|
@ -419,7 +419,7 @@ static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
|
||||
* info->num_fences.
|
||||
*/
|
||||
if (!info.num_fences) {
|
||||
info.status = dma_fence_is_signaled(sync_file->fence);
|
||||
info.status = dma_fence_get_status(sync_file->fence);
|
||||
goto no_fences;
|
||||
} else {
|
||||
info.status = 1;
|
||||
|
@ -24,6 +24,10 @@ menuconfig DRM
|
||||
details. You should also select and configure AGP
|
||||
(/dev/agpgart) support if it is available for your platform.
|
||||
|
||||
config DRM_MIPI_DBI
|
||||
tristate
|
||||
depends on DRM
|
||||
|
||||
config DRM_MIPI_DSI
|
||||
bool
|
||||
depends on DRM
|
||||
@ -336,7 +340,7 @@ source "drivers/gpu/drm/mxsfb/Kconfig"
|
||||
|
||||
source "drivers/gpu/drm/meson/Kconfig"
|
||||
|
||||
source "drivers/gpu/drm/tinydrm/Kconfig"
|
||||
source "drivers/gpu/drm/tiny/Kconfig"
|
||||
|
||||
source "drivers/gpu/drm/pl111/Kconfig"
|
||||
|
||||
|
@ -55,6 +55,7 @@ obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o
|
||||
obj-$(CONFIG_DRM_DEBUG_SELFTEST) += selftests/
|
||||
|
||||
obj-$(CONFIG_DRM) += drm.o
|
||||
obj-$(CONFIG_DRM_MIPI_DBI) += drm_mipi_dbi.o
|
||||
obj-$(CONFIG_DRM_MIPI_DSI) += drm_mipi_dsi.o
|
||||
obj-$(CONFIG_DRM_PANEL_ORIENTATION_QUIRKS) += drm_panel_orientation_quirks.o
|
||||
obj-y += arm/
|
||||
@ -62,7 +63,6 @@ obj-$(CONFIG_DRM_TTM) += ttm/
|
||||
obj-$(CONFIG_DRM_SCHED) += scheduler/
|
||||
obj-$(CONFIG_DRM_TDFX) += tdfx/
|
||||
obj-$(CONFIG_DRM_R128) += r128/
|
||||
obj-$(CONFIG_HSA_AMD) += amd/amdkfd/
|
||||
obj-$(CONFIG_DRM_RADEON)+= radeon/
|
||||
obj-$(CONFIG_DRM_AMDGPU)+= amd/amdgpu/
|
||||
obj-$(CONFIG_DRM_MGA) += mga/
|
||||
@ -111,7 +111,7 @@ obj-$(CONFIG_DRM_ARCPGU)+= arc/
|
||||
obj-y += hisilicon/
|
||||
obj-$(CONFIG_DRM_ZTE) += zte/
|
||||
obj-$(CONFIG_DRM_MXSFB) += mxsfb/
|
||||
obj-$(CONFIG_DRM_TINYDRM) += tinydrm/
|
||||
obj-y += tiny/
|
||||
obj-$(CONFIG_DRM_PL111) += pl111/
|
||||
obj-$(CONFIG_DRM_TVE200) += tve200/
|
||||
obj-$(CONFIG_DRM_XEN) += xen/
|
||||
|
@ -54,7 +54,7 @@ amdgpu-y += amdgpu_device.o amdgpu_kms.o \
|
||||
amdgpu_gtt_mgr.o amdgpu_vram_mgr.o amdgpu_virt.o amdgpu_atomfirmware.o \
|
||||
amdgpu_vf_error.o amdgpu_sched.o amdgpu_debugfs.o amdgpu_ids.o \
|
||||
amdgpu_gmc.o amdgpu_xgmi.o amdgpu_csa.o amdgpu_ras.o amdgpu_vm_cpu.o \
|
||||
amdgpu_vm_sdma.o amdgpu_discovery.o
|
||||
amdgpu_vm_sdma.o amdgpu_pmu.o amdgpu_discovery.o amdgpu_ras_eeprom.o smu_v11_0_i2c.o
|
||||
|
||||
amdgpu-$(CONFIG_PERF_EVENTS) += amdgpu_pmu.o
|
||||
|
||||
@ -66,7 +66,8 @@ amdgpu-$(CONFIG_DRM_AMDGPU_SI)+= si.o gmc_v6_0.o gfx_v6_0.o si_ih.o si_dma.o dce
|
||||
|
||||
amdgpu-y += \
|
||||
vi.o mxgpu_vi.o nbio_v6_1.o soc15.o emu_soc.o mxgpu_ai.o nbio_v7_0.o vega10_reg_init.o \
|
||||
vega20_reg_init.o nbio_v7_4.o nbio_v2_3.o nv.o navi10_reg_init.o
|
||||
vega20_reg_init.o nbio_v7_4.o nbio_v2_3.o nv.o navi10_reg_init.o navi14_reg_init.o \
|
||||
arct_reg_init.o navi12_reg_init.o
|
||||
|
||||
# add DF block
|
||||
amdgpu-y += \
|
||||
@ -77,9 +78,13 @@ amdgpu-y += \
|
||||
amdgpu-y += \
|
||||
gmc_v7_0.o \
|
||||
gmc_v8_0.o \
|
||||
gfxhub_v1_0.o mmhub_v1_0.o gmc_v9_0.o gfxhub_v1_1.o \
|
||||
gfxhub_v1_0.o mmhub_v1_0.o gmc_v9_0.o gfxhub_v1_1.o mmhub_v9_4.o \
|
||||
gfxhub_v2_0.o mmhub_v2_0.o gmc_v10_0.o
|
||||
|
||||
# add UMC block
|
||||
amdgpu-y += \
|
||||
umc_v6_1.o
|
||||
|
||||
# add IH block
|
||||
amdgpu-y += \
|
||||
amdgpu_irq.o \
|
||||
@ -95,7 +100,8 @@ amdgpu-y += \
|
||||
amdgpu_psp.o \
|
||||
psp_v3_1.o \
|
||||
psp_v10_0.o \
|
||||
psp_v11_0.o
|
||||
psp_v11_0.o \
|
||||
psp_v12_0.o
|
||||
|
||||
# add SMC block
|
||||
amdgpu-y += \
|
||||
@ -144,10 +150,12 @@ amdgpu-y += \
|
||||
amdgpu-y += \
|
||||
amdgpu_vcn.o \
|
||||
vcn_v1_0.o \
|
||||
vcn_v2_0.o
|
||||
vcn_v2_0.o \
|
||||
vcn_v2_5.o
|
||||
|
||||
# add ATHUB block
|
||||
amdgpu-y += \
|
||||
athub_v1_0.o \
|
||||
athub_v2_0.o
|
||||
|
||||
# add amdkfd interfaces
|
||||
@ -162,6 +170,7 @@ amdgpu-y += \
|
||||
amdgpu_amdkfd_gpuvm.o \
|
||||
amdgpu_amdkfd_gfx_v8.o \
|
||||
amdgpu_amdkfd_gfx_v9.o \
|
||||
amdgpu_amdkfd_arcturus.o \
|
||||
amdgpu_amdkfd_gfx_v10.o
|
||||
|
||||
ifneq ($(CONFIG_DRM_AMDGPU_CIK),)
|
||||
|
@ -86,6 +86,8 @@
|
||||
#include "amdgpu_smu.h"
|
||||
#include "amdgpu_discovery.h"
|
||||
#include "amdgpu_mes.h"
|
||||
#include "amdgpu_umc.h"
|
||||
#include "amdgpu_mmhub.h"
|
||||
|
||||
#define MAX_GPU_INSTANCE 16
|
||||
|
||||
@ -532,6 +534,14 @@ struct amdgpu_allowed_register_entry {
|
||||
bool grbm_indexed;
|
||||
};
|
||||
|
||||
enum amd_reset_method {
|
||||
AMD_RESET_METHOD_LEGACY = 0,
|
||||
AMD_RESET_METHOD_MODE0,
|
||||
AMD_RESET_METHOD_MODE1,
|
||||
AMD_RESET_METHOD_MODE2,
|
||||
AMD_RESET_METHOD_BACO
|
||||
};
|
||||
|
||||
/*
|
||||
* ASIC specific functions.
|
||||
*/
|
||||
@ -543,6 +553,7 @@ struct amdgpu_asic_funcs {
|
||||
u32 sh_num, u32 reg_offset, u32 *value);
|
||||
void (*set_vga_state)(struct amdgpu_device *adev, bool state);
|
||||
int (*reset)(struct amdgpu_device *adev);
|
||||
enum amd_reset_method (*reset_method)(struct amdgpu_device *adev);
|
||||
/* get the reference clock */
|
||||
u32 (*get_xclk)(struct amdgpu_device *adev);
|
||||
/* MM block clocks */
|
||||
@ -627,6 +638,9 @@ void amdgpu_cgs_destroy_device(struct cgs_device *cgs_device);
|
||||
typedef uint32_t (*amdgpu_rreg_t)(struct amdgpu_device*, uint32_t);
|
||||
typedef void (*amdgpu_wreg_t)(struct amdgpu_device*, uint32_t, uint32_t);
|
||||
|
||||
typedef uint64_t (*amdgpu_rreg64_t)(struct amdgpu_device*, uint32_t);
|
||||
typedef void (*amdgpu_wreg64_t)(struct amdgpu_device*, uint32_t, uint64_t);
|
||||
|
||||
typedef uint32_t (*amdgpu_block_rreg_t)(struct amdgpu_device*, uint32_t, uint32_t);
|
||||
typedef void (*amdgpu_block_wreg_t)(struct amdgpu_device*, uint32_t, uint32_t, uint32_t);
|
||||
|
||||
@ -648,6 +662,12 @@ struct nbio_hdp_flush_reg {
|
||||
u32 ref_and_mask_cp9;
|
||||
u32 ref_and_mask_sdma0;
|
||||
u32 ref_and_mask_sdma1;
|
||||
u32 ref_and_mask_sdma2;
|
||||
u32 ref_and_mask_sdma3;
|
||||
u32 ref_and_mask_sdma4;
|
||||
u32 ref_and_mask_sdma5;
|
||||
u32 ref_and_mask_sdma6;
|
||||
u32 ref_and_mask_sdma7;
|
||||
};
|
||||
|
||||
struct amdgpu_mmio_remap {
|
||||
@ -668,7 +688,7 @@ struct amdgpu_nbio_funcs {
|
||||
void (*sdma_doorbell_range)(struct amdgpu_device *adev, int instance,
|
||||
bool use_doorbell, int doorbell_index, int doorbell_size);
|
||||
void (*vcn_doorbell_range)(struct amdgpu_device *adev, bool use_doorbell,
|
||||
int doorbell_index);
|
||||
int doorbell_index, int instance);
|
||||
void (*enable_doorbell_aperture)(struct amdgpu_device *adev,
|
||||
bool enable);
|
||||
void (*enable_doorbell_selfring_aperture)(struct amdgpu_device *adev,
|
||||
@ -705,6 +725,9 @@ struct amdgpu_df_funcs {
|
||||
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 {
|
||||
@ -712,6 +735,12 @@ enum amd_hw_ip_block_type {
|
||||
HDP_HWIP,
|
||||
SDMA0_HWIP,
|
||||
SDMA1_HWIP,
|
||||
SDMA2_HWIP,
|
||||
SDMA3_HWIP,
|
||||
SDMA4_HWIP,
|
||||
SDMA5_HWIP,
|
||||
SDMA6_HWIP,
|
||||
SDMA7_HWIP,
|
||||
MMHUB_HWIP,
|
||||
ATHUB_HWIP,
|
||||
NBIO_HWIP,
|
||||
@ -728,10 +757,12 @@ enum amd_hw_ip_block_type {
|
||||
NBIF_HWIP,
|
||||
THM_HWIP,
|
||||
CLK_HWIP,
|
||||
UMC_HWIP,
|
||||
RSMU_HWIP,
|
||||
MAX_HWIP
|
||||
};
|
||||
|
||||
#define HWIP_MAX_INSTANCE 6
|
||||
#define HWIP_MAX_INSTANCE 8
|
||||
|
||||
struct amd_powerplay {
|
||||
void *pp_handle;
|
||||
@ -758,7 +789,6 @@ struct amdgpu_device {
|
||||
int usec_timeout;
|
||||
const struct amdgpu_asic_funcs *asic_funcs;
|
||||
bool shutdown;
|
||||
bool need_dma32;
|
||||
bool need_swiotlb;
|
||||
bool accel_working;
|
||||
struct notifier_block acpi_nb;
|
||||
@ -803,6 +833,8 @@ struct amdgpu_device {
|
||||
amdgpu_wreg_t pcie_wreg;
|
||||
amdgpu_rreg_t pciep_rreg;
|
||||
amdgpu_wreg_t pciep_wreg;
|
||||
amdgpu_rreg64_t pcie_rreg64;
|
||||
amdgpu_wreg64_t pcie_wreg64;
|
||||
/* protects concurrent UVD register access */
|
||||
spinlock_t uvd_ctx_idx_lock;
|
||||
amdgpu_rreg_t uvd_ctx_rreg;
|
||||
@ -836,6 +868,7 @@ struct amdgpu_device {
|
||||
dma_addr_t dummy_page_addr;
|
||||
struct amdgpu_vm_manager vm_manager;
|
||||
struct amdgpu_vmhub vmhub[AMDGPU_MAX_VMHUBS];
|
||||
unsigned num_vmhubs;
|
||||
|
||||
/* memory management */
|
||||
struct amdgpu_mman mman;
|
||||
@ -915,6 +948,9 @@ struct amdgpu_device {
|
||||
/* KFD */
|
||||
struct amdgpu_kfd_dev kfd;
|
||||
|
||||
/* UMC */
|
||||
struct amdgpu_umc umc;
|
||||
|
||||
/* display related functionality */
|
||||
struct amdgpu_display_manager dm;
|
||||
|
||||
@ -940,6 +976,7 @@ struct amdgpu_device {
|
||||
|
||||
const struct amdgpu_nbio_funcs *nbio_funcs;
|
||||
const struct amdgpu_df_funcs *df_funcs;
|
||||
const struct amdgpu_mmhub_funcs *mmhub_funcs;
|
||||
|
||||
/* delayed work_func for deferring clockgating during resume */
|
||||
struct delayed_work delayed_init_work;
|
||||
@ -965,6 +1002,7 @@ struct amdgpu_device {
|
||||
/* record last mm index being written through WREG32*/
|
||||
unsigned long last_mm_index;
|
||||
bool in_gpu_reset;
|
||||
enum pp_mp1_state mp1_state;
|
||||
struct mutex lock_reset;
|
||||
struct amdgpu_doorbell_index doorbell_index;
|
||||
|
||||
@ -1033,6 +1071,8 @@ int emu_soc_asic_init(struct amdgpu_device *adev);
|
||||
#define WREG32_PCIE(reg, v) adev->pcie_wreg(adev, (reg), (v))
|
||||
#define RREG32_PCIE_PORT(reg) adev->pciep_rreg(adev, (reg))
|
||||
#define WREG32_PCIE_PORT(reg, v) adev->pciep_wreg(adev, (reg), (v))
|
||||
#define RREG64_PCIE(reg) adev->pcie_rreg64(adev, (reg))
|
||||
#define WREG64_PCIE(reg, v) adev->pcie_wreg64(adev, (reg), (v))
|
||||
#define RREG32_SMC(reg) adev->smc_rreg(adev, (reg))
|
||||
#define WREG32_SMC(reg, v) adev->smc_wreg(adev, (reg), (v))
|
||||
#define RREG32_UVD_CTX(reg) adev->uvd_ctx_rreg(adev, (reg))
|
||||
@ -1093,6 +1133,7 @@ int emu_soc_asic_init(struct amdgpu_device *adev);
|
||||
*/
|
||||
#define amdgpu_asic_set_vga_state(adev, state) (adev)->asic_funcs->set_vga_state((adev), (state))
|
||||
#define amdgpu_asic_reset(adev) (adev)->asic_funcs->reset((adev))
|
||||
#define amdgpu_asic_reset_method(adev) (adev)->asic_funcs->reset_method((adev))
|
||||
#define amdgpu_asic_get_xclk(adev) (adev)->asic_funcs->get_xclk((adev))
|
||||
#define amdgpu_asic_set_uvd_clocks(adev, v, d) (adev)->asic_funcs->set_uvd_clocks((adev), (v), (d))
|
||||
#define amdgpu_asic_set_vce_clocks(adev, ev, ec) (adev)->asic_funcs->set_vce_clocks((adev), (ev), (ec))
|
||||
@ -1110,6 +1151,7 @@ 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_inc_vram_lost(adev) atomic_inc(&((adev)->vram_lost_counter));
|
||||
|
||||
/* Common functions */
|
||||
bool amdgpu_device_should_recover_gpu(struct amdgpu_device *adev);
|
||||
|
@ -87,7 +87,12 @@ void amdgpu_amdkfd_device_probe(struct amdgpu_device *adev)
|
||||
case CHIP_RAVEN:
|
||||
kfd2kgd = amdgpu_amdkfd_gfx_9_0_get_functions();
|
||||
break;
|
||||
case CHIP_ARCTURUS:
|
||||
kfd2kgd = amdgpu_amdkfd_arcturus_get_functions();
|
||||
break;
|
||||
case CHIP_NAVI10:
|
||||
case CHIP_NAVI14:
|
||||
case CHIP_NAVI12:
|
||||
kfd2kgd = amdgpu_amdkfd_gfx_10_0_get_functions();
|
||||
break;
|
||||
default:
|
||||
@ -651,8 +656,12 @@ void amdgpu_amdkfd_set_compute_idle(struct kgd_dev *kgd, bool idle)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)kgd;
|
||||
|
||||
if (adev->powerplay.pp_funcs &&
|
||||
adev->powerplay.pp_funcs->switch_power_profile)
|
||||
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);
|
||||
@ -715,6 +724,11 @@ struct kfd2kgd_calls *amdgpu_amdkfd_gfx_9_0_get_functions(void)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct kfd2kgd_calls *amdgpu_amdkfd_arcturus_get_functions(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct kfd2kgd_calls *amdgpu_amdkfd_gfx_10_0_get_functions(void)
|
||||
{
|
||||
return NULL;
|
||||
|
@ -140,6 +140,7 @@ bool amdgpu_amdkfd_have_atomics_support(struct kgd_dev *kgd);
|
||||
struct kfd2kgd_calls *amdgpu_amdkfd_gfx_7_get_functions(void);
|
||||
struct kfd2kgd_calls *amdgpu_amdkfd_gfx_8_0_get_functions(void);
|
||||
struct kfd2kgd_calls *amdgpu_amdkfd_gfx_9_0_get_functions(void);
|
||||
struct kfd2kgd_calls *amdgpu_amdkfd_arcturus_get_functions(void);
|
||||
struct kfd2kgd_calls *amdgpu_amdkfd_gfx_10_0_get_functions(void);
|
||||
|
||||
bool amdgpu_amdkfd_is_kfd_vmid(struct amdgpu_device *adev, u32 vmid);
|
||||
|
323
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_arcturus.c
Normal file
323
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_arcturus.c
Normal file
@ -0,0 +1,323 @@
|
||||
/*
|
||||
* Copyright 2019 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.
|
||||
*/
|
||||
|
||||
#undef pr_fmt
|
||||
#define pr_fmt(fmt) "kfd2kgd: " fmt
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/fdtable.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/mmu_context.h>
|
||||
#include <linux/firmware.h>
|
||||
#include "amdgpu.h"
|
||||
#include "amdgpu_amdkfd.h"
|
||||
#include "sdma0/sdma0_4_2_2_offset.h"
|
||||
#include "sdma0/sdma0_4_2_2_sh_mask.h"
|
||||
#include "sdma1/sdma1_4_2_2_offset.h"
|
||||
#include "sdma1/sdma1_4_2_2_sh_mask.h"
|
||||
#include "sdma2/sdma2_4_2_2_offset.h"
|
||||
#include "sdma2/sdma2_4_2_2_sh_mask.h"
|
||||
#include "sdma3/sdma3_4_2_2_offset.h"
|
||||
#include "sdma3/sdma3_4_2_2_sh_mask.h"
|
||||
#include "sdma4/sdma4_4_2_2_offset.h"
|
||||
#include "sdma4/sdma4_4_2_2_sh_mask.h"
|
||||
#include "sdma5/sdma5_4_2_2_offset.h"
|
||||
#include "sdma5/sdma5_4_2_2_sh_mask.h"
|
||||
#include "sdma6/sdma6_4_2_2_offset.h"
|
||||
#include "sdma6/sdma6_4_2_2_sh_mask.h"
|
||||
#include "sdma7/sdma7_4_2_2_offset.h"
|
||||
#include "sdma7/sdma7_4_2_2_sh_mask.h"
|
||||
#include "v9_structs.h"
|
||||
#include "soc15.h"
|
||||
#include "soc15d.h"
|
||||
#include "amdgpu_amdkfd_gfx_v9.h"
|
||||
|
||||
#define HQD_N_REGS 56
|
||||
#define DUMP_REG(addr) do { \
|
||||
if (WARN_ON_ONCE(i >= HQD_N_REGS)) \
|
||||
break; \
|
||||
(*dump)[i][0] = (addr) << 2; \
|
||||
(*dump)[i++][1] = RREG32(addr); \
|
||||
} while (0)
|
||||
|
||||
static inline struct amdgpu_device *get_amdgpu_device(struct kgd_dev *kgd)
|
||||
{
|
||||
return (struct amdgpu_device *)kgd;
|
||||
}
|
||||
|
||||
static inline struct v9_sdma_mqd *get_sdma_mqd(void *mqd)
|
||||
{
|
||||
return (struct v9_sdma_mqd *)mqd;
|
||||
}
|
||||
|
||||
static uint32_t get_sdma_base_addr(struct amdgpu_device *adev,
|
||||
unsigned int engine_id,
|
||||
unsigned int queue_id)
|
||||
{
|
||||
uint32_t 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 retval;
|
||||
|
||||
retval = base[engine_id] + queue_id * (mmSDMA0_RLC1_RB_CNTL -
|
||||
mmSDMA0_RLC0_RB_CNTL);
|
||||
|
||||
pr_debug("sdma base address: 0x%x\n", retval);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static u32 sdma_v4_0_get_reg_offset(struct amdgpu_device *adev,
|
||||
u32 instance, u32 offset)
|
||||
{
|
||||
switch (instance) {
|
||||
case 0:
|
||||
return (adev->reg_offset[SDMA0_HWIP][0][0] + offset);
|
||||
case 1:
|
||||
return (adev->reg_offset[SDMA1_HWIP][0][1] + offset);
|
||||
case 2:
|
||||
return (adev->reg_offset[SDMA2_HWIP][0][1] + offset);
|
||||
case 3:
|
||||
return (adev->reg_offset[SDMA3_HWIP][0][1] + offset);
|
||||
case 4:
|
||||
return (adev->reg_offset[SDMA4_HWIP][0][1] + offset);
|
||||
case 5:
|
||||
return (adev->reg_offset[SDMA5_HWIP][0][1] + offset);
|
||||
case 6:
|
||||
return (adev->reg_offset[SDMA6_HWIP][0][1] + offset);
|
||||
case 7:
|
||||
return (adev->reg_offset[SDMA7_HWIP][0][1] + offset);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kgd_hqd_sdma_load(struct kgd_dev *kgd, void *mqd,
|
||||
uint32_t __user *wptr, struct mm_struct *mm)
|
||||
{
|
||||
struct amdgpu_device *adev = get_amdgpu_device(kgd);
|
||||
struct v9_sdma_mqd *m;
|
||||
uint32_t sdma_base_addr, sdmax_gfx_context_cntl;
|
||||
unsigned long end_jiffies;
|
||||
uint32_t data;
|
||||
uint64_t data64;
|
||||
uint64_t __user *wptr64 = (uint64_t __user *)wptr;
|
||||
|
||||
m = get_sdma_mqd(mqd);
|
||||
sdma_base_addr = get_sdma_base_addr(adev, m->sdma_engine_id,
|
||||
m->sdma_queue_id);
|
||||
sdmax_gfx_context_cntl = sdma_v4_0_get_reg_offset(adev,
|
||||
m->sdma_engine_id, mmSDMA0_GFX_CONTEXT_CNTL);
|
||||
|
||||
WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_CNTL,
|
||||
m->sdmax_rlcx_rb_cntl & (~SDMA0_RLC0_RB_CNTL__RB_ENABLE_MASK));
|
||||
|
||||
end_jiffies = msecs_to_jiffies(2000) + jiffies;
|
||||
while (true) {
|
||||
data = RREG32(sdma_base_addr + mmSDMA0_RLC0_CONTEXT_STATUS);
|
||||
if (data & SDMA0_RLC0_CONTEXT_STATUS__IDLE_MASK)
|
||||
break;
|
||||
if (time_after(jiffies, end_jiffies))
|
||||
return -ETIME;
|
||||
usleep_range(500, 1000);
|
||||
}
|
||||
data = RREG32(sdmax_gfx_context_cntl);
|
||||
data = REG_SET_FIELD(data, SDMA0_GFX_CONTEXT_CNTL,
|
||||
RESUME_CTX, 0);
|
||||
WREG32(sdmax_gfx_context_cntl, data);
|
||||
|
||||
WREG32(sdma_base_addr + mmSDMA0_RLC0_DOORBELL_OFFSET,
|
||||
m->sdmax_rlcx_doorbell_offset);
|
||||
|
||||
data = REG_SET_FIELD(m->sdmax_rlcx_doorbell, SDMA0_RLC0_DOORBELL,
|
||||
ENABLE, 1);
|
||||
WREG32(sdma_base_addr + mmSDMA0_RLC0_DOORBELL, data);
|
||||
WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_RPTR, m->sdmax_rlcx_rb_rptr);
|
||||
WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_RPTR_HI,
|
||||
m->sdmax_rlcx_rb_rptr_hi);
|
||||
|
||||
WREG32(sdma_base_addr + mmSDMA0_RLC0_MINOR_PTR_UPDATE, 1);
|
||||
if (read_user_wptr(mm, wptr64, data64)) {
|
||||
WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_WPTR,
|
||||
lower_32_bits(data64));
|
||||
WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_WPTR_HI,
|
||||
upper_32_bits(data64));
|
||||
} else {
|
||||
WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_WPTR,
|
||||
m->sdmax_rlcx_rb_rptr);
|
||||
WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_WPTR_HI,
|
||||
m->sdmax_rlcx_rb_rptr_hi);
|
||||
}
|
||||
WREG32(sdma_base_addr + mmSDMA0_RLC0_MINOR_PTR_UPDATE, 0);
|
||||
|
||||
WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_BASE, m->sdmax_rlcx_rb_base);
|
||||
WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_BASE_HI,
|
||||
m->sdmax_rlcx_rb_base_hi);
|
||||
WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_RPTR_ADDR_LO,
|
||||
m->sdmax_rlcx_rb_rptr_addr_lo);
|
||||
WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_RPTR_ADDR_HI,
|
||||
m->sdmax_rlcx_rb_rptr_addr_hi);
|
||||
|
||||
data = REG_SET_FIELD(m->sdmax_rlcx_rb_cntl, SDMA0_RLC0_RB_CNTL,
|
||||
RB_ENABLE, 1);
|
||||
WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_CNTL, data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kgd_hqd_sdma_dump(struct kgd_dev *kgd,
|
||||
uint32_t engine_id, uint32_t queue_id,
|
||||
uint32_t (**dump)[2], uint32_t *n_regs)
|
||||
{
|
||||
struct amdgpu_device *adev = get_amdgpu_device(kgd);
|
||||
uint32_t sdma_base_addr = get_sdma_base_addr(adev, engine_id, queue_id);
|
||||
uint32_t i = 0, reg;
|
||||
#undef HQD_N_REGS
|
||||
#define HQD_N_REGS (19+6+7+10)
|
||||
|
||||
*dump = kmalloc_array(HQD_N_REGS * 2, sizeof(uint32_t), GFP_KERNEL);
|
||||
if (*dump == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
for (reg = mmSDMA0_RLC0_RB_CNTL; reg <= mmSDMA0_RLC0_DOORBELL; reg++)
|
||||
DUMP_REG(sdma_base_addr + reg);
|
||||
for (reg = mmSDMA0_RLC0_STATUS; reg <= mmSDMA0_RLC0_CSA_ADDR_HI; reg++)
|
||||
DUMP_REG(sdma_base_addr + reg);
|
||||
for (reg = mmSDMA0_RLC0_IB_SUB_REMAIN;
|
||||
reg <= mmSDMA0_RLC0_MINOR_PTR_UPDATE; reg++)
|
||||
DUMP_REG(sdma_base_addr + reg);
|
||||
for (reg = mmSDMA0_RLC0_MIDCMD_DATA0;
|
||||
reg <= mmSDMA0_RLC0_MIDCMD_CNTL; reg++)
|
||||
DUMP_REG(sdma_base_addr + reg);
|
||||
|
||||
WARN_ON_ONCE(i != HQD_N_REGS);
|
||||
*n_regs = i;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool kgd_hqd_sdma_is_occupied(struct kgd_dev *kgd, void *mqd)
|
||||
{
|
||||
struct amdgpu_device *adev = get_amdgpu_device(kgd);
|
||||
struct v9_sdma_mqd *m;
|
||||
uint32_t sdma_base_addr;
|
||||
uint32_t sdma_rlc_rb_cntl;
|
||||
|
||||
m = get_sdma_mqd(mqd);
|
||||
sdma_base_addr = get_sdma_base_addr(adev, m->sdma_engine_id,
|
||||
m->sdma_queue_id);
|
||||
|
||||
sdma_rlc_rb_cntl = RREG32(sdma_base_addr + mmSDMA0_RLC0_RB_CNTL);
|
||||
|
||||
if (sdma_rlc_rb_cntl & SDMA0_RLC0_RB_CNTL__RB_ENABLE_MASK)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int kgd_hqd_sdma_destroy(struct kgd_dev *kgd, void *mqd,
|
||||
unsigned int utimeout)
|
||||
{
|
||||
struct amdgpu_device *adev = get_amdgpu_device(kgd);
|
||||
struct v9_sdma_mqd *m;
|
||||
uint32_t sdma_base_addr;
|
||||
uint32_t temp;
|
||||
unsigned long end_jiffies = (utimeout * HZ / 1000) + jiffies;
|
||||
|
||||
m = get_sdma_mqd(mqd);
|
||||
sdma_base_addr = get_sdma_base_addr(adev, m->sdma_engine_id,
|
||||
m->sdma_queue_id);
|
||||
|
||||
temp = RREG32(sdma_base_addr + mmSDMA0_RLC0_RB_CNTL);
|
||||
temp = temp & ~SDMA0_RLC0_RB_CNTL__RB_ENABLE_MASK;
|
||||
WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_CNTL, temp);
|
||||
|
||||
while (true) {
|
||||
temp = RREG32(sdma_base_addr + mmSDMA0_RLC0_CONTEXT_STATUS);
|
||||
if (temp & SDMA0_RLC0_CONTEXT_STATUS__IDLE_MASK)
|
||||
break;
|
||||
if (time_after(jiffies, end_jiffies))
|
||||
return -ETIME;
|
||||
usleep_range(500, 1000);
|
||||
}
|
||||
|
||||
WREG32(sdma_base_addr + mmSDMA0_RLC0_DOORBELL, 0);
|
||||
WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_CNTL,
|
||||
RREG32(sdma_base_addr + mmSDMA0_RLC0_RB_CNTL) |
|
||||
SDMA0_RLC0_RB_CNTL__RB_ENABLE_MASK);
|
||||
|
||||
m->sdmax_rlcx_rb_rptr = RREG32(sdma_base_addr + mmSDMA0_RLC0_RB_RPTR);
|
||||
m->sdmax_rlcx_rb_rptr_hi =
|
||||
RREG32(sdma_base_addr + mmSDMA0_RLC0_RB_RPTR_HI);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct kfd2kgd_calls 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,
|
||||
.hqd_sdma_load = kgd_hqd_sdma_load,
|
||||
.hqd_dump = kgd_gfx_v9_hqd_dump,
|
||||
.hqd_sdma_dump = kgd_hqd_sdma_dump,
|
||||
.hqd_is_occupied = kgd_gfx_v9_hqd_is_occupied,
|
||||
.hqd_sdma_is_occupied = kgd_hqd_sdma_is_occupied,
|
||||
.hqd_destroy = kgd_gfx_v9_hqd_destroy,
|
||||
.hqd_sdma_destroy = kgd_hqd_sdma_destroy,
|
||||
.address_watch_disable = kgd_gfx_v9_address_watch_disable,
|
||||
.address_watch_execute = kgd_gfx_v9_address_watch_execute,
|
||||
.wave_control_execute = kgd_gfx_v9_wave_control_execute,
|
||||
.address_watch_get_offset = kgd_gfx_v9_address_watch_get_offset,
|
||||
.get_atc_vmid_pasid_mapping_pasid =
|
||||
kgd_gfx_v9_get_atc_vmid_pasid_mapping_pasid,
|
||||
.get_atc_vmid_pasid_mapping_valid =
|
||||
kgd_gfx_v9_get_atc_vmid_pasid_mapping_valid,
|
||||
.set_scratch_backing_va = kgd_gfx_v9_set_scratch_backing_va,
|
||||
.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,
|
||||
};
|
||||
|
||||
struct kfd2kgd_calls *amdgpu_amdkfd_arcturus_get_functions(void)
|
||||
{
|
||||
return (struct kfd2kgd_calls *)&kfd2kgd;
|
||||
}
|
||||
|
@ -27,7 +27,6 @@
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/mmu_context.h>
|
||||
#include <drm/drmP.h>
|
||||
#include "amdgpu.h"
|
||||
#include "amdgpu_amdkfd.h"
|
||||
#include "amdgpu_ucode.h"
|
||||
@ -802,42 +801,6 @@ static uint16_t get_atc_vmid_pasid_mapping_pasid(struct kgd_dev *kgd,
|
||||
return reg & ATC_VMID0_PASID_MAPPING__PASID_MASK;
|
||||
}
|
||||
|
||||
static void write_vmid_invalidate_request(struct kgd_dev *kgd, uint8_t vmid)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *) kgd;
|
||||
uint32_t req = (1 << vmid) |
|
||||
(0 << GCVM_INVALIDATE_ENG0_REQ__FLUSH_TYPE__SHIFT) |/* legacy */
|
||||
GCVM_INVALIDATE_ENG0_REQ__INVALIDATE_L2_PTES_MASK |
|
||||
GCVM_INVALIDATE_ENG0_REQ__INVALIDATE_L2_PDE0_MASK |
|
||||
GCVM_INVALIDATE_ENG0_REQ__INVALIDATE_L2_PDE1_MASK |
|
||||
GCVM_INVALIDATE_ENG0_REQ__INVALIDATE_L2_PDE2_MASK |
|
||||
GCVM_INVALIDATE_ENG0_REQ__INVALIDATE_L1_PTES_MASK;
|
||||
|
||||
mutex_lock(&adev->srbm_mutex);
|
||||
|
||||
/* Use light weight invalidation.
|
||||
*
|
||||
* TODO 1: agree on the right set of invalidation registers for
|
||||
* KFD use. Use the last one for now. Invalidate only GCHUB as
|
||||
* SDMA is now moved to GCHUB
|
||||
*
|
||||
* TODO 2: support range-based invalidation, requires kfg2kgd
|
||||
* interface change
|
||||
*/
|
||||
WREG32(SOC15_REG_OFFSET(GC, 0, mmGCVM_INVALIDATE_ENG0_ADDR_RANGE_LO32),
|
||||
0xffffffff);
|
||||
WREG32(SOC15_REG_OFFSET(GC, 0, mmGCVM_INVALIDATE_ENG0_ADDR_RANGE_HI32),
|
||||
0x0000001f);
|
||||
|
||||
WREG32(SOC15_REG_OFFSET(GC, 0, mmGCVM_INVALIDATE_ENG0_REQ), req);
|
||||
|
||||
while (!(RREG32(SOC15_REG_OFFSET(GC, 0, mmGCVM_INVALIDATE_ENG0_ACK)) &
|
||||
(1 << vmid)))
|
||||
cpu_relax();
|
||||
|
||||
mutex_unlock(&adev->srbm_mutex);
|
||||
}
|
||||
|
||||
static int invalidate_tlbs_with_kiq(struct amdgpu_device *adev, uint16_t pasid)
|
||||
{
|
||||
signed long r;
|
||||
@ -878,7 +841,8 @@ static int invalidate_tlbs(struct kgd_dev *kgd, uint16_t pasid)
|
||||
if (get_atc_vmid_pasid_mapping_valid(kgd, vmid)) {
|
||||
if (get_atc_vmid_pasid_mapping_pasid(kgd, vmid)
|
||||
== pasid) {
|
||||
write_vmid_invalidate_request(kgd, vmid);
|
||||
amdgpu_gmc_flush_gpu_tlb(adev, vmid,
|
||||
AMDGPU_GFXHUB_0, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -896,7 +860,7 @@ static int invalidate_tlbs_vmid(struct kgd_dev *kgd, uint16_t vmid)
|
||||
return 0;
|
||||
}
|
||||
|
||||
write_vmid_invalidate_request(kgd, vmid);
|
||||
amdgpu_gmc_flush_gpu_tlb(adev, vmid, AMDGPU_GFXHUB_0, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -47,6 +47,7 @@
|
||||
#include "soc15d.h"
|
||||
#include "mmhub_v1_0.h"
|
||||
#include "gfxhub_v1_0.h"
|
||||
#include "gmc_v9_0.h"
|
||||
|
||||
|
||||
#define V9_PIPE_PER_MEC (4)
|
||||
@ -58,66 +59,11 @@ enum hqd_dequeue_request_type {
|
||||
RESET_WAVES
|
||||
};
|
||||
|
||||
/*
|
||||
* Register access functions
|
||||
*/
|
||||
|
||||
static void kgd_program_sh_mem_settings(struct kgd_dev *kgd, uint32_t vmid,
|
||||
uint32_t sh_mem_config,
|
||||
uint32_t sh_mem_ape1_base, uint32_t sh_mem_ape1_limit,
|
||||
uint32_t sh_mem_bases);
|
||||
static int kgd_set_pasid_vmid_mapping(struct kgd_dev *kgd, unsigned int pasid,
|
||||
unsigned int vmid);
|
||||
static int kgd_init_interrupts(struct kgd_dev *kgd, uint32_t pipe_id);
|
||||
static int kgd_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);
|
||||
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);
|
||||
static int kgd_hqd_sdma_load(struct kgd_dev *kgd, void *mqd,
|
||||
uint32_t __user *wptr, struct mm_struct *mm);
|
||||
static int kgd_hqd_sdma_dump(struct kgd_dev *kgd,
|
||||
uint32_t engine_id, uint32_t queue_id,
|
||||
uint32_t (**dump)[2], uint32_t *n_regs);
|
||||
static bool kgd_hqd_is_occupied(struct kgd_dev *kgd, uint64_t queue_address,
|
||||
uint32_t pipe_id, uint32_t queue_id);
|
||||
static bool kgd_hqd_sdma_is_occupied(struct kgd_dev *kgd, void *mqd);
|
||||
static int kgd_hqd_destroy(struct kgd_dev *kgd, void *mqd,
|
||||
enum kfd_preempt_type reset_type,
|
||||
unsigned int utimeout, uint32_t pipe_id,
|
||||
uint32_t queue_id);
|
||||
static int kgd_hqd_sdma_destroy(struct kgd_dev *kgd, void *mqd,
|
||||
unsigned int utimeout);
|
||||
static int kgd_address_watch_disable(struct kgd_dev *kgd);
|
||||
static int kgd_address_watch_execute(struct kgd_dev *kgd,
|
||||
unsigned int watch_point_id,
|
||||
uint32_t cntl_val,
|
||||
uint32_t addr_hi,
|
||||
uint32_t addr_lo);
|
||||
static int kgd_wave_control_execute(struct kgd_dev *kgd,
|
||||
uint32_t gfx_index_val,
|
||||
uint32_t sq_cmd);
|
||||
static uint32_t kgd_address_watch_get_offset(struct kgd_dev *kgd,
|
||||
unsigned int watch_point_id,
|
||||
unsigned int reg_offset);
|
||||
|
||||
static bool get_atc_vmid_pasid_mapping_valid(struct kgd_dev *kgd,
|
||||
uint8_t vmid);
|
||||
static uint16_t get_atc_vmid_pasid_mapping_pasid(struct kgd_dev *kgd,
|
||||
uint8_t vmid);
|
||||
static void set_vm_context_page_table_base(struct kgd_dev *kgd, uint32_t vmid,
|
||||
uint64_t page_table_base);
|
||||
static void set_scratch_backing_va(struct kgd_dev *kgd,
|
||||
uint64_t va, uint32_t vmid);
|
||||
static int invalidate_tlbs(struct kgd_dev *kgd, uint16_t pasid);
|
||||
static int invalidate_tlbs_vmid(struct kgd_dev *kgd, uint16_t vmid);
|
||||
|
||||
/* Because of REG_GET_FIELD() being used, we put this function in the
|
||||
* asic specific file.
|
||||
*/
|
||||
static int amdgpu_amdkfd_get_tile_config(struct kgd_dev *kgd,
|
||||
int kgd_gfx_v9_get_tile_config(struct kgd_dev *kgd,
|
||||
struct tile_config *config)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)kgd;
|
||||
@ -135,39 +81,6 @@ static int amdgpu_amdkfd_get_tile_config(struct kgd_dev *kgd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct kfd2kgd_calls kfd2kgd = {
|
||||
.program_sh_mem_settings = kgd_program_sh_mem_settings,
|
||||
.set_pasid_vmid_mapping = kgd_set_pasid_vmid_mapping,
|
||||
.init_interrupts = kgd_init_interrupts,
|
||||
.hqd_load = kgd_hqd_load,
|
||||
.hqd_sdma_load = kgd_hqd_sdma_load,
|
||||
.hqd_dump = kgd_hqd_dump,
|
||||
.hqd_sdma_dump = kgd_hqd_sdma_dump,
|
||||
.hqd_is_occupied = kgd_hqd_is_occupied,
|
||||
.hqd_sdma_is_occupied = kgd_hqd_sdma_is_occupied,
|
||||
.hqd_destroy = kgd_hqd_destroy,
|
||||
.hqd_sdma_destroy = kgd_hqd_sdma_destroy,
|
||||
.address_watch_disable = kgd_address_watch_disable,
|
||||
.address_watch_execute = kgd_address_watch_execute,
|
||||
.wave_control_execute = kgd_wave_control_execute,
|
||||
.address_watch_get_offset = kgd_address_watch_get_offset,
|
||||
.get_atc_vmid_pasid_mapping_pasid =
|
||||
get_atc_vmid_pasid_mapping_pasid,
|
||||
.get_atc_vmid_pasid_mapping_valid =
|
||||
get_atc_vmid_pasid_mapping_valid,
|
||||
.set_scratch_backing_va = set_scratch_backing_va,
|
||||
.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,
|
||||
};
|
||||
|
||||
struct kfd2kgd_calls *amdgpu_amdkfd_gfx_9_0_get_functions(void)
|
||||
{
|
||||
return (struct kfd2kgd_calls *)&kfd2kgd;
|
||||
}
|
||||
|
||||
static inline struct amdgpu_device *get_amdgpu_device(struct kgd_dev *kgd)
|
||||
{
|
||||
return (struct amdgpu_device *)kgd;
|
||||
@ -215,7 +128,7 @@ static void release_queue(struct kgd_dev *kgd)
|
||||
unlock_srbm(kgd);
|
||||
}
|
||||
|
||||
static void kgd_program_sh_mem_settings(struct kgd_dev *kgd, uint32_t vmid,
|
||||
void kgd_gfx_v9_program_sh_mem_settings(struct kgd_dev *kgd, uint32_t vmid,
|
||||
uint32_t sh_mem_config,
|
||||
uint32_t sh_mem_ape1_base,
|
||||
uint32_t sh_mem_ape1_limit,
|
||||
@ -232,7 +145,7 @@ static void kgd_program_sh_mem_settings(struct kgd_dev *kgd, uint32_t vmid,
|
||||
unlock_srbm(kgd);
|
||||
}
|
||||
|
||||
static int kgd_set_pasid_vmid_mapping(struct kgd_dev *kgd, unsigned int pasid,
|
||||
int kgd_gfx_v9_set_pasid_vmid_mapping(struct kgd_dev *kgd, unsigned int pasid,
|
||||
unsigned int vmid)
|
||||
{
|
||||
struct amdgpu_device *adev = get_amdgpu_device(kgd);
|
||||
@ -293,7 +206,7 @@ static int kgd_set_pasid_vmid_mapping(struct kgd_dev *kgd, unsigned int pasid,
|
||||
* but still works
|
||||
*/
|
||||
|
||||
static int kgd_init_interrupts(struct kgd_dev *kgd, uint32_t pipe_id)
|
||||
int kgd_gfx_v9_init_interrupts(struct kgd_dev *kgd, uint32_t pipe_id)
|
||||
{
|
||||
struct amdgpu_device *adev = get_amdgpu_device(kgd);
|
||||
uint32_t mec;
|
||||
@ -343,7 +256,7 @@ static inline struct v9_sdma_mqd *get_sdma_mqd(void *mqd)
|
||||
return (struct v9_sdma_mqd *)mqd;
|
||||
}
|
||||
|
||||
static int kgd_hqd_load(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id,
|
||||
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)
|
||||
@ -438,7 +351,7 @@ static int kgd_hqd_load(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kgd_hqd_dump(struct kgd_dev *kgd,
|
||||
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)
|
||||
{
|
||||
@ -575,7 +488,7 @@ static int kgd_hqd_sdma_dump(struct kgd_dev *kgd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool kgd_hqd_is_occupied(struct kgd_dev *kgd, uint64_t queue_address,
|
||||
bool kgd_gfx_v9_hqd_is_occupied(struct kgd_dev *kgd, uint64_t queue_address,
|
||||
uint32_t pipe_id, uint32_t queue_id)
|
||||
{
|
||||
struct amdgpu_device *adev = get_amdgpu_device(kgd);
|
||||
@ -616,7 +529,7 @@ static bool kgd_hqd_sdma_is_occupied(struct kgd_dev *kgd, void *mqd)
|
||||
return false;
|
||||
}
|
||||
|
||||
static int kgd_hqd_destroy(struct kgd_dev *kgd, void *mqd,
|
||||
int kgd_gfx_v9_hqd_destroy(struct kgd_dev *kgd, void *mqd,
|
||||
enum kfd_preempt_type reset_type,
|
||||
unsigned int utimeout, uint32_t pipe_id,
|
||||
uint32_t queue_id)
|
||||
@ -704,7 +617,7 @@ static int kgd_hqd_sdma_destroy(struct kgd_dev *kgd, void *mqd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool get_atc_vmid_pasid_mapping_valid(struct kgd_dev *kgd,
|
||||
bool kgd_gfx_v9_get_atc_vmid_pasid_mapping_valid(struct kgd_dev *kgd,
|
||||
uint8_t vmid)
|
||||
{
|
||||
uint32_t reg;
|
||||
@ -715,7 +628,7 @@ static bool get_atc_vmid_pasid_mapping_valid(struct kgd_dev *kgd,
|
||||
return reg & ATC_VMID0_PASID_MAPPING__VALID_MASK;
|
||||
}
|
||||
|
||||
static uint16_t get_atc_vmid_pasid_mapping_pasid(struct kgd_dev *kgd,
|
||||
uint16_t kgd_gfx_v9_get_atc_vmid_pasid_mapping_pasid(struct kgd_dev *kgd,
|
||||
uint8_t vmid)
|
||||
{
|
||||
uint32_t reg;
|
||||
@ -754,10 +667,10 @@ static int invalidate_tlbs_with_kiq(struct amdgpu_device *adev, uint16_t pasid,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int invalidate_tlbs(struct kgd_dev *kgd, uint16_t pasid)
|
||||
int kgd_gfx_v9_invalidate_tlbs(struct kgd_dev *kgd, uint16_t pasid)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *) kgd;
|
||||
int vmid;
|
||||
int vmid, i;
|
||||
struct amdgpu_ring *ring = &adev->gfx.kiq.ring;
|
||||
uint32_t flush_type = 0;
|
||||
|
||||
@ -773,11 +686,12 @@ static int invalidate_tlbs(struct kgd_dev *kgd, uint16_t pasid)
|
||||
for (vmid = 0; vmid < 16; vmid++) {
|
||||
if (!amdgpu_amdkfd_is_kfd_vmid(adev, vmid))
|
||||
continue;
|
||||
if (get_atc_vmid_pasid_mapping_valid(kgd, vmid)) {
|
||||
if (get_atc_vmid_pasid_mapping_pasid(kgd, vmid)
|
||||
if (kgd_gfx_v9_get_atc_vmid_pasid_mapping_valid(kgd, vmid)) {
|
||||
if (kgd_gfx_v9_get_atc_vmid_pasid_mapping_pasid(kgd, vmid)
|
||||
== pasid) {
|
||||
amdgpu_gmc_flush_gpu_tlb(adev, vmid,
|
||||
flush_type);
|
||||
for (i = 0; i < adev->num_vmhubs; i++)
|
||||
amdgpu_gmc_flush_gpu_tlb(adev, vmid,
|
||||
i, flush_type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -786,9 +700,10 @@ static int invalidate_tlbs(struct kgd_dev *kgd, uint16_t pasid)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int invalidate_tlbs_vmid(struct kgd_dev *kgd, uint16_t vmid)
|
||||
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);
|
||||
@ -810,16 +725,18 @@ static int invalidate_tlbs_vmid(struct kgd_dev *kgd, uint16_t vmid)
|
||||
* TODO 2: support range-based invalidation, requires kfg2kgd
|
||||
* interface change
|
||||
*/
|
||||
amdgpu_gmc_flush_gpu_tlb(adev, vmid, 0);
|
||||
for (i = 0; i < adev->num_vmhubs; i++)
|
||||
amdgpu_gmc_flush_gpu_tlb(adev, vmid, i, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kgd_address_watch_disable(struct kgd_dev *kgd)
|
||||
int kgd_gfx_v9_address_watch_disable(struct kgd_dev *kgd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kgd_address_watch_execute(struct kgd_dev *kgd,
|
||||
int kgd_gfx_v9_address_watch_execute(struct kgd_dev *kgd,
|
||||
unsigned int watch_point_id,
|
||||
uint32_t cntl_val,
|
||||
uint32_t addr_hi,
|
||||
@ -828,7 +745,7 @@ static int kgd_address_watch_execute(struct kgd_dev *kgd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kgd_wave_control_execute(struct kgd_dev *kgd,
|
||||
int kgd_gfx_v9_wave_control_execute(struct kgd_dev *kgd,
|
||||
uint32_t gfx_index_val,
|
||||
uint32_t sq_cmd)
|
||||
{
|
||||
@ -853,14 +770,14 @@ static int kgd_wave_control_execute(struct kgd_dev *kgd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t kgd_address_watch_get_offset(struct kgd_dev *kgd,
|
||||
uint32_t kgd_gfx_v9_address_watch_get_offset(struct kgd_dev *kgd,
|
||||
unsigned int watch_point_id,
|
||||
unsigned int reg_offset)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void set_scratch_backing_va(struct kgd_dev *kgd,
|
||||
void kgd_gfx_v9_set_scratch_backing_va(struct kgd_dev *kgd,
|
||||
uint64_t va, uint32_t vmid)
|
||||
{
|
||||
/* No longer needed on GFXv9. The scratch base address is
|
||||
@ -869,7 +786,7 @@ static void set_scratch_backing_va(struct kgd_dev *kgd,
|
||||
*/
|
||||
}
|
||||
|
||||
static void set_vm_context_page_table_base(struct kgd_dev *kgd, uint32_t vmid,
|
||||
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);
|
||||
@ -884,7 +801,45 @@ static void set_vm_context_page_table_base(struct kgd_dev *kgd, uint32_t vmid,
|
||||
* now, all processes share the same address space size, like
|
||||
* on GFX8 and older.
|
||||
*/
|
||||
mmhub_v1_0_setup_vm_pt_regs(adev, vmid, page_table_base);
|
||||
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);
|
||||
|
||||
gfxhub_v1_0_setup_vm_pt_regs(adev, vmid, page_table_base);
|
||||
}
|
||||
|
||||
static const struct kfd2kgd_calls 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,
|
||||
.hqd_sdma_load = kgd_hqd_sdma_load,
|
||||
.hqd_dump = kgd_gfx_v9_hqd_dump,
|
||||
.hqd_sdma_dump = kgd_hqd_sdma_dump,
|
||||
.hqd_is_occupied = kgd_gfx_v9_hqd_is_occupied,
|
||||
.hqd_sdma_is_occupied = kgd_hqd_sdma_is_occupied,
|
||||
.hqd_destroy = kgd_gfx_v9_hqd_destroy,
|
||||
.hqd_sdma_destroy = kgd_hqd_sdma_destroy,
|
||||
.address_watch_disable = kgd_gfx_v9_address_watch_disable,
|
||||
.address_watch_execute = kgd_gfx_v9_address_watch_execute,
|
||||
.wave_control_execute = kgd_gfx_v9_wave_control_execute,
|
||||
.address_watch_get_offset = kgd_gfx_v9_address_watch_get_offset,
|
||||
.get_atc_vmid_pasid_mapping_pasid =
|
||||
kgd_gfx_v9_get_atc_vmid_pasid_mapping_pasid,
|
||||
.get_atc_vmid_pasid_mapping_valid =
|
||||
kgd_gfx_v9_get_atc_vmid_pasid_mapping_valid,
|
||||
.set_scratch_backing_va = kgd_gfx_v9_set_scratch_backing_va,
|
||||
.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,
|
||||
};
|
||||
|
||||
struct kfd2kgd_calls *amdgpu_amdkfd_gfx_9_0_get_functions(void)
|
||||
{
|
||||
return (struct kfd2kgd_calls *)&kfd2kgd;
|
||||
}
|
||||
|
69
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.h
Normal file
69
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.h
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2019 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.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
void kgd_gfx_v9_program_sh_mem_settings(struct kgd_dev *kgd, uint32_t vmid,
|
||||
uint32_t sh_mem_config,
|
||||
uint32_t sh_mem_ape1_base, uint32_t sh_mem_ape1_limit,
|
||||
uint32_t sh_mem_bases);
|
||||
int kgd_gfx_v9_set_pasid_vmid_mapping(struct kgd_dev *kgd, unsigned int pasid,
|
||||
unsigned int vmid);
|
||||
int kgd_gfx_v9_init_interrupts(struct kgd_dev *kgd, uint32_t pipe_id);
|
||||
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_hqd_dump(struct kgd_dev *kgd,
|
||||
uint32_t pipe_id, uint32_t queue_id,
|
||||
uint32_t (**dump)[2], uint32_t *n_regs);
|
||||
bool kgd_gfx_v9_hqd_is_occupied(struct kgd_dev *kgd, uint64_t queue_address,
|
||||
uint32_t pipe_id, uint32_t queue_id);
|
||||
int kgd_gfx_v9_hqd_destroy(struct kgd_dev *kgd, void *mqd,
|
||||
enum kfd_preempt_type reset_type,
|
||||
unsigned int utimeout, uint32_t pipe_id,
|
||||
uint32_t queue_id);
|
||||
int kgd_gfx_v9_address_watch_disable(struct kgd_dev *kgd);
|
||||
int kgd_gfx_v9_address_watch_execute(struct kgd_dev *kgd,
|
||||
unsigned int watch_point_id,
|
||||
uint32_t cntl_val,
|
||||
uint32_t addr_hi,
|
||||
uint32_t addr_lo);
|
||||
int kgd_gfx_v9_wave_control_execute(struct kgd_dev *kgd,
|
||||
uint32_t gfx_index_val,
|
||||
uint32_t sq_cmd);
|
||||
uint32_t kgd_gfx_v9_address_watch_get_offset(struct kgd_dev *kgd,
|
||||
unsigned int watch_point_id,
|
||||
unsigned int reg_offset);
|
||||
|
||||
bool kgd_gfx_v9_get_atc_vmid_pasid_mapping_valid(struct kgd_dev *kgd,
|
||||
uint8_t vmid);
|
||||
uint16_t kgd_gfx_v9_get_atc_vmid_pasid_mapping_pasid(struct kgd_dev *kgd,
|
||||
uint8_t vmid);
|
||||
void kgd_gfx_v9_set_vm_context_page_table_base(struct kgd_dev *kgd, uint32_t vmid,
|
||||
uint64_t page_table_base);
|
||||
void kgd_gfx_v9_set_scratch_backing_va(struct kgd_dev *kgd,
|
||||
uint64_t va, uint32_t vmid);
|
||||
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);
|
@ -218,14 +218,14 @@ void amdgpu_amdkfd_unreserve_memory_limit(struct amdgpu_bo *bo)
|
||||
static int amdgpu_amdkfd_remove_eviction_fence(struct amdgpu_bo *bo,
|
||||
struct amdgpu_amdkfd_fence *ef)
|
||||
{
|
||||
struct reservation_object *resv = bo->tbo.resv;
|
||||
struct reservation_object_list *old, *new;
|
||||
struct dma_resv *resv = bo->tbo.base.resv;
|
||||
struct dma_resv_list *old, *new;
|
||||
unsigned int i, j, k;
|
||||
|
||||
if (!ef)
|
||||
return -EINVAL;
|
||||
|
||||
old = reservation_object_get_list(resv);
|
||||
old = dma_resv_get_list(resv);
|
||||
if (!old)
|
||||
return 0;
|
||||
|
||||
@ -241,7 +241,7 @@ static int amdgpu_amdkfd_remove_eviction_fence(struct amdgpu_bo *bo,
|
||||
struct dma_fence *f;
|
||||
|
||||
f = rcu_dereference_protected(old->shared[i],
|
||||
reservation_object_held(resv));
|
||||
dma_resv_held(resv));
|
||||
|
||||
if (f->context == ef->base.context)
|
||||
RCU_INIT_POINTER(new->shared[--j], f);
|
||||
@ -263,7 +263,7 @@ static int amdgpu_amdkfd_remove_eviction_fence(struct amdgpu_bo *bo,
|
||||
struct dma_fence *f;
|
||||
|
||||
f = rcu_dereference_protected(new->shared[i],
|
||||
reservation_object_held(resv));
|
||||
dma_resv_held(resv));
|
||||
dma_fence_put(f);
|
||||
}
|
||||
kfree_rcu(old, rcu);
|
||||
@ -812,7 +812,7 @@ static int process_sync_pds_resv(struct amdkfd_process_info *process_info,
|
||||
struct amdgpu_bo *pd = peer_vm->root.base.bo;
|
||||
|
||||
ret = amdgpu_sync_resv(NULL,
|
||||
sync, pd->tbo.resv,
|
||||
sync, pd->tbo.base.resv,
|
||||
AMDGPU_FENCE_OWNER_KFD, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -887,7 +887,7 @@ static int init_kfd_vm(struct amdgpu_vm *vm, void **process_info,
|
||||
AMDGPU_FENCE_OWNER_KFD, false);
|
||||
if (ret)
|
||||
goto wait_pd_fail;
|
||||
ret = reservation_object_reserve_shared(vm->root.base.bo->tbo.resv, 1);
|
||||
ret = dma_resv_reserve_shared(vm->root.base.bo->tbo.base.resv, 1);
|
||||
if (ret)
|
||||
goto reserve_shared_fail;
|
||||
amdgpu_bo_fence(vm->root.base.bo,
|
||||
@ -1090,7 +1090,7 @@ int amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu(
|
||||
*/
|
||||
if (flags & ALLOC_MEM_FLAGS_VRAM) {
|
||||
domain = alloc_domain = AMDGPU_GEM_DOMAIN_VRAM;
|
||||
alloc_flags = AMDGPU_GEM_CREATE_VRAM_CLEARED;
|
||||
alloc_flags = AMDGPU_GEM_CREATE_VRAM_WIPE_ON_RELEASE;
|
||||
alloc_flags |= (flags & ALLOC_MEM_FLAGS_PUBLIC) ?
|
||||
AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED :
|
||||
AMDGPU_GEM_CREATE_NO_CPU_ACCESS;
|
||||
@ -2133,7 +2133,7 @@ int amdgpu_amdkfd_add_gws_to_process(void *info, void *gws, struct kgd_mem **mem
|
||||
* Add process eviction fence to bo so they can
|
||||
* evict each other.
|
||||
*/
|
||||
ret = reservation_object_reserve_shared(gws_bo->tbo.resv, 1);
|
||||
ret = dma_resv_reserve_shared(gws_bo->tbo.base.resv, 1);
|
||||
if (ret)
|
||||
goto reserve_shared_fail;
|
||||
amdgpu_bo_fence(gws_bo, &process_info->eviction_fence->base, true);
|
||||
|
@ -1505,6 +1505,7 @@ amdgpu_connector_add(struct amdgpu_device *adev,
|
||||
struct amdgpu_connector_atom_dig *amdgpu_dig_connector;
|
||||
struct drm_encoder *encoder;
|
||||
struct amdgpu_encoder *amdgpu_encoder;
|
||||
struct i2c_adapter *ddc = NULL;
|
||||
uint32_t subpixel_order = SubPixelNone;
|
||||
bool shared_ddc = false;
|
||||
bool is_dp_bridge = false;
|
||||
@ -1574,17 +1575,21 @@ amdgpu_connector_add(struct amdgpu_device *adev,
|
||||
amdgpu_connector->con_priv = amdgpu_dig_connector;
|
||||
if (i2c_bus->valid) {
|
||||
amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus);
|
||||
if (amdgpu_connector->ddc_bus)
|
||||
if (amdgpu_connector->ddc_bus) {
|
||||
has_aux = true;
|
||||
else
|
||||
ddc = &amdgpu_connector->ddc_bus->adapter;
|
||||
} else {
|
||||
DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
|
||||
}
|
||||
}
|
||||
switch (connector_type) {
|
||||
case DRM_MODE_CONNECTOR_VGA:
|
||||
case DRM_MODE_CONNECTOR_DVIA:
|
||||
default:
|
||||
drm_connector_init(dev, &amdgpu_connector->base,
|
||||
&amdgpu_connector_dp_funcs, connector_type);
|
||||
drm_connector_init_with_ddc(dev, &amdgpu_connector->base,
|
||||
&amdgpu_connector_dp_funcs,
|
||||
connector_type,
|
||||
ddc);
|
||||
drm_connector_helper_add(&amdgpu_connector->base,
|
||||
&amdgpu_connector_dp_helper_funcs);
|
||||
connector->interlace_allowed = true;
|
||||
@ -1602,8 +1607,10 @@ amdgpu_connector_add(struct amdgpu_device *adev,
|
||||
case DRM_MODE_CONNECTOR_HDMIA:
|
||||
case DRM_MODE_CONNECTOR_HDMIB:
|
||||
case DRM_MODE_CONNECTOR_DisplayPort:
|
||||
drm_connector_init(dev, &amdgpu_connector->base,
|
||||
&amdgpu_connector_dp_funcs, connector_type);
|
||||
drm_connector_init_with_ddc(dev, &amdgpu_connector->base,
|
||||
&amdgpu_connector_dp_funcs,
|
||||
connector_type,
|
||||
ddc);
|
||||
drm_connector_helper_add(&amdgpu_connector->base,
|
||||
&amdgpu_connector_dp_helper_funcs);
|
||||
drm_object_attach_property(&amdgpu_connector->base.base,
|
||||
@ -1644,8 +1651,10 @@ amdgpu_connector_add(struct amdgpu_device *adev,
|
||||
break;
|
||||
case DRM_MODE_CONNECTOR_LVDS:
|
||||
case DRM_MODE_CONNECTOR_eDP:
|
||||
drm_connector_init(dev, &amdgpu_connector->base,
|
||||
&amdgpu_connector_edp_funcs, connector_type);
|
||||
drm_connector_init_with_ddc(dev, &amdgpu_connector->base,
|
||||
&amdgpu_connector_edp_funcs,
|
||||
connector_type,
|
||||
ddc);
|
||||
drm_connector_helper_add(&amdgpu_connector->base,
|
||||
&amdgpu_connector_dp_helper_funcs);
|
||||
drm_object_attach_property(&amdgpu_connector->base.base,
|
||||
@ -1659,13 +1668,18 @@ amdgpu_connector_add(struct amdgpu_device *adev,
|
||||
} else {
|
||||
switch (connector_type) {
|
||||
case DRM_MODE_CONNECTOR_VGA:
|
||||
drm_connector_init(dev, &amdgpu_connector->base, &amdgpu_connector_vga_funcs, connector_type);
|
||||
drm_connector_helper_add(&amdgpu_connector->base, &amdgpu_connector_vga_helper_funcs);
|
||||
if (i2c_bus->valid) {
|
||||
amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus);
|
||||
if (!amdgpu_connector->ddc_bus)
|
||||
DRM_ERROR("VGA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
|
||||
else
|
||||
ddc = &amdgpu_connector->ddc_bus->adapter;
|
||||
}
|
||||
drm_connector_init_with_ddc(dev, &amdgpu_connector->base,
|
||||
&amdgpu_connector_vga_funcs,
|
||||
connector_type,
|
||||
ddc);
|
||||
drm_connector_helper_add(&amdgpu_connector->base, &amdgpu_connector_vga_helper_funcs);
|
||||
amdgpu_connector->dac_load_detect = true;
|
||||
drm_object_attach_property(&amdgpu_connector->base.base,
|
||||
adev->mode_info.load_detect_property,
|
||||
@ -1679,13 +1693,18 @@ amdgpu_connector_add(struct amdgpu_device *adev,
|
||||
connector->doublescan_allowed = true;
|
||||
break;
|
||||
case DRM_MODE_CONNECTOR_DVIA:
|
||||
drm_connector_init(dev, &amdgpu_connector->base, &amdgpu_connector_vga_funcs, connector_type);
|
||||
drm_connector_helper_add(&amdgpu_connector->base, &amdgpu_connector_vga_helper_funcs);
|
||||
if (i2c_bus->valid) {
|
||||
amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus);
|
||||
if (!amdgpu_connector->ddc_bus)
|
||||
DRM_ERROR("DVIA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
|
||||
else
|
||||
ddc = &amdgpu_connector->ddc_bus->adapter;
|
||||
}
|
||||
drm_connector_init_with_ddc(dev, &amdgpu_connector->base,
|
||||
&amdgpu_connector_vga_funcs,
|
||||
connector_type,
|
||||
ddc);
|
||||
drm_connector_helper_add(&amdgpu_connector->base, &amdgpu_connector_vga_helper_funcs);
|
||||
amdgpu_connector->dac_load_detect = true;
|
||||
drm_object_attach_property(&amdgpu_connector->base.base,
|
||||
adev->mode_info.load_detect_property,
|
||||
@ -1704,13 +1723,18 @@ amdgpu_connector_add(struct amdgpu_device *adev,
|
||||
if (!amdgpu_dig_connector)
|
||||
goto failed;
|
||||
amdgpu_connector->con_priv = amdgpu_dig_connector;
|
||||
drm_connector_init(dev, &amdgpu_connector->base, &amdgpu_connector_dvi_funcs, connector_type);
|
||||
drm_connector_helper_add(&amdgpu_connector->base, &amdgpu_connector_dvi_helper_funcs);
|
||||
if (i2c_bus->valid) {
|
||||
amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus);
|
||||
if (!amdgpu_connector->ddc_bus)
|
||||
DRM_ERROR("DVI: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
|
||||
else
|
||||
ddc = &amdgpu_connector->ddc_bus->adapter;
|
||||
}
|
||||
drm_connector_init_with_ddc(dev, &amdgpu_connector->base,
|
||||
&amdgpu_connector_dvi_funcs,
|
||||
connector_type,
|
||||
ddc);
|
||||
drm_connector_helper_add(&amdgpu_connector->base, &amdgpu_connector_dvi_helper_funcs);
|
||||
subpixel_order = SubPixelHorizontalRGB;
|
||||
drm_object_attach_property(&amdgpu_connector->base.base,
|
||||
adev->mode_info.coherent_mode_property,
|
||||
@ -1754,13 +1778,18 @@ amdgpu_connector_add(struct amdgpu_device *adev,
|
||||
if (!amdgpu_dig_connector)
|
||||
goto failed;
|
||||
amdgpu_connector->con_priv = amdgpu_dig_connector;
|
||||
drm_connector_init(dev, &amdgpu_connector->base, &amdgpu_connector_dvi_funcs, connector_type);
|
||||
drm_connector_helper_add(&amdgpu_connector->base, &amdgpu_connector_dvi_helper_funcs);
|
||||
if (i2c_bus->valid) {
|
||||
amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus);
|
||||
if (!amdgpu_connector->ddc_bus)
|
||||
DRM_ERROR("HDMI: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
|
||||
else
|
||||
ddc = &amdgpu_connector->ddc_bus->adapter;
|
||||
}
|
||||
drm_connector_init_with_ddc(dev, &amdgpu_connector->base,
|
||||
&amdgpu_connector_dvi_funcs,
|
||||
connector_type,
|
||||
ddc);
|
||||
drm_connector_helper_add(&amdgpu_connector->base, &amdgpu_connector_dvi_helper_funcs);
|
||||
drm_object_attach_property(&amdgpu_connector->base.base,
|
||||
adev->mode_info.coherent_mode_property,
|
||||
1);
|
||||
@ -1796,15 +1825,20 @@ amdgpu_connector_add(struct amdgpu_device *adev,
|
||||
if (!amdgpu_dig_connector)
|
||||
goto failed;
|
||||
amdgpu_connector->con_priv = amdgpu_dig_connector;
|
||||
drm_connector_init(dev, &amdgpu_connector->base, &amdgpu_connector_dp_funcs, connector_type);
|
||||
drm_connector_helper_add(&amdgpu_connector->base, &amdgpu_connector_dp_helper_funcs);
|
||||
if (i2c_bus->valid) {
|
||||
amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus);
|
||||
if (amdgpu_connector->ddc_bus)
|
||||
if (amdgpu_connector->ddc_bus) {
|
||||
has_aux = true;
|
||||
else
|
||||
ddc = &amdgpu_connector->ddc_bus->adapter;
|
||||
} else {
|
||||
DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
|
||||
}
|
||||
}
|
||||
drm_connector_init_with_ddc(dev, &amdgpu_connector->base,
|
||||
&amdgpu_connector_dp_funcs,
|
||||
connector_type,
|
||||
ddc);
|
||||
drm_connector_helper_add(&amdgpu_connector->base, &amdgpu_connector_dp_helper_funcs);
|
||||
subpixel_order = SubPixelHorizontalRGB;
|
||||
drm_object_attach_property(&amdgpu_connector->base.base,
|
||||
adev->mode_info.coherent_mode_property,
|
||||
@ -1838,15 +1872,20 @@ amdgpu_connector_add(struct amdgpu_device *adev,
|
||||
if (!amdgpu_dig_connector)
|
||||
goto failed;
|
||||
amdgpu_connector->con_priv = amdgpu_dig_connector;
|
||||
drm_connector_init(dev, &amdgpu_connector->base, &amdgpu_connector_edp_funcs, connector_type);
|
||||
drm_connector_helper_add(&amdgpu_connector->base, &amdgpu_connector_dp_helper_funcs);
|
||||
if (i2c_bus->valid) {
|
||||
amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus);
|
||||
if (amdgpu_connector->ddc_bus)
|
||||
if (amdgpu_connector->ddc_bus) {
|
||||
has_aux = true;
|
||||
else
|
||||
ddc = &amdgpu_connector->ddc_bus->adapter;
|
||||
} else {
|
||||
DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
|
||||
}
|
||||
}
|
||||
drm_connector_init_with_ddc(dev, &amdgpu_connector->base,
|
||||
&amdgpu_connector_edp_funcs,
|
||||
connector_type,
|
||||
ddc);
|
||||
drm_connector_helper_add(&amdgpu_connector->base, &amdgpu_connector_dp_helper_funcs);
|
||||
drm_object_attach_property(&amdgpu_connector->base.base,
|
||||
dev->mode_config.scaling_mode_property,
|
||||
DRM_MODE_SCALE_FULLSCREEN);
|
||||
@ -1859,13 +1898,18 @@ amdgpu_connector_add(struct amdgpu_device *adev,
|
||||
if (!amdgpu_dig_connector)
|
||||
goto failed;
|
||||
amdgpu_connector->con_priv = amdgpu_dig_connector;
|
||||
drm_connector_init(dev, &amdgpu_connector->base, &amdgpu_connector_lvds_funcs, connector_type);
|
||||
drm_connector_helper_add(&amdgpu_connector->base, &amdgpu_connector_lvds_helper_funcs);
|
||||
if (i2c_bus->valid) {
|
||||
amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus);
|
||||
if (!amdgpu_connector->ddc_bus)
|
||||
DRM_ERROR("LVDS: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
|
||||
else
|
||||
ddc = &amdgpu_connector->ddc_bus->adapter;
|
||||
}
|
||||
drm_connector_init_with_ddc(dev, &amdgpu_connector->base,
|
||||
&amdgpu_connector_lvds_funcs,
|
||||
connector_type,
|
||||
ddc);
|
||||
drm_connector_helper_add(&amdgpu_connector->base, &amdgpu_connector_lvds_helper_funcs);
|
||||
drm_object_attach_property(&amdgpu_connector->base.base,
|
||||
dev->mode_config.scaling_mode_property,
|
||||
DRM_MODE_SCALE_FULLSCREEN);
|
||||
|
@ -402,7 +402,7 @@ static int amdgpu_cs_bo_validate(struct amdgpu_cs_parser *p,
|
||||
struct ttm_operation_ctx ctx = {
|
||||
.interruptible = true,
|
||||
.no_wait_gpu = false,
|
||||
.resv = bo->tbo.resv,
|
||||
.resv = bo->tbo.base.resv,
|
||||
.flags = 0
|
||||
};
|
||||
uint32_t domain;
|
||||
@ -730,7 +730,7 @@ static int amdgpu_cs_sync_rings(struct amdgpu_cs_parser *p)
|
||||
|
||||
list_for_each_entry(e, &p->validated, tv.head) {
|
||||
struct amdgpu_bo *bo = ttm_to_amdgpu_bo(e->tv.bo);
|
||||
struct reservation_object *resv = bo->tbo.resv;
|
||||
struct dma_resv *resv = bo->tbo.base.resv;
|
||||
|
||||
r = amdgpu_sync_resv(p->adev, &p->job->sync, resv, p->filp,
|
||||
amdgpu_bo_explicit_sync(bo));
|
||||
@ -1732,7 +1732,7 @@ int amdgpu_cs_find_mapping(struct amdgpu_cs_parser *parser,
|
||||
*map = mapping;
|
||||
|
||||
/* Double check that the BO is reserved by this CS */
|
||||
if (READ_ONCE((*bo)->tbo.resv->lock.ctx) != &parser->ticket)
|
||||
if (dma_resv_locking_ctx((*bo)->tbo.base.resv) != &parser->ticket)
|
||||
return -EINVAL;
|
||||
|
||||
if (!((*bo)->flags & AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS)) {
|
||||
|
@ -42,7 +42,7 @@ const unsigned int amdgpu_ctx_num_entities[AMDGPU_HW_IP_NUM] = {
|
||||
[AMDGPU_HW_IP_VCN_JPEG] = 1,
|
||||
};
|
||||
|
||||
static int amdgput_ctx_total_num_entities(void)
|
||||
static int amdgpu_ctx_total_num_entities(void)
|
||||
{
|
||||
unsigned i, num_entities = 0;
|
||||
|
||||
@ -73,8 +73,8 @@ static int amdgpu_ctx_init(struct amdgpu_device *adev,
|
||||
struct drm_file *filp,
|
||||
struct amdgpu_ctx *ctx)
|
||||
{
|
||||
unsigned num_entities = amdgput_ctx_total_num_entities();
|
||||
unsigned i, j;
|
||||
unsigned num_entities = amdgpu_ctx_total_num_entities();
|
||||
unsigned i, j, k;
|
||||
int r;
|
||||
|
||||
if (priority < 0 || priority >= DRM_SCHED_PRIORITY_MAX)
|
||||
@ -123,7 +123,7 @@ static int amdgpu_ctx_init(struct amdgpu_device *adev,
|
||||
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;
|
||||
unsigned num_rings = 0;
|
||||
unsigned num_rqs = 0;
|
||||
|
||||
switch (i) {
|
||||
@ -154,16 +154,26 @@ static int amdgpu_ctx_init(struct amdgpu_device *adev,
|
||||
num_rings = 1;
|
||||
break;
|
||||
case AMDGPU_HW_IP_VCN_DEC:
|
||||
rings[0] = &adev->vcn.ring_dec;
|
||||
num_rings = 1;
|
||||
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;
|
||||
}
|
||||
break;
|
||||
case AMDGPU_HW_IP_VCN_ENC:
|
||||
rings[0] = &adev->vcn.ring_enc[0];
|
||||
num_rings = 1;
|
||||
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];
|
||||
}
|
||||
break;
|
||||
case AMDGPU_HW_IP_VCN_JPEG:
|
||||
rings[0] = &adev->vcn.ring_jpeg;
|
||||
num_rings = 1;
|
||||
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;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -197,7 +207,7 @@ error_free_fences:
|
||||
static void amdgpu_ctx_fini(struct kref *ref)
|
||||
{
|
||||
struct amdgpu_ctx *ctx = container_of(ref, struct amdgpu_ctx, refcount);
|
||||
unsigned num_entities = amdgput_ctx_total_num_entities();
|
||||
unsigned num_entities = amdgpu_ctx_total_num_entities();
|
||||
struct amdgpu_device *adev = ctx->adev;
|
||||
unsigned i, j;
|
||||
|
||||
@ -279,10 +289,7 @@ static void amdgpu_ctx_do_release(struct kref *ref)
|
||||
|
||||
ctx = container_of(ref, struct amdgpu_ctx, refcount);
|
||||
|
||||
num_entities = 0;
|
||||
for (i = 0; i < AMDGPU_HW_IP_NUM; i++)
|
||||
num_entities += amdgpu_ctx_num_entities[i];
|
||||
|
||||
num_entities = amdgpu_ctx_total_num_entities();
|
||||
for (i = 0; i < num_entities; i++)
|
||||
drm_sched_entity_destroy(&ctx->entities[0][i].entity);
|
||||
|
||||
@ -344,7 +351,7 @@ static int amdgpu_ctx_query2(struct amdgpu_device *adev,
|
||||
{
|
||||
struct amdgpu_ctx *ctx;
|
||||
struct amdgpu_ctx_mgr *mgr;
|
||||
uint32_t ras_counter;
|
||||
unsigned long ras_counter;
|
||||
|
||||
if (!fpriv)
|
||||
return -EINVAL;
|
||||
@ -514,7 +521,7 @@ struct dma_fence *amdgpu_ctx_get_fence(struct amdgpu_ctx *ctx,
|
||||
void amdgpu_ctx_priority_override(struct amdgpu_ctx *ctx,
|
||||
enum drm_sched_priority priority)
|
||||
{
|
||||
unsigned num_entities = amdgput_ctx_total_num_entities();
|
||||
unsigned num_entities = amdgpu_ctx_total_num_entities();
|
||||
enum drm_sched_priority ctx_prio;
|
||||
unsigned i;
|
||||
|
||||
@ -562,7 +569,7 @@ void amdgpu_ctx_mgr_init(struct amdgpu_ctx_mgr *mgr)
|
||||
|
||||
long amdgpu_ctx_mgr_entity_flush(struct amdgpu_ctx_mgr *mgr, long timeout)
|
||||
{
|
||||
unsigned num_entities = amdgput_ctx_total_num_entities();
|
||||
unsigned num_entities = amdgpu_ctx_total_num_entities();
|
||||
struct amdgpu_ctx *ctx;
|
||||
struct idr *idp;
|
||||
uint32_t id, i;
|
||||
@ -584,7 +591,7 @@ long amdgpu_ctx_mgr_entity_flush(struct amdgpu_ctx_mgr *mgr, long timeout)
|
||||
|
||||
void amdgpu_ctx_mgr_entity_fini(struct amdgpu_ctx_mgr *mgr)
|
||||
{
|
||||
unsigned num_entities = amdgput_ctx_total_num_entities();
|
||||
unsigned num_entities = amdgpu_ctx_total_num_entities();
|
||||
struct amdgpu_ctx *ctx;
|
||||
struct idr *idp;
|
||||
uint32_t id, i;
|
||||
|
@ -49,8 +49,8 @@ struct amdgpu_ctx {
|
||||
enum drm_sched_priority override_priority;
|
||||
struct mutex lock;
|
||||
atomic_t guilty;
|
||||
uint32_t ras_counter_ce;
|
||||
uint32_t ras_counter_ue;
|
||||
unsigned long ras_counter_ce;
|
||||
unsigned long ras_counter_ue;
|
||||
};
|
||||
|
||||
struct amdgpu_ctx_mgr {
|
||||
|
@ -70,7 +70,11 @@ MODULE_FIRMWARE("amdgpu/vega12_gpu_info.bin");
|
||||
MODULE_FIRMWARE("amdgpu/raven_gpu_info.bin");
|
||||
MODULE_FIRMWARE("amdgpu/picasso_gpu_info.bin");
|
||||
MODULE_FIRMWARE("amdgpu/raven2_gpu_info.bin");
|
||||
MODULE_FIRMWARE("amdgpu/arcturus_gpu_info.bin");
|
||||
MODULE_FIRMWARE("amdgpu/renoir_gpu_info.bin");
|
||||
MODULE_FIRMWARE("amdgpu/navi10_gpu_info.bin");
|
||||
MODULE_FIRMWARE("amdgpu/navi14_gpu_info.bin");
|
||||
MODULE_FIRMWARE("amdgpu/navi12_gpu_info.bin");
|
||||
|
||||
#define AMDGPU_RESUME_MS 2000
|
||||
|
||||
@ -98,7 +102,11 @@ static const char *amdgpu_asic_name[] = {
|
||||
"VEGA12",
|
||||
"VEGA20",
|
||||
"RAVEN",
|
||||
"ARCTURUS",
|
||||
"RENOIR",
|
||||
"NAVI10",
|
||||
"NAVI14",
|
||||
"NAVI12",
|
||||
"LAST",
|
||||
};
|
||||
|
||||
@ -412,6 +420,40 @@ static void amdgpu_invalid_wreg(struct amdgpu_device *adev, uint32_t reg, uint32
|
||||
BUG();
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_invalid_rreg64 - dummy 64 bit reg read function
|
||||
*
|
||||
* @adev: amdgpu device pointer
|
||||
* @reg: offset of register
|
||||
*
|
||||
* Dummy register read function. Used for register blocks
|
||||
* that certain asics don't have (all asics).
|
||||
* Returns the value in the register.
|
||||
*/
|
||||
static uint64_t amdgpu_invalid_rreg64(struct amdgpu_device *adev, uint32_t reg)
|
||||
{
|
||||
DRM_ERROR("Invalid callback to read 64 bit register 0x%04X\n", reg);
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_invalid_wreg64 - dummy reg write function
|
||||
*
|
||||
* @adev: amdgpu device pointer
|
||||
* @reg: offset of register
|
||||
* @v: value to write to the register
|
||||
*
|
||||
* Dummy register read function. Used for register blocks
|
||||
* that certain asics don't have (all asics).
|
||||
*/
|
||||
static void amdgpu_invalid_wreg64(struct amdgpu_device *adev, uint32_t reg, uint64_t v)
|
||||
{
|
||||
DRM_ERROR("Invalid callback to write 64 bit register 0x%04X with 0x%08llX\n",
|
||||
reg, v);
|
||||
BUG();
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_block_invalid_rreg - dummy reg read function
|
||||
*
|
||||
@ -1384,9 +1426,21 @@ static int amdgpu_device_parse_gpu_info_fw(struct amdgpu_device *adev)
|
||||
else
|
||||
chip_name = "raven";
|
||||
break;
|
||||
case CHIP_ARCTURUS:
|
||||
chip_name = "arcturus";
|
||||
break;
|
||||
case CHIP_RENOIR:
|
||||
chip_name = "renoir";
|
||||
break;
|
||||
case CHIP_NAVI10:
|
||||
chip_name = "navi10";
|
||||
break;
|
||||
case CHIP_NAVI14:
|
||||
chip_name = "navi14";
|
||||
break;
|
||||
case CHIP_NAVI12:
|
||||
chip_name = "navi12";
|
||||
break;
|
||||
}
|
||||
|
||||
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_gpu_info.bin", chip_name);
|
||||
@ -1529,7 +1583,10 @@ static int amdgpu_device_ip_early_init(struct amdgpu_device *adev)
|
||||
case CHIP_VEGA12:
|
||||
case CHIP_VEGA20:
|
||||
case CHIP_RAVEN:
|
||||
if (adev->asic_type == CHIP_RAVEN)
|
||||
case CHIP_ARCTURUS:
|
||||
case CHIP_RENOIR:
|
||||
if (adev->asic_type == CHIP_RAVEN ||
|
||||
adev->asic_type == CHIP_RENOIR)
|
||||
adev->family = AMDGPU_FAMILY_RV;
|
||||
else
|
||||
adev->family = AMDGPU_FAMILY_AI;
|
||||
@ -1539,6 +1596,8 @@ static int amdgpu_device_ip_early_init(struct amdgpu_device *adev)
|
||||
return r;
|
||||
break;
|
||||
case CHIP_NAVI10:
|
||||
case CHIP_NAVI14:
|
||||
case CHIP_NAVI12:
|
||||
adev->family = AMDGPU_FAMILY_NV;
|
||||
|
||||
r = nv_set_ip_blocks(adev);
|
||||
@ -1560,9 +1619,6 @@ static int amdgpu_device_ip_early_init(struct amdgpu_device *adev)
|
||||
r = amdgpu_virt_request_full_gpu(adev, true);
|
||||
if (r)
|
||||
return -EAGAIN;
|
||||
|
||||
/* query the reg access mode at the very beginning */
|
||||
amdgpu_virt_init_reg_access_mode(adev);
|
||||
}
|
||||
|
||||
adev->pm.pp_feature = amdgpu_pp_feature_mask;
|
||||
@ -1665,28 +1721,34 @@ static int amdgpu_device_fw_loading(struct amdgpu_device *adev)
|
||||
|
||||
if (adev->asic_type >= CHIP_VEGA10) {
|
||||
for (i = 0; i < adev->num_ip_blocks; i++) {
|
||||
if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_PSP) {
|
||||
if (adev->in_gpu_reset || adev->in_suspend) {
|
||||
if (amdgpu_sriov_vf(adev) && adev->in_gpu_reset)
|
||||
break; /* sriov gpu reset, psp need to do hw_init before IH because of hw limit */
|
||||
r = adev->ip_blocks[i].version->funcs->resume(adev);
|
||||
if (r) {
|
||||
DRM_ERROR("resume of IP block <%s> failed %d\n",
|
||||
if (adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_PSP)
|
||||
continue;
|
||||
|
||||
/* no need to do the fw loading again if already done*/
|
||||
if (adev->ip_blocks[i].status.hw == true)
|
||||
break;
|
||||
|
||||
if (adev->in_gpu_reset || adev->in_suspend) {
|
||||
r = adev->ip_blocks[i].version->funcs->resume(adev);
|
||||
if (r) {
|
||||
DRM_ERROR("resume of IP block <%s> failed %d\n",
|
||||
adev->ip_blocks[i].version->funcs->name, r);
|
||||
return r;
|
||||
}
|
||||
} else {
|
||||
r = adev->ip_blocks[i].version->funcs->hw_init(adev);
|
||||
if (r) {
|
||||
DRM_ERROR("hw_init of IP block <%s> failed %d\n",
|
||||
adev->ip_blocks[i].version->funcs->name, r);
|
||||
return r;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
} else {
|
||||
r = adev->ip_blocks[i].version->funcs->hw_init(adev);
|
||||
if (r) {
|
||||
DRM_ERROR("hw_init of IP block <%s> failed %d\n",
|
||||
adev->ip_blocks[i].version->funcs->name, r);
|
||||
return r;
|
||||
}
|
||||
adev->ip_blocks[i].status.hw = true;
|
||||
}
|
||||
|
||||
adev->ip_blocks[i].status.hw = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
r = amdgpu_pm_load_smu_firmware(adev, &smu_version);
|
||||
|
||||
return r;
|
||||
@ -2128,7 +2190,9 @@ static int amdgpu_device_ip_suspend_phase1(struct amdgpu_device *adev)
|
||||
if (r) {
|
||||
DRM_ERROR("suspend of IP block <%s> failed %d\n",
|
||||
adev->ip_blocks[i].version->funcs->name, r);
|
||||
return r;
|
||||
}
|
||||
adev->ip_blocks[i].status.hw = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2163,6 +2227,25 @@ static int amdgpu_device_ip_suspend_phase2(struct amdgpu_device *adev)
|
||||
DRM_ERROR("suspend of IP block <%s> failed %d\n",
|
||||
adev->ip_blocks[i].version->funcs->name, r);
|
||||
}
|
||||
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)) {
|
||||
/* todo */
|
||||
} 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);
|
||||
if (r) {
|
||||
DRM_ERROR("SMC failed to set mp1 state %d, %d\n",
|
||||
adev->mp1_state, r);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
adev->ip_blocks[i].status.hw = false;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -2215,6 +2298,7 @@ static int amdgpu_device_ip_reinit_early_sriov(struct amdgpu_device *adev)
|
||||
for (j = 0; j < adev->num_ip_blocks; j++) {
|
||||
block = &adev->ip_blocks[j];
|
||||
|
||||
block->status.hw = false;
|
||||
if (block->version->type != ip_order[i] ||
|
||||
!block->status.valid)
|
||||
continue;
|
||||
@ -2223,6 +2307,7 @@ static int amdgpu_device_ip_reinit_early_sriov(struct amdgpu_device *adev)
|
||||
DRM_INFO("RE-INIT-early: %s %s\n", block->version->funcs->name, r?"failed":"succeeded");
|
||||
if (r)
|
||||
return r;
|
||||
block->status.hw = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2250,13 +2335,15 @@ static int amdgpu_device_ip_reinit_late_sriov(struct amdgpu_device *adev)
|
||||
block = &adev->ip_blocks[j];
|
||||
|
||||
if (block->version->type != ip_order[i] ||
|
||||
!block->status.valid)
|
||||
!block->status.valid ||
|
||||
block->status.hw)
|
||||
continue;
|
||||
|
||||
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;
|
||||
block->status.hw = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2280,17 +2367,19 @@ static int amdgpu_device_ip_resume_phase1(struct amdgpu_device *adev)
|
||||
int i, r;
|
||||
|
||||
for (i = 0; i < adev->num_ip_blocks; i++) {
|
||||
if (!adev->ip_blocks[i].status.valid)
|
||||
if (!adev->ip_blocks[i].status.valid || adev->ip_blocks[i].status.hw)
|
||||
continue;
|
||||
if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_COMMON ||
|
||||
adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC ||
|
||||
adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_IH) {
|
||||
|
||||
r = adev->ip_blocks[i].version->funcs->resume(adev);
|
||||
if (r) {
|
||||
DRM_ERROR("resume of IP block <%s> failed %d\n",
|
||||
adev->ip_blocks[i].version->funcs->name, r);
|
||||
return r;
|
||||
}
|
||||
adev->ip_blocks[i].status.hw = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2315,7 +2404,7 @@ static int amdgpu_device_ip_resume_phase2(struct amdgpu_device *adev)
|
||||
int i, r;
|
||||
|
||||
for (i = 0; i < adev->num_ip_blocks; i++) {
|
||||
if (!adev->ip_blocks[i].status.valid)
|
||||
if (!adev->ip_blocks[i].status.valid || adev->ip_blocks[i].status.hw)
|
||||
continue;
|
||||
if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_COMMON ||
|
||||
adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC ||
|
||||
@ -2328,6 +2417,7 @@ static int amdgpu_device_ip_resume_phase2(struct amdgpu_device *adev)
|
||||
adev->ip_blocks[i].version->funcs->name, r);
|
||||
return r;
|
||||
}
|
||||
adev->ip_blocks[i].status.hw = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -2426,6 +2516,11 @@ bool amdgpu_device_asic_has_dc_support(enum amd_asic_type asic_type)
|
||||
#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
|
||||
@ -2509,6 +2604,8 @@ int amdgpu_device_init(struct amdgpu_device *adev,
|
||||
adev->pcie_wreg = &amdgpu_invalid_wreg;
|
||||
adev->pciep_rreg = &amdgpu_invalid_rreg;
|
||||
adev->pciep_wreg = &amdgpu_invalid_wreg;
|
||||
adev->pcie_rreg64 = &amdgpu_invalid_rreg64;
|
||||
adev->pcie_wreg64 = &amdgpu_invalid_wreg64;
|
||||
adev->uvd_ctx_rreg = &amdgpu_invalid_rreg;
|
||||
adev->uvd_ctx_wreg = &amdgpu_invalid_wreg;
|
||||
adev->didt_rreg = &amdgpu_invalid_rreg;
|
||||
@ -3389,7 +3486,7 @@ 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) {
|
||||
atomic_inc(&adev->vram_lost_counter);
|
||||
amdgpu_inc_vram_lost(adev);
|
||||
r = amdgpu_device_recover_vram(adev);
|
||||
}
|
||||
|
||||
@ -3431,6 +3528,7 @@ bool amdgpu_device_should_recover_gpu(struct amdgpu_device *adev)
|
||||
case CHIP_VEGA20:
|
||||
case CHIP_VEGA10:
|
||||
case CHIP_VEGA12:
|
||||
case CHIP_RAVEN:
|
||||
break;
|
||||
default:
|
||||
goto disabled;
|
||||
@ -3554,7 +3652,7 @@ static int amdgpu_do_asic_reset(struct amdgpu_hive_info *hive,
|
||||
vram_lost = amdgpu_device_check_vram_lost(tmp_adev);
|
||||
if (vram_lost) {
|
||||
DRM_INFO("VRAM is lost due to GPU reset!\n");
|
||||
atomic_inc(&tmp_adev->vram_lost_counter);
|
||||
amdgpu_inc_vram_lost(tmp_adev);
|
||||
}
|
||||
|
||||
r = amdgpu_gtt_mgr_recover(
|
||||
@ -3627,6 +3725,17 @@ static bool amdgpu_device_lock_adev(struct amdgpu_device *adev, bool trylock)
|
||||
|
||||
atomic_inc(&adev->gpu_reset_counter);
|
||||
adev->in_gpu_reset = 1;
|
||||
switch (amdgpu_asic_reset_method(adev)) {
|
||||
case AMD_RESET_METHOD_MODE1:
|
||||
adev->mp1_state = PP_MP1_STATE_SHUTDOWN;
|
||||
break;
|
||||
case AMD_RESET_METHOD_MODE2:
|
||||
adev->mp1_state = PP_MP1_STATE_RESET;
|
||||
break;
|
||||
default:
|
||||
adev->mp1_state = PP_MP1_STATE_NONE;
|
||||
break;
|
||||
}
|
||||
/* Block kfd: SRIOV would do it separately */
|
||||
if (!amdgpu_sriov_vf(adev))
|
||||
amdgpu_amdkfd_pre_reset(adev);
|
||||
@ -3640,6 +3749,7 @@ static void amdgpu_device_unlock_adev(struct amdgpu_device *adev)
|
||||
if (!amdgpu_sriov_vf(adev))
|
||||
amdgpu_amdkfd_post_reset(adev);
|
||||
amdgpu_vf_error_trans_all(adev);
|
||||
adev->mp1_state = PP_MP1_STATE_NONE;
|
||||
adev->in_gpu_reset = 0;
|
||||
mutex_unlock(&adev->lock_reset);
|
||||
}
|
||||
@ -3684,14 +3794,14 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
|
||||
|
||||
if (hive && !mutex_trylock(&hive->reset_lock)) {
|
||||
DRM_INFO("Bailing on TDR for s_job:%llx, hive: %llx as another already in progress",
|
||||
job->base.id, hive->hive_id);
|
||||
job ? job->base.id : -1, hive->hive_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Start with adev pre asic reset first for soft reset check.*/
|
||||
if (!amdgpu_device_lock_adev(adev, !hive)) {
|
||||
DRM_INFO("Bailing on TDR for s_job:%llx, as another already in progress",
|
||||
job->base.id);
|
||||
job ? job->base.id : -1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -3732,7 +3842,7 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
|
||||
if (!ring || !ring->sched.thread)
|
||||
continue;
|
||||
|
||||
drm_sched_stop(&ring->sched, &job->base);
|
||||
drm_sched_stop(&ring->sched, job ? &job->base : NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3757,9 +3867,7 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
|
||||
|
||||
|
||||
/* Guilty job will be freed after this*/
|
||||
r = amdgpu_device_pre_asic_reset(adev,
|
||||
job,
|
||||
&need_full_reset);
|
||||
r = amdgpu_device_pre_asic_reset(adev, job, &need_full_reset);
|
||||
if (r) {
|
||||
/*TODO Should we stop ?*/
|
||||
DRM_ERROR("GPU pre asic reset failed with err, %d for drm dev, %s ",
|
||||
|
@ -191,7 +191,8 @@ int amdgpu_display_crtc_page_flip_target(struct drm_crtc *crtc,
|
||||
}
|
||||
|
||||
if (!adev->enable_virtual_display) {
|
||||
r = amdgpu_bo_pin(new_abo, amdgpu_display_supported_domains(adev));
|
||||
r = amdgpu_bo_pin(new_abo,
|
||||
amdgpu_display_supported_domains(adev, new_abo->flags));
|
||||
if (unlikely(r != 0)) {
|
||||
DRM_ERROR("failed to pin new abo buffer before flip\n");
|
||||
goto unreserve;
|
||||
@ -204,7 +205,7 @@ int amdgpu_display_crtc_page_flip_target(struct drm_crtc *crtc,
|
||||
goto unpin;
|
||||
}
|
||||
|
||||
r = reservation_object_get_fences_rcu(new_abo->tbo.resv, &work->excl,
|
||||
r = dma_resv_get_fences_rcu(new_abo->tbo.base.resv, &work->excl,
|
||||
&work->shared_count,
|
||||
&work->shared);
|
||||
if (unlikely(r != 0)) {
|
||||
@ -495,13 +496,25 @@ static const struct drm_framebuffer_funcs amdgpu_fb_funcs = {
|
||||
.create_handle = drm_gem_fb_create_handle,
|
||||
};
|
||||
|
||||
uint32_t amdgpu_display_supported_domains(struct amdgpu_device *adev)
|
||||
uint32_t amdgpu_display_supported_domains(struct amdgpu_device *adev,
|
||||
uint64_t bo_flags)
|
||||
{
|
||||
uint32_t domain = AMDGPU_GEM_DOMAIN_VRAM;
|
||||
|
||||
#if defined(CONFIG_DRM_AMD_DC)
|
||||
if (adev->asic_type >= CHIP_CARRIZO && adev->asic_type < CHIP_RAVEN &&
|
||||
adev->flags & AMD_IS_APU &&
|
||||
/*
|
||||
* if amdgpu_bo_support_uswc returns false it means that USWC mappings
|
||||
* is not supported for this board. But this mapping is required
|
||||
* to avoid hang caused by placement of scanout BO in GTT on certain
|
||||
* APUs. So force the BO placement to VRAM in case this architecture
|
||||
* 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) &&
|
||||
amdgpu_bo_support_uswc(bo_flags) &&
|
||||
amdgpu_device_asic_has_dc_support(adev->asic_type))
|
||||
domain |= AMDGPU_GEM_DOMAIN_GTT;
|
||||
#endif
|
||||
|
@ -38,7 +38,8 @@
|
||||
int amdgpu_display_freesync_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *filp);
|
||||
void amdgpu_display_update_priority(struct amdgpu_device *adev);
|
||||
uint32_t amdgpu_display_supported_domains(struct amdgpu_device *adev);
|
||||
uint32_t amdgpu_display_supported_domains(struct amdgpu_device *adev,
|
||||
uint64_t bo_flags);
|
||||
struct drm_framebuffer *
|
||||
amdgpu_display_user_framebuffer_create(struct drm_device *dev,
|
||||
struct drm_file *file_priv,
|
||||
|
@ -137,23 +137,23 @@ int amdgpu_gem_prime_mmap(struct drm_gem_object *obj,
|
||||
}
|
||||
|
||||
static int
|
||||
__reservation_object_make_exclusive(struct reservation_object *obj)
|
||||
__dma_resv_make_exclusive(struct dma_resv *obj)
|
||||
{
|
||||
struct dma_fence **fences;
|
||||
unsigned int count;
|
||||
int r;
|
||||
|
||||
if (!reservation_object_get_list(obj)) /* no shared fences to convert */
|
||||
if (!dma_resv_get_list(obj)) /* no shared fences to convert */
|
||||
return 0;
|
||||
|
||||
r = reservation_object_get_fences_rcu(obj, NULL, &count, &fences);
|
||||
r = dma_resv_get_fences_rcu(obj, NULL, &count, &fences);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (count == 0) {
|
||||
/* Now that was unexpected. */
|
||||
} else if (count == 1) {
|
||||
reservation_object_add_excl_fence(obj, fences[0]);
|
||||
dma_resv_add_excl_fence(obj, fences[0]);
|
||||
dma_fence_put(fences[0]);
|
||||
kfree(fences);
|
||||
} else {
|
||||
@ -165,7 +165,7 @@ __reservation_object_make_exclusive(struct reservation_object *obj)
|
||||
if (!array)
|
||||
goto err_fences_put;
|
||||
|
||||
reservation_object_add_excl_fence(obj, &array->base);
|
||||
dma_resv_add_excl_fence(obj, &array->base);
|
||||
dma_fence_put(&array->base);
|
||||
}
|
||||
|
||||
@ -216,7 +216,7 @@ static int amdgpu_dma_buf_map_attach(struct dma_buf *dma_buf,
|
||||
* fences on the reservation object into a single exclusive
|
||||
* fence.
|
||||
*/
|
||||
r = __reservation_object_make_exclusive(bo->tbo.resv);
|
||||
r = __dma_resv_make_exclusive(bo->tbo.base.resv);
|
||||
if (r)
|
||||
goto error_unreserve;
|
||||
}
|
||||
@ -267,20 +267,6 @@ error:
|
||||
drm_gem_map_detach(dma_buf, attach);
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_gem_prime_res_obj - &drm_driver.gem_prime_res_obj implementation
|
||||
* @obj: GEM BO
|
||||
*
|
||||
* Returns:
|
||||
* The BO's reservation object.
|
||||
*/
|
||||
struct reservation_object *amdgpu_gem_prime_res_obj(struct drm_gem_object *obj)
|
||||
{
|
||||
struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj);
|
||||
|
||||
return bo->tbo.resv;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_dma_buf_begin_cpu_access - &dma_buf_ops.begin_cpu_access implementation
|
||||
* @dma_buf: Shared DMA buffer
|
||||
@ -299,7 +285,7 @@ static int amdgpu_dma_buf_begin_cpu_access(struct dma_buf *dma_buf,
|
||||
struct amdgpu_bo *bo = gem_to_amdgpu_bo(dma_buf->priv);
|
||||
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
|
||||
struct ttm_operation_ctx ctx = { true, false };
|
||||
u32 domain = amdgpu_display_supported_domains(adev);
|
||||
u32 domain = amdgpu_display_supported_domains(adev, bo->flags);
|
||||
int ret;
|
||||
bool reads = (direction == DMA_BIDIRECTIONAL ||
|
||||
direction == DMA_FROM_DEVICE);
|
||||
@ -339,14 +325,12 @@ const struct dma_buf_ops amdgpu_dmabuf_ops = {
|
||||
* @gobj: GEM BO
|
||||
* @flags: Flags such as DRM_CLOEXEC and DRM_RDWR.
|
||||
*
|
||||
* The main work is done by the &drm_gem_prime_export helper, which in turn
|
||||
* uses &amdgpu_gem_prime_res_obj.
|
||||
* The main work is done by the &drm_gem_prime_export helper.
|
||||
*
|
||||
* Returns:
|
||||
* Shared DMA buffer representing the GEM BO from the given device.
|
||||
*/
|
||||
struct dma_buf *amdgpu_gem_prime_export(struct drm_device *dev,
|
||||
struct drm_gem_object *gobj,
|
||||
struct dma_buf *amdgpu_gem_prime_export(struct drm_gem_object *gobj,
|
||||
int flags)
|
||||
{
|
||||
struct amdgpu_bo *bo = gem_to_amdgpu_bo(gobj);
|
||||
@ -356,9 +340,9 @@ struct dma_buf *amdgpu_gem_prime_export(struct drm_device *dev,
|
||||
bo->flags & AMDGPU_GEM_CREATE_VM_ALWAYS_VALID)
|
||||
return ERR_PTR(-EPERM);
|
||||
|
||||
buf = drm_gem_prime_export(dev, gobj, flags);
|
||||
buf = drm_gem_prime_export(gobj, flags);
|
||||
if (!IS_ERR(buf)) {
|
||||
buf->file->f_mapping = dev->anon_inode->i_mapping;
|
||||
buf->file->f_mapping = gobj->dev->anon_inode->i_mapping;
|
||||
buf->ops = &amdgpu_dmabuf_ops;
|
||||
}
|
||||
|
||||
@ -383,7 +367,7 @@ amdgpu_gem_prime_import_sg_table(struct drm_device *dev,
|
||||
struct dma_buf_attachment *attach,
|
||||
struct sg_table *sg)
|
||||
{
|
||||
struct reservation_object *resv = attach->dmabuf->resv;
|
||||
struct dma_resv *resv = attach->dmabuf->resv;
|
||||
struct amdgpu_device *adev = dev->dev_private;
|
||||
struct amdgpu_bo *bo;
|
||||
struct amdgpu_bo_param bp;
|
||||
@ -396,7 +380,7 @@ amdgpu_gem_prime_import_sg_table(struct drm_device *dev,
|
||||
bp.flags = 0;
|
||||
bp.type = ttm_bo_type_sg;
|
||||
bp.resv = resv;
|
||||
ww_mutex_lock(&resv->lock, NULL);
|
||||
dma_resv_lock(resv, NULL);
|
||||
ret = amdgpu_bo_create(adev, &bp, &bo);
|
||||
if (ret)
|
||||
goto error;
|
||||
@ -408,11 +392,11 @@ amdgpu_gem_prime_import_sg_table(struct drm_device *dev,
|
||||
if (attach->dmabuf->ops != &amdgpu_dmabuf_ops)
|
||||
bo->prime_shared_count = 1;
|
||||
|
||||
ww_mutex_unlock(&resv->lock);
|
||||
return &bo->gem_base;
|
||||
dma_resv_unlock(resv);
|
||||
return &bo->tbo.base;
|
||||
|
||||
error:
|
||||
ww_mutex_unlock(&resv->lock);
|
||||
dma_resv_unlock(resv);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
|
@ -30,12 +30,10 @@ struct drm_gem_object *
|
||||
amdgpu_gem_prime_import_sg_table(struct drm_device *dev,
|
||||
struct dma_buf_attachment *attach,
|
||||
struct sg_table *sg);
|
||||
struct dma_buf *amdgpu_gem_prime_export(struct drm_device *dev,
|
||||
struct drm_gem_object *gobj,
|
||||
struct dma_buf *amdgpu_gem_prime_export(struct drm_gem_object *gobj,
|
||||
int flags);
|
||||
struct drm_gem_object *amdgpu_gem_prime_import(struct drm_device *dev,
|
||||
struct dma_buf *dma_buf);
|
||||
struct reservation_object *amdgpu_gem_prime_res_obj(struct drm_gem_object *);
|
||||
void *amdgpu_gem_prime_vmap(struct drm_gem_object *obj);
|
||||
void amdgpu_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr);
|
||||
int amdgpu_gem_prime_mmap(struct drm_gem_object *obj,
|
||||
|
@ -130,13 +130,18 @@ typedef enum _AMDGPU_VEGA20_DOORBELL_ASSIGNMENT
|
||||
AMDGPU_VEGA20_DOORBELL_IH = 0x178,
|
||||
/* MMSCH: 392~407
|
||||
* overlap the doorbell assignment with VCN as they are mutually exclusive
|
||||
* VCE engine's doorbell is 32 bit and two VCE ring share one QWORD
|
||||
* VCN engine's doorbell is 32 bit and two VCN ring share one QWORD
|
||||
*/
|
||||
AMDGPU_VEGA20_DOORBELL64_VCN0_1 = 0x188, /* lower 32 bits for VNC0 and upper 32 bits for VNC1 */
|
||||
AMDGPU_VEGA20_DOORBELL64_VCN0_1 = 0x188, /* VNC0 */
|
||||
AMDGPU_VEGA20_DOORBELL64_VCN2_3 = 0x189,
|
||||
AMDGPU_VEGA20_DOORBELL64_VCN4_5 = 0x18A,
|
||||
AMDGPU_VEGA20_DOORBELL64_VCN6_7 = 0x18B,
|
||||
|
||||
AMDGPU_VEGA20_DOORBELL64_VCN8_9 = 0x18C, /* VNC1 */
|
||||
AMDGPU_VEGA20_DOORBELL64_VCNa_b = 0x18D,
|
||||
AMDGPU_VEGA20_DOORBELL64_VCNc_d = 0x18E,
|
||||
AMDGPU_VEGA20_DOORBELL64_VCNe_f = 0x18F,
|
||||
|
||||
AMDGPU_VEGA20_DOORBELL64_UVD_RING0_1 = 0x188,
|
||||
AMDGPU_VEGA20_DOORBELL64_UVD_RING2_3 = 0x189,
|
||||
AMDGPU_VEGA20_DOORBELL64_UVD_RING4_5 = 0x18A,
|
||||
|
@ -79,9 +79,10 @@
|
||||
* - 3.31.0 - Add support for per-flip tiling attribute changes with DC
|
||||
* - 3.32.0 - Add syncobj timeline support to AMDGPU_CS.
|
||||
* - 3.33.0 - Fixes for GDS ENOMEM failures in AMDGPU_CS.
|
||||
* - 3.34.0 - Non-DC can flip correctly between buffers with different pitches
|
||||
*/
|
||||
#define KMS_DRIVER_MAJOR 3
|
||||
#define KMS_DRIVER_MINOR 33
|
||||
#define KMS_DRIVER_MINOR 34
|
||||
#define KMS_DRIVER_PATCHLEVEL 0
|
||||
|
||||
#define AMDGPU_MAX_TIMEOUT_PARAM_LENTH 256
|
||||
@ -142,7 +143,7 @@ int amdgpu_async_gfx_ring = 1;
|
||||
int amdgpu_mcbp = 0;
|
||||
int amdgpu_discovery = -1;
|
||||
int amdgpu_mes = 0;
|
||||
int amdgpu_noretry;
|
||||
int amdgpu_noretry = 1;
|
||||
|
||||
struct amdgpu_mgpu_info mgpu_info = {
|
||||
.mutex = __MUTEX_INITIALIZER(mgpu_info.mutex),
|
||||
@ -610,7 +611,7 @@ MODULE_PARM_DESC(mes,
|
||||
module_param_named(mes, amdgpu_mes, int, 0444);
|
||||
|
||||
MODULE_PARM_DESC(noretry,
|
||||
"Disable retry faults (0 = retry enabled (default), 1 = retry disabled)");
|
||||
"Disable retry faults (0 = retry enabled, 1 = retry disabled (default))");
|
||||
module_param_named(noretry, amdgpu_noretry, int, 0644);
|
||||
|
||||
#ifdef CONFIG_HSA_AMD
|
||||
@ -996,6 +997,11 @@ static const struct pci_device_id pciidlist[] = {
|
||||
/* Raven */
|
||||
{0x1002, 0x15dd, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RAVEN|AMD_IS_APU},
|
||||
{0x1002, 0x15d8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RAVEN|AMD_IS_APU},
|
||||
/* Arcturus */
|
||||
{0x1002, 0x738C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARCTURUS|AMD_EXP_HW_SUPPORT},
|
||||
{0x1002, 0x7388, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARCTURUS|AMD_EXP_HW_SUPPORT},
|
||||
{0x1002, 0x738E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARCTURUS|AMD_EXP_HW_SUPPORT},
|
||||
{0x1002, 0x7390, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARCTURUS|AMD_EXP_HW_SUPPORT},
|
||||
/* Navi10 */
|
||||
{0x1002, 0x7310, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_NAVI10},
|
||||
{0x1002, 0x7312, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_NAVI10},
|
||||
@ -1004,6 +1010,11 @@ static const struct pci_device_id pciidlist[] = {
|
||||
{0x1002, 0x731A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_NAVI10},
|
||||
{0x1002, 0x731B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_NAVI10},
|
||||
{0x1002, 0x731F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_NAVI10},
|
||||
/* Navi14 */
|
||||
{0x1002, 0x7340, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_NAVI14},
|
||||
|
||||
/* Renoir */
|
||||
{0x1002, 0x1636, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RENOIR|AMD_IS_APU|AMD_EXP_HW_SUPPORT},
|
||||
|
||||
{0, 0, 0}
|
||||
};
|
||||
@ -1092,21 +1103,21 @@ amdgpu_pci_shutdown(struct pci_dev *pdev)
|
||||
* unfortunately we can't detect certain
|
||||
* hypervisors so just do this all the time.
|
||||
*/
|
||||
adev->mp1_state = PP_MP1_STATE_UNLOAD;
|
||||
amdgpu_device_ip_suspend(adev);
|
||||
adev->mp1_state = PP_MP1_STATE_NONE;
|
||||
}
|
||||
|
||||
static int amdgpu_pmops_suspend(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct drm_device *drm_dev = dev_get_drvdata(dev);
|
||||
|
||||
struct drm_device *drm_dev = pci_get_drvdata(pdev);
|
||||
return amdgpu_device_suspend(drm_dev, true, true);
|
||||
}
|
||||
|
||||
static int amdgpu_pmops_resume(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct drm_device *drm_dev = pci_get_drvdata(pdev);
|
||||
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)) {
|
||||
@ -1120,33 +1131,29 @@ static int amdgpu_pmops_resume(struct device *dev)
|
||||
|
||||
static int amdgpu_pmops_freeze(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct drm_device *drm_dev = dev_get_drvdata(dev);
|
||||
|
||||
struct drm_device *drm_dev = pci_get_drvdata(pdev);
|
||||
return amdgpu_device_suspend(drm_dev, false, true);
|
||||
}
|
||||
|
||||
static int amdgpu_pmops_thaw(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct drm_device *drm_dev = dev_get_drvdata(dev);
|
||||
|
||||
struct drm_device *drm_dev = pci_get_drvdata(pdev);
|
||||
return amdgpu_device_resume(drm_dev, false, true);
|
||||
}
|
||||
|
||||
static int amdgpu_pmops_poweroff(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct drm_device *drm_dev = dev_get_drvdata(dev);
|
||||
|
||||
struct drm_device *drm_dev = pci_get_drvdata(pdev);
|
||||
return amdgpu_device_suspend(drm_dev, true, true);
|
||||
}
|
||||
|
||||
static int amdgpu_pmops_restore(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct drm_device *drm_dev = dev_get_drvdata(dev);
|
||||
|
||||
struct drm_device *drm_dev = pci_get_drvdata(pdev);
|
||||
return amdgpu_device_resume(drm_dev, false, true);
|
||||
}
|
||||
|
||||
@ -1205,8 +1212,7 @@ static int amdgpu_pmops_runtime_resume(struct device *dev)
|
||||
|
||||
static int amdgpu_pmops_runtime_idle(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct drm_device *drm_dev = pci_get_drvdata(pdev);
|
||||
struct drm_device *drm_dev = dev_get_drvdata(dev);
|
||||
struct drm_crtc *crtc;
|
||||
|
||||
if (!amdgpu_device_is_px(drm_dev)) {
|
||||
@ -1373,7 +1379,7 @@ static struct drm_driver kms_driver = {
|
||||
.driver_features =
|
||||
DRIVER_USE_AGP | DRIVER_ATOMIC |
|
||||
DRIVER_GEM |
|
||||
DRIVER_PRIME | DRIVER_RENDER | DRIVER_MODESET | DRIVER_SYNCOBJ,
|
||||
DRIVER_RENDER | DRIVER_MODESET | DRIVER_SYNCOBJ,
|
||||
.load = amdgpu_driver_load_kms,
|
||||
.open = amdgpu_driver_open_kms,
|
||||
.postclose = amdgpu_driver_postclose_kms,
|
||||
@ -1397,7 +1403,6 @@ static struct drm_driver kms_driver = {
|
||||
.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
|
||||
.gem_prime_export = amdgpu_gem_prime_export,
|
||||
.gem_prime_import = amdgpu_gem_prime_import,
|
||||
.gem_prime_res_obj = amdgpu_gem_prime_res_obj,
|
||||
.gem_prime_get_sg_table = amdgpu_gem_prime_get_sg_table,
|
||||
.gem_prime_import_sg_table = amdgpu_gem_prime_import_sg_table,
|
||||
.gem_prime_vmap = amdgpu_gem_prime_vmap,
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user