summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/accel/amdxdna/amdnpu.rst1
-rw-r--r--Documentation/devicetree/bindings/display/bridge/simple-bridge.yaml1
-rw-r--r--Documentation/devicetree/bindings/display/panel/novatek,nt51021.yaml87
-rw-r--r--Documentation/devicetree/bindings/display/panel/raydium,rm69220.yaml74
-rw-r--r--Documentation/devicetree/bindings/display/panel/visionox,vtdr6130.yaml8
-rw-r--r--Documentation/devicetree/bindings/display/ste,mcde.yaml5
-rw-r--r--MAINTAINERS13
-rw-r--r--drivers/accel/amdxdna/aie.c39
-rw-r--r--drivers/accel/amdxdna/aie.h4
-rw-r--r--drivers/accel/amdxdna/aie2_ctx.c6
-rw-r--r--drivers/accel/amdxdna/aie2_error.c9
-rw-r--r--drivers/accel/amdxdna/aie2_message.c18
-rw-r--r--drivers/accel/amdxdna/aie2_pci.c15
-rw-r--r--drivers/accel/amdxdna/aie2_pci.h2
-rw-r--r--drivers/accel/amdxdna/aie4_pci.c8
-rw-r--r--drivers/accel/amdxdna/amdxdna_error.h10
-rw-r--r--drivers/accel/amdxdna/amdxdna_gem.c5
-rw-r--r--drivers/accel/amdxdna/amdxdna_mailbox.c219
-rw-r--r--drivers/accel/amdxdna/amdxdna_mailbox.h9
-rw-r--r--drivers/accel/amdxdna/amdxdna_mailbox_helper.c2
-rw-r--r--drivers/accel/amdxdna/amdxdna_mailbox_helper.h1
-rw-r--r--drivers/accel/amdxdna/amdxdna_pci_drv.c6
-rw-r--r--drivers/accel/amdxdna/amdxdna_pci_drv.h9
-rw-r--r--drivers/accel/ivpu/ivpu_drv.c85
-rw-r--r--drivers/accel/ivpu/ivpu_drv.h67
-rw-r--r--drivers/accel/ivpu/ivpu_fw.c41
-rw-r--r--drivers/accel/ivpu/ivpu_fw.h3
-rw-r--r--drivers/accel/ivpu/ivpu_hw.c11
-rw-r--r--drivers/accel/ivpu/ivpu_hw.h8
-rw-r--r--drivers/accel/ivpu/ivpu_hw_40xx_reg.h195
-rw-r--r--drivers/accel/ivpu/ivpu_hw_btrs.c56
-rw-r--r--drivers/accel/ivpu/ivpu_hw_btrs.h3
-rw-r--r--drivers/accel/ivpu/ivpu_hw_btrs_mtl_reg.h83
-rw-r--r--drivers/accel/ivpu/ivpu_hw_btrs_reg.h (renamed from drivers/accel/ivpu/ivpu_hw_btrs_lnl_reg.h)84
-rw-r--r--drivers/accel/ivpu/ivpu_hw_ip.c480
-rw-r--r--drivers/accel/ivpu/ivpu_hw_ip.h3
-rw-r--r--drivers/accel/ivpu/ivpu_hw_ip_reg.h (renamed from drivers/accel/ivpu/ivpu_hw_37xx_reg.h)69
-rw-r--r--drivers/accel/ivpu/ivpu_pm.c1
-rw-r--r--drivers/accel/qaic/mhi_controller.c192
-rw-r--r--drivers/accel/qaic/qaic.h1
-rw-r--r--drivers/accel/qaic/qaic_data.c14
-rw-r--r--drivers/accel/qaic/qaic_drv.c47
-rw-r--r--drivers/accel/qaic/sahara.c1
-rw-r--r--drivers/accel/rocket/rocket_job.c28
-rw-r--r--drivers/dma-buf/st-dma-fence-unwrap.c10
-rw-r--r--drivers/gpu/buddy.c1
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_wb_connector.c2
-rw-r--r--drivers/gpu/drm/arm/malidp_mw.c18
-rw-r--r--drivers/gpu/drm/bridge/adv7511/adv7511_drv.c22
-rw-r--r--drivers/gpu/drm/bridge/inno-hdmi.c1
-rw-r--r--drivers/gpu/drm/bridge/ite-it6263.c33
-rw-r--r--drivers/gpu/drm/bridge/ite-it66121.c13
-rw-r--r--drivers/gpu/drm/bridge/lontium-lt8713sx.c1
-rw-r--r--drivers/gpu/drm/bridge/lontium-lt8912b.c2
-rw-r--r--drivers/gpu/drm/bridge/lontium-lt9611.c16
-rw-r--r--drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c2
-rw-r--r--drivers/gpu/drm/bridge/simple-bridge.c5
-rw-r--r--drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c159
-rw-r--r--drivers/gpu/drm/hyperv/hyperv_drm_modeset.c2
-rw-r--r--drivers/gpu/drm/imx/ipuv3/imx-tve.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_abi16.c2
-rw-r--r--drivers/gpu/drm/panel/Kconfig26
-rw-r--r--drivers/gpu/drm/panel/Makefile2
-rw-r--r--drivers/gpu/drm/panel/panel-edp.c4
-rw-r--r--drivers/gpu/drm/panel/panel-novatek-nt51021.c875
-rw-r--r--drivers/gpu/drm/panel/panel-raydium-rm69220.c417
-rw-r--r--drivers/gpu/drm/panel/panel-ronbo-rb070d30.c14
-rw-r--r--drivers/gpu/drm/panel/panel-simple.c3
-rw-r--r--drivers/gpu/drm/panel/panel-visionox-vtdr6130.c221
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_device.c247
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_device.h5
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_drv.c198
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_drv.h9
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_features.h2
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_gem.c64
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_gem.h10
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c9
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_gpu.c5
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_issues.h8
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_job.c103
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_job.h4
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_mmu.c14
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_perfcnt.c319
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_perfcnt.h1
-rw-r--r--drivers/gpu/drm/panthor/panthor_drv.c6
-rw-r--r--drivers/gpu/drm/panthor/panthor_gem.c3
-rw-r--r--drivers/gpu/drm/panthor/panthor_sched.c14
-rw-r--r--drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c205
-rw-r--r--drivers/gpu/drm/rockchip/rk3066_hdmi.c10
-rw-r--r--drivers/gpu/drm/scheduler/sched_main.c5
-rw-r--r--drivers/gpu/drm/solomon/ssd130x.c2
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c25
-rw-r--r--drivers/gpu/drm/sysfb/drm_sysfb_helper.h2
-rw-r--r--drivers/gpu/drm/tiny/appletbdrm.c50
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo_util.c11
-rw-r--r--drivers/gpu/drm/vc4/tests/vc4_mock_output.c2
-rw-r--r--drivers/gpu/drm/vc4/vc4_bo.c3
-rw-r--r--drivers/gpu/drm/vc4/vc4_drv.c28
-rw-r--r--drivers/gpu/drm/vc4/vc4_hvs.c10
-rw-r--r--drivers/gpu/drm/vc4/vc4_txp.c2
-rw-r--r--drivers/gpu/drm/vc4/vc4_v3d.c7
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_plane.c1
-rw-r--r--include/drm/bridge/dw_hdmi_qp.h4
-rw-r--r--include/drm/gpu_scheduler.h2
-rw-r--r--include/uapi/drm/drm_fourcc.h24
-rw-r--r--include/uapi/drm/panfrost_drm.h29
106 files changed, 3702 insertions, 1617 deletions
diff --git a/Documentation/accel/amdxdna/amdnpu.rst b/Documentation/accel/amdxdna/amdnpu.rst
index 064973bf4893..d72af1b51ccf 100644
--- a/Documentation/accel/amdxdna/amdnpu.rst
+++ b/Documentation/accel/amdxdna/amdnpu.rst
@@ -289,6 +289,7 @@ Example of the output showing the implemented key value pairs:
drm-driver: amdxdna_accel_driver
drm-client-id: 3219
drm-pdev: 0000:c5:00.1
+ drm-engine-npu: 14003870 ns
amdxdna_accel_driver-heap-alloc: 60 KiB
amdxdna_accel_driver-internal-alloc: 67588 KiB
amdxdna_accel_driver-external-alloc: 0
diff --git a/Documentation/devicetree/bindings/display/bridge/simple-bridge.yaml b/Documentation/devicetree/bindings/display/bridge/simple-bridge.yaml
index 7636c24906ba..9e0e7e09774e 100644
--- a/Documentation/devicetree/bindings/display/bridge/simple-bridge.yaml
+++ b/Documentation/devicetree/bindings/display/bridge/simple-bridge.yaml
@@ -29,6 +29,7 @@ properties:
- adi,adv7123
- algoltek,ag6311
- asl-tek,cs5263
+ - chrontel,ch7218a
- dumb-vga-dac
- mstar,tsumu88adt3-lf-1
- parade,ps185hdm
diff --git a/Documentation/devicetree/bindings/display/panel/novatek,nt51021.yaml b/Documentation/devicetree/bindings/display/panel/novatek,nt51021.yaml
new file mode 100644
index 000000000000..7754a8cb1e5c
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/novatek,nt51021.yaml
@@ -0,0 +1,87 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/panel/novatek,nt51021.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Novatek NT51021 based DSI display Panels
+
+maintainers:
+ - Nickolay Goppen <setotau@mainlining.org>
+
+description:
+ The NT51021 IC from Novatek is a generic DSI Panel IC used to drive dsi
+ panels.
+ Right now, support is added only for a BOE WUXGA LCD display panels with a
+ resolution of 1200x1920. They are video mode DSI panels.
+
+allOf:
+ - $ref: panel-common.yaml#
+
+properties:
+ compatible:
+ items:
+ - enum:
+ - boe,tv101wum-nm0
+ - boe,tv101wum-nx0
+ - boe,tv080wum-nx2
+ - const: novatek,nt51021
+
+ reg:
+ maxItems: 1
+
+ reset-gpios:
+ maxItems: 1
+ description: phandle of gpio for reset line - This should be 8mA, gpio
+ can be configured using mux, pinctrl, pinctrl-names (active low)
+
+ vdd-supply:
+ description: phandle of the regulator that provides the supply voltage
+ for digital circuits
+
+ avdd-supply:
+ description: phandle of the regulator that provides the supply voltage
+ for analog circuits
+
+ havdd-supply:
+ description: phandle of the regulator that provides the supply voltage
+ for analog circuits
+
+required:
+ - compatible
+ - reg
+ - vdd-supply
+ - avdd-supply
+ - havdd-supply
+ - reset-gpios
+ - port
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ dsi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ panel@0 {
+ compatible = "boe,tv101wum-nx0", "novatek,nt51021";
+ reg = <0>;
+ vdd-supply = <&lcd_pwr>;
+ avdd-supply = <&lcd_pwr>;
+ havdd-supply = <&lcd_pwr>;
+
+ backlight = <&i2c_backlight>;
+ reset-gpios = <&tlmm 62 GPIO_ACTIVE_LOW>;
+
+ port {
+ panel_in: endpoint {
+ remote-endpoint = <&dsi0_out>;
+ };
+ };
+ };
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/display/panel/raydium,rm69220.yaml b/Documentation/devicetree/bindings/display/panel/raydium,rm69220.yaml
new file mode 100644
index 000000000000..3c94db88f797
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/raydium,rm69220.yaml
@@ -0,0 +1,74 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/panel/raydium,rm69220.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Raydium RM69220 based MIPI-DSI panels
+
+maintainers:
+ - Alexander Koskovich <akoskovich@pm.me>
+
+description:
+ The Raydium RM69220 is a generic DSI Panel IC used to control
+ AMOLED panels.
+
+allOf:
+ - $ref: panel-common.yaml#
+
+properties:
+ compatible:
+ items:
+ - enum:
+ - boe,bf068mwm-td0
+ - const: raydium,rm69220
+
+ reg:
+ maxItems: 1
+
+ dvdd-supply:
+ description: Digital voltage rail
+
+ vci-supply:
+ description: Analog voltage rail
+
+ vddio-supply:
+ description: I/O voltage rail
+
+required:
+ - compatible
+ - reg
+ - dvdd-supply
+ - vci-supply
+ - vddio-supply
+ - reset-gpios
+ - port
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ dsi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ panel@0 {
+ compatible = "boe,bf068mwm-td0", "raydium,rm69220";
+ reg = <0>;
+
+ reset-gpios = <&tlmm 12 GPIO_ACTIVE_LOW>;
+ dvdd-supply = <&vreg_oled_dvdd_1p8>;
+ vci-supply = <&vreg_l19b>;
+ vddio-supply = <&vreg_l9b>;
+
+ port {
+ panel_in_0: endpoint {
+ remote-endpoint = <&dsi0_out>;
+ };
+ };
+ };
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/display/panel/visionox,vtdr6130.yaml b/Documentation/devicetree/bindings/display/panel/visionox,vtdr6130.yaml
index c99f4146f1bb..682f30dc9ee4 100644
--- a/Documentation/devicetree/bindings/display/panel/visionox,vtdr6130.yaml
+++ b/Documentation/devicetree/bindings/display/panel/visionox,vtdr6130.yaml
@@ -14,7 +14,11 @@ allOf:
properties:
compatible:
- const: visionox,vtdr6130
+ oneOf:
+ - const: visionox,vtdr6130
+ - items:
+ - const: retroidpocket,rp6-panel
+ - const: visionox,vtdr6130
reg:
maxItems: 1
@@ -25,13 +29,13 @@ properties:
vdd-supply: true
port: true
reset-gpios: true
+ rotation: true
required:
- compatible
- reg
- vddio-supply
- vci-supply
- - vdd-supply
- reset-gpios
- port
diff --git a/Documentation/devicetree/bindings/display/ste,mcde.yaml b/Documentation/devicetree/bindings/display/ste,mcde.yaml
index 7a12d0b817e6..05e7e4ebc882 100644
--- a/Documentation/devicetree/bindings/display/ste,mcde.yaml
+++ b/Documentation/devicetree/bindings/display/ste,mcde.yaml
@@ -35,6 +35,9 @@ properties:
resets:
maxItems: 1
+ power-domains:
+ maxItems: 1
+
epod-supply:
description: a phandle to the EPOD regulator
@@ -109,6 +112,7 @@ examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/arm/ux500_pm_domains.h>
#include <dt-bindings/mfd/dbx500-prcmu.h>
#include <dt-bindings/gpio/gpio.h>
@@ -116,6 +120,7 @@ examples:
compatible = "ste,mcde";
reg = <0xa0350000 0x1000>;
interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
+ power-domains = <&pm_domains DOMAIN_B2R2_MCDE>;
epod-supply = <&db8500_b2r2_mcde_reg>;
vana-supply = <&ab8500_ldo_ana_reg>;
clocks = <&prcmu_clk PRCMU_MCDECLK>,
diff --git a/MAINTAINERS b/MAINTAINERS
index 4c8ed64144fd..84b684425bbc 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8368,6 +8368,13 @@ S: Maintained
F: Documentation/devicetree/bindings/display/panel/novatek,nt37801.yaml
F: drivers/gpu/drm/panel/panel-novatek-nt37801.c
+DRM DRIVER FOR NOVATEK NT51021 PANELS
+M: Ryan Brue <ryanbrue.dev@gmail.com>
+M: Nickolay Goppen <setotau@mainlining.org>
+S: Maintained
+F: Documentation/devicetree/bindings/display/panel/novatek,nt51021.yaml
+F: drivers/gpu/drm/panel/panel-novatek-nt51021.c
+
DRM DRIVER FOR NVIDIA GEFORCE/QUADRO GPUS
M: Lyude Paul <lyude@redhat.com>
M: Danilo Krummrich <dakr@kernel.org>
@@ -8457,6 +8464,12 @@ S: Maintained
F: Documentation/devicetree/bindings/display/panel/raydium,rm67191.yaml
F: drivers/gpu/drm/panel/panel-raydium-rm67191.c
+DRM DRIVER FOR RAYDIUM RM69220 PANELS
+M: Alexander Koskovich <akoskovich@pm.me>
+S: Maintained
+F: Documentation/devicetree/bindings/display/panel/raydium,rm69220.yaml
+F: drivers/gpu/drm/panel/panel-raydium-rm69220.c
+
DRM DRIVER FOR SAMSUNG DB7430 PANELS
M: Linus Walleij <linusw@kernel.org>
S: Maintained
diff --git a/drivers/accel/amdxdna/aie.c b/drivers/accel/amdxdna/aie.c
index dd6f36f222c7..bf8eb66baab8 100644
--- a/drivers/accel/amdxdna/aie.c
+++ b/drivers/accel/amdxdna/aie.c
@@ -118,6 +118,45 @@ void amdxdna_vbnv_init(struct amdxdna_dev *xdna)
amdxdna_update_vbnv(xdna, info->rev_vbnv_tbl, rev);
}
+void amdxdna_io_stats_job_start(struct amdxdna_client *client)
+{
+ int depth;
+
+ guard(spinlock)(&client->io_stats.lock);
+
+ depth = client->io_stats.job_depth++;
+ if (!depth)
+ client->io_stats.start_time = ktime_get_ns();
+}
+
+void amdxdna_io_stats_job_done(struct amdxdna_client *client)
+{
+ u64 busy_ns;
+ int depth;
+
+ guard(spinlock)(&client->io_stats.lock);
+
+ depth = --client->io_stats.job_depth;
+ if (!depth) {
+ busy_ns = ktime_get_ns() - client->io_stats.start_time;
+ client->io_stats.start_time = 0;
+ client->io_stats.busy_time += busy_ns;
+ }
+}
+
+u64 amdxdna_io_stats_busy_time_ns(struct amdxdna_client *client)
+{
+ u64 busy_ns;
+
+ guard(spinlock)(&client->io_stats.lock);
+
+ busy_ns = client->io_stats.busy_time;
+ if (client->io_stats.job_depth)
+ busy_ns += ktime_get_ns() - client->io_stats.start_time;
+
+ return busy_ns;
+}
+
int amdxdna_get_metadata(struct aie_device *aie,
struct amdxdna_client *client,
struct amdxdna_drm_get_info *args)
diff --git a/drivers/accel/amdxdna/aie.h b/drivers/accel/amdxdna/aie.h
index 0483d582b7f8..1fc5ddfe696a 100644
--- a/drivers/accel/amdxdna/aie.h
+++ b/drivers/accel/amdxdna/aie.h
@@ -117,4 +117,8 @@ void aie_smu_fini(struct smu_device *smu);
int aie_smu_set_clocks(struct smu_device *smu, u32 *npuclk, u32 *hclk);
int aie_smu_set_dpm(struct smu_device *smu, u32 dpm_level);
+void amdxdna_io_stats_job_start(struct amdxdna_client *client);
+void amdxdna_io_stats_job_done(struct amdxdna_client *client);
+u64 amdxdna_io_stats_busy_time_ns(struct amdxdna_client *client);
+
#endif /* _AIE_H_ */
diff --git a/drivers/accel/amdxdna/aie2_ctx.c b/drivers/accel/amdxdna/aie2_ctx.c
index d927c8c9d557..9c6b7353cbe9 100644
--- a/drivers/accel/amdxdna/aie2_ctx.c
+++ b/drivers/accel/amdxdna/aie2_ctx.c
@@ -290,6 +290,7 @@ aie2_sched_resp_handler(void *handle, void __iomem *data, size_t size)
int ret = 0;
u32 status;
+ amdxdna_io_stats_job_done(job->hwctx->client);
cmd_abo = job->cmd_bo;
if (unlikely(job->job_timeout)) {
@@ -322,6 +323,8 @@ aie2_sched_drvcmd_resp_handler(void *handle, void __iomem *data, size_t size)
struct amdxdna_sched_job *job = handle;
int ret = 0;
+ amdxdna_io_stats_job_done(job->hwctx->client);
+
if (unlikely(!data || size != sizeof(u32))) {
job->drv_cmd->result = U32_MAX;
ret = -EINVAL;
@@ -344,6 +347,7 @@ aie2_sched_cmdlist_resp_handler(void *handle, void __iomem *data, size_t size)
u32 cmd_status;
int ret = 0;
+ amdxdna_io_stats_job_done(job->hwctx->client);
cmd_abo = job->cmd_bo;
if (unlikely(job->job_timeout)) {
@@ -405,6 +409,7 @@ aie2_sched_job_run(struct drm_sched_job *sched_job)
kref_get(&job->refcnt);
fence = dma_fence_get(job->fence);
+ amdxdna_io_stats_job_start(job->hwctx->client);
if (job->drv_cmd) {
switch (job->drv_cmd->opcode) {
case SYNC_DEBUG_BO:
@@ -432,6 +437,7 @@ aie2_sched_job_run(struct drm_sched_job *sched_job)
out:
if (ret) {
+ amdxdna_io_stats_job_done(job->hwctx->client);
dma_fence_put(job->fence);
aie2_job_put(job);
mmput(job->mm);
diff --git a/drivers/accel/amdxdna/aie2_error.c b/drivers/accel/amdxdna/aie2_error.c
index babdac0157ab..8516574e33eb 100644
--- a/drivers/accel/amdxdna/aie2_error.c
+++ b/drivers/accel/amdxdna/aie2_error.c
@@ -343,15 +343,14 @@ void aie2_error_async_events_free(struct amdxdna_dev_hdl *ndev)
kfree(events);
}
-int aie2_error_async_events_alloc(struct amdxdna_dev_hdl *ndev)
+int aie2_error_async_events_alloc(struct amdxdna_dev_hdl *ndev, u32 num_events)
{
struct amdxdna_dev *xdna = ndev->aie.xdna;
- u32 total_col = ndev->total_col;
- u32 total_size = ASYNC_BUF_SIZE * total_col;
+ u32 total_size = ASYNC_BUF_SIZE * num_events;
struct async_events *events;
int i, ret;
- events = kzalloc_flex(*events, event, total_col);
+ events = kzalloc_flex(*events, event, num_events);
if (!events)
return -ENOMEM;
@@ -361,7 +360,7 @@ int aie2_error_async_events_alloc(struct amdxdna_dev_hdl *ndev)
goto free_events;
}
events->size = total_size;
- events->event_cnt = total_col;
+ events->event_cnt = num_events;
events->wq = alloc_ordered_workqueue("async_wq", 0);
if (!events->wq) {
diff --git a/drivers/accel/amdxdna/aie2_message.c b/drivers/accel/amdxdna/aie2_message.c
index f658760c3d48..56b919b350ac 100644
--- a/drivers/accel/amdxdna/aie2_message.c
+++ b/drivers/accel/amdxdna/aie2_message.c
@@ -261,8 +261,9 @@ int aie2_create_context(struct amdxdna_dev_hdl *ndev, struct amdxdna_hwctx *hwct
goto del_ctx_req;
}
+ /* +1 for the config_cu message that can be in-flight concurrently */
ret = xdna_mailbox_start_channel(hwctx->priv->mbox_chann, &x2i, &i2x,
- intr_reg, ret);
+ intr_reg, ret, HWCTX_MAX_CMDS + 1);
if (ret) {
XDNA_ERR(xdna, "Not able to create channel");
ret = -EINVAL;
@@ -486,7 +487,7 @@ int aie2_register_asyn_event_msg(struct amdxdna_dev_hdl *ndev, dma_addr_t addr,
req.buf_size = size;
XDNA_DBG(ndev->aie.xdna, "Register addr 0x%llx size 0x%x", addr, size);
- return xdna_mailbox_send_msg(ndev->aie.mgmt_chann, &msg, TX_TIMEOUT);
+ return xdna_mailbox_send_msg(ndev->aie.mgmt_chann, &msg);
}
int aie2_config_cu(struct amdxdna_hwctx *hwctx,
@@ -545,7 +546,8 @@ int aie2_config_cu(struct amdxdna_hwctx *hwctx,
msg.handle = hwctx;
msg.opcode = MSG_OP_CONFIG_CU;
msg.notify_cb = notify_cb;
- return xdna_mailbox_send_msg(chann, &msg, TX_TIMEOUT);
+
+ return xdna_mailbox_send_msg(chann, &msg);
}
static int aie2_init_exec_cu_req(struct amdxdna_gem_obj *cmd_bo, void *req,
@@ -950,7 +952,7 @@ int aie2_execbuf(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job *job,
print_hex_dump_debug("cmd: ", DUMP_PREFIX_OFFSET, 16, 4, &req,
0x40, false);
- ret = xdna_mailbox_send_msg(chann, &msg, TX_TIMEOUT);
+ ret = xdna_mailbox_send_msg(chann, &msg);
if (ret) {
XDNA_ERR(xdna, "Send message failed");
return ret;
@@ -1039,7 +1041,7 @@ int aie2_cmdlist_multi_execbuf(struct amdxdna_hwctx *hwctx,
msg.send_size = sizeof(req);
print_hex_dump_debug("cmdlist msg: ", DUMP_PREFIX_OFFSET, 16, 4,
&req, msg.send_size, false);
- ret = xdna_mailbox_send_msg(chann, &msg, TX_TIMEOUT);
+ ret = xdna_mailbox_send_msg(chann, &msg);
if (ret) {
XDNA_ERR(xdna, "Send message failed");
return ret;
@@ -1086,7 +1088,7 @@ int aie2_cmdlist_single_execbuf(struct amdxdna_hwctx *hwctx,
msg.send_size = sizeof(req);
print_hex_dump_debug("cmdlist msg: ", DUMP_PREFIX_OFFSET, 16, 4,
&req, msg.send_size, false);
- ret = xdna_mailbox_send_msg(chann, &msg, TX_TIMEOUT);
+ ret = xdna_mailbox_send_msg(chann, &msg);
if (ret) {
XDNA_ERR(hwctx->client->xdna, "Send message failed");
return ret;
@@ -1122,7 +1124,7 @@ int aie2_sync_bo(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job *job,
msg.send_size = sizeof(req);
msg.opcode = MSG_OP_SYNC_BO;
- ret = xdna_mailbox_send_msg(chann, &msg, TX_TIMEOUT);
+ ret = xdna_mailbox_send_msg(chann, &msg);
if (ret) {
XDNA_ERR(xdna, "Send message failed");
return ret;
@@ -1157,7 +1159,7 @@ int aie2_config_debug_bo(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job *
msg.send_size = sizeof(req);
msg.opcode = MSG_OP_CONFIG_DEBUG_BO;
- return xdna_mailbox_send_msg(chann, &msg, TX_TIMEOUT);
+ return xdna_mailbox_send_msg(chann, &msg);
}
int aie2_query_app_health(struct amdxdna_dev_hdl *ndev, u32 context_id,
diff --git a/drivers/accel/amdxdna/aie2_pci.c b/drivers/accel/amdxdna/aie2_pci.c
index 7a4314ca843b..d2fa46e4d3a4 100644
--- a/drivers/accel/amdxdna/aie2_pci.c
+++ b/drivers/accel/amdxdna/aie2_pci.c
@@ -24,6 +24,7 @@
#include "aie2_pci.h"
#include "aie2_solver.h"
#include "amdxdna_ctx.h"
+#include "amdxdna_error.h"
#include "amdxdna_gem.h"
#include "amdxdna_mailbox.h"
#include "amdxdna_pci_drv.h"
@@ -385,11 +386,21 @@ static int aie2_hw_start(struct amdxdna_dev *xdna)
}
xdna_mailbox_intr_reg = ndev->aie.mgmt_i2x.mb_head_ptr_reg + 4;
+ /*
+ * At most AMDXDNA_MAX_ASYNC_EVENT_BUFS async event messages plus one
+ * management command can be unresponded. The async slots stay busy
+ * until firmware reports an error. Every management command holds
+ * dev_lock across aie_send_mgmt_msg_wait(), and the response clears
+ * the slot before that wait returns, so a second ioctl blocks on
+ * dev_lock rather than observing -ENOBUFS. Async re-registration
+ * takes the same lock after the RX path has freed its slot.
+ */
ret = xdna_mailbox_start_channel(ndev->aie.mgmt_chann,
&ndev->aie.mgmt_x2i,
&ndev->aie.mgmt_i2x,
xdna_mailbox_intr_reg,
- mgmt_mb_irq);
+ mgmt_mb_irq,
+ AMDXDNA_MAX_ASYNC_EVENT_BUFS + 1);
if (ret) {
XDNA_ERR(xdna, "failed to start management mailbox channel");
ret = -EINVAL;
@@ -414,7 +425,7 @@ static int aie2_hw_start(struct amdxdna_dev *xdna)
goto stop_fw;
}
- ret = aie2_error_async_events_alloc(ndev);
+ ret = aie2_error_async_events_alloc(ndev, AMDXDNA_MAX_ASYNC_EVENT_BUFS);
if (ret) {
XDNA_ERR(xdna, "Allocate async events failed, ret %d", ret);
goto stop_fw;
diff --git a/drivers/accel/amdxdna/aie2_pci.h b/drivers/accel/amdxdna/aie2_pci.h
index 2c7019bd26b5..a5fd71329b93 100644
--- a/drivers/accel/amdxdna/aie2_pci.h
+++ b/drivers/accel/amdxdna/aie2_pci.h
@@ -244,7 +244,7 @@ int aie2_pm_set_mode(struct amdxdna_dev_hdl *ndev, enum amdxdna_power_mode_type
int aie2_pm_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level);
/* aie2_error.c */
-int aie2_error_async_events_alloc(struct amdxdna_dev_hdl *ndev);
+int aie2_error_async_events_alloc(struct amdxdna_dev_hdl *ndev, u32 num_events);
void aie2_error_async_events_free(struct amdxdna_dev_hdl *ndev);
int aie2_error_async_msg_thread(void *data);
int aie2_get_array_async_error(struct amdxdna_dev_hdl *ndev,
diff --git a/drivers/accel/amdxdna/aie4_pci.c b/drivers/accel/amdxdna/aie4_pci.c
index a58a83af42a4..e99ad35870ef 100644
--- a/drivers/accel/amdxdna/aie4_pci.c
+++ b/drivers/accel/amdxdna/aie4_pci.c
@@ -12,6 +12,7 @@
#include "aie.h"
#include "aie4_msg_priv.h"
#include "aie4_pci.h"
+#include "amdxdna_error.h"
#include "amdxdna_mailbox.h"
#include "amdxdna_mailbox_helper.h"
#include "amdxdna_pci_drv.h"
@@ -181,11 +182,16 @@ static int aie4_mailbox_start(struct amdxdna_dev *xdna,
goto free_channel;
}
+ /*
+ * At any given time, at most AMDXDNA_MAX_ASYNC_EVENT_BUFS async event
+ * messages plus 1 other management command can be unresponded.
+ */
ret = xdna_mailbox_start_channel(ndev->aie.mgmt_chann,
&ndev->aie.mgmt_x2i,
&ndev->aie.mgmt_i2x,
NO_IOHUB,
- mgmt_mb_irq);
+ mgmt_mb_irq,
+ AMDXDNA_MAX_ASYNC_EVENT_BUFS + 1);
if (ret) {
XDNA_ERR(xdna, "failed to start management mailbox channel");
ret = -EINVAL;
diff --git a/drivers/accel/amdxdna/amdxdna_error.h b/drivers/accel/amdxdna/amdxdna_error.h
index c51de86ec12b..326d7153b17d 100644
--- a/drivers/accel/amdxdna/amdxdna_error.h
+++ b/drivers/accel/amdxdna/amdxdna_error.h
@@ -56,4 +56,14 @@ enum amdxdna_error_module {
(FIELD_PREP(AMDXDNA_EXTRA_ERR_COL_MASK, col) | \
FIELD_PREP(AMDXDNA_EXTRA_ERR_ROW_MASK, row))
+/*
+ * Maximum number of async event buffers. This value is used in two places:
+ * (1) to size the management mailbox channel, which must happen before
+ * total_col is known from firmware; (2) to allocate the async event pool,
+ * which runs after total_col is known. Both counts must match. The channel
+ * is sized AMDXDNA_MAX_ASYNC_EVENT_BUFS + 1 (one extra for other management
+ * commands), so the pool cannot exceed AMDXDNA_MAX_ASYNC_EVENT_BUFS slots.
+ */
+#define AMDXDNA_MAX_ASYNC_EVENT_BUFS 4
+
#endif /* _AMDXDNA_ERROR_H_ */
diff --git a/drivers/accel/amdxdna/amdxdna_gem.c b/drivers/accel/amdxdna/amdxdna_gem.c
index f4832337ec31..f14484bc31ec 100644
--- a/drivers/accel/amdxdna/amdxdna_gem.c
+++ b/drivers/accel/amdxdna/amdxdna_gem.c
@@ -1140,6 +1140,11 @@ amdxdna_drm_create_dev_heap_bo(struct drm_device *dev,
struct amdxdna_gem_obj *abo;
int ret;
+ if (!xdna->dev_info->dev_mem_size) {
+ XDNA_DBG(xdna, "Device heap is not supported");
+ return ERR_PTR(-EOPNOTSUPP);
+ }
+
WARN_ON(!is_power_of_2(xdna->dev_info->dev_mem_size));
XDNA_DBG(xdna, "Requested dev heap size 0x%llx", args->size);
if (!args->size || !IS_ALIGNED(args->size, xdna->dev_info->dev_mem_size)) {
diff --git a/drivers/accel/amdxdna/amdxdna_mailbox.c b/drivers/accel/amdxdna/amdxdna_mailbox.c
index 05c3786de135..c4701b2703d7 100644
--- a/drivers/accel/amdxdna/amdxdna_mailbox.c
+++ b/drivers/accel/amdxdna/amdxdna_mailbox.c
@@ -9,7 +9,6 @@
#include <linux/interrupt.h>
#include <linux/iopoll.h>
#include <linux/slab.h>
-#include <linux/xarray.h>
#define CREATE_TRACE_POINTS
#include <trace/events/amdxdna.h>
@@ -35,9 +34,12 @@
(_chann)->msix_irq, ##args); \
})
+#define MSG_BUF_SZ(chann) \
+ (mailbox_get_ringbuf_size(chann, CHAN_RES_X2I) + \
+ sizeof(struct mailbox_msg))
+
#define MAGIC_VAL 0x1D000000U
#define MAGIC_VAL_MASK 0xFF000000
-#define MAX_MSG_ID_ENTRIES 256
#define MSG_RX_TIMER 200 /* milliseconds */
#define MAILBOX_NAME "xdna_mailbox"
@@ -57,8 +59,6 @@ struct mailbox_channel {
struct xdna_mailbox_chann_res res[CHAN_RES_NUM];
int msix_irq;
u32 iohub_int_addr;
- struct xarray chan_xa;
- u32 next_msgid;
u32 x2i_tail;
/* Received msg related fields */
@@ -66,6 +66,12 @@ struct mailbox_channel {
struct work_struct rx_work;
u32 i2x_head;
bool bad_state;
+
+ /* Pre-allocated message buffer pool */
+ void *msg_buf;
+ u32 msg_buf_num;
+ u32 next_slot; /* next slot index to try for allocation */
+ struct mutex lock;
};
#define MSG_BODY_SZ GENMASK(10, 0)
@@ -90,12 +96,36 @@ struct mailbox_pkg {
#define TOMBSTONE 0xDEADFACE
struct mailbox_msg {
+ bool busy;
void *handle;
int (*notify_cb)(void *handle, void __iomem *data, size_t size);
size_t pkg_size; /* package size in bytes */
struct mailbox_pkg pkg;
};
+/*
+ * Clear busy before invoking the callback so that a new submission can
+ * reuse the slot immediately - by the time notify_cb returns, the caller
+ * may already have submitted a new job that needs this slot.
+ *
+ * notify_cb and handle are cached in locals first. smp_store_release()
+ * ensures those loads complete before busy is cleared - without it the
+ * compiler or CPU could sink the loads past the store, letting a
+ * concurrent sender overwrite notify_cb/handle before we read them.
+ * Paired with smp_load_acquire() in mailbox_acquire_msgid().
+ */
+static int mailbox_msg_done(struct mailbox_msg *mb_msg, void __iomem *data, size_t size)
+{
+ int (*notify_cb)(void *, void __iomem *, size_t) = mb_msg->notify_cb;
+ void *handle = mb_msg->handle;
+
+ /* Pairs with smp_load_acquire() in mailbox_acquire_msgid(). */
+ smp_store_release(&mb_msg->busy, false);
+ if (notify_cb)
+ return notify_cb(handle, data, size);
+ return 0;
+}
+
static void mailbox_reg_write(struct mailbox_channel *mb_chann, u32 mbox_reg, u32 data)
{
struct xdna_mailbox_res *mb_res = &mb_chann->mb->res;
@@ -161,38 +191,57 @@ static inline int mailbox_validate_msgid(int msg_id)
return (msg_id & MAGIC_VAL_MASK) == MAGIC_VAL;
}
-static int mailbox_acquire_msgid(struct mailbox_channel *mb_chann, struct mailbox_msg *mb_msg)
+static struct mailbox_msg *mailbox_msg_ptr(struct mailbox_channel *mb_chann, u32 slot)
{
- u32 msg_id;
- int ret;
+ return mb_chann->msg_buf + slot * MSG_BUF_SZ(mb_chann);
+}
- ret = xa_alloc_cyclic_irq(&mb_chann->chan_xa, &msg_id, mb_msg,
- XA_LIMIT(0, MAX_MSG_ID_ENTRIES - 1),
- &mb_chann->next_msgid, GFP_NOWAIT);
- if (ret < 0)
- return ret;
+static int mailbox_acquire_msgid(struct mailbox_channel *mb_chann)
+{
+ struct mailbox_msg *mb_msg;
+ u32 slot;
+ u32 i;
/*
- * Add MAGIC_VAL to the higher bits.
+ * msg_id = slot | MAGIC_VAL. Scan slots starting from next_slot.
+ * smp_load_acquire() pairs with smp_store_release() in mailbox_msg_done()
+ * to ensure that once we observe busy == false, notify_cb and handle are
+ * also visible as their post-completion values before we overwrite them.
*/
- msg_id |= MAGIC_VAL;
- return msg_id;
-}
+ for (i = 0; i < mb_chann->msg_buf_num; i++) {
+ slot = (mb_chann->next_slot + i) % mb_chann->msg_buf_num;
+ mb_msg = mailbox_msg_ptr(mb_chann, slot);
+ /* Pairs with smp_store_release() in mailbox_msg_done(). */
+ if (!smp_load_acquire(&mb_msg->busy)) {
+ mb_chann->next_slot = (slot + 1) % mb_chann->msg_buf_num;
+ return slot | MAGIC_VAL;
+ }
+ }
-static void mailbox_release_msgid(struct mailbox_channel *mb_chann, int msg_id)
-{
- msg_id &= ~MAGIC_VAL_MASK;
- xa_erase_irq(&mb_chann->chan_xa, msg_id);
+ return -ENOBUFS;
}
-static void mailbox_release_msg(struct mailbox_channel *mb_chann,
- struct mailbox_msg *mb_msg)
+static struct mailbox_msg *mailbox_get_msg_buf(struct mailbox_channel *mb_chann,
+ size_t msg_size)
{
- MB_DBG(mb_chann, "msg_id 0x%x msg opcode 0x%x",
- mb_msg->pkg.header.id, mb_msg->pkg.header.opcode);
- if (mb_msg->notify_cb)
- mb_msg->notify_cb(mb_msg->handle, NULL, 0);
- kfree(mb_msg);
+ struct mailbox_msg *mb_msg;
+ int msg_id;
+ u32 slot;
+
+ /* msg_id = slot | MAGIC_VAL */
+ msg_id = mailbox_acquire_msgid(mb_chann);
+ if (msg_id < 0) {
+ MB_ERR(mb_chann, "No free message slot");
+ return NULL;
+ }
+
+ slot = msg_id & ~MAGIC_VAL_MASK;
+ mb_msg = mailbox_msg_ptr(mb_chann, slot);
+ memset(mb_msg, 0, msg_size + sizeof(*mb_msg));
+ mb_msg->busy = true;
+ mb_msg->pkg.header.id = msg_id;
+
+ return mb_msg;
}
static int
@@ -224,7 +273,7 @@ check_again:
if (tail < head && tmp_tail >= head) {
ret = read_poll_timeout(mailbox_get_headptr, head,
tmp_tail < head || tail >= head,
- 1, 100, false, mb_chann, CHAN_RES_X2I);
+ 1, 2000000, false, mb_chann, CHAN_RES_X2I);
if (ret)
return ret;
@@ -248,8 +297,9 @@ mailbox_get_resp(struct mailbox_channel *mb_chann, struct xdna_msg_header *heade
void __iomem *data)
{
struct mailbox_msg *mb_msg;
- int msg_id;
int ret = 0;
+ int msg_id;
+ u32 slot;
msg_id = header->id;
if (!mailbox_validate_msgid(msg_id)) {
@@ -257,22 +307,32 @@ mailbox_get_resp(struct mailbox_channel *mb_chann, struct xdna_msg_header *heade
return -EINVAL;
}
- msg_id &= ~MAGIC_VAL_MASK;
- mb_msg = xa_erase_irq(&mb_chann->chan_xa, msg_id);
- if (!mb_msg) {
- MB_ERR(mb_chann, "Cannot find msg 0x%x", msg_id);
+ slot = msg_id & ~MAGIC_VAL_MASK;
+ if (unlikely(slot >= mb_chann->msg_buf_num)) {
+ MB_ERR(mb_chann, "Invalid msg_id 0x%x", msg_id);
return -EINVAL;
}
+ mb_msg = mailbox_msg_ptr(mb_chann, slot);
MB_DBG(mb_chann, "opcode 0x%x size %d id 0x%x",
header->opcode, header->total_size, header->id);
- if (mb_msg->notify_cb) {
- ret = mb_msg->notify_cb(mb_msg->handle, data, header->total_size);
- if (unlikely(ret))
- MB_ERR(mb_chann, "Message callback ret %d", ret);
+
+ /*
+ * msg_id is slot | MAGIC_VAL and is reused as soon as the slot is
+ * freed. The management firmware protocol guarantees exactly one
+ * response for each request, so a response cannot refer to a previous
+ * user of a reused slot. Keep the busy check as a defensive guard
+ * against an unexpected response for an idle slot.
+ */
+ if (unlikely(!mb_msg->busy)) {
+ MB_WARN_ONCE(mb_chann, "Unexpected response for idle slot 0x%x", msg_id);
+ return 0;
}
- kfree(mb_msg);
+ ret = mailbox_msg_done(mb_msg, data, header->total_size);
+ if (unlikely(ret))
+ MB_ERR(mb_chann, "Message callback ret %d", ret);
+
return ret;
}
@@ -399,7 +459,7 @@ again:
}
int xdna_mailbox_send_msg(struct mailbox_channel *mb_chann,
- const struct xdna_mailbox_msg *msg, u64 tx_timeout)
+ const struct xdna_mailbox_msg *msg)
{
struct xdna_msg_header *header;
struct mailbox_msg *mb_msg;
@@ -428,9 +488,12 @@ int xdna_mailbox_send_msg(struct mailbox_channel *mb_chann,
return -EPIPE;
}
- mb_msg = kzalloc(sizeof(*mb_msg) + pkg_size, GFP_KERNEL);
- if (!mb_msg)
- return -ENOMEM;
+ mutex_lock(&mb_chann->lock);
+ mb_msg = mailbox_get_msg_buf(mb_chann, pkg_size);
+ if (!mb_msg) {
+ mutex_unlock(&mb_chann->lock);
+ return -ENOBUFS;
+ }
mb_msg->handle = msg->handle;
mb_msg->notify_cb = msg->notify_cb;
@@ -447,28 +510,18 @@ int xdna_mailbox_send_msg(struct mailbox_channel *mb_chann,
header->opcode = msg->opcode;
memcpy(mb_msg->pkg.payload, msg->send_data, msg->send_size);
- ret = mailbox_acquire_msgid(mb_chann, mb_msg);
- if (unlikely(ret < 0)) {
- MB_ERR(mb_chann, "mailbox_acquire_msgid failed");
- goto msg_id_failed;
- }
- header->id = ret;
-
MB_DBG(mb_chann, "opcode 0x%x size %d id 0x%x",
header->opcode, header->total_size, header->id);
ret = mailbox_send_msg(mb_chann, mb_msg);
if (ret) {
MB_DBG(mb_chann, "Error in mailbox send msg, ret %d", ret);
- goto release_id;
+ mb_msg->busy = false;
+ mutex_unlock(&mb_chann->lock);
+ return ret;
}
+ mutex_unlock(&mb_chann->lock);
- return 0;
-
-release_id:
- mailbox_release_msgid(mb_chann, header->id);
-msg_id_failed:
- kfree(mb_msg);
return ret;
}
@@ -487,6 +540,7 @@ struct mailbox_channel *xdna_mailbox_alloc_channel(struct mailbox *mb)
goto free_chann;
}
mb_chann->mb = mb;
+ mutex_init(&mb_chann->lock);
return mb_chann;
@@ -500,7 +554,9 @@ void xdna_mailbox_free_channel(struct mailbox_channel *mb_chann)
if (!mb_chann)
return;
+ kfree(mb_chann->msg_buf);
destroy_workqueue(mb_chann->work_q);
+ mutex_destroy(&mb_chann->lock);
kfree(mb_chann);
}
@@ -509,21 +565,32 @@ xdna_mailbox_start_channel(struct mailbox_channel *mb_chann,
const struct xdna_mailbox_chann_res *x2i,
const struct xdna_mailbox_chann_res *i2x,
u32 iohub_int_addr,
- int mb_irq)
+ int mb_irq, u32 n_msg)
{
int ret;
- if (!is_power_of_2(x2i->rb_size) || !is_power_of_2(i2x->rb_size)) {
- pr_err("Ring buf size must be power of 2\n");
- return -EINVAL;
- }
-
+ /*
+ * The ring buffer geometry, rb_start_addr and rb_size for both the
+ * x2i and the i2x channel, comes from AMD signed firmware, through
+ * the management or mailbox information block, or through the
+ * CREATE_CONTEXT response. The driver trusts those values by design
+ * and does not bound them against the mapped region.
+ */
mb_chann->msix_irq = mb_irq;
mb_chann->iohub_int_addr = iohub_int_addr;
memcpy(&mb_chann->res[CHAN_RES_X2I], x2i, sizeof(*x2i));
memcpy(&mb_chann->res[CHAN_RES_I2X], i2x, sizeof(*i2x));
- xa_init_flags(&mb_chann->chan_xa, XA_FLAGS_ALLOC | XA_FLAGS_LOCK_IRQ);
+ /*
+ * msg_buf is a flat array of n_msg slots, separate from the hardware
+ * ring buffer. Each slot is rb_size bytes - the combined size of the
+ * mailbox_msg metadata and the package payload must not exceed rb_size.
+ */
+ mb_chann->msg_buf = kcalloc(n_msg, MSG_BUF_SZ(mb_chann), GFP_KERNEL);
+ if (!mb_chann->msg_buf)
+ return -ENOMEM;
+
+ mb_chann->msg_buf_num = n_msg;
mb_chann->x2i_tail = mailbox_get_tailptr(mb_chann, CHAN_RES_X2I);
mb_chann->i2x_head = mailbox_get_headptr(mb_chann, CHAN_RES_I2X);
@@ -531,6 +598,8 @@ xdna_mailbox_start_channel(struct mailbox_channel *mb_chann,
ret = request_irq(mb_irq, mailbox_irq_handler, 0, MAILBOX_NAME, mb_chann);
if (ret) {
MB_ERR(mb_chann, "Failed to request irq %d ret %d", mb_irq, ret);
+ kfree(mb_chann->msg_buf);
+ mb_chann->msg_buf = NULL;
return ret;
}
@@ -544,7 +613,7 @@ xdna_mailbox_start_channel(struct mailbox_channel *mb_chann,
void xdna_mailbox_stop_channel(struct mailbox_channel *mb_chann)
{
struct mailbox_msg *mb_msg;
- unsigned long msg_id;
+ u32 i;
if (!mb_chann)
return;
@@ -555,12 +624,22 @@ void xdna_mailbox_stop_channel(struct mailbox_channel *mb_chann)
/* Cancel RX work and wait for it to finish */
drain_workqueue(mb_chann->work_q);
- /* We can clean up and release resources */
- xa_for_each_start(&mb_chann->chan_xa, msg_id, mb_msg, mb_chann->next_msgid)
- mailbox_release_msg(mb_chann, mb_msg);
- xa_for_each_range(&mb_chann->chan_xa, msg_id, mb_msg, 0, mb_chann->next_msgid - 1)
- mailbox_release_msg(mb_chann, mb_msg);
- xa_destroy(&mb_chann->chan_xa);
+ /* Release any in-flight messages in the pool
+ *
+ * Drain in submission order: next_slot points to the slot after
+ * the most recently assigned one, so start from next_slot and
+ * wrap around so callbacks fire oldest-first.
+ */
+ for (i = 0; i < mb_chann->msg_buf_num; i++) {
+ u32 slot = (mb_chann->next_slot + i) % mb_chann->msg_buf_num;
+
+ mb_msg = mailbox_msg_ptr(mb_chann, slot);
+ if (!mb_msg->busy)
+ continue;
+ MB_DBG(mb_chann, "msg_id 0x%x msg opcode 0x%x",
+ mb_msg->pkg.header.id, mb_msg->pkg.header.opcode);
+ mailbox_msg_done(mb_msg, NULL, 0);
+ }
MB_DBG(mb_chann, "Mailbox channel stopped, irq: %d", mb_chann->msix_irq);
}
diff --git a/drivers/accel/amdxdna/amdxdna_mailbox.h b/drivers/accel/amdxdna/amdxdna_mailbox.h
index 2908404303ae..7f4a40b4230b 100644
--- a/drivers/accel/amdxdna/amdxdna_mailbox.h
+++ b/drivers/accel/amdxdna/amdxdna_mailbox.h
@@ -88,6 +88,10 @@ struct mailbox_channel *xdna_mailbox_alloc_channel(struct mailbox *mb);
* @i2x: firmware to host mailbox resources
* @xdna_mailbox_intr_reg: register addr of MSI-X interrupt
* @mb_irq: Linux IRQ number associated with mailbox MSI-X interrupt vector index
+ * @n_msg: number of message slots to pre-allocate; must be non-zero for
+ * the PCI transport (the platform transport ignores this argument).
+ * Each slot is rb_size bytes. The caller must ensure at most n_msg
+ * messages are in flight at any time.
*
* Return: If success, return a handle of mailbox channel. Otherwise, return NULL.
*/
@@ -96,7 +100,7 @@ xdna_mailbox_start_channel(struct mailbox_channel *mb_chann,
const struct xdna_mailbox_chann_res *x2i,
const struct xdna_mailbox_chann_res *i2x,
u32 xdna_mailbox_intr_reg,
- int mb_irq);
+ int mb_irq, u32 n_msg);
/*
* xdna_mailbox_free_channel() -- free mailbox channel
@@ -117,11 +121,10 @@ void xdna_mailbox_stop_channel(struct mailbox_channel *mailbox_chann);
*
* @mailbox_chann: Mailbox channel handle
* @msg: message struct for message information
- * @tx_timeout: the timeout value for sending the message in ms.
*
* Return: If success return 0, otherwise, return error code
*/
int xdna_mailbox_send_msg(struct mailbox_channel *mailbox_chann,
- const struct xdna_mailbox_msg *msg, u64 tx_timeout);
+ const struct xdna_mailbox_msg *msg);
#endif /* _AIE_MAILBOX_ */
diff --git a/drivers/accel/amdxdna/amdxdna_mailbox_helper.c b/drivers/accel/amdxdna/amdxdna_mailbox_helper.c
index 6d0c24513476..ee33a34852f0 100644
--- a/drivers/accel/amdxdna/amdxdna_mailbox_helper.c
+++ b/drivers/accel/amdxdna/amdxdna_mailbox_helper.c
@@ -44,7 +44,7 @@ int xdna_send_msg_wait(struct amdxdna_dev *xdna, struct mailbox_channel *chann,
struct xdna_notify *hdl = msg->handle;
int ret;
- ret = xdna_mailbox_send_msg(chann, msg, TX_TIMEOUT);
+ ret = xdna_mailbox_send_msg(chann, msg);
if (ret) {
XDNA_ERR(xdna, "Send message failed, ret %d", ret);
return ret;
diff --git a/drivers/accel/amdxdna/amdxdna_mailbox_helper.h b/drivers/accel/amdxdna/amdxdna_mailbox_helper.h
index 556c712cad0a..11924d38f2fe 100644
--- a/drivers/accel/amdxdna/amdxdna_mailbox_helper.h
+++ b/drivers/accel/amdxdna/amdxdna_mailbox_helper.h
@@ -6,7 +6,6 @@
#ifndef _AMDXDNA_MAILBOX_HELPER_H
#define _AMDXDNA_MAILBOX_HELPER_H
-#define TX_TIMEOUT 2000 /* milliseconds */
#define RX_TIMEOUT 5000 /* milliseconds */
struct amdxdna_dev;
diff --git a/drivers/accel/amdxdna/amdxdna_pci_drv.c b/drivers/accel/amdxdna/amdxdna_pci_drv.c
index bb339e641416..67a02d6b7f97 100644
--- a/drivers/accel/amdxdna/amdxdna_pci_drv.c
+++ b/drivers/accel/amdxdna/amdxdna_pci_drv.c
@@ -14,6 +14,7 @@
#include <linux/iommu.h>
#include <linux/pci.h>
+#include "aie.h"
#include "amdxdna_cbuf.h"
#include "amdxdna_ctx.h"
#include "amdxdna_debugfs.h"
@@ -151,6 +152,8 @@ static int amdxdna_drm_open(struct drm_device *ddev, struct drm_file *filp)
filp->driver_priv = client;
client->filp = filp;
+ spin_lock_init(&client->io_stats.lock);
+
XDNA_DBG(xdna, "pid %d opened", client->pid);
return 0;
@@ -287,6 +290,9 @@ static void amdxdna_show_fdinfo(struct drm_printer *p, struct drm_file *filp)
size_t heap_usage, external_usage, internal_usage;
char *drv_name = filp->minor->dev->driver->name;
+ drm_printf(p, "drm-engine-npu:\t%llu ns\n",
+ amdxdna_io_stats_busy_time_ns(client));
+
mutex_lock(&client->mm_lock);
heap_usage = client->heap_usage;
diff --git a/drivers/accel/amdxdna/amdxdna_pci_drv.h b/drivers/accel/amdxdna/amdxdna_pci_drv.h
index a997d27a504d..510356a31532 100644
--- a/drivers/accel/amdxdna/amdxdna_pci_drv.h
+++ b/drivers/accel/amdxdna/amdxdna_pci_drv.h
@@ -143,6 +143,13 @@ struct amdxdna_device_id {
const struct amdxdna_dev_info *dev_info;
};
+struct amdxdna_io_stats {
+ spinlock_t lock; /* protect io stats */
+ int job_depth;
+ u64 start_time;
+ u64 busy_time;
+};
+
/*
* struct amdxdna_client - amdxdna client
* A per fd data structure for managing context and other user process stuffs.
@@ -169,6 +176,8 @@ struct amdxdna_client {
size_t heap_usage;
size_t total_bo_usage;
size_t total_int_bo_usage;
+
+ struct amdxdna_io_stats io_stats;
};
#define amdxdna_for_each_hwctx(client, hwctx_id, entry) \
diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c
index 647684219e9d..247ed6b2ff62 100644
--- a/drivers/accel/ivpu/ivpu_drv.c
+++ b/drivers/accel/ivpu/ivpu_drv.c
@@ -67,6 +67,48 @@ bool ivpu_force_snoop;
module_param_named(force_snoop, ivpu_force_snoop, bool, 0444);
MODULE_PARM_DESC(force_snoop, "Force snooping for NPU host memory access");
+static struct pci_device_id ivpu_pci_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_MTL) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_ARL) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_LNL) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PTL) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_WCL) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_NVL) },
+ {}
+};
+MODULE_DEVICE_TABLE(pci, ivpu_pci_ids);
+
+static int ivpu_ip_gen_init(struct ivpu_device *vdev)
+{
+ vdev->platform = IVPU_PLATFORM_INVALID;
+
+ switch (ivpu_device_id(vdev)) {
+ case PCI_DEVICE_ID_MTL:
+ case PCI_DEVICE_ID_ARL:
+ vdev->hw_ip_gen = IVPU_HW_IP_37XX;
+ vdev->btrs_gen = IVPU_HW_BTRS_MTL;
+ break;
+ case PCI_DEVICE_ID_LNL:
+ vdev->hw_ip_gen = IVPU_HW_IP_40XX;
+ vdev->btrs_gen = IVPU_HW_BTRS_LNL;
+ break;
+ case PCI_DEVICE_ID_PTL:
+ case PCI_DEVICE_ID_WCL:
+ vdev->hw_ip_gen = IVPU_HW_IP_50XX;
+ vdev->btrs_gen = IVPU_HW_BTRS_LNL;
+ break;
+ case PCI_DEVICE_ID_NVL:
+ vdev->hw_ip_gen = IVPU_HW_IP_60XX;
+ vdev->btrs_gen = IVPU_HW_BTRS_LNL;
+ break;
+ default:
+ ivpu_err(vdev, "Unknown PCI device [%04x:%04x]\n", ivpu_vendor_id(vdev),
+ ivpu_device_id(vdev));
+ return -EINVAL;
+ }
+ return 0;
+}
+
static struct ivpu_user_limits *ivpu_user_limits_alloc(struct ivpu_device *vdev, uid_t uid)
{
struct ivpu_user_limits *limits;
@@ -248,10 +290,7 @@ static int ivpu_get_param_ioctl(struct drm_device *dev, void *data, struct drm_f
break;
case DRM_IVPU_PARAM_FW_API_VERSION:
if (args->index < VPU_FW_API_VER_NUM) {
- struct vpu_firmware_header *fw_hdr;
-
- fw_hdr = (struct vpu_firmware_header *)vdev->fw->file->data;
- args->value = fw_hdr->api_version[args->index];
+ args->value = vdev->fw->api_version[args->index];
} else {
ret = -EINVAL;
}
@@ -481,6 +520,14 @@ int ivpu_boot(struct ivpu_device *vdev)
ivpu_fw_boot_params_setup(vdev, ivpu_bo_vaddr(vdev->fw->mem_bp));
vdev->fw->last_boot_mode = vdev->fw->next_boot_mode;
+ if (!ivpu_fw_is_warm_boot(vdev)) {
+ ret = ivpu_fw_load(vdev);
+ if (ret) {
+ ivpu_err(vdev, "Failed to load the firmware: %d\n", ret);
+ return ret;
+ }
+ }
+
ret = ivpu_hw_boot_fw(vdev);
if (ret) {
ivpu_err(vdev, "Failed to start the firmware: %d\n", ret);
@@ -497,6 +544,9 @@ int ivpu_boot(struct ivpu_device *vdev)
ivpu_hw_irq_enable(vdev);
ivpu_ipc_enable(vdev);
+ if (ivpu_test_mode & IVPU_TEST_MODE_FW_TEST)
+ return 0;
+
if (!ivpu_fw_is_warm_boot(vdev)) {
ret = ivpu_pm_dct_init(vdev);
if (ret)
@@ -650,6 +700,7 @@ static int ivpu_pci_init(struct ivpu_device *vdev)
struct pci_dev *pdev = to_pci_dev(vdev->drm.dev);
struct resource *bar0 = &pdev->resource[0];
struct resource *bar4 = &pdev->resource[4];
+ int dma_bits;
int ret;
ivpu_dbg(vdev, MISC, "Mapping BAR0 (RegV) %pR\n", bar0);
@@ -666,7 +717,12 @@ static int ivpu_pci_init(struct ivpu_device *vdev)
return PTR_ERR(vdev->regb);
}
- ret = dma_set_mask_and_coherent(vdev->drm.dev, DMA_BIT_MASK(vdev->hw->dma_bits));
+ if (ivpu_hw_ip_gen(vdev) >= IVPU_HW_IP_40XX)
+ dma_bits = 42;
+ else
+ dma_bits = 38;
+
+ ret = dma_set_mask_and_coherent(vdev->drm.dev, DMA_BIT_MASK(dma_bits));
if (ret) {
ivpu_err(vdev, "Failed to set DMA mask: %d\n", ret);
return ret;
@@ -714,12 +770,10 @@ static int ivpu_dev_init(struct ivpu_device *vdev)
if (!vdev->pm)
return -ENOMEM;
- if (ivpu_hw_ip_gen(vdev) >= IVPU_HW_IP_40XX)
- vdev->hw->dma_bits = 48;
- else
- vdev->hw->dma_bits = 38;
+ ret = ivpu_ip_gen_init(vdev);
+ if (ret)
+ return ret;
- vdev->platform = IVPU_PLATFORM_INVALID;
vdev->context_xa_limit.min = IVPU_USER_CONTEXT_MIN_SSID;
vdev->context_xa_limit.max = IVPU_USER_CONTEXT_MAX_SSID;
atomic64_set(&vdev->unique_id_counter, 0);
@@ -852,17 +906,6 @@ static void ivpu_dev_fini(struct ivpu_device *vdev)
xa_destroy(&vdev->context_xa);
}
-static struct pci_device_id ivpu_pci_ids[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_MTL) },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_ARL) },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_LNL) },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PTL_P) },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_WCL) },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_NVL) },
- {}
-};
-MODULE_DEVICE_TABLE(pci, ivpu_pci_ids);
-
static int ivpu_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct ivpu_device *vdev;
diff --git a/drivers/accel/ivpu/ivpu_drv.h b/drivers/accel/ivpu/ivpu_drv.h
index 8762b8969d96..a713f3645bfd 100644
--- a/drivers/accel/ivpu/ivpu_drv.h
+++ b/drivers/accel/ivpu/ivpu_drv.h
@@ -27,21 +27,13 @@
#define PCI_DEVICE_ID_MTL 0x7d1d
#define PCI_DEVICE_ID_ARL 0xad1d
#define PCI_DEVICE_ID_LNL 0x643e
-#define PCI_DEVICE_ID_PTL_P 0xb03e
+#define PCI_DEVICE_ID_PTL 0xb03e
#define PCI_DEVICE_ID_WCL 0xfd3e
#define PCI_DEVICE_ID_NVL 0xd71d
-#define IVPU_HW_IP_37XX 37
-#define IVPU_HW_IP_40XX 40
-#define IVPU_HW_IP_50XX 50
-#define IVPU_HW_IP_60XX 60
-
#define IVPU_HW_IP_REV_LNL_B0 4
#define IVPU_HW_IP_REV_NVL_A0 0
-#define IVPU_HW_BTRS_MTL 1
-#define IVPU_HW_BTRS_LNL 2
-
#define IVPU_GLOBAL_CONTEXT_MMU_SSID 0
/* SSID 1 is used by the VPU to represent reserved context */
#define IVPU_RESERVED_CONTEXT_MMU_SSID 1
@@ -107,10 +99,21 @@
ivpu_dbg(vdev, MISC, "Using WA: " #wa_name "\n"); \
} while (0)
+enum vpu_hw_ip {
+ IVPU_HW_IP_37XX = 37,
+ IVPU_HW_IP_40XX = 40,
+ IVPU_HW_IP_50XX = 50,
+ IVPU_HW_IP_60XX = 60,
+};
+
+enum vpu_hw_btrs {
+ IVPU_HW_BTRS_MTL = 1,
+ IVPU_HW_BTRS_LNL = 2,
+};
+
struct ivpu_wa_table {
bool punit_disabled;
bool clear_runtime_mem;
- bool interrupt_clear_with_0;
bool disable_clock_relinquish;
bool wp0_during_power_up;
bool disable_d0i2;
@@ -136,6 +139,8 @@ struct ivpu_device {
struct drm_device drm;
void __iomem *regb;
void __iomem *regv;
+ enum vpu_hw_ip hw_ip_gen;
+ enum vpu_hw_btrs btrs_gen;
u32 platform;
u32 irq;
@@ -225,6 +230,7 @@ extern bool ivpu_force_snoop;
#define IVPU_TEST_MODE_FW_TEST BIT(0)
#define IVPU_TEST_MODE_NULL_HW BIT(1)
#define IVPU_TEST_MODE_NULL_SUBMISSION BIT(2)
+#define IVPU_TEST_MODE_FREQ_CHANGE_ENABLE BIT(3)
#define IVPU_TEST_MODE_MIP_DISABLE BIT(6)
#define IVPU_TEST_MODE_DISABLE_TIMEOUTS BIT(8)
#define IVPU_TEST_MODE_TURBO_ENABLE BIT(9)
@@ -247,47 +253,24 @@ static inline u8 ivpu_revision(struct ivpu_device *vdev)
return to_pci_dev(vdev->drm.dev)->revision;
}
+static inline u16 ivpu_vendor_id(struct ivpu_device *vdev)
+{
+ return to_pci_dev(vdev->drm.dev)->vendor;
+}
+
static inline u16 ivpu_device_id(struct ivpu_device *vdev)
{
return to_pci_dev(vdev->drm.dev)->device;
}
-static inline int ivpu_hw_ip_gen(struct ivpu_device *vdev)
+static inline enum vpu_hw_ip ivpu_hw_ip_gen(struct ivpu_device *vdev)
{
- switch (ivpu_device_id(vdev)) {
- case PCI_DEVICE_ID_MTL:
- case PCI_DEVICE_ID_ARL:
- return IVPU_HW_IP_37XX;
- case PCI_DEVICE_ID_LNL:
- return IVPU_HW_IP_40XX;
- case PCI_DEVICE_ID_PTL_P:
- case PCI_DEVICE_ID_WCL:
- return IVPU_HW_IP_50XX;
- case PCI_DEVICE_ID_NVL:
- return IVPU_HW_IP_60XX;
- default:
- dump_stack();
- ivpu_err(vdev, "Unknown NPU IP generation\n");
- return 0;
- }
+ return vdev->hw_ip_gen;
}
-static inline int ivpu_hw_btrs_gen(struct ivpu_device *vdev)
+static inline enum vpu_hw_btrs ivpu_hw_btrs_gen(struct ivpu_device *vdev)
{
- switch (ivpu_device_id(vdev)) {
- case PCI_DEVICE_ID_MTL:
- case PCI_DEVICE_ID_ARL:
- return IVPU_HW_BTRS_MTL;
- case PCI_DEVICE_ID_LNL:
- case PCI_DEVICE_ID_PTL_P:
- case PCI_DEVICE_ID_WCL:
- case PCI_DEVICE_ID_NVL:
- return IVPU_HW_BTRS_LNL;
- default:
- dump_stack();
- ivpu_err(vdev, "Unknown buttress generation\n");
- return 0;
- }
+ return vdev->btrs_gen;
}
static inline struct ivpu_device *to_ivpu_device(struct drm_device *dev)
diff --git a/drivers/accel/ivpu/ivpu_fw.c b/drivers/accel/ivpu/ivpu_fw.c
index f9ddaa2420c4..96f5be23a867 100644
--- a/drivers/accel/ivpu/ivpu_fw.c
+++ b/drivers/accel/ivpu/ivpu_fw.c
@@ -28,15 +28,15 @@
#define ADDR_TO_L2_CACHE_CFG(addr) ((addr) >> 31)
/* Check if FW API is compatible with the driver */
-#define IVPU_FW_CHECK_API_COMPAT(vdev, fw_hdr, name, min_major) \
- ivpu_fw_check_api(vdev, fw_hdr, #name, \
+#define IVPU_FW_CHECK_API_COMPAT(vdev, name, min_major) \
+ ivpu_fw_check_api(vdev, #name, \
VPU_##name##_API_VER_INDEX, \
VPU_##name##_API_VER_MAJOR, \
VPU_##name##_API_VER_MINOR, min_major)
/* Check if API version is lower that the given version */
-#define IVPU_FW_CHECK_API_VER_LT(vdev, fw_hdr, name, major, minor) \
- ivpu_fw_check_api_ver_lt(vdev, fw_hdr, #name, VPU_##name##_API_VER_INDEX, major, minor)
+#define IVPU_FW_CHECK_API_VER_LT(vdev, name, major, minor) \
+ ivpu_fw_check_api_ver_lt(vdev, #name, VPU_##name##_API_VER_INDEX, major, minor)
#define IVPU_FOCUS_PRESENT_TIMER_MS 1000
@@ -93,12 +93,11 @@ static int ivpu_fw_request(struct ivpu_device *vdev)
}
static int
-ivpu_fw_check_api(struct ivpu_device *vdev, const struct vpu_firmware_header *fw_hdr,
- const char *str, int index, u16 expected_major, u16 expected_minor,
- u16 min_major)
+ivpu_fw_check_api(struct ivpu_device *vdev, const char *str, int index, u16 expected_major,
+ u16 expected_minor, u16 min_major)
{
- u16 major = (u16)(fw_hdr->api_version[index] >> 16);
- u16 minor = (u16)(fw_hdr->api_version[index]);
+ u16 major = (u16)(vdev->fw->api_version[index] >> 16);
+ u16 minor = (u16)(vdev->fw->api_version[index]);
if (major < min_major) {
ivpu_err(vdev, "Incompatible FW %s API version: %d.%d, required %d.0 or later\n",
@@ -116,11 +115,10 @@ ivpu_fw_check_api(struct ivpu_device *vdev, const struct vpu_firmware_header *fw
}
static bool
-ivpu_fw_check_api_ver_lt(struct ivpu_device *vdev, const struct vpu_firmware_header *fw_hdr,
- const char *str, int index, u16 major, u16 minor)
+ivpu_fw_check_api_ver_lt(struct ivpu_device *vdev, const char *str, int index, u16 major, u16 minor)
{
- u16 fw_major = (u16)(fw_hdr->api_version[index] >> 16);
- u16 fw_minor = (u16)(fw_hdr->api_version[index]);
+ u16 fw_major = (u16)(vdev->fw->api_version[index] >> 16);
+ u16 fw_minor = (u16)(vdev->fw->api_version[index]);
if (fw_major < major || (fw_major == major && fw_minor < minor))
return true;
@@ -142,7 +140,7 @@ 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)
+ivpu_fw_sched_mode_select(struct ivpu_device *vdev)
{
if (ivpu_hw_ip_gen(vdev) >= IVPU_HW_IP_60XX &&
ivpu_sched_mode == VPU_SCHEDULING_MODE_OS) {
@@ -153,7 +151,7 @@ ivpu_fw_sched_mode_select(struct ivpu_device *vdev, const struct vpu_firmware_he
if (ivpu_sched_mode != IVPU_SCHED_MODE_AUTO)
return ivpu_sched_mode;
- if (IVPU_FW_CHECK_API_VER_LT(vdev, fw_hdr, JSM, 3, 24))
+ if (IVPU_FW_CHECK_API_VER_LT(vdev, JSM, 3, 24))
return VPU_SCHEDULING_MODE_OS;
return VPU_SCHEDULING_MODE_HW;
@@ -302,9 +300,11 @@ static int ivpu_fw_parse(struct ivpu_device *vdev)
ivpu_info(vdev, "Firmware: %s, version: %s\n", fw->name, fw->version);
- if (IVPU_FW_CHECK_API_COMPAT(vdev, fw_hdr, BOOT, 3))
+ memcpy(fw->api_version, fw_hdr->api_version, sizeof(fw->api_version));
+
+ if (IVPU_FW_CHECK_API_COMPAT(vdev, BOOT, 3))
return -EINVAL;
- if (IVPU_FW_CHECK_API_COMPAT(vdev, fw_hdr, JSM, 3))
+ if (IVPU_FW_CHECK_API_COMPAT(vdev, JSM, 3))
return -EINVAL;
fw->boot_params_addr = boot_params_addr;
@@ -324,7 +324,7 @@ static int ivpu_fw_parse(struct ivpu_device *vdev)
fw->dvfs_mode = 0;
- fw->sched_mode = ivpu_fw_sched_mode_select(vdev, fw_hdr);
+ fw->sched_mode = ivpu_fw_sched_mode_select(vdev);
ivpu_info(vdev, "Scheduler mode: %s\n", fw->sched_mode ? "HW" : "OS");
ivpu_preemption_config_parse(vdev, fw_hdr);
@@ -473,8 +473,6 @@ int ivpu_fw_init(struct ivpu_device *vdev)
if (ret)
goto err_fw_release;
- ivpu_fw_load(vdev);
-
return 0;
err_fw_release:
@@ -488,7 +486,7 @@ void ivpu_fw_fini(struct ivpu_device *vdev)
ivpu_fw_release(vdev);
}
-void ivpu_fw_load(struct ivpu_device *vdev)
+int ivpu_fw_load(struct ivpu_device *vdev)
{
struct ivpu_fw_info *fw = vdev->fw;
u64 image_end_offset = fw->image_load_offset + fw->image_size;
@@ -505,6 +503,7 @@ void ivpu_fw_load(struct ivpu_device *vdev)
}
wmb(); /* Flush WC buffers after writing fw->mem */
+ return 0;
}
static void ivpu_fw_boot_params_print(struct ivpu_device *vdev, struct vpu_boot_params *boot_params)
diff --git a/drivers/accel/ivpu/ivpu_fw.h b/drivers/accel/ivpu/ivpu_fw.h
index d3c410912c9c..45a705431f22 100644
--- a/drivers/accel/ivpu/ivpu_fw.h
+++ b/drivers/accel/ivpu/ivpu_fw.h
@@ -20,6 +20,7 @@ struct ivpu_fw_info {
const struct firmware *file;
const char *name;
char version[FW_VERSION_STR_SIZE];
+ u32 api_version[VPU_FW_API_VER_NUM];
struct ivpu_bo *mem_bp;
struct ivpu_bo *mem_fw_ver;
struct ivpu_bo *mem;
@@ -54,7 +55,7 @@ struct ivpu_fw_info {
bool ivpu_is_within_range(u64 addr, size_t size, struct ivpu_addr_range *range);
int ivpu_fw_init(struct ivpu_device *vdev);
void ivpu_fw_fini(struct ivpu_device *vdev);
-void ivpu_fw_load(struct ivpu_device *vdev);
+int ivpu_fw_load(struct ivpu_device *vdev);
void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params *boot_params);
static inline bool ivpu_fw_is_warm_boot(struct ivpu_device *vdev)
diff --git a/drivers/accel/ivpu/ivpu_hw.c b/drivers/accel/ivpu/ivpu_hw.c
index 47ed9beeb3fb..86679d64fc14 100644
--- a/drivers/accel/ivpu/ivpu_hw.c
+++ b/drivers/accel/ivpu/ivpu_hw.c
@@ -67,9 +67,6 @@ static void wa_init(struct ivpu_device *vdev)
vdev->wa.punit_disabled = false;
vdev->wa.clear_runtime_mem = false;
- if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL)
- vdev->wa.interrupt_clear_with_0 = ivpu_hw_btrs_irqs_clear_with_0_mtl(vdev);
-
if ((ivpu_device_id(vdev) == PCI_DEVICE_ID_LNL &&
ivpu_revision(vdev) < IVPU_HW_IP_REV_LNL_B0) ||
(ivpu_device_id(vdev) == PCI_DEVICE_ID_NVL &&
@@ -90,7 +87,6 @@ static void wa_init(struct ivpu_device *vdev)
IVPU_PRINT_WA(punit_disabled);
IVPU_PRINT_WA(clear_runtime_mem);
- IVPU_PRINT_WA(interrupt_clear_with_0);
IVPU_PRINT_WA(disable_clock_relinquish);
IVPU_PRINT_WA(wp0_during_power_up);
IVPU_PRINT_WA(disable_d0i2);
@@ -98,7 +94,7 @@ static void wa_init(struct ivpu_device *vdev)
static void timeouts_init(struct ivpu_device *vdev)
{
- if (ivpu_test_mode & IVPU_TEST_MODE_DISABLE_TIMEOUTS) {
+ if (ivpu_test_mode & (IVPU_TEST_MODE_DISABLE_TIMEOUTS | IVPU_TEST_MODE_FW_TEST)) {
/* in milliseconds, negative value disables the timeout */
vdev->timeout.boot = -1;
vdev->timeout.jsm = -1;
@@ -378,11 +374,6 @@ void ivpu_hw_profiling_freq_drive(struct ivpu_device *vdev, bool enable)
void ivpu_irq_handlers_init(struct ivpu_device *vdev)
{
- if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX)
- vdev->hw->irq.ip_irq_handler = ivpu_hw_ip_irq_handler_37xx;
- else
- vdev->hw->irq.ip_irq_handler = ivpu_hw_ip_irq_handler_40xx;
-
if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL)
vdev->hw->irq.btrs_irq_handler = ivpu_hw_btrs_irq_handler_mtl;
else
diff --git a/drivers/accel/ivpu/ivpu_hw.h b/drivers/accel/ivpu/ivpu_hw.h
index 487a918e2fa9..8c1b61df6cd4 100644
--- a/drivers/accel/ivpu/ivpu_hw.h
+++ b/drivers/accel/ivpu/ivpu_hw.h
@@ -18,7 +18,6 @@ struct ivpu_addr_range {
struct ivpu_hw_info {
struct {
bool (*btrs_irq_handler)(struct ivpu_device *vdev, int irq);
- bool (*ip_irq_handler)(struct ivpu_device *vdev, int irq);
} irq;
struct {
struct ivpu_addr_range runtime;
@@ -49,9 +48,9 @@ struct ivpu_hw_info {
u32 tile_fuse;
u32 sku;
u16 config;
- int dma_bits;
ktime_t d0i3_entry_host_ts;
u64 d0i3_entry_vpu_ts;
+ u32 btrs_irq_mask;
atomic_t firewall_irq_counter;
};
@@ -74,11 +73,6 @@ static inline u32 ivpu_hw_btrs_irq_handler(struct ivpu_device *vdev, int irq)
return vdev->hw->irq.btrs_irq_handler(vdev, irq);
}
-static inline u32 ivpu_hw_ip_irq_handler(struct ivpu_device *vdev, int irq)
-{
- return vdev->hw->irq.ip_irq_handler(vdev, irq);
-}
-
static inline u64 ivpu_hw_range_size(const struct ivpu_addr_range *range)
{
return range->end - range->start;
diff --git a/drivers/accel/ivpu/ivpu_hw_40xx_reg.h b/drivers/accel/ivpu/ivpu_hw_40xx_reg.h
deleted file mode 100644
index fc0ee8d637f9..000000000000
--- a/drivers/accel/ivpu/ivpu_hw_40xx_reg.h
+++ /dev/null
@@ -1,195 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (C) 2020-2023 Intel Corporation
- */
-
-#ifndef __IVPU_HW_40XX_REG_H__
-#define __IVPU_HW_40XX_REG_H__
-
-#include <linux/bits.h>
-
-#define VPU_40XX_HOST_SS_CPR_CLK_EN 0x00000080u
-#define VPU_40XX_HOST_SS_CPR_CLK_EN_TOP_NOC_MASK BIT_MASK(1)
-#define VPU_40XX_HOST_SS_CPR_CLK_EN_DSS_MAS_MASK BIT_MASK(10)
-#define VPU_40XX_HOST_SS_CPR_CLK_EN_CSS_MAS_MASK BIT_MASK(11)
-
-#define VPU_40XX_HOST_SS_CPR_CLK_SET 0x00000084u
-#define VPU_40XX_HOST_SS_CPR_CLK_SET_TOP_NOC_MASK BIT_MASK(1)
-#define VPU_40XX_HOST_SS_CPR_CLK_SET_DSS_MAS_MASK BIT_MASK(10)
-#define VPU_40XX_HOST_SS_CPR_CLK_SET_MSS_MAS_MASK BIT_MASK(11)
-
-#define VPU_40XX_HOST_SS_CPR_RST_EN 0x00000090u
-#define VPU_40XX_HOST_SS_CPR_RST_EN_TOP_NOC_MASK BIT_MASK(1)
-#define VPU_40XX_HOST_SS_CPR_RST_EN_DSS_MAS_MASK BIT_MASK(10)
-#define VPU_40XX_HOST_SS_CPR_RST_EN_CSS_MAS_MASK BIT_MASK(11)
-
-#define VPU_40XX_HOST_SS_CPR_RST_SET 0x00000094u
-#define VPU_40XX_HOST_SS_CPR_RST_SET_TOP_NOC_MASK BIT_MASK(1)
-#define VPU_40XX_HOST_SS_CPR_RST_SET_DSS_MAS_MASK BIT_MASK(10)
-#define VPU_40XX_HOST_SS_CPR_RST_SET_MSS_MAS_MASK BIT_MASK(11)
-
-#define VPU_40XX_HOST_SS_CPR_RST_CLR 0x00000098u
-#define VPU_40XX_HOST_SS_CPR_RST_CLR_TOP_NOC_MASK BIT_MASK(1)
-#define VPU_40XX_HOST_SS_CPR_RST_CLR_DSS_MAS_MASK BIT_MASK(10)
-#define VPU_40XX_HOST_SS_CPR_RST_CLR_MSS_MAS_MASK BIT_MASK(11)
-
-#define VPU_40XX_HOST_SS_HW_VERSION 0x00000108u
-#define VPU_40XX_HOST_SS_HW_VERSION_SOC_REVISION_MASK GENMASK(7, 0)
-#define VPU_40XX_HOST_SS_HW_VERSION_SOC_NUMBER_MASK GENMASK(15, 8)
-#define VPU_40XX_HOST_SS_HW_VERSION_VPU_GENERATION_MASK GENMASK(23, 16)
-
-#define VPU_40XX_HOST_SS_SW_VERSION 0x0000010cu
-
-#define VPU_40XX_HOST_SS_GEN_CTRL 0x00000118u
-#define VPU_40XX_HOST_SS_GEN_CTRL_PS_MASK GENMASK(31, 29)
-
-#define VPU_40XX_HOST_SS_NOC_QREQN 0x00000154u
-#define VPU_40XX_HOST_SS_NOC_QREQN_TOP_SOCMMIO_MASK BIT_MASK(0)
-
-#define VPU_40XX_HOST_SS_NOC_QACCEPTN 0x00000158u
-#define VPU_40XX_HOST_SS_NOC_QACCEPTN_TOP_SOCMMIO_MASK BIT_MASK(0)
-
-#define VPU_40XX_HOST_SS_NOC_QDENY 0x0000015cu
-#define VPU_40XX_HOST_SS_NOC_QDENY_TOP_SOCMMIO_MASK BIT_MASK(0)
-
-#define VPU_40XX_TOP_NOC_QREQN 0x00000160u
-#define VPU_40XX_TOP_NOC_QREQN_CPU_CTRL_MASK BIT_MASK(0)
-#define VPU_40XX_TOP_NOC_QREQN_HOSTIF_L2CACHE_MASK BIT_MASK(2)
-
-#define VPU_40XX_TOP_NOC_QACCEPTN 0x00000164u
-#define VPU_40XX_TOP_NOC_QACCEPTN_CPU_CTRL_MASK BIT_MASK(0)
-#define VPU_40XX_TOP_NOC_QACCEPTN_HOSTIF_L2CACHE_MASK BIT_MASK(2)
-
-#define VPU_40XX_TOP_NOC_QDENY 0x00000168u
-#define VPU_40XX_TOP_NOC_QDENY_CPU_CTRL_MASK BIT_MASK(0)
-#define VPU_40XX_TOP_NOC_QDENY_HOSTIF_L2CACHE_MASK BIT_MASK(2)
-
-#define VPU_40XX_HOST_SS_FW_SOC_IRQ_EN 0x00000170u
-#define VPU_40XX_HOST_SS_FW_SOC_IRQ_EN_CSS_ROM_CMX_MASK BIT_MASK(0)
-#define VPU_40XX_HOST_SS_FW_SOC_IRQ_EN_CSS_DBG_MASK BIT_MASK(1)
-#define VPU_40XX_HOST_SS_FW_SOC_IRQ_EN_CSS_CTRL_MASK BIT_MASK(2)
-#define VPU_40XX_HOST_SS_FW_SOC_IRQ_EN_DEC400_MASK BIT_MASK(3)
-#define VPU_40XX_HOST_SS_FW_SOC_IRQ_EN_MSS_NCE_MASK BIT_MASK(4)
-#define VPU_40XX_HOST_SS_FW_SOC_IRQ_EN_MSS_MBI_MASK BIT_MASK(5)
-#define VPU_40XX_HOST_SS_FW_SOC_IRQ_EN_MSS_MBI_CMX_MASK BIT_MASK(6)
-
-#define VPU_40XX_HOST_SS_ICB_STATUS_0 0x00010210u
-#define VPU_40XX_HOST_SS_ICB_STATUS_0_TIMER_0_INT_MASK BIT_MASK(0)
-#define VPU_40XX_HOST_SS_ICB_STATUS_0_TIMER_1_INT_MASK BIT_MASK(1)
-#define VPU_40XX_HOST_SS_ICB_STATUS_0_TIMER_2_INT_MASK BIT_MASK(2)
-#define VPU_40XX_HOST_SS_ICB_STATUS_0_TIMER_3_INT_MASK BIT_MASK(3)
-#define VPU_40XX_HOST_SS_ICB_STATUS_0_HOST_IPC_FIFO_INT_MASK BIT_MASK(4)
-#define VPU_40XX_HOST_SS_ICB_STATUS_0_MMU_IRQ_0_INT_MASK BIT_MASK(5)
-#define VPU_40XX_HOST_SS_ICB_STATUS_0_MMU_IRQ_1_INT_MASK BIT_MASK(6)
-#define VPU_40XX_HOST_SS_ICB_STATUS_0_MMU_IRQ_2_INT_MASK BIT_MASK(7)
-#define VPU_40XX_HOST_SS_ICB_STATUS_0_NOC_FIREWALL_INT_MASK BIT_MASK(8)
-#define VPU_40XX_HOST_SS_ICB_STATUS_0_CPU_INT_REDIRECT_0_INT_MASK BIT_MASK(30)
-#define VPU_40XX_HOST_SS_ICB_STATUS_0_CPU_INT_REDIRECT_1_INT_MASK BIT_MASK(31)
-
-#define VPU_40XX_HOST_SS_ICB_STATUS_1 0x00010214u
-#define VPU_40XX_HOST_SS_ICB_STATUS_1_CPU_INT_REDIRECT_2_INT_MASK BIT_MASK(0)
-#define VPU_40XX_HOST_SS_ICB_STATUS_1_CPU_INT_REDIRECT_3_INT_MASK BIT_MASK(1)
-#define VPU_40XX_HOST_SS_ICB_STATUS_1_CPU_INT_REDIRECT_4_INT_MASK BIT_MASK(2)
-
-#define VPU_40XX_HOST_SS_ICB_CLEAR_0 0x00010220u
-#define VPU_40XX_HOST_SS_ICB_CLEAR_1 0x00010224u
-#define VPU_40XX_HOST_SS_ICB_ENABLE_0 0x00010240u
-#define VPU_40XX_HOST_SS_ICB_ENABLE_1 0x00010244u
-
-#define VPU_40XX_HOST_SS_TIM_IPC_FIFO_ATM 0x000200f4u
-
-#define VPU_40XX_HOST_SS_TIM_IPC_FIFO_STAT 0x000200fcu
-#define VPU_40XX_HOST_SS_TIM_IPC_FIFO_STAT_FILL_LEVEL_MASK GENMASK(23, 16)
-
-#define VPU_40XX_HOST_SS_AON_PWR_ISO_EN0 0x00030020u
-#define VPU_40XX_HOST_SS_AON_PWR_ISO_EN0_CSS_CPU_MASK BIT_MASK(3)
-
-#define VPU_40XX_HOST_SS_AON_PWR_ISLAND_EN0 0x00030024u
-#define VPU_40XX_HOST_SS_AON_PWR_ISLAND_EN0_CSS_CPU_MASK BIT_MASK(3)
-
-#define VPU_40XX_HOST_SS_AON_PWR_ISLAND_TRICKLE_EN0 0x00030028u
-#define VPU_40XX_HOST_SS_AON_PWR_ISLAND_TRICKLE_EN0_CSS_CPU_MASK BIT_MASK(3)
-
-#define VPU_40XX_HOST_SS_AON_PWR_ISLAND_STATUS0 0x0003002cu
-#define VPU_40XX_HOST_SS_AON_PWR_ISLAND_STATUS0_CSS_CPU_MASK BIT_MASK(3)
-
-#define VPU_50XX_HOST_SS_AON_PWR_ISLAND_EN_POST_DLY 0x00030068u
-#define VPU_50XX_HOST_SS_AON_PWR_ISLAND_EN_POST_DLY_POST_DLY_MASK GENMASK(7, 0)
-#define VPU_50XX_HOST_SS_AON_PWR_ISLAND_EN_POST_DLY_POST1_DLY_MASK GENMASK(15, 8)
-#define VPU_50XX_HOST_SS_AON_PWR_ISLAND_EN_POST_DLY_POST2_DLY_MASK GENMASK(23, 16)
-
-#define VPU_50XX_HOST_SS_AON_PWR_ISLAND_STATUS_DLY 0x0003006cu
-#define VPU_50XX_HOST_SS_AON_PWR_ISLAND_STATUS_DLY_STATUS_DLY_MASK GENMASK(7, 0)
-
-#define VPU_40XX_HOST_SS_AON_IDLE_GEN 0x00030200u
-#define VPU_40XX_HOST_SS_AON_IDLE_GEN_EN_MASK BIT_MASK(0)
-#define VPU_40XX_HOST_SS_AON_IDLE_GEN_HW_PG_EN_MASK BIT_MASK(1)
-
-#define VPU_40XX_HOST_SS_AON_DPU_ACTIVE 0x00030204u
-#define VPU_40XX_HOST_SS_AON_DPU_ACTIVE_DPU_ACTIVE_MASK BIT_MASK(0)
-
-#define VPU_50XX_HOST_SS_AON_FABRIC_REQ_OVERRIDE 0x00030210u
-#define VPU_50XX_HOST_SS_AON_FABRIC_REQ_OVERRIDE_REQ_OVERRIDE_MASK BIT_MASK(0)
-
-#define VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO 0x00040040u
-#define VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO_DONE_MASK BIT_MASK(0)
-#define VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO_IOSF_RS_ID_MASK GENMASK(2, 1)
-#define VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO_IMAGE_LOCATION_MASK GENMASK(31, 3)
-
-#define VPU_40XX_HOST_SS_WORKPOINT_CONFIG_MIRROR 0x00082020u
-#define VPU_40XX_HOST_SS_WORKPOINT_CONFIG_MIRROR_FINAL_PLL_FREQ_MASK GENMASK(15, 0)
-#define VPU_40XX_HOST_SS_WORKPOINT_CONFIG_MIRROR_CONFIG_ID_MASK GENMASK(31, 16)
-
-#define VPU_40XX_HOST_IF_TCU_PTW_OVERRIDES 0x00360000u
-#define VPU_40XX_HOST_IF_TCU_PTW_OVERRIDES_CACHE_OVERRIDE_EN_MASK BIT_MASK(0)
-#define VPU_40XX_HOST_IF_TCU_PTW_OVERRIDES_AWCACHE_OVERRIDE_MASK BIT_MASK(1)
-#define VPU_40XX_HOST_IF_TCU_PTW_OVERRIDES_ARCACHE_OVERRIDE_MASK BIT_MASK(2)
-#define VPU_40XX_HOST_IF_TCU_PTW_OVERRIDES_SNOOP_OVERRIDE_EN_MASK BIT_MASK(3)
-#define VPU_40XX_HOST_IF_TCU_PTW_OVERRIDES_AW_SNOOP_OVERRIDE_MASK BIT_MASK(4)
-#define VPU_40XX_HOST_IF_TCU_PTW_OVERRIDES_AR_SNOOP_OVERRIDE_MASK BIT_MASK(5)
-#define VPU_40XX_HOST_IF_TCU_PTW_OVERRIDES_PTW_AW_CONTEXT_FLAG_MASK GENMASK(10, 6)
-#define VPU_40XX_HOST_IF_TCU_PTW_OVERRIDES_PTW_AR_CONTEXT_FLAG_MASK GENMASK(15, 11)
-
-#define VPU_40XX_HOST_IF_TBU_MMUSSIDV 0x00360004u
-#define VPU_40XX_HOST_IF_TBU_MMUSSIDV_TBU0_AWMMUSSIDV_MASK BIT_MASK(0)
-#define VPU_40XX_HOST_IF_TBU_MMUSSIDV_TBU0_ARMMUSSIDV_MASK BIT_MASK(1)
-#define VPU_40XX_HOST_IF_TBU_MMUSSIDV_TBU1_AWMMUSSIDV_MASK BIT_MASK(2)
-#define VPU_40XX_HOST_IF_TBU_MMUSSIDV_TBU1_ARMMUSSIDV_MASK BIT_MASK(3)
-#define VPU_40XX_HOST_IF_TBU_MMUSSIDV_TBU2_AWMMUSSIDV_MASK BIT_MASK(4)
-#define VPU_40XX_HOST_IF_TBU_MMUSSIDV_TBU2_ARMMUSSIDV_MASK BIT_MASK(5)
-#define VPU_40XX_HOST_IF_TBU_MMUSSIDV_TBU3_AWMMUSSIDV_MASK BIT_MASK(6)
-#define VPU_40XX_HOST_IF_TBU_MMUSSIDV_TBU3_ARMMUSSIDV_MASK BIT_MASK(7)
-#define VPU_40XX_HOST_IF_TBU_MMUSSIDV_TBU4_AWMMUSSIDV_MASK BIT_MASK(8)
-#define VPU_40XX_HOST_IF_TBU_MMUSSIDV_TBU4_ARMMUSSIDV_MASK BIT_MASK(9)
-
-#define VPU_40XX_CPU_SS_DSU_LEON_RT_BASE 0x04000000u
-#define VPU_40XX_CPU_SS_DSU_LEON_RT_DSU_CTRL 0x04000000u
-#define VPU_40XX_CPU_SS_DSU_LEON_RT_PC_REG 0x04400010u
-#define VPU_40XX_CPU_SS_DSU_LEON_RT_NPC_REG 0x04400014u
-#define VPU_40XX_CPU_SS_DSU_LEON_RT_DSU_TRAP_REG 0x04400020u
-
-#define VPU_40XX_CPU_SS_TIM_WATCHDOG 0x0102009cu
-#define VPU_40XX_CPU_SS_TIM_WDOG_EN 0x010200a4u
-#define VPU_40XX_CPU_SS_TIM_SAFE 0x010200a8u
-
-#define VPU_40XX_CPU_SS_TIM_GEN_CONFIG 0x01021008u
-#define VPU_40XX_CPU_SS_TIM_GEN_CONFIG_WDOG_TO_INT_CLR_MASK BIT_MASK(9)
-
-#define VPU_40XX_CPU_SS_CPR_NOC_QREQN 0x01010030u
-#define VPU_40XX_CPU_SS_CPR_NOC_QREQN_TOP_MMIO_MASK BIT_MASK(0)
-
-#define VPU_40XX_CPU_SS_CPR_NOC_QACCEPTN 0x01010034u
-#define VPU_40XX_CPU_SS_CPR_NOC_QACCEPTN_TOP_MMIO_MASK BIT_MASK(0)
-
-#define VPU_40XX_CPU_SS_CPR_NOC_QDENY 0x01010038u
-#define VPU_40XX_CPU_SS_CPR_NOC_QDENY_TOP_MMIO_MASK BIT_MASK(0)
-
-#define VPU_40XX_CPU_SS_TIM_IPC_FIFO 0x010200f0u
-#define VPU_40XX_CPU_SS_TIM_PERF_EXT_FREE_CNT 0x01029008u
-
-#define VPU_40XX_CPU_SS_DOORBELL_0 0x01300000u
-#define VPU_40XX_CPU_SS_DOORBELL_0_SET_MASK BIT_MASK(0)
-
-#define VPU_40XX_CPU_SS_DOORBELL_1 0x01301000u
-
-#endif /* __IVPU_HW_40XX_REG_H__ */
diff --git a/drivers/accel/ivpu/ivpu_hw_btrs.c b/drivers/accel/ivpu/ivpu_hw_btrs.c
index a17c829adb89..840983a618ca 100644
--- a/drivers/accel/ivpu/ivpu_hw_btrs.c
+++ b/drivers/accel/ivpu/ivpu_hw_btrs.c
@@ -8,8 +8,7 @@
#include "ivpu_drv.h"
#include "ivpu_hw.h"
#include "ivpu_hw_btrs.h"
-#include "ivpu_hw_btrs_lnl_reg.h"
-#include "ivpu_hw_btrs_mtl_reg.h"
+#include "ivpu_hw_btrs_reg.h"
#include "ivpu_hw_reg_io.h"
#include "ivpu_jsm_msg.h"
#include "ivpu_pm.h"
@@ -24,9 +23,6 @@
(REG_FLD(VPU_HW_BTRS_LNL_INTERRUPT_STAT, IMR1_ERR)) | \
(REG_FLD(VPU_HW_BTRS_LNL_INTERRUPT_STAT, SURV_ERR)))
-#define BTRS_MTL_ALL_IRQ_MASK (BTRS_MTL_IRQ_MASK | (REG_FLD(VPU_HW_BTRS_MTL_INTERRUPT_STAT, \
- FREQ_CHANGE)))
-
#define BTRS_IRQ_DISABLE_MASK ((u32)-1)
#define BTRS_LNL_ALL_IRQ_MASK ((u32)-1)
@@ -49,9 +45,6 @@
#define BTRS_MTL_TILE_FUSE_ENABLE_BOTH 0x0
#define BTRS_MTL_TILE_SKU_BOTH 0x3630
-#define BTRS_LNL_TILE_MAX_NUM 6
-#define BTRS_LNL_TILE_MAX_MASK 0x3f
-
#define WEIGHTS_DEFAULT 0xf711f711u
#define WEIGHTS_ATS_DEFAULT 0x0000f711u
@@ -59,18 +52,6 @@
#define DCT_ENABLE 0x1
#define DCT_DISABLE 0x0
-int ivpu_hw_btrs_irqs_clear_with_0_mtl(struct ivpu_device *vdev)
-{
- REGB_WR32(VPU_HW_BTRS_MTL_INTERRUPT_STAT, BTRS_MTL_ALL_IRQ_MASK);
- if (REGB_RD32(VPU_HW_BTRS_MTL_INTERRUPT_STAT) == BTRS_MTL_ALL_IRQ_MASK) {
- /* Writing 1s does not clear the interrupt status register */
- REGB_WR32(VPU_HW_BTRS_MTL_INTERRUPT_STAT, 0x0);
- return true;
- }
-
- return false;
-}
-
static void freq_ratios_init_mtl(struct ivpu_device *vdev)
{
struct ivpu_hw_info *hw = vdev->hw;
@@ -115,13 +96,9 @@ void ivpu_hw_btrs_freq_ratios_init(struct ivpu_device *vdev)
static bool tile_disable_check(u32 config)
{
- /* Allowed values: 0 or one bit from range 0-5 (6 tiles) */
if (config == 0)
return true;
- if (config > BIT(BTRS_LNL_TILE_MAX_NUM - 1))
- return false;
-
if ((config & (config - 1)) == 0)
return true;
@@ -156,6 +133,11 @@ static int info_init_mtl(struct ivpu_device *vdev)
hw->tile_fuse = BTRS_MTL_TILE_FUSE_ENABLE_BOTH;
hw->sku = BTRS_MTL_TILE_SKU_BOTH;
hw->config = WP_CONFIG(MTL_CONFIG_2_TILE, MTL_PLL_RATIO_4_3);
+ hw->btrs_irq_mask = BTRS_MTL_IRQ_MASK;
+
+ if (ivpu_test_mode & IVPU_TEST_MODE_FREQ_CHANGE_ENABLE)
+ hw->btrs_irq_mask = REG_SET_FLD(VPU_HW_BTRS_MTL_INTERRUPT_STAT, FREQ_CHANGE,
+ hw->btrs_irq_mask);
return 0;
}
@@ -172,6 +154,11 @@ static int info_init_lnl(struct ivpu_device *vdev)
hw->tile_fuse = tile_fuse_config;
hw->pll.profiling_freq = PLL_PROFILING_FREQ_DEFAULT;
+ hw->btrs_irq_mask = BTRS_LNL_IRQ_MASK;
+
+ if (ivpu_test_mode & IVPU_TEST_MODE_FREQ_CHANGE_ENABLE)
+ hw->btrs_irq_mask = REG_SET_FLD(VPU_HW_BTRS_LNL_INTERRUPT_STAT, FREQ_CHANGE,
+ hw->btrs_irq_mask);
return 0;
}
@@ -698,7 +685,7 @@ int ivpu_hw_btrs_cfg_freq_init(struct ivpu_device *vdev)
/* Handler for IRQs from Buttress core (irqB) */
bool ivpu_hw_btrs_irq_handler_mtl(struct ivpu_device *vdev, int irq)
{
- u32 status = REGB_RD32(VPU_HW_BTRS_MTL_INTERRUPT_STAT) & BTRS_MTL_IRQ_MASK;
+ u32 status = REGB_RD32(VPU_HW_BTRS_MTL_INTERRUPT_STAT) & vdev->hw->btrs_irq_mask;
bool schedule_recovery = false;
if (!status)
@@ -729,14 +716,7 @@ bool ivpu_hw_btrs_irq_handler_mtl(struct ivpu_device *vdev, int irq)
}
/* This must be done after interrupts are cleared at the source. */
- if (IVPU_WA(interrupt_clear_with_0))
- /*
- * Writing 1 triggers an interrupt, so we can't perform read update write.
- * Clear local interrupt status by writing 0 to all bits.
- */
- REGB_WR32(VPU_HW_BTRS_MTL_INTERRUPT_STAT, 0x0);
- else
- REGB_WR32(VPU_HW_BTRS_MTL_INTERRUPT_STAT, status);
+ REGB_WR32(VPU_HW_BTRS_MTL_INTERRUPT_STAT, status);
if (schedule_recovery)
ivpu_pm_trigger_recovery(vdev, "Buttress IRQ");
@@ -747,7 +727,7 @@ bool ivpu_hw_btrs_irq_handler_mtl(struct ivpu_device *vdev, int irq)
/* Handler for IRQs from Buttress core (irqB) */
bool ivpu_hw_btrs_irq_handler_lnl(struct ivpu_device *vdev, int irq)
{
- u32 status = REGB_RD32(VPU_HW_BTRS_LNL_INTERRUPT_STAT) & BTRS_LNL_IRQ_MASK;
+ u32 status = REGB_RD32(VPU_HW_BTRS_LNL_INTERRUPT_STAT) & vdev->hw->btrs_irq_mask;
bool schedule_recovery = false;
if (!status)
@@ -889,10 +869,10 @@ void ivpu_hw_btrs_global_int_enable(struct ivpu_device *vdev)
void ivpu_hw_btrs_irq_enable(struct ivpu_device *vdev)
{
if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL) {
- REGB_WR32(VPU_HW_BTRS_MTL_LOCAL_INT_MASK, (u32)(~BTRS_MTL_IRQ_MASK));
+ REGB_WR32(VPU_HW_BTRS_MTL_LOCAL_INT_MASK, (u32)(~vdev->hw->btrs_irq_mask));
REGB_WR32(VPU_HW_BTRS_MTL_GLOBAL_INT_MASK, 0x0);
} else {
- REGB_WR32(VPU_HW_BTRS_LNL_LOCAL_INT_MASK, (u32)(~BTRS_LNL_IRQ_MASK));
+ REGB_WR32(VPU_HW_BTRS_LNL_LOCAL_INT_MASK, (u32)(~vdev->hw->btrs_irq_mask));
REGB_WR32(VPU_HW_BTRS_LNL_GLOBAL_INT_MASK, 0x0);
}
}
@@ -910,7 +890,7 @@ void ivpu_hw_btrs_irq_disable(struct ivpu_device *vdev)
static void diagnose_failure_mtl(struct ivpu_device *vdev)
{
- u32 reg = REGB_RD32(VPU_HW_BTRS_MTL_INTERRUPT_STAT) & BTRS_MTL_IRQ_MASK;
+ u32 reg = REGB_RD32(VPU_HW_BTRS_MTL_INTERRUPT_STAT) & vdev->hw->btrs_irq_mask;
if (REG_TEST_FLD(VPU_HW_BTRS_MTL_INTERRUPT_STAT, ATS_ERR, reg))
ivpu_err(vdev, "ATS_ERR irq 0x%016llx", REGB_RD64(VPU_HW_BTRS_MTL_ATS_ERR_LOG_0));
@@ -927,7 +907,7 @@ static void diagnose_failure_mtl(struct ivpu_device *vdev)
static void diagnose_failure_lnl(struct ivpu_device *vdev)
{
- u32 reg = REGB_RD32(VPU_HW_BTRS_LNL_INTERRUPT_STAT) & BTRS_LNL_IRQ_MASK;
+ u32 reg = REGB_RD32(VPU_HW_BTRS_LNL_INTERRUPT_STAT) & vdev->hw->btrs_irq_mask;
if (REG_TEST_FLD(VPU_HW_BTRS_LNL_INTERRUPT_STAT, ATS_ERR, reg)) {
ivpu_err(vdev, "ATS_ERR_LOG1 0x%08x ATS_ERR_LOG2 0x%08x\n",
diff --git a/drivers/accel/ivpu/ivpu_hw_btrs.h b/drivers/accel/ivpu/ivpu_hw_btrs.h
index d6343d734570..30c89ab8e4bd 100644
--- a/drivers/accel/ivpu/ivpu_hw_btrs.h
+++ b/drivers/accel/ivpu/ivpu_hw_btrs.h
@@ -7,8 +7,6 @@
#define __IVPU_HW_BTRS_H__
#include "ivpu_drv.h"
-#include "ivpu_hw_37xx_reg.h"
-#include "ivpu_hw_40xx_reg.h"
#include "ivpu_hw_reg_io.h"
#define PLL_PROFILING_FREQ_DEFAULT 38400000
@@ -19,7 +17,6 @@
int ivpu_hw_btrs_info_init(struct ivpu_device *vdev);
void ivpu_hw_btrs_freq_ratios_init(struct ivpu_device *vdev);
-int ivpu_hw_btrs_irqs_clear_with_0_mtl(struct ivpu_device *vdev);
int ivpu_hw_btrs_wp_drive(struct ivpu_device *vdev, bool enable);
int ivpu_hw_btrs_wait_for_clock_res_own_ack(struct ivpu_device *vdev);
int ivpu_hw_btrs_d0i3_enable(struct ivpu_device *vdev);
diff --git a/drivers/accel/ivpu/ivpu_hw_btrs_mtl_reg.h b/drivers/accel/ivpu/ivpu_hw_btrs_mtl_reg.h
deleted file mode 100644
index e93d539e066f..000000000000
--- a/drivers/accel/ivpu/ivpu_hw_btrs_mtl_reg.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (C) 2020-2023 Intel Corporation
- */
-
-#ifndef __IVPU_HW_BTRS_MTL_REG_H__
-#define __IVPU_HW_BTRS_MTL_REG_H__
-
-#include <linux/bits.h>
-
-#define VPU_HW_BTRS_MTL_INTERRUPT_TYPE 0x00000000u
-
-#define VPU_HW_BTRS_MTL_INTERRUPT_STAT 0x00000004u
-#define VPU_HW_BTRS_MTL_INTERRUPT_STAT_FREQ_CHANGE_MASK BIT_MASK(0)
-#define VPU_HW_BTRS_MTL_INTERRUPT_STAT_ATS_ERR_MASK BIT_MASK(1)
-#define VPU_HW_BTRS_MTL_INTERRUPT_STAT_UFI_ERR_MASK BIT_MASK(2)
-
-#define VPU_HW_BTRS_MTL_WP_REQ_PAYLOAD0 0x00000008u
-#define VPU_HW_BTRS_MTL_WP_REQ_PAYLOAD0_MIN_RATIO_MASK GENMASK(15, 0)
-#define VPU_HW_BTRS_MTL_WP_REQ_PAYLOAD0_MAX_RATIO_MASK GENMASK(31, 16)
-
-#define VPU_HW_BTRS_MTL_WP_REQ_PAYLOAD1 0x0000000cu
-#define VPU_HW_BTRS_MTL_WP_REQ_PAYLOAD1_TARGET_RATIO_MASK GENMASK(15, 0)
-#define VPU_HW_BTRS_MTL_WP_REQ_PAYLOAD1_EPP_MASK GENMASK(31, 16)
-
-#define VPU_HW_BTRS_MTL_WP_REQ_PAYLOAD2 0x00000010u
-#define VPU_HW_BTRS_MTL_WP_REQ_PAYLOAD2_CONFIG_MASK GENMASK(15, 0)
-
-#define VPU_HW_BTRS_MTL_WP_REQ_CMD 0x00000014u
-#define VPU_HW_BTRS_MTL_WP_REQ_CMD_SEND_MASK BIT_MASK(0)
-
-#define VPU_HW_BTRS_MTL_WP_DOWNLOAD 0x00000018u
-#define VPU_HW_BTRS_MTL_WP_DOWNLOAD_TARGET_RATIO_MASK GENMASK(15, 0)
-
-#define VPU_HW_BTRS_MTL_CURRENT_PLL 0x0000001cu
-#define VPU_HW_BTRS_MTL_CURRENT_PLL_RATIO_MASK GENMASK(15, 0)
-
-#define VPU_HW_BTRS_MTL_PLL_ENABLE 0x00000020u
-
-#define VPU_HW_BTRS_MTL_FMIN_FUSE 0x00000024u
-#define VPU_HW_BTRS_MTL_FMIN_FUSE_MIN_RATIO_MASK GENMASK(7, 0)
-#define VPU_HW_BTRS_MTL_FMIN_FUSE_PN_RATIO_MASK GENMASK(15, 8)
-
-#define VPU_HW_BTRS_MTL_FMAX_FUSE 0x00000028u
-#define VPU_HW_BTRS_MTL_FMAX_FUSE_MAX_RATIO_MASK GENMASK(7, 0)
-
-#define VPU_HW_BTRS_MTL_TILE_FUSE 0x0000002cu
-#define VPU_HW_BTRS_MTL_TILE_FUSE_VALID_MASK BIT_MASK(0)
-#define VPU_HW_BTRS_MTL_TILE_FUSE_SKU_MASK GENMASK(3, 2)
-
-#define VPU_HW_BTRS_MTL_LOCAL_INT_MASK 0x00000030u
-#define VPU_HW_BTRS_MTL_GLOBAL_INT_MASK 0x00000034u
-
-#define VPU_HW_BTRS_MTL_PLL_STATUS 0x00000040u
-#define VPU_HW_BTRS_MTL_PLL_STATUS_LOCK_MASK BIT_MASK(1)
-
-#define VPU_HW_BTRS_MTL_VPU_STATUS 0x00000044u
-#define VPU_HW_BTRS_MTL_VPU_STATUS_READY_MASK BIT_MASK(0)
-#define VPU_HW_BTRS_MTL_VPU_STATUS_IDLE_MASK BIT_MASK(1)
-
-#define VPU_HW_BTRS_MTL_VPU_D0I3_CONTROL 0x00000060u
-#define VPU_HW_BTRS_MTL_VPU_D0I3_CONTROL_INPROGRESS_MASK BIT_MASK(0)
-#define VPU_HW_BTRS_MTL_VPU_D0I3_CONTROL_I3_MASK BIT_MASK(2)
-
-#define VPU_HW_BTRS_MTL_VPU_IP_RESET 0x00000050u
-#define VPU_HW_BTRS_MTL_VPU_IP_RESET_TRIGGER_MASK BIT_MASK(0)
-
-#define VPU_HW_BTRS_MTL_VPU_TELEMETRY_OFFSET 0x00000080u
-#define VPU_HW_BTRS_MTL_VPU_TELEMETRY_SIZE 0x00000084u
-#define VPU_HW_BTRS_MTL_VPU_TELEMETRY_ENABLE 0x00000088u
-
-#define VPU_HW_BTRS_MTL_ATS_ERR_LOG_0 0x000000a0u
-#define VPU_HW_BTRS_MTL_ATS_ERR_LOG_1 0x000000a4u
-#define VPU_HW_BTRS_MTL_ATS_ERR_CLEAR 0x000000a8u
-
-#define VPU_HW_BTRS_MTL_UFI_ERR_LOG 0x000000b0u
-#define VPU_HW_BTRS_MTL_UFI_ERR_LOG_CQ_ID_MASK GENMASK(11, 0)
-#define VPU_HW_BTRS_MTL_UFI_ERR_LOG_AXI_ID_MASK GENMASK(19, 12)
-#define VPU_HW_BTRS_MTL_UFI_ERR_LOG_OPCODE_MASK GENMASK(24, 20)
-
-#define VPU_HW_BTRS_MTL_UFI_ERR_CLEAR 0x000000b4u
-
-#endif /* __IVPU_HW_BTRS_MTL_REG_H__ */
diff --git a/drivers/accel/ivpu/ivpu_hw_btrs_lnl_reg.h b/drivers/accel/ivpu/ivpu_hw_btrs_reg.h
index a81a9ba540fa..b9628bd9cb56 100644
--- a/drivers/accel/ivpu/ivpu_hw_btrs_lnl_reg.h
+++ b/drivers/accel/ivpu/ivpu_hw_btrs_reg.h
@@ -1,13 +1,85 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright (C) 2020-2024 Intel Corporation
+ * Copyright (C) 2020-2026 Intel Corporation
*/
-#ifndef __IVPU_HW_BTRS_LNL_REG_H__
-#define __IVPU_HW_BTRS_LNL_REG_H__
+#ifndef __IVPU_HW_BTRS_REG_H__
+#define __IVPU_HW_BTRS_REG_H__
#include <linux/bits.h>
+#define VPU_HW_BTRS_MTL_INTERRUPT_TYPE 0x00000000u
+
+#define VPU_HW_BTRS_MTL_INTERRUPT_STAT 0x00000004u
+#define VPU_HW_BTRS_MTL_INTERRUPT_STAT_FREQ_CHANGE_MASK BIT_MASK(0)
+#define VPU_HW_BTRS_MTL_INTERRUPT_STAT_ATS_ERR_MASK BIT_MASK(1)
+#define VPU_HW_BTRS_MTL_INTERRUPT_STAT_UFI_ERR_MASK BIT_MASK(2)
+
+#define VPU_HW_BTRS_MTL_WP_REQ_PAYLOAD0 0x00000008u
+#define VPU_HW_BTRS_MTL_WP_REQ_PAYLOAD0_MIN_RATIO_MASK GENMASK(15, 0)
+#define VPU_HW_BTRS_MTL_WP_REQ_PAYLOAD0_MAX_RATIO_MASK GENMASK(31, 16)
+
+#define VPU_HW_BTRS_MTL_WP_REQ_PAYLOAD1 0x0000000cu
+#define VPU_HW_BTRS_MTL_WP_REQ_PAYLOAD1_TARGET_RATIO_MASK GENMASK(15, 0)
+#define VPU_HW_BTRS_MTL_WP_REQ_PAYLOAD1_EPP_MASK GENMASK(31, 16)
+
+#define VPU_HW_BTRS_MTL_WP_REQ_PAYLOAD2 0x00000010u
+#define VPU_HW_BTRS_MTL_WP_REQ_PAYLOAD2_CONFIG_MASK GENMASK(15, 0)
+
+#define VPU_HW_BTRS_MTL_WP_REQ_CMD 0x00000014u
+#define VPU_HW_BTRS_MTL_WP_REQ_CMD_SEND_MASK BIT_MASK(0)
+
+#define VPU_HW_BTRS_MTL_WP_DOWNLOAD 0x00000018u
+#define VPU_HW_BTRS_MTL_WP_DOWNLOAD_TARGET_RATIO_MASK GENMASK(15, 0)
+
+#define VPU_HW_BTRS_MTL_CURRENT_PLL 0x0000001cu
+#define VPU_HW_BTRS_MTL_CURRENT_PLL_RATIO_MASK GENMASK(15, 0)
+
+#define VPU_HW_BTRS_MTL_PLL_ENABLE 0x00000020u
+
+#define VPU_HW_BTRS_MTL_FMIN_FUSE 0x00000024u
+#define VPU_HW_BTRS_MTL_FMIN_FUSE_MIN_RATIO_MASK GENMASK(7, 0)
+#define VPU_HW_BTRS_MTL_FMIN_FUSE_PN_RATIO_MASK GENMASK(15, 8)
+
+#define VPU_HW_BTRS_MTL_FMAX_FUSE 0x00000028u
+#define VPU_HW_BTRS_MTL_FMAX_FUSE_MAX_RATIO_MASK GENMASK(7, 0)
+
+#define VPU_HW_BTRS_MTL_TILE_FUSE 0x0000002cu
+#define VPU_HW_BTRS_MTL_TILE_FUSE_VALID_MASK BIT_MASK(0)
+#define VPU_HW_BTRS_MTL_TILE_FUSE_SKU_MASK GENMASK(3, 2)
+
+#define VPU_HW_BTRS_MTL_LOCAL_INT_MASK 0x00000030u
+#define VPU_HW_BTRS_MTL_GLOBAL_INT_MASK 0x00000034u
+
+#define VPU_HW_BTRS_MTL_PLL_STATUS 0x00000040u
+#define VPU_HW_BTRS_MTL_PLL_STATUS_LOCK_MASK BIT_MASK(1)
+
+#define VPU_HW_BTRS_MTL_VPU_STATUS 0x00000044u
+#define VPU_HW_BTRS_MTL_VPU_STATUS_READY_MASK BIT_MASK(0)
+#define VPU_HW_BTRS_MTL_VPU_STATUS_IDLE_MASK BIT_MASK(1)
+
+#define VPU_HW_BTRS_MTL_VPU_IP_RESET 0x00000050u
+#define VPU_HW_BTRS_MTL_VPU_IP_RESET_TRIGGER_MASK BIT_MASK(0)
+
+#define VPU_HW_BTRS_MTL_VPU_D0I3_CONTROL 0x00000060u
+#define VPU_HW_BTRS_MTL_VPU_D0I3_CONTROL_INPROGRESS_MASK BIT_MASK(0)
+#define VPU_HW_BTRS_MTL_VPU_D0I3_CONTROL_I3_MASK BIT_MASK(2)
+
+#define VPU_HW_BTRS_MTL_VPU_TELEMETRY_OFFSET 0x00000080u
+#define VPU_HW_BTRS_MTL_VPU_TELEMETRY_SIZE 0x00000084u
+#define VPU_HW_BTRS_MTL_VPU_TELEMETRY_ENABLE 0x00000088u
+
+#define VPU_HW_BTRS_MTL_ATS_ERR_LOG_0 0x000000a0u
+#define VPU_HW_BTRS_MTL_ATS_ERR_LOG_1 0x000000a4u
+#define VPU_HW_BTRS_MTL_ATS_ERR_CLEAR 0x000000a8u
+
+#define VPU_HW_BTRS_MTL_UFI_ERR_LOG 0x000000b0u
+#define VPU_HW_BTRS_MTL_UFI_ERR_LOG_CQ_ID_MASK GENMASK(11, 0)
+#define VPU_HW_BTRS_MTL_UFI_ERR_LOG_AXI_ID_MASK GENMASK(19, 12)
+#define VPU_HW_BTRS_MTL_UFI_ERR_LOG_OPCODE_MASK GENMASK(24, 20)
+
+#define VPU_HW_BTRS_MTL_UFI_ERR_CLEAR 0x000000b4u
+
#define VPU_HW_BTRS_LNL_INTERRUPT_STAT 0x00000000u
#define VPU_HW_BTRS_LNL_INTERRUPT_STAT_FREQ_CHANGE_MASK BIT_MASK(0)
#define VPU_HW_BTRS_LNL_INTERRUPT_STAT_ATS_ERR_MASK BIT_MASK(1)
@@ -79,12 +151,12 @@
#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)
+#define VPU_HW_BTRS_LNL_TILE_FUSE_CONFIG_MASK GENMASK(7, 1)
#define VPU_HW_BTRS_LNL_VPU_STATUS 0x00000154u
#define VPU_HW_BTRS_LNL_VPU_STATUS_READY_MASK BIT_MASK(0)
#define VPU_HW_BTRS_LNL_VPU_STATUS_IDLE_MASK BIT_MASK(1)
-#define VPU_HW_BTRS_LNL_VPU_STATUS_DUP_IDLE_MASK BIT_MASK(2)
+#define VPU_HW_BTRS_LNL_VPU_STATUS_DPU_IDLE_MASK BIT_MASK(2)
#define VPU_HW_BTRS_LNL_VPU_STATUS_CLOCK_RESOURCE_OWN_ACK_MASK BIT_MASK(6)
#define VPU_HW_BTRS_LNL_VPU_STATUS_POWER_RESOURCE_OWN_ACK_MASK BIT_MASK(7)
#define VPU_HW_BTRS_LNL_VPU_STATUS_PERF_CLK_MASK BIT_MASK(11)
@@ -109,4 +181,4 @@
#define VPU_HW_BTRS_LNL_FMAX_FUSE 0x00000178u
#define VPU_HW_BTRS_LNL_FMAX_FUSE_MAX_RATIO_MASK GENMASK(7, 0)
-#endif /* __IVPU_HW_BTRS_LNL_REG_H__ */
+#endif /* __IVPU_HW_BTRS_REG_H__ */
diff --git a/drivers/accel/ivpu/ivpu_hw_ip.c b/drivers/accel/ivpu/ivpu_hw_ip.c
index 46661fbf9d05..47f4f9e17d8a 100644
--- a/drivers/accel/ivpu/ivpu_hw_ip.c
+++ b/drivers/accel/ivpu/ivpu_hw_ip.c
@@ -7,10 +7,9 @@
#include "ivpu_fw.h"
#include "ivpu_gem.h"
#include "ivpu_hw.h"
-#include "ivpu_hw_37xx_reg.h"
-#include "ivpu_hw_40xx_reg.h"
#include "ivpu_hw_btrs.h"
#include "ivpu_hw_ip.h"
+#include "ivpu_hw_ip_reg.h"
#include "ivpu_hw_reg_io.h"
#include "ivpu_mmu.h"
#include "ivpu_pm.h"
@@ -18,49 +17,27 @@
#define TIM_SAFE_ENABLE 0xf1d0dead
#define TIM_WATCHDOG_RESET_VALUE 0xffffffff
-#define ICB_0_IRQ_MASK_37XX ((REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_0, HOST_IPC_FIFO_INT)) | \
- (REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_0, MMU_IRQ_0_INT)) | \
- (REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_0, MMU_IRQ_1_INT)) | \
- (REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_0, MMU_IRQ_2_INT)) | \
- (REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_0, NOC_FIREWALL_INT)) | \
- (REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_0, CPU_INT_REDIRECT_0_INT)) | \
- (REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_0, CPU_INT_REDIRECT_1_INT)))
-
-#define ICB_1_IRQ_MASK_37XX ((REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_1, CPU_INT_REDIRECT_2_INT)) | \
- (REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_1, CPU_INT_REDIRECT_3_INT)) | \
- (REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_1, CPU_INT_REDIRECT_4_INT)))
-
-#define ICB_0_1_IRQ_MASK_37XX ((((u64)ICB_1_IRQ_MASK_37XX) << 32) | ICB_0_IRQ_MASK_37XX)
-
-#define ICB_0_IRQ_MASK_40XX ((REG_FLD(VPU_40XX_HOST_SS_ICB_STATUS_0, HOST_IPC_FIFO_INT)) | \
- (REG_FLD(VPU_40XX_HOST_SS_ICB_STATUS_0, MMU_IRQ_0_INT)) | \
- (REG_FLD(VPU_40XX_HOST_SS_ICB_STATUS_0, MMU_IRQ_1_INT)) | \
- (REG_FLD(VPU_40XX_HOST_SS_ICB_STATUS_0, MMU_IRQ_2_INT)) | \
- (REG_FLD(VPU_40XX_HOST_SS_ICB_STATUS_0, NOC_FIREWALL_INT)) | \
- (REG_FLD(VPU_40XX_HOST_SS_ICB_STATUS_0, CPU_INT_REDIRECT_0_INT)) | \
- (REG_FLD(VPU_40XX_HOST_SS_ICB_STATUS_0, CPU_INT_REDIRECT_1_INT)))
-
-#define ICB_1_IRQ_MASK_40XX ((REG_FLD(VPU_40XX_HOST_SS_ICB_STATUS_1, CPU_INT_REDIRECT_2_INT)) | \
- (REG_FLD(VPU_40XX_HOST_SS_ICB_STATUS_1, CPU_INT_REDIRECT_3_INT)) | \
- (REG_FLD(VPU_40XX_HOST_SS_ICB_STATUS_1, CPU_INT_REDIRECT_4_INT)))
-
-#define ICB_0_1_IRQ_MASK_40XX ((((u64)ICB_1_IRQ_MASK_40XX) << 32) | ICB_0_IRQ_MASK_40XX)
-
-#define ITF_FIREWALL_VIOLATION_MASK_37XX ((REG_FLD(VPU_37XX_HOST_SS_FW_SOC_IRQ_EN, CSS_ROM_CMX)) | \
- (REG_FLD(VPU_37XX_HOST_SS_FW_SOC_IRQ_EN, CSS_DBG)) | \
- (REG_FLD(VPU_37XX_HOST_SS_FW_SOC_IRQ_EN, CSS_CTRL)) | \
- (REG_FLD(VPU_37XX_HOST_SS_FW_SOC_IRQ_EN, DEC400)) | \
- (REG_FLD(VPU_37XX_HOST_SS_FW_SOC_IRQ_EN, MSS_NCE)) | \
- (REG_FLD(VPU_37XX_HOST_SS_FW_SOC_IRQ_EN, MSS_MBI)) | \
- (REG_FLD(VPU_37XX_HOST_SS_FW_SOC_IRQ_EN, MSS_MBI_CMX)))
-
-#define ITF_FIREWALL_VIOLATION_MASK_40XX ((REG_FLD(VPU_40XX_HOST_SS_FW_SOC_IRQ_EN, CSS_ROM_CMX)) | \
- (REG_FLD(VPU_40XX_HOST_SS_FW_SOC_IRQ_EN, CSS_DBG)) | \
- (REG_FLD(VPU_40XX_HOST_SS_FW_SOC_IRQ_EN, CSS_CTRL)) | \
- (REG_FLD(VPU_40XX_HOST_SS_FW_SOC_IRQ_EN, DEC400)) | \
- (REG_FLD(VPU_40XX_HOST_SS_FW_SOC_IRQ_EN, MSS_NCE)) | \
- (REG_FLD(VPU_40XX_HOST_SS_FW_SOC_IRQ_EN, MSS_MBI)) | \
- (REG_FLD(VPU_40XX_HOST_SS_FW_SOC_IRQ_EN, MSS_MBI_CMX)))
+#define ICB_0_IRQ_MASK ((REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_0, HOST_IPC_FIFO_INT)) | \
+ (REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_0, MMU_IRQ_0_INT)) | \
+ (REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_0, MMU_IRQ_1_INT)) | \
+ (REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_0, MMU_IRQ_2_INT)) | \
+ (REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_0, NOC_FIREWALL_INT)) | \
+ (REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_0, CPU_INT_REDIRECT_0_INT)) | \
+ (REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_0, CPU_INT_REDIRECT_1_INT)))
+
+#define ICB_1_IRQ_MASK ((REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_1, CPU_INT_REDIRECT_2_INT)) | \
+ (REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_1, CPU_INT_REDIRECT_3_INT)) | \
+ (REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_1, CPU_INT_REDIRECT_4_INT)))
+
+#define ICB_0_1_IRQ_MASK ((((u64)ICB_1_IRQ_MASK) << 32) | ICB_0_IRQ_MASK)
+
+#define ITF_FIREWALL_VIOLATION_MASK ((REG_FLD(VPU_37XX_HOST_SS_FW_SOC_IRQ_EN, CSS_ROM_CMX)) | \
+ (REG_FLD(VPU_37XX_HOST_SS_FW_SOC_IRQ_EN, CSS_DBG)) | \
+ (REG_FLD(VPU_37XX_HOST_SS_FW_SOC_IRQ_EN, CSS_CTRL)) | \
+ (REG_FLD(VPU_37XX_HOST_SS_FW_SOC_IRQ_EN, DEC400)) | \
+ (REG_FLD(VPU_37XX_HOST_SS_FW_SOC_IRQ_EN, MSS_NCE)) | \
+ (REG_FLD(VPU_37XX_HOST_SS_FW_SOC_IRQ_EN, MSS_MBI)) | \
+ (REG_FLD(VPU_37XX_HOST_SS_FW_SOC_IRQ_EN, MSS_MBI_CMX)))
static int wait_for_ip_bar(struct ivpu_device *vdev)
{
@@ -78,7 +55,7 @@ static void host_ss_rst_clr(struct ivpu_device *vdev)
REGV_WR32(VPU_37XX_HOST_SS_CPR_RST_CLR, val);
}
-static int host_ss_noc_qreqn_check_37xx(struct ivpu_device *vdev, u32 exp_val)
+static int host_ss_noc_qreqn_check(struct ivpu_device *vdev, u32 exp_val)
{
u32 val = REGV_RD32(VPU_37XX_HOST_SS_NOC_QREQN);
@@ -88,25 +65,7 @@ static int host_ss_noc_qreqn_check_37xx(struct ivpu_device *vdev, u32 exp_val)
return 0;
}
-static int host_ss_noc_qreqn_check_40xx(struct ivpu_device *vdev, u32 exp_val)
-{
- u32 val = REGV_RD32(VPU_40XX_HOST_SS_NOC_QREQN);
-
- if (!REG_TEST_FLD_NUM(VPU_40XX_HOST_SS_NOC_QREQN, TOP_SOCMMIO, exp_val, val))
- return -EIO;
-
- return 0;
-}
-
-static int host_ss_noc_qreqn_check(struct ivpu_device *vdev, u32 exp_val)
-{
- if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX)
- return host_ss_noc_qreqn_check_37xx(vdev, exp_val);
- else
- return host_ss_noc_qreqn_check_40xx(vdev, exp_val);
-}
-
-static int host_ss_noc_qacceptn_check_37xx(struct ivpu_device *vdev, u32 exp_val)
+static int host_ss_noc_qacceptn_check(struct ivpu_device *vdev, u32 exp_val)
{
u32 val = REGV_RD32(VPU_37XX_HOST_SS_NOC_QACCEPTN);
@@ -116,25 +75,7 @@ static int host_ss_noc_qacceptn_check_37xx(struct ivpu_device *vdev, u32 exp_val
return 0;
}
-static int host_ss_noc_qacceptn_check_40xx(struct ivpu_device *vdev, u32 exp_val)
-{
- u32 val = REGV_RD32(VPU_40XX_HOST_SS_NOC_QACCEPTN);
-
- if (!REG_TEST_FLD_NUM(VPU_40XX_HOST_SS_NOC_QACCEPTN, TOP_SOCMMIO, exp_val, val))
- return -EIO;
-
- return 0;
-}
-
-static int host_ss_noc_qacceptn_check(struct ivpu_device *vdev, u32 exp_val)
-{
- if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX)
- return host_ss_noc_qacceptn_check_37xx(vdev, exp_val);
- else
- return host_ss_noc_qacceptn_check_40xx(vdev, exp_val);
-}
-
-static int host_ss_noc_qdeny_check_37xx(struct ivpu_device *vdev, u32 exp_val)
+static int host_ss_noc_qdeny_check(struct ivpu_device *vdev, u32 exp_val)
{
u32 val = REGV_RD32(VPU_37XX_HOST_SS_NOC_QDENY);
@@ -144,24 +85,6 @@ static int host_ss_noc_qdeny_check_37xx(struct ivpu_device *vdev, u32 exp_val)
return 0;
}
-static int host_ss_noc_qdeny_check_40xx(struct ivpu_device *vdev, u32 exp_val)
-{
- u32 val = REGV_RD32(VPU_40XX_HOST_SS_NOC_QDENY);
-
- if (!REG_TEST_FLD_NUM(VPU_40XX_HOST_SS_NOC_QDENY, TOP_SOCMMIO, exp_val, val))
- return -EIO;
-
- return 0;
-}
-
-static int host_ss_noc_qdeny_check(struct ivpu_device *vdev, u32 exp_val)
-{
- if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX)
- return host_ss_noc_qdeny_check_37xx(vdev, exp_val);
- else
- return host_ss_noc_qdeny_check_40xx(vdev, exp_val);
-}
-
static int top_noc_qrenqn_check_37xx(struct ivpu_device *vdev, u32 exp_val)
{
u32 val = REGV_RD32(VPU_37XX_TOP_NOC_QREQN);
@@ -175,9 +98,9 @@ static int top_noc_qrenqn_check_37xx(struct ivpu_device *vdev, u32 exp_val)
static int top_noc_qrenqn_check_40xx(struct ivpu_device *vdev, u32 exp_val)
{
- u32 val = REGV_RD32(VPU_40XX_TOP_NOC_QREQN);
+ u32 val = REGV_RD32(VPU_37XX_TOP_NOC_QREQN);
- if (!REG_TEST_FLD_NUM(VPU_40XX_TOP_NOC_QREQN, CPU_CTRL, exp_val, val) ||
+ if (!REG_TEST_FLD_NUM(VPU_37XX_TOP_NOC_QREQN, CPU_CTRL, exp_val, val) ||
!REG_TEST_FLD_NUM(VPU_40XX_TOP_NOC_QREQN, HOSTIF_L2CACHE, exp_val, val))
return -EIO;
@@ -224,7 +147,7 @@ int ivpu_hw_ip_host_ss_configure(struct ivpu_device *vdev)
return ret;
}
-static void idle_gen_drive_37xx(struct ivpu_device *vdev, bool enable)
+static void idle_gen_drive(struct ivpu_device *vdev, bool enable)
{
u32 val = REGV_RD32(VPU_37XX_HOST_SS_AON_VPU_IDLE_GEN);
@@ -236,75 +159,59 @@ static void idle_gen_drive_37xx(struct ivpu_device *vdev, bool enable)
REGV_WR32(VPU_37XX_HOST_SS_AON_VPU_IDLE_GEN, val);
}
-static void idle_gen_drive_40xx(struct ivpu_device *vdev, bool enable)
-{
- u32 val = REGV_RD32(VPU_40XX_HOST_SS_AON_IDLE_GEN);
-
- if (enable)
- val = REG_SET_FLD(VPU_40XX_HOST_SS_AON_IDLE_GEN, EN, val);
- else
- val = REG_CLR_FLD(VPU_40XX_HOST_SS_AON_IDLE_GEN, EN, val);
-
- REGV_WR32(VPU_40XX_HOST_SS_AON_IDLE_GEN, val);
-}
-
void ivpu_hw_ip_idle_gen_enable(struct ivpu_device *vdev)
{
- if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX)
- idle_gen_drive_37xx(vdev, true);
- else
- idle_gen_drive_40xx(vdev, true);
+ idle_gen_drive(vdev, true);
}
void ivpu_hw_ip_idle_gen_disable(struct ivpu_device *vdev)
{
- if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX)
- idle_gen_drive_37xx(vdev, false);
- else
- idle_gen_drive_40xx(vdev, false);
+ idle_gen_drive(vdev, false);
}
static void
-pwr_island_delay_set_50xx(struct ivpu_device *vdev, u32 post, u32 post1, u32 post2, u32 status)
+pwr_island_delay_write(struct ivpu_device *vdev, u32 post, u32 post1, u32 post2, u32 status)
{
u32 val;
- val = REGV_RD32(VPU_50XX_HOST_SS_AON_PWR_ISLAND_EN_POST_DLY);
- val = REG_SET_FLD_NUM(VPU_50XX_HOST_SS_AON_PWR_ISLAND_EN_POST_DLY, POST_DLY, post, val);
+ val = REG_SET_FLD_NUM(VPU_50XX_HOST_SS_AON_PWR_ISLAND_EN_POST_DLY, POST_DLY, post, 0);
val = REG_SET_FLD_NUM(VPU_50XX_HOST_SS_AON_PWR_ISLAND_EN_POST_DLY, POST1_DLY, post1, val);
val = REG_SET_FLD_NUM(VPU_50XX_HOST_SS_AON_PWR_ISLAND_EN_POST_DLY, POST2_DLY, post2, val);
REGV_WR32(VPU_50XX_HOST_SS_AON_PWR_ISLAND_EN_POST_DLY, val);
- val = REGV_RD32(VPU_50XX_HOST_SS_AON_PWR_ISLAND_STATUS_DLY);
- val = REG_SET_FLD_NUM(VPU_50XX_HOST_SS_AON_PWR_ISLAND_STATUS_DLY, STATUS_DLY, status, val);
+ val = REG_SET_FLD_NUM(VPU_50XX_HOST_SS_AON_PWR_ISLAND_STATUS_DLY, STATUS_DLY, status, 0);
REGV_WR32(VPU_50XX_HOST_SS_AON_PWR_ISLAND_STATUS_DLY, val);
}
-static void pwr_island_trickle_drive_37xx(struct ivpu_device *vdev, bool enable)
+static void pwr_island_delay_set_50xx(struct ivpu_device *vdev)
{
- u32 val = REGV_RD32(VPU_37XX_HOST_SS_AON_PWR_ISLAND_TRICKLE_EN0);
-
- if (enable)
- val = REG_SET_FLD(VPU_37XX_HOST_SS_AON_PWR_ISLAND_TRICKLE_EN0, MSS_CPU, val);
+ if (vdev->hw->pll.profiling_freq == PLL_PROFILING_FREQ_HIGH)
+ pwr_island_delay_write(vdev, 18, 0, 0, 46);
else
- val = REG_CLR_FLD(VPU_37XX_HOST_SS_AON_PWR_ISLAND_TRICKLE_EN0, MSS_CPU, val);
+ pwr_island_delay_write(vdev, 0, 0, 0, 3);
+}
- REGV_WR32(VPU_37XX_HOST_SS_AON_PWR_ISLAND_TRICKLE_EN0, val);
+static void pwr_island_delay_set_60xx(struct ivpu_device *vdev)
+{
+ if (vdev->hw->pll.profiling_freq == PLL_PROFILING_FREQ_HIGH)
+ pwr_island_delay_write(vdev, 198, 0, 198, 0);
+ else
+ pwr_island_delay_write(vdev, 17, 0, 17, 0);
}
-static void pwr_island_trickle_drive_40xx(struct ivpu_device *vdev, bool enable)
+static void pwr_island_trickle_drive(struct ivpu_device *vdev, bool enable)
{
- u32 val = REGV_RD32(VPU_40XX_HOST_SS_AON_PWR_ISLAND_TRICKLE_EN0);
+ u32 val = REGV_RD32(VPU_37XX_HOST_SS_AON_PWR_ISLAND_TRICKLE_EN0);
if (enable)
- val = REG_SET_FLD(VPU_40XX_HOST_SS_AON_PWR_ISLAND_TRICKLE_EN0, CSS_CPU, val);
+ val = REG_SET_FLD(VPU_37XX_HOST_SS_AON_PWR_ISLAND_TRICKLE_EN0, MSS_CPU, val);
else
- val = REG_CLR_FLD(VPU_40XX_HOST_SS_AON_PWR_ISLAND_TRICKLE_EN0, CSS_CPU, val);
+ val = REG_CLR_FLD(VPU_37XX_HOST_SS_AON_PWR_ISLAND_TRICKLE_EN0, MSS_CPU, val);
- REGV_WR32(VPU_40XX_HOST_SS_AON_PWR_ISLAND_TRICKLE_EN0, val);
+ REGV_WR32(VPU_37XX_HOST_SS_AON_PWR_ISLAND_TRICKLE_EN0, val);
}
-static void pwr_island_drive_37xx(struct ivpu_device *vdev, bool enable)
+static void pwr_island_drive(struct ivpu_device *vdev, bool enable)
{
u32 val = REGV_RD32(VPU_37XX_HOST_SS_AON_PWR_ISLAND_EN0);
@@ -316,29 +223,11 @@ static void pwr_island_drive_37xx(struct ivpu_device *vdev, bool enable)
REGV_WR32(VPU_37XX_HOST_SS_AON_PWR_ISLAND_EN0, val);
}
-static void pwr_island_drive_40xx(struct ivpu_device *vdev, bool enable)
-{
- u32 val = REGV_RD32(VPU_40XX_HOST_SS_AON_PWR_ISLAND_EN0);
-
- if (enable)
- val = REG_SET_FLD(VPU_40XX_HOST_SS_AON_PWR_ISLAND_EN0, CSS_CPU, val);
- else
- val = REG_CLR_FLD(VPU_40XX_HOST_SS_AON_PWR_ISLAND_EN0, CSS_CPU, val);
-
- REGV_WR32(VPU_40XX_HOST_SS_AON_PWR_ISLAND_EN0, val);
-}
-
static void pwr_island_enable(struct ivpu_device *vdev)
{
- if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX) {
- pwr_island_trickle_drive_37xx(vdev, true);
- ndelay(500);
- pwr_island_drive_37xx(vdev, true);
- } else {
- pwr_island_trickle_drive_40xx(vdev, true);
- ndelay(500);
- pwr_island_drive_40xx(vdev, true);
- }
+ pwr_island_trickle_drive(vdev, true);
+ ndelay(500);
+ pwr_island_drive(vdev, true);
}
static int wait_for_pwr_island_status(struct ivpu_device *vdev, u32 exp_val)
@@ -346,15 +235,11 @@ static int wait_for_pwr_island_status(struct ivpu_device *vdev, u32 exp_val)
if (IVPU_WA(punit_disabled))
return 0;
- if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX)
- return REGV_POLL_FLD(VPU_37XX_HOST_SS_AON_PWR_ISLAND_STATUS0, MSS_CPU, exp_val,
- vdev->timeout.pwr_island_status);
- else
- return REGV_POLL_FLD(VPU_40XX_HOST_SS_AON_PWR_ISLAND_STATUS0, CSS_CPU, exp_val,
- vdev->timeout.pwr_island_status);
+ return REGV_POLL_FLD(VPU_37XX_HOST_SS_AON_PWR_ISLAND_STATUS0, MSS_CPU, exp_val,
+ vdev->timeout.pwr_island_status);
}
-static void pwr_island_isolation_drive_37xx(struct ivpu_device *vdev, bool enable)
+static void pwr_island_isolation_drive(struct ivpu_device *vdev, bool enable)
{
u32 val = REGV_RD32(VPU_37XX_HOST_SS_AON_PWR_ISO_EN0);
@@ -366,26 +251,6 @@ static void pwr_island_isolation_drive_37xx(struct ivpu_device *vdev, bool enabl
REGV_WR32(VPU_37XX_HOST_SS_AON_PWR_ISO_EN0, val);
}
-static void pwr_island_isolation_drive_40xx(struct ivpu_device *vdev, bool enable)
-{
- u32 val = REGV_RD32(VPU_40XX_HOST_SS_AON_PWR_ISO_EN0);
-
- if (enable)
- val = REG_SET_FLD(VPU_40XX_HOST_SS_AON_PWR_ISO_EN0, CSS_CPU, val);
- else
- val = REG_CLR_FLD(VPU_40XX_HOST_SS_AON_PWR_ISO_EN0, CSS_CPU, val);
-
- REGV_WR32(VPU_40XX_HOST_SS_AON_PWR_ISO_EN0, val);
-}
-
-static void pwr_island_isolation_drive(struct ivpu_device *vdev, bool enable)
-{
- if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX)
- pwr_island_isolation_drive_37xx(vdev, enable);
- else
- pwr_island_isolation_drive_40xx(vdev, enable);
-}
-
static void pwr_island_isolation_disable(struct ivpu_device *vdev)
{
pwr_island_isolation_drive(vdev, false);
@@ -485,7 +350,7 @@ static void host_ss_rst_enable(struct ivpu_device *vdev)
host_ss_rst_drive(vdev, true);
}
-static void host_ss_noc_qreqn_top_socmmio_drive_37xx(struct ivpu_device *vdev, bool enable)
+static void host_ss_noc_qreqn_top_socmmio_drive(struct ivpu_device *vdev, bool enable)
{
u32 val = REGV_RD32(VPU_37XX_HOST_SS_NOC_QREQN);
@@ -496,25 +361,6 @@ static void host_ss_noc_qreqn_top_socmmio_drive_37xx(struct ivpu_device *vdev, b
REGV_WR32(VPU_37XX_HOST_SS_NOC_QREQN, val);
}
-static void host_ss_noc_qreqn_top_socmmio_drive_40xx(struct ivpu_device *vdev, bool enable)
-{
- u32 val = REGV_RD32(VPU_40XX_HOST_SS_NOC_QREQN);
-
- if (enable)
- val = REG_SET_FLD(VPU_40XX_HOST_SS_NOC_QREQN, TOP_SOCMMIO, val);
- else
- val = REG_CLR_FLD(VPU_40XX_HOST_SS_NOC_QREQN, TOP_SOCMMIO, val);
- REGV_WR32(VPU_40XX_HOST_SS_NOC_QREQN, val);
-}
-
-static void host_ss_noc_qreqn_top_socmmio_drive(struct ivpu_device *vdev, bool enable)
-{
- if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX)
- host_ss_noc_qreqn_top_socmmio_drive_37xx(vdev, enable);
- else
- host_ss_noc_qreqn_top_socmmio_drive_40xx(vdev, enable);
-}
-
static int host_ss_axi_drive(struct ivpu_device *vdev, bool enable)
{
int ret;
@@ -536,17 +382,17 @@ static int host_ss_axi_drive(struct ivpu_device *vdev, bool enable)
static void top_noc_qreqn_drive_40xx(struct ivpu_device *vdev, bool enable)
{
- u32 val = REGV_RD32(VPU_40XX_TOP_NOC_QREQN);
+ u32 val = REGV_RD32(VPU_37XX_TOP_NOC_QREQN);
if (enable) {
- val = REG_SET_FLD(VPU_40XX_TOP_NOC_QREQN, CPU_CTRL, val);
+ val = REG_SET_FLD(VPU_37XX_TOP_NOC_QREQN, CPU_CTRL, val);
val = REG_SET_FLD(VPU_40XX_TOP_NOC_QREQN, HOSTIF_L2CACHE, val);
} else {
- val = REG_CLR_FLD(VPU_40XX_TOP_NOC_QREQN, CPU_CTRL, val);
+ val = REG_CLR_FLD(VPU_37XX_TOP_NOC_QREQN, CPU_CTRL, val);
val = REG_CLR_FLD(VPU_40XX_TOP_NOC_QREQN, HOSTIF_L2CACHE, val);
}
- REGV_WR32(VPU_40XX_TOP_NOC_QREQN, val);
+ REGV_WR32(VPU_37XX_TOP_NOC_QREQN, val);
}
static void top_noc_qreqn_drive_37xx(struct ivpu_device *vdev, bool enable)
@@ -590,9 +436,9 @@ static int top_noc_qacceptn_check_37xx(struct ivpu_device *vdev, u32 exp_val)
static int top_noc_qacceptn_check_40xx(struct ivpu_device *vdev, u32 exp_val)
{
- u32 val = REGV_RD32(VPU_40XX_TOP_NOC_QACCEPTN);
+ u32 val = REGV_RD32(VPU_37XX_TOP_NOC_QACCEPTN);
- if (!REG_TEST_FLD_NUM(VPU_40XX_TOP_NOC_QACCEPTN, CPU_CTRL, exp_val, val) ||
+ if (!REG_TEST_FLD_NUM(VPU_37XX_TOP_NOC_QACCEPTN, CPU_CTRL, exp_val, val) ||
!REG_TEST_FLD_NUM(VPU_40XX_TOP_NOC_QACCEPTN, HOSTIF_L2CACHE, exp_val, val))
return -EIO;
@@ -620,9 +466,9 @@ static int top_noc_qdeny_check_37xx(struct ivpu_device *vdev, u32 exp_val)
static int top_noc_qdeny_check_40xx(struct ivpu_device *vdev, u32 exp_val)
{
- u32 val = REGV_RD32(VPU_40XX_TOP_NOC_QDENY);
+ u32 val = REGV_RD32(VPU_37XX_TOP_NOC_QDENY);
- if (!REG_TEST_FLD_NUM(VPU_40XX_TOP_NOC_QDENY, CPU_CTRL, exp_val, val) ||
+ if (!REG_TEST_FLD_NUM(VPU_37XX_TOP_NOC_QDENY, CPU_CTRL, exp_val, val) ||
!REG_TEST_FLD_NUM(VPU_40XX_TOP_NOC_QDENY, HOSTIF_L2CACHE, exp_val, val))
return -EIO;
@@ -675,35 +521,19 @@ static void dpu_active_drive_37xx(struct ivpu_device *vdev, bool enable)
static void pwr_island_delay_set(struct ivpu_device *vdev)
{
- bool high = vdev->hw->pll.profiling_freq == PLL_PROFILING_FREQ_HIGH;
- u32 post, post1, post2, status;
+ switch (ivpu_hw_ip_gen(vdev)) {
+ case IVPU_HW_IP_37XX:
+ case IVPU_HW_IP_40XX:
+ return;
- if (ivpu_hw_ip_gen(vdev) < IVPU_HW_IP_50XX)
+ case IVPU_HW_IP_50XX:
+ pwr_island_delay_set_50xx(vdev);
return;
- switch (ivpu_device_id(vdev)) {
- case PCI_DEVICE_ID_WCL:
- case PCI_DEVICE_ID_PTL_P:
- post = high ? 18 : 0;
- post1 = 0;
- post2 = 0;
- status = high ? 46 : 3;
- break;
-
- case PCI_DEVICE_ID_NVL:
- post = high ? 198 : 17;
- post1 = 0;
- post2 = high ? 198 : 17;
- status = 0;
- break;
-
- default:
- dump_stack();
- ivpu_err(vdev, "Unknown device ID\n");
+ case IVPU_HW_IP_60XX:
+ pwr_island_delay_set_60xx(vdev);
return;
}
-
- pwr_island_delay_set_50xx(vdev, post, post1, post2, status);
}
int ivpu_hw_ip_pwr_domain_enable(struct ivpu_device *vdev)
@@ -760,7 +590,7 @@ static void ivpu_hw_ip_snoop_disable_37xx(struct ivpu_device *vdev)
static void ivpu_hw_ip_snoop_disable_40xx(struct ivpu_device *vdev)
{
- u32 val = REGV_RD32(VPU_40XX_HOST_IF_TCU_PTW_OVERRIDES);
+ u32 val = REGV_RD32(VPU_37XX_HOST_IF_TCU_PTW_OVERRIDES);
val = REG_SET_FLD(VPU_40XX_HOST_IF_TCU_PTW_OVERRIDES, SNOOP_OVERRIDE_EN, val);
val = REG_SET_FLD(VPU_40XX_HOST_IF_TCU_PTW_OVERRIDES, AW_SNOOP_OVERRIDE, val);
@@ -770,7 +600,7 @@ static void ivpu_hw_ip_snoop_disable_40xx(struct ivpu_device *vdev)
else
val = REG_CLR_FLD(VPU_40XX_HOST_IF_TCU_PTW_OVERRIDES, AR_SNOOP_OVERRIDE, val);
- REGV_WR32(VPU_40XX_HOST_IF_TCU_PTW_OVERRIDES, val);
+ REGV_WR32(VPU_37XX_HOST_IF_TCU_PTW_OVERRIDES, val);
}
void ivpu_hw_ip_snoop_disable(struct ivpu_device *vdev)
@@ -795,24 +625,29 @@ static void ivpu_hw_ip_tbu_mmu_enable_37xx(struct ivpu_device *vdev)
static void ivpu_hw_ip_tbu_mmu_enable_40xx(struct ivpu_device *vdev)
{
- u32 val = REGV_RD32(VPU_40XX_HOST_IF_TBU_MMUSSIDV);
+ u32 val = REGV_RD32(VPU_37XX_HOST_IF_TBU_MMUSSIDV);
- val = REG_SET_FLD(VPU_40XX_HOST_IF_TBU_MMUSSIDV, TBU0_AWMMUSSIDV, val);
- val = REG_SET_FLD(VPU_40XX_HOST_IF_TBU_MMUSSIDV, TBU0_ARMMUSSIDV, val);
- val = REG_SET_FLD(VPU_40XX_HOST_IF_TBU_MMUSSIDV, TBU1_AWMMUSSIDV, val);
- val = REG_SET_FLD(VPU_40XX_HOST_IF_TBU_MMUSSIDV, TBU1_ARMMUSSIDV, val);
- val = REG_SET_FLD(VPU_40XX_HOST_IF_TBU_MMUSSIDV, TBU2_AWMMUSSIDV, val);
- val = REG_SET_FLD(VPU_40XX_HOST_IF_TBU_MMUSSIDV, TBU2_ARMMUSSIDV, val);
+ val = REG_SET_FLD(VPU_37XX_HOST_IF_TBU_MMUSSIDV, TBU0_AWMMUSSIDV, val);
+ val = REG_SET_FLD(VPU_37XX_HOST_IF_TBU_MMUSSIDV, TBU0_ARMMUSSIDV, val);
+ val = REG_SET_FLD(VPU_37XX_HOST_IF_TBU_MMUSSIDV, TBU1_AWMMUSSIDV, val);
+ val = REG_SET_FLD(VPU_37XX_HOST_IF_TBU_MMUSSIDV, TBU1_ARMMUSSIDV, val);
+ val = REG_SET_FLD(VPU_37XX_HOST_IF_TBU_MMUSSIDV, TBU2_AWMMUSSIDV, val);
+ val = REG_SET_FLD(VPU_37XX_HOST_IF_TBU_MMUSSIDV, TBU2_ARMMUSSIDV, val);
- REGV_WR32(VPU_40XX_HOST_IF_TBU_MMUSSIDV, val);
+ REGV_WR32(VPU_37XX_HOST_IF_TBU_MMUSSIDV, val);
}
void ivpu_hw_ip_tbu_mmu_enable(struct ivpu_device *vdev)
{
- if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX)
+ switch (ivpu_hw_ip_gen(vdev)) {
+ case IVPU_HW_IP_37XX:
return ivpu_hw_ip_tbu_mmu_enable_37xx(vdev);
- else
+
+ case IVPU_HW_IP_40XX:
+ case IVPU_HW_IP_50XX:
+ case IVPU_HW_IP_60XX:
return ivpu_hw_ip_tbu_mmu_enable_40xx(vdev);
+ }
}
static inline u64 get_entry_point_addr(struct ivpu_device *vdev)
@@ -936,29 +771,22 @@ static int soc_cpu_boot_60xx(struct ivpu_device *vdev)
int ivpu_hw_ip_soc_cpu_boot(struct ivpu_device *vdev)
{
- int ret;
+ ivpu_dbg(vdev, PM, "Booting firmware, mode: %s\n",
+ ivpu_fw_is_warm_boot(vdev) ? "warm boot" : "cold boot");
switch (ivpu_hw_ip_gen(vdev)) {
case IVPU_HW_IP_37XX:
- ret = soc_cpu_boot_37xx(vdev);
- break;
+ return soc_cpu_boot_37xx(vdev);
case IVPU_HW_IP_40XX:
case IVPU_HW_IP_50XX:
- ret = soc_cpu_boot_40xx(vdev);
- break;
+ return soc_cpu_boot_40xx(vdev);
- default:
- ret = soc_cpu_boot_60xx(vdev);
+ case IVPU_HW_IP_60XX:
+ return soc_cpu_boot_60xx(vdev);
}
- if (ret)
- return ret;
-
- ivpu_dbg(vdev, PM, "Booting firmware, mode: %s\n",
- ivpu_fw_is_warm_boot(vdev) ? "warm boot" : "cold boot");
-
- return 0;
+ return -EINVAL;
}
static void wdt_disable_37xx(struct ivpu_device *vdev)
@@ -1002,55 +830,30 @@ void ivpu_hw_ip_wdt_disable(struct ivpu_device *vdev)
return wdt_disable_40xx(vdev);
}
-static u32 ipc_rx_count_get_37xx(struct ivpu_device *vdev)
+u32 ivpu_hw_ip_ipc_rx_count_get(struct ivpu_device *vdev)
{
u32 count = readl(vdev->regv + VPU_37XX_HOST_SS_TIM_IPC_FIFO_STAT);
return REG_GET_FLD(VPU_37XX_HOST_SS_TIM_IPC_FIFO_STAT, FILL_LEVEL, count);
}
-static u32 ipc_rx_count_get_40xx(struct ivpu_device *vdev)
-{
- u32 count = readl(vdev->regv + VPU_40XX_HOST_SS_TIM_IPC_FIFO_STAT);
-
- return REG_GET_FLD(VPU_40XX_HOST_SS_TIM_IPC_FIFO_STAT, FILL_LEVEL, count);
-}
-
-u32 ivpu_hw_ip_ipc_rx_count_get(struct ivpu_device *vdev)
-{
- if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX)
- return ipc_rx_count_get_37xx(vdev);
- else
- return ipc_rx_count_get_40xx(vdev);
-}
-
void ivpu_hw_ip_irq_enable(struct ivpu_device *vdev)
{
- if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX) {
- REGV_WR32(VPU_37XX_HOST_SS_FW_SOC_IRQ_EN, ITF_FIREWALL_VIOLATION_MASK_37XX);
- REGV_WR64(VPU_37XX_HOST_SS_ICB_ENABLE_0, ICB_0_1_IRQ_MASK_37XX);
- } else {
- REGV_WR32(VPU_40XX_HOST_SS_FW_SOC_IRQ_EN, ITF_FIREWALL_VIOLATION_MASK_40XX);
- REGV_WR64(VPU_40XX_HOST_SS_ICB_ENABLE_0, ICB_0_1_IRQ_MASK_40XX);
- }
+ REGV_WR32(VPU_37XX_HOST_SS_FW_SOC_IRQ_EN, ITF_FIREWALL_VIOLATION_MASK);
+ REGV_WR64(VPU_37XX_HOST_SS_ICB_ENABLE_0, ICB_0_1_IRQ_MASK);
}
void ivpu_hw_ip_irq_disable(struct ivpu_device *vdev)
{
- if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX) {
- REGV_WR64(VPU_37XX_HOST_SS_ICB_ENABLE_0, 0x0ull);
- REGV_WR32(VPU_37XX_HOST_SS_FW_SOC_IRQ_EN, 0x0);
- } else {
- REGV_WR64(VPU_40XX_HOST_SS_ICB_ENABLE_0, 0x0ull);
- REGV_WR32(VPU_40XX_HOST_SS_FW_SOC_IRQ_EN, 0x0ul);
- }
+ REGV_WR64(VPU_37XX_HOST_SS_ICB_ENABLE_0, 0x0ull);
+ REGV_WR32(VPU_37XX_HOST_SS_FW_SOC_IRQ_EN, 0x0);
}
-static void diagnose_failure_37xx(struct ivpu_device *vdev)
+void ivpu_hw_ip_diagnose_failure(struct ivpu_device *vdev)
{
- u32 reg = REGV_RD32(VPU_37XX_HOST_SS_ICB_STATUS_0) & ICB_0_IRQ_MASK_37XX;
+ u32 reg = REGV_RD32(VPU_37XX_HOST_SS_ICB_STATUS_0) & ICB_0_IRQ_MASK;
- if (ipc_rx_count_get_37xx(vdev))
+ if (ivpu_hw_ip_ipc_rx_count_get(vdev))
ivpu_err(vdev, "IPC FIFO queue not empty, missed IPC IRQ");
if (REG_TEST_FLD(VPU_37XX_HOST_SS_ICB_STATUS_0, CPU_INT_REDIRECT_0_INT, reg))
@@ -1063,37 +866,9 @@ static void diagnose_failure_37xx(struct ivpu_device *vdev)
ivpu_err(vdev, "NOC Firewall irq detected\n");
}
-static void diagnose_failure_40xx(struct ivpu_device *vdev)
-{
- u32 reg = REGV_RD32(VPU_40XX_HOST_SS_ICB_STATUS_0) & ICB_0_IRQ_MASK_40XX;
-
- if (ipc_rx_count_get_40xx(vdev))
- ivpu_err(vdev, "IPC FIFO queue not empty, missed IPC IRQ");
-
- if (REG_TEST_FLD(VPU_40XX_HOST_SS_ICB_STATUS_0, CPU_INT_REDIRECT_0_INT, reg))
- ivpu_err(vdev, "WDT MSS timeout detected\n");
-
- if (REG_TEST_FLD(VPU_40XX_HOST_SS_ICB_STATUS_0, CPU_INT_REDIRECT_1_INT, reg))
- ivpu_err(vdev, "WDT NCE timeout detected\n");
-
- if (REG_TEST_FLD(VPU_40XX_HOST_SS_ICB_STATUS_0, NOC_FIREWALL_INT, reg))
- ivpu_err(vdev, "NOC Firewall irq detected\n");
-}
-
-void ivpu_hw_ip_diagnose_failure(struct ivpu_device *vdev)
-{
- if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX)
- diagnose_failure_37xx(vdev);
- else
- diagnose_failure_40xx(vdev);
-}
-
void ivpu_hw_ip_irq_clear(struct ivpu_device *vdev)
{
- if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX)
- REGV_WR64(VPU_37XX_HOST_SS_ICB_CLEAR_0, ICB_0_1_IRQ_MASK_37XX);
- else
- REGV_WR64(VPU_40XX_HOST_SS_ICB_CLEAR_0, ICB_0_1_IRQ_MASK_40XX);
+ REGV_WR64(VPU_37XX_HOST_SS_ICB_CLEAR_0, ICB_0_1_IRQ_MASK);
}
static void irq_wdt_nce_handler(struct ivpu_device *vdev)
@@ -1116,9 +891,9 @@ static void irq_noc_firewall_handler(struct ivpu_device *vdev)
}
/* Handler for IRQs from NPU core */
-bool ivpu_hw_ip_irq_handler_37xx(struct ivpu_device *vdev, int irq)
+bool ivpu_hw_ip_irq_handler(struct ivpu_device *vdev, int irq)
{
- u32 status = REGV_RD32(VPU_37XX_HOST_SS_ICB_STATUS_0) & ICB_0_IRQ_MASK_37XX;
+ u32 status = REGV_RD32(VPU_37XX_HOST_SS_ICB_STATUS_0) & ICB_0_IRQ_MASK;
if (!status)
return false;
@@ -1149,40 +924,6 @@ bool ivpu_hw_ip_irq_handler_37xx(struct ivpu_device *vdev, int irq)
return true;
}
-/* Handler for IRQs from NPU core */
-bool ivpu_hw_ip_irq_handler_40xx(struct ivpu_device *vdev, int irq)
-{
- u32 status = REGV_RD32(VPU_40XX_HOST_SS_ICB_STATUS_0) & ICB_0_IRQ_MASK_40XX;
-
- if (!status)
- return false;
-
- REGV_WR32(VPU_40XX_HOST_SS_ICB_CLEAR_0, status);
-
- if (REG_TEST_FLD(VPU_40XX_HOST_SS_ICB_STATUS_0, MMU_IRQ_0_INT, status))
- ivpu_mmu_irq_evtq_handler(vdev);
-
- if (REG_TEST_FLD(VPU_40XX_HOST_SS_ICB_STATUS_0, HOST_IPC_FIFO_INT, status))
- ivpu_ipc_irq_handler(vdev);
-
- if (REG_TEST_FLD(VPU_40XX_HOST_SS_ICB_STATUS_0, MMU_IRQ_1_INT, status))
- ivpu_dbg(vdev, IRQ, "MMU sync complete\n");
-
- if (REG_TEST_FLD(VPU_40XX_HOST_SS_ICB_STATUS_0, MMU_IRQ_2_INT, status))
- ivpu_mmu_irq_gerr_handler(vdev);
-
- if (REG_TEST_FLD(VPU_40XX_HOST_SS_ICB_STATUS_0, CPU_INT_REDIRECT_0_INT, status))
- irq_wdt_mss_handler(vdev);
-
- if (REG_TEST_FLD(VPU_40XX_HOST_SS_ICB_STATUS_0, CPU_INT_REDIRECT_1_INT, status))
- irq_wdt_nce_handler(vdev);
-
- if (REG_TEST_FLD(VPU_40XX_HOST_SS_ICB_STATUS_0, NOC_FIREWALL_INT, status))
- irq_noc_firewall_handler(vdev);
-
- return true;
-}
-
static void db_set_37xx(struct ivpu_device *vdev, u32 db_id)
{
u32 reg_stride = VPU_37XX_CPU_SS_DOORBELL_1 - VPU_37XX_CPU_SS_DOORBELL_0;
@@ -1209,10 +950,7 @@ void ivpu_hw_ip_db_set(struct ivpu_device *vdev, u32 db_id)
u32 ivpu_hw_ip_ipc_rx_addr_get(struct ivpu_device *vdev)
{
- if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX)
- return REGV_RD32(VPU_37XX_HOST_SS_TIM_IPC_FIFO_ATM);
- else
- return REGV_RD32(VPU_40XX_HOST_SS_TIM_IPC_FIFO_ATM);
+ return REGV_RD32(VPU_37XX_HOST_SS_TIM_IPC_FIFO_ATM);
}
void ivpu_hw_ip_ipc_tx_set(struct ivpu_device *vdev, u32 vpu_addr)
diff --git a/drivers/accel/ivpu/ivpu_hw_ip.h b/drivers/accel/ivpu/ivpu_hw_ip.h
index dbbcdd10a5f8..59ef904c08da 100644
--- a/drivers/accel/ivpu/ivpu_hw_ip.h
+++ b/drivers/accel/ivpu/ivpu_hw_ip.h
@@ -22,8 +22,7 @@ void ivpu_hw_ip_wdt_disable(struct ivpu_device *vdev);
void ivpu_hw_ip_diagnose_failure(struct ivpu_device *vdev);
u32 ivpu_hw_ip_ipc_rx_count_get(struct ivpu_device *vdev);
void ivpu_hw_ip_irq_clear(struct ivpu_device *vdev);
-bool ivpu_hw_ip_irq_handler_37xx(struct ivpu_device *vdev, int irq);
-bool ivpu_hw_ip_irq_handler_40xx(struct ivpu_device *vdev, int irq);
+bool ivpu_hw_ip_irq_handler(struct ivpu_device *vdev, int irq);
void ivpu_hw_ip_db_set(struct ivpu_device *vdev, u32 db_id);
u32 ivpu_hw_ip_ipc_rx_addr_get(struct ivpu_device *vdev);
void ivpu_hw_ip_ipc_tx_set(struct ivpu_device *vdev, u32 vpu_addr);
diff --git a/drivers/accel/ivpu/ivpu_hw_37xx_reg.h b/drivers/accel/ivpu/ivpu_hw_ip_reg.h
index cf5e2f01049c..126df1012f23 100644
--- a/drivers/accel/ivpu/ivpu_hw_37xx_reg.h
+++ b/drivers/accel/ivpu/ivpu_hw_ip_reg.h
@@ -1,18 +1,28 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright (C) 2020-2023 Intel Corporation
+ * Copyright (C) 2020-2026 Intel Corporation
*/
-#ifndef __IVPU_HW_37XX_REG_H__
-#define __IVPU_HW_37XX_REG_H__
+#ifndef __IVPU_HW_IP_REG_H__
+#define __IVPU_HW_IP_REG_H__
#include <linux/bits.h>
+#define VPU_40XX_HOST_SS_CPR_CLK_EN 0x00000080u
+#define VPU_40XX_HOST_SS_CPR_CLK_EN_TOP_NOC_MASK BIT_MASK(1)
+#define VPU_40XX_HOST_SS_CPR_CLK_EN_DSS_MAS_MASK BIT_MASK(10)
+#define VPU_40XX_HOST_SS_CPR_CLK_EN_CSS_MAS_MASK BIT_MASK(11)
+
#define VPU_37XX_HOST_SS_CPR_CLK_SET 0x00000084u
#define VPU_37XX_HOST_SS_CPR_CLK_SET_TOP_NOC_MASK BIT_MASK(1)
#define VPU_37XX_HOST_SS_CPR_CLK_SET_DSS_MAS_MASK BIT_MASK(10)
#define VPU_37XX_HOST_SS_CPR_CLK_SET_MSS_MAS_MASK BIT_MASK(11)
+#define VPU_40XX_HOST_SS_CPR_RST_EN 0x00000090u
+#define VPU_40XX_HOST_SS_CPR_RST_EN_TOP_NOC_MASK BIT_MASK(1)
+#define VPU_40XX_HOST_SS_CPR_RST_EN_DSS_MAS_MASK BIT_MASK(10)
+#define VPU_40XX_HOST_SS_CPR_RST_EN_CSS_MAS_MASK BIT_MASK(11)
+
#define VPU_37XX_HOST_SS_CPR_RST_SET 0x00000094u
#define VPU_37XX_HOST_SS_CPR_RST_SET_TOP_NOC_MASK BIT_MASK(1)
#define VPU_37XX_HOST_SS_CPR_RST_SET_DSS_MAS_MASK BIT_MASK(10)
@@ -29,6 +39,8 @@
#define VPU_37XX_HOST_SS_HW_VERSION_SOC_NUMBER_MASK GENMASK(15, 8)
#define VPU_37XX_HOST_SS_HW_VERSION_VPU_GENERATION_MASK GENMASK(23, 16)
+#define VPU_40XX_HOST_SS_SW_VERSION 0x0000010cu
+
#define VPU_37XX_HOST_SS_GEN_CTRL 0x00000118u
#define VPU_37XX_HOST_SS_GEN_CTRL_PS_MASK GENMASK(31, 29)
@@ -44,14 +56,17 @@
#define VPU_37XX_TOP_NOC_QREQN 0x00000160u
#define VPU_37XX_TOP_NOC_QREQN_CPU_CTRL_MASK BIT_MASK(0)
#define VPU_37XX_TOP_NOC_QREQN_HOSTIF_L2CACHE_MASK BIT_MASK(1)
+#define VPU_40XX_TOP_NOC_QREQN_HOSTIF_L2CACHE_MASK BIT_MASK(2)
#define VPU_37XX_TOP_NOC_QACCEPTN 0x00000164u
#define VPU_37XX_TOP_NOC_QACCEPTN_CPU_CTRL_MASK BIT_MASK(0)
#define VPU_37XX_TOP_NOC_QACCEPTN_HOSTIF_L2CACHE_MASK BIT_MASK(1)
+#define VPU_40XX_TOP_NOC_QACCEPTN_HOSTIF_L2CACHE_MASK BIT_MASK(2)
#define VPU_37XX_TOP_NOC_QDENY 0x00000168u
#define VPU_37XX_TOP_NOC_QDENY_CPU_CTRL_MASK BIT_MASK(0)
#define VPU_37XX_TOP_NOC_QDENY_HOSTIF_L2CACHE_MASK BIT_MASK(1)
+#define VPU_40XX_TOP_NOC_QDENY_HOSTIF_L2CACHE_MASK BIT_MASK(2)
#define VPU_37XX_HOST_SS_FW_SOC_IRQ_EN 0x00000170u
#define VPU_37XX_HOST_SS_FW_SOC_IRQ_EN_CSS_ROM_CMX_MASK BIT_MASK(0)
@@ -83,6 +98,7 @@
#define VPU_37XX_HOST_SS_ICB_CLEAR_0 0x00010220u
#define VPU_37XX_HOST_SS_ICB_CLEAR_1 0x00010224u
#define VPU_37XX_HOST_SS_ICB_ENABLE_0 0x00010240u
+#define VPU_40XX_HOST_SS_ICB_ENABLE_1 0x00010244u
#define VPU_37XX_HOST_SS_TIM_IPC_FIFO_ATM 0x000200f4u
@@ -104,12 +120,29 @@
#define VPU_37XX_HOST_SS_AON_PWR_ISLAND_STATUS0 0x0003002cu
#define VPU_37XX_HOST_SS_AON_PWR_ISLAND_STATUS0_MSS_CPU_MASK BIT_MASK(3)
+#define VPU_50XX_HOST_SS_AON_PWR_ISLAND_EN_POST_DLY 0x00030068u
+#define VPU_50XX_HOST_SS_AON_PWR_ISLAND_EN_POST_DLY_POST_DLY_MASK GENMASK(7, 0)
+#define VPU_50XX_HOST_SS_AON_PWR_ISLAND_EN_POST_DLY_POST1_DLY_MASK GENMASK(15, 8)
+#define VPU_50XX_HOST_SS_AON_PWR_ISLAND_EN_POST_DLY_POST2_DLY_MASK GENMASK(23, 16)
+
+#define VPU_50XX_HOST_SS_AON_PWR_ISLAND_STATUS_DLY 0x0003006cu
+#define VPU_50XX_HOST_SS_AON_PWR_ISLAND_STATUS_DLY_STATUS_DLY_MASK GENMASK(7, 0)
+
#define VPU_37XX_HOST_SS_AON_VPU_IDLE_GEN 0x00030200u
#define VPU_37XX_HOST_SS_AON_VPU_IDLE_GEN_EN_MASK BIT_MASK(0)
+#define VPU_40XX_HOST_SS_AON_VPU_IDLE_GEN_HW_PG_EN_MASK BIT_MASK(1)
#define VPU_37XX_HOST_SS_AON_DPU_ACTIVE 0x00030204u
#define VPU_37XX_HOST_SS_AON_DPU_ACTIVE_DPU_ACTIVE_MASK BIT_MASK(0)
+#define VPU_50XX_HOST_SS_AON_FABRIC_REQ_OVERRIDE 0x00030210u
+#define VPU_50XX_HOST_SS_AON_FABRIC_REQ_OVERRIDE_REQ_OVERRIDE_MASK BIT_MASK(0)
+
+#define VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO 0x00040040u
+#define VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO_DONE_MASK BIT_MASK(0)
+#define VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO_IOSF_RS_ID_MASK GENMASK(2, 1)
+#define VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO_IMAGE_LOCATION_MASK GENMASK(31, 3)
+
#define VPU_37XX_HOST_SS_LOADING_ADDRESS_LO 0x00041040u
#define VPU_37XX_HOST_SS_LOADING_ADDRESS_LO_DONE_MASK BIT_MASK(0)
#define VPU_37XX_HOST_SS_LOADING_ADDRESS_LO_IOSF_RS_ID_MASK GENMASK(2, 1)
@@ -126,6 +159,9 @@
#define VPU_37XX_HOST_IF_TCU_PTW_OVERRIDES_NOSNOOP_OVERRIDE_EN_MASK BIT_MASK(3)
#define VPU_37XX_HOST_IF_TCU_PTW_OVERRIDES_AW_NOSNOOP_OVERRIDE_MASK BIT_MASK(4)
#define VPU_37XX_HOST_IF_TCU_PTW_OVERRIDES_AR_NOSNOOP_OVERRIDE_MASK BIT_MASK(5)
+#define VPU_40XX_HOST_IF_TCU_PTW_OVERRIDES_SNOOP_OVERRIDE_EN_MASK BIT_MASK(3)
+#define VPU_40XX_HOST_IF_TCU_PTW_OVERRIDES_AW_SNOOP_OVERRIDE_MASK BIT_MASK(4)
+#define VPU_40XX_HOST_IF_TCU_PTW_OVERRIDES_AR_SNOOP_OVERRIDE_MASK BIT_MASK(5)
#define VPU_37XX_HOST_IF_TCU_PTW_OVERRIDES_PTW_AW_CONTEXT_FLAG_MASK GENMASK(10, 6)
#define VPU_37XX_HOST_IF_TCU_PTW_OVERRIDES_PTW_AR_CONTEXT_FLAG_MASK GENMASK(15, 11)
@@ -141,6 +177,17 @@
#define VPU_37XX_HOST_IF_TBU_MMUSSIDV_TBU4_AWMMUSSIDV_MASK BIT_MASK(8)
#define VPU_37XX_HOST_IF_TBU_MMUSSIDV_TBU4_ARMMUSSIDV_MASK BIT_MASK(9)
+#define VPU_40XX_CPU_SS_CPR_NOC_QREQN 0x01010030u
+#define VPU_40XX_CPU_SS_CPR_NOC_QREQN_TOP_MMIO_MASK BIT_MASK(0)
+
+#define VPU_40XX_CPU_SS_CPR_NOC_QACCEPTN 0x01010034u
+#define VPU_40XX_CPU_SS_CPR_NOC_QACCEPTN_TOP_MMIO_MASK BIT_MASK(0)
+
+#define VPU_40XX_CPU_SS_CPR_NOC_QDENY 0x01010038u
+#define VPU_40XX_CPU_SS_CPR_NOC_QDENY_TOP_MMIO_MASK BIT_MASK(0)
+
+#define VPU_40XX_CPU_SS_TIM_PERF_EXT_FREE_CNT 0x01029008u
+
#define VPU_37XX_CPU_SS_DSU_LEON_RT_BASE 0x04000000u
#define VPU_37XX_CPU_SS_DSU_LEON_RT_DSU_CTRL 0x04000000u
#define VPU_37XX_CPU_SS_DSU_LEON_RT_PC_REG 0x04400010u
@@ -161,18 +208,32 @@
#define VPU_37XX_CPU_SS_MSSCPU_CPR_LEON_RT_VEC_IRQI_RSTVEC_MASK GENMASK(31, 4)
#define VPU_37XX_CPU_SS_TIM_WATCHDOG 0x0602009cu
+#define VPU_40XX_CPU_SS_TIM_WATCHDOG 0x0102009cu
+
#define VPU_37XX_CPU_SS_TIM_WDOG_EN 0x060200a4u
+#define VPU_40XX_CPU_SS_TIM_WDOG_EN 0x010200a4u
+
#define VPU_37XX_CPU_SS_TIM_SAFE 0x060200a8u
+#define VPU_40XX_CPU_SS_TIM_SAFE 0x010200a8u
+
#define VPU_37XX_CPU_SS_TIM_IPC_FIFO 0x060200f0u
+#define VPU_40XX_CPU_SS_TIM_IPC_FIFO 0x010200f0u
#define VPU_37XX_CPU_SS_TIM_GEN_CONFIG 0x06021008u
#define VPU_37XX_CPU_SS_TIM_GEN_CONFIG_WDOG_TO_INT_CLR_MASK BIT_MASK(9)
+#define VPU_40XX_CPU_SS_TIM_GEN_CONFIG 0x01021008u
+#define VPU_40XX_CPU_SS_TIM_GEN_CONFIG_WDOG_TO_INT_CLR_MASK BIT_MASK(9)
+
#define VPU_37XX_CPU_SS_TIM_PERF_FREE_CNT 0x06029000u
#define VPU_37XX_CPU_SS_DOORBELL_0 0x06300000u
#define VPU_37XX_CPU_SS_DOORBELL_0_SET_MASK BIT_MASK(0)
+#define VPU_40XX_CPU_SS_DOORBELL_0 0x01300000u
+#define VPU_40XX_CPU_SS_DOORBELL_0_SET_MASK BIT_MASK(0)
+
#define VPU_37XX_CPU_SS_DOORBELL_1 0x06301000u
+#define VPU_40XX_CPU_SS_DOORBELL_1 0x01301000u
-#endif /* __IVPU_HW_37XX_REG_H__ */
+#endif /* __IVPU_HW_IP_REG_H__ */
diff --git a/drivers/accel/ivpu/ivpu_pm.c b/drivers/accel/ivpu/ivpu_pm.c
index de0becbfdffb..aa813262253e 100644
--- a/drivers/accel/ivpu/ivpu_pm.c
+++ b/drivers/accel/ivpu/ivpu_pm.c
@@ -46,7 +46,6 @@ static void ivpu_pm_prepare_cold_boot(struct ivpu_device *vdev)
ivpu_cmdq_reset_all_contexts(vdev);
ivpu_ipc_reset(vdev);
ivpu_fw_log_reset(vdev);
- ivpu_fw_load(vdev);
fw->last_heartbeat = 0;
ivpu_dbg(vdev, FW_BOOT, "Cold boot entry point 0x%llx", vdev->fw->cold_boot_entry_point);
diff --git a/drivers/accel/qaic/mhi_controller.c b/drivers/accel/qaic/mhi_controller.c
index 40e6d262ef21..c720b70b1e0f 100644
--- a/drivers/accel/qaic/mhi_controller.c
+++ b/drivers/accel/qaic/mhi_controller.c
@@ -23,6 +23,7 @@ MODULE_PARM_DESC(mhi_timeout_ms, "MHI controller timeout value");
static const char *fw_image_paths[FAMILY_MAX] = {
[FAMILY_AIC100] = "qcom/aic100/sbl.bin",
[FAMILY_AIC200] = "qcom/aic200/sbl.bin",
+ [FAMILY_AIC200_VF] = NULL,
};
static const struct mhi_channel_config aic100_channels[] = {
@@ -691,6 +692,159 @@ static const struct mhi_channel_config aic200_channels[] = {
},
};
+static const struct mhi_channel_config aic200vf_channels[] = {
+ {
+ .name = "QAIC_LOOPBACK",
+ .num = 0,
+ .num_elements = 32,
+ .local_elements = 0,
+ .event_ring = 0,
+ .dir = DMA_TO_DEVICE,
+ .ee_mask = MHI_CH_EE_AMSS,
+ .pollcfg = 0,
+ .doorbell = MHI_DB_BRST_DISABLE,
+ .lpm_notify = false,
+ .offload_channel = false,
+ .doorbell_mode_switch = false,
+ .wake_capable = false,
+ },
+ {
+ .name = "QAIC_LOOPBACK",
+ .num = 1,
+ .num_elements = 32,
+ .local_elements = 0,
+ .event_ring = 0,
+ .dir = DMA_FROM_DEVICE,
+ .ee_mask = MHI_CH_EE_AMSS,
+ .pollcfg = 0,
+ .doorbell = MHI_DB_BRST_DISABLE,
+ .lpm_notify = false,
+ .offload_channel = false,
+ .doorbell_mode_switch = false,
+ .wake_capable = false,
+ },
+ {
+ .name = "QAIC_SSR",
+ .num = 6,
+ .num_elements = 32,
+ .local_elements = 0,
+ .event_ring = 0,
+ .dir = DMA_TO_DEVICE,
+ .ee_mask = MHI_CH_EE_AMSS,
+ .pollcfg = 0,
+ .doorbell = MHI_DB_BRST_DISABLE,
+ .lpm_notify = false,
+ .offload_channel = false,
+ .doorbell_mode_switch = false,
+ .wake_capable = false,
+ },
+ {
+ .name = "QAIC_SSR",
+ .num = 7,
+ .num_elements = 32,
+ .local_elements = 0,
+ .event_ring = 0,
+ .dir = DMA_FROM_DEVICE,
+ .ee_mask = MHI_CH_EE_AMSS,
+ .pollcfg = 0,
+ .doorbell = MHI_DB_BRST_DISABLE,
+ .lpm_notify = false,
+ .offload_channel = false,
+ .doorbell_mode_switch = false,
+ .wake_capable = false,
+ },
+ {
+ .name = "QAIC_CONTROL",
+ .num = 10,
+ .num_elements = 128,
+ .local_elements = 0,
+ .event_ring = 0,
+ .dir = DMA_TO_DEVICE,
+ .ee_mask = MHI_CH_EE_AMSS,
+ .pollcfg = 0,
+ .doorbell = MHI_DB_BRST_DISABLE,
+ .lpm_notify = false,
+ .offload_channel = false,
+ .doorbell_mode_switch = false,
+ .wake_capable = false,
+ },
+ {
+ .name = "QAIC_CONTROL",
+ .num = 11,
+ .num_elements = 128,
+ .local_elements = 0,
+ .event_ring = 0,
+ .dir = DMA_FROM_DEVICE,
+ .ee_mask = MHI_CH_EE_AMSS,
+ .pollcfg = 0,
+ .doorbell = MHI_DB_BRST_DISABLE,
+ .lpm_notify = false,
+ .offload_channel = false,
+ .doorbell_mode_switch = false,
+ .wake_capable = false,
+ },
+ {
+ .name = "QAIC_TELEMETRY",
+ .num = 16,
+ .num_elements = 32,
+ .local_elements = 0,
+ .event_ring = 0,
+ .dir = DMA_TO_DEVICE,
+ .ee_mask = MHI_CH_EE_AMSS,
+ .pollcfg = 0,
+ .doorbell = MHI_DB_BRST_DISABLE,
+ .lpm_notify = false,
+ .offload_channel = false,
+ .doorbell_mode_switch = false,
+ .wake_capable = false,
+ },
+ {
+ .name = "QAIC_TELEMETRY",
+ .num = 17,
+ .num_elements = 32,
+ .local_elements = 0,
+ .event_ring = 0,
+ .dir = DMA_FROM_DEVICE,
+ .ee_mask = MHI_CH_EE_AMSS,
+ .pollcfg = 0,
+ .doorbell = MHI_DB_BRST_DISABLE,
+ .lpm_notify = false,
+ .offload_channel = false,
+ .doorbell_mode_switch = false,
+ .wake_capable = false,
+ },
+ {
+ .name = "IPCR",
+ .num = 24,
+ .num_elements = 32,
+ .local_elements = 0,
+ .event_ring = 0,
+ .dir = DMA_TO_DEVICE,
+ .ee_mask = MHI_CH_EE_AMSS,
+ .pollcfg = 0,
+ .doorbell = MHI_DB_BRST_DISABLE,
+ .lpm_notify = false,
+ .offload_channel = false,
+ .doorbell_mode_switch = false,
+ .wake_capable = false,
+ },
+ {
+ .name = "IPCR",
+ .num = 25,
+ .num_elements = 32,
+ .local_elements = 0,
+ .event_ring = 0,
+ .dir = DMA_FROM_DEVICE,
+ .ee_mask = MHI_CH_EE_AMSS,
+ .pollcfg = 0,
+ .doorbell = MHI_DB_BRST_DISABLE,
+ .lpm_notify = false,
+ .offload_channel = false,
+ .doorbell_mode_switch = false,
+ .wake_capable = false,
+ },
+};
+
static struct mhi_event_config aic100_events[] = {
{
.num_elements = 32,
@@ -721,6 +875,21 @@ static struct mhi_event_config aic200_events[] = {
},
};
+static struct mhi_event_config aic200vf_events[] = {
+ {
+ .num_elements = 32,
+ .irq_moderation_ms = 0,
+ .irq = 0,
+ .channel = U32_MAX,
+ .priority = 1,
+ .mode = MHI_DB_BRST_DISABLE,
+ .data_type = MHI_ER_CTRL,
+ .hardware_event = false,
+ .client_managed = false,
+ .offload_channel = false,
+ },
+};
+
static struct mhi_controller_config mhi_cntrl_configs[] = {
[FAMILY_AIC100] = {
.max_channels = 128,
@@ -744,6 +913,17 @@ static struct mhi_controller_config mhi_cntrl_configs[] = {
.use_bounce_buf = false,
.m2_no_db = false,
},
+ [FAMILY_AIC200_VF] = {
+ .max_channels = 128,
+ .timeout_ms = 0, /* controlled by mhi_timeout */
+ .buf_len = 0,
+ .num_channels = ARRAY_SIZE(aic200vf_channels),
+ .ch_cfg = aic200vf_channels,
+ .num_events = ARRAY_SIZE(aic200vf_events),
+ .event_cfg = aic200vf_events,
+ .use_bounce_buf = false,
+ .m2_no_db = false,
+ },
};
static int mhi_read_reg(struct mhi_controller *mhi_cntrl, void __iomem *addr, u32 *out)
@@ -864,11 +1044,19 @@ struct mhi_controller *qaic_mhi_register_controller(struct pci_dev *pci_dev, voi
mhi_cntrl->fw_image = fw_image_paths[family];
- if (family == FAMILY_AIC200) {
+ switch (family) {
+ case FAMILY_AIC200:
mhi_cntrl->name = "AIC200";
mhi_cntrl->seg_len = SZ_512K;
- } else {
+ break;
+ case FAMILY_AIC200_VF:
+ mhi_cntrl->name = "AIC200_VF";
+ break;
+ case FAMILY_AIC100:
mhi_cntrl->name = "AIC100";
+ break;
+ default:
+ mhi_cntrl->name = NULL;
}
/* use latest configured timeout */
diff --git a/drivers/accel/qaic/qaic.h b/drivers/accel/qaic/qaic.h
index 02ca99000e2a..889fa51da7da 100644
--- a/drivers/accel/qaic/qaic.h
+++ b/drivers/accel/qaic/qaic.h
@@ -35,6 +35,7 @@
enum aic_families {
FAMILY_AIC100,
FAMILY_AIC200,
+ FAMILY_AIC200_VF,
FAMILY_MAX,
};
diff --git a/drivers/accel/qaic/qaic_data.c b/drivers/accel/qaic/qaic_data.c
index 4d55531bf1c9..ee35e13091b3 100644
--- a/drivers/accel/qaic/qaic_data.c
+++ b/drivers/accel/qaic/qaic_data.c
@@ -1840,15 +1840,16 @@ int qaic_perf_stats_bo_ioctl(struct drm_device *dev, void *data, struct drm_file
goto free_ent;
}
bo = to_qaic_bo(obj);
+ ret = mutex_lock_interruptible(&bo->lock);
+ if (ret)
+ goto put_obj;
if (!bo->sliced) {
- drm_gem_object_put(obj);
ret = -EINVAL;
- goto free_ent;
+ goto unlock_bo;
}
if (bo->dbc->id != args->hdr.dbc_id) {
- drm_gem_object_put(obj);
ret = -EINVAL;
- goto free_ent;
+ goto unlock_bo;
}
/*
* perf stats ioctl is called before wait ioctl is complete then
@@ -1864,7 +1865,12 @@ int qaic_perf_stats_bo_ioctl(struct drm_device *dev, void *data, struct drm_file
bo->perf_stats.req_received_ts), 1000);
ent[i].queue_level_before = bo->perf_stats.queue_level_before;
ent[i].num_queue_element = bo->total_slice_nents;
+unlock_bo:
+ mutex_unlock(&bo->lock);
+put_obj:
drm_gem_object_put(obj);
+ if (ret)
+ goto free_ent;
}
if (copy_to_user(u64_to_user_ptr(args->data), ent, args->hdr.count * sizeof(*ent)))
diff --git a/drivers/accel/qaic/qaic_drv.c b/drivers/accel/qaic/qaic_drv.c
index c1bb6db78d12..9e1e184efe0d 100644
--- a/drivers/accel/qaic/qaic_drv.c
+++ b/drivers/accel/qaic/qaic_drv.c
@@ -40,6 +40,7 @@ MODULE_IMPORT_NS("DMA_BUF");
#define PCI_DEVICE_ID_QCOM_AIC080 0xa080
#define PCI_DEVICE_ID_QCOM_AIC100 0xa100
#define PCI_DEVICE_ID_QCOM_AIC200 0xa110
+#define PCI_DEVICE_ID_QCOM_AIC200VF 0xa111
#define QAIC_NAME "qaic"
#define QAIC_DESC "Qualcomm Cloud AI Accelerators"
#define CNTL_MAJOR 5
@@ -78,6 +79,13 @@ static const struct qaic_device_config aic200_config = {
.dbc_bar_idx = 2,
};
+static const struct qaic_device_config aic200vf_config = {
+ .family = FAMILY_AIC200_VF,
+ .bar_mask = BIT(0) | BIT(1) | BIT(2) | BIT(4),
+ .mhi_bar_idx = 1,
+ .dbc_bar_idx = 2,
+};
+
bool datapath_polling;
module_param(datapath_polling, bool, 0400);
MODULE_PARM_DESC(datapath_polling, "Operate the datapath in polling mode");
@@ -610,6 +618,8 @@ static void qaic_pci_remove(struct pci_dev *pdev)
{
struct qaic_device *qdev = pci_get_drvdata(pdev);
+ pci_disable_sriov(pdev);
+
if (!qdev)
return;
@@ -666,6 +676,7 @@ static const struct pci_device_id qaic_ids[] = {
{ PCI_DEVICE_DATA(QCOM, AIC080, (kernel_ulong_t)&aic080_config), },
{ PCI_DEVICE_DATA(QCOM, AIC100, (kernel_ulong_t)&aic100_config), },
{ PCI_DEVICE_DATA(QCOM, AIC200, (kernel_ulong_t)&aic200_config), },
+ { PCI_DEVICE_DATA(QCOM, AIC200VF, (kernel_ulong_t)&aic200vf_config), },
{ }
};
MODULE_DEVICE_TABLE(pci, qaic_ids);
@@ -762,6 +773,41 @@ static const struct dev_pm_ops qaic_pm_ops = {
SYSTEM_SLEEP_PM_OPS(qaic_pm_suspend, qaic_pm_resume)
};
+static int qaic_pci_sriov_configure(struct pci_dev *pdev, int num_vfs)
+{
+ struct qaic_device *qdev = pci_get_drvdata(pdev);
+ int rcu_id;
+ int ret;
+
+ if (num_vfs == 0) {
+ pci_disable_sriov(pdev);
+ return 0;
+ }
+
+ rcu_id = srcu_read_lock(&qdev->dev_lock);
+ /* Qaic device must be online to process VF bringup */
+ if (qdev->dev_state == QAIC_OFFLINE) {
+ ret = -ENODEV;
+ goto unlock_dev_srcu;
+ }
+ if (qdev->dev_state == QAIC_BOOT) {
+ ret = -EBUSY;
+ goto unlock_dev_srcu;
+ }
+
+ ret = pci_enable_sriov(pdev, num_vfs);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to enable SR-IOV: %d (requested %d VFs, max %d)\n",
+ ret, num_vfs, pci_sriov_get_totalvfs(pdev));
+ goto unlock_dev_srcu;
+ }
+
+ dev_dbg(&pdev->dev, "Successfully enabled %d VFs\n", num_vfs);
+unlock_dev_srcu:
+ srcu_read_unlock(&qdev->dev_lock, rcu_id);
+ return ret ?: num_vfs;
+}
+
static struct pci_driver qaic_pci_driver = {
.name = QAIC_NAME,
.id_table = qaic_ids,
@@ -769,6 +815,7 @@ static struct pci_driver qaic_pci_driver = {
.remove = qaic_pci_remove,
.shutdown = qaic_pci_shutdown,
.err_handler = &qaic_pci_err_handler,
+ .sriov_configure = qaic_pci_sriov_configure,
.driver = {
.pm = pm_sleep_ptr(&qaic_pm_ops),
},
diff --git a/drivers/accel/qaic/sahara.c b/drivers/accel/qaic/sahara.c
index 8476be9b9148..e951181e424f 100644
--- a/drivers/accel/qaic/sahara.c
+++ b/drivers/accel/qaic/sahara.c
@@ -881,6 +881,7 @@ static void sahara_mhi_remove(struct mhi_device *mhi_dev)
cancel_work_sync(&context->fw_work);
cancel_work_sync(&context->dump_work);
+ cancel_work_sync(&context->read_data_work);
vfree(context->mem_dump);
sahara_release_image(context);
mhi_unprepare_from_transfer(mhi_dev);
diff --git a/drivers/accel/rocket/rocket_job.c b/drivers/accel/rocket/rocket_job.c
index f40435505818..ce994748dd5d 100644
--- a/drivers/accel/rocket/rocket_job.c
+++ b/drivers/accel/rocket/rocket_job.c
@@ -7,6 +7,7 @@
#include <drm/drm_file.h>
#include <drm/drm_gem.h>
#include <drm/rocket_accel.h>
+#include <linux/align.h>
#include <linux/interrupt.h>
#include <linux/overflow.h>
#include <linux/iommu.h>
@@ -21,6 +22,15 @@
#define JOB_TIMEOUT_MS 500
+/*
+ * The PC unit fetches two 64-bit register commands per pc_data_amount unit,
+ * and the field holds (regcmd_count + 1) / 2 - 1.
+ */
+#define ROCKET_MAX_REGCMDS ((PC_REGISTER_AMOUNTS_PC_DATA_AMOUNT__MASK + 1) * 2U)
+
+/* Bits 3:0 of PC_BASE_ADDRESS hold the mode selection bit and reserved bits */
+#define ROCKET_REGCMD_ALIGN 16
+
static struct rocket_job *
to_rocket_job(struct drm_sched_job *sched_job)
{
@@ -78,7 +88,7 @@ rocket_copy_tasks(struct drm_device *dev,
return -ENOMEM;
}
- for (int i = 0; i < rjob->task_count; i++) {
+ for (unsigned int i = 0; i < rjob->task_count; i++) {
struct drm_rocket_task task = {0};
if (copy_from_user(&task,
@@ -95,6 +105,20 @@ rocket_copy_tasks(struct drm_device *dev,
goto fail;
}
+ if (task.regcmd_count > ROCKET_MAX_REGCMDS) {
+ drm_dbg(dev, "regcmd_count field in drm_rocket_task should be <= %u.\n",
+ ROCKET_MAX_REGCMDS);
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ if (!IS_ALIGNED(task.regcmd, ROCKET_REGCMD_ALIGN)) {
+ drm_dbg(dev, "regcmd field in drm_rocket_task should be aligned to %u bytes.\n",
+ ROCKET_REGCMD_ALIGN);
+ ret = -EINVAL;
+ goto fail;
+ }
+
rjob->tasks[i].regcmd = task.regcmd;
rjob->tasks[i].regcmd_count = task.regcmd_count;
}
@@ -494,8 +518,6 @@ int rocket_job_init(struct rocket_core *core)
return 0;
err_sched:
- drm_sched_fini(&core->sched);
-
destroy_workqueue(core->reset.wq);
return ret;
}
diff --git a/drivers/dma-buf/st-dma-fence-unwrap.c b/drivers/dma-buf/st-dma-fence-unwrap.c
index 4d9d313b460c..c5353b36f0e4 100644
--- a/drivers/dma-buf/st-dma-fence-unwrap.c
+++ b/drivers/dma-buf/st-dma-fence-unwrap.c
@@ -370,6 +370,15 @@ error_put_f1:
dma_fence_put(f1);
}
+static void test_dedup_empty(struct kunit *test)
+{
+ struct dma_fence *fence[1] = { NULL };
+ int ret;
+
+ ret = dma_fence_dedup_array(fence, 0);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+}
+
static void test_unwrap_merge_order(struct kunit *test)
{
struct dma_fence *fence, *f1, *f2, *a1, *a2, *c1, *c2;
@@ -595,6 +604,7 @@ static struct kunit_case dma_fence_unwrap_cases[] = {
KUNIT_CASE(test_unwrap_merge_order),
KUNIT_CASE(test_unwrap_merge_complex),
KUNIT_CASE(test_unwrap_merge_complex_seqno),
+ KUNIT_CASE(test_dedup_empty),
{}
};
diff --git a/drivers/gpu/buddy.c b/drivers/gpu/buddy.c
index 2f2aaadafe35..503f7d5934e4 100644
--- a/drivers/gpu/buddy.c
+++ b/drivers/gpu/buddy.c
@@ -2148,7 +2148,6 @@ EXPORT_SYMBOL(gpu_buddy_block_print);
* gpu_buddy_print - print allocator state
*
* @mm: GPU buddy manager
- * @p: GPU printer to use
*/
void gpu_buddy_print(struct gpu_buddy *mm)
{
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_wb_connector.c b/drivers/gpu/drm/arm/display/komeda/komeda_wb_connector.c
index 4872253a2449..f394971c0edb 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_wb_connector.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_wb_connector.c
@@ -128,7 +128,7 @@ static void komeda_wb_connector_destroy(struct drm_connector *connector)
}
static const struct drm_connector_funcs komeda_wb_connector_funcs = {
- .reset = drm_atomic_helper_connector_reset,
+ .atomic_create_state = drm_atomic_helper_connector_create_state,
.detect = komeda_wb_connector_detect,
.fill_modes = komeda_wb_connector_fill_modes,
.destroy = komeda_wb_connector_destroy,
diff --git a/drivers/gpu/drm/arm/malidp_mw.c b/drivers/gpu/drm/arm/malidp_mw.c
index f8be65119e3b..edd924ba722d 100644
--- a/drivers/gpu/drm/arm/malidp_mw.c
+++ b/drivers/gpu/drm/arm/malidp_mw.c
@@ -64,18 +64,18 @@ static const struct drm_connector_helper_funcs malidp_mw_connector_helper_funcs
.mode_valid = malidp_mw_connector_mode_valid,
};
-static void malidp_mw_connector_reset(struct drm_connector *connector)
+static struct drm_connector_state *
+malidp_mw_connector_create_state(struct drm_connector *connector)
{
- struct malidp_mw_connector_state *mw_state = kzalloc_obj(*mw_state);
+ struct malidp_mw_connector_state *mw_state;
- if (connector->state)
- __drm_atomic_helper_connector_destroy_state(connector->state);
+ mw_state = kzalloc_obj(*mw_state);
+ if (!mw_state)
+ return ERR_PTR(-ENOMEM);
- kfree(connector->state);
- connector->state = NULL;
+ __drm_atomic_helper_connector_state_init(&mw_state->base, connector);
- if (mw_state)
- __drm_atomic_helper_connector_reset(connector, &mw_state->base);
+ return &mw_state->base;
}
static enum drm_connector_status
@@ -111,7 +111,7 @@ malidp_mw_connector_duplicate_state(struct drm_connector *connector)
}
static const struct drm_connector_funcs malidp_mw_connector_funcs = {
- .reset = malidp_mw_connector_reset,
+ .atomic_create_state = malidp_mw_connector_create_state,
.detect = malidp_mw_connector_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.destroy = malidp_mw_connector_destroy,
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
index 038b852405b5..c3ef44074477 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
@@ -8,6 +8,7 @@
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/gpio/consumer.h>
+#include <linux/hdmi.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/slab.h>
@@ -775,11 +776,6 @@ static int adv7511_connector_init(struct adv7511 *adv)
* DRM Bridge Operations
*/
-static const struct adv7511 *bridge_to_adv7511_const(const struct drm_bridge *bridge)
-{
- return container_of(bridge, struct adv7511, bridge);
-}
-
static void adv7511_bridge_atomic_enable(struct drm_bridge *bridge,
struct drm_atomic_commit *state)
{
@@ -817,19 +813,6 @@ static void adv7511_bridge_atomic_disable(struct drm_bridge *bridge,
adv7511_power_off(adv);
}
-static enum drm_mode_status
-adv7511_bridge_hdmi_tmds_char_rate_valid(const struct drm_bridge *bridge,
- const struct drm_display_mode *mode,
- unsigned long long tmds_rate)
-{
- const struct adv7511 *adv = bridge_to_adv7511_const(bridge);
-
- if (tmds_rate > 1000ULL * adv->info->max_mode_clock_khz)
- return MODE_CLOCK_HIGH;
-
- return MODE_OK;
-}
-
static enum drm_mode_status adv7511_bridge_mode_valid(struct drm_bridge *bridge,
const struct drm_display_info *info,
const struct drm_display_mode *mode)
@@ -1006,7 +989,6 @@ static const struct drm_bridge_funcs adv7511_bridge_funcs = {
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
.atomic_create_state = drm_atomic_helper_bridge_create_state,
- .hdmi_tmds_char_rate_valid = adv7511_bridge_hdmi_tmds_char_rate_valid,
.hdmi_clear_audio_infoframe = adv7511_bridge_hdmi_clear_audio_infoframe,
.hdmi_write_audio_infoframe = adv7511_bridge_hdmi_write_audio_infoframe,
.hdmi_clear_avi_infoframe = adv7511_bridge_hdmi_clear_avi_infoframe,
@@ -1359,6 +1341,8 @@ static int adv7511_probe(struct i2c_client *i2c)
adv7511->bridge.vendor = "Analog";
adv7511->bridge.product = adv7511->info->name;
+ adv7511->bridge.supported_hdmi_ver = HDMI_VERSION_1_2;
+ adv7511->bridge.max_tmds_char_rate = 1000ULL * adv7511->info->max_mode_clock_khz;
#ifdef CONFIG_DRM_I2C_ADV7511_AUDIO
adv7511->bridge.ops |= DRM_BRIDGE_OP_HDMI_AUDIO;
diff --git a/drivers/gpu/drm/bridge/inno-hdmi.c b/drivers/gpu/drm/bridge/inno-hdmi.c
index dd35f5a875d3..ea3447d4f285 100644
--- a/drivers/gpu/drm/bridge/inno-hdmi.c
+++ b/drivers/gpu/drm/bridge/inno-hdmi.c
@@ -1119,6 +1119,7 @@ struct inno_hdmi *inno_hdmi_bind(struct device *dev,
hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
hdmi->bridge.vendor = "Inno";
hdmi->bridge.product = "Inno HDMI";
+ hdmi->bridge.supported_hdmi_ver = HDMI_VERSION_1_2;
hdmi->bridge.ddc = inno_hdmi_i2c_adapter(hdmi);
if (IS_ERR(hdmi->bridge.ddc))
diff --git a/drivers/gpu/drm/bridge/ite-it6263.c b/drivers/gpu/drm/bridge/ite-it6263.c
index 21ac8e58b9d2..e8e0197171e1 100644
--- a/drivers/gpu/drm/bridge/ite-it6263.c
+++ b/drivers/gpu/drm/bridge/ite-it6263.c
@@ -15,7 +15,6 @@
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
-#include <drm/display/drm_hdmi_helper.h>
#include <drm/display/drm_hdmi_state_helper.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
@@ -669,20 +668,6 @@ static void it6263_bridge_atomic_enable(struct drm_bridge *bridge,
regmap_write(regmap, HDMI_REG_PKT_GENERAL_CTRL, ENABLE_PKT | REPEAT_PKT);
}
-static enum drm_mode_status
-it6263_bridge_mode_valid(struct drm_bridge *bridge,
- const struct drm_display_info *info,
- const struct drm_display_mode *mode)
-{
- unsigned long long rate;
-
- rate = drm_hdmi_compute_mode_clock(mode, 8, DRM_OUTPUT_COLOR_FORMAT_RGB444);
- if (rate == 0)
- return MODE_NOCLOCK;
-
- return bridge->funcs->hdmi_tmds_char_rate_valid(bridge, mode, rate);
-}
-
static int it6263_bridge_attach(struct drm_bridge *bridge,
struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
@@ -753,20 +738,6 @@ it6263_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
return input_fmts;
}
-static enum drm_mode_status
-it6263_hdmi_tmds_char_rate_valid(const struct drm_bridge *bridge,
- const struct drm_display_mode *mode,
- unsigned long long tmds_rate)
-{
- if (mode->clock > MAX_PIXEL_CLOCK_KHZ)
- return MODE_CLOCK_HIGH;
-
- if (tmds_rate > MAX_HDMI_TMDS_CHAR_RATE_HZ)
- return MODE_CLOCK_HIGH;
-
- return MODE_OK;
-}
-
static int it6263_hdmi_clear_avi_infoframe(struct drm_bridge *bridge)
{
struct it6263 *it = bridge_to_it6263(bridge);
@@ -831,13 +802,11 @@ static const struct drm_bridge_funcs it6263_bridge_funcs = {
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
.atomic_create_state = drm_atomic_helper_bridge_create_state,
.attach = it6263_bridge_attach,
- .mode_valid = it6263_bridge_mode_valid,
.atomic_disable = it6263_bridge_atomic_disable,
.atomic_enable = it6263_bridge_atomic_enable,
.detect = it6263_bridge_detect,
.edid_read = it6263_bridge_edid_read,
.atomic_get_input_bus_fmts = it6263_bridge_atomic_get_input_bus_fmts,
- .hdmi_tmds_char_rate_valid = it6263_hdmi_tmds_char_rate_valid,
.hdmi_clear_avi_infoframe = it6263_hdmi_clear_avi_infoframe,
.hdmi_write_avi_infoframe = it6263_hdmi_write_avi_infoframe,
.hdmi_clear_hdmi_infoframe = it6263_hdmi_clear_hdmi_infoframe,
@@ -899,6 +868,8 @@ static int it6263_probe(struct i2c_client *client)
it->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
it->bridge.vendor = "ITE";
it->bridge.product = "IT6263";
+ it->bridge.supported_hdmi_ver = HDMI_VERSION_1_3;
+ it->bridge.max_tmds_char_rate = 1000ULL * MAX_PIXEL_CLOCK_KHZ;
return devm_drm_bridge_add(dev, &it->bridge);
}
diff --git a/drivers/gpu/drm/bridge/ite-it66121.c b/drivers/gpu/drm/bridge/ite-it66121.c
index 51fc68ffdf8f..c8d0a26e8e90 100644
--- a/drivers/gpu/drm/bridge/ite-it66121.c
+++ b/drivers/gpu/drm/bridge/ite-it66121.c
@@ -10,6 +10,7 @@
#include <linux/media-bus-format.h>
#include <linux/module.h>
#include <linux/device.h>
+#include <linux/hdmi.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/bitfield.h>
@@ -867,15 +868,6 @@ it66121_bridge_hdmi_tmds_char_rate_valid(const struct drm_bridge *bridge,
const struct drm_display_mode *mode,
unsigned long long tmds_rate)
{
- const struct it66121_ctx *ctx =
- container_of(bridge, const struct it66121_ctx, bridge);
- unsigned long long max_rate;
-
- max_rate = (ctx->bus_width == 12) ? 74250000ULL : 148500000ULL;
-
- if (tmds_rate > max_rate)
- return MODE_CLOCK_HIGH;
-
if (tmds_rate < HDMI_TMDS_CHAR_RATE_MIN_HZ)
return MODE_CLOCK_LOW;
@@ -1670,6 +1662,9 @@ static int it66121_probe(struct i2c_client *client)
DRM_BRIDGE_OP_HDMI;
ctx->bridge.vendor = "ITE";
ctx->bridge.product = "IT66121";
+ ctx->bridge.supported_hdmi_ver = HDMI_VERSION_1_2;
+ ctx->bridge.max_tmds_char_rate = ctx->bus_width == 12 ? 74250000ULL : 148500000ULL;
+
if (client->irq > 0) {
ctx->bridge.ops |= DRM_BRIDGE_OP_HPD;
diff --git a/drivers/gpu/drm/bridge/lontium-lt8713sx.c b/drivers/gpu/drm/bridge/lontium-lt8713sx.c
index 926f9e1e85bf..18696b75bec1 100644
--- a/drivers/gpu/drm/bridge/lontium-lt8713sx.c
+++ b/drivers/gpu/drm/bridge/lontium-lt8713sx.c
@@ -554,7 +554,6 @@ static int lt8713sx_probe(struct i2c_client *client)
lt8713sx_reset(lt8713sx);
- lt8713sx->bridge.funcs = &lt8713sx_bridge_funcs;
lt8713sx->bridge.of_node = dev->of_node;
lt8713sx->bridge.type = DRM_MODE_CONNECTOR_DisplayPort;
drm_bridge_add(&lt8713sx->bridge);
diff --git a/drivers/gpu/drm/bridge/lontium-lt8912b.c b/drivers/gpu/drm/bridge/lontium-lt8912b.c
index e347d04b7b2d..a4d05dcba9e0 100644
--- a/drivers/gpu/drm/bridge/lontium-lt8912b.c
+++ b/drivers/gpu/drm/bridge/lontium-lt8912b.c
@@ -416,7 +416,7 @@ static const struct drm_connector_funcs lt8912_connector_funcs = {
.detect = lt8912_connector_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.destroy = drm_connector_cleanup,
- .reset = drm_atomic_helper_connector_reset,
+ .atomic_create_state = drm_atomic_helper_connector_create_state,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c
index cdc2b188e2d8..2d1a28261037 100644
--- a/drivers/gpu/drm/bridge/lontium-lt9611.c
+++ b/drivers/gpu/drm/bridge/lontium-lt9611.c
@@ -5,6 +5,7 @@
*/
#include <linux/gpio/consumer.h>
+#include <linux/hdmi.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/media-bus-format.h>
@@ -952,18 +953,6 @@ static int lt9611_hdmi_write_hdmi_infoframe(struct drm_bridge *bridge,
return 0;
}
-static enum drm_mode_status
-lt9611_hdmi_tmds_char_rate_valid(const struct drm_bridge *bridge,
- const struct drm_display_mode *mode,
- unsigned long long tmds_rate)
-{
- /* 297 MHz for 4k@30 mode */
- if (tmds_rate > 297000000)
- return MODE_CLOCK_HIGH;
-
- return MODE_OK;
-}
-
static int lt9611_hdmi_audio_startup(struct drm_bridge *bridge,
struct drm_connector *connector)
{
@@ -1029,7 +1018,6 @@ static const struct drm_bridge_funcs lt9611_bridge_funcs = {
.atomic_create_state = drm_atomic_helper_bridge_create_state,
.atomic_get_input_bus_fmts = lt9611_atomic_get_input_bus_fmts,
- .hdmi_tmds_char_rate_valid = lt9611_hdmi_tmds_char_rate_valid,
.hdmi_write_audio_infoframe = lt9611_hdmi_write_audio_infoframe,
.hdmi_clear_audio_infoframe = lt9611_hdmi_clear_audio_infoframe,
.hdmi_write_avi_infoframe = lt9611_hdmi_write_avi_infoframe,
@@ -1175,6 +1163,8 @@ static int lt9611_probe(struct i2c_client *client)
lt9611->bridge.hdmi_audio_dev = dev;
lt9611->bridge.hdmi_audio_max_i2s_playback_channels = 8;
lt9611->bridge.hdmi_audio_dai_port = 2;
+ lt9611->bridge.supported_hdmi_ver = HDMI_VERSION_1_4;
+ lt9611->bridge.max_tmds_char_rate = 297000000; /* 297 MHz for 4k@30 mode */
drm_bridge_add(&lt9611->bridge);
diff --git a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c
index 4d244e6d4ed9..9153bf629fd1 100644
--- a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c
+++ b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c
@@ -149,7 +149,7 @@ static const struct drm_connector_funcs ge_b850v3_lvds_connector_funcs = {
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = ge_b850v3_lvds_detect,
.destroy = drm_connector_cleanup,
- .reset = drm_atomic_helper_connector_reset,
+ .atomic_create_state = drm_atomic_helper_connector_create_state,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
diff --git a/drivers/gpu/drm/bridge/simple-bridge.c b/drivers/gpu/drm/bridge/simple-bridge.c
index 3fba7002322e..fab793fb12b5 100644
--- a/drivers/gpu/drm/bridge/simple-bridge.c
+++ b/drivers/gpu/drm/bridge/simple-bridge.c
@@ -276,6 +276,11 @@ static const struct of_device_id simple_bridge_match[] = {
.connector_type = DRM_MODE_CONNECTOR_HDMIA,
},
}, {
+ .compatible = "chrontel,ch7218a",
+ .data = &(const struct simple_bridge_info) {
+ .connector_type = DRM_MODE_CONNECTOR_HDMIA,
+ },
+ }, {
.compatible = "mstar,tsumu88adt3-lf-1",
.data = &(const struct simple_bridge_info) {
.connector_type = DRM_MODE_CONNECTOR_HDMIA,
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
index c9568aea98dc..b268c9376087 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
@@ -2,6 +2,7 @@
/*
* Copyright (c) 2021-2022 Rockchip Electronics Co., Ltd.
* Copyright (c) 2024 Collabora Ltd.
+ * Copyright (c) 2025 Amazon.com, Inc. or its affiliates.
*
* Author: Algea Cao <algea.cao@rock-chips.com>
* Author: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
@@ -15,7 +16,6 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
-#include <linux/workqueue.h>
#include <drm/bridge/dw_hdmi_qp.h>
#include <drm/display/drm_hdmi_helper.h>
@@ -28,6 +28,7 @@
#include <drm/drm_edid.h>
#include <drm/drm_modes.h>
#include <drm/drm_print.h>
+#include <drm/drm_probe_helper.h>
#include <media/cec.h>
@@ -38,8 +39,6 @@
#define DDC_CI_ADDR 0x37
#define DDC_SEGMENT_ADDR 0x30
-#define SCRAMB_POLL_DELAY_MS 3000
-
struct dw_hdmi_qp_i2c {
struct i2c_adapter adap;
@@ -83,6 +82,9 @@ struct dw_hdmi_qp {
struct regmap *regm;
int main_irq;
+ /* Guards curr_conn between atomic hooks and HPD notify readers */
+ struct mutex mutex;
+ struct drm_connector *curr_conn;
unsigned long tmds_char_rate;
bool no_hpd;
};
@@ -350,22 +352,14 @@ static int dw_hdmi_qp_i2c_read(struct dw_hdmi_qp *hdmi,
stat = wait_for_completion_timeout(&i2c->cmp, HZ / 10);
if (!stat) {
- if (hdmi->no_hpd)
- dev_dbg_ratelimited(hdmi->dev,
- "i2c read timed out\n");
- else
- dev_err(hdmi->dev, "i2c read timed out\n");
+ dev_dbg_ratelimited(hdmi->dev, "i2c read timed out\n");
dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0);
return -EAGAIN;
}
/* Check for error condition on the bus */
if (i2c->stat & I2CM_NACK_RCVD_IRQ) {
- if (hdmi->no_hpd)
- dev_dbg_ratelimited(hdmi->dev,
- "i2c read error\n");
- else
- dev_err(hdmi->dev, "i2c read error\n");
+ dev_dbg_ratelimited(hdmi->dev, "i2c read error\n");
dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0);
return -EIO;
}
@@ -404,14 +398,14 @@ static int dw_hdmi_qp_i2c_write(struct dw_hdmi_qp *hdmi,
stat = wait_for_completion_timeout(&i2c->cmp, HZ / 10);
if (!stat) {
- dev_err(hdmi->dev, "i2c write time out!\n");
+ dev_dbg_ratelimited(hdmi->dev, "i2c write time out!\n");
dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0);
return -EAGAIN;
}
/* Check for error condition on the bus */
if (i2c->stat & I2CM_NACK_RCVD_IRQ) {
- dev_err(hdmi->dev, "i2c write nack!\n");
+ dev_dbg_ratelimited(hdmi->dev, "i2c write nack!\n");
dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0);
return -EIO;
}
@@ -547,6 +541,7 @@ static void dw_hdmi_qp_bridge_atomic_enable(struct drm_bridge *bridge,
struct drm_connector_state *conn_state;
struct drm_connector *connector;
unsigned int op_mode;
+ int ret;
connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder);
if (WARN_ON(!connector))
@@ -557,16 +552,26 @@ static void dw_hdmi_qp_bridge_atomic_enable(struct drm_bridge *bridge,
return;
if (connector->display_info.is_hdmi) {
- dev_dbg(hdmi->dev, "%s mode=HDMI %s rate=%llu bpc=%u\n", __func__,
- drm_hdmi_connector_get_output_format_name(conn_state->hdmi.output_format),
- conn_state->hdmi.tmds_char_rate, conn_state->hdmi.output_bpc);
op_mode = 0;
hdmi->tmds_char_rate = conn_state->hdmi.tmds_char_rate;
+
+ ret = drm_connector_hdmi_enable_scrambling(connector, conn_state);
+ if (ret)
+ dev_warn(hdmi->dev, "Failed to enable scrambling: %d\n", ret);
+
+ dev_dbg(hdmi->dev, "%s mode=HDMI %s rate=%llu bpc=%u scramb=%d\n", __func__,
+ drm_hdmi_connector_get_output_format_name(conn_state->hdmi.output_format),
+ conn_state->hdmi.tmds_char_rate, conn_state->hdmi.output_bpc,
+ connector->hdmi.scrambler_enabled);
} else {
- dev_dbg(hdmi->dev, "%s mode=DVI\n", __func__);
op_mode = OPMODE_DVI;
+ dev_dbg(hdmi->dev, "%s mode=DVI\n", __func__);
}
+ drm_connector_get(connector);
+ scoped_guard(mutex, &hdmi->mutex)
+ hdmi->curr_conn = connector;
+
hdmi->phy.ops->init(hdmi, hdmi->phy.data);
dw_hdmi_qp_mod(hdmi, HDCP2_BYPASS, HDCP2_BYPASS, HDCP2LOGIC_CONFIG0);
@@ -579,9 +584,20 @@ static void dw_hdmi_qp_bridge_atomic_disable(struct drm_bridge *bridge,
struct drm_atomic_commit *state)
{
struct dw_hdmi_qp *hdmi = bridge->driver_private;
+ struct drm_connector *connector;
+
+ scoped_guard(mutex, &hdmi->mutex) {
+ if (hdmi->curr_conn) {
+ drm_connector_put(hdmi->curr_conn);
+ hdmi->curr_conn = NULL;
+ }
+ }
hdmi->tmds_char_rate = 0;
+ connector = drm_atomic_get_old_connector_for_encoder(state, bridge->encoder);
+ drm_connector_hdmi_disable_scrambling(connector);
+
hdmi->phy.ops->disable(hdmi, hdmi->phy.data);
}
@@ -616,24 +632,24 @@ dw_hdmi_qp_bridge_edid_read(struct drm_bridge *bridge,
return drm_edid;
}
-static enum drm_mode_status
-dw_hdmi_qp_bridge_tmds_char_rate_valid(const struct drm_bridge *bridge,
- const struct drm_display_mode *mode,
- unsigned long long rate)
+static int dw_hdmi_qp_bridge_scrambler_enable(struct drm_bridge *bridge)
{
struct dw_hdmi_qp *hdmi = bridge->driver_private;
- /*
- * TODO: when hdmi->no_hpd is 1 we must not support modes that
- * require scrambling, including every mode with a clock above
- * HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ.
- */
- if (rate > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ) {
- dev_dbg(hdmi->dev, "Unsupported TMDS char rate: %lld\n", rate);
- return MODE_CLOCK_HIGH;
- }
+ dw_hdmi_qp_write(hdmi, 1, SCRAMB_CONFIG0);
+ dev_dbg(hdmi->dev, "scrambler enabled\n");
- return MODE_OK;
+ return 0;
+}
+
+static int dw_hdmi_qp_bridge_scrambler_disable(struct drm_bridge *bridge)
+{
+ struct dw_hdmi_qp *hdmi = bridge->driver_private;
+
+ dw_hdmi_qp_write(hdmi, 0, SCRAMB_CONFIG0);
+ dev_dbg(hdmi->dev, "scrambler disabled\n");
+
+ return 0;
}
static int dw_hdmi_qp_bridge_clear_avi_infoframe(struct drm_bridge *bridge)
@@ -982,6 +998,22 @@ static int dw_hdmi_qp_cec_transmit(struct drm_bridge *bridge, u8 attempts,
#define dw_hdmi_qp_cec_transmit NULL
#endif /* CONFIG_DRM_DW_HDMI_QP_CEC */
+static void dw_hdmi_qp_bridge_hpd_enable(struct drm_bridge *bridge)
+{
+ struct dw_hdmi_qp *hdmi = bridge->driver_private;
+
+ if (hdmi->phy.ops->enable_hpd)
+ hdmi->phy.ops->enable_hpd(hdmi, hdmi->phy.data);
+}
+
+static void dw_hdmi_qp_bridge_hpd_disable(struct drm_bridge *bridge)
+{
+ struct dw_hdmi_qp *hdmi = bridge->driver_private;
+
+ if (hdmi->phy.ops->disable_hpd)
+ hdmi->phy.ops->disable_hpd(hdmi, hdmi->phy.data);
+}
+
static const struct drm_bridge_funcs dw_hdmi_qp_bridge_funcs = {
.atomic_get_output_bus_fmts = drm_atomic_helper_bridge_get_hdmi_output_bus_fmts,
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
@@ -990,8 +1022,11 @@ static const struct drm_bridge_funcs dw_hdmi_qp_bridge_funcs = {
.atomic_enable = dw_hdmi_qp_bridge_atomic_enable,
.atomic_disable = dw_hdmi_qp_bridge_atomic_disable,
.detect = dw_hdmi_qp_bridge_detect,
+ .hpd_enable = dw_hdmi_qp_bridge_hpd_enable,
+ .hpd_disable = dw_hdmi_qp_bridge_hpd_disable,
.edid_read = dw_hdmi_qp_bridge_edid_read,
- .hdmi_tmds_char_rate_valid = dw_hdmi_qp_bridge_tmds_char_rate_valid,
+ .hdmi_scrambler_enable = dw_hdmi_qp_bridge_scrambler_enable,
+ .hdmi_scrambler_disable = dw_hdmi_qp_bridge_scrambler_disable,
.hdmi_clear_avi_infoframe = dw_hdmi_qp_bridge_clear_avi_infoframe,
.hdmi_write_avi_infoframe = dw_hdmi_qp_bridge_write_avi_infoframe,
.hdmi_clear_hdmi_infoframe = dw_hdmi_qp_bridge_clear_hdmi_infoframe,
@@ -1054,9 +1089,6 @@ static void dw_hdmi_qp_init_hw(struct dw_hdmi_qp *hdmi)
/* Clear DONE and ERROR interrupts */
dw_hdmi_qp_write(hdmi, I2CM_OP_DONE_CLEAR | I2CM_NACK_RCVD_CLEAR,
MAINUNIT_1_INT_CLEAR);
-
- if (hdmi->phy.ops->setup_hpd)
- hdmi->phy.ops->setup_hpd(hdmi, hdmi->phy.data);
}
struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev,
@@ -1079,6 +1111,10 @@ struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev,
if (IS_ERR(hdmi))
return ERR_CAST(hdmi);
+ ret = devm_mutex_init(dev, &hdmi->mutex);
+ if (ret)
+ return ERR_PTR(ret);
+
hdmi->dev = dev;
regs = devm_platform_ioremap_resource(pdev, 0);
@@ -1119,13 +1155,18 @@ struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev,
DRM_BRIDGE_OP_HDMI_AUDIO |
DRM_BRIDGE_OP_HDMI_HDR_DRM_INFOFRAME |
DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME;
- if (!hdmi->no_hpd)
- hdmi->bridge.ops |= DRM_BRIDGE_OP_HPD;
hdmi->bridge.of_node = pdev->dev.of_node;
hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
hdmi->bridge.vendor = "Synopsys";
hdmi->bridge.product = "DW HDMI QP TX";
+ if (hdmi->no_hpd) {
+ hdmi->bridge.supported_hdmi_ver = HDMI_VERSION_1_4;
+ } else {
+ hdmi->bridge.supported_hdmi_ver = HDMI_VERSION_2_0;
+ hdmi->bridge.ops |= DRM_BRIDGE_OP_HPD;
+ }
+
if (plat_data->supported_formats)
hdmi->bridge.supported_formats = plat_data->supported_formats;
@@ -1169,6 +1210,46 @@ struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev,
}
EXPORT_SYMBOL_GPL(dw_hdmi_qp_bind);
+/**
+ * dw_hdmi_qp_hpd_notify() - Notify a hot-plug detection event
+ * @hdmi: pointer to the DW HDMI QP controller
+ *
+ * Platform drivers should call this from their threaded IRQ handler or work
+ * function to notify the bridge of a connection status change.
+ * The bridge's .read_hpd() phy_ops callback is used to read the current
+ * connection status.
+ */
+void dw_hdmi_qp_hpd_notify(struct dw_hdmi_qp *hdmi)
+{
+ enum drm_connector_status status;
+ struct drm_connector *conn;
+
+ scoped_guard(mutex, &hdmi->mutex) {
+ conn = hdmi->curr_conn;
+ if (conn)
+ drm_connector_get(conn);
+ }
+
+ status = hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data);
+ dev_dbg(hdmi->dev, "%s status=%d\n", __func__, status);
+
+ /*
+ * When the display pipeline has been already active, switch to
+ * drm_connector_helper_hpd_irq_event() to ensure .detect_ctx()
+ * gets invoked, i.e. via drm_helper_probe_detect(), because
+ * drm_bridge_hpd_notify() defers to a delayed hotplug path in
+ * this case.
+ */
+ if (conn && status == connector_status_connected)
+ drm_connector_helper_hpd_irq_event(conn);
+ else
+ drm_bridge_hpd_notify(&hdmi->bridge, status);
+
+ if (conn)
+ drm_connector_put(conn);
+}
+EXPORT_SYMBOL_GPL(dw_hdmi_qp_hpd_notify);
+
void dw_hdmi_qp_suspend(struct device *dev, struct dw_hdmi_qp *hdmi)
{
disable_irq(hdmi->main_irq);
diff --git a/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c b/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c
index 523d1c7ea072..da399cb951a5 100644
--- a/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c
+++ b/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c
@@ -66,7 +66,7 @@ static const struct drm_connector_helper_funcs hv_drm_connector_helper_funcs = {
static const struct drm_connector_funcs hv_drm_connector_funcs = {
.fill_modes = drm_helper_probe_single_connector_modes,
.destroy = drm_connector_cleanup,
- .reset = drm_atomic_helper_connector_reset,
+ .atomic_create_state = drm_atomic_helper_connector_create_state,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
diff --git a/drivers/gpu/drm/imx/ipuv3/imx-tve.c b/drivers/gpu/drm/imx/ipuv3/imx-tve.c
index e861b8b9d8fa..4ece79374372 100644
--- a/drivers/gpu/drm/imx/ipuv3/imx-tve.c
+++ b/drivers/gpu/drm/imx/ipuv3/imx-tve.c
@@ -314,7 +314,7 @@ static void imx_tve_connector_destroy(struct drm_connector *connector)
static const struct drm_connector_funcs imx_tve_connector_funcs = {
.fill_modes = drm_helper_probe_single_connector_modes,
.destroy = imx_tve_connector_destroy,
- .reset = drm_atomic_helper_connector_reset,
+ .atomic_create_state = drm_atomic_helper_connector_create_state,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c
index e907c1d07887..d55d073f4804 100644
--- a/drivers/gpu/drm/nouveau/nouveau_abi16.c
+++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c
@@ -306,7 +306,7 @@ nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS)
getparam->value = 1;
break;
case NOUVEAU_GETPARAM_GRAPH_UNITS:
- getparam->value = nvkm_gr_units(gr);
+ getparam->value = gr ? nvkm_gr_units(gr) : 0;
break;
case NOUVEAU_GETPARAM_EXEC_PUSH_MAX: {
int ib_max = getparam_dma_ib_max(device);
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index 53a1fc2913fe..7a520b4d60fe 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -695,6 +695,8 @@ config DRM_PANEL_NOVATEK_NT36536
depends on OF
depends on DRM_MIPI_DSI
depends on BACKLIGHT_CLASS_DEVICE
+ select DRM_DISPLAY_DSC_HELPER
+ select DRM_DISPLAY_HELPER
select DRM_KMS_HELPER
help
Say Y here if you want to enable support for Novatek NT36536-based
@@ -753,6 +755,15 @@ config DRM_PANEL_NOVATEK_NT39016
Say Y here if you want to enable support for the panels built
around the Novatek NT39016 display controller.
+config DRM_PANEL_NOVATEK_NT51021
+ tristate "Novatek NT51021 DSI panel"
+ depends on OF
+ depends on DRM_MIPI_DSI
+ depends on BACKLIGHT_CLASS_DEVICE
+ help
+ Say Y here if you want to enable support for the panels built
+ around the Novatek NT51021 Display controller.
+
config DRM_PANEL_OLIMEX_LCD_OLINUXINO
tristate "Olimex LCD-OLinuXino panel"
depends on OF
@@ -850,6 +861,21 @@ config DRM_PANEL_RAYDIUM_RM692E5
Say Y here if you want to enable support for Raydium RM692E5-based
display panels, such as the one found in the Fairphone 5 smartphone.
+config DRM_PANEL_RAYDIUM_RM69220
+ tristate "Raydium RM69220-based DSI panel"
+ depends on OF
+ depends on DRM_MIPI_DSI
+ depends on BACKLIGHT_CLASS_DEVICE
+ select DRM_DISPLAY_DSC_HELPER
+ select DRM_DISPLAY_HELPER
+ help
+ Say Y here if you want to enable support for Raydium RM69220-based
+ display panels, such as the BOE BF068MWM-TD0 which can be found in
+ the Nothing Phone (3a).
+
+ To compile this driver as a module, choose M here: the module
+ will be called panel-raydium-rm69220.
+
config DRM_PANEL_RAYDIUM_RM69380
tristate "Raydium RM69380-based DSI panel"
depends on GPIOLIB
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index f2c9c80a218f..da5175909d54 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -72,6 +72,7 @@ obj-$(CONFIG_DRM_PANEL_NOVATEK_NT36672E) += panel-novatek-nt36672e.o
obj-$(CONFIG_DRM_PANEL_NOVATEK_NT37700F) += panel-novatek-nt37700f.o
obj-$(CONFIG_DRM_PANEL_NOVATEK_NT37801) += panel-novatek-nt37801.o
obj-$(CONFIG_DRM_PANEL_NOVATEK_NT39016) += panel-novatek-nt39016.o
+obj-$(CONFIG_DRM_PANEL_NOVATEK_NT51021) += panel-novatek-nt51021.o
obj-$(CONFIG_DRM_PANEL_MANTIX_MLAF057WE51) += panel-mantix-mlaf057we51.o
obj-$(CONFIG_DRM_PANEL_OLIMEX_LCD_OLINUXINO) += panel-olimex-lcd-olinuxino.o
obj-$(CONFIG_DRM_PANEL_ORISETECH_OTA5601A) += panel-orisetech-ota5601a.o
@@ -83,6 +84,7 @@ obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM67191) += panel-raydium-rm67191.o
obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM67200) += panel-raydium-rm67200.o
obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM68200) += panel-raydium-rm68200.o
obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM692E5) += panel-raydium-rm692e5.o
+obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM69220) += panel-raydium-rm69220.o
obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM69380) += panel-raydium-rm69380.o
obj-$(CONFIG_DRM_PANEL_RENESAS_R61307) += panel-renesas-r61307.o
obj-$(CONFIG_DRM_PANEL_RENESAS_R63419) += panel-renesas-r63419.o
diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c
index 5d7d696b7725..f83b93a1a414 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -1958,6 +1958,7 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('A', 'U', 'O', 0x0290, &delay_200_500_e50, "B140XTN07.5"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x04a4, &delay_200_500_e50, "B122UAN01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x0ba4, &delay_200_500_e50, "B140QAX01.H"),
+ EDP_PANEL_ENTRY('A', 'U', 'O', 0x0db3, &delay_200_500_e50, "Unknown"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x105c, &delay_200_500_e50, "B116XTN01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1062, &delay_200_500_e50, "B120XAN01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x125c, &delay_200_500_e50, "Unknown"),
@@ -1986,6 +1987,7 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('A', 'U', 'O', 0x635c, &delay_200_500_e50, "B116XAN06.3"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x639c, &delay_200_500_e50, "B140HAK02.7"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x643d, &delay_200_500_e50, "B140HAN06.4"),
+ EDP_PANEL_ENTRY('A', 'U', 'O', 0x65a9, &delay_200_500_e50, "B140HAN04.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x67a8, &delay_200_500_e200, "B140XTK02.4"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x723c, &delay_200_500_e50, "B140XTN07.2"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x73aa, &delay_200_500_e50, "B116XTN02.3"),
@@ -2003,6 +2005,7 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('A', 'U', 'O', 0xd497, &delay_200_500_e50, "B120XAN01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0xf390, &delay_200_500_e50, "B140XTN07.7"),
+ EDP_PANEL_ENTRY('B', 'O', 'E', 0x03f4, &delay_200_500_e50, "NV140FHD-N43"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0607, &delay_200_500_e200, "Unknown"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0608, &delay_200_500_e50, "NT116WHM-N11"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0609, &delay_200_500_e50_po2e200, "NT116WHM-N21 V4.1"),
@@ -2198,6 +2201,7 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('S', 'H', 'P', 0x1523, &delay_80_500_e50, "LQ140M1JW46"),
EDP_PANEL_ENTRY('S', 'H', 'P', 0x153a, &delay_200_500_e50, "LQ140T1JH01"),
EDP_PANEL_ENTRY('S', 'H', 'P', 0x154c, &delay_200_500_p2e100, "LQ116M1JW10"),
+ EDP_PANEL_ENTRY('S', 'H', 'P', 0x1572, &delay_200_500_e200, "LQ138P1JX61"),
EDP_PANEL_ENTRY('S', 'H', 'P', 0x158f, &delay_200_500_p2e100, "LQ134Z1"),
EDP_PANEL_ENTRY('S', 'H', 'P', 0x1593, &delay_200_500_p2e100, "LQ134N1"),
EDP_PANEL_ENTRY('S', 'H', 'P', 0x15a7, &delay_200_500_e200, "LQ120P1JX51"),
diff --git a/drivers/gpu/drm/panel/panel-novatek-nt51021.c b/drivers/gpu/drm/panel/panel-novatek-nt51021.c
new file mode 100644
index 000000000000..94e7d6aaf0cb
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-novatek-nt51021.c
@@ -0,0 +1,875 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2026, Ryan Brue <ryanbrue.dev@gmail.com>
+// Copyright (c) 2025, Nickolay Goppen <setotau@mainlining.org>
+// Copyright (c) 2024, Alexey Minnekhanov <alexeymin@minlexx.ru>
+
+/*
+ * This panel IC doesn't use the set_display_on command although
+ * it uses set_display_off command. This is not an error.
+ */
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
+
+struct novatek_nt51021_desc;
+
+struct novatek_nt51021_variant {
+ int (*init)(struct novatek_nt51021_desc *ctx);
+ int (*off)(struct novatek_nt51021_desc *ctx);
+
+ const struct drm_display_mode *display_mode;
+ unsigned long mode_flags;
+};
+
+struct novatek_nt51021_desc {
+ struct drm_panel panel;
+ struct mipi_dsi_device *dsi;
+ struct regulator_bulk_data *supplies;
+ struct gpio_desc *reset_gpio;
+
+ const struct novatek_nt51021_variant *variant;
+};
+
+static const struct regulator_bulk_data nt51021_novatek_supplies[] = {
+ { .supply = "vdd" },
+ { .supply = "avdd" },
+ { .supply = "havdd" },
+};
+
+static inline struct novatek_nt51021_desc *to_novatek_panel(struct drm_panel *panel)
+{
+ return container_of_const(panel, struct novatek_nt51021_desc, panel);
+}
+
+static void nt51021_novatek_reset(struct novatek_nt51021_desc *ctx)
+{
+ gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+ msleep(20);
+ gpiod_set_value_cansleep(ctx->reset_gpio, 0);
+ usleep_range(10000, 11000);
+}
+
+static void nt51021_cabc_on(struct mipi_dsi_multi_context *dsi_ctx)
+{
+ if (dsi_ctx->accum_err)
+ return;
+
+ mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x8f, 0x00);
+ mipi_dsi_usleep_range(dsi_ctx, 1000, 2000);
+ mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x8f, 0xa5);
+ mipi_dsi_usleep_range(dsi_ctx, 1000, 2000);
+ mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x83, 0xbb);
+ mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x84, 0x22);
+ mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x90, 0x40);
+ mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x8f, 0x00);
+ mipi_dsi_usleep_range(dsi_ctx, 1000, 2000);
+}
+
+static void nt51021_cabc_off(struct mipi_dsi_multi_context *dsi_ctx)
+{
+ if (dsi_ctx->accum_err)
+ return;
+
+ mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x8f, 0xa5);
+ mipi_dsi_usleep_range(dsi_ctx, 1000, 2000);
+ mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x83, 0xbb);
+ mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x84, 0x22);
+ mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x90, 0xc0);
+ mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x8f, 0x00);
+ mipi_dsi_usleep_range(dsi_ctx, 1000, 2000);
+}
+
+static int boe_tv080wum_nx2_init(struct novatek_nt51021_desc *ctx)
+{
+ struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
+
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8f, 0xa5);
+ mipi_dsi_usleep_range(&dsi_ctx, 1000, 2000);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x01, 0x00);
+ mipi_dsi_msleep(&dsi_ctx, 20);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8f, 0xa5);
+ mipi_dsi_usleep_range(&dsi_ctx, 1000, 2000);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x83, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x84, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8c, 0x8e);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcd, 0x6c);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc0, 0x8b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc8, 0xf0);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8b, 0x10);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa9, 0x20);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x97, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfa, 0x15);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfd, 0x1b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x83, 0xaa);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x84, 0x11);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa9, 0x4b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x85, 0x04);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x86, 0x08);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x98, 0xc1);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x83, 0xaa);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x84, 0x11);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc0, 0x05);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc1, 0x0c);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc2, 0x22);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc3, 0x34);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc4, 0x44);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc5, 0x52);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc6, 0x5d);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc7, 0x66);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc8, 0x70);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc9, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xca, 0x11);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcb, 0x3b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcc, 0x53);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcd, 0x69);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xce, 0x6a);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcf, 0x6c);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd0, 0x6b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd1, 0x75);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd2, 0x83);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd3, 0x99);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd4, 0x9a);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd5, 0xd0);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd6, 0xd6);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd7, 0xdb);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd8, 0xe1);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd9, 0xe7);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xda, 0xed);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdb, 0xf4);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdc, 0xfb);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdd, 0xff);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xde, 0xff);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdf, 0x0f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe0, 0x15);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe1, 0x1c);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe2, 0x32);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe3, 0x44);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe4, 0x52);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe5, 0x60);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe6, 0x6b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe7, 0x74);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe8, 0x7e);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe9, 0x14);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xea, 0x25);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xeb, 0x4d);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xec, 0x63);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xed, 0x71);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xee, 0x6a);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xef, 0x6c);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf0, 0x6b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf1, 0x75);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf2, 0x83);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf3, 0x99);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf4, 0x9a);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf5, 0xd0);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf6, 0xd6);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf7, 0xdb);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf8, 0xe1);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf9, 0xe7);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfa, 0xed);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfb, 0xf4);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfc, 0xfb);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfd, 0xff);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfe, 0xff);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xff, 0x0f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x83, 0xbb);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x84, 0x22);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa1, 0xff);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa2, 0xfe);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa3, 0xfa);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa4, 0xf7);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa5, 0xf3);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa6, 0xf1);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa7, 0xed);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa8, 0xeb);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa9, 0xe9);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xaa, 0xe6);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xaf, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb0, 0x35);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb1, 0x89);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb2, 0x99);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb3, 0x99);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb4, 0x0d);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb5, 0x1a);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb6, 0x16);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9a, 0x10);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9b, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x96, 0xe6);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x99, 0x06);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc0, 0x05);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc1, 0x0c);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc2, 0x22);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc3, 0x34);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc4, 0x44);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc5, 0x52);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc6, 0x5d);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc7, 0x66);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc8, 0x70);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc9, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xca, 0x11);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcb, 0x3b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcc, 0x53);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcd, 0x69);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xce, 0x6a);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcf, 0x6c);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd0, 0x6b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd1, 0x75);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd2, 0x83);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd3, 0x99);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd4, 0x9a);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd5, 0xd0);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd6, 0xd6);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd7, 0xdb);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd8, 0xe1);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd9, 0xe7);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xda, 0xed);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdb, 0xf4);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdc, 0xfb);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdd, 0xff);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xde, 0xff);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdf, 0x0f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe0, 0x15);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe1, 0x1c);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe2, 0x32);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe3, 0x44);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe4, 0x52);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe5, 0x60);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe6, 0x6b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe7, 0x74);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe8, 0x7e);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe9, 0x14);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xea, 0x25);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xeb, 0x4d);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xec, 0x63);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xed, 0x71);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xee, 0x6a);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xef, 0x6c);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf0, 0x6b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf1, 0x75);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf2, 0x83);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf3, 0x99);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf4, 0x9a);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf5, 0xd0);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf6, 0xd6);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf7, 0xdb);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf8, 0xe1);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf9, 0xe7);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfa, 0xed);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfb, 0xf4);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfc, 0xfb);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfd, 0xff);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfe, 0xff);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xff, 0x0f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x83, 0xcc);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x84, 0x33);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc0, 0x05);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc1, 0x0c);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc2, 0x22);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc3, 0x34);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc4, 0x44);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc5, 0x52);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc6, 0x5d);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc7, 0x66);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc8, 0x70);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc9, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xca, 0x11);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcb, 0x3b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcc, 0x53);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcd, 0x69);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xce, 0x6a);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcf, 0x6c);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd0, 0x6b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd1, 0x75);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd2, 0x83);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd3, 0x99);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd4, 0x9a);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd5, 0xd0);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd6, 0xd6);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd7, 0xdb);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd8, 0xe1);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd9, 0xe7);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xda, 0xed);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdb, 0xf4);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdc, 0xfb);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdd, 0xff);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xde, 0xff);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdf, 0x0f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe0, 0x15);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe1, 0x1c);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe2, 0x32);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe3, 0x44);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe4, 0x52);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe5, 0x60);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe6, 0x6b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe7, 0x74);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe8, 0x7e);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe9, 0x14);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xea, 0x25);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xeb, 0x4d);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xec, 0x63);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xed, 0x71);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xee, 0x6a);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xef, 0x6c);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf0, 0x6b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf1, 0x75);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf2, 0x83);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf3, 0x99);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf4, 0x9a);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf5, 0xd0);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf6, 0xd6);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf7, 0xdb);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf8, 0xe1);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf9, 0xe7);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfa, 0xed);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfb, 0xf4);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfc, 0xfb);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfd, 0xff);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfe, 0xff);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xff, 0x0f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x83, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x84, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9f, 0xff);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x83, 0xbb);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x84, 0x22);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x94, 0xba);
+ mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
+ mipi_dsi_usleep_range(&dsi_ctx, 5000, 6000);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8f, 0x00);
+ mipi_dsi_usleep_range(&dsi_ctx, 1000, 2000);
+
+ nt51021_cabc_on(&dsi_ctx);
+
+ return dsi_ctx.accum_err;
+}
+
+static int boe_tv101wum_nx0_init(struct novatek_nt51021_desc *ctx)
+{
+ struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
+
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8f, 0xa5);
+ mipi_dsi_usleep_range(&dsi_ctx, 1000, 2000);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x01, 0x00);
+ mipi_dsi_msleep(&dsi_ctx, 20);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8f, 0xa5);
+ mipi_dsi_usleep_range(&dsi_ctx, 1000, 2000);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x83, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x84, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8c, 0x8e);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfa, 0x12);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfd, 0x1b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcd, 0x6c);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc8, 0xfc);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x97, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8b, 0x10);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa9, 0x20);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x83, 0xaa);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x84, 0x11);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa9, 0x4b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x85, 0x04);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x86, 0x08);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x98, 0xc1);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9c, 0x10);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x83, 0xaa);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x84, 0x11);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc0, 0x0e);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc1, 0x11);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc2, 0x1f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc3, 0x30);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc4, 0x3f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc5, 0x4b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc6, 0x55);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc7, 0x5d);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc8, 0x68);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc9, 0xe3);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xca, 0xea);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcb, 0x01);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcc, 0x0a);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcd, 0x0a);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xce, 0x07);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcf, 0x08);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd0, 0x09);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd1, 0x1d);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd2, 0x31);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd3, 0x52);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd4, 0x5b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd5, 0xb6);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd6, 0xbd);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd7, 0xc5);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd8, 0xcd);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd9, 0xd6);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xda, 0xe0);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdb, 0xeb);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdc, 0xf8);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdd, 0xff);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xde, 0xfc);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdf, 0x0f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe0, 0x0e);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe1, 0x11);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe2, 0x1f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe3, 0x30);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe4, 0x3f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe5, 0x4b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe6, 0x55);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe7, 0x5d);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe8, 0x68);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe9, 0xe3);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xea, 0xea);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xeb, 0x01);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xec, 0x0a);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xed, 0x0a);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xee, 0x07);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xef, 0x08);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf0, 0x09);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf1, 0x1d);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf2, 0x31);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf3, 0x52);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf4, 0x5b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf5, 0xb6);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf6, 0xbd);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf7, 0xc5);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf8, 0xcd);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf9, 0xd6);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfa, 0xe0);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfb, 0xeb);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfc, 0xf8);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfd, 0xff);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfe, 0xfc);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xff, 0x0f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x83, 0xbb);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x84, 0x22);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa1, 0xff);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa2, 0xfe);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa3, 0xfa);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa4, 0xf7);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa5, 0xf3);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa6, 0xf1);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa7, 0xed);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa8, 0xeb);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa9, 0xe9);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xaa, 0xe6);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xaf, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb0, 0x12);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb1, 0x23);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb2, 0x34);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb3, 0x77);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb4, 0x0d);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb5, 0x1a);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb6, 0x16);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9a, 0x10);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9b, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x96, 0xe6);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x99, 0x06);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc0, 0x0e);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc1, 0x11);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc2, 0x1f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc3, 0x30);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc4, 0x3f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc5, 0x4b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc6, 0x55);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc7, 0x5d);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc8, 0x68);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc9, 0xe3);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xca, 0xea);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcb, 0x01);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcc, 0x0a);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcd, 0x0a);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xce, 0x07);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcf, 0x08);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd0, 0x09);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd1, 0x1d);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd2, 0x31);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd3, 0x52);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd4, 0x5b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd5, 0xb6);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd6, 0xbd);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd7, 0xc5);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd8, 0xcd);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd9, 0xd6);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xda, 0xe0);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdb, 0xeb);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdc, 0xf8);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdd, 0xff);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xde, 0xfc);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdf, 0x0f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe0, 0x0e);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe1, 0x11);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe2, 0x1f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe3, 0x30);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe4, 0x3f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe5, 0x4b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe6, 0x55);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe7, 0x5d);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe8, 0x68);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe9, 0xe3);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xea, 0xea);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xeb, 0x01);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xec, 0x0a);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xed, 0x0a);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xee, 0x07);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xef, 0x08);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf0, 0x09);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf1, 0x1d);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf2, 0x31);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf3, 0x52);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf4, 0x5b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf5, 0xb6);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf6, 0xbd);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf7, 0xc5);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf8, 0xcd);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf9, 0xd6);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfa, 0xe0);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfb, 0xeb);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfc, 0xf8);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfd, 0xff);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfe, 0xfc);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xff, 0x0f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x83, 0xcc);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x84, 0x33);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc0, 0x0e);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc1, 0x11);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc2, 0x1f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc3, 0x30);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc4, 0x3f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc5, 0x4b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc6, 0x55);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc7, 0x5d);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc8, 0x68);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc9, 0xe3);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xca, 0xea);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcb, 0x01);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcc, 0x0a);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcd, 0x0a);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xce, 0x07);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcf, 0x08);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd0, 0x09);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd1, 0x1d);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd2, 0x31);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd3, 0x52);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd4, 0x5b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd5, 0xb6);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd6, 0xbd);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd7, 0xc5);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd8, 0xcd);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd9, 0xd6);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xda, 0xe0);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdb, 0xeb);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdc, 0xf8);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdd, 0xff);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xde, 0xfc);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdf, 0x0f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe0, 0x0e);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe1, 0x11);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe2, 0x1f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe3, 0x30);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe4, 0x3f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe5, 0x4b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe6, 0x55);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe7, 0x5d);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe8, 0x68);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe9, 0xe3);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xea, 0xea);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xeb, 0x01);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xec, 0x0a);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xed, 0x0a);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xee, 0x07);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xef, 0x08);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf0, 0x09);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf1, 0x1d);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf2, 0x31);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf3, 0x52);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf4, 0x5b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf5, 0xb6);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf6, 0xbd);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf7, 0xc5);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf8, 0xcd);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf9, 0xd6);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfa, 0xe0);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfb, 0xeb);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfc, 0xf8);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfd, 0xff);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfe, 0xfc);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xff, 0x0f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x83, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x84, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9f, 0xff);
+ mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
+ mipi_dsi_usleep_range(&dsi_ctx, 5000, 6000);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8f, 0x00);
+ mipi_dsi_usleep_range(&dsi_ctx, 1000, 2000);
+
+ nt51021_cabc_on(&dsi_ctx);
+ mipi_dsi_usleep_range(&dsi_ctx, 1000, 2000);
+
+ return dsi_ctx.accum_err;
+}
+
+static int boe_tv101wum_nm0_init(struct novatek_nt51021_desc *ctx)
+{
+ struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
+
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8f, 0xa5);
+ mipi_dsi_usleep_range(&dsi_ctx, 1000, 2000);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x01, 0x00);
+ mipi_dsi_msleep(&dsi_ctx, 20);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8f, 0xa5);
+ mipi_dsi_usleep_range(&dsi_ctx, 1000, 2000);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x83, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x84, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8c, 0x80);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcd, 0x6c);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc0, 0x8b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc8, 0xf0);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x97, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8b, 0x10);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa9, 0x20);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x83, 0xaa);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x84, 0x11);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa9, 0x4b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x85, 0x04);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x86, 0x08);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9c, 0x10);
+ mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
+ mipi_dsi_msleep(&dsi_ctx, 120);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8f, 0x00);
+ mipi_dsi_msleep(&dsi_ctx, 5);
+
+ return dsi_ctx.accum_err;
+}
+
+static int nt51021_novatek_with_cabc_off(struct novatek_nt51021_desc *ctx)
+{
+ struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
+
+ nt51021_cabc_off(&dsi_ctx);
+
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8f, 0xa5);
+ mipi_dsi_msleep(&dsi_ctx, 20);
+ mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
+ mipi_dsi_msleep(&dsi_ctx, 130);
+ mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
+ mipi_dsi_msleep(&dsi_ctx, 70);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8f, 0x00);
+ mipi_dsi_usleep_range(&dsi_ctx, 4000, 5000);
+
+ return dsi_ctx.accum_err;
+}
+
+static int nt51021_novatek_off(struct novatek_nt51021_desc *ctx)
+{
+ struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
+
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8f, 0xa5);
+ mipi_dsi_msleep(&dsi_ctx, 20);
+ mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
+ mipi_dsi_msleep(&dsi_ctx, 130);
+ mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
+ mipi_dsi_msleep(&dsi_ctx, 70);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8f, 0x00);
+ mipi_dsi_usleep_range(&dsi_ctx, 4000, 5000);
+
+ return dsi_ctx.accum_err;
+}
+
+static int nt51021_novatek_prepare(struct drm_panel *panel)
+{
+ struct novatek_nt51021_desc *ctx = to_novatek_panel(panel);
+ struct device *dev = &ctx->dsi->dev;
+ int ret;
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(nt51021_novatek_supplies), ctx->supplies);
+ if (ret < 0) {
+ dev_err(dev, "Failed to enable regulators: %d\n", ret);
+ return ret;
+ }
+ nt51021_novatek_reset(ctx);
+
+ ret = ctx->variant->init(ctx);
+ if (ret < 0) {
+ dev_err(dev, "Failed to initialize panel: %d\n", ret);
+ gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+ regulator_bulk_disable(ARRAY_SIZE(nt51021_novatek_supplies), ctx->supplies);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int nt51021_novatek_unprepare(struct drm_panel *panel)
+{
+ struct novatek_nt51021_desc *ctx = to_novatek_panel(panel);
+ struct device *dev = &ctx->dsi->dev;
+ int ret;
+
+ ret = ctx->variant->off(ctx);
+ if (ret < 0)
+ dev_err(dev, "Failed to un-initialize panel: %d\n", ret);
+
+ gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+ regulator_bulk_disable(ARRAY_SIZE(nt51021_novatek_supplies), ctx->supplies);
+
+ return 0;
+}
+
+static int nt51021_novatek_get_modes(struct drm_panel *panel,
+ struct drm_connector *connector)
+{
+ struct novatek_nt51021_desc *ctx = to_novatek_panel(panel);
+
+ return drm_connector_helper_get_modes_fixed(connector,
+ ctx->variant->display_mode);
+}
+
+static const struct drm_panel_funcs nt51021_novatek_panel_funcs = {
+ .prepare = nt51021_novatek_prepare,
+ .unprepare = nt51021_novatek_unprepare,
+ .get_modes = nt51021_novatek_get_modes,
+};
+
+static int nt51021_novatek_probe(struct mipi_dsi_device *dsi)
+{
+ struct device *dev = &dsi->dev;
+ struct novatek_nt51021_desc *ctx;
+ int ret;
+
+ ctx = devm_drm_panel_alloc(dev, struct novatek_nt51021_desc, panel,
+ &nt51021_novatek_panel_funcs,
+ DRM_MODE_CONNECTOR_DSI);
+ if (IS_ERR(ctx))
+ return PTR_ERR(ctx);
+
+ ctx->variant = of_device_get_match_data(dev);
+ if (!ctx->variant)
+ return dev_err_probe(dev, -ENODEV, "No match data\n");
+
+ ret = devm_regulator_bulk_get_const(dev,
+ ARRAY_SIZE(nt51021_novatek_supplies),
+ nt51021_novatek_supplies,
+ &ctx->supplies);
+ if (ret < 0)
+ return ret;
+
+ ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(ctx->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
+ "Failed to get reset-gpios\n");
+
+ ctx->dsi = dsi;
+ mipi_dsi_set_drvdata(dsi, ctx);
+
+ dsi->lanes = 4;
+ dsi->format = MIPI_DSI_FMT_RGB888;
+ dsi->mode_flags = ctx->variant->mode_flags;
+
+ ctx->panel.prepare_prev_first = true;
+
+ ret = drm_panel_of_backlight(&ctx->panel);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get backlight\n");
+
+ ret = devm_drm_panel_add(dev, &ctx->panel);
+ if (ret)
+ return ret;
+
+ return devm_mipi_dsi_attach(dev, dsi);
+}
+
+static const struct drm_display_mode boe_tv080wum_nx2_mode = {
+ .clock = (1200 + 84 + 4 + 60) * (1920 + 36 + 1 + 25) * 60 / 1000,
+ .hdisplay = 1200,
+ .hsync_start = 1200 + 84,
+ .hsync_end = 1200 + 84 + 4,
+ .htotal = 1200 + 84 + 4 + 60,
+ .vdisplay = 1920,
+ .vsync_start = 1920 + 36,
+ .vsync_end = 1920 + 36 + 1,
+ .vtotal = 1920 + 36 + 1 + 25,
+ .width_mm = 107,
+ .height_mm = 172,
+ .type = DRM_MODE_TYPE_DRIVER,
+};
+
+static const struct drm_display_mode boe_tv101wum_nm0_mode = {
+ .clock = 163333,
+ .hdisplay = 1200,
+ .hsync_start = 1200 + 110,
+ .hsync_end = 1200 + 110 + 1,
+ .htotal = 1200 + 110 + 1 + 32,
+ .vdisplay = 1920,
+ .vsync_start = 1920 + 11,
+ .vsync_end = 1920 + 11 + 1,
+ .vtotal = 1920 + 11 + 1 + 14,
+ .width_mm = 135,
+ .height_mm = 216,
+ .type = DRM_MODE_TYPE_DRIVER,
+};
+
+static const struct drm_display_mode boe_tv101wum_nx0_mode = {
+ .clock = (1200 + 172 + 4 + 32) * (1920 + 25 + 1 + 14) * 60 / 1000,
+ .hdisplay = 1200,
+ .hsync_start = 1200 + 172,
+ .hsync_end = 1200 + 172 + 4,
+ .htotal = 1200 + 172 + 4 + 32,
+ .vdisplay = 1920,
+ .vsync_start = 1920 + 25,
+ .vsync_end = 1920 + 25 + 1,
+ .vtotal = 1920 + 25 + 1 + 14,
+ .width_mm = 135,
+ .height_mm = 216,
+ .type = DRM_MODE_TYPE_DRIVER,
+};
+
+#define NT51021_BURST_MODE_FLAGS (MIPI_DSI_MODE_VIDEO | \
+ MIPI_DSI_MODE_VIDEO_BURST | \
+ MIPI_DSI_MODE_NO_EOT_PACKET | \
+ MIPI_DSI_MODE_LPM)
+
+static const struct novatek_nt51021_variant boe_tv080wum_nx2_data = {
+ .init = boe_tv080wum_nx2_init,
+ .off = nt51021_novatek_with_cabc_off,
+ .display_mode = &boe_tv080wum_nx2_mode,
+ .mode_flags = NT51021_BURST_MODE_FLAGS,
+};
+
+static const struct novatek_nt51021_variant boe_tv101wum_nm0_data = {
+ .init = boe_tv101wum_nm0_init,
+ .off = nt51021_novatek_off,
+ .display_mode = &boe_tv101wum_nm0_mode,
+ .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM,
+};
+
+static const struct novatek_nt51021_variant boe_tv101wum_nx0_data = {
+ .init = boe_tv101wum_nx0_init,
+ .off = nt51021_novatek_with_cabc_off,
+ .display_mode = &boe_tv101wum_nx0_mode,
+ .mode_flags = NT51021_BURST_MODE_FLAGS,
+};
+
+static const struct of_device_id nt51021_novatek_of_match[] = {
+ { .compatible = "boe,tv080wum-nx2", .data = &boe_tv080wum_nx2_data },
+ { .compatible = "boe,tv101wum-nm0", .data = &boe_tv101wum_nm0_data },
+ { .compatible = "boe,tv101wum-nx0", .data = &boe_tv101wum_nx0_data },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, nt51021_novatek_of_match);
+
+static struct mipi_dsi_driver nt51021_boe_driver = {
+ .probe = nt51021_novatek_probe,
+ .driver = {
+ .name = "panel-novatek-nt51021",
+ .of_match_table = nt51021_novatek_of_match,
+ },
+};
+module_mipi_dsi_driver(nt51021_boe_driver);
+
+MODULE_AUTHOR("Nickolay Goppen <setotau@mainlining.org>");
+MODULE_AUTHOR("Alexey Minnekhanov <alexeymin@minlexx.ru>");
+MODULE_AUTHOR("Ryan Brue <ryanbrue.dev@gmail.com>");
+MODULE_DESCRIPTION("DRM driver for Novatek NT51021-based DSI panels");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/panel/panel-raydium-rm69220.c b/drivers/gpu/drm/panel/panel-raydium-rm69220.c
new file mode 100644
index 000000000000..3030f8b89760
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-raydium-rm69220.c
@@ -0,0 +1,417 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree.
+ * Copyright (c) 2026 Alexander Koskovich <akoskovich@pm.me>
+ */
+
+#include <linux/backlight.h>
+#include <linux/delay.h>
+#include <linux/device-id/of.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+
+#include <video/mipi_display.h>
+
+#include <drm/display/drm_dsc.h>
+#include <drm/display/drm_dsc_helper.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
+
+struct raydium_rm69220 {
+ struct drm_panel panel;
+ struct mipi_dsi_device *dsi;
+ struct drm_dsc_config dsc;
+ struct regulator_bulk_data *supplies;
+ struct gpio_desc *reset_gpio;
+};
+
+static const struct regulator_bulk_data raydium_rm69220_supplies[] = {
+ { .supply = "vddio" },
+ { .supply = "dvdd" },
+ { .supply = "vci" },
+};
+
+static inline
+struct raydium_rm69220 *to_raydium_rm69220(struct drm_panel *panel)
+{
+ return container_of(panel, struct raydium_rm69220, panel);
+}
+
+static void raydium_rm69220_reset(struct raydium_rm69220 *ctx)
+{
+ gpiod_set_value_cansleep(ctx->reset_gpio, 0);
+ usleep_range(1000, 2000);
+ gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+ usleep_range(1000, 2000);
+ gpiod_set_value_cansleep(ctx->reset_gpio, 0);
+ msleep(32);
+}
+
+static int raydium_rm69220_on(struct raydium_rm69220 *ctx)
+{
+ struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
+
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0x76);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x9a, 0x10);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x9b, 0x00);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0x77);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x9a, 0x10);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x9b, 0x00);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0x78);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x9a, 0x10);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x9b, 0x00);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0x79);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x9a, 0xf0);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x9b, 0x00);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0x74);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1a, 0xe0);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1b, 0x00);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0x40);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xa9, 0x68);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xab, 0x22);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0x40);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc0, 0xa6);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xbf, 0x87);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0x82);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x90);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0xd4);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x61, 0x08);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xa2, 0x04);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0x00);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfa, 0x01);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0xd2);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x97, 0x08);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x36, 0x11);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x39, 0xab);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3a, 0x30);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3b, 0x80);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3d, 0x09);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3f, 0x58);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x40, 0x04);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x41, 0x38);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x42, 0x00);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x43, 0x0d);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x44, 0x02);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x45, 0x1c);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x46, 0x02);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x47, 0x1c);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x48, 0x02);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x49, 0x00);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4a, 0x02);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4b, 0x0e);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4d, 0x20);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4e, 0x01);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4f, 0x39);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x50, 0x00);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x51, 0x07);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x53, 0x0c);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x54, 0x08);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x55, 0x00);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x56, 0x07);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x58, 0xd3);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x59, 0x18);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5a, 0x00);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5b, 0x10);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5c, 0xf0);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5d, 0x07);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5e, 0x10);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5f, 0x20);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x60, 0x00);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x61, 0x06);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x62, 0x0f);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x63, 0x0f);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x64, 0x33);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x65, 0x0e);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x66, 0x1c);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x67, 0x2a);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x68, 0x38);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x69, 0x46);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6a, 0x54);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6b, 0x62);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6c, 0x69);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6d, 0x70);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6e, 0x77);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x79);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x70, 0x7b);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x71, 0x7d);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x72, 0x7e);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x73, 0x01);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x74, 0x02);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x75, 0x22);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x76, 0x00);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x77, 0x2a);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x78, 0x40);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x79, 0x2a);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7a, 0xbe);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7b, 0x3a);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7c, 0xfc);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7d, 0x3a);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7e, 0xfa);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7f, 0x3a);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x80, 0xf8);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x81, 0x3b);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x82, 0x38);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x83, 0x3b);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x84, 0x78);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x85, 0x3b);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x86, 0xb6);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x87, 0x4b);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x88, 0xf6);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x89, 0x4c);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x8a, 0x34);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x8b, 0x4c);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x8c, 0x74);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x8d, 0x5c);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x8e, 0x74);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x8f, 0x8c);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x90, 0xf4);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x91, 0x00);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x92, 0x00);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x93, 0x00);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x94, 0x00);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x95, 0x00);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x96, 0x00);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0xa0);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x66, 0x06);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0x49);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x87, 0x00);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3f, 0x00);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0xa0);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x04, 0x07);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4b, 0x40);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4d, 0x40);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0xa1);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x58, 0x67);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x75, 0xa7);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0x00);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2f, 0x00);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0x00);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfa, 0x01);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc1, 0x03);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc2, 0x03);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x35, 0x00);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x51, 0x0d, 0xbb);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0x00);
+ mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
+ mipi_dsi_msleep(&dsi_ctx, 80);
+ mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
+ mipi_dsi_usleep_range(&dsi_ctx, 10000, 11000);
+
+ return dsi_ctx.accum_err;
+}
+
+static int raydium_rm69220_off(struct raydium_rm69220 *ctx)
+{
+ struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
+
+ mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
+ mipi_dsi_msleep(&dsi_ctx, 100);
+ mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
+ mipi_dsi_msleep(&dsi_ctx, 100);
+
+ return dsi_ctx.accum_err;
+}
+
+static int raydium_rm69220_prepare(struct drm_panel *panel)
+{
+ struct raydium_rm69220 *ctx = to_raydium_rm69220(panel);
+ struct device *dev = &ctx->dsi->dev;
+ struct drm_dsc_picture_parameter_set pps;
+ int ret;
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(raydium_rm69220_supplies), ctx->supplies);
+ if (ret < 0) {
+ dev_err(dev, "Failed to enable regulators: %d\n", ret);
+ return ret;
+ }
+
+ raydium_rm69220_reset(ctx);
+
+ ret = raydium_rm69220_on(ctx);
+ if (ret < 0) {
+ dev_err(dev, "Failed to initialize panel: %d\n", ret);
+ goto err;
+ }
+
+ drm_dsc_pps_payload_pack(&pps, &ctx->dsc);
+
+ ret = mipi_dsi_picture_parameter_set(ctx->dsi, &pps);
+ if (ret < 0) {
+ dev_err(dev, "failed to transmit PPS: %d\n", ret);
+ goto err;
+ }
+
+ ret = mipi_dsi_compression_mode(ctx->dsi, true);
+ if (ret < 0) {
+ dev_err(dev, "failed to enable compression mode: %d\n", ret);
+ goto err;
+ }
+
+ msleep(28);
+
+ return 0;
+
+err:
+ gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+ regulator_bulk_disable(ARRAY_SIZE(raydium_rm69220_supplies), ctx->supplies);
+ return ret;
+}
+
+static int raydium_rm69220_unprepare(struct drm_panel *panel)
+{
+ struct raydium_rm69220 *ctx = to_raydium_rm69220(panel);
+ struct device *dev = &ctx->dsi->dev;
+ int ret;
+
+ ret = raydium_rm69220_off(ctx);
+ if (ret < 0)
+ dev_err(dev, "Failed to un-initialize panel: %d\n", ret);
+
+ gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+ regulator_bulk_disable(ARRAY_SIZE(raydium_rm69220_supplies), ctx->supplies);
+
+ return 0;
+}
+
+static const struct drm_display_mode raydium_rm69220_mode = {
+ .clock = (1080 + 36 + 4 + 36) * (2392 + 72 + 4 + 52) * 120 / 1000,
+ .hdisplay = 1080,
+ .hsync_start = 1080 + 36,
+ .hsync_end = 1080 + 36 + 4,
+ .htotal = 1080 + 36 + 4 + 36,
+ .vdisplay = 2392,
+ .vsync_start = 2392 + 72,
+ .vsync_end = 2392 + 72 + 4,
+ .vtotal = 2392 + 72 + 4 + 52,
+ .width_mm = 71,
+ .height_mm = 157,
+ .type = DRM_MODE_TYPE_DRIVER,
+};
+
+static int raydium_rm69220_get_modes(struct drm_panel *panel,
+ struct drm_connector *connector)
+{
+ return drm_connector_helper_get_modes_fixed(connector, &raydium_rm69220_mode);
+}
+
+static const struct drm_panel_funcs raydium_rm69220_panel_funcs = {
+ .prepare = raydium_rm69220_prepare,
+ .unprepare = raydium_rm69220_unprepare,
+ .get_modes = raydium_rm69220_get_modes,
+};
+
+static int raydium_rm69220_bl_update_status(struct backlight_device *bl)
+{
+ struct mipi_dsi_device *dsi = bl_get_data(bl);
+ u16 brightness = backlight_get_brightness(bl);
+ int ret;
+
+ dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
+
+ ret = mipi_dsi_dcs_set_display_brightness_large(dsi, brightness);
+ if (ret < 0)
+ return ret;
+
+ dsi->mode_flags |= MIPI_DSI_MODE_LPM;
+
+ return 0;
+}
+
+static const struct backlight_ops raydium_rm69220_bl_ops = {
+ .update_status = raydium_rm69220_bl_update_status,
+};
+
+static struct backlight_device *
+raydium_rm69220_create_backlight(struct mipi_dsi_device *dsi)
+{
+ struct device *dev = &dsi->dev;
+ const struct backlight_properties props = {
+ .type = BACKLIGHT_RAW,
+ .brightness = 2946,
+ .max_brightness = 3442, /* 4095 is HBM max */
+ };
+
+ return devm_backlight_device_register(dev, dev_name(dev), dev, dsi,
+ &raydium_rm69220_bl_ops, &props);
+}
+
+static int raydium_rm69220_probe(struct mipi_dsi_device *dsi)
+{
+ struct device *dev = &dsi->dev;
+ struct raydium_rm69220 *ctx;
+ int ret;
+
+ ctx = devm_drm_panel_alloc(dev, struct raydium_rm69220, panel,
+ &raydium_rm69220_panel_funcs,
+ DRM_MODE_CONNECTOR_DSI);
+ if (IS_ERR(ctx))
+ return PTR_ERR(ctx);
+
+ ret = devm_regulator_bulk_get_const(dev,
+ ARRAY_SIZE(raydium_rm69220_supplies),
+ raydium_rm69220_supplies,
+ &ctx->supplies);
+ if (ret < 0)
+ return ret;
+
+ ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(ctx->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
+ "Failed to get reset-gpios\n");
+
+ ctx->dsi = dsi;
+
+ dsi->lanes = 4;
+ dsi->format = MIPI_DSI_FMT_RGB101010;
+ dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_NO_EOT_PACKET |
+ MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM |
+ MIPI_DSI_MODE_DSC_ALL_SLICES_IN_PKT;
+
+ ctx->panel.prepare_prev_first = true;
+
+ ctx->panel.backlight = raydium_rm69220_create_backlight(dsi);
+ if (IS_ERR(ctx->panel.backlight))
+ return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight),
+ "Failed to create backlight\n");
+
+ ret = devm_drm_panel_add(dev, &ctx->panel);
+ if (ret < 0)
+ return ret;
+
+ /* This panel only supports DSC; unconditionally enable it */
+ dsi->dsc = &ctx->dsc;
+
+ ctx->dsc.dsc_version_major = 1;
+ ctx->dsc.dsc_version_minor = 1;
+ ctx->dsc.slice_height = 13;
+ ctx->dsc.slice_width = 540;
+
+ ctx->dsc.slice_count = 1080 / ctx->dsc.slice_width;
+ ctx->dsc.bits_per_component = 10;
+ ctx->dsc.bits_per_pixel = 8 << 4; /* 4 fractional bits */
+ ctx->dsc.block_pred_enable = true;
+
+ return devm_mipi_dsi_attach(dev, dsi);
+}
+
+static const struct of_device_id raydium_rm69220_of_match[] = {
+ { .compatible = "boe,bf068mwm-td0" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, raydium_rm69220_of_match);
+
+static struct mipi_dsi_driver raydium_rm69220_driver = {
+ .probe = raydium_rm69220_probe,
+ .driver = {
+ .name = "panel-raydium-rm69220",
+ .of_match_table = raydium_rm69220_of_match,
+ },
+};
+module_mipi_dsi_driver(raydium_rm69220_driver);
+
+MODULE_AUTHOR("Alexander Koskovich <akoskovich@pm.me>");
+MODULE_DESCRIPTION("DRM driver for RM69220-equipped DSI panels");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/panel/panel-ronbo-rb070d30.c b/drivers/gpu/drm/panel/panel-ronbo-rb070d30.c
index c3fbc459c7e0..9adf97aba5d3 100644
--- a/drivers/gpu/drm/panel/panel-ronbo-rb070d30.c
+++ b/drivers/gpu/drm/panel/panel-ronbo-rb070d30.c
@@ -75,15 +75,25 @@ static int rb070d30_panel_unprepare(struct drm_panel *panel)
static int rb070d30_panel_enable(struct drm_panel *panel)
{
struct rb070d30_panel *ctx = panel_to_rb070d30_panel(panel);
+ struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
- return mipi_dsi_dcs_exit_sleep_mode(ctx->dsi);
+ mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
+ return dsi_ctx.accum_err;
}
static int rb070d30_panel_disable(struct drm_panel *panel)
{
struct rb070d30_panel *ctx = panel_to_rb070d30_panel(panel);
+ struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
- return mipi_dsi_dcs_enter_sleep_mode(ctx->dsi);
+ mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
+
+ /*
+ * Returning an error would leave panel->enabled set, causing the
+ * next enable to be skipped even after unprepare powers off the panel.
+ * The helper above already logs any command failure.
+ */
+ return 0;
}
/* Default timings */
diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
index d7dbd7442919..a944c34642dc 100644
--- a/drivers/gpu/drm/panel/panel-simple.c
+++ b/drivers/gpu/drm/panel/panel-simple.c
@@ -4379,6 +4379,9 @@ static const struct panel_desc raystar_rff500f_awh_dnn = {
.width = 108,
.height = 65,
},
+ .delay = {
+ .enable = 250,
+ },
.bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
.connector_type = DRM_MODE_CONNECTOR_LVDS,
};
diff --git a/drivers/gpu/drm/panel/panel-visionox-vtdr6130.c b/drivers/gpu/drm/panel/panel-visionox-vtdr6130.c
index 6733e0e1d061..d0db128cda81 100644
--- a/drivers/gpu/drm/panel/panel-visionox-vtdr6130.c
+++ b/drivers/gpu/drm/panel/panel-visionox-vtdr6130.c
@@ -11,6 +11,7 @@
#include <drm/display/drm_dsc.h>
#include <drm/display/drm_dsc_helper.h>
#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_of.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
@@ -18,10 +19,24 @@
struct visionox_vtdr6130 {
struct drm_panel panel;
- struct drm_dsc_config dsc;
struct mipi_dsi_device *dsi;
struct gpio_desc *reset_gpio;
struct regulator_bulk_data *supplies;
+ enum drm_panel_orientation orientation;
+ struct visionox_vtdr6130_desc *desc;
+};
+
+struct visionox_vtdr6130_desc {
+ unsigned int bpc;
+ unsigned int lanes;
+ unsigned long mode_flags;
+ enum mipi_dsi_pixel_format format;
+
+ const struct drm_display_mode *modes;
+ unsigned int num_modes;
+ int (*init_sequence)(struct visionox_vtdr6130 *ctx);
+
+ struct drm_dsc_config dsc;
};
static const struct regulator_bulk_data visionox_vtdr6130_supplies[] = {
@@ -45,6 +60,82 @@ static void visionox_vtdr6130_reset(struct visionox_vtdr6130 *ctx)
usleep_range(10000, 11000);
}
+static int retroidpocket_rp6_on(struct visionox_vtdr6130 *ctx)
+{
+ struct mipi_dsi_device *dsi = ctx->dsi;
+ struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
+ struct drm_dsc_picture_parameter_set pps;
+
+ dsi->mode_flags |= MIPI_DSI_MODE_LPM;
+
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x03, 0x01);
+ mipi_dsi_dcs_set_tear_on_multi(&dsi_ctx, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx,
+ MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x20);
+ mipi_dsi_dcs_set_display_brightness_multi(&dsi_ctx, 0xff07);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x02);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_ADDRESS_MODE, 0x02);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x59, 0x00);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6c, 0x00);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6d, 0x00);
+
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x70, 0x11, 0x00, 0x00, 0x89,
+ 0x30, 0x80, 0x07, 0x80, 0x04, 0x38, 0x00,
+ 0x14, 0x02, 0x1c, 0x02, 0x1c, 0x02, 0x00,
+ 0x02, 0x25, 0x00, 0x20, 0x01, 0xd5, 0x00,
+ 0x07, 0x00, 0x0d, 0x05, 0x7a, 0x05, 0x16,
+ 0x18, 0x00, 0x10, 0xf0, 0x03, 0x0c, 0x20,
+ 0x00, 0x06, 0x0b, 0x0b, 0x33, 0x0e, 0x1c,
+ 0x2a, 0x38, 0x46, 0x54, 0x62, 0x69, 0x70,
+ 0x77, 0x79, 0x7b, 0x7d, 0x7e, 0x01, 0x02,
+ 0x01, 0x00, 0x09, 0x40, 0x09, 0xbe, 0x19,
+ 0xfc, 0x19, 0xfa, 0x19, 0xf8, 0x1a, 0x38,
+ 0x1a, 0x78, 0x1a, 0xb6, 0x2a, 0xb6, 0x2a,
+ 0xf4, 0x2a, 0xf4, 0x4b, 0x34, 0x63, 0x74,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
+
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf0, 0xaa, 0x10);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb1, 0x02, 0x15, 0x00, 0x14,
+ 0x00, 0x20, 0x00, 0x02, 0x16, 0x00, 0x14,
+ 0x07, 0xb4, 0x00, 0x02, 0x16, 0x00, 0x14,
+ 0x00, 0x10, 0x00);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf0, 0xaa, 0x14);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb2, 0x03, 0x33);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb4, 0x0a, 0x72, 0x00, 0x00,
+ 0x0a, 0x72, 0x00, 0x00, 0x0a, 0x72, 0x00,
+ 0x00);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb5, 0x00, 0x1e, 0x1e, 0x1e,
+ 0x1e, 0x1e, 0x1e, 0x06, 0x01);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb9, 0x00, 0x00, 0x08, 0x1e,
+ 0x1e, 0x1e);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xbc, 0x10, 0x00, 0x00, 0x08,
+ 0x11, 0x1e, 0x7c, 0x1e, 0x7c, 0x1e, 0x7c);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xbe, 0x10, 0x10, 0x00, 0x0c,
+ 0x22, 0x1e, 0x62, 0x1e, 0x62, 0x1e, 0x62);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x5a, 0x80);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x65, 0x13);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfd, 0x01);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x5a, 0x81);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf9, 0x00);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x5a, 0x83);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x65, 0x04);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf8, 0x00);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf0, 0xaa, 0x00);
+ mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x5a, 0x00);
+
+ mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
+ mipi_dsi_msleep(&dsi_ctx, 150);
+
+ mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
+ mipi_dsi_msleep(&dsi_ctx, 50);
+
+ drm_dsc_pps_payload_pack(&pps, dsi->dsc);
+ mipi_dsi_picture_parameter_set_multi(&dsi_ctx, &pps);
+ mipi_dsi_compression_mode_multi(&dsi_ctx, true);
+
+ return dsi_ctx.accum_err;
+}
+
static int visionox_vtdr6130_on(struct visionox_vtdr6130 *ctx)
{
struct mipi_dsi_device *dsi = ctx->dsi;
@@ -160,7 +251,7 @@ static int visionox_vtdr6130_prepare(struct drm_panel *panel)
visionox_vtdr6130_reset(ctx);
- ret = visionox_vtdr6130_on(ctx);
+ ret = ctx->desc->init_sequence(ctx);
if (ret < 0) {
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
regulator_bulk_disable(ARRAY_SIZE(visionox_vtdr6130_supplies),
@@ -185,26 +276,87 @@ static int visionox_vtdr6130_unprepare(struct drm_panel *panel)
return 0;
}
-static const struct drm_display_mode visionox_vtdr6130_mode = {
- .clock = (1080 + 20 + 2 + 20) * (2400 + 20 + 2 + 18) * 144 / 1000,
- .hdisplay = 1080,
- .hsync_start = 1080 + 20,
- .hsync_end = 1080 + 20 + 2,
- .htotal = 1080 + 20 + 2 + 20,
- .vdisplay = 2400,
- .vsync_start = 2400 + 20,
- .vsync_end = 2400 + 20 + 2,
- .vtotal = 2400 + 20 + 2 + 18,
- .width_mm = 71,
- .height_mm = 157,
+static const struct drm_display_mode retroidpocket_rp6_modes[] = {
+ {
+ .clock = (1080 + 22 + 2 + 16) * (1920 + 16 + 2 + 20) * 120 / 1000,
+ .hdisplay = 1080,
+ .hsync_start = 1080 + 22,
+ .hsync_end = 1080 + 22 + 2,
+ .htotal = 1080 + 22 + 2 + 16,
+ .vdisplay = 1920,
+ .vsync_start = 1920 + 16,
+ .vsync_end = 1920 + 16 + 2,
+ .vtotal = 1920 + 16 + 2 + 20,
+ .width_mm = 69,
+ .height_mm = 122,
+ },
+};
+
+static struct visionox_vtdr6130_desc retroidpocket_rp6_panel_desc = {
+ .modes = retroidpocket_rp6_modes,
+ .num_modes = ARRAY_SIZE(retroidpocket_rp6_modes),
+ .bpc = 8,
+ .lanes = 4,
+ .format = MIPI_DSI_FMT_RGB888,
+ .mode_flags = MIPI_DSI_MODE_NO_EOT_PACKET |
+ MIPI_DSI_CLOCK_NON_CONTINUOUS,
+ .init_sequence = retroidpocket_rp6_on,
+ .dsc = {
+ .dsc_version_major = 0x1,
+ .dsc_version_minor = 0x1,
+ .slice_height = 12,
+ .slice_width = 540,
+ .slice_count = 2,
+ .bits_per_component = 8,
+ .bits_per_pixel = 8 << 4,
+ .block_pred_enable = true,
+ },
+};
+
+static const struct drm_display_mode visionox_vtdr6130_modes[] = {
+ {
+ .clock = (1080 + 20 + 2 + 20) * (2400 + 20 + 2 + 18) * 144 / 1000,
+ .hdisplay = 1080,
+ .hsync_start = 1080 + 20,
+ .hsync_end = 1080 + 20 + 2,
+ .htotal = 1080 + 20 + 2 + 20,
+ .vdisplay = 2400,
+ .vsync_start = 2400 + 20,
+ .vsync_end = 2400 + 20 + 2,
+ .vtotal = 2400 + 20 + 2 + 18,
+ .width_mm = 71,
+ .height_mm = 157,
+ },
+};
+
+static struct visionox_vtdr6130_desc visionox_vtdr6130_panel_desc = {
+ .modes = visionox_vtdr6130_modes,
+ .num_modes = ARRAY_SIZE(visionox_vtdr6130_modes),
+ .bpc = 8,
+ .lanes = 4,
+ .format = MIPI_DSI_FMT_RGB888,
+ .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_NO_EOT_PACKET |
+ MIPI_DSI_CLOCK_NON_CONTINUOUS,
+ .init_sequence = visionox_vtdr6130_on,
+ .dsc = {
+ .dsc_version_major = 0x1,
+ .dsc_version_minor = 0x2,
+ .slice_height = 40,
+ .slice_width = 540,
+ .slice_count = 2,
+ .bits_per_component = 8,
+ .bits_per_pixel = 8 << 4,
+ .block_pred_enable = true,
+ },
};
static int visionox_vtdr6130_get_modes(struct drm_panel *panel,
struct drm_connector *connector)
{
+ struct visionox_vtdr6130 *ctx = to_visionox_vtdr6130(panel);
struct drm_display_mode *mode;
- mode = drm_mode_duplicate(connector->dev, &visionox_vtdr6130_mode);
+ mode = drm_mode_duplicate(connector->dev, ctx->desc->modes);
if (!mode)
return -ENOMEM;
@@ -218,10 +370,18 @@ static int visionox_vtdr6130_get_modes(struct drm_panel *panel,
return 1;
}
+static enum drm_panel_orientation visionox_vtdr6130_get_orientation(struct drm_panel *panel)
+{
+ struct visionox_vtdr6130 *ctx = to_visionox_vtdr6130(panel);
+
+ return ctx->orientation;
+}
+
static const struct drm_panel_funcs visionox_vtdr6130_panel_funcs = {
.prepare = visionox_vtdr6130_prepare,
.unprepare = visionox_vtdr6130_unprepare,
.get_modes = visionox_vtdr6130_get_modes,
+ .get_orientation = visionox_vtdr6130_get_orientation,
};
static int visionox_vtdr6130_bl_update_status(struct backlight_device *bl)
@@ -274,25 +434,25 @@ static int visionox_vtdr6130_probe(struct mipi_dsi_device *dsi)
return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
"Failed to get reset-gpios\n");
+ ctx->desc = (struct visionox_vtdr6130_desc *)of_device_get_match_data(dev);
+ if (!ctx->desc)
+ return -ENODEV;
+
ctx->dsi = dsi;
mipi_dsi_set_drvdata(dsi, ctx);
- ctx->dsc.dsc_version_major = 0x1;
- ctx->dsc.dsc_version_minor = 0x2;
- ctx->dsc.slice_height = 40;
- ctx->dsc.slice_width = 540;
- ctx->dsc.slice_count = 2;
- ctx->dsc.bits_per_component = 8;
- ctx->dsc.bits_per_pixel = 8 << 4;
- ctx->dsc.block_pred_enable = true;
-
- dsi->dsc = &ctx->dsc;
- dsi->lanes = 4;
- dsi->format = MIPI_DSI_FMT_RGB888;
- dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_NO_EOT_PACKET |
- MIPI_DSI_CLOCK_NON_CONTINUOUS;
+ dsi->dsc = &ctx->desc->dsc;
+ dsi->lanes = ctx->desc->lanes;
+ dsi->format = ctx->desc->format;
+ dsi->mode_flags = ctx->desc->mode_flags;
ctx->panel.prepare_prev_first = true;
+ ret = drm_of_get_panel_orientation(dev->of_node, &ctx->orientation);
+ if (ret < 0) {
+ dev_err(dev, "Failed to get orientation %d\n", ret);
+ return ret;
+ }
+
ctx->panel.backlight = visionox_vtdr6130_create_backlight(dsi);
if (IS_ERR(ctx->panel.backlight))
return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight),
@@ -306,7 +466,8 @@ static int visionox_vtdr6130_probe(struct mipi_dsi_device *dsi)
}
static const struct of_device_id visionox_vtdr6130_of_match[] = {
- { .compatible = "visionox,vtdr6130" },
+ { .compatible = "retroidpocket,rp6-panel", .data = &retroidpocket_rp6_panel_desc },
+ { .compatible = "visionox,vtdr6130", .data = &visionox_vtdr6130_panel_desc },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, visionox_vtdr6130_of_match);
diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c
index 485349faf251..fb0a1b45007b 100644
--- a/drivers/gpu/drm/panfrost/panfrost_device.c
+++ b/drivers/gpu/drm/panfrost/panfrost_device.c
@@ -2,12 +2,15 @@
/* Copyright 2018 Marty E. Plummer <hanetzer@startmail.com> */
/* Copyright 2019 Linaro, Ltd, Rob Herring <robh@kernel.org> */
+#include <linux/debugfs.h>
#include <linux/clk.h>
#include <linux/reset.h>
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_print.h>
#include "panfrost_device.h"
#include "panfrost_devfreq.h"
@@ -34,10 +37,46 @@ static void panfrost_reset_fini(struct panfrost_device *pfdev)
reset_control_assert(pfdev->rstc);
}
-static int panfrost_clk_init(struct panfrost_device *pfdev)
+static int panfrost_clks_enable(struct panfrost_device *pfdev, bool on_resume)
{
int err;
+
+ err = clk_prepare_enable(pfdev->clock);
+ if (err)
+ return err;
+
+ err = clk_prepare_enable(pfdev->bus_clock);
+ if (err)
+ goto disable_clock;
+
+ if (on_resume) {
+ err = clk_prepare_enable(pfdev->bus_ace_clock);
+ if (err)
+ goto disable_bus_clock;
+ }
+
+ return 0;
+
+disable_bus_clock:
+ clk_disable_unprepare(pfdev->bus_clock);
+disable_clock:
+ clk_disable_unprepare(pfdev->clock);
+
+ return err;
+}
+
+static void panfrost_clks_disable(struct panfrost_device *pfdev, bool on_suspend)
+{
+ if (on_suspend)
+ clk_disable_unprepare(pfdev->bus_ace_clock);
+ clk_disable_unprepare(pfdev->bus_clock);
+ clk_disable_unprepare(pfdev->clock);
+}
+
+static int panfrost_clk_init(struct panfrost_device *pfdev)
+{
unsigned long rate;
+ int err;
pfdev->clock = devm_clk_get(pfdev->base.dev, NULL);
if (IS_ERR(pfdev->clock)) {
@@ -48,53 +87,59 @@ static int panfrost_clk_init(struct panfrost_device *pfdev)
rate = clk_get_rate(pfdev->clock);
dev_info(pfdev->base.dev, "clock rate = %lu\n", rate);
- err = clk_prepare_enable(pfdev->clock);
+ err = clk_prepare(pfdev->clock);
if (err)
return err;
pfdev->bus_clock = devm_clk_get_optional(pfdev->base.dev, "bus");
if (IS_ERR(pfdev->bus_clock)) {
- dev_err(pfdev->base.dev, "get bus_clock failed %ld\n",
- PTR_ERR(pfdev->bus_clock));
err = PTR_ERR(pfdev->bus_clock);
- goto disable_clock;
+ dev_err(pfdev->base.dev, "get bus_clock failed %d\n", err);
+ goto unprepare_clock;
}
if (pfdev->bus_clock) {
rate = clk_get_rate(pfdev->bus_clock);
dev_info(pfdev->base.dev, "bus_clock rate = %lu\n", rate);
- err = clk_prepare_enable(pfdev->bus_clock);
+ err = clk_prepare(pfdev->bus_clock);
if (err)
- goto disable_clock;
+ goto unprepare_clock;
}
pfdev->bus_ace_clock = devm_clk_get_optional(pfdev->base.dev, "bus_ace");
if (IS_ERR(pfdev->bus_ace_clock)) {
err = PTR_ERR(pfdev->bus_ace_clock);
dev_err(pfdev->base.dev, "get bus_ace_clock failed %d\n", err);
- goto disable_bus_clock;
+ goto unprepare_bus_clock;
}
- err = clk_prepare_enable(pfdev->bus_ace_clock);
+ err = clk_prepare(pfdev->bus_ace_clock);
if (err)
- goto disable_bus_clock;
+ goto unprepare_bus_clock;
+
+ err = panfrost_clks_enable(pfdev, true);
+ if (err)
+ goto unprepare_bus_ace_clock;
return 0;
-disable_bus_clock:
- clk_disable_unprepare(pfdev->bus_clock);
-disable_clock:
- clk_disable_unprepare(pfdev->clock);
+unprepare_bus_ace_clock:
+ clk_unprepare(pfdev->bus_ace_clock);
+unprepare_bus_clock:
+ clk_unprepare(pfdev->bus_clock);
+unprepare_clock:
+ clk_unprepare(pfdev->clock);
return err;
}
static void panfrost_clk_fini(struct panfrost_device *pfdev)
{
- clk_disable_unprepare(pfdev->bus_ace_clock);
- clk_disable_unprepare(pfdev->bus_clock);
- clk_disable_unprepare(pfdev->clock);
+ panfrost_clks_disable(pfdev, true);
+ clk_unprepare(pfdev->bus_ace_clock);
+ clk_unprepare(pfdev->bus_clock);
+ clk_unprepare(pfdev->clock);
}
static int panfrost_regulator_init(struct panfrost_device *pfdev)
@@ -214,14 +259,14 @@ err:
int panfrost_device_init(struct panfrost_device *pfdev)
{
+ bool device_initialised = false;
int err;
- mutex_init(&pfdev->sched_lock);
- INIT_LIST_HEAD(&pfdev->as_lru_list);
-
- spin_lock_init(&pfdev->as_lock);
+ pfdev->comp = of_device_get_match_data(pfdev->base.dev);
+ if (!pfdev->comp)
+ return -ENODEV;
- spin_lock_init(&pfdev->cycle_counter.lock);
+ pfdev->coherent = device_get_dma_attr(pfdev->base.dev) == DEV_DMA_COHERENT;
#ifdef CONFIG_DEBUG_FS
mutex_init(&pfdev->debugfs.gems_lock);
@@ -280,9 +325,41 @@ int panfrost_device_init(struct panfrost_device *pfdev)
if (err)
goto out_job;
- panfrost_gem_init(pfdev);
+ err = panfrost_gem_init(pfdev);
+ if (err)
+ goto out_perfcnt;
+
+ device_initialised = true;
+
+ /* The reason we must manually set the PM status and usage counter is
+ * we have just powered the device up but did not go through the PM
+ * runtime resume callback, so we need to update these ourselves.
+ */
+ pm_runtime_get_noresume(pfdev->base.dev);
+ pm_runtime_set_active(pfdev->base.dev);
+ pm_runtime_mark_last_busy(pfdev->base.dev);
+ pm_runtime_enable(pfdev->base.dev);
+ pm_runtime_set_autosuspend_delay(pfdev->base.dev, 50); /* ~3 frames */
+ pm_runtime_use_autosuspend(pfdev->base.dev);
+
+ /*
+ * Register the DRM device with the core and the connectors with
+ * sysfs
+ */
+ err = drm_dev_register(&pfdev->base, 0);
+ if (err < 0)
+ goto err_disable_rpm;
+
+ pm_runtime_put_autosuspend(pfdev->base.dev);
return 0;
+
+err_disable_rpm:
+ pm_runtime_dont_use_autosuspend(pfdev->base.dev);
+ pm_runtime_disable(pfdev->base.dev);
+ panfrost_gem_fini(pfdev);
+out_perfcnt:
+ panfrost_perfcnt_fini(pfdev);
out_job:
panfrost_jm_fini(pfdev);
out_mmu:
@@ -299,11 +376,23 @@ out_reset:
panfrost_reset_fini(pfdev);
out_pm_domain:
panfrost_pm_domain_fini(pfdev);
+
+ if (device_initialised) {
+ pm_runtime_set_suspended(pfdev->base.dev);
+ pm_runtime_put_noidle(pfdev->base.dev);
+ }
+
return err;
}
void panfrost_device_fini(struct panfrost_device *pfdev)
{
+ drm_WARN_ON(&pfdev->base, pm_runtime_get_sync(pfdev->base.dev) < 0);
+
+ pm_runtime_dont_use_autosuspend(pfdev->base.dev);
+ pm_runtime_disable(pfdev->base.dev);
+
+ panfrost_gem_fini(pfdev);
panfrost_perfcnt_fini(pfdev);
panfrost_jm_fini(pfdev);
panfrost_mmu_fini(pfdev);
@@ -313,6 +402,9 @@ void panfrost_device_fini(struct panfrost_device *pfdev)
panfrost_clk_fini(pfdev);
panfrost_reset_fini(pfdev);
panfrost_pm_domain_fini(pfdev);
+
+ pm_runtime_set_suspended(pfdev->base.dev);
+ pm_runtime_put_noidle(pfdev->base.dev);
}
#define PANFROST_EXCEPTION(id) \
@@ -417,6 +509,8 @@ bool panfrost_exception_needs_reset(const struct panfrost_device *pfdev,
void panfrost_device_reset(struct panfrost_device *pfdev, bool enable_job_int)
{
+ guard(rwsem_write)(&pfdev->reset.lock);
+
panfrost_gpu_soft_reset(pfdev);
panfrost_gpu_power_on(pfdev);
@@ -425,6 +519,8 @@ void panfrost_device_reset(struct panfrost_device *pfdev, bool enable_job_int)
panfrost_jm_reset_interrupts(pfdev);
if (enable_job_int)
panfrost_jm_enable_interrupts(pfdev);
+
+ panfrost_perfcnt_reset(pfdev);
}
static int panfrost_device_runtime_resume(struct device *dev)
@@ -437,34 +533,17 @@ static int panfrost_device_runtime_resume(struct device *dev)
if (ret)
return ret;
- ret = clk_enable(pfdev->clock);
- if (ret)
- goto err_clk;
-
- ret = clk_enable(pfdev->bus_clock);
- if (ret)
- goto err_bus_clk;
-
- ret = clk_enable(pfdev->bus_ace_clock);
- if (ret)
- goto err_bus_ace_clk;
+ ret = panfrost_clks_enable(pfdev, true);
+ if (ret) {
+ reset_control_assert(pfdev->rstc);
+ return ret;
+ }
}
panfrost_device_reset(pfdev, true);
panfrost_devfreq_resume(pfdev);
return 0;
-
-err_bus_ace_clk:
- if (pfdev->comp->pm_features & BIT(GPU_PM_RT))
- clk_disable(pfdev->bus_clock);
-err_bus_clk:
- if (pfdev->comp->pm_features & BIT(GPU_PM_RT))
- clk_disable(pfdev->clock);
-err_clk:
- if (pfdev->comp->pm_features & BIT(GPU_PM_RT))
- reset_control_assert(pfdev->rstc);
- return ret;
}
static int panfrost_device_runtime_suspend(struct device *dev)
@@ -481,9 +560,7 @@ static int panfrost_device_runtime_suspend(struct device *dev)
panfrost_gpu_power_off(pfdev);
if (pfdev->comp->pm_features & BIT(GPU_PM_RT)) {
- clk_disable(pfdev->bus_ace_clock);
- clk_disable(pfdev->bus_clock);
- clk_disable(pfdev->clock);
+ panfrost_clks_disable(pfdev, true);
reset_control_assert(pfdev->rstc);
}
@@ -507,15 +584,9 @@ static int panfrost_device_resume(struct device *dev)
}
if (pfdev->comp->pm_features & BIT(GPU_PM_CLK_DIS)) {
- ret = clk_enable(pfdev->clock);
+ ret = panfrost_clks_enable(pfdev, false);
if (ret)
goto err_clk;
-
- if (pfdev->bus_clock) {
- ret = clk_enable(pfdev->bus_clock);
- if (ret)
- goto err_bus_clk;
- }
}
ret = pm_runtime_force_resume(dev);
@@ -525,11 +596,8 @@ static int panfrost_device_resume(struct device *dev)
return 0;
err_resume:
- if (pfdev->comp->pm_features & BIT(GPU_PM_CLK_DIS) && pfdev->bus_clock)
- clk_disable(pfdev->bus_clock);
-err_bus_clk:
if (pfdev->comp->pm_features & BIT(GPU_PM_CLK_DIS))
- clk_disable(pfdev->clock);
+ panfrost_clks_disable(pfdev, false);
err_clk:
if (pfdev->comp->pm_features & BIT(GPU_PM_VREG_OFF))
dev_pm_opp_set_opp(dev, NULL);
@@ -545,12 +613,8 @@ static int panfrost_device_suspend(struct device *dev)
if (ret)
return ret;
- if (pfdev->comp->pm_features & BIT(GPU_PM_CLK_DIS)) {
- if (pfdev->bus_clock)
- clk_disable(pfdev->bus_clock);
-
- clk_disable(pfdev->clock);
- }
+ if (pfdev->comp->pm_features & BIT(GPU_PM_CLK_DIS))
+ panfrost_clks_disable(pfdev, false);
if (pfdev->comp->pm_features & BIT(GPU_PM_VREG_OFF))
dev_pm_opp_set_opp(dev, NULL);
@@ -562,3 +626,56 @@ EXPORT_GPL_DEV_PM_OPS(panfrost_pm_ops) = {
RUNTIME_PM_OPS(panfrost_device_runtime_suspend, panfrost_device_runtime_resume, NULL)
SYSTEM_SLEEP_PM_OPS(panfrost_device_suspend, panfrost_device_resume)
};
+
+#ifdef CONFIG_DEBUG_FS
+static int reset_get(void *data, u64 *val)
+{
+ struct panfrost_device *pfdev =
+ container_of(data, struct panfrost_device, base);
+
+ *val = atomic_read(&pfdev->reset.pending);
+ return 0;
+}
+
+static int reset_set(void *data, u64 val)
+{
+ struct panfrost_device *pfdev =
+ container_of(data, struct panfrost_device, base);
+ int ret;
+
+ if (val != 1)
+ return -EINVAL;
+
+ ret = pm_runtime_get_if_active(pfdev->base.dev);
+ if (!ret)
+ return 0;
+
+ panfrost_device_schedule_reset(pfdev);
+ flush_work(&pfdev->reset.work);
+
+ /* ret < 0 means runtime PM for the device is disabled, so we
+ * only need to return the PM reference in the opposite case
+ */
+ if (ret > 0)
+ pm_runtime_put(pfdev->base.dev);
+
+ return 0;
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(panfrost_reset_debugfs_fops,
+ reset_get, reset_set,
+ "0x%08llx\n");
+
+static void panfrost_reset_debugfs_init(struct drm_minor *minor)
+{
+ debugfs_create_file("reset", 0600, minor->debugfs_root,
+ minor->dev, &panfrost_reset_debugfs_fops);
+}
+
+void panfrost_device_debugfs_init(struct drm_minor *minor)
+{
+ panfrost_gem_debugfs_init(minor);
+ panfrost_sched_debugfs_init(minor);
+ panfrost_reset_debugfs_init(minor);
+}
+#endif // CONFIG_DEBUG_FS
diff --git a/drivers/gpu/drm/panfrost/panfrost_device.h b/drivers/gpu/drm/panfrost/panfrost_device.h
index 1fe1554f2652..63452febb1cf 100644
--- a/drivers/gpu/drm/panfrost/panfrost_device.h
+++ b/drivers/gpu/drm/panfrost/panfrost_device.h
@@ -165,6 +165,7 @@ struct panfrost_device {
struct {
struct workqueue_struct *wq;
struct work_struct work;
+ struct rw_semaphore lock;
atomic_t pending;
} reset;
@@ -341,4 +342,8 @@ panfrost_device_schedule_reset(struct panfrost_device *pfdev)
queue_work(pfdev->reset.wq, &pfdev->reset.work);
}
+#ifdef CONFIG_DEBUG_FS
+void panfrost_device_debugfs_init(struct drm_minor *minor);
+#endif // CONFIG_DEBUG_FS
+
#endif
diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c
index 70c05210ea84..7c348a0bf1ee 100644
--- a/drivers/gpu/drm/panfrost/panfrost_drv.c
+++ b/drivers/gpu/drm/panfrost/panfrost_drv.c
@@ -21,7 +21,6 @@
#include <drm/drm_timeout.h>
#include "panfrost_device.h"
-#include "panfrost_drv.h"
#include "panfrost_gem.h"
#include "panfrost_mmu.h"
#include "panfrost_job.h"
@@ -42,9 +41,12 @@ static int panfrost_ioctl_query_timestamp(struct panfrost_device *pfdev,
if (ret)
return ret;
- panfrost_cycle_counter_get(pfdev);
- *arg = panfrost_timestamp_read(pfdev);
- panfrost_cycle_counter_put(pfdev);
+ /* We should not read timestamp register while the GPU is being reset */
+ scoped_guard(rwsem_read, &pfdev->reset.lock) {
+ panfrost_cycle_counter_get(pfdev);
+ *arg = panfrost_timestamp_read(pfdev);
+ panfrost_cycle_counter_put(pfdev);
+ }
pm_runtime_put(pfdev->base.dev);
return 0;
@@ -793,133 +795,6 @@ static const struct file_operations panfrost_drm_driver_fops = {
.show_fdinfo = drm_show_fdinfo,
};
-#ifdef CONFIG_DEBUG_FS
-static int panthor_gems_show(struct seq_file *m, void *data)
-{
- struct drm_info_node *node = m->private;
- struct panfrost_device *pfdev = to_panfrost_device(node->minor->dev);
-
- panfrost_gem_debugfs_print_bos(pfdev, m);
-
- return 0;
-}
-
-static void show_panfrost_jm_ctx(struct panfrost_jm_ctx *jm_ctx, u32 handle,
- struct seq_file *m)
-{
- struct drm_device *ddev = ((struct drm_info_node *)m->private)->minor->dev;
- const char *prio = "UNKNOWN";
-
- static const char * const prios[] = {
- [DRM_SCHED_PRIORITY_HIGH] = "HIGH",
- [DRM_SCHED_PRIORITY_NORMAL] = "NORMAL",
- [DRM_SCHED_PRIORITY_LOW] = "LOW",
- };
-
- if (jm_ctx->slot_entity[0].priority !=
- jm_ctx->slot_entity[1].priority)
- drm_warn(ddev, "Slot priorities should be the same in a single context");
-
- if (jm_ctx->slot_entity[0].priority < ARRAY_SIZE(prios))
- prio = prios[jm_ctx->slot_entity[0].priority];
-
- seq_printf(m, " JM context %u: priority %s\n", handle, prio);
-}
-
-static int show_file_jm_ctxs(struct panfrost_file_priv *pfile,
- struct seq_file *m)
-{
- struct panfrost_jm_ctx *jm_ctx;
- unsigned long i;
-
- xa_lock(&pfile->jm_ctxs);
- xa_for_each(&pfile->jm_ctxs, i, jm_ctx) {
- jm_ctx = panfrost_jm_ctx_get(jm_ctx);
- xa_unlock(&pfile->jm_ctxs);
- show_panfrost_jm_ctx(jm_ctx, i, m);
- panfrost_jm_ctx_put(jm_ctx);
- xa_lock(&pfile->jm_ctxs);
- }
- xa_unlock(&pfile->jm_ctxs);
-
- return 0;
-}
-
-static struct drm_info_list panthor_debugfs_list[] = {
- {"gems",
- panthor_gems_show, 0, NULL},
-};
-
-static int panthor_gems_debugfs_init(struct drm_minor *minor)
-{
- drm_debugfs_create_files(panthor_debugfs_list,
- ARRAY_SIZE(panthor_debugfs_list),
- minor->debugfs_root, minor);
-
- return 0;
-}
-
-static int show_each_file(struct seq_file *m, void *arg)
-{
- struct drm_info_node *node = (struct drm_info_node *)m->private;
- struct drm_device *ddev = node->minor->dev;
- int (*show)(struct panfrost_file_priv *, struct seq_file *) =
- node->info_ent->data;
- struct drm_file *file;
- int ret;
-
- ret = mutex_lock_interruptible(&ddev->filelist_mutex);
- if (ret)
- return ret;
-
- list_for_each_entry(file, &ddev->filelist, lhead) {
- struct task_struct *task;
- struct panfrost_file_priv *pfile = file->driver_priv;
- struct pid *pid;
-
- /*
- * Although we have a valid reference on file->pid, that does
- * not guarantee that the task_struct who called get_pid() is
- * still alive (e.g. get_pid(current) => fork() => exit()).
- * Therefore, we need to protect this ->comm access using RCU.
- */
- rcu_read_lock();
- pid = rcu_dereference(file->pid);
- task = pid_task(pid, PIDTYPE_TGID);
- seq_printf(m, "client_id %8llu pid %8d command %s:\n",
- file->client_id, pid_nr(pid),
- task ? task->comm : "<unknown>");
- rcu_read_unlock();
-
- ret = show(pfile, m);
- if (ret < 0)
- break;
-
- seq_puts(m, "\n");
- }
-
- mutex_unlock(&ddev->filelist_mutex);
- return ret;
-}
-
-static struct drm_info_list panfrost_sched_debugfs_list[] = {
- { "sched_ctxs", show_each_file, 0, show_file_jm_ctxs },
-};
-
-static void panfrost_sched_debugfs_init(struct drm_minor *minor)
-{
- drm_debugfs_create_files(panfrost_sched_debugfs_list,
- ARRAY_SIZE(panfrost_sched_debugfs_list),
- minor->debugfs_root, minor);
-}
-
-static void panfrost_debugfs_init(struct drm_minor *minor)
-{
- panthor_gems_debugfs_init(minor);
- panfrost_sched_debugfs_init(minor);
-}
-#endif
-
/*
* Panfrost driver version:
* - 1.0 - initial interface
@@ -933,6 +808,7 @@ static void panfrost_debugfs_init(struct drm_minor *minor)
* - 1.6 - adds PANFROST_BO_MAP_WB, PANFROST_IOCTL_SYNC_BO,
* PANFROST_IOCTL_QUERY_BO_INFO and
* DRM_PANFROST_PARAM_SELECTED_COHERENCY
+ * - 1.7 - adds PERFCNT_DUMP state field
*/
static const struct drm_driver panfrost_drm_driver = {
.driver_features = DRIVER_RENDER | DRIVER_GEM | DRIVER_SYNCOBJ,
@@ -945,26 +821,19 @@ static const struct drm_driver panfrost_drm_driver = {
.name = "panfrost",
.desc = "panfrost DRM",
.major = 1,
- .minor = 6,
+ .minor = 7,
.gem_create_object = panfrost_gem_create_object,
.gem_prime_import = panfrost_gem_prime_import,
.gem_prime_import_sg_table = panfrost_gem_prime_import_sg_table,
#ifdef CONFIG_DEBUG_FS
- .debugfs_init = panfrost_debugfs_init,
+ .debugfs_init = panfrost_device_debugfs_init,
#endif
};
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
-bool panfrost_transparent_hugepage = true;
-module_param_named(transparent_hugepage, panfrost_transparent_hugepage, bool, 0400);
-MODULE_PARM_DESC(transparent_hugepage, "Use a dedicated tmpfs mount point with Transparent Hugepage enabled (true = default)");
-#endif
-
static int panfrost_probe(struct platform_device *pdev)
{
struct panfrost_device *pfdev;
- int err;
pfdev = devm_drm_dev_alloc(&pdev->dev, &panfrost_drm_driver,
struct panfrost_device, base);
@@ -973,50 +842,7 @@ static int panfrost_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, pfdev);
- pfdev->comp = of_device_get_match_data(&pdev->dev);
- if (!pfdev->comp)
- return -ENODEV;
-
- pfdev->coherent = device_get_dma_attr(&pdev->dev) == DEV_DMA_COHERENT;
-
- mutex_init(&pfdev->shrinker_lock);
- INIT_LIST_HEAD(&pfdev->shrinker_list);
-
- err = panfrost_device_init(pfdev);
- if (err) {
- if (err != -EPROBE_DEFER)
- dev_err(&pdev->dev, "Fatal error during GPU init\n");
- goto err_out0;
- }
-
- pm_runtime_set_active(pfdev->base.dev);
- pm_runtime_mark_last_busy(pfdev->base.dev);
- pm_runtime_enable(pfdev->base.dev);
- pm_runtime_set_autosuspend_delay(pfdev->base.dev, 50); /* ~3 frames */
- pm_runtime_use_autosuspend(pfdev->base.dev);
-
- /*
- * Register the DRM device with the core and the connectors with
- * sysfs
- */
- err = drm_dev_register(&pfdev->base, 0);
- if (err < 0)
- goto err_out1;
-
- err = panfrost_gem_shrinker_init(&pfdev->base);
- if (err)
- goto err_out2;
-
- return 0;
-
-err_out2:
- drm_dev_unregister(&pfdev->base);
-err_out1:
- pm_runtime_disable(pfdev->base.dev);
- panfrost_device_fini(pfdev);
- pm_runtime_set_suspended(pfdev->base.dev);
-err_out0:
- return err;
+ return panfrost_device_init(pfdev);
}
static void panfrost_remove(struct platform_device *pdev)
@@ -1024,12 +850,8 @@ static void panfrost_remove(struct platform_device *pdev)
struct panfrost_device *pfdev = platform_get_drvdata(pdev);
drm_dev_unregister(&pfdev->base);
- panfrost_gem_shrinker_cleanup(&pfdev->base);
- pm_runtime_get_sync(pfdev->base.dev);
- pm_runtime_disable(pfdev->base.dev);
panfrost_device_fini(pfdev);
- pm_runtime_set_suspended(pfdev->base.dev);
}
static ssize_t profiling_show(struct device *dev,
diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.h b/drivers/gpu/drm/panfrost/panfrost_drv.h
deleted file mode 100644
index a2277ec61aab..000000000000
--- a/drivers/gpu/drm/panfrost/panfrost_drv.h
+++ /dev/null
@@ -1,9 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 or MIT */
-/* Copyright 2025 Amazon.com, Inc. or its affiliates */
-
-#ifndef __PANFROST_DRV_H__
-#define __PANFROST_DRV_H__
-
-extern bool panfrost_transparent_hugepage;
-
-#endif
diff --git a/drivers/gpu/drm/panfrost/panfrost_features.h b/drivers/gpu/drm/panfrost/panfrost_features.h
index 52f9d69f6db9..34c65847192f 100644
--- a/drivers/gpu/drm/panfrost/panfrost_features.h
+++ b/drivers/gpu/drm/panfrost/panfrost_features.h
@@ -121,6 +121,8 @@ enum panfrost_hw_feature {
BIT_ULL(HW_FEATURE_IDVS_GROUP_SIZE) | \
BIT_ULL(HW_FEATURE_CLEAN_ONLY_SAFE))
+#define hw_features_g68 hw_features_g57
+
static inline bool panfrost_has_hw_feature(struct panfrost_device *pfdev,
enum panfrost_hw_feature feat)
{
diff --git a/drivers/gpu/drm/panfrost/panfrost_gem.c b/drivers/gpu/drm/panfrost/panfrost_gem.c
index 3a7fce428898..518f24549b9d 100644
--- a/drivers/gpu/drm/panfrost/panfrost_gem.c
+++ b/drivers/gpu/drm/panfrost/panfrost_gem.c
@@ -9,26 +9,38 @@
#include <linux/dma-mapping.h>
#include <drm/panfrost_drm.h>
+#include <drm/drm_debugfs.h>
#include <drm/drm_print.h>
#include "panfrost_device.h"
-#include "panfrost_drv.h"
#include "panfrost_gem.h"
#include "panfrost_mmu.h"
-void panfrost_gem_init(struct panfrost_device *pfdev)
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+static bool panfrost_transparent_hugepage = true;
+module_param_named(transparent_hugepage, panfrost_transparent_hugepage, bool, 0400);
+MODULE_PARM_DESC(transparent_hugepage, "Use a dedicated tmpfs mount point with Transparent Hugepage enabled (true = default)");
+#else
+#define panfrost_transparent_hugepage false
+#endif
+
+int panfrost_gem_init(struct panfrost_device *pfdev)
{
- int err;
+ if (panfrost_transparent_hugepage) {
+ int err = drm_gem_huge_mnt_create(&pfdev->base, "within_size");
+
+ if (err)
+ drm_warn(&pfdev->base,
+ "Can't use Transparent Hugepage (%d)\n", err);
+ else
+ drm_info(&pfdev->base, "Using Transparent Hugepage\n");
+ }
- if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) &&
- !panfrost_transparent_hugepage)
- return;
+ return panfrost_gem_shrinker_init(pfdev);
+}
- err = drm_gem_huge_mnt_create(&pfdev->base, "within_size");
- if (drm_gem_get_huge_mnt(&pfdev->base))
- drm_info(&pfdev->base, "Using Transparent Hugepage\n");
- else if (err)
- drm_warn(&pfdev->base, "Can't use Transparent Hugepage (%d)\n",
- err);
+void panfrost_gem_fini(struct panfrost_device *pfdev)
+{
+ panfrost_gem_shrinker_fini(pfdev);
}
#ifdef CONFIG_DEBUG_FS
@@ -724,8 +736,8 @@ static void panfrost_gem_debugfs_bo_print(struct panfrost_gem_object *bo,
totals->reclaimable += resident_size;
}
-void panfrost_gem_debugfs_print_bos(struct panfrost_device *pfdev,
- struct seq_file *m)
+static void panfrost_gem_debugfs_print_bos(struct panfrost_device *pfdev,
+ struct seq_file *m)
{
struct gem_size_totals totals = {0};
struct panfrost_gem_object *bo;
@@ -745,4 +757,28 @@ void panfrost_gem_debugfs_print_bos(struct panfrost_device *pfdev,
seq_printf(m, "Total size: %zd, Total resident: %zd, Total reclaimable: %zd\n",
totals.size, totals.resident, totals.reclaimable);
}
+
+static int panfrost_gems_show(struct seq_file *m, void *data)
+{
+ struct drm_info_node *node = m->private;
+ struct panfrost_device *pfdev = to_panfrost_device(node->minor->dev);
+
+ panfrost_gem_debugfs_print_bos(pfdev, m);
+
+ return 0;
+}
+
+static struct drm_info_list panfrost_debugfs_list[] = {
+ {"gems",
+ panfrost_gems_show, 0, NULL},
+};
+
+int panfrost_gem_debugfs_init(struct drm_minor *minor)
+{
+ drm_debugfs_create_files(panfrost_debugfs_list,
+ ARRAY_SIZE(panfrost_debugfs_list),
+ minor->debugfs_root, minor);
+
+ return 0;
+}
#endif
diff --git a/drivers/gpu/drm/panfrost/panfrost_gem.h b/drivers/gpu/drm/panfrost/panfrost_gem.h
index 79d4377019e9..3008afcf4bff 100644
--- a/drivers/gpu/drm/panfrost/panfrost_gem.h
+++ b/drivers/gpu/drm/panfrost/panfrost_gem.h
@@ -129,7 +129,8 @@ drm_mm_node_to_panfrost_mapping(struct drm_mm_node *node)
return container_of(node, struct panfrost_gem_mapping, mmnode);
}
-void panfrost_gem_init(struct panfrost_device *pfdev);
+int panfrost_gem_init(struct panfrost_device *pfdev);
+void panfrost_gem_fini(struct panfrost_device *pfdev);
struct drm_gem_object *panfrost_gem_create_object(struct drm_device *dev, size_t size);
@@ -154,8 +155,8 @@ panfrost_gem_mapping_get(struct panfrost_gem_object *bo,
void panfrost_gem_mapping_put(struct panfrost_gem_mapping *mapping);
void panfrost_gem_teardown_mappings_locked(struct panfrost_gem_object *bo);
-int panfrost_gem_shrinker_init(struct drm_device *dev);
-void panfrost_gem_shrinker_cleanup(struct drm_device *dev);
+int panfrost_gem_shrinker_init(struct panfrost_device *pfdev);
+void panfrost_gem_shrinker_fini(struct panfrost_device *pfdev);
void panfrost_gem_set_label(struct drm_gem_object *obj, const char *label);
int panfrost_gem_sync(struct drm_gem_object *obj, u32 type,
@@ -163,8 +164,7 @@ int panfrost_gem_sync(struct drm_gem_object *obj, u32 type,
void panfrost_gem_internal_set_label(struct drm_gem_object *obj, const char *label);
#ifdef CONFIG_DEBUG_FS
-void panfrost_gem_debugfs_print_bos(struct panfrost_device *pfdev,
- struct seq_file *m);
+int panfrost_gem_debugfs_init(struct drm_minor *minor);
#endif
#endif /* __PANFROST_GEM_H__ */
diff --git a/drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c b/drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c
index 2fe967a90bcb..72cd7a165e6d 100644
--- a/drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c
+++ b/drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c
@@ -95,9 +95,10 @@ panfrost_gem_shrinker_scan(struct shrinker *shrinker, struct shrink_control *sc)
*
* This function registers and sets up the panfrost shrinker.
*/
-int panfrost_gem_shrinker_init(struct drm_device *dev)
+int panfrost_gem_shrinker_init(struct panfrost_device *pfdev)
{
- struct panfrost_device *pfdev = to_panfrost_device(dev);
+ mutex_init(&pfdev->shrinker_lock);
+ INIT_LIST_HEAD(&pfdev->shrinker_list);
pfdev->shrinker = shrinker_alloc(0, "drm-panfrost");
if (!pfdev->shrinker)
@@ -118,10 +119,8 @@ int panfrost_gem_shrinker_init(struct drm_device *dev)
*
* This function unregisters the panfrost shrinker.
*/
-void panfrost_gem_shrinker_cleanup(struct drm_device *dev)
+void panfrost_gem_shrinker_fini(struct panfrost_device *pfdev)
{
- struct panfrost_device *pfdev = to_panfrost_device(dev);
-
if (pfdev->shrinker)
shrinker_free(pfdev->shrinker);
}
diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.c b/drivers/gpu/drm/panfrost/panfrost_gpu.c
index 7d555e63e21a..6081b27829e1 100644
--- a/drivers/gpu/drm/panfrost/panfrost_gpu.c
+++ b/drivers/gpu/drm/panfrost/panfrost_gpu.c
@@ -242,6 +242,9 @@ static const struct panfrost_model gpu_models[] = {
/* MediaTek MT8188 Mali-G57 MC3 */
GPU_MODEL(g57, 0x9093,
GPU_REV(g57, 0, 0)),
+
+ GPU_MODEL(g68, 0x9004,
+ GPU_REV(g68, 1, 0), GPU_REV(g68, 1, 1)),
{0},
};
@@ -516,6 +519,8 @@ int panfrost_gpu_init(struct panfrost_device *pfdev)
{
int err;
+ spin_lock_init(&pfdev->cycle_counter.lock);
+
err = panfrost_gpu_soft_reset(pfdev);
if (err)
return err;
diff --git a/drivers/gpu/drm/panfrost/panfrost_issues.h b/drivers/gpu/drm/panfrost/panfrost_issues.h
index eb60cb83667a..dd39946bb572 100644
--- a/drivers/gpu/drm/panfrost/panfrost_issues.h
+++ b/drivers/gpu/drm/panfrost/panfrost_issues.h
@@ -265,6 +265,14 @@ enum panfrost_hw_issue {
#define hw_issues_g57_r0p0 (\
BIT_ULL(HW_ISSUE_TTRX_3485))
+#define hw_issues_g68 (\
+ BIT_ULL(HW_ISSUE_TTRX_2968_TTRX_3162))
+
+#define hw_issues_g68_r1p0 (\
+ BIT_ULL(HW_ISSUE_TTRX_3485))
+
+#define hw_issues_g68_r1p1 0
+
static inline bool panfrost_has_hw_issue(const struct panfrost_device *pfdev,
enum panfrost_hw_issue issue)
{
diff --git a/drivers/gpu/drm/panfrost/panfrost_job.c b/drivers/gpu/drm/panfrost/panfrost_job.c
index d59b4863b8ad..4ddf4b722ddf 100644
--- a/drivers/gpu/drm/panfrost/panfrost_job.c
+++ b/drivers/gpu/drm/panfrost/panfrost_job.c
@@ -8,6 +8,8 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/dma-resv.h>
+#include <drm/drm_debugfs.h>
+#include <drm/drm_print.h>
#include <drm/gpu_scheduler.h>
#include <drm/panfrost_drm.h>
@@ -874,6 +876,8 @@ int panfrost_jm_init(struct panfrost_device *pfdev)
INIT_WORK(&pfdev->reset.work, panfrost_reset_work);
spin_lock_init(&js->job_lock);
+ mutex_init(&pfdev->sched_lock);
+ init_rwsem(&pfdev->reset.lock);
js->irq = platform_get_irq_byname(to_platform_device(pfdev->base.dev), "job");
if (js->irq < 0)
@@ -929,7 +933,7 @@ void panfrost_jm_fini(struct panfrost_device *pfdev)
drm_sched_fini(&js->queue[j].sched);
}
- cancel_work_sync(&pfdev->reset.work);
+ disable_work_sync(&pfdev->reset.work);
destroy_workqueue(pfdev->reset.wq);
}
@@ -1137,3 +1141,100 @@ int panfrost_jm_ctx_destroy(struct drm_file *file, u32 handle)
panfrost_jm_ctx_put(jm_ctx);
return 0;
}
+
+#ifdef CONFIG_DEBUG_FS
+static void show_panfrost_jm_ctx(struct panfrost_jm_ctx *jm_ctx, u32 handle,
+ struct seq_file *m)
+{
+ struct drm_device *ddev = ((struct drm_info_node *)m->private)->minor->dev;
+ const char *prio = "UNKNOWN";
+
+ static const char * const prios[] = {
+ [DRM_SCHED_PRIORITY_HIGH] = "HIGH",
+ [DRM_SCHED_PRIORITY_NORMAL] = "NORMAL",
+ [DRM_SCHED_PRIORITY_LOW] = "LOW",
+ };
+
+ if (jm_ctx->slot_entity[0].priority !=
+ jm_ctx->slot_entity[1].priority)
+ drm_warn(ddev, "Slot priorities should be the same in a single context");
+
+ if (jm_ctx->slot_entity[0].priority < ARRAY_SIZE(prios))
+ prio = prios[jm_ctx->slot_entity[0].priority];
+
+ seq_printf(m, " JM context %u: priority %s\n", handle, prio);
+}
+
+static int show_file_jm_ctxs(struct panfrost_file_priv *pfile,
+ struct seq_file *m)
+{
+ struct panfrost_jm_ctx *jm_ctx;
+ unsigned long i;
+
+ xa_lock(&pfile->jm_ctxs);
+ xa_for_each(&pfile->jm_ctxs, i, jm_ctx) {
+ jm_ctx = panfrost_jm_ctx_get(jm_ctx);
+ xa_unlock(&pfile->jm_ctxs);
+ show_panfrost_jm_ctx(jm_ctx, i, m);
+ panfrost_jm_ctx_put(jm_ctx);
+ xa_lock(&pfile->jm_ctxs);
+ }
+ xa_unlock(&pfile->jm_ctxs);
+
+ return 0;
+}
+
+static int show_each_file(struct seq_file *m, void *arg)
+{
+ struct drm_info_node *node = (struct drm_info_node *)m->private;
+ struct drm_device *ddev = node->minor->dev;
+ int (*show)(struct panfrost_file_priv *, struct seq_file *) =
+ node->info_ent->data;
+ struct drm_file *file;
+ int ret;
+
+ ret = mutex_lock_interruptible(&ddev->filelist_mutex);
+ if (ret)
+ return ret;
+
+ list_for_each_entry(file, &ddev->filelist, lhead) {
+ struct task_struct *task;
+ struct panfrost_file_priv *pfile = file->driver_priv;
+ struct pid *pid;
+
+ /*
+ * Although we have a valid reference on file->pid, that does
+ * not guarantee that the task_struct who called get_pid() is
+ * still alive (e.g. get_pid(current) => fork() => exit()).
+ * Therefore, we need to protect this ->comm access using RCU.
+ */
+ rcu_read_lock();
+ pid = rcu_dereference(file->pid);
+ task = pid_task(pid, PIDTYPE_TGID);
+ seq_printf(m, "client_id %8llu pid %8d command %s:\n",
+ file->client_id, pid_nr(pid),
+ task ? task->comm : "<unknown>");
+ rcu_read_unlock();
+
+ ret = show(pfile, m);
+ if (ret < 0)
+ break;
+
+ seq_puts(m, "\n");
+ }
+
+ mutex_unlock(&ddev->filelist_mutex);
+ return ret;
+}
+
+static struct drm_info_list panfrost_sched_debugfs_list[] = {
+ { "sched_ctxs", show_each_file, 0, show_file_jm_ctxs },
+};
+
+void panfrost_sched_debugfs_init(struct drm_minor *minor)
+{
+ drm_debugfs_create_files(panfrost_sched_debugfs_list,
+ ARRAY_SIZE(panfrost_sched_debugfs_list),
+ minor->debugfs_root, minor);
+}
+#endif
diff --git a/drivers/gpu/drm/panfrost/panfrost_job.h b/drivers/gpu/drm/panfrost/panfrost_job.h
index c3f57e41a571..3e3b9717838f 100644
--- a/drivers/gpu/drm/panfrost/panfrost_job.h
+++ b/drivers/gpu/drm/panfrost/panfrost_job.h
@@ -74,4 +74,8 @@ int panfrost_job_get_slot(struct panfrost_job *job);
int panfrost_job_push(struct panfrost_job *job);
void panfrost_job_put(struct panfrost_job *job);
+#ifdef CONFIG_DEBUG_FS
+void panfrost_sched_debugfs_init(struct drm_minor *minor);
+#endif
+
#endif
diff --git a/drivers/gpu/drm/panfrost/panfrost_mmu.c b/drivers/gpu/drm/panfrost/panfrost_mmu.c
index 4a3162c3b659..faa62643caf1 100644
--- a/drivers/gpu/drm/panfrost/panfrost_mmu.c
+++ b/drivers/gpu/drm/panfrost/panfrost_mmu.c
@@ -336,6 +336,12 @@ void panfrost_mmu_as_put(struct panfrost_device *pfdev, struct panfrost_mmu *mmu
WARN_ON(atomic_read(&mmu->as_count) < 0);
}
+static void panfrost_mmu_enable_interrupts(struct panfrost_device *pfdev)
+{
+ mmu_write(pfdev, MMU_INT_CLEAR, ~0);
+ mmu_write(pfdev, MMU_INT_MASK, ~0);
+}
+
void panfrost_mmu_reset(struct panfrost_device *pfdev)
{
struct panfrost_mmu *mmu, *mmu_tmp;
@@ -355,8 +361,7 @@ void panfrost_mmu_reset(struct panfrost_device *pfdev)
spin_unlock(&pfdev->as_lock);
- mmu_write(pfdev, MMU_INT_CLEAR, ~0);
- mmu_write(pfdev, MMU_INT_MASK, ~0);
+ panfrost_mmu_enable_interrupts(pfdev);
}
static size_t get_pgsize(u64 addr, size_t size, size_t *count)
@@ -955,6 +960,9 @@ int panfrost_mmu_init(struct panfrost_device *pfdev)
{
int err;
+ INIT_LIST_HEAD(&pfdev->as_lru_list);
+ spin_lock_init(&pfdev->as_lock);
+
pfdev->mmu_irq = platform_get_irq_byname(to_platform_device(pfdev->base.dev), "mmu");
if (pfdev->mmu_irq < 0)
return pfdev->mmu_irq;
@@ -970,6 +978,8 @@ int panfrost_mmu_init(struct panfrost_device *pfdev)
return err;
}
+ panfrost_mmu_enable_interrupts(pfdev);
+
return 0;
}
diff --git a/drivers/gpu/drm/panfrost/panfrost_perfcnt.c b/drivers/gpu/drm/panfrost/panfrost_perfcnt.c
index 7020c0192e18..a9def452d5ef 100644
--- a/drivers/gpu/drm/panfrost/panfrost_perfcnt.c
+++ b/drivers/gpu/drm/panfrost/panfrost_perfcnt.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright 2019 Collabora Ltd */
+#include "asm-generic/errno-base.h"
#include <linux/completion.h>
#include <linux/iopoll.h>
#include <linux/iosys-map.h>
@@ -11,6 +12,7 @@
#include <drm/drm_file.h>
#include <drm/drm_gem_shmem_helper.h>
#include <drm/panfrost_drm.h>
+#include <drm/drm_print.h>
#include "panfrost_device.h"
#include "panfrost_features.h"
@@ -28,13 +30,33 @@
struct panfrost_perfcnt {
struct panfrost_gem_mapping *mapping;
+ unsigned int counterset;
size_t bosize;
void *buf;
struct panfrost_file_priv *user;
struct mutex lock;
struct completion dump_comp;
+ u32 state;
+ bool owns_as_ref;
};
+static void panfrost_perfcnt_hw_disable(struct panfrost_device *pfdev)
+{
+ struct panfrost_perfcnt *perfcnt = pfdev->perfcnt;
+
+ gpu_write(pfdev, GPU_PERFCNT_CFG,
+ GPU_PERFCNT_CFG_MODE(GPU_PERFCNT_CFG_MODE_OFF));
+ gpu_write(pfdev, GPU_PRFCNT_JM_EN, 0x0);
+ gpu_write(pfdev, GPU_PRFCNT_SHADER_EN, 0x0);
+ gpu_write(pfdev, GPU_PRFCNT_MMU_L2_EN, 0x0);
+ gpu_write(pfdev, GPU_PRFCNT_TILER_EN, 0);
+
+ if (perfcnt->owns_as_ref) {
+ panfrost_mmu_as_put(pfdev, perfcnt->mapping->mmu);
+ perfcnt->owns_as_ref = false;
+ }
+}
+
void panfrost_perfcnt_clean_cache_done(struct panfrost_device *pfdev)
{
complete(&pfdev->perfcnt->dump_comp);
@@ -42,30 +64,136 @@ void panfrost_perfcnt_clean_cache_done(struct panfrost_device *pfdev)
void panfrost_perfcnt_sample_done(struct panfrost_device *pfdev)
{
- gpu_write(pfdev, GPU_CMD, GPU_CMD_CLEAN_CACHES);
+ if (pfdev->features.selected_coherency != COHERENCY_ACE)
+ gpu_write(pfdev, GPU_CMD, GPU_CMD_CLEAN_CACHES);
+ else
+ complete(&pfdev->perfcnt->dump_comp);
+}
+
+static int panfrost_perfcnt_hw_enable(struct panfrost_device *pfdev)
+{
+ struct panfrost_perfcnt *perfcnt = pfdev->perfcnt;
+ u32 cfg, as;
+ int ret;
+
+ lockdep_assert_held(&pfdev->reset.lock);
+ drm_WARN_ON(&pfdev->base, perfcnt->owns_as_ref);
+
+ ret = panfrost_mmu_as_get(pfdev, perfcnt->mapping->mmu);
+ if (ret < 0)
+ return ret;
+
+ perfcnt->owns_as_ref = true;
+
+ as = ret;
+ cfg = GPU_PERFCNT_CFG_AS(as) |
+ GPU_PERFCNT_CFG_MODE(GPU_PERFCNT_CFG_MODE_MANUAL);
+
+ /*
+ * Bifrost GPUs have 2 set of counters, but we're only interested by
+ * the first one for now.
+ */
+ if (panfrost_model_is_bifrost(pfdev))
+ cfg |= GPU_PERFCNT_CFG_SETSEL(perfcnt->counterset);
+
+ gpu_write(pfdev, GPU_PRFCNT_JM_EN, 0xffffffff);
+ gpu_write(pfdev, GPU_PRFCNT_SHADER_EN, 0xffffffff);
+ gpu_write(pfdev, GPU_PRFCNT_MMU_L2_EN, 0xffffffff);
+
+ /*
+ * Due to PRLAM-8186 we need to disable the Tiler before we enable HW
+ * counters.
+ */
+ if (panfrost_has_hw_issue(pfdev, HW_ISSUE_8186))
+ gpu_write(pfdev, GPU_PRFCNT_TILER_EN, 0);
+ else
+ gpu_write(pfdev, GPU_PRFCNT_TILER_EN, 0xffffffff);
+
+ gpu_write(pfdev, GPU_PERFCNT_CFG, cfg);
+
+ if (panfrost_has_hw_issue(pfdev, HW_ISSUE_8186))
+ gpu_write(pfdev, GPU_PRFCNT_TILER_EN, 0xffffffff);
+
+ return 0;
}
-static int panfrost_perfcnt_dump_locked(struct panfrost_device *pfdev)
+static int panfrost_perfcnt_dump_locked(struct panfrost_device *pfdev, u32 *state)
{
- u64 gpuva;
+ struct panfrost_perfcnt *perfcnt = pfdev->perfcnt;
+ u64 gpuva = perfcnt->mapping->mmnode.start << PAGE_SHIFT;
int ret;
- reinit_completion(&pfdev->perfcnt->dump_comp);
- gpuva = pfdev->perfcnt->mapping->mmnode.start << PAGE_SHIFT;
- gpu_write(pfdev, GPU_PERFCNT_BASE_LO, lower_32_bits(gpuva));
- gpu_write(pfdev, GPU_PERFCNT_BASE_HI, upper_32_bits(gpuva));
- gpu_write(pfdev, GPU_INT_CLEAR,
- GPU_IRQ_CLEAN_CACHES_COMPLETED |
- GPU_IRQ_PERFCNT_SAMPLE_COMPLETED);
- gpu_write(pfdev, GPU_CMD, GPU_CMD_PERFCNT_SAMPLE);
+ scoped_guard(rwsem_read, &pfdev->reset.lock) {
+ *state = perfcnt->state;
+ if (perfcnt->state & PANFROST_PERFCNT_SESSION_DEAD)
+ return -EIO;
+
+ perfcnt->state = 0;
+
+ reinit_completion(&pfdev->perfcnt->dump_comp);
+
+ gpu_write(pfdev, GPU_PERFCNT_BASE_LO, lower_32_bits(gpuva));
+ gpu_write(pfdev, GPU_PERFCNT_BASE_HI, upper_32_bits(gpuva));
+ gpu_write(pfdev, GPU_INT_CLEAR, GPU_IRQ_CLEAN_CACHES_COMPLETED |
+ GPU_IRQ_PERFCNT_SAMPLE_COMPLETED);
+ gpu_write(pfdev, GPU_CMD, GPU_CMD_PERFCNT_SAMPLE);
+ }
+
+ /*
+ * Here we release the reset semaphore because perfcnt should not get in the way
+ * of a HW reset. Besides, a legitimate reset might be issued during the wait.
+ */
ret = wait_for_completion_interruptible_timeout(&pfdev->perfcnt->dump_comp,
msecs_to_jiffies(1000));
+
if (!ret)
ret = -ETIMEDOUT;
- else if (ret > 0)
- ret = 0;
- return ret;
+ /* We need to restore perfcnt state so the next successful dump can relay it to UM */
+ if (ret < 0) {
+ perfcnt->state |= *state;
+ *state = 0;
+ return ret;
+ }
+
+ scoped_guard(rwsem_read, &pfdev->reset.lock) {
+ *state |= perfcnt->state;
+
+ /* UM must re-enable their session before requesting new dumps. */
+ if (perfcnt->state & PANFROST_PERFCNT_SESSION_DEAD)
+ return -EIO;
+
+ /* If we faced a reset during our SAMPLE, the user needs to try again. */
+ if (perfcnt->state & PANFROST_PERFCNT_SESSION_INTERRUPTED_BY_RESET)
+ return -EAGAIN;
+ }
+
+ return 0;
+}
+
+static int panfrost_perfcnt_disable_locked(struct panfrost_device *pfdev,
+ struct drm_file *file_priv)
+{
+ struct panfrost_file_priv *user = file_priv->driver_priv;
+ struct panfrost_perfcnt *perfcnt = pfdev->perfcnt;
+ struct iosys_map map = IOSYS_MAP_INIT_VADDR(perfcnt->buf);
+
+ if (user != perfcnt->user)
+ return -EINVAL;
+
+ scoped_guard(rwsem_read, &pfdev->reset.lock) {
+ panfrost_perfcnt_hw_disable(pfdev);
+ perfcnt->user = NULL;
+ }
+
+ drm_gem_vunmap(&perfcnt->mapping->obj->base.base, &map);
+ perfcnt->buf = NULL;
+ panfrost_gem_close(&perfcnt->mapping->obj->base.base, file_priv);
+ panfrost_gem_mapping_put(perfcnt->mapping);
+ perfcnt->mapping = NULL;
+ pm_runtime_put_autosuspend(pfdev->base.dev);
+
+ return 0;
}
static int panfrost_perfcnt_enable_locked(struct panfrost_device *pfdev,
@@ -74,14 +202,29 @@ static int panfrost_perfcnt_enable_locked(struct panfrost_device *pfdev,
{
struct panfrost_file_priv *user = file_priv->driver_priv;
struct panfrost_perfcnt *perfcnt = pfdev->perfcnt;
- struct iosys_map map;
struct drm_gem_shmem_object *bo;
- u32 cfg, as;
+ struct iosys_map map;
int ret;
- if (user == perfcnt->user)
+ if (perfcnt->user == user) {
+ scoped_guard(rwsem_read, &pfdev->reset.lock) {
+ if (perfcnt->state & PANFROST_PERFCNT_SESSION_DEAD) {
+ /* A successful reset might've come through in the time gap
+ * between the last failed one and this re-enable attempt.
+ */
+ ret = (perfcnt->owns_as_ref) ? 0 :
+ panfrost_perfcnt_hw_enable(pfdev);
+ if (!ret)
+ perfcnt->state = 0;
+
+ return ret;
+ }
+ }
+
return 0;
- else if (perfcnt->user)
+ }
+
+ if (perfcnt->user)
return -EBUSY;
ret = pm_runtime_get_sync(pfdev->base.dev);
@@ -109,65 +252,30 @@ static int panfrost_perfcnt_enable_locked(struct panfrost_device *pfdev,
ret = drm_gem_vmap(&bo->base, &map);
if (ret)
goto err_put_mapping;
+
perfcnt->buf = map.vaddr;
+ perfcnt->counterset = counterset;
panfrost_gem_internal_set_label(&bo->base, "Perfcnt sample buffer");
- /*
- * Invalidate the cache and clear the counters to start from a fresh
- * state.
- */
- reinit_completion(&pfdev->perfcnt->dump_comp);
- gpu_write(pfdev, GPU_INT_CLEAR,
- GPU_IRQ_CLEAN_CACHES_COMPLETED |
- GPU_IRQ_PERFCNT_SAMPLE_COMPLETED);
- gpu_write(pfdev, GPU_CMD, GPU_CMD_PERFCNT_CLEAR);
- gpu_write(pfdev, GPU_CMD, GPU_CMD_CLEAN_INV_CACHES);
- ret = wait_for_completion_timeout(&pfdev->perfcnt->dump_comp,
- msecs_to_jiffies(1000));
- if (!ret) {
- ret = -ETIMEDOUT;
- goto err_vunmap;
- }
-
- ret = panfrost_mmu_as_get(pfdev, perfcnt->mapping->mmu);
- if (ret < 0)
- goto err_vunmap;
-
- as = ret;
- cfg = GPU_PERFCNT_CFG_AS(as) |
- GPU_PERFCNT_CFG_MODE(GPU_PERFCNT_CFG_MODE_MANUAL);
-
- /*
- * Bifrost GPUs have 2 set of counters, but we're only interested by
- * the first one for now.
- */
- if (panfrost_model_is_bifrost(pfdev))
- cfg |= GPU_PERFCNT_CFG_SETSEL(counterset);
-
- gpu_write(pfdev, GPU_PRFCNT_JM_EN, 0xffffffff);
- gpu_write(pfdev, GPU_PRFCNT_SHADER_EN, 0xffffffff);
- gpu_write(pfdev, GPU_PRFCNT_MMU_L2_EN, 0xffffffff);
-
- /*
- * Due to PRLAM-8186 we need to disable the Tiler before we enable HW
- * counters.
- */
- if (panfrost_has_hw_issue(pfdev, HW_ISSUE_8186))
- gpu_write(pfdev, GPU_PRFCNT_TILER_EN, 0);
- else
- gpu_write(pfdev, GPU_PRFCNT_TILER_EN, 0xffffffff);
+ scoped_guard(rwsem_read, &pfdev->reset.lock) {
+ /*
+ * Clear the counters to start from a fresh state.
+ */
+ gpu_write(pfdev, GPU_INT_CLEAR, GPU_IRQ_PERFCNT_SAMPLE_COMPLETED);
+ gpu_write(pfdev, GPU_CMD, GPU_CMD_PERFCNT_CLEAR);
- gpu_write(pfdev, GPU_PERFCNT_CFG, cfg);
+ ret = panfrost_perfcnt_hw_enable(pfdev);
+ if (ret)
+ goto err_vunmap;
- if (panfrost_has_hw_issue(pfdev, HW_ISSUE_8186))
- gpu_write(pfdev, GPU_PRFCNT_TILER_EN, 0xffffffff);
+ perfcnt->user = user;
+ perfcnt->state = 0;
+ }
/* The BO ref is retained by the mapping. */
drm_gem_object_put(&bo->base);
- perfcnt->user = user;
-
return 0;
err_vunmap:
@@ -183,35 +291,6 @@ err_put_pm:
return ret;
}
-static int panfrost_perfcnt_disable_locked(struct panfrost_device *pfdev,
- struct drm_file *file_priv)
-{
- struct panfrost_file_priv *user = file_priv->driver_priv;
- struct panfrost_perfcnt *perfcnt = pfdev->perfcnt;
- struct iosys_map map = IOSYS_MAP_INIT_VADDR(perfcnt->buf);
-
- if (user != perfcnt->user)
- return -EINVAL;
-
- gpu_write(pfdev, GPU_PRFCNT_JM_EN, 0x0);
- gpu_write(pfdev, GPU_PRFCNT_SHADER_EN, 0x0);
- gpu_write(pfdev, GPU_PRFCNT_MMU_L2_EN, 0x0);
- gpu_write(pfdev, GPU_PRFCNT_TILER_EN, 0);
- gpu_write(pfdev, GPU_PERFCNT_CFG,
- GPU_PERFCNT_CFG_MODE(GPU_PERFCNT_CFG_MODE_OFF));
-
- perfcnt->user = NULL;
- drm_gem_vunmap(&perfcnt->mapping->obj->base.base, &map);
- perfcnt->buf = NULL;
- panfrost_gem_close(&perfcnt->mapping->obj->base.base, file_priv);
- panfrost_mmu_as_put(pfdev, perfcnt->mapping->mmu);
- panfrost_gem_mapping_put(perfcnt->mapping);
- perfcnt->mapping = NULL;
- pm_runtime_put_autosuspend(pfdev->base.dev);
-
- return 0;
-}
-
int panfrost_ioctl_perfcnt_enable(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
@@ -252,13 +331,16 @@ int panfrost_ioctl_perfcnt_dump(struct drm_device *dev, void *data,
if (ret)
return ret;
+ if (req->pad)
+ return -EINVAL;
+
mutex_lock(&perfcnt->lock);
if (perfcnt->user != file_priv->driver_priv) {
ret = -EINVAL;
goto out;
}
- ret = panfrost_perfcnt_dump_locked(pfdev);
+ ret = panfrost_perfcnt_dump_locked(pfdev, &req->state);
if (ret)
goto out;
@@ -325,18 +407,12 @@ int panfrost_perfcnt_init(struct panfrost_device *pfdev)
return -ENOMEM;
perfcnt->bosize = size;
+ pfdev->perfcnt = perfcnt;
+ mutex_init(&perfcnt->lock);
+ init_completion(&perfcnt->dump_comp);
/* Start with everything disabled. */
- gpu_write(pfdev, GPU_PERFCNT_CFG,
- GPU_PERFCNT_CFG_MODE(GPU_PERFCNT_CFG_MODE_OFF));
- gpu_write(pfdev, GPU_PRFCNT_JM_EN, 0);
- gpu_write(pfdev, GPU_PRFCNT_SHADER_EN, 0);
- gpu_write(pfdev, GPU_PRFCNT_MMU_L2_EN, 0);
- gpu_write(pfdev, GPU_PRFCNT_TILER_EN, 0);
-
- init_completion(&perfcnt->dump_comp);
- mutex_init(&perfcnt->lock);
- pfdev->perfcnt = perfcnt;
+ panfrost_perfcnt_hw_disable(pfdev);
return 0;
}
@@ -344,10 +420,27 @@ int panfrost_perfcnt_init(struct panfrost_device *pfdev)
void panfrost_perfcnt_fini(struct panfrost_device *pfdev)
{
/* Disable everything before leaving. */
- gpu_write(pfdev, GPU_PERFCNT_CFG,
- GPU_PERFCNT_CFG_MODE(GPU_PERFCNT_CFG_MODE_OFF));
- gpu_write(pfdev, GPU_PRFCNT_JM_EN, 0);
- gpu_write(pfdev, GPU_PRFCNT_SHADER_EN, 0);
- gpu_write(pfdev, GPU_PRFCNT_MMU_L2_EN, 0);
- gpu_write(pfdev, GPU_PRFCNT_TILER_EN, 0);
+ panfrost_perfcnt_hw_disable(pfdev);
+}
+
+void panfrost_perfcnt_reset(struct panfrost_device *pfdev)
+{
+ struct panfrost_perfcnt *perfcnt = pfdev->perfcnt;
+
+ if (drm_WARN_ON(&pfdev->base, !perfcnt))
+ return;
+
+ lockdep_assert_held(&pfdev->reset.lock);
+
+ if (!perfcnt->user)
+ return;
+
+ /* All active AS are released during the MMU post_reset. */
+ perfcnt->owns_as_ref = false;
+ perfcnt->state |= PANFROST_PERFCNT_SESSION_INTERRUPTED_BY_RESET;
+ if (panfrost_perfcnt_hw_enable(pfdev))
+ perfcnt->state |= PANFROST_PERFCNT_SESSION_DEAD;
+
+ /* Unblock pending sample requests. */
+ complete(&perfcnt->dump_comp);
}
diff --git a/drivers/gpu/drm/panfrost/panfrost_perfcnt.h b/drivers/gpu/drm/panfrost/panfrost_perfcnt.h
index 8bbcf5f5fb33..8b9bc704b634 100644
--- a/drivers/gpu/drm/panfrost/panfrost_perfcnt.h
+++ b/drivers/gpu/drm/panfrost/panfrost_perfcnt.h
@@ -14,5 +14,6 @@ int panfrost_ioctl_perfcnt_enable(struct drm_device *dev, void *data,
struct drm_file *file_priv);
int panfrost_ioctl_perfcnt_dump(struct drm_device *dev, void *data,
struct drm_file *file_priv);
+void panfrost_perfcnt_reset(struct panfrost_device *pfdev);
#endif
diff --git a/drivers/gpu/drm/panthor/panthor_drv.c b/drivers/gpu/drm/panthor/panthor_drv.c
index 1ca8aedd83f4..dc8d0191aef4 100644
--- a/drivers/gpu/drm/panthor/panthor_drv.c
+++ b/drivers/gpu/drm/panthor/panthor_drv.c
@@ -1081,7 +1081,7 @@ static int panthor_ioctl_bo_mmap_offset(struct drm_device *ddev, void *data,
struct drm_panthor_bo_mmap_offset *args = data;
struct panthor_gem_object *bo;
struct drm_gem_object *obj;
- int ret;
+ int ret = 0;
if (args->pad)
return -EINVAL;
@@ -1096,10 +1096,6 @@ static int panthor_ioctl_bo_mmap_offset(struct drm_device *ddev, void *data,
goto out;
}
- ret = drm_gem_create_mmap_offset(obj);
- if (ret)
- goto out;
-
args->offset = drm_vma_node_offset_addr(&obj->vma_node);
out:
diff --git a/drivers/gpu/drm/panthor/panthor_gem.c b/drivers/gpu/drm/panthor/panthor_gem.c
index c07a44057e42..22b57ab6f929 100644
--- a/drivers/gpu/drm/panthor/panthor_gem.c
+++ b/drivers/gpu/drm/panthor/panthor_gem.c
@@ -744,6 +744,9 @@ static int panthor_gem_mmap(struct drm_gem_object *obj, struct vm_area_struct *v
struct panthor_gem_object *bo = to_panthor_bo(obj);
int ret;
+ if (bo->flags & DRM_PANTHOR_BO_NO_MMAP)
+ return -EINVAL;
+
if (drm_gem_is_imported(obj)) {
/* Reset both vm_ops and vm_private_data, so we don't end up with
* vm_ops pointing to our implementation if the dma-buf backend
diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c
index 0493858e55d7..a343c5180e01 100644
--- a/drivers/gpu/drm/panthor/panthor_sched.c
+++ b/drivers/gpu/drm/panthor/panthor_sched.c
@@ -3770,12 +3770,18 @@ int panthor_group_destroy(struct panthor_file *pfile, u32 group_handle)
struct panthor_group_pool *gpool = pfile->groups;
struct panthor_device *ptdev = pfile->ptdev;
struct panthor_scheduler *sched = ptdev->scheduler;
- struct panthor_group *group;
+ struct panthor_group *group = NULL;
- if (!xa_get_mark(&gpool->xa, group_handle, GROUP_REGISTERED))
- return -EINVAL;
+ /*
+ * Check the mark and erase the entry atomically, so a concurrent
+ * destroy + create can't make us erase a group that's still being
+ * initialized and happens to reuse the same handle.
+ */
+ xa_lock(&gpool->xa);
+ if (xa_get_mark(&gpool->xa, group_handle, GROUP_REGISTERED))
+ group = __xa_erase(&gpool->xa, group_handle);
+ xa_unlock(&gpool->xa);
- group = xa_erase(&gpool->xa, group_handle);
if (!group)
return -EINVAL;
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index 9c4cf68d79d5..f2a1ea8dfefa 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -24,7 +24,6 @@
#include <drm/drm_bridge_connector.h>
#include <drm/drm_managed.h>
#include <drm/drm_of.h>
-#include <drm/drm_probe_helper.h>
#include "rockchip_drm_drv.h"
@@ -34,6 +33,7 @@
#define RK3576_IOC_HDMI_HPD_STATUS 0xa440
#define RK3576_HDMI_LEVEL_INT BIT(3)
+#define RK3576_HDMI_OHPD_INT BIT(4)
#define RK3576_VO0_GRF_SOC_CON1 0x0004
#define RK3576_HDMI_FRL_MOD BIT(0)
@@ -64,7 +64,9 @@
#define RK3588_HPD_HDMI1_IO_EN_MASK BIT(13)
#define RK3588_GRF_SOC_STATUS1 0x0384
#define RK3588_HDMI0_LEVEL_INT BIT(16)
+#define RK3588_HDMI0_OHPD_INT BIT(17)
#define RK3588_HDMI1_LEVEL_INT BIT(24)
+#define RK3588_HDMI1_OHPD_INT BIT(25)
#define RK3588_GRF_VO1_CON3 0x000c
#define RK3588_GRF_VO1_CON6 0x0018
#define RK3588_COLOR_DEPTH_MASK GENMASK(7, 4)
@@ -96,6 +98,7 @@ struct rockchip_hdmi_qp {
struct phy *phy;
struct gpio_desc *frl_enable_gpio;
struct delayed_work hpd_work;
+ int hpd_irq;
int port_id;
const struct rockchip_hdmi_qp_ctrl_ops *ctrl_ops;
unsigned long long tmds_char_rate;
@@ -274,9 +277,8 @@ dw_hdmi_qp_rk3588_read_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
return val ? connector_status_connected : connector_status_disconnected;
}
-static void dw_hdmi_qp_rk3588_setup_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
+static void dw_hdmi_qp_rk3588_unmask_hpd(struct rockchip_hdmi_qp *hdmi)
{
- struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
u32 val;
if (hdmi->port_id)
@@ -289,11 +291,48 @@ static void dw_hdmi_qp_rk3588_setup_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
}
+static void dw_hdmi_qp_rk3588_mask_hpd(struct rockchip_hdmi_qp *hdmi)
+{
+ u32 val;
+
+ if (hdmi->port_id)
+ val = FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_MSK, 1);
+ else
+ val = FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_MSK, 1);
+
+ regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
+}
+
+static void dw_hdmi_qp_rk3588_enable_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
+{
+ struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
+
+ dw_hdmi_qp_rk3588_unmask_hpd(hdmi);
+ enable_irq(hdmi->hpd_irq);
+}
+
+static void dw_hdmi_qp_rk3588_disable_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
+{
+ struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
+
+ disable_irq(hdmi->hpd_irq);
+ dw_hdmi_qp_rk3588_mask_hpd(hdmi);
+
+ /*
+ * Cannot use the _sync() variant: the work takes mode_config.mutex,
+ * which the connector probe path already holds when acquiring the
+ * hpd_state_mutex this caller runs under. Requeuing is already ruled
+ * out by disable_irq().
+ */
+ cancel_delayed_work(&hdmi->hpd_work);
+}
+
static const struct dw_hdmi_qp_phy_ops rk3588_hdmi_phy_ops = {
.init = dw_hdmi_qp_rk3588_phy_init,
.disable = dw_hdmi_qp_rk3588_phy_disable,
.read_hpd = dw_hdmi_qp_rk3588_read_hpd,
- .setup_hpd = dw_hdmi_qp_rk3588_setup_hpd,
+ .enable_hpd = dw_hdmi_qp_rk3588_enable_hpd,
+ .disable_hpd = dw_hdmi_qp_rk3588_disable_hpd,
};
static enum drm_connector_status
@@ -308,23 +347,49 @@ dw_hdmi_qp_rk3576_read_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
connector_status_connected : connector_status_disconnected;
}
-static void dw_hdmi_qp_rk3576_setup_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
+static void dw_hdmi_qp_rk3576_unmask_hpd(struct rockchip_hdmi_qp *hdmi)
+{
+ regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0,
+ FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_CLR, 1) |
+ FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 0));
+}
+
+static void dw_hdmi_qp_rk3576_mask_hpd(struct rockchip_hdmi_qp *hdmi)
+{
+ regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0,
+ FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 1));
+}
+
+static void dw_hdmi_qp_rk3576_enable_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
{
struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
- u32 val;
- val = (FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_CLR, 1) |
- FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 0));
+ dw_hdmi_qp_rk3576_unmask_hpd(hdmi);
+ enable_irq(hdmi->hpd_irq);
+}
- regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
- regmap_write(hdmi->regmap, 0xa404, 0xffff0102);
+static void dw_hdmi_qp_rk3576_disable_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
+{
+ struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
+
+ disable_irq(hdmi->hpd_irq);
+ dw_hdmi_qp_rk3576_mask_hpd(hdmi);
+
+ /*
+ * Cannot use the _sync() variant: the work takes mode_config.mutex,
+ * which the connector probe path already holds when acquiring the
+ * hpd_state_mutex this caller runs under. Requeuing is already ruled
+ * out by disable_irq().
+ */
+ cancel_delayed_work(&hdmi->hpd_work);
}
static const struct dw_hdmi_qp_phy_ops rk3576_hdmi_phy_ops = {
.init = dw_hdmi_qp_rk3588_phy_init,
.disable = dw_hdmi_qp_rk3588_phy_disable,
.read_hpd = dw_hdmi_qp_rk3576_read_hpd,
- .setup_hpd = dw_hdmi_qp_rk3576_setup_hpd,
+ .enable_hpd = dw_hdmi_qp_rk3576_enable_hpd,
+ .disable_hpd = dw_hdmi_qp_rk3576_disable_hpd,
};
static void dw_hdmi_qp_rk3588_hpd_work(struct work_struct *work)
@@ -332,26 +397,19 @@ static void dw_hdmi_qp_rk3588_hpd_work(struct work_struct *work)
struct rockchip_hdmi_qp *hdmi = container_of(work,
struct rockchip_hdmi_qp,
hpd_work.work);
- struct drm_device *drm = hdmi->encoder.encoder.dev;
- bool changed;
- if (drm) {
- changed = drm_helper_hpd_irq_event(drm);
- if (changed)
- dev_dbg(hdmi->dev, "connector status changed\n");
- }
+ dw_hdmi_qp_hpd_notify(hdmi->hdmi);
}
static irqreturn_t dw_hdmi_qp_rk3576_hardirq(int irq, void *dev_id)
{
struct rockchip_hdmi_qp *hdmi = dev_id;
- u32 intr_stat, val;
+ u32 intr_stat;
regmap_read(hdmi->regmap, RK3576_IOC_HDMI_HPD_STATUS, &intr_stat);
- if (intr_stat) {
- val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 1);
- regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
+ if (intr_stat & RK3576_HDMI_OHPD_INT) {
+ dw_hdmi_qp_rk3576_mask_hpd(hdmi);
return IRQ_WAKE_THREAD;
}
@@ -361,15 +419,11 @@ static irqreturn_t dw_hdmi_qp_rk3576_hardirq(int irq, void *dev_id)
static irqreturn_t dw_hdmi_qp_rk3576_irq(int irq, void *dev_id)
{
struct rockchip_hdmi_qp *hdmi = dev_id;
- u32 val;
- val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_CLR, 1);
- regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
mod_delayed_work(system_percpu_wq, &hdmi->hpd_work,
msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
- val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 0);
- regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
+ dw_hdmi_qp_rk3576_unmask_hpd(hdmi);
return IRQ_HANDLED;
}
@@ -377,16 +431,14 @@ static irqreturn_t dw_hdmi_qp_rk3576_irq(int irq, void *dev_id)
static irqreturn_t dw_hdmi_qp_rk3588_hardirq(int irq, void *dev_id)
{
struct rockchip_hdmi_qp *hdmi = dev_id;
- u32 intr_stat, val;
+ u32 intr_stat;
regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &intr_stat);
+ intr_stat &= hdmi->port_id ? RK3588_HDMI1_OHPD_INT : RK3588_HDMI0_OHPD_INT;
+
if (intr_stat) {
- if (hdmi->port_id)
- val = FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_MSK, 1);
- else
- val = FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_MSK, 1);
- regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
+ dw_hdmi_qp_rk3588_mask_hpd(hdmi);
return IRQ_WAKE_THREAD;
}
@@ -396,22 +448,11 @@ static irqreturn_t dw_hdmi_qp_rk3588_hardirq(int irq, void *dev_id)
static irqreturn_t dw_hdmi_qp_rk3588_irq(int irq, void *dev_id)
{
struct rockchip_hdmi_qp *hdmi = dev_id;
- u32 val;
-
- if (hdmi->port_id)
- val = FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_CLR, 1);
- else
- val = FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_CLR, 1);
- regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
mod_delayed_work(system_percpu_wq, &hdmi->hpd_work,
msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
- if (hdmi->port_id)
- val |= FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_MSK, 0);
- else
- val |= FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_MSK, 0);
- regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
+ dw_hdmi_qp_rk3588_unmask_hpd(hdmi);
return IRQ_HANDLED;
}
@@ -424,11 +465,11 @@ static void dw_hdmi_qp_rk3576_io_init(struct rockchip_hdmi_qp *hdmi)
FIELD_PREP_WM16(RK3576_SDAIN_MASK, 1) |
FIELD_PREP_WM16(RK3576_HDMI_GRANT_SEL, 1) |
FIELD_PREP_WM16(RK3576_I2S_SEL_MASK, 1);
-
regmap_write(hdmi->vo_regmap, RK3576_VO0_GRF_SOC_CON14, val);
- val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 0);
- regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
+ regmap_write(hdmi->regmap, 0xa404, 0xffff0102);
+
+ dw_hdmi_qp_rk3576_mask_hpd(hdmi);
}
static void dw_hdmi_qp_rk3588_io_init(struct rockchip_hdmi_qp *hdmi)
@@ -453,11 +494,7 @@ static void dw_hdmi_qp_rk3588_io_init(struct rockchip_hdmi_qp *hdmi)
val = FIELD_PREP_WM16(RK3588_HDMI0_GRANT_SEL, 1);
regmap_write(hdmi->vo_regmap, RK3588_GRF_VO1_CON9, val);
- if (hdmi->port_id)
- val = FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_MSK, 1);
- else
- val = FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_MSK, 1);
- regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
+ dw_hdmi_qp_rk3588_mask_hpd(hdmi);
}
static void dw_hdmi_qp_rk3576_enc_init(struct rockchip_hdmi_qp *hdmi,
@@ -561,9 +598,9 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
struct resource *res;
struct clk_bulk_data *clks;
struct clk *ref_clk;
- int ret, irq, i;
+ int ret, i;
- if (!pdev->dev.of_node)
+ if (!dev->of_node)
return -ENODEV;
hdmi = drmm_kzalloc(drm, sizeof(*hdmi), GFP_KERNEL);
@@ -583,7 +620,7 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
return dev_err_probe(dev, -ENODEV, "Missing platform ctrl ops\n");
hdmi->ctrl_ops = cfg->ctrl_ops;
- hdmi->dev = &pdev->dev;
+ hdmi->dev = dev;
hdmi->port_id = -ENODEV;
/* Identify port ID by matching base IO address */
@@ -594,7 +631,7 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
}
}
if (hdmi->port_id < 0)
- return dev_err_probe(hdmi->dev, hdmi->port_id,
+ return dev_err_probe(dev, hdmi->port_id,
"Failed to match HDMI port ID\n");
plat_data.phy_ops = cfg->phy_ops;
@@ -622,37 +659,36 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
hdmi->regmap = syscon_regmap_lookup_by_phandle(dev->of_node,
"rockchip,grf");
if (IS_ERR(hdmi->regmap))
- return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->regmap),
+ return dev_err_probe(dev, PTR_ERR(hdmi->regmap),
"Unable to get rockchip,grf\n");
hdmi->vo_regmap = syscon_regmap_lookup_by_phandle(dev->of_node,
"rockchip,vo-grf");
if (IS_ERR(hdmi->vo_regmap))
- return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->vo_regmap),
+ return dev_err_probe(dev, PTR_ERR(hdmi->vo_regmap),
"Unable to get rockchip,vo-grf\n");
- ret = devm_clk_bulk_get_all_enabled(hdmi->dev, &clks);
+ ret = devm_clk_bulk_get_all_enabled(dev, &clks);
if (ret < 0)
- return dev_err_probe(hdmi->dev, ret, "Failed to get clocks\n");
+ return dev_err_probe(dev, ret, "Failed to get clocks\n");
- ref_clk = clk_get(hdmi->dev, "ref");
+ ref_clk = clk_get(dev, "ref");
if (IS_ERR(ref_clk))
- return dev_err_probe(hdmi->dev, PTR_ERR(ref_clk),
+ return dev_err_probe(dev, PTR_ERR(ref_clk),
"Failed to get ref clock\n");
plat_data.ref_clk_rate = clk_get_rate(ref_clk);
clk_put(ref_clk);
- hdmi->frl_enable_gpio = devm_gpiod_get_optional(hdmi->dev, "frl-enable",
+ hdmi->frl_enable_gpio = devm_gpiod_get_optional(dev, "frl-enable",
GPIOD_OUT_LOW);
if (IS_ERR(hdmi->frl_enable_gpio))
- return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->frl_enable_gpio),
+ return dev_err_probe(dev, PTR_ERR(hdmi->frl_enable_gpio),
"Failed to request FRL enable GPIO\n");
hdmi->phy = devm_of_phy_get_by_index(dev, dev->of_node, 0);
if (IS_ERR(hdmi->phy))
- return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->phy),
- "Failed to get phy\n");
+ return dev_err_probe(dev, PTR_ERR(hdmi->phy), "Failed to get phy\n");
cfg->ctrl_ops->io_init(hdmi);
@@ -666,14 +702,14 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
if (plat_data.cec_irq < 0)
return plat_data.cec_irq;
- irq = platform_get_irq_byname(pdev, "hpd");
- if (irq < 0)
- return irq;
+ hdmi->hpd_irq = platform_get_irq_byname(pdev, "hpd");
+ if (hdmi->hpd_irq < 0)
+ return hdmi->hpd_irq;
- ret = devm_request_threaded_irq(hdmi->dev, irq,
+ ret = devm_request_threaded_irq(dev, hdmi->hpd_irq,
cfg->ctrl_ops->hardirq_callback,
cfg->ctrl_ops->irq_callback,
- IRQF_SHARED, "dw-hdmi-qp-hpd",
+ IRQF_NO_AUTOEN, "dw-hdmi-qp-hpd",
hdmi);
if (ret)
return ret;
@@ -681,20 +717,20 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
drm_encoder_helper_add(encoder, &dw_hdmi_qp_rockchip_encoder_helper_funcs);
ret = drmm_encoder_init(drm, encoder, NULL, DRM_MODE_ENCODER_TMDS, NULL);
if (ret)
- return dev_err_probe(hdmi->dev, ret, "Failed to init encoder");
-
- platform_set_drvdata(pdev, hdmi);
+ return dev_err_probe(dev, ret, "Failed to init encoder\n");
hdmi->hdmi = dw_hdmi_qp_bind(pdev, encoder, &plat_data);
if (IS_ERR(hdmi->hdmi))
- return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->hdmi),
- "Failed to bind dw-hdmi-qp");
+ return dev_err_probe(dev, PTR_ERR(hdmi->hdmi),
+ "Failed to bind dw-hdmi-qp\n");
connector = drm_bridge_connector_init(drm, encoder);
if (IS_ERR(connector))
- return dev_err_probe(hdmi->dev, PTR_ERR(connector),
+ return dev_err_probe(dev, PTR_ERR(connector),
"Failed to init bridge connector\n");
+ platform_set_drvdata(pdev, hdmi);
+
return 0;
}
@@ -704,6 +740,8 @@ static void dw_hdmi_qp_rockchip_unbind(struct device *dev,
{
struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev);
+ dev_set_drvdata(dev, NULL);
+
cancel_delayed_work_sync(&hdmi->hpd_work);
}
@@ -726,6 +764,11 @@ static int __maybe_unused dw_hdmi_qp_rockchip_suspend(struct device *dev)
{
struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev);
+ if (!hdmi)
+ return 0;
+
+ cancel_delayed_work_sync(&hdmi->hpd_work);
+
dw_hdmi_qp_suspend(dev, hdmi->hdmi);
return 0;
@@ -735,12 +778,14 @@ static int __maybe_unused dw_hdmi_qp_rockchip_resume(struct device *dev)
{
struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev);
+ if (!hdmi)
+ return 0;
+
hdmi->ctrl_ops->io_init(hdmi);
dw_hdmi_qp_resume(dev, hdmi->hdmi);
- if (hdmi->encoder.encoder.dev)
- drm_helper_hpd_irq_event(hdmi->encoder.encoder.dev);
+ dw_hdmi_qp_hpd_notify(hdmi->hdmi);
return 0;
}
diff --git a/drivers/gpu/drm/rockchip/rk3066_hdmi.c b/drivers/gpu/drm/rockchip/rk3066_hdmi.c
index f28d6a883e09..273f61758b10 100644
--- a/drivers/gpu/drm/rockchip/rk3066_hdmi.c
+++ b/drivers/gpu/drm/rockchip/rk3066_hdmi.c
@@ -14,6 +14,7 @@
#include <drm/drm_probe_helper.h>
#include <linux/clk.h>
+#include <linux/hdmi.h>
#include <linux/mfd/syscon.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
@@ -703,7 +704,6 @@ rk3066_hdmi_register(struct drm_device *drm, struct rk3066_hdmi *hdmi)
DRM_MODE_ENCODER_TMDS, NULL);
hdmi->bridge.driver_private = hdmi;
- hdmi->bridge.funcs = &rk3066_hdmi_bridge_funcs;
hdmi->bridge.ops = DRM_BRIDGE_OP_DETECT |
DRM_BRIDGE_OP_EDID |
DRM_BRIDGE_OP_HDMI |
@@ -712,6 +712,7 @@ rk3066_hdmi_register(struct drm_device *drm, struct rk3066_hdmi *hdmi)
hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
hdmi->bridge.vendor = "Rockchip";
hdmi->bridge.product = "RK3066 HDMI";
+ hdmi->bridge.supported_hdmi_ver = HDMI_VERSION_1_4;
hdmi->bridge.ddc = rk3066_hdmi_i2c_adapter(hdmi);
if (IS_ERR(hdmi->bridge.ddc))
@@ -747,9 +748,10 @@ static int rk3066_hdmi_bind(struct device *dev, struct device *master,
int irq;
int ret;
- hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
- if (!hdmi)
- return -ENOMEM;
+ hdmi = devm_drm_bridge_alloc(dev, struct rk3066_hdmi, bridge,
+ &rk3066_hdmi_bridge_funcs);
+ if (IS_ERR(hdmi))
+ return PTR_ERR(hdmi);
hdmi->dev = dev;
hdmi->drm_dev = drm;
diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c
index b9580ce1ddec..99252674e266 100644
--- a/drivers/gpu/drm/scheduler/sched_main.c
+++ b/drivers/gpu/drm/scheduler/sched_main.c
@@ -1202,6 +1202,11 @@ static void drm_sched_cancel_remaining_jobs(struct drm_gpu_scheduler *sched)
* is implemented, all jobs will be canceled through it and afterwards cleaned
* up through &struct drm_sched_backend_ops.free_job. If cancel_job is not
* implemented, memory could leak.
+ *
+ * The user must wait one RCU grace period between signaling the last hardware-
+ * fence and calling this function because the timeline name returned by
+ * scheduler fences must stay valid until all readers have exited their RCU read
+ * side critical section.
*/
void drm_sched_fini(struct drm_gpu_scheduler *sched)
{
diff --git a/drivers/gpu/drm/solomon/ssd130x.c b/drivers/gpu/drm/solomon/ssd130x.c
index 8cbf18754487..ee43cf0da879 100644
--- a/drivers/gpu/drm/solomon/ssd130x.c
+++ b/drivers/gpu/drm/solomon/ssd130x.c
@@ -1985,7 +1985,7 @@ static const struct drm_connector_helper_funcs ssd130x_connector_helper_funcs =
};
static const struct drm_connector_funcs ssd130x_connector_funcs = {
- .reset = drm_atomic_helper_connector_reset,
+ .atomic_create_state = drm_atomic_helper_connector_create_state,
.fill_modes = drm_helper_probe_single_connector_modes,
.destroy = drm_connector_cleanup,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
index d98b6f12a7bc..6f4fe0c8efae 100644
--- a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
+++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
@@ -192,10 +192,6 @@ sun4i_hdmi_connector_clock_valid(const struct drm_connector *connector,
if (mode->flags & DRM_MODE_FLAG_DBLCLK)
return MODE_BAD;
- /* HDMI 1.0 max TMDS character rate */
- if (clock > HDMI_1_0_TMDS_CHAR_RATE_MAX_HZ)
- return MODE_CLOCK_HIGH;
-
rounded_rate = clk_round_rate(hdmi->tmds_clk, clock);
if (rounded_rate > 0 &&
max_t(unsigned long, rounded_rate, clock) -
@@ -253,6 +249,15 @@ static struct i2c_adapter *sun4i_hdmi_get_ddc(struct device *dev)
}
static const struct drm_connector_hdmi_funcs sun4i_hdmi_hdmi_connector_funcs = {
+ /*
+ * NOTE: Those are likely to be wrong, but I couldn't find
+ * the actual ones in the BSP.
+ */
+ .vendor = "AW",
+ .product = "HDMI",
+ .supported_hdmi_ver = HDMI_VERSION_1_2,
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ .max_bpc = 8,
.tmds_char_rate_valid = sun4i_hdmi_connector_clock_valid,
.avi = {
.clear_infoframe = sun4i_hdmi_clear_avi_infoframe,
@@ -654,19 +659,11 @@ static int sun4i_hdmi_bind(struct device *dev, struct device *master,
drm_connector_helper_add(&hdmi->connector,
&sun4i_hdmi_connector_helper_funcs);
- ret = drmm_connector_hdmi_ini2(drm, &hdmi->connector,
- /*
- * NOTE: Those are likely to be
- * wrong, but I couldn't find the
- * actual ones in the BSP.
- */
- "AW", "HDMI",
+ ret = drmm_connector_hdmi_init(drm, &hdmi->connector,
&sun4i_hdmi_connector_funcs,
&sun4i_hdmi_hdmi_connector_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- hdmi->ddc_i2c,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
- 8);
+ hdmi->ddc_i2c);
if (ret) {
dev_err(dev,
"Couldn't initialise the HDMI connector\n");
diff --git a/drivers/gpu/drm/sysfb/drm_sysfb_helper.h b/drivers/gpu/drm/sysfb/drm_sysfb_helper.h
index c043428e02fd..6dab27b41c08 100644
--- a/drivers/gpu/drm/sysfb/drm_sysfb_helper.h
+++ b/drivers/gpu/drm/sysfb/drm_sysfb_helper.h
@@ -194,7 +194,7 @@ int drm_sysfb_connector_helper_get_modes(struct drm_connector *connector);
.get_modes = drm_sysfb_connector_helper_get_modes
#define DRM_SYSFB_CONNECTOR_FUNCS \
- .reset = drm_atomic_helper_connector_reset, \
+ .atomic_create_state = drm_atomic_helper_connector_create_state, \
.fill_modes = drm_helper_probe_single_connector_modes, \
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, \
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state
diff --git a/drivers/gpu/drm/tiny/appletbdrm.c b/drivers/gpu/drm/tiny/appletbdrm.c
index 4297d9c1125e..ebfe37557bfe 100644
--- a/drivers/gpu/drm/tiny/appletbdrm.c
+++ b/drivers/gpu/drm/tiny/appletbdrm.c
@@ -30,6 +30,7 @@
#include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_gem_shmem_helper.h>
+#include <drm/drm_modeset_helper.h>
#include <drm/drm_plane.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
@@ -589,7 +590,7 @@ static const struct drm_mode_config_funcs appletbdrm_mode_config_funcs = {
};
static const struct drm_connector_funcs appletbdrm_connector_funcs = {
- .reset = drm_atomic_helper_connector_reset,
+ .atomic_create_state = drm_atomic_helper_connector_create_state,
.destroy = drm_connector_cleanup,
.fill_modes = drm_helper_probe_single_connector_modes,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
@@ -724,7 +725,7 @@ static int appletbdrm_setup_mode_config(struct appletbdrm_device *adev)
ret = drm_connector_attach_encoder(connector, encoder);
if (ret) {
- drm_err(drm, "Failed to initialize simple display pipe\n");
+ drm_err(drm, "Failed to attach connector to encoder\n");
return ret;
}
@@ -821,6 +822,48 @@ static void appletbdrm_shutdown(struct usb_interface *intf)
drm_atomic_helper_shutdown(&adev->drm);
}
+static int appletbdrm_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct appletbdrm_device *adev = usb_get_intfdata(intf);
+
+ return drm_mode_config_helper_suspend(&adev->drm);
+}
+
+static int appletbdrm_resume(struct usb_interface *intf)
+{
+ struct appletbdrm_device *adev = usb_get_intfdata(intf);
+
+ return drm_mode_config_helper_resume(&adev->drm);
+}
+
+static int appletbdrm_reset_resume(struct usb_interface *intf)
+{
+ struct appletbdrm_device *adev = usb_get_intfdata(intf);
+ struct drm_device *drm = &adev->drm;
+ int ret, resume_ret;
+
+ /*
+ * A reset puts the device back into its initial state, where it
+ * expects the same handshake as during probe. Resume the DRM side
+ * even if the handshake fails, so that the state saved on suspend
+ * is released.
+ */
+ ret = appletbdrm_get_information(adev);
+ if (ret) {
+ drm_err(drm, "Failed to get display information\n");
+ goto resume;
+ }
+
+ ret = appletbdrm_signal_readiness(adev);
+ if (ret)
+ drm_err(drm, "Failed to signal readiness\n");
+
+resume:
+ resume_ret = drm_mode_config_helper_resume(drm);
+
+ return ret ? ret : resume_ret;
+}
+
static const struct usb_device_id appletbdrm_usb_id_table[] = {
{ USB_DEVICE_INTERFACE_CLASS(0x05ac, 0x8302, USB_CLASS_AUDIO_VIDEO) },
{}
@@ -832,6 +875,9 @@ static struct usb_driver appletbdrm_usb_driver = {
.probe = appletbdrm_probe,
.disconnect = appletbdrm_disconnect,
.shutdown = appletbdrm_shutdown,
+ .suspend = appletbdrm_suspend,
+ .resume = appletbdrm_resume,
+ .reset_resume = appletbdrm_reset_resume,
.id_table = appletbdrm_usb_id_table,
};
module_usb_driver(appletbdrm_usb_driver);
diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c
index bd0b23ac2cc4..f9458a4d5a09 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_util.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_util.c
@@ -356,6 +356,10 @@ static int ttm_bo_kmap_ttm(struct ttm_buffer_object *bo,
if (ret)
return ret;
+ /* Imported sg tables only come with DMA addresses, no pages to map. */
+ if (!ttm->pages)
+ return -EINVAL;
+
if (num_pages == 1 && ttm->caching == ttm_cached &&
!(man->use_tt && (ttm->page_flags & TTM_TT_FLAG_DECRYPTED))) {
/*
@@ -419,7 +423,7 @@ EXPORT_SYMBOL(ttm_bo_kmap_try_from_panic);
*
* Returns
* -ENOMEM: Out of memory.
- * -EINVAL: Invalid range.
+ * -EINVAL: Invalid range or the BO has no pages to map.
*/
int ttm_bo_kmap(struct ttm_buffer_object *bo,
unsigned long start_page, unsigned long num_pages,
@@ -493,7 +497,7 @@ EXPORT_SYMBOL(ttm_bo_kunmap);
*
* Returns
* -ENOMEM: Out of memory.
- * -EINVAL: Invalid range.
+ * -EINVAL: Invalid range or the BO has no pages to map.
*/
int ttm_bo_vmap(struct ttm_buffer_object *bo, struct iosys_map *map)
{
@@ -537,6 +541,9 @@ int ttm_bo_vmap(struct ttm_buffer_object *bo, struct iosys_map *map)
if (ret)
return ret;
+ if (!ttm->pages)
+ return -EINVAL;
+
/*
* We need to use vmap to get the desired page protection
* or to make the buffer object look contiguous.
diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock_output.c b/drivers/gpu/drm/vc4/tests/vc4_mock_output.c
index b53c3635ce67..54f952e4b1ac 100644
--- a/drivers/gpu/drm/vc4/tests/vc4_mock_output.c
+++ b/drivers/gpu/drm/vc4/tests/vc4_mock_output.c
@@ -17,7 +17,7 @@ static const struct drm_connector_helper_funcs vc4_dummy_connector_helper_funcs
static const struct drm_connector_funcs vc4_dummy_connector_funcs = {
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
- .reset = drm_atomic_helper_connector_reset,
+ .atomic_create_state = drm_atomic_helper_connector_create_state,
};
struct vc4_dummy_output *vc4_dummy_output(struct kunit *test,
diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c
index 49ea2ed0996b..320c5a0c71ed 100644
--- a/drivers/gpu/drm/vc4/vc4_bo.c
+++ b/drivers/gpu/drm/vc4/vc4_bo.c
@@ -303,7 +303,8 @@ static void vc4_bo_purge(struct drm_gem_object *obj)
drm_vma_node_unmap(&obj->vma_node, dev->anon_inode->i_mapping);
- dma_free_wc(dev->dev, obj->size, bo->base.vaddr, bo->base.dma_addr);
+ dma_free_wc(drm_dev_dma_dev(dev), obj->size, bo->base.vaddr,
+ bo->base.dma_addr);
bo->base.vaddr = NULL;
bo->madv = __VC4_MADV_PURGED;
}
diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c
index eb859c65a453..83a9443db98f 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.c
+++ b/drivers/gpu/drm/vc4/vc4_drv.c
@@ -24,10 +24,8 @@
#include <linux/clk.h>
#include <linux/component.h>
#include <linux/device.h>
-#include <linux/dma-mapping.h>
#include <linux/io.h>
#include <linux/module.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
@@ -273,15 +271,6 @@ static void vc4_component_unbind_all(void *ptr)
component_unbind_all(vc4->dev, &vc4->base);
}
-static const struct of_device_id vc4_dma_range_matches[] = {
- { .compatible = "brcm,bcm2711-hvs" },
- { .compatible = "brcm,bcm2712-hvs" },
- { .compatible = "brcm,bcm2835-hvs" },
- { .compatible = "brcm,bcm2835-v3d" },
- { .compatible = "brcm,cygnus-v3d" },
- {}
-};
-
static int vc4_drm_bind(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -294,8 +283,6 @@ static int vc4_drm_bind(struct device *dev)
enum vc4_gen gen;
int ret = 0;
- dev->coherent_dma_mask = DMA_BIT_MASK(32);
-
gen = (enum vc4_gen)of_device_get_match_data(dev);
if (gen > VC4_GEN_4)
@@ -303,21 +290,6 @@ static int vc4_drm_bind(struct device *dev)
else
driver = &vc4_drm_driver;
- if (gen >= VC4_GEN_6_C)
- dma_set_mask_and_coherent(dev, DMA_BIT_MASK(36));
- else
- dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
-
- node = of_find_matching_node_and_match(NULL, vc4_dma_range_matches,
- NULL);
- if (node) {
- ret = of_dma_configure(dev, node, true);
- of_node_put(node);
-
- if (ret)
- return ret;
- }
-
vc4 = devm_drm_dev_alloc(dev, driver, struct vc4_dev, base);
if (IS_ERR(vc4))
return PTR_ERR(vc4);
diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c
index e715147d091c..b1fb096858cc 100644
--- a/drivers/gpu/drm/vc4/vc4_hvs.c
+++ b/drivers/gpu/drm/vc4/vc4_hvs.c
@@ -22,6 +22,7 @@
#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/component.h>
+#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
#include <drm/drm_atomic_helper.h>
@@ -1662,6 +1663,15 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data)
hvs->regset.nregs = ARRAY_SIZE(vc4_hvs_regs);
}
+ if (vc4->gen >= VC4_GEN_6_C) {
+ ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(36));
+ if (ret)
+ return ret;
+ }
+
+ if (drm_dev_dma_dev(drm) == drm->dev)
+ drm_dev_set_dma_dev(drm, dev);
+
if (vc4->gen >= VC4_GEN_5) {
struct rpi_firmware *firmware;
struct device_node *node;
diff --git a/drivers/gpu/drm/vc4/vc4_txp.c b/drivers/gpu/drm/vc4/vc4_txp.c
index c469f8b1068b..642953cba25f 100644
--- a/drivers/gpu/drm/vc4/vc4_txp.c
+++ b/drivers/gpu/drm/vc4/vc4_txp.c
@@ -378,7 +378,7 @@ static const struct drm_connector_funcs vc4_txp_connector_funcs = {
.detect = vc4_txp_connector_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.destroy = drm_connector_cleanup,
- .reset = drm_atomic_helper_connector_reset,
+ .atomic_create_state = drm_atomic_helper_connector_create_state,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
diff --git a/drivers/gpu/drm/vc4/vc4_v3d.c b/drivers/gpu/drm/vc4/vc4_v3d.c
index b40d98c9d1d2..6b85053c77d6 100644
--- a/drivers/gpu/drm/vc4/vc4_v3d.c
+++ b/drivers/gpu/drm/vc4/vc4_v3d.c
@@ -423,6 +423,13 @@ static int vc4_v3d_bind(struct device *dev, struct device *master, void *data)
vc4->v3d = v3d;
v3d->vc4 = vc4;
+ /*
+ * In headless setups where HVS is absent, use V3D as the fallback
+ * DMA controller for buffer allocations.
+ */
+ if (drm_dev_dma_dev(drm) == drm->dev)
+ drm_dev_set_dma_dev(drm, dev);
+
v3d->clk = devm_clk_get_optional(dev, NULL);
if (IS_ERR(v3d->clk))
return dev_err_probe(dev, PTR_ERR(v3d->clk), "Failed to get V3D clock\n");
diff --git a/drivers/gpu/drm/virtio/virtgpu_plane.c b/drivers/gpu/drm/virtio/virtgpu_plane.c
index 10718bc73693..eef9ef42dffe 100644
--- a/drivers/gpu/drm/virtio/virtgpu_plane.c
+++ b/drivers/gpu/drm/virtio/virtgpu_plane.c
@@ -38,6 +38,7 @@
static const uint32_t virtio_gpu_formats[] = {
DRM_FORMAT_HOST_XRGB8888,
+ DRM_FORMAT_HOST_ARGB8888,
};
static const uint32_t virtio_gpu_cursor_formats[] = {
diff --git a/include/drm/bridge/dw_hdmi_qp.h b/include/drm/bridge/dw_hdmi_qp.h
index 6ea9c561cfef..ad33f9cafdeb 100644
--- a/include/drm/bridge/dw_hdmi_qp.h
+++ b/include/drm/bridge/dw_hdmi_qp.h
@@ -16,7 +16,8 @@ struct dw_hdmi_qp_phy_ops {
int (*init)(struct dw_hdmi_qp *hdmi, void *data);
void (*disable)(struct dw_hdmi_qp *hdmi, void *data);
enum drm_connector_status (*read_hpd)(struct dw_hdmi_qp *hdmi, void *data);
- void (*setup_hpd)(struct dw_hdmi_qp *hdmi, void *data);
+ void (*enable_hpd)(struct dw_hdmi_qp *hdmi, void *data);
+ void (*disable_hpd)(struct dw_hdmi_qp *hdmi, void *data);
};
struct dw_hdmi_qp_plat_data {
@@ -34,6 +35,7 @@ struct dw_hdmi_qp_plat_data {
struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev,
struct drm_encoder *encoder,
const struct dw_hdmi_qp_plat_data *plat_data);
+void dw_hdmi_qp_hpd_notify(struct dw_hdmi_qp *hdmi);
void dw_hdmi_qp_suspend(struct device *dev, struct dw_hdmi_qp *hdmi);
void dw_hdmi_qp_resume(struct device *dev, struct dw_hdmi_qp *hdmi);
#endif /* __DW_HDMI_QP__ */
diff --git a/include/drm/gpu_scheduler.h b/include/drm/gpu_scheduler.h
index 563d7fb88a6d..3b0978fa8cf0 100644
--- a/include/drm/gpu_scheduler.h
+++ b/include/drm/gpu_scheduler.h
@@ -101,7 +101,7 @@ struct drm_sched_entity {
*
* Lock protecting the run-queue (@rq) to which this entity belongs,
* @priority, @last_scheduled and the list of schedulers (@sched_list,
- * @num_sched_list) and @rr_ts.
+ * @num_sched_list), @rr_ts and @stopped.
*/
spinlock_t lock;
diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h
index a103fdc0b3a3..0bb049f91524 100644
--- a/include/uapi/drm/drm_fourcc.h
+++ b/include/uapi/drm/drm_fourcc.h
@@ -1627,6 +1627,30 @@ drm_fourcc_canonicalize_nvidia_format_mod(__u64 modifier)
#define DRM_FORMAT_MOD_APPLE_GPU_TILED_COMPRESSED fourcc_mod_code(APPLE, 2)
/*
+ * Apple Interchange layout
+ *
+ * Apple Interchange is a compressed framebuffer format used exclusively for
+ * sharing buffers between hardware blocks (GPU, display controller, video
+ * codecs) on Apple platforms. It is similar to and uses the same compression
+ * scheme as GPU_TILED_COMPRESSED. There is no known uncompressed variant
+ * of Apple Interchange.
+ *
+ * Unlike the GPU layouts, tile size is not dependent on bit depth. RGB
+ * images and the chroma components of YUV images use 16x16 tiles. The
+ * luma component of YUV images uses 32x32 tiles. Compression tiles
+ * are once again 16x16 with 8 bytes of metadata per compression subtile.
+ *
+ * Following the example set by GPU_TILED_{,COMPRESSED}, Interchange images
+ * are treated as a single plane by software and do not have a meaningful
+ * stride.
+ *
+ * AGX has limited support for Apple Interchange. It cannot be used for Z/S
+ * buffers or array images, for example. It is intended for scanout buffer
+ * sharing only.
+ */
+#define DRM_FORMAT_MOD_APPLE_INTERCHANGE fourcc_mod_code(APPLE, 3)
+
+/*
* AMD modifiers
*
* Memory layout:
diff --git a/include/uapi/drm/panfrost_drm.h b/include/uapi/drm/panfrost_drm.h
index 50d5337f35ef..7831c48c59c0 100644
--- a/include/uapi/drm/panfrost_drm.h
+++ b/include/uapi/drm/panfrost_drm.h
@@ -47,7 +47,7 @@ extern "C" {
* them for anything but debugging purpose.
*/
#define DRM_IOCTL_PANFROST_PERFCNT_ENABLE DRM_IOW(DRM_COMMAND_BASE + DRM_PANFROST_PERFCNT_ENABLE, struct drm_panfrost_perfcnt_enable)
-#define DRM_IOCTL_PANFROST_PERFCNT_DUMP DRM_IOW(DRM_COMMAND_BASE + DRM_PANFROST_PERFCNT_DUMP, struct drm_panfrost_perfcnt_dump)
+#define DRM_IOCTL_PANFROST_PERFCNT_DUMP DRM_IOWR(DRM_COMMAND_BASE + DRM_PANFROST_PERFCNT_DUMP, struct drm_panfrost_perfcnt_dump)
#define PANFROST_JD_REQ_FS (1 << 0)
#define PANFROST_JD_REQ_CYCLE_COUNT (1 << 1)
@@ -270,8 +270,35 @@ struct drm_panfrost_perfcnt_enable {
__u32 counterset;
};
+/*
+ * The next two flags describe the state of a perfcnt dump request
+ * as influenced by a device reset. They are the only values the
+ * perfcnt_dump ioctl state field can take on.
+ * Only certain state and ioctl retval combinations are legitimate.
+ */
+
+/* A new perfcnt_enable ioctl should be issued before requesting
+ * more dumps, because a HW reset failed to recreate perfcnt's
+ * original state. Otherwise further perfcnt_dump's will fail.
+ * This flag being set means ioctl's retval is always -EIO.
+ */
+#define PANFROST_PERFCNT_SESSION_DEAD (1 << 0)
+
+/* A HW reset happened before or during a sample request, and
+ * perfcnt's internal state was successfully restored. There
+ * are two possible outcomes depending on the ioctl's retval:
+ * 0: A reset happened before a dump was requested, but did
+ * nonetheless succeed. Counter values are relative to last reset.
+ * -EAGAIN: A reset happened when a counter values sampling
+ * request was ongoing. Values are undefined so a new dump ioctl
+ * should be issued.
+ */
+#define PANFROST_PERFCNT_SESSION_INTERRUPTED_BY_RESET (1 << 1)
+
struct drm_panfrost_perfcnt_dump {
__u64 buf_ptr;
+ __u32 state;
+ __u32 pad; /* MBZ */
};
/* madvise provides a way to tell the kernel in case a buffers contents