Merge tag 'drm-misc-next-2025-11-05-1' of https://gitlab.freedesktop.org/drm/misc/kernel into drm-next

drm-misc-next for v6.19-rc1:

UAPI Changes:
- Add userptr support to ivpu.
- Add IOCTL's for resource and telemetry data in amdxdna.

Core Changes:
- Improve some atomic state checking handling.
- drm/client updates.
- Use forward declarations instead of including drm_print.h
- RUse allocation flags in ttm_pool/device_init and allow specifying max
  useful pool size and propagate ENOSPC.
- Updates and fixes to scheduler and bridge code.
- Add support for quirking DisplayID checksum errors.

Driver Changes:
- Assorted cleanups and fixes in rcar-du, accel/ivpu, panel/nv3052cf,
  sti, imxm, accel/qaic, accel/amdxdna, imagination, tidss, sti,
  panthor, vkms.
- Add Samsung S6E3FC2X01 DDIC/AMS641RW, Synaptics TDDI series DSI,
  TL121BVMS07-00 (IL79900A) panels.
- Add mali MediaTek MT8196 SoC gpu support.
- Add etnaviv GC8000 Nano Ultra VIP r6205 support.
- Document powervr ge7800 support in the devicetree.

Signed-off-by: Dave Airlie <airlied@redhat.com>

From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: https://patch.msgid.link/5afae707-c9aa-4a47-b726-5e1f1aa7a106@linux.intel.com
This commit is contained in:
Dave Airlie
2025-11-07 12:40:51 +10:00
479 changed files with 3826 additions and 1463 deletions

View File

