mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-12-27 13:30:45 -05:00
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:
@@ -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).
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 = <®_avdd>;
|
||||
avee-supply = <®_avee>;
|
||||
pp1800-supply = <®_pp1800>;
|
||||
backlight = <&backlight>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
@@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
@@ -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>;
|
||||
};
|
||||
|
||||
...
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
==================
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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, \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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__)
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
213
drivers/accel/ivpu/ivpu_gem_userptr.c
Normal file
213
drivers/accel/ivpu/ivpu_gem_userptr.c
Normal 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;
|
||||
}
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
/**
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
*/
|
||||
|
||||
#include <drm/drm_gpuvm.h>
|
||||
#include <drm/drm_print.h>
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/interval_tree_generic.h>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
#include <linux/stacktrace.h>
|
||||
|
||||
#include <drm/drm_mm.h>
|
||||
#include <drm/drm_print.h>
|
||||
|
||||
/**
|
||||
* DOC: Overview
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_print.h>
|
||||
|
||||
#include "etnaviv_cmdbuf.h"
|
||||
#include "etnaviv_gpu.h"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user