main drm pull request for 4.12 kernel
-----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJZCTzvAAoJEAx081l5xIa+9kcQAJsQiija4/7QGx6IzakOMqjx WulJ3zYG/cU/HLwCBcuWRDF6wAj+7iWNeLCPmolHwEazcI8tQVdgMlWtbdMbDh8U ckzD3FBXsEVfIfab+u6tyoUkm3l/VDhMXbjkUK7NTo/+dkRqe5LuFfZPCGN09jft Y+5salkRXzDhXPSFsqmjfzhx1v7PTgf0a5HUenKWEWOv+sJQaW4/iPvcDSIcg5qR l9WjAqro1NpFYhUodnh6DkLeledL1U5whdtp/yvrUAck8y+WP/jwGYmQ7pZ0UkQm f0M3kV6K67ox9eqN++jsGX5o8sB1qF01Uh95kBAnyzYzsw4ZlMCx6pV7PDX+J88M UBNMEqX10hrLkNJA9lGjPWx+/6fudcwg9anKvTRO3Uyx7MbYoJAgjzAM+yBqqtV0 8Otxa4Bw0V2pmUD+0lqJDERRvE77VCXkLb8SaI5lQo0MHpQqT2cZA+GD+B+rZHO6 Ie5LDFY87vM2GG1IECufG+xOa3v6sn2FfQ1ouu1KNGKOAMBKcQCQyQx3kGVuNW2i HDACVXALJgXdRlVLm4jydOCZdRoguX7AWmRjtdwxgaO+lBcGfLhkXdjLQ7Ho+29p 32ArJfkZPfA53vMB6lHxAfbtrs1q2RzyVnPHj/KqeJnGZbABKTsF2HQ5BQc4Xq/J mqXoz6Oubdvk4Pwyx7Ne =UxFF -----END PGP SIGNATURE----- Merge tag 'drm-for-v4.12' of git://people.freedesktop.org/~airlied/linux Pull drm u pdates from Dave Airlie: "This is the main drm pull request for v4.12. Apart from two fixes pulls, everything should have been in drm-next for at least 2 weeks. The biggest thing in here is AMD released the public headers for their upcoming VEGA GPUs. These as always are quite a sizeable chunk of header files. They've also added initial non-display support for those GPUs, though they aren't available in production yet. Otherwise it's pretty much normal. New bridge drivers: - megachips-stdpxxxx-ge-b850v3-fw LVDS->DP++ - generic LVDS bridge support. Core: - Displayport link train failure reporting to userspace - debugfs interface cleaned up - subsystem TODO in kerneldoc now - Extended fbdev support (flipping and vblank wait) - drm_platform removed - EDP CRC support in helper - HF-VSDB SCDC support in EDID parser - Lots of code cleanups and header extraction - Thunderbolt external GPU awareness - Atomic helper improvements - Documentation improvements panel: - Sitronix and Samsung new panel support amdgpu: - Preliminary vega10 support - Multi-level page table support - GPU sensor support for userspace - PRT support for sparse buffers - SR-IOV improvements - Non-contig VRAM CPU mapping i915: - Atomic modesetting enabled by default on Gen5+ - LSPCON improvements - Atomic state handling for cdclk - GPU reset improvements - In-kernel unit tests - Geminilake improvements and color manager support - Designware i2c fixes - vblank evasion improvements - Hotplug safe connector iterators - GVT scheduler QoS support - GVT Kabylake support nouveau: - Acceleration support for Pascal (GP10x). - Rearchitecture of code handling proprietary signed firmware - Fix GTX 970 with odd MMU configuration - GP10B support - GP107 acceleration support vmwgfx: - Atomic modesetting support for vmwgfx omapdrm: - Support for render nodes - Refactor omapdss code - Fix some probe ordering issues - Fix too dark RGB565 rendering sunxi: - prelim rework for multiple pipes. mali-dp: - Color management support - Plane scaling - Power management improvements imx-drm: - Prefetch Resolve Engine/Gasket on i.MX6QP - Deferred plane disabling - Separate alpha support mediatek: - Mediatek SoC MT2701 support rcar-du: - Gen3 HDMI support msm: - 4k support for newer chips - OPP bindings for gpu - prep work for per-process pagetables vc4: - HDMI audio support - fixes qxl: - minor fixes. dw-hdmi: - PHY improvements - CSC fixes - Amlogic GX SoC support" * tag 'drm-for-v4.12' of git://people.freedesktop.org/~airlied/linux: (1778 commits) drm/nouveau/fb/gf100-: Fix 32 bit wraparound in new ram detection drm/nouveau/secboot/gm20b: fix the error return code in gm20b_secboot_tegra_read_wpr() drm/nouveau/kms: Increase max retries in scanout position queries. drm/nouveau/bios/bitP: check that table is long enough for optional pointers drm/nouveau/fifo/nv40: no ctxsw for pre-nv44 mpeg engine drm: mali-dp: use div_u64 for expensive 64-bit divisions drm/i915: Confirm the request is still active before adding it to the await drm/i915: Avoid busy-spinning on VLV_GLTC_PW_STATUS mmio drm/i915/selftests: Allocate inode/file dynamically drm/i915: Fix system hang with EI UP masked on Haswell drm/i915: checking for NULL instead of IS_ERR() in mock selftests drm/i915: Perform link quality check unconditionally during long pulse drm/i915: Fix use after free in lpe_audio_platdev_destroy() drm/i915: Use the right mapping_gfp_mask for final shmem allocation drm/i915: Make legacy cursor updates more unsynced drm/i915: Apply a cond_resched() to the saturated signaler drm/i915: Park the signaler before sleeping drm: mali-dp: Check the mclk rate and allow up/down scaling drm: mali-dp: Enable image enhancement when scaling drm: mali-dp: Add plane upscaling support ...
This commit is contained in:
commit
2f34c1231b
@ -59,9 +59,9 @@
|
||||
/* Fixed header pattern */
|
||||
header: .byte 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0x00
|
||||
|
||||
mfg_id: .word swap16(mfgname2id(MFG_LNX1, MFG_LNX2, MFG_LNX3))
|
||||
mfg_id: .hword swap16(mfgname2id(MFG_LNX1, MFG_LNX2, MFG_LNX3))
|
||||
|
||||
prod_code: .word 0
|
||||
prod_code: .hword 0
|
||||
|
||||
/* Serial number. 32 bits, little endian. */
|
||||
serial_number: .long SERIAL
|
||||
@ -177,7 +177,7 @@ std_vres: .byte (XY_RATIO<<6)+VFREQ-60
|
||||
|
||||
descriptor1:
|
||||
/* Pixel clock in 10 kHz units. (0.-655.35 MHz, little-endian) */
|
||||
clock: .word CLOCK/10
|
||||
clock: .hword CLOCK/10
|
||||
|
||||
/* Horizontal active pixels 8 lsbits (0-4095) */
|
||||
x_act_lsb: .byte XPIX&0xff
|
||||
|
@ -0,0 +1,111 @@
|
||||
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"
|
||||
- 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"
|
||||
|
||||
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
|
||||
|
||||
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>;
|
||||
};
|
||||
};
|
||||
};
|
@ -34,6 +34,9 @@ Optional properties for HDMI:
|
||||
- hpd-gpios: The GPIO pin for HDMI hotplug detect (if it doesn't appear
|
||||
as an interrupt/status bit in the HDMI controller
|
||||
itself). See bindings/pinctrl/brcm,bcm2835-gpio.txt
|
||||
- dmas: Should contain one entry pointing to the DMA channel used to
|
||||
transfer audio data
|
||||
- dma-names: Should contain "audio-rx"
|
||||
|
||||
Required properties for DPI:
|
||||
- compatible: Should be "brcm,bcm2835-dpi"
|
||||
|
@ -0,0 +1,64 @@
|
||||
Parallel to LVDS Encoder
|
||||
------------------------
|
||||
|
||||
This binding supports the parallel to LVDS encoders that don't require any
|
||||
configuration.
|
||||
|
||||
LVDS is a physical layer specification defined in ANSI/TIA/EIA-644-A. Multiple
|
||||
incompatible data link layers have been used over time to transmit image data
|
||||
to LVDS panels. This binding targets devices compatible with the following
|
||||
specifications only.
|
||||
|
||||
[JEIDA] "Digital Interface Standards for Monitor", JEIDA-59-1999, February
|
||||
1999 (Version 1.0), Japan Electronic Industry Development Association (JEIDA)
|
||||
[LDI] "Open LVDS Display Interface", May 1999 (Version 0.95), National
|
||||
Semiconductor
|
||||
[VESA] "VESA Notebook Panel Standard", October 2007 (Version 1.0), Video
|
||||
Electronics Standards Association (VESA)
|
||||
|
||||
Those devices have been marketed under the FPD-Link and FlatLink brand names
|
||||
among others.
|
||||
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: Must be "lvds-encoder"
|
||||
|
||||
Required nodes:
|
||||
|
||||
This device has two video ports. Their connections are modeled using the OF
|
||||
graph bindings specified in Documentation/devicetree/bindings/graph.txt.
|
||||
|
||||
- Video port 0 for parallel input
|
||||
- Video port 1 for LVDS output
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
lvds-encoder {
|
||||
compatible = "lvds-encoder";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
|
||||
lvds_enc_in: endpoint {
|
||||
remote-endpoint = <&display_out_rgb>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
|
||||
lvds_enc_out: endpoint {
|
||||
remote-endpoint = <&lvds_panel_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
@ -0,0 +1,94 @@
|
||||
Drivers for the second video output of the GE B850v3:
|
||||
STDP4028-ge-b850v3-fw bridges (LVDS-DP)
|
||||
STDP2690-ge-b850v3-fw bridges (DP-DP++)
|
||||
|
||||
The video processing pipeline on the second output on the GE B850v3:
|
||||
|
||||
Host -> LVDS|--(STDP4028)--|DP -> DP|--(STDP2690)--|DP++ -> Video output
|
||||
|
||||
Each bridge has a dedicated flash containing firmware for supporting the custom
|
||||
design. The result is that, in this design, neither the STDP4028 nor the
|
||||
STDP2690 behave as the stock bridges would. The compatible strings include the
|
||||
suffix "-ge-b850v3-fw" to make it clear that the driver is for the bridges with
|
||||
the firmware specific for the GE B850v3.
|
||||
|
||||
The hardware do not provide control over the video processing pipeline, as the
|
||||
two bridges behaves as a single one. The only interfaces exposed by the
|
||||
hardware are EDID, HPD, and interrupts.
|
||||
|
||||
stdp4028-ge-b850v3-fw required properties:
|
||||
- compatible : "megachips,stdp4028-ge-b850v3-fw"
|
||||
- reg : I2C bus address
|
||||
- interrupt-parent : phandle of the interrupt controller that services
|
||||
interrupts to the device
|
||||
- interrupts : one interrupt should be described here, as in
|
||||
<0 IRQ_TYPE_LEVEL_HIGH>
|
||||
- ports : One input port(reg = <0>) and one output port(reg = <1>)
|
||||
|
||||
stdp2690-ge-b850v3-fw required properties:
|
||||
compatible : "megachips,stdp2690-ge-b850v3-fw"
|
||||
- reg : I2C bus address
|
||||
- ports : One input port(reg = <0>) and one output port(reg = <1>)
|
||||
|
||||
Example:
|
||||
|
||||
&mux2_i2c2 {
|
||||
status = "okay";
|
||||
clock-frequency = <100000>;
|
||||
|
||||
stdp4028@73 {
|
||||
compatible = "megachips,stdp4028-ge-b850v3-fw";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
reg = <0x73>;
|
||||
|
||||
interrupt-parent = <&gpio2>;
|
||||
interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
stdp4028_in: endpoint {
|
||||
remote-endpoint = <&lvds0_out>;
|
||||
};
|
||||
};
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
stdp4028_out: endpoint {
|
||||
remote-endpoint = <&stdp2690_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
stdp2690@72 {
|
||||
compatible = "megachips,stdp2690-ge-b850v3-fw";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
reg = <0x72>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
stdp2690_in: endpoint {
|
||||
remote-endpoint = <&stdp4028_out>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
stdp2690_out: endpoint {
|
||||
/* Connector for external display */
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
@ -0,0 +1,75 @@
|
||||
Renesas Gen3 DWC HDMI TX Encoder
|
||||
================================
|
||||
|
||||
The HDMI transmitter is a Synopsys DesignWare HDMI 1.4 TX controller IP
|
||||
with a companion PHY IP.
|
||||
|
||||
These DT bindings follow the Synopsys DWC HDMI TX bindings defined in
|
||||
Documentation/devicetree/bindings/display/bridge/dw_hdmi.txt with the
|
||||
following device-specific properties.
|
||||
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : Shall contain one or more of
|
||||
- "renesas,r8a7795-hdmi" for R8A7795 (R-Car H3) compatible HDMI TX
|
||||
- "renesas,rcar-gen3-hdmi" for the generic R-Car Gen3 compatible HDMI TX
|
||||
|
||||
When compatible with generic versions, nodes must list the SoC-specific
|
||||
version corresponding to the platform first, followed by the
|
||||
family-specific version.
|
||||
|
||||
- reg: See dw_hdmi.txt.
|
||||
- interrupts: HDMI interrupt number
|
||||
- clocks: See dw_hdmi.txt.
|
||||
- clock-names: Shall contain "iahb" and "isfr" as defined in dw_hdmi.txt.
|
||||
- ports: See dw_hdmi.txt. The DWC HDMI shall have one port numbered 0
|
||||
corresponding to the video input of the controller and one port numbered 1
|
||||
corresponding to its HDMI output. Each port shall have a single endpoint.
|
||||
|
||||
Optional properties:
|
||||
|
||||
- power-domains: Shall reference the power domain that contains the DWC HDMI,
|
||||
if any.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
hdmi0: hdmi0@fead0000 {
|
||||
compatible = "renesas,r8a7795-dw-hdmi";
|
||||
reg = <0 0xfead0000 0 0x10000>;
|
||||
interrupts = <0 389 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cpg CPG_CORE R8A7795_CLK_S0D4>, <&cpg CPG_MOD 729>;
|
||||
clock-names = "iahb", "isfr";
|
||||
power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
|
||||
status = "disabled";
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
dw_hdmi0_in: endpoint {
|
||||
remote-endpoint = <&du_out_hdmi0>;
|
||||
};
|
||||
};
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
rcar_dw_hdmi0_out: endpoint {
|
||||
remote-endpoint = <&hdmi0_con>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
hdmi0-out {
|
||||
compatible = "hdmi-connector";
|
||||
label = "HDMI0 OUT";
|
||||
type = "a";
|
||||
|
||||
port {
|
||||
hdmi0_con: endpoint {
|
||||
remote-endpoint = <&rcar_dw_hdmi0_out>;
|
||||
};
|
||||
};
|
||||
};
|
@ -21,13 +21,19 @@ Freescale i.MX IPUv3
|
||||
====================
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "fsl,<chip>-ipu"
|
||||
- compatible: Should be "fsl,<chip>-ipu" where <chip> is one of
|
||||
- imx51
|
||||
- imx53
|
||||
- imx6q
|
||||
- imx6qp
|
||||
- reg: should be register base and length as documented in the
|
||||
datasheet
|
||||
- interrupts: Should contain sync interrupt and error interrupt,
|
||||
in this order.
|
||||
- resets: phandle pointing to the system reset controller and
|
||||
reset line index, see reset/fsl,imx-src.txt for details
|
||||
Additional required properties for fsl,imx6qp-ipu:
|
||||
- fsl,prg: phandle to prg node associated with this IPU instance
|
||||
Optional properties:
|
||||
- port@[0-3]: Port nodes with endpoint definitions as defined in
|
||||
Documentation/devicetree/bindings/media/video-interfaces.txt.
|
||||
@ -53,6 +59,57 @@ ipu: ipu@18000000 {
|
||||
};
|
||||
};
|
||||
|
||||
Freescale i.MX PRE (Prefetch Resolve Engine)
|
||||
============================================
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "fsl,imx6qp-pre"
|
||||
- reg: should be register base and length as documented in the
|
||||
datasheet
|
||||
- clocks : phandle to the PRE axi clock input, as described
|
||||
in Documentation/devicetree/bindings/clock/clock-bindings.txt and
|
||||
Documentation/devicetree/bindings/clock/imx6q-clock.txt.
|
||||
- clock-names: should be "axi"
|
||||
- interrupts: should contain the PRE interrupt
|
||||
- fsl,iram: phandle pointing to the mmio-sram device node, that should be
|
||||
used for the PRE SRAM double buffer.
|
||||
|
||||
example:
|
||||
|
||||
pre@21c8000 {
|
||||
compatible = "fsl,imx6qp-pre";
|
||||
reg = <0x021c8000 0x1000>;
|
||||
interrupts = <GIC_SPI 90 IRQ_TYPE_EDGE_RISING>;
|
||||
clocks = <&clks IMX6QDL_CLK_PRE0>;
|
||||
clock-names = "axi";
|
||||
fsl,iram = <&ocram2>;
|
||||
};
|
||||
|
||||
Freescale i.MX PRG (Prefetch Resolve Gasket)
|
||||
============================================
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "fsl,imx6qp-prg"
|
||||
- reg: should be register base and length as documented in the
|
||||
datasheet
|
||||
- clocks : phandles to the PRG ipg and axi clock inputs, as described
|
||||
in Documentation/devicetree/bindings/clock/clock-bindings.txt and
|
||||
Documentation/devicetree/bindings/clock/imx6q-clock.txt.
|
||||
- clock-names: should be "ipg" and "axi"
|
||||
- fsl,pres: phandles to the PRE units attached to this PRG, with the fixed
|
||||
PRE as the first entry and the muxable PREs following.
|
||||
|
||||
example:
|
||||
|
||||
prg@21cc000 {
|
||||
compatible = "fsl,imx6qp-prg";
|
||||
reg = <0x021cc000 0x1000>;
|
||||
clocks = <&clks IMX6QDL_CLK_PRG0_APB>,
|
||||
<&clks IMX6QDL_CLK_PRG0_AXI>;
|
||||
clock-names = "ipg", "axi";
|
||||
fsl,pres = <&pre1>, <&pre2>, <&pre3>;
|
||||
};
|
||||
|
||||
Parallel display support
|
||||
========================
|
||||
|
||||
|
@ -40,6 +40,7 @@ Required properties (all function blocks):
|
||||
"mediatek,<chip>-dpi" - DPI controller, see mediatek,dpi.txt
|
||||
"mediatek,<chip>-disp-mutex" - display mutex
|
||||
"mediatek,<chip>-disp-od" - overdrive
|
||||
the supported chips are mt2701 and mt8173.
|
||||
- reg: Physical base address and length of the function block register space
|
||||
- interrupts: The interrupt signal from the function block (required, except for
|
||||
merge and split function blocks).
|
||||
@ -54,6 +55,7 @@ Required properties (DMA function blocks):
|
||||
"mediatek,<chip>-disp-ovl"
|
||||
"mediatek,<chip>-disp-rdma"
|
||||
"mediatek,<chip>-disp-wdma"
|
||||
the supported chips are mt2701 and mt8173.
|
||||
- larb: Should contain a phandle pointing to the local arbiter device as defined
|
||||
in Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.txt
|
||||
- iommus: Should point to the respective IOMMU block with master port as
|
||||
|
@ -7,6 +7,7 @@ channel output.
|
||||
|
||||
Required properties:
|
||||
- compatible: "mediatek,<chip>-dsi"
|
||||
the supported chips are mt2701 and mt8173.
|
||||
- reg: Physical base address and length of the controller's registers
|
||||
- interrupts: The interrupt signal from the function block.
|
||||
- clocks: device clocks
|
||||
@ -25,6 +26,7 @@ The MIPI TX configuration module controls the MIPI D-PHY.
|
||||
|
||||
Required properties:
|
||||
- compatible: "mediatek,<chip>-mipi-tx"
|
||||
the supported chips are mt2701 and mt8173.
|
||||
- reg: Physical base address and length of the controller's registers
|
||||
- clocks: PLL reference clock
|
||||
- clock-output-names: name of the output clock line to the DSI encoder
|
||||
|
@ -0,0 +1,26 @@
|
||||
Ampire AM-480272H3TMQW-T01H 4.3" WQVGA TFT LCD panel
|
||||
|
||||
This binding is compatible with the simple-panel binding, which is specified
|
||||
in simple-panel.txt in this directory.
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "ampire,am-480272h3tmqw-t01h"
|
||||
|
||||
Optional properties:
|
||||
- power-supply: regulator to provide the supply voltage
|
||||
- enable-gpios: GPIO pin to enable or disable the panel
|
||||
- backlight: phandle of the backlight device attached to the panel
|
||||
|
||||
Optional nodes:
|
||||
- Video port for RGB input.
|
||||
|
||||
Example:
|
||||
panel_rgb: panel-rgb {
|
||||
compatible = "ampire,am-480272h3tmqw-t01h";
|
||||
enable-gpios = <&gpioa 8 1>;
|
||||
port {
|
||||
panel_in_rgb: endpoint {
|
||||
remote-endpoint = <&controller_out_rgb>;
|
||||
};
|
||||
};
|
||||
};
|
@ -0,0 +1,47 @@
|
||||
Mitsubishi AA204XD12 LVDS Display Panel
|
||||
=======================================
|
||||
|
||||
The AA104XD12 is a 10.4" XGA TFT-LCD display panel.
|
||||
|
||||
These DT bindings follow the LVDS panel bindings defined in panel-lvds.txt
|
||||
with the following device-specific properties.
|
||||
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: Shall contain "mitsubishi,aa121td01" and "panel-lvds", in that
|
||||
order.
|
||||
- vcc-supply: Reference to the regulator powering the panel VCC pins.
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
panel {
|
||||
compatible = "mitsubishi,aa104xd12", "panel-lvds";
|
||||
vcc-supply = <&vcc_3v3>;
|
||||
|
||||
width-mm = <210>;
|
||||
height-mm = <158>;
|
||||
|
||||
data-mapping = "jeida-24";
|
||||
|
||||
panel-timing {
|
||||
/* 1024x768 @65Hz */
|
||||
clock-frequency = <65000000>;
|
||||
hactive = <1024>;
|
||||
vactive = <768>;
|
||||
hsync-len = <136>;
|
||||
hfront-porch = <20>;
|
||||
hback-porch = <160>;
|
||||
vfront-porch = <3>;
|
||||
vback-porch = <29>;
|
||||
vsync-len = <6>;
|
||||
};
|
||||
|
||||
port {
|
||||
panel_in: endpoint {
|
||||
remote-endpoint = <&lvds_encoder>;
|
||||
};
|
||||
};
|
||||
};
|
@ -0,0 +1,47 @@
|
||||
Mitsubishi AA121TD01 LVDS Display Panel
|
||||
=======================================
|
||||
|
||||
The AA121TD01 is a 12.1" WXGA TFT-LCD display panel.
|
||||
|
||||
These DT bindings follow the LVDS panel bindings defined in panel-lvds.txt
|
||||
with the following device-specific properties.
|
||||
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: Shall contain "mitsubishi,aa121td01" and "panel-lvds", in that
|
||||
order.
|
||||
- vcc-supply: Reference to the regulator powering the panel VCC pins.
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
panel {
|
||||
compatible = "mitsubishi,aa121td01", "panel-lvds";
|
||||
vcc-supply = <&vcc_3v3>;
|
||||
|
||||
width-mm = <261>;
|
||||
height-mm = <163>;
|
||||
|
||||
data-mapping = "jeida-24";
|
||||
|
||||
panel-timing {
|
||||
/* 1280x800 @60Hz */
|
||||
clock-frequency = <71000000>;
|
||||
hactive = <1280>;
|
||||
vactive = <800>;
|
||||
hsync-len = <70>;
|
||||
hfront-porch = <20>;
|
||||
hback-porch = <70>;
|
||||
vsync-len = <5>;
|
||||
vfront-porch = <3>;
|
||||
vback-porch = <15>;
|
||||
};
|
||||
|
||||
port {
|
||||
panel_in: endpoint {
|
||||
remote-endpoint = <&lvds_encoder>;
|
||||
};
|
||||
};
|
||||
};
|
@ -0,0 +1,91 @@
|
||||
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/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.
|
||||
|
||||
|
||||
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.
|
@ -9,6 +9,7 @@ Optional properties:
|
||||
- enable-gpios: panel enable gpio
|
||||
- reset-gpios: GPIO to control the RESET pin
|
||||
- vcc-supply: phandle of regulator that will be used to enable power to the display
|
||||
- backlight: phandle of the backlight device
|
||||
|
||||
Required nodes:
|
||||
- "panel-timing" containing video timings
|
||||
@ -22,6 +23,8 @@ lcd0: display@0 {
|
||||
compatible = "samsung,lte430wq-f0c", "panel-dpi";
|
||||
label = "lcd";
|
||||
|
||||
backlight = <&backlight>;
|
||||
|
||||
port {
|
||||
lcd_in: endpoint {
|
||||
remote-endpoint = <&dpi_out>;
|
||||
|
120
Documentation/devicetree/bindings/display/panel/panel-lvds.txt
Normal file
120
Documentation/devicetree/bindings/display/panel/panel-lvds.txt
Normal file
@ -0,0 +1,120 @@
|
||||
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.
|
||||
- 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>;
|
||||
};
|
||||
};
|
||||
};
|
@ -0,0 +1,28 @@
|
||||
Samsung S6E3HA2 5.7" 1440x2560 AMOLED panel
|
||||
|
||||
Required properties:
|
||||
- compatible: "samsung,s6e3ha2"
|
||||
- reg: the virtual channel number of a DSI peripheral
|
||||
- vdd3-supply: I/O voltage supply
|
||||
- vci-supply: voltage supply for analog circuits
|
||||
- reset-gpios: a GPIO spec for the reset pin (active low)
|
||||
- enable-gpios: a GPIO spec for the panel enable pin (active high)
|
||||
|
||||
Optional properties:
|
||||
- te-gpios: a GPIO spec for the tearing effect synchronization signal
|
||||
gpio pin (active high)
|
||||
|
||||
Example:
|
||||
&dsi {
|
||||
...
|
||||
|
||||
panel@0 {
|
||||
compatible = "samsung,s6e3ha2";
|
||||
reg = <0>;
|
||||
vdd3-supply = <&ldo27_reg>;
|
||||
vci-supply = <&ldo28_reg>;
|
||||
reset-gpios = <&gpg0 0 GPIO_ACTIVE_LOW>;
|
||||
enable-gpios = <&gpf1 5 GPIO_ACTIVE_HIGH>;
|
||||
te-gpios = <&gpf1 3 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
};
|
@ -0,0 +1,37 @@
|
||||
Sitronix ST7789V RGB panel with SPI control bus
|
||||
|
||||
Required properties:
|
||||
- compatible: "sitronix,st7789v"
|
||||
- reg: Chip select of the panel on the SPI bus
|
||||
- reset-gpios: a GPIO phandle for the reset pin
|
||||
- power-supply: phandle of the regulator that provides the supply voltage
|
||||
|
||||
Optional properties:
|
||||
- backlight: phandle to the backlight used
|
||||
|
||||
The generic bindings for the SPI slaves documented in [1] also applies
|
||||
|
||||
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:
|
||||
|
||||
panel@0 {
|
||||
compatible = "sitronix,st7789v";
|
||||
reg = <0>;
|
||||
reset-gpios = <&pio 6 11 GPIO_ACTIVE_LOW>;
|
||||
backlight = <&pwm_bl>;
|
||||
spi-max-frequency = <100000>;
|
||||
spi-cpol;
|
||||
spi-cpha;
|
||||
|
||||
port {
|
||||
panel_input: endpoint {
|
||||
remote-endpoint = <&tcon0_out_panel>;
|
||||
};
|
||||
};
|
||||
};
|
@ -0,0 +1,48 @@
|
||||
Winstar Display Corporation 3.5" QVGA (320x240) TFT LCD panel
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "winstar,wf35ltiacd"
|
||||
- power-supply: regulator to provide the VCC supply voltage (3.3 volts)
|
||||
|
||||
This binding is compatible with the simple-panel binding, which is specified
|
||||
in simple-panel.txt in this directory.
|
||||
|
||||
Example:
|
||||
backlight: backlight {
|
||||
compatible = "pwm-backlight";
|
||||
pwms = <&hlcdc_pwm 0 50000 PWM_POLARITY_INVERTED>;
|
||||
brightness-levels = <0 31 63 95 127 159 191 223 255>;
|
||||
default-brightness-level = <191>;
|
||||
power-supply = <&bl_reg>;
|
||||
};
|
||||
|
||||
bl_reg: backlight_regulator {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "backlight-power-supply";
|
||||
regulator-min-microvolt = <5000000>;
|
||||
regulator-max-microvolt = <5000000>;
|
||||
};
|
||||
|
||||
panel: panel {
|
||||
compatible = "winstar,wf35ltiacd", "simple-panel";
|
||||
backlight = <&backlight>;
|
||||
power-supply = <&panel_reg>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
panel_input: endpoint {
|
||||
remote-endpoint = <&hlcdc_panel_output>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
panel_reg: panel_regulator {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "panel-power-supply";
|
||||
regulator-min-microvolt = <3300000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
};
|
@ -36,6 +36,9 @@ Required Properties:
|
||||
When supplied they must be named "dclkin.x" with "x" being the input
|
||||
clock numerical index.
|
||||
|
||||
- vsps: A list of phandles to the VSP nodes that handle the memory
|
||||
interfaces for the DU channels.
|
||||
|
||||
Required nodes:
|
||||
|
||||
The connections to the DU output video ports are modeled using the OF graph
|
||||
|
@ -5,16 +5,24 @@ Required properties:
|
||||
- #address-cells: Should be <1>.
|
||||
- #size-cells: Should be <0>.
|
||||
- compatible: "rockchip,rk3288-mipi-dsi", "snps,dw-mipi-dsi".
|
||||
"rockchip,rk3399-mipi-dsi", "snps,dw-mipi-dsi".
|
||||
- reg: Represent the physical address range of the controller.
|
||||
- interrupts: Represent the controller's interrupt to the CPU(s).
|
||||
- clocks, clock-names: Phandles to the controller's pll reference
|
||||
clock(ref) and APB clock(pclk), as described in [1].
|
||||
clock(ref) and APB clock(pclk). For RK3399, a phy config clock
|
||||
(phy_cfg) and a grf clock(grf) are required. As described in [1].
|
||||
- rockchip,grf: this soc should set GRF regs to mux vopl/vopb.
|
||||
- ports: contain a port node with endpoint definitions as defined in [2].
|
||||
For vopb,set the reg = <0> and set the reg = <1> for vopl.
|
||||
|
||||
Optional properties:
|
||||
- power-domains: a phandle to mipi dsi power domain node.
|
||||
- resets: list of phandle + reset specifier pairs, as described in [3].
|
||||
- reset-names: string reset name, must be "apb".
|
||||
|
||||
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||
[2] Documentation/devicetree/bindings/media/video-interfaces.txt
|
||||
[3] Documentation/devicetree/bindings/reset/reset.txt
|
||||
|
||||
Example:
|
||||
mipi_dsi: mipi@ff960000 {
|
||||
@ -25,6 +33,8 @@ Example:
|
||||
interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cru SCLK_MIPI_24M>, <&cru PCLK_MIPI_DSI0>;
|
||||
clock-names = "ref", "pclk";
|
||||
resets = <&cru SRST_MIPIDSI0>;
|
||||
reset-names = "apb";
|
||||
rockchip,grf = <&grf>;
|
||||
status = "okay";
|
||||
|
||||
|
@ -179,6 +179,7 @@ maxim Maxim Integrated Products
|
||||
mcube mCube
|
||||
meas Measurement Specialties
|
||||
mediatek MediaTek Inc.
|
||||
megachips MegaChips
|
||||
melexis Melexis N.V.
|
||||
melfas MELFAS Inc.
|
||||
memsic MEMSIC Inc.
|
||||
@ -337,6 +338,7 @@ wd Western Digital Corp.
|
||||
wetek WeTek Electronics, limited.
|
||||
wexler Wexler
|
||||
winbond Winbond Electronics corp.
|
||||
winstar Winstar Display Corp.
|
||||
wlf Wolfson Microelectronics
|
||||
wm Wondermedia Technologies, Inc.
|
||||
x-powers X-Powers
|
||||
|
15
Documentation/gpu/bridge/dw-hdmi.rst
Normal file
15
Documentation/gpu/bridge/dw-hdmi.rst
Normal file
@ -0,0 +1,15 @@
|
||||
=======================================================
|
||||
drm/bridge/dw-hdmi Synopsys DesignWare HDMI Controller
|
||||
=======================================================
|
||||
|
||||
Synopsys DesignWare HDMI Controller
|
||||
===================================
|
||||
|
||||
This section covers everything related to the Synopsys DesignWare HDMI
|
||||
Controller implemented as a DRM bridge.
|
||||
|
||||
Supported Input Formats and Encodings
|
||||
-------------------------------------
|
||||
|
||||
.. kernel-doc:: include/drm/bridge/dw_hdmi.h
|
||||
:doc: Supported input formats and encodings
|
@ -140,12 +140,12 @@ Device Instance and Driver Handling
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_drv.c
|
||||
:doc: driver instance overview
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_drv.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: include/drm/drm_drv.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_drv.c
|
||||
:export:
|
||||
|
||||
Driver Load
|
||||
-----------
|
||||
|
||||
@ -240,120 +240,21 @@ drivers.
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_pci.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_platform.c
|
||||
:export:
|
||||
|
||||
Open/Close, File Operations and IOCTLs
|
||||
======================================
|
||||
|
||||
Open and Close
|
||||
--------------
|
||||
|
||||
Open and close handlers. None of those methods are mandatory::
|
||||
|
||||
int (*firstopen) (struct drm_device *);
|
||||
void (*lastclose) (struct drm_device *);
|
||||
int (*open) (struct drm_device *, struct drm_file *);
|
||||
void (*preclose) (struct drm_device *, struct drm_file *);
|
||||
void (*postclose) (struct drm_device *, struct drm_file *);
|
||||
|
||||
The firstopen method is called by the DRM core for legacy UMS (User Mode
|
||||
Setting) drivers only when an application opens a device that has no
|
||||
other opened file handle. UMS drivers can implement it to acquire device
|
||||
resources. KMS drivers can't use the method and must acquire resources
|
||||
in the load method instead.
|
||||
|
||||
Similarly the lastclose method is called when the last application
|
||||
holding a file handle opened on the device closes it, for both UMS and
|
||||
KMS drivers. Additionally, the method is also called at module unload
|
||||
time or, for hot-pluggable devices, when the device is unplugged. The
|
||||
firstopen and lastclose calls can thus be unbalanced.
|
||||
|
||||
The open method is called every time the device is opened by an
|
||||
application. Drivers can allocate per-file private data in this method
|
||||
and store them in the struct :c:type:`struct drm_file
|
||||
<drm_file>` driver_priv field. Note that the open method is
|
||||
called before firstopen.
|
||||
|
||||
The close operation is split into preclose and postclose methods.
|
||||
Drivers must stop and cleanup all per-file operations in the preclose
|
||||
method. For instance pending vertical blanking and page flip events must
|
||||
be cancelled. No per-file operation is allowed on the file handle after
|
||||
returning from the preclose method.
|
||||
|
||||
Finally the postclose method is called as the last step of the close
|
||||
operation, right before calling the lastclose method if no other open
|
||||
file handle exists for the device. Drivers that have allocated per-file
|
||||
private data in the open method should free it here.
|
||||
|
||||
The lastclose method should restore CRTC and plane properties to default
|
||||
value, so that a subsequent open of the device will not inherit state
|
||||
from the previous user. It can also be used to execute delayed power
|
||||
switching state changes, e.g. in conjunction with the :ref:`vga_switcheroo`
|
||||
infrastructure. Beyond that KMS drivers should not do any
|
||||
further cleanup. Only legacy UMS drivers might need to clean up device
|
||||
state so that the vga console or an independent fbdev driver could take
|
||||
over.
|
||||
|
||||
File Operations
|
||||
---------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_fops.c
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_file.c
|
||||
:doc: file operations
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_fops.c
|
||||
.. kernel-doc:: include/drm/drm_file.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_file.c
|
||||
:export:
|
||||
|
||||
IOCTLs
|
||||
------
|
||||
|
||||
struct drm_ioctl_desc \*ioctls; int num_ioctls;
|
||||
Driver-specific ioctls descriptors table.
|
||||
|
||||
Driver-specific ioctls numbers start at DRM_COMMAND_BASE. The ioctls
|
||||
descriptors table is indexed by the ioctl number offset from the base
|
||||
value. Drivers can use the DRM_IOCTL_DEF_DRV() macro to initialize
|
||||
the table entries.
|
||||
|
||||
::
|
||||
|
||||
DRM_IOCTL_DEF_DRV(ioctl, func, flags)
|
||||
|
||||
``ioctl`` is the ioctl name. Drivers must define the DRM_##ioctl and
|
||||
DRM_IOCTL_##ioctl macros to the ioctl number offset from
|
||||
DRM_COMMAND_BASE and the ioctl number respectively. The first macro is
|
||||
private to the device while the second must be exposed to userspace in a
|
||||
public header.
|
||||
|
||||
``func`` is a pointer to the ioctl handler function compatible with the
|
||||
``drm_ioctl_t`` type.
|
||||
|
||||
::
|
||||
|
||||
typedef int drm_ioctl_t(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
|
||||
``flags`` is a bitmask combination of the following values. It restricts
|
||||
how the ioctl is allowed to be called.
|
||||
|
||||
- DRM_AUTH - Only authenticated callers allowed
|
||||
|
||||
- DRM_MASTER - The ioctl can only be called on the master file handle
|
||||
|
||||
- DRM_ROOT_ONLY - Only callers with the SYSADMIN capability allowed
|
||||
|
||||
- DRM_CONTROL_ALLOW - The ioctl can only be called on a control
|
||||
device
|
||||
|
||||
- DRM_UNLOCKED - The ioctl handler will be called without locking the
|
||||
DRM global mutex. This is the enforced default for kms drivers (i.e.
|
||||
using the DRIVER_MODESET flag) and hence shouldn't be used any more
|
||||
for new drivers.
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_ioctl.c
|
||||
:export:
|
||||
|
||||
|
||||
Misc Utilities
|
||||
==============
|
||||
|
||||
|
@ -37,10 +37,12 @@ Modeset Helper Reference for Common Vtables
|
||||
===========================================
|
||||
|
||||
.. kernel-doc:: include/drm/drm_modeset_helper_vtables.h
|
||||
:internal:
|
||||
:doc: overview
|
||||
|
||||
.. kernel-doc:: include/drm/drm_modeset_helper_vtables.h
|
||||
:doc: overview
|
||||
:internal:
|
||||
|
||||
.. _drm_atomic_helper:
|
||||
|
||||
Atomic Modeset Helper Functions Reference
|
||||
=========================================
|
||||
@ -84,27 +86,27 @@ Legacy CRTC/Modeset Helper Functions Reference
|
||||
Simple KMS Helper Reference
|
||||
===========================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_simple_kms_helper.c
|
||||
:doc: overview
|
||||
|
||||
.. kernel-doc:: include/drm/drm_simple_kms_helper.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_simple_kms_helper.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_simple_kms_helper.c
|
||||
:doc: overview
|
||||
|
||||
fbdev Helper Functions Reference
|
||||
================================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_fb_helper.c
|
||||
:doc: fbdev helpers
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_fb_helper.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: include/drm/drm_fb_helper.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_fb_helper.c
|
||||
:export:
|
||||
|
||||
Framebuffer CMA Helper Functions Reference
|
||||
==========================================
|
||||
|
||||
@ -114,6 +116,8 @@ Framebuffer CMA Helper Functions Reference
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_fb_cma_helper.c
|
||||
:export:
|
||||
|
||||
.. _drm_bridges:
|
||||
|
||||
Bridges
|
||||
=======
|
||||
|
||||
@ -139,18 +143,20 @@ Bridge Helper Reference
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_bridge.c
|
||||
:export:
|
||||
|
||||
.. _drm_panel_helper:
|
||||
|
||||
Panel Helper Reference
|
||||
======================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_panel.c
|
||||
:doc: drm panel
|
||||
|
||||
.. kernel-doc:: include/drm/drm_panel.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_panel.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_panel.c
|
||||
:doc: drm panel
|
||||
|
||||
Display Port Helper Functions Reference
|
||||
=======================================
|
||||
|
||||
@ -217,6 +223,18 @@ EDID Helper Functions Reference
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_edid.c
|
||||
:export:
|
||||
|
||||
SCDC Helper Functions Reference
|
||||
===============================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_scdc_helper.c
|
||||
:doc: scdc helpers
|
||||
|
||||
.. kernel-doc:: include/drm/drm_scdc_helper.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_scdc_helper.c
|
||||
:export:
|
||||
|
||||
Rectangle Utilities Reference
|
||||
=============================
|
||||
|
||||
|
@ -15,35 +15,271 @@ be setup by initializing the following fields.
|
||||
- struct drm_mode_config_funcs \*funcs;
|
||||
Mode setting functions.
|
||||
|
||||
Mode Configuration
|
||||
Overview
|
||||
========
|
||||
|
||||
.. kernel-render:: DOT
|
||||
:alt: KMS Display Pipeline
|
||||
:caption: KMS Display Pipeline Overview
|
||||
|
||||
digraph "KMS" {
|
||||
node [shape=box]
|
||||
|
||||
subgraph cluster_static {
|
||||
style=dashed
|
||||
label="Static Objects"
|
||||
|
||||
node [bgcolor=grey style=filled]
|
||||
"drm_plane A" -> "drm_crtc"
|
||||
"drm_plane B" -> "drm_crtc"
|
||||
"drm_crtc" -> "drm_encoder A"
|
||||
"drm_crtc" -> "drm_encoder B"
|
||||
}
|
||||
|
||||
subgraph cluster_user_created {
|
||||
style=dashed
|
||||
label="Userspace-Created"
|
||||
|
||||
node [shape=oval]
|
||||
"drm_framebuffer 1" -> "drm_plane A"
|
||||
"drm_framebuffer 2" -> "drm_plane B"
|
||||
}
|
||||
|
||||
subgraph cluster_connector {
|
||||
style=dashed
|
||||
label="Hotpluggable"
|
||||
|
||||
"drm_encoder A" -> "drm_connector A"
|
||||
"drm_encoder B" -> "drm_connector B"
|
||||
}
|
||||
}
|
||||
|
||||
The basic object structure KMS presents to userspace is fairly simple.
|
||||
Framebuffers (represented by :c:type:`struct drm_framebuffer <drm_framebuffer>`,
|
||||
see `Frame Buffer Abstraction`_) feed into planes. One or more (or even no)
|
||||
planes feed their pixel data into a CRTC (represented by :c:type:`struct
|
||||
drm_crtc <drm_crtc>`, see `CRTC Abstraction`_) for blending. The precise
|
||||
blending step is explained in more detail in `Plane Composition Properties`_ and
|
||||
related chapters.
|
||||
|
||||
For the output routing the first step is encoders (represented by
|
||||
:c:type:`struct drm_encoder <drm_encoder>`, see `Encoder Abstraction`_). Those
|
||||
are really just internal artifacts of the helper libraries used to implement KMS
|
||||
drivers. Besides that they make it unecessarily more complicated for userspace
|
||||
to figure out which connections between a CRTC and a connector are possible, and
|
||||
what kind of cloning is supported, they serve no purpose in the userspace API.
|
||||
Unfortunately encoders have been exposed to userspace, hence can't remove them
|
||||
at this point. Futhermore the exposed restrictions are often wrongly set by
|
||||
drivers, and in many cases not powerful enough to express the real restrictions.
|
||||
A CRTC can be connected to multiple encoders, and for an active CRTC there must
|
||||
be at least one encoder.
|
||||
|
||||
The final, and real, endpoint in the display chain is the connector (represented
|
||||
by :c:type:`struct drm_connector <drm_connector>`, see `Connector
|
||||
Abstraction`_). Connectors can have different possible encoders, but the kernel
|
||||
driver selects which encoder to use for each connector. The use case is DVI,
|
||||
which could switch between an analog and a digital encoder. Encoders can also
|
||||
drive multiple different connectors. There is exactly one active connector for
|
||||
every active encoder.
|
||||
|
||||
Internally the output pipeline is a bit more complex and matches today's
|
||||
hardware more closely:
|
||||
|
||||
.. kernel-render:: DOT
|
||||
:alt: KMS Output Pipeline
|
||||
:caption: KMS Output Pipeline
|
||||
|
||||
digraph "Output Pipeline" {
|
||||
node [shape=box]
|
||||
|
||||
subgraph {
|
||||
"drm_crtc" [bgcolor=grey style=filled]
|
||||
}
|
||||
|
||||
subgraph cluster_internal {
|
||||
style=dashed
|
||||
label="Internal Pipeline"
|
||||
{
|
||||
node [bgcolor=grey style=filled]
|
||||
"drm_encoder A";
|
||||
"drm_encoder B";
|
||||
"drm_encoder C";
|
||||
}
|
||||
|
||||
{
|
||||
node [bgcolor=grey style=filled]
|
||||
"drm_encoder B" -> "drm_bridge B"
|
||||
"drm_encoder C" -> "drm_bridge C1"
|
||||
"drm_bridge C1" -> "drm_bridge C2";
|
||||
}
|
||||
}
|
||||
|
||||
"drm_crtc" -> "drm_encoder A"
|
||||
"drm_crtc" -> "drm_encoder B"
|
||||
"drm_crtc" -> "drm_encoder C"
|
||||
|
||||
|
||||
subgraph cluster_output {
|
||||
style=dashed
|
||||
label="Outputs"
|
||||
|
||||
"drm_encoder A" -> "drm_connector A";
|
||||
"drm_bridge B" -> "drm_connector B";
|
||||
"drm_bridge C2" -> "drm_connector C";
|
||||
|
||||
"drm_panel"
|
||||
}
|
||||
}
|
||||
|
||||
Internally two additional helper objects come into play. First, to be able to
|
||||
share code for encoders (sometimes on the same SoC, sometimes off-chip) one or
|
||||
more :ref:`drm_bridges` (represented by :c:type:`struct drm_bridge
|
||||
<drm_bridge>`) can be linked to an encoder. This link is static and cannot be
|
||||
changed, which means the cross-bar (if there is any) needs to be mapped between
|
||||
the CRTC and any encoders. Often for drivers with bridges there's no code left
|
||||
at the encoder level. Atomic drivers can leave out all the encoder callbacks to
|
||||
essentially only leave a dummy routing object behind, which is needed for
|
||||
backwards compatibility since encoders are exposed to userspace.
|
||||
|
||||
The second object is for panels, represented by :c:type:`struct drm_panel
|
||||
<drm_panel>`, see :ref:`drm_panel_helper`. Panels do not have a fixed binding
|
||||
point, but are generally linked to the driver private structure that embeds
|
||||
:c:type:`struct drm_connector <drm_connector>`.
|
||||
|
||||
Note that currently the bridge chaining and interactions with connectors and
|
||||
panels are still in-flux and not really fully sorted out yet.
|
||||
|
||||
KMS Core Structures and Functions
|
||||
=================================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_mode_config.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: include/drm/drm_mode_config.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_mode_config.c
|
||||
:export:
|
||||
|
||||
Modeset Base Object Abstraction
|
||||
===============================
|
||||
|
||||
.. kernel-render:: DOT
|
||||
:alt: Mode Objects and Properties
|
||||
:caption: Mode Objects and Properties
|
||||
|
||||
digraph {
|
||||
node [shape=box]
|
||||
|
||||
"drm_property A" -> "drm_mode_object A"
|
||||
"drm_property A" -> "drm_mode_object B"
|
||||
"drm_property B" -> "drm_mode_object A"
|
||||
}
|
||||
|
||||
The base structure for all KMS objects is :c:type:`struct drm_mode_object
|
||||
<drm_mode_object>`. One of the base services it provides is tracking properties,
|
||||
which are especially important for the atomic IOCTL (see `Atomic Mode
|
||||
Setting`_). The somewhat surprising part here is that properties are not
|
||||
directly instantiated on each object, but free-standing mode objects themselves,
|
||||
represented by :c:type:`struct drm_property <drm_property>`, which only specify
|
||||
the type and value range of a property. Any given property can be attached
|
||||
multiple times to different objects using :c:func:`drm_object_attach_property()
|
||||
<drm_object_attach_property>`.
|
||||
|
||||
.. kernel-doc:: include/drm/drm_mode_object.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_mode_object.c
|
||||
:export:
|
||||
|
||||
Atomic Mode Setting Function Reference
|
||||
======================================
|
||||
Atomic Mode Setting
|
||||
===================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_atomic.c
|
||||
:export:
|
||||
|
||||
.. kernel-render:: DOT
|
||||
:alt: Mode Objects and Properties
|
||||
:caption: Mode Objects and Properties
|
||||
|
||||
digraph {
|
||||
node [shape=box]
|
||||
|
||||
subgraph cluster_state {
|
||||
style=dashed
|
||||
label="Free-standing state"
|
||||
|
||||
"drm_atomic_state" -> "duplicated drm_plane_state A"
|
||||
"drm_atomic_state" -> "duplicated drm_plane_state B"
|
||||
"drm_atomic_state" -> "duplicated drm_crtc_state"
|
||||
"drm_atomic_state" -> "duplicated drm_connector_state"
|
||||
"drm_atomic_state" -> "duplicated driver private state"
|
||||
}
|
||||
|
||||
subgraph cluster_current {
|
||||
style=dashed
|
||||
label="Current state"
|
||||
|
||||
"drm_device" -> "drm_plane A"
|
||||
"drm_device" -> "drm_plane B"
|
||||
"drm_device" -> "drm_crtc"
|
||||
"drm_device" -> "drm_connector"
|
||||
"drm_device" -> "driver private object"
|
||||
|
||||
"drm_plane A" -> "drm_plane_state A"
|
||||
"drm_plane B" -> "drm_plane_state B"
|
||||
"drm_crtc" -> "drm_crtc_state"
|
||||
"drm_connector" -> "drm_connector_state"
|
||||
"driver private object" -> "driver private state"
|
||||
}
|
||||
|
||||
"drm_atomic_state" -> "drm_device" [label="atomic_commit"]
|
||||
"duplicated drm_plane_state A" -> "drm_device"[style=invis]
|
||||
}
|
||||
|
||||
Atomic provides transactional modeset (including planes) updates, but a
|
||||
bit differently from the usual transactional approach of try-commit and
|
||||
rollback:
|
||||
|
||||
- Firstly, no hardware changes are allowed when the commit would fail. This
|
||||
allows us to implement the DRM_MODE_ATOMIC_TEST_ONLY mode, which allows
|
||||
userspace to explore whether certain configurations would work or not.
|
||||
|
||||
- This would still allow setting and rollback of just the software state,
|
||||
simplifying conversion of existing drivers. But auditing drivers for
|
||||
correctness of the atomic_check code becomes really hard with that: Rolling
|
||||
back changes in data structures all over the place is hard to get right.
|
||||
|
||||
- Lastly, for backwards compatibility and to support all use-cases, atomic
|
||||
updates need to be incremental and be able to execute in parallel. Hardware
|
||||
doesn't always allow it, but where possible plane updates on different CRTCs
|
||||
should not interfere, and not get stalled due to output routing changing on
|
||||
different CRTCs.
|
||||
|
||||
Taken all together there's two consequences for the atomic design:
|
||||
|
||||
- The overall state is split up into per-object state structures:
|
||||
:c:type:`struct drm_plane_state <drm_plane_state>` for planes, :c:type:`struct
|
||||
drm_crtc_state <drm_crtc_state>` for CRTCs and :c:type:`struct
|
||||
drm_connector_state <drm_connector_state>` for connectors. These are the only
|
||||
objects with userspace-visible and settable state. For internal state drivers
|
||||
can subclass these structures through embeddeding, or add entirely new state
|
||||
structures for their globally shared hardware functions.
|
||||
|
||||
- An atomic update is assembled and validated as an entirely free-standing pile
|
||||
of structures within the :c:type:`drm_atomic_state <drm_atomic_state>`
|
||||
container. Again drivers can subclass that container for their own state
|
||||
structure tracking needs. Only when a state is committed is it applied to the
|
||||
driver and modeset objects. This way rolling back an update boils down to
|
||||
releasing memory and unreferencing objects like framebuffers.
|
||||
|
||||
Read on in this chapter, and also in :ref:`drm_atomic_helper` for more detailed
|
||||
coverage of specific topics.
|
||||
|
||||
Atomic Mode Setting Function Reference
|
||||
--------------------------------------
|
||||
|
||||
.. kernel-doc:: include/drm/drm_atomic.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_atomic.c
|
||||
:export:
|
||||
|
||||
CRTC Abstraction
|
||||
================
|
||||
|
||||
@ -68,12 +304,12 @@ Frame Buffer Abstraction
|
||||
Frame Buffer Functions Reference
|
||||
--------------------------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_framebuffer.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: include/drm/drm_framebuffer.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_framebuffer.c
|
||||
:export:
|
||||
|
||||
DRM Format Handling
|
||||
===================
|
||||
|
||||
@ -376,8 +612,8 @@ operation handler.
|
||||
Vertical Blanking and Interrupt Handling Functions Reference
|
||||
------------------------------------------------------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_irq.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: include/drm/drm_irq.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_irq.c
|
||||
:export:
|
||||
|
@ -183,14 +183,12 @@ GEM Objects Lifetime
|
||||
--------------------
|
||||
|
||||
All GEM objects are reference-counted by the GEM core. References can be
|
||||
acquired and release by :c:func:`calling
|
||||
drm_gem_object_reference()` and
|
||||
:c:func:`drm_gem_object_unreference()` respectively. The caller
|
||||
must hold the :c:type:`struct drm_device <drm_device>`
|
||||
struct_mutex lock when calling
|
||||
:c:func:`drm_gem_object_reference()`. As a convenience, GEM
|
||||
provides :c:func:`drm_gem_object_unreference_unlocked()`
|
||||
functions that can be called without holding the lock.
|
||||
acquired and release by :c:func:`calling drm_gem_object_get()` and
|
||||
:c:func:`drm_gem_object_put()` respectively. The caller must hold the
|
||||
:c:type:`struct drm_device <drm_device>` struct_mutex lock when calling
|
||||
:c:func:`drm_gem_object_get()`. As a convenience, GEM provides
|
||||
:c:func:`drm_gem_object_put_unlocked()` functions that can be called without
|
||||
holding the lock.
|
||||
|
||||
When the last reference to a GEM object is released the GEM core calls
|
||||
the :c:type:`struct drm_driver <drm_driver>` gem_free_object
|
||||
@ -367,36 +365,36 @@ from the client in libdrm.
|
||||
GEM Function Reference
|
||||
----------------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_gem.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: include/drm/drm_gem.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_gem.c
|
||||
:export:
|
||||
|
||||
GEM CMA Helper Functions Reference
|
||||
----------------------------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_gem_cma_helper.c
|
||||
:doc: cma helpers
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_gem_cma_helper.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: include/drm/drm_gem_cma_helper.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_gem_cma_helper.c
|
||||
:export:
|
||||
|
||||
VMA Offset Manager
|
||||
==================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_vma_manager.c
|
||||
:doc: vma offset manager
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_vma_manager.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: include/drm/drm_vma_manager.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_vma_manager.c
|
||||
:export:
|
||||
|
||||
PRIME Buffer Sharing
|
||||
====================
|
||||
|
||||
@ -451,6 +449,9 @@ PRIME Helper Functions
|
||||
PRIME Function References
|
||||
-------------------------
|
||||
|
||||
.. kernel-doc:: include/drm/drm_prime.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_prime.c
|
||||
:export:
|
||||
|
||||
@ -472,12 +473,12 @@ LRU Scan/Eviction Support
|
||||
DRM MM Range Allocator Function References
|
||||
------------------------------------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_mm.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: include/drm/drm_mm.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_mm.c
|
||||
:export:
|
||||
|
||||
DRM Cache Handling
|
||||
==================
|
||||
|
||||
|
@ -21,6 +21,8 @@ libdrm Device Lookup
|
||||
:doc: getunique and setversion story
|
||||
|
||||
|
||||
.. _drm_primary_node:
|
||||
|
||||
Primary Nodes, DRM Master and Authentication
|
||||
============================================
|
||||
|
||||
@ -103,6 +105,8 @@ is already rather painful for the DRM subsystem, with multiple different uAPIs
|
||||
for the same thing co-existing. If we add a few more complete mistakes into the
|
||||
mix every year it would be entirely unmanageable.
|
||||
|
||||
.. _drm_render_node:
|
||||
|
||||
Render nodes
|
||||
============
|
||||
|
||||
@ -156,6 +160,20 @@ other hand, a driver requires shared state between clients which is
|
||||
visible to user-space and accessible beyond open-file boundaries, they
|
||||
cannot support render nodes.
|
||||
|
||||
IOCTL Support on Device Nodes
|
||||
=============================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_ioctl.c
|
||||
:doc: driver specific ioctls
|
||||
|
||||
.. kernel-doc:: include/drm/drm_ioctl.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_ioctl.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_ioc32.c
|
||||
:export:
|
||||
|
||||
Testing and validation
|
||||
======================
|
||||
@ -203,6 +221,28 @@ Display CRC Support
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_debugfs_crc.c
|
||||
:doc: CRC ABI
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_debugfs_crc.c
|
||||
:export:
|
||||
|
||||
Debugfs Support
|
||||
---------------
|
||||
|
||||
.. kernel-doc:: include/drm/drm_debugfs.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_debugfs.c
|
||||
:export:
|
||||
|
||||
Sysfs Support
|
||||
=============
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_sysfs.c
|
||||
:doc: overview
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_sysfs.c
|
||||
:export:
|
||||
|
||||
|
||||
VBlank event handling
|
||||
=====================
|
||||
|
||||
|
@ -222,6 +222,15 @@ Video BIOS Table (VBT)
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/intel_vbt_defs.h
|
||||
:internal:
|
||||
|
||||
Display clocks
|
||||
--------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/intel_cdclk.c
|
||||
:doc: CDCLK / RAWCLK
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/intel_cdclk.c
|
||||
:internal:
|
||||
|
||||
Display PLLs
|
||||
------------
|
||||
|
||||
|
@ -11,9 +11,13 @@ Linux GPU Driver Developer's Guide
|
||||
drm-kms-helpers
|
||||
drm-uapi
|
||||
i915
|
||||
meson
|
||||
tinydrm
|
||||
vc4
|
||||
vga-switcheroo
|
||||
vgaarbiter
|
||||
bridge/dw-hdmi
|
||||
todo
|
||||
|
||||
.. only:: subproject and html
|
||||
|
||||
|
@ -50,3 +50,38 @@ names are "Notes" with information for dangerous or tricky corner cases,
|
||||
and "FIXME" where the interface could be cleaned up.
|
||||
|
||||
Also read the :ref:`guidelines for the kernel documentation at large <doc_guide>`.
|
||||
|
||||
Getting Started
|
||||
===============
|
||||
|
||||
Developers interested in helping out with the DRM subsystem are very welcome.
|
||||
Often people will resort to sending in patches for various issues reported by
|
||||
checkpatch or sparse. We welcome such contributions.
|
||||
|
||||
Anyone looking to kick it up a notch can find a list of janitorial tasks on
|
||||
the :ref:`TODO list <todo>`.
|
||||
|
||||
Contribution Process
|
||||
====================
|
||||
|
||||
Mostly the DRM subsystem works like any other kernel subsystem, see :ref:`the
|
||||
main process guidelines and documentation <process_index>` for how things work.
|
||||
Here we just document some of the specialities of the GPU subsystem.
|
||||
|
||||
Feature Merge Deadlines
|
||||
-----------------------
|
||||
|
||||
All feature work must be in the linux-next tree by the -rc6 release of the
|
||||
current release cycle, otherwise they must be postponed and can't reach the next
|
||||
merge window. All patches must have landed in the drm-next tree by latest -rc7,
|
||||
but if your branch is not in linux-next then this must have happened by -rc6
|
||||
already.
|
||||
|
||||
After that point only bugfixes (like after the upstream merge window has closed
|
||||
with the -rc1 release) are allowed. No new platform enabling or new drivers are
|
||||
allowed.
|
||||
|
||||
This means that there's a blackout-period of about one month where feature work
|
||||
can't be merged. The recommended way to deal with that is having a -next tree
|
||||
that's always open, but making sure to not feed it into linux-next during the
|
||||
blackout period. As an example, drm-misc works like that.
|
||||
|
@ -1,10 +1,5 @@
|
||||
Owner Module/Drivers,Group,Property Name,Type,Property Values,Object attached,Description/Restrictions
|
||||
,,“scaling mode”,ENUM,"{ ""None"", ""Full"", ""Center"", ""Full aspect"" }",Connector,"Supported by: amdgpu, gma500, i915, nouveau and radeon."
|
||||
,Connector,“EDID”,BLOB | IMMUTABLE,0,Connector,Contains id of edid blob ptr object.
|
||||
,,“DPMS”,ENUM,"{ “On”, “Standby”, “Suspend”, “Off” }",Connector,Contains DPMS operation mode value.
|
||||
,,“PATH”,BLOB | IMMUTABLE,0,Connector,Contains topology path to a connector.
|
||||
,,“TILE”,BLOB | IMMUTABLE,0,Connector,Contains tiling information for a connector.
|
||||
,,“CRTC_ID”,OBJECT,DRM_MODE_OBJECT_CRTC,Connector,CRTC that connector is attached to (atomic)
|
||||
,DVI-I,“subconnector”,ENUM,"{ “Unknown”, “DVI-D”, “DVI-A” }",Connector,TBD
|
||||
,,“select subconnector”,ENUM,"{ “Automatic”, “DVI-D”, “DVI-A” }",Connector,TBD
|
||||
,TV,“subconnector”,ENUM,"{ ""Unknown"", ""Composite"", ""SVIDEO"", ""Component"", ""SCART"" }",Connector,TBD
|
||||
|
|
61
Documentation/gpu/meson.rst
Normal file
61
Documentation/gpu/meson.rst
Normal file
@ -0,0 +1,61 @@
|
||||
=============================================
|
||||
drm/meson AmLogic Meson Video Processing Unit
|
||||
=============================================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/meson/meson_drv.c
|
||||
:doc: Video Processing Unit
|
||||
|
||||
Video Processing Unit
|
||||
=====================
|
||||
|
||||
The Amlogic Meson Display controller is composed of several components
|
||||
that are going to be documented below:
|
||||
|
||||
.. code::
|
||||
|
||||
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 |-------|______|----|____________| |________________| | |
|
||||
___|__________________________________________________________|_______________|
|
||||
|
||||
Video Input Unit
|
||||
================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/meson/meson_viu.c
|
||||
:doc: Video Input Unit
|
||||
|
||||
Video Post Processing
|
||||
=====================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/meson/meson_vpp.c
|
||||
:doc: Video Post Processing
|
||||
|
||||
Video Encoder
|
||||
=============
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/meson/meson_venc.c
|
||||
:doc: Video Encoder
|
||||
|
||||
Video Canvas Management
|
||||
=======================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/meson/meson_canvas.c
|
||||
:doc: Canvas
|
||||
|
||||
Video Clocks
|
||||
============
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/meson/meson_vclk.c
|
||||
:doc: Video Clocks
|
||||
|
||||
HDMI Video Output
|
||||
=================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/meson/meson_dw_hdmi.c
|
||||
:doc: HDMI Output
|
407
Documentation/gpu/todo.rst
Normal file
407
Documentation/gpu/todo.rst
Normal file
@ -0,0 +1,407 @@
|
||||
.. _todo:
|
||||
|
||||
=========
|
||||
TODO list
|
||||
=========
|
||||
|
||||
This section contains a list of smaller janitorial tasks in the kernel DRM
|
||||
graphics subsystem useful as newbie projects. Or for slow rainy days.
|
||||
|
||||
Subsystem-wide refactorings
|
||||
===========================
|
||||
|
||||
De-midlayer drivers
|
||||
-------------------
|
||||
|
||||
With the recent ``drm_bus`` cleanup patches for 3.17 it is no longer required
|
||||
to have a ``drm_bus`` structure set up. Drivers can directly set up the
|
||||
``drm_device`` structure instead of relying on bus methods in ``drm_usb.c``
|
||||
and ``drm_pci.c``. The goal is to get rid of the driver's ``->load`` /
|
||||
``->unload`` callbacks and open-code the load/unload sequence properly, using
|
||||
the new two-stage ``drm_device`` setup/teardown.
|
||||
|
||||
Once all existing drivers are converted we can also remove those bus support
|
||||
files for USB and platform devices.
|
||||
|
||||
All you need is a GPU for a non-converted driver (currently almost all of
|
||||
them, but also all the virtual ones used by KVM, so everyone qualifies).
|
||||
|
||||
Contact: Daniel Vetter, Thierry Reding, respective driver maintainers
|
||||
|
||||
Switch from reference/unreference to get/put
|
||||
--------------------------------------------
|
||||
|
||||
For some reason DRM core uses ``reference``/``unreference`` suffixes for
|
||||
refcounting functions, but kernel uses ``get``/``put`` (e.g.
|
||||
``kref_get``/``put()``). It would be good to switch over for consistency, and
|
||||
it's shorter. Needs to be done in 3 steps for each pair of functions:
|
||||
|
||||
* Create new ``get``/``put`` functions, define the old names as compatibility
|
||||
wrappers
|
||||
* Switch over each file/driver using a cocci-generated spatch.
|
||||
* Once all users of the old names are gone, remove them.
|
||||
|
||||
This way drivers/patches in the progress of getting merged won't break.
|
||||
|
||||
Contact: Daniel Vetter
|
||||
|
||||
Convert existing KMS drivers to atomic modesetting
|
||||
--------------------------------------------------
|
||||
|
||||
3.19 has the atomic modeset interfaces and helpers, so drivers can now be
|
||||
converted over. Modern compositors like Wayland or Surfaceflinger on Android
|
||||
really want an atomic modeset interface, so this is all about the bright
|
||||
future.
|
||||
|
||||
There is a conversion guide for atomic and all you need is a GPU for a
|
||||
non-converted driver (again virtual HW drivers for KVM are still all
|
||||
suitable).
|
||||
|
||||
As part of this drivers also need to convert to universal plane (which means
|
||||
exposing primary & cursor as proper plane objects). But that's much easier to
|
||||
do by directly using the new atomic helper driver callbacks.
|
||||
|
||||
Contact: Daniel Vetter, respective driver maintainers
|
||||
|
||||
Clean up the clipped coordination confusion around planes
|
||||
---------------------------------------------------------
|
||||
|
||||
We have a helper to get this right with drm_plane_helper_check_update(), but
|
||||
it's not consistently used. This should be fixed, preferrably in the atomic
|
||||
helpers (and drivers then moved over to clipped coordinates). Probably the
|
||||
helper should also be moved from drm_plane_helper.c to the atomic helpers, to
|
||||
avoid confusion - the other helpers in that file are all deprecated legacy
|
||||
helpers.
|
||||
|
||||
Contact: Ville Syrjälä, Daniel Vetter, driver maintainers
|
||||
|
||||
Implement deferred fbdev setup in the helper
|
||||
--------------------------------------------
|
||||
|
||||
Many (especially embedded drivers) want to delay fbdev setup until there's a
|
||||
real screen plugged in. This is to avoid the dreaded fallback to the low-res
|
||||
fbdev default. Many drivers have a hacked-up (and often broken) version of this,
|
||||
better to do it once in the shared helpers. Thierry has a patch series, but that
|
||||
one needs to be rebased and final polish applied.
|
||||
|
||||
Contact: Thierry Reding, Daniel Vetter, driver maintainers
|
||||
|
||||
Convert early atomic drivers to async commit helpers
|
||||
----------------------------------------------------
|
||||
|
||||
For the first year the atomic modeset helpers didn't support asynchronous /
|
||||
nonblocking commits, and every driver had to hand-roll them. This is fixed
|
||||
now, but there's still a pile of existing drivers that easily could be
|
||||
converted over to the new infrastructure.
|
||||
|
||||
One issue with the helpers is that they require that drivers handle completion
|
||||
events for atomic commits correctly. But fixing these bugs is good anyway.
|
||||
|
||||
Contact: Daniel Vetter, respective driver maintainers
|
||||
|
||||
Better manual-upload support for atomic
|
||||
---------------------------------------
|
||||
|
||||
This would be especially useful for tinydrm:
|
||||
|
||||
- Add a struct drm_rect dirty_clip to drm_crtc_state. When duplicating the
|
||||
crtc state, clear that to the max values, x/y = 0 and w/h = MAX_INT, in
|
||||
__drm_atomic_helper_crtc_duplicate_state().
|
||||
|
||||
- Move tinydrm_merge_clips into drm_framebuffer.c, dropping the tinydrm_
|
||||
prefix ofc and using drm_fb_. drm_framebuffer.c makes sense since this
|
||||
is a function useful to implement the fb->dirty function.
|
||||
|
||||
- Create a new drm_fb_dirty function which does essentially what e.g.
|
||||
mipi_dbi_fb_dirty does. You can use e.g. drm_atomic_helper_update_plane as the
|
||||
template. But instead of doing a simple full-screen plane update, this new
|
||||
helper also sets crtc_state->dirty_clip to the right coordinates. And of
|
||||
course it needs to check whether the fb is actually active (and maybe where),
|
||||
so there's some book-keeping involved. There's also some good fun involved in
|
||||
scaling things appropriately. For that case we might simply give up and
|
||||
declare the entire area covered by the plane as dirty.
|
||||
|
||||
Contact: Noralf Trønnes, Daniel Vetter
|
||||
|
||||
Fallout from atomic KMS
|
||||
-----------------------
|
||||
|
||||
``drm_atomic_helper.c`` provides a batch of functions which implement legacy
|
||||
IOCTLs on top of the new atomic driver interface. Which is really nice for
|
||||
gradual conversion of drivers, but unfortunately the semantic mismatches are
|
||||
a bit too severe. So there's some follow-up work to adjust the function
|
||||
interfaces to fix these issues:
|
||||
|
||||
* atomic needs the lock acquire context. At the moment that's passed around
|
||||
implicitly with some horrible hacks, and it's also allocate with
|
||||
``GFP_NOFAIL`` behind the scenes. All legacy paths need to start allocating
|
||||
the acquire context explicitly on stack and then also pass it down into
|
||||
drivers explicitly so that the legacy-on-atomic functions can use them.
|
||||
|
||||
* A bunch of the vtable hooks are now in the wrong place: DRM has a split
|
||||
between core vfunc tables (named ``drm_foo_funcs``), which are used to
|
||||
implement the userspace ABI. And then there's the optional hooks for the
|
||||
helper libraries (name ``drm_foo_helper_funcs``), which are purely for
|
||||
internal use. Some of these hooks should be move from ``_funcs`` to
|
||||
``_helper_funcs`` since they are not part of the core ABI. There's a
|
||||
``FIXME`` comment in the kerneldoc for each such case in ``drm_crtc.h``.
|
||||
|
||||
* There's a new helper ``drm_atomic_helper_best_encoder()`` which could be
|
||||
used by all atomic drivers which don't select the encoder for a given
|
||||
connector at runtime. That's almost all of them, and would allow us to get
|
||||
rid of a lot of ``best_encoder`` boilerplate in drivers.
|
||||
|
||||
Contact: Daniel Vetter
|
||||
|
||||
Get rid of dev->struct_mutex from GEM drivers
|
||||
---------------------------------------------
|
||||
|
||||
``dev->struct_mutex`` is the Big DRM Lock from legacy days and infested
|
||||
everything. Nowadays in modern drivers the only bit where it's mandatory is
|
||||
serializing GEM buffer object destruction. Which unfortunately means drivers
|
||||
have to keep track of that lock and either call ``unreference`` or
|
||||
``unreference_locked`` depending upon context.
|
||||
|
||||
Core GEM doesn't have a need for ``struct_mutex`` any more since kernel 4.8,
|
||||
and there's a ``gem_free_object_unlocked`` callback for any drivers which are
|
||||
entirely ``struct_mutex`` free.
|
||||
|
||||
For drivers that need ``struct_mutex`` it should be replaced with a driver-
|
||||
private lock. The tricky part is the BO free functions, since those can't
|
||||
reliably take that lock any more. Instead state needs to be protected with
|
||||
suitable subordinate locks or some cleanup work pushed to a worker thread. For
|
||||
performance-critical drivers it might also be better to go with a more
|
||||
fine-grained per-buffer object and per-context lockings scheme. Currently the
|
||||
following drivers still use ``struct_mutex``: ``msm``, ``omapdrm`` and
|
||||
``udl``.
|
||||
|
||||
Contact: Daniel Vetter, respective driver maintainers
|
||||
|
||||
Switch to drm_connector_list_iter for any connector_list walking
|
||||
----------------------------------------------------------------
|
||||
|
||||
Connectors can be hotplugged, and we now have a special list of helpers to walk
|
||||
the connector_list in a race-free fashion, without incurring deadlocks on
|
||||
mutexes and other fun stuff.
|
||||
|
||||
Unfortunately most drivers are not converted yet. At least all those supporting
|
||||
DP MST hotplug should be converted, since for those drivers the difference
|
||||
matters. See drm_for_each_connector_iter() vs. drm_for_each_connector().
|
||||
|
||||
Contact: Daniel Vetter
|
||||
|
||||
Core refactorings
|
||||
=================
|
||||
|
||||
Use new IDR deletion interface to clean up drm_gem_handle_delete()
|
||||
------------------------------------------------------------------
|
||||
|
||||
See the "This is gross" comment -- apparently the IDR system now can return an
|
||||
error code instead of oopsing.
|
||||
|
||||
Clean up the DRM header mess
|
||||
----------------------------
|
||||
|
||||
Currently the DRM subsystem has only one global header, ``drmP.h``. This is
|
||||
used both for functions exported to helper libraries and drivers and functions
|
||||
only used internally in the ``drm.ko`` module. The goal would be to move all
|
||||
header declarations not needed outside of ``drm.ko`` into
|
||||
``drivers/gpu/drm/drm_*_internal.h`` header files. ``EXPORT_SYMBOL`` also
|
||||
needs to be dropped for these functions.
|
||||
|
||||
This would nicely tie in with the below task to create kerneldoc after the API
|
||||
is cleaned up. Or with the "hide legacy cruft better" task.
|
||||
|
||||
Note that this is well in progress, but ``drmP.h`` is still huge. The updated
|
||||
plan is to switch to per-file driver API headers, which will also structure
|
||||
the kerneldoc better. This should also allow more fine-grained ``#include``
|
||||
directives.
|
||||
|
||||
In the end no .c file should need to include ``drmP.h`` anymore.
|
||||
|
||||
Contact: Daniel Vetter
|
||||
|
||||
Add missing kerneldoc for exported functions
|
||||
--------------------------------------------
|
||||
|
||||
The DRM reference documentation is still lacking kerneldoc in a few areas. The
|
||||
task would be to clean up interfaces like moving functions around between
|
||||
files to better group them and improving the interfaces like dropping return
|
||||
values for functions that never fail. Then write kerneldoc for all exported
|
||||
functions and an overview section and integrate it all into the drm DocBook.
|
||||
|
||||
See https://dri.freedesktop.org/docs/drm/ for what's there already.
|
||||
|
||||
Contact: Daniel Vetter
|
||||
|
||||
Hide legacy cruft better
|
||||
------------------------
|
||||
|
||||
Way back DRM supported only drivers which shadow-attached to PCI devices with
|
||||
userspace or fbdev drivers setting up outputs. Modern DRM drivers take charge
|
||||
of the entire device, you can spot them with the DRIVER_MODESET flag.
|
||||
|
||||
Unfortunately there's still large piles of legacy code around which needs to
|
||||
be hidden so that driver writers don't accidentally end up using it. And to
|
||||
prevent security issues in those legacy IOCTLs from being exploited on modern
|
||||
drivers. This has multiple possible subtasks:
|
||||
|
||||
* Extract support code for legacy features into a ``drm-legacy.ko`` kernel
|
||||
module and compile it only when one of the legacy drivers is enabled.
|
||||
|
||||
This is mostly done, the only thing left is to split up ``drm_irq.c`` into
|
||||
legacy cruft and the parts needed by modern KMS drivers.
|
||||
|
||||
Contact: Daniel Vetter
|
||||
|
||||
Make panic handling work
|
||||
------------------------
|
||||
|
||||
This is a really varied tasks with lots of little bits and pieces:
|
||||
|
||||
* The panic path can't be tested currently, leading to constant breaking. The
|
||||
main issue here is that panics can be triggered from hardirq contexts and
|
||||
hence all panic related callback can run in hardirq context. It would be
|
||||
awesome if we could test at least the fbdev helper code and driver code by
|
||||
e.g. trigger calls through drm debugfs files. hardirq context could be
|
||||
achieved by using an IPI to the local processor.
|
||||
|
||||
* There's a massive confusion of different panic handlers. DRM fbdev emulation
|
||||
helpers have one, but on top of that the fbcon code itself also has one. We
|
||||
need to make sure that they stop fighting over each another.
|
||||
|
||||
* ``drm_can_sleep()`` is a mess. It hides real bugs in normal operations and
|
||||
isn't a full solution for panic paths. We need to make sure that it only
|
||||
returns true if there's a panic going on for real, and fix up all the
|
||||
fallout.
|
||||
|
||||
* The panic handler must never sleep, which also means it can't ever
|
||||
``mutex_lock()``. Also it can't grab any other lock unconditionally, not
|
||||
even spinlocks (because NMI and hardirq can panic too). We need to either
|
||||
make sure to not call such paths, or trylock everything. Really tricky.
|
||||
|
||||
* For the above locking troubles reasons it's pretty much impossible to
|
||||
attempt a synchronous modeset from panic handlers. The only thing we could
|
||||
try to achive is an atomic ``set_base`` of the primary plane, and hope that
|
||||
it shows up. Everything else probably needs to be delayed to some worker or
|
||||
something else which happens later on. Otherwise it just kills the box
|
||||
harder, prevent the panic from going out on e.g. netconsole.
|
||||
|
||||
* There's also proposal for a simplied DRM console instead of the full-blown
|
||||
fbcon and DRM fbdev emulation. Any kind of panic handling tricks should
|
||||
obviously work for both console, in case we ever get kmslog merged.
|
||||
|
||||
Contact: Daniel Vetter
|
||||
|
||||
Clean up the debugfs support
|
||||
----------------------------
|
||||
|
||||
There's a bunch of issues with it:
|
||||
|
||||
- The drm_info_list ->show() function doesn't even bother to cast to the drm
|
||||
structure for you. This is lazy.
|
||||
|
||||
- We probably want to have some support for debugfs files on crtc/connectors and
|
||||
maybe other kms objects directly in core. There's even drm_print support in
|
||||
the funcs for these objects to dump kms state, so it's all there. And then the
|
||||
->show() functions should obviously give you a pointer to the right object.
|
||||
|
||||
- The drm_info_list stuff is centered on drm_minor instead of drm_device. For
|
||||
anything we want to print drm_device (or maybe drm_file) is the right thing.
|
||||
|
||||
- The drm_driver->debugfs_init hooks we have is just an artifact of the old
|
||||
midlayered load sequence. DRM debugfs should work more like sysfs, where you
|
||||
can create properties/files for an object anytime you want, and the core
|
||||
takes care of publishing/unpuplishing all the files at register/unregister
|
||||
time. Drivers shouldn't need to worry about these technicalities, and fixing
|
||||
this (together with the drm_minor->drm_device move) would allow us to remove
|
||||
debugfs_init.
|
||||
|
||||
Contact: Daniel Vetter
|
||||
|
||||
Better Testing
|
||||
==============
|
||||
|
||||
Enable trinity for DRM
|
||||
----------------------
|
||||
|
||||
And fix up the fallout. Should be really interesting ...
|
||||
|
||||
Make KMS tests in i-g-t generic
|
||||
-------------------------------
|
||||
|
||||
The i915 driver team maintains an extensive testsuite for the i915 DRM driver,
|
||||
including tons of testcases for corner-cases in the modesetting API. It would
|
||||
be awesome if those tests (at least the ones not relying on Intel-specific GEM
|
||||
features) could be made to run on any KMS driver.
|
||||
|
||||
Basic work to run i-g-t tests on non-i915 is done, what's now missing is mass-
|
||||
converting things over. For modeset tests we also first need a bit of
|
||||
infrastructure to use dumb buffers for untiled buffers, to be able to run all
|
||||
the non-i915 specific modeset tests.
|
||||
|
||||
Contact: Daniel Vetter
|
||||
|
||||
Create a virtual KMS driver for testing (vkms)
|
||||
----------------------------------------------
|
||||
|
||||
With all the latest helpers it should be fairly simple to create a virtual KMS
|
||||
driver useful for testing, or for running X or similar on headless machines
|
||||
(to be able to still use the GPU). This would be similar to vgem, but aimed at
|
||||
the modeset side.
|
||||
|
||||
Once the basics are there there's tons of possibilities to extend it.
|
||||
|
||||
Contact: Daniel Vetter
|
||||
|
||||
Driver Specific
|
||||
===============
|
||||
|
||||
tinydrm
|
||||
-------
|
||||
|
||||
Tinydrm is the helper driver for really simple fb drivers. The goal is to make
|
||||
those drivers as simple as possible, so lots of room for refactoring:
|
||||
|
||||
- backlight helpers, probably best to put them into a new drm_backlight.c.
|
||||
This is because drivers/video is de-facto unmaintained. We could also
|
||||
move drivers/video/backlight to drivers/gpu/backlight and take it all
|
||||
over within drm-misc, but that's more work.
|
||||
|
||||
- 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.
|
||||
|
||||
- tinydrm_lastclose could be drm_fb_helper_lastclose. Only thing we need
|
||||
for that is to store the drm_fb_helper pointer somewhere in
|
||||
drm_device->mode_config. And then we could roll that out to all the
|
||||
drivers.
|
||||
|
||||
- tinydrm_gem_cma_prime_import_sg_table should probably go into the cma
|
||||
helpers, as a _vmapped variant (since not every driver needs the vmap).
|
||||
And tinydrm_gem_cma_free_object could the be merged into
|
||||
drm_gem_cma_free_object().
|
||||
|
||||
- tinydrm_fb_create we could move into drm_simple_pipe, only need to add
|
||||
the fb_create hook to drm_simple_pipe_funcs, which would again simplify a
|
||||
bunch of things (since it gives you a one-stop vfunc for simple drivers).
|
||||
|
||||
- Quick aside: The unregister devm stuff is kinda getting the lifetimes of
|
||||
a drm_device wrong. Doesn't matter, since everyone else gets it wrong
|
||||
too :-)
|
||||
|
||||
- With the fbdev pointer in dev->mode_config we could also make
|
||||
suspend/resume helpers entirely generic, at least if we add a
|
||||
dev->mode_config.suspend_state. We could even provide a generic pm_ops
|
||||
structure with those.
|
||||
|
||||
- also rework the drm_framebuffer_funcs->dirty hook wire-up, see above.
|
||||
|
||||
Contact: Noralf Trønnes, Daniel Vetter
|
||||
|
||||
Outside DRM
|
||||
===========
|
89
Documentation/gpu/vc4.rst
Normal file
89
Documentation/gpu/vc4.rst
Normal file
@ -0,0 +1,89 @@
|
||||
=====================================
|
||||
drm/vc4 Broadcom VC4 Graphics Driver
|
||||
=====================================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/vc4/vc4_drv.c
|
||||
:doc: Broadcom VC4 Graphics Driver
|
||||
|
||||
Display Hardware Handling
|
||||
=========================
|
||||
|
||||
This section covers everything related to the display hardware including
|
||||
the mode setting infrastructure, plane, sprite and cursor handling and
|
||||
display, output probing and related topics.
|
||||
|
||||
Pixel Valve (DRM CRTC)
|
||||
----------------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
:doc: VC4 CRTC module
|
||||
|
||||
HVS
|
||||
---
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/vc4/vc4_hvs.c
|
||||
:doc: VC4 HVS module.
|
||||
|
||||
HVS planes
|
||||
----------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/vc4/vc4_plane.c
|
||||
:doc: VC4 plane module
|
||||
|
||||
HDMI encoder
|
||||
------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
:doc: VC4 Falcon HDMI module
|
||||
|
||||
DSI encoder
|
||||
-----------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/vc4/vc4_dsi.c
|
||||
:doc: VC4 DSI0/DSI1 module
|
||||
|
||||
DPI encoder
|
||||
-----------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/vc4/vc4_dpi.c
|
||||
:doc: VC4 DPI module
|
||||
|
||||
VEC (Composite TV out) encoder
|
||||
------------------------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/vc4/vc4_vec.c
|
||||
:doc: VC4 SDTV module
|
||||
|
||||
Memory Management and 3D Command Submission
|
||||
===========================================
|
||||
|
||||
This section covers the GEM implementation in the vc4 driver.
|
||||
|
||||
GPU buffer object (BO) management
|
||||
---------------------------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/vc4/vc4_bo.c
|
||||
:doc: VC4 GEM BO management support
|
||||
|
||||
V3D binner command list (BCL) validation
|
||||
----------------------------------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/vc4/vc4_validate.c
|
||||
:doc: Command list validator for VC4.
|
||||
|
||||
V3D render command list (RCL) generation
|
||||
----------------------------------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/vc4/vc4_render_cl.c
|
||||
:doc: Render command list generation
|
||||
|
||||
Shader validator for VC4
|
||||
---------------------------
|
||||
.. kernel-doc:: drivers/gpu/drm/vc4/vc4_validate_shaders.c
|
||||
:doc: Shader validator for VC4.
|
||||
|
||||
V3D Interrupts
|
||||
--------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/vc4/vc4_irq.c
|
||||
:doc: Interrupt management for the V3D engine
|
@ -1258,6 +1258,319 @@ The following tables list existing packed RGB formats.
|
||||
- b\ :sub:`2`
|
||||
- b\ :sub:`1`
|
||||
- b\ :sub:`0`
|
||||
* .. _MEDIA-BUS-FMT-RGB101010-1X30:
|
||||
|
||||
- MEDIA_BUS_FMT_RGB101010_1X30
|
||||
- 0x1018
|
||||
-
|
||||
- 0
|
||||
- 0
|
||||
- r\ :sub:`9`
|
||||
- r\ :sub:`8`
|
||||
- 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:`9`
|
||||
- g\ :sub:`8`
|
||||
- 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:`9`
|
||||
- b\ :sub:`8`
|
||||
- b\ :sub:`7`
|
||||
- b\ :sub:`6`
|
||||
- b\ :sub:`5`
|
||||
- b\ :sub:`4`
|
||||
- b\ :sub:`3`
|
||||
- b\ :sub:`2`
|
||||
- b\ :sub:`1`
|
||||
- b\ :sub:`0`
|
||||
|
||||
.. raw:: latex
|
||||
|
||||
\endgroup
|
||||
|
||||
|
||||
The following table list existing packed 36bit wide RGB formats.
|
||||
|
||||
.. tabularcolumns:: |p{4.0cm}|p{0.7cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|
|
||||
|
||||
.. _v4l2-mbus-pixelcode-rgb-36:
|
||||
|
||||
.. raw:: latex
|
||||
|
||||
\begingroup
|
||||
\tiny
|
||||
\setlength{\tabcolsep}{2pt}
|
||||
|
||||
.. flat-table:: 36bit RGB formats
|
||||
:header-rows: 2
|
||||
:stub-columns: 0
|
||||
:widths: 36 7 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
|
||||
|
||||
* - Identifier
|
||||
- Code
|
||||
-
|
||||
- :cspan:`35` Data organization
|
||||
* -
|
||||
-
|
||||
- Bit
|
||||
- 35
|
||||
- 34
|
||||
- 33
|
||||
- 32
|
||||
- 31
|
||||
- 30
|
||||
- 29
|
||||
- 28
|
||||
- 27
|
||||
- 26
|
||||
- 25
|
||||
- 24
|
||||
- 23
|
||||
- 22
|
||||
- 21
|
||||
- 20
|
||||
- 19
|
||||
- 18
|
||||
- 17
|
||||
- 16
|
||||
- 15
|
||||
- 14
|
||||
- 13
|
||||
- 12
|
||||
- 11
|
||||
- 10
|
||||
- 9
|
||||
- 8
|
||||
- 7
|
||||
- 6
|
||||
- 5
|
||||
- 4
|
||||
- 3
|
||||
- 2
|
||||
- 1
|
||||
- 0
|
||||
* .. _MEDIA-BUS-FMT-RGB121212-1X36:
|
||||
|
||||
- MEDIA_BUS_FMT_RGB121212_1X36
|
||||
- 0x1019
|
||||
-
|
||||
- r\ :sub:`11`
|
||||
- r\ :sub:`10`
|
||||
- r\ :sub:`9`
|
||||
- r\ :sub:`8`
|
||||
- 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:`11`
|
||||
- g\ :sub:`10`
|
||||
- g\ :sub:`9`
|
||||
- g\ :sub:`8`
|
||||
- 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:`11`
|
||||
- b\ :sub:`10`
|
||||
- b\ :sub:`9`
|
||||
- b\ :sub:`8`
|
||||
- b\ :sub:`7`
|
||||
- b\ :sub:`6`
|
||||
- b\ :sub:`5`
|
||||
- b\ :sub:`4`
|
||||
- b\ :sub:`3`
|
||||
- b\ :sub:`2`
|
||||
- b\ :sub:`1`
|
||||
- b\ :sub:`0`
|
||||
|
||||
.. raw:: latex
|
||||
|
||||
\endgroup
|
||||
|
||||
|
||||
The following table list existing packed 48bit wide RGB formats.
|
||||
|
||||
.. tabularcolumns:: |p{4.0cm}|p{0.7cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|
|
||||
|
||||
.. _v4l2-mbus-pixelcode-rgb-48:
|
||||
|
||||
.. raw:: latex
|
||||
|
||||
\begingroup
|
||||
\tiny
|
||||
\setlength{\tabcolsep}{2pt}
|
||||
|
||||
.. flat-table:: 48bit RGB formats
|
||||
:header-rows: 3
|
||||
:stub-columns: 0
|
||||
:widths: 36 7 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
|
||||
|
||||
* - Identifier
|
||||
- Code
|
||||
-
|
||||
- :cspan:`31` Data organization
|
||||
* -
|
||||
-
|
||||
- Bit
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
- 47
|
||||
- 46
|
||||
- 45
|
||||
- 44
|
||||
- 43
|
||||
- 42
|
||||
- 41
|
||||
- 40
|
||||
- 39
|
||||
- 38
|
||||
- 37
|
||||
- 36
|
||||
- 35
|
||||
- 34
|
||||
- 33
|
||||
- 32
|
||||
* -
|
||||
-
|
||||
-
|
||||
- 31
|
||||
- 30
|
||||
- 29
|
||||
- 28
|
||||
- 27
|
||||
- 26
|
||||
- 25
|
||||
- 24
|
||||
- 23
|
||||
- 22
|
||||
- 21
|
||||
- 20
|
||||
- 19
|
||||
- 18
|
||||
- 17
|
||||
- 16
|
||||
- 15
|
||||
- 14
|
||||
- 13
|
||||
- 12
|
||||
- 11
|
||||
- 10
|
||||
- 9
|
||||
- 8
|
||||
- 7
|
||||
- 6
|
||||
- 5
|
||||
- 4
|
||||
- 3
|
||||
- 2
|
||||
- 1
|
||||
- 0
|
||||
* .. _MEDIA-BUS-FMT-RGB161616-1X48:
|
||||
|
||||
- MEDIA_BUS_FMT_RGB161616_1X48
|
||||
- 0x101a
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
- r\ :sub:`15`
|
||||
- r\ :sub:`14`
|
||||
- r\ :sub:`13`
|
||||
- r\ :sub:`12`
|
||||
- r\ :sub:`11`
|
||||
- r\ :sub:`10`
|
||||
- r\ :sub:`9`
|
||||
- r\ :sub:`8`
|
||||
- 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:`15`
|
||||
- g\ :sub:`14`
|
||||
- g\ :sub:`13`
|
||||
- g\ :sub:`12`
|
||||
- g\ :sub:`11`
|
||||
- g\ :sub:`10`
|
||||
- g\ :sub:`9`
|
||||
- g\ :sub:`8`
|
||||
- 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:`15`
|
||||
- b\ :sub:`14`
|
||||
- b\ :sub:`13`
|
||||
- b\ :sub:`12`
|
||||
- b\ :sub:`11`
|
||||
- b\ :sub:`10`
|
||||
- b\ :sub:`9`
|
||||
- b\ :sub:`8`
|
||||
- b\ :sub:`7`
|
||||
- b\ :sub:`6`
|
||||
- b\ :sub:`5`
|
||||
- b\ :sub:`4`
|
||||
- b\ :sub:`3`
|
||||
- b\ :sub:`2`
|
||||
- b\ :sub:`1`
|
||||
- b\ :sub:`0`
|
||||
|
||||
.. raw:: latex
|
||||
|
||||
@ -2344,7 +2657,8 @@ The format code is made of the following information.
|
||||
|
||||
- The number of bus samples per pixel. Pixels that are wider than the
|
||||
bus width must be transferred in multiple samples. Common values are
|
||||
1, 1.5 (encoded as 1_5) and 2.
|
||||
0.5 (encoded as 0_5; in this case two pixels are transferred per bus
|
||||
sample), 1, 1.5 (encoded as 1_5) and 2.
|
||||
|
||||
- The bus width. When the bus width is larger than the number of bits
|
||||
per pixel component, several components are packed in a single bus
|
||||
@ -5962,6 +6276,78 @@ the following codes.
|
||||
- v\ :sub:`2`
|
||||
- v\ :sub:`1`
|
||||
- v\ :sub:`0`
|
||||
* .. _MEDIA-BUS-FMT-UYYVYY8-0-5X24:
|
||||
|
||||
- MEDIA_BUS_FMT_UYYVYY8_0_5X24
|
||||
- 0x2026
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
- u\ :sub:`7`
|
||||
- u\ :sub:`6`
|
||||
- u\ :sub:`5`
|
||||
- u\ :sub:`4`
|
||||
- u\ :sub:`3`
|
||||
- u\ :sub:`2`
|
||||
- u\ :sub:`1`
|
||||
- u\ :sub:`0`
|
||||
- y\ :sub:`7`
|
||||
- y\ :sub:`6`
|
||||
- y\ :sub:`5`
|
||||
- y\ :sub:`4`
|
||||
- y\ :sub:`3`
|
||||
- y\ :sub:`2`
|
||||
- y\ :sub:`1`
|
||||
- y\ :sub:`0`
|
||||
- y\ :sub:`7`
|
||||
- y\ :sub:`6`
|
||||
- y\ :sub:`5`
|
||||
- y\ :sub:`4`
|
||||
- y\ :sub:`3`
|
||||
- y\ :sub:`2`
|
||||
- y\ :sub:`1`
|
||||
- y\ :sub:`0`
|
||||
* -
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
- v\ :sub:`7`
|
||||
- v\ :sub:`6`
|
||||
- v\ :sub:`5`
|
||||
- v\ :sub:`4`
|
||||
- v\ :sub:`3`
|
||||
- v\ :sub:`2`
|
||||
- v\ :sub:`1`
|
||||
- v\ :sub:`0`
|
||||
- y\ :sub:`7`
|
||||
- y\ :sub:`6`
|
||||
- y\ :sub:`5`
|
||||
- y\ :sub:`4`
|
||||
- y\ :sub:`3`
|
||||
- y\ :sub:`2`
|
||||
- y\ :sub:`1`
|
||||
- y\ :sub:`0`
|
||||
- y\ :sub:`7`
|
||||
- y\ :sub:`6`
|
||||
- y\ :sub:`5`
|
||||
- y\ :sub:`4`
|
||||
- y\ :sub:`3`
|
||||
- y\ :sub:`2`
|
||||
- y\ :sub:`1`
|
||||
- y\ :sub:`0`
|
||||
* .. _MEDIA-BUS-FMT-UYVY12-1X24:
|
||||
|
||||
- MEDIA_BUS_FMT_UYVY12_1X24
|
||||
@ -6287,6 +6673,78 @@ the following codes.
|
||||
- v\ :sub:`2`
|
||||
- v\ :sub:`1`
|
||||
- v\ :sub:`0`
|
||||
* .. _MEDIA-BUS-FMT-UYYVYY10-0-5X30:
|
||||
|
||||
- MEDIA_BUS_FMT_UYYVYY10_0_5X30
|
||||
- 0x2027
|
||||
-
|
||||
-
|
||||
-
|
||||
- u\ :sub:`9`
|
||||
- u\ :sub:`8`
|
||||
- u\ :sub:`7`
|
||||
- u\ :sub:`6`
|
||||
- u\ :sub:`5`
|
||||
- u\ :sub:`4`
|
||||
- u\ :sub:`3`
|
||||
- u\ :sub:`2`
|
||||
- u\ :sub:`1`
|
||||
- u\ :sub:`0`
|
||||
- y\ :sub:`9`
|
||||
- y\ :sub:`8`
|
||||
- y\ :sub:`7`
|
||||
- y\ :sub:`6`
|
||||
- y\ :sub:`5`
|
||||
- y\ :sub:`4`
|
||||
- y\ :sub:`3`
|
||||
- y\ :sub:`2`
|
||||
- y\ :sub:`1`
|
||||
- y\ :sub:`0`
|
||||
- y\ :sub:`9`
|
||||
- y\ :sub:`8`
|
||||
- y\ :sub:`7`
|
||||
- y\ :sub:`6`
|
||||
- y\ :sub:`5`
|
||||
- y\ :sub:`4`
|
||||
- y\ :sub:`3`
|
||||
- y\ :sub:`2`
|
||||
- y\ :sub:`1`
|
||||
- y\ :sub:`0`
|
||||
* -
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
- v\ :sub:`9`
|
||||
- v\ :sub:`8`
|
||||
- v\ :sub:`7`
|
||||
- v\ :sub:`6`
|
||||
- v\ :sub:`5`
|
||||
- v\ :sub:`4`
|
||||
- v\ :sub:`3`
|
||||
- v\ :sub:`2`
|
||||
- v\ :sub:`1`
|
||||
- v\ :sub:`0`
|
||||
- y\ :sub:`9`
|
||||
- y\ :sub:`8`
|
||||
- y\ :sub:`7`
|
||||
- y\ :sub:`6`
|
||||
- y\ :sub:`5`
|
||||
- y\ :sub:`4`
|
||||
- y\ :sub:`3`
|
||||
- y\ :sub:`2`
|
||||
- y\ :sub:`1`
|
||||
- y\ :sub:`0`
|
||||
- y\ :sub:`9`
|
||||
- y\ :sub:`8`
|
||||
- y\ :sub:`7`
|
||||
- y\ :sub:`6`
|
||||
- y\ :sub:`5`
|
||||
- y\ :sub:`4`
|
||||
- y\ :sub:`3`
|
||||
- y\ :sub:`2`
|
||||
- y\ :sub:`1`
|
||||
- y\ :sub:`0`
|
||||
* .. _MEDIA-BUS-FMT-AYUV8-1X32:
|
||||
|
||||
- MEDIA_BUS_FMT_AYUV8_1X32
|
||||
@ -6326,6 +6784,506 @@ the following codes.
|
||||
- v\ :sub:`0`
|
||||
|
||||
|
||||
.. raw:: latex
|
||||
|
||||
\endgroup
|
||||
|
||||
|
||||
The following table list existing packed 36bit wide YUV formats.
|
||||
|
||||
.. raw:: latex
|
||||
|
||||
\begingroup
|
||||
\tiny
|
||||
\setlength{\tabcolsep}{2pt}
|
||||
|
||||
.. tabularcolumns:: |p{4.0cm}|p{0.7cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|
|
||||
|
||||
.. _v4l2-mbus-pixelcode-yuv8-36bit:
|
||||
|
||||
.. flat-table:: 36bit YUV Formats
|
||||
:header-rows: 2
|
||||
:stub-columns: 0
|
||||
:widths: 36 7 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
|
||||
|
||||
* - Identifier
|
||||
- Code
|
||||
-
|
||||
- :cspan:`35` Data organization
|
||||
* -
|
||||
-
|
||||
- Bit
|
||||
- 35
|
||||
- 34
|
||||
- 33
|
||||
- 32
|
||||
- 31
|
||||
- 30
|
||||
- 29
|
||||
- 28
|
||||
- 27
|
||||
- 26
|
||||
- 25
|
||||
- 24
|
||||
- 23
|
||||
- 22
|
||||
- 21
|
||||
- 10
|
||||
- 19
|
||||
- 18
|
||||
- 17
|
||||
- 16
|
||||
- 15
|
||||
- 14
|
||||
- 13
|
||||
- 12
|
||||
- 11
|
||||
- 10
|
||||
- 9
|
||||
- 8
|
||||
- 7
|
||||
- 6
|
||||
- 5
|
||||
- 4
|
||||
- 3
|
||||
- 2
|
||||
- 1
|
||||
- 0
|
||||
* .. _MEDIA-BUS-FMT-UYYVYY12-0-5X36:
|
||||
|
||||
- MEDIA_BUS_FMT_UYYVYY12_0_5X36
|
||||
- 0x2028
|
||||
-
|
||||
- u\ :sub:`11`
|
||||
- u\ :sub:`10`
|
||||
- u\ :sub:`9`
|
||||
- u\ :sub:`8`
|
||||
- u\ :sub:`7`
|
||||
- u\ :sub:`6`
|
||||
- u\ :sub:`5`
|
||||
- u\ :sub:`4`
|
||||
- u\ :sub:`3`
|
||||
- u\ :sub:`2`
|
||||
- u\ :sub:`1`
|
||||
- u\ :sub:`0`
|
||||
- y\ :sub:`11`
|
||||
- y\ :sub:`10`
|
||||
- y\ :sub:`9`
|
||||
- y\ :sub:`8`
|
||||
- y\ :sub:`7`
|
||||
- y\ :sub:`6`
|
||||
- y\ :sub:`5`
|
||||
- y\ :sub:`4`
|
||||
- y\ :sub:`3`
|
||||
- y\ :sub:`2`
|
||||
- y\ :sub:`1`
|
||||
- y\ :sub:`0`
|
||||
- y\ :sub:`11`
|
||||
- y\ :sub:`10`
|
||||
- y\ :sub:`9`
|
||||
- y\ :sub:`8`
|
||||
- y\ :sub:`7`
|
||||
- y\ :sub:`6`
|
||||
- y\ :sub:`5`
|
||||
- y\ :sub:`4`
|
||||
- y\ :sub:`3`
|
||||
- y\ :sub:`2`
|
||||
- y\ :sub:`1`
|
||||
- y\ :sub:`0`
|
||||
* -
|
||||
-
|
||||
-
|
||||
- v\ :sub:`11`
|
||||
- v\ :sub:`10`
|
||||
- v\ :sub:`9`
|
||||
- v\ :sub:`8`
|
||||
- v\ :sub:`7`
|
||||
- v\ :sub:`6`
|
||||
- v\ :sub:`5`
|
||||
- v\ :sub:`4`
|
||||
- v\ :sub:`3`
|
||||
- v\ :sub:`2`
|
||||
- v\ :sub:`1`
|
||||
- v\ :sub:`0`
|
||||
- y\ :sub:`11`
|
||||
- y\ :sub:`10`
|
||||
- y\ :sub:`9`
|
||||
- y\ :sub:`8`
|
||||
- y\ :sub:`7`
|
||||
- y\ :sub:`6`
|
||||
- y\ :sub:`5`
|
||||
- y\ :sub:`4`
|
||||
- y\ :sub:`3`
|
||||
- y\ :sub:`2`
|
||||
- y\ :sub:`1`
|
||||
- y\ :sub:`0`
|
||||
- y\ :sub:`11`
|
||||
- y\ :sub:`10`
|
||||
- y\ :sub:`9`
|
||||
- y\ :sub:`8`
|
||||
- y\ :sub:`7`
|
||||
- y\ :sub:`6`
|
||||
- y\ :sub:`5`
|
||||
- y\ :sub:`4`
|
||||
- y\ :sub:`3`
|
||||
- y\ :sub:`2`
|
||||
- y\ :sub:`1`
|
||||
- y\ :sub:`0`
|
||||
* .. _MEDIA-BUS-FMT-YUV12-1X36:
|
||||
|
||||
- MEDIA_BUS_FMT_YUV12_1X36
|
||||
- 0x2029
|
||||
-
|
||||
- y\ :sub:`11`
|
||||
- y\ :sub:`10`
|
||||
- y\ :sub:`9`
|
||||
- y\ :sub:`8`
|
||||
- y\ :sub:`7`
|
||||
- y\ :sub:`6`
|
||||
- y\ :sub:`5`
|
||||
- y\ :sub:`4`
|
||||
- y\ :sub:`3`
|
||||
- y\ :sub:`2`
|
||||
- y\ :sub:`1`
|
||||
- y\ :sub:`0`
|
||||
- u\ :sub:`11`
|
||||
- u\ :sub:`10`
|
||||
- u\ :sub:`9`
|
||||
- u\ :sub:`8`
|
||||
- u\ :sub:`7`
|
||||
- u\ :sub:`6`
|
||||
- u\ :sub:`5`
|
||||
- u\ :sub:`4`
|
||||
- u\ :sub:`3`
|
||||
- u\ :sub:`2`
|
||||
- u\ :sub:`1`
|
||||
- u\ :sub:`0`
|
||||
- v\ :sub:`11`
|
||||
- v\ :sub:`10`
|
||||
- v\ :sub:`9`
|
||||
- v\ :sub:`8`
|
||||
- v\ :sub:`7`
|
||||
- v\ :sub:`6`
|
||||
- v\ :sub:`5`
|
||||
- v\ :sub:`4`
|
||||
- v\ :sub:`3`
|
||||
- v\ :sub:`2`
|
||||
- v\ :sub:`1`
|
||||
- v\ :sub:`0`
|
||||
|
||||
|
||||
.. raw:: latex
|
||||
|
||||
\endgroup
|
||||
|
||||
|
||||
The following table list existing packed 48bit wide YUV formats.
|
||||
|
||||
.. raw:: latex
|
||||
|
||||
\begingroup
|
||||
\tiny
|
||||
\setlength{\tabcolsep}{2pt}
|
||||
|
||||
.. tabularcolumns:: |p{4.0cm}|p{0.7cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|
|
||||
|
||||
.. _v4l2-mbus-pixelcode-yuv8-48bit:
|
||||
|
||||
.. flat-table:: 48bit YUV Formats
|
||||
:header-rows: 3
|
||||
:stub-columns: 0
|
||||
:widths: 36 7 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
|
||||
|
||||
* - Identifier
|
||||
- Code
|
||||
-
|
||||
- :cspan:`31` Data organization
|
||||
* -
|
||||
-
|
||||
- Bit
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
- 47
|
||||
- 46
|
||||
- 45
|
||||
- 44
|
||||
- 43
|
||||
- 42
|
||||
- 41
|
||||
- 40
|
||||
- 39
|
||||
- 38
|
||||
- 37
|
||||
- 36
|
||||
- 35
|
||||
- 34
|
||||
- 33
|
||||
- 32
|
||||
* -
|
||||
-
|
||||
-
|
||||
- 31
|
||||
- 30
|
||||
- 29
|
||||
- 28
|
||||
- 27
|
||||
- 26
|
||||
- 25
|
||||
- 24
|
||||
- 23
|
||||
- 22
|
||||
- 21
|
||||
- 10
|
||||
- 19
|
||||
- 18
|
||||
- 17
|
||||
- 16
|
||||
- 15
|
||||
- 14
|
||||
- 13
|
||||
- 12
|
||||
- 11
|
||||
- 10
|
||||
- 9
|
||||
- 8
|
||||
- 7
|
||||
- 6
|
||||
- 5
|
||||
- 4
|
||||
- 3
|
||||
- 2
|
||||
- 1
|
||||
- 0
|
||||
* .. _MEDIA-BUS-FMT-YUV16-1X48:
|
||||
|
||||
- MEDIA_BUS_FMT_YUV16_1X48
|
||||
- 0x202a
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
- y\ :sub:`15`
|
||||
- y\ :sub:`14`
|
||||
- y\ :sub:`13`
|
||||
- y\ :sub:`12`
|
||||
- y\ :sub:`11`
|
||||
- y\ :sub:`10`
|
||||
- y\ :sub:`8`
|
||||
- y\ :sub:`8`
|
||||
- y\ :sub:`7`
|
||||
- y\ :sub:`6`
|
||||
- y\ :sub:`5`
|
||||
- y\ :sub:`4`
|
||||
- y\ :sub:`3`
|
||||
- y\ :sub:`2`
|
||||
- y\ :sub:`1`
|
||||
- y\ :sub:`0`
|
||||
* -
|
||||
-
|
||||
-
|
||||
- u\ :sub:`15`
|
||||
- u\ :sub:`14`
|
||||
- u\ :sub:`13`
|
||||
- u\ :sub:`12`
|
||||
- u\ :sub:`11`
|
||||
- u\ :sub:`10`
|
||||
- u\ :sub:`9`
|
||||
- u\ :sub:`8`
|
||||
- u\ :sub:`7`
|
||||
- u\ :sub:`6`
|
||||
- u\ :sub:`5`
|
||||
- u\ :sub:`4`
|
||||
- u\ :sub:`3`
|
||||
- u\ :sub:`2`
|
||||
- u\ :sub:`1`
|
||||
- u\ :sub:`0`
|
||||
- v\ :sub:`15`
|
||||
- v\ :sub:`14`
|
||||
- v\ :sub:`13`
|
||||
- v\ :sub:`12`
|
||||
- v\ :sub:`11`
|
||||
- v\ :sub:`10`
|
||||
- v\ :sub:`9`
|
||||
- v\ :sub:`8`
|
||||
- v\ :sub:`7`
|
||||
- v\ :sub:`6`
|
||||
- v\ :sub:`5`
|
||||
- v\ :sub:`4`
|
||||
- v\ :sub:`3`
|
||||
- v\ :sub:`2`
|
||||
- v\ :sub:`1`
|
||||
- v\ :sub:`0`
|
||||
* .. _MEDIA-BUS-FMT-UYYVYY16-0-5X48:
|
||||
|
||||
- MEDIA_BUS_FMT_UYYVYY16_0_5X48
|
||||
- 0x202b
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
- u\ :sub:`15`
|
||||
- u\ :sub:`14`
|
||||
- u\ :sub:`13`
|
||||
- u\ :sub:`12`
|
||||
- u\ :sub:`11`
|
||||
- u\ :sub:`10`
|
||||
- u\ :sub:`9`
|
||||
- u\ :sub:`8`
|
||||
- u\ :sub:`7`
|
||||
- u\ :sub:`6`
|
||||
- u\ :sub:`5`
|
||||
- u\ :sub:`4`
|
||||
- u\ :sub:`3`
|
||||
- u\ :sub:`2`
|
||||
- u\ :sub:`1`
|
||||
- u\ :sub:`0`
|
||||
* -
|
||||
-
|
||||
-
|
||||
- y\ :sub:`15`
|
||||
- y\ :sub:`14`
|
||||
- y\ :sub:`13`
|
||||
- y\ :sub:`12`
|
||||
- y\ :sub:`11`
|
||||
- y\ :sub:`10`
|
||||
- y\ :sub:`9`
|
||||
- y\ :sub:`8`
|
||||
- y\ :sub:`7`
|
||||
- y\ :sub:`6`
|
||||
- y\ :sub:`5`
|
||||
- y\ :sub:`4`
|
||||
- y\ :sub:`3`
|
||||
- y\ :sub:`2`
|
||||
- y\ :sub:`1`
|
||||
- y\ :sub:`0`
|
||||
- y\ :sub:`15`
|
||||
- y\ :sub:`14`
|
||||
- y\ :sub:`13`
|
||||
- y\ :sub:`12`
|
||||
- y\ :sub:`11`
|
||||
- y\ :sub:`10`
|
||||
- y\ :sub:`8`
|
||||
- y\ :sub:`8`
|
||||
- y\ :sub:`7`
|
||||
- y\ :sub:`6`
|
||||
- y\ :sub:`5`
|
||||
- y\ :sub:`4`
|
||||
- y\ :sub:`3`
|
||||
- y\ :sub:`2`
|
||||
- y\ :sub:`1`
|
||||
- y\ :sub:`0`
|
||||
* -
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
- v\ :sub:`15`
|
||||
- v\ :sub:`14`
|
||||
- v\ :sub:`13`
|
||||
- v\ :sub:`12`
|
||||
- v\ :sub:`11`
|
||||
- v\ :sub:`10`
|
||||
- v\ :sub:`9`
|
||||
- v\ :sub:`8`
|
||||
- v\ :sub:`7`
|
||||
- v\ :sub:`6`
|
||||
- v\ :sub:`5`
|
||||
- v\ :sub:`4`
|
||||
- v\ :sub:`3`
|
||||
- v\ :sub:`2`
|
||||
- v\ :sub:`1`
|
||||
- v\ :sub:`0`
|
||||
* -
|
||||
-
|
||||
-
|
||||
- y\ :sub:`15`
|
||||
- y\ :sub:`14`
|
||||
- y\ :sub:`13`
|
||||
- y\ :sub:`12`
|
||||
- y\ :sub:`11`
|
||||
- y\ :sub:`10`
|
||||
- y\ :sub:`9`
|
||||
- y\ :sub:`8`
|
||||
- y\ :sub:`7`
|
||||
- y\ :sub:`6`
|
||||
- y\ :sub:`5`
|
||||
- y\ :sub:`4`
|
||||
- y\ :sub:`3`
|
||||
- y\ :sub:`2`
|
||||
- y\ :sub:`1`
|
||||
- y\ :sub:`0`
|
||||
- y\ :sub:`15`
|
||||
- y\ :sub:`14`
|
||||
- y\ :sub:`13`
|
||||
- y\ :sub:`12`
|
||||
- y\ :sub:`11`
|
||||
- y\ :sub:`10`
|
||||
- y\ :sub:`8`
|
||||
- y\ :sub:`8`
|
||||
- y\ :sub:`7`
|
||||
- y\ :sub:`6`
|
||||
- y\ :sub:`5`
|
||||
- y\ :sub:`4`
|
||||
- y\ :sub:`3`
|
||||
- y\ :sub:`2`
|
||||
- y\ :sub:`1`
|
||||
- y\ :sub:`0`
|
||||
|
||||
|
||||
.. raw:: latex
|
||||
|
||||
\endgroup
|
||||
|
@ -3,6 +3,7 @@
|
||||
\renewcommand\thesection*
|
||||
\renewcommand\thesubsection*
|
||||
|
||||
.. _process_index:
|
||||
|
||||
Working with the kernel development community
|
||||
=============================================
|
||||
|
37
MAINTAINERS
37
MAINTAINERS
@ -4178,6 +4178,7 @@ F: Documentation/devicetree/bindings/video/
|
||||
F: Documentation/gpu/
|
||||
F: include/drm/
|
||||
F: include/uapi/drm/
|
||||
F: include/linux/vga*
|
||||
|
||||
DRM DRIVERS AND MISC GPU PATCHES
|
||||
M: Daniel Vetter <daniel.vetter@intel.com>
|
||||
@ -4191,6 +4192,7 @@ F: drivers/gpu/vga/
|
||||
F: drivers/gpu/drm/*
|
||||
F: include/drm/drm*
|
||||
F: include/uapi/drm/drm*
|
||||
F: include/linux/vga*
|
||||
|
||||
DRM DRIVER FOR AST SERVER GRAPHICS CHIPS
|
||||
M: Dave Airlie <airlied@redhat.com>
|
||||
@ -4206,7 +4208,7 @@ F: drivers/gpu/drm/bridge/
|
||||
DRM DRIVER FOR BOCHS VIRTUAL GPU
|
||||
M: Gerd Hoffmann <kraxel@redhat.com>
|
||||
L: virtualization@lists.linux-foundation.org
|
||||
T: git git://git.kraxel.org/linux drm-qemu
|
||||
T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
S: Maintained
|
||||
F: drivers/gpu/drm/bochs/
|
||||
|
||||
@ -4214,7 +4216,7 @@ DRM DRIVER FOR QEMU'S CIRRUS DEVICE
|
||||
M: Dave Airlie <airlied@redhat.com>
|
||||
M: Gerd Hoffmann <kraxel@redhat.com>
|
||||
L: virtualization@lists.linux-foundation.org
|
||||
T: git git://git.kraxel.org/linux drm-qemu
|
||||
T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
S: Obsolete
|
||||
W: https://www.kraxel.org/blog/2014/10/qemu-using-cirrus-considered-harmful/
|
||||
F: drivers/gpu/drm/cirrus/
|
||||
@ -4271,6 +4273,7 @@ L: dri-devel@lists.freedesktop.org
|
||||
S: Supported
|
||||
F: drivers/gpu/drm/atmel-hlcdc/
|
||||
F: Documentation/devicetree/bindings/drm/atmel/
|
||||
T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
|
||||
DRM DRIVERS FOR ALLWINNER A10
|
||||
M: Maxime Ripard <maxime.ripard@free-electrons.com>
|
||||
@ -4278,6 +4281,7 @@ L: dri-devel@lists.freedesktop.org
|
||||
S: Supported
|
||||
F: drivers/gpu/drm/sun4i/
|
||||
F: Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mripard/linux.git
|
||||
|
||||
DRM DRIVERS FOR AMLOGIC SOCS
|
||||
M: Neil Armstrong <narmstrong@baylibre.com>
|
||||
@ -4287,6 +4291,9 @@ W: http://linux-meson.com/
|
||||
S: Supported
|
||||
F: drivers/gpu/drm/meson/
|
||||
F: Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt
|
||||
F: Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt
|
||||
F: Documentation/gpu/meson.rst
|
||||
T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
|
||||
DRM DRIVERS FOR EXYNOS
|
||||
M: Inki Dae <inki.dae@samsung.com>
|
||||
@ -4411,13 +4418,14 @@ S: Supported
|
||||
F: drivers/gpu/drm/rcar-du/
|
||||
F: drivers/gpu/drm/shmobile/
|
||||
F: include/linux/platform_data/shmob_drm.h
|
||||
F: Documentation/devicetree/bindings/display/bridge/renesas,dw-hdmi.txt
|
||||
F: Documentation/devicetree/bindings/display/renesas,du.txt
|
||||
|
||||
DRM DRIVER FOR QXL VIRTUAL GPU
|
||||
M: Dave Airlie <airlied@redhat.com>
|
||||
M: Gerd Hoffmann <kraxel@redhat.com>
|
||||
L: virtualization@lists.linux-foundation.org
|
||||
T: git git://git.kraxel.org/linux drm-qemu
|
||||
T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
S: Maintained
|
||||
F: drivers/gpu/drm/qxl/
|
||||
F: include/uapi/drm/qxl_drm.h
|
||||
@ -4428,6 +4436,7 @@ L: dri-devel@lists.freedesktop.org
|
||||
S: Maintained
|
||||
F: drivers/gpu/drm/rockchip/
|
||||
F: Documentation/devicetree/bindings/display/rockchip/
|
||||
T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
|
||||
DRM DRIVER FOR SAVAGE VIDEO CARDS
|
||||
S: Orphan / Obsolete
|
||||
@ -4443,7 +4452,7 @@ DRM DRIVERS FOR STI
|
||||
M: Benjamin Gaignard <benjamin.gaignard@linaro.org>
|
||||
M: Vincent Abriou <vincent.abriou@st.com>
|
||||
L: dri-devel@lists.freedesktop.org
|
||||
T: git http://git.linaro.org/people/benjamin.gaignard/kernel.git
|
||||
T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
S: Maintained
|
||||
F: drivers/gpu/drm/sti
|
||||
F: Documentation/devicetree/bindings/display/st,stih4xx.txt
|
||||
@ -4486,6 +4495,7 @@ S: Supported
|
||||
F: drivers/gpu/drm/vc4/
|
||||
F: include/uapi/drm/vc4_drm.h
|
||||
F: Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt
|
||||
T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
|
||||
DRM DRIVERS FOR TI OMAP
|
||||
M: Tomi Valkeinen <tomi.valkeinen@ti.com>
|
||||
@ -4508,6 +4518,7 @@ L: dri-devel@lists.freedesktop.org
|
||||
S: Maintained
|
||||
F: drivers/gpu/drm/zte/
|
||||
F: Documentation/devicetree/bindings/display/zte,vou.txt
|
||||
T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
|
||||
DSBR100 USB FM RADIO DRIVER
|
||||
M: Alexey Klimov <klimov.linux@gmail.com>
|
||||
@ -8185,6 +8196,14 @@ L: linux-wireless@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/net/wireless/mediatek/mt7601u/
|
||||
|
||||
MEGACHIPS STDPXXXX-GE-B850V3-FW LVDS/DP++ BRIDGES
|
||||
M: Peter Senna Tschudin <peter.senna@collabora.com>
|
||||
M: Martin Donnelly <martin.donnelly@ge.com>
|
||||
M: Martyn Welch <martyn.welch@collabora.co.uk>
|
||||
S: Maintained
|
||||
F: drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c
|
||||
F: Documentation/devicetree/bindings/video/bridge/megachips-stdpxxxx-ge-b850v3-fw.txt
|
||||
|
||||
MEGARAID SCSI/SAS DRIVERS
|
||||
M: Kashyap Desai <kashyap.desai@broadcom.com>
|
||||
M: Sumit Saxena <sumit.saxena@broadcom.com>
|
||||
@ -13359,6 +13378,14 @@ L: kvm@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/vfio/platform/
|
||||
|
||||
VGA_SWITCHEROO
|
||||
R: Lukas Wunner <lukas@wunner.de>
|
||||
S: Maintained
|
||||
F: Documentation/gpu/vga-switcheroo.rst
|
||||
F: drivers/gpu/vga/vga_switcheroo.c
|
||||
F: include/linux/vga_switcheroo.h
|
||||
T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
|
||||
VIDEOBUF2 FRAMEWORK
|
||||
M: Pawel Osciak <pawel@osciak.com>
|
||||
M: Marek Szyprowski <m.szyprowski@samsung.com>
|
||||
@ -13426,7 +13453,7 @@ M: David Airlie <airlied@linux.ie>
|
||||
M: Gerd Hoffmann <kraxel@redhat.com>
|
||||
L: dri-devel@lists.freedesktop.org
|
||||
L: virtualization@lists.linux-foundation.org
|
||||
T: git git://git.kraxel.org/linux drm-qemu
|
||||
T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
S: Maintained
|
||||
F: drivers/gpu/drm/virtio/
|
||||
F: include/uapi/linux/virtio_gpu.h
|
||||
|
@ -5,6 +5,8 @@
|
||||
#ifndef IOSF_MBI_SYMS_H
|
||||
#define IOSF_MBI_SYMS_H
|
||||
|
||||
#include <linux/notifier.h>
|
||||
|
||||
#define MBI_MCR_OFFSET 0xD0
|
||||
#define MBI_MDR_OFFSET 0xD4
|
||||
#define MBI_MCRX_OFFSET 0xD8
|
||||
@ -47,6 +49,10 @@
|
||||
#define QRK_MBI_UNIT_MM 0x05
|
||||
#define QRK_MBI_UNIT_SOC 0x31
|
||||
|
||||
/* Action values for the pmic_bus_access_notifier functions */
|
||||
#define MBI_PMIC_BUS_ACCESS_BEGIN 1
|
||||
#define MBI_PMIC_BUS_ACCESS_END 2
|
||||
|
||||
#if IS_ENABLED(CONFIG_IOSF_MBI)
|
||||
|
||||
bool iosf_mbi_available(void);
|
||||
@ -88,6 +94,65 @@ int iosf_mbi_write(u8 port, u8 opcode, u32 offset, u32 mdr);
|
||||
*/
|
||||
int iosf_mbi_modify(u8 port, u8 opcode, u32 offset, u32 mdr, u32 mask);
|
||||
|
||||
/**
|
||||
* iosf_mbi_punit_acquire() - Acquire access to the P-Unit
|
||||
*
|
||||
* One some systems the P-Unit accesses the PMIC to change various voltages
|
||||
* through the same bus as other kernel drivers use for e.g. battery monitoring.
|
||||
*
|
||||
* If a driver sends requests to the P-Unit which require the P-Unit to access
|
||||
* the PMIC bus while another driver is also accessing the PMIC bus various bad
|
||||
* things happen.
|
||||
*
|
||||
* To avoid these problems this function must be called before accessing the
|
||||
* P-Unit or the PMIC, be it through iosf_mbi* functions or through other means.
|
||||
*
|
||||
* Note on these systems the i2c-bus driver will request a sempahore from the
|
||||
* P-Unit for exclusive access to the PMIC bus when i2c drivers are accessing
|
||||
* it, but this does not appear to be sufficient, we still need to avoid making
|
||||
* certain P-Unit requests during the access window to avoid problems.
|
||||
*
|
||||
* This function locks a mutex, as such it may sleep.
|
||||
*/
|
||||
void iosf_mbi_punit_acquire(void);
|
||||
|
||||
/**
|
||||
* iosf_mbi_punit_release() - Release access to the P-Unit
|
||||
*/
|
||||
void iosf_mbi_punit_release(void);
|
||||
|
||||
/**
|
||||
* iosf_mbi_register_pmic_bus_access_notifier - Register PMIC bus notifier
|
||||
*
|
||||
* This function can be used by drivers which may need to acquire P-Unit
|
||||
* managed resources from interrupt context, where iosf_mbi_punit_acquire()
|
||||
* can not be used.
|
||||
*
|
||||
* This function allows a driver to register a notifier to get notified (in a
|
||||
* process context) before other drivers start accessing the PMIC bus.
|
||||
*
|
||||
* This allows the driver to acquire any resources, which it may need during
|
||||
* the window the other driver is accessing the PMIC, before hand.
|
||||
*
|
||||
* @nb: notifier_block to register
|
||||
*/
|
||||
int iosf_mbi_register_pmic_bus_access_notifier(struct notifier_block *nb);
|
||||
|
||||
/**
|
||||
* iosf_mbi_register_pmic_bus_access_notifier - Unregister PMIC bus notifier
|
||||
*
|
||||
* @nb: notifier_block to unregister
|
||||
*/
|
||||
int iosf_mbi_unregister_pmic_bus_access_notifier(struct notifier_block *nb);
|
||||
|
||||
/**
|
||||
* iosf_mbi_call_pmic_bus_access_notifier_chain - Call PMIC bus notifier chain
|
||||
*
|
||||
* @val: action to pass into listener's notifier_call function
|
||||
* @v: data pointer to pass into listener's notifier_call function
|
||||
*/
|
||||
int iosf_mbi_call_pmic_bus_access_notifier_chain(unsigned long val, void *v);
|
||||
|
||||
#else /* CONFIG_IOSF_MBI is not enabled */
|
||||
static inline
|
||||
bool iosf_mbi_available(void)
|
||||
@ -115,6 +180,28 @@ int iosf_mbi_modify(u8 port, u8 opcode, u32 offset, u32 mdr, u32 mask)
|
||||
WARN(1, "IOSF_MBI driver not available");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
static inline void iosf_mbi_punit_acquire(void) {}
|
||||
static inline void iosf_mbi_punit_release(void) {}
|
||||
|
||||
static inline
|
||||
int iosf_mbi_register_pmic_bus_access_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline
|
||||
int iosf_mbi_unregister_pmic_bus_access_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline
|
||||
int iosf_mbi_call_pmic_bus_access_notifier_chain(unsigned long val, void *v)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_IOSF_MBI */
|
||||
|
||||
#endif /* IOSF_MBI_SYMS_H */
|
||||
|
@ -526,6 +526,7 @@ static const struct pci_device_id intel_early_ids[] __initconst = {
|
||||
INTEL_SKL_IDS(&gen9_early_ops),
|
||||
INTEL_BXT_IDS(&gen9_early_ops),
|
||||
INTEL_KBL_IDS(&gen9_early_ops),
|
||||
INTEL_GLK_IDS(&gen9_early_ops),
|
||||
};
|
||||
|
||||
static void __init
|
||||
|
@ -34,6 +34,8 @@
|
||||
|
||||
static struct pci_dev *mbi_pdev;
|
||||
static DEFINE_SPINLOCK(iosf_mbi_lock);
|
||||
static DEFINE_MUTEX(iosf_mbi_punit_mutex);
|
||||
static BLOCKING_NOTIFIER_HEAD(iosf_mbi_pmic_bus_access_notifier);
|
||||
|
||||
static inline u32 iosf_mbi_form_mcr(u8 op, u8 port, u8 offset)
|
||||
{
|
||||
@ -190,6 +192,53 @@ bool iosf_mbi_available(void)
|
||||
}
|
||||
EXPORT_SYMBOL(iosf_mbi_available);
|
||||
|
||||
void iosf_mbi_punit_acquire(void)
|
||||
{
|
||||
mutex_lock(&iosf_mbi_punit_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(iosf_mbi_punit_acquire);
|
||||
|
||||
void iosf_mbi_punit_release(void)
|
||||
{
|
||||
mutex_unlock(&iosf_mbi_punit_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(iosf_mbi_punit_release);
|
||||
|
||||
int iosf_mbi_register_pmic_bus_access_notifier(struct notifier_block *nb)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Wait for the bus to go inactive before registering */
|
||||
mutex_lock(&iosf_mbi_punit_mutex);
|
||||
ret = blocking_notifier_chain_register(
|
||||
&iosf_mbi_pmic_bus_access_notifier, nb);
|
||||
mutex_unlock(&iosf_mbi_punit_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(iosf_mbi_register_pmic_bus_access_notifier);
|
||||
|
||||
int iosf_mbi_unregister_pmic_bus_access_notifier(struct notifier_block *nb)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Wait for the bus to go inactive before unregistering */
|
||||
mutex_lock(&iosf_mbi_punit_mutex);
|
||||
ret = blocking_notifier_chain_unregister(
|
||||
&iosf_mbi_pmic_bus_access_notifier, nb);
|
||||
mutex_unlock(&iosf_mbi_punit_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(iosf_mbi_unregister_pmic_bus_access_notifier);
|
||||
|
||||
int iosf_mbi_call_pmic_bus_access_notifier_chain(unsigned long val, void *v)
|
||||
{
|
||||
return blocking_notifier_call_chain(
|
||||
&iosf_mbi_pmic_bus_access_notifier, val, v);
|
||||
}
|
||||
EXPORT_SYMBOL(iosf_mbi_call_pmic_bus_access_notifier_chain);
|
||||
|
||||
#ifdef CONFIG_IOSF_MBI_DEBUG
|
||||
static u32 dbg_mdr;
|
||||
static u32 dbg_mcr;
|
||||
|
@ -332,14 +332,6 @@ static void i810_write_entry(dma_addr_t addr, unsigned int entry,
|
||||
writel_relaxed(addr | pte_flags, intel_private.gtt + entry);
|
||||
}
|
||||
|
||||
static const struct aper_size_info_fixed intel_fake_agp_sizes[] = {
|
||||
{32, 8192, 3},
|
||||
{64, 16384, 4},
|
||||
{128, 32768, 5},
|
||||
{256, 65536, 6},
|
||||
{512, 131072, 7},
|
||||
};
|
||||
|
||||
static unsigned int intel_gtt_stolen_size(void)
|
||||
{
|
||||
u16 gmch_ctrl;
|
||||
@ -670,6 +662,14 @@ static int intel_gtt_init(void)
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_AGP_INTEL)
|
||||
static const struct aper_size_info_fixed intel_fake_agp_sizes[] = {
|
||||
{32, 8192, 3},
|
||||
{64, 16384, 4},
|
||||
{128, 32768, 5},
|
||||
{256, 65536, 6},
|
||||
{512, 131072, 7},
|
||||
};
|
||||
|
||||
static int intel_fake_agp_fetch_size(void)
|
||||
{
|
||||
int num_sizes = ARRAY_SIZE(intel_fake_agp_sizes);
|
||||
|
@ -405,8 +405,8 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info)
|
||||
|| !exp_info->ops->map_dma_buf
|
||||
|| !exp_info->ops->unmap_dma_buf
|
||||
|| !exp_info->ops->release
|
||||
|| !exp_info->ops->kmap_atomic
|
||||
|| !exp_info->ops->kmap
|
||||
|| !exp_info->ops->map_atomic
|
||||
|| !exp_info->ops->map
|
||||
|| !exp_info->ops->mmap)) {
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
@ -872,7 +872,7 @@ void *dma_buf_kmap_atomic(struct dma_buf *dmabuf, unsigned long page_num)
|
||||
{
|
||||
WARN_ON(!dmabuf);
|
||||
|
||||
return dmabuf->ops->kmap_atomic(dmabuf, page_num);
|
||||
return dmabuf->ops->map_atomic(dmabuf, page_num);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dma_buf_kmap_atomic);
|
||||
|
||||
@ -889,8 +889,8 @@ void dma_buf_kunmap_atomic(struct dma_buf *dmabuf, unsigned long page_num,
|
||||
{
|
||||
WARN_ON(!dmabuf);
|
||||
|
||||
if (dmabuf->ops->kunmap_atomic)
|
||||
dmabuf->ops->kunmap_atomic(dmabuf, page_num, vaddr);
|
||||
if (dmabuf->ops->unmap_atomic)
|
||||
dmabuf->ops->unmap_atomic(dmabuf, page_num, vaddr);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dma_buf_kunmap_atomic);
|
||||
|
||||
@ -907,7 +907,7 @@ void *dma_buf_kmap(struct dma_buf *dmabuf, unsigned long page_num)
|
||||
{
|
||||
WARN_ON(!dmabuf);
|
||||
|
||||
return dmabuf->ops->kmap(dmabuf, page_num);
|
||||
return dmabuf->ops->map(dmabuf, page_num);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dma_buf_kmap);
|
||||
|
||||
@ -924,8 +924,8 @@ void dma_buf_kunmap(struct dma_buf *dmabuf, unsigned long page_num,
|
||||
{
|
||||
WARN_ON(!dmabuf);
|
||||
|
||||
if (dmabuf->ops->kunmap)
|
||||
dmabuf->ops->kunmap(dmabuf, page_num, vaddr);
|
||||
if (dmabuf->ops->unmap)
|
||||
dmabuf->ops->unmap(dmabuf, page_num, vaddr);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dma_buf_kunmap);
|
||||
|
||||
@ -1059,7 +1059,11 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused)
|
||||
int ret;
|
||||
struct dma_buf *buf_obj;
|
||||
struct dma_buf_attachment *attach_obj;
|
||||
int count = 0, attach_count;
|
||||
struct reservation_object *robj;
|
||||
struct reservation_object_list *fobj;
|
||||
struct dma_fence *fence;
|
||||
unsigned seq;
|
||||
int count = 0, attach_count, shared_count, i;
|
||||
size_t size = 0;
|
||||
|
||||
ret = mutex_lock_interruptible(&db_list.lock);
|
||||
@ -1068,7 +1072,8 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused)
|
||||
return ret;
|
||||
|
||||
seq_puts(s, "\nDma-buf Objects:\n");
|
||||
seq_puts(s, "size\tflags\tmode\tcount\texp_name\n");
|
||||
seq_printf(s, "%-8s\t%-8s\t%-8s\t%-8s\texp_name\n",
|
||||
"size", "flags", "mode", "count");
|
||||
|
||||
list_for_each_entry(buf_obj, &db_list.head, list_node) {
|
||||
ret = mutex_lock_interruptible(&buf_obj->lock);
|
||||
@ -1085,6 +1090,34 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused)
|
||||
file_count(buf_obj->file),
|
||||
buf_obj->exp_name);
|
||||
|
||||
robj = buf_obj->resv;
|
||||
while (true) {
|
||||
seq = read_seqcount_begin(&robj->seq);
|
||||
rcu_read_lock();
|
||||
fobj = rcu_dereference(robj->fence);
|
||||
shared_count = fobj ? fobj->shared_count : 0;
|
||||
fence = rcu_dereference(robj->fence_excl);
|
||||
if (!read_seqcount_retry(&robj->seq, seq))
|
||||
break;
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
if (fence)
|
||||
seq_printf(s, "\tExclusive fence: %s %s %ssignalled\n",
|
||||
fence->ops->get_driver_name(fence),
|
||||
fence->ops->get_timeline_name(fence),
|
||||
dma_fence_is_signaled(fence) ? "" : "un");
|
||||
for (i = 0; i < shared_count; i++) {
|
||||
fence = rcu_dereference(fobj->shared[i]);
|
||||
if (!dma_fence_get_rcu(fence))
|
||||
continue;
|
||||
seq_printf(s, "\tShared fence: %s %s %ssignalled\n",
|
||||
fence->ops->get_driver_name(fence),
|
||||
fence->ops->get_timeline_name(fence),
|
||||
dma_fence_is_signaled(fence) ? "" : "un");
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
seq_puts(s, "\tAttached Devices:\n");
|
||||
attach_count = 0;
|
||||
|
||||
|
@ -144,3 +144,29 @@ struct dma_fence_array *dma_fence_array_create(int num_fences,
|
||||
return array;
|
||||
}
|
||||
EXPORT_SYMBOL(dma_fence_array_create);
|
||||
|
||||
/**
|
||||
* dma_fence_match_context - Check if all fences are from the given context
|
||||
* @fence: [in] fence or fence array
|
||||
* @context: [in] fence context to check all fences against
|
||||
*
|
||||
* Checks the provided fence or, for a fence array, all fences in the array
|
||||
* against the given context. Returns false if any fence is from a different
|
||||
* context.
|
||||
*/
|
||||
bool dma_fence_match_context(struct dma_fence *fence, u64 context)
|
||||
{
|
||||
struct dma_fence_array *array = to_dma_fence_array(fence);
|
||||
unsigned i;
|
||||
|
||||
if (!dma_fence_is_array(fence))
|
||||
return fence->context == context;
|
||||
|
||||
for (i = 0; i < array->num_fences; i++) {
|
||||
if (array->fences[i]->context != context)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL(dma_fence_match_context);
|
||||
|
@ -240,6 +240,8 @@ EXPORT_SYMBOL(dma_fence_enable_sw_signaling);
|
||||
* after it signals with dma_fence_signal. The callback itself can be called
|
||||
* from irq context.
|
||||
*
|
||||
* Returns 0 in case of success, -ENOENT if the fence is already signaled
|
||||
* and -EINVAL in case of error.
|
||||
*/
|
||||
int dma_fence_add_callback(struct dma_fence *fence, struct dma_fence_cb *cb,
|
||||
dma_fence_func_t func)
|
||||
|
@ -99,6 +99,15 @@ config DRM_FBDEV_EMULATION
|
||||
|
||||
If in doubt, say "Y".
|
||||
|
||||
config DRM_FBDEV_OVERALLOC
|
||||
int "Overallocation of the fbdev buffer"
|
||||
depends on DRM_FBDEV_EMULATION
|
||||
default 100
|
||||
help
|
||||
Defines the fbdev buffer overallocation in percent. Default
|
||||
is 100. Typical values for double buffering will be 200,
|
||||
triple buffering 300.
|
||||
|
||||
config DRM_LOAD_EDID_FIRMWARE
|
||||
bool "Allow to specify an EDID data set instead of probing for it"
|
||||
depends on DRM_KMS_HELPER
|
||||
|
@ -4,10 +4,10 @@
|
||||
|
||||
drm-y := drm_auth.o drm_bufs.o drm_cache.o \
|
||||
drm_context.o drm_dma.o \
|
||||
drm_fops.o drm_gem.o drm_ioctl.o drm_irq.o \
|
||||
drm_file.o drm_gem.o drm_ioctl.o drm_irq.o \
|
||||
drm_lock.o drm_memory.o drm_drv.o \
|
||||
drm_scatter.o drm_pci.o \
|
||||
drm_platform.o drm_sysfs.o drm_hashtab.o drm_mm.o \
|
||||
drm_sysfs.o drm_hashtab.o drm_mm.o \
|
||||
drm_crtc.o drm_fourcc.o drm_modes.o drm_edid.o \
|
||||
drm_info.o drm_encoder_slave.o \
|
||||
drm_trace_points.o drm_global.o drm_prime.o \
|
||||
@ -31,7 +31,8 @@ drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o
|
||||
drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_probe_helper.o \
|
||||
drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \
|
||||
drm_kms_helper_common.o drm_dp_dual_mode_helper.o \
|
||||
drm_simple_kms_helper.o drm_modeset_helper.o
|
||||
drm_simple_kms_helper.o drm_modeset_helper.o \
|
||||
drm_scdc_helper.o
|
||||
|
||||
drm_kms_helper-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
|
||||
drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o
|
||||
|
@ -24,7 +24,7 @@ amdgpu-y += amdgpu_device.o amdgpu_kms.o \
|
||||
atombios_encoders.o amdgpu_sa.o atombios_i2c.o \
|
||||
amdgpu_prime.o amdgpu_vm.o amdgpu_ib.o amdgpu_pll.o \
|
||||
amdgpu_ucode.o amdgpu_bo_list.o amdgpu_ctx.o amdgpu_sync.o \
|
||||
amdgpu_gtt_mgr.o amdgpu_vram_mgr.o amdgpu_virt.o
|
||||
amdgpu_gtt_mgr.o amdgpu_vram_mgr.o amdgpu_virt.o amdgpu_atomfirmware.o
|
||||
|
||||
# add asic specific block
|
||||
amdgpu-$(CONFIG_DRM_AMDGPU_CIK)+= cik.o cik_ih.o kv_smc.o kv_dpm.o \
|
||||
@ -34,12 +34,13 @@ amdgpu-$(CONFIG_DRM_AMDGPU_CIK)+= cik.o cik_ih.o kv_smc.o kv_dpm.o \
|
||||
amdgpu-$(CONFIG_DRM_AMDGPU_SI)+= si.o gmc_v6_0.o gfx_v6_0.o si_ih.o si_dma.o dce_v6_0.o si_dpm.o si_smc.o
|
||||
|
||||
amdgpu-y += \
|
||||
vi.o mxgpu_vi.o
|
||||
vi.o mxgpu_vi.o nbio_v6_1.o soc15.o mxgpu_ai.o
|
||||
|
||||
# add GMC block
|
||||
amdgpu-y += \
|
||||
gmc_v7_0.o \
|
||||
gmc_v8_0.o
|
||||
gmc_v8_0.o \
|
||||
gfxhub_v1_0.o mmhub_v1_0.o gmc_v9_0.o
|
||||
|
||||
# add IH block
|
||||
amdgpu-y += \
|
||||
@ -47,7 +48,13 @@ amdgpu-y += \
|
||||
amdgpu_ih.o \
|
||||
iceland_ih.o \
|
||||
tonga_ih.o \
|
||||
cz_ih.o
|
||||
cz_ih.o \
|
||||
vega10_ih.o
|
||||
|
||||
# add PSP block
|
||||
amdgpu-y += \
|
||||
amdgpu_psp.o \
|
||||
psp_v3_1.o
|
||||
|
||||
# add SMC block
|
||||
amdgpu-y += \
|
||||
@ -63,23 +70,27 @@ amdgpu-y += \
|
||||
# add GFX block
|
||||
amdgpu-y += \
|
||||
amdgpu_gfx.o \
|
||||
gfx_v8_0.o
|
||||
gfx_v8_0.o \
|
||||
gfx_v9_0.o
|
||||
|
||||
# add async DMA block
|
||||
amdgpu-y += \
|
||||
sdma_v2_4.o \
|
||||
sdma_v3_0.o
|
||||
sdma_v3_0.o \
|
||||
sdma_v4_0.o
|
||||
|
||||
# add UVD block
|
||||
amdgpu-y += \
|
||||
amdgpu_uvd.o \
|
||||
uvd_v5_0.o \
|
||||
uvd_v6_0.o
|
||||
uvd_v6_0.o \
|
||||
uvd_v7_0.o
|
||||
|
||||
# add VCE block
|
||||
amdgpu-y += \
|
||||
amdgpu_vce.o \
|
||||
vce_v3_0.o
|
||||
vce_v3_0.o \
|
||||
vce_v4_0.o
|
||||
|
||||
# add amdkfd interfaces
|
||||
amdgpu-y += \
|
||||
|
@ -32,7 +32,7 @@
|
||||
#include <linux/wait.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/interval_tree.h>
|
||||
#include <linux/rbtree.h>
|
||||
#include <linux/hashtable.h>
|
||||
#include <linux/dma-fence.h>
|
||||
|
||||
@ -52,6 +52,7 @@
|
||||
#include "amdgpu_irq.h"
|
||||
#include "amdgpu_ucode.h"
|
||||
#include "amdgpu_ttm.h"
|
||||
#include "amdgpu_psp.h"
|
||||
#include "amdgpu_gds.h"
|
||||
#include "amdgpu_sync.h"
|
||||
#include "amdgpu_ring.h"
|
||||
@ -59,6 +60,8 @@
|
||||
#include "amd_powerplay.h"
|
||||
#include "amdgpu_dpm.h"
|
||||
#include "amdgpu_acp.h"
|
||||
#include "amdgpu_uvd.h"
|
||||
#include "amdgpu_vce.h"
|
||||
|
||||
#include "gpu_scheduler.h"
|
||||
#include "amdgpu_virt.h"
|
||||
@ -79,7 +82,7 @@ extern int amdgpu_pcie_gen2;
|
||||
extern int amdgpu_msi;
|
||||
extern int amdgpu_lockup_timeout;
|
||||
extern int amdgpu_dpm;
|
||||
extern int amdgpu_smc_load_fw;
|
||||
extern int amdgpu_fw_load_type;
|
||||
extern int amdgpu_aspm;
|
||||
extern int amdgpu_runtime_pm;
|
||||
extern unsigned amdgpu_ip_block_mask;
|
||||
@ -101,6 +104,11 @@ extern char *amdgpu_disable_cu;
|
||||
extern char *amdgpu_virtual_display;
|
||||
extern unsigned amdgpu_pp_feature_mask;
|
||||
extern int amdgpu_vram_page_split;
|
||||
extern int amdgpu_ngg;
|
||||
extern int amdgpu_prim_buf_per_se;
|
||||
extern int amdgpu_pos_buf_per_se;
|
||||
extern int amdgpu_cntl_sb_buf_per_se;
|
||||
extern int amdgpu_param_buf_per_se;
|
||||
|
||||
#define AMDGPU_WAIT_IDLE_TIMEOUT_IN_MS 3000
|
||||
#define AMDGPU_MAX_USEC_TIMEOUT 100000 /* 100 ms */
|
||||
@ -109,14 +117,11 @@ extern int amdgpu_vram_page_split;
|
||||
#define AMDGPU_IB_POOL_SIZE 16
|
||||
#define AMDGPU_DEBUGFS_MAX_COMPONENTS 32
|
||||
#define AMDGPUFB_CONN_LIMIT 4
|
||||
#define AMDGPU_BIOS_NUM_SCRATCH 8
|
||||
#define AMDGPU_BIOS_NUM_SCRATCH 16
|
||||
|
||||
/* max number of IP instances */
|
||||
#define AMDGPU_MAX_SDMA_INSTANCES 2
|
||||
|
||||
/* hardcode that limit for now */
|
||||
#define AMDGPU_VA_RESERVED_SIZE (8 << 20)
|
||||
|
||||
/* hard reset data */
|
||||
#define AMDGPU_ASIC_RESET_DATA 0x39d5e86b
|
||||
|
||||
@ -280,7 +285,7 @@ struct amdgpu_vm_pte_funcs {
|
||||
void (*set_pte_pde)(struct amdgpu_ib *ib,
|
||||
uint64_t pe,
|
||||
uint64_t addr, unsigned count,
|
||||
uint32_t incr, uint32_t flags);
|
||||
uint32_t incr, uint64_t flags);
|
||||
};
|
||||
|
||||
/* provided by the gmc block */
|
||||
@ -293,7 +298,15 @@ struct amdgpu_gart_funcs {
|
||||
void *cpu_pt_addr, /* cpu addr of page table */
|
||||
uint32_t gpu_page_idx, /* pte/pde to update */
|
||||
uint64_t addr, /* addr to write into pte/pde */
|
||||
uint32_t flags); /* access flags */
|
||||
uint64_t flags); /* access flags */
|
||||
/* enable/disable PRT support */
|
||||
void (*set_prt)(struct amdgpu_device *adev, bool enable);
|
||||
/* set pte flags based per asic */
|
||||
uint64_t (*get_vm_pte_flags)(struct amdgpu_device *adev,
|
||||
uint32_t flags);
|
||||
/* adjust mc addr in fb for APU case */
|
||||
u64 (*adjust_mc_addr)(struct amdgpu_device *adev, u64 addr);
|
||||
uint32_t (*get_invalidate_req)(unsigned int vm_id);
|
||||
};
|
||||
|
||||
/* provided by the ih block */
|
||||
@ -355,7 +368,10 @@ struct amdgpu_bo_list_entry {
|
||||
|
||||
struct amdgpu_bo_va_mapping {
|
||||
struct list_head list;
|
||||
struct interval_tree_node it;
|
||||
struct rb_node rb;
|
||||
uint64_t start;
|
||||
uint64_t last;
|
||||
uint64_t __subtree_last;
|
||||
uint64_t offset;
|
||||
uint64_t flags;
|
||||
};
|
||||
@ -522,6 +538,10 @@ struct amdgpu_gart {
|
||||
struct page **pages;
|
||||
#endif
|
||||
bool ready;
|
||||
|
||||
/* Asic default pte flags */
|
||||
uint64_t gart_pte_flags;
|
||||
|
||||
const struct amdgpu_gart_funcs *gart_funcs;
|
||||
};
|
||||
|
||||
@ -537,9 +557,22 @@ void amdgpu_gart_unbind(struct amdgpu_device *adev, uint64_t offset,
|
||||
int pages);
|
||||
int amdgpu_gart_bind(struct amdgpu_device *adev, uint64_t offset,
|
||||
int pages, struct page **pagelist,
|
||||
dma_addr_t *dma_addr, uint32_t flags);
|
||||
dma_addr_t *dma_addr, uint64_t flags);
|
||||
int amdgpu_ttm_recover_gart(struct amdgpu_device *adev);
|
||||
|
||||
/*
|
||||
* VMHUB structures, functions & helpers
|
||||
*/
|
||||
struct amdgpu_vmhub {
|
||||
uint32_t ctx0_ptb_addr_lo32;
|
||||
uint32_t ctx0_ptb_addr_hi32;
|
||||
uint32_t vm_inv_eng0_req;
|
||||
uint32_t vm_inv_eng0_ack;
|
||||
uint32_t vm_context0_cntl;
|
||||
uint32_t vm_l2_pro_fault_status;
|
||||
uint32_t vm_l2_pro_fault_cntl;
|
||||
};
|
||||
|
||||
/*
|
||||
* GPU MC structures, functions & helpers
|
||||
*/
|
||||
@ -567,6 +600,14 @@ struct amdgpu_mc {
|
||||
uint32_t vram_type;
|
||||
uint32_t srbm_soft_reset;
|
||||
struct amdgpu_mode_mc_save save;
|
||||
bool prt_warning;
|
||||
/* apertures */
|
||||
u64 shared_aperture_start;
|
||||
u64 shared_aperture_end;
|
||||
u64 private_aperture_start;
|
||||
u64 private_aperture_end;
|
||||
/* protects concurrent invalidation */
|
||||
spinlock_t invalidate_lock;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -601,6 +642,83 @@ struct amdgpu_doorbell {
|
||||
u32 num_doorbells; /* Number of doorbells actually reserved for amdgpu. */
|
||||
};
|
||||
|
||||
/*
|
||||
* 64bit doorbell, offset are in QWORD, occupy 2KB doorbell space
|
||||
*/
|
||||
typedef enum _AMDGPU_DOORBELL64_ASSIGNMENT
|
||||
{
|
||||
/*
|
||||
* All compute related doorbells: kiq, hiq, diq, traditional compute queue, user queue, should locate in
|
||||
* a continues range so that programming CP_MEC_DOORBELL_RANGE_LOWER/UPPER can cover this range.
|
||||
* Compute related doorbells are allocated from 0x00 to 0x8a
|
||||
*/
|
||||
|
||||
|
||||
/* kernel scheduling */
|
||||
AMDGPU_DOORBELL64_KIQ = 0x00,
|
||||
|
||||
/* HSA interface queue and debug queue */
|
||||
AMDGPU_DOORBELL64_HIQ = 0x01,
|
||||
AMDGPU_DOORBELL64_DIQ = 0x02,
|
||||
|
||||
/* Compute engines */
|
||||
AMDGPU_DOORBELL64_MEC_RING0 = 0x03,
|
||||
AMDGPU_DOORBELL64_MEC_RING1 = 0x04,
|
||||
AMDGPU_DOORBELL64_MEC_RING2 = 0x05,
|
||||
AMDGPU_DOORBELL64_MEC_RING3 = 0x06,
|
||||
AMDGPU_DOORBELL64_MEC_RING4 = 0x07,
|
||||
AMDGPU_DOORBELL64_MEC_RING5 = 0x08,
|
||||
AMDGPU_DOORBELL64_MEC_RING6 = 0x09,
|
||||
AMDGPU_DOORBELL64_MEC_RING7 = 0x0a,
|
||||
|
||||
/* User queue doorbell range (128 doorbells) */
|
||||
AMDGPU_DOORBELL64_USERQUEUE_START = 0x0b,
|
||||
AMDGPU_DOORBELL64_USERQUEUE_END = 0x8a,
|
||||
|
||||
/* Graphics engine */
|
||||
AMDGPU_DOORBELL64_GFX_RING0 = 0x8b,
|
||||
|
||||
/*
|
||||
* Other graphics doorbells can be allocated here: from 0x8c to 0xef
|
||||
* Graphics voltage island aperture 1
|
||||
* default non-graphics QWORD index is 0xF0 - 0xFF inclusive
|
||||
*/
|
||||
|
||||
/* sDMA engines */
|
||||
AMDGPU_DOORBELL64_sDMA_ENGINE0 = 0xF0,
|
||||
AMDGPU_DOORBELL64_sDMA_HI_PRI_ENGINE0 = 0xF1,
|
||||
AMDGPU_DOORBELL64_sDMA_ENGINE1 = 0xF2,
|
||||
AMDGPU_DOORBELL64_sDMA_HI_PRI_ENGINE1 = 0xF3,
|
||||
|
||||
/* Interrupt handler */
|
||||
AMDGPU_DOORBELL64_IH = 0xF4, /* For legacy interrupt ring buffer */
|
||||
AMDGPU_DOORBELL64_IH_RING1 = 0xF5, /* For page migration request log */
|
||||
AMDGPU_DOORBELL64_IH_RING2 = 0xF6, /* For page migration translation/invalidation log */
|
||||
|
||||
/* VCN engine use 32 bits doorbell */
|
||||
AMDGPU_DOORBELL64_VCN0_1 = 0xF8, /* lower 32 bits for VNC0 and upper 32 bits for VNC1 */
|
||||
AMDGPU_DOORBELL64_VCN2_3 = 0xF9,
|
||||
AMDGPU_DOORBELL64_VCN4_5 = 0xFA,
|
||||
AMDGPU_DOORBELL64_VCN6_7 = 0xFB,
|
||||
|
||||
/* 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
|
||||
*/
|
||||
AMDGPU_DOORBELL64_RING0_1 = 0xF8,
|
||||
AMDGPU_DOORBELL64_RING2_3 = 0xF9,
|
||||
AMDGPU_DOORBELL64_RING4_5 = 0xFA,
|
||||
AMDGPU_DOORBELL64_RING6_7 = 0xFB,
|
||||
|
||||
AMDGPU_DOORBELL64_UVD_RING0_1 = 0xFC,
|
||||
AMDGPU_DOORBELL64_UVD_RING2_3 = 0xFD,
|
||||
AMDGPU_DOORBELL64_UVD_RING4_5 = 0xFE,
|
||||
AMDGPU_DOORBELL64_UVD_RING6_7 = 0xFF,
|
||||
|
||||
AMDGPU_DOORBELL64_MAX_ASSIGNMENT = 0xFF,
|
||||
AMDGPU_DOORBELL64_INVALID = 0xFFFF
|
||||
} AMDGPU_DOORBELL64_ASSIGNMENT;
|
||||
|
||||
|
||||
void amdgpu_doorbell_get_kfd_info(struct amdgpu_device *adev,
|
||||
phys_addr_t *aperture_base,
|
||||
size_t *aperture_size,
|
||||
@ -699,6 +817,7 @@ void amdgpu_ctx_mgr_fini(struct amdgpu_ctx_mgr *mgr);
|
||||
|
||||
struct amdgpu_fpriv {
|
||||
struct amdgpu_vm vm;
|
||||
struct amdgpu_bo_va *prt_va;
|
||||
struct mutex bo_list_lock;
|
||||
struct idr bo_list_handles;
|
||||
struct amdgpu_ctx_mgr ctx_mgr;
|
||||
@ -776,9 +895,12 @@ struct amdgpu_rlc {
|
||||
struct amdgpu_mec {
|
||||
struct amdgpu_bo *hpd_eop_obj;
|
||||
u64 hpd_eop_gpu_addr;
|
||||
struct amdgpu_bo *mec_fw_obj;
|
||||
u64 mec_fw_gpu_addr;
|
||||
u32 num_pipe;
|
||||
u32 num_mec;
|
||||
u32 num_queue;
|
||||
void *mqd_backup[AMDGPU_MAX_COMPUTE_RINGS + 1];
|
||||
};
|
||||
|
||||
struct amdgpu_kiq {
|
||||
@ -810,7 +932,16 @@ struct amdgpu_rb_config {
|
||||
uint32_t raster_config_1;
|
||||
};
|
||||
|
||||
struct amdgpu_gca_config {
|
||||
struct gb_addr_config {
|
||||
uint16_t pipe_interleave_size;
|
||||
uint8_t num_pipes;
|
||||
uint8_t max_compress_frags;
|
||||
uint8_t num_banks;
|
||||
uint8_t num_se;
|
||||
uint8_t num_rb_per_se;
|
||||
};
|
||||
|
||||
struct amdgpu_gfx_config {
|
||||
unsigned max_shader_engines;
|
||||
unsigned max_tile_pipes;
|
||||
unsigned max_cu_per_sh;
|
||||
@ -839,7 +970,11 @@ struct amdgpu_gca_config {
|
||||
uint32_t tile_mode_array[32];
|
||||
uint32_t macrotile_mode_array[16];
|
||||
|
||||
struct gb_addr_config gb_addr_config_fields;
|
||||
struct amdgpu_rb_config rb_config[AMDGPU_GFX_MAX_SE][AMDGPU_GFX_MAX_SH_PER_SE];
|
||||
|
||||
/* gfx configure feature */
|
||||
uint32_t double_offchip_lds_buf;
|
||||
};
|
||||
|
||||
struct amdgpu_cu_info {
|
||||
@ -857,9 +992,31 @@ struct amdgpu_gfx_funcs {
|
||||
void (*read_wave_sgprs)(struct amdgpu_device *adev, uint32_t simd, uint32_t wave, uint32_t start, uint32_t size, uint32_t *dst);
|
||||
};
|
||||
|
||||
struct amdgpu_ngg_buf {
|
||||
struct amdgpu_bo *bo;
|
||||
uint64_t gpu_addr;
|
||||
uint32_t size;
|
||||
uint32_t bo_size;
|
||||
};
|
||||
|
||||
enum {
|
||||
PRIM = 0,
|
||||
POS,
|
||||
CNTL,
|
||||
PARAM,
|
||||
NGG_BUF_MAX
|
||||
};
|
||||
|
||||
struct amdgpu_ngg {
|
||||
struct amdgpu_ngg_buf buf[NGG_BUF_MAX];
|
||||
uint32_t gds_reserve_addr;
|
||||
uint32_t gds_reserve_size;
|
||||
bool init;
|
||||
};
|
||||
|
||||
struct amdgpu_gfx {
|
||||
struct mutex gpu_clock_mutex;
|
||||
struct amdgpu_gca_config config;
|
||||
struct amdgpu_gfx_config config;
|
||||
struct amdgpu_rlc rlc;
|
||||
struct amdgpu_mec mec;
|
||||
struct amdgpu_kiq kiq;
|
||||
@ -899,6 +1056,9 @@ struct amdgpu_gfx {
|
||||
/* reset mask */
|
||||
uint32_t grbm_soft_reset;
|
||||
uint32_t srbm_soft_reset;
|
||||
bool in_reset;
|
||||
/* NGG */
|
||||
struct amdgpu_ngg ngg;
|
||||
};
|
||||
|
||||
int amdgpu_ib_get(struct amdgpu_device *adev, struct amdgpu_vm *vm,
|
||||
@ -1007,66 +1167,11 @@ struct amdgpu_wb {
|
||||
|
||||
int amdgpu_wb_get(struct amdgpu_device *adev, u32 *wb);
|
||||
void amdgpu_wb_free(struct amdgpu_device *adev, u32 wb);
|
||||
int amdgpu_wb_get_64bit(struct amdgpu_device *adev, u32 *wb);
|
||||
void amdgpu_wb_free_64bit(struct amdgpu_device *adev, u32 wb);
|
||||
|
||||
void amdgpu_get_pcie_info(struct amdgpu_device *adev);
|
||||
|
||||
/*
|
||||
* UVD
|
||||
*/
|
||||
#define AMDGPU_DEFAULT_UVD_HANDLES 10
|
||||
#define AMDGPU_MAX_UVD_HANDLES 40
|
||||
#define AMDGPU_UVD_STACK_SIZE (200*1024)
|
||||
#define AMDGPU_UVD_HEAP_SIZE (256*1024)
|
||||
#define AMDGPU_UVD_SESSION_SIZE (50*1024)
|
||||
#define AMDGPU_UVD_FIRMWARE_OFFSET 256
|
||||
|
||||
struct amdgpu_uvd {
|
||||
struct amdgpu_bo *vcpu_bo;
|
||||
void *cpu_addr;
|
||||
uint64_t gpu_addr;
|
||||
unsigned fw_version;
|
||||
void *saved_bo;
|
||||
unsigned max_handles;
|
||||
atomic_t handles[AMDGPU_MAX_UVD_HANDLES];
|
||||
struct drm_file *filp[AMDGPU_MAX_UVD_HANDLES];
|
||||
struct delayed_work idle_work;
|
||||
const struct firmware *fw; /* UVD firmware */
|
||||
struct amdgpu_ring ring;
|
||||
struct amdgpu_irq_src irq;
|
||||
bool address_64_bit;
|
||||
bool use_ctx_buf;
|
||||
struct amd_sched_entity entity;
|
||||
uint32_t srbm_soft_reset;
|
||||
};
|
||||
|
||||
/*
|
||||
* VCE
|
||||
*/
|
||||
#define AMDGPU_MAX_VCE_HANDLES 16
|
||||
#define AMDGPU_VCE_FIRMWARE_OFFSET 256
|
||||
|
||||
#define AMDGPU_VCE_HARVEST_VCE0 (1 << 0)
|
||||
#define AMDGPU_VCE_HARVEST_VCE1 (1 << 1)
|
||||
|
||||
struct amdgpu_vce {
|
||||
struct amdgpu_bo *vcpu_bo;
|
||||
uint64_t gpu_addr;
|
||||
unsigned fw_version;
|
||||
unsigned fb_version;
|
||||
atomic_t handles[AMDGPU_MAX_VCE_HANDLES];
|
||||
struct drm_file *filp[AMDGPU_MAX_VCE_HANDLES];
|
||||
uint32_t img_size[AMDGPU_MAX_VCE_HANDLES];
|
||||
struct delayed_work idle_work;
|
||||
struct mutex idle_mutex;
|
||||
const struct firmware *fw; /* VCE firmware */
|
||||
struct amdgpu_ring ring[AMDGPU_MAX_VCE_RINGS];
|
||||
struct amdgpu_irq_src irq;
|
||||
unsigned harvest_config;
|
||||
struct amd_sched_entity entity;
|
||||
uint32_t srbm_soft_reset;
|
||||
unsigned num_rings;
|
||||
};
|
||||
|
||||
/*
|
||||
* SDMA
|
||||
*/
|
||||
@ -1095,11 +1200,22 @@ struct amdgpu_sdma {
|
||||
/*
|
||||
* Firmware
|
||||
*/
|
||||
enum amdgpu_firmware_load_type {
|
||||
AMDGPU_FW_LOAD_DIRECT = 0,
|
||||
AMDGPU_FW_LOAD_SMU,
|
||||
AMDGPU_FW_LOAD_PSP,
|
||||
};
|
||||
|
||||
struct amdgpu_firmware {
|
||||
struct amdgpu_firmware_info ucode[AMDGPU_UCODE_ID_MAXIMUM];
|
||||
bool smu_load;
|
||||
enum amdgpu_firmware_load_type load_type;
|
||||
struct amdgpu_bo *fw_buf;
|
||||
unsigned int fw_size;
|
||||
unsigned int max_ucodes;
|
||||
/* firmwares are loaded by psp instead of smu from vega10 */
|
||||
const struct amdgpu_psp_funcs *funcs;
|
||||
struct amdgpu_bo *rbuf;
|
||||
struct mutex mutex;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -1112,10 +1228,6 @@ void amdgpu_benchmark(struct amdgpu_device *adev, int test_number);
|
||||
* Testing
|
||||
*/
|
||||
void amdgpu_test_moves(struct amdgpu_device *adev);
|
||||
void amdgpu_test_ring_sync(struct amdgpu_device *adev,
|
||||
struct amdgpu_ring *cpA,
|
||||
struct amdgpu_ring *cpB);
|
||||
void amdgpu_test_syncing(struct amdgpu_device *adev);
|
||||
|
||||
/*
|
||||
* MMU Notifier
|
||||
@ -1202,6 +1314,8 @@ struct amdgpu_asic_funcs {
|
||||
/* static power management */
|
||||
int (*get_pcie_lanes)(struct amdgpu_device *adev);
|
||||
void (*set_pcie_lanes)(struct amdgpu_device *adev, int lanes);
|
||||
/* get config memsize register */
|
||||
u32 (*get_config_memsize)(struct amdgpu_device *adev);
|
||||
};
|
||||
|
||||
/*
|
||||
@ -1342,9 +1456,11 @@ struct amdgpu_device {
|
||||
bool have_disp_power_ref;
|
||||
|
||||
/* BIOS */
|
||||
bool is_atom_fw;
|
||||
uint8_t *bios;
|
||||
uint32_t bios_size;
|
||||
struct amdgpu_bo *stollen_vga_memory;
|
||||
uint32_t bios_scratch_reg_offset;
|
||||
uint32_t bios_scratch[AMDGPU_BIOS_NUM_SCRATCH];
|
||||
|
||||
/* Register/doorbell mmio */
|
||||
@ -1391,6 +1507,7 @@ struct amdgpu_device {
|
||||
struct amdgpu_gart gart;
|
||||
struct amdgpu_dummy_page dummy_page;
|
||||
struct amdgpu_vm_manager vm_manager;
|
||||
struct amdgpu_vmhub vmhub[AMDGPU_MAX_VMHUBS];
|
||||
|
||||
/* memory management */
|
||||
struct amdgpu_mman mman;
|
||||
@ -1457,6 +1574,9 @@ struct amdgpu_device {
|
||||
/* firmwares */
|
||||
struct amdgpu_firmware firmware;
|
||||
|
||||
/* PSP */
|
||||
struct psp_context psp;
|
||||
|
||||
/* GDS */
|
||||
struct amdgpu_gds gds;
|
||||
|
||||
@ -1501,23 +1621,32 @@ void amdgpu_device_fini(struct amdgpu_device *adev);
|
||||
int amdgpu_gpu_wait_for_idle(struct amdgpu_device *adev);
|
||||
|
||||
uint32_t amdgpu_mm_rreg(struct amdgpu_device *adev, uint32_t reg,
|
||||
bool always_indirect);
|
||||
uint32_t acc_flags);
|
||||
void amdgpu_mm_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v,
|
||||
bool always_indirect);
|
||||
uint32_t acc_flags);
|
||||
u32 amdgpu_io_rreg(struct amdgpu_device *adev, u32 reg);
|
||||
void amdgpu_io_wreg(struct amdgpu_device *adev, u32 reg, u32 v);
|
||||
|
||||
u32 amdgpu_mm_rdoorbell(struct amdgpu_device *adev, u32 index);
|
||||
void amdgpu_mm_wdoorbell(struct amdgpu_device *adev, u32 index, u32 v);
|
||||
u64 amdgpu_mm_rdoorbell64(struct amdgpu_device *adev, u32 index);
|
||||
void amdgpu_mm_wdoorbell64(struct amdgpu_device *adev, u32 index, u64 v);
|
||||
|
||||
/*
|
||||
* Registers read & write functions.
|
||||
*/
|
||||
#define RREG32(reg) amdgpu_mm_rreg(adev, (reg), false)
|
||||
#define RREG32_IDX(reg) amdgpu_mm_rreg(adev, (reg), true)
|
||||
#define DREG32(reg) printk(KERN_INFO "REGISTER: " #reg " : 0x%08X\n", amdgpu_mm_rreg(adev, (reg), false))
|
||||
#define WREG32(reg, v) amdgpu_mm_wreg(adev, (reg), (v), false)
|
||||
#define WREG32_IDX(reg, v) amdgpu_mm_wreg(adev, (reg), (v), true)
|
||||
|
||||
#define AMDGPU_REGS_IDX (1<<0)
|
||||
#define AMDGPU_REGS_NO_KIQ (1<<1)
|
||||
|
||||
#define RREG32_NO_KIQ(reg) amdgpu_mm_rreg(adev, (reg), AMDGPU_REGS_NO_KIQ)
|
||||
#define WREG32_NO_KIQ(reg, v) amdgpu_mm_wreg(adev, (reg), (v), AMDGPU_REGS_NO_KIQ)
|
||||
|
||||
#define RREG32(reg) amdgpu_mm_rreg(adev, (reg), 0)
|
||||
#define RREG32_IDX(reg) amdgpu_mm_rreg(adev, (reg), AMDGPU_REGS_IDX)
|
||||
#define DREG32(reg) printk(KERN_INFO "REGISTER: " #reg " : 0x%08X\n", amdgpu_mm_rreg(adev, (reg), 0))
|
||||
#define WREG32(reg, v) amdgpu_mm_wreg(adev, (reg), (v), 0)
|
||||
#define WREG32_IDX(reg, v) amdgpu_mm_wreg(adev, (reg), (v), AMDGPU_REGS_IDX)
|
||||
#define REG_SET(FIELD, v) (((v) << FIELD##_SHIFT) & FIELD##_MASK)
|
||||
#define REG_GET(FIELD, v) (((v) << FIELD##_SHIFT) & FIELD##_MASK)
|
||||
#define RREG32_PCIE(reg) adev->pcie_rreg(adev, (reg))
|
||||
@ -1556,6 +1685,8 @@ void amdgpu_mm_wdoorbell(struct amdgpu_device *adev, u32 index, u32 v);
|
||||
|
||||
#define RDOORBELL32(index) amdgpu_mm_rdoorbell(adev, (index))
|
||||
#define WDOORBELL32(index, v) amdgpu_mm_wdoorbell(adev, (index), (v))
|
||||
#define RDOORBELL64(index) amdgpu_mm_rdoorbell64(adev, (index))
|
||||
#define WDOORBELL64(index, v) amdgpu_mm_wdoorbell64(adev, (index), (v))
|
||||
|
||||
#define REG_FIELD_SHIFT(reg, field) reg##__##field##__SHIFT
|
||||
#define REG_FIELD_MASK(reg, field) reg##__##field##_MASK
|
||||
@ -1570,6 +1701,12 @@ void amdgpu_mm_wdoorbell(struct amdgpu_device *adev, u32 index, u32 v);
|
||||
#define WREG32_FIELD(reg, field, val) \
|
||||
WREG32(mm##reg, (RREG32(mm##reg) & ~REG_FIELD_MASK(reg, field)) | (val) << REG_FIELD_SHIFT(reg, field))
|
||||
|
||||
#define WREG32_FIELD_OFFSET(reg, offset, field, val) \
|
||||
WREG32(mm##reg + offset, (RREG32(mm##reg + offset) & ~REG_FIELD_MASK(reg, field)) | (val) << REG_FIELD_SHIFT(reg, field))
|
||||
|
||||
#define WREG32_FIELD15(ip, idx, reg, field, val) \
|
||||
WREG32(SOC15_REG_OFFSET(ip, idx, mm##reg), (RREG32(SOC15_REG_OFFSET(ip, idx, mm##reg)) & ~REG_FIELD_MASK(reg, field)) | (val) << REG_FIELD_SHIFT(reg, field))
|
||||
|
||||
/*
|
||||
* BIOS helpers.
|
||||
*/
|
||||
@ -1584,7 +1721,7 @@ static inline void amdgpu_ring_write(struct amdgpu_ring *ring, uint32_t v)
|
||||
{
|
||||
if (ring->count_dw <= 0)
|
||||
DRM_ERROR("amdgpu: writing more dwords to the ring than expected!\n");
|
||||
ring->ring[ring->wptr++] = v;
|
||||
ring->ring[ring->wptr++ & ring->buf_mask] = v;
|
||||
ring->wptr &= ring->ptr_mask;
|
||||
ring->count_dw--;
|
||||
}
|
||||
@ -1597,9 +1734,9 @@ static inline void amdgpu_ring_write_multiple(struct amdgpu_ring *ring, void *sr
|
||||
if (ring->count_dw < count_dw) {
|
||||
DRM_ERROR("amdgpu: writing more dwords to the ring than expected!\n");
|
||||
} else {
|
||||
occupied = ring->wptr & ring->ptr_mask;
|
||||
occupied = ring->wptr & ring->buf_mask;
|
||||
dst = (void *)&ring->ring[occupied];
|
||||
chunk1 = ring->ptr_mask + 1 - occupied;
|
||||
chunk1 = ring->buf_mask + 1 - occupied;
|
||||
chunk1 = (chunk1 >= count_dw) ? count_dw: chunk1;
|
||||
chunk2 = count_dw - chunk1;
|
||||
chunk1 <<= 2;
|
||||
@ -1650,11 +1787,13 @@ amdgpu_get_sdma_instance(struct amdgpu_ring *ring)
|
||||
#define amdgpu_asic_read_disabled_bios(adev) (adev)->asic_funcs->read_disabled_bios((adev))
|
||||
#define amdgpu_asic_read_bios_from_rom(adev, b, l) (adev)->asic_funcs->read_bios_from_rom((adev), (b), (l))
|
||||
#define amdgpu_asic_read_register(adev, se, sh, offset, v)((adev)->asic_funcs->read_register((adev), (se), (sh), (offset), (v)))
|
||||
#define amdgpu_asic_get_config_memsize(adev) (adev)->asic_funcs->get_config_memsize((adev))
|
||||
#define amdgpu_gart_flush_gpu_tlb(adev, vmid) (adev)->gart.gart_funcs->flush_gpu_tlb((adev), (vmid))
|
||||
#define amdgpu_gart_set_pte_pde(adev, pt, idx, addr, flags) (adev)->gart.gart_funcs->set_pte_pde((adev), (pt), (idx), (addr), (flags))
|
||||
#define amdgpu_vm_copy_pte(adev, ib, pe, src, count) ((adev)->vm_manager.vm_pte_funcs->copy_pte((ib), (pe), (src), (count)))
|
||||
#define amdgpu_vm_write_pte(adev, ib, pe, value, count, incr) ((adev)->vm_manager.vm_pte_funcs->write_pte((ib), (pe), (value), (count), (incr)))
|
||||
#define amdgpu_vm_set_pte_pde(adev, ib, pe, addr, count, incr, flags) ((adev)->vm_manager.vm_pte_funcs->set_pte_pde((ib), (pe), (addr), (count), (incr), (flags)))
|
||||
#define amdgpu_vm_get_pte_flags(adev, flags) (adev)->gart.gart_funcs->get_vm_pte_flags((adev),(flags))
|
||||
#define amdgpu_ring_parse_cs(r, p, ib) ((r)->funcs->parse_cs((p), (ib)))
|
||||
#define amdgpu_ring_test_ring(r) (r)->funcs->test_ring((r))
|
||||
#define amdgpu_ring_test_ib(r, t) (r)->funcs->test_ib((r), (t))
|
||||
@ -1698,6 +1837,7 @@ amdgpu_get_sdma_instance(struct amdgpu_ring *ring)
|
||||
#define amdgpu_gfx_get_gpu_clock_counter(adev) (adev)->gfx.funcs->get_gpu_clock_counter((adev))
|
||||
#define amdgpu_gfx_select_se_sh(adev, se, sh, instance) (adev)->gfx.funcs->select_se_sh((adev), (se), (sh), (instance))
|
||||
#define amdgpu_gds_switch(adev, r, v, d, w, a) (adev)->gds.funcs->patch_gds_switch((r), (v), (d), (w), (a))
|
||||
#define amdgpu_psp_check_fw_loading_status(adev, i) (adev)->firmware.funcs->check_fw_loading_status((adev), (i))
|
||||
|
||||
/* Common functions */
|
||||
int amdgpu_gpu_reset(struct amdgpu_device *adev);
|
||||
@ -1723,7 +1863,7 @@ bool amdgpu_ttm_tt_affect_userptr(struct ttm_tt *ttm, unsigned long start,
|
||||
bool amdgpu_ttm_tt_userptr_invalidated(struct ttm_tt *ttm,
|
||||
int *last_invalidated);
|
||||
bool amdgpu_ttm_tt_is_readonly(struct ttm_tt *ttm);
|
||||
uint32_t amdgpu_ttm_tt_pte_flags(struct amdgpu_device *adev, struct ttm_tt *ttm,
|
||||
uint64_t amdgpu_ttm_tt_pte_flags(struct amdgpu_device *adev, struct ttm_tt *ttm,
|
||||
struct ttm_mem_reg *mem);
|
||||
void amdgpu_vram_location(struct amdgpu_device *adev, struct amdgpu_mc *mc, u64 base);
|
||||
void amdgpu_gtt_location(struct amdgpu_device *adev, struct amdgpu_mc *mc);
|
||||
@ -1742,12 +1882,14 @@ void amdgpu_unregister_atpx_handler(void);
|
||||
bool amdgpu_has_atpx_dgpu_power_cntl(void);
|
||||
bool amdgpu_is_atpx_hybrid(void);
|
||||
bool amdgpu_atpx_dgpu_req_power_for_displays(void);
|
||||
bool amdgpu_has_atpx(void);
|
||||
#else
|
||||
static inline void amdgpu_register_atpx_handler(void) {}
|
||||
static inline void amdgpu_unregister_atpx_handler(void) {}
|
||||
static inline bool amdgpu_has_atpx_dgpu_power_cntl(void) { return false; }
|
||||
static inline bool amdgpu_is_atpx_hybrid(void) { return false; }
|
||||
static inline bool amdgpu_atpx_dgpu_req_power_for_displays(void) { return false; }
|
||||
static inline bool amdgpu_has_atpx(void) { return false; }
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -1762,8 +1904,6 @@ void amdgpu_driver_lastclose_kms(struct drm_device *dev);
|
||||
int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv);
|
||||
void amdgpu_driver_postclose_kms(struct drm_device *dev,
|
||||
struct drm_file *file_priv);
|
||||
void amdgpu_driver_preclose_kms(struct drm_device *dev,
|
||||
struct drm_file *file_priv);
|
||||
int amdgpu_suspend(struct amdgpu_device *adev);
|
||||
int amdgpu_device_suspend(struct drm_device *dev, bool suspend, bool fbcon);
|
||||
int amdgpu_device_resume(struct drm_device *dev, bool resume, bool fbcon);
|
||||
|
@ -74,9 +74,9 @@ static void amdgpu_afmt_calc_cts(uint32_t clock, int *CTS, int *N, int freq)
|
||||
|
||||
/* Check that we are in spec (not always possible) */
|
||||
if (n < (128*freq/1500))
|
||||
printk(KERN_WARNING "Calculated ACR N value is too small. You may experience audio problems.\n");
|
||||
pr_warn("Calculated ACR N value is too small. You may experience audio problems.\n");
|
||||
if (n > (128*freq/300))
|
||||
printk(KERN_WARNING "Calculated ACR N value is too large. You may experience audio problems.\n");
|
||||
pr_warn("Calculated ACR N value is too large. You may experience audio problems.\n");
|
||||
|
||||
*N = n;
|
||||
*CTS = cts;
|
||||
|
@ -754,6 +754,35 @@ union igp_info {
|
||||
struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_9 info_9;
|
||||
};
|
||||
|
||||
/*
|
||||
* Return vram width from integrated system info table, if available,
|
||||
* or 0 if not.
|
||||
*/
|
||||
int amdgpu_atombios_get_vram_width(struct amdgpu_device *adev)
|
||||
{
|
||||
struct amdgpu_mode_info *mode_info = &adev->mode_info;
|
||||
int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
|
||||
u16 data_offset, size;
|
||||
union igp_info *igp_info;
|
||||
u8 frev, crev;
|
||||
|
||||
/* get any igp specific overrides */
|
||||
if (amdgpu_atom_parse_data_header(mode_info->atom_context, index, &size,
|
||||
&frev, &crev, &data_offset)) {
|
||||
igp_info = (union igp_info *)
|
||||
(mode_info->atom_context->bios + data_offset);
|
||||
switch (crev) {
|
||||
case 8:
|
||||
case 9:
|
||||
return igp_info->info_8.ucUMAChannelNumber * 64;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void amdgpu_atombios_get_igp_ss_overrides(struct amdgpu_device *adev,
|
||||
struct amdgpu_atom_ss *ss,
|
||||
int id)
|
||||
@ -1748,3 +1777,31 @@ void amdgpu_atombios_copy_swap(u8 *dst, u8 *src, u8 num_bytes, bool to_le)
|
||||
memcpy(dst, src, num_bytes);
|
||||
#endif
|
||||
}
|
||||
|
||||
int amdgpu_atombios_allocate_fb_scratch(struct amdgpu_device *adev)
|
||||
{
|
||||
struct atom_context *ctx = adev->mode_info.atom_context;
|
||||
int index = GetIndexIntoMasterTable(DATA, VRAM_UsageByFirmware);
|
||||
uint16_t data_offset;
|
||||
int usage_bytes = 0;
|
||||
struct _ATOM_VRAM_USAGE_BY_FIRMWARE *firmware_usage;
|
||||
|
||||
if (amdgpu_atom_parse_data_header(ctx, index, NULL, NULL, NULL, &data_offset)) {
|
||||
firmware_usage = (struct _ATOM_VRAM_USAGE_BY_FIRMWARE *)(ctx->bios + data_offset);
|
||||
|
||||
DRM_DEBUG("atom firmware requested %08x %dkb\n",
|
||||
le32_to_cpu(firmware_usage->asFirmwareVramReserveInfo[0].ulStartAddrUsedByFirmware),
|
||||
le16_to_cpu(firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb));
|
||||
|
||||
usage_bytes = le16_to_cpu(firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb) * 1024;
|
||||
}
|
||||
ctx->scratch_size_bytes = 0;
|
||||
if (usage_bytes == 0)
|
||||
usage_bytes = 20 * 1024;
|
||||
/* allocate some scratch memory */
|
||||
ctx->scratch = kzalloc(usage_bytes, GFP_KERNEL);
|
||||
if (!ctx->scratch)
|
||||
return -ENOMEM;
|
||||
ctx->scratch_size_bytes = usage_bytes;
|
||||
return 0;
|
||||
}
|
||||
|
@ -148,6 +148,8 @@ int amdgpu_atombios_get_clock_info(struct amdgpu_device *adev);
|
||||
|
||||
int amdgpu_atombios_get_gfx_info(struct amdgpu_device *adev);
|
||||
|
||||
int amdgpu_atombios_get_vram_width(struct amdgpu_device *adev);
|
||||
|
||||
bool amdgpu_atombios_get_asic_ss_info(struct amdgpu_device *adev,
|
||||
struct amdgpu_atom_ss *ss,
|
||||
int id, u32 clock);
|
||||
@ -215,4 +217,7 @@ int amdgpu_atombios_get_clock_dividers(struct amdgpu_device *adev,
|
||||
int amdgpu_atombios_get_svi2_info(struct amdgpu_device *adev,
|
||||
u8 voltage_type,
|
||||
u8 *svd_gpio_id, u8 *svc_gpio_id);
|
||||
|
||||
int amdgpu_atombios_allocate_fb_scratch(struct amdgpu_device *adev);
|
||||
|
||||
#endif
|
||||
|
112
drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c
Normal file
112
drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c
Normal file
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright 2016 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.
|
||||
*
|
||||
*/
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/amdgpu_drm.h>
|
||||
#include "amdgpu.h"
|
||||
#include "atomfirmware.h"
|
||||
#include "amdgpu_atomfirmware.h"
|
||||
#include "atom.h"
|
||||
|
||||
#define get_index_into_master_table(master_table, table_name) (offsetof(struct master_table, table_name) / sizeof(uint16_t))
|
||||
|
||||
bool amdgpu_atomfirmware_gpu_supports_virtualization(struct amdgpu_device *adev)
|
||||
{
|
||||
int index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
|
||||
firmwareinfo);
|
||||
uint16_t data_offset;
|
||||
|
||||
if (amdgpu_atom_parse_data_header(adev->mode_info.atom_context, index, NULL,
|
||||
NULL, NULL, &data_offset)) {
|
||||
struct atom_firmware_info_v3_1 *firmware_info =
|
||||
(struct atom_firmware_info_v3_1 *)(adev->mode_info.atom_context->bios +
|
||||
data_offset);
|
||||
|
||||
if (le32_to_cpu(firmware_info->firmware_capability) &
|
||||
ATOM_FIRMWARE_CAP_GPU_VIRTUALIZATION)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void amdgpu_atomfirmware_scratch_regs_init(struct amdgpu_device *adev)
|
||||
{
|
||||
int index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
|
||||
firmwareinfo);
|
||||
uint16_t data_offset;
|
||||
|
||||
if (amdgpu_atom_parse_data_header(adev->mode_info.atom_context, index, NULL,
|
||||
NULL, NULL, &data_offset)) {
|
||||
struct atom_firmware_info_v3_1 *firmware_info =
|
||||
(struct atom_firmware_info_v3_1 *)(adev->mode_info.atom_context->bios +
|
||||
data_offset);
|
||||
|
||||
adev->bios_scratch_reg_offset =
|
||||
le32_to_cpu(firmware_info->bios_scratch_reg_startaddr);
|
||||
}
|
||||
}
|
||||
|
||||
void amdgpu_atomfirmware_scratch_regs_save(struct amdgpu_device *adev)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < AMDGPU_BIOS_NUM_SCRATCH; i++)
|
||||
adev->bios_scratch[i] = RREG32(adev->bios_scratch_reg_offset + i);
|
||||
}
|
||||
|
||||
void amdgpu_atomfirmware_scratch_regs_restore(struct amdgpu_device *adev)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < AMDGPU_BIOS_NUM_SCRATCH; i++)
|
||||
WREG32(adev->bios_scratch_reg_offset + i, adev->bios_scratch[i]);
|
||||
}
|
||||
|
||||
int amdgpu_atomfirmware_allocate_fb_scratch(struct amdgpu_device *adev)
|
||||
{
|
||||
struct atom_context *ctx = adev->mode_info.atom_context;
|
||||
int index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
|
||||
vram_usagebyfirmware);
|
||||
uint16_t data_offset;
|
||||
int usage_bytes = 0;
|
||||
|
||||
if (amdgpu_atom_parse_data_header(ctx, index, NULL, NULL, NULL, &data_offset)) {
|
||||
struct vram_usagebyfirmware_v2_1 *firmware_usage =
|
||||
(struct vram_usagebyfirmware_v2_1 *)(ctx->bios + data_offset);
|
||||
|
||||
DRM_DEBUG("atom firmware requested %08x %dkb fw %dkb drv\n",
|
||||
le32_to_cpu(firmware_usage->start_address_in_kb),
|
||||
le16_to_cpu(firmware_usage->used_by_firmware_in_kb),
|
||||
le16_to_cpu(firmware_usage->used_by_driver_in_kb));
|
||||
|
||||
usage_bytes = le16_to_cpu(firmware_usage->used_by_driver_in_kb) * 1024;
|
||||
}
|
||||
ctx->scratch_size_bytes = 0;
|
||||
if (usage_bytes == 0)
|
||||
usage_bytes = 20 * 1024;
|
||||
/* allocate some scratch memory */
|
||||
ctx->scratch = kzalloc(usage_bytes, GFP_KERNEL);
|
||||
if (!ctx->scratch)
|
||||
return -ENOMEM;
|
||||
ctx->scratch_size_bytes = usage_bytes;
|
||||
return 0;
|
||||
}
|
33
drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.h
Normal file
33
drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.h
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2014 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __AMDGPU_ATOMFIRMWARE_H__
|
||||
#define __AMDGPU_ATOMFIRMWARE_H__
|
||||
|
||||
bool amdgpu_atomfirmware_gpu_supports_virtualization(struct amdgpu_device *adev);
|
||||
void amdgpu_atomfirmware_scratch_regs_init(struct amdgpu_device *adev);
|
||||
void amdgpu_atomfirmware_scratch_regs_save(struct amdgpu_device *adev);
|
||||
void amdgpu_atomfirmware_scratch_regs_restore(struct amdgpu_device *adev);
|
||||
int amdgpu_atomfirmware_allocate_fb_scratch(struct amdgpu_device *adev);
|
||||
|
||||
#endif
|
@ -583,8 +583,8 @@ static bool amdgpu_atpx_detect(void)
|
||||
|
||||
if (has_atpx && vga_count == 2) {
|
||||
acpi_get_name(amdgpu_atpx_priv.atpx.handle, ACPI_FULL_PATHNAME, &buffer);
|
||||
printk(KERN_INFO "vga_switcheroo: detected switching method %s handle\n",
|
||||
acpi_method_name);
|
||||
pr_info("vga_switcheroo: detected switching method %s handle\n",
|
||||
acpi_method_name);
|
||||
amdgpu_atpx_priv.atpx_detected = true;
|
||||
amdgpu_atpx_priv.bridge_pm_usable = d3_supported;
|
||||
amdgpu_atpx_init();
|
||||
|
@ -86,6 +86,18 @@ static bool check_atom_bios(uint8_t *bios, size_t size)
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool is_atom_fw(uint8_t *bios)
|
||||
{
|
||||
uint16_t bios_header_start = bios[0x48] | (bios[0x49] << 8);
|
||||
uint8_t frev = bios[bios_header_start + 2];
|
||||
uint8_t crev = bios[bios_header_start + 3];
|
||||
|
||||
if ((frev < 3) ||
|
||||
((frev == 3) && (crev < 3)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* If you boot an IGP board with a discrete card as the primary,
|
||||
* the IGP rom is not accessible via the rom bar as the IGP rom is
|
||||
@ -419,26 +431,30 @@ static inline bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)
|
||||
bool amdgpu_get_bios(struct amdgpu_device *adev)
|
||||
{
|
||||
if (amdgpu_atrm_get_bios(adev))
|
||||
return true;
|
||||
goto success;
|
||||
|
||||
if (amdgpu_acpi_vfct_bios(adev))
|
||||
return true;
|
||||
goto success;
|
||||
|
||||
if (igp_read_bios_from_vram(adev))
|
||||
return true;
|
||||
goto success;
|
||||
|
||||
if (amdgpu_read_bios(adev))
|
||||
return true;
|
||||
goto success;
|
||||
|
||||
if (amdgpu_read_bios_from_rom(adev))
|
||||
return true;
|
||||
goto success;
|
||||
|
||||
if (amdgpu_read_disabled_bios(adev))
|
||||
return true;
|
||||
goto success;
|
||||
|
||||
if (amdgpu_read_platform_bios(adev))
|
||||
return true;
|
||||
goto success;
|
||||
|
||||
DRM_ERROR("Unable to locate a BIOS ROM\n");
|
||||
return false;
|
||||
|
||||
success:
|
||||
adev->is_atom_fw = is_atom_fw(adev->bios);
|
||||
return true;
|
||||
}
|
||||
|
@ -237,7 +237,7 @@ int amdgpu_bo_list_ioctl(struct drm_device *dev, void *data,
|
||||
struct amdgpu_fpriv *fpriv = filp->driver_priv;
|
||||
union drm_amdgpu_bo_list *args = data;
|
||||
uint32_t handle = args->in.list_handle;
|
||||
const void __user *uptr = (const void*)(long)args->in.bo_info_ptr;
|
||||
const void __user *uptr = (const void*)(uintptr_t)args->in.bo_info_ptr;
|
||||
|
||||
struct drm_amdgpu_bo_list_entry *info;
|
||||
struct amdgpu_bo_list *list;
|
||||
|
@ -571,7 +571,9 @@ static const struct amdgpu_irq_src_funcs cgs_irq_funcs = {
|
||||
.process = cgs_process_irq,
|
||||
};
|
||||
|
||||
static int amdgpu_cgs_add_irq_source(struct cgs_device *cgs_device, unsigned src_id,
|
||||
static int amdgpu_cgs_add_irq_source(void *cgs_device,
|
||||
unsigned client_id,
|
||||
unsigned src_id,
|
||||
unsigned num_types,
|
||||
cgs_irq_source_set_func_t set,
|
||||
cgs_irq_handler_func_t handler,
|
||||
@ -597,7 +599,7 @@ static int amdgpu_cgs_add_irq_source(struct cgs_device *cgs_device, unsigned src
|
||||
irq_params->handler = handler;
|
||||
irq_params->private_data = private_data;
|
||||
source->data = (void *)irq_params;
|
||||
ret = amdgpu_irq_add_id(adev, src_id, source);
|
||||
ret = amdgpu_irq_add_id(adev, client_id, src_id, source);
|
||||
if (ret) {
|
||||
kfree(irq_params);
|
||||
kfree(source);
|
||||
@ -606,16 +608,26 @@ static int amdgpu_cgs_add_irq_source(struct cgs_device *cgs_device, unsigned src
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int amdgpu_cgs_irq_get(struct cgs_device *cgs_device, unsigned src_id, unsigned type)
|
||||
static int amdgpu_cgs_irq_get(void *cgs_device, unsigned client_id,
|
||||
unsigned src_id, unsigned type)
|
||||
{
|
||||
CGS_FUNC_ADEV;
|
||||
return amdgpu_irq_get(adev, adev->irq.sources[src_id], type);
|
||||
|
||||
if (!adev->irq.client[client_id].sources)
|
||||
return -EINVAL;
|
||||
|
||||
return amdgpu_irq_get(adev, adev->irq.client[client_id].sources[src_id], type);
|
||||
}
|
||||
|
||||
static int amdgpu_cgs_irq_put(struct cgs_device *cgs_device, unsigned src_id, unsigned type)
|
||||
static int amdgpu_cgs_irq_put(void *cgs_device, unsigned client_id,
|
||||
unsigned src_id, unsigned type)
|
||||
{
|
||||
CGS_FUNC_ADEV;
|
||||
return amdgpu_irq_put(adev, adev->irq.sources[src_id], type);
|
||||
|
||||
if (!adev->irq.client[client_id].sources)
|
||||
return -EINVAL;
|
||||
|
||||
return amdgpu_irq_put(adev, adev->irq.client[client_id].sources[src_id], type);
|
||||
}
|
||||
|
||||
static int amdgpu_cgs_set_clockgating_state(struct cgs_device *cgs_device,
|
||||
@ -825,9 +837,8 @@ static int amdgpu_cgs_get_firmware_info(struct cgs_device *cgs_device,
|
||||
uint32_t ucode_start_address;
|
||||
const uint8_t *src;
|
||||
const struct smc_firmware_header_v1_0 *hdr;
|
||||
|
||||
if (CGS_UCODE_ID_SMU_SK == type)
|
||||
amdgpu_cgs_rel_firmware(cgs_device, CGS_UCODE_ID_SMU);
|
||||
const struct common_firmware_header *header;
|
||||
struct amdgpu_firmware_info *ucode = NULL;
|
||||
|
||||
if (!adev->pm.fw) {
|
||||
switch (adev->asic_type) {
|
||||
@ -889,6 +900,9 @@ static int amdgpu_cgs_get_firmware_info(struct cgs_device *cgs_device,
|
||||
case CHIP_POLARIS12:
|
||||
strcpy(fw_name, "amdgpu/polaris12_smc.bin");
|
||||
break;
|
||||
case CHIP_VEGA10:
|
||||
strcpy(fw_name, "amdgpu/vega10_smc.bin");
|
||||
break;
|
||||
default:
|
||||
DRM_ERROR("SMC firmware not supported\n");
|
||||
return -EINVAL;
|
||||
@ -907,6 +921,15 @@ static int amdgpu_cgs_get_firmware_info(struct cgs_device *cgs_device,
|
||||
adev->pm.fw = NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) {
|
||||
ucode = &adev->firmware.ucode[AMDGPU_UCODE_ID_SMC];
|
||||
ucode->ucode_id = AMDGPU_UCODE_ID_SMC;
|
||||
ucode->fw = adev->pm.fw;
|
||||
header = (const struct common_firmware_header *)ucode->fw->data;
|
||||
adev->firmware.fw_size +=
|
||||
ALIGN(le32_to_cpu(header->ucode_size_bytes), PAGE_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
hdr = (const struct smc_firmware_header_v1_0 *) adev->pm.fw->data;
|
||||
|
@ -82,6 +82,15 @@ int amdgpu_cs_get_ring(struct amdgpu_device *adev, u32 ip_type,
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
case AMDGPU_HW_IP_UVD_ENC:
|
||||
if (ring < adev->uvd.num_enc_rings){
|
||||
*out_ring = &adev->uvd.ring_enc[ring];
|
||||
} else {
|
||||
DRM_ERROR("only %d UVD ENC rings are supported\n",
|
||||
adev->uvd.num_enc_rings);
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(*out_ring && (*out_ring)->adev)) {
|
||||
@ -152,7 +161,7 @@ int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data)
|
||||
}
|
||||
|
||||
/* get chunks */
|
||||
chunk_array_user = (uint64_t __user *)(unsigned long)(cs->in.chunks);
|
||||
chunk_array_user = (uint64_t __user *)(uintptr_t)(cs->in.chunks);
|
||||
if (copy_from_user(chunk_array, chunk_array_user,
|
||||
sizeof(uint64_t)*cs->in.num_chunks)) {
|
||||
ret = -EFAULT;
|
||||
@ -172,7 +181,7 @@ int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data)
|
||||
struct drm_amdgpu_cs_chunk user_chunk;
|
||||
uint32_t __user *cdata;
|
||||
|
||||
chunk_ptr = (void __user *)(unsigned long)chunk_array[i];
|
||||
chunk_ptr = (void __user *)(uintptr_t)chunk_array[i];
|
||||
if (copy_from_user(&user_chunk, chunk_ptr,
|
||||
sizeof(struct drm_amdgpu_cs_chunk))) {
|
||||
ret = -EFAULT;
|
||||
@ -183,7 +192,7 @@ int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data)
|
||||
p->chunks[i].length_dw = user_chunk.length_dw;
|
||||
|
||||
size = p->chunks[i].length_dw;
|
||||
cdata = (void __user *)(unsigned long)user_chunk.chunk_data;
|
||||
cdata = (void __user *)(uintptr_t)user_chunk.chunk_data;
|
||||
|
||||
p->chunks[i].kdata = drm_malloc_ab(size, sizeof(uint32_t));
|
||||
if (p->chunks[i].kdata == NULL) {
|
||||
@ -759,23 +768,33 @@ static void amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser, int error, bo
|
||||
amdgpu_bo_unref(&parser->uf_entry.robj);
|
||||
}
|
||||
|
||||
static int amdgpu_bo_vm_update_pte(struct amdgpu_cs_parser *p,
|
||||
struct amdgpu_vm *vm)
|
||||
static int amdgpu_bo_vm_update_pte(struct amdgpu_cs_parser *p)
|
||||
{
|
||||
struct amdgpu_device *adev = p->adev;
|
||||
struct amdgpu_fpriv *fpriv = p->filp->driver_priv;
|
||||
struct amdgpu_vm *vm = &fpriv->vm;
|
||||
struct amdgpu_bo_va *bo_va;
|
||||
struct amdgpu_bo *bo;
|
||||
int i, r;
|
||||
|
||||
r = amdgpu_vm_update_page_directory(adev, vm);
|
||||
r = amdgpu_vm_update_directories(adev, vm);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = amdgpu_sync_fence(adev, &p->job->sync, vm->page_directory_fence);
|
||||
r = amdgpu_sync_fence(adev, &p->job->sync, vm->last_dir_update);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = amdgpu_vm_clear_freed(adev, vm);
|
||||
r = amdgpu_vm_clear_freed(adev, vm, NULL);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = amdgpu_vm_bo_update(adev, fpriv->prt_va, false);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = amdgpu_sync_fence(adev, &p->job->sync,
|
||||
fpriv->prt_va->last_pt_update);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
@ -853,9 +872,9 @@ static int amdgpu_cs_ib_vm_chunk(struct amdgpu_device *adev,
|
||||
}
|
||||
|
||||
if (p->job->vm) {
|
||||
p->job->vm_pd_addr = amdgpu_bo_gpu_offset(vm->page_directory);
|
||||
p->job->vm_pd_addr = amdgpu_bo_gpu_offset(vm->root.bo);
|
||||
|
||||
r = amdgpu_bo_vm_update_pte(p, vm);
|
||||
r = amdgpu_bo_vm_update_pte(p);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
@ -869,7 +888,7 @@ static int amdgpu_cs_ib_fill(struct amdgpu_device *adev,
|
||||
struct amdgpu_fpriv *fpriv = parser->filp->driver_priv;
|
||||
struct amdgpu_vm *vm = &fpriv->vm;
|
||||
int i, j;
|
||||
int r;
|
||||
int r, ce_preempt = 0, de_preempt = 0;
|
||||
|
||||
for (i = 0, j = 0; i < parser->nchunks && j < parser->job->num_ibs; i++) {
|
||||
struct amdgpu_cs_chunk *chunk;
|
||||
@ -884,13 +903,26 @@ static int amdgpu_cs_ib_fill(struct amdgpu_device *adev,
|
||||
if (chunk->chunk_id != AMDGPU_CHUNK_ID_IB)
|
||||
continue;
|
||||
|
||||
if (chunk_ib->ip_type == AMDGPU_HW_IP_GFX && amdgpu_sriov_vf(adev)) {
|
||||
if (chunk_ib->flags & AMDGPU_IB_FLAG_PREEMPT) {
|
||||
if (chunk_ib->flags & AMDGPU_IB_FLAG_CE)
|
||||
ce_preempt++;
|
||||
else
|
||||
de_preempt++;
|
||||
}
|
||||
|
||||
/* each GFX command submit allows 0 or 1 IB preemptible for CE & DE */
|
||||
if (ce_preempt > 1 || de_preempt > 1)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = amdgpu_cs_get_ring(adev, chunk_ib->ip_type,
|
||||
chunk_ib->ip_instance, chunk_ib->ring,
|
||||
&ring);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (ib->flags & AMDGPU_IB_FLAG_PREAMBLE) {
|
||||
if (chunk_ib->flags & AMDGPU_IB_FLAG_PREAMBLE) {
|
||||
parser->job->preamble_status |= AMDGPU_PREAMBLE_IB_PRESENT;
|
||||
if (!parser->ctx->preamble_presented) {
|
||||
parser->job->preamble_status |= AMDGPU_PREAMBLE_IB_PRESENT_FIRST;
|
||||
@ -917,7 +949,7 @@ static int amdgpu_cs_ib_fill(struct amdgpu_device *adev,
|
||||
}
|
||||
|
||||
if ((chunk_ib->va_start + chunk_ib->ib_bytes) >
|
||||
(m->it.last + 1) * AMDGPU_GPU_PAGE_SIZE) {
|
||||
(m->last + 1) * AMDGPU_GPU_PAGE_SIZE) {
|
||||
DRM_ERROR("IB va_start+ib_bytes is invalid\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -928,7 +960,7 @@ static int amdgpu_cs_ib_fill(struct amdgpu_device *adev,
|
||||
return r;
|
||||
}
|
||||
|
||||
offset = ((uint64_t)m->it.start) * AMDGPU_GPU_PAGE_SIZE;
|
||||
offset = m->start * AMDGPU_GPU_PAGE_SIZE;
|
||||
kptr += chunk_ib->va_start - offset;
|
||||
|
||||
r = amdgpu_ib_get(adev, vm, chunk_ib->ib_bytes, ib);
|
||||
@ -1210,6 +1242,7 @@ static int amdgpu_cs_wait_all_fences(struct amdgpu_device *adev,
|
||||
continue;
|
||||
|
||||
r = dma_fence_wait_timeout(fence, true, timeout);
|
||||
dma_fence_put(fence);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -1307,7 +1340,7 @@ int amdgpu_cs_wait_fences_ioctl(struct drm_device *dev, void *data,
|
||||
if (fences == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
fences_user = (void __user *)(unsigned long)(wait->in.fences);
|
||||
fences_user = (void __user *)(uintptr_t)(wait->in.fences);
|
||||
if (copy_from_user(fences, fences_user,
|
||||
sizeof(struct drm_amdgpu_fence) * fence_count)) {
|
||||
r = -EFAULT;
|
||||
@ -1356,8 +1389,8 @@ amdgpu_cs_find_mapping(struct amdgpu_cs_parser *parser,
|
||||
continue;
|
||||
|
||||
list_for_each_entry(mapping, &lobj->bo_va->valids, list) {
|
||||
if (mapping->it.start > addr ||
|
||||
addr > mapping->it.last)
|
||||
if (mapping->start > addr ||
|
||||
addr > mapping->last)
|
||||
continue;
|
||||
|
||||
*bo = lobj->bo_va->bo;
|
||||
@ -1365,8 +1398,8 @@ amdgpu_cs_find_mapping(struct amdgpu_cs_parser *parser,
|
||||
}
|
||||
|
||||
list_for_each_entry(mapping, &lobj->bo_va->invalids, list) {
|
||||
if (mapping->it.start > addr ||
|
||||
addr > mapping->it.last)
|
||||
if (mapping->start > addr ||
|
||||
addr > mapping->last)
|
||||
continue;
|
||||
|
||||
*bo = lobj->bo_va->bo;
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include "amdgpu_i2c.h"
|
||||
#include "atom.h"
|
||||
#include "amdgpu_atombios.h"
|
||||
#include "amdgpu_atomfirmware.h"
|
||||
#include "amd_pcie.h"
|
||||
#ifdef CONFIG_DRM_AMDGPU_SI
|
||||
#include "si.h"
|
||||
@ -48,9 +49,11 @@
|
||||
#include "cik.h"
|
||||
#endif
|
||||
#include "vi.h"
|
||||
#include "soc15.h"
|
||||
#include "bif/bif_4_1_d.h"
|
||||
#include <linux/pci.h>
|
||||
#include <linux/firmware.h>
|
||||
#include "amdgpu_pm.h"
|
||||
|
||||
static int amdgpu_debugfs_regs_init(struct amdgpu_device *adev);
|
||||
static void amdgpu_debugfs_regs_cleanup(struct amdgpu_device *adev);
|
||||
@ -74,6 +77,7 @@ static const char *amdgpu_asic_name[] = {
|
||||
"POLARIS10",
|
||||
"POLARIS11",
|
||||
"POLARIS12",
|
||||
"VEGA10",
|
||||
"LAST",
|
||||
};
|
||||
|
||||
@ -90,16 +94,16 @@ bool amdgpu_device_is_px(struct drm_device *dev)
|
||||
* MMIO register access helper functions.
|
||||
*/
|
||||
uint32_t amdgpu_mm_rreg(struct amdgpu_device *adev, uint32_t reg,
|
||||
bool always_indirect)
|
||||
uint32_t acc_flags)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
if (amdgpu_sriov_runtime(adev)) {
|
||||
if (!(acc_flags & AMDGPU_REGS_NO_KIQ) && amdgpu_sriov_runtime(adev)) {
|
||||
BUG_ON(in_interrupt());
|
||||
return amdgpu_virt_kiq_rreg(adev, reg);
|
||||
}
|
||||
|
||||
if ((reg * 4) < adev->rmmio_size && !always_indirect)
|
||||
if ((reg * 4) < adev->rmmio_size && !(acc_flags & AMDGPU_REGS_IDX))
|
||||
ret = readl(((void __iomem *)adev->rmmio) + (reg * 4));
|
||||
else {
|
||||
unsigned long flags;
|
||||
@ -114,16 +118,16 @@ uint32_t amdgpu_mm_rreg(struct amdgpu_device *adev, uint32_t reg,
|
||||
}
|
||||
|
||||
void amdgpu_mm_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v,
|
||||
bool always_indirect)
|
||||
uint32_t acc_flags)
|
||||
{
|
||||
trace_amdgpu_mm_wreg(adev->pdev->device, reg, v);
|
||||
|
||||
if (amdgpu_sriov_runtime(adev)) {
|
||||
if (!(acc_flags & AMDGPU_REGS_NO_KIQ) && amdgpu_sriov_runtime(adev)) {
|
||||
BUG_ON(in_interrupt());
|
||||
return amdgpu_virt_kiq_wreg(adev, reg, v);
|
||||
}
|
||||
|
||||
if ((reg * 4) < adev->rmmio_size && !always_indirect)
|
||||
if ((reg * 4) < adev->rmmio_size && !(acc_flags & AMDGPU_REGS_IDX))
|
||||
writel(v, ((void __iomem *)adev->rmmio) + (reg * 4));
|
||||
else {
|
||||
unsigned long flags;
|
||||
@ -194,6 +198,44 @@ void amdgpu_mm_wdoorbell(struct amdgpu_device *adev, u32 index, u32 v)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_mm_rdoorbell64 - read a doorbell Qword
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
* @index: doorbell index
|
||||
*
|
||||
* Returns the value in the doorbell aperture at the
|
||||
* requested doorbell index (VEGA10+).
|
||||
*/
|
||||
u64 amdgpu_mm_rdoorbell64(struct amdgpu_device *adev, u32 index)
|
||||
{
|
||||
if (index < adev->doorbell.num_doorbells) {
|
||||
return atomic64_read((atomic64_t *)(adev->doorbell.ptr + index));
|
||||
} else {
|
||||
DRM_ERROR("reading beyond doorbell aperture: 0x%08x!\n", index);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_mm_wdoorbell64 - write a doorbell Qword
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
* @index: doorbell index
|
||||
* @v: value to write
|
||||
*
|
||||
* Writes @v to the doorbell aperture at the
|
||||
* requested doorbell index (VEGA10+).
|
||||
*/
|
||||
void amdgpu_mm_wdoorbell64(struct amdgpu_device *adev, u32 index, u64 v)
|
||||
{
|
||||
if (index < adev->doorbell.num_doorbells) {
|
||||
atomic64_set((atomic64_t *)(adev->doorbell.ptr + index), v);
|
||||
} else {
|
||||
DRM_ERROR("writing beyond doorbell aperture: 0x%08x!\n", index);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_invalid_rreg - dummy reg read function
|
||||
*
|
||||
@ -515,6 +557,29 @@ int amdgpu_wb_get(struct amdgpu_device *adev, u32 *wb)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_wb_get_64bit - Allocate a wb entry
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
* @wb: wb index
|
||||
*
|
||||
* Allocate a wb slot for use by the driver (all asics).
|
||||
* Returns 0 on success or -EINVAL on failure.
|
||||
*/
|
||||
int amdgpu_wb_get_64bit(struct amdgpu_device *adev, u32 *wb)
|
||||
{
|
||||
unsigned long offset = bitmap_find_next_zero_area_off(adev->wb.used,
|
||||
adev->wb.num_wb, 0, 2, 7, 0);
|
||||
if ((offset + 1) < adev->wb.num_wb) {
|
||||
__set_bit(offset, adev->wb.used);
|
||||
__set_bit(offset + 1, adev->wb.used);
|
||||
*wb = offset;
|
||||
return 0;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_wb_free - Free a wb entry
|
||||
*
|
||||
@ -529,6 +594,22 @@ void amdgpu_wb_free(struct amdgpu_device *adev, u32 wb)
|
||||
__clear_bit(wb, adev->wb.used);
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_wb_free_64bit - Free a wb entry
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
* @wb: wb index
|
||||
*
|
||||
* Free a wb slot allocated for use by the driver (all asics)
|
||||
*/
|
||||
void amdgpu_wb_free_64bit(struct amdgpu_device *adev, u32 wb)
|
||||
{
|
||||
if ((wb + 1) < adev->wb.num_wb) {
|
||||
__clear_bit(wb, adev->wb.used);
|
||||
__clear_bit(wb + 1, adev->wb.used);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_vram_location - try to find VRAM location
|
||||
* @adev: amdgpu device structure holding all necessary informations
|
||||
@ -602,7 +683,7 @@ void amdgpu_gtt_location(struct amdgpu_device *adev, struct amdgpu_mc *mc)
|
||||
dev_warn(adev->dev, "limiting GTT\n");
|
||||
mc->gtt_size = size_bf;
|
||||
}
|
||||
mc->gtt_start = (mc->vram_start & ~mc->gtt_base_align) - mc->gtt_size;
|
||||
mc->gtt_start = 0;
|
||||
} else {
|
||||
if (mc->gtt_size > size_af) {
|
||||
dev_warn(adev->dev, "limiting GTT\n");
|
||||
@ -636,9 +717,9 @@ bool amdgpu_need_post(struct amdgpu_device *adev)
|
||||
return true;
|
||||
}
|
||||
/* then check MEM_SIZE, in case the crtcs are off */
|
||||
reg = RREG32(mmCONFIG_MEMSIZE);
|
||||
reg = amdgpu_asic_get_config_memsize(adev);
|
||||
|
||||
if (reg)
|
||||
if ((reg != 0) && (reg != 0xffffffff))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@ -915,8 +996,13 @@ static int amdgpu_atombios_init(struct amdgpu_device *adev)
|
||||
}
|
||||
|
||||
mutex_init(&adev->mode_info.atom_context->mutex);
|
||||
amdgpu_atombios_scratch_regs_init(adev);
|
||||
amdgpu_atom_allocate_fb_scratch(adev->mode_info.atom_context);
|
||||
if (adev->is_atom_fw) {
|
||||
amdgpu_atomfirmware_scratch_regs_init(adev);
|
||||
amdgpu_atomfirmware_allocate_fb_scratch(adev);
|
||||
} else {
|
||||
amdgpu_atombios_scratch_regs_init(adev);
|
||||
amdgpu_atombios_allocate_fb_scratch(adev);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -954,6 +1040,62 @@ static bool amdgpu_check_pot_argument(int arg)
|
||||
return (arg & (arg - 1)) == 0;
|
||||
}
|
||||
|
||||
static void amdgpu_check_block_size(struct amdgpu_device *adev)
|
||||
{
|
||||
/* defines number of bits in page table versus page directory,
|
||||
* a page is 4KB so we have 12 bits offset, minimum 9 bits in the
|
||||
* page table and the remaining bits are in the page directory */
|
||||
if (amdgpu_vm_block_size == -1)
|
||||
return;
|
||||
|
||||
if (amdgpu_vm_block_size < 9) {
|
||||
dev_warn(adev->dev, "VM page table size (%d) too small\n",
|
||||
amdgpu_vm_block_size);
|
||||
goto def_value;
|
||||
}
|
||||
|
||||
if (amdgpu_vm_block_size > 24 ||
|
||||
(amdgpu_vm_size * 1024) < (1ull << amdgpu_vm_block_size)) {
|
||||
dev_warn(adev->dev, "VM page table size (%d) too large\n",
|
||||
amdgpu_vm_block_size);
|
||||
goto def_value;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
def_value:
|
||||
amdgpu_vm_block_size = -1;
|
||||
}
|
||||
|
||||
static void amdgpu_check_vm_size(struct amdgpu_device *adev)
|
||||
{
|
||||
if (!amdgpu_check_pot_argument(amdgpu_vm_size)) {
|
||||
dev_warn(adev->dev, "VM size (%d) must be a power of 2\n",
|
||||
amdgpu_vm_size);
|
||||
goto def_value;
|
||||
}
|
||||
|
||||
if (amdgpu_vm_size < 1) {
|
||||
dev_warn(adev->dev, "VM size (%d) too small, min is 1GB\n",
|
||||
amdgpu_vm_size);
|
||||
goto def_value;
|
||||
}
|
||||
|
||||
/*
|
||||
* Max GPUVM size for Cayman, SI, CI VI are 40 bits.
|
||||
*/
|
||||
if (amdgpu_vm_size > 1024) {
|
||||
dev_warn(adev->dev, "VM size (%d) too large, max is 1TB\n",
|
||||
amdgpu_vm_size);
|
||||
goto def_value;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
def_value:
|
||||
amdgpu_vm_size = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_check_arguments - validate module params
|
||||
*
|
||||
@ -983,54 +1125,9 @@ static void amdgpu_check_arguments(struct amdgpu_device *adev)
|
||||
}
|
||||
}
|
||||
|
||||
if (!amdgpu_check_pot_argument(amdgpu_vm_size)) {
|
||||
dev_warn(adev->dev, "VM size (%d) must be a power of 2\n",
|
||||
amdgpu_vm_size);
|
||||
amdgpu_vm_size = 8;
|
||||
}
|
||||
amdgpu_check_vm_size(adev);
|
||||
|
||||
if (amdgpu_vm_size < 1) {
|
||||
dev_warn(adev->dev, "VM size (%d) too small, min is 1GB\n",
|
||||
amdgpu_vm_size);
|
||||
amdgpu_vm_size = 8;
|
||||
}
|
||||
|
||||
/*
|
||||
* Max GPUVM size for Cayman, SI and CI are 40 bits.
|
||||
*/
|
||||
if (amdgpu_vm_size > 1024) {
|
||||
dev_warn(adev->dev, "VM size (%d) too large, max is 1TB\n",
|
||||
amdgpu_vm_size);
|
||||
amdgpu_vm_size = 8;
|
||||
}
|
||||
|
||||
/* defines number of bits in page table versus page directory,
|
||||
* a page is 4KB so we have 12 bits offset, minimum 9 bits in the
|
||||
* page table and the remaining bits are in the page directory */
|
||||
if (amdgpu_vm_block_size == -1) {
|
||||
|
||||
/* Total bits covered by PD + PTs */
|
||||
unsigned bits = ilog2(amdgpu_vm_size) + 18;
|
||||
|
||||
/* Make sure the PD is 4K in size up to 8GB address space.
|
||||
Above that split equal between PD and PTs */
|
||||
if (amdgpu_vm_size <= 8)
|
||||
amdgpu_vm_block_size = bits - 9;
|
||||
else
|
||||
amdgpu_vm_block_size = (bits + 3) / 2;
|
||||
|
||||
} else if (amdgpu_vm_block_size < 9) {
|
||||
dev_warn(adev->dev, "VM page table size (%d) too small\n",
|
||||
amdgpu_vm_block_size);
|
||||
amdgpu_vm_block_size = 9;
|
||||
}
|
||||
|
||||
if (amdgpu_vm_block_size > 24 ||
|
||||
(amdgpu_vm_size * 1024) < (1ull << amdgpu_vm_block_size)) {
|
||||
dev_warn(adev->dev, "VM page table size (%d) too large\n",
|
||||
amdgpu_vm_block_size);
|
||||
amdgpu_vm_block_size = 9;
|
||||
}
|
||||
amdgpu_check_block_size(adev);
|
||||
|
||||
if (amdgpu_vram_page_split != -1 && (amdgpu_vram_page_split < 16 ||
|
||||
!amdgpu_check_pot_argument(amdgpu_vram_page_split))) {
|
||||
@ -1059,7 +1156,7 @@ static void amdgpu_switcheroo_set_state(struct pci_dev *pdev, enum vga_switchero
|
||||
if (state == VGA_SWITCHEROO_ON) {
|
||||
unsigned d3_delay = dev->pdev->d3_delay;
|
||||
|
||||
printk(KERN_INFO "amdgpu: switched on\n");
|
||||
pr_info("amdgpu: switched on\n");
|
||||
/* don't suspend or resume card normally */
|
||||
dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
|
||||
|
||||
@ -1070,7 +1167,7 @@ static void amdgpu_switcheroo_set_state(struct pci_dev *pdev, enum vga_switchero
|
||||
dev->switch_power_state = DRM_SWITCH_POWER_ON;
|
||||
drm_kms_helper_poll_enable(dev);
|
||||
} else {
|
||||
printk(KERN_INFO "amdgpu: switched off\n");
|
||||
pr_info("amdgpu: switched off\n");
|
||||
drm_kms_helper_poll_disable(dev);
|
||||
dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
|
||||
amdgpu_device_suspend(dev, true, true);
|
||||
@ -1114,13 +1211,15 @@ int amdgpu_set_clockgating_state(struct amdgpu_device *adev,
|
||||
for (i = 0; i < adev->num_ip_blocks; i++) {
|
||||
if (!adev->ip_blocks[i].status.valid)
|
||||
continue;
|
||||
if (adev->ip_blocks[i].version->type == block_type) {
|
||||
r = adev->ip_blocks[i].version->funcs->set_clockgating_state((void *)adev,
|
||||
state);
|
||||
if (r)
|
||||
return r;
|
||||
break;
|
||||
}
|
||||
if (adev->ip_blocks[i].version->type != block_type)
|
||||
continue;
|
||||
if (!adev->ip_blocks[i].version->funcs->set_clockgating_state)
|
||||
continue;
|
||||
r = adev->ip_blocks[i].version->funcs->set_clockgating_state(
|
||||
(void *)adev, state);
|
||||
if (r)
|
||||
DRM_ERROR("set_clockgating_state of IP block <%s> failed %d\n",
|
||||
adev->ip_blocks[i].version->funcs->name, r);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
@ -1134,13 +1233,15 @@ int amdgpu_set_powergating_state(struct amdgpu_device *adev,
|
||||
for (i = 0; i < adev->num_ip_blocks; i++) {
|
||||
if (!adev->ip_blocks[i].status.valid)
|
||||
continue;
|
||||
if (adev->ip_blocks[i].version->type == block_type) {
|
||||
r = adev->ip_blocks[i].version->funcs->set_powergating_state((void *)adev,
|
||||
state);
|
||||
if (r)
|
||||
return r;
|
||||
break;
|
||||
}
|
||||
if (adev->ip_blocks[i].version->type != block_type)
|
||||
continue;
|
||||
if (!adev->ip_blocks[i].version->funcs->set_powergating_state)
|
||||
continue;
|
||||
r = adev->ip_blocks[i].version->funcs->set_powergating_state(
|
||||
(void *)adev, state);
|
||||
if (r)
|
||||
DRM_ERROR("set_powergating_state of IP block <%s> failed %d\n",
|
||||
adev->ip_blocks[i].version->funcs->name, r);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
@ -1345,6 +1446,13 @@ static int amdgpu_early_init(struct amdgpu_device *adev)
|
||||
return r;
|
||||
break;
|
||||
#endif
|
||||
case CHIP_VEGA10:
|
||||
adev->family = AMDGPU_FAMILY_AI;
|
||||
|
||||
r = soc15_set_ip_blocks(adev);
|
||||
if (r)
|
||||
return r;
|
||||
break;
|
||||
default:
|
||||
/* FIXME: not supported yet */
|
||||
return -EINVAL;
|
||||
@ -1476,6 +1584,9 @@ static int amdgpu_late_init(struct amdgpu_device *adev)
|
||||
}
|
||||
}
|
||||
|
||||
amdgpu_dpm_enable_uvd(adev, false);
|
||||
amdgpu_dpm_enable_vce(adev, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1607,6 +1718,53 @@ int amdgpu_suspend(struct amdgpu_device *adev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amdgpu_sriov_reinit_early(struct amdgpu_device *adev)
|
||||
{
|
||||
int i, r;
|
||||
|
||||
for (i = 0; i < adev->num_ip_blocks; i++) {
|
||||
if (!adev->ip_blocks[i].status.valid)
|
||||
continue;
|
||||
|
||||
if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_COMMON ||
|
||||
adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC ||
|
||||
adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_IH)
|
||||
r = adev->ip_blocks[i].version->funcs->hw_init(adev);
|
||||
|
||||
if (r) {
|
||||
DRM_ERROR("resume of IP block <%s> failed %d\n",
|
||||
adev->ip_blocks[i].version->funcs->name, r);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amdgpu_sriov_reinit_late(struct amdgpu_device *adev)
|
||||
{
|
||||
int i, r;
|
||||
|
||||
for (i = 0; i < adev->num_ip_blocks; i++) {
|
||||
if (!adev->ip_blocks[i].status.valid)
|
||||
continue;
|
||||
|
||||
if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_COMMON ||
|
||||
adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC ||
|
||||
adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_IH )
|
||||
continue;
|
||||
|
||||
r = adev->ip_blocks[i].version->funcs->hw_init(adev);
|
||||
if (r) {
|
||||
DRM_ERROR("resume of IP block <%s> failed %d\n",
|
||||
adev->ip_blocks[i].version->funcs->name, r);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amdgpu_resume(struct amdgpu_device *adev)
|
||||
{
|
||||
int i, r;
|
||||
@ -1627,8 +1785,13 @@ static int amdgpu_resume(struct amdgpu_device *adev)
|
||||
|
||||
static void amdgpu_device_detect_sriov_bios(struct amdgpu_device *adev)
|
||||
{
|
||||
if (amdgpu_atombios_has_gpu_virtualization_table(adev))
|
||||
adev->virt.caps |= AMDGPU_SRIOV_CAPS_SRIOV_VBIOS;
|
||||
if (adev->is_atom_fw) {
|
||||
if (amdgpu_atomfirmware_gpu_supports_virtualization(adev))
|
||||
adev->virt.caps |= AMDGPU_SRIOV_CAPS_SRIOV_VBIOS;
|
||||
} else {
|
||||
if (amdgpu_atombios_has_gpu_virtualization_table(adev))
|
||||
adev->virt.caps |= AMDGPU_SRIOV_CAPS_SRIOV_VBIOS;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1693,6 +1856,7 @@ int amdgpu_device_init(struct amdgpu_device *adev,
|
||||
* can recall function without having locking issues */
|
||||
mutex_init(&adev->vm_manager.lock);
|
||||
atomic_set(&adev->irq.ih.lock, 0);
|
||||
mutex_init(&adev->firmware.mutex);
|
||||
mutex_init(&adev->pm.mutex);
|
||||
mutex_init(&adev->gfx.gpu_clock_mutex);
|
||||
mutex_init(&adev->srbm_mutex);
|
||||
@ -1763,7 +1927,9 @@ int amdgpu_device_init(struct amdgpu_device *adev,
|
||||
runtime = true;
|
||||
if (amdgpu_device_is_px(ddev))
|
||||
runtime = true;
|
||||
vga_switcheroo_register_client(adev->pdev, &amdgpu_switcheroo_ops, runtime);
|
||||
if (!pci_is_thunderbolt_attached(adev->pdev))
|
||||
vga_switcheroo_register_client(adev->pdev,
|
||||
&amdgpu_switcheroo_ops, runtime);
|
||||
if (runtime)
|
||||
vga_switcheroo_init_domain_pm_ops(adev->dev, &adev->vga_pm_domain);
|
||||
|
||||
@ -1799,14 +1965,16 @@ int amdgpu_device_init(struct amdgpu_device *adev,
|
||||
DRM_INFO("GPU post is not needed\n");
|
||||
}
|
||||
|
||||
/* Initialize clocks */
|
||||
r = amdgpu_atombios_get_clock_info(adev);
|
||||
if (r) {
|
||||
dev_err(adev->dev, "amdgpu_atombios_get_clock_info failed\n");
|
||||
goto failed;
|
||||
if (!adev->is_atom_fw) {
|
||||
/* Initialize clocks */
|
||||
r = amdgpu_atombios_get_clock_info(adev);
|
||||
if (r) {
|
||||
dev_err(adev->dev, "amdgpu_atombios_get_clock_info failed\n");
|
||||
return r;
|
||||
}
|
||||
/* init i2c buses */
|
||||
amdgpu_atombios_i2c_init(adev);
|
||||
}
|
||||
/* init i2c buses */
|
||||
amdgpu_atombios_i2c_init(adev);
|
||||
|
||||
/* Fence driver */
|
||||
r = amdgpu_fence_driver_init(adev);
|
||||
@ -1835,8 +2003,6 @@ int amdgpu_device_init(struct amdgpu_device *adev,
|
||||
/* Get a log2 for easy divisions. */
|
||||
adev->mm_stats.log2_max_MBps = ilog2(max(1u, max_MBps));
|
||||
|
||||
amdgpu_fbdev_init(adev);
|
||||
|
||||
r = amdgpu_ib_pool_init(adev);
|
||||
if (r) {
|
||||
dev_err(adev->dev, "IB initialization failed (%d).\n", r);
|
||||
@ -1847,21 +2013,19 @@ int amdgpu_device_init(struct amdgpu_device *adev,
|
||||
if (r)
|
||||
DRM_ERROR("ib ring test failed (%d).\n", r);
|
||||
|
||||
amdgpu_fbdev_init(adev);
|
||||
|
||||
r = amdgpu_gem_debugfs_init(adev);
|
||||
if (r) {
|
||||
if (r)
|
||||
DRM_ERROR("registering gem debugfs failed (%d).\n", r);
|
||||
}
|
||||
|
||||
r = amdgpu_debugfs_regs_init(adev);
|
||||
if (r) {
|
||||
if (r)
|
||||
DRM_ERROR("registering register debugfs failed (%d).\n", r);
|
||||
}
|
||||
|
||||
r = amdgpu_debugfs_firmware_init(adev);
|
||||
if (r) {
|
||||
if (r)
|
||||
DRM_ERROR("registering firmware debugfs failed (%d).\n", r);
|
||||
return r;
|
||||
}
|
||||
|
||||
if ((amdgpu_testing & 1)) {
|
||||
if (adev->accel_working)
|
||||
@ -1869,12 +2033,6 @@ int amdgpu_device_init(struct amdgpu_device *adev,
|
||||
else
|
||||
DRM_INFO("amdgpu: acceleration disabled, skipping move tests\n");
|
||||
}
|
||||
if ((amdgpu_testing & 2)) {
|
||||
if (adev->accel_working)
|
||||
amdgpu_test_syncing(adev);
|
||||
else
|
||||
DRM_INFO("amdgpu: acceleration disabled, skipping sync tests\n");
|
||||
}
|
||||
if (amdgpu_benchmarking) {
|
||||
if (adev->accel_working)
|
||||
amdgpu_benchmark(adev, amdgpu_benchmarking);
|
||||
@ -1926,7 +2084,8 @@ void amdgpu_device_fini(struct amdgpu_device *adev)
|
||||
amdgpu_atombios_fini(adev);
|
||||
kfree(adev->bios);
|
||||
adev->bios = NULL;
|
||||
vga_switcheroo_unregister_client(adev->pdev);
|
||||
if (!pci_is_thunderbolt_attached(adev->pdev))
|
||||
vga_switcheroo_unregister_client(adev->pdev);
|
||||
if (adev->flags & AMD_IS_PX)
|
||||
vga_switcheroo_fini_domain_pm_ops(adev->dev);
|
||||
vga_client_register(adev->pdev, NULL, NULL, NULL);
|
||||
@ -2020,7 +2179,10 @@ int amdgpu_device_suspend(struct drm_device *dev, bool suspend, bool fbcon)
|
||||
*/
|
||||
amdgpu_bo_evict_vram(adev);
|
||||
|
||||
amdgpu_atombios_scratch_regs_save(adev);
|
||||
if (adev->is_atom_fw)
|
||||
amdgpu_atomfirmware_scratch_regs_save(adev);
|
||||
else
|
||||
amdgpu_atombios_scratch_regs_save(adev);
|
||||
pci_save_state(dev->pdev);
|
||||
if (suspend) {
|
||||
/* Shut down the device */
|
||||
@ -2072,7 +2234,10 @@ int amdgpu_device_resume(struct drm_device *dev, bool resume, bool fbcon)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
amdgpu_atombios_scratch_regs_restore(adev);
|
||||
if (adev->is_atom_fw)
|
||||
amdgpu_atomfirmware_scratch_regs_restore(adev);
|
||||
else
|
||||
amdgpu_atombios_scratch_regs_restore(adev);
|
||||
|
||||
/* post card */
|
||||
if (amdgpu_need_post(adev)) {
|
||||
@ -2082,9 +2247,10 @@ int amdgpu_device_resume(struct drm_device *dev, bool resume, bool fbcon)
|
||||
}
|
||||
|
||||
r = amdgpu_resume(adev);
|
||||
if (r)
|
||||
if (r) {
|
||||
DRM_ERROR("amdgpu_resume failed (%d).\n", r);
|
||||
|
||||
return r;
|
||||
}
|
||||
amdgpu_fence_driver_resume(adev);
|
||||
|
||||
if (resume) {
|
||||
@ -2285,6 +2451,117 @@ err:
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_sriov_gpu_reset - reset the asic
|
||||
*
|
||||
* @adev: amdgpu device pointer
|
||||
* @voluntary: if this reset is requested by guest.
|
||||
* (true means by guest and false means by HYPERVISOR )
|
||||
*
|
||||
* Attempt the reset the GPU if it has hung (all asics).
|
||||
* for SRIOV case.
|
||||
* Returns 0 for success or an error on failure.
|
||||
*/
|
||||
int amdgpu_sriov_gpu_reset(struct amdgpu_device *adev, bool voluntary)
|
||||
{
|
||||
int i, r = 0;
|
||||
int resched;
|
||||
struct amdgpu_bo *bo, *tmp;
|
||||
struct amdgpu_ring *ring;
|
||||
struct dma_fence *fence = NULL, *next = NULL;
|
||||
|
||||
mutex_lock(&adev->virt.lock_reset);
|
||||
atomic_inc(&adev->gpu_reset_counter);
|
||||
adev->gfx.in_reset = true;
|
||||
|
||||
/* block TTM */
|
||||
resched = ttm_bo_lock_delayed_workqueue(&adev->mman.bdev);
|
||||
|
||||
/* block scheduler */
|
||||
for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
|
||||
ring = adev->rings[i];
|
||||
|
||||
if (!ring || !ring->sched.thread)
|
||||
continue;
|
||||
|
||||
kthread_park(ring->sched.thread);
|
||||
amd_sched_hw_job_reset(&ring->sched);
|
||||
}
|
||||
|
||||
/* after all hw jobs are reset, hw fence is meaningless, so force_completion */
|
||||
amdgpu_fence_driver_force_completion(adev);
|
||||
|
||||
/* request to take full control of GPU before re-initialization */
|
||||
if (voluntary)
|
||||
amdgpu_virt_reset_gpu(adev);
|
||||
else
|
||||
amdgpu_virt_request_full_gpu(adev, true);
|
||||
|
||||
|
||||
/* Resume IP prior to SMC */
|
||||
amdgpu_sriov_reinit_early(adev);
|
||||
|
||||
/* we need recover gart prior to run SMC/CP/SDMA resume */
|
||||
amdgpu_ttm_recover_gart(adev);
|
||||
|
||||
/* now we are okay to resume SMC/CP/SDMA */
|
||||
amdgpu_sriov_reinit_late(adev);
|
||||
|
||||
amdgpu_irq_gpu_reset_resume_helper(adev);
|
||||
|
||||
if (amdgpu_ib_ring_tests(adev))
|
||||
dev_err(adev->dev, "[GPU_RESET] ib ring test failed (%d).\n", r);
|
||||
|
||||
/* release full control of GPU after ib test */
|
||||
amdgpu_virt_release_full_gpu(adev, true);
|
||||
|
||||
DRM_INFO("recover vram bo from shadow\n");
|
||||
|
||||
ring = adev->mman.buffer_funcs_ring;
|
||||
mutex_lock(&adev->shadow_list_lock);
|
||||
list_for_each_entry_safe(bo, tmp, &adev->shadow_list, shadow_list) {
|
||||
amdgpu_recover_vram_from_shadow(adev, ring, bo, &next);
|
||||
if (fence) {
|
||||
r = dma_fence_wait(fence, false);
|
||||
if (r) {
|
||||
WARN(r, "recovery from shadow isn't completed\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dma_fence_put(fence);
|
||||
fence = next;
|
||||
}
|
||||
mutex_unlock(&adev->shadow_list_lock);
|
||||
|
||||
if (fence) {
|
||||
r = dma_fence_wait(fence, false);
|
||||
if (r)
|
||||
WARN(r, "recovery from shadow isn't completed\n");
|
||||
}
|
||||
dma_fence_put(fence);
|
||||
|
||||
for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
|
||||
struct amdgpu_ring *ring = adev->rings[i];
|
||||
if (!ring || !ring->sched.thread)
|
||||
continue;
|
||||
|
||||
amd_sched_job_recovery(&ring->sched);
|
||||
kthread_unpark(ring->sched.thread);
|
||||
}
|
||||
|
||||
drm_helper_resume_force_mode(adev->ddev);
|
||||
ttm_bo_unlock_delayed_workqueue(&adev->mman.bdev, resched);
|
||||
if (r) {
|
||||
/* bad news, how to tell it to userspace ? */
|
||||
dev_info(adev->dev, "GPU reset failed\n");
|
||||
}
|
||||
|
||||
adev->gfx.in_reset = false;
|
||||
mutex_unlock(&adev->virt.lock_reset);
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_gpu_reset - reset the asic
|
||||
*
|
||||
@ -2300,7 +2577,7 @@ int amdgpu_gpu_reset(struct amdgpu_device *adev)
|
||||
bool need_full_reset;
|
||||
|
||||
if (amdgpu_sriov_vf(adev))
|
||||
return 0;
|
||||
return amdgpu_sriov_gpu_reset(adev, true);
|
||||
|
||||
if (!amdgpu_check_soft_reset(adev)) {
|
||||
DRM_INFO("No hardware hang detected. Did some blocks stall?\n");
|
||||
@ -2346,9 +2623,15 @@ retry:
|
||||
amdgpu_display_stop_mc_access(adev, &save);
|
||||
amdgpu_wait_for_idle(adev, AMD_IP_BLOCK_TYPE_GMC);
|
||||
}
|
||||
amdgpu_atombios_scratch_regs_save(adev);
|
||||
if (adev->is_atom_fw)
|
||||
amdgpu_atomfirmware_scratch_regs_save(adev);
|
||||
else
|
||||
amdgpu_atombios_scratch_regs_save(adev);
|
||||
r = amdgpu_asic_reset(adev);
|
||||
amdgpu_atombios_scratch_regs_restore(adev);
|
||||
if (adev->is_atom_fw)
|
||||
amdgpu_atomfirmware_scratch_regs_restore(adev);
|
||||
else
|
||||
amdgpu_atombios_scratch_regs_restore(adev);
|
||||
/* post card */
|
||||
amdgpu_atom_asic_init(adev->mode_info.atom_context);
|
||||
|
||||
@ -2387,7 +2670,7 @@ retry:
|
||||
if (fence) {
|
||||
r = dma_fence_wait(fence, false);
|
||||
if (r) {
|
||||
WARN(r, "recovery from shadow isn't comleted\n");
|
||||
WARN(r, "recovery from shadow isn't completed\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -2399,7 +2682,7 @@ retry:
|
||||
if (fence) {
|
||||
r = dma_fence_wait(fence, false);
|
||||
if (r)
|
||||
WARN(r, "recovery from shadow isn't comleted\n");
|
||||
WARN(r, "recovery from shadow isn't completed\n");
|
||||
}
|
||||
dma_fence_put(fence);
|
||||
}
|
||||
@ -2954,24 +3237,42 @@ static ssize_t amdgpu_debugfs_sensor_read(struct file *f, char __user *buf,
|
||||
size_t size, loff_t *pos)
|
||||
{
|
||||
struct amdgpu_device *adev = file_inode(f)->i_private;
|
||||
int idx, r;
|
||||
int32_t value;
|
||||
int idx, x, outsize, r, valuesize;
|
||||
uint32_t values[16];
|
||||
|
||||
if (size != 4 || *pos & 0x3)
|
||||
if (size & 3 || *pos & 0x3)
|
||||
return -EINVAL;
|
||||
|
||||
if (amdgpu_dpm == 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* convert offset to sensor number */
|
||||
idx = *pos >> 2;
|
||||
|
||||
valuesize = sizeof(values);
|
||||
if (adev->powerplay.pp_funcs && adev->powerplay.pp_funcs->read_sensor)
|
||||
r = adev->powerplay.pp_funcs->read_sensor(adev->powerplay.pp_handle, idx, &value);
|
||||
r = adev->powerplay.pp_funcs->read_sensor(adev->powerplay.pp_handle, idx, &values[0], &valuesize);
|
||||
else if (adev->pm.funcs && adev->pm.funcs->read_sensor)
|
||||
r = adev->pm.funcs->read_sensor(adev, idx, &values[0],
|
||||
&valuesize);
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
if (!r)
|
||||
r = put_user(value, (int32_t *)buf);
|
||||
if (size > valuesize)
|
||||
return -EINVAL;
|
||||
|
||||
return !r ? 4 : r;
|
||||
outsize = 0;
|
||||
x = 0;
|
||||
if (!r) {
|
||||
while (size) {
|
||||
r = put_user(values[x++], (int32_t *)buf);
|
||||
buf += 4;
|
||||
size -= 4;
|
||||
outsize += 4;
|
||||
}
|
||||
}
|
||||
|
||||
return !r ? outsize : r;
|
||||
}
|
||||
|
||||
static ssize_t amdgpu_debugfs_wave_read(struct file *f, char __user *buf,
|
||||
|
@ -311,7 +311,8 @@ int amdgpu_crtc_page_flip_target(struct drm_crtc *crtc,
|
||||
struct drm_framebuffer *fb,
|
||||
struct drm_pending_vblank_event *event,
|
||||
uint32_t page_flip_flags,
|
||||
uint32_t target)
|
||||
uint32_t target,
|
||||
struct drm_modeset_acquire_ctx *ctx)
|
||||
{
|
||||
struct amdgpu_bo *new_abo;
|
||||
struct amdgpu_flip_work *work;
|
||||
@ -332,7 +333,8 @@ int amdgpu_crtc_page_flip_target(struct drm_crtc *crtc,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int amdgpu_crtc_set_config(struct drm_mode_set *set)
|
||||
int amdgpu_crtc_set_config(struct drm_mode_set *set,
|
||||
struct drm_modeset_acquire_ctx *ctx)
|
||||
{
|
||||
struct drm_device *dev;
|
||||
struct amdgpu_device *adev;
|
||||
@ -349,7 +351,7 @@ int amdgpu_crtc_set_config(struct drm_mode_set *set)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = drm_crtc_helper_set_config(set);
|
||||
ret = drm_crtc_helper_set_config(set, ctx);
|
||||
|
||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
|
||||
if (crtc->enabled)
|
||||
@ -612,6 +614,12 @@ amdgpu_user_framebuffer_create(struct drm_device *dev,
|
||||
return ERR_PTR(-ENOENT);
|
||||
}
|
||||
|
||||
/* Handle is imported dma-buf, so cannot be migrated to VRAM for scanout */
|
||||
if (obj->import_attach) {
|
||||
DRM_DEBUG_KMS("Cannot create framebuffer from imported dma_buf\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
amdgpu_fb = kzalloc(sizeof(*amdgpu_fb), GFP_KERNEL);
|
||||
if (amdgpu_fb == NULL) {
|
||||
drm_gem_object_unreference_unlocked(obj);
|
||||
|
@ -31,86 +31,88 @@
|
||||
|
||||
void amdgpu_dpm_print_class_info(u32 class, u32 class2)
|
||||
{
|
||||
printk("\tui class: ");
|
||||
const char *s;
|
||||
|
||||
switch (class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) {
|
||||
case ATOM_PPLIB_CLASSIFICATION_UI_NONE:
|
||||
default:
|
||||
printk("none\n");
|
||||
s = "none";
|
||||
break;
|
||||
case ATOM_PPLIB_CLASSIFICATION_UI_BATTERY:
|
||||
printk("battery\n");
|
||||
s = "battery";
|
||||
break;
|
||||
case ATOM_PPLIB_CLASSIFICATION_UI_BALANCED:
|
||||
printk("balanced\n");
|
||||
s = "balanced";
|
||||
break;
|
||||
case ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE:
|
||||
printk("performance\n");
|
||||
s = "performance";
|
||||
break;
|
||||
}
|
||||
printk("\tinternal class: ");
|
||||
printk("\tui class: %s\n", s);
|
||||
printk("\tinternal class:");
|
||||
if (((class & ~ATOM_PPLIB_CLASSIFICATION_UI_MASK) == 0) &&
|
||||
(class2 == 0))
|
||||
printk("none");
|
||||
pr_cont(" none");
|
||||
else {
|
||||
if (class & ATOM_PPLIB_CLASSIFICATION_BOOT)
|
||||
printk("boot ");
|
||||
pr_cont(" boot");
|
||||
if (class & ATOM_PPLIB_CLASSIFICATION_THERMAL)
|
||||
printk("thermal ");
|
||||
pr_cont(" thermal");
|
||||
if (class & ATOM_PPLIB_CLASSIFICATION_LIMITEDPOWERSOURCE)
|
||||
printk("limited_pwr ");
|
||||
pr_cont(" limited_pwr");
|
||||
if (class & ATOM_PPLIB_CLASSIFICATION_REST)
|
||||
printk("rest ");
|
||||
pr_cont(" rest");
|
||||
if (class & ATOM_PPLIB_CLASSIFICATION_FORCED)
|
||||
printk("forced ");
|
||||
pr_cont(" forced");
|
||||
if (class & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE)
|
||||
printk("3d_perf ");
|
||||
pr_cont(" 3d_perf");
|
||||
if (class & ATOM_PPLIB_CLASSIFICATION_OVERDRIVETEMPLATE)
|
||||
printk("ovrdrv ");
|
||||
pr_cont(" ovrdrv");
|
||||
if (class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
|
||||
printk("uvd ");
|
||||
pr_cont(" uvd");
|
||||
if (class & ATOM_PPLIB_CLASSIFICATION_3DLOW)
|
||||
printk("3d_low ");
|
||||
pr_cont(" 3d_low");
|
||||
if (class & ATOM_PPLIB_CLASSIFICATION_ACPI)
|
||||
printk("acpi ");
|
||||
pr_cont(" acpi");
|
||||
if (class & ATOM_PPLIB_CLASSIFICATION_HD2STATE)
|
||||
printk("uvd_hd2 ");
|
||||
pr_cont(" uvd_hd2");
|
||||
if (class & ATOM_PPLIB_CLASSIFICATION_HDSTATE)
|
||||
printk("uvd_hd ");
|
||||
pr_cont(" uvd_hd");
|
||||
if (class & ATOM_PPLIB_CLASSIFICATION_SDSTATE)
|
||||
printk("uvd_sd ");
|
||||
pr_cont(" uvd_sd");
|
||||
if (class2 & ATOM_PPLIB_CLASSIFICATION2_LIMITEDPOWERSOURCE_2)
|
||||
printk("limited_pwr2 ");
|
||||
pr_cont(" limited_pwr2");
|
||||
if (class2 & ATOM_PPLIB_CLASSIFICATION2_ULV)
|
||||
printk("ulv ");
|
||||
pr_cont(" ulv");
|
||||
if (class2 & ATOM_PPLIB_CLASSIFICATION2_MVC)
|
||||
printk("uvd_mvc ");
|
||||
pr_cont(" uvd_mvc");
|
||||
}
|
||||
printk("\n");
|
||||
pr_cont("\n");
|
||||
}
|
||||
|
||||
void amdgpu_dpm_print_cap_info(u32 caps)
|
||||
{
|
||||
printk("\tcaps: ");
|
||||
printk("\tcaps:");
|
||||
if (caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY)
|
||||
printk("single_disp ");
|
||||
pr_cont(" single_disp");
|
||||
if (caps & ATOM_PPLIB_SUPPORTS_VIDEO_PLAYBACK)
|
||||
printk("video ");
|
||||
pr_cont(" video");
|
||||
if (caps & ATOM_PPLIB_DISALLOW_ON_DC)
|
||||
printk("no_dc ");
|
||||
printk("\n");
|
||||
pr_cont(" no_dc");
|
||||
pr_cont("\n");
|
||||
}
|
||||
|
||||
void amdgpu_dpm_print_ps_status(struct amdgpu_device *adev,
|
||||
struct amdgpu_ps *rps)
|
||||
{
|
||||
printk("\tstatus: ");
|
||||
printk("\tstatus:");
|
||||
if (rps == adev->pm.dpm.current_ps)
|
||||
printk("c ");
|
||||
pr_cont(" c");
|
||||
if (rps == adev->pm.dpm.requested_ps)
|
||||
printk("r ");
|
||||
pr_cont(" r");
|
||||
if (rps == adev->pm.dpm.boot_ps)
|
||||
printk("b ");
|
||||
printk("\n");
|
||||
pr_cont(" b");
|
||||
pr_cont("\n");
|
||||
}
|
||||
|
||||
|
||||
|
@ -270,8 +270,18 @@ struct amdgpu_dpm_funcs {
|
||||
struct amdgpu_ps *cps,
|
||||
struct amdgpu_ps *rps,
|
||||
bool *equal);
|
||||
int (*read_sensor)(struct amdgpu_device *adev, int idx, void *value,
|
||||
int *size);
|
||||
|
||||
struct amd_vce_state* (*get_vce_clock_state)(struct amdgpu_device *adev, unsigned idx);
|
||||
int (*reset_power_profile_state)(struct amdgpu_device *adev,
|
||||
struct amd_pp_profile *request);
|
||||
int (*get_power_profile_state)(struct amdgpu_device *adev,
|
||||
struct amd_pp_profile *query);
|
||||
int (*set_power_profile_state)(struct amdgpu_device *adev,
|
||||
struct amd_pp_profile *request);
|
||||
int (*switch_power_profile)(struct amdgpu_device *adev,
|
||||
enum amd_pp_profile_type type);
|
||||
};
|
||||
|
||||
#define amdgpu_dpm_pre_set_power_state(adev) (adev)->pm.funcs->pre_set_power_state((adev))
|
||||
@ -282,10 +292,10 @@ struct amdgpu_dpm_funcs {
|
||||
#define amdgpu_dpm_vblank_too_short(adev) (adev)->pm.funcs->vblank_too_short((adev))
|
||||
#define amdgpu_dpm_enable_bapm(adev, e) (adev)->pm.funcs->enable_bapm((adev), (e))
|
||||
|
||||
#define amdgpu_dpm_read_sensor(adev, idx, value) \
|
||||
#define amdgpu_dpm_read_sensor(adev, idx, value, size) \
|
||||
((adev)->pp_enabled ? \
|
||||
(adev)->powerplay.pp_funcs->read_sensor(adev->powerplay.pp_handle, (idx), (value)) : \
|
||||
-EINVAL)
|
||||
(adev)->powerplay.pp_funcs->read_sensor(adev->powerplay.pp_handle, (idx), (value), (size)) : \
|
||||
(adev)->pm.funcs->read_sensor((adev), (idx), (value), (size)))
|
||||
|
||||
#define amdgpu_dpm_get_temperature(adev) \
|
||||
((adev)->pp_enabled ? \
|
||||
@ -388,6 +398,22 @@ struct amdgpu_dpm_funcs {
|
||||
(adev)->powerplay.pp_funcs->get_performance_level((adev)->powerplay.pp_handle) : \
|
||||
(adev)->pm.dpm.forced_level)
|
||||
|
||||
#define amdgpu_dpm_reset_power_profile_state(adev, request) \
|
||||
((adev)->powerplay.pp_funcs->reset_power_profile_state(\
|
||||
(adev)->powerplay.pp_handle, request))
|
||||
|
||||
#define amdgpu_dpm_get_power_profile_state(adev, query) \
|
||||
((adev)->powerplay.pp_funcs->get_power_profile_state(\
|
||||
(adev)->powerplay.pp_handle, query))
|
||||
|
||||
#define amdgpu_dpm_set_power_profile_state(adev, request) \
|
||||
((adev)->powerplay.pp_funcs->set_power_profile_state(\
|
||||
(adev)->powerplay.pp_handle, request))
|
||||
|
||||
#define amdgpu_dpm_switch_power_profile(adev, type) \
|
||||
((adev)->powerplay.pp_funcs->switch_power_profile(\
|
||||
(adev)->powerplay.pp_handle, type))
|
||||
|
||||
struct amdgpu_dpm {
|
||||
struct amdgpu_ps *ps;
|
||||
/* number of valid power states */
|
||||
|
@ -60,9 +60,12 @@
|
||||
* - 3.8.0 - Add support raster config init in the kernel
|
||||
* - 3.9.0 - Add support for memory query info about VRAM and GTT.
|
||||
* - 3.10.0 - Add support for new fences ioctl, new gem ioctl flags
|
||||
* - 3.11.0 - Add support for sensor query info (clocks, temp, etc).
|
||||
* - 3.12.0 - Add query for double offchip LDS buffers
|
||||
* - 3.13.0 - Add PRT support
|
||||
*/
|
||||
#define KMS_DRIVER_MAJOR 3
|
||||
#define KMS_DRIVER_MINOR 10
|
||||
#define KMS_DRIVER_MINOR 13
|
||||
#define KMS_DRIVER_PATCHLEVEL 0
|
||||
|
||||
int amdgpu_vram_limit = 0;
|
||||
@ -77,13 +80,13 @@ int amdgpu_pcie_gen2 = -1;
|
||||
int amdgpu_msi = -1;
|
||||
int amdgpu_lockup_timeout = 0;
|
||||
int amdgpu_dpm = -1;
|
||||
int amdgpu_smc_load_fw = 1;
|
||||
int amdgpu_fw_load_type = -1;
|
||||
int amdgpu_aspm = -1;
|
||||
int amdgpu_runtime_pm = -1;
|
||||
unsigned amdgpu_ip_block_mask = 0xffffffff;
|
||||
int amdgpu_bapm = -1;
|
||||
int amdgpu_deep_color = 0;
|
||||
int amdgpu_vm_size = 64;
|
||||
int amdgpu_vm_size = -1;
|
||||
int amdgpu_vm_block_size = -1;
|
||||
int amdgpu_vm_fault_stop = 0;
|
||||
int amdgpu_vm_debug = 0;
|
||||
@ -100,6 +103,11 @@ unsigned amdgpu_pg_mask = 0xffffffff;
|
||||
char *amdgpu_disable_cu = NULL;
|
||||
char *amdgpu_virtual_display = NULL;
|
||||
unsigned amdgpu_pp_feature_mask = 0xffffffff;
|
||||
int amdgpu_ngg = 0;
|
||||
int amdgpu_prim_buf_per_se = 0;
|
||||
int amdgpu_pos_buf_per_se = 0;
|
||||
int amdgpu_cntl_sb_buf_per_se = 0;
|
||||
int amdgpu_param_buf_per_se = 0;
|
||||
|
||||
MODULE_PARM_DESC(vramlimit, "Restrict VRAM for testing, in megabytes");
|
||||
module_param_named(vramlimit, amdgpu_vram_limit, int, 0600);
|
||||
@ -137,8 +145,8 @@ module_param_named(lockup_timeout, amdgpu_lockup_timeout, int, 0444);
|
||||
MODULE_PARM_DESC(dpm, "DPM support (1 = enable, 0 = disable, -1 = auto)");
|
||||
module_param_named(dpm, amdgpu_dpm, int, 0444);
|
||||
|
||||
MODULE_PARM_DESC(smc_load_fw, "SMC firmware loading(1 = enable, 0 = disable)");
|
||||
module_param_named(smc_load_fw, amdgpu_smc_load_fw, int, 0444);
|
||||
MODULE_PARM_DESC(fw_load_type, "firmware loading type (0 = direct, 1 = SMU, 2 = PSP, -1 = auto)");
|
||||
module_param_named(fw_load_type, amdgpu_fw_load_type, int, 0444);
|
||||
|
||||
MODULE_PARM_DESC(aspm, "ASPM support (1 = enable, 0 = disable, -1 = auto)");
|
||||
module_param_named(aspm, amdgpu_aspm, int, 0444);
|
||||
@ -207,6 +215,22 @@ MODULE_PARM_DESC(virtual_display,
|
||||
"Enable virtual display feature (the virtual_display will be set like xxxx:xx:xx.x,x;xxxx:xx:xx.x,x)");
|
||||
module_param_named(virtual_display, amdgpu_virtual_display, charp, 0444);
|
||||
|
||||
MODULE_PARM_DESC(ngg, "Next Generation Graphics (1 = enable, 0 = disable(default depending on gfx))");
|
||||
module_param_named(ngg, amdgpu_ngg, int, 0444);
|
||||
|
||||
MODULE_PARM_DESC(prim_buf_per_se, "the size of Primitive Buffer per Shader Engine (default depending on gfx)");
|
||||
module_param_named(prim_buf_per_se, amdgpu_prim_buf_per_se, int, 0444);
|
||||
|
||||
MODULE_PARM_DESC(pos_buf_per_se, "the size of Position Buffer per Shader Engine (default depending on gfx)");
|
||||
module_param_named(pos_buf_per_se, amdgpu_pos_buf_per_se, int, 0444);
|
||||
|
||||
MODULE_PARM_DESC(cntl_sb_buf_per_se, "the size of Control Sideband per Shader Engine (default depending on gfx)");
|
||||
module_param_named(cntl_sb_buf_per_se, amdgpu_cntl_sb_buf_per_se, int, 0444);
|
||||
|
||||
MODULE_PARM_DESC(param_buf_per_se, "the size of Off-Chip Pramater Cache per Shader Engine (default depending on gfx)");
|
||||
module_param_named(param_buf_per_se, amdgpu_param_buf_per_se, int, 0444);
|
||||
|
||||
|
||||
static const struct pci_device_id pciidlist[] = {
|
||||
#ifdef CONFIG_DRM_AMDGPU_SI
|
||||
{0x1002, 0x6780, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI},
|
||||
@ -409,6 +433,7 @@ static const struct pci_device_id pciidlist[] = {
|
||||
{0x1002, 0x67C2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS10},
|
||||
{0x1002, 0x67C4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS10},
|
||||
{0x1002, 0x67C7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS10},
|
||||
{0x1002, 0x67D0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS10},
|
||||
{0x1002, 0x67DF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS10},
|
||||
{0x1002, 0x67C8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS10},
|
||||
{0x1002, 0x67C9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS10},
|
||||
@ -423,7 +448,14 @@ static const struct pci_device_id pciidlist[] = {
|
||||
{0x1002, 0x6987, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12},
|
||||
{0x1002, 0x6995, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12},
|
||||
{0x1002, 0x699F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12},
|
||||
|
||||
/* Vega 10 */
|
||||
{0x1002, 0x6860, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VEGA10|AMD_EXP_HW_SUPPORT},
|
||||
{0x1002, 0x6861, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VEGA10|AMD_EXP_HW_SUPPORT},
|
||||
{0x1002, 0x6862, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VEGA10|AMD_EXP_HW_SUPPORT},
|
||||
{0x1002, 0x6863, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VEGA10|AMD_EXP_HW_SUPPORT},
|
||||
{0x1002, 0x6867, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VEGA10|AMD_EXP_HW_SUPPORT},
|
||||
{0x1002, 0x686c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VEGA10|AMD_EXP_HW_SUPPORT},
|
||||
{0x1002, 0x687f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VEGA10|AMD_EXP_HW_SUPPORT},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
@ -686,7 +718,6 @@ static struct drm_driver kms_driver = {
|
||||
DRIVER_PRIME | DRIVER_RENDER | DRIVER_MODESET,
|
||||
.load = amdgpu_driver_load_kms,
|
||||
.open = amdgpu_driver_open_kms,
|
||||
.preclose = amdgpu_driver_preclose_kms,
|
||||
.postclose = amdgpu_driver_postclose_kms,
|
||||
.lastclose = amdgpu_driver_lastclose_kms,
|
||||
.set_busid = drm_pci_set_busid,
|
||||
|
@ -147,11 +147,11 @@ static int amdgpufb_create_pinned_object(struct amdgpu_fbdev *rfbdev,
|
||||
ret = amdgpu_gem_object_create(adev, aligned_size, 0,
|
||||
AMDGPU_GEM_DOMAIN_VRAM,
|
||||
AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED |
|
||||
AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS,
|
||||
AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS |
|
||||
AMDGPU_GEM_CREATE_VRAM_CLEARED,
|
||||
true, &gobj);
|
||||
if (ret) {
|
||||
printk(KERN_ERR "failed to allocate framebuffer (%d)\n",
|
||||
aligned_size);
|
||||
pr_err("failed to allocate framebuffer (%d)\n", aligned_size);
|
||||
return -ENOMEM;
|
||||
}
|
||||
abo = gem_to_amdgpu_bo(gobj);
|
||||
@ -224,7 +224,7 @@ static int amdgpufb_create(struct drm_fb_helper *helper,
|
||||
info = drm_fb_helper_alloc_fbi(helper);
|
||||
if (IS_ERR(info)) {
|
||||
ret = PTR_ERR(info);
|
||||
goto out_unref;
|
||||
goto out;
|
||||
}
|
||||
|
||||
info->par = rfbdev;
|
||||
@ -233,7 +233,7 @@ static int amdgpufb_create(struct drm_fb_helper *helper,
|
||||
ret = amdgpu_framebuffer_init(adev->ddev, &rfbdev->rfb, &mode_cmd, gobj);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to initialize framebuffer %d\n", ret);
|
||||
goto out_destroy_fbi;
|
||||
goto out;
|
||||
}
|
||||
|
||||
fb = &rfbdev->rfb.base;
|
||||
@ -241,8 +241,6 @@ static int amdgpufb_create(struct drm_fb_helper *helper,
|
||||
/* setup helper */
|
||||
rfbdev->helper.fb = fb;
|
||||
|
||||
memset_io(abo->kptr, 0x0, amdgpu_bo_size(abo));
|
||||
|
||||
strcpy(info->fix.id, "amdgpudrmfb");
|
||||
|
||||
drm_fb_helper_fill_fix(info, fb->pitches[0], fb->format->depth);
|
||||
@ -266,7 +264,7 @@ static int amdgpufb_create(struct drm_fb_helper *helper,
|
||||
|
||||
if (info->screen_base == NULL) {
|
||||
ret = -ENOSPC;
|
||||
goto out_destroy_fbi;
|
||||
goto out;
|
||||
}
|
||||
|
||||
DRM_INFO("fb mappable at 0x%lX\n", info->fix.smem_start);
|
||||
@ -278,9 +276,7 @@ static int amdgpufb_create(struct drm_fb_helper *helper,
|
||||
vga_switcheroo_client_fb_set(adev->ddev->pdev, info);
|
||||
return 0;
|
||||
|
||||
out_destroy_fbi:
|
||||
drm_fb_helper_release_fbi(helper);
|
||||
out_unref:
|
||||
out:
|
||||
if (abo) {
|
||||
|
||||
}
|
||||
@ -304,7 +300,6 @@ static int amdgpu_fbdev_destroy(struct drm_device *dev, struct amdgpu_fbdev *rfb
|
||||
struct amdgpu_framebuffer *rfb = &rfbdev->rfb;
|
||||
|
||||
drm_fb_helper_unregister_fbi(&rfbdev->helper);
|
||||
drm_fb_helper_release_fbi(&rfbdev->helper);
|
||||
|
||||
if (rfb->obj) {
|
||||
amdgpufb_destroy_pinned_object(rfb->obj);
|
||||
|
@ -229,7 +229,8 @@ void amdgpu_gart_unbind(struct amdgpu_device *adev, uint64_t offset,
|
||||
unsigned p;
|
||||
int i, j;
|
||||
u64 page_base;
|
||||
uint32_t flags = AMDGPU_PTE_SYSTEM;
|
||||
/* Starting from VEGA10, system bit must be 0 to mean invalid. */
|
||||
uint64_t flags = 0;
|
||||
|
||||
if (!adev->gart.ready) {
|
||||
WARN(1, "trying to unbind memory from uninitialized GART !\n");
|
||||
@ -271,7 +272,7 @@ void amdgpu_gart_unbind(struct amdgpu_device *adev, uint64_t offset,
|
||||
*/
|
||||
int amdgpu_gart_bind(struct amdgpu_device *adev, uint64_t offset,
|
||||
int pages, struct page **pagelist, dma_addr_t *dma_addr,
|
||||
uint32_t flags)
|
||||
uint64_t flags)
|
||||
{
|
||||
unsigned t;
|
||||
unsigned p;
|
||||
|
@ -152,6 +152,7 @@ void amdgpu_gem_object_close(struct drm_gem_object *obj,
|
||||
struct ttm_validate_buffer tv;
|
||||
struct ww_acquire_ctx ticket;
|
||||
struct amdgpu_bo_va *bo_va;
|
||||
struct dma_fence *fence = NULL;
|
||||
int r;
|
||||
|
||||
INIT_LIST_HEAD(&list);
|
||||
@ -173,6 +174,17 @@ void amdgpu_gem_object_close(struct drm_gem_object *obj,
|
||||
if (bo_va) {
|
||||
if (--bo_va->ref_count == 0) {
|
||||
amdgpu_vm_bo_rmv(adev, bo_va);
|
||||
|
||||
r = amdgpu_vm_clear_freed(adev, vm, &fence);
|
||||
if (unlikely(r)) {
|
||||
dev_err(adev->dev, "failed to clear page "
|
||||
"tables on GEM object close (%d)\n", r);
|
||||
}
|
||||
|
||||
if (fence) {
|
||||
amdgpu_bo_fence(bo, fence, true);
|
||||
dma_fence_put(fence);
|
||||
}
|
||||
}
|
||||
}
|
||||
ttm_eu_backoff_reservation(&ticket, &list);
|
||||
@ -507,14 +519,16 @@ static int amdgpu_gem_va_check(void *param, struct amdgpu_bo *bo)
|
||||
* amdgpu_gem_va_update_vm -update the bo_va in its VM
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
* @vm: vm to update
|
||||
* @bo_va: bo_va to update
|
||||
* @list: validation list
|
||||
* @operation: map or unmap
|
||||
* @operation: map, unmap or clear
|
||||
*
|
||||
* Update the bo_va directly after setting its address. Errors are not
|
||||
* vital here, so they are not reported back to userspace.
|
||||
*/
|
||||
static void amdgpu_gem_va_update_vm(struct amdgpu_device *adev,
|
||||
struct amdgpu_vm *vm,
|
||||
struct amdgpu_bo_va *bo_va,
|
||||
struct list_head *list,
|
||||
uint32_t operation)
|
||||
@ -529,20 +543,21 @@ static void amdgpu_gem_va_update_vm(struct amdgpu_device *adev,
|
||||
goto error;
|
||||
}
|
||||
|
||||
r = amdgpu_vm_validate_pt_bos(adev, bo_va->vm, amdgpu_gem_va_check,
|
||||
r = amdgpu_vm_validate_pt_bos(adev, vm, amdgpu_gem_va_check,
|
||||
NULL);
|
||||
if (r)
|
||||
goto error;
|
||||
|
||||
r = amdgpu_vm_update_page_directory(adev, bo_va->vm);
|
||||
r = amdgpu_vm_update_directories(adev, vm);
|
||||
if (r)
|
||||
goto error;
|
||||
|
||||
r = amdgpu_vm_clear_freed(adev, bo_va->vm);
|
||||
r = amdgpu_vm_clear_freed(adev, vm, NULL);
|
||||
if (r)
|
||||
goto error;
|
||||
|
||||
if (operation == AMDGPU_VA_OP_MAP)
|
||||
if (operation == AMDGPU_VA_OP_MAP ||
|
||||
operation == AMDGPU_VA_OP_REPLACE)
|
||||
r = amdgpu_vm_bo_update(adev, bo_va, false);
|
||||
|
||||
error:
|
||||
@ -553,6 +568,12 @@ error:
|
||||
int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *filp)
|
||||
{
|
||||
const uint32_t valid_flags = AMDGPU_VM_DELAY_UPDATE |
|
||||
AMDGPU_VM_PAGE_READABLE | AMDGPU_VM_PAGE_WRITEABLE |
|
||||
AMDGPU_VM_PAGE_EXECUTABLE | AMDGPU_VM_MTYPE_MASK;
|
||||
const uint32_t prt_flags = AMDGPU_VM_DELAY_UPDATE |
|
||||
AMDGPU_VM_PAGE_PRT;
|
||||
|
||||
struct drm_amdgpu_gem_va *args = data;
|
||||
struct drm_gem_object *gobj;
|
||||
struct amdgpu_device *adev = dev->dev_private;
|
||||
@ -563,7 +584,7 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data,
|
||||
struct ttm_validate_buffer tv;
|
||||
struct ww_acquire_ctx ticket;
|
||||
struct list_head list;
|
||||
uint32_t invalid_flags, va_flags = 0;
|
||||
uint64_t va_flags;
|
||||
int r = 0;
|
||||
|
||||
if (!adev->vm_manager.enabled)
|
||||
@ -577,17 +598,17 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
invalid_flags = ~(AMDGPU_VM_DELAY_UPDATE | AMDGPU_VM_PAGE_READABLE |
|
||||
AMDGPU_VM_PAGE_WRITEABLE | AMDGPU_VM_PAGE_EXECUTABLE);
|
||||
if ((args->flags & invalid_flags)) {
|
||||
dev_err(&dev->pdev->dev, "invalid flags 0x%08X vs 0x%08X\n",
|
||||
args->flags, invalid_flags);
|
||||
if ((args->flags & ~valid_flags) && (args->flags & ~prt_flags)) {
|
||||
dev_err(&dev->pdev->dev, "invalid flags combination 0x%08X\n",
|
||||
args->flags);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (args->operation) {
|
||||
case AMDGPU_VA_OP_MAP:
|
||||
case AMDGPU_VA_OP_UNMAP:
|
||||
case AMDGPU_VA_OP_CLEAR:
|
||||
case AMDGPU_VA_OP_REPLACE:
|
||||
break;
|
||||
default:
|
||||
dev_err(&dev->pdev->dev, "unsupported operation %d\n",
|
||||
@ -595,38 +616,47 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
gobj = drm_gem_object_lookup(filp, args->handle);
|
||||
if (gobj == NULL)
|
||||
return -ENOENT;
|
||||
abo = gem_to_amdgpu_bo(gobj);
|
||||
INIT_LIST_HEAD(&list);
|
||||
tv.bo = &abo->tbo;
|
||||
tv.shared = false;
|
||||
list_add(&tv.head, &list);
|
||||
if ((args->operation != AMDGPU_VA_OP_CLEAR) &&
|
||||
!(args->flags & AMDGPU_VM_PAGE_PRT)) {
|
||||
gobj = drm_gem_object_lookup(filp, args->handle);
|
||||
if (gobj == NULL)
|
||||
return -ENOENT;
|
||||
abo = gem_to_amdgpu_bo(gobj);
|
||||
tv.bo = &abo->tbo;
|
||||
tv.shared = false;
|
||||
list_add(&tv.head, &list);
|
||||
} else {
|
||||
gobj = NULL;
|
||||
abo = NULL;
|
||||
}
|
||||
|
||||
amdgpu_vm_get_pd_bo(&fpriv->vm, &list, &vm_pd);
|
||||
|
||||
r = ttm_eu_reserve_buffers(&ticket, &list, true, NULL);
|
||||
if (r) {
|
||||
drm_gem_object_unreference_unlocked(gobj);
|
||||
return r;
|
||||
}
|
||||
if (r)
|
||||
goto error_unref;
|
||||
|
||||
bo_va = amdgpu_vm_bo_find(&fpriv->vm, abo);
|
||||
if (!bo_va) {
|
||||
ttm_eu_backoff_reservation(&ticket, &list);
|
||||
drm_gem_object_unreference_unlocked(gobj);
|
||||
return -ENOENT;
|
||||
if (abo) {
|
||||
bo_va = amdgpu_vm_bo_find(&fpriv->vm, abo);
|
||||
if (!bo_va) {
|
||||
r = -ENOENT;
|
||||
goto error_backoff;
|
||||
}
|
||||
} else if (args->operation != AMDGPU_VA_OP_CLEAR) {
|
||||
bo_va = fpriv->prt_va;
|
||||
} else {
|
||||
bo_va = NULL;
|
||||
}
|
||||
|
||||
switch (args->operation) {
|
||||
case AMDGPU_VA_OP_MAP:
|
||||
if (args->flags & AMDGPU_VM_PAGE_READABLE)
|
||||
va_flags |= AMDGPU_PTE_READABLE;
|
||||
if (args->flags & AMDGPU_VM_PAGE_WRITEABLE)
|
||||
va_flags |= AMDGPU_PTE_WRITEABLE;
|
||||
if (args->flags & AMDGPU_VM_PAGE_EXECUTABLE)
|
||||
va_flags |= AMDGPU_PTE_EXECUTABLE;
|
||||
r = amdgpu_vm_alloc_pts(adev, bo_va->vm, args->va_address,
|
||||
args->map_size);
|
||||
if (r)
|
||||
goto error_backoff;
|
||||
|
||||
va_flags = amdgpu_vm_get_pte_flags(adev, args->flags);
|
||||
r = amdgpu_vm_bo_map(adev, bo_va, args->va_address,
|
||||
args->offset_in_bo, args->map_size,
|
||||
va_flags);
|
||||
@ -634,14 +664,34 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data,
|
||||
case AMDGPU_VA_OP_UNMAP:
|
||||
r = amdgpu_vm_bo_unmap(adev, bo_va, args->va_address);
|
||||
break;
|
||||
|
||||
case AMDGPU_VA_OP_CLEAR:
|
||||
r = amdgpu_vm_bo_clear_mappings(adev, &fpriv->vm,
|
||||
args->va_address,
|
||||
args->map_size);
|
||||
break;
|
||||
case AMDGPU_VA_OP_REPLACE:
|
||||
r = amdgpu_vm_alloc_pts(adev, bo_va->vm, args->va_address,
|
||||
args->map_size);
|
||||
if (r)
|
||||
goto error_backoff;
|
||||
|
||||
va_flags = amdgpu_vm_get_pte_flags(adev, args->flags);
|
||||
r = amdgpu_vm_bo_replace_map(adev, bo_va, args->va_address,
|
||||
args->offset_in_bo, args->map_size,
|
||||
va_flags);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!r && !(args->flags & AMDGPU_VM_DELAY_UPDATE) &&
|
||||
!amdgpu_vm_debug)
|
||||
amdgpu_gem_va_update_vm(adev, bo_va, &list, args->operation);
|
||||
if (!r && !(args->flags & AMDGPU_VM_DELAY_UPDATE) && !amdgpu_vm_debug)
|
||||
amdgpu_gem_va_update_vm(adev, &fpriv->vm, bo_va, &list,
|
||||
args->operation);
|
||||
|
||||
error_backoff:
|
||||
ttm_eu_backoff_reservation(&ticket, &list);
|
||||
|
||||
error_unref:
|
||||
drm_gem_object_unreference_unlocked(gobj);
|
||||
return r;
|
||||
}
|
||||
@ -667,7 +717,7 @@ int amdgpu_gem_op_ioctl(struct drm_device *dev, void *data,
|
||||
switch (args->op) {
|
||||
case AMDGPU_GEM_OP_GET_GEM_CREATE_INFO: {
|
||||
struct drm_amdgpu_gem_create_in info;
|
||||
void __user *out = (void __user *)(long)args->value;
|
||||
void __user *out = (void __user *)(uintptr_t)args->value;
|
||||
|
||||
info.bo_size = robj->gem_base.size;
|
||||
info.alignment = robj->tbo.mem.page_alignment << PAGE_SHIFT;
|
||||
@ -679,6 +729,11 @@ int amdgpu_gem_op_ioctl(struct drm_device *dev, void *data,
|
||||
break;
|
||||
}
|
||||
case AMDGPU_GEM_OP_SET_PLACEMENT:
|
||||
if (robj->prime_shared_count && (args->value & AMDGPU_GEM_DOMAIN_VRAM)) {
|
||||
r = -EINVAL;
|
||||
amdgpu_bo_unreserve(robj);
|
||||
break;
|
||||
}
|
||||
if (amdgpu_ttm_tt_get_usermm(robj->tbo.ttm)) {
|
||||
r = -EPERM;
|
||||
amdgpu_bo_unreserve(robj);
|
||||
|
@ -161,9 +161,6 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs,
|
||||
return r;
|
||||
}
|
||||
|
||||
if (ring->funcs->init_cond_exec)
|
||||
patch_offset = amdgpu_ring_init_cond_exec(ring);
|
||||
|
||||
if (vm) {
|
||||
r = amdgpu_vm_flush(ring, job);
|
||||
if (r) {
|
||||
@ -172,7 +169,14 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs,
|
||||
}
|
||||
}
|
||||
|
||||
if (ring->funcs->emit_hdp_flush)
|
||||
if (ring->funcs->init_cond_exec)
|
||||
patch_offset = amdgpu_ring_init_cond_exec(ring);
|
||||
|
||||
if (ring->funcs->emit_hdp_flush
|
||||
#ifdef CONFIG_X86_64
|
||||
&& !(adev->flags & AMD_IS_APU)
|
||||
#endif
|
||||
)
|
||||
amdgpu_ring_emit_hdp_flush(ring);
|
||||
|
||||
skip_preamble = ring->current_ctx == fence_ctx;
|
||||
@ -202,7 +206,11 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs,
|
||||
need_ctx_switch = false;
|
||||
}
|
||||
|
||||
if (ring->funcs->emit_hdp_invalidate)
|
||||
if (ring->funcs->emit_hdp_invalidate
|
||||
#ifdef CONFIG_X86_64
|
||||
&& !(adev->flags & AMD_IS_APU)
|
||||
#endif
|
||||
)
|
||||
amdgpu_ring_emit_hdp_invalidate(ring);
|
||||
|
||||
r = amdgpu_fence_emit(ring, f);
|
||||
@ -214,6 +222,9 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs,
|
||||
return r;
|
||||
}
|
||||
|
||||
if (ring->funcs->insert_end)
|
||||
ring->funcs->insert_end(ring);
|
||||
|
||||
/* wrap the last IB with fence */
|
||||
if (job && job->uf_addr) {
|
||||
amdgpu_ring_emit_fence(ring, job->uf_addr, job->uf_sequence,
|
||||
|
@ -25,6 +25,48 @@
|
||||
#define __AMDGPU_IH_H__
|
||||
|
||||
struct amdgpu_device;
|
||||
/*
|
||||
* vega10+ IH clients
|
||||
*/
|
||||
enum amdgpu_ih_clientid
|
||||
{
|
||||
AMDGPU_IH_CLIENTID_IH = 0x00,
|
||||
AMDGPU_IH_CLIENTID_ACP = 0x01,
|
||||
AMDGPU_IH_CLIENTID_ATHUB = 0x02,
|
||||
AMDGPU_IH_CLIENTID_BIF = 0x03,
|
||||
AMDGPU_IH_CLIENTID_DCE = 0x04,
|
||||
AMDGPU_IH_CLIENTID_ISP = 0x05,
|
||||
AMDGPU_IH_CLIENTID_PCIE0 = 0x06,
|
||||
AMDGPU_IH_CLIENTID_RLC = 0x07,
|
||||
AMDGPU_IH_CLIENTID_SDMA0 = 0x08,
|
||||
AMDGPU_IH_CLIENTID_SDMA1 = 0x09,
|
||||
AMDGPU_IH_CLIENTID_SE0SH = 0x0a,
|
||||
AMDGPU_IH_CLIENTID_SE1SH = 0x0b,
|
||||
AMDGPU_IH_CLIENTID_SE2SH = 0x0c,
|
||||
AMDGPU_IH_CLIENTID_SE3SH = 0x0d,
|
||||
AMDGPU_IH_CLIENTID_SYSHUB = 0x0e,
|
||||
AMDGPU_IH_CLIENTID_THM = 0x0f,
|
||||
AMDGPU_IH_CLIENTID_UVD = 0x10,
|
||||
AMDGPU_IH_CLIENTID_VCE0 = 0x11,
|
||||
AMDGPU_IH_CLIENTID_VMC = 0x12,
|
||||
AMDGPU_IH_CLIENTID_XDMA = 0x13,
|
||||
AMDGPU_IH_CLIENTID_GRBM_CP = 0x14,
|
||||
AMDGPU_IH_CLIENTID_ATS = 0x15,
|
||||
AMDGPU_IH_CLIENTID_ROM_SMUIO = 0x16,
|
||||
AMDGPU_IH_CLIENTID_DF = 0x17,
|
||||
AMDGPU_IH_CLIENTID_VCE1 = 0x18,
|
||||
AMDGPU_IH_CLIENTID_PWR = 0x19,
|
||||
AMDGPU_IH_CLIENTID_UTCL2 = 0x1b,
|
||||
AMDGPU_IH_CLIENTID_EA = 0x1c,
|
||||
AMDGPU_IH_CLIENTID_UTCL2LOG = 0x1d,
|
||||
AMDGPU_IH_CLIENTID_MP0 = 0x1e,
|
||||
AMDGPU_IH_CLIENTID_MP1 = 0x1f,
|
||||
|
||||
AMDGPU_IH_CLIENTID_MAX
|
||||
|
||||
};
|
||||
|
||||
#define AMDGPU_IH_CLIENTID_LEGACY 0
|
||||
|
||||
/*
|
||||
* R6xx+ IH ring
|
||||
@ -46,12 +88,19 @@ struct amdgpu_ih_ring {
|
||||
dma_addr_t rb_dma_addr; /* only used when use_bus_addr = true */
|
||||
};
|
||||
|
||||
#define AMDGPU_IH_SRC_DATA_MAX_SIZE_DW 4
|
||||
|
||||
struct amdgpu_iv_entry {
|
||||
unsigned client_id;
|
||||
unsigned src_id;
|
||||
unsigned src_data;
|
||||
unsigned ring_id;
|
||||
unsigned vm_id;
|
||||
unsigned vm_id_src;
|
||||
uint64_t timestamp;
|
||||
unsigned timestamp_src;
|
||||
unsigned pas_id;
|
||||
unsigned pasid_src;
|
||||
unsigned src_data[AMDGPU_IH_SRC_DATA_MAX_SIZE_DW];
|
||||
const uint32_t *iv_entry;
|
||||
};
|
||||
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "amdgpu_ih.h"
|
||||
#include "atom.h"
|
||||
#include "amdgpu_connectors.h"
|
||||
#include "amdgpu_trace.h"
|
||||
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
@ -89,23 +90,28 @@ static void amdgpu_irq_reset_work_func(struct work_struct *work)
|
||||
static void amdgpu_irq_disable_all(struct amdgpu_device *adev)
|
||||
{
|
||||
unsigned long irqflags;
|
||||
unsigned i, j;
|
||||
unsigned i, j, k;
|
||||
int r;
|
||||
|
||||
spin_lock_irqsave(&adev->irq.lock, irqflags);
|
||||
for (i = 0; i < AMDGPU_MAX_IRQ_SRC_ID; ++i) {
|
||||
struct amdgpu_irq_src *src = adev->irq.sources[i];
|
||||
|
||||
if (!src || !src->funcs->set || !src->num_types)
|
||||
for (i = 0; i < AMDGPU_IH_CLIENTID_MAX; ++i) {
|
||||
if (!adev->irq.client[i].sources)
|
||||
continue;
|
||||
|
||||
for (j = 0; j < src->num_types; ++j) {
|
||||
atomic_set(&src->enabled_types[j], 0);
|
||||
r = src->funcs->set(adev, src, j,
|
||||
AMDGPU_IRQ_STATE_DISABLE);
|
||||
if (r)
|
||||
DRM_ERROR("error disabling interrupt (%d)\n",
|
||||
r);
|
||||
for (j = 0; j < AMDGPU_MAX_IRQ_SRC_ID; ++j) {
|
||||
struct amdgpu_irq_src *src = adev->irq.client[i].sources[j];
|
||||
|
||||
if (!src || !src->funcs->set || !src->num_types)
|
||||
continue;
|
||||
|
||||
for (k = 0; k < src->num_types; ++k) {
|
||||
atomic_set(&src->enabled_types[k], 0);
|
||||
r = src->funcs->set(adev, src, k,
|
||||
AMDGPU_IRQ_STATE_DISABLE);
|
||||
if (r)
|
||||
DRM_ERROR("error disabling interrupt (%d)\n",
|
||||
r);
|
||||
}
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&adev->irq.lock, irqflags);
|
||||
@ -254,7 +260,7 @@ int amdgpu_irq_init(struct amdgpu_device *adev)
|
||||
*/
|
||||
void amdgpu_irq_fini(struct amdgpu_device *adev)
|
||||
{
|
||||
unsigned i;
|
||||
unsigned i, j;
|
||||
|
||||
drm_vblank_cleanup(adev->ddev);
|
||||
if (adev->irq.installed) {
|
||||
@ -266,19 +272,25 @@ void amdgpu_irq_fini(struct amdgpu_device *adev)
|
||||
cancel_work_sync(&adev->reset_work);
|
||||
}
|
||||
|
||||
for (i = 0; i < AMDGPU_MAX_IRQ_SRC_ID; ++i) {
|
||||
struct amdgpu_irq_src *src = adev->irq.sources[i];
|
||||
|
||||
if (!src)
|
||||
for (i = 0; i < AMDGPU_IH_CLIENTID_MAX; ++i) {
|
||||
if (!adev->irq.client[i].sources)
|
||||
continue;
|
||||
|
||||
kfree(src->enabled_types);
|
||||
src->enabled_types = NULL;
|
||||
if (src->data) {
|
||||
kfree(src->data);
|
||||
kfree(src);
|
||||
adev->irq.sources[i] = NULL;
|
||||
for (j = 0; j < AMDGPU_MAX_IRQ_SRC_ID; ++j) {
|
||||
struct amdgpu_irq_src *src = adev->irq.client[i].sources[j];
|
||||
|
||||
if (!src)
|
||||
continue;
|
||||
|
||||
kfree(src->enabled_types);
|
||||
src->enabled_types = NULL;
|
||||
if (src->data) {
|
||||
kfree(src->data);
|
||||
kfree(src);
|
||||
adev->irq.client[i].sources[j] = NULL;
|
||||
}
|
||||
}
|
||||
kfree(adev->irq.client[i].sources);
|
||||
}
|
||||
}
|
||||
|
||||
@ -290,16 +302,29 @@ void amdgpu_irq_fini(struct amdgpu_device *adev)
|
||||
* @source: irq source
|
||||
*
|
||||
*/
|
||||
int amdgpu_irq_add_id(struct amdgpu_device *adev, unsigned src_id,
|
||||
int amdgpu_irq_add_id(struct amdgpu_device *adev,
|
||||
unsigned client_id, unsigned src_id,
|
||||
struct amdgpu_irq_src *source)
|
||||
{
|
||||
if (client_id >= AMDGPU_IH_CLIENTID_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
if (src_id >= AMDGPU_MAX_IRQ_SRC_ID)
|
||||
return -EINVAL;
|
||||
|
||||
if (adev->irq.sources[src_id] != NULL)
|
||||
if (!source->funcs)
|
||||
return -EINVAL;
|
||||
|
||||
if (!source->funcs)
|
||||
if (!adev->irq.client[client_id].sources) {
|
||||
adev->irq.client[client_id].sources =
|
||||
kcalloc(AMDGPU_MAX_IRQ_SRC_ID,
|
||||
sizeof(struct amdgpu_irq_src *),
|
||||
GFP_KERNEL);
|
||||
if (!adev->irq.client[client_id].sources)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (adev->irq.client[client_id].sources[src_id] != NULL)
|
||||
return -EINVAL;
|
||||
|
||||
if (source->num_types && !source->enabled_types) {
|
||||
@ -313,8 +338,7 @@ int amdgpu_irq_add_id(struct amdgpu_device *adev, unsigned src_id,
|
||||
source->enabled_types = types;
|
||||
}
|
||||
|
||||
adev->irq.sources[src_id] = source;
|
||||
|
||||
adev->irq.client[client_id].sources[src_id] = source;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -329,10 +353,18 @@ int amdgpu_irq_add_id(struct amdgpu_device *adev, unsigned src_id,
|
||||
void amdgpu_irq_dispatch(struct amdgpu_device *adev,
|
||||
struct amdgpu_iv_entry *entry)
|
||||
{
|
||||
unsigned client_id = entry->client_id;
|
||||
unsigned src_id = entry->src_id;
|
||||
struct amdgpu_irq_src *src;
|
||||
int r;
|
||||
|
||||
trace_amdgpu_iv(entry);
|
||||
|
||||
if (client_id >= AMDGPU_IH_CLIENTID_MAX) {
|
||||
DRM_DEBUG("Invalid client_id in IV: %d\n", client_id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (src_id >= AMDGPU_MAX_IRQ_SRC_ID) {
|
||||
DRM_DEBUG("Invalid src_id in IV: %d\n", src_id);
|
||||
return;
|
||||
@ -341,7 +373,13 @@ void amdgpu_irq_dispatch(struct amdgpu_device *adev,
|
||||
if (adev->irq.virq[src_id]) {
|
||||
generic_handle_irq(irq_find_mapping(adev->irq.domain, src_id));
|
||||
} else {
|
||||
src = adev->irq.sources[src_id];
|
||||
if (!adev->irq.client[client_id].sources) {
|
||||
DRM_DEBUG("Unregistered interrupt client_id: %d src_id: %d\n",
|
||||
client_id, src_id);
|
||||
return;
|
||||
}
|
||||
|
||||
src = adev->irq.client[client_id].sources[src_id];
|
||||
if (!src) {
|
||||
DRM_DEBUG("Unhandled interrupt src_id: %d\n", src_id);
|
||||
return;
|
||||
@ -385,13 +423,20 @@ int amdgpu_irq_update(struct amdgpu_device *adev,
|
||||
|
||||
void amdgpu_irq_gpu_reset_resume_helper(struct amdgpu_device *adev)
|
||||
{
|
||||
int i, j;
|
||||
for (i = 0; i < AMDGPU_MAX_IRQ_SRC_ID; i++) {
|
||||
struct amdgpu_irq_src *src = adev->irq.sources[i];
|
||||
if (!src)
|
||||
int i, j, k;
|
||||
|
||||
for (i = 0; i < AMDGPU_IH_CLIENTID_MAX; ++i) {
|
||||
if (!adev->irq.client[i].sources)
|
||||
continue;
|
||||
for (j = 0; j < src->num_types; j++)
|
||||
amdgpu_irq_update(adev, src, j);
|
||||
|
||||
for (j = 0; j < AMDGPU_MAX_IRQ_SRC_ID; ++j) {
|
||||
struct amdgpu_irq_src *src = adev->irq.client[i].sources[j];
|
||||
|
||||
if (!src)
|
||||
continue;
|
||||
for (k = 0; k < src->num_types; k++)
|
||||
amdgpu_irq_update(adev, src, k);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "amdgpu_ih.h"
|
||||
|
||||
#define AMDGPU_MAX_IRQ_SRC_ID 0x100
|
||||
#define AMDGPU_MAX_IRQ_CLIENT_ID 0x100
|
||||
|
||||
struct amdgpu_device;
|
||||
struct amdgpu_iv_entry;
|
||||
@ -44,6 +45,10 @@ struct amdgpu_irq_src {
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct amdgpu_irq_client {
|
||||
struct amdgpu_irq_src **sources;
|
||||
};
|
||||
|
||||
/* provided by interrupt generating IP blocks */
|
||||
struct amdgpu_irq_src_funcs {
|
||||
int (*set)(struct amdgpu_device *adev, struct amdgpu_irq_src *source,
|
||||
@ -58,7 +63,7 @@ struct amdgpu_irq {
|
||||
bool installed;
|
||||
spinlock_t lock;
|
||||
/* interrupt sources */
|
||||
struct amdgpu_irq_src *sources[AMDGPU_MAX_IRQ_SRC_ID];
|
||||
struct amdgpu_irq_client client[AMDGPU_IH_CLIENTID_MAX];
|
||||
|
||||
/* status, etc. */
|
||||
bool msi_enabled; /* msi enabled */
|
||||
@ -80,7 +85,8 @@ irqreturn_t amdgpu_irq_handler(int irq, void *arg);
|
||||
|
||||
int amdgpu_irq_init(struct amdgpu_device *adev);
|
||||
void amdgpu_irq_fini(struct amdgpu_device *adev);
|
||||
int amdgpu_irq_add_id(struct amdgpu_device *adev, unsigned src_id,
|
||||
int amdgpu_irq_add_id(struct amdgpu_device *adev,
|
||||
unsigned client_id, unsigned src_id,
|
||||
struct amdgpu_irq_src *source);
|
||||
void amdgpu_irq_dispatch(struct amdgpu_device *adev,
|
||||
struct amdgpu_iv_entry *entry);
|
||||
|
@ -36,12 +36,6 @@
|
||||
#include <linux/pm_runtime.h>
|
||||
#include "amdgpu_amdkfd.h"
|
||||
|
||||
#if defined(CONFIG_VGA_SWITCHEROO)
|
||||
bool amdgpu_has_atpx(void);
|
||||
#else
|
||||
static inline bool amdgpu_has_atpx(void) { return false; }
|
||||
#endif
|
||||
|
||||
/**
|
||||
* amdgpu_driver_unload_kms - Main unload function for KMS.
|
||||
*
|
||||
@ -103,7 +97,8 @@ int amdgpu_driver_load_kms(struct drm_device *dev, unsigned long flags)
|
||||
amdgpu_has_atpx() &&
|
||||
(amdgpu_is_atpx_hybrid() ||
|
||||
amdgpu_has_atpx_dgpu_power_cntl()) &&
|
||||
((flags & AMD_IS_APU) == 0))
|
||||
((flags & AMD_IS_APU) == 0) &&
|
||||
!pci_is_thunderbolt_attached(dev->pdev))
|
||||
flags |= AMD_IS_PX;
|
||||
|
||||
/* amdgpu_device_init should report only fatal error
|
||||
@ -208,6 +203,14 @@ static int amdgpu_firmware_info(struct drm_amdgpu_info_firmware *fw_info,
|
||||
fw_info->ver = adev->sdma.instance[query_fw->index].fw_version;
|
||||
fw_info->feature = adev->sdma.instance[query_fw->index].feature_version;
|
||||
break;
|
||||
case AMDGPU_INFO_FW_SOS:
|
||||
fw_info->ver = adev->psp.sos_fw_version;
|
||||
fw_info->feature = adev->psp.sos_feature_version;
|
||||
break;
|
||||
case AMDGPU_INFO_FW_ASD:
|
||||
fw_info->ver = adev->psp.asd_fw_version;
|
||||
fw_info->feature = adev->psp.asd_feature_version;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -234,12 +237,13 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
|
||||
struct amdgpu_device *adev = dev->dev_private;
|
||||
struct drm_amdgpu_info *info = data;
|
||||
struct amdgpu_mode_info *minfo = &adev->mode_info;
|
||||
void __user *out = (void __user *)(long)info->return_pointer;
|
||||
void __user *out = (void __user *)(uintptr_t)info->return_pointer;
|
||||
uint32_t size = info->return_size;
|
||||
struct drm_crtc *crtc;
|
||||
uint32_t ui32 = 0;
|
||||
uint64_t ui64 = 0;
|
||||
int i, found;
|
||||
int ui32_size = sizeof(ui32);
|
||||
|
||||
if (!info->return_size || !info->return_pointer)
|
||||
return -EINVAL;
|
||||
@ -308,6 +312,13 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
|
||||
ib_start_alignment = AMDGPU_GPU_PAGE_SIZE;
|
||||
ib_size_alignment = 1;
|
||||
break;
|
||||
case AMDGPU_HW_IP_UVD_ENC:
|
||||
type = AMD_IP_BLOCK_TYPE_UVD;
|
||||
for (i = 0; i < adev->uvd.num_enc_rings; i++)
|
||||
ring_mask |= ((adev->uvd.ring_enc[i].ready ? 1 : 0) << i);
|
||||
ib_start_alignment = AMDGPU_GPU_PAGE_SIZE;
|
||||
ib_size_alignment = 1;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -347,6 +358,9 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
|
||||
case AMDGPU_HW_IP_VCE:
|
||||
type = AMD_IP_BLOCK_TYPE_VCE;
|
||||
break;
|
||||
case AMDGPU_HW_IP_UVD_ENC:
|
||||
type = AMD_IP_BLOCK_TYPE_UVD;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -527,6 +541,15 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
|
||||
dev_info.vram_type = adev->mc.vram_type;
|
||||
dev_info.vram_bit_width = adev->mc.vram_width;
|
||||
dev_info.vce_harvest_config = adev->vce.harvest_config;
|
||||
dev_info.gc_double_offchip_lds_buf =
|
||||
adev->gfx.config.double_offchip_lds_buf;
|
||||
|
||||
if (amdgpu_ngg) {
|
||||
dev_info.prim_buf_gpu_addr = adev->gfx.ngg.buf[PRIM].gpu_addr;
|
||||
dev_info.pos_buf_gpu_addr = adev->gfx.ngg.buf[POS].gpu_addr;
|
||||
dev_info.cntl_sb_buf_gpu_addr = adev->gfx.ngg.buf[CNTL].gpu_addr;
|
||||
dev_info.param_buf_gpu_addr = adev->gfx.ngg.buf[PARAM].gpu_addr;
|
||||
}
|
||||
|
||||
return copy_to_user(out, &dev_info,
|
||||
min((size_t)size, sizeof(dev_info))) ? -EFAULT : 0;
|
||||
@ -596,6 +619,80 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
case AMDGPU_INFO_SENSOR: {
|
||||
struct pp_gpu_power query = {0};
|
||||
int query_size = sizeof(query);
|
||||
|
||||
if (amdgpu_dpm == 0)
|
||||
return -ENOENT;
|
||||
|
||||
switch (info->sensor_info.type) {
|
||||
case AMDGPU_INFO_SENSOR_GFX_SCLK:
|
||||
/* get sclk in Mhz */
|
||||
if (amdgpu_dpm_read_sensor(adev,
|
||||
AMDGPU_PP_SENSOR_GFX_SCLK,
|
||||
(void *)&ui32, &ui32_size)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
ui32 /= 100;
|
||||
break;
|
||||
case AMDGPU_INFO_SENSOR_GFX_MCLK:
|
||||
/* get mclk in Mhz */
|
||||
if (amdgpu_dpm_read_sensor(adev,
|
||||
AMDGPU_PP_SENSOR_GFX_MCLK,
|
||||
(void *)&ui32, &ui32_size)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
ui32 /= 100;
|
||||
break;
|
||||
case AMDGPU_INFO_SENSOR_GPU_TEMP:
|
||||
/* get temperature in millidegrees C */
|
||||
if (amdgpu_dpm_read_sensor(adev,
|
||||
AMDGPU_PP_SENSOR_GPU_TEMP,
|
||||
(void *)&ui32, &ui32_size)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
case AMDGPU_INFO_SENSOR_GPU_LOAD:
|
||||
/* get GPU load */
|
||||
if (amdgpu_dpm_read_sensor(adev,
|
||||
AMDGPU_PP_SENSOR_GPU_LOAD,
|
||||
(void *)&ui32, &ui32_size)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
case AMDGPU_INFO_SENSOR_GPU_AVG_POWER:
|
||||
/* get average GPU power */
|
||||
if (amdgpu_dpm_read_sensor(adev,
|
||||
AMDGPU_PP_SENSOR_GPU_POWER,
|
||||
(void *)&query, &query_size)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
ui32 = query.average_gpu_power >> 8;
|
||||
break;
|
||||
case AMDGPU_INFO_SENSOR_VDDNB:
|
||||
/* get VDDNB in millivolts */
|
||||
if (amdgpu_dpm_read_sensor(adev,
|
||||
AMDGPU_PP_SENSOR_VDDNB,
|
||||
(void *)&ui32, &ui32_size)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
case AMDGPU_INFO_SENSOR_VDDGFX:
|
||||
/* get VDDGFX in millivolts */
|
||||
if (amdgpu_dpm_read_sensor(adev,
|
||||
AMDGPU_PP_SENSOR_VDDGFX,
|
||||
(void *)&ui32, &ui32_size)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DRM_DEBUG_KMS("Invalid request %d\n",
|
||||
info->sensor_info.type);
|
||||
return -EINVAL;
|
||||
}
|
||||
return copy_to_user(out, &ui32, min(size, 4u)) ? -EFAULT : 0;
|
||||
}
|
||||
default:
|
||||
DRM_DEBUG_KMS("Invalid request %d\n", info->query);
|
||||
return -EINVAL;
|
||||
@ -655,6 +752,14 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv)
|
||||
goto out_suspend;
|
||||
}
|
||||
|
||||
fpriv->prt_va = amdgpu_vm_bo_add(adev, &fpriv->vm, NULL);
|
||||
if (!fpriv->prt_va) {
|
||||
r = -ENOMEM;
|
||||
amdgpu_vm_fini(adev, &fpriv->vm);
|
||||
kfree(fpriv);
|
||||
goto out_suspend;
|
||||
}
|
||||
|
||||
if (amdgpu_sriov_vf(adev)) {
|
||||
r = amdgpu_map_static_csa(adev, &fpriv->vm);
|
||||
if (r)
|
||||
@ -694,11 +799,15 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev,
|
||||
if (!fpriv)
|
||||
return;
|
||||
|
||||
pm_runtime_get_sync(dev->dev);
|
||||
|
||||
amdgpu_ctx_mgr_fini(&fpriv->ctx_mgr);
|
||||
|
||||
amdgpu_uvd_free_handles(adev, file_priv);
|
||||
amdgpu_vce_free_handles(adev, file_priv);
|
||||
|
||||
amdgpu_vm_bo_rmv(adev, fpriv->prt_va);
|
||||
|
||||
if (amdgpu_sriov_vf(adev)) {
|
||||
/* TODO: how to handle reserve failure */
|
||||
BUG_ON(amdgpu_bo_reserve(adev->virt.csa_obj, false));
|
||||
@ -722,21 +831,6 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev,
|
||||
pm_runtime_put_autosuspend(dev->dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_driver_preclose_kms - drm callback for pre close
|
||||
*
|
||||
* @dev: drm dev pointer
|
||||
* @file_priv: drm file
|
||||
*
|
||||
* On device pre close, tear down hyperz and cmask filps on r1xx-r5xx
|
||||
* (all asics).
|
||||
*/
|
||||
void amdgpu_driver_preclose_kms(struct drm_device *dev,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
pm_runtime_get_sync(dev->dev);
|
||||
}
|
||||
|
||||
/*
|
||||
* VBlank related functions.
|
||||
*/
|
||||
@ -989,6 +1083,23 @@ static int amdgpu_debugfs_firmware_info(struct seq_file *m, void *data)
|
||||
fw_info.feature, fw_info.ver);
|
||||
}
|
||||
|
||||
/* PSP SOS */
|
||||
query_fw.fw_type = AMDGPU_INFO_FW_SOS;
|
||||
ret = amdgpu_firmware_info(&fw_info, &query_fw, adev);
|
||||
if (ret)
|
||||
return ret;
|
||||
seq_printf(m, "SOS feature version: %u, firmware version: 0x%08x\n",
|
||||
fw_info.feature, fw_info.ver);
|
||||
|
||||
|
||||
/* PSP ASD */
|
||||
query_fw.fw_type = AMDGPU_INFO_FW_ASD;
|
||||
ret = amdgpu_firmware_info(&fw_info, &query_fw, adev);
|
||||
if (ret)
|
||||
return ret;
|
||||
seq_printf(m, "ASD feature version: %u, firmware version: 0x%08x\n",
|
||||
fw_info.feature, fw_info.ver);
|
||||
|
||||
/* SMC */
|
||||
query_fw.fw_type = AMDGPU_INFO_FW_SMC;
|
||||
ret = amdgpu_firmware_info(&fw_info, &query_fw, adev);
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mmu_notifier.h>
|
||||
#include <linux/interval_tree.h>
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm.h>
|
||||
|
||||
|
@ -590,11 +590,13 @@ int amdgpu_align_pitch(struct amdgpu_device *adev, int width, int bpp, bool tile
|
||||
/* amdgpu_display.c */
|
||||
void amdgpu_print_display_setup(struct drm_device *dev);
|
||||
int amdgpu_modeset_create_props(struct amdgpu_device *adev);
|
||||
int amdgpu_crtc_set_config(struct drm_mode_set *set);
|
||||
int amdgpu_crtc_set_config(struct drm_mode_set *set,
|
||||
struct drm_modeset_acquire_ctx *ctx);
|
||||
int amdgpu_crtc_page_flip_target(struct drm_crtc *crtc,
|
||||
struct drm_framebuffer *fb,
|
||||
struct drm_pending_vblank_event *event,
|
||||
uint32_t page_flip_flags, uint32_t target);
|
||||
uint32_t page_flip_flags, uint32_t target,
|
||||
struct drm_modeset_acquire_ctx *ctx);
|
||||
void amdgpu_crtc_cleanup_flip_ctx(struct amdgpu_flip_work *work,
|
||||
struct amdgpu_bo *new_abo);
|
||||
int amdgpu_crtc_prepare_flip(struct drm_crtc *crtc,
|
||||
|
@ -122,20 +122,19 @@ static void amdgpu_ttm_placement_init(struct amdgpu_device *adev,
|
||||
|
||||
if (domain & AMDGPU_GEM_DOMAIN_VRAM) {
|
||||
unsigned visible_pfn = adev->mc.visible_vram_size >> PAGE_SHIFT;
|
||||
unsigned lpfn = 0;
|
||||
|
||||
/* This forces a reallocation if the flag wasn't set before */
|
||||
if (flags & AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS)
|
||||
lpfn = adev->mc.real_vram_size >> PAGE_SHIFT;
|
||||
|
||||
places[c].fpfn = 0;
|
||||
places[c].lpfn = lpfn;
|
||||
places[c].lpfn = 0;
|
||||
places[c].flags = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED |
|
||||
TTM_PL_FLAG_VRAM;
|
||||
|
||||
if (flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED)
|
||||
places[c].lpfn = visible_pfn;
|
||||
else
|
||||
places[c].flags |= TTM_PL_FLAG_TOPDOWN;
|
||||
|
||||
if (flags & AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS)
|
||||
places[c].flags |= TTM_PL_FLAG_CONTIGUOUS;
|
||||
c++;
|
||||
}
|
||||
|
||||
@ -395,32 +394,18 @@ int amdgpu_bo_create_restricted(struct amdgpu_device *adev,
|
||||
amdgpu_fill_placement_to_bo(bo, placement);
|
||||
/* Kernel allocation are uninterruptible */
|
||||
|
||||
if (!resv) {
|
||||
bool locked;
|
||||
|
||||
reservation_object_init(&bo->tbo.ttm_resv);
|
||||
locked = ww_mutex_trylock(&bo->tbo.ttm_resv.lock);
|
||||
WARN_ON(!locked);
|
||||
}
|
||||
|
||||
initial_bytes_moved = atomic64_read(&adev->num_bytes_moved);
|
||||
r = ttm_bo_init(&adev->mman.bdev, &bo->tbo, size, type,
|
||||
&bo->placement, page_align, !kernel, NULL,
|
||||
acc_size, sg, resv ? resv : &bo->tbo.ttm_resv,
|
||||
&amdgpu_ttm_bo_destroy);
|
||||
r = ttm_bo_init_reserved(&adev->mman.bdev, &bo->tbo, size, type,
|
||||
&bo->placement, page_align, !kernel, NULL,
|
||||
acc_size, sg, resv, &amdgpu_ttm_bo_destroy);
|
||||
amdgpu_cs_report_moved_bytes(adev,
|
||||
atomic64_read(&adev->num_bytes_moved) - initial_bytes_moved);
|
||||
|
||||
if (unlikely(r != 0)) {
|
||||
if (!resv)
|
||||
ww_mutex_unlock(&bo->tbo.resv->lock);
|
||||
if (unlikely(r != 0))
|
||||
return r;
|
||||
}
|
||||
|
||||
bo->tbo.priority = ilog2(bo->tbo.num_pages);
|
||||
if (kernel)
|
||||
bo->tbo.priority *= 2;
|
||||
bo->tbo.priority = min(bo->tbo.priority, (unsigned)(TTM_MAX_BO_PRIORITY - 1));
|
||||
bo->tbo.priority = 1;
|
||||
|
||||
if (flags & AMDGPU_GEM_CREATE_VRAM_CLEARED &&
|
||||
bo->tbo.mem.placement & TTM_PL_FLAG_VRAM) {
|
||||
@ -436,7 +421,7 @@ int amdgpu_bo_create_restricted(struct amdgpu_device *adev,
|
||||
dma_fence_put(fence);
|
||||
}
|
||||
if (!resv)
|
||||
ww_mutex_unlock(&bo->tbo.resv->lock);
|
||||
amdgpu_bo_unreserve(bo);
|
||||
*bo_ptr = bo;
|
||||
|
||||
trace_amdgpu_bo_create(bo);
|
||||
@ -665,6 +650,10 @@ int amdgpu_bo_pin_restricted(struct amdgpu_bo *bo, u32 domain,
|
||||
if (WARN_ON_ONCE(min_offset > max_offset))
|
||||
return -EINVAL;
|
||||
|
||||
/* A shared bo cannot be migrated to VRAM */
|
||||
if (bo->prime_shared_count && (domain == AMDGPU_GEM_DOMAIN_VRAM))
|
||||
return -EINVAL;
|
||||
|
||||
if (bo->pin_count) {
|
||||
uint32_t mem_type = bo->tbo.mem.mem_type;
|
||||
|
||||
@ -827,7 +816,10 @@ int amdgpu_bo_fbdev_mmap(struct amdgpu_bo *bo,
|
||||
|
||||
int amdgpu_bo_set_tiling_flags(struct amdgpu_bo *bo, u64 tiling_flags)
|
||||
{
|
||||
if (AMDGPU_TILING_GET(tiling_flags, TILE_SPLIT) > 6)
|
||||
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
|
||||
|
||||
if (adev->family <= AMDGPU_FAMILY_CZ &&
|
||||
AMDGPU_TILING_GET(tiling_flags, TILE_SPLIT) > 6)
|
||||
return -EINVAL;
|
||||
|
||||
bo->tiling_flags = tiling_flags;
|
||||
@ -939,8 +931,7 @@ int amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo)
|
||||
size = bo->mem.num_pages << PAGE_SHIFT;
|
||||
offset = bo->mem.start << PAGE_SHIFT;
|
||||
/* TODO: figure out how to map scattered VRAM to the CPU */
|
||||
if ((offset + size) <= adev->mc.visible_vram_size &&
|
||||
(abo->flags & AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS))
|
||||
if ((offset + size) <= adev->mc.visible_vram_size)
|
||||
return 0;
|
||||
|
||||
/* Can't move a pinned BO to visible VRAM */
|
||||
@ -948,7 +939,6 @@ int amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo)
|
||||
return -EINVAL;
|
||||
|
||||
/* hurrah the memory is not visible ! */
|
||||
abo->flags |= AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS;
|
||||
amdgpu_ttm_placement_from_domain(abo, AMDGPU_GEM_DOMAIN_VRAM);
|
||||
lpfn = adev->mc.visible_vram_size >> PAGE_SHIFT;
|
||||
for (i = 0; i < abo->placement.num_placement; i++) {
|
||||
|
@ -43,16 +43,22 @@ static const struct cg_flag_name clocks[] = {
|
||||
{AMD_CG_SUPPORT_GFX_CGTS_LS, "Graphics Coarse Grain Tree Shader Light Sleep"},
|
||||
{AMD_CG_SUPPORT_GFX_CP_LS, "Graphics Command Processor Light Sleep"},
|
||||
{AMD_CG_SUPPORT_GFX_RLC_LS, "Graphics Run List Controller Light Sleep"},
|
||||
{AMD_CG_SUPPORT_GFX_3D_CGCG, "Graphics 3D Coarse Grain Clock Gating"},
|
||||
{AMD_CG_SUPPORT_GFX_3D_CGLS, "Graphics 3D Coarse Grain memory Light Sleep"},
|
||||
{AMD_CG_SUPPORT_MC_LS, "Memory Controller Light Sleep"},
|
||||
{AMD_CG_SUPPORT_MC_MGCG, "Memory Controller Medium Grain Clock Gating"},
|
||||
{AMD_CG_SUPPORT_SDMA_LS, "System Direct Memory Access Light Sleep"},
|
||||
{AMD_CG_SUPPORT_SDMA_MGCG, "System Direct Memory Access Medium Grain Clock Gating"},
|
||||
{AMD_CG_SUPPORT_BIF_MGCG, "Bus Interface Medium Grain Clock Gating"},
|
||||
{AMD_CG_SUPPORT_BIF_LS, "Bus Interface Light Sleep"},
|
||||
{AMD_CG_SUPPORT_UVD_MGCG, "Unified Video Decoder Medium Grain Clock Gating"},
|
||||
{AMD_CG_SUPPORT_VCE_MGCG, "Video Compression Engine Medium Grain Clock Gating"},
|
||||
{AMD_CG_SUPPORT_HDP_LS, "Host Data Path Light Sleep"},
|
||||
{AMD_CG_SUPPORT_HDP_MGCG, "Host Data Path Medium Grain Clock Gating"},
|
||||
{AMD_CG_SUPPORT_DRM_MGCG, "Digital Right Management Medium Grain Clock Gating"},
|
||||
{AMD_CG_SUPPORT_DRM_LS, "Digital Right Management Light Sleep"},
|
||||
{AMD_CG_SUPPORT_ROM_MGCG, "Rom Medium Grain Clock Gating"},
|
||||
{AMD_CG_SUPPORT_DF_MGCG, "Data Fabric Medium Grain Clock Gating"},
|
||||
{0, NULL},
|
||||
};
|
||||
|
||||
@ -610,6 +616,174 @@ fail:
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t amdgpu_get_pp_power_profile(struct device *dev,
|
||||
char *buf, struct amd_pp_profile *query)
|
||||
{
|
||||
struct drm_device *ddev = dev_get_drvdata(dev);
|
||||
struct amdgpu_device *adev = ddev->dev_private;
|
||||
int ret = 0;
|
||||
|
||||
if (adev->pp_enabled)
|
||||
ret = amdgpu_dpm_get_power_profile_state(
|
||||
adev, query);
|
||||
else if (adev->pm.funcs->get_power_profile_state)
|
||||
ret = adev->pm.funcs->get_power_profile_state(
|
||||
adev, query);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return snprintf(buf, PAGE_SIZE,
|
||||
"%d %d %d %d %d\n",
|
||||
query->min_sclk / 100,
|
||||
query->min_mclk / 100,
|
||||
query->activity_threshold,
|
||||
query->up_hyst,
|
||||
query->down_hyst);
|
||||
}
|
||||
|
||||
static ssize_t amdgpu_get_pp_gfx_power_profile(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct amd_pp_profile query = {0};
|
||||
|
||||
query.type = AMD_PP_GFX_PROFILE;
|
||||
|
||||
return amdgpu_get_pp_power_profile(dev, buf, &query);
|
||||
}
|
||||
|
||||
static ssize_t amdgpu_get_pp_compute_power_profile(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct amd_pp_profile query = {0};
|
||||
|
||||
query.type = AMD_PP_COMPUTE_PROFILE;
|
||||
|
||||
return amdgpu_get_pp_power_profile(dev, buf, &query);
|
||||
}
|
||||
|
||||
static ssize_t amdgpu_set_pp_power_profile(struct device *dev,
|
||||
const char *buf,
|
||||
size_t count,
|
||||
struct amd_pp_profile *request)
|
||||
{
|
||||
struct drm_device *ddev = dev_get_drvdata(dev);
|
||||
struct amdgpu_device *adev = ddev->dev_private;
|
||||
uint32_t loop = 0;
|
||||
char *sub_str, buf_cpy[128], *tmp_str;
|
||||
const char delimiter[3] = {' ', '\n', '\0'};
|
||||
long int value;
|
||||
int ret = 0;
|
||||
|
||||
if (strncmp("reset", buf, strlen("reset")) == 0) {
|
||||
if (adev->pp_enabled)
|
||||
ret = amdgpu_dpm_reset_power_profile_state(
|
||||
adev, request);
|
||||
else if (adev->pm.funcs->reset_power_profile_state)
|
||||
ret = adev->pm.funcs->reset_power_profile_state(
|
||||
adev, request);
|
||||
if (ret) {
|
||||
count = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
if (strncmp("set", buf, strlen("set")) == 0) {
|
||||
if (adev->pp_enabled)
|
||||
ret = amdgpu_dpm_set_power_profile_state(
|
||||
adev, request);
|
||||
else if (adev->pm.funcs->set_power_profile_state)
|
||||
ret = adev->pm.funcs->set_power_profile_state(
|
||||
adev, request);
|
||||
if (ret) {
|
||||
count = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
if (count + 1 >= 128) {
|
||||
count = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
memcpy(buf_cpy, buf, count + 1);
|
||||
tmp_str = buf_cpy;
|
||||
|
||||
while (tmp_str[0]) {
|
||||
sub_str = strsep(&tmp_str, delimiter);
|
||||
ret = kstrtol(sub_str, 0, &value);
|
||||
if (ret) {
|
||||
count = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
switch (loop) {
|
||||
case 0:
|
||||
/* input unit MHz convert to dpm table unit 10KHz*/
|
||||
request->min_sclk = (uint32_t)value * 100;
|
||||
break;
|
||||
case 1:
|
||||
/* input unit MHz convert to dpm table unit 10KHz*/
|
||||
request->min_mclk = (uint32_t)value * 100;
|
||||
break;
|
||||
case 2:
|
||||
request->activity_threshold = (uint16_t)value;
|
||||
break;
|
||||
case 3:
|
||||
request->up_hyst = (uint8_t)value;
|
||||
break;
|
||||
case 4:
|
||||
request->down_hyst = (uint8_t)value;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
loop++;
|
||||
}
|
||||
|
||||
if (adev->pp_enabled)
|
||||
ret = amdgpu_dpm_set_power_profile_state(
|
||||
adev, request);
|
||||
else if (adev->pm.funcs->set_power_profile_state)
|
||||
ret = adev->pm.funcs->set_power_profile_state(
|
||||
adev, request);
|
||||
|
||||
if (ret)
|
||||
count = -EINVAL;
|
||||
|
||||
fail:
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t amdgpu_set_pp_gfx_power_profile(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct amd_pp_profile request = {0};
|
||||
|
||||
request.type = AMD_PP_GFX_PROFILE;
|
||||
|
||||
return amdgpu_set_pp_power_profile(dev, buf, count, &request);
|
||||
}
|
||||
|
||||
static ssize_t amdgpu_set_pp_compute_power_profile(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct amd_pp_profile request = {0};
|
||||
|
||||
request.type = AMD_PP_COMPUTE_PROFILE;
|
||||
|
||||
return amdgpu_set_pp_power_profile(dev, buf, count, &request);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(power_dpm_state, S_IRUGO | S_IWUSR, amdgpu_get_dpm_state, amdgpu_set_dpm_state);
|
||||
static DEVICE_ATTR(power_dpm_force_performance_level, S_IRUGO | S_IWUSR,
|
||||
amdgpu_get_dpm_forced_performance_level,
|
||||
@ -637,6 +811,12 @@ static DEVICE_ATTR(pp_sclk_od, S_IRUGO | S_IWUSR,
|
||||
static DEVICE_ATTR(pp_mclk_od, S_IRUGO | S_IWUSR,
|
||||
amdgpu_get_pp_mclk_od,
|
||||
amdgpu_set_pp_mclk_od);
|
||||
static DEVICE_ATTR(pp_gfx_power_profile, S_IRUGO | S_IWUSR,
|
||||
amdgpu_get_pp_gfx_power_profile,
|
||||
amdgpu_set_pp_gfx_power_profile);
|
||||
static DEVICE_ATTR(pp_compute_power_profile, S_IRUGO | S_IWUSR,
|
||||
amdgpu_get_pp_compute_power_profile,
|
||||
amdgpu_set_pp_compute_power_profile);
|
||||
|
||||
static ssize_t amdgpu_hwmon_show_temp(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
@ -1142,11 +1322,11 @@ void amdgpu_dpm_enable_vce(struct amdgpu_device *adev, bool enable)
|
||||
/* XXX select vce level based on ring/task */
|
||||
adev->pm.dpm.vce_level = AMD_VCE_LEVEL_AC_ALL;
|
||||
mutex_unlock(&adev->pm.mutex);
|
||||
amdgpu_pm_compute_clocks(adev);
|
||||
amdgpu_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
|
||||
AMD_PG_STATE_UNGATE);
|
||||
amdgpu_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
|
||||
AMD_CG_STATE_UNGATE);
|
||||
amdgpu_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
|
||||
AMD_PG_STATE_UNGATE);
|
||||
amdgpu_pm_compute_clocks(adev);
|
||||
} else {
|
||||
amdgpu_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
|
||||
AMD_PG_STATE_GATE);
|
||||
@ -1255,6 +1435,20 @@ int amdgpu_pm_sysfs_init(struct amdgpu_device *adev)
|
||||
DRM_ERROR("failed to create device file pp_mclk_od\n");
|
||||
return ret;
|
||||
}
|
||||
ret = device_create_file(adev->dev,
|
||||
&dev_attr_pp_gfx_power_profile);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to create device file "
|
||||
"pp_gfx_power_profile\n");
|
||||
return ret;
|
||||
}
|
||||
ret = device_create_file(adev->dev,
|
||||
&dev_attr_pp_compute_power_profile);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to create device file "
|
||||
"pp_compute_power_profile\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = amdgpu_debugfs_pm_init(adev);
|
||||
if (ret) {
|
||||
@ -1284,6 +1478,10 @@ void amdgpu_pm_sysfs_fini(struct amdgpu_device *adev)
|
||||
device_remove_file(adev->dev, &dev_attr_pp_dpm_pcie);
|
||||
device_remove_file(adev->dev, &dev_attr_pp_sclk_od);
|
||||
device_remove_file(adev->dev, &dev_attr_pp_mclk_od);
|
||||
device_remove_file(adev->dev,
|
||||
&dev_attr_pp_gfx_power_profile);
|
||||
device_remove_file(adev->dev,
|
||||
&dev_attr_pp_compute_power_profile);
|
||||
}
|
||||
|
||||
void amdgpu_pm_compute_clocks(struct amdgpu_device *adev)
|
||||
@ -1340,7 +1538,9 @@ void amdgpu_pm_compute_clocks(struct amdgpu_device *adev)
|
||||
|
||||
static int amdgpu_debugfs_pm_info_pp(struct seq_file *m, struct amdgpu_device *adev)
|
||||
{
|
||||
int32_t value;
|
||||
uint32_t value;
|
||||
struct pp_gpu_power query = {0};
|
||||
int size;
|
||||
|
||||
/* sanity check PP is enabled */
|
||||
if (!(adev->powerplay.pp_funcs &&
|
||||
@ -1348,47 +1548,60 @@ static int amdgpu_debugfs_pm_info_pp(struct seq_file *m, struct amdgpu_device *a
|
||||
return -EINVAL;
|
||||
|
||||
/* GPU Clocks */
|
||||
size = sizeof(value);
|
||||
seq_printf(m, "GFX Clocks and Power:\n");
|
||||
if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GFX_MCLK, &value))
|
||||
if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GFX_MCLK, (void *)&value, &size))
|
||||
seq_printf(m, "\t%u MHz (MCLK)\n", value/100);
|
||||
if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GFX_SCLK, &value))
|
||||
if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GFX_SCLK, (void *)&value, &size))
|
||||
seq_printf(m, "\t%u MHz (SCLK)\n", value/100);
|
||||
if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_VDDGFX, &value))
|
||||
if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_VDDGFX, (void *)&value, &size))
|
||||
seq_printf(m, "\t%u mV (VDDGFX)\n", value);
|
||||
if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_VDDNB, &value))
|
||||
if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_VDDNB, (void *)&value, &size))
|
||||
seq_printf(m, "\t%u mV (VDDNB)\n", value);
|
||||
size = sizeof(query);
|
||||
if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_POWER, (void *)&query, &size)) {
|
||||
seq_printf(m, "\t%u.%u W (VDDC)\n", query.vddc_power >> 8,
|
||||
query.vddc_power & 0xff);
|
||||
seq_printf(m, "\t%u.%u W (VDDCI)\n", query.vddci_power >> 8,
|
||||
query.vddci_power & 0xff);
|
||||
seq_printf(m, "\t%u.%u W (max GPU)\n", query.max_gpu_power >> 8,
|
||||
query.max_gpu_power & 0xff);
|
||||
seq_printf(m, "\t%u.%u W (average GPU)\n", query.average_gpu_power >> 8,
|
||||
query.average_gpu_power & 0xff);
|
||||
}
|
||||
size = sizeof(value);
|
||||
seq_printf(m, "\n");
|
||||
|
||||
/* GPU Temp */
|
||||
if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_TEMP, &value))
|
||||
if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_TEMP, (void *)&value, &size))
|
||||
seq_printf(m, "GPU Temperature: %u C\n", value/1000);
|
||||
|
||||
/* GPU Load */
|
||||
if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_LOAD, &value))
|
||||
if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_LOAD, (void *)&value, &size))
|
||||
seq_printf(m, "GPU Load: %u %%\n", value);
|
||||
seq_printf(m, "\n");
|
||||
|
||||
/* UVD clocks */
|
||||
if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_UVD_POWER, &value)) {
|
||||
if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_UVD_POWER, (void *)&value, &size)) {
|
||||
if (!value) {
|
||||
seq_printf(m, "UVD: Disabled\n");
|
||||
} else {
|
||||
seq_printf(m, "UVD: Enabled\n");
|
||||
if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_UVD_DCLK, &value))
|
||||
if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_UVD_DCLK, (void *)&value, &size))
|
||||
seq_printf(m, "\t%u MHz (DCLK)\n", value/100);
|
||||
if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_UVD_VCLK, &value))
|
||||
if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_UVD_VCLK, (void *)&value, &size))
|
||||
seq_printf(m, "\t%u MHz (VCLK)\n", value/100);
|
||||
}
|
||||
}
|
||||
seq_printf(m, "\n");
|
||||
|
||||
/* VCE clocks */
|
||||
if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_VCE_POWER, &value)) {
|
||||
if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_VCE_POWER, (void *)&value, &size)) {
|
||||
if (!value) {
|
||||
seq_printf(m, "VCE: Disabled\n");
|
||||
} else {
|
||||
seq_printf(m, "VCE: Enabled\n");
|
||||
if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_VCE_ECCLK, &value))
|
||||
if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_VCE_ECCLK, (void *)&value, &size))
|
||||
seq_printf(m, "\t%u MHz (ECCLK)\n", value/100);
|
||||
}
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ static int amdgpu_create_pp_handle(struct amdgpu_device *adev)
|
||||
amd_pp = &(adev->powerplay);
|
||||
pp_init.chip_family = adev->family;
|
||||
pp_init.chip_id = adev->asic_type;
|
||||
pp_init.pm_en = amdgpu_dpm != 0 ? true : false;
|
||||
pp_init.pm_en = (amdgpu_dpm != 0 && !amdgpu_sriov_vf(adev)) ? true : false;
|
||||
pp_init.feature_mask = amdgpu_pp_feature_mask;
|
||||
pp_init.device = amdgpu_cgs_create_device(adev);
|
||||
ret = amd_powerplay_create(&pp_init, &(amd_pp->pp_handle));
|
||||
@ -71,6 +71,7 @@ static int amdgpu_pp_early_init(void *handle)
|
||||
case CHIP_TOPAZ:
|
||||
case CHIP_CARRIZO:
|
||||
case CHIP_STONEY:
|
||||
case CHIP_VEGA10:
|
||||
adev->pp_enabled = true;
|
||||
if (amdgpu_create_pp_handle(adev))
|
||||
return -EINVAL;
|
||||
@ -163,7 +164,7 @@ static int amdgpu_pp_hw_init(void *handle)
|
||||
int ret = 0;
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
if (adev->pp_enabled && adev->firmware.smu_load)
|
||||
if (adev->pp_enabled && adev->firmware.load_type == AMDGPU_FW_LOAD_SMU)
|
||||
amdgpu_ucode_init_bo(adev);
|
||||
|
||||
if (adev->powerplay.ip_funcs->hw_init)
|
||||
@ -190,7 +191,7 @@ static int amdgpu_pp_hw_fini(void *handle)
|
||||
ret = adev->powerplay.ip_funcs->hw_fini(
|
||||
adev->powerplay.pp_handle);
|
||||
|
||||
if (adev->pp_enabled && adev->firmware.smu_load)
|
||||
if (adev->pp_enabled && adev->firmware.load_type == AMDGPU_FW_LOAD_SMU)
|
||||
amdgpu_ucode_fini_bo(adev);
|
||||
|
||||
return ret;
|
||||
|
481
drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
Normal file
481
drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
Normal file
@ -0,0 +1,481 @@
|
||||
/*
|
||||
* Copyright 2016 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.
|
||||
*
|
||||
* Author: Huang Rui
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/firmware.h>
|
||||
#include "drmP.h"
|
||||
#include "amdgpu.h"
|
||||
#include "amdgpu_psp.h"
|
||||
#include "amdgpu_ucode.h"
|
||||
#include "soc15_common.h"
|
||||
#include "psp_v3_1.h"
|
||||
|
||||
static void psp_set_funcs(struct amdgpu_device *adev);
|
||||
|
||||
static int psp_early_init(void *handle)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
psp_set_funcs(adev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int psp_sw_init(void *handle)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
struct psp_context *psp = &adev->psp;
|
||||
int ret;
|
||||
|
||||
switch (adev->asic_type) {
|
||||
case CHIP_VEGA10:
|
||||
psp->init_microcode = psp_v3_1_init_microcode;
|
||||
psp->bootloader_load_sysdrv = psp_v3_1_bootloader_load_sysdrv;
|
||||
psp->bootloader_load_sos = psp_v3_1_bootloader_load_sos;
|
||||
psp->prep_cmd_buf = psp_v3_1_prep_cmd_buf;
|
||||
psp->ring_init = psp_v3_1_ring_init;
|
||||
psp->cmd_submit = psp_v3_1_cmd_submit;
|
||||
psp->compare_sram_data = psp_v3_1_compare_sram_data;
|
||||
psp->smu_reload_quirk = psp_v3_1_smu_reload_quirk;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
psp->adev = adev;
|
||||
|
||||
ret = psp_init_microcode(psp);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to load psp firmware!\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int psp_sw_fini(void *handle)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int psp_wait_for(struct psp_context *psp, uint32_t reg_index,
|
||||
uint32_t reg_val, uint32_t mask, bool check_changed)
|
||||
{
|
||||
uint32_t val;
|
||||
int i;
|
||||
struct amdgpu_device *adev = psp->adev;
|
||||
|
||||
val = RREG32(reg_index);
|
||||
|
||||
for (i = 0; i < adev->usec_timeout; i++) {
|
||||
if (check_changed) {
|
||||
if (val != reg_val)
|
||||
return 0;
|
||||
} else {
|
||||
if ((val & mask) == reg_val)
|
||||
return 0;
|
||||
}
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
return -ETIME;
|
||||
}
|
||||
|
||||
static int
|
||||
psp_cmd_submit_buf(struct psp_context *psp,
|
||||
struct amdgpu_firmware_info *ucode,
|
||||
struct psp_gfx_cmd_resp *cmd, uint64_t fence_mc_addr,
|
||||
int index)
|
||||
{
|
||||
int ret;
|
||||
struct amdgpu_bo *cmd_buf_bo;
|
||||
uint64_t cmd_buf_mc_addr;
|
||||
struct psp_gfx_cmd_resp *cmd_buf_mem;
|
||||
struct amdgpu_device *adev = psp->adev;
|
||||
|
||||
ret = amdgpu_bo_create_kernel(adev, PSP_CMD_BUFFER_SIZE, PAGE_SIZE,
|
||||
AMDGPU_GEM_DOMAIN_VRAM,
|
||||
&cmd_buf_bo, &cmd_buf_mc_addr,
|
||||
(void **)&cmd_buf_mem);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
memset(cmd_buf_mem, 0, PSP_CMD_BUFFER_SIZE);
|
||||
|
||||
memcpy(cmd_buf_mem, cmd, sizeof(struct psp_gfx_cmd_resp));
|
||||
|
||||
ret = psp_cmd_submit(psp, ucode, cmd_buf_mc_addr,
|
||||
fence_mc_addr, index);
|
||||
|
||||
while (*((unsigned int *)psp->fence_buf) != index) {
|
||||
msleep(1);
|
||||
}
|
||||
|
||||
amdgpu_bo_free_kernel(&cmd_buf_bo,
|
||||
&cmd_buf_mc_addr,
|
||||
(void **)&cmd_buf_mem);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void psp_prep_tmr_cmd_buf(struct psp_gfx_cmd_resp *cmd,
|
||||
uint64_t tmr_mc, uint32_t size)
|
||||
{
|
||||
cmd->cmd_id = GFX_CMD_ID_SETUP_TMR;
|
||||
cmd->cmd.cmd_setup_tmr.buf_phy_addr_lo = (uint32_t)tmr_mc;
|
||||
cmd->cmd.cmd_setup_tmr.buf_phy_addr_hi = (uint32_t)(tmr_mc >> 32);
|
||||
cmd->cmd.cmd_setup_tmr.buf_size = size;
|
||||
}
|
||||
|
||||
/* Set up Trusted Memory Region */
|
||||
static int psp_tmr_init(struct psp_context *psp)
|
||||
{
|
||||
int ret;
|
||||
struct psp_gfx_cmd_resp *cmd;
|
||||
|
||||
cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL);
|
||||
if (!cmd)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* Allocate 3M memory aligned to 1M from Frame Buffer (local
|
||||
* physical).
|
||||
*
|
||||
* Note: this memory need be reserved till the driver
|
||||
* uninitializes.
|
||||
*/
|
||||
ret = amdgpu_bo_create_kernel(psp->adev, 0x300000, 0x100000,
|
||||
AMDGPU_GEM_DOMAIN_VRAM,
|
||||
&psp->tmr_bo, &psp->tmr_mc_addr, &psp->tmr_buf);
|
||||
if (ret)
|
||||
goto failed;
|
||||
|
||||
psp_prep_tmr_cmd_buf(cmd, psp->tmr_mc_addr, 0x300000);
|
||||
|
||||
ret = psp_cmd_submit_buf(psp, NULL, cmd,
|
||||
psp->fence_buf_mc_addr, 1);
|
||||
if (ret)
|
||||
goto failed_mem;
|
||||
|
||||
kfree(cmd);
|
||||
|
||||
return 0;
|
||||
|
||||
failed_mem:
|
||||
amdgpu_bo_free_kernel(&psp->tmr_bo, &psp->tmr_mc_addr, &psp->tmr_buf);
|
||||
failed:
|
||||
kfree(cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void psp_prep_asd_cmd_buf(struct psp_gfx_cmd_resp *cmd,
|
||||
uint64_t asd_mc, uint64_t asd_mc_shared,
|
||||
uint32_t size, uint32_t shared_size)
|
||||
{
|
||||
cmd->cmd_id = GFX_CMD_ID_LOAD_ASD;
|
||||
cmd->cmd.cmd_load_ta.app_phy_addr_lo = lower_32_bits(asd_mc);
|
||||
cmd->cmd.cmd_load_ta.app_phy_addr_hi = upper_32_bits(asd_mc);
|
||||
cmd->cmd.cmd_load_ta.app_len = size;
|
||||
|
||||
cmd->cmd.cmd_load_ta.cmd_buf_phy_addr_lo = lower_32_bits(asd_mc_shared);
|
||||
cmd->cmd.cmd_load_ta.cmd_buf_phy_addr_hi = upper_32_bits(asd_mc_shared);
|
||||
cmd->cmd.cmd_load_ta.cmd_buf_len = shared_size;
|
||||
}
|
||||
|
||||
static int psp_asd_load(struct psp_context *psp)
|
||||
{
|
||||
int ret;
|
||||
struct amdgpu_bo *asd_bo, *asd_shared_bo;
|
||||
uint64_t asd_mc_addr, asd_shared_mc_addr;
|
||||
void *asd_buf, *asd_shared_buf;
|
||||
struct psp_gfx_cmd_resp *cmd;
|
||||
|
||||
cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL);
|
||||
if (!cmd)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* Allocate 16k memory aligned to 4k from Frame Buffer (local
|
||||
* physical) for shared ASD <-> Driver
|
||||
*/
|
||||
ret = amdgpu_bo_create_kernel(psp->adev, PSP_ASD_SHARED_MEM_SIZE, PAGE_SIZE,
|
||||
AMDGPU_GEM_DOMAIN_VRAM,
|
||||
&asd_shared_bo, &asd_shared_mc_addr, &asd_buf);
|
||||
if (ret)
|
||||
goto failed;
|
||||
|
||||
/*
|
||||
* Allocate 256k memory aligned to 4k from Frame Buffer (local
|
||||
* physical) for ASD firmware
|
||||
*/
|
||||
ret = amdgpu_bo_create_kernel(psp->adev, PSP_ASD_BIN_SIZE, PAGE_SIZE,
|
||||
AMDGPU_GEM_DOMAIN_VRAM,
|
||||
&asd_bo, &asd_mc_addr, &asd_buf);
|
||||
if (ret)
|
||||
goto failed_mem;
|
||||
|
||||
memcpy(asd_buf, psp->asd_start_addr, psp->asd_ucode_size);
|
||||
|
||||
psp_prep_asd_cmd_buf(cmd, asd_mc_addr, asd_shared_mc_addr,
|
||||
psp->asd_ucode_size, PSP_ASD_SHARED_MEM_SIZE);
|
||||
|
||||
ret = psp_cmd_submit_buf(psp, NULL, cmd,
|
||||
psp->fence_buf_mc_addr, 2);
|
||||
if (ret)
|
||||
goto failed_mem1;
|
||||
|
||||
amdgpu_bo_free_kernel(&asd_bo, &asd_mc_addr, &asd_buf);
|
||||
amdgpu_bo_free_kernel(&asd_shared_bo, &asd_shared_mc_addr, &asd_shared_buf);
|
||||
kfree(cmd);
|
||||
|
||||
return 0;
|
||||
|
||||
failed_mem1:
|
||||
amdgpu_bo_free_kernel(&asd_bo, &asd_mc_addr, &asd_buf);
|
||||
failed_mem:
|
||||
amdgpu_bo_free_kernel(&asd_shared_bo, &asd_shared_mc_addr, &asd_shared_buf);
|
||||
failed:
|
||||
kfree(cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int psp_load_fw(struct amdgpu_device *adev)
|
||||
{
|
||||
int ret;
|
||||
struct psp_gfx_cmd_resp *cmd;
|
||||
int i;
|
||||
struct amdgpu_firmware_info *ucode;
|
||||
struct psp_context *psp = &adev->psp;
|
||||
|
||||
cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL);
|
||||
if (!cmd)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = psp_bootloader_load_sysdrv(psp);
|
||||
if (ret)
|
||||
goto failed;
|
||||
|
||||
ret = psp_bootloader_load_sos(psp);
|
||||
if (ret)
|
||||
goto failed;
|
||||
|
||||
ret = psp_ring_init(psp, PSP_RING_TYPE__KM);
|
||||
if (ret)
|
||||
goto failed;
|
||||
|
||||
ret = amdgpu_bo_create_kernel(adev, PSP_FENCE_BUFFER_SIZE, PAGE_SIZE,
|
||||
AMDGPU_GEM_DOMAIN_VRAM,
|
||||
&psp->fence_buf_bo,
|
||||
&psp->fence_buf_mc_addr,
|
||||
&psp->fence_buf);
|
||||
if (ret)
|
||||
goto failed;
|
||||
|
||||
memset(psp->fence_buf, 0, PSP_FENCE_BUFFER_SIZE);
|
||||
|
||||
ret = psp_tmr_init(psp);
|
||||
if (ret)
|
||||
goto failed_mem;
|
||||
|
||||
ret = psp_asd_load(psp);
|
||||
if (ret)
|
||||
goto failed_mem;
|
||||
|
||||
for (i = 0; i < adev->firmware.max_ucodes; i++) {
|
||||
ucode = &adev->firmware.ucode[i];
|
||||
if (!ucode->fw)
|
||||
continue;
|
||||
|
||||
if (ucode->ucode_id == AMDGPU_UCODE_ID_SMC &&
|
||||
psp_smu_reload_quirk(psp))
|
||||
continue;
|
||||
|
||||
ret = psp_prep_cmd_buf(ucode, cmd);
|
||||
if (ret)
|
||||
goto failed_mem;
|
||||
|
||||
ret = psp_cmd_submit_buf(psp, ucode, cmd,
|
||||
psp->fence_buf_mc_addr, i + 3);
|
||||
if (ret)
|
||||
goto failed_mem;
|
||||
|
||||
#if 0
|
||||
/* check if firmware loaded sucessfully */
|
||||
if (!amdgpu_psp_check_fw_loading_status(adev, i))
|
||||
return -EINVAL;
|
||||
#endif
|
||||
}
|
||||
|
||||
amdgpu_bo_free_kernel(&psp->fence_buf_bo,
|
||||
&psp->fence_buf_mc_addr, &psp->fence_buf);
|
||||
kfree(cmd);
|
||||
|
||||
return 0;
|
||||
|
||||
failed_mem:
|
||||
amdgpu_bo_free_kernel(&psp->fence_buf_bo,
|
||||
&psp->fence_buf_mc_addr, &psp->fence_buf);
|
||||
failed:
|
||||
kfree(cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int psp_hw_init(void *handle)
|
||||
{
|
||||
int ret;
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
|
||||
if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&adev->firmware.mutex);
|
||||
/*
|
||||
* This sequence is just used on hw_init only once, no need on
|
||||
* resume.
|
||||
*/
|
||||
ret = amdgpu_ucode_init_bo(adev);
|
||||
if (ret)
|
||||
goto failed;
|
||||
|
||||
ret = psp_load_fw(adev);
|
||||
if (ret) {
|
||||
DRM_ERROR("PSP firmware loading failed\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
mutex_unlock(&adev->firmware.mutex);
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
adev->firmware.load_type = AMDGPU_FW_LOAD_DIRECT;
|
||||
mutex_unlock(&adev->firmware.mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int psp_hw_fini(void *handle)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
struct psp_context *psp = &adev->psp;
|
||||
|
||||
if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP)
|
||||
amdgpu_ucode_fini_bo(adev);
|
||||
|
||||
if (psp->tmr_buf)
|
||||
amdgpu_bo_free_kernel(&psp->tmr_bo, &psp->tmr_mc_addr, &psp->tmr_buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int psp_suspend(void *handle)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int psp_resume(void *handle)
|
||||
{
|
||||
int ret;
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&adev->firmware.mutex);
|
||||
|
||||
ret = psp_load_fw(adev);
|
||||
if (ret)
|
||||
DRM_ERROR("PSP resume failed\n");
|
||||
|
||||
mutex_unlock(&adev->firmware.mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool psp_check_fw_loading_status(struct amdgpu_device *adev,
|
||||
enum AMDGPU_UCODE_ID ucode_type)
|
||||
{
|
||||
struct amdgpu_firmware_info *ucode = NULL;
|
||||
|
||||
if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) {
|
||||
DRM_INFO("firmware is not loaded by PSP\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!adev->firmware.fw_size)
|
||||
return false;
|
||||
|
||||
ucode = &adev->firmware.ucode[ucode_type];
|
||||
if (!ucode->fw || !ucode->ucode_size)
|
||||
return false;
|
||||
|
||||
return psp_compare_sram_data(&adev->psp, ucode, ucode_type);
|
||||
}
|
||||
|
||||
static int psp_set_clockgating_state(void *handle,
|
||||
enum amd_clockgating_state state)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int psp_set_powergating_state(void *handle,
|
||||
enum amd_powergating_state state)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct amd_ip_funcs psp_ip_funcs = {
|
||||
.name = "psp",
|
||||
.early_init = psp_early_init,
|
||||
.late_init = NULL,
|
||||
.sw_init = psp_sw_init,
|
||||
.sw_fini = psp_sw_fini,
|
||||
.hw_init = psp_hw_init,
|
||||
.hw_fini = psp_hw_fini,
|
||||
.suspend = psp_suspend,
|
||||
.resume = psp_resume,
|
||||
.is_idle = NULL,
|
||||
.wait_for_idle = NULL,
|
||||
.soft_reset = NULL,
|
||||
.set_clockgating_state = psp_set_clockgating_state,
|
||||
.set_powergating_state = psp_set_powergating_state,
|
||||
};
|
||||
|
||||
static const struct amdgpu_psp_funcs psp_funcs = {
|
||||
.check_fw_loading_status = psp_check_fw_loading_status,
|
||||
};
|
||||
|
||||
static void psp_set_funcs(struct amdgpu_device *adev)
|
||||
{
|
||||
if (NULL == adev->firmware.funcs)
|
||||
adev->firmware.funcs = &psp_funcs;
|
||||
}
|
||||
|
||||
const struct amdgpu_ip_block_version psp_v3_1_ip_block =
|
||||
{
|
||||
.type = AMD_IP_BLOCK_TYPE_PSP,
|
||||
.major = 3,
|
||||
.minor = 1,
|
||||
.rev = 0,
|
||||
.funcs = &psp_ip_funcs,
|
||||
};
|
127
drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
Normal file
127
drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
Normal file
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright 2016 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.
|
||||
*
|
||||
* Author: Huang Rui
|
||||
*
|
||||
*/
|
||||
#ifndef __AMDGPU_PSP_H__
|
||||
#define __AMDGPU_PSP_H__
|
||||
|
||||
#include "amdgpu.h"
|
||||
#include "psp_gfx_if.h"
|
||||
|
||||
#define PSP_FENCE_BUFFER_SIZE 0x1000
|
||||
#define PSP_CMD_BUFFER_SIZE 0x1000
|
||||
#define PSP_ASD_BIN_SIZE 0x40000
|
||||
#define PSP_ASD_SHARED_MEM_SIZE 0x4000
|
||||
|
||||
enum psp_ring_type
|
||||
{
|
||||
PSP_RING_TYPE__INVALID = 0,
|
||||
/*
|
||||
* These values map to the way the PSP kernel identifies the
|
||||
* rings.
|
||||
*/
|
||||
PSP_RING_TYPE__UM = 1, /* User mode ring (formerly called RBI) */
|
||||
PSP_RING_TYPE__KM = 2 /* Kernel mode ring (formerly called GPCOM) */
|
||||
};
|
||||
|
||||
struct psp_ring
|
||||
{
|
||||
enum psp_ring_type ring_type;
|
||||
struct psp_gfx_rb_frame *ring_mem;
|
||||
uint64_t ring_mem_mc_addr;
|
||||
void *ring_mem_handle;
|
||||
uint32_t ring_size;
|
||||
};
|
||||
|
||||
struct psp_context
|
||||
{
|
||||
struct amdgpu_device *adev;
|
||||
struct psp_ring km_ring;
|
||||
|
||||
int (*init_microcode)(struct psp_context *psp);
|
||||
int (*bootloader_load_sysdrv)(struct psp_context *psp);
|
||||
int (*bootloader_load_sos)(struct psp_context *psp);
|
||||
int (*prep_cmd_buf)(struct amdgpu_firmware_info *ucode,
|
||||
struct psp_gfx_cmd_resp *cmd);
|
||||
int (*ring_init)(struct psp_context *psp, enum psp_ring_type ring_type);
|
||||
int (*cmd_submit)(struct psp_context *psp, struct amdgpu_firmware_info *ucode,
|
||||
uint64_t cmd_buf_mc_addr, uint64_t fence_mc_addr, int index);
|
||||
bool (*compare_sram_data)(struct psp_context *psp,
|
||||
struct amdgpu_firmware_info *ucode,
|
||||
enum AMDGPU_UCODE_ID ucode_type);
|
||||
bool (*smu_reload_quirk)(struct psp_context *psp);
|
||||
|
||||
/* sos firmware */
|
||||
const struct firmware *sos_fw;
|
||||
uint32_t sos_fw_version;
|
||||
uint32_t sos_feature_version;
|
||||
uint32_t sys_bin_size;
|
||||
uint32_t sos_bin_size;
|
||||
uint8_t *sys_start_addr;
|
||||
uint8_t *sos_start_addr;
|
||||
|
||||
/* tmr buffer */
|
||||
struct amdgpu_bo *tmr_bo;
|
||||
uint64_t tmr_mc_addr;
|
||||
void *tmr_buf;
|
||||
|
||||
/* asd firmware */
|
||||
const struct firmware *asd_fw;
|
||||
uint32_t asd_fw_version;
|
||||
uint32_t asd_feature_version;
|
||||
uint32_t asd_ucode_size;
|
||||
uint8_t *asd_start_addr;
|
||||
|
||||
/* fence buffer */
|
||||
struct amdgpu_bo *fence_buf_bo;
|
||||
uint64_t fence_buf_mc_addr;
|
||||
void *fence_buf;
|
||||
};
|
||||
|
||||
struct amdgpu_psp_funcs {
|
||||
bool (*check_fw_loading_status)(struct amdgpu_device *adev,
|
||||
enum AMDGPU_UCODE_ID);
|
||||
};
|
||||
|
||||
#define psp_prep_cmd_buf(ucode, type) (psp)->prep_cmd_buf((ucode), (type))
|
||||
#define psp_ring_init(psp, type) (psp)->ring_init((psp), (type))
|
||||
#define psp_cmd_submit(psp, ucode, cmd_mc, fence_mc, index) \
|
||||
(psp)->cmd_submit((psp), (ucode), (cmd_mc), (fence_mc), (index))
|
||||
#define psp_compare_sram_data(psp, ucode, type) \
|
||||
(psp)->compare_sram_data((psp), (ucode), (type))
|
||||
#define psp_init_microcode(psp) \
|
||||
((psp)->init_microcode ? (psp)->init_microcode((psp)) : 0)
|
||||
#define psp_bootloader_load_sysdrv(psp) \
|
||||
((psp)->bootloader_load_sysdrv ? (psp)->bootloader_load_sysdrv((psp)) : 0)
|
||||
#define psp_bootloader_load_sos(psp) \
|
||||
((psp)->bootloader_load_sos ? (psp)->bootloader_load_sos((psp)) : 0)
|
||||
#define psp_smu_reload_quirk(psp) \
|
||||
((psp)->smu_reload_quirk ? (psp)->smu_reload_quirk((psp)) : false)
|
||||
|
||||
extern const struct amd_ip_funcs psp_ip_funcs;
|
||||
|
||||
extern const struct amdgpu_ip_block_version psp_v3_1_ip_block;
|
||||
extern int psp_wait_for(struct psp_context *psp, uint32_t reg_index,
|
||||
uint32_t field_val, uint32_t mask, bool check_changed);
|
||||
|
||||
#endif
|
@ -182,16 +182,32 @@ int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring,
|
||||
return r;
|
||||
}
|
||||
|
||||
r = amdgpu_wb_get(adev, &ring->rptr_offs);
|
||||
if (r) {
|
||||
dev_err(adev->dev, "(%d) ring rptr_offs wb alloc failed\n", r);
|
||||
return r;
|
||||
}
|
||||
if (ring->funcs->support_64bit_ptrs) {
|
||||
r = amdgpu_wb_get_64bit(adev, &ring->rptr_offs);
|
||||
if (r) {
|
||||
dev_err(adev->dev, "(%d) ring rptr_offs wb alloc failed\n", r);
|
||||
return r;
|
||||
}
|
||||
|
||||
r = amdgpu_wb_get_64bit(adev, &ring->wptr_offs);
|
||||
if (r) {
|
||||
dev_err(adev->dev, "(%d) ring wptr_offs wb alloc failed\n", r);
|
||||
return r;
|
||||
}
|
||||
|
||||
} else {
|
||||
r = amdgpu_wb_get(adev, &ring->rptr_offs);
|
||||
if (r) {
|
||||
dev_err(adev->dev, "(%d) ring rptr_offs wb alloc failed\n", r);
|
||||
return r;
|
||||
}
|
||||
|
||||
r = amdgpu_wb_get(adev, &ring->wptr_offs);
|
||||
if (r) {
|
||||
dev_err(adev->dev, "(%d) ring wptr_offs wb alloc failed\n", r);
|
||||
return r;
|
||||
}
|
||||
|
||||
r = amdgpu_wb_get(adev, &ring->wptr_offs);
|
||||
if (r) {
|
||||
dev_err(adev->dev, "(%d) ring wptr_offs wb alloc failed\n", r);
|
||||
return r;
|
||||
}
|
||||
|
||||
r = amdgpu_wb_get(adev, &ring->fence_offs);
|
||||
@ -219,6 +235,9 @@ int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring,
|
||||
ring->ring_size = roundup_pow_of_two(max_dw * 4 *
|
||||
amdgpu_sched_hw_submission);
|
||||
|
||||
ring->buf_mask = (ring->ring_size / 4) - 1;
|
||||
ring->ptr_mask = ring->funcs->support_64bit_ptrs ?
|
||||
0xffffffffffffffff : ring->buf_mask;
|
||||
/* Allocate ring buffer */
|
||||
if (ring->ring_obj == NULL) {
|
||||
r = amdgpu_bo_create_kernel(adev, ring->ring_size, PAGE_SIZE,
|
||||
@ -230,9 +249,9 @@ int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring,
|
||||
dev_err(adev->dev, "(%d) ring create failed\n", r);
|
||||
return r;
|
||||
}
|
||||
memset((void *)ring->ring, 0, ring->ring_size);
|
||||
amdgpu_ring_clear_ring(ring);
|
||||
}
|
||||
ring->ptr_mask = (ring->ring_size / 4) - 1;
|
||||
|
||||
ring->max_dw = max_dw;
|
||||
|
||||
if (amdgpu_debugfs_ring_init(adev, ring)) {
|
||||
@ -253,10 +272,18 @@ void amdgpu_ring_fini(struct amdgpu_ring *ring)
|
||||
{
|
||||
ring->ready = false;
|
||||
|
||||
amdgpu_wb_free(ring->adev, ring->cond_exe_offs);
|
||||
amdgpu_wb_free(ring->adev, ring->fence_offs);
|
||||
amdgpu_wb_free(ring->adev, ring->rptr_offs);
|
||||
amdgpu_wb_free(ring->adev, ring->wptr_offs);
|
||||
if (ring->funcs->support_64bit_ptrs) {
|
||||
amdgpu_wb_free_64bit(ring->adev, ring->cond_exe_offs);
|
||||
amdgpu_wb_free_64bit(ring->adev, ring->fence_offs);
|
||||
amdgpu_wb_free_64bit(ring->adev, ring->rptr_offs);
|
||||
amdgpu_wb_free_64bit(ring->adev, ring->wptr_offs);
|
||||
} else {
|
||||
amdgpu_wb_free(ring->adev, ring->cond_exe_offs);
|
||||
amdgpu_wb_free(ring->adev, ring->fence_offs);
|
||||
amdgpu_wb_free(ring->adev, ring->rptr_offs);
|
||||
amdgpu_wb_free(ring->adev, ring->wptr_offs);
|
||||
}
|
||||
|
||||
|
||||
amdgpu_bo_free_kernel(&ring->ring_obj,
|
||||
&ring->gpu_addr,
|
||||
@ -293,8 +320,8 @@ static ssize_t amdgpu_debugfs_ring_read(struct file *f, char __user *buf,
|
||||
|
||||
if (*pos < 12) {
|
||||
early[0] = amdgpu_ring_get_rptr(ring);
|
||||
early[1] = amdgpu_ring_get_wptr(ring);
|
||||
early[2] = ring->wptr;
|
||||
early[1] = amdgpu_ring_get_wptr(ring) & ring->buf_mask;
|
||||
early[2] = ring->wptr & ring->buf_mask;
|
||||
for (i = *pos / 4; i < 3 && size; i++) {
|
||||
r = put_user(early[i], (uint32_t *)buf);
|
||||
if (r)
|
||||
|
@ -27,10 +27,11 @@
|
||||
#include "gpu_scheduler.h"
|
||||
|
||||
/* max number of rings */
|
||||
#define AMDGPU_MAX_RINGS 16
|
||||
#define AMDGPU_MAX_RINGS 18
|
||||
#define AMDGPU_MAX_GFX_RINGS 1
|
||||
#define AMDGPU_MAX_COMPUTE_RINGS 8
|
||||
#define AMDGPU_MAX_VCE_RINGS 3
|
||||
#define AMDGPU_MAX_UVD_ENC_RINGS 2
|
||||
|
||||
/* some special values for the owner field */
|
||||
#define AMDGPU_FENCE_OWNER_UNDEFINED ((void*)0ul)
|
||||
@ -45,7 +46,8 @@ enum amdgpu_ring_type {
|
||||
AMDGPU_RING_TYPE_SDMA,
|
||||
AMDGPU_RING_TYPE_UVD,
|
||||
AMDGPU_RING_TYPE_VCE,
|
||||
AMDGPU_RING_TYPE_KIQ
|
||||
AMDGPU_RING_TYPE_KIQ,
|
||||
AMDGPU_RING_TYPE_UVD_ENC
|
||||
};
|
||||
|
||||
struct amdgpu_device;
|
||||
@ -96,10 +98,11 @@ struct amdgpu_ring_funcs {
|
||||
enum amdgpu_ring_type type;
|
||||
uint32_t align_mask;
|
||||
u32 nop;
|
||||
bool support_64bit_ptrs;
|
||||
|
||||
/* ring read/write ptr handling */
|
||||
u32 (*get_rptr)(struct amdgpu_ring *ring);
|
||||
u32 (*get_wptr)(struct amdgpu_ring *ring);
|
||||
u64 (*get_rptr)(struct amdgpu_ring *ring);
|
||||
u64 (*get_wptr)(struct amdgpu_ring *ring);
|
||||
void (*set_wptr)(struct amdgpu_ring *ring);
|
||||
/* validating and patching of IBs */
|
||||
int (*parse_cs)(struct amdgpu_cs_parser *p, uint32_t ib_idx);
|
||||
@ -126,6 +129,7 @@ struct amdgpu_ring_funcs {
|
||||
int (*test_ib)(struct amdgpu_ring *ring, long timeout);
|
||||
/* insert NOP packets */
|
||||
void (*insert_nop)(struct amdgpu_ring *ring, uint32_t count);
|
||||
void (*insert_end)(struct amdgpu_ring *ring);
|
||||
/* pad the indirect buffer to the necessary number of dw */
|
||||
void (*pad_ib)(struct amdgpu_ring *ring, struct amdgpu_ib *ib);
|
||||
unsigned (*init_cond_exec)(struct amdgpu_ring *ring);
|
||||
@ -148,19 +152,23 @@ struct amdgpu_ring {
|
||||
struct amdgpu_bo *ring_obj;
|
||||
volatile uint32_t *ring;
|
||||
unsigned rptr_offs;
|
||||
unsigned wptr;
|
||||
unsigned wptr_old;
|
||||
u64 wptr;
|
||||
u64 wptr_old;
|
||||
unsigned ring_size;
|
||||
unsigned max_dw;
|
||||
int count_dw;
|
||||
uint64_t gpu_addr;
|
||||
uint32_t ptr_mask;
|
||||
uint64_t ptr_mask;
|
||||
uint32_t buf_mask;
|
||||
bool ready;
|
||||
u32 idx;
|
||||
u32 me;
|
||||
u32 pipe;
|
||||
u32 queue;
|
||||
struct amdgpu_bo *mqd_obj;
|
||||
uint64_t mqd_gpu_addr;
|
||||
void *mqd_ptr;
|
||||
uint64_t eop_gpu_addr;
|
||||
u32 doorbell_index;
|
||||
bool use_doorbell;
|
||||
unsigned wptr_offs;
|
||||
@ -184,5 +192,12 @@ int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring,
|
||||
unsigned ring_size, struct amdgpu_irq_src *irq_src,
|
||||
unsigned irq_type);
|
||||
void amdgpu_ring_fini(struct amdgpu_ring *ring);
|
||||
static inline void amdgpu_ring_clear_ring(struct amdgpu_ring *ring)
|
||||
{
|
||||
int i = 0;
|
||||
while (i <= ring->buf_mask)
|
||||
ring->ring[i++] = ring->funcs->nop;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -228,7 +228,7 @@ out_unref:
|
||||
out_cleanup:
|
||||
kfree(gtt_obj);
|
||||
if (r) {
|
||||
printk(KERN_WARNING "Error while testing BO move.\n");
|
||||
pr_warn("Error while testing BO move\n");
|
||||
}
|
||||
}
|
||||
|
||||
@ -237,82 +237,3 @@ void amdgpu_test_moves(struct amdgpu_device *adev)
|
||||
if (adev->mman.buffer_funcs)
|
||||
amdgpu_do_test_moves(adev);
|
||||
}
|
||||
|
||||
void amdgpu_test_ring_sync(struct amdgpu_device *adev,
|
||||
struct amdgpu_ring *ringA,
|
||||
struct amdgpu_ring *ringB)
|
||||
{
|
||||
}
|
||||
|
||||
static void amdgpu_test_ring_sync2(struct amdgpu_device *adev,
|
||||
struct amdgpu_ring *ringA,
|
||||
struct amdgpu_ring *ringB,
|
||||
struct amdgpu_ring *ringC)
|
||||
{
|
||||
}
|
||||
|
||||
static bool amdgpu_test_sync_possible(struct amdgpu_ring *ringA,
|
||||
struct amdgpu_ring *ringB)
|
||||
{
|
||||
if (ringA == &ringA->adev->vce.ring[0] &&
|
||||
ringB == &ringB->adev->vce.ring[1])
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void amdgpu_test_syncing(struct amdgpu_device *adev)
|
||||
{
|
||||
int i, j, k;
|
||||
|
||||
for (i = 1; i < AMDGPU_MAX_RINGS; ++i) {
|
||||
struct amdgpu_ring *ringA = adev->rings[i];
|
||||
if (!ringA || !ringA->ready)
|
||||
continue;
|
||||
|
||||
for (j = 0; j < i; ++j) {
|
||||
struct amdgpu_ring *ringB = adev->rings[j];
|
||||
if (!ringB || !ringB->ready)
|
||||
continue;
|
||||
|
||||
if (!amdgpu_test_sync_possible(ringA, ringB))
|
||||
continue;
|
||||
|
||||
DRM_INFO("Testing syncing between rings %d and %d...\n", i, j);
|
||||
amdgpu_test_ring_sync(adev, ringA, ringB);
|
||||
|
||||
DRM_INFO("Testing syncing between rings %d and %d...\n", j, i);
|
||||
amdgpu_test_ring_sync(adev, ringB, ringA);
|
||||
|
||||
for (k = 0; k < j; ++k) {
|
||||
struct amdgpu_ring *ringC = adev->rings[k];
|
||||
if (!ringC || !ringC->ready)
|
||||
continue;
|
||||
|
||||
if (!amdgpu_test_sync_possible(ringA, ringC))
|
||||
continue;
|
||||
|
||||
if (!amdgpu_test_sync_possible(ringB, ringC))
|
||||
continue;
|
||||
|
||||
DRM_INFO("Testing syncing between rings %d, %d and %d...\n", i, j, k);
|
||||
amdgpu_test_ring_sync2(adev, ringA, ringB, ringC);
|
||||
|
||||
DRM_INFO("Testing syncing between rings %d, %d and %d...\n", i, k, j);
|
||||
amdgpu_test_ring_sync2(adev, ringA, ringC, ringB);
|
||||
|
||||
DRM_INFO("Testing syncing between rings %d, %d and %d...\n", j, i, k);
|
||||
amdgpu_test_ring_sync2(adev, ringB, ringA, ringC);
|
||||
|
||||
DRM_INFO("Testing syncing between rings %d, %d and %d...\n", j, k, i);
|
||||
amdgpu_test_ring_sync2(adev, ringB, ringC, ringA);
|
||||
|
||||
DRM_INFO("Testing syncing between rings %d, %d and %d...\n", k, i, j);
|
||||
amdgpu_test_ring_sync2(adev, ringC, ringA, ringB);
|
||||
|
||||
DRM_INFO("Testing syncing between rings %d, %d and %d...\n", k, j, i);
|
||||
amdgpu_test_ring_sync2(adev, ringC, ringB, ringA);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,9 @@
|
||||
#define TRACE_SYSTEM amdgpu
|
||||
#define TRACE_INCLUDE_FILE amdgpu_trace
|
||||
|
||||
#define AMDGPU_JOB_GET_TIMELINE_NAME(job) \
|
||||
job->base.s_fence->finished.ops->get_timeline_name(&job->base.s_fence->finished)
|
||||
|
||||
TRACE_EVENT(amdgpu_mm_rreg,
|
||||
TP_PROTO(unsigned did, uint32_t reg, uint32_t value),
|
||||
TP_ARGS(did, reg, value),
|
||||
@ -49,6 +52,43 @@ TRACE_EVENT(amdgpu_mm_wreg,
|
||||
(unsigned long)__entry->value)
|
||||
);
|
||||
|
||||
TRACE_EVENT(amdgpu_iv,
|
||||
TP_PROTO(struct amdgpu_iv_entry *iv),
|
||||
TP_ARGS(iv),
|
||||
TP_STRUCT__entry(
|
||||
__field(unsigned, client_id)
|
||||
__field(unsigned, src_id)
|
||||
__field(unsigned, ring_id)
|
||||
__field(unsigned, vm_id)
|
||||
__field(unsigned, vm_id_src)
|
||||
__field(uint64_t, timestamp)
|
||||
__field(unsigned, timestamp_src)
|
||||
__field(unsigned, pas_id)
|
||||
__array(unsigned, src_data, 4)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->client_id = iv->client_id;
|
||||
__entry->src_id = iv->src_id;
|
||||
__entry->ring_id = iv->ring_id;
|
||||
__entry->vm_id = iv->vm_id;
|
||||
__entry->vm_id_src = iv->vm_id_src;
|
||||
__entry->timestamp = iv->timestamp;
|
||||
__entry->timestamp_src = iv->timestamp_src;
|
||||
__entry->pas_id = iv->pas_id;
|
||||
__entry->src_data[0] = iv->src_data[0];
|
||||
__entry->src_data[1] = iv->src_data[1];
|
||||
__entry->src_data[2] = iv->src_data[2];
|
||||
__entry->src_data[3] = iv->src_data[3];
|
||||
),
|
||||
TP_printk("client_id:%u src_id:%u ring:%u vm_id:%u timestamp: %llu pas_id:%u src_data: %08x %08x %08x %08x\n",
|
||||
__entry->client_id, __entry->src_id,
|
||||
__entry->ring_id, __entry->vm_id,
|
||||
__entry->timestamp, __entry->pas_id,
|
||||
__entry->src_data[0], __entry->src_data[1],
|
||||
__entry->src_data[2], __entry->src_data[3])
|
||||
);
|
||||
|
||||
|
||||
TRACE_EVENT(amdgpu_bo_create,
|
||||
TP_PROTO(struct amdgpu_bo *bo),
|
||||
TP_ARGS(bo),
|
||||
@ -70,7 +110,7 @@ TRACE_EVENT(amdgpu_bo_create,
|
||||
__entry->visible = bo->flags;
|
||||
),
|
||||
|
||||
TP_printk("bo=%p,pages=%u,type=%d,prefered=%d,allowed=%d,visible=%d",
|
||||
TP_printk("bo=%p, pages=%u, type=%d, prefered=%d, allowed=%d, visible=%d",
|
||||
__entry->bo, __entry->pages, __entry->type,
|
||||
__entry->prefer, __entry->allow, __entry->visible)
|
||||
);
|
||||
@ -101,50 +141,51 @@ TRACE_EVENT(amdgpu_cs_ioctl,
|
||||
TP_PROTO(struct amdgpu_job *job),
|
||||
TP_ARGS(job),
|
||||
TP_STRUCT__entry(
|
||||
__field(struct amdgpu_device *, adev)
|
||||
__field(struct amd_sched_job *, sched_job)
|
||||
__field(struct amdgpu_ib *, ib)
|
||||
__field(uint64_t, sched_job_id)
|
||||
__string(timeline, AMDGPU_JOB_GET_TIMELINE_NAME(job))
|
||||
__field(unsigned int, context)
|
||||
__field(unsigned int, seqno)
|
||||
__field(struct dma_fence *, fence)
|
||||
__field(char *, ring_name)
|
||||
__field(u32, num_ibs)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->adev = job->adev;
|
||||
__entry->sched_job = &job->base;
|
||||
__entry->ib = job->ibs;
|
||||
__entry->fence = &job->base.s_fence->finished;
|
||||
__entry->sched_job_id = job->base.id;
|
||||
__assign_str(timeline, AMDGPU_JOB_GET_TIMELINE_NAME(job))
|
||||
__entry->context = job->base.s_fence->finished.context;
|
||||
__entry->seqno = job->base.s_fence->finished.seqno;
|
||||
__entry->ring_name = job->ring->name;
|
||||
__entry->num_ibs = job->num_ibs;
|
||||
),
|
||||
TP_printk("adev=%p, sched_job=%p, first ib=%p, sched fence=%p, ring name:%s, num_ibs:%u",
|
||||
__entry->adev, __entry->sched_job, __entry->ib,
|
||||
__entry->fence, __entry->ring_name, __entry->num_ibs)
|
||||
TP_printk("sched_job=%llu, timeline=%s, context=%u, seqno=%u, ring_name=%s, num_ibs=%u",
|
||||
__entry->sched_job_id, __get_str(timeline), __entry->context,
|
||||
__entry->seqno, __entry->ring_name, __entry->num_ibs)
|
||||
);
|
||||
|
||||
TRACE_EVENT(amdgpu_sched_run_job,
|
||||
TP_PROTO(struct amdgpu_job *job),
|
||||
TP_ARGS(job),
|
||||
TP_STRUCT__entry(
|
||||
__field(struct amdgpu_device *, adev)
|
||||
__field(struct amd_sched_job *, sched_job)
|
||||
__field(struct amdgpu_ib *, ib)
|
||||
__field(struct dma_fence *, fence)
|
||||
__field(uint64_t, sched_job_id)
|
||||
__string(timeline, AMDGPU_JOB_GET_TIMELINE_NAME(job))
|
||||
__field(unsigned int, context)
|
||||
__field(unsigned int, seqno)
|
||||
__field(char *, ring_name)
|
||||
__field(u32, num_ibs)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->adev = job->adev;
|
||||
__entry->sched_job = &job->base;
|
||||
__entry->ib = job->ibs;
|
||||
__entry->fence = &job->base.s_fence->finished;
|
||||
__entry->sched_job_id = job->base.id;
|
||||
__assign_str(timeline, AMDGPU_JOB_GET_TIMELINE_NAME(job))
|
||||
__entry->context = job->base.s_fence->finished.context;
|
||||
__entry->seqno = job->base.s_fence->finished.seqno;
|
||||
__entry->ring_name = job->ring->name;
|
||||
__entry->num_ibs = job->num_ibs;
|
||||
),
|
||||
TP_printk("adev=%p, sched_job=%p, first ib=%p, sched fence=%p, ring name:%s, num_ibs:%u",
|
||||
__entry->adev, __entry->sched_job, __entry->ib,
|
||||
__entry->fence, __entry->ring_name, __entry->num_ibs)
|
||||
TP_printk("sched_job=%llu, timeline=%s, context=%u, seqno=%u, ring_name=%s, num_ibs=%u",
|
||||
__entry->sched_job_id, __get_str(timeline), __entry->context,
|
||||
__entry->seqno, __entry->ring_name, __entry->num_ibs)
|
||||
);
|
||||
|
||||
|
||||
@ -184,9 +225,9 @@ TRACE_EVENT(amdgpu_vm_bo_map,
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->bo = bo_va->bo;
|
||||
__entry->start = mapping->it.start;
|
||||
__entry->last = mapping->it.last;
|
||||
__entry->bo = bo_va ? bo_va->bo : NULL;
|
||||
__entry->start = mapping->start;
|
||||
__entry->last = mapping->last;
|
||||
__entry->offset = mapping->offset;
|
||||
__entry->flags = mapping->flags;
|
||||
),
|
||||
@ -209,8 +250,8 @@ TRACE_EVENT(amdgpu_vm_bo_unmap,
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->bo = bo_va->bo;
|
||||
__entry->start = mapping->it.start;
|
||||
__entry->last = mapping->it.last;
|
||||
__entry->start = mapping->start;
|
||||
__entry->last = mapping->last;
|
||||
__entry->offset = mapping->offset;
|
||||
__entry->flags = mapping->flags;
|
||||
),
|
||||
@ -229,8 +270,8 @@ DECLARE_EVENT_CLASS(amdgpu_vm_mapping,
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->soffset = mapping->it.start;
|
||||
__entry->eoffset = mapping->it.last + 1;
|
||||
__entry->soffset = mapping->start;
|
||||
__entry->eoffset = mapping->last + 1;
|
||||
__entry->flags = mapping->flags;
|
||||
),
|
||||
TP_printk("soffs=%010llx, eoffs=%010llx, flags=%08x",
|
||||
@ -321,7 +362,7 @@ TRACE_EVENT(amdgpu_bo_list_set,
|
||||
__entry->bo = bo;
|
||||
__entry->bo_size = amdgpu_bo_size(bo);
|
||||
),
|
||||
TP_printk("list=%p, bo=%p, bo_size = %Ld",
|
||||
TP_printk("list=%p, bo=%p, bo_size=%Ld",
|
||||
__entry->list,
|
||||
__entry->bo,
|
||||
__entry->bo_size)
|
||||
@ -339,7 +380,7 @@ TRACE_EVENT(amdgpu_cs_bo_status,
|
||||
__entry->total_bo = total_bo;
|
||||
__entry->total_size = total_size;
|
||||
),
|
||||
TP_printk("total bo size = %Ld, total bo count = %Ld",
|
||||
TP_printk("total_bo_size=%Ld, total_bo_count=%Ld",
|
||||
__entry->total_bo, __entry->total_size)
|
||||
);
|
||||
|
||||
@ -359,11 +400,12 @@ TRACE_EVENT(amdgpu_ttm_bo_move,
|
||||
__entry->new_placement = new_placement;
|
||||
__entry->old_placement = old_placement;
|
||||
),
|
||||
TP_printk("bo=%p from:%d to %d with size = %Ld",
|
||||
TP_printk("bo=%p, from=%d, to=%d, size=%Ld",
|
||||
__entry->bo, __entry->old_placement,
|
||||
__entry->new_placement, __entry->bo_size)
|
||||
);
|
||||
|
||||
#undef AMDGPU_JOB_GET_TIMELINE_NAME
|
||||
#endif
|
||||
|
||||
/* This part must be outside protection */
|
||||
|
@ -529,40 +529,12 @@ static int amdgpu_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_
|
||||
case TTM_PL_TT:
|
||||
break;
|
||||
case TTM_PL_VRAM:
|
||||
if (mem->start == AMDGPU_BO_INVALID_OFFSET)
|
||||
return -EINVAL;
|
||||
|
||||
mem->bus.offset = mem->start << PAGE_SHIFT;
|
||||
/* check if it's visible */
|
||||
if ((mem->bus.offset + mem->bus.size) > adev->mc.visible_vram_size)
|
||||
return -EINVAL;
|
||||
mem->bus.base = adev->mc.aper_base;
|
||||
mem->bus.is_iomem = true;
|
||||
#ifdef __alpha__
|
||||
/*
|
||||
* Alpha: use bus.addr to hold the ioremap() return,
|
||||
* so we can modify bus.base below.
|
||||
*/
|
||||
if (mem->placement & TTM_PL_FLAG_WC)
|
||||
mem->bus.addr =
|
||||
ioremap_wc(mem->bus.base + mem->bus.offset,
|
||||
mem->bus.size);
|
||||
else
|
||||
mem->bus.addr =
|
||||
ioremap_nocache(mem->bus.base + mem->bus.offset,
|
||||
mem->bus.size);
|
||||
if (!mem->bus.addr)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* Alpha: Use just the bus offset plus
|
||||
* the hose/domain memory base for bus.base.
|
||||
* It then can be used to build PTEs for VRAM
|
||||
* access, as done in ttm_bo_vm_fault().
|
||||
*/
|
||||
mem->bus.base = (mem->bus.base & 0x0ffffffffUL) +
|
||||
adev->ddev->hose->dense_mem_base;
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
@ -574,6 +546,18 @@ static void amdgpu_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_re
|
||||
{
|
||||
}
|
||||
|
||||
static unsigned long amdgpu_ttm_io_mem_pfn(struct ttm_buffer_object *bo,
|
||||
unsigned long page_offset)
|
||||
{
|
||||
struct drm_mm_node *mm = bo->mem.mm_node;
|
||||
uint64_t size = mm->size;
|
||||
uint64_t offset = page_offset;
|
||||
|
||||
page_offset = do_div(offset, size);
|
||||
mm += offset;
|
||||
return (bo->mem.bus.base >> PAGE_SHIFT) + mm->start + page_offset;
|
||||
}
|
||||
|
||||
/*
|
||||
* TTM backend functions.
|
||||
*/
|
||||
@ -746,7 +730,7 @@ int amdgpu_ttm_bind(struct ttm_buffer_object *bo, struct ttm_mem_reg *bo_mem)
|
||||
{
|
||||
struct ttm_tt *ttm = bo->ttm;
|
||||
struct amdgpu_ttm_tt *gtt = (void *)bo->ttm;
|
||||
uint32_t flags;
|
||||
uint64_t flags;
|
||||
int r;
|
||||
|
||||
if (!ttm || amdgpu_ttm_is_bound(ttm))
|
||||
@ -1027,10 +1011,10 @@ bool amdgpu_ttm_tt_is_readonly(struct ttm_tt *ttm)
|
||||
return !!(gtt->userflags & AMDGPU_GEM_USERPTR_READONLY);
|
||||
}
|
||||
|
||||
uint32_t amdgpu_ttm_tt_pte_flags(struct amdgpu_device *adev, struct ttm_tt *ttm,
|
||||
uint64_t amdgpu_ttm_tt_pte_flags(struct amdgpu_device *adev, struct ttm_tt *ttm,
|
||||
struct ttm_mem_reg *mem)
|
||||
{
|
||||
uint32_t flags = 0;
|
||||
uint64_t flags = 0;
|
||||
|
||||
if (mem && mem->mem_type != TTM_PL_SYSTEM)
|
||||
flags |= AMDGPU_PTE_VALID;
|
||||
@ -1042,9 +1026,7 @@ uint32_t amdgpu_ttm_tt_pte_flags(struct amdgpu_device *adev, struct ttm_tt *ttm,
|
||||
flags |= AMDGPU_PTE_SNOOPED;
|
||||
}
|
||||
|
||||
if (adev->asic_type >= CHIP_TONGA)
|
||||
flags |= AMDGPU_PTE_EXECUTABLE;
|
||||
|
||||
flags |= adev->gart.gart_pte_flags;
|
||||
flags |= AMDGPU_PTE_READABLE;
|
||||
|
||||
if (!amdgpu_ttm_tt_is_readonly(ttm))
|
||||
@ -1091,6 +1073,7 @@ static struct ttm_bo_driver amdgpu_bo_driver = {
|
||||
.fault_reserve_notify = &amdgpu_bo_fault_reserve_notify,
|
||||
.io_mem_reserve = &amdgpu_ttm_io_mem_reserve,
|
||||
.io_mem_free = &amdgpu_ttm_io_mem_free,
|
||||
.io_mem_pfn = amdgpu_ttm_io_mem_pfn,
|
||||
};
|
||||
|
||||
int amdgpu_ttm_init(struct amdgpu_device *adev)
|
||||
@ -1160,27 +1143,33 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
|
||||
adev->gds.oa.gfx_partition_size = adev->gds.oa.gfx_partition_size << AMDGPU_OA_SHIFT;
|
||||
adev->gds.oa.cs_partition_size = adev->gds.oa.cs_partition_size << AMDGPU_OA_SHIFT;
|
||||
/* GDS Memory */
|
||||
r = ttm_bo_init_mm(&adev->mman.bdev, AMDGPU_PL_GDS,
|
||||
adev->gds.mem.total_size >> PAGE_SHIFT);
|
||||
if (r) {
|
||||
DRM_ERROR("Failed initializing GDS heap.\n");
|
||||
return r;
|
||||
if (adev->gds.mem.total_size) {
|
||||
r = ttm_bo_init_mm(&adev->mman.bdev, AMDGPU_PL_GDS,
|
||||
adev->gds.mem.total_size >> PAGE_SHIFT);
|
||||
if (r) {
|
||||
DRM_ERROR("Failed initializing GDS heap.\n");
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
/* GWS */
|
||||
r = ttm_bo_init_mm(&adev->mman.bdev, AMDGPU_PL_GWS,
|
||||
adev->gds.gws.total_size >> PAGE_SHIFT);
|
||||
if (r) {
|
||||
DRM_ERROR("Failed initializing gws heap.\n");
|
||||
return r;
|
||||
if (adev->gds.gws.total_size) {
|
||||
r = ttm_bo_init_mm(&adev->mman.bdev, AMDGPU_PL_GWS,
|
||||
adev->gds.gws.total_size >> PAGE_SHIFT);
|
||||
if (r) {
|
||||
DRM_ERROR("Failed initializing gws heap.\n");
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
/* OA */
|
||||
r = ttm_bo_init_mm(&adev->mman.bdev, AMDGPU_PL_OA,
|
||||
adev->gds.oa.total_size >> PAGE_SHIFT);
|
||||
if (r) {
|
||||
DRM_ERROR("Failed initializing oa heap.\n");
|
||||
return r;
|
||||
if (adev->gds.oa.total_size) {
|
||||
r = ttm_bo_init_mm(&adev->mman.bdev, AMDGPU_PL_OA,
|
||||
adev->gds.oa.total_size >> PAGE_SHIFT);
|
||||
if (r) {
|
||||
DRM_ERROR("Failed initializing oa heap.\n");
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
r = amdgpu_ttm_debugfs_init(adev);
|
||||
@ -1208,9 +1197,12 @@ void amdgpu_ttm_fini(struct amdgpu_device *adev)
|
||||
}
|
||||
ttm_bo_clean_mm(&adev->mman.bdev, TTM_PL_VRAM);
|
||||
ttm_bo_clean_mm(&adev->mman.bdev, TTM_PL_TT);
|
||||
ttm_bo_clean_mm(&adev->mman.bdev, AMDGPU_PL_GDS);
|
||||
ttm_bo_clean_mm(&adev->mman.bdev, AMDGPU_PL_GWS);
|
||||
ttm_bo_clean_mm(&adev->mman.bdev, AMDGPU_PL_OA);
|
||||
if (adev->gds.mem.total_size)
|
||||
ttm_bo_clean_mm(&adev->mman.bdev, AMDGPU_PL_GDS);
|
||||
if (adev->gds.gws.total_size)
|
||||
ttm_bo_clean_mm(&adev->mman.bdev, AMDGPU_PL_GWS);
|
||||
if (adev->gds.oa.total_size)
|
||||
ttm_bo_clean_mm(&adev->mman.bdev, AMDGPU_PL_OA);
|
||||
ttm_bo_device_release(&adev->mman.bdev);
|
||||
amdgpu_gart_fini(adev);
|
||||
amdgpu_ttm_global_fini(adev);
|
||||
|
@ -217,10 +217,55 @@ bool amdgpu_ucode_hdr_version(union amdgpu_firmware_header *hdr,
|
||||
return true;
|
||||
}
|
||||
|
||||
static int amdgpu_ucode_init_single_fw(struct amdgpu_firmware_info *ucode,
|
||||
uint64_t mc_addr, void *kptr)
|
||||
enum amdgpu_firmware_load_type
|
||||
amdgpu_ucode_get_load_type(struct amdgpu_device *adev, int load_type)
|
||||
{
|
||||
switch (adev->asic_type) {
|
||||
#ifdef CONFIG_DRM_AMDGPU_SI
|
||||
case CHIP_TAHITI:
|
||||
case CHIP_PITCAIRN:
|
||||
case CHIP_VERDE:
|
||||
case CHIP_OLAND:
|
||||
return AMDGPU_FW_LOAD_DIRECT;
|
||||
#endif
|
||||
#ifdef CONFIG_DRM_AMDGPU_CIK
|
||||
case CHIP_BONAIRE:
|
||||
case CHIP_KAVERI:
|
||||
case CHIP_KABINI:
|
||||
case CHIP_HAWAII:
|
||||
case CHIP_MULLINS:
|
||||
return AMDGPU_FW_LOAD_DIRECT;
|
||||
#endif
|
||||
case CHIP_TOPAZ:
|
||||
case CHIP_TONGA:
|
||||
case CHIP_FIJI:
|
||||
case CHIP_CARRIZO:
|
||||
case CHIP_STONEY:
|
||||
case CHIP_POLARIS10:
|
||||
case CHIP_POLARIS11:
|
||||
case CHIP_POLARIS12:
|
||||
if (!load_type)
|
||||
return AMDGPU_FW_LOAD_DIRECT;
|
||||
else
|
||||
return AMDGPU_FW_LOAD_SMU;
|
||||
case CHIP_VEGA10:
|
||||
if (!load_type)
|
||||
return AMDGPU_FW_LOAD_DIRECT;
|
||||
else
|
||||
return AMDGPU_FW_LOAD_PSP;
|
||||
default:
|
||||
DRM_ERROR("Unknow firmware load type\n");
|
||||
}
|
||||
|
||||
return AMDGPU_FW_LOAD_DIRECT;
|
||||
}
|
||||
|
||||
static int amdgpu_ucode_init_single_fw(struct amdgpu_device *adev,
|
||||
struct amdgpu_firmware_info *ucode,
|
||||
uint64_t mc_addr, void *kptr)
|
||||
{
|
||||
const struct common_firmware_header *header = NULL;
|
||||
const struct gfx_firmware_header_v1_0 *cp_hdr = NULL;
|
||||
|
||||
if (NULL == ucode->fw)
|
||||
return 0;
|
||||
@ -232,9 +277,36 @@ static int amdgpu_ucode_init_single_fw(struct amdgpu_firmware_info *ucode,
|
||||
return 0;
|
||||
|
||||
header = (const struct common_firmware_header *)ucode->fw->data;
|
||||
memcpy(ucode->kaddr, (void *)((uint8_t *)ucode->fw->data +
|
||||
le32_to_cpu(header->ucode_array_offset_bytes)),
|
||||
le32_to_cpu(header->ucode_size_bytes));
|
||||
|
||||
cp_hdr = (const struct gfx_firmware_header_v1_0 *)ucode->fw->data;
|
||||
|
||||
if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP ||
|
||||
(ucode->ucode_id != AMDGPU_UCODE_ID_CP_MEC1 &&
|
||||
ucode->ucode_id != AMDGPU_UCODE_ID_CP_MEC2 &&
|
||||
ucode->ucode_id != AMDGPU_UCODE_ID_CP_MEC1_JT &&
|
||||
ucode->ucode_id != AMDGPU_UCODE_ID_CP_MEC2_JT)) {
|
||||
ucode->ucode_size = le32_to_cpu(header->ucode_size_bytes);
|
||||
|
||||
memcpy(ucode->kaddr, (void *)((uint8_t *)ucode->fw->data +
|
||||
le32_to_cpu(header->ucode_array_offset_bytes)),
|
||||
ucode->ucode_size);
|
||||
} else if (ucode->ucode_id == AMDGPU_UCODE_ID_CP_MEC1 ||
|
||||
ucode->ucode_id == AMDGPU_UCODE_ID_CP_MEC2) {
|
||||
ucode->ucode_size = le32_to_cpu(header->ucode_size_bytes) -
|
||||
le32_to_cpu(cp_hdr->jt_size) * 4;
|
||||
|
||||
memcpy(ucode->kaddr, (void *)((uint8_t *)ucode->fw->data +
|
||||
le32_to_cpu(header->ucode_array_offset_bytes)),
|
||||
ucode->ucode_size);
|
||||
} else if (ucode->ucode_id == AMDGPU_UCODE_ID_CP_MEC1_JT ||
|
||||
ucode->ucode_id == AMDGPU_UCODE_ID_CP_MEC2_JT) {
|
||||
ucode->ucode_size = le32_to_cpu(cp_hdr->jt_size) * 4;
|
||||
|
||||
memcpy(ucode->kaddr, (void *)((uint8_t *)ucode->fw->data +
|
||||
le32_to_cpu(header->ucode_array_offset_bytes) +
|
||||
le32_to_cpu(cp_hdr->jt_offset) * 4),
|
||||
ucode->ucode_size);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -260,10 +332,11 @@ static int amdgpu_ucode_patch_jt(struct amdgpu_firmware_info *ucode,
|
||||
(le32_to_cpu(header->jt_offset) * 4);
|
||||
memcpy(dst_addr, src_addr, le32_to_cpu(header->jt_size) * 4);
|
||||
|
||||
ucode->ucode_size += le32_to_cpu(header->jt_size) * 4;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int amdgpu_ucode_init_bo(struct amdgpu_device *adev)
|
||||
{
|
||||
struct amdgpu_bo **bo = &adev->firmware.fw_buf;
|
||||
@ -303,20 +376,32 @@ int amdgpu_ucode_init_bo(struct amdgpu_device *adev)
|
||||
|
||||
amdgpu_bo_unreserve(*bo);
|
||||
|
||||
for (i = 0; i < AMDGPU_UCODE_ID_MAXIMUM; i++) {
|
||||
memset(fw_buf_ptr, 0, adev->firmware.fw_size);
|
||||
|
||||
/*
|
||||
* if SMU loaded firmware, it needn't add SMC, UVD, and VCE
|
||||
* ucode info here
|
||||
*/
|
||||
if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP)
|
||||
adev->firmware.max_ucodes = AMDGPU_UCODE_ID_MAXIMUM - 4;
|
||||
else
|
||||
adev->firmware.max_ucodes = AMDGPU_UCODE_ID_MAXIMUM;
|
||||
|
||||
for (i = 0; i < adev->firmware.max_ucodes; i++) {
|
||||
ucode = &adev->firmware.ucode[i];
|
||||
if (ucode->fw) {
|
||||
header = (const struct common_firmware_header *)ucode->fw->data;
|
||||
amdgpu_ucode_init_single_fw(ucode, fw_mc_addr + fw_offset,
|
||||
fw_buf_ptr + fw_offset);
|
||||
if (i == AMDGPU_UCODE_ID_CP_MEC1) {
|
||||
amdgpu_ucode_init_single_fw(adev, ucode, fw_mc_addr + fw_offset,
|
||||
(void *)((uint8_t *)fw_buf_ptr + fw_offset));
|
||||
if (i == AMDGPU_UCODE_ID_CP_MEC1 &&
|
||||
adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) {
|
||||
const struct gfx_firmware_header_v1_0 *cp_hdr;
|
||||
cp_hdr = (const struct gfx_firmware_header_v1_0 *)ucode->fw->data;
|
||||
amdgpu_ucode_patch_jt(ucode, fw_mc_addr + fw_offset,
|
||||
fw_buf_ptr + fw_offset);
|
||||
fw_offset += ALIGN(le32_to_cpu(cp_hdr->jt_size) << 2, PAGE_SIZE);
|
||||
}
|
||||
fw_offset += ALIGN(le32_to_cpu(header->ucode_size_bytes), PAGE_SIZE);
|
||||
fw_offset += ALIGN(ucode->ucode_size, PAGE_SIZE);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@ -328,7 +413,8 @@ failed_pin:
|
||||
failed_reserve:
|
||||
amdgpu_bo_unref(bo);
|
||||
failed:
|
||||
adev->firmware.smu_load = false;
|
||||
if (err)
|
||||
adev->firmware.load_type = AMDGPU_FW_LOAD_DIRECT;
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -338,7 +424,7 @@ int amdgpu_ucode_fini_bo(struct amdgpu_device *adev)
|
||||
int i;
|
||||
struct amdgpu_firmware_info *ucode = NULL;
|
||||
|
||||
for (i = 0; i < AMDGPU_UCODE_ID_MAXIMUM; i++) {
|
||||
for (i = 0; i < adev->firmware.max_ucodes; i++) {
|
||||
ucode = &adev->firmware.ucode[i];
|
||||
if (ucode->fw) {
|
||||
ucode->mc_addr = 0;
|
||||
|
@ -49,6 +49,14 @@ struct smc_firmware_header_v1_0 {
|
||||
uint32_t ucode_start_addr;
|
||||
};
|
||||
|
||||
/* version_major=1, version_minor=0 */
|
||||
struct psp_firmware_header_v1_0 {
|
||||
struct common_firmware_header header;
|
||||
uint32_t ucode_feature_version;
|
||||
uint32_t sos_offset_bytes;
|
||||
uint32_t sos_size_bytes;
|
||||
};
|
||||
|
||||
/* version_major=1, version_minor=0 */
|
||||
struct gfx_firmware_header_v1_0 {
|
||||
struct common_firmware_header header;
|
||||
@ -110,6 +118,7 @@ union amdgpu_firmware_header {
|
||||
struct common_firmware_header common;
|
||||
struct mc_firmware_header_v1_0 mc;
|
||||
struct smc_firmware_header_v1_0 smc;
|
||||
struct psp_firmware_header_v1_0 psp;
|
||||
struct gfx_firmware_header_v1_0 gfx;
|
||||
struct rlc_firmware_header_v1_0 rlc;
|
||||
struct rlc_firmware_header_v2_0 rlc_v2_0;
|
||||
@ -128,9 +137,14 @@ enum AMDGPU_UCODE_ID {
|
||||
AMDGPU_UCODE_ID_CP_PFP,
|
||||
AMDGPU_UCODE_ID_CP_ME,
|
||||
AMDGPU_UCODE_ID_CP_MEC1,
|
||||
AMDGPU_UCODE_ID_CP_MEC1_JT,
|
||||
AMDGPU_UCODE_ID_CP_MEC2,
|
||||
AMDGPU_UCODE_ID_CP_MEC2_JT,
|
||||
AMDGPU_UCODE_ID_RLC_G,
|
||||
AMDGPU_UCODE_ID_STORAGE,
|
||||
AMDGPU_UCODE_ID_SMC,
|
||||
AMDGPU_UCODE_ID_UVD,
|
||||
AMDGPU_UCODE_ID_VCE,
|
||||
AMDGPU_UCODE_ID_MAXIMUM,
|
||||
};
|
||||
|
||||
@ -161,6 +175,8 @@ struct amdgpu_firmware_info {
|
||||
uint64_t mc_addr;
|
||||
/* kernel linear address */
|
||||
void *kaddr;
|
||||
/* ucode_size_bytes */
|
||||
uint32_t ucode_size;
|
||||
};
|
||||
|
||||
void amdgpu_ucode_print_mc_hdr(const struct common_firmware_header *hdr);
|
||||
@ -174,4 +190,7 @@ bool amdgpu_ucode_hdr_version(union amdgpu_firmware_header *hdr,
|
||||
int amdgpu_ucode_init_bo(struct amdgpu_device *adev);
|
||||
int amdgpu_ucode_fini_bo(struct amdgpu_device *adev);
|
||||
|
||||
enum amdgpu_firmware_load_type
|
||||
amdgpu_ucode_get_load_type(struct amdgpu_device *adev, int load_type);
|
||||
|
||||
#endif
|
||||
|
@ -67,6 +67,14 @@
|
||||
#define FIRMWARE_POLARIS11 "amdgpu/polaris11_uvd.bin"
|
||||
#define FIRMWARE_POLARIS12 "amdgpu/polaris12_uvd.bin"
|
||||
|
||||
#define FIRMWARE_VEGA10 "amdgpu/vega10_uvd.bin"
|
||||
|
||||
#define mmUVD_GPCOM_VCPU_DATA0_VEGA10 (0x03c4 + 0x7e00)
|
||||
#define mmUVD_GPCOM_VCPU_DATA1_VEGA10 (0x03c5 + 0x7e00)
|
||||
#define mmUVD_GPCOM_VCPU_CMD_VEGA10 (0x03c3 + 0x7e00)
|
||||
#define mmUVD_NO_OP_VEGA10 (0x03ff + 0x7e00)
|
||||
#define mmUVD_ENGINE_CNTL_VEGA10 (0x03c6 + 0x7e00)
|
||||
|
||||
/**
|
||||
* amdgpu_uvd_cs_ctx - Command submission parser context
|
||||
*
|
||||
@ -101,6 +109,8 @@ MODULE_FIRMWARE(FIRMWARE_POLARIS10);
|
||||
MODULE_FIRMWARE(FIRMWARE_POLARIS11);
|
||||
MODULE_FIRMWARE(FIRMWARE_POLARIS12);
|
||||
|
||||
MODULE_FIRMWARE(FIRMWARE_VEGA10);
|
||||
|
||||
static void amdgpu_uvd_idle_work_handler(struct work_struct *work);
|
||||
|
||||
int amdgpu_uvd_sw_init(struct amdgpu_device *adev)
|
||||
@ -151,6 +161,9 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev)
|
||||
case CHIP_POLARIS11:
|
||||
fw_name = FIRMWARE_POLARIS11;
|
||||
break;
|
||||
case CHIP_VEGA10:
|
||||
fw_name = FIRMWARE_VEGA10;
|
||||
break;
|
||||
case CHIP_POLARIS12:
|
||||
fw_name = FIRMWARE_POLARIS12;
|
||||
break;
|
||||
@ -203,9 +216,11 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev)
|
||||
DRM_ERROR("POLARIS10/11 UVD firmware version %hu.%hu is too old.\n",
|
||||
version_major, version_minor);
|
||||
|
||||
bo_size = AMDGPU_GPU_PAGE_ALIGN(le32_to_cpu(hdr->ucode_size_bytes) + 8)
|
||||
+ AMDGPU_UVD_STACK_SIZE + AMDGPU_UVD_HEAP_SIZE
|
||||
bo_size = AMDGPU_UVD_STACK_SIZE + AMDGPU_UVD_HEAP_SIZE
|
||||
+ AMDGPU_UVD_SESSION_SIZE * adev->uvd.max_handles;
|
||||
if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP)
|
||||
bo_size += AMDGPU_GPU_PAGE_ALIGN(le32_to_cpu(hdr->ucode_size_bytes) + 8);
|
||||
|
||||
r = amdgpu_bo_create_kernel(adev, bo_size, PAGE_SIZE,
|
||||
AMDGPU_GEM_DOMAIN_VRAM, &adev->uvd.vcpu_bo,
|
||||
&adev->uvd.gpu_addr, &adev->uvd.cpu_addr);
|
||||
@ -319,11 +334,13 @@ int amdgpu_uvd_resume(struct amdgpu_device *adev)
|
||||
unsigned offset;
|
||||
|
||||
hdr = (const struct common_firmware_header *)adev->uvd.fw->data;
|
||||
offset = le32_to_cpu(hdr->ucode_array_offset_bytes);
|
||||
memcpy_toio(adev->uvd.cpu_addr, adev->uvd.fw->data + offset,
|
||||
le32_to_cpu(hdr->ucode_size_bytes));
|
||||
size -= le32_to_cpu(hdr->ucode_size_bytes);
|
||||
ptr += le32_to_cpu(hdr->ucode_size_bytes);
|
||||
if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) {
|
||||
offset = le32_to_cpu(hdr->ucode_array_offset_bytes);
|
||||
memcpy_toio(adev->uvd.cpu_addr, adev->uvd.fw->data + offset,
|
||||
le32_to_cpu(hdr->ucode_size_bytes));
|
||||
size -= le32_to_cpu(hdr->ucode_size_bytes);
|
||||
ptr += le32_to_cpu(hdr->ucode_size_bytes);
|
||||
}
|
||||
memset_io(ptr, 0, size);
|
||||
}
|
||||
|
||||
@ -724,10 +741,10 @@ static int amdgpu_uvd_cs_pass2(struct amdgpu_uvd_cs_ctx *ctx)
|
||||
|
||||
start = amdgpu_bo_gpu_offset(bo);
|
||||
|
||||
end = (mapping->it.last + 1 - mapping->it.start);
|
||||
end = (mapping->last + 1 - mapping->start);
|
||||
end = end * AMDGPU_GPU_PAGE_SIZE + start;
|
||||
|
||||
addr -= ((uint64_t)mapping->it.start) * AMDGPU_GPU_PAGE_SIZE;
|
||||
addr -= mapping->start * AMDGPU_GPU_PAGE_SIZE;
|
||||
start += addr;
|
||||
|
||||
amdgpu_set_ib_value(ctx->parser, ctx->ib_idx, ctx->data0,
|
||||
@ -936,6 +953,7 @@ static int amdgpu_uvd_send_msg(struct amdgpu_ring *ring, struct amdgpu_bo *bo,
|
||||
struct dma_fence *f = NULL;
|
||||
struct amdgpu_device *adev = ring->adev;
|
||||
uint64_t addr;
|
||||
uint32_t data[4];
|
||||
int i, r;
|
||||
|
||||
memset(&tv, 0, sizeof(tv));
|
||||
@ -961,16 +979,28 @@ static int amdgpu_uvd_send_msg(struct amdgpu_ring *ring, struct amdgpu_bo *bo,
|
||||
if (r)
|
||||
goto err;
|
||||
|
||||
if (adev->asic_type >= CHIP_VEGA10) {
|
||||
data[0] = PACKET0(mmUVD_GPCOM_VCPU_DATA0_VEGA10, 0);
|
||||
data[1] = PACKET0(mmUVD_GPCOM_VCPU_DATA1_VEGA10, 0);
|
||||
data[2] = PACKET0(mmUVD_GPCOM_VCPU_CMD_VEGA10, 0);
|
||||
data[3] = PACKET0(mmUVD_NO_OP_VEGA10, 0);
|
||||
} else {
|
||||
data[0] = PACKET0(mmUVD_GPCOM_VCPU_DATA0, 0);
|
||||
data[1] = PACKET0(mmUVD_GPCOM_VCPU_DATA1, 0);
|
||||
data[2] = PACKET0(mmUVD_GPCOM_VCPU_CMD, 0);
|
||||
data[3] = PACKET0(mmUVD_NO_OP, 0);
|
||||
}
|
||||
|
||||
ib = &job->ibs[0];
|
||||
addr = amdgpu_bo_gpu_offset(bo);
|
||||
ib->ptr[0] = PACKET0(mmUVD_GPCOM_VCPU_DATA0, 0);
|
||||
ib->ptr[0] = data[0];
|
||||
ib->ptr[1] = addr;
|
||||
ib->ptr[2] = PACKET0(mmUVD_GPCOM_VCPU_DATA1, 0);
|
||||
ib->ptr[2] = data[1];
|
||||
ib->ptr[3] = addr >> 32;
|
||||
ib->ptr[4] = PACKET0(mmUVD_GPCOM_VCPU_CMD, 0);
|
||||
ib->ptr[4] = data[2];
|
||||
ib->ptr[5] = 0;
|
||||
for (i = 6; i < 16; i += 2) {
|
||||
ib->ptr[i] = PACKET0(mmUVD_NO_OP, 0);
|
||||
ib->ptr[i] = data[3];
|
||||
ib->ptr[i+1] = 0;
|
||||
}
|
||||
ib->length_dw = 16;
|
||||
@ -1108,6 +1138,9 @@ static void amdgpu_uvd_idle_work_handler(struct work_struct *work)
|
||||
container_of(work, struct amdgpu_device, uvd.idle_work.work);
|
||||
unsigned fences = amdgpu_fence_count_emitted(&adev->uvd.ring);
|
||||
|
||||
if (amdgpu_sriov_vf(adev))
|
||||
return;
|
||||
|
||||
if (fences == 0) {
|
||||
if (adev->pm.dpm_enabled) {
|
||||
amdgpu_dpm_enable_uvd(adev, false);
|
||||
@ -1129,6 +1162,9 @@ void amdgpu_uvd_ring_begin_use(struct amdgpu_ring *ring)
|
||||
struct amdgpu_device *adev = ring->adev;
|
||||
bool set_clocks = !cancel_delayed_work_sync(&adev->uvd.idle_work);
|
||||
|
||||
if (amdgpu_sriov_vf(adev))
|
||||
return;
|
||||
|
||||
if (set_clocks) {
|
||||
if (adev->pm.dpm_enabled) {
|
||||
amdgpu_dpm_enable_uvd(adev, true);
|
||||
|
@ -24,6 +24,35 @@
|
||||
#ifndef __AMDGPU_UVD_H__
|
||||
#define __AMDGPU_UVD_H__
|
||||
|
||||
#define AMDGPU_DEFAULT_UVD_HANDLES 10
|
||||
#define AMDGPU_MAX_UVD_HANDLES 40
|
||||
#define AMDGPU_UVD_STACK_SIZE (200*1024)
|
||||
#define AMDGPU_UVD_HEAP_SIZE (256*1024)
|
||||
#define AMDGPU_UVD_SESSION_SIZE (50*1024)
|
||||
#define AMDGPU_UVD_FIRMWARE_OFFSET 256
|
||||
|
||||
struct amdgpu_uvd {
|
||||
struct amdgpu_bo *vcpu_bo;
|
||||
void *cpu_addr;
|
||||
uint64_t gpu_addr;
|
||||
unsigned fw_version;
|
||||
void *saved_bo;
|
||||
unsigned max_handles;
|
||||
atomic_t handles[AMDGPU_MAX_UVD_HANDLES];
|
||||
struct drm_file *filp[AMDGPU_MAX_UVD_HANDLES];
|
||||
struct delayed_work idle_work;
|
||||
const struct firmware *fw; /* UVD firmware */
|
||||
struct amdgpu_ring ring;
|
||||
struct amdgpu_ring ring_enc[AMDGPU_MAX_UVD_ENC_RINGS];
|
||||
struct amdgpu_irq_src irq;
|
||||
bool address_64_bit;
|
||||
bool use_ctx_buf;
|
||||
struct amd_sched_entity entity;
|
||||
struct amd_sched_entity entity_enc;
|
||||
uint32_t srbm_soft_reset;
|
||||
unsigned num_enc_rings;
|
||||
};
|
||||
|
||||
int amdgpu_uvd_sw_init(struct amdgpu_device *adev);
|
||||
int amdgpu_uvd_sw_fini(struct amdgpu_device *adev);
|
||||
int amdgpu_uvd_suspend(struct amdgpu_device *adev);
|
||||
|
@ -54,6 +54,8 @@
|
||||
#define FIRMWARE_POLARIS11 "amdgpu/polaris11_vce.bin"
|
||||
#define FIRMWARE_POLARIS12 "amdgpu/polaris12_vce.bin"
|
||||
|
||||
#define FIRMWARE_VEGA10 "amdgpu/vega10_vce.bin"
|
||||
|
||||
#ifdef CONFIG_DRM_AMDGPU_CIK
|
||||
MODULE_FIRMWARE(FIRMWARE_BONAIRE);
|
||||
MODULE_FIRMWARE(FIRMWARE_KABINI);
|
||||
@ -69,6 +71,8 @@ MODULE_FIRMWARE(FIRMWARE_POLARIS10);
|
||||
MODULE_FIRMWARE(FIRMWARE_POLARIS11);
|
||||
MODULE_FIRMWARE(FIRMWARE_POLARIS12);
|
||||
|
||||
MODULE_FIRMWARE(FIRMWARE_VEGA10);
|
||||
|
||||
static void amdgpu_vce_idle_work_handler(struct work_struct *work);
|
||||
|
||||
/**
|
||||
@ -123,6 +127,9 @@ int amdgpu_vce_sw_init(struct amdgpu_device *adev, unsigned long size)
|
||||
case CHIP_POLARIS11:
|
||||
fw_name = FIRMWARE_POLARIS11;
|
||||
break;
|
||||
case CHIP_VEGA10:
|
||||
fw_name = FIRMWARE_VEGA10;
|
||||
break;
|
||||
case CHIP_POLARIS12:
|
||||
fw_name = FIRMWARE_POLARIS12;
|
||||
break;
|
||||
@ -313,6 +320,9 @@ static void amdgpu_vce_idle_work_handler(struct work_struct *work)
|
||||
container_of(work, struct amdgpu_device, vce.idle_work.work);
|
||||
unsigned i, count = 0;
|
||||
|
||||
if (amdgpu_sriov_vf(adev))
|
||||
return;
|
||||
|
||||
for (i = 0; i < adev->vce.num_rings; i++)
|
||||
count += amdgpu_fence_count_emitted(&adev->vce.ring[i]);
|
||||
|
||||
@ -343,6 +353,9 @@ void amdgpu_vce_ring_begin_use(struct amdgpu_ring *ring)
|
||||
struct amdgpu_device *adev = ring->adev;
|
||||
bool set_clocks;
|
||||
|
||||
if (amdgpu_sriov_vf(adev))
|
||||
return;
|
||||
|
||||
mutex_lock(&adev->vce.idle_mutex);
|
||||
set_clocks = !cancel_delayed_work_sync(&adev->vce.idle_work);
|
||||
if (set_clocks) {
|
||||
@ -582,13 +595,13 @@ static int amdgpu_vce_cs_reloc(struct amdgpu_cs_parser *p, uint32_t ib_idx,
|
||||
}
|
||||
|
||||
if ((addr + (uint64_t)size) >
|
||||
((uint64_t)mapping->it.last + 1) * AMDGPU_GPU_PAGE_SIZE) {
|
||||
(mapping->last + 1) * AMDGPU_GPU_PAGE_SIZE) {
|
||||
DRM_ERROR("BO to small for addr 0x%010Lx %d %d\n",
|
||||
addr, lo, hi);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
addr -= ((uint64_t)mapping->it.start) * AMDGPU_GPU_PAGE_SIZE;
|
||||
addr -= mapping->start * AMDGPU_GPU_PAGE_SIZE;
|
||||
addr += amdgpu_bo_gpu_offset(bo);
|
||||
addr -= ((uint64_t)size) * ((uint64_t)index);
|
||||
|
||||
@ -944,6 +957,10 @@ int amdgpu_vce_ring_test_ring(struct amdgpu_ring *ring)
|
||||
unsigned i;
|
||||
int r;
|
||||
|
||||
/* TODO: remove it if VCE can work for sriov */
|
||||
if (amdgpu_sriov_vf(adev))
|
||||
return 0;
|
||||
|
||||
r = amdgpu_ring_alloc(ring, 16);
|
||||
if (r) {
|
||||
DRM_ERROR("amdgpu: vce failed to lock ring %d (%d).\n",
|
||||
@ -982,6 +999,10 @@ int amdgpu_vce_ring_test_ib(struct amdgpu_ring *ring, long timeout)
|
||||
struct dma_fence *fence = NULL;
|
||||
long r;
|
||||
|
||||
/* TODO: remove it if VCE can work for sriov */
|
||||
if (amdgpu_sriov_vf(ring->adev))
|
||||
return 0;
|
||||
|
||||
/* skip vce ring1/2 ib test for now, since it's not reliable */
|
||||
if (ring != &ring->adev->vce.ring[0])
|
||||
return 0;
|
||||
|
@ -24,6 +24,31 @@
|
||||
#ifndef __AMDGPU_VCE_H__
|
||||
#define __AMDGPU_VCE_H__
|
||||
|
||||
#define AMDGPU_MAX_VCE_HANDLES 16
|
||||
#define AMDGPU_VCE_FIRMWARE_OFFSET 256
|
||||
|
||||
#define AMDGPU_VCE_HARVEST_VCE0 (1 << 0)
|
||||
#define AMDGPU_VCE_HARVEST_VCE1 (1 << 1)
|
||||
|
||||
struct amdgpu_vce {
|
||||
struct amdgpu_bo *vcpu_bo;
|
||||
uint64_t gpu_addr;
|
||||
unsigned fw_version;
|
||||
unsigned fb_version;
|
||||
atomic_t handles[AMDGPU_MAX_VCE_HANDLES];
|
||||
struct drm_file *filp[AMDGPU_MAX_VCE_HANDLES];
|
||||
uint32_t img_size[AMDGPU_MAX_VCE_HANDLES];
|
||||
struct delayed_work idle_work;
|
||||
struct mutex idle_mutex;
|
||||
const struct firmware *fw; /* VCE firmware */
|
||||
struct amdgpu_ring ring[AMDGPU_MAX_VCE_RINGS];
|
||||
struct amdgpu_irq_src irq;
|
||||
unsigned harvest_config;
|
||||
struct amd_sched_entity entity;
|
||||
uint32_t srbm_soft_reset;
|
||||
unsigned num_rings;
|
||||
};
|
||||
|
||||
int amdgpu_vce_sw_init(struct amdgpu_device *adev, unsigned long size);
|
||||
int amdgpu_vce_sw_fini(struct amdgpu_device *adev);
|
||||
int amdgpu_vce_suspend(struct amdgpu_device *adev);
|
||||
|
@ -75,6 +75,15 @@ int amdgpu_map_static_csa(struct amdgpu_device *adev, struct amdgpu_vm *vm)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
r = amdgpu_vm_alloc_pts(adev, bo_va->vm, AMDGPU_CSA_VADDR,
|
||||
AMDGPU_CSA_SIZE);
|
||||
if (r) {
|
||||
DRM_ERROR("failed to allocate pts for static CSA, err=%d\n", r);
|
||||
amdgpu_vm_bo_rmv(adev, bo_va);
|
||||
ttm_eu_backoff_reservation(&ticket, &list);
|
||||
return r;
|
||||
}
|
||||
|
||||
r = amdgpu_vm_bo_map(adev, bo_va, AMDGPU_CSA_VADDR, 0,AMDGPU_CSA_SIZE,
|
||||
AMDGPU_PTE_READABLE | AMDGPU_PTE_WRITEABLE |
|
||||
AMDGPU_PTE_EXECUTABLE);
|
||||
@ -97,7 +106,8 @@ void amdgpu_virt_init_setting(struct amdgpu_device *adev)
|
||||
adev->mode_info.num_crtc = 1;
|
||||
adev->enable_virtual_display = true;
|
||||
|
||||
mutex_init(&adev->virt.lock);
|
||||
mutex_init(&adev->virt.lock_kiq);
|
||||
mutex_init(&adev->virt.lock_reset);
|
||||
}
|
||||
|
||||
uint32_t amdgpu_virt_kiq_rreg(struct amdgpu_device *adev, uint32_t reg)
|
||||
@ -110,14 +120,12 @@ uint32_t amdgpu_virt_kiq_rreg(struct amdgpu_device *adev, uint32_t reg)
|
||||
|
||||
BUG_ON(!ring->funcs->emit_rreg);
|
||||
|
||||
mutex_lock(&adev->virt.lock);
|
||||
mutex_lock(&adev->virt.lock_kiq);
|
||||
amdgpu_ring_alloc(ring, 32);
|
||||
amdgpu_ring_emit_hdp_flush(ring);
|
||||
amdgpu_ring_emit_rreg(ring, reg);
|
||||
amdgpu_ring_emit_hdp_invalidate(ring);
|
||||
amdgpu_fence_emit(ring, &f);
|
||||
amdgpu_ring_commit(ring);
|
||||
mutex_unlock(&adev->virt.lock);
|
||||
mutex_unlock(&adev->virt.lock_kiq);
|
||||
|
||||
r = dma_fence_wait(f, false);
|
||||
if (r)
|
||||
@ -138,14 +146,12 @@ void amdgpu_virt_kiq_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v)
|
||||
|
||||
BUG_ON(!ring->funcs->emit_wreg);
|
||||
|
||||
mutex_lock(&adev->virt.lock);
|
||||
mutex_lock(&adev->virt.lock_kiq);
|
||||
amdgpu_ring_alloc(ring, 32);
|
||||
amdgpu_ring_emit_hdp_flush(ring);
|
||||
amdgpu_ring_emit_wreg(ring, reg, v);
|
||||
amdgpu_ring_emit_hdp_invalidate(ring);
|
||||
amdgpu_fence_emit(ring, &f);
|
||||
amdgpu_ring_commit(ring);
|
||||
mutex_unlock(&adev->virt.lock);
|
||||
mutex_unlock(&adev->virt.lock_kiq);
|
||||
|
||||
r = dma_fence_wait(f, false);
|
||||
if (r)
|
||||
|
@ -30,6 +30,12 @@
|
||||
#define AMDGPU_PASSTHROUGH_MODE (1 << 3) /* thw whole GPU is pass through for VM */
|
||||
#define AMDGPU_SRIOV_CAPS_RUNTIME (1 << 4) /* is out of full access mode */
|
||||
|
||||
struct amdgpu_mm_table {
|
||||
struct amdgpu_bo *bo;
|
||||
uint32_t *cpu_addr;
|
||||
uint64_t gpu_addr;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct amdgpu_virt_ops - amdgpu device virt operations
|
||||
*/
|
||||
@ -46,10 +52,12 @@ struct amdgpu_virt {
|
||||
uint64_t csa_vmid0_addr;
|
||||
bool chained_ib_support;
|
||||
uint32_t reg_val_offs;
|
||||
struct mutex lock;
|
||||
struct mutex lock_kiq;
|
||||
struct mutex lock_reset;
|
||||
struct amdgpu_irq_src ack_irq;
|
||||
struct amdgpu_irq_src rcv_irq;
|
||||
struct delayed_work flr_work;
|
||||
struct work_struct flr_work;
|
||||
struct amdgpu_mm_table mm_table;
|
||||
const struct amdgpu_virt_ops *ops;
|
||||
};
|
||||
|
||||
@ -89,5 +97,6 @@ void amdgpu_virt_kiq_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v);
|
||||
int amdgpu_virt_request_full_gpu(struct amdgpu_device *adev, bool init);
|
||||
int amdgpu_virt_release_full_gpu(struct amdgpu_device *adev, bool init);
|
||||
int amdgpu_virt_reset_gpu(struct amdgpu_device *adev);
|
||||
int amdgpu_sriov_gpu_reset(struct amdgpu_device *adev, bool voluntary);
|
||||
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -45,7 +45,7 @@ struct amdgpu_bo_list_entry;
|
||||
#define AMDGPU_VM_MAX_UPDATE_SIZE 0x3FFFF
|
||||
|
||||
/* number of entries in page table */
|
||||
#define AMDGPU_VM_PTE_COUNT (1 << amdgpu_vm_block_size)
|
||||
#define AMDGPU_VM_PTE_COUNT(adev) (1 << (adev)->vm_manager.block_size)
|
||||
|
||||
/* PTBs (Page Table Blocks) need to be aligned to 32K */
|
||||
#define AMDGPU_VM_PTB_ALIGN_SIZE 32768
|
||||
@ -53,26 +53,44 @@ struct amdgpu_bo_list_entry;
|
||||
/* LOG2 number of continuous pages for the fragment field */
|
||||
#define AMDGPU_LOG2_PAGES_PER_FRAG 4
|
||||
|
||||
#define AMDGPU_PTE_VALID (1 << 0)
|
||||
#define AMDGPU_PTE_SYSTEM (1 << 1)
|
||||
#define AMDGPU_PTE_SNOOPED (1 << 2)
|
||||
#define AMDGPU_PTE_VALID (1ULL << 0)
|
||||
#define AMDGPU_PTE_SYSTEM (1ULL << 1)
|
||||
#define AMDGPU_PTE_SNOOPED (1ULL << 2)
|
||||
|
||||
/* VI only */
|
||||
#define AMDGPU_PTE_EXECUTABLE (1 << 4)
|
||||
#define AMDGPU_PTE_EXECUTABLE (1ULL << 4)
|
||||
|
||||
#define AMDGPU_PTE_READABLE (1 << 5)
|
||||
#define AMDGPU_PTE_WRITEABLE (1 << 6)
|
||||
#define AMDGPU_PTE_READABLE (1ULL << 5)
|
||||
#define AMDGPU_PTE_WRITEABLE (1ULL << 6)
|
||||
|
||||
#define AMDGPU_PTE_FRAG(x) ((x & 0x1f) << 7)
|
||||
#define AMDGPU_PTE_FRAG(x) ((x & 0x1fULL) << 7)
|
||||
|
||||
#define AMDGPU_PTE_PRT (1ULL << 63)
|
||||
|
||||
/* VEGA10 only */
|
||||
#define AMDGPU_PTE_MTYPE(a) ((uint64_t)a << 57)
|
||||
#define AMDGPU_PTE_MTYPE_MASK AMDGPU_PTE_MTYPE(3ULL)
|
||||
|
||||
/* How to programm VM fault handling */
|
||||
#define AMDGPU_VM_FAULT_STOP_NEVER 0
|
||||
#define AMDGPU_VM_FAULT_STOP_FIRST 1
|
||||
#define AMDGPU_VM_FAULT_STOP_ALWAYS 2
|
||||
|
||||
/* max number of VMHUB */
|
||||
#define AMDGPU_MAX_VMHUBS 2
|
||||
#define AMDGPU_GFXHUB 0
|
||||
#define AMDGPU_MMHUB 1
|
||||
|
||||
/* hardcode that limit for now */
|
||||
#define AMDGPU_VA_RESERVED_SIZE (8 << 20)
|
||||
|
||||
struct amdgpu_vm_pt {
|
||||
struct amdgpu_bo *bo;
|
||||
uint64_t addr;
|
||||
|
||||
/* array of page tables, one for each directory entry */
|
||||
struct amdgpu_vm_pt *entries;
|
||||
unsigned last_entry_used;
|
||||
};
|
||||
|
||||
struct amdgpu_vm {
|
||||
@ -92,14 +110,10 @@ struct amdgpu_vm {
|
||||
struct list_head freed;
|
||||
|
||||
/* contains the page directory */
|
||||
struct amdgpu_bo *page_directory;
|
||||
unsigned max_pde_used;
|
||||
struct dma_fence *page_directory_fence;
|
||||
struct amdgpu_vm_pt root;
|
||||
struct dma_fence *last_dir_update;
|
||||
uint64_t last_eviction_counter;
|
||||
|
||||
/* array of page tables, one for each page directory entry */
|
||||
struct amdgpu_vm_pt *page_tables;
|
||||
|
||||
/* for id and flush management per ring */
|
||||
struct amdgpu_vm_id *ids[AMDGPU_MAX_RINGS];
|
||||
|
||||
@ -117,7 +131,6 @@ struct amdgpu_vm {
|
||||
|
||||
struct amdgpu_vm_id {
|
||||
struct list_head list;
|
||||
struct dma_fence *first;
|
||||
struct amdgpu_sync active;
|
||||
struct dma_fence *last_flush;
|
||||
atomic64_t owner;
|
||||
@ -147,7 +160,10 @@ struct amdgpu_vm_manager {
|
||||
u64 fence_context;
|
||||
unsigned seqno[AMDGPU_MAX_RINGS];
|
||||
|
||||
uint32_t max_pfn;
|
||||
uint64_t max_pfn;
|
||||
uint32_t num_level;
|
||||
uint64_t vm_size;
|
||||
uint32_t block_size;
|
||||
/* vram base address for page table entry */
|
||||
u64 vram_base_offset;
|
||||
/* is vm enabled? */
|
||||
@ -159,6 +175,10 @@ struct amdgpu_vm_manager {
|
||||
atomic_t vm_pte_next_ring;
|
||||
/* client id counter */
|
||||
atomic64_t client_counter;
|
||||
|
||||
/* partial resident texture handling */
|
||||
spinlock_t prt_lock;
|
||||
atomic_t num_prt_users;
|
||||
};
|
||||
|
||||
void amdgpu_vm_manager_init(struct amdgpu_device *adev);
|
||||
@ -173,15 +193,19 @@ int amdgpu_vm_validate_pt_bos(struct amdgpu_device *adev, struct amdgpu_vm *vm,
|
||||
void *param);
|
||||
void amdgpu_vm_move_pt_bos_in_lru(struct amdgpu_device *adev,
|
||||
struct amdgpu_vm *vm);
|
||||
int amdgpu_vm_alloc_pts(struct amdgpu_device *adev,
|
||||
struct amdgpu_vm *vm,
|
||||
uint64_t saddr, uint64_t size);
|
||||
int amdgpu_vm_grab_id(struct amdgpu_vm *vm, struct amdgpu_ring *ring,
|
||||
struct amdgpu_sync *sync, struct dma_fence *fence,
|
||||
struct amdgpu_job *job);
|
||||
int amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job);
|
||||
void amdgpu_vm_reset_id(struct amdgpu_device *adev, unsigned vm_id);
|
||||
int amdgpu_vm_update_page_directory(struct amdgpu_device *adev,
|
||||
struct amdgpu_vm *vm);
|
||||
int amdgpu_vm_update_directories(struct amdgpu_device *adev,
|
||||
struct amdgpu_vm *vm);
|
||||
int amdgpu_vm_clear_freed(struct amdgpu_device *adev,
|
||||
struct amdgpu_vm *vm);
|
||||
struct amdgpu_vm *vm,
|
||||
struct dma_fence **fence);
|
||||
int amdgpu_vm_clear_invalids(struct amdgpu_device *adev, struct amdgpu_vm *vm,
|
||||
struct amdgpu_sync *sync);
|
||||
int amdgpu_vm_bo_update(struct amdgpu_device *adev,
|
||||
@ -198,10 +222,18 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev,
|
||||
struct amdgpu_bo_va *bo_va,
|
||||
uint64_t addr, uint64_t offset,
|
||||
uint64_t size, uint64_t flags);
|
||||
int amdgpu_vm_bo_replace_map(struct amdgpu_device *adev,
|
||||
struct amdgpu_bo_va *bo_va,
|
||||
uint64_t addr, uint64_t offset,
|
||||
uint64_t size, uint64_t flags);
|
||||
int amdgpu_vm_bo_unmap(struct amdgpu_device *adev,
|
||||
struct amdgpu_bo_va *bo_va,
|
||||
uint64_t addr);
|
||||
int amdgpu_vm_bo_clear_mappings(struct amdgpu_device *adev,
|
||||
struct amdgpu_vm *vm,
|
||||
uint64_t saddr, uint64_t size);
|
||||
void amdgpu_vm_bo_rmv(struct amdgpu_device *adev,
|
||||
struct amdgpu_bo_va *bo_va);
|
||||
void amdgpu_vm_adjust_size(struct amdgpu_device *adev, uint64_t vm_size);
|
||||
|
||||
#endif
|
||||
|
@ -93,7 +93,6 @@ static int amdgpu_vram_mgr_new(struct ttm_mem_type_manager *man,
|
||||
const struct ttm_place *place,
|
||||
struct ttm_mem_reg *mem)
|
||||
{
|
||||
struct amdgpu_bo *bo = container_of(tbo, struct amdgpu_bo, tbo);
|
||||
struct amdgpu_vram_mgr *mgr = man->priv;
|
||||
struct drm_mm *mm = &mgr->mm;
|
||||
struct drm_mm_node *nodes;
|
||||
@ -106,8 +105,8 @@ static int amdgpu_vram_mgr_new(struct ttm_mem_type_manager *man,
|
||||
if (!lpfn)
|
||||
lpfn = man->size;
|
||||
|
||||
if (bo->flags & AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS ||
|
||||
place->lpfn || amdgpu_vram_page_split == -1) {
|
||||
if (place->flags & TTM_PL_FLAG_CONTIGUOUS ||
|
||||
amdgpu_vram_page_split == -1) {
|
||||
pages_per_node = ~0ul;
|
||||
num_nodes = 1;
|
||||
} else {
|
||||
@ -124,12 +123,14 @@ static int amdgpu_vram_mgr_new(struct ttm_mem_type_manager *man,
|
||||
if (place->flags & TTM_PL_FLAG_TOPDOWN)
|
||||
mode = DRM_MM_INSERT_HIGH;
|
||||
|
||||
mem->start = 0;
|
||||
pages_left = mem->num_pages;
|
||||
|
||||
spin_lock(&mgr->lock);
|
||||
for (i = 0; i < num_nodes; ++i) {
|
||||
unsigned long pages = min(pages_left, pages_per_node);
|
||||
uint32_t alignment = mem->page_alignment;
|
||||
unsigned long start;
|
||||
|
||||
if (pages == pages_per_node)
|
||||
alignment = pages_per_node;
|
||||
@ -141,11 +142,19 @@ static int amdgpu_vram_mgr_new(struct ttm_mem_type_manager *man,
|
||||
if (unlikely(r))
|
||||
goto error;
|
||||
|
||||
/* Calculate a virtual BO start address to easily check if
|
||||
* everything is CPU accessible.
|
||||
*/
|
||||
start = nodes[i].start + nodes[i].size;
|
||||
if (start > mem->num_pages)
|
||||
start -= mem->num_pages;
|
||||
else
|
||||
start = 0;
|
||||
mem->start = max(mem->start, start);
|
||||
pages_left -= pages;
|
||||
}
|
||||
spin_unlock(&mgr->lock);
|
||||
|
||||
mem->start = num_nodes == 1 ? nodes[0].start : AMDGPU_BO_INVALID_OFFSET;
|
||||
mem->mm_node = nodes;
|
||||
|
||||
return 0;
|
||||
|
@ -166,7 +166,7 @@ static uint32_t atom_iio_execute(struct atom_context *ctx, int base,
|
||||
case ATOM_IIO_END:
|
||||
return temp;
|
||||
default:
|
||||
printk(KERN_INFO "Unknown IIO opcode.\n");
|
||||
pr_info("Unknown IIO opcode\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -190,22 +190,19 @@ static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr,
|
||||
val = gctx->card->reg_read(gctx->card, idx);
|
||||
break;
|
||||
case ATOM_IO_PCI:
|
||||
printk(KERN_INFO
|
||||
"PCI registers are not implemented.\n");
|
||||
pr_info("PCI registers are not implemented\n");
|
||||
return 0;
|
||||
case ATOM_IO_SYSIO:
|
||||
printk(KERN_INFO
|
||||
"SYSIO registers are not implemented.\n");
|
||||
pr_info("SYSIO registers are not implemented\n");
|
||||
return 0;
|
||||
default:
|
||||
if (!(gctx->io_mode & 0x80)) {
|
||||
printk(KERN_INFO "Bad IO mode.\n");
|
||||
pr_info("Bad IO mode\n");
|
||||
return 0;
|
||||
}
|
||||
if (!gctx->iio[gctx->io_mode & 0x7F]) {
|
||||
printk(KERN_INFO
|
||||
"Undefined indirect IO read method %d.\n",
|
||||
gctx->io_mode & 0x7F);
|
||||
pr_info("Undefined indirect IO read method %d\n",
|
||||
gctx->io_mode & 0x7F);
|
||||
return 0;
|
||||
}
|
||||
val =
|
||||
@ -469,22 +466,19 @@ static void atom_put_dst(atom_exec_context *ctx, int arg, uint8_t attr,
|
||||
gctx->card->reg_write(gctx->card, idx, val);
|
||||
break;
|
||||
case ATOM_IO_PCI:
|
||||
printk(KERN_INFO
|
||||
"PCI registers are not implemented.\n");
|
||||
pr_info("PCI registers are not implemented\n");
|
||||
return;
|
||||
case ATOM_IO_SYSIO:
|
||||
printk(KERN_INFO
|
||||
"SYSIO registers are not implemented.\n");
|
||||
pr_info("SYSIO registers are not implemented\n");
|
||||
return;
|
||||
default:
|
||||
if (!(gctx->io_mode & 0x80)) {
|
||||
printk(KERN_INFO "Bad IO mode.\n");
|
||||
pr_info("Bad IO mode\n");
|
||||
return;
|
||||
}
|
||||
if (!gctx->iio[gctx->io_mode & 0xFF]) {
|
||||
printk(KERN_INFO
|
||||
"Undefined indirect IO write method %d.\n",
|
||||
gctx->io_mode & 0x7F);
|
||||
pr_info("Undefined indirect IO write method %d\n",
|
||||
gctx->io_mode & 0x7F);
|
||||
return;
|
||||
}
|
||||
atom_iio_execute(gctx, gctx->iio[gctx->io_mode & 0xFF],
|
||||
@ -850,17 +844,17 @@ static void atom_op_postcard(atom_exec_context *ctx, int *ptr, int arg)
|
||||
|
||||
static void atom_op_repeat(atom_exec_context *ctx, int *ptr, int arg)
|
||||
{
|
||||
printk(KERN_INFO "unimplemented!\n");
|
||||
pr_info("unimplemented!\n");
|
||||
}
|
||||
|
||||
static void atom_op_restorereg(atom_exec_context *ctx, int *ptr, int arg)
|
||||
{
|
||||
printk(KERN_INFO "unimplemented!\n");
|
||||
pr_info("unimplemented!\n");
|
||||
}
|
||||
|
||||
static void atom_op_savereg(atom_exec_context *ctx, int *ptr, int arg)
|
||||
{
|
||||
printk(KERN_INFO "unimplemented!\n");
|
||||
pr_info("unimplemented!\n");
|
||||
}
|
||||
|
||||
static void atom_op_setdatablock(atom_exec_context *ctx, int *ptr, int arg)
|
||||
@ -1023,7 +1017,7 @@ static void atom_op_switch(atom_exec_context *ctx, int *ptr, int arg)
|
||||
}
|
||||
(*ptr) += 2;
|
||||
} else {
|
||||
printk(KERN_INFO "Bad case.\n");
|
||||
pr_info("Bad case\n");
|
||||
return;
|
||||
}
|
||||
(*ptr) += 2;
|
||||
@ -1306,8 +1300,7 @@ struct atom_context *amdgpu_atom_parse(struct card_info *card, void *bios)
|
||||
struct atom_context *ctx =
|
||||
kzalloc(sizeof(struct atom_context), GFP_KERNEL);
|
||||
char *str;
|
||||
char name[512];
|
||||
int i;
|
||||
u16 idx;
|
||||
|
||||
if (!ctx)
|
||||
return NULL;
|
||||
@ -1316,14 +1309,14 @@ struct atom_context *amdgpu_atom_parse(struct card_info *card, void *bios)
|
||||
ctx->bios = bios;
|
||||
|
||||
if (CU16(0) != ATOM_BIOS_MAGIC) {
|
||||
printk(KERN_INFO "Invalid BIOS magic.\n");
|
||||
pr_info("Invalid BIOS magic\n");
|
||||
kfree(ctx);
|
||||
return NULL;
|
||||
}
|
||||
if (strncmp
|
||||
(CSTR(ATOM_ATI_MAGIC_PTR), ATOM_ATI_MAGIC,
|
||||
strlen(ATOM_ATI_MAGIC))) {
|
||||
printk(KERN_INFO "Invalid ATI magic.\n");
|
||||
pr_info("Invalid ATI magic\n");
|
||||
kfree(ctx);
|
||||
return NULL;
|
||||
}
|
||||
@ -1332,7 +1325,7 @@ struct atom_context *amdgpu_atom_parse(struct card_info *card, void *bios)
|
||||
if (strncmp
|
||||
(CSTR(base + ATOM_ROM_MAGIC_PTR), ATOM_ROM_MAGIC,
|
||||
strlen(ATOM_ROM_MAGIC))) {
|
||||
printk(KERN_INFO "Invalid ATOM magic.\n");
|
||||
pr_info("Invalid ATOM magic\n");
|
||||
kfree(ctx);
|
||||
return NULL;
|
||||
}
|
||||
@ -1345,18 +1338,13 @@ struct atom_context *amdgpu_atom_parse(struct card_info *card, void *bios)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
str = CSTR(CU16(base + ATOM_ROM_MSG_PTR));
|
||||
while (*str && ((*str == '\n') || (*str == '\r')))
|
||||
str++;
|
||||
/* name string isn't always 0 terminated */
|
||||
for (i = 0; i < 511; i++) {
|
||||
name[i] = str[i];
|
||||
if (name[i] < '.' || name[i] > 'z') {
|
||||
name[i] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
printk(KERN_INFO "ATOM BIOS: %s\n", name);
|
||||
idx = CU16(ATOM_ROM_PART_NUMBER_PTR);
|
||||
if (idx == 0)
|
||||
idx = 0x80;
|
||||
|
||||
str = CSTR(idx);
|
||||
if (*str != '\0')
|
||||
pr_info("ATOM BIOS: %s\n", str);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
@ -1429,29 +1417,3 @@ bool amdgpu_atom_parse_cmd_header(struct atom_context *ctx, int index, uint8_t *
|
||||
return true;
|
||||
}
|
||||
|
||||
int amdgpu_atom_allocate_fb_scratch(struct atom_context *ctx)
|
||||
{
|
||||
int index = GetIndexIntoMasterTable(DATA, VRAM_UsageByFirmware);
|
||||
uint16_t data_offset;
|
||||
int usage_bytes = 0;
|
||||
struct _ATOM_VRAM_USAGE_BY_FIRMWARE *firmware_usage;
|
||||
|
||||
if (amdgpu_atom_parse_data_header(ctx, index, NULL, NULL, NULL, &data_offset)) {
|
||||
firmware_usage = (struct _ATOM_VRAM_USAGE_BY_FIRMWARE *)(ctx->bios + data_offset);
|
||||
|
||||
DRM_DEBUG("atom firmware requested %08x %dkb\n",
|
||||
le32_to_cpu(firmware_usage->asFirmwareVramReserveInfo[0].ulStartAddrUsedByFirmware),
|
||||
le16_to_cpu(firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb));
|
||||
|
||||
usage_bytes = le16_to_cpu(firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb) * 1024;
|
||||
}
|
||||
ctx->scratch_size_bytes = 0;
|
||||
if (usage_bytes == 0)
|
||||
usage_bytes = 20 * 1024;
|
||||
/* allocate some scratch memory */
|
||||
ctx->scratch = kzalloc(usage_bytes, GFP_KERNEL);
|
||||
if (!ctx->scratch)
|
||||
return -ENOMEM;
|
||||
ctx->scratch_size_bytes = usage_bytes;
|
||||
return 0;
|
||||
}
|
||||
|
@ -32,6 +32,7 @@
|
||||
#define ATOM_ATI_MAGIC_PTR 0x30
|
||||
#define ATOM_ATI_MAGIC " 761295520"
|
||||
#define ATOM_ROM_TABLE_PTR 0x48
|
||||
#define ATOM_ROM_PART_NUMBER_PTR 0x6E
|
||||
|
||||
#define ATOM_ROM_MAGIC "ATOM"
|
||||
#define ATOM_ROM_MAGIC_PTR 4
|
||||
@ -151,7 +152,6 @@ bool amdgpu_atom_parse_data_header(struct atom_context *ctx, int index, uint16_t
|
||||
uint8_t *frev, uint8_t *crev, uint16_t *data_start);
|
||||
bool amdgpu_atom_parse_cmd_header(struct atom_context *ctx, int index,
|
||||
uint8_t *frev, uint8_t *crev);
|
||||
int amdgpu_atom_allocate_fb_scratch(struct atom_context *ctx);
|
||||
#include "atom-types.h"
|
||||
#include "atombios.h"
|
||||
#include "ObjectID.h"
|
||||
|
@ -3681,6 +3681,40 @@ static int ci_find_boot_level(struct ci_single_dpm_table *table,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ci_save_default_power_profile(struct amdgpu_device *adev)
|
||||
{
|
||||
struct ci_power_info *pi = ci_get_pi(adev);
|
||||
struct SMU7_Discrete_GraphicsLevel *levels =
|
||||
pi->smc_state_table.GraphicsLevel;
|
||||
uint32_t min_level = 0;
|
||||
|
||||
pi->default_gfx_power_profile.activity_threshold =
|
||||
be16_to_cpu(levels[0].ActivityLevel);
|
||||
pi->default_gfx_power_profile.up_hyst = levels[0].UpH;
|
||||
pi->default_gfx_power_profile.down_hyst = levels[0].DownH;
|
||||
pi->default_gfx_power_profile.type = AMD_PP_GFX_PROFILE;
|
||||
|
||||
pi->default_compute_power_profile = pi->default_gfx_power_profile;
|
||||
pi->default_compute_power_profile.type = AMD_PP_COMPUTE_PROFILE;
|
||||
|
||||
/* Optimize compute power profile: Use only highest
|
||||
* 2 power levels (if more than 2 are available), Hysteresis:
|
||||
* 0ms up, 5ms down
|
||||
*/
|
||||
if (pi->smc_state_table.GraphicsDpmLevelCount > 2)
|
||||
min_level = pi->smc_state_table.GraphicsDpmLevelCount - 2;
|
||||
else if (pi->smc_state_table.GraphicsDpmLevelCount == 2)
|
||||
min_level = 1;
|
||||
pi->default_compute_power_profile.min_sclk =
|
||||
be32_to_cpu(levels[min_level].SclkFrequency);
|
||||
|
||||
pi->default_compute_power_profile.up_hyst = 0;
|
||||
pi->default_compute_power_profile.down_hyst = 5;
|
||||
|
||||
pi->gfx_power_profile = pi->default_gfx_power_profile;
|
||||
pi->compute_power_profile = pi->default_compute_power_profile;
|
||||
}
|
||||
|
||||
static int ci_init_smc_table(struct amdgpu_device *adev)
|
||||
{
|
||||
struct ci_power_info *pi = ci_get_pi(adev);
|
||||
@ -3826,6 +3860,8 @@ static int ci_init_smc_table(struct amdgpu_device *adev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ci_save_default_power_profile(adev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -5804,9 +5840,7 @@ static int ci_dpm_init_microcode(struct amdgpu_device *adev)
|
||||
|
||||
out:
|
||||
if (err) {
|
||||
printk(KERN_ERR
|
||||
"cik_smc: Failed to load firmware \"%s\"\n",
|
||||
fw_name);
|
||||
pr_err("cik_smc: Failed to load firmware \"%s\"\n", fw_name);
|
||||
release_firmware(adev->pm.fw);
|
||||
adev->pm.fw = NULL;
|
||||
}
|
||||
@ -6250,11 +6284,13 @@ static int ci_dpm_sw_init(void *handle)
|
||||
int ret;
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
ret = amdgpu_irq_add_id(adev, 230, &adev->pm.dpm.thermal.irq);
|
||||
ret = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, 230,
|
||||
&adev->pm.dpm.thermal.irq);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = amdgpu_irq_add_id(adev, 231, &adev->pm.dpm.thermal.irq);
|
||||
ret = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, 231,
|
||||
&adev->pm.dpm.thermal.irq);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -6688,6 +6724,260 @@ static int ci_dpm_set_mclk_od(struct amdgpu_device *adev, uint32_t value)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ci_dpm_get_power_profile_state(struct amdgpu_device *adev,
|
||||
struct amd_pp_profile *query)
|
||||
{
|
||||
struct ci_power_info *pi = ci_get_pi(adev);
|
||||
|
||||
if (!pi || !query)
|
||||
return -EINVAL;
|
||||
|
||||
if (query->type == AMD_PP_GFX_PROFILE)
|
||||
memcpy(query, &pi->gfx_power_profile,
|
||||
sizeof(struct amd_pp_profile));
|
||||
else if (query->type == AMD_PP_COMPUTE_PROFILE)
|
||||
memcpy(query, &pi->compute_power_profile,
|
||||
sizeof(struct amd_pp_profile));
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ci_populate_requested_graphic_levels(struct amdgpu_device *adev,
|
||||
struct amd_pp_profile *request)
|
||||
{
|
||||
struct ci_power_info *pi = ci_get_pi(adev);
|
||||
struct ci_dpm_table *dpm_table = &(pi->dpm_table);
|
||||
struct SMU7_Discrete_GraphicsLevel *levels =
|
||||
pi->smc_state_table.GraphicsLevel;
|
||||
uint32_t array = pi->dpm_table_start +
|
||||
offsetof(SMU7_Discrete_DpmTable, GraphicsLevel);
|
||||
uint32_t array_size = sizeof(struct SMU7_Discrete_GraphicsLevel) *
|
||||
SMU7_MAX_LEVELS_GRAPHICS;
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < dpm_table->sclk_table.count; i++) {
|
||||
levels[i].ActivityLevel =
|
||||
cpu_to_be16(request->activity_threshold);
|
||||
levels[i].EnabledForActivity = 1;
|
||||
levels[i].UpH = request->up_hyst;
|
||||
levels[i].DownH = request->down_hyst;
|
||||
}
|
||||
|
||||
return amdgpu_ci_copy_bytes_to_smc(adev, array, (uint8_t *)levels,
|
||||
array_size, pi->sram_end);
|
||||
}
|
||||
|
||||
static void ci_find_min_clock_masks(struct amdgpu_device *adev,
|
||||
uint32_t *sclk_mask, uint32_t *mclk_mask,
|
||||
uint32_t min_sclk, uint32_t min_mclk)
|
||||
{
|
||||
struct ci_power_info *pi = ci_get_pi(adev);
|
||||
struct ci_dpm_table *dpm_table = &(pi->dpm_table);
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < dpm_table->sclk_table.count; i++) {
|
||||
if (dpm_table->sclk_table.dpm_levels[i].enabled &&
|
||||
dpm_table->sclk_table.dpm_levels[i].value >= min_sclk)
|
||||
*sclk_mask |= 1 << i;
|
||||
}
|
||||
|
||||
for (i = 0; i < dpm_table->mclk_table.count; i++) {
|
||||
if (dpm_table->mclk_table.dpm_levels[i].enabled &&
|
||||
dpm_table->mclk_table.dpm_levels[i].value >= min_mclk)
|
||||
*mclk_mask |= 1 << i;
|
||||
}
|
||||
}
|
||||
|
||||
static int ci_set_power_profile_state(struct amdgpu_device *adev,
|
||||
struct amd_pp_profile *request)
|
||||
{
|
||||
struct ci_power_info *pi = ci_get_pi(adev);
|
||||
int tmp_result, result = 0;
|
||||
uint32_t sclk_mask = 0, mclk_mask = 0;
|
||||
|
||||
tmp_result = ci_freeze_sclk_mclk_dpm(adev);
|
||||
if (tmp_result) {
|
||||
DRM_ERROR("Failed to freeze SCLK MCLK DPM!");
|
||||
result = tmp_result;
|
||||
}
|
||||
|
||||
tmp_result = ci_populate_requested_graphic_levels(adev,
|
||||
request);
|
||||
if (tmp_result) {
|
||||
DRM_ERROR("Failed to populate requested graphic levels!");
|
||||
result = tmp_result;
|
||||
}
|
||||
|
||||
tmp_result = ci_unfreeze_sclk_mclk_dpm(adev);
|
||||
if (tmp_result) {
|
||||
DRM_ERROR("Failed to unfreeze SCLK MCLK DPM!");
|
||||
result = tmp_result;
|
||||
}
|
||||
|
||||
ci_find_min_clock_masks(adev, &sclk_mask, &mclk_mask,
|
||||
request->min_sclk, request->min_mclk);
|
||||
|
||||
if (sclk_mask) {
|
||||
if (!pi->sclk_dpm_key_disabled)
|
||||
amdgpu_ci_send_msg_to_smc_with_parameter(
|
||||
adev,
|
||||
PPSMC_MSG_SCLKDPM_SetEnabledMask,
|
||||
pi->dpm_level_enable_mask.
|
||||
sclk_dpm_enable_mask &
|
||||
sclk_mask);
|
||||
}
|
||||
|
||||
if (mclk_mask) {
|
||||
if (!pi->mclk_dpm_key_disabled)
|
||||
amdgpu_ci_send_msg_to_smc_with_parameter(
|
||||
adev,
|
||||
PPSMC_MSG_MCLKDPM_SetEnabledMask,
|
||||
pi->dpm_level_enable_mask.
|
||||
mclk_dpm_enable_mask &
|
||||
mclk_mask);
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int ci_dpm_set_power_profile_state(struct amdgpu_device *adev,
|
||||
struct amd_pp_profile *request)
|
||||
{
|
||||
struct ci_power_info *pi = ci_get_pi(adev);
|
||||
int ret = -1;
|
||||
|
||||
if (!pi || !request)
|
||||
return -EINVAL;
|
||||
|
||||
if (adev->pm.dpm.forced_level !=
|
||||
AMD_DPM_FORCED_LEVEL_AUTO)
|
||||
return -EINVAL;
|
||||
|
||||
if (request->min_sclk ||
|
||||
request->min_mclk ||
|
||||
request->activity_threshold ||
|
||||
request->up_hyst ||
|
||||
request->down_hyst) {
|
||||
if (request->type == AMD_PP_GFX_PROFILE)
|
||||
memcpy(&pi->gfx_power_profile, request,
|
||||
sizeof(struct amd_pp_profile));
|
||||
else if (request->type == AMD_PP_COMPUTE_PROFILE)
|
||||
memcpy(&pi->compute_power_profile, request,
|
||||
sizeof(struct amd_pp_profile));
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
if (request->type == pi->current_power_profile)
|
||||
ret = ci_set_power_profile_state(
|
||||
adev,
|
||||
request);
|
||||
} else {
|
||||
/* set power profile if it exists */
|
||||
switch (request->type) {
|
||||
case AMD_PP_GFX_PROFILE:
|
||||
ret = ci_set_power_profile_state(
|
||||
adev,
|
||||
&pi->gfx_power_profile);
|
||||
break;
|
||||
case AMD_PP_COMPUTE_PROFILE:
|
||||
ret = ci_set_power_profile_state(
|
||||
adev,
|
||||
&pi->compute_power_profile);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
pi->current_power_profile = request->type;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ci_dpm_reset_power_profile_state(struct amdgpu_device *adev,
|
||||
struct amd_pp_profile *request)
|
||||
{
|
||||
struct ci_power_info *pi = ci_get_pi(adev);
|
||||
|
||||
if (!pi || !request)
|
||||
return -EINVAL;
|
||||
|
||||
if (request->type == AMD_PP_GFX_PROFILE) {
|
||||
pi->gfx_power_profile = pi->default_gfx_power_profile;
|
||||
return ci_dpm_set_power_profile_state(adev,
|
||||
&pi->gfx_power_profile);
|
||||
} else if (request->type == AMD_PP_COMPUTE_PROFILE) {
|
||||
pi->compute_power_profile =
|
||||
pi->default_compute_power_profile;
|
||||
return ci_dpm_set_power_profile_state(adev,
|
||||
&pi->compute_power_profile);
|
||||
} else
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int ci_dpm_switch_power_profile(struct amdgpu_device *adev,
|
||||
enum amd_pp_profile_type type)
|
||||
{
|
||||
struct ci_power_info *pi = ci_get_pi(adev);
|
||||
struct amd_pp_profile request = {0};
|
||||
|
||||
if (!pi)
|
||||
return -EINVAL;
|
||||
|
||||
if (pi->current_power_profile != type) {
|
||||
request.type = type;
|
||||
return ci_dpm_set_power_profile_state(adev, &request);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ci_dpm_read_sensor(struct amdgpu_device *adev, int idx,
|
||||
void *value, int *size)
|
||||
{
|
||||
u32 activity_percent = 50;
|
||||
int ret;
|
||||
|
||||
/* size must be at least 4 bytes for all sensors */
|
||||
if (*size < 4)
|
||||
return -EINVAL;
|
||||
|
||||
switch (idx) {
|
||||
case AMDGPU_PP_SENSOR_GFX_SCLK:
|
||||
*((uint32_t *)value) = ci_get_average_sclk_freq(adev);
|
||||
*size = 4;
|
||||
return 0;
|
||||
case AMDGPU_PP_SENSOR_GFX_MCLK:
|
||||
*((uint32_t *)value) = ci_get_average_mclk_freq(adev);
|
||||
*size = 4;
|
||||
return 0;
|
||||
case AMDGPU_PP_SENSOR_GPU_TEMP:
|
||||
*((uint32_t *)value) = ci_dpm_get_temp(adev);
|
||||
*size = 4;
|
||||
return 0;
|
||||
case AMDGPU_PP_SENSOR_GPU_LOAD:
|
||||
ret = ci_read_smc_soft_register(adev,
|
||||
offsetof(SMU7_SoftRegisters,
|
||||
AverageGraphicsA),
|
||||
&activity_percent);
|
||||
if (ret == 0) {
|
||||
activity_percent += 0x80;
|
||||
activity_percent >>= 8;
|
||||
activity_percent =
|
||||
activity_percent > 100 ? 100 : activity_percent;
|
||||
}
|
||||
*((uint32_t *)value) = activity_percent;
|
||||
*size = 4;
|
||||
return 0;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
const struct amd_ip_funcs ci_dpm_ip_funcs = {
|
||||
.name = "ci_dpm",
|
||||
.early_init = ci_dpm_early_init,
|
||||
@ -6730,6 +7020,11 @@ static const struct amdgpu_dpm_funcs ci_dpm_funcs = {
|
||||
.set_mclk_od = ci_dpm_set_mclk_od,
|
||||
.check_state_equal = ci_check_state_equal,
|
||||
.get_vce_clock_state = amdgpu_get_vce_clock_state,
|
||||
.get_power_profile_state = ci_dpm_get_power_profile_state,
|
||||
.set_power_profile_state = ci_dpm_set_power_profile_state,
|
||||
.reset_power_profile_state = ci_dpm_reset_power_profile_state,
|
||||
.switch_power_profile = ci_dpm_switch_power_profile,
|
||||
.read_sensor = ci_dpm_read_sensor,
|
||||
};
|
||||
|
||||
static void ci_dpm_set_dpm_funcs(struct amdgpu_device *adev)
|
||||
|
@ -295,6 +295,13 @@ struct ci_power_info {
|
||||
bool fan_is_controlled_by_smc;
|
||||
u32 t_min;
|
||||
u32 fan_ctrl_default_mode;
|
||||
|
||||
/* power profile */
|
||||
struct amd_pp_profile gfx_power_profile;
|
||||
struct amd_pp_profile compute_power_profile;
|
||||
struct amd_pp_profile default_gfx_power_profile;
|
||||
struct amd_pp_profile default_compute_power_profile;
|
||||
enum amd_pp_profile_type current_power_profile;
|
||||
};
|
||||
|
||||
#define CISLANDS_VOLTAGE_CONTROL_NONE 0x0
|
||||
|
@ -1212,6 +1212,11 @@ static int cik_asic_reset(struct amdgpu_device *adev)
|
||||
return r;
|
||||
}
|
||||
|
||||
static u32 cik_get_config_memsize(struct amdgpu_device *adev)
|
||||
{
|
||||
return RREG32(mmCONFIG_MEMSIZE);
|
||||
}
|
||||
|
||||
static int cik_set_uvd_clock(struct amdgpu_device *adev, u32 clock,
|
||||
u32 cntl_reg, u32 status_reg)
|
||||
{
|
||||
@ -1641,6 +1646,7 @@ static const struct amdgpu_asic_funcs cik_asic_funcs =
|
||||
.get_xclk = &cik_get_xclk,
|
||||
.set_uvd_clocks = &cik_set_uvd_clocks,
|
||||
.set_vce_clocks = &cik_set_vce_clocks,
|
||||
.get_config_memsize = &cik_get_config_memsize,
|
||||
};
|
||||
|
||||
static int cik_common_early_init(void *handle)
|
||||
@ -1779,6 +1785,8 @@ static int cik_common_early_init(void *handle)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
adev->firmware.load_type = amdgpu_ucode_get_load_type(adev, amdgpu_fw_load_type);
|
||||
|
||||
amdgpu_get_pcie_info(adev);
|
||||
|
||||
return 0;
|
||||
|
@ -248,8 +248,9 @@ static void cik_ih_decode_iv(struct amdgpu_device *adev,
|
||||
dw[2] = le32_to_cpu(adev->irq.ih.ring[ring_index + 2]);
|
||||
dw[3] = le32_to_cpu(adev->irq.ih.ring[ring_index + 3]);
|
||||
|
||||
entry->client_id = AMDGPU_IH_CLIENTID_LEGACY;
|
||||
entry->src_id = dw[0] & 0xff;
|
||||
entry->src_data = dw[1] & 0xfffffff;
|
||||
entry->src_data[0] = dw[1] & 0xfffffff;
|
||||
entry->ring_id = dw[2] & 0xff;
|
||||
entry->vm_id = (dw[2] >> 8) & 0xff;
|
||||
entry->pas_id = (dw[2] >> 16) & 0xffff;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user