@@ -36,7 +36,7 @@ polling mode and reenables the IRQ line.
This mitigation in QAIC is very effective. The same lprnet usecase that
generates 100k IRQs per second (per /proc/interrupts) is reduced to roughly 64
IRQs over 5 minutes while keeping the host system stable, and having the same
workload throughput performance (within run to run noise variation).
workload throughput performance (within run-to-run noise variation).
Single MSI Mode
---------------
@@ -49,7 +49,7 @@ useful to be able to fall back to a single MSI when needed.
To support this fallback, we allow the case where only one MSI is able to be
allocated, and share that one MSI between MHI and the DBCs. The device detects
when only one MSI has been configured and directs the interrupts for the DBCs
to the interrupt normally used for MHI. Unfortunately this means that the
to the interrupt normally used for MHI. Unfortunately, this means that the
interrupt handlers for every DBC and MHI wake up for every interrupt that
arrives; however, the DBC threaded irq handlers only are started when work to be
done is detected (MHI will always start its threaded handler).
@@ -62,9 +62,9 @@ never disabled, allowing each new entry to the FIFO to trigger a new interrupt.
Neural Network Control (NNC) Protocol
=====================================
The implementation of NNC is split between the KMD (QAIC) and UMD. In general
The implementation of NNC is split between the KMD (QAIC) and UMD. In general,
QAIC understands how to encode/decode NNC wire protocol, and elements of the
protocol which require kernel space knowledge to process (for example, mapping
protocol which requires kernel space knowledge to process (for example, mapping
host memory to device IOVAs). QAIC understands the structure of a message, and
all of the transactions. QAIC does not understand commands (the payload of a
passthrough transaction).

View File

@@ -157,7 +157,8 @@ examples:
panel@0 {
reg = <0>;
compatible = "raspberrypi,dsi-7inch";
compatible = "raspberrypi,dsi-7inch", "ilitek,ili9881c";
power-supply = <&vcc_lcd_reg>;
port {
panel_in: endpoint {

View File

@@ -0,0 +1,68 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/panel/ilitek,il79900a.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Ilitek IL79900a based MIPI-DSI panels
maintainers:
- Langyan Ye <yelangyan@huaqin.corp-partner.google.com>
allOf:
- $ref: panel-common.yaml#
properties:
compatible:
items:
- enum:
- tianma,tl121bvms07-00
- const: ilitek,il79900a
reg:
maxItems: 1
description: DSI virtual channel used by the panel
enable-gpios:
maxItems: 1
description: GPIO specifier for the enable pin
avdd-supply:
description: Positive analog voltage supply (AVDD)
avee-supply:
description: Negative analog voltage supply (AVEE)
pp1800-supply:
description: 1.8V logic voltage supply
backlight: true
required:
- compatible
- reg
- enable-gpios
- avdd-supply
- avee-supply
- pp1800-supply
additionalProperties: false
examples:
- |
dsi {
#address-cells = <1>;
#size-cells = <0>;
panel@0 {
compatible = "tianma,tl121bvms07-00", "ilitek,il79900a";
reg = <0>;
enable-gpios = <&pio 25 0>;
avdd-supply = <&reg_avdd>;
avee-supply = <&reg_avee>;
pp1800-supply = <&reg_pp1800>;
backlight = <&backlight>;
};
};
...

View File

@@ -56,8 +56,6 @@ properties:
- panasonic,vvx10f034n00
# Samsung s6e3fa7 1080x2220 based AMS559NK06 AMOLED panel
- samsung,s6e3fa7-ams559nk06
# Samsung s6e3fc2x01 1080x2340 AMOLED panel
- samsung,s6e3fc2x01
# Samsung sofef00 1080x2280 AMOLED panel
- samsung,sofef00
# Shangai Top Display Optoelectronics 7" TL070WSH30 1024x600 TFT LCD panel
@@ -80,7 +78,6 @@ allOf:
properties:
compatible:
enum:
- samsung,s6e3fc2x01
- samsung,sofef00
then:
properties:

View File

@@ -33,6 +33,8 @@ properties:
- samsung,atna45dc02
# Samsung 15.6" 3K (2880x1620 pixels) eDP AMOLED panel
- samsung,atna56ac03
# Samsung 16.0" 3K (2880x1800 pixels) eDP AMOLED panel
- samsung,atna60cl08
- const: samsung,atna33xc20
enable-gpios: true

View File

@@ -0,0 +1,81 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/panel/samsung,s6e3fc2x01.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Samsung S6E3FC2X01 AMOLED DDIC
description: The S6E3FC2X01 is display driver IC with connected panel.
maintainers:
- David Heidelberg <david@ixit.cz>
allOf:
- $ref: panel-common.yaml#
properties:
compatible:
items:
- enum:
# Samsung 6.41 inch, 1080x2340 pixels, 19.5:9 ratio
- samsung,s6e3fc2x01-ams641rw
- const: samsung,s6e3fc2x01
reg:
maxItems: 1
reset-gpios: true
port: true
vddio-supply:
description: VDD regulator
vci-supply:
description: VCI regulator
poc-supply:
description: POC regulator
required:
- compatible
- reset-gpios
- vddio-supply
- vci-supply
- poc-supply
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
dsi {
#address-cells = <1>;
#size-cells = <0>;
panel@0 {
compatible = "samsung,s6e3fc2x01-ams641rw", "samsung,s6e3fc2x01";
reg = <0>;
vddio-supply = <&vreg_l14a_1p88>;
vci-supply = <&s2dos05_buck1>;
poc-supply = <&s2dos05_ldo1>;
te-gpios = <&tlmm 10 GPIO_ACTIVE_HIGH>;
reset-gpios = <&tlmm 6 GPIO_ACTIVE_HIGH>;
pinctrl-0 = <&sde_dsi_active &sde_te_active_sleep>;
pinctrl-1 = <&sde_dsi_suspend &sde_te_active_sleep>;
pinctrl-names = "default", "sleep";
port {
panel_in: endpoint {
remote-endpoint = <&mdss_dsi0_out>;
};
};
};
};
...

View File

@@ -0,0 +1,89 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/panel/synaptics,td4300-panel.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Synaptics TDDI Display Panel Controller
maintainers:
- Kaustabh Chakraborty <kauschluss@disroot.org>
allOf:
- $ref: panel-common.yaml#
properties:
compatible:
enum:
- syna,td4101-panel
- syna,td4300-panel
reg:
maxItems: 1
vio-supply:
description: core I/O voltage supply
vsn-supply:
description: negative voltage supply for analog circuits
vsp-supply:
description: positive voltage supply for analog circuits
backlight-gpios:
maxItems: 1
description: backlight enable GPIO
reset-gpios: true
width-mm: true
height-mm: true
panel-timing: true
required:
- compatible
- reg
- width-mm
- height-mm
- panel-timing
additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
dsi {
#address-cells = <1>;
#size-cells = <0>;
panel@0 {
compatible = "syna,td4300-panel";
reg = <0>;
vio-supply = <&panel_vio_reg>;
vsn-supply = <&panel_vsn_reg>;
vsp-supply = <&panel_vsp_reg>;
backlight-gpios = <&gpd3 5 GPIO_ACTIVE_LOW>;
reset-gpios = <&gpd3 4 GPIO_ACTIVE_LOW>;
width-mm = <68>;
height-mm = <121>;
panel-timing {
clock-frequency = <144389520>;
hactive = <1080>;
hsync-len = <4>;
hfront-porch = <120>;
hback-porch = <32>;
vactive = <1920>;
vsync-len = <2>;
vfront-porch = <21>;
vback-porch = <4>;
};
};
};
...

View File

@@ -19,6 +19,7 @@ properties:
- items:
- enum:
- mediatek,mt8196-mali
- nxp,imx95-mali # G310
- rockchip,rk3588-mali
- const: arm,mali-valhall-csf # Mali Valhall GPU model/revision is fully discoverable
@@ -45,7 +46,9 @@ properties:
minItems: 1
items:
- const: core
- const: coregroup
- enum:
- coregroup
- stacks
- const: stacks
mali-supply: true
@@ -110,6 +113,27 @@ allOf:
power-domain-names: false
required:
- mali-supply
- if:
properties:
compatible:
contains:
const: mediatek,mt8196-mali
then:
properties:
mali-supply: false
sram-supply: false
operating-points-v2: false
power-domains:
maxItems: 1
power-domain-names: false
clocks:
maxItems: 2
clock-names:
items:
- const: core
- const: stacks
required:
- power-domains
examples:
- |
@@ -145,5 +169,17 @@ examples:
};
};
};
- |
gpu@48000000 {
compatible = "mediatek,mt8196-mali", "arm,mali-valhall-csf";
reg = <0x48000000 0x480000>;
clocks = <&gpufreq 0>, <&gpufreq 1>;
clock-names = "core", "stacks";
interrupts = <GIC_SPI 606 IRQ_TYPE_LEVEL_HIGH 0>,
<GIC_SPI 605 IRQ_TYPE_LEVEL_HIGH 0>,
<GIC_SPI 604 IRQ_TYPE_LEVEL_HIGH 0>;
interrupt-names = "job", "mmu", "gpu";
power-domains = <&gpufreq>;
};
...

View File

@@ -19,6 +19,10 @@ properties:
- renesas,r8a77961-gpu
- const: img,img-gx6250
- const: img,img-rogue
- items:
- const: renesas,r8a77965-gpu
- const: img,img-ge7800
- const: img,img-rogue
- items:
- enum:
- ti,am62-gpu
@@ -100,12 +104,12 @@ allOf:
clocks:
maxItems: 1
- if:
properties:
compatible:
contains:
enum:
- img,img-ge7800
- img,img-gx6250
- thead,th1520-gpu
then:
@@ -135,8 +139,9 @@ allOf:
compatible:
contains:
enum:
- img,img-gx6250
- img,img-bxs-4-64
- img,img-ge7800
- img,img-gx6250
then:
properties:
power-domains:

View File

@@ -159,26 +159,23 @@ To return to graphical mode, do::
sudo systemctl isolate graphical.target
Once you are in text only mode, you can run tests using the --device switch
or IGT_DEVICE variable to specify the device filter for the driver we want
to test. IGT_DEVICE can also be used with the run-test.sh script to run the
Once you are in text only mode, you can run tests using the IGT_FORCE_DRIVER
variable to specify the device filter for the driver we want to test.
IGT_FORCE_DRIVER can also be used with the run-tests.sh script to run the
tests for a specific driver::
sudo ./build/tests/<name of test> --device "sys:/sys/devices/platform/vkms"
sudo IGT_DEVICE="sys:/sys/devices/platform/vkms" ./build/tests/<name of test>
sudo IGT_DEVICE="sys:/sys/devices/platform/vkms" ./scripts/run-tests.sh -t <name of test>
sudo IGT_FORCE_DRIVER="vkms" ./build/tests/<name of test>
sudo IGT_FORCE_DRIVER="vkms" ./scripts/run-tests.sh -t <name of test>
For example, to test the functionality of the writeback library,
we can run the kms_writeback test::
sudo ./build/tests/kms_writeback --device "sys:/sys/devices/platform/vkms"
sudo IGT_DEVICE="sys:/sys/devices/platform/vkms" ./build/tests/kms_writeback
sudo IGT_DEVICE="sys:/sys/devices/platform/vkms" ./scripts/run-tests.sh -t kms_writeback
sudo IGT_FORCE_DRIVER="vkms" ./build/tests/kms_writeback
sudo IGT_FORCE_DRIVER="vkms" ./scripts/run-tests.sh -t kms_writeback
You can also run subtests if you do not want to run the entire test::
sudo ./build/tests/kms_flip --run-subtest basic-plain-flip --device "sys:/sys/devices/platform/vkms"
sudo IGT_DEVICE="sys:/sys/devices/platform/vkms" ./build/tests/kms_flip --run-subtest basic-plain-flip
sudo IGT_FORCE_DRIVER="vkms" ./build/tests/kms_flip --run-subtest basic-plain-flip
Testing With KUnit
==================

View File

@@ -8068,6 +8068,12 @@ S: Maintained
F: Documentation/devicetree/bindings/display/panel/samsung,s6d7aa0.yaml
F: drivers/gpu/drm/panel/panel-samsung-s6d7aa0.c
DRM DRIVER FOR SAMSUNG S6E3FC2X01 DDIC
M: David Heidelberg <david@ixit.cz>
S: Maintained
F: Documentation/devicetree/bindings/display/panel/samsung,s6e3fc2x01.yaml
F: drivers/gpu/drm/panel/panel-samsung-s6e3fc2x01.c
DRM DRIVER FOR SAMSUNG S6E3HA8 PANELS
M: Dzmitry Sankouski <dsankouski@gmail.com>
S: Maintained

View File

@@ -34,6 +34,41 @@ usb2_picophy2: phy3 {
status = "disabled";
};
display-subsystem {
compatible = "st,sti-display-subsystem";
ports = <&compositor>, <&hqvdp>, <&tvout>, <&sti_hdmi>;
assigned-clocks = <&clk_s_d2_quadfs 0>,
<&clk_s_d2_quadfs 1>,
<&clk_s_c0_pll1 0>,
<&clk_s_c0_flexgen CLK_COMPO_DVP>,
<&clk_s_c0_flexgen CLK_MAIN_DISP>,
<&clk_s_d2_flexgen CLK_PIX_MAIN_DISP>,
<&clk_s_d2_flexgen CLK_PIX_AUX_DISP>,
<&clk_s_d2_flexgen CLK_PIX_GDP1>,
<&clk_s_d2_flexgen CLK_PIX_GDP2>,
<&clk_s_d2_flexgen CLK_PIX_GDP3>,
<&clk_s_d2_flexgen CLK_PIX_GDP4>;
assigned-clock-parents = <0>,
<0>,
<0>,
<&clk_s_c0_pll1 0>,
<&clk_s_c0_pll1 0>,
<&clk_s_d2_quadfs 0>,
<&clk_s_d2_quadfs 1>,
<&clk_s_d2_quadfs 0>,
<&clk_s_d2_quadfs 0>,
<&clk_s_d2_quadfs 0>,
<&clk_s_d2_quadfs 0>;
assigned-clock-rates = <297000000>,
<297000000>,
<0>,
<400000000>,
<400000000>;
};
soc {
ohci0: usb@9a03c00 {
compatible = "st,st-ohci-300x";
@@ -99,153 +134,176 @@ ehci1: usb@9a83e00 {
status = "disabled";
};
sti-display-subsystem@0 {
compatible = "st,sti-display-subsystem";
#address-cells = <1>;
#size-cells = <1>;
compositor: display-controller@9d11000 {
compatible = "st,stih407-compositor";
reg = <0x9d11000 0x1000>;
reg = <0 0>;
assigned-clocks = <&clk_s_d2_quadfs 0>,
<&clk_s_d2_quadfs 1>,
<&clk_s_c0_pll1 0>,
<&clk_s_c0_flexgen CLK_COMPO_DVP>,
<&clk_s_c0_flexgen CLK_MAIN_DISP>,
<&clk_s_d2_flexgen CLK_PIX_MAIN_DISP>,
<&clk_s_d2_flexgen CLK_PIX_AUX_DISP>,
<&clk_s_d2_flexgen CLK_PIX_GDP1>,
<&clk_s_d2_flexgen CLK_PIX_GDP2>,
<&clk_s_d2_flexgen CLK_PIX_GDP3>,
<&clk_s_d2_flexgen CLK_PIX_GDP4>;
clock-names = "compo_main",
"compo_aux",
"pix_main",
"pix_aux",
"pix_gdp1",
"pix_gdp2",
"pix_gdp3",
"pix_gdp4",
"main_parent",
"aux_parent";
assigned-clock-parents = <0>,
<0>,
<0>,
<&clk_s_c0_pll1 0>,
<&clk_s_c0_pll1 0>,
<&clk_s_d2_quadfs 0>,
<&clk_s_d2_quadfs 1>,
<&clk_s_d2_quadfs 0>,
clocks = <&clk_s_c0_flexgen CLK_COMPO_DVP>,
<&clk_s_c0_flexgen CLK_COMPO_DVP>,
<&clk_s_d2_flexgen CLK_PIX_MAIN_DISP>,
<&clk_s_d2_flexgen CLK_PIX_AUX_DISP>,
<&clk_s_d2_flexgen CLK_PIX_GDP1>,
<&clk_s_d2_flexgen CLK_PIX_GDP2>,
<&clk_s_d2_flexgen CLK_PIX_GDP3>,
<&clk_s_d2_flexgen CLK_PIX_GDP4>,
<&clk_s_d2_quadfs 0>,
<&clk_s_d2_quadfs 1>;
reset-names = "compo-main", "compo-aux";
resets = <&softreset STIH407_COMPO_SOFTRESET>,
<&softreset STIH407_COMPO_SOFTRESET>;
st,vtg = <&vtg_main>, <&vtg_aux>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
compo_main_out: endpoint {
remote-endpoint = <&tvout_in0>;
};
};
port@1 {
reg = <1>;
compo_aux_out: endpoint {
remote-endpoint = <&tvout_in1>;
};
};
};
};
tvout: encoder@8d08000 {
compatible = "st,stih407-tvout";
reg = <0x8d08000 0x1000>;
reg-names = "tvout-reg";
reset-names = "tvout";
resets = <&softreset STIH407_HDTVOUT_SOFTRESET>;
assigned-clocks = <&clk_s_d2_flexgen CLK_PIX_HDMI>,
<&clk_s_d2_flexgen CLK_TMDS_HDMI>,
<&clk_s_d2_flexgen CLK_REF_HDMIPHY>,
<&clk_s_d0_flexgen CLK_PCM_0>,
<&clk_s_d2_flexgen CLK_PIX_HDDAC>,
<&clk_s_d2_flexgen CLK_HDDAC>;
assigned-clock-parents = <&clk_s_d2_quadfs 0>,
<&clk_tmdsout_hdmi>,
<&clk_s_d2_quadfs 0>,
<&clk_s_d0_quadfs 0>,
<&clk_s_d2_quadfs 0>,
<&clk_s_d2_quadfs 0>;
assigned-clock-rates = <297000000>,
<297000000>,
<0>,
<400000000>,
<400000000>;
ranges;
sti-compositor@9d11000 {
compatible = "st,stih407-compositor";
reg = <0x9d11000 0x1000>;
clock-names = "compo_main",
"compo_aux",
"pix_main",
"pix_aux",
"pix_gdp1",
"pix_gdp2",
"pix_gdp3",
"pix_gdp4",
"main_parent",
"aux_parent";
clocks = <&clk_s_c0_flexgen CLK_COMPO_DVP>,
<&clk_s_c0_flexgen CLK_COMPO_DVP>,
<&clk_s_d2_flexgen CLK_PIX_MAIN_DISP>,
<&clk_s_d2_flexgen CLK_PIX_AUX_DISP>,
<&clk_s_d2_flexgen CLK_PIX_GDP1>,
<&clk_s_d2_flexgen CLK_PIX_GDP2>,
<&clk_s_d2_flexgen CLK_PIX_GDP3>,
<&clk_s_d2_flexgen CLK_PIX_GDP4>,
<&clk_s_d2_quadfs 0>,
<&clk_s_d2_quadfs 1>;
reset-names = "compo-main", "compo-aux";
resets = <&softreset STIH407_COMPO_SOFTRESET>,
<&softreset STIH407_COMPO_SOFTRESET>;
st,vtg = <&vtg_main>, <&vtg_aux>;
};
sti-tvout@8d08000 {
compatible = "st,stih407-tvout";
reg = <0x8d08000 0x1000>;
reg-names = "tvout-reg";
reset-names = "tvout";
resets = <&softreset STIH407_HDTVOUT_SOFTRESET>;
ports {
#address-cells = <1>;
#size-cells = <1>;
assigned-clocks = <&clk_s_d2_flexgen CLK_PIX_HDMI>,
<&clk_s_d2_flexgen CLK_TMDS_HDMI>,
<&clk_s_d2_flexgen CLK_REF_HDMIPHY>,
<&clk_s_d0_flexgen CLK_PCM_0>,
<&clk_s_d2_flexgen CLK_PIX_HDDAC>,
<&clk_s_d2_flexgen CLK_HDDAC>;
#size-cells = <0>;
assigned-clock-parents = <&clk_s_d2_quadfs 0>,
<&clk_tmdsout_hdmi>,
<&clk_s_d2_quadfs 0>,
<&clk_s_d0_quadfs 0>,
<&clk_s_d2_quadfs 0>,
<&clk_s_d2_quadfs 0>;
port@0 {
reg = <0>;
tvout_in0: endpoint {
remote-endpoint = <&compo_main_out>;
};
};
port@1 {
reg = <1>;
tvout_in1: endpoint {
remote-endpoint = <&compo_aux_out>;
};
};
port@2 {
reg = <2>;
tvout_out0: endpoint {
remote-endpoint = <&hdmi_in>;
};
};
port@3 {
reg = <3>;
tvout_out1: endpoint {
remote-endpoint = <&hda_in>;
};
};
};
};
sti_hdmi: sti-hdmi@8d04000 {
compatible = "st,stih407-hdmi";
reg = <0x8d04000 0x1000>;
reg-names = "hdmi-reg";
#sound-dai-cells = <0>;
interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "irq";
clock-names = "pix",
"tmds",
"phy",
"audio",
"main_parent",
"aux_parent";
sti_hdmi: hdmi@8d04000 {
compatible = "st,stih407-hdmi";
reg = <0x8d04000 0x1000>;
reg-names = "hdmi-reg";
#sound-dai-cells = <0>;
interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "irq";
clock-names = "pix",
"tmds",
"phy",
"audio",
"main_parent",
"aux_parent";
clocks = <&clk_s_d2_flexgen CLK_PIX_HDMI>,
<&clk_s_d2_flexgen CLK_TMDS_HDMI>,
<&clk_s_d2_flexgen CLK_REF_HDMIPHY>,
<&clk_s_d0_flexgen CLK_PCM_0>,
<&clk_s_d2_quadfs 0>,
<&clk_s_d2_quadfs 1>;
clocks = <&clk_s_d2_flexgen CLK_PIX_HDMI>,
<&clk_s_d2_flexgen CLK_TMDS_HDMI>,
<&clk_s_d2_flexgen CLK_REF_HDMIPHY>,
<&clk_s_d0_flexgen CLK_PCM_0>,
<&clk_s_d2_quadfs 0>,
<&clk_s_d2_quadfs 1>;
hdmi,hpd-gpio = <&pio5 3 GPIO_ACTIVE_LOW>;
reset-names = "hdmi";
resets = <&softreset STIH407_HDMI_TX_PHY_SOFTRESET>;
ddc = <&hdmiddc>;
hdmi,hpd-gpio = <&pio5 3 GPIO_ACTIVE_LOW>;
reset-names = "hdmi";
resets = <&softreset STIH407_HDMI_TX_PHY_SOFTRESET>;
ddc = <&hdmiddc>;
port {
hdmi_in: endpoint {
remote-endpoint = <&tvout_out0>;
};
};
};
sti-hda@8d02000 {
compatible = "st,stih407-hda";
status = "disabled";
reg = <0x8d02000 0x400>, <0x92b0120 0x4>;
reg-names = "hda-reg", "video-dacs-ctrl";
clock-names = "pix",
"hddac",
"main_parent",
"aux_parent";
clocks = <&clk_s_d2_flexgen CLK_PIX_HDDAC>,
<&clk_s_d2_flexgen CLK_HDDAC>,
<&clk_s_d2_quadfs 0>,
<&clk_s_d2_quadfs 1>;
};
analog@8d02000 {
compatible = "st,stih407-hda";
status = "disabled";
reg = <0x8d02000 0x400>, <0x92b0120 0x4>;
reg-names = "hda-reg", "video-dacs-ctrl";
clock-names = "pix",
"hddac",
"main_parent",
"aux_parent";
clocks = <&clk_s_d2_flexgen CLK_PIX_HDDAC>,
<&clk_s_d2_flexgen CLK_HDDAC>,
<&clk_s_d2_quadfs 0>,
<&clk_s_d2_quadfs 1>;
sti-hqvdp@9c00000 {
compatible = "st,stih407-hqvdp";
reg = <0x9C00000 0x100000>;
clock-names = "hqvdp", "pix_main";
clocks = <&clk_s_c0_flexgen CLK_MAIN_DISP>,
<&clk_s_d2_flexgen CLK_PIX_MAIN_DISP>;
reset-names = "hqvdp";
resets = <&softreset STIH407_HDQVDP_SOFTRESET>;
st,vtg = <&vtg_main>;
port {
hda_in: endpoint {
remote-endpoint = <&tvout_out1>;
};
};
};
hqvdp: plane@9c00000 {
compatible = "st,stih407-hqvdp";
reg = <0x9C00000 0x100000>;
clock-names = "hqvdp", "pix_main";
clocks = <&clk_s_c0_flexgen CLK_MAIN_DISP>,
<&clk_s_d2_flexgen CLK_PIX_MAIN_DISP>;
reset-names = "hqvdp";
resets = <&softreset STIH407_HDQVDP_SOFTRESET>;
st,vtg = <&vtg_main>;
};
bdisp0:bdisp@9f10000 {
compatible = "st,stih407-bdisp";
reg = <0x9f10000 0x1000>;

View File

@@ -250,6 +250,28 @@ dummy: clock-dummy {
clock-output-names = "dummy";
};
gpu_opp_table: opp-table {
compatible = "operating-points-v2";
opp-500000000 {
opp-hz = /bits/ 64 <500000000>;
opp-hz-real = /bits/ 64 <500000000>;
opp-microvolt = <920000>;
};
opp-800000000 {
opp-hz = /bits/ 64 <800000000>;
opp-hz-real = /bits/ 64 <800000000>;
opp-microvolt = <920000>;
};
opp-1000000000 {
opp-hz = /bits/ 64 <1000000000>;
opp-hz-real = /bits/ 64 <1000000000>;
opp-microvolt = <920000>;
};
};
clk_ext1: clock-ext1 {
compatible = "fixed-clock";
#clock-cells = <0>;
@@ -2138,6 +2160,21 @@ netc_emdio: mdio@0,0 {
};
};
gpu: gpu@4d900000 {
compatible = "nxp,imx95-mali", "arm,mali-valhall-csf";
reg = <0 0x4d900000 0 0x480000>;
clocks = <&scmi_clk IMX95_CLK_GPU>, <&scmi_clk IMX95_CLK_GPUAPB>;
clock-names = "core", "coregroup";
interrupts = <GIC_SPI 289 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 290 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 288 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "job", "mmu", "gpu";
operating-points-v2 = <&gpu_opp_table>;
power-domains = <&scmi_devpd IMX95_PD_GPU>;
#cooling-cells = <2>;
dynamic-power-coefficient = <1013>;
};
ddr-pmu@4e090dc0 {
compatible = "fsl,imx95-ddr-pmu", "fsl,imx93-ddr-pmu";
reg = <0x0 0x4e090dc0 0x0 0x200>;

View File

@@ -204,10 +204,13 @@ aie2_sched_resp_handler(void *handle, void __iomem *data, size_t size)
cmd_abo = job->cmd_bo;
if (unlikely(!data))
if (unlikely(job->job_timeout)) {
amdxdna_cmd_set_state(cmd_abo, ERT_CMD_STATE_TIMEOUT);
ret = -EINVAL;
goto out;
}
if (unlikely(size != sizeof(u32))) {
if (unlikely(!data) || unlikely(size != sizeof(u32))) {
amdxdna_cmd_set_state(cmd_abo, ERT_CMD_STATE_ABORT);
ret = -EINVAL;
goto out;
@@ -258,6 +261,13 @@ aie2_sched_cmdlist_resp_handler(void *handle, void __iomem *data, size_t size)
int ret = 0;
cmd_abo = job->cmd_bo;
if (unlikely(job->job_timeout)) {
amdxdna_cmd_set_state(cmd_abo, ERT_CMD_STATE_TIMEOUT);
ret = -EINVAL;
goto out;
}
if (unlikely(!data) || unlikely(size != sizeof(u32) * 3)) {
amdxdna_cmd_set_state(cmd_abo, ERT_CMD_STATE_ABORT);
ret = -EINVAL;
@@ -370,6 +380,7 @@ aie2_sched_job_timedout(struct drm_sched_job *sched_job)
xdna = hwctx->client->xdna;
trace_xdna_job(sched_job, hwctx->name, "job timedout", job->seq);
job->job_timeout = true;
mutex_lock(&xdna->dev_lock);
aie2_hwctx_stop(xdna, hwctx, sched_job);
@@ -545,7 +556,6 @@ int aie2_hwctx_init(struct amdxdna_hwctx *hwctx)
struct drm_gpu_scheduler *sched;
struct amdxdna_hwctx_priv *priv;
struct amdxdna_gem_obj *heap;
struct amdxdna_dev_hdl *ndev;
int i, ret;
priv = kzalloc(sizeof(*hwctx->priv), GFP_KERNEL);
@@ -643,8 +653,6 @@ int aie2_hwctx_init(struct amdxdna_hwctx *hwctx)
amdxdna_pm_suspend_put(xdna);
hwctx->status = HWCTX_STAT_INIT;
ndev = xdna->dev_handle;
ndev->hwctx_num++;
init_waitqueue_head(&priv->job_free_wq);
XDNA_DBG(xdna, "hwctx %s init completed", hwctx->name);
@@ -677,13 +685,10 @@ int aie2_hwctx_init(struct amdxdna_hwctx *hwctx)
void aie2_hwctx_fini(struct amdxdna_hwctx *hwctx)
{
struct amdxdna_dev_hdl *ndev;
struct amdxdna_dev *xdna;
int idx;
xdna = hwctx->client->xdna;
ndev = xdna->dev_handle;
ndev->hwctx_num--;
XDNA_DBG(xdna, "%s sequence number %lld", hwctx->name, hwctx->priv->seq);
drm_sched_entity_destroy(&hwctx->priv->entity);

View File

@@ -27,6 +27,8 @@
#define DECLARE_AIE2_MSG(name, op) \
DECLARE_XDNA_MSG_COMMON(name, op, MAX_AIE2_STATUS_CODE)
#define EXEC_MSG_OPS(xdna) ((xdna)->dev_handle->exec_msg_ops)
static int aie2_send_mgmt_msg_wait(struct amdxdna_dev_hdl *ndev,
struct xdna_mailbox_msg *msg)
{
@@ -45,7 +47,7 @@ static int aie2_send_mgmt_msg_wait(struct amdxdna_dev_hdl *ndev,
ndev->mgmt_chann = NULL;
}
if (!ret && *hdl->data != AIE2_STATUS_SUCCESS) {
if (!ret && *hdl->status != AIE2_STATUS_SUCCESS) {
XDNA_ERR(xdna, "command opcode 0x%x failed, status 0x%x",
msg->opcode, *hdl->data);
ret = -EINVAL;
@@ -233,6 +235,7 @@ int aie2_create_context(struct amdxdna_dev_hdl *ndev, struct amdxdna_hwctx *hwct
ret = -EINVAL;
goto out_destroy_context;
}
ndev->hwctx_num++;
XDNA_DBG(xdna, "%s mailbox channel irq: %d, msix_id: %d",
hwctx->name, ret, resp.msix_id);
@@ -267,6 +270,7 @@ int aie2_destroy_context(struct amdxdna_dev_hdl *ndev, struct amdxdna_hwctx *hwc
hwctx->fw_ctx_id);
hwctx->priv->mbox_chann = NULL;
hwctx->fw_ctx_id = -1;
ndev->hwctx_num--;
return ret;
}
@@ -332,11 +336,6 @@ int aie2_query_status(struct amdxdna_dev_hdl *ndev, char __user *buf,
goto fail;
}
if (resp.status != AIE2_STATUS_SUCCESS) {
XDNA_ERR(xdna, "Query NPU status failed, status 0x%x", resp.status);
ret = -EINVAL;
goto fail;
}
XDNA_DBG(xdna, "Query NPU status completed");
if (size < resp.size) {
@@ -358,6 +357,55 @@ int aie2_query_status(struct amdxdna_dev_hdl *ndev, char __user *buf,
return ret;
}
int aie2_query_telemetry(struct amdxdna_dev_hdl *ndev,
char __user *buf, u32 size,
struct amdxdna_drm_query_telemetry_header *header)
{
DECLARE_AIE2_MSG(get_telemetry, MSG_OP_GET_TELEMETRY);
struct amdxdna_dev *xdna = ndev->xdna;
dma_addr_t dma_addr;
u8 *addr;
int ret;
if (header->type >= MAX_TELEMETRY_TYPE)
return -EINVAL;
addr = dma_alloc_noncoherent(xdna->ddev.dev, size, &dma_addr,
DMA_FROM_DEVICE, GFP_KERNEL);
if (!addr)
return -ENOMEM;
req.buf_addr = dma_addr;
req.buf_size = size;
req.type = header->type;
drm_clflush_virt_range(addr, size); /* device can access */
ret = aie2_send_mgmt_msg_wait(ndev, &msg);
if (ret) {
XDNA_ERR(xdna, "Query telemetry failed, status %d", ret);
goto free_buf;
}
if (size < resp.size) {
ret = -EINVAL;
XDNA_ERR(xdna, "Bad buffer size. Available: %u. Needs: %u", size, resp.size);
goto free_buf;
}
if (copy_to_user(buf, addr, resp.size)) {
ret = -EFAULT;
XDNA_ERR(xdna, "Failed to copy telemetry to user space");
goto free_buf;
}
header->major = resp.major;
header->minor = resp.minor;
free_buf:
dma_free_noncoherent(xdna->ddev.dev, size, addr, dma_addr, DMA_FROM_DEVICE);
return ret;
}
int aie2_register_asyn_event_msg(struct amdxdna_dev_hdl *ndev, dma_addr_t addr, u32 size,
void *handle, int (*cb)(void*, void __iomem *, size_t))
{
@@ -433,66 +481,316 @@ int aie2_config_cu(struct amdxdna_hwctx *hwctx,
return xdna_mailbox_send_msg(chann, &msg, TX_TIMEOUT);
}
static int aie2_init_exec_cu_req(struct amdxdna_gem_obj *cmd_bo, void *req,
size_t *size, u32 *msg_op)
{
struct execute_buffer_req *cu_req = req;
u32 cmd_len;
void *cmd;
cmd = amdxdna_cmd_get_payload(cmd_bo, &cmd_len);
if (cmd_len > sizeof(cu_req->payload))
return -EINVAL;
cu_req->cu_idx = amdxdna_cmd_get_cu_idx(cmd_bo);
if (cu_req->cu_idx == INVALID_CU_IDX)
return -EINVAL;
memcpy(cu_req->payload, cmd, cmd_len);
*size = sizeof(*cu_req);
*msg_op = MSG_OP_EXECUTE_BUFFER_CF;
return 0;
}
static int aie2_init_exec_dpu_req(struct amdxdna_gem_obj *cmd_bo, void *req,
size_t *size, u32 *msg_op)
{
struct exec_dpu_req *dpu_req = req;
struct amdxdna_cmd_start_npu *sn;
u32 cmd_len;
sn = amdxdna_cmd_get_payload(cmd_bo, &cmd_len);
if (cmd_len - sizeof(*sn) > sizeof(dpu_req->payload))
return -EINVAL;
dpu_req->cu_idx = amdxdna_cmd_get_cu_idx(cmd_bo);
if (dpu_req->cu_idx == INVALID_CU_IDX)
return -EINVAL;
dpu_req->inst_buf_addr = sn->buffer;
dpu_req->inst_size = sn->buffer_size;
dpu_req->inst_prop_cnt = sn->prop_count;
memcpy(dpu_req->payload, sn->prop_args, cmd_len - sizeof(*sn));
*size = sizeof(*dpu_req);
*msg_op = MSG_OP_EXEC_DPU;
return 0;
}
static void aie2_init_exec_chain_req(void *req, u64 slot_addr, size_t size, u32 cmd_cnt)
{
struct cmd_chain_req *chain_req = req;
chain_req->buf_addr = slot_addr;
chain_req->buf_size = size;
chain_req->count = cmd_cnt;
}
static void aie2_init_npu_chain_req(void *req, u64 slot_addr, size_t size, u32 cmd_cnt)
{
struct cmd_chain_npu_req *npu_chain_req = req;
npu_chain_req->flags = 0;
npu_chain_req->reserved = 0;
npu_chain_req->buf_addr = slot_addr;
npu_chain_req->buf_size = size;
npu_chain_req->count = cmd_cnt;
}
static int
aie2_cmdlist_fill_cf(struct amdxdna_gem_obj *cmd_bo, void *slot, size_t *size)
{
struct cmd_chain_slot_execbuf_cf *cf_slot = slot;
u32 cmd_len;
void *cmd;
cmd = amdxdna_cmd_get_payload(cmd_bo, &cmd_len);
if (*size < sizeof(*cf_slot) + cmd_len)
return -EINVAL;
cf_slot->cu_idx = amdxdna_cmd_get_cu_idx(cmd_bo);
if (cf_slot->cu_idx == INVALID_CU_IDX)
return -EINVAL;
cf_slot->arg_cnt = cmd_len / sizeof(u32);
memcpy(cf_slot->args, cmd, cmd_len);
/* Accurate slot size to hint firmware to do necessary copy */
*size = sizeof(*cf_slot) + cmd_len;
return 0;
}
static int
aie2_cmdlist_fill_dpu(struct amdxdna_gem_obj *cmd_bo, void *slot, size_t *size)
{
struct cmd_chain_slot_dpu *dpu_slot = slot;
struct amdxdna_cmd_start_npu *sn;
u32 cmd_len;
u32 arg_sz;
sn = amdxdna_cmd_get_payload(cmd_bo, &cmd_len);
arg_sz = cmd_len - sizeof(*sn);
if (cmd_len < sizeof(*sn) || arg_sz > MAX_DPU_ARGS_SIZE)
return -EINVAL;
if (*size < sizeof(*dpu_slot) + arg_sz)
return -EINVAL;
dpu_slot->cu_idx = amdxdna_cmd_get_cu_idx(cmd_bo);
if (dpu_slot->cu_idx == INVALID_CU_IDX)
return -EINVAL;
dpu_slot->inst_buf_addr = sn->buffer;
dpu_slot->inst_size = sn->buffer_size;
dpu_slot->inst_prop_cnt = sn->prop_count;
dpu_slot->arg_cnt = arg_sz / sizeof(u32);
memcpy(dpu_slot->args, sn->prop_args, arg_sz);
/* Accurate slot size to hint firmware to do necessary copy */
*size = sizeof(*dpu_slot) + arg_sz;
return 0;
}
static u32 aie2_get_chain_msg_op(u32 cmd_op)
{
switch (cmd_op) {
case ERT_START_CU:
return MSG_OP_CHAIN_EXEC_BUFFER_CF;
case ERT_START_NPU:
return MSG_OP_CHAIN_EXEC_DPU;
default:
break;
}
return MSG_OP_MAX_OPCODE;
}
static struct aie2_exec_msg_ops legacy_exec_message_ops = {
.init_cu_req = aie2_init_exec_cu_req,
.init_dpu_req = aie2_init_exec_dpu_req,
.init_chain_req = aie2_init_exec_chain_req,
.fill_cf_slot = aie2_cmdlist_fill_cf,
.fill_dpu_slot = aie2_cmdlist_fill_dpu,
.get_chain_msg_op = aie2_get_chain_msg_op,
};
static int
aie2_cmdlist_fill_npu_cf(struct amdxdna_gem_obj *cmd_bo, void *slot, size_t *size)
{
struct cmd_chain_slot_npu *npu_slot = slot;
u32 cmd_len;
void *cmd;
cmd = amdxdna_cmd_get_payload(cmd_bo, &cmd_len);
if (*size < sizeof(*npu_slot) + cmd_len)
return -EINVAL;
npu_slot->cu_idx = amdxdna_cmd_get_cu_idx(cmd_bo);
if (npu_slot->cu_idx == INVALID_CU_IDX)
return -EINVAL;
memset(npu_slot, 0, sizeof(*npu_slot));
npu_slot->type = EXEC_NPU_TYPE_NON_ELF;
npu_slot->arg_cnt = cmd_len / sizeof(u32);
memcpy(npu_slot->args, cmd, cmd_len);
*size = sizeof(*npu_slot) + cmd_len;
return 0;
}
static int
aie2_cmdlist_fill_npu_dpu(struct amdxdna_gem_obj *cmd_bo, void *slot, size_t *size)
{
struct cmd_chain_slot_npu *npu_slot = slot;
struct amdxdna_cmd_start_npu *sn;
u32 cmd_len;
u32 arg_sz;
sn = amdxdna_cmd_get_payload(cmd_bo, &cmd_len);
arg_sz = cmd_len - sizeof(*sn);
if (cmd_len < sizeof(*sn) || arg_sz > MAX_NPU_ARGS_SIZE)
return -EINVAL;
if (*size < sizeof(*npu_slot) + arg_sz)
return -EINVAL;
npu_slot->cu_idx = amdxdna_cmd_get_cu_idx(cmd_bo);
if (npu_slot->cu_idx == INVALID_CU_IDX)
return -EINVAL;
memset(npu_slot, 0, sizeof(*npu_slot));
npu_slot->type = EXEC_NPU_TYPE_PARTIAL_ELF;
npu_slot->inst_buf_addr = sn->buffer;
npu_slot->inst_size = sn->buffer_size;
npu_slot->inst_prop_cnt = sn->prop_count;
npu_slot->arg_cnt = arg_sz / sizeof(u32);
memcpy(npu_slot->args, sn->prop_args, arg_sz);
*size = sizeof(*npu_slot) + arg_sz;
return 0;
}
static u32 aie2_get_npu_chain_msg_op(u32 cmd_op)
{
return MSG_OP_CHAIN_EXEC_NPU;
}
static struct aie2_exec_msg_ops npu_exec_message_ops = {
.init_cu_req = aie2_init_exec_cu_req,
.init_dpu_req = aie2_init_exec_dpu_req,
.init_chain_req = aie2_init_npu_chain_req,
.fill_cf_slot = aie2_cmdlist_fill_npu_cf,
.fill_dpu_slot = aie2_cmdlist_fill_npu_dpu,
.get_chain_msg_op = aie2_get_npu_chain_msg_op,
};
static int aie2_init_exec_req(void *req, struct amdxdna_gem_obj *cmd_abo,
size_t *size, u32 *msg_op)
{
struct amdxdna_dev *xdna = cmd_abo->client->xdna;
int ret;
u32 op;
op = amdxdna_cmd_get_op(cmd_abo);
switch (op) {
case ERT_START_CU:
ret = EXEC_MSG_OPS(xdna)->init_cu_req(cmd_abo, req, size, msg_op);
if (ret) {
XDNA_DBG(xdna, "Init CU req failed ret %d", ret);
return ret;
}
break;
case ERT_START_NPU:
ret = EXEC_MSG_OPS(xdna)->init_dpu_req(cmd_abo, req, size, msg_op);
if (ret) {
XDNA_DBG(xdna, "Init DPU req failed ret %d", ret);
return ret;
}
break;
default:
XDNA_ERR(xdna, "Unsupported op %d", op);
ret = -EOPNOTSUPP;
break;
}
return ret;
}
static int
aie2_cmdlist_fill_slot(void *slot, struct amdxdna_gem_obj *cmd_abo,
size_t *size, u32 *cmd_op)
{
struct amdxdna_dev *xdna = cmd_abo->client->xdna;
int ret;
u32 op;
op = amdxdna_cmd_get_op(cmd_abo);
if (*cmd_op == ERT_INVALID_CMD)
*cmd_op = op;
else if (op != *cmd_op)
return -EINVAL;
switch (op) {
case ERT_START_CU:
ret = EXEC_MSG_OPS(xdna)->fill_cf_slot(cmd_abo, slot, size);
break;
case ERT_START_NPU:
ret = EXEC_MSG_OPS(xdna)->fill_dpu_slot(cmd_abo, slot, size);
break;
default:
XDNA_INFO(xdna, "Unsupported op %d", op);
ret = -EOPNOTSUPP;
break;
}
return ret;
}
void aie2_msg_init(struct amdxdna_dev_hdl *ndev)
{
if (AIE2_FEATURE_ON(ndev, AIE2_NPU_COMMAND))
ndev->exec_msg_ops = &npu_exec_message_ops;
else
ndev->exec_msg_ops = &legacy_exec_message_ops;
}
static inline struct amdxdna_gem_obj *
aie2_cmdlist_get_cmd_buf(struct amdxdna_sched_job *job)
{
int idx = get_job_idx(job->seq);
return job->hwctx->priv->cmd_buf[idx];
}
int aie2_execbuf(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job *job,
int (*notify_cb)(void *, void __iomem *, size_t))
{
struct mailbox_channel *chann = hwctx->priv->mbox_chann;
struct amdxdna_dev *xdna = hwctx->client->xdna;
struct amdxdna_gem_obj *cmd_abo = job->cmd_bo;
union {
struct execute_buffer_req ebuf;
struct exec_dpu_req dpu;
} req;
struct xdna_mailbox_msg msg;
u32 payload_len;
void *payload;
int cu_idx;
union exec_req req;
int ret;
u32 op;
if (!chann)
return -ENODEV;
payload = amdxdna_cmd_get_payload(cmd_abo, &payload_len);
if (!payload) {
XDNA_ERR(xdna, "Invalid command, cannot get payload");
return -EINVAL;
}
ret = aie2_init_exec_req(&req, cmd_abo, &msg.send_size, &msg.opcode);
if (ret)
return ret;
cu_idx = amdxdna_cmd_get_cu_idx(cmd_abo);
if (cu_idx < 0) {
XDNA_DBG(xdna, "Invalid cu idx");
return -EINVAL;
}
op = amdxdna_cmd_get_op(cmd_abo);
switch (op) {
case ERT_START_CU:
if (unlikely(payload_len > sizeof(req.ebuf.payload)))
XDNA_DBG(xdna, "Invalid ebuf payload len: %d", payload_len);
req.ebuf.cu_idx = cu_idx;
memcpy(req.ebuf.payload, payload, sizeof(req.ebuf.payload));
msg.send_size = sizeof(req.ebuf);
msg.opcode = MSG_OP_EXECUTE_BUFFER_CF;
break;
case ERT_START_NPU: {
struct amdxdna_cmd_start_npu *sn = payload;
if (unlikely(payload_len - sizeof(*sn) > sizeof(req.dpu.payload)))
XDNA_DBG(xdna, "Invalid dpu payload len: %d", payload_len);
req.dpu.inst_buf_addr = sn->buffer;
req.dpu.inst_size = sn->buffer_size;
req.dpu.inst_prop_cnt = sn->prop_count;
req.dpu.cu_idx = cu_idx;
memcpy(req.dpu.payload, sn->prop_args, sizeof(req.dpu.payload));
msg.send_size = sizeof(req.dpu);
msg.opcode = MSG_OP_EXEC_DPU;
break;
}
default:
XDNA_DBG(xdna, "Invalid ERT cmd op code: %d", op);
return -EINVAL;
}
msg.handle = job;
msg.notify_cb = notify_cb;
msg.send_data = (u8 *)&req;
@@ -508,135 +806,6 @@ int aie2_execbuf(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job *job,
return 0;
}
static int
aie2_cmdlist_fill_one_slot_cf(void *cmd_buf, u32 offset,
struct amdxdna_gem_obj *abo, u32 *size)
{
struct cmd_chain_slot_execbuf_cf *buf = cmd_buf + offset;
int cu_idx = amdxdna_cmd_get_cu_idx(abo);
u32 payload_len;
void *payload;
if (cu_idx < 0)
return -EINVAL;
payload = amdxdna_cmd_get_payload(abo, &payload_len);
if (!payload)
return -EINVAL;
if (!slot_has_space(*buf, offset, payload_len))
return -ENOSPC;
buf->cu_idx = cu_idx;
buf->arg_cnt = payload_len / sizeof(u32);
memcpy(buf->args, payload, payload_len);
/* Accurate buf size to hint firmware to do necessary copy */
*size = sizeof(*buf) + payload_len;
return 0;
}
static int
aie2_cmdlist_fill_one_slot_dpu(void *cmd_buf, u32 offset,
struct amdxdna_gem_obj *abo, u32 *size)
{
struct cmd_chain_slot_dpu *buf = cmd_buf + offset;
int cu_idx = amdxdna_cmd_get_cu_idx(abo);
struct amdxdna_cmd_start_npu *sn;
u32 payload_len;
void *payload;
u32 arg_sz;
if (cu_idx < 0)
return -EINVAL;
payload = amdxdna_cmd_get_payload(abo, &payload_len);
if (!payload)
return -EINVAL;
sn = payload;
arg_sz = payload_len - sizeof(*sn);
if (payload_len < sizeof(*sn) || arg_sz > MAX_DPU_ARGS_SIZE)
return -EINVAL;
if (!slot_has_space(*buf, offset, arg_sz))
return -ENOSPC;
buf->inst_buf_addr = sn->buffer;
buf->inst_size = sn->buffer_size;
buf->inst_prop_cnt = sn->prop_count;
buf->cu_idx = cu_idx;
buf->arg_cnt = arg_sz / sizeof(u32);
memcpy(buf->args, sn->prop_args, arg_sz);
/* Accurate buf size to hint firmware to do necessary copy */
*size = sizeof(*buf) + arg_sz;
return 0;
}
static int
aie2_cmdlist_fill_one_slot(u32 op, struct amdxdna_gem_obj *cmdbuf_abo, u32 offset,
struct amdxdna_gem_obj *abo, u32 *size)
{
u32 this_op = amdxdna_cmd_get_op(abo);
void *cmd_buf = cmdbuf_abo->mem.kva;
int ret;
if (this_op != op) {
ret = -EINVAL;
goto done;
}
switch (op) {
case ERT_START_CU:
ret = aie2_cmdlist_fill_one_slot_cf(cmd_buf, offset, abo, size);
break;
case ERT_START_NPU:
ret = aie2_cmdlist_fill_one_slot_dpu(cmd_buf, offset, abo, size);
break;
default:
ret = -EOPNOTSUPP;
}
done:
if (ret) {
XDNA_ERR(abo->client->xdna, "Can't fill slot for cmd op %d ret %d",
op, ret);
}
return ret;
}
static inline struct amdxdna_gem_obj *
aie2_cmdlist_get_cmd_buf(struct amdxdna_sched_job *job)
{
int idx = get_job_idx(job->seq);
return job->hwctx->priv->cmd_buf[idx];
}
static void
aie2_cmdlist_prepare_request(struct cmd_chain_req *req,
struct amdxdna_gem_obj *cmdbuf_abo, u32 size, u32 cnt)
{
req->buf_addr = cmdbuf_abo->mem.dev_addr;
req->buf_size = size;
req->count = cnt;
drm_clflush_virt_range(cmdbuf_abo->mem.kva, size);
XDNA_DBG(cmdbuf_abo->client->xdna, "Command buf addr 0x%llx size 0x%x count %d",
req->buf_addr, size, cnt);
}
static inline u32
aie2_cmd_op_to_msg_op(u32 op)
{
switch (op) {
case ERT_START_CU:
return MSG_OP_CHAIN_EXEC_BUFFER_CF;
case ERT_START_NPU:
return MSG_OP_CHAIN_EXEC_DPU;
default:
return MSG_OP_MAX_OPCODE;
}
}
int aie2_cmdlist_multi_execbuf(struct amdxdna_hwctx *hwctx,
struct amdxdna_sched_job *job,
int (*notify_cb)(void *, void __iomem *, size_t))
@@ -645,12 +814,13 @@ int aie2_cmdlist_multi_execbuf(struct amdxdna_hwctx *hwctx,
struct mailbox_channel *chann = hwctx->priv->mbox_chann;
struct amdxdna_client *client = hwctx->client;
struct amdxdna_gem_obj *cmd_abo = job->cmd_bo;
struct amdxdna_dev *xdna = client->xdna;
struct amdxdna_cmd_chain *payload;
struct xdna_mailbox_msg msg;
struct cmd_chain_req req;
union exec_chain_req req;
u32 payload_len;
u32 offset = 0;
u32 size;
size_t size;
int ret;
u32 op;
u32 i;
@@ -661,41 +831,42 @@ int aie2_cmdlist_multi_execbuf(struct amdxdna_hwctx *hwctx,
payload_len < struct_size(payload, data, payload->command_count))
return -EINVAL;
op = ERT_INVALID_CMD;
for (i = 0; i < payload->command_count; i++) {
u32 boh = (u32)(payload->data[i]);
struct amdxdna_gem_obj *abo;
abo = amdxdna_gem_get_obj(client, boh, AMDXDNA_BO_CMD);
if (!abo) {
XDNA_ERR(client->xdna, "Failed to find cmd BO %d", boh);
XDNA_ERR(xdna, "Failed to find cmd BO %d", boh);
return -ENOENT;
}
/* All sub-cmd should have same op, use the first one. */
if (i == 0)
op = amdxdna_cmd_get_op(abo);
ret = aie2_cmdlist_fill_one_slot(op, cmdbuf_abo, offset, abo, &size);
size = cmdbuf_abo->mem.size - offset;
ret = aie2_cmdlist_fill_slot(cmdbuf_abo->mem.kva + offset,
abo, &size, &op);
amdxdna_gem_put_obj(abo);
if (ret)
return -EINVAL;
return ret;
offset += size;
}
/* The offset is the accumulated total size of the cmd buffer */
aie2_cmdlist_prepare_request(&req, cmdbuf_abo, offset, payload->command_count);
msg.opcode = aie2_cmd_op_to_msg_op(op);
msg.opcode = EXEC_MSG_OPS(xdna)->get_chain_msg_op(op);
if (msg.opcode == MSG_OP_MAX_OPCODE)
return -EOPNOTSUPP;
/* The offset is the accumulated total size of the cmd buffer */
EXEC_MSG_OPS(xdna)->init_chain_req(&req, cmdbuf_abo->mem.dev_addr,
offset, payload->command_count);
drm_clflush_virt_range(cmdbuf_abo->mem.kva, offset);
msg.handle = job;
msg.notify_cb = notify_cb;
msg.send_data = (u8 *)&req;
msg.send_size = sizeof(req);
ret = xdna_mailbox_send_msg(chann, &msg, TX_TIMEOUT);
if (ret) {
XDNA_ERR(hwctx->client->xdna, "Send message failed");
XDNA_ERR(xdna, "Send message failed");
return ret;
}
@@ -708,23 +879,27 @@ int aie2_cmdlist_single_execbuf(struct amdxdna_hwctx *hwctx,
{
struct amdxdna_gem_obj *cmdbuf_abo = aie2_cmdlist_get_cmd_buf(job);
struct mailbox_channel *chann = hwctx->priv->mbox_chann;
struct amdxdna_dev *xdna = hwctx->client->xdna;
struct amdxdna_gem_obj *cmd_abo = job->cmd_bo;
struct xdna_mailbox_msg msg;
struct cmd_chain_req req;
u32 size;
union exec_chain_req req;
u32 op = ERT_INVALID_CMD;
size_t size;
int ret;
u32 op;
op = amdxdna_cmd_get_op(cmd_abo);
ret = aie2_cmdlist_fill_one_slot(op, cmdbuf_abo, 0, cmd_abo, &size);
size = cmdbuf_abo->mem.size;
ret = aie2_cmdlist_fill_slot(cmdbuf_abo->mem.kva, cmd_abo, &size, &op);
if (ret)
return ret;
aie2_cmdlist_prepare_request(&req, cmdbuf_abo, size, 1);
msg.opcode = aie2_cmd_op_to_msg_op(op);
msg.opcode = EXEC_MSG_OPS(xdna)->get_chain_msg_op(op);
if (msg.opcode == MSG_OP_MAX_OPCODE)
return -EOPNOTSUPP;
EXEC_MSG_OPS(xdna)->init_chain_req(&req, cmdbuf_abo->mem.dev_addr,
size, 1);
drm_clflush_virt_range(cmdbuf_abo->mem.kva, size);
msg.handle = job;
msg.notify_cb = notify_cb;
msg.send_data = (u8 *)&req;

View File

@@ -9,7 +9,8 @@
enum aie2_msg_opcode {
MSG_OP_CREATE_CONTEXT = 0x2,
MSG_OP_DESTROY_CONTEXT = 0x3,
MSG_OP_SYNC_BO = 0x7,
MSG_OP_GET_TELEMETRY = 0x4,
MSG_OP_SYNC_BO = 0x7,
MSG_OP_EXECUTE_BUFFER_CF = 0xC,
MSG_OP_QUERY_COL_STATUS = 0xD,
MSG_OP_QUERY_AIE_TILE_INFO = 0xE,
@@ -19,6 +20,7 @@ enum aie2_msg_opcode {
MSG_OP_CHAIN_EXEC_BUFFER_CF = 0x12,
MSG_OP_CHAIN_EXEC_DPU = 0x13,
MSG_OP_CONFIG_DEBUG_BO = 0x14,
MSG_OP_CHAIN_EXEC_NPU = 0x18,
MSG_OP_MAX_XRT_OPCODE,
MSG_OP_SUSPEND = 0x101,
MSG_OP_RESUME = 0x102,
@@ -136,6 +138,28 @@ struct destroy_ctx_resp {
enum aie2_msg_status status;
} __packed;
enum telemetry_type {
TELEMETRY_TYPE_DISABLED,
TELEMETRY_TYPE_HEALTH,
TELEMETRY_TYPE_ERROR_INFO,
TELEMETRY_TYPE_PROFILING,
TELEMETRY_TYPE_DEBUG,
MAX_TELEMETRY_TYPE
};
struct get_telemetry_req {
enum telemetry_type type;
__u64 buf_addr;
__u32 buf_size;
} __packed;
struct get_telemetry_resp {
__u32 major;
__u32 minor;
__u32 size;
enum aie2_msg_status status;
} __packed;
struct execute_buffer_req {
__u32 cu_idx;
__u32 payload[19];
@@ -149,6 +173,16 @@ struct exec_dpu_req {
__u32 payload[35];
} __packed;
enum exec_npu_type {
EXEC_NPU_TYPE_NON_ELF = 0x1,
EXEC_NPU_TYPE_PARTIAL_ELF = 0x2,
};
union exec_req {
struct execute_buffer_req ebuf;
struct exec_dpu_req dpu_req;
};
struct execute_buffer_resp {
enum aie2_msg_status status;
} __packed;
@@ -320,9 +354,6 @@ struct async_event_msg_resp {
} __packed;
#define MAX_CHAIN_CMDBUF_SIZE SZ_4K
#define slot_has_space(slot, offset, payload_size) \
(MAX_CHAIN_CMDBUF_SIZE >= (offset) + (payload_size) + \
sizeof(typeof(slot)))
struct cmd_chain_slot_execbuf_cf {
__u32 cu_idx;
@@ -340,12 +371,40 @@ struct cmd_chain_slot_dpu {
__u32 args[] __counted_by(arg_cnt);
};
#define MAX_NPU_ARGS_SIZE (26 * sizeof(__u32))
struct cmd_chain_slot_npu {
enum exec_npu_type type;
u64 inst_buf_addr;
u64 save_buf_addr;
u64 restore_buf_addr;
u32 inst_size;
u32 save_size;
u32 restore_size;
u32 inst_prop_cnt;
u32 cu_idx;
u32 arg_cnt;
u32 args[] __counted_by(arg_cnt);
} __packed;
struct cmd_chain_req {
__u64 buf_addr;
__u32 buf_size;
__u32 count;
} __packed;
struct cmd_chain_npu_req {
u32 flags;
u32 reserved;
u64 buf_addr;
u32 buf_size;
u32 count;
} __packed;
union exec_chain_req {
struct cmd_chain_npu_req npu_req;
struct cmd_chain_req req;
};
struct cmd_chain_resp {
enum aie2_msg_status status;
__u32 fail_cmd_idx;

View File

@@ -55,6 +55,7 @@ struct mgmt_mbox_chann_info {
static int aie2_check_protocol(struct amdxdna_dev_hdl *ndev, u32 fw_major, u32 fw_minor)
{
const struct aie2_fw_feature_tbl *feature;
struct amdxdna_dev *xdna = ndev->xdna;
/*
@@ -78,6 +79,17 @@ static int aie2_check_protocol(struct amdxdna_dev_hdl *ndev, u32 fw_major, u32 f
XDNA_ERR(xdna, "Firmware minor version smaller than supported");
return -EINVAL;
}
for (feature = ndev->priv->fw_feature_tbl; feature && feature->min_minor;
feature++) {
if (fw_minor < feature->min_minor)
continue;
if (feature->max_minor > 0 && fw_minor > feature->max_minor)
continue;
set_bit(feature->feature, &ndev->feature_mask);
}
return 0;
}
@@ -587,6 +599,7 @@ static int aie2_init(struct amdxdna_dev *xdna)
}
release_firmware(fw);
aie2_msg_init(ndev);
amdxdna_pm_init(xdna);
return 0;
@@ -825,6 +838,100 @@ static int aie2_get_hwctx_status(struct amdxdna_client *client,
return 0;
}
static int aie2_query_resource_info(struct amdxdna_client *client,
struct amdxdna_drm_get_info *args)
{
struct amdxdna_drm_get_resource_info res_info;
const struct amdxdna_dev_priv *priv;
struct amdxdna_dev_hdl *ndev;
struct amdxdna_dev *xdna;
xdna = client->xdna;
ndev = xdna->dev_handle;
priv = ndev->priv;
res_info.npu_clk_max = priv->dpm_clk_tbl[ndev->max_dpm_level].hclk;
res_info.npu_tops_max = ndev->max_tops;
res_info.npu_task_max = priv->hwctx_limit;
res_info.npu_tops_curr = ndev->curr_tops;
res_info.npu_task_curr = ndev->hwctx_num;
if (copy_to_user(u64_to_user_ptr(args->buffer), &res_info, sizeof(res_info)))
return -EFAULT;
return 0;
}
static int aie2_fill_hwctx_map(struct amdxdna_hwctx *hwctx, void *arg)
{
struct amdxdna_dev *xdna = hwctx->client->xdna;
u32 *map = arg;
if (hwctx->fw_ctx_id >= xdna->dev_handle->priv->hwctx_limit) {
XDNA_ERR(xdna, "Invalid fw ctx id %d/%d ", hwctx->fw_ctx_id,
xdna->dev_handle->priv->hwctx_limit);
return -EINVAL;
}
map[hwctx->fw_ctx_id] = hwctx->id;
return 0;
}
static int aie2_get_telemetry(struct amdxdna_client *client,
struct amdxdna_drm_get_info *args)
{
struct amdxdna_drm_query_telemetry_header *header __free(kfree) = NULL;
u32 telemetry_data_sz, header_sz, elem_num;
struct amdxdna_dev *xdna = client->xdna;
struct amdxdna_client *tmp_client;
int ret;
elem_num = xdna->dev_handle->priv->hwctx_limit;
header_sz = struct_size(header, map, elem_num);
if (args->buffer_size <= header_sz) {
XDNA_ERR(xdna, "Invalid buffer size");
return -EINVAL;
}
telemetry_data_sz = args->buffer_size - header_sz;
if (telemetry_data_sz > SZ_4M) {
XDNA_ERR(xdna, "Buffer size is too big, %d", telemetry_data_sz);
return -EINVAL;
}
header = kzalloc(header_sz, GFP_KERNEL);
if (!header)
return -ENOMEM;
if (copy_from_user(header, u64_to_user_ptr(args->buffer), sizeof(*header))) {
XDNA_ERR(xdna, "Failed to copy telemetry header from user");
return -EFAULT;
}
header->map_num_elements = elem_num;
list_for_each_entry(tmp_client, &xdna->client_list, node) {
ret = amdxdna_hwctx_walk(tmp_client, &header->map,
aie2_fill_hwctx_map);
if (ret)
return ret;
}
ret = aie2_query_telemetry(xdna->dev_handle,
u64_to_user_ptr(args->buffer + header_sz),
telemetry_data_sz, header);
if (ret) {
XDNA_ERR(xdna, "Query telemetry failed ret %d", ret);
return ret;
}
if (copy_to_user(u64_to_user_ptr(args->buffer), header, header_sz)) {
XDNA_ERR(xdna, "Copy header failed");
return -EFAULT;
}
return 0;
}
static int aie2_get_info(struct amdxdna_client *client, struct amdxdna_drm_get_info *args)
{
struct amdxdna_dev *xdna = client->xdna;
@@ -859,6 +966,12 @@ static int aie2_get_info(struct amdxdna_client *client, struct amdxdna_drm_get_i
case DRM_AMDXDNA_GET_POWER_MODE:
ret = aie2_get_power_mode(client, args);
break;
case DRM_AMDXDNA_QUERY_TELEMETRY:
ret = aie2_get_telemetry(client, args);
break;
case DRM_AMDXDNA_QUERY_RESOURCE_INFO:
ret = aie2_query_resource_info(client, args);
break;
default:
XDNA_ERR(xdna, "Not supported request parameter %u", args->param);
ret = -EOPNOTSUPP;

View File

@@ -156,6 +156,17 @@ enum aie2_dev_status {
AIE2_DEV_START,
};
struct aie2_exec_msg_ops {
int (*init_cu_req)(struct amdxdna_gem_obj *cmd_bo, void *req,
size_t *size, u32 *msg_op);
int (*init_dpu_req)(struct amdxdna_gem_obj *cmd_bo, void *req,
size_t *size, u32 *msg_op);
void (*init_chain_req)(void *req, u64 slot_addr, size_t size, u32 cmd_cnt);
int (*fill_cf_slot)(struct amdxdna_gem_obj *cmd_bo, void *slot, size_t *size);
int (*fill_dpu_slot)(struct amdxdna_gem_obj *cmd_bo, void *slot, size_t *size);
u32 (*get_chain_msg_op)(u32 cmd_op);
};
struct amdxdna_dev_hdl {
struct amdxdna_dev *xdna;
const struct amdxdna_dev_priv *priv;
@@ -173,6 +184,8 @@ struct amdxdna_dev_hdl {
u32 total_col;
struct aie_version version;
struct aie_metadata metadata;
unsigned long feature_mask;
struct aie2_exec_msg_ops *exec_msg_ops;
/* power management and clock*/
enum amdxdna_power_mode_type pw_mode;
@@ -182,6 +195,8 @@ struct amdxdna_dev_hdl {
u32 clk_gating;
u32 npuclk_freq;
u32 hclk_freq;
u32 max_tops;
u32 curr_tops;
/* Mailbox and the management channel */
struct mailbox *mbox;
@@ -206,12 +221,26 @@ struct aie2_hw_ops {
int (*set_dpm)(struct amdxdna_dev_hdl *ndev, u32 dpm_level);
};
enum aie2_fw_feature {
AIE2_NPU_COMMAND,
AIE2_FEATURE_MAX
};
struct aie2_fw_feature_tbl {
enum aie2_fw_feature feature;
u32 max_minor;
u32 min_minor;
};
#define AIE2_FEATURE_ON(ndev, feature) test_bit(feature, &(ndev)->feature_mask)
struct amdxdna_dev_priv {
const char *fw_path;
u64 protocol_major;
u64 protocol_minor;
const struct rt_config *rt_config;
const struct dpm_clk_freq *dpm_clk_tbl;
const struct aie2_fw_feature_tbl *fw_feature_tbl;
#define COL_ALIGN_NONE 0
#define COL_ALIGN_NATURE 1
@@ -219,6 +248,7 @@ struct amdxdna_dev_priv {
u32 mbox_dev_addr;
/* If mbox_size is 0, use BAR size. See MBOX_SIZE macro */
u32 mbox_size;
u32 hwctx_limit;
u32 sram_dev_addr;
struct aie2_bar_off_pair sram_offs[SRAM_MAX_INDEX];
struct aie2_bar_off_pair psp_regs_off[PSP_MAX_REGS];
@@ -236,6 +266,7 @@ extern const struct dpm_clk_freq npu1_dpm_clk_table[];
extern const struct dpm_clk_freq npu4_dpm_clk_table[];
extern const struct rt_config npu1_default_rt_cfg[];
extern const struct rt_config npu4_default_rt_cfg[];
extern const struct aie2_fw_feature_tbl npu4_fw_feature_table[];
/* aie2_smu.c */
int aie2_smu_init(struct amdxdna_dev_hdl *ndev);
@@ -260,6 +291,7 @@ int aie2_get_array_async_error(struct amdxdna_dev_hdl *ndev,
struct amdxdna_drm_get_array *args);
/* aie2_message.c */
void aie2_msg_init(struct amdxdna_dev_hdl *ndev);
int aie2_suspend_fw(struct amdxdna_dev_hdl *ndev);
int aie2_resume_fw(struct amdxdna_dev_hdl *ndev);
int aie2_set_runtime_cfg(struct amdxdna_dev_hdl *ndev, u32 type, u64 value);
@@ -273,6 +305,9 @@ int aie2_create_context(struct amdxdna_dev_hdl *ndev, struct amdxdna_hwctx *hwct
int aie2_destroy_context(struct amdxdna_dev_hdl *ndev, struct amdxdna_hwctx *hwctx);
int aie2_map_host_buf(struct amdxdna_dev_hdl *ndev, u32 context_id, u64 addr, u64 size);
int aie2_query_status(struct amdxdna_dev_hdl *ndev, char __user *buf, u32 size, u32 *cols_filled);
int aie2_query_telemetry(struct amdxdna_dev_hdl *ndev,
char __user *buf, u32 size,
struct amdxdna_drm_query_telemetry_header *header);
int aie2_register_asyn_event_msg(struct amdxdna_dev_hdl *ndev, dma_addr_t addr, u32 size,
void *handle, int (*cb)(void*, void __iomem *, size_t));
int aie2_config_cu(struct amdxdna_hwctx *hwctx,

View File

@@ -23,6 +23,13 @@
#define AIE2_SMU_SET_SOFT_DPMLEVEL 0x7
#define AIE2_SMU_SET_HARD_DPMLEVEL 0x8
#define NPU4_DPM_TOPS(ndev, dpm_level) \
({ \
typeof(ndev) _ndev = ndev; \
(4096 * (_ndev)->total_col * \
(_ndev)->priv->dpm_clk_tbl[dpm_level].hclk / 1000000); \
})
static int aie2_smu_exec(struct amdxdna_dev_hdl *ndev, u32 reg_cmd,
u32 reg_arg, u32 *out)
{
@@ -84,6 +91,8 @@ int npu1_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level)
amdxdna_pm_suspend_put(ndev->xdna);
ndev->hclk_freq = freq;
ndev->dpm_level = dpm_level;
ndev->max_tops = 2 * ndev->total_col;
ndev->curr_tops = ndev->max_tops * freq / 1028;
XDNA_DBG(ndev->xdna, "MP-NPU clock %d, H clock %d\n",
ndev->npuclk_freq, ndev->hclk_freq);
@@ -121,6 +130,8 @@ int npu4_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level)
ndev->npuclk_freq = ndev->priv->dpm_clk_tbl[dpm_level].npuclk;
ndev->hclk_freq = ndev->priv->dpm_clk_tbl[dpm_level].hclk;
ndev->dpm_level = dpm_level;
ndev->max_tops = NPU4_DPM_TOPS(ndev, ndev->max_dpm_level);
ndev->curr_tops = NPU4_DPM_TOPS(ndev, dpm_level);
XDNA_DBG(ndev->xdna, "MP-NPU clock %d, H clock %d\n",
ndev->npuclk_freq, ndev->hclk_freq);

View File

@@ -113,14 +113,14 @@ void *amdxdna_cmd_get_payload(struct amdxdna_gem_obj *abo, u32 *size)
return &cmd->data[num_masks];
}
int amdxdna_cmd_get_cu_idx(struct amdxdna_gem_obj *abo)
u32 amdxdna_cmd_get_cu_idx(struct amdxdna_gem_obj *abo)
{
struct amdxdna_cmd *cmd = abo->mem.kva;
u32 num_masks, i;
u32 *cu_mask;
if (amdxdna_cmd_get_op(abo) == ERT_CMD_CHAIN)
return -1;
return INVALID_CU_IDX;
num_masks = 1 + FIELD_GET(AMDXDNA_CMD_EXTRA_CU_MASK, cmd->header);
cu_mask = cmd->data;
@@ -129,7 +129,7 @@ int amdxdna_cmd_get_cu_idx(struct amdxdna_gem_obj *abo)
return ffs(cu_mask[i]) - 1;
}
return -1;
return INVALID_CU_IDX;
}
/*

View File

@@ -13,9 +13,10 @@
struct amdxdna_hwctx_priv;
enum ert_cmd_opcode {
ERT_START_CU = 0,
ERT_CMD_CHAIN = 19,
ERT_START_NPU = 20,
ERT_START_CU = 0,
ERT_CMD_CHAIN = 19,
ERT_START_NPU = 20,
ERT_INVALID_CMD = ~0U,
};
enum ert_cmd_state {
@@ -64,6 +65,8 @@ struct amdxdna_cmd {
u32 data[];
};
#define INVALID_CU_IDX (~0U)
struct amdxdna_hwctx {
struct amdxdna_client *client;
struct amdxdna_hwctx_priv *priv;
@@ -116,6 +119,7 @@ struct amdxdna_sched_job {
/* user can wait on this fence */
struct dma_fence *out_fence;
bool job_done;
bool job_timeout;
u64 seq;
struct amdxdna_drv_cmd *drv_cmd;
struct amdxdna_gem_obj *cmd_bo;
@@ -149,7 +153,7 @@ amdxdna_cmd_get_state(struct amdxdna_gem_obj *abo)
}
void *amdxdna_cmd_get_payload(struct amdxdna_gem_obj *abo, u32 *size);
int amdxdna_cmd_get_cu_idx(struct amdxdna_gem_obj *abo);
u32 amdxdna_cmd_get_cu_idx(struct amdxdna_gem_obj *abo);
void amdxdna_sched_job_cleanup(struct amdxdna_sched_job *job);
void amdxdna_hwctx_remove_all(struct amdxdna_client *client);

View File

@@ -8,6 +8,7 @@
#include <drm/drm_device.h>
#include <drm/drm_gem.h>
#include <drm/drm_gem_shmem_helper.h>
#include <drm/drm_print.h>
#include <drm/gpu_scheduler.h>
#include <linux/dma-buf.h>
#include <linux/dma-direct.h>

View File

@@ -16,16 +16,18 @@ struct xdna_notify {
u32 *data;
size_t size;
int error;
u32 *status;
};
#define DECLARE_XDNA_MSG_COMMON(name, op, status) \
#define DECLARE_XDNA_MSG_COMMON(name, op, s) \
struct name##_req req = { 0 }; \
struct name##_resp resp = { status }; \
struct name##_resp resp = { .status = s }; \
struct xdna_notify hdl = { \
.error = 0, \
.data = (u32 *)&resp, \
.size = sizeof(resp), \
.comp = COMPLETION_INITIALIZER_ONSTACK(hdl.comp), \
.status = (u32 *)&resp.status, \
}; \
struct xdna_mailbox_msg msg = { \
.send_data = (u8 *)&req, \

View File

@@ -29,9 +29,11 @@ MODULE_FIRMWARE("amdnpu/17f0_20/npu.sbin");
* 0.1: Support getting all hardware contexts by DRM_IOCTL_AMDXDNA_GET_ARRAY
* 0.2: Support getting last error hardware error
* 0.3: Support firmware debug buffer
* 0.4: Support getting resource information
* 0.5: Support getting telemetry data
*/
#define AMDXDNA_DRIVER_MAJOR 0
#define AMDXDNA_DRIVER_MINOR 3
#define AMDXDNA_DRIVER_MINOR 5
/*
* Bind the driver base on (vendor_id, device_id) pair and later use the

View File

@@ -63,16 +63,23 @@ const struct dpm_clk_freq npu1_dpm_clk_table[] = {
{ 0 }
};
static const struct aie2_fw_feature_tbl npu1_fw_feature_table[] = {
{ .feature = AIE2_NPU_COMMAND, .min_minor = 8 },
{ 0 }
};
static const struct amdxdna_dev_priv npu1_dev_priv = {
.fw_path = "amdnpu/1502_00/npu.sbin",
.protocol_major = 0x5,
.protocol_minor = 0x7,
.rt_config = npu1_default_rt_cfg,
.dpm_clk_tbl = npu1_dpm_clk_table,
.fw_feature_tbl = npu1_fw_feature_table,
.col_align = COL_ALIGN_NONE,
.mbox_dev_addr = NPU1_MBOX_BAR_BASE,
.mbox_size = 0, /* Use BAR size */
.sram_dev_addr = NPU1_SRAM_BAR_BASE,
.hwctx_limit = 6,
.sram_offs = {
DEFINE_BAR_OFFSET(MBOX_CHANN_OFF, NPU1_SRAM, MPNPU_SRAM_X2I_MAILBOX_0),
DEFINE_BAR_OFFSET(FW_ALIVE_OFF, NPU1_SRAM, MPNPU_SRAM_I2X_MAILBOX_15),

View File

@@ -67,10 +67,12 @@ static const struct amdxdna_dev_priv npu2_dev_priv = {
.protocol_minor = 0x6,
.rt_config = npu4_default_rt_cfg,
.dpm_clk_tbl = npu4_dpm_clk_table,
.fw_feature_tbl = npu4_fw_feature_table,
.col_align = COL_ALIGN_NATURE,
.mbox_dev_addr = NPU2_MBOX_BAR_BASE,
.mbox_size = 0, /* Use BAR size */
.sram_dev_addr = NPU2_SRAM_BAR_BASE,
.hwctx_limit = 16,
.sram_offs = {
DEFINE_BAR_OFFSET(MBOX_CHANN_OFF, NPU2_SRAM, MPNPU_SRAM_X2I_MAILBOX_0),
DEFINE_BAR_OFFSET(FW_ALIVE_OFF, NPU2_SRAM, MPNPU_SRAM_X2I_MAILBOX_15),

View File

@@ -83,16 +83,23 @@ const struct dpm_clk_freq npu4_dpm_clk_table[] = {
{ 0 }
};
const struct aie2_fw_feature_tbl npu4_fw_feature_table[] = {
{ .feature = AIE2_NPU_COMMAND, .min_minor = 15 },
{ 0 }
};
static const struct amdxdna_dev_priv npu4_dev_priv = {
.fw_path = "amdnpu/17f0_10/npu.sbin",
.protocol_major = 0x6,
.protocol_minor = 12,
.rt_config = npu4_default_rt_cfg,
.dpm_clk_tbl = npu4_dpm_clk_table,
.fw_feature_tbl = npu4_fw_feature_table,
.col_align = COL_ALIGN_NATURE,
.mbox_dev_addr = NPU4_MBOX_BAR_BASE,
.mbox_size = 0, /* Use BAR size */
.sram_dev_addr = NPU4_SRAM_BAR_BASE,
.hwctx_limit = 16,
.sram_offs = {
DEFINE_BAR_OFFSET(MBOX_CHANN_OFF, NPU4_SRAM, MPNPU_SRAM_X2I_MAILBOX_0),
DEFINE_BAR_OFFSET(FW_ALIVE_OFF, NPU4_SRAM, MPNPU_SRAM_X2I_MAILBOX_15),

View File

@@ -67,10 +67,12 @@ static const struct amdxdna_dev_priv npu5_dev_priv = {
.protocol_minor = 12,
.rt_config = npu4_default_rt_cfg,
.dpm_clk_tbl = npu4_dpm_clk_table,
.fw_feature_tbl = npu4_fw_feature_table,
.col_align = COL_ALIGN_NATURE,
.mbox_dev_addr = NPU5_MBOX_BAR_BASE,
.mbox_size = 0, /* Use BAR size */
.sram_dev_addr = NPU5_SRAM_BAR_BASE,
.hwctx_limit = 16,
.sram_offs = {
DEFINE_BAR_OFFSET(MBOX_CHANN_OFF, NPU5_SRAM, MPNPU_SRAM_X2I_MAILBOX_0),
DEFINE_BAR_OFFSET(FW_ALIVE_OFF, NPU5_SRAM, MPNPU_SRAM_X2I_MAILBOX_15),

View File

@@ -67,10 +67,12 @@ static const struct amdxdna_dev_priv npu6_dev_priv = {
.protocol_minor = 12,
.rt_config = npu4_default_rt_cfg,
.dpm_clk_tbl = npu4_dpm_clk_table,
.fw_feature_tbl = npu4_fw_feature_table,
.col_align = COL_ALIGN_NATURE,
.mbox_dev_addr = NPU6_MBOX_BAR_BASE,
.mbox_size = 0, /* Use BAR size */
.sram_dev_addr = NPU6_SRAM_BAR_BASE,
.hwctx_limit = 16,
.sram_offs = {
DEFINE_BAR_OFFSET(MBOX_CHANN_OFF, NPU6_SRAM, MPNPU_SRAM_X2I_MAILBOX_0),
DEFINE_BAR_OFFSET(FW_ALIVE_OFF, NPU6_SRAM, MPNPU_SRAM_X2I_MAILBOX_15),

View File

@@ -12,6 +12,7 @@
#include <drm/drm_file.h>
#include <drm/drm_gem.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_print.h>
#include <drm/ethosu_accel.h>
#include "ethosu_device.h"

View File

@@ -6,6 +6,7 @@ intel_vpu-y := \
ivpu_fw.o \
ivpu_fw_log.o \
ivpu_gem.o \
ivpu_gem_userptr.o \
ivpu_hw.o \
ivpu_hw_btrs.o \
ivpu_hw_ip.o \

View File

@@ -57,7 +57,7 @@ MODULE_PARM_DESC(pll_max_ratio, "Maximum PLL ratio used to set NPU frequency");
int ivpu_sched_mode = IVPU_SCHED_MODE_AUTO;
module_param_named(sched_mode, ivpu_sched_mode, int, 0444);
MODULE_PARM_DESC(sched_mode, "Scheduler mode: -1 - Use default scheduler, 0 - Use OS scheduler, 1 - Use HW scheduler");
MODULE_PARM_DESC(sched_mode, "Scheduler mode: -1 - Use default scheduler, 0 - Use OS scheduler (supported on 27XX - 50XX), 1 - Use HW scheduler");
bool ivpu_disable_mmu_cont_pages;
module_param_named(disable_mmu_cont_pages, ivpu_disable_mmu_cont_pages, bool, 0444);
@@ -134,6 +134,8 @@ bool ivpu_is_capable(struct ivpu_device *vdev, u32 capability)
return true;
case DRM_IVPU_CAP_DMA_MEMORY_RANGE:
return true;
case DRM_IVPU_CAP_BO_CREATE_FROM_USERPTR:
return true;
case DRM_IVPU_CAP_MANAGE_CMDQ:
return vdev->fw->sched_mode == VPU_SCHEDULING_MODE_HW;
default:
@@ -313,6 +315,7 @@ static const struct drm_ioctl_desc ivpu_drm_ioctls[] = {
DRM_IOCTL_DEF_DRV(IVPU_CMDQ_CREATE, ivpu_cmdq_create_ioctl, 0),
DRM_IOCTL_DEF_DRV(IVPU_CMDQ_DESTROY, ivpu_cmdq_destroy_ioctl, 0),
DRM_IOCTL_DEF_DRV(IVPU_CMDQ_SUBMIT, ivpu_cmdq_submit_ioctl, 0),
DRM_IOCTL_DEF_DRV(IVPU_BO_CREATE_FROM_USERPTR, ivpu_bo_create_from_userptr_ioctl, 0),
};
static int ivpu_wait_for_ready(struct ivpu_device *vdev)

View File

@@ -79,6 +79,7 @@
#define IVPU_DBG_KREF BIT(11)
#define IVPU_DBG_RPM BIT(12)
#define IVPU_DBG_MMU_MAP BIT(13)
#define IVPU_DBG_IOCTL BIT(14)
#define ivpu_err(vdev, fmt, ...) \
drm_err(&(vdev)->drm, "%s(): " fmt, __func__, ##__VA_ARGS__)

View File

@@ -144,6 +144,12 @@ bool ivpu_is_within_range(u64 addr, size_t size, struct ivpu_addr_range *range)
static u32
ivpu_fw_sched_mode_select(struct ivpu_device *vdev, const struct vpu_firmware_header *fw_hdr)
{
if (ivpu_hw_ip_gen(vdev) >= IVPU_HW_IP_60XX &&
ivpu_sched_mode == VPU_SCHEDULING_MODE_OS) {
ivpu_warn(vdev, "OS sched mode is not supported, using HW mode\n");
return VPU_SCHEDULING_MODE_HW;
}
if (ivpu_sched_mode != IVPU_SCHED_MODE_AUTO)
return ivpu_sched_mode;

View File

@@ -96,7 +96,7 @@ int __must_check ivpu_bo_bind(struct ivpu_bo *bo)
if (!bo->mmu_mapped) {
drm_WARN_ON(&vdev->drm, !bo->ctx);
ret = ivpu_mmu_context_map_sgt(vdev, bo->ctx, bo->vpu_addr, sgt,
ivpu_bo_is_snooped(bo));
ivpu_bo_is_snooped(bo), ivpu_bo_is_read_only(bo));
if (ret) {
ivpu_err(vdev, "Failed to map BO in MMU: %d\n", ret);
goto unlock;
@@ -128,8 +128,6 @@ ivpu_bo_alloc_vpu_addr(struct ivpu_bo *bo, struct ivpu_mmu_context *ctx,
bo->ctx_id = ctx->id;
bo->vpu_addr = bo->mm_node.start;
ivpu_dbg_bo(vdev, bo, "vaddr");
} else {
ivpu_err(vdev, "Failed to add BO to context %u: %d\n", ctx->id, ret);
}
ivpu_bo_unlock(bo);
@@ -158,9 +156,6 @@ static void ivpu_bo_unbind_locked(struct ivpu_bo *bo)
bo->ctx = NULL;
}
if (drm_gem_is_imported(&bo->base.base))
return;
if (bo->base.sgt) {
if (bo->base.base.import_attach) {
dma_buf_unmap_attachment(bo->base.base.import_attach,
@@ -292,8 +287,8 @@ static int ivpu_gem_bo_open(struct drm_gem_object *obj, struct drm_file *file)
struct ivpu_addr_range *range;
if (bo->ctx) {
ivpu_warn(vdev, "Can't add BO to ctx %u: already in ctx %u\n",
file_priv->ctx.id, bo->ctx->id);
ivpu_dbg(vdev, IOCTL, "Can't add BO %pe to ctx %u: already in ctx %u\n",
bo, file_priv->ctx.id, bo->ctx->id);
return -EALREADY;
}
@@ -318,7 +313,6 @@ static void ivpu_gem_bo_free(struct drm_gem_object *obj)
mutex_lock(&vdev->bo_list_lock);
list_del(&bo->bo_list_node);
mutex_unlock(&vdev->bo_list_lock);
drm_WARN_ON(&vdev->drm, !drm_gem_is_imported(&bo->base.base) &&
!dma_resv_test_signaled(obj->resv, DMA_RESV_USAGE_READ));
@@ -329,6 +323,8 @@ static void ivpu_gem_bo_free(struct drm_gem_object *obj)
ivpu_bo_unbind_locked(bo);
ivpu_bo_unlock(bo);
mutex_unlock(&vdev->bo_list_lock);
drm_WARN_ON(&vdev->drm, bo->mmu_mapped);
drm_WARN_ON(&vdev->drm, bo->ctx);
@@ -359,15 +355,19 @@ int ivpu_bo_create_ioctl(struct drm_device *dev, void *data, struct drm_file *fi
struct ivpu_bo *bo;
int ret;
if (args->flags & ~DRM_IVPU_BO_FLAGS)
if (args->flags & ~DRM_IVPU_BO_FLAGS) {
ivpu_dbg(vdev, IOCTL, "Invalid BO flags 0x%x\n", args->flags);
return -EINVAL;
}
if (size == 0)
if (size == 0) {
ivpu_dbg(vdev, IOCTL, "Invalid BO size %llu\n", args->size);
return -EINVAL;
}
bo = ivpu_bo_alloc(vdev, size, args->flags);
if (IS_ERR(bo)) {
ivpu_err(vdev, "Failed to allocate BO: %pe (ctx %u size %llu flags 0x%x)",
ivpu_dbg(vdev, IOCTL, "Failed to allocate BO: %pe ctx %u size %llu flags 0x%x\n",
bo, file_priv->ctx.id, args->size, args->flags);
return PTR_ERR(bo);
}
@@ -376,7 +376,7 @@ int ivpu_bo_create_ioctl(struct drm_device *dev, void *data, struct drm_file *fi
ret = drm_gem_handle_create(file, &bo->base.base, &args->handle);
if (ret) {
ivpu_err(vdev, "Failed to create handle for BO: %pe (ctx %u size %llu flags 0x%x)",
ivpu_dbg(vdev, IOCTL, "Failed to create handle for BO: %pe ctx %u size %llu flags 0x%x\n",
bo, file_priv->ctx.id, args->size, args->flags);
} else {
args->vpu_addr = bo->vpu_addr;
@@ -405,14 +405,17 @@ ivpu_bo_create(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx,
bo = ivpu_bo_alloc(vdev, size, flags);
if (IS_ERR(bo)) {
ivpu_err(vdev, "Failed to allocate BO: %pe (vpu_addr 0x%llx size %llu flags 0x%x)",
ivpu_err(vdev, "Failed to allocate BO: %pe vpu_addr 0x%llx size %llu flags 0x%x\n",
bo, range->start, size, flags);
return NULL;
}
ret = ivpu_bo_alloc_vpu_addr(bo, ctx, range);
if (ret)
if (ret) {
ivpu_err(vdev, "Failed to allocate NPU address for BO: %pe ctx %u size %llu: %d\n",
bo, ctx->id, size, ret);
goto err_put;
}
ret = ivpu_bo_bind(bo);
if (ret)

View File

@@ -38,6 +38,8 @@ void ivpu_bo_free(struct ivpu_bo *bo);
int ivpu_bo_create_ioctl(struct drm_device *dev, void *data, struct drm_file *file);
int ivpu_bo_info_ioctl(struct drm_device *dev, void *data, struct drm_file *file);
int ivpu_bo_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file);
int ivpu_bo_create_from_userptr_ioctl(struct drm_device *dev, void *data,
struct drm_file *file);
void ivpu_bo_list(struct drm_device *dev, struct drm_printer *p);
void ivpu_bo_list_print(struct drm_device *dev);
@@ -75,6 +77,11 @@ static inline bool ivpu_bo_is_snooped(struct ivpu_bo *bo)
return ivpu_bo_cache_mode(bo) == DRM_IVPU_BO_CACHED;
}
static inline bool ivpu_bo_is_read_only(struct ivpu_bo *bo)
{
return bo->flags & DRM_IVPU_BO_READ_ONLY;
}
static inline void *ivpu_to_cpu_addr(struct ivpu_bo *bo, u32 vpu_addr)
{
if (vpu_addr < bo->vpu_addr)

View File

@@ -0,0 +1,213 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2020-2025 Intel Corporation
*/
#include <linux/dma-buf.h>
#include <linux/err.h>
#include <linux/highmem.h>
#include <linux/mm.h>
#include <linux/mman.h>
#include <linux/scatterlist.h>
#include <linux/slab.h>
#include <linux/capability.h>
#include <drm/drm_device.h>
#include <drm/drm_file.h>
#include <drm/drm_gem.h>
#include "ivpu_drv.h"
#include "ivpu_gem.h"
static struct sg_table *
ivpu_gem_userptr_dmabuf_map(struct dma_buf_attachment *attachment,
enum dma_data_direction direction)
{
struct sg_table *sgt = attachment->dmabuf->priv;
int ret;
ret = dma_map_sgtable(attachment->dev, sgt, direction, DMA_ATTR_SKIP_CPU_SYNC);
if (ret)
return ERR_PTR(ret);
return sgt;
}
static void ivpu_gem_userptr_dmabuf_unmap(struct dma_buf_attachment *attachment,
struct sg_table *sgt,
enum dma_data_direction direction)
{
dma_unmap_sgtable(attachment->dev, sgt, direction, DMA_ATTR_SKIP_CPU_SYNC);
}
static void ivpu_gem_userptr_dmabuf_release(struct dma_buf *dma_buf)
{
struct sg_table *sgt = dma_buf->priv;
struct sg_page_iter page_iter;
struct page *page;
for_each_sgtable_page(sgt, &page_iter, 0) {
page = sg_page_iter_page(&page_iter);
unpin_user_page(page);
}
sg_free_table(sgt);
kfree(sgt);
}
static const struct dma_buf_ops ivpu_gem_userptr_dmabuf_ops = {
.map_dma_buf = ivpu_gem_userptr_dmabuf_map,
.unmap_dma_buf = ivpu_gem_userptr_dmabuf_unmap,
.release = ivpu_gem_userptr_dmabuf_release,
};
static struct dma_buf *
ivpu_create_userptr_dmabuf(struct ivpu_device *vdev, void __user *user_ptr,
size_t size, uint32_t flags)
{
struct dma_buf_export_info exp_info = {};
struct dma_buf *dma_buf;
struct sg_table *sgt;
struct page **pages;
unsigned long nr_pages = size >> PAGE_SHIFT;
unsigned int gup_flags = FOLL_LONGTERM;
int ret, i, pinned;
/* Add FOLL_WRITE only if the BO is not read-only */
if (!(flags & DRM_IVPU_BO_READ_ONLY))
gup_flags |= FOLL_WRITE;
pages = kvmalloc_array(nr_pages, sizeof(*pages), GFP_KERNEL);
if (!pages)
return ERR_PTR(-ENOMEM);
pinned = pin_user_pages_fast((unsigned long)user_ptr, nr_pages, gup_flags, pages);
if (pinned < 0) {
ret = pinned;
ivpu_dbg(vdev, IOCTL, "Failed to pin user pages: %d\n", ret);
goto free_pages_array;
}
if (pinned != nr_pages) {
ivpu_dbg(vdev, IOCTL, "Pinned %d pages, expected %lu\n", pinned, nr_pages);
ret = -EFAULT;
goto unpin_pages;
}
sgt = kmalloc(sizeof(*sgt), GFP_KERNEL);
if (!sgt) {
ret = -ENOMEM;
goto unpin_pages;
}
ret = sg_alloc_table_from_pages(sgt, pages, nr_pages, 0, size, GFP_KERNEL);
if (ret) {
ivpu_dbg(vdev, IOCTL, "Failed to create sg table: %d\n", ret);
goto free_sgt;
}
exp_info.exp_name = "ivpu_userptr_dmabuf";
exp_info.owner = THIS_MODULE;
exp_info.ops = &ivpu_gem_userptr_dmabuf_ops;
exp_info.size = size;
exp_info.flags = O_RDWR | O_CLOEXEC;
exp_info.priv = sgt;
dma_buf = dma_buf_export(&exp_info);
if (IS_ERR(dma_buf)) {
ret = PTR_ERR(dma_buf);
ivpu_dbg(vdev, IOCTL, "Failed to export userptr dma-buf: %d\n", ret);
goto free_sg_table;
}
kvfree(pages);
return dma_buf;
free_sg_table:
sg_free_table(sgt);
free_sgt:
kfree(sgt);
unpin_pages:
for (i = 0; i < pinned; i++)
unpin_user_page(pages[i]);
free_pages_array:
kvfree(pages);
return ERR_PTR(ret);
}
static struct ivpu_bo *
ivpu_bo_create_from_userptr(struct ivpu_device *vdev, void __user *user_ptr,
size_t size, uint32_t flags)
{
struct dma_buf *dma_buf;
struct drm_gem_object *obj;
struct ivpu_bo *bo;
dma_buf = ivpu_create_userptr_dmabuf(vdev, user_ptr, size, flags);
if (IS_ERR(dma_buf))
return ERR_CAST(dma_buf);
obj = ivpu_gem_prime_import(&vdev->drm, dma_buf);
if (IS_ERR(obj)) {
dma_buf_put(dma_buf);
return ERR_CAST(obj);
}
dma_buf_put(dma_buf);
bo = to_ivpu_bo(obj);
bo->flags = flags;
return bo;
}
int ivpu_bo_create_from_userptr_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
{
struct drm_ivpu_bo_create_from_userptr *args = data;
struct ivpu_file_priv *file_priv = file->driver_priv;
struct ivpu_device *vdev = to_ivpu_device(dev);
void __user *user_ptr = u64_to_user_ptr(args->user_ptr);
struct ivpu_bo *bo;
int ret;
if (args->flags & ~(DRM_IVPU_BO_HIGH_MEM | DRM_IVPU_BO_DMA_MEM | DRM_IVPU_BO_READ_ONLY)) {
ivpu_dbg(vdev, IOCTL, "Invalid BO flags: 0x%x\n", args->flags);
return -EINVAL;
}
if (!args->user_ptr || !args->size) {
ivpu_dbg(vdev, IOCTL, "Userptr or size are zero: ptr %llx size %llu\n",
args->user_ptr, args->size);
return -EINVAL;
}
if (!PAGE_ALIGNED(args->user_ptr) || !PAGE_ALIGNED(args->size)) {
ivpu_dbg(vdev, IOCTL, "Userptr or size not page aligned: ptr %llx size %llu\n",
args->user_ptr, args->size);
return -EINVAL;
}
if (!access_ok(user_ptr, args->size)) {
ivpu_dbg(vdev, IOCTL, "Userptr is not accessible: ptr %llx size %llu\n",
args->user_ptr, args->size);
return -EFAULT;
}
bo = ivpu_bo_create_from_userptr(vdev, user_ptr, args->size, args->flags);
if (IS_ERR(bo))
return PTR_ERR(bo);
ret = drm_gem_handle_create(file, &bo->base.base, &args->handle);
if (ret) {
ivpu_dbg(vdev, IOCTL, "Failed to create handle for BO: %pe ctx %u size %llu flags 0x%x\n",
bo, file_priv->ctx.id, args->size, args->flags);
} else {
ivpu_dbg(vdev, BO, "Created userptr BO: handle=%u vpu_addr=0x%llx size=%llu flags=0x%x\n",
args->handle, bo->vpu_addr, args->size, bo->flags);
args->vpu_addr = bo->vpu_addr;
}
drm_gem_object_put(&bo->base.base);
return ret;
}

View File

@@ -321,6 +321,14 @@ static int wait_for_pll_lock(struct ivpu_device *vdev, bool enable)
return REGB_POLL_FLD(VPU_HW_BTRS_MTL_PLL_STATUS, LOCK, exp_val, PLL_TIMEOUT_US);
}
static int wait_for_cdyn_deassert(struct ivpu_device *vdev)
{
if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL)
return 0;
return REGB_POLL_FLD(VPU_HW_BTRS_LNL_CDYN, CDYN, 0, PLL_TIMEOUT_US);
}
int ivpu_hw_btrs_wp_drive(struct ivpu_device *vdev, bool enable)
{
struct wp_request wp;
@@ -354,6 +362,14 @@ int ivpu_hw_btrs_wp_drive(struct ivpu_device *vdev, bool enable)
return ret;
}
if (!enable) {
ret = wait_for_cdyn_deassert(vdev);
if (ret) {
ivpu_err(vdev, "Timed out waiting for CDYN deassert\n");
return ret;
}
}
return 0;
}
@@ -673,7 +689,7 @@ bool ivpu_hw_btrs_irq_handler_lnl(struct ivpu_device *vdev, int irq)
if (REG_TEST_FLD(VPU_HW_BTRS_LNL_INTERRUPT_STAT, SURV_ERR, status)) {
ivpu_dbg(vdev, IRQ, "Survivability IRQ\n");
queue_work(system_wq, &vdev->irq_dct_work);
queue_work(system_percpu_wq, &vdev->irq_dct_work);
}
if (REG_TEST_FLD(VPU_HW_BTRS_LNL_INTERRUPT_STAT, FREQ_CHANGE, status)) {

View File

@@ -74,6 +74,9 @@
#define VPU_HW_BTRS_LNL_PLL_FREQ 0x00000148u
#define VPU_HW_BTRS_LNL_PLL_FREQ_RATIO_MASK GENMASK(15, 0)
#define VPU_HW_BTRS_LNL_CDYN 0x0000014cu
#define VPU_HW_BTRS_LNL_CDYN_CDYN_MASK GENMASK(15, 0)
#define VPU_HW_BTRS_LNL_TILE_FUSE 0x00000150u
#define VPU_HW_BTRS_LNL_TILE_FUSE_VALID_MASK BIT_MASK(0)
#define VPU_HW_BTRS_LNL_TILE_FUSE_CONFIG_MASK GENMASK(6, 1)

View File

@@ -459,7 +459,7 @@ void ivpu_ipc_irq_handler(struct ivpu_device *vdev)
}
}
queue_work(system_wq, &vdev->irq_ipc_work);
queue_work(system_percpu_wq, &vdev->irq_ipc_work);
}
void ivpu_ipc_irq_work_fn(struct work_struct *work)

View File

@@ -348,7 +348,7 @@ static struct ivpu_cmdq *ivpu_cmdq_acquire(struct ivpu_file_priv *file_priv, u32
cmdq = xa_load(&file_priv->cmdq_xa, cmdq_id);
if (!cmdq) {
ivpu_warn_ratelimited(vdev, "Failed to find command queue with ID: %u\n", cmdq_id);
ivpu_dbg(vdev, IOCTL, "Failed to find command queue with ID: %u\n", cmdq_id);
return NULL;
}
@@ -534,7 +534,7 @@ ivpu_job_create(struct ivpu_file_priv *file_priv, u32 engine_idx, u32 bo_count)
job->bo_count = bo_count;
job->done_fence = ivpu_fence_create(vdev);
if (!job->done_fence) {
ivpu_warn_ratelimited(vdev, "Failed to create a fence\n");
ivpu_err(vdev, "Failed to create a fence\n");
goto err_free_job;
}
@@ -591,7 +591,7 @@ bool ivpu_job_handle_engine_error(struct ivpu_device *vdev, u32 job_id, u32 job_
* status and ensure both are handled in the same way
*/
job->file_priv->has_mmu_faults = true;
queue_work(system_wq, &vdev->context_abort_work);
queue_work(system_percpu_wq, &vdev->context_abort_work);
return true;
}
default:
@@ -687,7 +687,6 @@ static int ivpu_job_submit(struct ivpu_job *job, u8 priority, u32 cmdq_id)
else
cmdq = ivpu_cmdq_acquire(file_priv, cmdq_id);
if (!cmdq) {
ivpu_warn_ratelimited(vdev, "Failed to get job queue, ctx %d\n", file_priv->ctx.id);
ret = -EINVAL;
goto err_unlock;
}
@@ -771,8 +770,11 @@ ivpu_job_prepare_bos_for_submit(struct drm_file *file, struct ivpu_job *job, u32
for (i = 0; i < buf_count; i++) {
struct drm_gem_object *obj = drm_gem_object_lookup(file, buf_handles[i]);
if (!obj)
if (!obj) {
ivpu_dbg(vdev, IOCTL, "Failed to lookup GEM object with handle %u\n",
buf_handles[i]);
return -ENOENT;
}
job->bos[i] = to_ivpu_bo(obj);
@@ -783,12 +785,13 @@ ivpu_job_prepare_bos_for_submit(struct drm_file *file, struct ivpu_job *job, u32
bo = job->bos[CMD_BUF_IDX];
if (!dma_resv_test_signaled(bo->base.base.resv, DMA_RESV_USAGE_READ)) {
ivpu_warn(vdev, "Buffer is already in use\n");
ivpu_dbg(vdev, IOCTL, "Buffer is already in use by another job\n");
return -EBUSY;
}
if (commands_offset >= ivpu_bo_size(bo)) {
ivpu_warn(vdev, "Invalid command buffer offset %u\n", commands_offset);
ivpu_dbg(vdev, IOCTL, "Invalid commands offset %u for buffer size %zu\n",
commands_offset, ivpu_bo_size(bo));
return -EINVAL;
}
@@ -798,11 +801,11 @@ ivpu_job_prepare_bos_for_submit(struct drm_file *file, struct ivpu_job *job, u32
struct ivpu_bo *preempt_bo = job->bos[preempt_buffer_index];
if (ivpu_bo_size(preempt_bo) < ivpu_fw_preempt_buf_size(vdev)) {
ivpu_warn(vdev, "Preemption buffer is too small\n");
ivpu_dbg(vdev, IOCTL, "Preemption buffer is too small\n");
return -EINVAL;
}
if (ivpu_bo_is_mappable(preempt_bo)) {
ivpu_warn(vdev, "Preemption buffer cannot be mappable\n");
ivpu_dbg(vdev, IOCTL, "Preemption buffer cannot be mappable\n");
return -EINVAL;
}
job->primary_preempt_buf = preempt_bo;
@@ -811,14 +814,14 @@ ivpu_job_prepare_bos_for_submit(struct drm_file *file, struct ivpu_job *job, u32
ret = drm_gem_lock_reservations((struct drm_gem_object **)job->bos, buf_count,
&acquire_ctx);
if (ret) {
ivpu_warn(vdev, "Failed to lock reservations: %d\n", ret);
ivpu_warn_ratelimited(vdev, "Failed to lock reservations: %d\n", ret);
return ret;
}
for (i = 0; i < buf_count; i++) {
ret = dma_resv_reserve_fences(job->bos[i]->base.base.resv, 1);
if (ret) {
ivpu_warn(vdev, "Failed to reserve fences: %d\n", ret);
ivpu_warn_ratelimited(vdev, "Failed to reserve fences: %d\n", ret);
goto unlock_reservations;
}
}
@@ -865,17 +868,14 @@ static int ivpu_submit(struct drm_file *file, struct ivpu_file_priv *file_priv,
job = ivpu_job_create(file_priv, engine, buffer_count);
if (!job) {
ivpu_err(vdev, "Failed to create job\n");
ret = -ENOMEM;
goto err_exit_dev;
}
ret = ivpu_job_prepare_bos_for_submit(file, job, buf_handles, buffer_count, cmds_offset,
preempt_buffer_index);
if (ret) {
ivpu_err(vdev, "Failed to prepare job: %d\n", ret);
if (ret)
goto err_destroy_job;
}
down_read(&vdev->pm->reset_lock);
ret = ivpu_job_submit(job, priority, cmdq_id);
@@ -901,26 +901,39 @@ static int ivpu_submit(struct drm_file *file, struct ivpu_file_priv *file_priv,
int ivpu_submit_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
{
struct ivpu_file_priv *file_priv = file->driver_priv;
struct ivpu_device *vdev = file_priv->vdev;
struct drm_ivpu_submit *args = data;
u8 priority;
if (args->engine != DRM_IVPU_ENGINE_COMPUTE)
if (args->engine != DRM_IVPU_ENGINE_COMPUTE) {
ivpu_dbg(vdev, IOCTL, "Invalid engine %d\n", args->engine);
return -EINVAL;
}
if (args->priority > DRM_IVPU_JOB_PRIORITY_REALTIME)
if (args->priority > DRM_IVPU_JOB_PRIORITY_REALTIME) {
ivpu_dbg(vdev, IOCTL, "Invalid priority %d\n", args->priority);
return -EINVAL;
}
if (args->buffer_count == 0 || args->buffer_count > JOB_MAX_BUFFER_COUNT)
if (args->buffer_count == 0 || args->buffer_count > JOB_MAX_BUFFER_COUNT) {
ivpu_dbg(vdev, IOCTL, "Invalid buffer count %u\n", args->buffer_count);
return -EINVAL;
}
if (!IS_ALIGNED(args->commands_offset, 8))
if (!IS_ALIGNED(args->commands_offset, 8)) {
ivpu_dbg(vdev, IOCTL, "Invalid commands offset %u\n", args->commands_offset);
return -EINVAL;
}
if (!file_priv->ctx.id)
if (!file_priv->ctx.id) {
ivpu_dbg(vdev, IOCTL, "Context not initialized\n");
return -EINVAL;
}
if (file_priv->has_mmu_faults)
if (file_priv->has_mmu_faults) {
ivpu_dbg(vdev, IOCTL, "Context %u has MMU faults\n", file_priv->ctx.id);
return -EBADFD;
}
priority = ivpu_job_to_jsm_priority(args->priority);
@@ -931,28 +944,44 @@ int ivpu_submit_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
int ivpu_cmdq_submit_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
{
struct ivpu_file_priv *file_priv = file->driver_priv;
struct ivpu_device *vdev = file_priv->vdev;
struct drm_ivpu_cmdq_submit *args = data;
if (!ivpu_is_capable(file_priv->vdev, DRM_IVPU_CAP_MANAGE_CMDQ))
if (!ivpu_is_capable(file_priv->vdev, DRM_IVPU_CAP_MANAGE_CMDQ)) {
ivpu_dbg(vdev, IOCTL, "Command queue management not supported\n");
return -ENODEV;
}
if (args->cmdq_id < IVPU_CMDQ_MIN_ID || args->cmdq_id > IVPU_CMDQ_MAX_ID)
if (args->cmdq_id < IVPU_CMDQ_MIN_ID || args->cmdq_id > IVPU_CMDQ_MAX_ID) {
ivpu_dbg(vdev, IOCTL, "Invalid command queue ID %u\n", args->cmdq_id);
return -EINVAL;
}
if (args->buffer_count == 0 || args->buffer_count > JOB_MAX_BUFFER_COUNT)
if (args->buffer_count == 0 || args->buffer_count > JOB_MAX_BUFFER_COUNT) {
ivpu_dbg(vdev, IOCTL, "Invalid buffer count %u\n", args->buffer_count);
return -EINVAL;
}
if (args->preempt_buffer_index >= args->buffer_count)
if (args->preempt_buffer_index >= args->buffer_count) {
ivpu_dbg(vdev, IOCTL, "Invalid preemption buffer index %u\n",
args->preempt_buffer_index);
return -EINVAL;
}
if (!IS_ALIGNED(args->commands_offset, 8))
if (!IS_ALIGNED(args->commands_offset, 8)) {
ivpu_dbg(vdev, IOCTL, "Invalid commands offset %u\n", args->commands_offset);
return -EINVAL;
}
if (!file_priv->ctx.id)
if (!file_priv->ctx.id) {
ivpu_dbg(vdev, IOCTL, "Context not initialized\n");
return -EINVAL;
}
if (file_priv->has_mmu_faults)
if (file_priv->has_mmu_faults) {
ivpu_dbg(vdev, IOCTL, "Context %u has MMU faults\n", file_priv->ctx.id);
return -EBADFD;
}
return ivpu_submit(file, file_priv, args->cmdq_id, args->buffer_count, VPU_ENGINE_COMPUTE,
(void __user *)args->buffers_ptr, args->commands_offset,
@@ -967,11 +996,15 @@ int ivpu_cmdq_create_ioctl(struct drm_device *dev, void *data, struct drm_file *
struct ivpu_cmdq *cmdq;
int ret;
if (!ivpu_is_capable(vdev, DRM_IVPU_CAP_MANAGE_CMDQ))
if (!ivpu_is_capable(vdev, DRM_IVPU_CAP_MANAGE_CMDQ)) {
ivpu_dbg(vdev, IOCTL, "Command queue management not supported\n");
return -ENODEV;
}
if (args->priority > DRM_IVPU_JOB_PRIORITY_REALTIME)
if (args->priority > DRM_IVPU_JOB_PRIORITY_REALTIME) {
ivpu_dbg(vdev, IOCTL, "Invalid priority %d\n", args->priority);
return -EINVAL;
}
ret = ivpu_rpm_get(vdev);
if (ret < 0)
@@ -999,8 +1032,10 @@ int ivpu_cmdq_destroy_ioctl(struct drm_device *dev, void *data, struct drm_file
u32 cmdq_id = 0;
int ret;
if (!ivpu_is_capable(vdev, DRM_IVPU_CAP_MANAGE_CMDQ))
if (!ivpu_is_capable(vdev, DRM_IVPU_CAP_MANAGE_CMDQ)) {
ivpu_dbg(vdev, IOCTL, "Command queue management not supported\n");
return -ENODEV;
}
ret = ivpu_rpm_get(vdev);
if (ret < 0)
@@ -1114,6 +1149,5 @@ void ivpu_context_abort_work_fn(struct work_struct *work)
mutex_unlock(&vdev->submitted_jobs_lock);
runtime_put:
pm_runtime_mark_last_busy(vdev->drm.dev);
pm_runtime_put_autosuspend(vdev->drm.dev);
}

View File

@@ -970,7 +970,7 @@ void ivpu_mmu_irq_evtq_handler(struct ivpu_device *vdev)
}
}
queue_work(system_wq, &vdev->context_abort_work);
queue_work(system_percpu_wq, &vdev->context_abort_work);
}
void ivpu_mmu_evtq_dump(struct ivpu_device *vdev)

View File

@@ -430,7 +430,7 @@ static void ivpu_mmu_context_unmap_pages(struct ivpu_mmu_context *ctx, u64 vpu_a
int
ivpu_mmu_context_map_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx,
u64 vpu_addr, struct sg_table *sgt, bool llc_coherent)
u64 vpu_addr, struct sg_table *sgt, bool llc_coherent, bool read_only)
{
size_t start_vpu_addr = vpu_addr;
struct scatterlist *sg;
@@ -450,6 +450,8 @@ ivpu_mmu_context_map_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx,
prot = IVPU_MMU_ENTRY_MAPPED;
if (llc_coherent)
prot |= IVPU_MMU_ENTRY_FLAG_LLC_COHERENT;
if (read_only)
prot |= IVPU_MMU_ENTRY_FLAG_RO;
mutex_lock(&ctx->lock);
@@ -527,7 +529,8 @@ ivpu_mmu_context_unmap_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *ct
ret = ivpu_mmu_invalidate_tlb(vdev, ctx->id);
if (ret)
ivpu_warn(vdev, "Failed to invalidate TLB for ctx %u: %d\n", ctx->id, ret);
ivpu_warn_ratelimited(vdev, "Failed to invalidate TLB for ctx %u: %d\n",
ctx->id, ret);
}
int

View File

@@ -42,7 +42,7 @@ int ivpu_mmu_context_insert_node(struct ivpu_mmu_context *ctx, const struct ivpu
void ivpu_mmu_context_remove_node(struct ivpu_mmu_context *ctx, struct drm_mm_node *node);
int ivpu_mmu_context_map_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx,
u64 vpu_addr, struct sg_table *sgt, bool llc_coherent);
u64 vpu_addr, struct sg_table *sgt, bool llc_coherent, bool read_only);
void ivpu_mmu_context_unmap_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx,
u64 vpu_addr, struct sg_table *sgt);
int ivpu_mmu_context_set_pages_ro(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx,

View File

@@ -8,6 +8,7 @@
#include "ivpu_drv.h"
#include "ivpu_gem.h"
#include "ivpu_hw.h"
#include "ivpu_jsm_msg.h"
#include "ivpu_ms.h"
#include "ivpu_pm.h"
@@ -37,8 +38,8 @@ int ivpu_ms_start_ioctl(struct drm_device *dev, void *data, struct drm_file *fil
struct drm_ivpu_metric_streamer_start *args = data;
struct ivpu_device *vdev = file_priv->vdev;
struct ivpu_ms_instance *ms;
u64 single_buff_size;
u32 sample_size;
u64 buf_size;
int ret;
if (!args->metric_group_mask || !args->read_period_samples ||
@@ -52,7 +53,8 @@ int ivpu_ms_start_ioctl(struct drm_device *dev, void *data, struct drm_file *fil
mutex_lock(&file_priv->ms_lock);
if (get_instance_by_mask(file_priv, args->metric_group_mask)) {
ivpu_err(vdev, "Instance already exists (mask %#llx)\n", args->metric_group_mask);
ivpu_dbg(vdev, IOCTL, "Instance already exists (mask %#llx)\n",
args->metric_group_mask);
ret = -EALREADY;
goto unlock;
}
@@ -69,12 +71,18 @@ int ivpu_ms_start_ioctl(struct drm_device *dev, void *data, struct drm_file *fil
if (ret)
goto err_free_ms;
single_buff_size = sample_size *
((u64)args->read_period_samples * MS_READ_PERIOD_MULTIPLIER);
ms->bo = ivpu_bo_create_global(vdev, PAGE_ALIGN(single_buff_size * MS_NUM_BUFFERS),
DRM_IVPU_BO_CACHED | DRM_IVPU_BO_MAPPABLE);
buf_size = PAGE_ALIGN((u64)args->read_period_samples * sample_size *
MS_READ_PERIOD_MULTIPLIER * MS_NUM_BUFFERS);
if (buf_size > ivpu_hw_range_size(&vdev->hw->ranges.global)) {
ivpu_dbg(vdev, IOCTL, "Requested MS buffer size %llu exceeds range size %llu\n",
buf_size, ivpu_hw_range_size(&vdev->hw->ranges.global));
ret = -EINVAL;
goto err_free_ms;
}
ms->bo = ivpu_bo_create_global(vdev, buf_size, DRM_IVPU_BO_CACHED | DRM_IVPU_BO_MAPPABLE);
if (!ms->bo) {
ivpu_err(vdev, "Failed to allocate MS buffer (size %llu)\n", single_buff_size);
ivpu_dbg(vdev, IOCTL, "Failed to allocate MS buffer (size %llu)\n", buf_size);
ret = -ENOMEM;
goto err_free_ms;
}
@@ -175,7 +183,8 @@ int ivpu_ms_get_data_ioctl(struct drm_device *dev, void *data, struct drm_file *
ms = get_instance_by_mask(file_priv, args->metric_group_mask);
if (!ms) {
ivpu_err(vdev, "Instance doesn't exist for mask: %#llx\n", args->metric_group_mask);
ivpu_dbg(vdev, IOCTL, "Instance doesn't exist for mask: %#llx\n",
args->metric_group_mask);
ret = -EINVAL;
goto unlock;
}

View File

@@ -186,7 +186,7 @@ void ivpu_pm_trigger_recovery(struct ivpu_device *vdev, const char *reason)
if (atomic_cmpxchg(&vdev->pm->reset_pending, 0, 1) == 0) {
ivpu_hw_diagnose_failure(vdev);
ivpu_hw_irq_disable(vdev); /* Disable IRQ early to protect from IRQ storm */
queue_work(system_unbound_wq, &vdev->pm->recovery_work);
queue_work(system_dfl_wq, &vdev->pm->recovery_work);
}
}
@@ -226,7 +226,8 @@ void ivpu_start_job_timeout_detection(struct ivpu_device *vdev)
unsigned long timeout_ms = ivpu_tdr_timeout_ms ? ivpu_tdr_timeout_ms : vdev->timeout.tdr;
/* No-op if already queued */
queue_delayed_work(system_wq, &vdev->pm->job_timeout_work, msecs_to_jiffies(timeout_ms));
queue_delayed_work(system_percpu_wq, &vdev->pm->job_timeout_work,
msecs_to_jiffies(timeout_ms));
}
void ivpu_stop_job_timeout_detection(struct ivpu_device *vdev)
@@ -359,7 +360,6 @@ int ivpu_rpm_get(struct ivpu_device *vdev)
void ivpu_rpm_put(struct ivpu_device *vdev)
{
pm_runtime_mark_last_busy(vdev->drm.dev);
pm_runtime_put_autosuspend(vdev->drm.dev);
}
@@ -428,7 +428,6 @@ void ivpu_pm_enable(struct ivpu_device *vdev)
struct device *dev = vdev->drm.dev;
pm_runtime_allow(dev);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
}

View File

@@ -2,6 +2,7 @@
/* Copyright 2024-2025 Tomeu Vizoso <tomeu@tomeuvizoso.net> */
#include <drm/drm_device.h>
#include <drm/drm_print.h>
#include <drm/drm_utils.h>
#include <drm/rocket_accel.h>
#include <linux/dma-mapping.h>

View File

@@ -16,6 +16,7 @@
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_of.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>

View File

@@ -1798,7 +1798,7 @@ static int amdgpu_ttm_pools_init(struct amdgpu_device *adev)
for (i = 0; i < adev->gmc.num_mem_partitions; i++) {
ttm_pool_init(&adev->mman.ttm_pools[i], adev->dev,
adev->gmc.mem_partitions[i].numa.node,
false, false);
TTM_ALLOCATION_POOL_BENEFICIAL_ORDER(get_order(SZ_2M)));
}
return 0;
}
@@ -1891,8 +1891,11 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
r = ttm_device_init(&adev->mman.bdev, &amdgpu_bo_driver, adev->dev,
adev_to_drm(adev)->anon_inode->i_mapping,
adev_to_drm(adev)->vma_offset_manager,
adev->need_swiotlb,
dma_addressing_limited(adev->dev));
(adev->need_swiotlb ?
TTM_ALLOCATION_POOL_USE_DMA_ALLOC : 0) |
(dma_addressing_limited(adev->dev) ?
TTM_ALLOCATION_POOL_USE_DMA32 : 0) |
TTM_ALLOCATION_POOL_BENEFICIAL_ORDER(get_order(SZ_2M)));
if (r) {
dev_err(adev->dev,
"failed initializing buffer object driver(%d).\n", r);

View File

@@ -9,6 +9,7 @@
#include <drm/drm_gem.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_print.h>
#include "komeda_framebuffer.h"
#include "komeda_dev.h"

View File

@@ -22,6 +22,7 @@
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_of.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>

View File

@@ -33,6 +33,7 @@
#include <drm/drm_modeset_helper.h>
#include <drm/drm_module.h>
#include <drm/drm_of.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>

View File

@@ -29,6 +29,7 @@
#include <drm/drm_modeset_helper.h>
#include <drm/drm_module.h>
#include <drm/drm_of.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>

View File

@@ -14,6 +14,7 @@
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_writeback.h>

View File

@@ -13,6 +13,7 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>

View File

@@ -12,6 +12,7 @@
#include <drm/drm_debugfs.h>
#include <drm/drm_file.h>
#include <drm/drm_print.h>
#include "armada_crtc.h"
#include "armada_drm.h"

View File

@@ -6,6 +6,7 @@
#include <drm/drm_modeset_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_print.h>
#include "armada_drm.h"
#include "armada_fb.h"

View File

@@ -13,6 +13,7 @@
#include <drm/drm_drv.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_print.h>
#include "armada_crtc.h"
#include "armada_drm.h"

View File

@@ -10,6 +10,7 @@
#include <drm/armada_drm.h>
#include <drm/drm_prime.h>
#include <drm/drm_print.h>
#include "armada_drm.h"
#include "armada_gem.h"

View File

@@ -12,6 +12,7 @@
#include <drm/drm_atomic_uapi.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_plane_helper.h>
#include <drm/drm_print.h>
#include "armada_crtc.h"
#include "armada_drm.h"

View File

@@ -8,6 +8,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_plane_helper.h>
#include <drm/drm_print.h>
#include "armada_crtc.h"
#include "armada_drm.h"

View File

@@ -43,6 +43,7 @@
#include <drm/drm_gem_shmem_helper.h>
#include <drm/drm_managed.h>
#include <drm/drm_panic.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include "ast_drv.h"

View File

@@ -25,6 +25,7 @@
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_module.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>

View File

@@ -16,6 +16,7 @@
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_print.h>
#include "atmel_hlcdc_dc.h"

View File

@@ -2049,6 +2049,8 @@ struct dw_dp *dw_dp_bind(struct device *dev, struct drm_encoder *encoder,
bridge->type = DRM_MODE_CONNECTOR_DisplayPort;
bridge->ycbcr_420_allowed = true;
devm_drm_bridge_add(dev, bridge);
dp->aux.dev = dev;
dp->aux.drm_dev = encoder->dev;
dp->aux.name = dev_name(dev);

View File

@@ -100,7 +100,7 @@ static void drm_log_clear_line(struct drm_log_scanout *scanout, u32 line)
return;
iosys_map_memset(&map, r.y1 * fb->pitches[0], 0, height * fb->pitches[0]);
drm_client_buffer_vunmap_local(scanout->buffer);
drm_client_framebuffer_flush(scanout->buffer, &r);
drm_client_buffer_flush(scanout->buffer, &r);
}
static void drm_log_draw_line(struct drm_log_scanout *scanout, const char *s,
@@ -133,7 +133,7 @@ static void drm_log_draw_line(struct drm_log_scanout *scanout, const char *s,
if (scanout->line >= scanout->rows)
scanout->line = 0;
drm_client_buffer_vunmap_local(scanout->buffer);
drm_client_framebuffer_flush(scanout->buffer, &r);
drm_client_buffer_flush(scanout->buffer, &r);
}
static void drm_log_draw_new_line(struct drm_log_scanout *scanout,
@@ -204,7 +204,7 @@ static int drm_log_setup_modeset(struct drm_client_dev *client,
if (format == DRM_FORMAT_INVALID)
return -EINVAL;
scanout->buffer = drm_client_framebuffer_create(client, width, height, format);
scanout->buffer = drm_client_buffer_create_dumb(client, width, height, format);
if (IS_ERR(scanout->buffer)) {
drm_warn(client->dev, "drm_log can't create framebuffer %d %d %p4cc\n",
width, height, &format);
@@ -272,7 +272,7 @@ static void drm_log_init_client(struct drm_log *dlog)
err_failed_commit:
for (i = 0; i < n_modeset; i++)
drm_client_framebuffer_delete(dlog->scanout[i].buffer);
drm_client_buffer_delete(dlog->scanout[i].buffer);
err_nomodeset:
kfree(dlog->scanout);
@@ -286,7 +286,7 @@ static void drm_log_free_scanout(struct drm_client_dev *client)
if (dlog->n_scanout) {
for (i = 0; i < dlog->n_scanout; i++)
drm_client_framebuffer_delete(dlog->scanout[i].buffer);
drm_client_buffer_delete(dlog->scanout[i].buffer);
dlog->n_scanout = 0;
kfree(dlog->scanout);
dlog->scanout = NULL;

View File

@@ -652,15 +652,7 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
struct drm_bridge_connector *bridge_connector;
struct drm_connector *connector;
struct i2c_adapter *ddc = NULL;
struct drm_bridge *panel_bridge __free(drm_bridge_put) = NULL;
struct drm_bridge *bridge_edid __free(drm_bridge_put) = NULL;
struct drm_bridge *bridge_hpd __free(drm_bridge_put) = NULL;
struct drm_bridge *bridge_detect __free(drm_bridge_put) = NULL;
struct drm_bridge *bridge_modes __free(drm_bridge_put) = NULL;
struct drm_bridge *bridge_hdmi __free(drm_bridge_put) = NULL;
struct drm_bridge *bridge_hdmi_audio __free(drm_bridge_put) = NULL;
struct drm_bridge *bridge_dp_audio __free(drm_bridge_put) = NULL;
struct drm_bridge *bridge_hdmi_cec __free(drm_bridge_put) = NULL;
struct drm_bridge *panel_bridge __free(drm_bridge_put) = NULL;
unsigned int supported_formats = BIT(HDMI_COLORSPACE_RGB);
unsigned int max_bpc = 8;
bool support_hdcp = false;
@@ -699,29 +691,29 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
connector->ycbcr_420_allowed = false;
if (bridge->ops & DRM_BRIDGE_OP_EDID) {
drm_bridge_put(bridge_edid);
bridge_edid = drm_bridge_get(bridge);
drm_bridge_put(bridge_connector->bridge_edid);
bridge_connector->bridge_edid = drm_bridge_get(bridge);
}
if (bridge->ops & DRM_BRIDGE_OP_HPD) {
drm_bridge_put(bridge_hpd);
bridge_hpd = drm_bridge_get(bridge);
drm_bridge_put(bridge_connector->bridge_hpd);
bridge_connector->bridge_hpd = drm_bridge_get(bridge);
}
if (bridge->ops & DRM_BRIDGE_OP_DETECT) {
drm_bridge_put(bridge_detect);
bridge_detect = drm_bridge_get(bridge);
drm_bridge_put(bridge_connector->bridge_detect);
bridge_connector->bridge_detect = drm_bridge_get(bridge);
}
if (bridge->ops & DRM_BRIDGE_OP_MODES) {
drm_bridge_put(bridge_modes);
bridge_modes = drm_bridge_get(bridge);
drm_bridge_put(bridge_connector->bridge_modes);
bridge_connector->bridge_modes = drm_bridge_get(bridge);
}
if (bridge->ops & DRM_BRIDGE_OP_HDMI) {
if (bridge_hdmi)
if (bridge_connector->bridge_hdmi)
return ERR_PTR(-EBUSY);
if (!bridge->funcs->hdmi_write_infoframe ||
!bridge->funcs->hdmi_clear_infoframe)
return ERR_PTR(-EINVAL);
bridge_hdmi = drm_bridge_get(bridge);
bridge_connector->bridge_hdmi = drm_bridge_get(bridge);
if (bridge->supported_formats)
supported_formats = bridge->supported_formats;
@@ -730,10 +722,10 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
}
if (bridge->ops & DRM_BRIDGE_OP_HDMI_AUDIO) {
if (bridge_hdmi_audio)
if (bridge_connector->bridge_hdmi_audio)
return ERR_PTR(-EBUSY);
if (bridge_dp_audio)
if (bridge_connector->bridge_dp_audio)
return ERR_PTR(-EBUSY);
if (!bridge->hdmi_audio_max_i2s_playback_channels &&
@@ -744,14 +736,14 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
!bridge->funcs->hdmi_audio_shutdown)
return ERR_PTR(-EINVAL);
bridge_hdmi_audio = drm_bridge_get(bridge);
bridge_connector->bridge_hdmi_audio = drm_bridge_get(bridge);
}
if (bridge->ops & DRM_BRIDGE_OP_DP_AUDIO) {
if (bridge_dp_audio)
if (bridge_connector->bridge_dp_audio)
return ERR_PTR(-EBUSY);
if (bridge_hdmi_audio)
if (bridge_connector->bridge_hdmi_audio)
return ERR_PTR(-EBUSY);
if (!bridge->hdmi_audio_max_i2s_playback_channels &&
@@ -762,21 +754,21 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
!bridge->funcs->dp_audio_shutdown)
return ERR_PTR(-EINVAL);
bridge_dp_audio = drm_bridge_get(bridge);
bridge_connector->bridge_dp_audio = drm_bridge_get(bridge);
}
if (bridge->ops & DRM_BRIDGE_OP_HDMI_CEC_NOTIFIER) {
if (bridge_connector->bridge_hdmi_cec)
return ERR_PTR(-EBUSY);
bridge_connector->bridge_hdmi_cec = bridge;
bridge_connector->bridge_hdmi_cec = drm_bridge_get(bridge);
}
if (bridge->ops & DRM_BRIDGE_OP_HDMI_CEC_ADAPTER) {
if (bridge_hdmi_cec)
if (bridge_connector->bridge_hdmi_cec)
return ERR_PTR(-EBUSY);
bridge_hdmi_cec = drm_bridge_get(bridge);
bridge_connector->bridge_hdmi_cec = drm_bridge_get(bridge);
if (!bridge->funcs->hdmi_cec_enable ||
!bridge->funcs->hdmi_cec_log_addr ||
@@ -795,8 +787,10 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
if (bridge->ddc)
ddc = bridge->ddc;
if (drm_bridge_is_panel(bridge))
if (drm_bridge_is_panel(bridge)) {
drm_bridge_put(panel_bridge);
panel_bridge = drm_bridge_get(bridge);
}
if (bridge->support_hdcp)
support_hdcp = true;
@@ -805,13 +799,13 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
if (connector_type == DRM_MODE_CONNECTOR_Unknown)
return ERR_PTR(-EINVAL);
if (bridge_hdmi) {
if (bridge_connector->bridge_hdmi) {
if (!connector->ycbcr_420_allowed)
supported_formats &= ~BIT(HDMI_COLORSPACE_YUV420);
ret = drmm_connector_hdmi_init(drm, connector,
bridge_hdmi->vendor,
bridge_hdmi->product,
bridge_connector->bridge_hdmi->vendor,
bridge_connector->bridge_hdmi->product,
&drm_bridge_connector_funcs,
&drm_bridge_connector_hdmi_funcs,
connector_type, ddc,
@@ -827,14 +821,15 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
return ERR_PTR(ret);
}
if (bridge_hdmi_audio || bridge_dp_audio) {
if (bridge_connector->bridge_hdmi_audio ||
bridge_connector->bridge_dp_audio) {
struct device *dev;
struct drm_bridge *bridge;
if (bridge_hdmi_audio)
bridge = bridge_hdmi_audio;
if (bridge_connector->bridge_hdmi_audio)
bridge = bridge_connector->bridge_hdmi_audio;
else
bridge = bridge_dp_audio;
bridge = bridge_connector->bridge_dp_audio;
dev = bridge->hdmi_audio_dev;
@@ -848,9 +843,9 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
return ERR_PTR(ret);
}
if (bridge_hdmi_cec &&
bridge_hdmi_cec->ops & DRM_BRIDGE_OP_HDMI_CEC_NOTIFIER) {
struct drm_bridge *bridge = bridge_hdmi_cec;
if (bridge_connector->bridge_hdmi_cec &&
bridge_connector->bridge_hdmi_cec->ops & DRM_BRIDGE_OP_HDMI_CEC_NOTIFIER) {
struct drm_bridge *bridge = bridge_connector->bridge_hdmi_cec;
ret = drmm_connector_hdmi_cec_notifier_register(connector,
NULL,
@@ -859,9 +854,9 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
return ERR_PTR(ret);
}
if (bridge_hdmi_cec &&
bridge_hdmi_cec->ops & DRM_BRIDGE_OP_HDMI_CEC_ADAPTER) {
struct drm_bridge *bridge = bridge_hdmi_cec;
if (bridge_connector->bridge_hdmi_cec &&
bridge_connector->bridge_hdmi_cec->ops & DRM_BRIDGE_OP_HDMI_CEC_ADAPTER) {
struct drm_bridge *bridge = bridge_connector->bridge_hdmi_cec;
ret = drmm_connector_hdmi_cec_register(connector,
&drm_bridge_connector_hdmi_cec_funcs,
@@ -874,9 +869,9 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
drm_connector_helper_add(connector, &drm_bridge_connector_helper_funcs);
if (bridge_hpd)
if (bridge_connector->bridge_hpd)
connector->polled = DRM_CONNECTOR_POLL_HPD;
else if (bridge_detect)
else if (bridge_connector->bridge_detect)
connector->polled = DRM_CONNECTOR_POLL_CONNECT
| DRM_CONNECTOR_POLL_DISCONNECT;
@@ -887,15 +882,6 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
IS_ENABLED(CONFIG_DRM_DISPLAY_HDCP_HELPER))
drm_connector_attach_content_protection_property(connector, true);
bridge_connector->bridge_edid = drm_bridge_get(bridge_edid);
bridge_connector->bridge_hpd = drm_bridge_get(bridge_hpd);
bridge_connector->bridge_detect = drm_bridge_get(bridge_detect);
bridge_connector->bridge_modes = drm_bridge_get(bridge_modes);
bridge_connector->bridge_hdmi = drm_bridge_get(bridge_hdmi);
bridge_connector->bridge_hdmi_audio = drm_bridge_get(bridge_hdmi_audio);
bridge_connector->bridge_dp_audio = drm_bridge_get(bridge_dp_audio);
bridge_connector->bridge_hdmi_cec = drm_bridge_get(bridge_hdmi_cec);
return connector;
}
EXPORT_SYMBOL_GPL(drm_bridge_connector_init);

View File

@@ -200,6 +200,8 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state)
drm_dbg_atomic(dev, "Clearing atomic state %p\n", state);
state->checked = false;
for (i = 0; i < state->num_connector; i++) {
struct drm_connector *connector = state->connectors[i].ptr;
@@ -348,6 +350,7 @@ drm_atomic_get_crtc_state(struct drm_atomic_state *state,
struct drm_crtc_state *crtc_state;
WARN_ON(!state->acquire_ctx);
drm_WARN_ON(state->dev, state->checked);
crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
if (crtc_state)
@@ -528,6 +531,7 @@ drm_atomic_get_plane_state(struct drm_atomic_state *state,
struct drm_plane_state *plane_state;
WARN_ON(!state->acquire_ctx);
drm_WARN_ON(state->dev, state->checked);
/* the legacy pointers should never be set */
WARN_ON(plane->fb);
@@ -836,6 +840,9 @@ drm_atomic_get_private_obj_state(struct drm_atomic_state *state,
struct __drm_private_objs_state *arr;
struct drm_private_state *obj_state;
WARN_ON(!state->acquire_ctx);
drm_WARN_ON(state->dev, state->checked);
obj_state = drm_atomic_get_new_private_obj_state(state, obj);
if (obj_state)
return obj_state;
@@ -1129,6 +1136,7 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state,
struct drm_connector_state *connector_state;
WARN_ON(!state->acquire_ctx);
drm_WARN_ON(state->dev, state->checked);
ret = drm_modeset_lock(&config->connection_mutex, state->acquire_ctx);
if (ret)
@@ -1541,6 +1549,8 @@ int drm_atomic_check_only(struct drm_atomic_state *state)
requested_crtc, affected_crtc);
}
state->checked = true;
return 0;
}
EXPORT_SYMBOL(drm_atomic_check_only);

View File

@@ -422,6 +422,9 @@ static bool drm_bridge_is_atomic(struct drm_bridge *bridge)
* If non-NULL the previous bridge must be already attached by a call to this
* function.
*
* The bridge to be attached must have been previously added by
* drm_bridge_add().
*
* Note that bridges attached to encoders are auto-detached during encoder
* cleanup in drm_encoder_cleanup(), so drm_bridge_attach() should generally
* *not* be balanced with a drm_bridge_detach() in driver code.
@@ -438,6 +441,12 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
if (!encoder || !bridge)
return -EINVAL;
if (!bridge->container)
DRM_WARN("DRM bridge corrupted or not allocated by devm_drm_bridge_alloc()\n");
if (list_empty(&bridge->list))
DRM_WARN("Missing drm_bridge_add() before attach\n");
drm_bridge_get(bridge);
if (previous && (!previous->dev || previous->encoder != encoder)) {

View File

@@ -11,6 +11,7 @@
#include <linux/sizes.h>
#include <drm/drm_buddy.h>
#include <drm/drm_print.h>
enum drm_buddy_free_tree {
DRM_BUDDY_CLEAR_TREE = 0,

View File

@@ -17,6 +17,7 @@
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_mode.h>
#include <drm/drm_print.h>
@@ -176,25 +177,51 @@ void drm_client_release(struct drm_client_dev *client)
}
EXPORT_SYMBOL(drm_client_release);
static void drm_client_buffer_delete(struct drm_client_buffer *buffer)
/**
* drm_client_buffer_delete - Delete a client buffer
* @buffer: DRM client buffer
*/
void drm_client_buffer_delete(struct drm_client_buffer *buffer)
{
if (buffer->gem) {
drm_gem_vunmap(buffer->gem, &buffer->map);
drm_gem_object_put(buffer->gem);
}
struct drm_gem_object *gem;
int ret;
if (!buffer)
return;
gem = buffer->fb->obj[0];
drm_gem_vunmap(gem, &buffer->map);
ret = drm_mode_rmfb(buffer->client->dev, buffer->fb->base.id, buffer->client->file);
if (ret)
drm_err(buffer->client->dev,
"Error removing FB:%u (%d)\n", buffer->fb->base.id, ret);
drm_gem_object_put(buffer->gem);
kfree(buffer);
}
EXPORT_SYMBOL(drm_client_buffer_delete);
static struct drm_client_buffer *
drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height,
u32 format, u32 *handle)
u32 format, u32 handle, u32 pitch)
{
const struct drm_format_info *info = drm_format_info(format);
struct drm_mode_create_dumb dumb_args = { };
struct drm_mode_fb_cmd2 fb_req = {
.width = width,
.height = height,
.pixel_format = format,
.handles = {
handle,
},
.pitches = {
pitch,
},
};
struct drm_device *dev = client->dev;
struct drm_client_buffer *buffer;
struct drm_gem_object *obj;
struct drm_framebuffer *fb;
int ret;
buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
@@ -203,28 +230,38 @@ drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height,
buffer->client = client;
dumb_args.width = width;
dumb_args.height = height;
dumb_args.bpp = drm_format_info_bpp(info, 0);
ret = drm_mode_create_dumb(dev, &dumb_args, client->file);
if (ret)
goto err_delete;
obj = drm_gem_object_lookup(client->file, dumb_args.handle);
obj = drm_gem_object_lookup(client->file, handle);
if (!obj) {
ret = -ENOENT;
goto err_delete;
}
buffer->pitch = dumb_args.pitch;
ret = drm_mode_addfb2(dev, &fb_req, client->file);
if (ret)
goto err_drm_gem_object_put;
fb = drm_framebuffer_lookup(dev, client->file, fb_req.fb_id);
if (drm_WARN_ON(dev, !fb)) {
ret = -ENOENT;
goto err_drm_mode_rmfb;
}
/* drop the reference we picked up in framebuffer lookup */
drm_framebuffer_put(fb);
strscpy(fb->comm, client->name, TASK_COMM_LEN);
buffer->gem = obj;
*handle = dumb_args.handle;
buffer->fb = fb;
return buffer;
err_drm_mode_rmfb:
drm_mode_rmfb(dev, fb_req.fb_id, client->file);
err_drm_gem_object_put:
drm_gem_object_put(obj);
err_delete:
drm_client_buffer_delete(buffer);
kfree(buffer);
return ERR_PTR(ret);
}
@@ -251,7 +288,7 @@ drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height,
int drm_client_buffer_vmap_local(struct drm_client_buffer *buffer,
struct iosys_map *map_copy)
{
struct drm_gem_object *gem = buffer->gem;
struct drm_gem_object *gem = buffer->fb->obj[0];
struct iosys_map *map = &buffer->map;
int ret;
@@ -280,7 +317,7 @@ EXPORT_SYMBOL(drm_client_buffer_vmap_local);
*/
void drm_client_buffer_vunmap_local(struct drm_client_buffer *buffer)
{
struct drm_gem_object *gem = buffer->gem;
struct drm_gem_object *gem = buffer->fb->obj[0];
struct iosys_map *map = &buffer->map;
drm_gem_vunmap_locked(gem, map);
@@ -311,9 +348,10 @@ EXPORT_SYMBOL(drm_client_buffer_vunmap_local);
int drm_client_buffer_vmap(struct drm_client_buffer *buffer,
struct iosys_map *map_copy)
{
struct drm_gem_object *gem = buffer->fb->obj[0];
int ret;
ret = drm_gem_vmap(buffer->gem, &buffer->map);
ret = drm_gem_vmap(gem, &buffer->map);
if (ret)
return ret;
*map_copy = buffer->map;
@@ -332,57 +370,14 @@ EXPORT_SYMBOL(drm_client_buffer_vmap);
*/
void drm_client_buffer_vunmap(struct drm_client_buffer *buffer)
{
drm_gem_vunmap(buffer->gem, &buffer->map);
struct drm_gem_object *gem = buffer->fb->obj[0];
drm_gem_vunmap(gem, &buffer->map);
}
EXPORT_SYMBOL(drm_client_buffer_vunmap);
static void drm_client_buffer_rmfb(struct drm_client_buffer *buffer)
{
int ret;
if (!buffer->fb)
return;
ret = drm_mode_rmfb(buffer->client->dev, buffer->fb->base.id, buffer->client->file);
if (ret)
drm_err(buffer->client->dev,
"Error removing FB:%u (%d)\n", buffer->fb->base.id, ret);
buffer->fb = NULL;
}
static int drm_client_buffer_addfb(struct drm_client_buffer *buffer,
u32 width, u32 height, u32 format,
u32 handle)
{
struct drm_client_dev *client = buffer->client;
struct drm_mode_fb_cmd2 fb_req = { };
int ret;
fb_req.width = width;
fb_req.height = height;
fb_req.pixel_format = format;
fb_req.handles[0] = handle;
fb_req.pitches[0] = buffer->pitch;
ret = drm_mode_addfb2(client->dev, &fb_req, client->file);
if (ret)
return ret;
buffer->fb = drm_framebuffer_lookup(client->dev, buffer->client->file, fb_req.fb_id);
if (WARN_ON(!buffer->fb))
return -ENOENT;
/* drop the reference we picked up in framebuffer lookup */
drm_framebuffer_put(buffer->fb);
strscpy(buffer->fb->comm, client->name, TASK_COMM_LEN);
return 0;
}
/**
* drm_client_framebuffer_create - Create a client framebuffer
* drm_client_buffer_create_dumb - Create a client buffer backed by a dumb buffer
* @client: DRM client
* @width: Framebuffer width
* @height: Framebuffer height
@@ -390,24 +385,33 @@ static int drm_client_buffer_addfb(struct drm_client_buffer *buffer,
*
* This function creates a &drm_client_buffer which consists of a
* &drm_framebuffer backed by a dumb buffer.
* Call drm_client_framebuffer_delete() to free the buffer.
* Call drm_client_buffer_delete() to free the buffer.
*
* Returns:
* Pointer to a client buffer or an error pointer on failure.
*/
struct drm_client_buffer *
drm_client_framebuffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format)
drm_client_buffer_create_dumb(struct drm_client_dev *client, u32 width, u32 height, u32 format)
{
const struct drm_format_info *info = drm_format_info(format);
struct drm_device *dev = client->dev;
struct drm_mode_create_dumb dumb_args = { };
struct drm_client_buffer *buffer;
u32 handle;
int ret;
buffer = drm_client_buffer_create(client, width, height, format,
&handle);
if (IS_ERR(buffer))
return buffer;
dumb_args.width = width;
dumb_args.height = height;
dumb_args.bpp = drm_format_info_bpp(info, 0);
ret = drm_mode_create_dumb(dev, &dumb_args, client->file);
if (ret)
return ERR_PTR(ret);
ret = drm_client_buffer_addfb(buffer, width, height, format, handle);
buffer = drm_client_buffer_create(client, width, height, format,
dumb_args.handle, dumb_args.pitch);
if (IS_ERR(buffer)) {
ret = PTR_ERR(buffer);
goto err_drm_mode_destroy_dumb;
}
/*
* The handle is only needed for creating the framebuffer, destroy it
@@ -415,34 +419,19 @@ drm_client_framebuffer_create(struct drm_client_dev *client, u32 width, u32 heig
* object as DMA-buf. The framebuffer and our buffer structure are still
* holding references to the GEM object to prevent its destruction.
*/
drm_mode_destroy_dumb(client->dev, handle, client->file);
if (ret) {
drm_client_buffer_delete(buffer);
return ERR_PTR(ret);
}
drm_mode_destroy_dumb(client->dev, dumb_args.handle, client->file);
return buffer;
err_drm_mode_destroy_dumb:
drm_mode_destroy_dumb(client->dev, dumb_args.handle, client->file);
return ERR_PTR(ret);
}
EXPORT_SYMBOL(drm_client_framebuffer_create);
EXPORT_SYMBOL(drm_client_buffer_create_dumb);
/**
* drm_client_framebuffer_delete - Delete a client framebuffer
* @buffer: DRM client buffer (can be NULL)
*/
void drm_client_framebuffer_delete(struct drm_client_buffer *buffer)
{
if (!buffer)
return;
drm_client_buffer_rmfb(buffer);
drm_client_buffer_delete(buffer);
}
EXPORT_SYMBOL(drm_client_framebuffer_delete);
/**
* drm_client_framebuffer_flush - Manually flush client framebuffer
* @buffer: DRM client buffer (can be NULL)
* drm_client_buffer_flush - Manually flush client buffer
* @buffer: DRM client buffer
* @rect: Damage rectangle (if NULL flushes all)
*
* This calls &drm_framebuffer_funcs->dirty (if present) to flush buffer changes
@@ -451,7 +440,7 @@ EXPORT_SYMBOL(drm_client_framebuffer_delete);
* Returns:
* Zero on success or negative error code on failure.
*/
int drm_client_framebuffer_flush(struct drm_client_buffer *buffer, struct drm_rect *rect)
int drm_client_buffer_flush(struct drm_client_buffer *buffer, struct drm_rect *rect)
{
if (!buffer || !buffer->fb || !buffer->fb->funcs->dirty)
return 0;
@@ -471,4 +460,4 @@ int drm_client_framebuffer_flush(struct drm_client_buffer *buffer, struct drm_re
return buffer->fb->funcs->dirty(buffer->fb, buffer->client->file,
0, 0, NULL, 0);
}
EXPORT_SYMBOL(drm_client_framebuffer_flush);
EXPORT_SYMBOL(drm_client_buffer_flush);

View File

@@ -9,6 +9,34 @@
#include "drm_crtc_internal.h"
#include "drm_displayid_internal.h"
enum {
QUIRK_IGNORE_CHECKSUM,
};
struct displayid_quirk {
const struct drm_edid_ident ident;
u8 quirks;
};
static const struct displayid_quirk quirks[] = {
{
.ident = DRM_EDID_IDENT_INIT('C', 'S', 'O', 5142, "MNE007ZA1-5"),
.quirks = BIT(QUIRK_IGNORE_CHECKSUM),
},
};
static u8 get_quirks(const struct drm_edid *drm_edid)
{
int i;
for (i = 0; i < ARRAY_SIZE(quirks); i++) {
if (drm_edid_match(drm_edid, &quirks[i].ident))
return quirks[i].quirks;
}
return 0;
}
static const struct displayid_header *
displayid_get_header(const u8 *displayid, int length, int index)
{
@@ -23,7 +51,7 @@ displayid_get_header(const u8 *displayid, int length, int index)
}
static const struct displayid_header *
validate_displayid(const u8 *displayid, int length, int idx)
validate_displayid(const u8 *displayid, int length, int idx, bool ignore_checksum)
{
int i, dispid_length;
u8 csum = 0;
@@ -41,33 +69,35 @@ validate_displayid(const u8 *displayid, int length, int idx)
for (i = 0; i < dispid_length; i++)
csum += displayid[idx + i];
if (csum) {
DRM_NOTE("DisplayID checksum invalid, remainder is %d\n", csum);
return ERR_PTR(-EINVAL);
DRM_NOTE("DisplayID checksum invalid, remainder is %d%s\n", csum,
ignore_checksum ? " (ignoring)" : "");
if (!ignore_checksum)
return ERR_PTR(-EINVAL);
}
return base;
}
static const u8 *drm_find_displayid_extension(const struct drm_edid *drm_edid,
int *length, int *idx,
int *ext_index)
static const u8 *find_next_displayid_extension(struct displayid_iter *iter)
{
const struct displayid_header *base;
const u8 *displayid;
bool ignore_checksum = iter->quirks & BIT(QUIRK_IGNORE_CHECKSUM);
displayid = drm_edid_find_extension(drm_edid, DISPLAYID_EXT, ext_index);
displayid = drm_edid_find_extension(iter->drm_edid, DISPLAYID_EXT, &iter->ext_index);
if (!displayid)
return NULL;
/* EDID extensions block checksum isn't for us */
*length = EDID_LENGTH - 1;
*idx = 1;
iter->length = EDID_LENGTH - 1;
iter->idx = 1;
base = validate_displayid(displayid, *length, *idx);
base = validate_displayid(displayid, iter->length, iter->idx, ignore_checksum);
if (IS_ERR(base))
return NULL;
*length = *idx + sizeof(*base) + base->bytes;
iter->length = iter->idx + sizeof(*base) + base->bytes;
return displayid;
}
@@ -78,6 +108,7 @@ void displayid_iter_edid_begin(const struct drm_edid *drm_edid,
memset(iter, 0, sizeof(*iter));
iter->drm_edid = drm_edid;
iter->quirks = get_quirks(drm_edid);
}
static const struct displayid_block *
@@ -126,10 +157,7 @@ __displayid_iter_next(struct displayid_iter *iter)
/* The first section we encounter is the base section */
bool base_section = !iter->section;
iter->section = drm_find_displayid_extension(iter->drm_edid,
&iter->length,
&iter->idx,
&iter->ext_index);
iter->section = find_next_displayid_extension(iter);
if (!iter->section) {
iter->drm_edid = NULL;
return NULL;

View File

@@ -167,6 +167,8 @@ struct displayid_iter {
u8 version;
u8 primary_use;
u8 quirks;
};
void displayid_iter_edid_begin(const struct drm_edid *drm_edid,

View File

@@ -29,6 +29,7 @@
#include <drm/drm_fourcc.h>
#include <drm/drm_gem.h>
#include <drm/drm_mode.h>
#include <drm/drm_print.h>
#include "drm_crtc_internal.h"
#include "drm_internal.h"

View File

@@ -10,6 +10,7 @@
#include <drm/drm_fb_helper.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_print.h>
/*
* struct fb_ops
@@ -55,7 +56,7 @@ static void drm_fbdev_dma_fb_destroy(struct fb_info *info)
drm_fb_helper_fini(fb_helper);
drm_client_buffer_vunmap(fb_helper->buffer);
drm_client_framebuffer_delete(fb_helper->buffer);
drm_client_buffer_delete(fb_helper->buffer);
drm_client_release(&fb_helper->client);
}
@@ -88,7 +89,7 @@ static void drm_fbdev_dma_shadowed_fb_destroy(struct fb_info *info)
vfree(shadow);
drm_client_buffer_vunmap(fb_helper->buffer);
drm_client_framebuffer_delete(fb_helper->buffer);
drm_client_buffer_delete(fb_helper->buffer);
drm_client_release(&fb_helper->client);
}
@@ -281,7 +282,7 @@ int drm_fbdev_dma_driver_fbdev_probe(struct drm_fb_helper *fb_helper,
format = drm_driver_legacy_fb_format(dev, sizes->surface_bpp,
sizes->surface_depth);
buffer = drm_client_framebuffer_create(client, sizes->surface_width,
buffer = drm_client_buffer_create_dumb(client, sizes->surface_width,
sizes->surface_height, format);
if (IS_ERR(buffer))
return PTR_ERR(buffer);
@@ -324,7 +325,7 @@ int drm_fbdev_dma_driver_fbdev_probe(struct drm_fb_helper *fb_helper,
fb_helper->buffer = NULL;
drm_client_buffer_vunmap(buffer);
err_drm_client_buffer_delete:
drm_client_framebuffer_delete(buffer);
drm_client_buffer_delete(buffer);
return ret;
}
EXPORT_SYMBOL(drm_fbdev_dma_driver_fbdev_probe);

View File

@@ -9,6 +9,7 @@
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_gem_shmem_helper.h>
#include <drm/drm_print.h>
/*
* struct fb_ops
@@ -63,7 +64,7 @@ static void drm_fbdev_shmem_fb_destroy(struct fb_info *info)
drm_fb_helper_fini(fb_helper);
drm_client_buffer_vunmap(fb_helper->buffer);
drm_client_framebuffer_delete(fb_helper->buffer);
drm_client_buffer_delete(fb_helper->buffer);
drm_client_release(&fb_helper->client);
}
@@ -147,7 +148,7 @@ int drm_fbdev_shmem_driver_fbdev_probe(struct drm_fb_helper *fb_helper,
sizes->surface_bpp);
format = drm_driver_legacy_fb_format(dev, sizes->surface_bpp, sizes->surface_depth);
buffer = drm_client_framebuffer_create(client, sizes->surface_width,
buffer = drm_client_buffer_create_dumb(client, sizes->surface_width,
sizes->surface_height, format);
if (IS_ERR(buffer))
return PTR_ERR(buffer);
@@ -204,7 +205,7 @@ int drm_fbdev_shmem_driver_fbdev_probe(struct drm_fb_helper *fb_helper,
fb_helper->buffer = NULL;
drm_client_buffer_vunmap(buffer);
err_drm_client_buffer_delete:
drm_client_framebuffer_delete(buffer);
drm_client_buffer_delete(buffer);
return ret;
}
EXPORT_SYMBOL(drm_fbdev_shmem_driver_fbdev_probe);

View File

@@ -50,7 +50,7 @@ static void drm_fbdev_ttm_fb_destroy(struct fb_info *info)
fb_deferred_io_cleanup(info);
drm_fb_helper_fini(fb_helper);
vfree(shadow);
drm_client_framebuffer_delete(fb_helper->buffer);
drm_client_buffer_delete(fb_helper->buffer);
drm_client_release(&fb_helper->client);
}
@@ -187,7 +187,7 @@ int drm_fbdev_ttm_driver_fbdev_probe(struct drm_fb_helper *fb_helper,
format = drm_driver_legacy_fb_format(dev, sizes->surface_bpp,
sizes->surface_depth);
buffer = drm_client_framebuffer_create(client, sizes->surface_width,
buffer = drm_client_buffer_create_dumb(client, sizes->surface_width,
sizes->surface_height, format);
if (IS_ERR(buffer))
return PTR_ERR(buffer);
@@ -200,7 +200,7 @@ int drm_fbdev_ttm_driver_fbdev_probe(struct drm_fb_helper *fb_helper,
screen_buffer = vzalloc(screen_size);
if (!screen_buffer) {
ret = -ENOMEM;
goto err_drm_client_framebuffer_delete;
goto err_drm_client_buffer_delete;
}
info = drm_fb_helper_alloc_info(fb_helper);
@@ -233,10 +233,10 @@ int drm_fbdev_ttm_driver_fbdev_probe(struct drm_fb_helper *fb_helper,
drm_fb_helper_release_info(fb_helper);
err_vfree:
vfree(screen_buffer);
err_drm_client_framebuffer_delete:
err_drm_client_buffer_delete:
fb_helper->fb = NULL;
fb_helper->buffer = NULL;
drm_client_framebuffer_delete(buffer);
drm_client_buffer_delete(buffer);
return ret;
}
EXPORT_SYMBOL(drm_fbdev_ttm_driver_fbdev_probe);

View File

@@ -22,6 +22,7 @@
#include <drm/drm_drv.h>
#include <drm/drm_dumb_buffers.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_print.h>
#include <drm/drm_vma_manager.h>
/**

View File

@@ -16,6 +16,7 @@
#include <drm/drm_gem.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_modeset_helper.h>
#include <drm/drm_print.h>
#include "drm_internal.h"

View File

@@ -4,6 +4,7 @@
#include <linux/module.h>
#include <drm/drm_gem_ttm_helper.h>
#include <drm/drm_print.h>
#include <drm/ttm/ttm_placement.h>
#include <drm/ttm/ttm_tt.h>

View File

@@ -17,6 +17,7 @@
#include <drm/drm_mode.h>
#include <drm/drm_plane.h>
#include <drm/drm_prime.h>
#include <drm/drm_print.h>
#include <drm/ttm/ttm_range_manager.h>
#include <drm/ttm/ttm_tt.h>
@@ -859,7 +860,7 @@ static int drm_vram_mm_init(struct drm_vram_mm *vmm, struct drm_device *dev,
ret = ttm_device_init(&vmm->bdev, &bo_driver, dev->dev,
dev->anon_inode->i_mapping,
dev->vma_offset_manager,
false, true);
TTM_ALLOCATION_POOL_USE_DMA32);
if (ret)
return ret;

View File

@@ -26,6 +26,7 @@
*/
#include <drm/drm_gpuvm.h>
#include <drm/drm_print.h>
#include <linux/export.h>
#include <linux/interval_tree_generic.h>

View File

@@ -26,6 +26,7 @@
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_mipi_dbi.h>
#include <drm/drm_modes.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_rect.h>
#include <video/mipi_display.h>

View File

@@ -49,6 +49,7 @@
#include <linux/stacktrace.h>
#include <drm/drm_mm.h>
#include <drm/drm_print.h>
/**
* DOC: Overview

View File

@@ -37,6 +37,7 @@
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem.h>
#include <drm/drm_prime.h>
#include <drm/drm_print.h>
#include "drm_internal.h"

View File

@@ -4,6 +4,7 @@
*/
#include <drm/drm_drv.h>
#include <drm/drm_print.h>
#include "etnaviv_cmdbuf.h"
#include "etnaviv_gpu.h"

View File

@@ -17,6 +17,7 @@
#include <drm/drm_ioctl.h>
#include <drm/drm_of.h>
#include <drm/drm_prime.h>
#include <drm/drm_print.h>
#include "etnaviv_cmdbuf.h"
#include "etnaviv_drv.h"

View File

@@ -4,6 +4,7 @@
*/
#include <drm/drm_prime.h>
#include <drm/drm_print.h>
#include <linux/dma-mapping.h>
#include <linux/shmem_fs.h>
#include <linux/spinlock.h>

View File

@@ -4,6 +4,7 @@
*/
#include <drm/drm_file.h>
#include <drm/drm_print.h>
#include <linux/dma-fence-array.h>
#include <linux/file.h>
#include <linux/dma-resv.h>

View File

@@ -16,6 +16,8 @@
#include <linux/reset.h>
#include <linux/thermal.h>
#include <drm/drm_print.h>
#include "etnaviv_cmdbuf.h"
#include "etnaviv_dump.h"
#include "etnaviv_gpu.h"

View File

@@ -196,6 +196,38 @@ static const struct etnaviv_chip_identity etnaviv_chip_identities[] = {
.minor_features10 = 0x90044250,
.minor_features11 = 0x00000024,
},
{
.model = 0x8000,
.revision = 0x6205,
.product_id = 0x80003,
.customer_id = 0x15,
.eco_id = 0,
.stream_count = 16,
.register_max = 64,
.thread_count = 512,
.shader_core_count = 2,
.nn_core_count = 2,
.vertex_cache_size = 16,
.vertex_output_buffer_size = 1024,
.pixel_pipes = 1,
.instruction_count = 512,
.num_constants = 320,
.buffer_size = 0,
.varyings_count = 16,
.features = 0xe0287c8d,
.minor_features0 = 0xc1799eff,
.minor_features1 = 0xfefbfad9,
.minor_features2 = 0xeb9d4fbf,
.minor_features3 = 0xedfffced,
.minor_features4 = 0xdb0dafc7,
.minor_features5 = 0x7b5ac333,
.minor_features6 = 0xfcce6000,
.minor_features7 = 0x03fbfa6f,
.minor_features8 = 0x00ef0ef0,
.minor_features9 = 0x0eca703c,
.minor_features10 = 0x898048f0,
.minor_features11 = 0x00000034,
},
{
.model = 0x8000,
.revision = 0x7120,

View File

@@ -6,6 +6,8 @@
#include <linux/dma-mapping.h>
#include <linux/scatterlist.h>
#include <drm/drm_print.h>
#include "common.xml.h"
#include "etnaviv_cmdbuf.h"
#include "etnaviv_drv.h"

View File

@@ -20,6 +20,7 @@
#include <drm/drm_blend.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_print.h>
#include <drm/drm_vblank.h>
#include "exynos_drm_crtc.h"

View File

@@ -20,6 +20,7 @@
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_print.h>
#include <drm/drm_vblank.h>
#include <drm/exynos_drm.h>

View File

@@ -14,6 +14,7 @@
#include <drm/drm_framebuffer.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <drm/exynos_drm.h>

View File

@@ -16,6 +16,7 @@
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_prime.h>
#include <drm/drm_print.h>
#include <drm/exynos_drm.h>
#include "exynos_drm_drv.h"

View File

@@ -23,6 +23,7 @@
#include <drm/drm_blend.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_print.h>
#include <drm/drm_vblank.h>
#include <drm/exynos_drm.h>

View File

@@ -21,6 +21,7 @@
#include <linux/workqueue.h>
#include <drm/drm_file.h>
#include <drm/drm_print.h>
#include <drm/exynos_drm.h>
#include "exynos_drm_drv.h"

View File

@@ -12,6 +12,7 @@
#include <drm/drm_dumb_buffers.h>
#include <drm/drm_prime.h>
#include <drm/drm_print.h>
#include <drm/drm_vma_manager.h>
#include <drm/exynos_drm.h>

View File

@@ -22,6 +22,7 @@
#include <drm/drm_file.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_mode.h>
#include <drm/drm_print.h>
#include <drm/exynos_drm.h>
#include "exynos_drm_drv.h"

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