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:
Linus Torvalds 2019-09-19 16:24:24 -07:00
commit 574cc45397
1621 changed files with 262709 additions and 38616 deletions

View File

@ -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>;
};
};
};

View File

@ -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>;
};
};
};

View File

@ -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>;
};
};
};

View 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>;
};
};
};

View File

@ -39,9 +39,11 @@ Required sub-nodes:
- port: describes LCD panel signals, following the common binding - port: describes LCD panel signals, following the common binding
for video transmitter interfaces; see for video transmitter interfaces; see
Documentation/devicetree/bindings/media/video-interfaces.txt; Documentation/devicetree/bindings/media/video-interfaces.txt
when it is a TFT panel, the port's endpoint must define the
following property: 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, - arm,pl11x,tft-r0g0b0-pads: an array of three 32-bit values,
defining the way CLD pads are wired up; first value defining the way CLD pads are wired up; first value
@ -80,7 +82,6 @@ Example:
port { port {
clcd_pads: endpoint { clcd_pads: endpoint {
remote-endpoint = <&clcd_panel>; remote-endpoint = <&clcd_panel>;
arm,pl11x,tft-r0g0b0-pads = <0 8 16>;
}; };
}; };

View File

@ -26,9 +26,8 @@ Optional properties:
- clocks: phandle and clock specifier for each clock listed in - clocks: phandle and clock specifier for each clock listed in
the clock-names property the clock-names property
- clock-names: "mclk" - clock-names: "mclk"
Describes SII902x MCLK input. MCLK is used to produce Describes SII902x MCLK input. MCLK can be used to produce
HDMI audio CTS values. This property is required if HDMI audio CTS values. This property follows
"#sound-dai-cells"-property is present. This property follows
Documentation/devicetree/bindings/clock/clock-bindings.txt Documentation/devicetree/bindings/clock/clock-bindings.txt
consumer binding. consumer binding.

View File

@ -9,6 +9,7 @@ Optional properties:
- label: a symbolic name for the connector - label: a symbolic name for the connector
- hpd-gpios: HPD GPIO number - hpd-gpios: HPD GPIO number
- ddc-i2c-bus: phandle link to the I2C controller used for DDC EDID probing - ddc-i2c-bus: phandle link to the I2C controller used for DDC EDID probing
- ddc-en-gpios: signal to enable DDC bus
Required nodes: Required nodes:
- Video port for HDMI input - Video port for HDMI input

View File

@ -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>;
};
};
};

View File

@ -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>;
};
};
};
...

View File

@ -10,7 +10,7 @@ Required properties:
- compatible: should be "arm,versatile-tft-panel" - compatible: should be "arm,versatile-tft-panel"
Required subnodes: Required subnodes:
- port: see display/panel/panel-common.txt, graph.txt - port: see display/panel/panel-common.yaml, graph.txt
Example: Example:

View File

@ -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

View File

@ -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
...

View File

@ -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.

View File

@ -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
...

View File

@ -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>;
};
};

View File

@ -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.

View File

@ -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
...

View File

@ -40,7 +40,7 @@ simple-panel.txt
| Identifier | compatbile | description | | Identifier | compatbile | description |
+=================+=====================+=====================================+ +=================+=====================+=====================================+
| ETM0700G0DH6 | edt,etm070080dh6 | WVGA TFT Display with capacitive | | ETM0700G0DH6 | edt,etm070080dh6 | WVGA TFT Display with capacitive |
| | | Touchscreen | | | edt,etm0700g0dh6 | Touchscreen |
+-----------------+---------------------+-------------------------------------+ +-----------------+---------------------+-------------------------------------+
| ETM0700G0BDH6 | edt,etm070080bdh6 | Same as ETM0700G0DH6 but with | | ETM0700G0BDH6 | edt,etm070080bdh6 | Same as ETM0700G0DH6 but with |
| | | inverted pixel clock. | | | | inverted pixel clock. |

View File

@ -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.

View File

@ -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.

View File

@ -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
...

View File

@ -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>;
};
};
};
};

View 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
...

View File

@ -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>;
};
};
};

View File

@ -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>;
};
};
};
...

View File

@ -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>;
};
};
};

View File

@ -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>;
};
};
};
...

View File

@ -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>;
};
};
};
};
...

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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 ]
...

View File

@ -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>;
};
};
};

View File

@ -1,4 +0,0 @@
Common display properties
-------------------------
- rotation: Display rotation in degrees counter clockwise (0,90,180,270)

View File

@ -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.

View File

@ -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
...

View File

@ -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>;
};
};
};
};

View File

@ -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>;
};
};
};
};
...

View File

@ -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>;
};
};
};

View File

@ -5,6 +5,9 @@ Required properties:
- reg: DSI virtual channel of the peripheral - reg: DSI virtual channel of the peripheral
- reset-gpios: panel reset gpio - reset-gpios: panel reset gpio
- backlight: phandle of the backlight device attached to the panel - 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: Example:
@ -14,5 +17,7 @@ Example:
reg = <0>; reg = <0>;
backlight = <&backlight>; backlight = <&backlight>;
reset-gpios = <&gpio3 13 GPIO_ACTIVE_LOW>; reset-gpios = <&gpio3 13 GPIO_ACTIVE_LOW>;
vcc-supply = <&reg_2v8_p>;
iovcc-supply = <&reg_1v8_p>;
}; };
}; };

View File

@ -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>;
};
};
};

View File

@ -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>;
};
};
};
...

View File

@ -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>;
};
};
};

View File

@ -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.

View File

@ -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.

View File

@ -1,28 +1 @@
Simple display panel See panel-common.yaml in this directory.
====================
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>;
};

View File

@ -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.

View File

@ -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
...

View File

@ -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>;
};
};
};

View File

@ -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>;
};
};
};

View 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>;
};
};
};
};
...

View File

@ -14,6 +14,8 @@ Required properties:
- rockchip,grf: this soc should set GRF regs to mux vopl/vopb. - rockchip,grf: this soc should set GRF regs to mux vopl/vopb.
- ports: contain a port node with endpoint definitions as defined in [2]. - 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. 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: Optional properties:
- power-domains: a phandle to mipi dsi power domain node. - power-domains: a phandle to mipi dsi power domain node.
@ -40,11 +42,12 @@ Example:
ports { ports {
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
reg = <1>;
mipi_in: port { mipi_in: port@0 {
reg = <0>;
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
mipi_in_vopb: endpoint@0 { mipi_in_vopb: endpoint@0 {
reg = <0>; reg = <0>;
remote-endpoint = <&vopb_out_mipi>; remote-endpoint = <&vopb_out_mipi>;
@ -54,6 +57,16 @@ Example:
remote-endpoint = <&vopl_out_mipi>; 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 { panel {
@ -64,5 +77,11 @@ Example:
pinctrl-names = "default"; pinctrl-names = "default";
pinctrl-0 = <&lcd_en>; pinctrl-0 = <&lcd_en>;
backlight = <&backlight>; backlight = <&backlight>;
port {
panel_in_mipi: endpoint {
remote-endpoint = <&mipi_out_panel>;
};
};
}; };
}; };

View File

@ -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 0 for the VOP input, the remote endpoint maybe vopb or vopl
- video port 1 for either a panel or subsequent encoder - 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: Example:
lvds_panel: lvds-panel { lvds_panel: lvds-panel {

View File

@ -27,6 +27,15 @@ Optional properties:
- solomon,prechargep2: Length of precharge period (phase 2) in clock cycles. - solomon,prechargep2: Length of precharge period (phase 2) in clock cycles.
This needs to be the higher, the higher the capacitance This needs to be the higher, the higher the capacitance
of the OLED's pixels is 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 [0]: Documentation/devicetree/bindings/pwm/pwm.txt
@ -46,4 +55,5 @@ ssd1306: oled@3c {
solomon,com-lrremap; solomon,com-lrremap;
solomon,com-invdir; solomon,com-invdir;
solomon,com-offset = <32>; solomon,com-offset = <32>;
solomon,lookup-table = /bits/ 8 <0x3f 0x3f 0x3f 0x3f>;
}; };

View File

@ -521,6 +521,8 @@ patternProperties:
description: Lenovo Group Ltd. description: Lenovo Group Ltd.
"^lg,.*": "^lg,.*":
description: LG Corporation description: LG Corporation
"^lgphilips,.*":
description: LG Display
"^libretech,.*": "^libretech,.*":
description: Shenzhen Libre Technology Co., Ltd description: Shenzhen Libre Technology Co., Ltd
"^licheepi,.*": "^licheepi,.*":
@ -951,6 +953,9 @@ patternProperties:
description: Tecon Microprocessor Technologies, LLC. description: Tecon Microprocessor Technologies, LLC.
"^topeet,.*": "^topeet,.*":
description: Topeet description: Topeet
"^toppoly,.*":
description: TPO (deprecated, use tpo)
deprecated: true
"^toradex,.*": "^toradex,.*":
description: Toradex AG description: Toradex AG
"^toshiba,.*": "^toshiba,.*":

View File

@ -11,7 +11,6 @@ GPU Driver Documentation
meson meson
pl111 pl111
tegra tegra
tinydrm
tve200 tve200
v3d v3d
vc4 vc4

View File

@ -263,6 +263,18 @@ the MST topology helpers easier to understand
drm_dp_mst_topology_put_port drm_dp_mst_topology_put_port
drm_dp_mst_get_mstb_malloc drm_dp_mst_put_mstb_malloc 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 MIPI DSI Helper Functions Reference
=================================== ===================================

View File

@ -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 created for the OPTIMUS range of multi-gpu platforms. To userspace PRIME
buffers are dma-buf based file descriptors. 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 .. kernel-doc:: drivers/gpu/drm/drm_prime.c
share buffer objects across processes. They offer additional security: :doc: overview and lifetime rules
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.
PRIME Helper Functions PRIME Helper Functions
---------------------- ----------------------

View File

@ -91,9 +91,6 @@ Frontbuffer Tracking
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_frontbuffer.c .. kernel-doc:: drivers/gpu/drm/i915/display/intel_frontbuffer.c
:internal: :internal:
.. kernel-doc:: drivers/gpu/drm/i915/i915_gem.c
:functions: i915_gem_track_fb
Display FIFO Underrun Reporting Display FIFO Underrun Reporting
------------------------------- -------------------------------
@ -430,31 +427,31 @@ WOPCM Layout
GuC GuC
=== ===
Firmware Layout
-------------------
.. kernel-doc:: drivers/gpu/drm/i915/gt/uc/intel_uc_fw_abi.h
:doc: Firmware Layout
GuC-specific firmware loader 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: :internal:
GuC-based command submission 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 :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: :internal:
GuC Firmware Layout
-------------------
.. kernel-doc:: drivers/gpu/drm/i915/intel_guc_fwif.h
:doc: GuC Firmware Layout
GuC Address Space 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 :doc: GuC Address Space
Tracing Tracing

View File

@ -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>`. 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 Getting Started
=============== ===============

View File

@ -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:

View File

@ -162,7 +162,7 @@ Clean up mmap forwarding
A lot of drivers forward gem mmap calls to dma-buf mmap for imported buffers. 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. 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 Contact: Daniel Vetter
@ -196,15 +196,6 @@ Might be good to also have some igt testcases for this.
Contact: Daniel Vetter, Noralf Tronnes 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() idr_init_base()
--------------- ---------------
@ -215,22 +206,13 @@ efficient.
Contact: Daniel Vetter 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 struct drm_gem_object_funcs
--------------------------- ---------------------------
GEM objects can now have a function table instead of having the callbacks on the 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 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 We also need a 2nd version of the CMA define that doesn't require the
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
vmapping to be present (different hook for prime importing). Plus this needs to vmapping to be present (different hook for prime importing). Plus this needs to
be rolled out to all drivers using their own implementations, too. 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 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 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 this (together with the drm_minor->drm_device move) would allow us to remove
debugfs_init. debugfs_init.
- Drop the return code and error checking from all debugfs functions. Greg KH is
working on this already.
Contact: Daniel Vetter Contact: Daniel Vetter
KMS cleanups KMS cleanups
@ -440,39 +412,22 @@ fit the available time.
Contact: Daniel Vetter 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 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 AMD DC Display Driver
--------------------- ---------------------

View File

@ -1313,6 +1313,113 @@ The following tables list existing packed RGB formats.
- g\ :sub:`6` - g\ :sub:`6`
- g\ :sub:`5` - g\ :sub:`5`
- g\ :sub:`4` - 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:
- MEDIA_BUS_FMT_ARGB888_1X32 - MEDIA_BUS_FMT_ARGB888_1X32

View File

@ -834,17 +834,11 @@ F: drivers/iommu/amd_iommu*.[ch]
F: include/linux/amd-iommu.h F: include/linux/amd-iommu.h
AMD KFD AMD KFD
M: Oded Gabbay <oded.gabbay@gmail.com> M: Felix Kuehling <Felix.Kuehling@amd.com>
L: dri-devel@lists.freedesktop.org L: amd-gfx@lists.freedesktop.org
T: git git://people.freedesktop.org/~gabbayo/linux.git T: git git://people.freedesktop.org/~agd5f/linux
S: Supported S: Supported
F: drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c F: drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd*.[ch]
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/amdkfd/ F: drivers/gpu/drm/amd/amdkfd/
F: drivers/gpu/drm/amd/include/cik_structs.h F: drivers/gpu/drm/amd/include/cik_structs.h
F: drivers/gpu/drm/amd/include/kgd_kfd_interface.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: drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c
F: Documentation/devicetree/bindings/display/panel/feiyang,fy07024di26a30d.txt 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 DRM DRIVER FOR ILITEK ILI9225 PANELS
M: David Lechner <david@lechnology.com> M: David Lechner <david@lechnology.com>
T: git git://anongit.freedesktop.org/drm/drm-misc
S: Maintained S: Maintained
F: drivers/gpu/drm/tinydrm/ili9225.c F: drivers/gpu/drm/tiny/ili9225.c
F: Documentation/devicetree/bindings/display/ilitek,ili9225.txt F: Documentation/devicetree/bindings/display/ilitek,ili9225.txt
DRM DRIVER FOR HX8357D PANELS DRM DRIVER FOR HX8357D PANELS
M: Eric Anholt <eric@anholt.net> M: Eric Anholt <eric@anholt.net>
T: git git://anongit.freedesktop.org/drm/drm-misc T: git git://anongit.freedesktop.org/drm/drm-misc
S: Maintained S: Maintained
F: drivers/gpu/drm/tinydrm/hx8357d.c F: drivers/gpu/drm/tiny/hx8357d.c
F: Documentation/devicetree/bindings/display/himax,hx8357d.txt F: Documentation/devicetree/bindings/display/himax,hx8357d.txt
DRM DRIVER FOR INTEL I810 VIDEO CARDS DRM DRIVER FOR INTEL I810 VIDEO CARDS
@ -5174,8 +5175,9 @@ F: drivers/gpu/drm/mgag200/
DRM DRIVER FOR MI0283QT DRM DRIVER FOR MI0283QT
M: Noralf Trønnes <noralf@tronnes.org> M: Noralf Trønnes <noralf@tronnes.org>
T: git git://anongit.freedesktop.org/drm/drm-misc
S: Maintained 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 F: Documentation/devicetree/bindings/display/multi-inno,mi0283qt.txt
DRM DRIVER FOR MSM ADRENO GPU 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 DRM DRIVER FOR PERVASIVE DISPLAYS REPAPER PANELS
M: Noralf Trønnes <noralf@tronnes.org> M: Noralf Trønnes <noralf@tronnes.org>
T: git git://anongit.freedesktop.org/drm/drm-misc
S: Maintained S: Maintained
F: drivers/gpu/drm/tinydrm/repaper.c F: drivers/gpu/drm/tiny/repaper.c
F: Documentation/devicetree/bindings/display/repaper.txt F: Documentation/devicetree/bindings/display/repaper.txt
DRM DRIVER FOR QEMU'S CIRRUS DEVICE DRM DRIVER FOR QEMU'S CIRRUS DEVICE
@ -5230,6 +5233,12 @@ S: Maintained
F: drivers/gpu/drm/qxl/ F: drivers/gpu/drm/qxl/
F: include/uapi/drm/qxl_drm.h 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 DRM DRIVER FOR RAGE 128 VIDEO CARDS
S: Orphan / Obsolete S: Orphan / Obsolete
F: drivers/gpu/drm/r128/ F: drivers/gpu/drm/r128/
@ -5237,6 +5246,7 @@ F: include/uapi/drm/r128_drm.h
DRM DRIVER FOR ROCKTECH JH057N00900 PANELS DRM DRIVER FOR ROCKTECH JH057N00900 PANELS
M: Guido Günther <agx@sigxcpu.org> M: Guido Günther <agx@sigxcpu.org>
R: Purism Kernel Team <kernel@puri.sm>
S: Maintained S: Maintained
F: drivers/gpu/drm/panel/panel-rocktech-jh057n00900.c F: drivers/gpu/drm/panel/panel-rocktech-jh057n00900.c
F: Documentation/devicetree/bindings/display/panel/rocktech,jh057n00900.txt 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 DRM DRIVER FOR SITRONIX ST7586 PANELS
M: David Lechner <david@lechnology.com> M: David Lechner <david@lechnology.com>
T: git git://anongit.freedesktop.org/drm/drm-misc
S: Maintained S: Maintained
F: drivers/gpu/drm/tinydrm/st7586.c F: drivers/gpu/drm/tiny/st7586.c
F: Documentation/devicetree/bindings/display/sitronix,st7586.txt F: Documentation/devicetree/bindings/display/sitronix,st7586.txt
DRM DRIVER FOR SITRONIX ST7735R PANELS DRM DRIVER FOR SITRONIX ST7735R PANELS
M: David Lechner <david@lechnology.com> M: David Lechner <david@lechnology.com>
T: git git://anongit.freedesktop.org/drm/drm-misc
S: Maintained S: Maintained
F: drivers/gpu/drm/tinydrm/st7735r.c F: drivers/gpu/drm/tiny/st7735r.c
F: Documentation/devicetree/bindings/display/sitronix,st7735r.txt F: Documentation/devicetree/bindings/display/sitronix,st7735r.txt
DRM DRIVER FOR ST-ERICSSON MCDE 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 T: git git://anongit.freedesktop.org/drm/drm-misc
S: Maintained S: Maintained
F: drivers/gpu/drm/panel/panel-tpo-tpg110.c 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 DRM DRIVER FOR USB DISPLAYLINK VIDEO ADAPTERS
M: Dave Airlie <airlied@redhat.com> M: Dave Airlie <airlied@redhat.com>
@ -5367,12 +5379,13 @@ L: linux-amlogic@lists.infradead.org
W: http://linux-meson.com/ W: http://linux-meson.com/
S: Supported S: Supported
F: drivers/gpu/drm/meson/ F: drivers/gpu/drm/meson/
F: Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt F: Documentation/devicetree/bindings/display/amlogic,meson-vpu.yaml
F: Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt F: Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.yaml
F: Documentation/gpu/meson.rst F: Documentation/gpu/meson.rst
T: git git://anongit.freedesktop.org/drm/drm-misc T: git git://anongit.freedesktop.org/drm/drm-misc
DRM DRIVERS FOR ATMEL HLCDC DRM DRIVERS FOR ATMEL HLCDC
M: Sam Ravnborg <sam@ravnborg.org>
M: Boris Brezillon <bbrezillon@kernel.org> M: Boris Brezillon <bbrezillon@kernel.org>
L: dri-devel@lists.freedesktop.org L: dri-devel@lists.freedesktop.org
S: Supported S: Supported
@ -5382,7 +5395,10 @@ T: git git://anongit.freedesktop.org/drm/drm-misc
DRM DRIVERS FOR BRIDGE CHIPS DRM DRIVERS FOR BRIDGE CHIPS
M: Andrzej Hajda <a.hajda@samsung.com> M: Andrzej Hajda <a.hajda@samsung.com>
M: Neil Armstrong <narmstrong@baylibre.com>
R: Laurent Pinchart <Laurent.pinchart@ideasonboard.com> R: Laurent Pinchart <Laurent.pinchart@ideasonboard.com>
R: Jonas Karlman <jonas@kwiboo.se>
R: Jernej Skrabec <jernej.skrabec@siol.net>
S: Maintained S: Maintained
T: git git://anongit.freedesktop.org/drm/drm-misc T: git git://anongit.freedesktop.org/drm/drm-misc
F: drivers/gpu/drm/bridge/ F: drivers/gpu/drm/bridge/
@ -5570,14 +5586,6 @@ F: drivers/gpu/drm/panel/
F: include/drm/drm_panel.h F: include/drm/drm_panel.h
F: Documentation/devicetree/bindings/display/panel/ 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 DRM DRIVERS FOR XEN
M: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com> M: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
T: git git://anongit.freedesktop.org/drm/drm-misc T: git git://anongit.freedesktop.org/drm/drm-misc

View File

@ -549,6 +549,7 @@ static const struct pci_device_id intel_early_ids[] __initconst = {
INTEL_CNL_IDS(&gen9_early_ops), INTEL_CNL_IDS(&gen9_early_ops),
INTEL_ICL_11_IDS(&gen11_early_ops), INTEL_ICL_11_IDS(&gen11_early_ops),
INTEL_EHL_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); struct resource intel_graphics_stolen_res __ro_after_init = DEFINE_RES_MEM(0, 0);

View File

@ -39,4 +39,9 @@ config UDMABUF
A driver to let userspace turn memfd regions into dma-bufs. A driver to let userspace turn memfd regions into dma-bufs.
Qemu can use this to create host dmabufs for guest framebuffers. 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 endmenu

View File

@ -1,6 +1,12 @@
# SPDX-License-Identifier: GPL-2.0-only # SPDX-License-Identifier: GPL-2.0-only
obj-y := dma-buf.o dma-fence.o dma-fence-array.o dma-fence-chain.o \ 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_SYNC_FILE) += sync_file.o
obj-$(CONFIG_SW_SYNC) += sw_sync.o sync_debug.o obj-$(CONFIG_SW_SYNC) += sw_sync.o sync_debug.o
obj-$(CONFIG_UDMABUF) += udmabuf.o obj-$(CONFIG_UDMABUF) += udmabuf.o
dmabuf_selftests-y := \
selftest.o \
st-dma-fence.o
obj-$(CONFIG_DMABUF_SELFTESTS) += dmabuf_selftests.o

View File

@ -21,7 +21,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/reservation.h> #include <linux/dma-resv.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/mount.h> #include <linux/mount.h>
#include <linux/pseudo_fs.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); list_del(&dmabuf->list_node);
mutex_unlock(&db_list.lock); mutex_unlock(&db_list.lock);
if (dmabuf->resv == (struct reservation_object *)&dmabuf[1]) if (dmabuf->resv == (struct dma_resv *)&dmabuf[1])
reservation_object_fini(dmabuf->resv); dma_resv_fini(dmabuf->resv);
module_put(dmabuf->owner); module_put(dmabuf->owner);
kfree(dmabuf); 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 * To support cross-device and cross-driver synchronization of buffer access
* implicit fences (represented internally in the kernel with &struct fence) can * 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 * 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() * Userspace can query the state of these implicitly tracked fences using poll()
* and related system calls: * 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) static __poll_t dma_buf_poll(struct file *file, poll_table *poll)
{ {
struct dma_buf *dmabuf; struct dma_buf *dmabuf;
struct reservation_object *resv; struct dma_resv *resv;
struct reservation_object_list *fobj; struct dma_resv_list *fobj;
struct dma_fence *fence_excl; struct dma_fence *fence_excl;
__poll_t events; __poll_t events;
unsigned shared_count, seq; unsigned shared_count, seq;
@ -506,13 +506,13 @@ static struct file *dma_buf_getfile(struct dma_buf *dmabuf, int flags)
struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info) struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info)
{ {
struct dma_buf *dmabuf; struct dma_buf *dmabuf;
struct reservation_object *resv = exp_info->resv; struct dma_resv *resv = exp_info->resv;
struct file *file; struct file *file;
size_t alloc_size = sizeof(struct dma_buf); size_t alloc_size = sizeof(struct dma_buf);
int ret; int ret;
if (!exp_info->resv) if (!exp_info->resv)
alloc_size += sizeof(struct reservation_object); alloc_size += sizeof(struct dma_resv);
else else
/* prevent &dma_buf[1] == dma_buf->resv */ /* prevent &dma_buf[1] == dma_buf->resv */
alloc_size += 1; 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; dmabuf->cb_excl.active = dmabuf->cb_shared.active = 0;
if (!resv) { if (!resv) {
resv = (struct reservation_object *)&dmabuf[1]; resv = (struct dma_resv *)&dmabuf[1];
reservation_object_init(resv); dma_resv_init(resv);
} }
dmabuf->resv = resv; dmabuf->resv = resv;
@ -909,11 +909,11 @@ static int __dma_buf_begin_cpu_access(struct dma_buf *dmabuf,
{ {
bool write = (direction == DMA_BIDIRECTIONAL || bool write = (direction == DMA_BIDIRECTIONAL ||
direction == DMA_TO_DEVICE); direction == DMA_TO_DEVICE);
struct reservation_object *resv = dmabuf->resv; struct dma_resv *resv = dmabuf->resv;
long ret; long ret;
/* Wait on any implicit rendering fences */ /* 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); MAX_SCHEDULE_TIMEOUT);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -1154,8 +1154,8 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused)
int ret; int ret;
struct dma_buf *buf_obj; struct dma_buf *buf_obj;
struct dma_buf_attachment *attach_obj; struct dma_buf_attachment *attach_obj;
struct reservation_object *robj; struct dma_resv *robj;
struct reservation_object_list *fobj; struct dma_resv_list *fobj;
struct dma_fence *fence; struct dma_fence *fence;
unsigned seq; unsigned seq;
int count = 0, attach_count, shared_count, i; int count = 0, attach_count, shared_count, i;

View File

@ -13,6 +13,8 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/dma-fence-array.h> #include <linux/dma-fence-array.h>
#define PENDING_ERROR 1
static const char *dma_fence_array_get_driver_name(struct dma_fence *fence) static const char *dma_fence_array_get_driver_name(struct dma_fence *fence)
{ {
return "dma_fence_array"; return "dma_fence_array";
@ -23,10 +25,29 @@ static const char *dma_fence_array_get_timeline_name(struct dma_fence *fence)
return "unbound"; 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) static void irq_dma_fence_array_work(struct irq_work *wrk)
{ {
struct dma_fence_array *array = container_of(wrk, typeof(*array), work); 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_signal(&array->base);
dma_fence_put(&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); container_of(cb, struct dma_fence_array_cb, cb);
struct dma_fence_array *array = array_cb->array; 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)) if (atomic_dec_and_test(&array->num_pending))
irq_work_queue(&array->work); irq_work_queue(&array->work);
else else
@ -63,9 +86,14 @@ static bool dma_fence_array_enable_signaling(struct dma_fence *fence)
dma_fence_get(&array->base); dma_fence_get(&array->base);
if (dma_fence_add_callback(array->fences[i], &cb[i].cb, if (dma_fence_add_callback(array->fences[i], &cb[i].cb,
dma_fence_array_cb_func)) { dma_fence_array_cb_func)) {
int error = array->fences[i]->error;
dma_fence_array_set_pending_error(array, error);
dma_fence_put(&array->base); 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; 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); atomic_set(&array->num_pending, signal_on_any ? 1 : num_fences);
array->fences = fences; array->fences = fences;
array->base.error = PENDING_ERROR;
return array; return array;
} }
EXPORT_SYMBOL(dma_fence_array_create); EXPORT_SYMBOL(dma_fence_array_create);

View File

@ -178,8 +178,30 @@ static bool dma_fence_chain_signaled(struct dma_fence *fence)
static void dma_fence_chain_release(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_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_put(chain->fence);
dma_fence_free(fence); dma_fence_free(fence);
} }

View File

@ -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 * - Then there's also implicit fencing, where the synchronization points are
* implicitly passed around as part of shared &dma_buf instances. Such * 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. * &dma_buf.resv pointer.
*/ */
@ -129,31 +129,27 @@ EXPORT_SYMBOL(dma_fence_context_alloc);
int dma_fence_signal_locked(struct dma_fence *fence) int dma_fence_signal_locked(struct dma_fence *fence)
{ {
struct dma_fence_cb *cur, *tmp; struct dma_fence_cb *cur, *tmp;
int ret = 0; struct list_head cb_list;
lockdep_assert_held(fence->lock); lockdep_assert_held(fence->lock);
if (WARN_ON(!fence)) if (unlikely(test_and_set_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
&fence->flags)))
return -EINVAL; return -EINVAL;
if (test_and_set_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) { /* Stash the cb_list before replacing it with the timestamp */
ret = -EINVAL; list_replace(&fence->cb_list, &cb_list);
/* fence->timestamp = ktime_get();
* we might have raced with the unlocked dma_fence_signal, set_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags);
* still run through all callbacks trace_dma_fence_signaled(fence);
*/
} else {
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_for_each_entry_safe(cur, tmp, &cb_list, node) {
list_del_init(&cur->node); INIT_LIST_HEAD(&cur->node);
cur->func(fence, cur); cur->func(fence, cur);
} }
return ret;
return 0;
} }
EXPORT_SYMBOL(dma_fence_signal_locked); EXPORT_SYMBOL(dma_fence_signal_locked);
@ -173,28 +169,16 @@ EXPORT_SYMBOL(dma_fence_signal_locked);
int dma_fence_signal(struct dma_fence *fence) int dma_fence_signal(struct dma_fence *fence)
{ {
unsigned long flags; unsigned long flags;
int ret;
if (!fence) if (!fence)
return -EINVAL; return -EINVAL;
if (test_and_set_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) spin_lock_irqsave(fence->lock, flags);
return -EINVAL; ret = dma_fence_signal_locked(fence);
spin_unlock_irqrestore(fence->lock, flags);
fence->timestamp = ktime_get(); return ret;
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;
} }
EXPORT_SYMBOL(dma_fence_signal); EXPORT_SYMBOL(dma_fence_signal);
@ -248,7 +232,8 @@ void dma_fence_release(struct kref *kref)
trace_dma_fence_destroy(fence); 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 %s:%s:%llx:%llx released with pending signals!\n",
fence->ops->get_driver_name(fence), fence->ops->get_driver_name(fence),
fence->ops->get_timeline_name(fence), fence->ops->get_timeline_name(fence),

View File

@ -32,7 +32,7 @@
* Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com> * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
*/ */
#include <linux/reservation.h> #include <linux/dma-resv.h>
#include <linux/export.h> #include <linux/export.h>
/** /**
@ -56,26 +56,103 @@ const char reservation_seqcount_string[] = "reservation_seqcount";
EXPORT_SYMBOL(reservation_seqcount_string); EXPORT_SYMBOL(reservation_seqcount_string);
/** /**
* reservation_object_reserve_shared - Reserve space to add shared fences to * dma_resv_list_alloc - allocate fence list
* a reservation_object. * @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 * @obj: reservation object
* @num_fences: number of fences we want to add * @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. * be called with obj->lock held.
* *
* RETURNS * RETURNS
* Zero for success, or -errno * Zero for success, or -errno
*/ */
int reservation_object_reserve_shared(struct reservation_object *obj, int dma_resv_reserve_shared(struct dma_resv *obj, unsigned int num_fences)
unsigned int num_fences)
{ {
struct reservation_object_list *old, *new; struct dma_resv_list *old, *new;
unsigned int i, j, k, max; 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 && old->shared_max) {
if ((old->shared_count + num_fences) <= 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; max = 4;
} }
new = kmalloc(offsetof(typeof(*new), shared[max]), GFP_KERNEL); new = dma_resv_list_alloc(max);
if (!new) if (!new)
return -ENOMEM; return -ENOMEM;
@ -101,79 +178,76 @@ int reservation_object_reserve_shared(struct reservation_object *obj,
struct dma_fence *fence; struct dma_fence *fence;
fence = rcu_dereference_protected(old->shared[i], fence = rcu_dereference_protected(old->shared[i],
reservation_object_held(obj)); dma_resv_held(obj));
if (dma_fence_is_signaled(fence)) if (dma_fence_is_signaled(fence))
RCU_INIT_POINTER(new->shared[--k], fence); RCU_INIT_POINTER(new->shared[--k], fence);
else else
RCU_INIT_POINTER(new->shared[j++], fence); RCU_INIT_POINTER(new->shared[j++], fence);
} }
new->shared_count = j; new->shared_count = j;
new->shared_max = max;
preempt_disable();
write_seqcount_begin(&obj->seq);
/* /*
* RCU_INIT_POINTER can be used here, * We are not changing the effective set of fences here so can
* seqcount provides the necessary barriers * 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); rcu_assign_pointer(obj->fence, new);
write_seqcount_end(&obj->seq);
preempt_enable();
if (!old) if (!old)
return 0; return 0;
/* Drop the references to the signaled fences */ /* 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; struct dma_fence *fence;
fence = rcu_dereference_protected(new->shared[i], fence = rcu_dereference_protected(new->shared[i],
reservation_object_held(obj)); dma_resv_held(obj));
dma_fence_put(fence); dma_fence_put(fence);
} }
kfree_rcu(old, rcu); kfree_rcu(old, rcu);
return 0; 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 * @obj: the reservation object
* @fence: the shared fence to add * @fence: the shared fence to add
* *
* Add a fence to a shared slot, obj->lock must be held, and * 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, void dma_resv_add_shared_fence(struct dma_resv *obj, struct dma_fence *fence)
struct dma_fence *fence)
{ {
struct reservation_object_list *fobj; struct dma_resv_list *fobj;
struct dma_fence *old;
unsigned int i, count; unsigned int i, count;
dma_fence_get(fence); 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; count = fobj->shared_count;
preempt_disable(); preempt_disable();
write_seqcount_begin(&obj->seq); write_seqcount_begin(&obj->seq);
for (i = 0; i < count; ++i) { for (i = 0; i < count; ++i) {
struct dma_fence *old_fence;
old_fence = rcu_dereference_protected(fobj->shared[i], old = rcu_dereference_protected(fobj->shared[i],
reservation_object_held(obj)); dma_resv_held(obj));
if (old_fence->context == fence->context || if (old->context == fence->context ||
dma_fence_is_signaled(old_fence)) { dma_fence_is_signaled(old))
dma_fence_put(old_fence);
goto replace; goto replace;
}
} }
BUG_ON(fobj->shared_count >= fobj->shared_max); BUG_ON(fobj->shared_count >= fobj->shared_max);
old = NULL;
count++; count++;
replace: replace:
@ -183,26 +257,26 @@ void reservation_object_add_shared_fence(struct reservation_object *obj,
write_seqcount_end(&obj->seq); write_seqcount_end(&obj->seq);
preempt_enable(); 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 * @obj: the reservation object
* @fence: the shared fence to add * @fence: the shared fence to add
* *
* Add a fence to the exclusive slot. The obj->lock must be held. * Add a fence to the exclusive slot. The obj->lock must be held.
*/ */
void reservation_object_add_excl_fence(struct reservation_object *obj, void dma_resv_add_excl_fence(struct dma_resv *obj, struct dma_fence *fence)
struct dma_fence *fence)
{ {
struct dma_fence *old_fence = reservation_object_get_excl(obj); struct dma_fence *old_fence = dma_resv_get_excl(obj);
struct reservation_object_list *old; struct dma_resv_list *old;
u32 i = 0; 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) if (old)
i = old->shared_count; i = old->shared_count;
@ -221,28 +295,26 @@ void reservation_object_add_excl_fence(struct reservation_object *obj,
/* inplace update, no shared fences */ /* inplace update, no shared fences */
while (i--) while (i--)
dma_fence_put(rcu_dereference_protected(old->shared[i], dma_fence_put(rcu_dereference_protected(old->shared[i],
reservation_object_held(obj))); dma_resv_held(obj)));
dma_fence_put(old_fence); 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 * @dst: the destination reservation object
* @src: the source reservation object * @src: the source reservation object
* *
* Copy all fences from src to dst. dst-lock must be held. * Copy all fences from src to dst. dst-lock must be held.
*/ */
int reservation_object_copy_fences(struct reservation_object *dst, int dma_resv_copy_fences(struct dma_resv *dst, struct dma_resv *src)
struct reservation_object *src)
{ {
struct reservation_object_list *src_list, *dst_list; struct dma_resv_list *src_list, *dst_list;
struct dma_fence *old, *new; struct dma_fence *old, *new;
size_t size;
unsigned i; unsigned i;
reservation_object_assert_held(dst); dma_resv_assert_held(dst);
rcu_read_lock(); rcu_read_lock();
src_list = rcu_dereference(src->fence); src_list = rcu_dereference(src->fence);
@ -251,10 +323,9 @@ int reservation_object_copy_fences(struct reservation_object *dst,
if (src_list) { if (src_list) {
unsigned shared_count = src_list->shared_count; unsigned shared_count = src_list->shared_count;
size = offsetof(typeof(*src_list), shared[shared_count]);
rcu_read_unlock(); rcu_read_unlock();
dst_list = kmalloc(size, GFP_KERNEL); dst_list = dma_resv_list_alloc(shared_count);
if (!dst_list) if (!dst_list)
return -ENOMEM; return -ENOMEM;
@ -266,7 +337,6 @@ int reservation_object_copy_fences(struct reservation_object *dst,
} }
dst_list->shared_count = 0; dst_list->shared_count = 0;
dst_list->shared_max = shared_count;
for (i = 0; i < src_list->shared_count; ++i) { for (i = 0; i < src_list->shared_count; ++i) {
struct dma_fence *fence; struct dma_fence *fence;
@ -276,7 +346,7 @@ int reservation_object_copy_fences(struct reservation_object *dst,
continue; continue;
if (!dma_fence_get_rcu(fence)) { if (!dma_fence_get_rcu(fence)) {
kfree(dst_list); dma_resv_list_free(dst_list);
src_list = rcu_dereference(src->fence); src_list = rcu_dereference(src->fence);
goto retry; goto retry;
} }
@ -295,8 +365,8 @@ int reservation_object_copy_fences(struct reservation_object *dst,
new = dma_fence_get_rcu_safe(&src->fence_excl); new = dma_fence_get_rcu_safe(&src->fence_excl);
rcu_read_unlock(); rcu_read_unlock();
src_list = reservation_object_get_list(dst); src_list = dma_resv_get_list(dst);
old = reservation_object_get_excl(dst); old = dma_resv_get_excl(dst);
preempt_disable(); preempt_disable();
write_seqcount_begin(&dst->seq); write_seqcount_begin(&dst->seq);
@ -306,16 +376,15 @@ int reservation_object_copy_fences(struct reservation_object *dst,
write_seqcount_end(&dst->seq); write_seqcount_end(&dst->seq);
preempt_enable(); preempt_enable();
if (src_list) dma_resv_list_free(src_list);
kfree_rcu(src_list, rcu);
dma_fence_put(old); dma_fence_put(old);
return 0; 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 * fences without update side lock held
* @obj: the reservation object * @obj: the reservation object
* @pfence_excl: the returned exclusive fence (or NULL) * @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 * exclusive fence is not specified the fence is put into the array of the
* shared fences as well. Returns either zero or -ENOMEM. * shared fences as well. Returns either zero or -ENOMEM.
*/ */
int reservation_object_get_fences_rcu(struct reservation_object *obj, int dma_resv_get_fences_rcu(struct dma_resv *obj,
struct dma_fence **pfence_excl, struct dma_fence **pfence_excl,
unsigned *pshared_count, unsigned *pshared_count,
struct dma_fence ***pshared) struct dma_fence ***pshared)
{ {
struct dma_fence **shared = NULL; struct dma_fence **shared = NULL;
struct dma_fence *fence_excl; struct dma_fence *fence_excl;
@ -338,7 +407,7 @@ int reservation_object_get_fences_rcu(struct reservation_object *obj,
int ret = 1; int ret = 1;
do { do {
struct reservation_object_list *fobj; struct dma_resv_list *fobj;
unsigned int i, seq; unsigned int i, seq;
size_t sz = 0; 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])) if (!dma_fence_get_rcu(shared[i]))
break; 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)) { if (i != shared_count || read_seqcount_retry(&obj->seq, seq)) {
@ -406,6 +468,11 @@ int reservation_object_get_fences_rcu(struct reservation_object *obj,
rcu_read_unlock(); rcu_read_unlock();
} while (ret); } while (ret);
if (pfence_excl)
*pfence_excl = fence_excl;
else if (fence_excl)
shared[++shared_count] = fence_excl;
if (!shared_count) { if (!shared_count) {
kfree(shared); kfree(shared);
shared = NULL; shared = NULL;
@ -413,15 +480,12 @@ int reservation_object_get_fences_rcu(struct reservation_object *obj,
*pshared_count = shared_count; *pshared_count = shared_count;
*pshared = shared; *pshared = shared;
if (pfence_excl)
*pfence_excl = fence_excl;
return ret; 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. * shared and/or exclusive fences.
* @obj: the reservation object * @obj: the reservation object
* @wait_all: if true, wait on all fences, else wait on just exclusive fence * @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 * Returns -ERESTARTSYS if interrupted, 0 if the wait timed out, or
* greater than zer on success. * greater than zer on success.
*/ */
long reservation_object_wait_timeout_rcu(struct reservation_object *obj, long dma_resv_wait_timeout_rcu(struct dma_resv *obj,
bool wait_all, bool intr, bool wait_all, bool intr,
unsigned long timeout) unsigned long timeout)
{ {
struct dma_fence *fence; struct dma_fence *fence;
unsigned seq, shared_count; unsigned seq, shared_count;
@ -462,8 +526,7 @@ long reservation_object_wait_timeout_rcu(struct reservation_object *obj,
} }
if (wait_all) { if (wait_all) {
struct reservation_object_list *fobj = struct dma_resv_list *fobj = rcu_dereference(obj->fence);
rcu_dereference(obj->fence);
if (fobj) if (fobj)
shared_count = fobj->shared_count; shared_count = fobj->shared_count;
@ -506,11 +569,10 @@ long reservation_object_wait_timeout_rcu(struct reservation_object *obj,
rcu_read_unlock(); rcu_read_unlock();
goto retry; goto retry;
} }
EXPORT_SYMBOL_GPL(reservation_object_wait_timeout_rcu); EXPORT_SYMBOL_GPL(dma_resv_wait_timeout_rcu);
static inline int static inline int dma_resv_test_signaled_single(struct dma_fence *passed_fence)
reservation_object_test_signaled_single(struct dma_fence *passed_fence)
{ {
struct dma_fence *fence, *lfence = passed_fence; struct dma_fence *fence, *lfence = passed_fence;
int ret = 1; 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. * fences have been signaled.
* @obj: the reservation object * @obj: the reservation object
* @test_all: if true, test all fences, otherwise only test the exclusive * @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 * RETURNS
* true if all fences signaled, else false * true if all fences signaled, else false
*/ */
bool reservation_object_test_signaled_rcu(struct reservation_object *obj, bool dma_resv_test_signaled_rcu(struct dma_resv *obj, bool test_all)
bool test_all)
{ {
unsigned seq, shared_count; unsigned seq, shared_count;
int ret; int ret;
@ -551,8 +612,7 @@ bool reservation_object_test_signaled_rcu(struct reservation_object *obj,
if (test_all) { if (test_all) {
unsigned i; unsigned i;
struct reservation_object_list *fobj = struct dma_resv_list *fobj = rcu_dereference(obj->fence);
rcu_dereference(obj->fence);
if (fobj) if (fobj)
shared_count = fobj->shared_count; shared_count = fobj->shared_count;
@ -560,7 +620,7 @@ bool reservation_object_test_signaled_rcu(struct reservation_object *obj,
for (i = 0; i < shared_count; ++i) { for (i = 0; i < shared_count; ++i) {
struct dma_fence *fence = rcu_dereference(fobj->shared[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) if (ret < 0)
goto retry; goto retry;
else if (!ret) else if (!ret)
@ -575,8 +635,7 @@ bool reservation_object_test_signaled_rcu(struct reservation_object *obj,
struct dma_fence *fence_excl = rcu_dereference(obj->fence_excl); struct dma_fence *fence_excl = rcu_dereference(obj->fence_excl);
if (fence_excl) { if (fence_excl) {
ret = reservation_object_test_signaled_single( ret = dma_resv_test_signaled_single(fence_excl);
fence_excl);
if (ret < 0) if (ret < 0)
goto retry; goto retry;
@ -588,4 +647,4 @@ bool reservation_object_test_signaled_rcu(struct reservation_object *obj,
rcu_read_unlock(); rcu_read_unlock();
return ret; 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
View 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");

View 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__ */

View 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)

View 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;
}

View File

@ -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_pt *pt = dma_fence_to_sync_pt(fence);
struct sync_timeline *parent = dma_fence_parent(fence); struct sync_timeline *parent = dma_fence_parent(fence);
unsigned long flags;
spin_lock_irqsave(fence->lock, flags);
if (!list_empty(&pt->link)) { if (!list_empty(&pt->link)) {
unsigned long flags; list_del(&pt->link);
rb_erase(&pt->node, &parent->pt_tree);
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);
} }
spin_unlock_irqrestore(fence->lock, flags);
sync_timeline_put(parent); sync_timeline_put(parent);
dma_fence_free(fence); dma_fence_free(fence);
@ -265,7 +262,8 @@ static struct sync_pt *sync_pt_create(struct sync_timeline *obj,
p = &parent->rb_left; p = &parent->rb_left;
} else { } else {
if (dma_fence_get_rcu(&other->base)) { if (dma_fence_get_rcu(&other->base)) {
dma_fence_put(&pt->base); sync_timeline_put(obj);
kfree(pt);
pt = other; pt = other;
goto unlock; goto unlock;
} }

View File

@ -419,7 +419,7 @@ static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
* info->num_fences. * info->num_fences.
*/ */
if (!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; goto no_fences;
} else { } else {
info.status = 1; info.status = 1;

View File

@ -24,6 +24,10 @@ menuconfig DRM
details. You should also select and configure AGP details. You should also select and configure AGP
(/dev/agpgart) support if it is available for your platform. (/dev/agpgart) support if it is available for your platform.
config DRM_MIPI_DBI
tristate
depends on DRM
config DRM_MIPI_DSI config DRM_MIPI_DSI
bool bool
depends on DRM depends on DRM
@ -336,7 +340,7 @@ source "drivers/gpu/drm/mxsfb/Kconfig"
source "drivers/gpu/drm/meson/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" source "drivers/gpu/drm/pl111/Kconfig"

View File

@ -55,6 +55,7 @@ obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o
obj-$(CONFIG_DRM_DEBUG_SELFTEST) += selftests/ obj-$(CONFIG_DRM_DEBUG_SELFTEST) += selftests/
obj-$(CONFIG_DRM) += drm.o 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_MIPI_DSI) += drm_mipi_dsi.o
obj-$(CONFIG_DRM_PANEL_ORIENTATION_QUIRKS) += drm_panel_orientation_quirks.o obj-$(CONFIG_DRM_PANEL_ORIENTATION_QUIRKS) += drm_panel_orientation_quirks.o
obj-y += arm/ obj-y += arm/
@ -62,7 +63,6 @@ obj-$(CONFIG_DRM_TTM) += ttm/
obj-$(CONFIG_DRM_SCHED) += scheduler/ obj-$(CONFIG_DRM_SCHED) += scheduler/
obj-$(CONFIG_DRM_TDFX) += tdfx/ obj-$(CONFIG_DRM_TDFX) += tdfx/
obj-$(CONFIG_DRM_R128) += r128/ obj-$(CONFIG_DRM_R128) += r128/
obj-$(CONFIG_HSA_AMD) += amd/amdkfd/
obj-$(CONFIG_DRM_RADEON)+= radeon/ obj-$(CONFIG_DRM_RADEON)+= radeon/
obj-$(CONFIG_DRM_AMDGPU)+= amd/amdgpu/ obj-$(CONFIG_DRM_AMDGPU)+= amd/amdgpu/
obj-$(CONFIG_DRM_MGA) += mga/ obj-$(CONFIG_DRM_MGA) += mga/
@ -111,7 +111,7 @@ obj-$(CONFIG_DRM_ARCPGU)+= arc/
obj-y += hisilicon/ obj-y += hisilicon/
obj-$(CONFIG_DRM_ZTE) += zte/ obj-$(CONFIG_DRM_ZTE) += zte/
obj-$(CONFIG_DRM_MXSFB) += mxsfb/ obj-$(CONFIG_DRM_MXSFB) += mxsfb/
obj-$(CONFIG_DRM_TINYDRM) += tinydrm/ obj-y += tiny/
obj-$(CONFIG_DRM_PL111) += pl111/ obj-$(CONFIG_DRM_PL111) += pl111/
obj-$(CONFIG_DRM_TVE200) += tve200/ obj-$(CONFIG_DRM_TVE200) += tve200/
obj-$(CONFIG_DRM_XEN) += xen/ obj-$(CONFIG_DRM_XEN) += xen/

View File

@ -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_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_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_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 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 += \ 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 \ 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 # add DF block
amdgpu-y += \ amdgpu-y += \
@ -77,9 +78,13 @@ amdgpu-y += \
amdgpu-y += \ amdgpu-y += \
gmc_v7_0.o \ gmc_v7_0.o \
gmc_v8_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 gfxhub_v2_0.o mmhub_v2_0.o gmc_v10_0.o
# add UMC block
amdgpu-y += \
umc_v6_1.o
# add IH block # add IH block
amdgpu-y += \ amdgpu-y += \
amdgpu_irq.o \ amdgpu_irq.o \
@ -95,7 +100,8 @@ amdgpu-y += \
amdgpu_psp.o \ amdgpu_psp.o \
psp_v3_1.o \ psp_v3_1.o \
psp_v10_0.o \ psp_v10_0.o \
psp_v11_0.o psp_v11_0.o \
psp_v12_0.o
# add SMC block # add SMC block
amdgpu-y += \ amdgpu-y += \
@ -144,10 +150,12 @@ amdgpu-y += \
amdgpu-y += \ amdgpu-y += \
amdgpu_vcn.o \ amdgpu_vcn.o \
vcn_v1_0.o \ vcn_v1_0.o \
vcn_v2_0.o vcn_v2_0.o \
vcn_v2_5.o
# add ATHUB block # add ATHUB block
amdgpu-y += \ amdgpu-y += \
athub_v1_0.o \
athub_v2_0.o athub_v2_0.o
# add amdkfd interfaces # add amdkfd interfaces
@ -162,6 +170,7 @@ amdgpu-y += \
amdgpu_amdkfd_gpuvm.o \ amdgpu_amdkfd_gpuvm.o \
amdgpu_amdkfd_gfx_v8.o \ amdgpu_amdkfd_gfx_v8.o \
amdgpu_amdkfd_gfx_v9.o \ amdgpu_amdkfd_gfx_v9.o \
amdgpu_amdkfd_arcturus.o \
amdgpu_amdkfd_gfx_v10.o amdgpu_amdkfd_gfx_v10.o
ifneq ($(CONFIG_DRM_AMDGPU_CIK),) ifneq ($(CONFIG_DRM_AMDGPU_CIK),)

View File

@ -86,6 +86,8 @@
#include "amdgpu_smu.h" #include "amdgpu_smu.h"
#include "amdgpu_discovery.h" #include "amdgpu_discovery.h"
#include "amdgpu_mes.h" #include "amdgpu_mes.h"
#include "amdgpu_umc.h"
#include "amdgpu_mmhub.h"
#define MAX_GPU_INSTANCE 16 #define MAX_GPU_INSTANCE 16
@ -532,6 +534,14 @@ struct amdgpu_allowed_register_entry {
bool grbm_indexed; 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. * ASIC specific functions.
*/ */
@ -543,6 +553,7 @@ struct amdgpu_asic_funcs {
u32 sh_num, u32 reg_offset, u32 *value); u32 sh_num, u32 reg_offset, u32 *value);
void (*set_vga_state)(struct amdgpu_device *adev, bool state); void (*set_vga_state)(struct amdgpu_device *adev, bool state);
int (*reset)(struct amdgpu_device *adev); int (*reset)(struct amdgpu_device *adev);
enum amd_reset_method (*reset_method)(struct amdgpu_device *adev);
/* get the reference clock */ /* get the reference clock */
u32 (*get_xclk)(struct amdgpu_device *adev); u32 (*get_xclk)(struct amdgpu_device *adev);
/* MM block clocks */ /* 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 uint32_t (*amdgpu_rreg_t)(struct amdgpu_device*, uint32_t);
typedef void (*amdgpu_wreg_t)(struct amdgpu_device*, uint32_t, 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 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); 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_cp9;
u32 ref_and_mask_sdma0; u32 ref_and_mask_sdma0;
u32 ref_and_mask_sdma1; 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 { struct amdgpu_mmio_remap {
@ -668,7 +688,7 @@ struct amdgpu_nbio_funcs {
void (*sdma_doorbell_range)(struct amdgpu_device *adev, int instance, void (*sdma_doorbell_range)(struct amdgpu_device *adev, int instance,
bool use_doorbell, int doorbell_index, int doorbell_size); bool use_doorbell, int doorbell_index, int doorbell_size);
void (*vcn_doorbell_range)(struct amdgpu_device *adev, bool use_doorbell, 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, void (*enable_doorbell_aperture)(struct amdgpu_device *adev,
bool enable); bool enable);
void (*enable_doorbell_selfring_aperture)(struct amdgpu_device *adev, void (*enable_doorbell_selfring_aperture)(struct amdgpu_device *adev,
@ -705,6 +725,9 @@ struct amdgpu_df_funcs {
int is_disable); int is_disable);
void (*pmc_get_count)(struct amdgpu_device *adev, uint64_t config, void (*pmc_get_count)(struct amdgpu_device *adev, uint64_t config,
uint64_t *count); 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 */ /* Define the HW IP blocks will be used in driver , add more if necessary */
enum amd_hw_ip_block_type { enum amd_hw_ip_block_type {
@ -712,6 +735,12 @@ enum amd_hw_ip_block_type {
HDP_HWIP, HDP_HWIP,
SDMA0_HWIP, SDMA0_HWIP,
SDMA1_HWIP, SDMA1_HWIP,
SDMA2_HWIP,
SDMA3_HWIP,
SDMA4_HWIP,
SDMA5_HWIP,
SDMA6_HWIP,
SDMA7_HWIP,
MMHUB_HWIP, MMHUB_HWIP,
ATHUB_HWIP, ATHUB_HWIP,
NBIO_HWIP, NBIO_HWIP,
@ -728,10 +757,12 @@ enum amd_hw_ip_block_type {
NBIF_HWIP, NBIF_HWIP,
THM_HWIP, THM_HWIP,
CLK_HWIP, CLK_HWIP,
UMC_HWIP,
RSMU_HWIP,
MAX_HWIP MAX_HWIP
}; };
#define HWIP_MAX_INSTANCE 6 #define HWIP_MAX_INSTANCE 8
struct amd_powerplay { struct amd_powerplay {
void *pp_handle; void *pp_handle;
@ -758,7 +789,6 @@ struct amdgpu_device {
int usec_timeout; int usec_timeout;
const struct amdgpu_asic_funcs *asic_funcs; const struct amdgpu_asic_funcs *asic_funcs;
bool shutdown; bool shutdown;
bool need_dma32;
bool need_swiotlb; bool need_swiotlb;
bool accel_working; bool accel_working;
struct notifier_block acpi_nb; struct notifier_block acpi_nb;
@ -803,6 +833,8 @@ struct amdgpu_device {
amdgpu_wreg_t pcie_wreg; amdgpu_wreg_t pcie_wreg;
amdgpu_rreg_t pciep_rreg; amdgpu_rreg_t pciep_rreg;
amdgpu_wreg_t pciep_wreg; amdgpu_wreg_t pciep_wreg;
amdgpu_rreg64_t pcie_rreg64;
amdgpu_wreg64_t pcie_wreg64;
/* protects concurrent UVD register access */ /* protects concurrent UVD register access */
spinlock_t uvd_ctx_idx_lock; spinlock_t uvd_ctx_idx_lock;
amdgpu_rreg_t uvd_ctx_rreg; amdgpu_rreg_t uvd_ctx_rreg;
@ -836,6 +868,7 @@ struct amdgpu_device {
dma_addr_t dummy_page_addr; dma_addr_t dummy_page_addr;
struct amdgpu_vm_manager vm_manager; struct amdgpu_vm_manager vm_manager;
struct amdgpu_vmhub vmhub[AMDGPU_MAX_VMHUBS]; struct amdgpu_vmhub vmhub[AMDGPU_MAX_VMHUBS];
unsigned num_vmhubs;
/* memory management */ /* memory management */
struct amdgpu_mman mman; struct amdgpu_mman mman;
@ -915,6 +948,9 @@ struct amdgpu_device {
/* KFD */ /* KFD */
struct amdgpu_kfd_dev kfd; struct amdgpu_kfd_dev kfd;
/* UMC */
struct amdgpu_umc umc;
/* display related functionality */ /* display related functionality */
struct amdgpu_display_manager dm; struct amdgpu_display_manager dm;
@ -940,6 +976,7 @@ struct amdgpu_device {
const struct amdgpu_nbio_funcs *nbio_funcs; const struct amdgpu_nbio_funcs *nbio_funcs;
const struct amdgpu_df_funcs *df_funcs; const struct amdgpu_df_funcs *df_funcs;
const struct amdgpu_mmhub_funcs *mmhub_funcs;
/* delayed work_func for deferring clockgating during resume */ /* delayed work_func for deferring clockgating during resume */
struct delayed_work delayed_init_work; struct delayed_work delayed_init_work;
@ -965,6 +1002,7 @@ struct amdgpu_device {
/* record last mm index being written through WREG32*/ /* record last mm index being written through WREG32*/
unsigned long last_mm_index; unsigned long last_mm_index;
bool in_gpu_reset; bool in_gpu_reset;
enum pp_mp1_state mp1_state;
struct mutex lock_reset; struct mutex lock_reset;
struct amdgpu_doorbell_index doorbell_index; 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 WREG32_PCIE(reg, v) adev->pcie_wreg(adev, (reg), (v))
#define RREG32_PCIE_PORT(reg) adev->pciep_rreg(adev, (reg)) #define RREG32_PCIE_PORT(reg) adev->pciep_rreg(adev, (reg))
#define WREG32_PCIE_PORT(reg, v) adev->pciep_wreg(adev, (reg), (v)) #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 RREG32_SMC(reg) adev->smc_rreg(adev, (reg))
#define WREG32_SMC(reg, v) adev->smc_wreg(adev, (reg), (v)) #define WREG32_SMC(reg, v) adev->smc_wreg(adev, (reg), (v))
#define RREG32_UVD_CTX(reg) adev->uvd_ctx_rreg(adev, (reg)) #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_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(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_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_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)) #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_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_need_reset_on_init(adev) (adev)->asic_funcs->need_reset_on_init((adev))
#define amdgpu_asic_get_pcie_replay_count(adev) ((adev)->asic_funcs->get_pcie_replay_count((adev))) #define amdgpu_asic_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 */ /* Common functions */
bool amdgpu_device_should_recover_gpu(struct amdgpu_device *adev); bool amdgpu_device_should_recover_gpu(struct amdgpu_device *adev);

View File

@ -87,7 +87,12 @@ void amdgpu_amdkfd_device_probe(struct amdgpu_device *adev)
case CHIP_RAVEN: case CHIP_RAVEN:
kfd2kgd = amdgpu_amdkfd_gfx_9_0_get_functions(); kfd2kgd = amdgpu_amdkfd_gfx_9_0_get_functions();
break; break;
case CHIP_ARCTURUS:
kfd2kgd = amdgpu_amdkfd_arcturus_get_functions();
break;
case CHIP_NAVI10: case CHIP_NAVI10:
case CHIP_NAVI14:
case CHIP_NAVI12:
kfd2kgd = amdgpu_amdkfd_gfx_10_0_get_functions(); kfd2kgd = amdgpu_amdkfd_gfx_10_0_get_functions();
break; break;
default: 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; struct amdgpu_device *adev = (struct amdgpu_device *)kgd;
if (adev->powerplay.pp_funcs && if (is_support_sw_smu(adev))
adev->powerplay.pp_funcs->switch_power_profile) 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, amdgpu_dpm_switch_power_profile(adev,
PP_SMC_POWER_PROFILE_COMPUTE, PP_SMC_POWER_PROFILE_COMPUTE,
!idle); !idle);
@ -715,6 +724,11 @@ struct kfd2kgd_calls *amdgpu_amdkfd_gfx_9_0_get_functions(void)
return NULL; return NULL;
} }
struct kfd2kgd_calls *amdgpu_amdkfd_arcturus_get_functions(void)
{
return NULL;
}
struct kfd2kgd_calls *amdgpu_amdkfd_gfx_10_0_get_functions(void) struct kfd2kgd_calls *amdgpu_amdkfd_gfx_10_0_get_functions(void)
{ {
return NULL; return NULL;

View File

@ -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_7_get_functions(void);
struct kfd2kgd_calls *amdgpu_amdkfd_gfx_8_0_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_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); struct kfd2kgd_calls *amdgpu_amdkfd_gfx_10_0_get_functions(void);
bool amdgpu_amdkfd_is_kfd_vmid(struct amdgpu_device *adev, u32 vmid); bool amdgpu_amdkfd_is_kfd_vmid(struct amdgpu_device *adev, u32 vmid);

View 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;
}

View File

@ -27,7 +27,6 @@
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/firmware.h> #include <linux/firmware.h>
#include <linux/mmu_context.h> #include <linux/mmu_context.h>
#include <drm/drmP.h>
#include "amdgpu.h" #include "amdgpu.h"
#include "amdgpu_amdkfd.h" #include "amdgpu_amdkfd.h"
#include "amdgpu_ucode.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; 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) static int invalidate_tlbs_with_kiq(struct amdgpu_device *adev, uint16_t pasid)
{ {
signed long r; 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_valid(kgd, vmid)) {
if (get_atc_vmid_pasid_mapping_pasid(kgd, vmid) if (get_atc_vmid_pasid_mapping_pasid(kgd, vmid)
== pasid) { == pasid) {
write_vmid_invalidate_request(kgd, vmid); amdgpu_gmc_flush_gpu_tlb(adev, vmid,
AMDGPU_GFXHUB_0, 0);
break; break;
} }
} }
@ -896,7 +860,7 @@ static int invalidate_tlbs_vmid(struct kgd_dev *kgd, uint16_t vmid)
return 0; return 0;
} }
write_vmid_invalidate_request(kgd, vmid); amdgpu_gmc_flush_gpu_tlb(adev, vmid, AMDGPU_GFXHUB_0, 0);
return 0; return 0;
} }

View File

@ -47,6 +47,7 @@
#include "soc15d.h" #include "soc15d.h"
#include "mmhub_v1_0.h" #include "mmhub_v1_0.h"
#include "gfxhub_v1_0.h" #include "gfxhub_v1_0.h"
#include "gmc_v9_0.h"
#define V9_PIPE_PER_MEC (4) #define V9_PIPE_PER_MEC (4)
@ -58,66 +59,11 @@ enum hqd_dequeue_request_type {
RESET_WAVES 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 /* Because of REG_GET_FIELD() being used, we put this function in the
* asic specific file. * 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 tile_config *config)
{ {
struct amdgpu_device *adev = (struct amdgpu_device *)kgd; 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; 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) static inline struct amdgpu_device *get_amdgpu_device(struct kgd_dev *kgd)
{ {
return (struct amdgpu_device *)kgd; return (struct amdgpu_device *)kgd;
@ -215,7 +128,7 @@ static void release_queue(struct kgd_dev *kgd)
unlock_srbm(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_config,
uint32_t sh_mem_ape1_base, uint32_t sh_mem_ape1_base,
uint32_t sh_mem_ape1_limit, 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); 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) unsigned int vmid)
{ {
struct amdgpu_device *adev = get_amdgpu_device(kgd); 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 * 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); struct amdgpu_device *adev = get_amdgpu_device(kgd);
uint32_t mec; uint32_t mec;
@ -343,7 +256,7 @@ static inline struct v9_sdma_mqd *get_sdma_mqd(void *mqd)
return (struct v9_sdma_mqd *)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 queue_id, uint32_t __user *wptr,
uint32_t wptr_shift, uint32_t wptr_mask, uint32_t wptr_shift, uint32_t wptr_mask,
struct mm_struct *mm) 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; 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 pipe_id, uint32_t queue_id,
uint32_t (**dump)[2], uint32_t *n_regs) uint32_t (**dump)[2], uint32_t *n_regs)
{ {
@ -575,7 +488,7 @@ static int kgd_hqd_sdma_dump(struct kgd_dev *kgd,
return 0; 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) uint32_t pipe_id, uint32_t queue_id)
{ {
struct amdgpu_device *adev = get_amdgpu_device(kgd); 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; 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, enum kfd_preempt_type reset_type,
unsigned int utimeout, uint32_t pipe_id, unsigned int utimeout, uint32_t pipe_id,
uint32_t queue_id) uint32_t queue_id)
@ -704,7 +617,7 @@ static int kgd_hqd_sdma_destroy(struct kgd_dev *kgd, void *mqd,
return 0; 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) uint8_t vmid)
{ {
uint32_t reg; 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; 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) uint8_t vmid)
{ {
uint32_t reg; uint32_t reg;
@ -754,10 +667,10 @@ static int invalidate_tlbs_with_kiq(struct amdgpu_device *adev, uint16_t pasid,
return 0; 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; struct amdgpu_device *adev = (struct amdgpu_device *) kgd;
int vmid; int vmid, i;
struct amdgpu_ring *ring = &adev->gfx.kiq.ring; struct amdgpu_ring *ring = &adev->gfx.kiq.ring;
uint32_t flush_type = 0; 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++) { for (vmid = 0; vmid < 16; vmid++) {
if (!amdgpu_amdkfd_is_kfd_vmid(adev, vmid)) if (!amdgpu_amdkfd_is_kfd_vmid(adev, vmid))
continue; continue;
if (get_atc_vmid_pasid_mapping_valid(kgd, vmid)) { if (kgd_gfx_v9_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_pasid(kgd, vmid)
== pasid) { == pasid) {
amdgpu_gmc_flush_gpu_tlb(adev, vmid, for (i = 0; i < adev->num_vmhubs; i++)
flush_type); amdgpu_gmc_flush_gpu_tlb(adev, vmid,
i, flush_type);
break; break;
} }
} }
@ -786,9 +700,10 @@ static int invalidate_tlbs(struct kgd_dev *kgd, uint16_t pasid)
return 0; 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; struct amdgpu_device *adev = (struct amdgpu_device *) kgd;
int i;
if (!amdgpu_amdkfd_is_kfd_vmid(adev, vmid)) { if (!amdgpu_amdkfd_is_kfd_vmid(adev, vmid)) {
pr_err("non kfd vmid %d\n", 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 * TODO 2: support range-based invalidation, requires kfg2kgd
* interface change * 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; 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; 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, unsigned int watch_point_id,
uint32_t cntl_val, uint32_t cntl_val,
uint32_t addr_hi, uint32_t addr_hi,
@ -828,7 +745,7 @@ static int kgd_address_watch_execute(struct kgd_dev *kgd,
return 0; 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 gfx_index_val,
uint32_t sq_cmd) uint32_t sq_cmd)
{ {
@ -853,14 +770,14 @@ static int kgd_wave_control_execute(struct kgd_dev *kgd,
return 0; 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 watch_point_id,
unsigned int reg_offset) unsigned int reg_offset)
{ {
return 0; 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) uint64_t va, uint32_t vmid)
{ {
/* No longer needed on GFXv9. The scratch base address is /* 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) uint64_t page_table_base)
{ {
struct amdgpu_device *adev = get_amdgpu_device(kgd); 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 * now, all processes share the same address space size, like
* on GFX8 and older. * 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); 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;
}

View 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);

View File

@ -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, static int amdgpu_amdkfd_remove_eviction_fence(struct amdgpu_bo *bo,
struct amdgpu_amdkfd_fence *ef) struct amdgpu_amdkfd_fence *ef)
{ {
struct reservation_object *resv = bo->tbo.resv; struct dma_resv *resv = bo->tbo.base.resv;
struct reservation_object_list *old, *new; struct dma_resv_list *old, *new;
unsigned int i, j, k; unsigned int i, j, k;
if (!ef) if (!ef)
return -EINVAL; return -EINVAL;
old = reservation_object_get_list(resv); old = dma_resv_get_list(resv);
if (!old) if (!old)
return 0; return 0;
@ -241,7 +241,7 @@ static int amdgpu_amdkfd_remove_eviction_fence(struct amdgpu_bo *bo,
struct dma_fence *f; struct dma_fence *f;
f = rcu_dereference_protected(old->shared[i], f = rcu_dereference_protected(old->shared[i],
reservation_object_held(resv)); dma_resv_held(resv));
if (f->context == ef->base.context) if (f->context == ef->base.context)
RCU_INIT_POINTER(new->shared[--j], f); 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; struct dma_fence *f;
f = rcu_dereference_protected(new->shared[i], f = rcu_dereference_protected(new->shared[i],
reservation_object_held(resv)); dma_resv_held(resv));
dma_fence_put(f); dma_fence_put(f);
} }
kfree_rcu(old, rcu); 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; struct amdgpu_bo *pd = peer_vm->root.base.bo;
ret = amdgpu_sync_resv(NULL, ret = amdgpu_sync_resv(NULL,
sync, pd->tbo.resv, sync, pd->tbo.base.resv,
AMDGPU_FENCE_OWNER_KFD, false); AMDGPU_FENCE_OWNER_KFD, false);
if (ret) if (ret)
return ret; return ret;
@ -887,7 +887,7 @@ static int init_kfd_vm(struct amdgpu_vm *vm, void **process_info,
AMDGPU_FENCE_OWNER_KFD, false); AMDGPU_FENCE_OWNER_KFD, false);
if (ret) if (ret)
goto wait_pd_fail; 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) if (ret)
goto reserve_shared_fail; goto reserve_shared_fail;
amdgpu_bo_fence(vm->root.base.bo, 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) { if (flags & ALLOC_MEM_FLAGS_VRAM) {
domain = alloc_domain = AMDGPU_GEM_DOMAIN_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) ? alloc_flags |= (flags & ALLOC_MEM_FLAGS_PUBLIC) ?
AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED : AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED :
AMDGPU_GEM_CREATE_NO_CPU_ACCESS; 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 * Add process eviction fence to bo so they can
* evict each other. * 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) if (ret)
goto reserve_shared_fail; goto reserve_shared_fail;
amdgpu_bo_fence(gws_bo, &process_info->eviction_fence->base, true); amdgpu_bo_fence(gws_bo, &process_info->eviction_fence->base, true);

View File

@ -1505,6 +1505,7 @@ amdgpu_connector_add(struct amdgpu_device *adev,
struct amdgpu_connector_atom_dig *amdgpu_dig_connector; struct amdgpu_connector_atom_dig *amdgpu_dig_connector;
struct drm_encoder *encoder; struct drm_encoder *encoder;
struct amdgpu_encoder *amdgpu_encoder; struct amdgpu_encoder *amdgpu_encoder;
struct i2c_adapter *ddc = NULL;
uint32_t subpixel_order = SubPixelNone; uint32_t subpixel_order = SubPixelNone;
bool shared_ddc = false; bool shared_ddc = false;
bool is_dp_bridge = false; bool is_dp_bridge = false;
@ -1574,17 +1575,21 @@ amdgpu_connector_add(struct amdgpu_device *adev,
amdgpu_connector->con_priv = amdgpu_dig_connector; amdgpu_connector->con_priv = amdgpu_dig_connector;
if (i2c_bus->valid) { if (i2c_bus->valid) {
amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus); amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus);
if (amdgpu_connector->ddc_bus) if (amdgpu_connector->ddc_bus) {
has_aux = true; 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_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
}
} }
switch (connector_type) { switch (connector_type) {
case DRM_MODE_CONNECTOR_VGA: case DRM_MODE_CONNECTOR_VGA:
case DRM_MODE_CONNECTOR_DVIA: case DRM_MODE_CONNECTOR_DVIA:
default: default:
drm_connector_init(dev, &amdgpu_connector->base, drm_connector_init_with_ddc(dev, &amdgpu_connector->base,
&amdgpu_connector_dp_funcs, connector_type); &amdgpu_connector_dp_funcs,
connector_type,
ddc);
drm_connector_helper_add(&amdgpu_connector->base, drm_connector_helper_add(&amdgpu_connector->base,
&amdgpu_connector_dp_helper_funcs); &amdgpu_connector_dp_helper_funcs);
connector->interlace_allowed = true; connector->interlace_allowed = true;
@ -1602,8 +1607,10 @@ amdgpu_connector_add(struct amdgpu_device *adev,
case DRM_MODE_CONNECTOR_HDMIA: case DRM_MODE_CONNECTOR_HDMIA:
case DRM_MODE_CONNECTOR_HDMIB: case DRM_MODE_CONNECTOR_HDMIB:
case DRM_MODE_CONNECTOR_DisplayPort: case DRM_MODE_CONNECTOR_DisplayPort:
drm_connector_init(dev, &amdgpu_connector->base, drm_connector_init_with_ddc(dev, &amdgpu_connector->base,
&amdgpu_connector_dp_funcs, connector_type); &amdgpu_connector_dp_funcs,
connector_type,
ddc);
drm_connector_helper_add(&amdgpu_connector->base, drm_connector_helper_add(&amdgpu_connector->base,
&amdgpu_connector_dp_helper_funcs); &amdgpu_connector_dp_helper_funcs);
drm_object_attach_property(&amdgpu_connector->base.base, drm_object_attach_property(&amdgpu_connector->base.base,
@ -1644,8 +1651,10 @@ amdgpu_connector_add(struct amdgpu_device *adev,
break; break;
case DRM_MODE_CONNECTOR_LVDS: case DRM_MODE_CONNECTOR_LVDS:
case DRM_MODE_CONNECTOR_eDP: case DRM_MODE_CONNECTOR_eDP:
drm_connector_init(dev, &amdgpu_connector->base, drm_connector_init_with_ddc(dev, &amdgpu_connector->base,
&amdgpu_connector_edp_funcs, connector_type); &amdgpu_connector_edp_funcs,
connector_type,
ddc);
drm_connector_helper_add(&amdgpu_connector->base, drm_connector_helper_add(&amdgpu_connector->base,
&amdgpu_connector_dp_helper_funcs); &amdgpu_connector_dp_helper_funcs);
drm_object_attach_property(&amdgpu_connector->base.base, drm_object_attach_property(&amdgpu_connector->base.base,
@ -1659,13 +1668,18 @@ amdgpu_connector_add(struct amdgpu_device *adev,
} else { } else {
switch (connector_type) { switch (connector_type) {
case DRM_MODE_CONNECTOR_VGA: 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) { if (i2c_bus->valid) {
amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus); amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus);
if (!amdgpu_connector->ddc_bus) if (!amdgpu_connector->ddc_bus)
DRM_ERROR("VGA: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); 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; amdgpu_connector->dac_load_detect = true;
drm_object_attach_property(&amdgpu_connector->base.base, drm_object_attach_property(&amdgpu_connector->base.base,
adev->mode_info.load_detect_property, adev->mode_info.load_detect_property,
@ -1679,13 +1693,18 @@ amdgpu_connector_add(struct amdgpu_device *adev,
connector->doublescan_allowed = true; connector->doublescan_allowed = true;
break; break;
case DRM_MODE_CONNECTOR_DVIA: 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) { if (i2c_bus->valid) {
amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus); amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus);
if (!amdgpu_connector->ddc_bus) if (!amdgpu_connector->ddc_bus)
DRM_ERROR("DVIA: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); 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; amdgpu_connector->dac_load_detect = true;
drm_object_attach_property(&amdgpu_connector->base.base, drm_object_attach_property(&amdgpu_connector->base.base,
adev->mode_info.load_detect_property, adev->mode_info.load_detect_property,
@ -1704,13 +1723,18 @@ amdgpu_connector_add(struct amdgpu_device *adev,
if (!amdgpu_dig_connector) if (!amdgpu_dig_connector)
goto failed; goto failed;
amdgpu_connector->con_priv = amdgpu_dig_connector; 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) { if (i2c_bus->valid) {
amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus); amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus);
if (!amdgpu_connector->ddc_bus) if (!amdgpu_connector->ddc_bus)
DRM_ERROR("DVI: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); 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; subpixel_order = SubPixelHorizontalRGB;
drm_object_attach_property(&amdgpu_connector->base.base, drm_object_attach_property(&amdgpu_connector->base.base,
adev->mode_info.coherent_mode_property, adev->mode_info.coherent_mode_property,
@ -1754,13 +1778,18 @@ amdgpu_connector_add(struct amdgpu_device *adev,
if (!amdgpu_dig_connector) if (!amdgpu_dig_connector)
goto failed; goto failed;
amdgpu_connector->con_priv = amdgpu_dig_connector; 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) { if (i2c_bus->valid) {
amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus); amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus);
if (!amdgpu_connector->ddc_bus) if (!amdgpu_connector->ddc_bus)
DRM_ERROR("HDMI: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); 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, drm_object_attach_property(&amdgpu_connector->base.base,
adev->mode_info.coherent_mode_property, adev->mode_info.coherent_mode_property,
1); 1);
@ -1796,15 +1825,20 @@ amdgpu_connector_add(struct amdgpu_device *adev,
if (!amdgpu_dig_connector) if (!amdgpu_dig_connector)
goto failed; goto failed;
amdgpu_connector->con_priv = amdgpu_dig_connector; 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) { if (i2c_bus->valid) {
amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus); amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus);
if (amdgpu_connector->ddc_bus) if (amdgpu_connector->ddc_bus) {
has_aux = true; 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_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; subpixel_order = SubPixelHorizontalRGB;
drm_object_attach_property(&amdgpu_connector->base.base, drm_object_attach_property(&amdgpu_connector->base.base,
adev->mode_info.coherent_mode_property, adev->mode_info.coherent_mode_property,
@ -1838,15 +1872,20 @@ amdgpu_connector_add(struct amdgpu_device *adev,
if (!amdgpu_dig_connector) if (!amdgpu_dig_connector)
goto failed; goto failed;
amdgpu_connector->con_priv = amdgpu_dig_connector; 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) { if (i2c_bus->valid) {
amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus); amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus);
if (amdgpu_connector->ddc_bus) if (amdgpu_connector->ddc_bus) {
has_aux = true; 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_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, drm_object_attach_property(&amdgpu_connector->base.base,
dev->mode_config.scaling_mode_property, dev->mode_config.scaling_mode_property,
DRM_MODE_SCALE_FULLSCREEN); DRM_MODE_SCALE_FULLSCREEN);
@ -1859,13 +1898,18 @@ amdgpu_connector_add(struct amdgpu_device *adev,
if (!amdgpu_dig_connector) if (!amdgpu_dig_connector)
goto failed; goto failed;
amdgpu_connector->con_priv = amdgpu_dig_connector; 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) { if (i2c_bus->valid) {
amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus); amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus);
if (!amdgpu_connector->ddc_bus) if (!amdgpu_connector->ddc_bus)
DRM_ERROR("LVDS: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); 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, drm_object_attach_property(&amdgpu_connector->base.base,
dev->mode_config.scaling_mode_property, dev->mode_config.scaling_mode_property,
DRM_MODE_SCALE_FULLSCREEN); DRM_MODE_SCALE_FULLSCREEN);

View File

@ -402,7 +402,7 @@ static int amdgpu_cs_bo_validate(struct amdgpu_cs_parser *p,
struct ttm_operation_ctx ctx = { struct ttm_operation_ctx ctx = {
.interruptible = true, .interruptible = true,
.no_wait_gpu = false, .no_wait_gpu = false,
.resv = bo->tbo.resv, .resv = bo->tbo.base.resv,
.flags = 0 .flags = 0
}; };
uint32_t domain; 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) { list_for_each_entry(e, &p->validated, tv.head) {
struct amdgpu_bo *bo = ttm_to_amdgpu_bo(e->tv.bo); 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, r = amdgpu_sync_resv(p->adev, &p->job->sync, resv, p->filp,
amdgpu_bo_explicit_sync(bo)); amdgpu_bo_explicit_sync(bo));
@ -1732,7 +1732,7 @@ int amdgpu_cs_find_mapping(struct amdgpu_cs_parser *parser,
*map = mapping; *map = mapping;
/* Double check that the BO is reserved by this CS */ /* 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; return -EINVAL;
if (!((*bo)->flags & AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS)) { if (!((*bo)->flags & AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS)) {

View File

@ -42,7 +42,7 @@ const unsigned int amdgpu_ctx_num_entities[AMDGPU_HW_IP_NUM] = {
[AMDGPU_HW_IP_VCN_JPEG] = 1, [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; unsigned i, num_entities = 0;
@ -73,8 +73,8 @@ static int amdgpu_ctx_init(struct amdgpu_device *adev,
struct drm_file *filp, struct drm_file *filp,
struct amdgpu_ctx *ctx) struct amdgpu_ctx *ctx)
{ {
unsigned num_entities = amdgput_ctx_total_num_entities(); unsigned num_entities = amdgpu_ctx_total_num_entities();
unsigned i, j; unsigned i, j, k;
int r; int r;
if (priority < 0 || priority >= DRM_SCHED_PRIORITY_MAX) 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) { for (i = 0; i < AMDGPU_HW_IP_NUM; ++i) {
struct amdgpu_ring *rings[AMDGPU_MAX_RINGS]; struct amdgpu_ring *rings[AMDGPU_MAX_RINGS];
struct drm_sched_rq *rqs[AMDGPU_MAX_RINGS]; struct drm_sched_rq *rqs[AMDGPU_MAX_RINGS];
unsigned num_rings; unsigned num_rings = 0;
unsigned num_rqs = 0; unsigned num_rqs = 0;
switch (i) { switch (i) {
@ -154,16 +154,26 @@ static int amdgpu_ctx_init(struct amdgpu_device *adev,
num_rings = 1; num_rings = 1;
break; break;
case AMDGPU_HW_IP_VCN_DEC: case AMDGPU_HW_IP_VCN_DEC:
rings[0] = &adev->vcn.ring_dec; for (j = 0; j < adev->vcn.num_vcn_inst; ++j) {
num_rings = 1; if (adev->vcn.harvest_config & (1 << j))
continue;
rings[num_rings++] = &adev->vcn.inst[j].ring_dec;
}
break; break;
case AMDGPU_HW_IP_VCN_ENC: case AMDGPU_HW_IP_VCN_ENC:
rings[0] = &adev->vcn.ring_enc[0]; for (j = 0; j < adev->vcn.num_vcn_inst; ++j) {
num_rings = 1; 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; break;
case AMDGPU_HW_IP_VCN_JPEG: case AMDGPU_HW_IP_VCN_JPEG:
rings[0] = &adev->vcn.ring_jpeg; for (j = 0; j < adev->vcn.num_vcn_inst; ++j) {
num_rings = 1; if (adev->vcn.harvest_config & (1 << j))
continue;
rings[num_rings++] = &adev->vcn.inst[j].ring_jpeg;
}
break; break;
} }
@ -197,7 +207,7 @@ static int amdgpu_ctx_init(struct amdgpu_device *adev,
static void amdgpu_ctx_fini(struct kref *ref) static void amdgpu_ctx_fini(struct kref *ref)
{ {
struct amdgpu_ctx *ctx = container_of(ref, struct amdgpu_ctx, refcount); 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; struct amdgpu_device *adev = ctx->adev;
unsigned i, j; unsigned i, j;
@ -279,10 +289,7 @@ static void amdgpu_ctx_do_release(struct kref *ref)
ctx = container_of(ref, struct amdgpu_ctx, refcount); ctx = container_of(ref, struct amdgpu_ctx, refcount);
num_entities = 0; num_entities = amdgpu_ctx_total_num_entities();
for (i = 0; i < AMDGPU_HW_IP_NUM; i++)
num_entities += amdgpu_ctx_num_entities[i];
for (i = 0; i < num_entities; i++) for (i = 0; i < num_entities; i++)
drm_sched_entity_destroy(&ctx->entities[0][i].entity); 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 *ctx;
struct amdgpu_ctx_mgr *mgr; struct amdgpu_ctx_mgr *mgr;
uint32_t ras_counter; unsigned long ras_counter;
if (!fpriv) if (!fpriv)
return -EINVAL; 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, void amdgpu_ctx_priority_override(struct amdgpu_ctx *ctx,
enum drm_sched_priority priority) 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; enum drm_sched_priority ctx_prio;
unsigned i; 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) 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 amdgpu_ctx *ctx;
struct idr *idp; struct idr *idp;
uint32_t id, i; 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) 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 amdgpu_ctx *ctx;
struct idr *idp; struct idr *idp;
uint32_t id, i; uint32_t id, i;

View File

@ -49,8 +49,8 @@ struct amdgpu_ctx {
enum drm_sched_priority override_priority; enum drm_sched_priority override_priority;
struct mutex lock; struct mutex lock;
atomic_t guilty; atomic_t guilty;
uint32_t ras_counter_ce; unsigned long ras_counter_ce;
uint32_t ras_counter_ue; unsigned long ras_counter_ue;
}; };
struct amdgpu_ctx_mgr { struct amdgpu_ctx_mgr {

View File

@ -70,7 +70,11 @@ MODULE_FIRMWARE("amdgpu/vega12_gpu_info.bin");
MODULE_FIRMWARE("amdgpu/raven_gpu_info.bin"); MODULE_FIRMWARE("amdgpu/raven_gpu_info.bin");
MODULE_FIRMWARE("amdgpu/picasso_gpu_info.bin"); MODULE_FIRMWARE("amdgpu/picasso_gpu_info.bin");
MODULE_FIRMWARE("amdgpu/raven2_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/navi10_gpu_info.bin");
MODULE_FIRMWARE("amdgpu/navi14_gpu_info.bin");
MODULE_FIRMWARE("amdgpu/navi12_gpu_info.bin");
#define AMDGPU_RESUME_MS 2000 #define AMDGPU_RESUME_MS 2000
@ -98,7 +102,11 @@ static const char *amdgpu_asic_name[] = {
"VEGA12", "VEGA12",
"VEGA20", "VEGA20",
"RAVEN", "RAVEN",
"ARCTURUS",
"RENOIR",
"NAVI10", "NAVI10",
"NAVI14",
"NAVI12",
"LAST", "LAST",
}; };
@ -412,6 +420,40 @@ static void amdgpu_invalid_wreg(struct amdgpu_device *adev, uint32_t reg, uint32
BUG(); 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 * 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 else
chip_name = "raven"; chip_name = "raven";
break; break;
case CHIP_ARCTURUS:
chip_name = "arcturus";
break;
case CHIP_RENOIR:
chip_name = "renoir";
break;
case CHIP_NAVI10: case CHIP_NAVI10:
chip_name = "navi10"; chip_name = "navi10";
break; 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); 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_VEGA12:
case CHIP_VEGA20: case CHIP_VEGA20:
case CHIP_RAVEN: 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; adev->family = AMDGPU_FAMILY_RV;
else else
adev->family = AMDGPU_FAMILY_AI; adev->family = AMDGPU_FAMILY_AI;
@ -1539,6 +1596,8 @@ static int amdgpu_device_ip_early_init(struct amdgpu_device *adev)
return r; return r;
break; break;
case CHIP_NAVI10: case CHIP_NAVI10:
case CHIP_NAVI14:
case CHIP_NAVI12:
adev->family = AMDGPU_FAMILY_NV; adev->family = AMDGPU_FAMILY_NV;
r = nv_set_ip_blocks(adev); 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); r = amdgpu_virt_request_full_gpu(adev, true);
if (r) if (r)
return -EAGAIN; 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; 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) { if (adev->asic_type >= CHIP_VEGA10) {
for (i = 0; i < adev->num_ip_blocks; i++) { for (i = 0; i < adev->num_ip_blocks; i++) {
if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_PSP) { if (adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_PSP)
if (adev->in_gpu_reset || adev->in_suspend) { continue;
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 */ /* no need to do the fw loading again if already done*/
r = adev->ip_blocks[i].version->funcs->resume(adev); if (adev->ip_blocks[i].status.hw == true)
if (r) { break;
DRM_ERROR("resume of IP block <%s> failed %d\n",
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); adev->ip_blocks[i].version->funcs->name, r);
return r; return r;
} }
} else { } else {
r = adev->ip_blocks[i].version->funcs->hw_init(adev); r = adev->ip_blocks[i].version->funcs->hw_init(adev);
if (r) { if (r) {
DRM_ERROR("hw_init of IP block <%s> failed %d\n", DRM_ERROR("hw_init of IP block <%s> failed %d\n",
adev->ip_blocks[i].version->funcs->name, r); adev->ip_blocks[i].version->funcs->name, r);
return 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); r = amdgpu_pm_load_smu_firmware(adev, &smu_version);
return r; return r;
@ -2128,7 +2190,9 @@ static int amdgpu_device_ip_suspend_phase1(struct amdgpu_device *adev)
if (r) { if (r) {
DRM_ERROR("suspend of IP block <%s> failed %d\n", DRM_ERROR("suspend of IP block <%s> failed %d\n",
adev->ip_blocks[i].version->funcs->name, r); 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", DRM_ERROR("suspend of IP block <%s> failed %d\n",
adev->ip_blocks[i].version->funcs->name, r); 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; 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++) { for (j = 0; j < adev->num_ip_blocks; j++) {
block = &adev->ip_blocks[j]; block = &adev->ip_blocks[j];
block->status.hw = false;
if (block->version->type != ip_order[i] || if (block->version->type != ip_order[i] ||
!block->status.valid) !block->status.valid)
continue; 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"); DRM_INFO("RE-INIT-early: %s %s\n", block->version->funcs->name, r?"failed":"succeeded");
if (r) if (r)
return 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]; block = &adev->ip_blocks[j];
if (block->version->type != ip_order[i] || if (block->version->type != ip_order[i] ||
!block->status.valid) !block->status.valid ||
block->status.hw)
continue; continue;
r = block->version->funcs->hw_init(adev); r = block->version->funcs->hw_init(adev);
DRM_INFO("RE-INIT-late: %s %s\n", block->version->funcs->name, r?"failed":"succeeded"); DRM_INFO("RE-INIT-late: %s %s\n", block->version->funcs->name, r?"failed":"succeeded");
if (r) if (r)
return 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; int i, r;
for (i = 0; i < adev->num_ip_blocks; i++) { 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; continue;
if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_COMMON || 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_GMC ||
adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_IH) { adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_IH) {
r = adev->ip_blocks[i].version->funcs->resume(adev); r = adev->ip_blocks[i].version->funcs->resume(adev);
if (r) { if (r) {
DRM_ERROR("resume of IP block <%s> failed %d\n", DRM_ERROR("resume of IP block <%s> failed %d\n",
adev->ip_blocks[i].version->funcs->name, r); adev->ip_blocks[i].version->funcs->name, r);
return 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; int i, r;
for (i = 0; i < adev->num_ip_blocks; i++) { 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; continue;
if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_COMMON || 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_GMC ||
@ -2328,6 +2417,7 @@ static int amdgpu_device_ip_resume_phase2(struct amdgpu_device *adev)
adev->ip_blocks[i].version->funcs->name, r); adev->ip_blocks[i].version->funcs->name, r);
return r; return r;
} }
adev->ip_blocks[i].status.hw = true;
} }
return 0; return 0;
@ -2426,6 +2516,11 @@ bool amdgpu_device_asic_has_dc_support(enum amd_asic_type asic_type)
#endif #endif
#if defined(CONFIG_DRM_AMD_DC_DCN2_0) #if defined(CONFIG_DRM_AMD_DC_DCN2_0)
case CHIP_NAVI10: case CHIP_NAVI10:
case CHIP_NAVI14:
case CHIP_NAVI12:
#endif
#if defined(CONFIG_DRM_AMD_DC_DCN2_1)
case CHIP_RENOIR:
#endif #endif
return amdgpu_dc != 0; return amdgpu_dc != 0;
#endif #endif
@ -2509,6 +2604,8 @@ int amdgpu_device_init(struct amdgpu_device *adev,
adev->pcie_wreg = &amdgpu_invalid_wreg; adev->pcie_wreg = &amdgpu_invalid_wreg;
adev->pciep_rreg = &amdgpu_invalid_rreg; adev->pciep_rreg = &amdgpu_invalid_rreg;
adev->pciep_wreg = &amdgpu_invalid_wreg; 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_rreg = &amdgpu_invalid_rreg;
adev->uvd_ctx_wreg = &amdgpu_invalid_wreg; adev->uvd_ctx_wreg = &amdgpu_invalid_wreg;
adev->didt_rreg = &amdgpu_invalid_rreg; adev->didt_rreg = &amdgpu_invalid_rreg;
@ -3389,7 +3486,7 @@ static int amdgpu_device_reset_sriov(struct amdgpu_device *adev,
amdgpu_virt_init_data_exchange(adev); amdgpu_virt_init_data_exchange(adev);
amdgpu_virt_release_full_gpu(adev, true); amdgpu_virt_release_full_gpu(adev, true);
if (!r && adev->virt.gim_feature & AMDGIM_FEATURE_GIM_FLR_VRAMLOST) { 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); 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_VEGA20:
case CHIP_VEGA10: case CHIP_VEGA10:
case CHIP_VEGA12: case CHIP_VEGA12:
case CHIP_RAVEN:
break; break;
default: default:
goto disabled; 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); vram_lost = amdgpu_device_check_vram_lost(tmp_adev);
if (vram_lost) { if (vram_lost) {
DRM_INFO("VRAM is lost due to GPU reset!\n"); 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( 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); atomic_inc(&adev->gpu_reset_counter);
adev->in_gpu_reset = 1; 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 */ /* Block kfd: SRIOV would do it separately */
if (!amdgpu_sriov_vf(adev)) if (!amdgpu_sriov_vf(adev))
amdgpu_amdkfd_pre_reset(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)) if (!amdgpu_sriov_vf(adev))
amdgpu_amdkfd_post_reset(adev); amdgpu_amdkfd_post_reset(adev);
amdgpu_vf_error_trans_all(adev); amdgpu_vf_error_trans_all(adev);
adev->mp1_state = PP_MP1_STATE_NONE;
adev->in_gpu_reset = 0; adev->in_gpu_reset = 0;
mutex_unlock(&adev->lock_reset); 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)) { if (hive && !mutex_trylock(&hive->reset_lock)) {
DRM_INFO("Bailing on TDR for s_job:%llx, hive: %llx as another already in progress", 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; return 0;
} }
/* Start with adev pre asic reset first for soft reset check.*/ /* Start with adev pre asic reset first for soft reset check.*/
if (!amdgpu_device_lock_adev(adev, !hive)) { if (!amdgpu_device_lock_adev(adev, !hive)) {
DRM_INFO("Bailing on TDR for s_job:%llx, as another already in progress", DRM_INFO("Bailing on TDR for s_job:%llx, as another already in progress",
job->base.id); job ? job->base.id : -1);
return 0; return 0;
} }
@ -3732,7 +3842,7 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
if (!ring || !ring->sched.thread) if (!ring || !ring->sched.thread)
continue; 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*/ /* Guilty job will be freed after this*/
r = amdgpu_device_pre_asic_reset(adev, r = amdgpu_device_pre_asic_reset(adev, job, &need_full_reset);
job,
&need_full_reset);
if (r) { if (r) {
/*TODO Should we stop ?*/ /*TODO Should we stop ?*/
DRM_ERROR("GPU pre asic reset failed with err, %d for drm dev, %s ", DRM_ERROR("GPU pre asic reset failed with err, %d for drm dev, %s ",

View File

@ -191,7 +191,8 @@ int amdgpu_display_crtc_page_flip_target(struct drm_crtc *crtc,
} }
if (!adev->enable_virtual_display) { 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)) { if (unlikely(r != 0)) {
DRM_ERROR("failed to pin new abo buffer before flip\n"); DRM_ERROR("failed to pin new abo buffer before flip\n");
goto unreserve; goto unreserve;
@ -204,7 +205,7 @@ int amdgpu_display_crtc_page_flip_target(struct drm_crtc *crtc,
goto unpin; 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_count,
&work->shared); &work->shared);
if (unlikely(r != 0)) { if (unlikely(r != 0)) {
@ -495,13 +496,25 @@ static const struct drm_framebuffer_funcs amdgpu_fb_funcs = {
.create_handle = drm_gem_fb_create_handle, .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; uint32_t domain = AMDGPU_GEM_DOMAIN_VRAM;
#if defined(CONFIG_DRM_AMD_DC) #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)) amdgpu_device_asic_has_dc_support(adev->asic_type))
domain |= AMDGPU_GEM_DOMAIN_GTT; domain |= AMDGPU_GEM_DOMAIN_GTT;
#endif #endif

View File

@ -38,7 +38,8 @@
int amdgpu_display_freesync_ioctl(struct drm_device *dev, void *data, int amdgpu_display_freesync_ioctl(struct drm_device *dev, void *data,
struct drm_file *filp); struct drm_file *filp);
void amdgpu_display_update_priority(struct amdgpu_device *adev); 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 * struct drm_framebuffer *
amdgpu_display_user_framebuffer_create(struct drm_device *dev, amdgpu_display_user_framebuffer_create(struct drm_device *dev,
struct drm_file *file_priv, struct drm_file *file_priv,

View File

@ -137,23 +137,23 @@ int amdgpu_gem_prime_mmap(struct drm_gem_object *obj,
} }
static int static int
__reservation_object_make_exclusive(struct reservation_object *obj) __dma_resv_make_exclusive(struct dma_resv *obj)
{ {
struct dma_fence **fences; struct dma_fence **fences;
unsigned int count; unsigned int count;
int r; 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; return 0;
r = reservation_object_get_fences_rcu(obj, NULL, &count, &fences); r = dma_resv_get_fences_rcu(obj, NULL, &count, &fences);
if (r) if (r)
return r; return r;
if (count == 0) { if (count == 0) {
/* Now that was unexpected. */ /* Now that was unexpected. */
} else if (count == 1) { } 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]); dma_fence_put(fences[0]);
kfree(fences); kfree(fences);
} else { } else {
@ -165,7 +165,7 @@ __reservation_object_make_exclusive(struct reservation_object *obj)
if (!array) if (!array)
goto err_fences_put; 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); 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 * fences on the reservation object into a single exclusive
* fence. * fence.
*/ */
r = __reservation_object_make_exclusive(bo->tbo.resv); r = __dma_resv_make_exclusive(bo->tbo.base.resv);
if (r) if (r)
goto error_unreserve; goto error_unreserve;
} }
@ -267,20 +267,6 @@ static void amdgpu_dma_buf_map_detach(struct dma_buf *dma_buf,
drm_gem_map_detach(dma_buf, attach); 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 * amdgpu_dma_buf_begin_cpu_access - &dma_buf_ops.begin_cpu_access implementation
* @dma_buf: Shared DMA buffer * @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_bo *bo = gem_to_amdgpu_bo(dma_buf->priv);
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
struct ttm_operation_ctx ctx = { true, false }; 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; int ret;
bool reads = (direction == DMA_BIDIRECTIONAL || bool reads = (direction == DMA_BIDIRECTIONAL ||
direction == DMA_FROM_DEVICE); direction == DMA_FROM_DEVICE);
@ -339,14 +325,12 @@ const struct dma_buf_ops amdgpu_dmabuf_ops = {
* @gobj: GEM BO * @gobj: GEM BO
* @flags: Flags such as DRM_CLOEXEC and DRM_RDWR. * @flags: Flags such as DRM_CLOEXEC and DRM_RDWR.
* *
* The main work is done by the &drm_gem_prime_export helper, which in turn * The main work is done by the &drm_gem_prime_export helper.
* uses &amdgpu_gem_prime_res_obj.
* *
* Returns: * Returns:
* Shared DMA buffer representing the GEM BO from the given device. * Shared DMA buffer representing the GEM BO from the given device.
*/ */
struct dma_buf *amdgpu_gem_prime_export(struct drm_device *dev, struct dma_buf *amdgpu_gem_prime_export(struct drm_gem_object *gobj,
struct drm_gem_object *gobj,
int flags) int flags)
{ {
struct amdgpu_bo *bo = gem_to_amdgpu_bo(gobj); 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) bo->flags & AMDGPU_GEM_CREATE_VM_ALWAYS_VALID)
return ERR_PTR(-EPERM); return ERR_PTR(-EPERM);
buf = drm_gem_prime_export(dev, gobj, flags); buf = drm_gem_prime_export(gobj, flags);
if (!IS_ERR(buf)) { 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; 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 dma_buf_attachment *attach,
struct sg_table *sg) 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_device *adev = dev->dev_private;
struct amdgpu_bo *bo; struct amdgpu_bo *bo;
struct amdgpu_bo_param bp; struct amdgpu_bo_param bp;
@ -396,7 +380,7 @@ amdgpu_gem_prime_import_sg_table(struct drm_device *dev,
bp.flags = 0; bp.flags = 0;
bp.type = ttm_bo_type_sg; bp.type = ttm_bo_type_sg;
bp.resv = resv; bp.resv = resv;
ww_mutex_lock(&resv->lock, NULL); dma_resv_lock(resv, NULL);
ret = amdgpu_bo_create(adev, &bp, &bo); ret = amdgpu_bo_create(adev, &bp, &bo);
if (ret) if (ret)
goto error; goto error;
@ -408,11 +392,11 @@ amdgpu_gem_prime_import_sg_table(struct drm_device *dev,
if (attach->dmabuf->ops != &amdgpu_dmabuf_ops) if (attach->dmabuf->ops != &amdgpu_dmabuf_ops)
bo->prime_shared_count = 1; bo->prime_shared_count = 1;
ww_mutex_unlock(&resv->lock); dma_resv_unlock(resv);
return &bo->gem_base; return &bo->tbo.base;
error: error:
ww_mutex_unlock(&resv->lock); dma_resv_unlock(resv);
return ERR_PTR(ret); return ERR_PTR(ret);
} }

View File

@ -30,12 +30,10 @@ struct drm_gem_object *
amdgpu_gem_prime_import_sg_table(struct drm_device *dev, amdgpu_gem_prime_import_sg_table(struct drm_device *dev,
struct dma_buf_attachment *attach, struct dma_buf_attachment *attach,
struct sg_table *sg); struct sg_table *sg);
struct dma_buf *amdgpu_gem_prime_export(struct drm_device *dev, struct dma_buf *amdgpu_gem_prime_export(struct drm_gem_object *gobj,
struct drm_gem_object *gobj,
int flags); int flags);
struct drm_gem_object *amdgpu_gem_prime_import(struct drm_device *dev, struct drm_gem_object *amdgpu_gem_prime_import(struct drm_device *dev,
struct dma_buf *dma_buf); 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_vmap(struct drm_gem_object *obj);
void amdgpu_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr); void amdgpu_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr);
int amdgpu_gem_prime_mmap(struct drm_gem_object *obj, int amdgpu_gem_prime_mmap(struct drm_gem_object *obj,

View File

@ -130,13 +130,18 @@ typedef enum _AMDGPU_VEGA20_DOORBELL_ASSIGNMENT
AMDGPU_VEGA20_DOORBELL_IH = 0x178, AMDGPU_VEGA20_DOORBELL_IH = 0x178,
/* MMSCH: 392~407 /* MMSCH: 392~407
* overlap the doorbell assignment with VCN as they are mutually exclusive * 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_VCN2_3 = 0x189,
AMDGPU_VEGA20_DOORBELL64_VCN4_5 = 0x18A, AMDGPU_VEGA20_DOORBELL64_VCN4_5 = 0x18A,
AMDGPU_VEGA20_DOORBELL64_VCN6_7 = 0x18B, 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_RING0_1 = 0x188,
AMDGPU_VEGA20_DOORBELL64_UVD_RING2_3 = 0x189, AMDGPU_VEGA20_DOORBELL64_UVD_RING2_3 = 0x189,
AMDGPU_VEGA20_DOORBELL64_UVD_RING4_5 = 0x18A, AMDGPU_VEGA20_DOORBELL64_UVD_RING4_5 = 0x18A,

View File

@ -79,9 +79,10 @@
* - 3.31.0 - Add support for per-flip tiling attribute changes with DC * - 3.31.0 - Add support for per-flip tiling attribute changes with DC
* - 3.32.0 - Add syncobj timeline support to AMDGPU_CS. * - 3.32.0 - Add syncobj timeline support to AMDGPU_CS.
* - 3.33.0 - Fixes for GDS ENOMEM failures in 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_MAJOR 3
#define KMS_DRIVER_MINOR 33 #define KMS_DRIVER_MINOR 34
#define KMS_DRIVER_PATCHLEVEL 0 #define KMS_DRIVER_PATCHLEVEL 0
#define AMDGPU_MAX_TIMEOUT_PARAM_LENTH 256 #define AMDGPU_MAX_TIMEOUT_PARAM_LENTH 256
@ -142,7 +143,7 @@ int amdgpu_async_gfx_ring = 1;
int amdgpu_mcbp = 0; int amdgpu_mcbp = 0;
int amdgpu_discovery = -1; int amdgpu_discovery = -1;
int amdgpu_mes = 0; int amdgpu_mes = 0;
int amdgpu_noretry; int amdgpu_noretry = 1;
struct amdgpu_mgpu_info mgpu_info = { struct amdgpu_mgpu_info mgpu_info = {
.mutex = __MUTEX_INITIALIZER(mgpu_info.mutex), .mutex = __MUTEX_INITIALIZER(mgpu_info.mutex),
@ -610,7 +611,7 @@ MODULE_PARM_DESC(mes,
module_param_named(mes, amdgpu_mes, int, 0444); module_param_named(mes, amdgpu_mes, int, 0444);
MODULE_PARM_DESC(noretry, 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); module_param_named(noretry, amdgpu_noretry, int, 0644);
#ifdef CONFIG_HSA_AMD #ifdef CONFIG_HSA_AMD
@ -996,6 +997,11 @@ static const struct pci_device_id pciidlist[] = {
/* Raven */ /* Raven */
{0x1002, 0x15dd, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RAVEN|AMD_IS_APU}, {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}, {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 */ /* Navi10 */
{0x1002, 0x7310, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_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}, {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, 0x731A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_NAVI10},
{0x1002, 0x731B, 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}, {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} {0, 0, 0}
}; };
@ -1092,21 +1103,21 @@ amdgpu_pci_shutdown(struct pci_dev *pdev)
* unfortunately we can't detect certain * unfortunately we can't detect certain
* hypervisors so just do this all the time. * hypervisors so just do this all the time.
*/ */
adev->mp1_state = PP_MP1_STATE_UNLOAD;
amdgpu_device_ip_suspend(adev); amdgpu_device_ip_suspend(adev);
adev->mp1_state = PP_MP1_STATE_NONE;
} }
static int amdgpu_pmops_suspend(struct device *dev) 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); return amdgpu_device_suspend(drm_dev, true, true);
} }
static int amdgpu_pmops_resume(struct device *dev) static int amdgpu_pmops_resume(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);
/* GPU comes up enabled by the bios on resume */ /* GPU comes up enabled by the bios on resume */
if (amdgpu_device_is_px(drm_dev)) { 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) 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); return amdgpu_device_suspend(drm_dev, false, true);
} }
static int amdgpu_pmops_thaw(struct device *dev) 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); return amdgpu_device_resume(drm_dev, false, true);
} }
static int amdgpu_pmops_poweroff(struct device *dev) 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); return amdgpu_device_suspend(drm_dev, true, true);
} }
static int amdgpu_pmops_restore(struct device *dev) 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); 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) static int amdgpu_pmops_runtime_idle(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);
struct drm_crtc *crtc; struct drm_crtc *crtc;
if (!amdgpu_device_is_px(drm_dev)) { if (!amdgpu_device_is_px(drm_dev)) {
@ -1373,7 +1379,7 @@ static struct drm_driver kms_driver = {
.driver_features = .driver_features =
DRIVER_USE_AGP | DRIVER_ATOMIC | DRIVER_USE_AGP | DRIVER_ATOMIC |
DRIVER_GEM | DRIVER_GEM |
DRIVER_PRIME | DRIVER_RENDER | DRIVER_MODESET | DRIVER_SYNCOBJ, DRIVER_RENDER | DRIVER_MODESET | DRIVER_SYNCOBJ,
.load = amdgpu_driver_load_kms, .load = amdgpu_driver_load_kms,
.open = amdgpu_driver_open_kms, .open = amdgpu_driver_open_kms,
.postclose = amdgpu_driver_postclose_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, .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
.gem_prime_export = amdgpu_gem_prime_export, .gem_prime_export = amdgpu_gem_prime_export,
.gem_prime_import = amdgpu_gem_prime_import, .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_get_sg_table = amdgpu_gem_prime_get_sg_table,
.gem_prime_import_sg_table = amdgpu_gem_prime_import_sg_table, .gem_prime_import_sg_table = amdgpu_gem_prime_import_sg_table,
.gem_prime_vmap = amdgpu_gem_prime_vmap, .gem_prime_vmap = amdgpu_gem_prime_vmap,

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