summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2026-05-08 14:14:24 +1000
committerDave Airlie <airlied@redhat.com>2026-05-08 14:16:04 +1000
commitf96538285cfdbb3acf5e3356e0bb88c38815790b (patch)
treec3042402dac03417cb32cca85ad67f56de7e50cd
parentbc0400e6f41cbc43a5eaa5ed1c7749da7af7eb1d (diff)
parent921578cf373981eba92774a27f7644a11282cf89 (diff)
Merge tag 'drm-misc-next-2026-05-07' of https://gitlab.freedesktop.org/drm/misc/kernel into drm-next
drm-misc-next for v7.2-rc1: UAPI Changes: - Support medium/low power modes in amdxdna. - Support limiting frequency in ivpu. - Document license for drm core uAPI headers. - Add the following DRM formats: P230, Y7, XYYY2101010, T430, XVUY210101010. Cross-subsystem Changes: - Add and improve dt-bindings. - Remove unused dma-fence-array's signal_on_any support. Core Changes: - Do not call drop_master on file close if not master. - Convert drm-bridge and drm/atomic to use drm_printf_indent. - Remove the extra call to drm_connector_attach_encoder after drm_bridge_connector_init(). - Assorted docbook updates. Driver Changes: - Bugfixes in amdxdna, ivpu, mipi-dsi, imagination, nouveau, panthor, bridge/analogix_dp, ipv3, lontium-lt8912b, verisilicon, tve200, etnaviv, panel/focaltech-ota7290b, panel/jadard-jd9365da-h3, bridge/ite-it6263, renesas, xlnx, bridge/cdns-dsi, gma500, bridge/microchip-lvds, mgag200. - Add support for MStar TSUMU88ADT3-LF-1 bridge. - Add support for WaveShare 7, Novatek NT35532, Startek KD070HDFLD092, ChipWealth CH13726A AMOLED, Team Source Display TST070WSNE-196C, Displaytech DT050BTFT-PTS panels. - Improve mipi-dsi shutdown and convert a panasonic panel to use the mipi-dsi wrappers. - Allowing dumping vbios over debugfs in GSP-RM mode. - Update maintainers for ivpu, add reviewer for drm-bridge code and update maintainers for LT8912B DRM HDMI bridge. - Add test pattern support to bridge/ti-sn65dsi83. - Convert vmwgfx to vblank timers. - Add power management to sysfb drm drivers to allow suspend/resume. - Support the aforementioned new drm formats in xlnx/qynqmp. - Fix panel Kconfig dependencies. - Add carveout support for debugging and bringup to amxdna. - Add support for long command tx via videobuffer in bridge/tc358768. Signed-off-by: Dave Airlie <airlied@redhat.com> From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Link: https://patch.msgid.link/f73f342d-6efb-416d-81b0-1716bdd98d5f@linux.intel.com
-rw-r--r--Documentation/ABI/obsolete/sysfs-driver-ivpu30
-rw-r--r--Documentation/ABI/testing/sysfs-driver-ivpu65
-rw-r--r--Documentation/devicetree/bindings/display/bridge/lvds-codec.yaml1
-rw-r--r--Documentation/devicetree/bindings/display/bridge/simple-bridge.yaml1
-rw-r--r--Documentation/devicetree/bindings/display/panel/chipwealth,ch13726a.yaml67
-rw-r--r--Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml2
-rw-r--r--Documentation/devicetree/bindings/display/panel/novatek,nt35532.yaml80
-rw-r--r--Documentation/devicetree/bindings/display/panel/panel-simple-dsi.yaml2
-rw-r--r--Documentation/devicetree/bindings/display/panel/panel-simple.yaml4
-rw-r--r--Documentation/devicetree/bindings/vendor-prefixes.yaml2
-rw-r--r--Documentation/gpu/drm-uapi.rst4
-rw-r--r--MAINTAINERS13
-rw-r--r--drivers/accel/amdxdna/Makefile2
-rw-r--r--drivers/accel/amdxdna/aie2_ctx.c48
-rw-r--r--drivers/accel/amdxdna/aie2_pci.c3
-rw-r--r--drivers/accel/amdxdna/aie2_pci.h1
-rw-r--r--drivers/accel/amdxdna/aie2_pm.c10
-rw-r--r--drivers/accel/amdxdna/aie2_solver.c10
-rw-r--r--drivers/accel/amdxdna/amdxdna_cbuf.c280
-rw-r--r--drivers/accel/amdxdna/amdxdna_cbuf.h18
-rw-r--r--drivers/accel/amdxdna/amdxdna_ctx.c3
-rw-r--r--drivers/accel/amdxdna/amdxdna_ctx.h1
-rw-r--r--drivers/accel/amdxdna/amdxdna_debugfs.c129
-rw-r--r--drivers/accel/amdxdna/amdxdna_debugfs.h18
-rw-r--r--drivers/accel/amdxdna/amdxdna_gem.c95
-rw-r--r--drivers/accel/amdxdna/amdxdna_iommu.c77
-rw-r--r--drivers/accel/amdxdna/amdxdna_mailbox.c1
-rw-r--r--drivers/accel/amdxdna/amdxdna_pci_drv.c89
-rw-r--r--drivers/accel/amdxdna/amdxdna_pci_drv.h8
-rw-r--r--drivers/accel/amdxdna/npu1_regs.c1
-rw-r--r--drivers/accel/amdxdna/npu4_regs.c1
-rw-r--r--drivers/accel/amdxdna/npu5_regs.c1
-rw-r--r--drivers/accel/amdxdna/npu6_regs.c1
-rw-r--r--drivers/accel/ivpu/ivpu_drv.c8
-rw-r--r--drivers/accel/ivpu/ivpu_hw.h16
-rw-r--r--drivers/accel/ivpu/ivpu_hw_btrs.c112
-rw-r--r--drivers/accel/ivpu/ivpu_hw_btrs.h10
-rw-r--r--drivers/accel/ivpu/ivpu_hw_ip.c16
-rw-r--r--drivers/accel/ivpu/ivpu_jsm_msg.c18
-rw-r--r--drivers/accel/ivpu/ivpu_jsm_msg.h3
-rw-r--r--drivers/accel/ivpu/ivpu_sysfs.c186
-rw-r--r--drivers/accel/ivpu/vpu_jsm_api.h34
-rw-r--r--drivers/dma-buf/dma-fence-array.c13
-rw-r--r--drivers/dma-buf/dma-fence-unwrap.c3
-rw-r--r--drivers/dma-buf/dma-resv.c3
-rw-r--r--drivers/dma-buf/st-dma-fence-unwrap.c2
-rw-r--r--drivers/gpu/drm/adp/adp_drv.c2
-rw-r--r--drivers/gpu/drm/bridge/adv7511/adv7511_drv.c2
-rw-r--r--drivers/gpu/drm/bridge/analogix/analogix_dp_core.c2
-rw-r--r--drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c11
-rw-r--r--drivers/gpu/drm/bridge/ite-it6263.c29
-rw-r--r--drivers/gpu/drm/bridge/ite-it6505.c2
-rw-r--r--drivers/gpu/drm/bridge/lontium-lt8912b.c1
-rw-r--r--drivers/gpu/drm/bridge/microchip-lvds.c63
-rw-r--r--drivers/gpu/drm/bridge/simple-bridge.c5
-rw-r--r--drivers/gpu/drm/bridge/tc358768.c202
-rw-r--r--drivers/gpu/drm/bridge/ti-sn65dsi83.c14
-rw-r--r--drivers/gpu/drm/bridge/ti-sn65dsi86.c2
-rw-r--r--drivers/gpu/drm/bridge/ti-tfp410.c2
-rw-r--r--drivers/gpu/drm/display/drm_bridge_connector.c11
-rw-r--r--drivers/gpu/drm/drm_atomic.c110
-rw-r--r--drivers/gpu/drm/drm_auth.c2
-rw-r--r--drivers/gpu/drm/drm_bridge.c13
-rw-r--r--drivers/gpu/drm/drm_fourcc.c25
-rw-r--r--drivers/gpu/drm/drm_mipi_dsi.c28
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_drv.h12
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c3
-rw-r--r--drivers/gpu/drm/exynos/exynos_dp.c2
-rw-r--r--drivers/gpu/drm/gma500/psb_drv.c1
-rw-r--r--drivers/gpu/drm/hyperv/hyperv_drm_proto.c2
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c3
-rw-r--r--drivers/gpu/drm/imagination/pvr_fw_trace.c2
-rw-r--r--drivers/gpu/drm/imx/dc/dc-kms.c8
-rw-r--r--drivers/gpu/drm/imx/dcss/dcss-kms.c2
-rw-r--r--drivers/gpu/drm/imx/ipuv3/Kconfig2
-rw-r--r--drivers/gpu/drm/imx/ipuv3/imx-ldb.c2
-rw-r--r--drivers/gpu/drm/imx/ipuv3/parallel-display.c2
-rw-r--r--drivers/gpu/drm/imx/lcdc/imx-lcdc.c2
-rw-r--r--drivers/gpu/drm/ingenic/ingenic-drm-drv.c2
-rw-r--r--drivers/gpu/drm/kmb/kmb_dsi.c2
-rw-r--r--drivers/gpu/drm/mediatek/mtk_dpi.c1
-rw-r--r--drivers/gpu/drm/mediatek/mtk_dsi.c1
-rw-r--r--drivers/gpu/drm/meson/meson_encoder_cvbs.c2
-rw-r--r--drivers/gpu/drm/meson/meson_encoder_hdmi.c2
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_drv.c1
-rw-r--r--drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c7
-rw-r--r--drivers/gpu/drm/msm/dp/dp_drm.c2
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi_manager.c4
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi.c2
-rw-r--r--drivers/gpu/drm/mxsfb/lcdif_drv.c6
-rw-r--r--drivers/gpu/drm/nouveau/dispnv50/disp.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bios.c21
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drm.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_sched.c3
-rw-r--r--drivers/gpu/drm/omapdrm/omap_drv.c2
-rw-r--r--drivers/gpu/drm/panel/Kconfig45
-rw-r--r--drivers/gpu/drm/panel/Makefile2
-rw-r--r--drivers/gpu/drm/panel/panel-chipwealth-ch13726a.c333
-rw-r--r--drivers/gpu/drm/panel/panel-focaltech-ota7290b.c4
-rw-r--r--drivers/gpu/drm/panel/panel-ilitek-ili9881c.c251
-rw-r--r--drivers/gpu/drm/panel/panel-jadard-jd9365da-h3.c8
-rw-r--r--drivers/gpu/drm/panel/panel-novatek-nt35532.c796
-rw-r--r--drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c24
-rw-r--r--drivers/gpu/drm/panel/panel-simple.c101
-rw-r--r--drivers/gpu/drm/panthor/panthor_device.c28
-rw-r--r--drivers/gpu/drm/panthor/panthor_device.h92
-rw-r--r--drivers/gpu/drm/panthor/panthor_drv.c8
-rw-r--r--drivers/gpu/drm/panthor/panthor_drv.h2
-rw-r--r--drivers/gpu/drm/panthor/panthor_fw.c40
-rw-r--r--drivers/gpu/drm/panthor/panthor_fw.h1
-rw-r--r--drivers/gpu/drm/panthor/panthor_fw_regs.h29
-rw-r--r--drivers/gpu/drm/panthor/panthor_gpu.c101
-rw-r--r--drivers/gpu/drm/panthor/panthor_gpu.h6
-rw-r--r--drivers/gpu/drm/panthor/panthor_gpu_regs.h119
-rw-r--r--drivers/gpu/drm/panthor/panthor_heap.c2
-rw-r--r--drivers/gpu/drm/panthor/panthor_hw.c54
-rw-r--r--drivers/gpu/drm/panthor/panthor_hw.h2
-rw-r--r--drivers/gpu/drm/panthor/panthor_mmu.c46
-rw-r--r--drivers/gpu/drm/panthor/panthor_mmu_regs.h69
-rw-r--r--drivers/gpu/drm/panthor/panthor_pwr.c93
-rw-r--r--drivers/gpu/drm/panthor/panthor_pwr_regs.h79
-rw-r--r--drivers/gpu/drm/panthor/panthor_regs.h291
-rw-r--r--drivers/gpu/drm/panthor/panthor_sched.c5
-rw-r--r--drivers/gpu/drm/renesas/rcar-du/rcar_du_encoder.c2
-rw-r--r--drivers/gpu/drm/renesas/rz-du/rzg2l_du_encoder.c2
-rw-r--r--drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c12
-rw-r--r--drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c16
-rw-r--r--drivers/gpu/drm/rockchip/analogix_dp-rockchip.c2
-rw-r--r--drivers/gpu/drm/rockchip/cdn-dp-core.c2
-rw-r--r--drivers/gpu/drm/rockchip/dw_dp-rockchip.c2
-rw-r--r--drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c2
-rw-r--r--drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c2
-rw-r--r--drivers/gpu/drm/rockchip/rk3066_hdmi.c2
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_lvds.c6
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_rgb.c9
-rw-r--r--drivers/gpu/drm/sysfb/corebootdrm.c21
-rw-r--r--drivers/gpu/drm/sysfb/efidrm.c19
-rw-r--r--drivers/gpu/drm/sysfb/ofdrm.c19
-rw-r--r--drivers/gpu/drm/sysfb/simpledrm.c21
-rw-r--r--drivers/gpu/drm/sysfb/vesadrm.c19
-rw-r--r--drivers/gpu/drm/tegra/hdmi.c2
-rw-r--r--drivers/gpu/drm/tegra/rgb.c2
-rw-r--r--drivers/gpu/drm/tests/drm_bridge_test.c2
-rw-r--r--drivers/gpu/drm/tidss/tidss_encoder.c6
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_encoder.c6
-rw-r--r--drivers/gpu/drm/tve200/tve200_drv.c6
-rw-r--r--drivers/gpu/drm/verisilicon/vs_bridge.c1
-rw-r--r--drivers/gpu/drm/verisilicon/vs_plane.c54
-rw-r--r--drivers/gpu/drm/verisilicon/vs_plane.h18
-rw-r--r--drivers/gpu/drm/verisilicon/vs_primary_plane.c48
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.h2
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c1
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c1
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c1
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c70
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_vkms.h2
-rw-r--r--drivers/gpu/drm/xe/xe_sync.c2
-rw-r--r--drivers/gpu/drm/xe/xe_vm.c2
-rw-r--r--drivers/gpu/drm/xlnx/Kconfig4
-rw-r--r--drivers/gpu/drm/xlnx/zynqmp_disp.c56
-rw-r--r--drivers/gpu/drm/xlnx/zynqmp_kms.c6
-rw-r--r--include/drm/drm_debugfs_crc.h2
-rw-r--r--include/drm/drm_gpusvm.h7
-rw-r--r--include/drm/drm_mipi_dsi.h1
-rw-r--r--include/linux/dma-fence-array.h6
-rw-r--r--include/trace/events/amdxdna.h42
-rw-r--r--include/uapi/drm/drm.h20
-rw-r--r--include/uapi/drm/drm_fourcc.h48
-rw-r--r--include/uapi/drm/drm_mode.h19
-rw-r--r--include/uapi/drm/drm_sarea.h20
170 files changed, 4176 insertions, 1193 deletions
diff --git a/Documentation/ABI/obsolete/sysfs-driver-ivpu b/Documentation/ABI/obsolete/sysfs-driver-ivpu
new file mode 100644
index 000000000000..b906e7149729
--- /dev/null
+++ b/Documentation/ABI/obsolete/sysfs-driver-ivpu
@@ -0,0 +1,30 @@
+What: /sys/bus/pci/drivers/intel_vpu/.../sched_mode
+Date: October 2024
+KernelVersion: 6.12
+Contact: dri-devel@lists.freedesktop.org
+Description: Current NPU scheduling mode. Returns one of the following strings:
+ - "HW" - Hardware Scheduler mode
+ - "OS" - Operating System Scheduler mode
+ Read-only.
+ Deprecated since the "OS" scheduling mode is not usable
+ and will be removed from future versions of the driver.
+ Will be removed in 2027
+
+What: /sys/bus/pci/drivers/intel_vpu/.../npu_max_frequency_mhz
+Date: April 2025
+KernelVersion: 6.15
+Contact: dri-devel@lists.freedesktop.org
+Description: Legacy alias for /sys/bus/pci/drivers/intel_vpu/.../freq/hw_max_freq.
+ Shows maximum frequency in MHz of the NPU's data processing unit.
+ Read-only.
+ Will be removed in 2027
+
+What: /sys/bus/pci/drivers/intel_vpu/.../npu_current_frequency_mhz
+Date: April 2025
+KernelVersion: 6.15
+Contact: dri-devel@lists.freedesktop.org
+Description: Legacy alias for /sys/bus/pci/drivers/intel_vpu/.../freq/current_freq.
+ Shows current frequency in MHz of the NPU's data processing unit.
+ The value is read only when the device is active; otherwise it returns 0.
+ Read-only.
+ Will be removed in 2027
diff --git a/Documentation/ABI/testing/sysfs-driver-ivpu b/Documentation/ABI/testing/sysfs-driver-ivpu
new file mode 100644
index 000000000000..91685774edfc
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-ivpu
@@ -0,0 +1,65 @@
+What: /sys/bus/pci/drivers/intel_vpu/.../npu_busy_time_us
+Date: May 2024
+KernelVersion: 6.11
+Contact: dri-devel@lists.freedesktop.org
+Description: Time in microseconds that the device spent executing jobs. The time is
+ counted when and only when there are jobs submitted to firmware. This time
+ can be used to measure the utilization of NPU, either by calculating the
+ difference between two timepoints or monitoring utilization percentage by
+ reading periodically. Recommended read period is 1 second to avoid impact
+ on job submission performance. Read-only.
+
+What: /sys/bus/pci/drivers/intel_vpu/.../npu_memory_utilization
+Date: Jan 2025
+KernelVersion: 6.15
+Contact: dri-devel@lists.freedesktop.org
+Description: Current NPU memory utilization in bytes. Reports the total size of all
+ resident buffer objects allocated for NPU use. Read-only.
+
+What: /sys/bus/pci/drivers/intel_vpu/.../freq/hw_min_freq
+Date: April 2026
+KernelVersion: 7.2
+Contact: dri-devel@lists.freedesktop.org
+Description: Minimum frequency in MHz supported by the NPU hardware. This is a
+ hardware capability and cannot be changed. Read-only.
+
+What: /sys/bus/pci/drivers/intel_vpu/.../freq/hw_efficient_freq
+Date: April 2026
+KernelVersion: 7.2
+Contact: dri-devel@lists.freedesktop.org
+Description: Most efficient operating frequency in MHz for the NPU. This represents
+ the frequency at which the NPU operates most efficiently in terms of power
+ and performance. Read-only.
+
+What: /sys/bus/pci/drivers/intel_vpu/.../freq/hw_max_freq
+Date: April 2026
+KernelVersion: 7.2
+Contact: dri-devel@lists.freedesktop.org
+Description: Maximum frequency in MHz supported by the NPU hardware. This is a
+ hardware capability and cannot be changed. Read-only.
+
+What: /sys/bus/pci/drivers/intel_vpu/.../freq/current_freq
+Date: April 2026
+KernelVersion: 7.2
+Contact: dri-devel@lists.freedesktop.org
+Description: Current operating frequency in MHz of the NPU. The value is valid only
+ when the device is active; returns 0 when idle. The actual frequency may
+ be lower than the requested range due to power or thermal constraints.
+ Read-only.
+
+What: /sys/bus/pci/drivers/intel_vpu/.../freq/set_min_freq
+Date: April 2026
+KernelVersion: 7.2
+Contact: dri-devel@lists.freedesktop.org
+Description: Configured minimum operating frequency in MHz (50XX devices and newer).
+ Values written are clamped to hardware limits (hw_min_freq to hw_max_freq).
+ If set_min_freq exceeds set_max_freq, the driver clamps set_min_freq to
+ set_max_freq when selecting the operating frequency. Read-write.
+
+What: /sys/bus/pci/drivers/intel_vpu/.../freq/set_max_freq
+Date: April 2026
+KernelVersion: 7.2
+Contact: dri-devel@lists.freedesktop.org
+Description: Configured maximum operating frequency in MHz (50XX devices and newer).
+ Values written are clamped to hardware limits (hw_min_freq to hw_max_freq).
+ Read-write.
diff --git a/Documentation/devicetree/bindings/display/bridge/lvds-codec.yaml b/Documentation/devicetree/bindings/display/bridge/lvds-codec.yaml
index 7586d681bcc6..0363201f0e61 100644
--- a/Documentation/devicetree/bindings/display/bridge/lvds-codec.yaml
+++ b/Documentation/devicetree/bindings/display/bridge/lvds-codec.yaml
@@ -34,6 +34,7 @@ properties:
- items:
- enum:
- doestek,dtc34lm85am # For the Doestek DTC34LM85AM Flat Panel Display (FPD) Transmitter
+ - idt,v103 # For the Triple 10-BIT LVDS Transmitter
- onnn,fin3385 # OnSemi FIN3385
- ti,ds90c185 # For the TI DS90C185 FPD-Link Serializer
- ti,ds90c187 # For the TI DS90C187 FPD-Link Serializer
diff --git a/Documentation/devicetree/bindings/display/bridge/simple-bridge.yaml b/Documentation/devicetree/bindings/display/bridge/simple-bridge.yaml
index e6808419f625..7636c24906ba 100644
--- a/Documentation/devicetree/bindings/display/bridge/simple-bridge.yaml
+++ b/Documentation/devicetree/bindings/display/bridge/simple-bridge.yaml
@@ -30,6 +30,7 @@ properties:
- algoltek,ag6311
- asl-tek,cs5263
- dumb-vga-dac
+ - mstar,tsumu88adt3-lf-1
- parade,ps185hdm
- radxa,ra620
- realtek,rtd2171
diff --git a/Documentation/devicetree/bindings/display/panel/chipwealth,ch13726a.yaml b/Documentation/devicetree/bindings/display/panel/chipwealth,ch13726a.yaml
new file mode 100644
index 000000000000..c8d7b61037e6
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/chipwealth,ch13726a.yaml
@@ -0,0 +1,67 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/panel/chipwealth,ch13726a.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Chip Wealth Technology CH13726A AMOLED driver
+
+maintainers:
+ - Neil Armstrong <neil.armstrong@linaro.org>
+
+description:
+ Chip Wealth Technology CH13726A is a single-chip solution
+ for AMOLED connected using a MIPI-DSI video interface.
+
+allOf:
+ - $ref: panel-common.yaml#
+
+properties:
+ compatible:
+ items:
+ - const: ayntec,thor-panel-bottom
+ - const: chipwealth,ch13726a
+
+ reg:
+ maxItems: 1
+ description: DSI virtual channel
+
+ vdd-supply: true
+ vddio-supply: true
+ vdd1v2-supply: true
+ avdd-supply: true
+
+ port: true
+ reset-gpios: true
+ rotation: true
+
+required:
+ - compatible
+ - reg
+ - vdd-supply
+ - vddio-supply
+ - vdd1v2-supply
+ - avdd-supply
+ - reset-gpios
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ dsi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ panel@0 {
+ compatible = "ayntec,thor-panel-bottom", "chipwealth,ch13726a";
+ reg = <0>;
+ vdd1v2-supply = <&vreg_l11b_1p2>;
+ vddio-supply = <&vdd_disp_1v8>;
+ vdd-supply = <&vreg_l13b_3p0>;
+ avdd-supply = <&vdd_disp2_2v8>;
+ reset-gpios = <&tlmm 133 GPIO_ACTIVE_HIGH>;
+ };
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml b/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml
index d979701a00a8..42e35986fbf6 100644
--- a/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml
+++ b/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml
@@ -24,6 +24,7 @@ properties:
- raspberrypi,dsi-7inch
- startek,kd050hdfia020
- tdo,tl050hdv35
+ - waveshare,7.0-dsi-touch-a
- wanchanglong,w552946aaa
- wanchanglong,w552946aba
- const: ilitek,ili9881c
@@ -34,6 +35,7 @@ properties:
backlight: true
port: true
power-supply: true
+ iovcc-supply: true
reset-gpios: true
rotation: true
diff --git a/Documentation/devicetree/bindings/display/panel/novatek,nt35532.yaml b/Documentation/devicetree/bindings/display/panel/novatek,nt35532.yaml
new file mode 100644
index 000000000000..ff6fdad7febf
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/novatek,nt35532.yaml
@@ -0,0 +1,80 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/panel/novatek,nt35532.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Novatek NT35532-based DSI display panels
+
+maintainers:
+ - Cristian Cozzolino <cristian_ci@protonmail.com>
+
+allOf:
+ - $ref: panel-common.yaml#
+
+properties:
+ compatible:
+ items:
+ - enum:
+ - flipkart,rimob-panel-nt35532-cs
+ - const: novatek,nt35532
+
+ reg:
+ maxItems: 1
+
+ backlight: true
+ reset-gpios: true
+
+ avdd-supply:
+ description: positive boost supply regulator
+
+ avee-supply:
+ description: negative boost supply regulator
+
+ vci-supply:
+ description: regulator that supplies the analog voltage
+
+ vddam-supply:
+ description: power supply for MIPI interface
+
+ vddi-supply:
+ description: regulator that supplies the I/O voltage
+
+ port: true
+
+required:
+ - compatible
+ - reg
+ - reset-gpios
+ - vddi-supply
+ - port
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ dsi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ panel@0 {
+ compatible = "flipkart,rimob-panel-nt35532-cs", "novatek,nt35532";
+ reg = <0>;
+
+ backlight = <&pmi8950_wled>;
+ reset-gpios = <&tlmm 61 GPIO_ACTIVE_LOW>;
+ avdd-supply = <&lab>;
+ avee-supply = <&ibb>;
+ vci-supply = <&pm8953_l17>;
+ vddi-supply = <&pm8953_l6>;
+
+ port {
+ panel_in: endpoint {
+ remote-endpoint = <&dsi0_out>;
+ };
+ };
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/display/panel/panel-simple-dsi.yaml b/Documentation/devicetree/bindings/display/panel/panel-simple-dsi.yaml
index cc8d795df732..6d4133b91e7c 100644
--- a/Documentation/devicetree/bindings/display/panel/panel-simple-dsi.yaml
+++ b/Documentation/devicetree/bindings/display/panel/panel-simple-dsi.yaml
@@ -63,6 +63,8 @@ properties:
- samsung,s6e3fa7-ams559nk06
# Shangai Top Display Optoelectronics 7" TL070WSH30 1024x600 TFT LCD panel
- tdo,tl070wsh30
+ # Team Source Display Technology 7" TST070WSBE-196C 1024x600 TFT LCD panel
+ - team-source-display,tst070wsbe-196c
reg:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml
index 6e83e03d7456..44ec7388d851 100644
--- a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml
+++ b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml
@@ -97,6 +97,8 @@ properties:
- dataimage,fg1001l0dsswmg01
# DataImage, Inc. 7" WVGA (800x480) TFT LCD panel with 24-bit parallel interface.
- dataimage,scf0700c48ggu18
+ # Displaytech DT050BTFT-PTS 5.0" 800x480 TFT LCD Panel
+ - displaytech,dt050btft-pts
# DLC Display Co. DLC1010GIG 10.1" WXGA TFT LCD Panel
- dlc,dlc1010gig
# Emerging Display Technology Corp. 3.5" QVGA TFT LCD panel
@@ -304,6 +306,8 @@ properties:
- shelly,sca07010-bfn-lnn
# Starry KR070PE2T 7" WVGA TFT LCD panel
- starry,kr070pe2t
+ # Startek KD070HDFLD092 7" WSVGA TFT LCD panel
+ - startek,kd070hdfld092
# Startek KD070WVFPA043-C069A 7" TFT LCD panel
- startek,kd070wvfpa
# Team Source Display Technology TST043015CMHX 4.3" WQVGA TFT LCD panel
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index 28784d66ae7b..11c55b5df0e4 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -437,6 +437,8 @@ patternProperties:
description: Diodes, Inc.
"^dioo,.*":
description: Dioo Microcircuit Co., Ltd
+ "^displaytech,.*":
+ description: Displaytech Ltd.
"^djn,.*":
description: Shenzhen DJN Optronics Technology Co., Ltd
"^dlc,.*":
diff --git a/Documentation/gpu/drm-uapi.rst b/Documentation/gpu/drm-uapi.rst
index 579e87cb9ff7..32206ce62931 100644
--- a/Documentation/gpu/drm-uapi.rst
+++ b/Documentation/gpu/drm-uapi.rst
@@ -118,6 +118,10 @@ is already rather painful for the DRM subsystem, with multiple different uAPIs
for the same thing co-existing. If we add a few more complete mistakes into the
mix every year it would be entirely unmanageable.
+The DRM subsystem has however no concern with independent closed-source
+userspace implementations. To officialize that position, the DRM uAPI headers
+are covered by the MIT license.
+
.. _drm_render_node:
Render nodes
diff --git a/MAINTAINERS b/MAINTAINERS
index 882214b0e7db..2e8d160babc2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -7835,11 +7835,13 @@ F: drivers/soc/ti/smartreflex.c
F: include/linux/power/smartreflex.h
DRM ACCEL DRIVERS FOR INTEL VPU
-M: Maciej Falkowski <maciej.falkowski@linux.intel.com>
M: Karol Wachowski <karol.wachowski@linux.intel.com>
+M: Andrzej Kacprowski <andrzej.kacprowski@linux.intel.com>
L: dri-devel@lists.freedesktop.org
S: Supported
T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
+F: Documentation/ABI/obsolete/sysfs-driver-ivpu
+F: Documentation/ABI/testing/sysfs-driver-ivpu
F: drivers/accel/ivpu/
F: include/uapi/drm/ivpu_accel.h
@@ -8148,6 +8150,12 @@ T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
F: Documentation/devicetree/bindings/display/panel/novatek,nt35510.yaml
F: drivers/gpu/drm/panel/panel-novatek-nt35510.c
+DRM DRIVER FOR NOVATEK NT35532 PANELS
+M: Cristian Cozzolino <cristian_ci@protonmail.com>
+S: Maintained
+F: Documentation/devicetree/bindings/display/panel/novatek,nt35532.yaml
+F: drivers/gpu/drm/panel/panel-novatek-nt35532.c
+
DRM DRIVER FOR NOVATEK NT35560 PANELS
M: Linus Walleij <linusw@kernel.org>
S: Maintained
@@ -8558,6 +8566,7 @@ M: Robert Foss <rfoss@kernel.org>
R: Laurent Pinchart <Laurent.pinchart@ideasonboard.com>
R: Jonas Karlman <jonas@kwiboo.se>
R: Jernej Skrabec <jernej.skrabec@gmail.com>
+R: Luca Ceresoli <luca.ceresoli@bootlin.com>
S: Maintained
T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
F: Documentation/devicetree/bindings/display/bridge/
@@ -15018,7 +15027,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid.git
F: drivers/hid/hid-lg-g15.c
LONTIUM LT8912B MIPI TO HDMI BRIDGE
-M: Adrien Grassein <adrien.grassein@gmail.com>
+M: Francesco Dolcini <francesco@dolcini.it>
S: Maintained
F: Documentation/devicetree/bindings/display/bridge/lontium,lt8912b.yaml
F: drivers/gpu/drm/bridge/lontium-lt8912b.c
diff --git a/drivers/accel/amdxdna/Makefile b/drivers/accel/amdxdna/Makefile
index 79369e497540..d7720c8c8a98 100644
--- a/drivers/accel/amdxdna/Makefile
+++ b/drivers/accel/amdxdna/Makefile
@@ -12,6 +12,7 @@ amdxdna-y := \
aie2_solver.o \
aie4_message.o \
aie4_pci.o \
+ amdxdna_cbuf.o \
amdxdna_ctx.o \
amdxdna_gem.o \
amdxdna_iommu.o \
@@ -28,4 +29,5 @@ amdxdna-y := \
npu6_regs.o
amdxdna-$(CONFIG_PCI_IOV) += aie4_sriov.o
+amdxdna-$(CONFIG_DEBUG_FS) += amdxdna_debugfs.o
obj-$(CONFIG_DRM_ACCEL_AMDXDNA) = amdxdna.o
diff --git a/drivers/accel/amdxdna/aie2_ctx.c b/drivers/accel/amdxdna/aie2_ctx.c
index d37123d925b6..139825ac8515 100644
--- a/drivers/accel/amdxdna/aie2_ctx.c
+++ b/drivers/accel/amdxdna/aie2_ctx.c
@@ -64,6 +64,7 @@ static void aie2_job_release(struct kref *ref)
struct amdxdna_sched_job *job;
job = container_of(ref, struct amdxdna_sched_job, refcnt);
+
amdxdna_sched_job_cleanup(job);
atomic64_inc(&job->hwctx->job_free_cnt);
wake_up(&job->hwctx->priv->job_free_wq);
@@ -195,7 +196,8 @@ aie2_sched_notify(struct amdxdna_sched_job *job)
{
struct dma_fence *fence = job->fence;
- trace_xdna_job(&job->base, job->hwctx->name, "signaled fence", job->seq);
+ trace_xdna_job(&job->base, job->hwctx->name, "signaling fence",
+ job->seq, job->drv_cmd ? job->drv_cmd->opcode : DEFAULT_IO);
aie2_tdr_signal(job->hwctx->client->xdna);
job->hwctx->priv->completed++;
@@ -366,6 +368,9 @@ aie2_sched_job_run(struct drm_sched_job *sched_job)
struct dma_fence *fence;
int ret;
+ trace_xdna_job(sched_job, hwctx->name, "job run",
+ job->seq, job->drv_cmd ? job->drv_cmd->opcode : DEFAULT_IO);
+
if (!hwctx->priv->mbox_chann)
return NULL;
@@ -409,7 +414,8 @@ out:
} else {
aie2_tdr_signal(hwctx->client->xdna);
}
- trace_xdna_job(sched_job, hwctx->name, "sent to device", job->seq);
+ trace_xdna_job(sched_job, hwctx->name, "sent to device",
+ job->seq, job->drv_cmd ? job->drv_cmd->opcode : DEFAULT_IO);
return fence;
}
@@ -419,7 +425,8 @@ static void aie2_sched_job_free(struct drm_sched_job *sched_job)
struct amdxdna_sched_job *job = drm_job_to_xdna_job(sched_job);
struct amdxdna_hwctx *hwctx = job->hwctx;
- trace_xdna_job(sched_job, hwctx->name, "job free", job->seq);
+ trace_xdna_job(sched_job, hwctx->name, "job free",
+ job->seq, job->drv_cmd ? job->drv_cmd->opcode : DEFAULT_IO);
if (!job->job_done)
up(&hwctx->priv->job_sem);
@@ -437,7 +444,6 @@ aie2_sched_job_timedout(struct drm_sched_job *sched_job)
int ret;
xdna = hwctx->client->xdna;
- trace_xdna_job(sched_job, hwctx->name, "job timedout", job->seq);
guard(mutex)(&xdna->dev_lock);
@@ -540,22 +546,24 @@ static int aie2_alloc_resource(struct amdxdna_hwctx *hwctx)
{
struct amdxdna_dev *xdna = hwctx->client->xdna;
struct alloc_requests *xrs_req;
+ u32 temporal_only_col = 0;
int ret;
- if (AIE_FEATURE_ON(&xdna->dev_handle->aie, AIE2_TEMPORAL_ONLY)) {
- hwctx->num_unused_col = xdna->dev_handle->total_col - hwctx->num_col;
- hwctx->num_col = xdna->dev_handle->total_col;
- return aie2_create_context(xdna->dev_handle, hwctx);
- }
-
xrs_req = kzalloc_obj(*xrs_req);
if (!xrs_req)
return -ENOMEM;
- xrs_req->cdo.start_cols = hwctx->col_list;
- xrs_req->cdo.cols_len = hwctx->col_list_len;
- xrs_req->cdo.ncols = hwctx->num_col;
- xrs_req->cdo.qos_cap.opc = hwctx->max_opc;
+ if (AIE_FEATURE_ON(&xdna->dev_handle->aie, AIE2_TEMPORAL_ONLY)) {
+ xrs_req->cdo.start_cols = &temporal_only_col;
+ xrs_req->cdo.cols_len = 1;
+ xrs_req->cdo.ncols = xdna->dev_handle->total_col;
+ } else {
+ xrs_req->cdo.start_cols = hwctx->col_list;
+ xrs_req->cdo.cols_len = hwctx->col_list_len;
+ xrs_req->cdo.ncols = hwctx->num_col;
+ }
+ /* Use platform opc */
+ xrs_req->cdo.qos_cap.opc = xdna->dev_handle->priv->col_opc * hwctx->num_col;
xrs_req->rqos.gops = hwctx->qos.gops;
xrs_req->rqos.fps = hwctx->qos.fps;
@@ -579,15 +587,9 @@ static void aie2_release_resource(struct amdxdna_hwctx *hwctx)
struct amdxdna_dev *xdna = hwctx->client->xdna;
int ret;
- if (AIE_FEATURE_ON(&xdna->dev_handle->aie, AIE2_TEMPORAL_ONLY)) {
- ret = aie2_destroy_context(xdna->dev_handle, hwctx);
- if (ret && ret != -ENODEV)
- XDNA_ERR(xdna, "Destroy temporal only context failed, ret %d", ret);
- } else {
- ret = xrs_release_resource(xdna->xrs_hdl, (uintptr_t)hwctx);
- if (ret)
- XDNA_ERR(xdna, "Release AIE resource failed, ret %d", ret);
- }
+ ret = xrs_release_resource(xdna->xrs_hdl, (uintptr_t)hwctx);
+ if (ret)
+ XDNA_ERR(xdna, "Release AIE resource failed, ret %d", ret);
}
static int aie2_ctx_syncobj_create(struct amdxdna_hwctx *hwctx)
diff --git a/drivers/accel/amdxdna/aie2_pci.c b/drivers/accel/amdxdna/aie2_pci.c
index 1d1fb012294a..f0ddb843eb21 100644
--- a/drivers/accel/amdxdna/aie2_pci.c
+++ b/drivers/accel/amdxdna/aie2_pci.c
@@ -246,6 +246,7 @@ static int aie2_xrs_load(void *cb_arg, struct xrs_action_load *action)
xdna = hwctx->client->xdna;
hwctx->start_col = action->part.start_col;
+ hwctx->num_unused_col = action->part.ncols - hwctx->num_col;
hwctx->num_col = action->part.ncols;
ret = aie2_create_context(xdna->dev_handle, hwctx);
if (ret)
@@ -594,7 +595,7 @@ static int aie2_init(struct amdxdna_dev *xdna)
xrs_cfg.clk_list.num_levels = ndev->max_dpm_level + 1;
for (i = 0; i < xrs_cfg.clk_list.num_levels; i++)
xrs_cfg.clk_list.cu_clk_list[i] = ndev->priv->dpm_clk_tbl[i].hclk;
- xrs_cfg.sys_eff_factor = 1;
+ xrs_cfg.sys_eff_factor = 2;
xrs_cfg.ddev = &xdna->ddev;
xrs_cfg.actions = &aie2_xrs_actions;
xrs_cfg.total_col = ndev->total_col;
diff --git a/drivers/accel/amdxdna/aie2_pci.h b/drivers/accel/amdxdna/aie2_pci.h
index c44616065058..f12073175676 100644
--- a/drivers/accel/amdxdna/aie2_pci.h
+++ b/drivers/accel/amdxdna/aie2_pci.h
@@ -237,6 +237,7 @@ struct amdxdna_dev_priv {
#define COL_ALIGN_NONE 0
#define COL_ALIGN_NATURE 1
u32 col_align;
+ u32 col_opc;
u32 mbox_dev_addr;
/* If mbox_size is 0, use BAR size. See MBOX_SIZE macro */
u32 mbox_size;
diff --git a/drivers/accel/amdxdna/aie2_pm.c b/drivers/accel/amdxdna/aie2_pm.c
index 786d688bd82c..4fe6030d2c41 100644
--- a/drivers/accel/amdxdna/aie2_pm.c
+++ b/drivers/accel/amdxdna/aie2_pm.c
@@ -74,7 +74,7 @@ int aie2_pm_init(struct amdxdna_dev_hdl *ndev)
return ret;
ndev->pw_mode = POWER_MODE_DEFAULT;
- ndev->dft_dpm_level = ndev->max_dpm_level;
+ ndev->dft_dpm_level = 0;
return 0;
}
@@ -108,6 +108,14 @@ int aie2_pm_set_mode(struct amdxdna_dev_hdl *ndev, enum amdxdna_power_mode_type
clk_gating = AIE2_CLK_GATING_ENABLE;
dpm_level = ndev->dft_dpm_level;
break;
+ case POWER_MODE_LOW:
+ clk_gating = AIE2_CLK_GATING_ENABLE;
+ dpm_level = 0;
+ break;
+ case POWER_MODE_MEDIUM:
+ clk_gating = AIE2_CLK_GATING_ENABLE;
+ dpm_level = ndev->max_dpm_level / 2;
+ break;
default:
return -EOPNOTSUPP;
}
diff --git a/drivers/accel/amdxdna/aie2_solver.c b/drivers/accel/amdxdna/aie2_solver.c
index 3611e3268d79..6f3ee77d5264 100644
--- a/drivers/accel/amdxdna/aie2_solver.c
+++ b/drivers/accel/amdxdna/aie2_solver.c
@@ -52,7 +52,7 @@ static u32 calculate_gops(struct aie_qos *rqos)
u32 service_rate = 0;
if (rqos->latency)
- service_rate = (1000 / rqos->latency);
+ service_rate = max_t(u32, 1000 / rqos->latency, 1);
if (rqos->fps > service_rate)
return rqos->fps * rqos->gops;
@@ -348,6 +348,7 @@ int xrs_release_resource(void *hdl, u64 rid)
{
struct solver_state *xrs = hdl;
struct solver_node *node;
+ u32 level = 0;
node = rg_search_node(&xrs->rgp, rid);
if (!node) {
@@ -358,6 +359,13 @@ int xrs_release_resource(void *hdl, u64 rid)
xrs->cfg.actions->unload(node->cb_arg);
remove_solver_node(&xrs->rgp, node);
+ /* set the dpm level which fits all the sessions */
+ list_for_each_entry(node, &xrs->rgp.node_list, list) {
+ if (node->dpm_level > level)
+ level = node->dpm_level;
+ }
+ xrs->cfg.actions->set_dft_dpm_level(xrs->cfg.ddev, level);
+
return 0;
}
diff --git a/drivers/accel/amdxdna/amdxdna_cbuf.c b/drivers/accel/amdxdna/amdxdna_cbuf.c
new file mode 100644
index 000000000000..a504560aae98
--- /dev/null
+++ b/drivers/accel/amdxdna/amdxdna_cbuf.c
@@ -0,0 +1,280 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2026, Advanced Micro Devices, Inc.
+ */
+
+#include <drm/drm_mm.h>
+#include <drm/drm_prime.h>
+
+#include "amdxdna_cbuf.h"
+#include "amdxdna_pci_drv.h"
+
+/*
+ * Carveout memory is a chunk of memory which is physically contiguous and
+ * is reserved during early boot time. There is only one chunk of such memory
+ * per device. Once available, all BOs accessible from device should be
+ * allocated from this memory. This is a platform debug/bringup feature.
+ */
+struct amdxdna_carveout {
+ u64 addr;
+ u64 size;
+ struct drm_mm mm;
+ struct mutex lock; /* protect mm */
+};
+
+bool amdxdna_use_carveout(struct amdxdna_dev *xdna)
+{
+ return !!xdna->carveout;
+}
+
+void amdxdna_get_carveout_conf(struct amdxdna_dev *xdna, u64 *addr, u64 *size)
+{
+ if (amdxdna_use_carveout(xdna)) {
+ *addr = xdna->carveout->addr;
+ *size = xdna->carveout->size;
+ } else {
+ *addr = 0;
+ *size = 0;
+ }
+}
+
+int amdxdna_carveout_init(struct amdxdna_dev *xdna, u64 carveout_addr, u64 carveout_size)
+{
+ struct amdxdna_carveout *carveout;
+
+ /* Only allow carveout memory to be set up once. */
+ if (amdxdna_use_carveout(xdna)) {
+ XDNA_ERR(xdna, "Carveout memory has already been set up.");
+ return -EBUSY;
+ }
+
+ carveout = kzalloc_obj(*carveout);
+ if (!carveout)
+ return -ENOMEM;
+
+ carveout->addr = carveout_addr;
+ carveout->size = carveout_size;
+ mutex_init(&carveout->lock);
+ drm_mm_init(&carveout->mm, carveout->addr, carveout->size);
+
+ xdna->carveout = carveout;
+ XDNA_INFO(xdna, "Use carveout mem: 0x%llx@0x%llx\n", carveout->size, carveout->addr);
+ return 0;
+}
+
+void amdxdna_carveout_fini(struct amdxdna_dev *xdna)
+{
+ struct amdxdna_carveout *carveout = xdna->carveout;
+
+ if (!amdxdna_use_carveout(xdna))
+ return;
+
+ XDNA_INFO(xdna, "Cleanup carveout mem: 0x%llx@0x%llx\n", carveout->size, carveout->addr);
+ drm_mm_takedown(&carveout->mm);
+ mutex_destroy(&carveout->lock);
+ kfree(carveout);
+ xdna->carveout = NULL;
+}
+
+struct amdxdna_cbuf_priv {
+ struct amdxdna_dev *xdna;
+ struct drm_mm_node node;
+};
+
+static struct sg_table *amdxdna_cbuf_map(struct dma_buf_attachment *attach,
+ enum dma_data_direction direction)
+{
+ struct amdxdna_cbuf_priv *cbuf = attach->dmabuf->priv;
+ struct device *dev = attach->dev;
+ struct scatterlist *sgl, *sg;
+ int ret, n_entries, i;
+ struct sg_table *sgt;
+ dma_addr_t dma_addr;
+ size_t dma_size;
+ size_t max_seg;
+
+ sgt = kzalloc_obj(*sgt);
+ if (!sgt)
+ return ERR_PTR(-ENOMEM);
+
+ max_seg = min_t(size_t, UINT_MAX, dma_max_mapping_size(dev));
+ n_entries = (cbuf->node.size + max_seg - 1) / max_seg;
+ sgl = kzalloc_objs(*sg, n_entries);
+ if (!sgl) {
+ ret = -ENOMEM;
+ goto free_sgt;
+ }
+ sg_init_table(sgl, n_entries);
+ sgt->orig_nents = n_entries;
+ sgt->nents = n_entries;
+ sgt->sgl = sgl;
+
+ dma_size = cbuf->node.size;
+ dma_addr = dma_map_resource(dev, cbuf->node.start, dma_size,
+ direction, DMA_ATTR_SKIP_CPU_SYNC);
+ ret = dma_mapping_error(dev, dma_addr);
+ if (ret) {
+ pr_err("Failed to dma_map_resource carveout dma buf, ret %d\n", ret);
+ goto free_sgl;
+ }
+
+ for_each_sgtable_dma_sg(sgt, sg, i) {
+ size_t len = min_t(size_t, max_seg, dma_size);
+
+ sg_dma_address(sg) = dma_addr;
+ sg_dma_len(sg) = len;
+ dma_addr += len;
+ dma_size -= len;
+ }
+
+ return sgt;
+
+free_sgl:
+ kfree(sgl);
+free_sgt:
+ kfree(sgt);
+ return ERR_PTR(ret);
+}
+
+static void amdxdna_cbuf_unmap(struct dma_buf_attachment *attach,
+ struct sg_table *sgt,
+ enum dma_data_direction direction)
+{
+ dma_unmap_resource(attach->dev, sg_dma_address(sgt->sgl),
+ drm_prime_get_contiguous_size(sgt), direction,
+ DMA_ATTR_SKIP_CPU_SYNC);
+ sg_free_table(sgt);
+ kfree(sgt);
+}
+
+static void amdxdna_cbuf_release(struct dma_buf *dbuf)
+{
+ struct amdxdna_cbuf_priv *cbuf = dbuf->priv;
+ struct amdxdna_carveout *carveout;
+
+ carveout = cbuf->xdna->carveout;
+ mutex_lock(&carveout->lock);
+ drm_mm_remove_node(&cbuf->node);
+ mutex_unlock(&carveout->lock);
+
+ kfree(cbuf);
+}
+
+static vm_fault_t amdxdna_cbuf_vm_fault(struct vm_fault *vmf)
+{
+ struct vm_area_struct *vma = vmf->vma;
+ struct amdxdna_cbuf_priv *cbuf;
+ unsigned long pfn;
+ pgoff_t pgoff;
+
+ cbuf = vma->vm_private_data;
+ pgoff = (vmf->address - vma->vm_start) >> PAGE_SHIFT;
+ pfn = (cbuf->node.start >> PAGE_SHIFT) + pgoff;
+
+ return vmf_insert_pfn(vma, vmf->address, pfn);
+}
+
+static const struct vm_operations_struct amdxdna_cbuf_vm_ops = {
+ .fault = amdxdna_cbuf_vm_fault,
+};
+
+static int amdxdna_cbuf_mmap(struct dma_buf *dbuf, struct vm_area_struct *vma)
+{
+ struct amdxdna_cbuf_priv *cbuf = dbuf->priv;
+
+ vma->vm_ops = &amdxdna_cbuf_vm_ops;
+ vma->vm_private_data = cbuf;
+ vm_flags_set(vma, VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP);
+
+ return 0;
+}
+
+static int amdxdna_cbuf_vmap(struct dma_buf *dbuf, struct iosys_map *map)
+{
+ struct amdxdna_cbuf_priv *cbuf = dbuf->priv;
+ void *kva;
+
+ kva = memremap(cbuf->node.start, cbuf->node.size, MEMREMAP_WB);
+ if (!kva) {
+ pr_err("Failed to vmap carveout dma buf\n");
+ return -ENOMEM;
+ }
+
+ iosys_map_set_vaddr(map, kva);
+ return 0;
+}
+
+static void amdxdna_cbuf_vunmap(struct dma_buf *dbuf, struct iosys_map *map)
+{
+ memunmap(map->vaddr);
+}
+
+static const struct dma_buf_ops amdxdna_cbuf_dmabuf_ops = {
+ .map_dma_buf = amdxdna_cbuf_map,
+ .unmap_dma_buf = amdxdna_cbuf_unmap,
+ .release = amdxdna_cbuf_release,
+ .mmap = amdxdna_cbuf_mmap,
+ .vmap = amdxdna_cbuf_vmap,
+ .vunmap = amdxdna_cbuf_vunmap,
+};
+
+static int amdxdna_cbuf_clear(struct dma_buf *dbuf)
+{
+ struct iosys_map vmap = IOSYS_MAP_INIT_VADDR(NULL);
+
+ dma_buf_vmap(dbuf, &vmap);
+ if (!vmap.vaddr)
+ return -EFAULT;
+
+ memset(vmap.vaddr, 0, dbuf->size);
+ dma_buf_vunmap(dbuf, &vmap);
+
+ return 0;
+}
+
+struct dma_buf *amdxdna_get_cbuf(struct drm_device *dev, size_t size, u64 alignment)
+{
+ struct amdxdna_dev *xdna = to_xdna_dev(dev);
+ DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
+ struct amdxdna_carveout *carveout;
+ struct amdxdna_cbuf_priv *cbuf;
+ struct dma_buf *dbuf;
+ int ret;
+
+ cbuf = kzalloc_obj(*cbuf);
+ if (!cbuf)
+ return ERR_PTR(-ENOMEM);
+ cbuf->xdna = xdna;
+
+ carveout = xdna->carveout;
+ mutex_lock(&carveout->lock);
+ ret = drm_mm_insert_node_generic(&carveout->mm, &cbuf->node, size,
+ alignment, 0, DRM_MM_INSERT_BEST);
+ mutex_unlock(&carveout->lock);
+ if (ret)
+ goto free_cbuf;
+
+ exp_info.size = size;
+ exp_info.ops = &amdxdna_cbuf_dmabuf_ops;
+ exp_info.priv = cbuf;
+ exp_info.flags = O_RDWR;
+ dbuf = dma_buf_export(&exp_info);
+ if (IS_ERR(dbuf)) {
+ ret = PTR_ERR(dbuf);
+ goto remove_node;
+ }
+
+ ret = amdxdna_cbuf_clear(dbuf);
+ if (ret) {
+ dma_buf_put(dbuf);
+ goto out;
+ }
+ return dbuf;
+
+remove_node:
+ drm_mm_remove_node(&cbuf->node);
+free_cbuf:
+ kfree(cbuf);
+out:
+ return ERR_PTR(ret);
+}
diff --git a/drivers/accel/amdxdna/amdxdna_cbuf.h b/drivers/accel/amdxdna/amdxdna_cbuf.h
new file mode 100644
index 000000000000..8e89336ffd50
--- /dev/null
+++ b/drivers/accel/amdxdna/amdxdna_cbuf.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2026, Advanced Micro Devices, Inc.
+ */
+#ifndef _AMDXDNA_CBUF_H_
+#define _AMDXDNA_CBUF_H_
+
+#include "amdxdna_pci_drv.h"
+#include <drm/drm_device.h>
+#include <linux/dma-buf.h>
+
+bool amdxdna_use_carveout(struct amdxdna_dev *xdna);
+int amdxdna_carveout_init(struct amdxdna_dev *xdna, u64 carveout_addr, u64 carveout_size);
+void amdxdna_carveout_fini(struct amdxdna_dev *xdna);
+void amdxdna_get_carveout_conf(struct amdxdna_dev *xdna, u64 *addr, u64 *size);
+struct dma_buf *amdxdna_get_cbuf(struct drm_device *dev, size_t size, u64 alignment);
+
+#endif
diff --git a/drivers/accel/amdxdna/amdxdna_ctx.c b/drivers/accel/amdxdna/amdxdna_ctx.c
index ff6c3e8e5a15..2c2c21992c87 100644
--- a/drivers/accel/amdxdna/amdxdna_ctx.c
+++ b/drivers/accel/amdxdna/amdxdna_ctx.c
@@ -514,7 +514,6 @@ int amdxdna_cmd_submit(struct amdxdna_client *client,
goto unlock_srcu;
}
-
job->hwctx = hwctx;
job->mm = current->mm;
@@ -612,6 +611,8 @@ int amdxdna_drm_submit_cmd_ioctl(struct drm_device *dev, void *data, struct drm_
if (args->ext || args->ext_flags)
return -EINVAL;
+ trace_amdxdna_debug_point(current->comm, args->type, "job received");
+
switch (args->type) {
case AMDXDNA_CMD_SUBMIT_EXEC_BUF:
return amdxdna_drm_submit_execbuf(client, args);
diff --git a/drivers/accel/amdxdna/amdxdna_ctx.h b/drivers/accel/amdxdna/amdxdna_ctx.h
index a8557d7e8923..355798687376 100644
--- a/drivers/accel/amdxdna/amdxdna_ctx.h
+++ b/drivers/accel/amdxdna/amdxdna_ctx.h
@@ -119,6 +119,7 @@ struct amdxdna_hwctx {
container_of(j, struct amdxdna_sched_job, base)
enum amdxdna_job_opcode {
+ DEFAULT_IO,
SYNC_DEBUG_BO,
ATTACH_DEBUG_BO,
DETACH_DEBUG_BO,
diff --git a/drivers/accel/amdxdna/amdxdna_debugfs.c b/drivers/accel/amdxdna/amdxdna_debugfs.c
new file mode 100644
index 000000000000..a6ec17c63629
--- /dev/null
+++ b/drivers/accel/amdxdna/amdxdna_debugfs.c
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2026, Advanced Micro Devices, Inc.
+ */
+
+#include "amdxdna_cbuf.h"
+#include "amdxdna_debugfs.h"
+
+#include <drm/drm_file.h>
+#include <linux/debugfs.h>
+#include <linux/pm_runtime.h>
+#include <linux/seq_file.h>
+#include <linux/string.h>
+#include <linux/uaccess.h>
+
+#define _DBGFS_FOPS(_open, _release, _write) \
+{ \
+ .owner = THIS_MODULE, \
+ .open = _open, \
+ .read = seq_read, \
+ .llseek = seq_lseek, \
+ .release = _release, \
+ .write = _write, \
+}
+
+#define AMDXDNA_DBGFS_FOPS(_name, _show, _write) \
+ static int amdxdna_dbgfs_##_name##_open(struct inode *inode, struct file *file) \
+ { \
+ return single_open(file, _show, inode->i_private); \
+ } \
+ static int amdxdna_dbgfs_##_name##_release(struct inode *inode, struct file *file) \
+ { \
+ return single_release(inode, file); \
+ } \
+ static const struct file_operations amdxdna_fops_##_name = \
+ _DBGFS_FOPS(amdxdna_dbgfs_##_name##_open, amdxdna_dbgfs_##_name##_release, _write)
+
+#define AMDXDNA_DBGFS_FILE(_name, _mode) { #_name, &amdxdna_fops_##_name, _mode }
+
+#define file_to_xdna(file) (((struct seq_file *)(file)->private_data)->private)
+
+static ssize_t amdxdna_carveout_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct amdxdna_dev *xdna = file_to_xdna(file);
+ char kbuf[128];
+ u64 size, addr;
+ char *sep;
+ int ret;
+
+ if (count == 0 || count >= sizeof(kbuf))
+ return -EINVAL;
+
+ if (copy_from_user(kbuf, buf, count))
+ return -EFAULT;
+ kbuf[count] = '\0';
+ strim(kbuf);
+ XDNA_DBG(xdna, "Trying to set carveout to %s", kbuf);
+
+ sep = strchr(kbuf, '@');
+ if (!sep)
+ return -EINVAL;
+ *sep = '\0';
+ sep++;
+
+ ret = kstrtou64(kbuf, 0, &size);
+ if (ret)
+ return ret;
+
+ ret = kstrtou64(sep, 0, &addr);
+ if (ret)
+ return ret;
+
+ /* Sanity check the addr and size. */
+ if (!size)
+ return -EINVAL;
+ if (!IS_ALIGNED(addr, PAGE_SIZE) || !IS_ALIGNED(size, PAGE_SIZE))
+ return -EINVAL;
+
+ guard(mutex)(&xdna->dev_lock);
+
+ ret = amdxdna_carveout_init(xdna, addr, size);
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+static int amdxdna_carveout_show(struct seq_file *m, void *unused)
+{
+ struct amdxdna_dev *xdna = m->private;
+ u64 addr, size;
+
+ guard(mutex)(&xdna->dev_lock);
+ amdxdna_get_carveout_conf(xdna, &addr, &size);
+ seq_printf(m, "0x%llx@0x%llx\n", size, addr);
+ return 0;
+}
+
+/*
+ * Input/output format: <carveout_size>@<carveout_address>
+ */
+AMDXDNA_DBGFS_FOPS(carveout, amdxdna_carveout_show, amdxdna_carveout_write);
+
+static const struct {
+ const char *name;
+ const struct file_operations *fops;
+ umode_t mode;
+} amdxdna_dbgfs_files[] = {
+ AMDXDNA_DBGFS_FILE(carveout, 0600),
+};
+
+void amdxdna_debugfs_init(struct amdxdna_dev *xdna)
+{
+ struct drm_minor *minor = xdna->ddev.accel;
+ int i;
+
+ /*
+ * It should be okay that debugfs fails to init.
+ * We rely on DRM framework to finish debugfs.
+ */
+ for (i = 0; i < ARRAY_SIZE(amdxdna_dbgfs_files); i++) {
+ debugfs_create_file(amdxdna_dbgfs_files[i].name,
+ amdxdna_dbgfs_files[i].mode,
+ minor->debugfs_root,
+ xdna,
+ amdxdna_dbgfs_files[i].fops);
+ }
+}
diff --git a/drivers/accel/amdxdna/amdxdna_debugfs.h b/drivers/accel/amdxdna/amdxdna_debugfs.h
new file mode 100644
index 000000000000..2abb45de3f7e
--- /dev/null
+++ b/drivers/accel/amdxdna/amdxdna_debugfs.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2026, Advanced Micro Devices, Inc.
+ */
+#ifndef _AMDXDNA_DEBUGFS_H_
+#define _AMDXDNA_DEBUGFS_H_
+
+#include "amdxdna_pci_drv.h"
+
+#if defined(CONFIG_DEBUG_FS)
+void amdxdna_debugfs_init(struct amdxdna_dev *xdna);
+#else
+static inline void amdxdna_debugfs_init(struct amdxdna_dev *xdna)
+{
+}
+#endif /* CONFIG_DEBUG_FS */
+
+#endif
diff --git a/drivers/accel/amdxdna/amdxdna_gem.c b/drivers/accel/amdxdna/amdxdna_gem.c
index 238ee244d4a6..ebfc472aa9e7 100644
--- a/drivers/accel/amdxdna/amdxdna_gem.c
+++ b/drivers/accel/amdxdna/amdxdna_gem.c
@@ -16,6 +16,7 @@
#include <linux/pagemap.h>
#include <linux/vmalloc.h>
+#include "amdxdna_cbuf.h"
#include "amdxdna_ctx.h"
#include "amdxdna_gem.h"
#include "amdxdna_pci_drv.h"
@@ -516,10 +517,6 @@ static void amdxdna_imported_obj_free(struct amdxdna_gem_obj *abo)
static inline bool
amdxdna_gem_skip_bo_usage(struct amdxdna_gem_obj *abo)
{
- /* Do not count imported BOs since the buffer is not allocated by us. */
- if (is_import_bo(abo))
- return true;
-
/* Already counted as part of HEAP BO */
if (abo->type == AMDXDNA_BO_DEV)
return true;
@@ -571,9 +568,7 @@ static void amdxdna_gem_obj_free(struct drm_gem_object *gobj)
if (abo->type == AMDXDNA_BO_DEV_HEAP)
drm_mm_takedown(&abo->mm);
- if (amdxdna_iova_on(xdna))
- amdxdna_iommu_unmap_bo(xdna, abo);
-
+ amdxdna_dma_unmap_bo(xdna, abo);
amdxdna_gem_vunmap(abo);
mutex_destroy(&abo->lock);
@@ -591,18 +586,20 @@ static int amdxdna_gem_obj_open(struct drm_gem_object *gobj, struct drm_file *fi
guard(mutex)(&abo->lock);
abo->open_ref++;
+ if (abo->open_ref > 1)
+ return 0;
- if (abo->open_ref == 1) {
- /* Attached to the client when first opened by it. */
- abo->client = filp->driver_priv;
- amdxdna_gem_add_bo_usage(abo);
- }
- if (amdxdna_iova_on(xdna)) {
- ret = amdxdna_iommu_map_bo(xdna, abo);
+ /* Attached to the client when first opened by it. */
+ abo->client = filp->driver_priv;
+
+ /* No need to set up dma addr mapping in PASID mode. */
+ if (!amdxdna_pasid_on(abo->client)) {
+ ret = amdxdna_dma_map_bo(xdna, abo);
if (ret)
return ret;
}
+ amdxdna_gem_add_bo_usage(abo);
return 0;
}
@@ -620,6 +617,39 @@ static void amdxdna_gem_obj_close(struct drm_gem_object *gobj, struct drm_file *
}
}
+static int amdxdna_gem_obj_vmap(struct drm_gem_object *obj, struct iosys_map *map)
+{
+ struct amdxdna_gem_obj *abo = to_xdna_obj(obj);
+ int ret;
+
+ iosys_map_clear(map);
+
+ dma_resv_assert_held(obj->resv);
+
+ if (is_import_bo(abo))
+ ret = dma_buf_vmap(abo->dma_buf, map);
+ else
+ ret = drm_gem_shmem_object_vmap(obj, map);
+ if (ret)
+ return ret;
+ if (!map->vaddr)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void amdxdna_gem_obj_vunmap(struct drm_gem_object *obj, struct iosys_map *map)
+{
+ struct amdxdna_gem_obj *abo = to_xdna_obj(obj);
+
+ dma_resv_assert_held(obj->resv);
+
+ if (is_import_bo(abo))
+ dma_buf_vunmap(abo->dma_buf, map);
+ else
+ drm_gem_shmem_object_vunmap(obj, map);
+}
+
static int amdxdna_gem_dev_obj_vmap(struct drm_gem_object *obj, struct iosys_map *map)
{
struct amdxdna_gem_obj *abo = to_xdna_obj(obj);
@@ -645,8 +675,8 @@ static const struct drm_gem_object_funcs amdxdna_gem_shmem_funcs = {
.pin = drm_gem_shmem_object_pin,
.unpin = drm_gem_shmem_object_unpin,
.get_sg_table = drm_gem_shmem_object_get_sg_table,
- .vmap = drm_gem_shmem_object_vmap,
- .vunmap = drm_gem_shmem_object_vunmap,
+ .vmap = amdxdna_gem_obj_vmap,
+ .vunmap = amdxdna_gem_obj_vunmap,
.mmap = amdxdna_gem_obj_mmap,
.vm_ops = &drm_gem_shmem_vm_ops,
.export = amdxdna_gem_prime_export,
@@ -714,6 +744,36 @@ amdxdna_gem_create_ubuf_object(struct drm_device *dev, struct amdxdna_drm_create
return to_xdna_obj(gobj);
}
+static struct amdxdna_gem_obj *
+amdxdna_gem_create_cbuf_object(struct drm_device *dev, struct amdxdna_drm_create_bo *args)
+{
+ struct amdxdna_dev *xdna = to_xdna_dev(dev);
+ size_t size = PAGE_ALIGN(args->size);
+ struct drm_gem_object *gobj;
+ struct amdxdna_gem_obj *ret;
+ struct dma_buf *dma_buf;
+ u64 align;
+
+ if (!size) {
+ XDNA_ERR(xdna, "Invalid BO size 0x%llx", args->size);
+ return ERR_PTR(-EINVAL);
+ }
+
+ align = (args->type == AMDXDNA_BO_DEV_HEAP) ? xdna->dev_info->dev_mem_size : 0;
+ dma_buf = amdxdna_get_cbuf(dev, size, align);
+ if (IS_ERR(dma_buf))
+ return ERR_CAST(dma_buf);
+
+ gobj = amdxdna_gem_prime_import(dev, dma_buf);
+ if (IS_ERR(gobj))
+ ret = ERR_CAST(gobj);
+ else
+ ret = to_xdna_obj(gobj);
+
+ dma_buf_put(dma_buf);
+ return ret;
+}
+
struct drm_gem_object *
amdxdna_gem_prime_import(struct drm_device *dev, struct dma_buf *dma_buf)
{
@@ -769,6 +829,8 @@ amdxdna_drm_create_share_bo(struct drm_device *dev,
if (args->vaddr)
abo = amdxdna_gem_create_ubuf_object(dev, args);
+ else if (amdxdna_use_carveout(to_xdna_dev(dev)))
+ abo = amdxdna_gem_create_cbuf_object(dev, args);
else
abo = amdxdna_gem_create_shmem_object(dev, args);
if (IS_ERR(abo))
@@ -884,7 +946,6 @@ int amdxdna_drm_create_bo_ioctl(struct drm_device *dev, void *data, struct drm_f
args->type, args->vaddr, args->size, args->flags);
switch (args->type) {
case AMDXDNA_BO_CMD:
- fallthrough;
case AMDXDNA_BO_SHARE:
abo = amdxdna_drm_create_share_bo(dev, args, filp);
break;
diff --git a/drivers/accel/amdxdna/amdxdna_iommu.c b/drivers/accel/amdxdna/amdxdna_iommu.c
index 5a9f06183487..eff00131d0f8 100644
--- a/drivers/accel/amdxdna/amdxdna_iommu.c
+++ b/drivers/accel/amdxdna/amdxdna_iommu.c
@@ -35,14 +35,15 @@ static struct iova *amdxdna_iommu_alloc_iova(struct amdxdna_dev *xdna,
return iova;
}
-int amdxdna_iommu_map_bo(struct amdxdna_dev *xdna, struct amdxdna_gem_obj *abo)
+int amdxdna_dma_map_bo(struct amdxdna_dev *xdna, struct amdxdna_gem_obj *abo)
{
+ unsigned long contig_sz;
struct sg_table *sgt;
dma_addr_t dma_addr;
struct iova *iova;
ssize_t size;
- if (abo->type != AMDXDNA_BO_DEV_HEAP && abo->type != AMDXDNA_BO_SHMEM)
+ if (abo->type != AMDXDNA_BO_DEV_HEAP && abo->type != AMDXDNA_BO_SHARE)
return 0;
sgt = drm_gem_shmem_get_pages_sgt(&abo->base);
@@ -51,47 +52,63 @@ int amdxdna_iommu_map_bo(struct amdxdna_dev *xdna, struct amdxdna_gem_obj *abo)
return PTR_ERR(sgt);
}
- if (!sgt->orig_nents || !sg_page(sgt->sgl)) {
- XDNA_ERR(xdna, "sgl is zero length or not page backed");
+ if (!sgt->orig_nents) {
+ XDNA_ERR(xdna, "sgl is zero length");
return -EOPNOTSUPP;
}
- iova = amdxdna_iommu_alloc_iova(xdna, abo->mem.size, &dma_addr,
- (abo->type == AMDXDNA_BO_DEV_HEAP));
- if (IS_ERR(iova)) {
- XDNA_ERR(xdna, "Alloc iova failed, ret %ld", PTR_ERR(iova));
- return PTR_ERR(iova);
+ if (amdxdna_iova_on(xdna)) {
+ if (!sg_page(sgt->sgl)) {
+ XDNA_ERR(xdna, "sgl is not page backed");
+ return -EOPNOTSUPP;
+ }
+
+ iova = amdxdna_iommu_alloc_iova(xdna, abo->mem.size, &dma_addr,
+ (abo->type == AMDXDNA_BO_DEV_HEAP));
+ if (IS_ERR(iova)) {
+ XDNA_ERR(xdna, "Alloc iova failed, ret %ld", PTR_ERR(iova));
+ return PTR_ERR(iova);
+ }
+
+ size = iommu_map_sgtable(xdna->domain, dma_addr, sgt,
+ IOMMU_READ | IOMMU_WRITE);
+ if (size < 0) {
+ XDNA_ERR(xdna, "iommu_map_sgtable failed: %zd", size);
+ __free_iova(&xdna->iovad, iova);
+ return size;
+ }
+ if (size < abo->mem.size) {
+ iommu_unmap(xdna->domain, dma_addr, size);
+ __free_iova(&xdna->iovad, iova);
+ return -ENXIO;
+ }
+ abo->mem.dma_addr = dma_addr;
+ } else {
+ /* Device doesn't support scatter/gather list, fail non-contiguous mapping. */
+ contig_sz = drm_prime_get_contiguous_size(sgt);
+ if (contig_sz < abo->mem.size) {
+ XDNA_ERR(xdna,
+ "noncontiguous dma addr, contig size:%ld, expected size:%ld",
+ contig_sz, abo->mem.size);
+ return -EINVAL;
+ }
+ abo->mem.dma_addr = sg_dma_address(sgt->sgl);
}
-
- size = iommu_map_sgtable(xdna->domain, dma_addr, sgt,
- IOMMU_READ | IOMMU_WRITE);
- if (size < 0) {
- XDNA_ERR(xdna, "iommu_map_sgtable failed: %zd", size);
- __free_iova(&xdna->iovad, iova);
- return size;
- }
-
- if (size < abo->mem.size) {
- iommu_unmap(xdna->domain, dma_addr, size);
- __free_iova(&xdna->iovad, iova);
- return -ENXIO;
- }
-
- abo->mem.dma_addr = dma_addr;
-
return 0;
}
-void amdxdna_iommu_unmap_bo(struct amdxdna_dev *xdna, struct amdxdna_gem_obj *abo)
+void amdxdna_dma_unmap_bo(struct amdxdna_dev *xdna, struct amdxdna_gem_obj *abo)
{
size_t size;
if (abo->mem.dma_addr == AMDXDNA_INVALID_ADDR)
return;
- size = iova_align(&xdna->iovad, abo->mem.size);
- iommu_unmap(xdna->domain, abo->mem.dma_addr, size);
- free_iova(&xdna->iovad, iova_pfn(&xdna->iovad, abo->mem.dma_addr));
+ if (amdxdna_iova_on(xdna)) {
+ size = iova_align(&xdna->iovad, abo->mem.size);
+ iommu_unmap(xdna->domain, abo->mem.dma_addr, size);
+ free_iova(&xdna->iovad, iova_pfn(&xdna->iovad, abo->mem.dma_addr));
+ }
abo->mem.dma_addr = AMDXDNA_INVALID_ADDR;
}
diff --git a/drivers/accel/amdxdna/amdxdna_mailbox.c b/drivers/accel/amdxdna/amdxdna_mailbox.c
index 37771bdb24a1..cc8865f4e79c 100644
--- a/drivers/accel/amdxdna/amdxdna_mailbox.c
+++ b/drivers/accel/amdxdna/amdxdna_mailbox.c
@@ -361,6 +361,7 @@ static void mailbox_rx_worker(struct work_struct *rx_work)
int ret;
mb_chann = container_of(rx_work, struct mailbox_channel, rx_work);
+ trace_mbox_rx_worker(MAILBOX_NAME, mb_chann->msix_irq);
if (READ_ONCE(mb_chann->bad_state)) {
MB_ERR(mb_chann, "Channel in bad state, work aborted");
diff --git a/drivers/accel/amdxdna/amdxdna_pci_drv.c b/drivers/accel/amdxdna/amdxdna_pci_drv.c
index 21eddfc538d0..1b08a08343cf 100644
--- a/drivers/accel/amdxdna/amdxdna_pci_drv.c
+++ b/drivers/accel/amdxdna/amdxdna_pci_drv.c
@@ -14,7 +14,9 @@
#include <linux/iommu.h>
#include <linux/pci.h>
+#include "amdxdna_cbuf.h"
#include "amdxdna_ctx.h"
+#include "amdxdna_debugfs.h"
#include "amdxdna_gem.h"
#include "amdxdna_pci_drv.h"
#include "amdxdna_pm.h"
@@ -67,11 +69,40 @@ static const struct amdxdna_device_id amdxdna_ids[] = {
{0}
};
+static int amdxdna_sva_init(struct amdxdna_client *client)
+{
+ struct amdxdna_dev *xdna = client->xdna;
+
+ client->sva = iommu_sva_bind_device(xdna->ddev.dev, client->mm);
+ if (IS_ERR(client->sva)) {
+ XDNA_ERR(xdna, "SVA bind device failed, ret %ld", PTR_ERR(client->sva));
+ return PTR_ERR(client->sva);
+ }
+
+ client->pasid = iommu_sva_get_pasid(client->sva);
+ if (client->pasid == IOMMU_PASID_INVALID) {
+ iommu_sva_unbind_device(client->sva);
+ XDNA_ERR(xdna, "SVA get pasid failed");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static void amdxdna_sva_fini(struct amdxdna_client *client)
+{
+ if (IS_ERR_OR_NULL(client->sva))
+ return;
+
+ iommu_sva_unbind_device(client->sva);
+ client->sva = NULL;
+ client->pasid = IOMMU_PASID_INVALID;
+}
+
static int amdxdna_drm_open(struct drm_device *ddev, struct drm_file *filp)
{
struct amdxdna_dev *xdna = to_xdna_dev(ddev);
struct amdxdna_client *client;
- int ret;
client = kzalloc_obj(*client);
if (!client)
@@ -80,22 +111,13 @@ static int amdxdna_drm_open(struct drm_device *ddev, struct drm_file *filp)
client->pid = pid_nr(rcu_access_pointer(filp->pid));
client->xdna = xdna;
client->pasid = IOMMU_PASID_INVALID;
+ client->mm = current->mm;
if (!amdxdna_iova_on(xdna)) {
- client->sva = iommu_sva_bind_device(xdna->ddev.dev, current->mm);
- if (IS_ERR(client->sva)) {
- ret = PTR_ERR(client->sva);
- XDNA_ERR(xdna, "SVA bind device failed, ret %d", ret);
- goto failed;
- }
- client->pasid = iommu_sva_get_pasid(client->sva);
- if (client->pasid == IOMMU_PASID_INVALID) {
- XDNA_ERR(xdna, "SVA get pasid failed");
- ret = -ENODEV;
- goto unbind_sva;
- }
+ /* No need to fail open since user may use pa + carveout later. */
+ if (amdxdna_sva_init(client))
+ XDNA_WARN(xdna, "PASID not available for pid %d", client->pid);
}
- client->mm = current->mm;
mmgrab(client->mm);
init_srcu_struct(&client->hwctx_srcu);
xa_init_flags(&client->hwctx_xa, XA_FLAGS_ALLOC);
@@ -110,14 +132,6 @@ static int amdxdna_drm_open(struct drm_device *ddev, struct drm_file *filp)
XDNA_DBG(xdna, "pid %d opened", client->pid);
return 0;
-
-unbind_sva:
- if (!IS_ERR_OR_NULL(client->sva))
- iommu_sva_unbind_device(client->sva);
-failed:
- kfree(client);
-
- return ret;
}
static void amdxdna_client_cleanup(struct amdxdna_client *client)
@@ -131,11 +145,8 @@ static void amdxdna_client_cleanup(struct amdxdna_client *client)
drm_gem_object_put(to_gobj(client->dev_heap));
mutex_destroy(&client->mm_lock);
-
- if (!IS_ERR_OR_NULL(client->sva))
- iommu_sva_unbind_device(client->sva);
mmdrop(client->mm);
-
+ amdxdna_sva_fini(client);
kfree(client);
}
@@ -242,15 +253,17 @@ static void amdxdna_show_fdinfo(struct drm_printer *p, struct drm_file *filp)
/*
* Note for driver specific BO memory usage stat.
- * Total memory alloc = amdxdna-internal-alloc + amdxdna-external-alloc
+ * Total memory in use = amdxdna-internal-alloc + amdxdna-external-alloc, which
+ * includes both imported and created BOs. To avoid double counts, it includes
+ * HEAP BO, but not DEV BO. DEV BO is counted by amdxdna-heap-alloc.
*/
drm_fdinfo_print_size(p, drv_name, "heap", "alloc", heap_usage);
drm_fdinfo_print_size(p, drv_name, "internal", "alloc", internal_usage);
drm_fdinfo_print_size(p, drv_name, "external", "alloc", external_usage);
/*
* Note for DRM standard BO memory stat.
- * drm-total-memory counts both DEV BO and HEAP BO
- * drm-shared-memory counts BO imported
+ * drm-total-memory counts both DEV BO and HEAP BO. The DEV BO size is double counted.
+ * drm-shared-memory counts BO shared with other processes/devices.
*/
drm_show_memory_stats(p, filp);
}
@@ -299,25 +312,38 @@ amdxdna_get_dev_info(struct pci_dev *pdev)
return NULL;
}
+static void amdxdna_xdna_drm_release(struct drm_device *drm, void *res)
+{
+ struct amdxdna_dev *xdna = res;
+
+ amdxdna_carveout_fini(xdna);
+}
+
static int amdxdna_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct device *dev = &pdev->dev;
struct amdxdna_dev *xdna;
+ struct drm_device *ddev;
int ret;
xdna = devm_drm_dev_alloc(dev, &amdxdna_drm_drv, typeof(*xdna), ddev);
if (IS_ERR(xdna))
return PTR_ERR(xdna);
+ ddev = &xdna->ddev;
xdna->dev_info = amdxdna_get_dev_info(pdev);
if (!xdna->dev_info)
return -ENODEV;
- drmm_mutex_init(&xdna->ddev, &xdna->dev_lock);
+ drmm_mutex_init(ddev, &xdna->dev_lock);
init_rwsem(&xdna->notifier_lock);
INIT_LIST_HEAD(&xdna->client_list);
pci_set_drvdata(pdev, xdna);
+ ret = drmm_add_action(ddev, amdxdna_xdna_drm_release, xdna);
+ if (ret)
+ return ret;
+
if (IS_ENABLED(CONFIG_LOCKDEP)) {
fs_reclaim_acquire(GFP_KERNEL);
might_lock(&xdna->notifier_lock);
@@ -348,12 +374,13 @@ static int amdxdna_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto failed_dev_fini;
}
- ret = drm_dev_register(&xdna->ddev, 0);
+ ret = drm_dev_register(ddev, 0);
if (ret) {
XDNA_ERR(xdna, "DRM register failed, ret %d", ret);
goto failed_sysfs_fini;
}
+ amdxdna_debugfs_init(xdna);
return 0;
failed_sysfs_fini:
diff --git a/drivers/accel/amdxdna/amdxdna_pci_drv.h b/drivers/accel/amdxdna/amdxdna_pci_drv.h
index bdd0dc83f92e..b1548cf16f59 100644
--- a/drivers/accel/amdxdna/amdxdna_pci_drv.h
+++ b/drivers/accel/amdxdna/amdxdna_pci_drv.h
@@ -104,6 +104,8 @@ struct amdxdna_fw_ver {
u32 build;
};
+struct amdxdna_carveout;
+
struct amdxdna_dev {
struct drm_device ddev;
struct amdxdna_dev_hdl *dev_handle;
@@ -121,6 +123,8 @@ struct amdxdna_dev {
struct iova_domain iovad;
/* Accurate board name queried from firmware, or default_vbnv as fallback */
const char *vbnv;
+
+ struct amdxdna_carveout *carveout;
};
/*
@@ -172,11 +176,11 @@ void amdxdna_sysfs_fini(struct amdxdna_dev *xdna);
int amdxdna_iommu_init(struct amdxdna_dev *xdna);
void amdxdna_iommu_fini(struct amdxdna_dev *xdna);
-int amdxdna_iommu_map_bo(struct amdxdna_dev *xdna, struct amdxdna_gem_obj *abo);
-void amdxdna_iommu_unmap_bo(struct amdxdna_dev *xdna, struct amdxdna_gem_obj *abo);
void *amdxdna_iommu_alloc(struct amdxdna_dev *xdna, size_t size, dma_addr_t *dma_addr);
void amdxdna_iommu_free(struct amdxdna_dev *xdna, size_t size,
void *cpu_addr, dma_addr_t dma_addr);
+int amdxdna_dma_map_bo(struct amdxdna_dev *xdna, struct amdxdna_gem_obj *abo);
+void amdxdna_dma_unmap_bo(struct amdxdna_dev *xdna, struct amdxdna_gem_obj *abo);
static inline bool amdxdna_iova_on(struct amdxdna_dev *xdna)
{
diff --git a/drivers/accel/amdxdna/npu1_regs.c b/drivers/accel/amdxdna/npu1_regs.c
index d7e50c6b06ef..4e48c030a69f 100644
--- a/drivers/accel/amdxdna/npu1_regs.c
+++ b/drivers/accel/amdxdna/npu1_regs.c
@@ -97,6 +97,7 @@ static const struct amdxdna_dev_priv npu1_dev_priv = {
.rt_config = npu1_default_rt_cfg,
.dpm_clk_tbl = npu1_dpm_clk_table,
.col_align = COL_ALIGN_NONE,
+ .col_opc = 2048,
.mbox_dev_addr = NPU1_MBOX_BAR_BASE,
.mbox_size = 0, /* Use BAR size */
.sram_dev_addr = NPU1_SRAM_BAR_BASE,
diff --git a/drivers/accel/amdxdna/npu4_regs.c b/drivers/accel/amdxdna/npu4_regs.c
index 935999ced70f..eddc31803a50 100644
--- a/drivers/accel/amdxdna/npu4_regs.c
+++ b/drivers/accel/amdxdna/npu4_regs.c
@@ -160,6 +160,7 @@ static const struct amdxdna_dev_priv npu4_dev_priv = {
.rt_config = npu4_default_rt_cfg,
.dpm_clk_tbl = npu4_dpm_clk_table,
.col_align = COL_ALIGN_NATURE,
+ .col_opc = 4096,
.mbox_dev_addr = NPU4_MBOX_BAR_BASE,
.mbox_size = 0, /* Use BAR size */
.sram_dev_addr = NPU4_SRAM_BAR_BASE,
diff --git a/drivers/accel/amdxdna/npu5_regs.c b/drivers/accel/amdxdna/npu5_regs.c
index 795bd1996845..a9102978e4a8 100644
--- a/drivers/accel/amdxdna/npu5_regs.c
+++ b/drivers/accel/amdxdna/npu5_regs.c
@@ -67,6 +67,7 @@ static const struct amdxdna_dev_priv npu5_dev_priv = {
.rt_config = npu4_default_rt_cfg,
.dpm_clk_tbl = npu4_dpm_clk_table,
.col_align = COL_ALIGN_NATURE,
+ .col_opc = 4096,
.mbox_dev_addr = NPU5_MBOX_BAR_BASE,
.mbox_size = 0, /* Use BAR size */
.sram_dev_addr = NPU5_SRAM_BAR_BASE,
diff --git a/drivers/accel/amdxdna/npu6_regs.c b/drivers/accel/amdxdna/npu6_regs.c
index 3125d1ce45ab..e0db3a09740b 100644
--- a/drivers/accel/amdxdna/npu6_regs.c
+++ b/drivers/accel/amdxdna/npu6_regs.c
@@ -67,6 +67,7 @@ static const struct amdxdna_dev_priv npu6_dev_priv = {
.rt_config = npu4_default_rt_cfg,
.dpm_clk_tbl = npu4_dpm_clk_table,
.col_align = COL_ALIGN_NATURE,
+ .col_opc = 4096,
.mbox_dev_addr = NPU6_MBOX_BAR_BASE,
.mbox_size = 0, /* Use BAR size */
.sram_dev_addr = NPU6_SRAM_BAR_BASE,
diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c
index 2801378e3e19..e6d631108145 100644
--- a/drivers/accel/ivpu/ivpu_drv.c
+++ b/drivers/accel/ivpu/ivpu_drv.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (C) 2020-2025 Intel Corporation
+ * Copyright (C) 2020-2026 Intel Corporation
*/
#include <linux/firmware.h>
@@ -234,7 +234,7 @@ static int ivpu_get_param_ioctl(struct drm_device *dev, void *data, struct drm_f
args->value = vdev->platform;
break;
case DRM_IVPU_PARAM_CORE_CLOCK_RATE:
- args->value = ivpu_hw_dpu_max_freq_get(vdev);
+ args->value = ivpu_hw_btrs_pll_ratio_to_hz(vdev, vdev->hw->pll.max_ratio);
break;
case DRM_IVPU_PARAM_NUM_CONTEXTS:
args->value = file_priv->user_limits->max_ctx_count;
@@ -487,6 +487,10 @@ int ivpu_boot(struct ivpu_device *vdev)
ret = ivpu_hw_sched_init(vdev);
if (ret)
goto err_disable_ipc;
+
+ ret = ivpu_hw_btrs_cfg_freq_init(vdev);
+ if (ret)
+ goto err_disable_ipc;
}
return 0;
diff --git a/drivers/accel/ivpu/ivpu_hw.h b/drivers/accel/ivpu/ivpu_hw.h
index b6d0f0d0dccc..487a918e2fa9 100644
--- a/drivers/accel/ivpu/ivpu_hw.h
+++ b/drivers/accel/ivpu/ivpu_hw.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright (C) 2020-2025 Intel Corporation
+ * Copyright (C) 2020-2026 Intel Corporation
*/
#ifndef __IVPU_HW_H__
@@ -28,6 +28,7 @@ struct ivpu_hw_info {
struct ivpu_addr_range dma;
} ranges;
struct {
+ /* Hardware min and max pll ratio */
u8 min_ratio;
u8 max_ratio;
/*
@@ -35,6 +36,9 @@ struct ivpu_hw_info {
* performance to power ratio at this frequency.
*/
u8 pn_ratio;
+ /* Pll ratios configured via sysfs interface */
+ u8 cfg_min_ratio;
+ u8 cfg_max_ratio;
u32 profiling_freq;
} pll;
struct {
@@ -80,16 +84,6 @@ static inline u64 ivpu_hw_range_size(const struct ivpu_addr_range *range)
return range->end - range->start;
}
-static inline u32 ivpu_hw_dpu_max_freq_get(struct ivpu_device *vdev)
-{
- return ivpu_hw_btrs_dpu_max_freq_get(vdev);
-}
-
-static inline u32 ivpu_hw_dpu_freq_get(struct ivpu_device *vdev)
-{
- return ivpu_hw_btrs_dpu_freq_get(vdev);
-}
-
static inline void ivpu_hw_irq_clear(struct ivpu_device *vdev)
{
ivpu_hw_ip_irq_clear(vdev);
diff --git a/drivers/accel/ivpu/ivpu_hw_btrs.c b/drivers/accel/ivpu/ivpu_hw_btrs.c
index 06e65c592618..dac935164e11 100644
--- a/drivers/accel/ivpu/ivpu_hw_btrs.c
+++ b/drivers/accel/ivpu/ivpu_hw_btrs.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (C) 2020-2025 Intel Corporation
+ * Copyright (C) 2020-2026 Intel Corporation
*/
#include <linux/units.h>
@@ -11,6 +11,7 @@
#include "ivpu_hw_btrs_lnl_reg.h"
#include "ivpu_hw_btrs_mtl_reg.h"
#include "ivpu_hw_reg_io.h"
+#include "ivpu_jsm_msg.h"
#include "ivpu_pm.h"
#define BTRS_MTL_IRQ_MASK ((REG_FLD(VPU_HW_BTRS_MTL_INTERRUPT_STAT, ATS_ERR)) | \
@@ -33,8 +34,7 @@
#define PLL_CDYN_DEFAULT 0x80
#define PLL_EPP_DEFAULT 0x80
-#define PLL_REF_CLK_FREQ 50000000ull
-#define PLL_RATIO_TO_FREQ(x) ((x) * PLL_REF_CLK_FREQ)
+#define PLL_REF_CLK_FREQ_MHZ 50
#define PLL_TIMEOUT_US (1500 * USEC_PER_MSEC)
#define IDLE_TIMEOUT_US (5 * USEC_PER_MSEC)
@@ -59,8 +59,6 @@
#define DCT_ENABLE 0x1
#define DCT_DISABLE 0x0
-static u32 pll_ratio_to_dpu_freq(struct ivpu_device *vdev, u32 ratio);
-
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);
@@ -111,6 +109,8 @@ void ivpu_hw_btrs_freq_ratios_init(struct ivpu_device *vdev)
hw->pll.min_ratio = clamp_t(u8, ivpu_pll_min_ratio, hw->pll.min_ratio, hw->pll.max_ratio);
hw->pll.max_ratio = clamp_t(u8, ivpu_pll_max_ratio, hw->pll.min_ratio, hw->pll.max_ratio);
hw->pll.pn_ratio = clamp_t(u8, hw->pll.pn_ratio, hw->pll.min_ratio, hw->pll.max_ratio);
+ hw->pll.cfg_max_ratio = hw->pll.max_ratio;
+ hw->pll.cfg_min_ratio = hw->pll.min_ratio;
}
static bool tile_disable_check(u32 config)
@@ -341,8 +341,8 @@ int ivpu_hw_btrs_wp_drive(struct ivpu_device *vdev, bool enable)
prepare_wp_request(vdev, &wp, enable);
- ivpu_dbg(vdev, PM, "PLL workpoint request: %lu MHz, config: 0x%x, epp: 0x%x, cdyn: 0x%x\n",
- pll_ratio_to_dpu_freq(vdev, wp.target) / HZ_PER_MHZ, wp.cfg, wp.epp, wp.cdyn);
+ ivpu_dbg(vdev, PM, "PLL workpoint request: %u MHz, config: 0x%x, epp: 0x%x, cdyn: 0x%x\n",
+ ivpu_hw_btrs_pll_ratio_to_mhz(vdev, wp.target), wp.cfg, wp.epp, wp.cdyn);
ret = wp_request_send(vdev, &wp);
if (ret) {
@@ -598,35 +598,101 @@ static u32 pll_config_get_lnl(struct ivpu_device *vdev)
return REGB_RD32(VPU_HW_BTRS_LNL_PLL_FREQ);
}
-static u32 pll_ratio_to_dpu_freq_mtl(u16 ratio)
+static u32 pll_ratio_to_mhz_mtl(u8 pll_ratio)
{
- return (PLL_RATIO_TO_FREQ(ratio) * 2) / 3;
+ return (pll_ratio * PLL_REF_CLK_FREQ_MHZ * 2) / 3;
}
-static u32 pll_ratio_to_dpu_freq_lnl(u16 ratio)
+static u32 pll_ratio_to_mhz_lnl(u8 pll_ratio)
{
- return PLL_RATIO_TO_FREQ(ratio) / 2;
+ return (pll_ratio * PLL_REF_CLK_FREQ_MHZ) / 2;
}
-static u32 pll_ratio_to_dpu_freq(struct ivpu_device *vdev, u32 ratio)
+u32 ivpu_hw_btrs_pll_ratio_to_mhz(struct ivpu_device *vdev, u8 pll_ratio)
{
if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL)
- return pll_ratio_to_dpu_freq_mtl(ratio);
+ return pll_ratio_to_mhz_mtl(pll_ratio);
else
- return pll_ratio_to_dpu_freq_lnl(ratio);
+ return pll_ratio_to_mhz_lnl(pll_ratio);
}
-u32 ivpu_hw_btrs_dpu_max_freq_get(struct ivpu_device *vdev)
+u32 ivpu_hw_btrs_pll_ratio_to_hz(struct ivpu_device *vdev, u8 pll_ratio)
{
- return pll_ratio_to_dpu_freq(vdev, vdev->hw->pll.max_ratio);
+ return ivpu_hw_btrs_pll_ratio_to_mhz(vdev, pll_ratio) * HZ_PER_MHZ;
}
-u32 ivpu_hw_btrs_dpu_freq_get(struct ivpu_device *vdev)
+u32 ivpu_hw_btrs_current_freq_get(struct ivpu_device *vdev)
{
if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL)
- return pll_ratio_to_dpu_freq_mtl(pll_config_get_mtl(vdev));
+ return pll_ratio_to_mhz_mtl(pll_config_get_mtl(vdev));
else
- return pll_ratio_to_dpu_freq_lnl(pll_config_get_lnl(vdev));
+ return pll_ratio_to_mhz_lnl(pll_config_get_lnl(vdev));
+}
+
+static int ivpu_hw_btrs_cfg_freq_set(struct ivpu_device *vdev, u8 cfg_min_ratio, u8 cfg_max_ratio)
+{
+ u8 min_ratio = clamp_t(u8, cfg_min_ratio, vdev->hw->pll.min_ratio, cfg_max_ratio);
+ u8 pn_ratio = clamp_t(u8, vdev->hw->pll.pn_ratio, min_ratio, cfg_max_ratio);
+ int ret;
+
+ ivpu_dbg(vdev, PM, "Set frequency range to min: %u, pn: %u, max: %u MHz\n",
+ ivpu_hw_btrs_pll_ratio_to_mhz(vdev, min_ratio),
+ ivpu_hw_btrs_pll_ratio_to_mhz(vdev, pn_ratio),
+ ivpu_hw_btrs_pll_ratio_to_mhz(vdev, cfg_max_ratio));
+
+ ret = ivpu_rpm_get(vdev);
+ if (ret < 0)
+ return ret;
+
+ ret = ivpu_jsm_msg_freq_config(vdev, min_ratio, pn_ratio, cfg_max_ratio);
+ ivpu_rpm_put(vdev);
+
+ if (ret) {
+ ivpu_warn(vdev,
+ "Failed to set frequency to min: %u, pn: %u, max: %u MHz, ret %d\n",
+ ivpu_hw_btrs_pll_ratio_to_mhz(vdev, min_ratio),
+ ivpu_hw_btrs_pll_ratio_to_mhz(vdev, pn_ratio),
+ ivpu_hw_btrs_pll_ratio_to_mhz(vdev, cfg_max_ratio),
+ ret);
+ return ret;
+ }
+
+ vdev->hw->pll.cfg_min_ratio = cfg_min_ratio;
+ vdev->hw->pll.cfg_max_ratio = cfg_max_ratio;
+
+ return 0;
+}
+
+static u8 dpu_mhz_to_pll_ratio_lnl(u32 freq_mhz)
+{
+ return clamp_t(u32, freq_mhz / (PLL_REF_CLK_FREQ_MHZ / 2), 0, U8_MAX);
+}
+
+int ivpu_hw_btrs_cfg_max_freq_set(struct ivpu_device *vdev, u32 max_freq_mhz)
+{
+ u8 ratio = dpu_mhz_to_pll_ratio_lnl(max_freq_mhz);
+ u8 cfg_max_ratio = clamp_t(u8, ratio, vdev->hw->pll.min_ratio, vdev->hw->pll.max_ratio);
+
+ return ivpu_hw_btrs_cfg_freq_set(vdev, vdev->hw->pll.cfg_min_ratio, cfg_max_ratio);
+}
+
+int ivpu_hw_btrs_cfg_min_freq_set(struct ivpu_device *vdev, u32 min_freq_mhz)
+{
+ u8 ratio = dpu_mhz_to_pll_ratio_lnl(min_freq_mhz);
+ u8 cfg_min_ratio = clamp_t(u8, ratio, vdev->hw->pll.min_ratio, vdev->hw->pll.max_ratio);
+
+ return ivpu_hw_btrs_cfg_freq_set(vdev, cfg_min_ratio, vdev->hw->pll.cfg_max_ratio);
+}
+
+int ivpu_hw_btrs_cfg_freq_init(struct ivpu_device *vdev)
+{
+ if (vdev->hw->pll.min_ratio == vdev->hw->pll.cfg_min_ratio &&
+ vdev->hw->pll.max_ratio == vdev->hw->pll.cfg_max_ratio)
+ return 0;
+
+ return ivpu_hw_btrs_cfg_freq_set(vdev,
+ vdev->hw->pll.cfg_min_ratio,
+ vdev->hw->pll.cfg_max_ratio);
}
/* Handler for IRQs from Buttress core (irqB) */
@@ -641,8 +707,8 @@ bool ivpu_hw_btrs_irq_handler_mtl(struct ivpu_device *vdev, int irq)
if (REG_TEST_FLD(VPU_HW_BTRS_MTL_INTERRUPT_STAT, FREQ_CHANGE, status)) {
u32 pll = pll_config_get_mtl(vdev);
- ivpu_dbg(vdev, IRQ, "FREQ_CHANGE irq, wp %08x, %lu MHz",
- pll, pll_ratio_to_dpu_freq_mtl(pll) / HZ_PER_MHZ);
+ ivpu_dbg(vdev, IRQ, "FREQ_CHANGE irq, wp %08x, %u MHz",
+ pll, pll_ratio_to_mhz_mtl(pll));
}
if (REG_TEST_FLD(VPU_HW_BTRS_MTL_INTERRUPT_STAT, ATS_ERR, status)) {
@@ -695,8 +761,8 @@ bool ivpu_hw_btrs_irq_handler_lnl(struct ivpu_device *vdev, int irq)
if (REG_TEST_FLD(VPU_HW_BTRS_LNL_INTERRUPT_STAT, FREQ_CHANGE, status)) {
u32 pll = pll_config_get_lnl(vdev);
- ivpu_dbg(vdev, IRQ, "FREQ_CHANGE irq, wp %08x, %lu MHz",
- pll, pll_ratio_to_dpu_freq_lnl(pll) / HZ_PER_MHZ);
+ ivpu_dbg(vdev, IRQ, "FREQ_CHANGE irq, wp %08x, %u MHz",
+ pll, pll_ratio_to_mhz_lnl(pll));
}
if (REG_TEST_FLD(VPU_HW_BTRS_LNL_INTERRUPT_STAT, ATS_ERR, status)) {
diff --git a/drivers/accel/ivpu/ivpu_hw_btrs.h b/drivers/accel/ivpu/ivpu_hw_btrs.h
index c4c10e22f30f..d6343d734570 100644
--- a/drivers/accel/ivpu/ivpu_hw_btrs.h
+++ b/drivers/accel/ivpu/ivpu_hw_btrs.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright (C) 2020-2025 Intel Corporation
+ * Copyright (C) 2020-2026 Intel Corporation
*/
#ifndef __IVPU_HW_BTRS_H__
@@ -31,8 +31,12 @@ int ivpu_hw_btrs_ip_reset(struct ivpu_device *vdev);
void ivpu_hw_btrs_profiling_freq_reg_set_lnl(struct ivpu_device *vdev);
void ivpu_hw_btrs_ats_print_lnl(struct ivpu_device *vdev);
void ivpu_hw_btrs_clock_relinquish_disable_lnl(struct ivpu_device *vdev);
-u32 ivpu_hw_btrs_dpu_max_freq_get(struct ivpu_device *vdev);
-u32 ivpu_hw_btrs_dpu_freq_get(struct ivpu_device *vdev);
+u32 ivpu_hw_btrs_pll_ratio_to_mhz(struct ivpu_device *vdev, u8 pll_ratio);
+u32 ivpu_hw_btrs_pll_ratio_to_hz(struct ivpu_device *vdev, u8 pll_ratio);
+u32 ivpu_hw_btrs_current_freq_get(struct ivpu_device *vdev);
+int ivpu_hw_btrs_cfg_min_freq_set(struct ivpu_device *vdev, u32 freq_mhz);
+int ivpu_hw_btrs_cfg_max_freq_set(struct ivpu_device *vdev, u32 freq_mhz);
+int ivpu_hw_btrs_cfg_freq_init(struct ivpu_device *vdev);
bool ivpu_hw_btrs_irq_handler_mtl(struct ivpu_device *vdev, int irq);
bool ivpu_hw_btrs_irq_handler_lnl(struct ivpu_device *vdev, int irq);
int ivpu_hw_btrs_dct_get_request(struct ivpu_device *vdev, bool *enable);
diff --git a/drivers/accel/ivpu/ivpu_hw_ip.c b/drivers/accel/ivpu/ivpu_hw_ip.c
index 37f95a0551ed..81f0b1f8f5a6 100644
--- a/drivers/accel/ivpu/ivpu_hw_ip.c
+++ b/drivers/accel/ivpu/ivpu_hw_ip.c
@@ -308,26 +308,26 @@ static void pwr_island_trickle_drive_40xx(struct ivpu_device *vdev, bool enable)
static void pwr_island_drive_37xx(struct ivpu_device *vdev, bool enable)
{
- u32 val = REGV_RD32(VPU_40XX_HOST_SS_AON_PWR_ISLAND_EN0);
+ u32 val = REGV_RD32(VPU_37XX_HOST_SS_AON_PWR_ISLAND_EN0);
if (enable)
- val = REG_SET_FLD(VPU_40XX_HOST_SS_AON_PWR_ISLAND_EN0, CSS_CPU, val);
+ val = REG_SET_FLD(VPU_37XX_HOST_SS_AON_PWR_ISLAND_EN0, MSS_CPU, val);
else
- val = REG_CLR_FLD(VPU_40XX_HOST_SS_AON_PWR_ISLAND_EN0, CSS_CPU, val);
+ val = REG_CLR_FLD(VPU_37XX_HOST_SS_AON_PWR_ISLAND_EN0, MSS_CPU, val);
- REGV_WR32(VPU_40XX_HOST_SS_AON_PWR_ISLAND_EN0, val);
+ 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_37XX_HOST_SS_AON_PWR_ISLAND_EN0);
+ u32 val = REGV_RD32(VPU_40XX_HOST_SS_AON_PWR_ISLAND_EN0);
if (enable)
- val = REG_SET_FLD(VPU_37XX_HOST_SS_AON_PWR_ISLAND_EN0, MSS_CPU, val);
+ val = REG_SET_FLD(VPU_40XX_HOST_SS_AON_PWR_ISLAND_EN0, CSS_CPU, val);
else
- val = REG_CLR_FLD(VPU_37XX_HOST_SS_AON_PWR_ISLAND_EN0, MSS_CPU, val);
+ val = REG_CLR_FLD(VPU_40XX_HOST_SS_AON_PWR_ISLAND_EN0, CSS_CPU, val);
- REGV_WR32(VPU_37XX_HOST_SS_AON_PWR_ISLAND_EN0, val);
+ REGV_WR32(VPU_40XX_HOST_SS_AON_PWR_ISLAND_EN0, val);
}
static void pwr_island_enable(struct ivpu_device *vdev)
diff --git a/drivers/accel/ivpu/ivpu_jsm_msg.c b/drivers/accel/ivpu/ivpu_jsm_msg.c
index 07b1d6f615a9..17b42a76aef9 100644
--- a/drivers/accel/ivpu/ivpu_jsm_msg.c
+++ b/drivers/accel/ivpu/ivpu_jsm_msg.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (C) 2020-2024 Intel Corporation
+ * Copyright (C) 2020-2026 Intel Corporation
*/
#include "ivpu_drv.h"
@@ -86,6 +86,9 @@ const char *ivpu_jsm_msg_type_to_str(enum vpu_ipc_msg_type type)
IVPU_CASE_TO_STR(VPU_JSM_MSG_DCT_ENABLE_DONE);
IVPU_CASE_TO_STR(VPU_JSM_MSG_DCT_DISABLE);
IVPU_CASE_TO_STR(VPU_JSM_MSG_DCT_DISABLE_DONE);
+ IVPU_CASE_TO_STR(VPU_JSM_MSG_FREQ_CONFIG);
+ IVPU_CASE_TO_STR(VPU_JSM_MSG_FREQ_CONFIG_RSP);
+ IVPU_CASE_TO_STR(VPU_JSM_MSG_RESERVED_111E);
}
#undef IVPU_CASE_TO_STR
@@ -571,3 +574,16 @@ int ivpu_jsm_state_dump_no_reply(struct ivpu_device *vdev)
return ivpu_ipc_send_and_wait(vdev, &req, VPU_IPC_CHAN_ASYNC_CMD,
vdev->timeout.state_dump_msg);
}
+
+int ivpu_jsm_msg_freq_config(struct ivpu_device *vdev, u16 min_ratio, u16 pn_ratio, u16 max_ratio)
+{
+ struct vpu_jsm_msg req = { .type = VPU_JSM_MSG_FREQ_CONFIG};
+ struct vpu_jsm_msg resp;
+
+ req.payload.freq_config.min_freq_pll_ratio = min_ratio;
+ req.payload.freq_config.pn_freq_pll_ratio = pn_ratio;
+ req.payload.freq_config.max_freq_pll_ratio = max_ratio;
+
+ return ivpu_ipc_send_receive_internal(vdev, &req, VPU_JSM_MSG_FREQ_CONFIG_RSP, &resp,
+ VPU_IPC_CHAN_ASYNC_CMD, vdev->timeout.jsm);
+}
diff --git a/drivers/accel/ivpu/ivpu_jsm_msg.h b/drivers/accel/ivpu/ivpu_jsm_msg.h
index a74f5a0b0d93..28ffe07422b0 100644
--- a/drivers/accel/ivpu/ivpu_jsm_msg.h
+++ b/drivers/accel/ivpu/ivpu_jsm_msg.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright (C) 2020-2024 Intel Corporation
+ * Copyright (C) 2020-2026 Intel Corporation
*/
#ifndef __IVPU_JSM_MSG_H__
@@ -45,5 +45,6 @@ int ivpu_jsm_dct_enable(struct ivpu_device *vdev, u32 active_us, u32 inactive_us
int ivpu_jsm_dct_disable(struct ivpu_device *vdev);
int ivpu_jsm_state_dump(struct ivpu_device *vdev);
int ivpu_jsm_state_dump_no_reply(struct ivpu_device *vdev);
+int ivpu_jsm_msg_freq_config(struct ivpu_device *vdev, u16 min_ratio, u16 pn_ratio, u16 max_ratio);
#endif
diff --git a/drivers/accel/ivpu/ivpu_sysfs.c b/drivers/accel/ivpu/ivpu_sysfs.c
index d250a10caca9..95d201b3b8aa 100644
--- a/drivers/accel/ivpu/ivpu_sysfs.c
+++ b/drivers/accel/ivpu/ivpu_sysfs.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (C) 2024-2025 Intel Corporation
+ * Copyright (C) 2024-2026 Intel Corporation
*/
#include <linux/device.h>
@@ -82,8 +82,7 @@ static DEVICE_ATTR_RO(npu_memory_utilization);
* - "OS" - Operating System Scheduler mode
*
*/
-static ssize_t
-sched_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t sched_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct drm_device *drm = dev_get_drvdata(dev);
struct ivpu_device *vdev = to_ivpu_device(drm);
@@ -94,47 +93,162 @@ sched_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
static DEVICE_ATTR_RO(sched_mode);
/**
- * DOC: npu_max_frequency
+ * DOC: NPU frequency control and information
+ *
+ * Hardware frequency capabilities:
+ * freq/hw_min_freq - Minimum frequency supported by the NPU hardware.
+ * freq/hw_max_freq - Maximum frequency supported by the NPU hardware.
+ * freq/hw_efficient_freq - Most efficient operating frequency for the NPU.
+ *
+ * Configurable frequency limits (50XX devices and newer):
+ * freq/set_min_freq - Configured minimum operating frequency.
+ * freq/set_max_freq - Configured maximum operating frequency.
+ *
+ * Clamping behavior: Values written to set_min_freq and set_max_freq are
+ * clamped to hardware limits. If set_min_freq exceeds set_max_freq, the driver
+ * clamps set_min_freq to set_max_freq when selecting the operating frequency.
+ *
+ * Current operating frequency:
+ * freq/current_freq - Current frequency in MHz. Valid only when the device is
+ * active; returns 0 when idle. May be lower than the requested range due to
+ * power or thermal constraints.
*
- * The npu_max_frequency shows maximum frequency in MHz of the NPU's data
- * processing unit
+ * Legacy attributes (backward compatibility):
+ * npu_max_frequency_mhz - Alias for freq/hw_max_freq.
+ * npu_current_frequency_mhz - Alias for freq/current_freq.
*/
+
+static ssize_t hw_min_freq_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct drm_device *drm = dev_get_drvdata(dev);
+ struct ivpu_device *vdev = to_ivpu_device(drm);
+ u32 freq_mhz = ivpu_hw_btrs_pll_ratio_to_mhz(vdev, vdev->hw->pll.min_ratio);
+
+ return sysfs_emit(buf, "%u\n", freq_mhz);
+}
+
+static DEVICE_ATTR_RO(hw_min_freq);
+
+static ssize_t hw_efficient_freq_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct drm_device *drm = dev_get_drvdata(dev);
+ struct ivpu_device *vdev = to_ivpu_device(drm);
+ u32 freq_mhz = ivpu_hw_btrs_pll_ratio_to_mhz(vdev, vdev->hw->pll.pn_ratio);
+
+ return sysfs_emit(buf, "%u\n", freq_mhz);
+}
+
+static DEVICE_ATTR_RO(hw_efficient_freq);
+
+static ssize_t hw_max_freq_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct drm_device *drm = dev_get_drvdata(dev);
+ struct ivpu_device *vdev = to_ivpu_device(drm);
+ u32 freq_mhz = ivpu_hw_btrs_pll_ratio_to_mhz(vdev, vdev->hw->pll.max_ratio);
+
+ return sysfs_emit(buf, "%u\n", freq_mhz);
+}
+
+static DEVICE_ATTR_RO(hw_max_freq);
+
+static ssize_t set_min_freq_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct drm_device *drm = dev_get_drvdata(dev);
+ struct ivpu_device *vdev = to_ivpu_device(drm);
+ u32 freq_mhz = ivpu_hw_btrs_pll_ratio_to_mhz(vdev, vdev->hw->pll.cfg_min_ratio);
+
+ return sysfs_emit(buf, "%u\n", freq_mhz);
+}
+
static ssize_t
-npu_max_frequency_mhz_show(struct device *dev, struct device_attribute *attr, char *buf)
+set_min_freq_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct drm_device *drm = dev_get_drvdata(dev);
struct ivpu_device *vdev = to_ivpu_device(drm);
- u32 freq = ivpu_hw_dpu_max_freq_get(vdev);
+ u32 freq_mhz;
+ int ret;
+
+ ret = kstrtou32(buf, 10, &freq_mhz);
+ if (ret)
+ return ret;
- return sysfs_emit(buf, "%lu\n", freq / HZ_PER_MHZ);
+ ret = ivpu_hw_btrs_cfg_min_freq_set(vdev, freq_mhz);
+ if (ret)
+ return ret;
+
+ return count;
}
-static DEVICE_ATTR_RO(npu_max_frequency_mhz);
+static DEVICE_ATTR_RW(set_min_freq);
+
+static ssize_t set_max_freq_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct drm_device *drm = dev_get_drvdata(dev);
+ struct ivpu_device *vdev = to_ivpu_device(drm);
+ u32 freq_mhz = ivpu_hw_btrs_pll_ratio_to_mhz(vdev, vdev->hw->pll.cfg_max_ratio);
+
+ return sysfs_emit(buf, "%u\n", freq_mhz);
+}
-/**
- * DOC: npu_current_frequency_mhz
- *
- * The npu_current_frequency_mhz shows current frequency in MHz of the NPU's
- * data processing unit
- */
static ssize_t
-npu_current_frequency_mhz_show(struct device *dev, struct device_attribute *attr, char *buf)
+set_max_freq_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct drm_device *drm = dev_get_drvdata(dev);
+ struct ivpu_device *vdev = to_ivpu_device(drm);
+ u32 freq_mhz;
+ int ret;
+
+ ret = kstrtou32(buf, 10, &freq_mhz);
+ if (ret)
+ return ret;
+
+ /* Convert MHz to Hz and set max frequency */
+ ret = ivpu_hw_btrs_cfg_max_freq_set(vdev, freq_mhz);
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+static DEVICE_ATTR_RW(set_max_freq);
+
+static ssize_t current_freq_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct drm_device *drm = dev_get_drvdata(dev);
struct ivpu_device *vdev = to_ivpu_device(drm);
- u32 freq = 0;
+ u32 freq_mhz = 0;
/* Read frequency only if device is active, otherwise frequency is 0 */
if (pm_runtime_get_if_active(vdev->drm.dev) > 0) {
- freq = ivpu_hw_dpu_freq_get(vdev);
+ freq_mhz = ivpu_hw_btrs_current_freq_get(vdev);
pm_runtime_put_autosuspend(vdev->drm.dev);
}
- return sysfs_emit(buf, "%lu\n", freq / HZ_PER_MHZ);
+ return sysfs_emit(buf, "%u\n", freq_mhz);
}
-static DEVICE_ATTR_RO(npu_current_frequency_mhz);
+static DEVICE_ATTR_RO(current_freq);
+
+/* Alias to current_freq for legacy compat */
+static struct device_attribute dev_attr_npu_max_frequency_mhz =
+ __ATTR(npu_max_frequency_mhz, 0444, hw_max_freq_show, NULL);
+
+static struct device_attribute dev_attr_npu_current_frequency_mhz =
+ __ATTR(npu_current_frequency_mhz, 0444, current_freq_show, NULL);
+
+static struct attribute *ivpu_freq_attrs[] = {
+ &dev_attr_hw_min_freq.attr,
+ &dev_attr_hw_efficient_freq.attr,
+ &dev_attr_hw_max_freq.attr,
+ &dev_attr_current_freq.attr,
+ NULL,
+};
+
+static struct attribute_group ivpu_freq_attr_group = {
+ .name = "freq",
+ .attrs = ivpu_freq_attrs,
+};
static struct attribute *ivpu_dev_attrs[] = {
&dev_attr_npu_busy_time_us.attr,
@@ -154,6 +268,32 @@ void ivpu_sysfs_init(struct ivpu_device *vdev)
int ret;
ret = devm_device_add_group(vdev->drm.dev, &ivpu_dev_attr_group);
- if (ret)
- ivpu_warn(vdev, "Failed to add group to device, ret %d", ret);
+ if (ret) {
+ ivpu_warn(vdev, "Failed to add sysfs group to device, ret %d", ret);
+ return;
+ }
+
+ ret = devm_device_add_group(vdev->drm.dev, &ivpu_freq_attr_group);
+ if (ret) {
+ ivpu_warn(vdev, "Failed to add sysfs freq group, ret %d", ret);
+ return;
+ }
+
+ if (ivpu_hw_ip_gen(vdev) >= IVPU_HW_IP_50XX) {
+ ret = sysfs_add_file_to_group(&vdev->drm.dev->kobj,
+ &dev_attr_set_min_freq.attr,
+ "freq");
+ if (ret) {
+ ivpu_warn(vdev, "Failed to add sysfs set_min_freq to device, ret %d", ret);
+ return;
+ }
+
+ ret = sysfs_add_file_to_group(&vdev->drm.dev->kobj,
+ &dev_attr_set_max_freq.attr,
+ "freq");
+ if (ret) {
+ ivpu_warn(vdev, "Failed to add sysfs set_max_freq to device, ret %d", ret);
+ return;
+ }
+ }
}
diff --git a/drivers/accel/ivpu/vpu_jsm_api.h b/drivers/accel/ivpu/vpu_jsm_api.h
index bca6a44dc041..6d58d04cc0c4 100644
--- a/drivers/accel/ivpu/vpu_jsm_api.h
+++ b/drivers/accel/ivpu/vpu_jsm_api.h
@@ -23,7 +23,7 @@
/*
* Minor version changes when API backward compatibility is preserved.
*/
-#define VPU_JSM_API_VER_MINOR 33
+#define VPU_JSM_API_VER_MINOR 34
/*
* API header changed (field names, documentation, formatting) but API itself has not been changed
@@ -605,6 +605,16 @@ enum vpu_ipc_msg_type {
*/
VPU_JSM_MSG_DCT_DISABLE = 0x111d,
/**
+ * Reserved command ID to ensure that the following command requests /
+ * responses have the same lower byte value.
+ */
+ VPU_JSM_MSG_RESERVED_111E = 0x111e,
+ /**
+ * Control command: Configure VPU frequency scaling parameters.
+ * @see vpu_ipc_msg_payload_freq_config
+ */
+ VPU_JSM_MSG_FREQ_CONFIG = 0x111f,
+ /**
* Dump VPU state. To be used for debug purposes only.
* This command has no payload.
* NOTE: Please introduce new ASYNC commands before this one.
@@ -767,6 +777,11 @@ enum vpu_ipc_msg_type {
*/
VPU_JSM_MSG_DCT_DISABLE_DONE = 0x221e,
/**
+ * Response to control command: Configure VPU frequency scaling parameters.
+ * @see vpu_ipc_msg_payload_freq_config
+ */
+ VPU_JSM_MSG_FREQ_CONFIG_RSP = 0x221f,
+ /**
* Response to state dump control command.
* This command has no payload.
* NOTE: Please introduce new ASYNC responses before this one.
@@ -1650,6 +1665,22 @@ struct vpu_ipc_msg_payload_pwr_dct_control {
u32 dct_inactive_us;
};
+/**
+ * Payload for @ref VPU_JSM_MSG_FREQ_CONFIG message.
+ *
+ * This payload allows the host to configure the VPU frequency scaling parameters.
+ */
+struct vpu_ipc_msg_payload_freq_config {
+ /** Minimum frequency PLL ratio */
+ u32 min_freq_pll_ratio;
+ /** Efficiency frequency PLL ratio */
+ u32 pn_freq_pll_ratio;
+ /** Maximum frequency PLL ratio */
+ u32 max_freq_pll_ratio;
+ /** Reserved for 64-bit alignment */
+ u32 reserved_0;
+};
+
/*
* Payloads union, used to define complete message format.
*/
@@ -1692,6 +1723,7 @@ union vpu_ipc_msg_payload {
struct vpu_ipc_msg_payload_hws_resume_engine hws_resume_engine;
struct vpu_ipc_msg_payload_pwr_d0i3_enter pwr_d0i3_enter;
struct vpu_ipc_msg_payload_pwr_dct_control pwr_dct_control;
+ struct vpu_ipc_msg_payload_freq_config freq_config;
};
/**
diff --git a/drivers/dma-buf/dma-fence-array.c b/drivers/dma-buf/dma-fence-array.c
index 089f69469524..5e10e8df372f 100644
--- a/drivers/dma-buf/dma-fence-array.c
+++ b/drivers/dma-buf/dma-fence-array.c
@@ -190,15 +190,13 @@ EXPORT_SYMBOL(dma_fence_array_alloc);
* @fences: [in] array containing the fences
* @context: [in] fence context to use
* @seqno: [in] sequence number to use
- * @signal_on_any: [in] signal on any fence in the array
*
* Implementation of @dma_fence_array_create without allocation. Useful to init
* a preallocated dma fence array in the path of reclaim or dma fence signaling.
*/
void dma_fence_array_init(struct dma_fence_array *array,
int num_fences, struct dma_fence **fences,
- u64 context, unsigned seqno,
- bool signal_on_any)
+ u64 context, unsigned seqno)
{
static struct lock_class_key dma_fence_array_lock_key;
@@ -222,7 +220,7 @@ void dma_fence_array_init(struct dma_fence_array *array,
*/
lockdep_set_class(&array->base.inline_lock, &dma_fence_array_lock_key);
- atomic_set(&array->num_pending, signal_on_any ? 1 : num_fences);
+ atomic_set(&array->num_pending, num_fences);
array->fences = fences;
array->base.error = PENDING_ERROR;
@@ -249,7 +247,6 @@ EXPORT_SYMBOL(dma_fence_array_init);
* @fences: [in] array containing the fences
* @context: [in] fence context to use
* @seqno: [in] sequence number to use
- * @signal_on_any: [in] signal on any fence in the array
*
* Allocate a dma_fence_array object and initialize the base fence with
* dma_fence_init().
@@ -264,8 +261,7 @@ EXPORT_SYMBOL(dma_fence_array_init);
*/
struct dma_fence_array *dma_fence_array_create(int num_fences,
struct dma_fence **fences,
- u64 context, unsigned seqno,
- bool signal_on_any)
+ u64 context, unsigned seqno)
{
struct dma_fence_array *array;
@@ -273,8 +269,7 @@ struct dma_fence_array *dma_fence_array_create(int num_fences,
if (!array)
return NULL;
- dma_fence_array_init(array, num_fences, fences,
- context, seqno, signal_on_any);
+ dma_fence_array_init(array, num_fences, fences, context, seqno);
return array;
}
diff --git a/drivers/dma-buf/dma-fence-unwrap.c b/drivers/dma-buf/dma-fence-unwrap.c
index 07fe9bf45aea..53bb40e70b27 100644
--- a/drivers/dma-buf/dma-fence-unwrap.c
+++ b/drivers/dma-buf/dma-fence-unwrap.c
@@ -180,8 +180,7 @@ struct dma_fence *__dma_fence_unwrap_merge(unsigned int num_fences,
if (count > 1) {
result = dma_fence_array_create(count, array,
- dma_fence_context_alloc(1),
- 1, false);
+ dma_fence_context_alloc(1), 1);
if (!result) {
for (i = 0; i < count; i++)
dma_fence_put(array[i]);
diff --git a/drivers/dma-buf/dma-resv.c b/drivers/dma-buf/dma-resv.c
index ce9e6c04897f..39a92d9f2413 100644
--- a/drivers/dma-buf/dma-resv.c
+++ b/drivers/dma-buf/dma-resv.c
@@ -648,8 +648,7 @@ int dma_resv_get_singleton(struct dma_resv *obj, enum dma_resv_usage usage,
}
array = dma_fence_array_create(count, fences,
- dma_fence_context_alloc(1),
- 1, false);
+ dma_fence_context_alloc(1), 1);
if (!array) {
while (count--)
dma_fence_put(fences[count]);
diff --git a/drivers/dma-buf/st-dma-fence-unwrap.c b/drivers/dma-buf/st-dma-fence-unwrap.c
index 51c87869b7b8..4e7ee25372ba 100644
--- a/drivers/dma-buf/st-dma-fence-unwrap.c
+++ b/drivers/dma-buf/st-dma-fence-unwrap.c
@@ -64,7 +64,7 @@ static struct dma_fence *mock_array(unsigned int num_fences, ...)
array = dma_fence_array_create(num_fences, fences,
dma_fence_context_alloc(1),
- 1, false);
+ 1);
if (!array)
goto error_free;
return &array->base;
diff --git a/drivers/gpu/drm/adp/adp_drv.c b/drivers/gpu/drm/adp/adp_drv.c
index a5913c71b39c..ce9dd6222634 100644
--- a/drivers/gpu/drm/adp/adp_drv.c
+++ b/drivers/gpu/drm/adp/adp_drv.c
@@ -444,8 +444,6 @@ static int adp_setup_mode_config(struct adp_drv_private *adp)
if (IS_ERR(adp->connector))
return PTR_ERR(adp->connector);
- drm_connector_attach_encoder(adp->connector, adp->encoder);
-
ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
if (ret < 0) {
drm_err(drm, "failed to initialize vblank");
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
index b47d8eea4566..821a3008a1e7 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
@@ -768,8 +768,6 @@ static int adv7511_connector_init(struct adv7511 *adv)
return PTR_ERR(connector);
}
- drm_connector_attach_encoder(connector, bridge->encoder);
-
return 0;
}
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 6bfb43b07604..8cf6b73bceac 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -1486,7 +1486,7 @@ int analogix_dp_bind(struct analogix_dp_device *dp, struct drm_device *drm_dev)
dp->plat_data->next_bridge = devm_drm_panel_bridge_add(dp->dev,
dp->plat_data->panel);
if (IS_ERR(dp->plat_data->next_bridge)) {
- ret = PTR_ERR(bridge);
+ ret = PTR_ERR(dp->plat_data->next_bridge);
goto err_unregister_aux;
}
}
diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
index 50ea40a6ae05..cf90d4468b5c 100644
--- a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
+++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
@@ -1230,7 +1230,7 @@ static const struct mipi_dsi_host_ops cdns_dsi_ops = {
.transfer = cdns_dsi_transfer,
};
-static int __maybe_unused cdns_dsi_resume(struct device *dev)
+static int cdns_dsi_resume(struct device *dev)
{
struct cdns_dsi *dsi = dev_get_drvdata(dev);
@@ -1241,7 +1241,7 @@ static int __maybe_unused cdns_dsi_resume(struct device *dev)
return 0;
}
-static int __maybe_unused cdns_dsi_suspend(struct device *dev)
+static int cdns_dsi_suspend(struct device *dev)
{
struct cdns_dsi *dsi = dev_get_drvdata(dev);
@@ -1251,8 +1251,9 @@ static int __maybe_unused cdns_dsi_suspend(struct device *dev)
return 0;
}
-static UNIVERSAL_DEV_PM_OPS(cdns_dsi_pm_ops, cdns_dsi_suspend, cdns_dsi_resume,
- NULL);
+static const struct dev_pm_ops cdns_dsi_pm_ops = {
+ RUNTIME_PM_OPS(cdns_dsi_suspend, cdns_dsi_resume, NULL)
+};
static int cdns_dsi_drm_probe(struct platform_device *pdev)
{
@@ -1399,7 +1400,7 @@ static struct platform_driver cdns_dsi_platform_driver = {
.driver = {
.name = "cdns-dsi",
.of_match_table = cdns_dsi_of_match,
- .pm = &cdns_dsi_pm_ops,
+ .pm = pm_ptr(&cdns_dsi_pm_ops),
},
};
module_platform_driver(cdns_dsi_platform_driver);
diff --git a/drivers/gpu/drm/bridge/ite-it6263.c b/drivers/gpu/drm/bridge/ite-it6263.c
index 48499aaba6a9..c7d588be12cb 100644
--- a/drivers/gpu/drm/bridge/ite-it6263.c
+++ b/drivers/gpu/drm/bridge/ite-it6263.c
@@ -200,6 +200,7 @@ struct it6263 {
struct regmap *lvds_regmap;
struct drm_bridge bridge;
struct drm_bridge *next_bridge;
+ struct gpio_desc *reset_gpio;
int lvds_data_mapping;
bool lvds_dual_link;
bool lvds_link12_swap;
@@ -603,6 +604,15 @@ static void it6263_bridge_atomic_enable(struct drm_bridge *bridge,
bool pclk_high;
int i, ret;
+ it6263_hw_reset(it->reset_gpio);
+
+ ret = it6263_lvds_set_i2c_addr(it);
+ if (ret)
+ dev_err(it->dev, "failed to set I2C addr\n");
+
+ it6263_lvds_config(it);
+ it6263_hdmi_config(it);
+
connector = drm_atomic_get_new_connector_for_encoder(state,
bridge->encoder);
crtc = drm_atomic_get_new_connector_state(state, connector)->crtc;
@@ -697,8 +707,6 @@ static int it6263_bridge_attach(struct drm_bridge *bridge,
return ret;
}
- drm_connector_attach_encoder(connector, encoder);
-
return 0;
}
@@ -815,7 +823,6 @@ static int it6263_hdmi_write_hdmi_infoframe(struct drm_bridge *bridge,
regmap_write(regmap, HDMI_REG_PKT_NULL_CTRL,
ENABLE_PKT | REPEAT_PKT);
-
return 0;
}
@@ -840,7 +847,6 @@ static const struct drm_bridge_funcs it6263_bridge_funcs = {
static int it6263_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
- struct gpio_desc *reset_gpio;
struct it6263 *it;
int ret;
@@ -858,9 +864,9 @@ static int it6263_probe(struct i2c_client *client)
return dev_err_probe(dev, PTR_ERR(it->hdmi_regmap),
"failed to init I2C regmap for HDMI\n");
- reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
- if (IS_ERR(reset_gpio))
- return dev_err_probe(dev, PTR_ERR(reset_gpio),
+ it->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(it->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(it->reset_gpio),
"failed to get reset gpio\n");
ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(it6263_supplies),
@@ -872,12 +878,6 @@ static int it6263_probe(struct i2c_client *client)
if (ret)
return ret;
- it6263_hw_reset(reset_gpio);
-
- ret = it6263_lvds_set_i2c_addr(it);
- if (ret)
- return dev_err_probe(dev, ret, "failed to set I2C addr\n");
-
it->lvds_i2c = devm_i2c_new_dummy_device(dev, client->adapter,
LVDS_INPUT_CTRL_I2C_ADDR);
if (IS_ERR(it->lvds_i2c))
@@ -890,9 +890,6 @@ static int it6263_probe(struct i2c_client *client)
return dev_err_probe(dev, PTR_ERR(it->lvds_regmap),
"failed to init I2C regmap for LVDS\n");
- it6263_lvds_config(it);
- it6263_hdmi_config(it);
-
i2c_set_clientdata(client, it);
it->bridge.of_node = dev->of_node;
diff --git a/drivers/gpu/drm/bridge/ite-it6505.c b/drivers/gpu/drm/bridge/ite-it6505.c
index 0651e44fc07e..6b7cb132a437 100644
--- a/drivers/gpu/drm/bridge/ite-it6505.c
+++ b/drivers/gpu/drm/bridge/ite-it6505.c
@@ -2048,7 +2048,7 @@ static void it6505_start_hdcp(struct it6505 *it6505)
DRM_DEV_DEBUG_DRIVER(dev, "start");
it6505_reset_hdcp(it6505);
- queue_delayed_work(system_wq, &it6505->hdcp_work,
+ queue_delayed_work(system_percpu_wq, &it6505->hdcp_work,
msecs_to_jiffies(2400));
}
diff --git a/drivers/gpu/drm/bridge/lontium-lt8912b.c b/drivers/gpu/drm/bridge/lontium-lt8912b.c
index 8a0b48efca58..729b12b67470 100644
--- a/drivers/gpu/drm/bridge/lontium-lt8912b.c
+++ b/drivers/gpu/drm/bridge/lontium-lt8912b.c
@@ -493,6 +493,7 @@ static int lt8912_attach_dsi(struct lt8912 *lt)
dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
MIPI_DSI_MODE_LPM |
+ MIPI_DSI_MODE_VIDEO_NO_HFP |
MIPI_DSI_MODE_NO_EOT_PACKET;
ret = devm_mipi_dsi_attach(dev, dsi);
diff --git a/drivers/gpu/drm/bridge/microchip-lvds.c b/drivers/gpu/drm/bridge/microchip-lvds.c
index 9f4ff82bc6b4..12fc442f9867 100644
--- a/drivers/gpu/drm/bridge/microchip-lvds.c
+++ b/drivers/gpu/drm/bridge/microchip-lvds.c
@@ -11,6 +11,7 @@
#include <linux/component.h>
#include <linux/delay.h>
#include <linux/jiffies.h>
+#include <linux/media-bus-format.h>
#include <linux/mfd/syscon.h>
#include <linux/of_graph.h>
#include <linux/pinctrl/devinfo.h>
@@ -23,7 +24,6 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_of.h>
-#include <drm/drm_panel.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_simple_kms_helper.h>
@@ -41,9 +41,11 @@
/* Bitfields in LVDSC_CFGR (Configuration Register) */
#define LVDSC_CFGR_PIXSIZE_24BITS 0
+#define LVDSC_CFGR_PIXSIZE_18BITS BIT(0)
#define LVDSC_CFGR_DEN_POL_HIGH 0
#define LVDSC_CFGR_DC_UNBALANCED 0
#define LVDSC_CFGR_MAPPING_JEIDA BIT(6)
+#define LVDSC_CFGR_MAPPING_VESA 0
/*Bitfields in LVDSC_SR */
#define LVDSC_SR_CS BIT(0)
@@ -56,7 +58,6 @@ struct mchp_lvds {
struct device *dev;
void __iomem *regs;
struct clk *pclk;
- struct drm_panel *panel;
struct drm_bridge bridge;
struct drm_bridge *panel_bridge;
};
@@ -76,9 +77,10 @@ static inline void lvds_writel(struct mchp_lvds *lvds, u32 offset, u32 val)
writel_relaxed(val, lvds->regs + offset);
}
-static void lvds_serialiser_on(struct mchp_lvds *lvds)
+static void lvds_serialiser_on(struct mchp_lvds *lvds, u32 bus_format)
{
unsigned long timeout = jiffies + msecs_to_jiffies(LVDS_POLL_TIMEOUT_MS);
+ u8 map, pix_size;
/* The LVDSC registers can only be written if WPEN is cleared */
lvds_writel(lvds, LVDSC_WPMR, (LVDSC_WPMR_WPKEY_PSSWD &
@@ -93,11 +95,24 @@ static void lvds_serialiser_on(struct mchp_lvds *lvds)
usleep_range(1000, 2000);
}
+ switch (bus_format) {
+ case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
+ map = LVDSC_CFGR_MAPPING_JEIDA;
+ pix_size = LVDSC_CFGR_PIXSIZE_18BITS;
+ break;
+ case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:
+ map = LVDSC_CFGR_MAPPING_VESA;
+ pix_size = LVDSC_CFGR_PIXSIZE_24BITS;
+ break;
+ default:
+ map = LVDSC_CFGR_MAPPING_JEIDA;
+ pix_size = LVDSC_CFGR_PIXSIZE_24BITS;
+ break;
+ }
+
/* Configure the LVDSC */
- lvds_writel(lvds, LVDSC_CFGR, (LVDSC_CFGR_MAPPING_JEIDA |
- LVDSC_CFGR_DC_UNBALANCED |
- LVDSC_CFGR_DEN_POL_HIGH |
- LVDSC_CFGR_PIXSIZE_24BITS));
+ lvds_writel(lvds, LVDSC_CFGR, map | LVDSC_CFGR_DC_UNBALANCED |
+ LVDSC_CFGR_DEN_POL_HIGH | pix_size);
/* Enable the LVDS serializer */
lvds_writel(lvds, LVDSC_CR, LVDSC_CR_SER_EN);
@@ -113,9 +128,11 @@ static int mchp_lvds_attach(struct drm_bridge *bridge,
bridge, flags);
}
-static void mchp_lvds_enable(struct drm_bridge *bridge)
+static void mchp_lvds_atomic_enable(struct drm_bridge *bridge,
+ struct drm_atomic_state *state)
{
struct mchp_lvds *lvds = bridge_to_lvds(bridge);
+ struct drm_connector *connector;
int ret;
ret = clk_prepare_enable(lvds->pclk);
@@ -130,10 +147,18 @@ static void mchp_lvds_enable(struct drm_bridge *bridge)
return;
}
- lvds_serialiser_on(lvds);
+ /* default to jeida-24 */
+ u32 bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA;
+
+ connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder);
+ if (connector && connector->display_info.num_bus_formats)
+ bus_format = connector->display_info.bus_formats[0];
+
+ lvds_serialiser_on(lvds, bus_format);
}
-static void mchp_lvds_disable(struct drm_bridge *bridge)
+static void mchp_lvds_atomic_disable(struct drm_bridge *bridge,
+ struct drm_atomic_state *state)
{
struct mchp_lvds *lvds = bridge_to_lvds(bridge);
@@ -143,15 +168,14 @@ static void mchp_lvds_disable(struct drm_bridge *bridge)
static const struct drm_bridge_funcs mchp_lvds_bridge_funcs = {
.attach = mchp_lvds_attach,
- .enable = mchp_lvds_enable,
- .disable = mchp_lvds_disable,
+ .atomic_enable = mchp_lvds_atomic_enable,
+ .atomic_disable = mchp_lvds_atomic_disable,
};
static int mchp_lvds_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct mchp_lvds *lvds;
- struct device_node *port;
int ret;
if (!dev->of_node)
@@ -173,19 +197,6 @@ static int mchp_lvds_probe(struct platform_device *pdev)
return dev_err_probe(lvds->dev, PTR_ERR(lvds->pclk),
"could not get pclk_lvds\n");
- port = of_graph_get_remote_node(dev->of_node, 1, 0);
- if (!port) {
- dev_err(dev,
- "can't find port point, please init lvds panel port!\n");
- return -ENODEV;
- }
-
- lvds->panel = of_drm_find_panel(port);
- of_node_put(port);
-
- if (IS_ERR(lvds->panel))
- return -EPROBE_DEFER;
-
lvds->panel_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0);
if (IS_ERR(lvds->panel_bridge))
diff --git a/drivers/gpu/drm/bridge/simple-bridge.c b/drivers/gpu/drm/bridge/simple-bridge.c
index 8aa31ca3c72d..cc13c98f9be6 100644
--- a/drivers/gpu/drm/bridge/simple-bridge.c
+++ b/drivers/gpu/drm/bridge/simple-bridge.c
@@ -271,6 +271,11 @@ static const struct of_device_id simple_bridge_match[] = {
.connector_type = DRM_MODE_CONNECTOR_HDMIA,
},
}, {
+ .compatible = "mstar,tsumu88adt3-lf-1",
+ .data = &(const struct simple_bridge_info) {
+ .connector_type = DRM_MODE_CONNECTOR_HDMIA,
+ },
+ }, {
.compatible = "parade,ps185hdm",
.data = &(const struct simple_bridge_info) {
.connector_type = DRM_MODE_CONNECTOR_HDMIA,
diff --git a/drivers/gpu/drm/bridge/tc358768.c b/drivers/gpu/drm/bridge/tc358768.c
index e652a2bcd64a..0f2820b37302 100644
--- a/drivers/gpu/drm/bridge/tc358768.c
+++ b/drivers/gpu/drm/bridge/tc358768.c
@@ -45,6 +45,9 @@
/* Debug (16-bit addressable) */
#define TC358768_VBUFCTRL 0x00E0
+#define TC358768_VBUFCTRL_VBUF_EN BIT(15)
+#define TC358768_VBUFCTRL_TX_EN BIT(14)
+#define TC358768_VBUFCTRL_MASK BIT(13)
#define TC358768_DBG_WIDTH 0x00E2
#define TC358768_DBG_VBLANK 0x00E4
#define TC358768_DBG_DATA 0x00E8
@@ -115,7 +118,7 @@
#define TC358768_DSI_HACT 0x062C
/* TC358768_DSI_CONTROL (0x040C) register */
-#define TC358768_DSI_CONTROL_DIS_MODE BIT(15)
+#define TC358768_DSI_CONTROL_DSI_MODE BIT(15)
#define TC358768_DSI_CONTROL_TXMD BIT(7)
#define TC358768_DSI_CONTROL_HSCKMD BIT(5)
#define TC358768_DSI_CONTROL_EOTDIS BIT(0)
@@ -123,7 +126,7 @@
/* TC358768_DSI_CONFW (0x0500) register */
#define TC358768_DSI_CONFW_MODE_SET (5 << 29)
#define TC358768_DSI_CONFW_MODE_CLR (6 << 29)
-#define TC358768_DSI_CONFW_ADDR_DSI_CONTROL (0x3 << 24)
+#define TC358768_DSI_CONFW_ADDR(x) ((x) << 24)
/* TC358768_DSICMD_TX (0x0600) register */
#define TC358768_DSI_CMDTX_DC_START BIT(0)
@@ -232,6 +235,36 @@ static void tc358768_update_bits(struct tc358768_priv *priv, u32 reg, u32 mask,
tc358768_write(priv, reg, tmp);
}
+static void tc358768_confw_update_bits(struct tc358768_priv *priv, u16 reg,
+ u16 mask, u16 val)
+{
+ u8 confw_addr;
+ u32 confw_val;
+
+ switch (reg) {
+ case TC358768_DSI_CONTROL:
+ confw_addr = 0x3;
+ break;
+ default:
+ priv->error = -EINVAL;
+ return;
+ }
+
+ if (mask != val) {
+ confw_val = TC358768_DSI_CONFW_MODE_CLR |
+ TC358768_DSI_CONFW_ADDR(confw_addr) |
+ mask;
+ tc358768_write(priv, TC358768_DSI_CONFW, confw_val);
+ }
+
+ if (val & mask) {
+ confw_val = TC358768_DSI_CONFW_MODE_SET |
+ TC358768_DSI_CONFW_ADDR(confw_addr) |
+ (val & mask);
+ tc358768_write(priv, TC358768_DSI_CONFW, confw_val);
+ }
+}
+
static void tc358768_dsicmd_tx(struct tc358768_priv *priv)
{
u32 val;
@@ -448,6 +481,8 @@ static int tc358768_dsi_host_attach(struct mipi_dsi_host *host,
DRM_MODE_CONNECTOR_DSI);
if (IS_ERR(bridge))
return PTR_ERR(bridge);
+
+ bridge->pre_enable_prev_first = true;
}
priv->output.dev = dev;
@@ -505,9 +540,21 @@ static ssize_t tc358768_dsi_host_transfer(struct mipi_dsi_host *host,
return -ENOTSUPP;
}
+ if (msg->tx_len > 1024) {
+ dev_warn(priv->dev, "Maximum 1024 byte MIPI tx is supported\n");
+ return -EINVAL;
+ }
+
if (msg->tx_len > 8) {
- dev_warn(priv->dev, "Maximum 8 byte MIPI tx is supported\n");
- return -ENOTSUPP;
+ u32 confctl;
+
+ tc358768_read(priv, TC358768_CONFCTL, &confctl);
+
+ if (confctl & BIT(6)) {
+ dev_warn(priv->dev,
+ "Video is currently active. Unable to transmit long command\n");
+ return -EBUSY;
+ }
}
ret = mipi_dsi_create_packet(&packet, msg);
@@ -520,23 +567,66 @@ static ssize_t tc358768_dsi_host_transfer(struct mipi_dsi_host *host,
tc358768_write(priv, TC358768_DSICMD_WC, 0);
tc358768_write(priv, TC358768_DSICMD_WD0,
(packet.header[2] << 8) | packet.header[1]);
- } else {
- int i;
-
+ tc358768_dsicmd_tx(priv);
+ } else if (packet.payload_length <= 8) {
tc358768_write(priv, TC358768_DSICMD_TYPE,
(0x40 << 8) | (packet.header[0] & 0x3f));
tc358768_write(priv, TC358768_DSICMD_WC, packet.payload_length);
- for (i = 0; i < packet.payload_length; i += 2) {
+
+ for (int i = 0; i < packet.payload_length; i += 2) {
u16 val = packet.payload[i];
if (i + 1 < packet.payload_length)
val |= packet.payload[i + 1] << 8;
-
tc358768_write(priv, TC358768_DSICMD_WD0 + i, val);
}
- }
- tc358768_dsicmd_tx(priv);
+ tc358768_dsicmd_tx(priv);
+ } else {
+ unsigned long tx_sleep_us;
+ size_t len;
+
+ /* For packets over 8 bytes we need to use the video buffer */
+ tc358768_write(priv, TC358768_DATAFMT, BIT(0)); /* txdt_en */
+ tc358768_write(priv, TC358768_DSITX_DT, packet.header[0] & 0x3f);
+ tc358768_write(priv, TC358768_CMDBYTE, packet.payload_length);
+ tc358768_write(priv, TC358768_VBUFCTRL, TC358768_VBUFCTRL_VBUF_EN);
+
+ /*
+ * Write the payload in 2-byte chunks, and pad with zeroes to
+ * align to 4 bytes.
+ */
+ len = ALIGN(packet.payload_length, 4);
+
+ for (int i = 0; i < len; i += 2) {
+ u16 val = 0;
+
+ if (i < packet.payload_length)
+ val |= packet.payload[i];
+ if (i + 1 < packet.payload_length)
+ val |= packet.payload[i + 1] << 8;
+
+ tc358768_write(priv, TC358768_DBG_DATA, val);
+ }
+
+ /* Start transmission */
+ tc358768_write(priv, TC358768_VBUFCTRL,
+ TC358768_VBUFCTRL_VBUF_EN |
+ TC358768_VBUFCTRL_TX_EN |
+ TC358768_VBUFCTRL_MASK);
+
+ /*
+ * The TC358768 spec says to wait until the transmission has
+ * been finished, estimating the sleep time based on the payload
+ * and clock rates. We use a simple safe estimate of 2us per
+ * byte (LP mode transmission).
+ */
+ tx_sleep_us = packet.payload_length * 2;
+ usleep_range(tx_sleep_us, tx_sleep_us * 2);
+
+ tc358768_write(priv, TC358768_VBUFCTRL, TC358768_VBUFCTRL_MASK);
+ tc358768_write(priv, TC358768_VBUFCTRL, 0); /* Stop transmission */
+ }
ret = tc358768_clear_error(priv);
if (ret)
@@ -690,8 +780,7 @@ static void tc358768_bridge_atomic_pre_enable(struct drm_bridge *bridge,
{
struct tc358768_priv *priv = bridge_to_tc358768(bridge);
struct mipi_dsi_device *dsi_dev = priv->output.dev;
- unsigned long mode_flags = dsi_dev->mode_flags;
- u32 val, val2, lptxcnt, hact, data_type;
+ u32 val, mask, val2, lptxcnt, hact;
s32 raw_val;
struct drm_crtc_state *crtc_state;
struct drm_connector_state *conn_state;
@@ -712,11 +801,6 @@ static void tc358768_bridge_atomic_pre_enable(struct drm_bridge *bridge,
u32 dsi_vsdly;
const u32 internal_dly = 40;
- if (mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) {
- dev_warn_once(dev, "Non-continuous mode unimplemented, falling back to continuous\n");
- mode_flags &= ~MIPI_DSI_CLOCK_NON_CONTINUOUS;
- }
-
tc358768_hw_enable(priv);
ret = tc358768_sw_reset(priv);
@@ -726,6 +810,9 @@ static void tc358768_bridge_atomic_pre_enable(struct drm_bridge *bridge,
return;
}
+ /* Release RstPtr so that the video buffer can be used for DSI commands */
+ tc358768_update_bits(priv, TC358768_PP_MISC, BIT(14), 0);
+
connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder);
conn_state = drm_atomic_get_new_connector_state(state, connector);
crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
@@ -742,30 +829,20 @@ static void tc358768_bridge_atomic_pre_enable(struct drm_bridge *bridge,
dsiclk = priv->dsiclk;
hsbyteclk = dsiclk / 4;
- /* Data Format Control Register */
- val = BIT(2) | BIT(1) | BIT(0); /* rdswap_en | dsitx_en | txdt_en */
switch (dsi_dev->format) {
case MIPI_DSI_FMT_RGB888:
- val |= (0x3 << 4);
hact = vm.hactive * 3;
- data_type = MIPI_DSI_PACKED_PIXEL_STREAM_24;
break;
case MIPI_DSI_FMT_RGB666:
- val |= (0x4 << 4);
hact = vm.hactive * 3;
- data_type = MIPI_DSI_PACKED_PIXEL_STREAM_18;
break;
case MIPI_DSI_FMT_RGB666_PACKED:
- val |= (0x4 << 4) | BIT(3);
hact = vm.hactive * 18 / 8;
- data_type = MIPI_DSI_PIXEL_STREAM_3BYTE_18;
break;
case MIPI_DSI_FMT_RGB565:
- val |= (0x5 << 4);
hact = vm.hactive * 2;
- data_type = MIPI_DSI_PACKED_PIXEL_STREAM_16;
break;
default:
dev_err(dev, "Invalid data format (%u)\n",
@@ -921,9 +998,6 @@ static void tc358768_bridge_atomic_pre_enable(struct drm_bridge *bridge,
/* VSDly[9:0] */
tc358768_write(priv, TC358768_VSDLY, dsi_vsdly - internal_dly);
- tc358768_write(priv, TC358768_DATAFMT, val);
- tc358768_write(priv, TC358768_DSITX_DT, data_type);
-
/* Enable D-PHY (HiZ->LP11) */
tc358768_write(priv, TC358768_CLW_CNTRL, 0x0000);
/* Enable lanes */
@@ -1000,7 +1074,7 @@ static void tc358768_bridge_atomic_pre_enable(struct drm_bridge *bridge,
tc358768_write(priv, TC358768_HSTXVREGEN, val);
tc358768_write(priv, TC358768_TXOPTIONCNTRL,
- (mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) ? 0 : BIT(0));
+ (dsi_dev->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) ? 0 : BIT(0));
/* TXTAGOCNT[26:16] RXTASURECNT[10:0] */
val = tc358768_ps_to_ns((lptxcnt + 1) * hsbyteclk_ps * 4);
@@ -1063,33 +1137,63 @@ static void tc358768_bridge_atomic_pre_enable(struct drm_bridge *bridge,
tc358768_write(priv, TC358768_DSI_START, 0x1);
/* Configure DSI_Control register */
- val = TC358768_DSI_CONFW_MODE_CLR | TC358768_DSI_CONFW_ADDR_DSI_CONTROL;
- val |= TC358768_DSI_CONTROL_TXMD | TC358768_DSI_CONTROL_HSCKMD |
- 0x3 << 1 | TC358768_DSI_CONTROL_EOTDIS;
- tc358768_write(priv, TC358768_DSI_CONFW, val);
+ val = (dsi_dev->lanes - 1) << 1;
- val = TC358768_DSI_CONFW_MODE_SET | TC358768_DSI_CONFW_ADDR_DSI_CONTROL;
- val |= (dsi_dev->lanes - 1) << 1;
+ if (!(dsi_dev->mode_flags & MIPI_DSI_MODE_LPM))
+ val |= TC358768_DSI_CONTROL_TXMD;
- val |= TC358768_DSI_CONTROL_TXMD;
-
- if (!(mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS))
+ if (!(dsi_dev->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS))
val |= TC358768_DSI_CONTROL_HSCKMD;
if (dsi_dev->mode_flags & MIPI_DSI_MODE_NO_EOT_PACKET)
val |= TC358768_DSI_CONTROL_EOTDIS;
- tc358768_write(priv, TC358768_DSI_CONFW, val);
+ mask = TC358768_DSI_CONTROL_TXMD | TC358768_DSI_CONTROL_HSCKMD |
+ 0x3 << 1 | TC358768_DSI_CONTROL_EOTDIS;
+
+ tc358768_confw_update_bits(priv, TC358768_DSI_CONTROL, mask, val);
- val = TC358768_DSI_CONFW_MODE_CLR | TC358768_DSI_CONFW_ADDR_DSI_CONTROL;
- val |= TC358768_DSI_CONTROL_DIS_MODE; /* DSI mode */
- tc358768_write(priv, TC358768_DSI_CONFW, val);
+ tc358768_confw_update_bits(priv, TC358768_DSI_CONTROL,
+ TC358768_DSI_CONTROL_DSI_MODE, 0);
ret = tc358768_clear_error(priv);
if (ret)
dev_err(dev, "Bridge pre_enable failed: %d\n", ret);
}
+static void tc358768_config_video_format(struct tc358768_priv *priv)
+{
+ struct mipi_dsi_device *dsi_dev = priv->output.dev;
+ u32 val, data_type;
+
+ /* Data Format Control Register */
+ val = BIT(2) | BIT(1) | BIT(0); /* rdswap_en | dsitx_en | txdt_en */
+ switch (dsi_dev->format) {
+ case MIPI_DSI_FMT_RGB888:
+ val |= (0x3 << 4);
+ data_type = MIPI_DSI_PACKED_PIXEL_STREAM_24;
+ break;
+ case MIPI_DSI_FMT_RGB666:
+ val |= (0x4 << 4);
+ data_type = MIPI_DSI_PACKED_PIXEL_STREAM_18;
+ break;
+ case MIPI_DSI_FMT_RGB666_PACKED:
+ val |= (0x4 << 4) | BIT(3);
+ data_type = MIPI_DSI_PIXEL_STREAM_3BYTE_18;
+ break;
+ case MIPI_DSI_FMT_RGB565:
+ val |= (0x5 << 4);
+ data_type = MIPI_DSI_PACKED_PIXEL_STREAM_16;
+ break;
+ default:
+ dev_err(priv->dev, "Invalid data format (%u)\n", dsi_dev->format);
+ return;
+ }
+
+ tc358768_write(priv, TC358768_DATAFMT, val);
+ tc358768_write(priv, TC358768_DSITX_DT, data_type);
+}
+
static void tc358768_bridge_atomic_enable(struct drm_bridge *bridge,
struct drm_atomic_commit *state)
{
@@ -1101,6 +1205,14 @@ static void tc358768_bridge_atomic_enable(struct drm_bridge *bridge,
return;
}
+ /* Configure video format registers */
+ tc358768_config_video_format(priv);
+
+ /* Enable HS mode for video TX */
+ tc358768_confw_update_bits(priv, TC358768_DSI_CONTROL,
+ TC358768_DSI_CONTROL_TXMD,
+ TC358768_DSI_CONTROL_TXMD);
+
/* clear FrmStop and RstPtr */
tc358768_update_bits(priv, TC358768_PP_MISC, 0x3 << 14, 0);
diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi83.c b/drivers/gpu/drm/bridge/ti-sn65dsi83.c
index 108953a8fa45..42b451432bbb 100644
--- a/drivers/gpu/drm/bridge/ti-sn65dsi83.c
+++ b/drivers/gpu/drm/bridge/ti-sn65dsi83.c
@@ -114,6 +114,7 @@
#define REG_VID_CHA_HORIZONTAL_FRONT_PORCH 0x38
#define REG_VID_CHA_VERTICAL_FRONT_PORCH 0x3a
#define REG_VID_CHA_TEST_PATTERN 0x3c
+#define REG_VID_CHA_TEST_PATTERN_EN BIT(4)
/* IRQ registers */
#define REG_IRQ_GLOBAL 0xe0
#define REG_IRQ_GLOBAL_IRQ_EN BIT(0)
@@ -134,6 +135,9 @@
#define REG_IRQ_STAT_CHA_SOT_BIT_ERR BIT(2)
#define REG_IRQ_STAT_CHA_PLL_UNLOCK BIT(0)
+static bool sn65dsi83_test_pattern;
+module_param_named(test_pattern, sn65dsi83_test_pattern, bool, 0644);
+
enum sn65dsi83_channel {
CHANNEL_A,
CHANNEL_B
@@ -523,6 +527,7 @@ static void sn65dsi83_atomic_pre_enable(struct drm_bridge *bridge,
const struct drm_display_mode *mode;
struct drm_connector *connector;
struct drm_crtc *crtc;
+ bool test_pattern = sn65dsi83_test_pattern;
bool lvds_format_24bpp;
bool lvds_format_jeida;
unsigned int pval;
@@ -645,7 +650,11 @@ static void sn65dsi83_atomic_pre_enable(struct drm_bridge *bridge,
REG_LVDS_LANE_CHB_LVDS_TERM : 0));
regmap_write(ctx->regmap, REG_LVDS_CM, 0x00);
- le16val = cpu_to_le16(mode->hdisplay);
+ /*
+ * Active line length needs to be halved for test pattern
+ * generation in dual LVDS output.
+ */
+ le16val = cpu_to_le16(mode->hdisplay / (test_pattern ? dual_factor : 1));
regmap_bulk_write(ctx->regmap, REG_VID_CHA_ACTIVE_LINE_LENGTH_LOW,
&le16val, 2);
le16val = cpu_to_le16(mode->vdisplay);
@@ -668,7 +677,8 @@ static void sn65dsi83_atomic_pre_enable(struct drm_bridge *bridge,
(mode->hsync_start - mode->hdisplay) / dual_factor);
regmap_write(ctx->regmap, REG_VID_CHA_VERTICAL_FRONT_PORCH,
mode->vsync_start - mode->vdisplay);
- regmap_write(ctx->regmap, REG_VID_CHA_TEST_PATTERN, 0x00);
+ regmap_write(ctx->regmap, REG_VID_CHA_TEST_PATTERN,
+ test_pattern ? REG_VID_CHA_TEST_PATTERN_EN : 0);
/* Enable PLL */
regmap_write(ctx->regmap, REG_RC_PLL_EN, REG_RC_PLL_EN_PLL_EN);
diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
index 671b2bc75cb1..0884ec459cc5 100644
--- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c
+++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
@@ -776,8 +776,6 @@ static int ti_sn_bridge_attach(struct drm_bridge *bridge,
goto err_initted_aux;
}
- drm_connector_attach_encoder(pdata->connector, pdata->bridge.encoder);
-
return 0;
err_initted_aux:
diff --git a/drivers/gpu/drm/bridge/ti-tfp410.c b/drivers/gpu/drm/bridge/ti-tfp410.c
index 3b6b0e92cf89..bf4ab4eaf269 100644
--- a/drivers/gpu/drm/bridge/ti-tfp410.c
+++ b/drivers/gpu/drm/bridge/ti-tfp410.c
@@ -114,7 +114,7 @@ static void tfp410_hpd_callback(void *arg, enum drm_connector_status status)
{
struct tfp410 *dvi = arg;
- mod_delayed_work(system_wq, &dvi->hpd_work,
+ mod_delayed_work(system_percpu_wq, &dvi->hpd_work,
msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
}
diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
index a23b7e33fba6..649969fca141 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -773,8 +773,11 @@ static void drm_bridge_connector_put_bridges(struct drm_device *dev, void *data)
* @drm: the DRM device
* @encoder: the encoder where the bridge chain starts
*
- * Allocate, initialise and register a &drm_bridge_connector with the @drm
- * device. The connector is associated with a chain of bridges that starts at
+ * Create a new &drm_bridge_connector for the @drm device. The connector is
+ * allocated, initialised, registered with the @drm device and attached to
+ * @encoder.
+ *
+ * The connector is associated with a chain of bridges that starts at
* the @encoder. All bridges in the chain shall report bridge operation flags
* (&drm_bridge->ops) and bridge output type (&drm_bridge->type), and none of
* them may create a DRM connector directly.
@@ -1055,6 +1058,10 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
IS_ENABLED(CONFIG_DRM_DISPLAY_HDCP_HELPER))
drm_connector_attach_content_protection_property(connector, true);
+ ret = drm_connector_attach_encoder(connector, encoder);
+ if (ret)
+ return ERR_PTR(ret);
+
return connector;
}
EXPORT_SYMBOL_GPL(drm_bridge_connector_init);
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 4ffa057e2784..170de30c28ae 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -463,19 +463,19 @@ static void drm_atomic_crtc_print_state(struct drm_printer *p,
struct drm_crtc *crtc = state->crtc;
drm_printf(p, "crtc[%u]: %s\n", crtc->base.id, crtc->name);
- drm_printf(p, "\tenable=%d\n", state->enable);
- drm_printf(p, "\tactive=%d\n", state->active);
- drm_printf(p, "\tself_refresh_active=%d\n", state->self_refresh_active);
- drm_printf(p, "\tplanes_changed=%d\n", state->planes_changed);
- drm_printf(p, "\tmode_changed=%d\n", state->mode_changed);
- drm_printf(p, "\tactive_changed=%d\n", state->active_changed);
- drm_printf(p, "\tconnectors_changed=%d\n", state->connectors_changed);
- drm_printf(p, "\tcolor_mgmt_changed=%d\n", state->color_mgmt_changed);
- drm_printf(p, "\tplane_mask=%x\n", state->plane_mask);
- drm_printf(p, "\tconnector_mask=%x\n", state->connector_mask);
- drm_printf(p, "\tencoder_mask=%x\n", state->encoder_mask);
- drm_printf(p, "\tmode: " DRM_MODE_FMT "\n", DRM_MODE_ARG(&state->mode));
- drm_printf(p, "\tbackground_color=%llx\n", state->background_color);
+ drm_printf_indent(p, 1, "enable=%d\n", state->enable);
+ drm_printf_indent(p, 1, "active=%d\n", state->active);
+ drm_printf_indent(p, 1, "self_refresh_active=%d\n", state->self_refresh_active);
+ drm_printf_indent(p, 1, "planes_changed=%d\n", state->planes_changed);
+ drm_printf_indent(p, 1, "mode_changed=%d\n", state->mode_changed);
+ drm_printf_indent(p, 1, "active_changed=%d\n", state->active_changed);
+ drm_printf_indent(p, 1, "connectors_changed=%d\n", state->connectors_changed);
+ drm_printf_indent(p, 1, "color_mgmt_changed=%d\n", state->color_mgmt_changed);
+ drm_printf_indent(p, 1, "plane_mask=%x\n", state->plane_mask);
+ drm_printf_indent(p, 1, "connector_mask=%x\n", state->connector_mask);
+ drm_printf_indent(p, 1, "encoder_mask=%x\n", state->encoder_mask);
+ drm_printf_indent(p, 1, "mode: " DRM_MODE_FMT "\n", DRM_MODE_ARG(&state->mode));
+ drm_printf_indent(p, 1, "background_color=%llx\n", state->background_color);
if (crtc->funcs->atomic_print_state)
crtc->funcs->atomic_print_state(p, state);
@@ -818,38 +818,38 @@ static void drm_atomic_colorop_print_state(struct drm_printer *p,
struct drm_colorop *colorop = state->colorop;
drm_printf(p, "colorop[%u]:\n", colorop->base.id);
- drm_printf(p, "\ttype=%s\n", drm_get_colorop_type_name(colorop->type));
+ drm_printf_indent(p, 1, "type=%s\n", drm_get_colorop_type_name(colorop->type));
if (colorop->bypass_property)
- drm_printf(p, "\tbypass=%u\n", state->bypass);
+ drm_printf_indent(p, 1, "bypass=%u\n", state->bypass);
switch (colorop->type) {
case DRM_COLOROP_1D_CURVE:
- drm_printf(p, "\tcurve_1d_type=%s\n",
- drm_get_colorop_curve_1d_type_name(state->curve_1d_type));
+ drm_printf_indent(p, 1, "curve_1d_type=%s\n",
+ drm_get_colorop_curve_1d_type_name(state->curve_1d_type));
break;
case DRM_COLOROP_1D_LUT:
- drm_printf(p, "\tsize=%d\n", colorop->size);
- drm_printf(p, "\tinterpolation=%s\n",
- drm_get_colorop_lut1d_interpolation_name(colorop->lut1d_interpolation));
- drm_printf(p, "\tdata blob id=%d\n", state->data ? state->data->base.id : 0);
+ drm_printf_indent(p, 1, "size=%d\n", colorop->size);
+ drm_printf_indent(p, 1, "interpolation=%s\n",
+ drm_get_colorop_lut1d_interpolation_name(colorop->lut1d_interpolation));
+ drm_printf_indent(p, 1, "data blob id=%d\n", state->data ? state->data->base.id : 0);
break;
case DRM_COLOROP_CTM_3X4:
- drm_printf(p, "\tdata blob id=%d\n", state->data ? state->data->base.id : 0);
+ drm_printf_indent(p, 1, "data blob id=%d\n", state->data ? state->data->base.id : 0);
break;
case DRM_COLOROP_MULTIPLIER:
- drm_printf(p, "\tmultiplier=%llu\n", state->multiplier);
+ drm_printf_indent(p, 1, "multiplier=%llu\n", state->multiplier);
break;
case DRM_COLOROP_3D_LUT:
- drm_printf(p, "\tsize=%d\n", colorop->size);
- drm_printf(p, "\tinterpolation=%s\n",
- drm_get_colorop_lut3d_interpolation_name(colorop->lut3d_interpolation));
- drm_printf(p, "\tdata blob id=%d\n", state->data ? state->data->base.id : 0);
+ drm_printf_indent(p, 1, "size=%d\n", colorop->size);
+ drm_printf_indent(p, 1, "interpolation=%s\n",
+ drm_get_colorop_lut3d_interpolation_name(colorop->lut3d_interpolation));
+ drm_printf_indent(p, 1, "data blob id=%d\n", state->data ? state->data->base.id : 0);
break;
default:
break;
}
- drm_printf(p, "\tnext=%d\n", colorop->next ? colorop->next->base.id : 0);
+ drm_printf_indent(p, 1, "next=%d\n", colorop->next ? colorop->next->base.id : 0);
}
static void drm_atomic_plane_print_state(struct drm_printer *p,
@@ -860,21 +860,21 @@ static void drm_atomic_plane_print_state(struct drm_printer *p,
struct drm_rect dest = drm_plane_state_dest(state);
drm_printf(p, "plane[%u]: %s\n", plane->base.id, plane->name);
- drm_printf(p, "\tcrtc=%s\n", state->crtc ? state->crtc->name : "(null)");
- drm_printf(p, "\tfb=%u\n", state->fb ? state->fb->base.id : 0);
+ drm_printf_indent(p, 1, "crtc=%s\n", state->crtc ? state->crtc->name : "(null)");
+ drm_printf_indent(p, 1, "fb=%u\n", state->fb ? state->fb->base.id : 0);
if (state->fb)
drm_framebuffer_print_info(p, 2, state->fb);
- drm_printf(p, "\tcrtc-pos=" DRM_RECT_FMT "\n", DRM_RECT_ARG(&dest));
- drm_printf(p, "\tsrc-pos=" DRM_RECT_FP_FMT "\n", DRM_RECT_FP_ARG(&src));
- drm_printf(p, "\trotation=%x\n", state->rotation);
- drm_printf(p, "\tnormalized-zpos=%x\n", state->normalized_zpos);
- drm_printf(p, "\tcolor-encoding=%s\n",
- drm_get_color_encoding_name(state->color_encoding));
- drm_printf(p, "\tcolor-range=%s\n",
- drm_get_color_range_name(state->color_range));
- drm_printf(p, "\tcolor_mgmt_changed=%d\n", state->color_mgmt_changed);
- drm_printf(p, "\tcolor-pipeline=%d\n",
- state->color_pipeline ? state->color_pipeline->base.id : 0);
+ drm_printf_indent(p, 1, "crtc-pos=" DRM_RECT_FMT "\n", DRM_RECT_ARG(&dest));
+ drm_printf_indent(p, 1, "src-pos=" DRM_RECT_FP_FMT "\n", DRM_RECT_FP_ARG(&src));
+ drm_printf_indent(p, 1, "rotation=%x\n", state->rotation);
+ drm_printf_indent(p, 1, "normalized-zpos=%x\n", state->normalized_zpos);
+ drm_printf_indent(p, 1, "color-encoding=%s\n",
+ drm_get_color_encoding_name(state->color_encoding));
+ drm_printf_indent(p, 1, "color-range=%s\n",
+ drm_get_color_range_name(state->color_range));
+ drm_printf_indent(p, 1, "color_mgmt_changed=%d\n", state->color_mgmt_changed);
+ drm_printf_indent(p, 1, "color-pipeline=%d\n",
+ state->color_pipeline ? state->color_pipeline->base.id : 0);
if (plane->funcs->atomic_print_state)
plane->funcs->atomic_print_state(p, state);
}
@@ -1347,27 +1347,27 @@ static void drm_atomic_connector_print_state(struct drm_printer *p,
struct drm_connector *connector = state->connector;
drm_printf(p, "connector[%u]: %s\n", connector->base.id, connector->name);
- drm_printf(p, "\tcrtc=%s\n", state->crtc ? state->crtc->name : "(null)");
- drm_printf(p, "\tself_refresh_aware=%d\n", state->self_refresh_aware);
- drm_printf(p, "\tinterlace_allowed=%d\n", connector->interlace_allowed);
- drm_printf(p, "\tycbcr_420_allowed=%d\n", connector->ycbcr_420_allowed);
- drm_printf(p, "\tmax_requested_bpc=%d\n", state->max_requested_bpc);
- drm_printf(p, "\tcolorspace=%s\n", drm_get_colorspace_name(state->colorspace));
+ drm_printf_indent(p, 1, "crtc=%s\n", state->crtc ? state->crtc->name : "(null)");
+ drm_printf_indent(p, 1, "self_refresh_aware=%d\n", state->self_refresh_aware);
+ drm_printf_indent(p, 1, "interlace_allowed=%d\n", connector->interlace_allowed);
+ drm_printf_indent(p, 1, "ycbcr_420_allowed=%d\n", connector->ycbcr_420_allowed);
+ drm_printf_indent(p, 1, "max_requested_bpc=%d\n", state->max_requested_bpc);
+ drm_printf_indent(p, 1, "colorspace=%s\n", drm_get_colorspace_name(state->colorspace));
if (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA ||
connector->connector_type == DRM_MODE_CONNECTOR_HDMIB) {
- drm_printf(p, "\tbroadcast_rgb=%s\n",
- drm_hdmi_connector_get_broadcast_rgb_name(state->hdmi.broadcast_rgb));
- drm_printf(p, "\tis_limited_range=%c\n", state->hdmi.is_limited_range ? 'y' : 'n');
- drm_printf(p, "\toutput_bpc=%u\n", state->hdmi.output_bpc);
- drm_printf(p, "\toutput_format=%s\n",
- drm_hdmi_connector_get_output_format_name(state->hdmi.output_format));
- drm_printf(p, "\ttmds_char_rate=%llu\n", state->hdmi.tmds_char_rate);
+ drm_printf_indent(p, 1, "broadcast_rgb=%s\n",
+ drm_hdmi_connector_get_broadcast_rgb_name(state->hdmi.broadcast_rgb));
+ drm_printf_indent(p, 1, "is_limited_range=%c\n", state->hdmi.is_limited_range ? 'y' : 'n');
+ drm_printf_indent(p, 1, "output_bpc=%u\n", state->hdmi.output_bpc);
+ drm_printf_indent(p, 1, "output_format=%s\n",
+ drm_hdmi_connector_get_output_format_name(state->hdmi.output_format));
+ drm_printf_indent(p, 1, "tmds_char_rate=%llu\n", state->hdmi.tmds_char_rate);
}
if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
if (state->writeback_job && state->writeback_job->fb)
- drm_printf(p, "\tfb=%d\n", state->writeback_job->fb->base.id);
+ drm_printf_indent(p, 1, "fb=%d\n", state->writeback_job->fb->base.id);
if (connector->funcs->atomic_print_state)
connector->funcs->atomic_print_state(p, state);
diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c
index e17bb0f1f9e0..e5013b870ba0 100644
--- a/drivers/gpu/drm/drm_auth.c
+++ b/drivers/gpu/drm/drm_auth.c
@@ -347,7 +347,7 @@ void drm_master_release(struct drm_file *file_priv)
if (!drm_is_current_master_locked(file_priv))
goto out;
- if (dev->master == file_priv->master)
+ if (dev->master && dev->master == file_priv->master)
drm_drop_master(dev, file_priv);
out:
if (drm_core_check_feature(dev, DRIVER_MODESET) && file_priv->is_master) {
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index d33ca2099135..ce180f0b26b2 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -1614,18 +1614,17 @@ static void drm_bridge_debugfs_show_bridge(struct drm_printer *p,
drm_printf(p, "bridge[%u]: %ps\n", idx, bridge->funcs);
- drm_printf(p, "\trefcount: %u%s\n", refcount,
- lingering ? " [lingering]" : "");
+ drm_printf_indent(p, 1, "refcount: %u%s\n", refcount,
+ lingering ? " [lingering]" : "");
- drm_printf(p, "\ttype: [%d] %s\n",
- bridge->type,
- drm_get_connector_type_name(bridge->type));
+ drm_printf_indent(p, 1, "type: [%d] %s\n", bridge->type,
+ drm_get_connector_type_name(bridge->type));
/* The OF node could be freed after drm_bridge_remove() */
if (bridge->of_node && !lingering)
- drm_printf(p, "\tOF: %pOFfc\n", bridge->of_node);
+ drm_printf_indent(p, 1, "OF: %pOFfc\n", bridge->of_node);
- drm_printf(p, "\tops: [0x%x]", bridge->ops);
+ drm_printf_indent(p, 1, "ops: [0x%x]", bridge->ops);
if (bridge->ops & DRM_BRIDGE_OP_DETECT)
drm_puts(p, " detect");
if (bridge->ops & DRM_BRIDGE_OP_EDID)
diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c
index e0d533611040..60cd02b7ea64 100644
--- a/drivers/gpu/drm/drm_fourcc.c
+++ b/drivers/gpu/drm/drm_fourcc.c
@@ -275,6 +275,7 @@ const struct drm_format_info *__drm_format_info(u32 format)
{ .format = DRM_FORMAT_YVU422, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 2, .vsub = 1, .is_yuv = true },
{ .format = DRM_FORMAT_YUV444, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 1, .vsub = 1, .is_yuv = true },
{ .format = DRM_FORMAT_YVU444, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 1, .vsub = 1, .is_yuv = true },
+ { .format = DRM_FORMAT_Y8, .depth = 8, .num_planes = 1, .cpp = { 1, 0, 0 }, .hsub = 1, .vsub = 1, .is_yuv = true },
{ .format = DRM_FORMAT_NV12, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 2, .is_yuv = true },
{ .format = DRM_FORMAT_NV21, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 2, .is_yuv = true },
{ .format = DRM_FORMAT_NV16, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true },
@@ -287,6 +288,7 @@ const struct drm_format_info *__drm_format_info(u32 format)
{ .format = DRM_FORMAT_VYUY, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true },
{ .format = DRM_FORMAT_XYUV8888, .depth = 0, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .is_yuv = true },
{ .format = DRM_FORMAT_VUY888, .depth = 0, .num_planes = 1, .cpp = { 3, 0, 0 }, .hsub = 1, .vsub = 1, .is_yuv = true },
+ { .format = DRM_FORMAT_XVUY2101010, .depth = 0, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .is_yuv = true },
{ .format = DRM_FORMAT_AYUV, .depth = 0, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true, .is_yuv = true },
{ .format = DRM_FORMAT_Y210, .depth = 0, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true },
{ .format = DRM_FORMAT_Y212, .depth = 0, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true },
@@ -354,6 +356,9 @@ const struct drm_format_info *__drm_format_info(u32 format)
{ .format = DRM_FORMAT_P030, .depth = 0, .num_planes = 2,
.char_per_block = { 4, 8, 0 }, .block_w = { 3, 3, 0 }, .block_h = { 1, 1, 0 },
.hsub = 2, .vsub = 2, .is_yuv = true},
+ { .format = DRM_FORMAT_P230, .depth = 0, .num_planes = 2,
+ .char_per_block = { 4, 8, 0 }, .block_w = { 3, 3, 0 }, .block_h = { 1, 1, 0 },
+ .hsub = 2, .vsub = 1, .is_yuv = true },
{ .format = DRM_FORMAT_S010, .depth = 0, .num_planes = 3,
.char_per_block = { 2, 2, 2 }, .block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 },
.hsub = 2, .vsub = 2, .is_yuv = true},
@@ -381,6 +386,12 @@ const struct drm_format_info *__drm_format_info(u32 format)
{ .format = DRM_FORMAT_S416, .depth = 0, .num_planes = 3,
.char_per_block = { 2, 2, 2 }, .block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 },
.hsub = 1, .vsub = 1, .is_yuv = true},
+ { .format = DRM_FORMAT_XYYY2101010, .depth = 0, .num_planes = 1,
+ .char_per_block = { 4, 0, 0 }, .block_w = { 3, 0, 0 }, .block_h = { 1, 0, 0 },
+ .hsub = 1, .vsub = 1, .is_yuv = true },
+ { .format = DRM_FORMAT_T430, .depth = 0, .num_planes = 3,
+ .char_per_block = { 4, 4, 4 }, .block_w = { 3, 3, 3 }, .block_h = { 1, 1, 1 },
+ .hsub = 1, .vsub = 1, .is_yuv = true },
};
unsigned int i;
@@ -491,12 +502,20 @@ EXPORT_SYMBOL(drm_format_info_block_height);
*/
unsigned int drm_format_info_bpp(const struct drm_format_info *info, int plane)
{
+ unsigned int block_size;
+
if (!info || plane < 0 || plane >= info->num_planes)
return 0;
- return info->char_per_block[plane] * 8 /
- (drm_format_info_block_width(info, plane) *
- drm_format_info_block_height(info, plane));
+ block_size = drm_format_info_block_width(info, plane) *
+ drm_format_info_block_height(info, plane);
+
+ if (info->char_per_block[plane] * 8 % block_size) {
+ pr_warn("unable to return an integer bpp\n");
+ return 0;
+ }
+
+ return info->char_per_block[plane] * 8 / block_size;
}
EXPORT_SYMBOL(drm_format_info_bpp);
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c
index 0390e14d3157..3ac1dd5ad640 100644
--- a/drivers/gpu/drm/drm_mipi_dsi.c
+++ b/drivers/gpu/drm/drm_mipi_dsi.c
@@ -587,6 +587,9 @@ EXPORT_SYMBOL(mipi_dsi_create_packet);
* mipi_dsi_shutdown_peripheral() - sends a Shutdown Peripheral command
* @dsi: DSI peripheral device
*
+ * This function is deprecated. Use mipi_dsi_shutdown_peripheral_multi()
+ * instead.
+ *
* Return: 0 on success or a negative error code on failure.
*/
int mipi_dsi_shutdown_peripheral(struct mipi_dsi_device *dsi)
@@ -1980,6 +1983,31 @@ void mipi_dsi_dcs_set_tear_scanline_multi(struct mipi_dsi_multi_context *ctx,
}
EXPORT_SYMBOL(mipi_dsi_dcs_set_tear_scanline_multi);
+/**
+ * mipi_dsi_shutdown_peripheral_multi() - sends a Shutdown Peripheral command
+ * @ctx: Context for multiple DSI transactions
+ *
+ * Like mipi_dsi_shutdown_peripheral() but deals with errors in a way that
+ * makes it convenient to make several calls in a row.
+ */
+void mipi_dsi_shutdown_peripheral_multi(struct mipi_dsi_multi_context *ctx)
+{
+ struct mipi_dsi_device *dsi = ctx->dsi;
+ struct device *dev = &dsi->dev;
+ int ret;
+
+ if (ctx->accum_err)
+ return;
+
+ ret = mipi_dsi_shutdown_peripheral(dsi);
+ if (ret < 0) {
+ ctx->accum_err = ret;
+ dev_err(dev, "Failed to shutdown peripheral: %d\n",
+ ctx->accum_err);
+ }
+}
+EXPORT_SYMBOL(mipi_dsi_shutdown_peripheral_multi);
+
static int mipi_dsi_drv_probe(struct device *dev)
{
struct mipi_dsi_driver *drv = to_mipi_dsi_driver(dev->driver);
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.h b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
index 20dad16fd554..55a9e745604d 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
@@ -94,18 +94,6 @@ void etnaviv_gem_describe_objects(struct etnaviv_drm_private *priv,
#define VERB(fmt, ...) if (0) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
/*
- * Return the storage size of a structure with a variable length array.
- * The array is nelem elements of elem_size, where the base structure
- * is defined by base. If the size overflows size_t, return zero.
- */
-static inline size_t size_vstruct(size_t nelem, size_t elem_size, size_t base)
-{
- if (elem_size && nelem > (SIZE_MAX - base) / elem_size)
- return 0;
- return base + nelem * elem_size;
-}
-
-/*
* Etnaviv timeouts are specified wrt CLOCK_MONOTONIC, not jiffies.
* We need to calculate the timeout in terms of number of jiffies
* between the specified timeout and the current CLOCK_MONOTONIC time.
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
index fbf693addd74..1a77a09b3377 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
@@ -32,9 +32,8 @@ static struct etnaviv_gem_submit *submit_create(struct drm_device *dev,
struct etnaviv_gpu *gpu, size_t nr_bos, size_t nr_pmrs)
{
struct etnaviv_gem_submit *submit;
- size_t sz = size_vstruct(nr_bos, sizeof(submit->bos[0]), sizeof(*submit));
- submit = kzalloc(sz, GFP_KERNEL);
+ submit = kzalloc_flex(*submit, bos, nr_bos);
if (!submit)
return NULL;
diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
index 6884ea6d04eb..b80540328150 100644
--- a/drivers/gpu/drm/exynos/exynos_dp.c
+++ b/drivers/gpu/drm/exynos/exynos_dp.c
@@ -118,7 +118,7 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
return ret;
}
- return drm_connector_attach_encoder(connector, dp->plat_data.encoder);
+ return 0;
}
static void exynos_dp_unbind(struct device *dev, struct device *master,
diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c
index 005ab7f5355f..947f7c4ff4e9 100644
--- a/drivers/gpu/drm/gma500/psb_drv.c
+++ b/drivers/gpu/drm/gma500/psb_drv.c
@@ -24,7 +24,6 @@
#include <drm/drm_drv.h>
#include <drm/drm_file.h>
#include <drm/drm_ioctl.h>
-#include <drm/drm_pciids.h>
#include <drm/drm_print.h>
#include <drm/drm_vblank.h>
diff --git a/drivers/gpu/drm/hyperv/hyperv_drm_proto.c b/drivers/gpu/drm/hyperv/hyperv_drm_proto.c
index 051ecc526832..753d97bff76f 100644
--- a/drivers/gpu/drm/hyperv/hyperv_drm_proto.c
+++ b/drivers/gpu/drm/hyperv/hyperv_drm_proto.c
@@ -10,7 +10,7 @@
#include "hyperv_drm.h"
-#define VMBUS_RING_BUFSIZE (256 * 1024)
+#define VMBUS_RING_BUFSIZE VMBUS_RING_SIZE(256 * 1024)
#define VMBUS_VSP_TIMEOUT (10 * HZ)
#define SYNTHVID_VERSION(major, minor) ((minor) << 16 | (major))
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
index 65ce54b20ec2..05997e8bbb29 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
@@ -3205,8 +3205,7 @@ eb_composite_fence_create(struct i915_execbuffer *eb, int out_fence_fd)
fence_array = dma_fence_array_create(eb->num_batches,
fences,
eb->context->parallel.fence_context,
- eb->context->parallel.seqno++,
- false);
+ eb->context->parallel.seqno++);
if (!fence_array) {
kfree(fences);
return ERR_PTR(-ENOMEM);
diff --git a/drivers/gpu/drm/imagination/pvr_fw_trace.c b/drivers/gpu/drm/imagination/pvr_fw_trace.c
index 6193811ef7be..6bb5baa6c41b 100644
--- a/drivers/gpu/drm/imagination/pvr_fw_trace.c
+++ b/drivers/gpu/drm/imagination/pvr_fw_trace.c
@@ -77,7 +77,7 @@ const struct kernel_param_ops pvr_fw_trace_init_mask_ops = {
};
param_check_hexint(init_fw_trace_mask, &pvr_fw_trace_init_mask);
-module_param_cb(init_fw_trace_mask, &pvr_fw_trace_init_mask_ops, &pvr_fw_trace_init_mask, 0600);
+module_param_cb(init_fw_trace_mask, &pvr_fw_trace_init_mask_ops, &pvr_fw_trace_init_mask, 0400);
__MODULE_PARM_TYPE(init_fw_trace_mask, "hexint");
MODULE_PARM_DESC(init_fw_trace_mask,
"Enable FW trace for the specified groups at device init time");
diff --git a/drivers/gpu/drm/imx/dc/dc-kms.c b/drivers/gpu/drm/imx/dc/dc-kms.c
index 2b18aa37a4a8..0f8cfaf4c4d1 100644
--- a/drivers/gpu/drm/imx/dc/dc-kms.c
+++ b/drivers/gpu/drm/imx/dc/dc-kms.c
@@ -81,13 +81,7 @@ static int dc_kms_init_encoder_per_crtc(struct dc_drm_device *dc_drm,
return ret;
}
- ret = drm_connector_attach_encoder(connector, encoder);
- if (ret)
- dev_err(dev,
- "failed to attach encoder to connector for CRTC%u: %d\n",
- crtc->index, ret);
-
- return ret;
+ return 0;
}
int dc_kms_init(struct dc_drm_device *dc_drm)
diff --git a/drivers/gpu/drm/imx/dcss/dcss-kms.c b/drivers/gpu/drm/imx/dcss/dcss-kms.c
index 3633e8f3aff6..50bd7f36d36d 100644
--- a/drivers/gpu/drm/imx/dcss/dcss-kms.c
+++ b/drivers/gpu/drm/imx/dcss/dcss-kms.c
@@ -103,8 +103,6 @@ static int dcss_kms_bridge_connector_init(struct dcss_kms_dev *kms)
return PTR_ERR(kms->connector);
}
- drm_connector_attach_encoder(kms->connector, encoder);
-
return 0;
}
diff --git a/drivers/gpu/drm/imx/ipuv3/Kconfig b/drivers/gpu/drm/imx/ipuv3/Kconfig
index 351dc65913eb..3ca237515e46 100644
--- a/drivers/gpu/drm/imx/ipuv3/Kconfig
+++ b/drivers/gpu/drm/imx/ipuv3/Kconfig
@@ -13,6 +13,7 @@ config DRM_IMX
config DRM_IMX_PARALLEL_DISPLAY
tristate "Support for parallel displays"
depends on DRM_IMX
+ depends on OF
select DRM_BRIDGE
select DRM_BRIDGE_CONNECTOR
select DRM_DISPLAY_HELPER
@@ -33,6 +34,7 @@ config DRM_IMX_LDB
tristate "Support for LVDS displays"
depends on DRM_IMX
depends on COMMON_CLK
+ depends on OF
select MFD_SYSCON
select DRM_BRIDGE
select DRM_BRIDGE_CONNECTOR
diff --git a/drivers/gpu/drm/imx/ipuv3/imx-ldb.c b/drivers/gpu/drm/imx/ipuv3/imx-ldb.c
index 730caf883e83..63d6a1e7c1bd 100644
--- a/drivers/gpu/drm/imx/ipuv3/imx-ldb.c
+++ b/drivers/gpu/drm/imx/ipuv3/imx-ldb.c
@@ -407,8 +407,6 @@ static int imx_ldb_register(struct drm_device *drm,
if (IS_ERR(connector))
return PTR_ERR(connector);
- drm_connector_attach_encoder(connector, encoder);
-
return 0;
}
diff --git a/drivers/gpu/drm/imx/ipuv3/parallel-display.c b/drivers/gpu/drm/imx/ipuv3/parallel-display.c
index 6c505becb31d..0f06db95f00f 100644
--- a/drivers/gpu/drm/imx/ipuv3/parallel-display.c
+++ b/drivers/gpu/drm/imx/ipuv3/parallel-display.c
@@ -216,8 +216,6 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data)
if (IS_ERR(connector))
return PTR_ERR(connector);
- drm_connector_attach_encoder(connector, encoder);
-
return 0;
}
diff --git a/drivers/gpu/drm/imx/lcdc/imx-lcdc.c b/drivers/gpu/drm/imx/lcdc/imx-lcdc.c
index e200b40f30fe..f52832b43aca 100644
--- a/drivers/gpu/drm/imx/lcdc/imx-lcdc.c
+++ b/drivers/gpu/drm/imx/lcdc/imx-lcdc.c
@@ -448,8 +448,6 @@ static int imx_lcdc_probe(struct platform_device *pdev)
if (IS_ERR(lcdc->connector))
return dev_err_probe(drm->dev, PTR_ERR(lcdc->connector), "Cannot init bridge connector\n");
- drm_connector_attach_encoder(lcdc->connector, &lcdc->pipe.encoder);
-
/*
* The LCDC controller does not have an enable bit. The
* controller starts directly when the clocks are enabled.
diff --git a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c
index 2350c9499aef..42c86f195c66 100644
--- a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c
+++ b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c
@@ -1330,8 +1330,6 @@ static int ingenic_drm_bind(struct device *dev, bool has_components)
ret = PTR_ERR(connector);
goto err_drvdata;
}
-
- drm_connector_attach_encoder(connector, encoder);
}
drm_for_each_encoder(encoder, drm) {
diff --git a/drivers/gpu/drm/kmb/kmb_dsi.c b/drivers/gpu/drm/kmb/kmb_dsi.c
index 4b5a9c051e65..59d0e856392f 100644
--- a/drivers/gpu/drm/kmb/kmb_dsi.c
+++ b/drivers/gpu/drm/kmb/kmb_dsi.c
@@ -1457,7 +1457,7 @@ int kmb_dsi_encoder_init(struct drm_device *dev, struct kmb_dsi *kmb_dsi)
drm_encoder_cleanup(encoder);
return PTR_ERR(connector);
}
- drm_connector_attach_encoder(connector, encoder);
+
return 0;
}
diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
index 53360b5d12ba..cc6d74ce8b5e 100644
--- a/drivers/gpu/drm/mediatek/mtk_dpi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
@@ -1049,7 +1049,6 @@ static int mtk_dpi_bind(struct device *dev, struct device *master, void *data)
ret = PTR_ERR(dpi->connector);
goto err_cleanup;
}
- drm_connector_attach_encoder(dpi->connector, &dpi->encoder);
return 0;
diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c
index dacc36ccb731..46cf4b043f12 100644
--- a/drivers/gpu/drm/mediatek/mtk_dsi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
@@ -936,7 +936,6 @@ static int mtk_dsi_encoder_init(struct drm_device *drm, struct mtk_dsi *dsi)
ret = PTR_ERR(dsi->connector);
goto err_cleanup_encoder;
}
- drm_connector_attach_encoder(dsi->connector, &dsi->encoder);
return 0;
diff --git a/drivers/gpu/drm/meson/meson_encoder_cvbs.c b/drivers/gpu/drm/meson/meson_encoder_cvbs.c
index 574ffffd4a27..8b26a0031cde 100644
--- a/drivers/gpu/drm/meson/meson_encoder_cvbs.c
+++ b/drivers/gpu/drm/meson/meson_encoder_cvbs.c
@@ -279,8 +279,6 @@ int meson_encoder_cvbs_probe(struct meson_drm *priv)
return dev_err_probe(priv->dev, PTR_ERR(connector),
"Unable to create CVBS bridge connector\n");
- drm_connector_attach_encoder(connector, &meson_encoder_cvbs->encoder);
-
priv->encoders[MESON_ENC_CVBS] = meson_encoder_cvbs;
return 0;
diff --git a/drivers/gpu/drm/meson/meson_encoder_hdmi.c b/drivers/gpu/drm/meson/meson_encoder_hdmi.c
index d766625aa1d0..55c0601df3c6 100644
--- a/drivers/gpu/drm/meson/meson_encoder_hdmi.c
+++ b/drivers/gpu/drm/meson/meson_encoder_hdmi.c
@@ -433,8 +433,6 @@ int meson_encoder_hdmi_probe(struct meson_drm *priv)
"Unable to create HDMI bridge connector\n");
goto err_put_node;
}
- drm_connector_attach_encoder(meson_encoder_hdmi->connector,
- &meson_encoder_hdmi->encoder);
/*
* We should have now in place:
diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c
index a32be27c39e8..d7b5dfdb28aa 100644
--- a/drivers/gpu/drm/mgag200/mgag200_drv.c
+++ b/drivers/gpu/drm/mgag200/mgag200_drv.c
@@ -19,7 +19,6 @@
#include <drm/drm_ioctl.h>
#include <drm/drm_managed.h>
#include <drm/drm_module.h>
-#include <drm/drm_pciids.h>
#include <drm/drm_print.h>
#include "mgag200_drv.h"
diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c
index 809ca191e9de..7726edb0d4ed 100644
--- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c
+++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c
@@ -232,13 +232,6 @@ static int mdp4_modeset_init_intf(struct mdp4_kms *mdp4_kms,
return PTR_ERR(connector);
}
- ret = drm_connector_attach_encoder(connector, encoder);
- if (ret) {
- DRM_DEV_ERROR(dev->dev, "failed to attach LVDS connector: %d\n", ret);
-
- return ret;
- }
-
break;
case DRM_MODE_ENCODER_TMDS:
encoder = mdp4_dtv_encoder_init(dev);
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c
index ec4652e620c4..349175457566 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.c
+++ b/drivers/gpu/drm/msm/dp/dp_drm.c
@@ -376,7 +376,5 @@ struct drm_connector *msm_dp_drm_connector_init(struct msm_dp *msm_dp_display,
if (!msm_dp_display->is_edp)
drm_connector_attach_dp_subconnector_property(connector);
- drm_connector_attach_encoder(connector, encoder);
-
return connector;
}
diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c
index ca400924d4ee..46faeaae9d94 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_manager.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c
@@ -485,10 +485,6 @@ int msm_dsi_manager_connector_init(struct msm_dsi *msm_dsi,
return PTR_ERR(connector);
}
- ret = drm_connector_attach_encoder(connector, encoder);
- if (ret < 0)
- return ret;
-
return 0;
}
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
index 852abb2466f0..d9491aac1a89 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.c
@@ -190,8 +190,6 @@ int msm_hdmi_modeset_init(struct hdmi *hdmi,
goto fail;
}
- drm_connector_attach_encoder(hdmi->connector, hdmi->encoder);
-
ret = devm_request_irq(dev->dev, hdmi->irq,
msm_hdmi_irq, IRQF_TRIGGER_HIGH,
"hdmi_isr", hdmi);
diff --git a/drivers/gpu/drm/mxsfb/lcdif_drv.c b/drivers/gpu/drm/mxsfb/lcdif_drv.c
index 7f07ae24e0dc..f5bb59cd5028 100644
--- a/drivers/gpu/drm/mxsfb/lcdif_drv.c
+++ b/drivers/gpu/drm/mxsfb/lcdif_drv.c
@@ -99,12 +99,6 @@ static int lcdif_attach_bridge(struct lcdif_drm_private *lcdif)
return dev_err_probe(dev, PTR_ERR(connector),
"Failed to init bridge_connector for endpoint%u\n",
of_ep.id);
-
- ret = drm_connector_attach_encoder(connector, encoder);
- if (ret)
- return dev_err_probe(dev, ret,
- "Failed to attach connector for endpoint%u\n",
- of_ep.id);
}
return 0;
diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c
index b983f4f9bcd7..364227f5456f 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/disp.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c
@@ -2474,7 +2474,7 @@ nv50_disp_atomic_commit(struct drm_device *dev,
pm_runtime_get_noresume(dev->dev);
if (nonblock)
- queue_work(system_unbound_wq, &state->commit_work);
+ queue_work(system_dfl_wq, &state->commit_work);
else
nv50_disp_atomic_commit_tail(state);
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c
index c8335f5b49db..38032bb95826 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bios.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bios.c
@@ -2085,10 +2085,27 @@ nouveau_bios_init(struct drm_device *dev)
int ret;
/* only relevant for PCI devices */
- if (!dev_is_pci(dev->dev) ||
- nvkm_gsp_rm(nvxx_device(drm)->gsp))
+ if (!dev_is_pci(dev->dev))
return 0;
+ if (nvkm_gsp_rm(nvxx_device(drm)->gsp)) {
+ struct nvkm_bios *nvkm_bios = nvxx_bios(drm);
+
+ /*
+ * If this GPU has an nvkm_device_chip.bios entry, then the VBIOS
+ * data was already read by the nvkm layer during nvkm_bios_new().
+ * Point the legacy DRM-level VBIOS structure at the same buffer
+ * so that any remaining legacy code can access it. This exposes
+ * the VBIOS via the DRM debugfs entries.
+ */
+ if (nvkm_bios) {
+ bios->data = nvkm_bios->data;
+ bios->length = nvkm_bios->size;
+ }
+
+ return 0;
+ }
+
if (!NVInitVBIOS(dev))
return -ENODEV;
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
index 517ff2c31dce..e16f59b00f6f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -632,7 +632,7 @@ nouveau_drm_device_init(struct nouveau_drm *drm)
struct drm_device *dev = drm->dev;
int ret;
- drm->sched_wq = alloc_workqueue("nouveau_sched_wq_shared", 0,
+ drm->sched_wq = alloc_workqueue("nouveau_sched_wq_shared", WQ_PERCPU,
WQ_MAX_ACTIVE);
if (!drm->sched_wq)
return -ENOMEM;
diff --git a/drivers/gpu/drm/nouveau/nouveau_sched.c b/drivers/gpu/drm/nouveau/nouveau_sched.c
index 179edf90a531..2cbae003d6de 100644
--- a/drivers/gpu/drm/nouveau/nouveau_sched.c
+++ b/drivers/gpu/drm/nouveau/nouveau_sched.c
@@ -413,7 +413,8 @@ nouveau_sched_init(struct nouveau_sched *sched, struct nouveau_drm *drm,
int ret;
if (!wq) {
- wq = alloc_workqueue("nouveau_sched_wq_%d", 0, WQ_MAX_ACTIVE,
+ wq = alloc_workqueue("nouveau_sched_wq_%d", WQ_PERCPU,
+ WQ_MAX_ACTIVE,
current->pid);
if (!wq)
return -ENOMEM;
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
index 2042a633835f..92d6a1f9c0a1 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.c
+++ b/drivers/gpu/drm/omapdrm/omap_drv.c
@@ -507,8 +507,6 @@ static int omap_modeset_init(struct drm_device *dev)
return PTR_ERR(pipe->connector);
}
- drm_connector_attach_encoder(pipe->connector, encoder);
-
crtc = omap_crtc_init(dev, pipe, priv->planes[i]);
if (IS_ERR(crtc))
return PTR_ERR(crtc);
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index 979109c27b9b..b0e9b92e2c84 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -105,8 +105,20 @@ config DRM_PANEL_BOE_TV101WUM_LL2
Say Y here if you want to support for BOE TV101WUM-LL2
WUXGA PANEL DSI Video Mode panel
+config DRM_PANEL_CHIPWEALTH_CH13726A
+ tristate "CHIPWEALTH CH13726A-based DSI panel"
+ depends on OF
+ depends on DRM_MIPI_DSI
+ depends on BACKLIGHT_CLASS_DEVICE
+ select DRM_DISPLAY_DP_HELPER
+ select DRM_DISPLAY_HELPER
+ help
+ Say Y here if you want to enable support for ChipWealth
+ CH13726A-based display panels.
+
config DRM_PANEL_EBBG_FT8719
tristate "EBBG FT8719 panel driver"
+ depends on GPIOLIB
depends on OF
depends on DRM_MIPI_DSI
depends on BACKLIGHT_CLASS_DEVICE
@@ -357,7 +369,8 @@ config DRM_PANEL_JADARD_JD9365DA_H3
config DRM_PANEL_JDI_LPM102A188A
tristate "JDI LPM102A188A DSI panel"
- depends on OF && GPIOLIB
+ depends on GPIOLIB
+ depends on OF
depends on DRM_MIPI_DSI
depends on BACKLIGHT_CLASS_DEVICE
help
@@ -472,6 +485,7 @@ config DRM_PANEL_LG_LG4573
config DRM_PANEL_LG_SW43408
tristate "LG SW43408 panel"
+ depends on GPIOLIB
depends on OF
depends on DRM_MIPI_DSI
depends on BACKLIGHT_CLASS_DEVICE
@@ -562,6 +576,16 @@ config DRM_PANEL_NOVATEK_NT35510
around the Novatek NT35510 display controller, such as some
Hydis panels.
+config DRM_PANEL_NOVATEK_NT35532
+ tristate "Novatek NT35532-based DSI video mode panel"
+ depends on OF
+ depends on DRM_MIPI_DSI
+ depends on BACKLIGHT_CLASS_DEVICE
+ select DRM_KMS_HELPER
+ help
+ Say Y or M here if you want to enable support for Novatek
+ NT35532-based 1080p video mode DSI panels.
+
config DRM_PANEL_NOVATEK_NT35560
tristate "Novatek NT35560 DSI command mode panel"
depends on OF
@@ -597,6 +621,7 @@ config DRM_PANEL_NOVATEK_NT36523
config DRM_PANEL_NOVATEK_NT36672A
tristate "Novatek NT36672A DSI panel"
+ depends on GPIOLIB
depends on OF
depends on DRM_MIPI_DSI
depends on BACKLIGHT_CLASS_DEVICE
@@ -607,6 +632,7 @@ config DRM_PANEL_NOVATEK_NT36672A
config DRM_PANEL_NOVATEK_NT36672E
tristate "Novatek NT36672E DSI panel"
+ depends on GPIOLIB
depends on OF
depends on DRM_MIPI_DSI
depends on BACKLIGHT_CLASS_DEVICE
@@ -744,7 +770,8 @@ config DRM_PANEL_RAYDIUM_RM692E5
config DRM_PANEL_RAYDIUM_RM69380
tristate "Raydium RM69380-based DSI panel"
- depends on OF && GPIOLIB
+ depends on GPIOLIB
+ depends on OF
depends on DRM_MIPI_DSI
depends on BACKLIGHT_CLASS_DEVICE
help
@@ -902,10 +929,10 @@ config DRM_PANEL_SAMSUNG_S6D7AA0
config DRM_PANEL_SAMSUNG_S6E3FC2X01
tristate "Samsung S6E3FC2X01 DSI panel controller"
+ depends on GPIOLIB
depends on OF
depends on DRM_MIPI_DSI
depends on BACKLIGHT_CLASS_DEVICE
- select VIDEOMODE_HELPERS
help
Say Y or M here if you want to enable support for the
Samsung S6E3FC2 DDIC and connected MIPI DSI panel.
@@ -922,11 +949,18 @@ config DRM_PANEL_SAMSUNG_S6E3HA2
config DRM_PANEL_SAMSUNG_S6E3HA8
tristate "Samsung S6E3HA8 DSI video mode panel"
+ depends on GPIOLIB
depends on OF
depends on DRM_MIPI_DSI
depends on BACKLIGHT_CLASS_DEVICE
select DRM_DISPLAY_DSC_HELPER
- select VIDEOMODE_HELPERS
+ help
+ Say Y or M here if you want to enable support for the
+ Samsung S6E3HA8 DDIC and connected MIPI DSI panel.
+ Currently supported panels:
+
+ Samsung AMB577PX01 (found in the Samsung S9 smartphone)
+
config DRM_PANEL_SAMSUNG_S6E63J0X03
tristate "Samsung S6E63J0X03 DSI command mode panel"
@@ -994,10 +1028,10 @@ config DRM_PANEL_SAMSUNG_S6E8FC0
config DRM_PANEL_SAMSUNG_SOFEF00
tristate "Samsung SOFEF00 DSI panel controller"
+ depends on GPIOLIB
depends on OF
depends on DRM_MIPI_DSI
depends on BACKLIGHT_CLASS_DEVICE
- select VIDEOMODE_HELPERS
help
Say Y or M here if you want to enable support for the Samsung AMOLED
panel SOFEF00 DDIC and connected panel.
@@ -1262,6 +1296,7 @@ config DRM_PANEL_VISIONOX_R66451
config DRM_PANEL_VISIONOX_RM69299
tristate "Visionox RM69299"
+ depends on GPIOLIB
depends on OF
depends on DRM_MIPI_DSI
depends on BACKLIGHT_CLASS_DEVICE
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index 0d694acbfbb6..c2c5cf817116 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_DRM_PANEL_BOE_TD4320) += panel-boe-td4320.o
obj-$(CONFIG_DRM_PANEL_BOE_TH101MB31UIG002_28A) += panel-boe-th101mb31ig002-28a.o
obj-$(CONFIG_DRM_PANEL_BOE_TV101WUM_LL2) += panel-boe-tv101wum-ll2.o
obj-$(CONFIG_DRM_PANEL_BOE_TV101WUM_NL6) += panel-boe-tv101wum-nl6.o
+obj-$(CONFIG_DRM_PANEL_CHIPWEALTH_CH13726A) += panel-chipwealth-ch13726a.o
obj-$(CONFIG_DRM_PANEL_DSI_CM) += panel-dsi-cm.o
obj-$(CONFIG_DRM_PANEL_LVDS) += panel-lvds.o
obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o
@@ -55,6 +56,7 @@ obj-$(CONFIG_DRM_PANEL_NEC_NL8048HL11) += panel-nec-nl8048hl11.o
obj-$(CONFIG_DRM_PANEL_NEWVISION_NV3051D) += panel-newvision-nv3051d.o
obj-$(CONFIG_DRM_PANEL_NEWVISION_NV3052C) += panel-newvision-nv3052c.o
obj-$(CONFIG_DRM_PANEL_NOVATEK_NT35510) += panel-novatek-nt35510.o
+obj-$(CONFIG_DRM_PANEL_NOVATEK_NT35532) += panel-novatek-nt35532.o
obj-$(CONFIG_DRM_PANEL_NOVATEK_NT35560) += panel-novatek-nt35560.o
obj-$(CONFIG_DRM_PANEL_NOVATEK_NT35950) += panel-novatek-nt35950.o
obj-$(CONFIG_DRM_PANEL_NOVATEK_NT36523) += panel-novatek-nt36523.o
diff --git a/drivers/gpu/drm/panel/panel-chipwealth-ch13726a.c b/drivers/gpu/drm/panel/panel-chipwealth-ch13726a.c
new file mode 100644
index 000000000000..be76bc825c3f
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-chipwealth-ch13726a.c
@@ -0,0 +1,333 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * ChipWealth CH13726A MIPI-DSI panel driver
+ * Copyright (c) 2024, Teguh Sobirin <teguh@sobir.in>.
+ */
+
+#include <linux/backlight.h>
+#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 <video/mipi_display.h>
+
+static const struct regulator_bulk_data ch13726a_supplies[] = {
+ { .supply = "vdd1v2", },
+ { .supply = "vddio", },
+ { .supply = "vdd", },
+ { .supply = "avdd", },
+};
+
+struct ch13726a_panel {
+ struct drm_panel panel;
+ struct mipi_dsi_device *dsi;
+ struct regulator_bulk_data *supplies;
+ struct gpio_desc *reset_gpio;
+ struct ch13726a_desc *desc;
+ enum drm_panel_orientation orientation;
+};
+
+struct ch13726a_desc {
+ unsigned int width_mm;
+ unsigned int height_mm;
+ unsigned int bpc;
+
+ const struct drm_display_mode *modes;
+ unsigned int num_modes;
+};
+
+static inline struct ch13726a_panel *to_ch13726a_panel(struct drm_panel *panel)
+{
+ return container_of(panel, struct ch13726a_panel, panel);
+}
+
+static void ch13726a_reset(struct ch13726a_panel *ctx)
+{
+ gpiod_set_value_cansleep(ctx->reset_gpio, 0);
+ usleep_range(10000, 11000);
+ gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+ usleep_range(10000, 11000);
+ gpiod_set_value_cansleep(ctx->reset_gpio, 0);
+ usleep_range(10000, 11000);
+}
+
+static int ch13726a_on(struct ch13726a_panel *ctx)
+{
+ struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
+
+ ctx->dsi->mode_flags |= MIPI_DSI_MODE_LPM;
+
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf0, 0x50);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb9, 0x00);
+
+ mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
+
+ mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
+
+ return dsi_ctx.accum_err;
+}
+
+static int ch13726a_disable(struct drm_panel *panel)
+{
+ struct ch13726a_panel *ctx = to_ch13726a_panel(panel);
+ struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
+
+ ctx->dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
+
+ mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
+ mipi_dsi_msleep(&dsi_ctx, 50);
+ mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
+
+ return dsi_ctx.accum_err;
+}
+
+static int ch13726a_prepare(struct drm_panel *panel)
+{
+ struct ch13726a_panel *ctx = to_ch13726a_panel(panel);
+ struct device *dev = &ctx->dsi->dev;
+ int ret;
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(ch13726a_supplies), ctx->supplies);
+ if (ret < 0) {
+ dev_err(dev, "Failed to enable regulators: %d\n", ret);
+ return ret;
+ }
+
+ ch13726a_reset(ctx);
+
+ ret = ch13726a_on(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(ch13726a_supplies), ctx->supplies);
+ return ret;
+ }
+
+ msleep(28);
+
+ return 0;
+}
+
+static int ch13726a_unprepare(struct drm_panel *panel)
+{
+ struct ch13726a_panel *ctx = to_ch13726a_panel(panel);
+
+ gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+ regulator_bulk_disable(ARRAY_SIZE(ch13726a_supplies), ctx->supplies);
+
+ return 0;
+}
+
+static const struct drm_display_mode thor_bottom_modes[] = {
+ {
+ /* 120Hz */
+ .clock = (1080 + 28 + 4 + 36) * (1240 + 16 + 4 + 8) * 120 / 1000,
+ .hdisplay = 1080,
+ .hsync_start = 1080 + 28,
+ .hsync_end = 1080 + 28 + 4,
+ .htotal = 1080 + 28 + 4 + 36,
+ .vdisplay = 1240,
+ .vsync_start = 1240 + 16,
+ .vsync_end = 1240 + 16 + 4,
+ .vtotal = 1240 + 16 + 4 + 8,
+ },
+ {
+ /* 60Hz */
+ .clock = (1080 + 28 + 4 + 36) * (1240 + 16 + 4 + 8) * 60 / 1000,
+ .hdisplay = 1080,
+ .hsync_start = 1080 + 28,
+ .hsync_end = 1080 + 28 + 4,
+ .htotal = 1080 + 28 + 4 + 36,
+ .vdisplay = 1240,
+ .vsync_start = 1240 + 16,
+ .vsync_end = 1240 + 16 + 4,
+ .vtotal = 1240 + 16 + 4 + 8,
+ }
+};
+
+static struct ch13726a_desc thor_bottom_desc = {
+ .modes = thor_bottom_modes,
+ .num_modes = ARRAY_SIZE(thor_bottom_modes),
+ .width_mm = 65,
+ .height_mm = 75,
+ .bpc = 8,
+};
+
+static int ch13726a_get_modes(struct drm_panel *panel,
+ struct drm_connector *connector)
+{
+ struct ch13726a_panel *ctx = to_ch13726a_panel(panel);
+
+ for (uint8_t i = 0; i < ctx->desc->num_modes; i++) {
+ const struct drm_display_mode *m = &ctx->desc->modes[i];
+ struct drm_display_mode *mode;
+
+ mode = drm_mode_duplicate(connector->dev, m);
+ if (!mode) {
+ dev_err(&ctx->dsi->dev, "failed to add mode %ux%u@%u\n",
+ m->hdisplay, m->vdisplay, drm_mode_vrefresh(m));
+ return -ENOMEM;
+ }
+
+ mode->type = DRM_MODE_TYPE_DRIVER;
+ if (i == 0)
+ mode->type |= DRM_MODE_TYPE_PREFERRED;
+
+ drm_mode_set_name(mode);
+ drm_mode_probed_add(connector, mode);
+ }
+
+ connector->display_info.width_mm = ctx->desc->width_mm;
+ connector->display_info.height_mm = ctx->desc->height_mm;
+ connector->display_info.bpc = ctx->desc->bpc;
+
+ return ctx->desc->num_modes;
+}
+
+static enum drm_panel_orientation ch13726a_get_orientation(struct drm_panel *panel)
+{
+ struct ch13726a_panel *ctx = to_ch13726a_panel(panel);
+
+ return ctx->orientation;
+}
+
+static const struct drm_panel_funcs ch13726a_panel_funcs = {
+ .prepare = ch13726a_prepare,
+ .unprepare = ch13726a_unprepare,
+ .disable = ch13726a_disable,
+ .get_modes = ch13726a_get_modes,
+ .get_orientation = ch13726a_get_orientation,
+};
+
+static int ch13726a_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(dsi, brightness);
+ if (ret < 0)
+ return ret;
+
+ dsi->mode_flags |= MIPI_DSI_MODE_LPM;
+
+ return 0;
+}
+
+static const struct backlight_ops ch13726a_bl_ops = {
+ .update_status = ch13726a_bl_update_status,
+};
+
+static struct backlight_device *
+ch13726a_create_backlight(struct mipi_dsi_device *dsi)
+{
+ struct device *dev = &dsi->dev;
+ const struct backlight_properties props = {
+ .type = BACKLIGHT_RAW,
+ .brightness = 255,
+ .max_brightness = 255,
+ };
+
+ return devm_backlight_device_register(dev, dev_name(dev), dev, dsi,
+ &ch13726a_bl_ops, &props);
+}
+
+static int ch13726a_probe(struct mipi_dsi_device *dsi)
+{
+ struct device *dev = &dsi->dev;
+ struct ch13726a_panel *ctx;
+ int ret;
+
+ ctx = devm_drm_panel_alloc(dev, __typeof(*ctx), panel,
+ &ch13726a_panel_funcs,
+ DRM_MODE_CONNECTOR_DSI);
+ if (IS_ERR(ctx))
+ return PTR_ERR(ctx);
+
+ ctx->desc = (struct ch13726a_desc *)of_device_get_match_data(dev);
+ if (!ctx->desc)
+ return -ENODEV;
+
+ ret = devm_regulator_bulk_get_const(dev,
+ ARRAY_SIZE(ch13726a_supplies),
+ ch13726a_supplies,
+ &ctx->supplies);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Failed to get regulators\n");
+
+ 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");
+
+ ret = of_drm_get_panel_orientation(dev->of_node, &ctx->orientation);
+ if (ret < 0) {
+ dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, ret);
+ return ret;
+ }
+
+ ctx->dsi = dsi;
+ mipi_dsi_set_drvdata(dsi, ctx);
+
+ dsi->lanes = 4;
+ dsi->format = MIPI_DSI_FMT_RGB888;
+ dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
+ MIPI_DSI_CLOCK_NON_CONTINUOUS;
+
+ ctx->panel.prepare_prev_first = true;
+
+ ctx->panel.backlight = ch13726a_create_backlight(dsi);
+ if (IS_ERR(ctx->panel.backlight))
+ return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight),
+ "Failed to create backlight\n");
+
+ drm_panel_add(&ctx->panel);
+
+ ret = mipi_dsi_attach(dsi);
+ if (ret < 0) {
+ dev_err(dev, "Failed to attach to DSI host: %d\n", ret);
+ drm_panel_remove(&ctx->panel);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void ch13726a_remove(struct mipi_dsi_device *dsi)
+{
+ struct ch13726a_panel *ctx = mipi_dsi_get_drvdata(dsi);
+ int ret;
+
+ ret = mipi_dsi_detach(dsi);
+ if (ret < 0)
+ dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
+
+ drm_panel_remove(&ctx->panel);
+}
+
+static const struct of_device_id ch13726a_of_match[] = {
+ { .compatible = "ayntec,thor-panel-bottom", .data = &thor_bottom_desc },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, ch13726a_of_match);
+
+static struct mipi_dsi_driver ch13726a_driver = {
+ .probe = ch13726a_probe,
+ .remove = ch13726a_remove,
+ .driver = {
+ .name = "panel-ch13726a-amoled",
+ .of_match_table = ch13726a_of_match,
+ },
+};
+module_mipi_dsi_driver(ch13726a_driver);
+
+MODULE_DESCRIPTION("DRM driver for CH13726A DSI panels");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/panel/panel-focaltech-ota7290b.c b/drivers/gpu/drm/panel/panel-focaltech-ota7290b.c
index dd420bb19440..ed02a8daf96f 100644
--- a/drivers/gpu/drm/panel/panel-focaltech-ota7290b.c
+++ b/drivers/gpu/drm/panel/panel-focaltech-ota7290b.c
@@ -156,8 +156,8 @@ static int ota7290b_probe(struct mipi_dsi_device *dsi)
ctx = devm_drm_panel_alloc(&dsi->dev, struct ota7290b, panel,
&ota7290b_funcs,
DRM_MODE_CONNECTOR_DSI);
- if (!ctx)
- return -ENOMEM;
+ if (IS_ERR(ctx))
+ return PTR_ERR(ctx);
mipi_dsi_set_drvdata(dsi, ctx);
ctx->dsi = dsi;
diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c
index 947b47841b01..0652cdb57d11 100644
--- a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c
+++ b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c
@@ -52,6 +52,7 @@ struct ili9881c {
const struct ili9881c_desc *desc;
struct regulator *power;
+ struct regulator *iovcc;
struct gpio_desc *reset;
enum drm_panel_orientation orientation;
@@ -1997,6 +1998,205 @@ static const struct ili9881c_instr bsd1218_a101kl68_init[] = {
ILI9881C_COMMAND_INSTR(0xd3, 0x3f),
};
+static const struct ili9881c_instr waveshare_7inch_a_init[] = {
+ ILI9881C_SWITCH_PAGE_INSTR(3),
+ ILI9881C_COMMAND_INSTR(0x01, 0x00),
+ ILI9881C_COMMAND_INSTR(0x02, 0x00),
+ ILI9881C_COMMAND_INSTR(0x03, 0x73),
+ ILI9881C_COMMAND_INSTR(0x04, 0x00),
+ ILI9881C_COMMAND_INSTR(0x05, 0x00),
+ ILI9881C_COMMAND_INSTR(0x06, 0x0a),
+ ILI9881C_COMMAND_INSTR(0x07, 0x00),
+ ILI9881C_COMMAND_INSTR(0x08, 0x00),
+ ILI9881C_COMMAND_INSTR(0x09, 0x61),
+ ILI9881C_COMMAND_INSTR(0x0a, 0x00),
+ ILI9881C_COMMAND_INSTR(0x0b, 0x00),
+ ILI9881C_COMMAND_INSTR(0x0c, 0x01),
+ ILI9881C_COMMAND_INSTR(0x0d, 0x00),
+ ILI9881C_COMMAND_INSTR(0x0e, 0x00),
+ ILI9881C_COMMAND_INSTR(0x0f, 0x61),
+ ILI9881C_COMMAND_INSTR(0x10, 0x61),
+ ILI9881C_COMMAND_INSTR(0x11, 0x00),
+ ILI9881C_COMMAND_INSTR(0x12, 0x00),
+ ILI9881C_COMMAND_INSTR(0x13, 0x00),
+ ILI9881C_COMMAND_INSTR(0x14, 0x00),
+ ILI9881C_COMMAND_INSTR(0x15, 0x00),
+ ILI9881C_COMMAND_INSTR(0x16, 0x00),
+ ILI9881C_COMMAND_INSTR(0x17, 0x00),
+ ILI9881C_COMMAND_INSTR(0x18, 0x00),
+ ILI9881C_COMMAND_INSTR(0x19, 0x00),
+ ILI9881C_COMMAND_INSTR(0x1a, 0x00),
+ ILI9881C_COMMAND_INSTR(0x1b, 0x00),
+ ILI9881C_COMMAND_INSTR(0x1c, 0x00),
+ ILI9881C_COMMAND_INSTR(0x1d, 0x00),
+ ILI9881C_COMMAND_INSTR(0x1e, 0x40),
+ ILI9881C_COMMAND_INSTR(0x1f, 0x80),
+ ILI9881C_COMMAND_INSTR(0x20, 0x06),
+ ILI9881C_COMMAND_INSTR(0x21, 0x01),
+ ILI9881C_COMMAND_INSTR(0x22, 0x00),
+ ILI9881C_COMMAND_INSTR(0x23, 0x00),
+ ILI9881C_COMMAND_INSTR(0x24, 0x00),
+ ILI9881C_COMMAND_INSTR(0x25, 0x00),
+ ILI9881C_COMMAND_INSTR(0x26, 0x00),
+ ILI9881C_COMMAND_INSTR(0x27, 0x00),
+ ILI9881C_COMMAND_INSTR(0x28, 0x33),
+ ILI9881C_COMMAND_INSTR(0x29, 0x03),
+ ILI9881C_COMMAND_INSTR(0x2a, 0x00),
+ ILI9881C_COMMAND_INSTR(0x2b, 0x00),
+ ILI9881C_COMMAND_INSTR(0x2c, 0x00),
+ ILI9881C_COMMAND_INSTR(0x2d, 0x00),
+ ILI9881C_COMMAND_INSTR(0x2e, 0x00),
+ ILI9881C_COMMAND_INSTR(0x2f, 0x00),
+ ILI9881C_COMMAND_INSTR(0x30, 0x00),
+ ILI9881C_COMMAND_INSTR(0x31, 0x00),
+ ILI9881C_COMMAND_INSTR(0x32, 0x00),
+ ILI9881C_COMMAND_INSTR(0x33, 0x00),
+ ILI9881C_COMMAND_INSTR(0x34, 0x04),
+ ILI9881C_COMMAND_INSTR(0x35, 0x00),
+ ILI9881C_COMMAND_INSTR(0x36, 0x00),
+ ILI9881C_COMMAND_INSTR(0x37, 0x00),
+ ILI9881C_COMMAND_INSTR(0x38, 0x3c),
+ ILI9881C_COMMAND_INSTR(0x39, 0x00),
+ ILI9881C_COMMAND_INSTR(0x3a, 0x00),
+ ILI9881C_COMMAND_INSTR(0x3b, 0x00),
+ ILI9881C_COMMAND_INSTR(0x3c, 0x00),
+ ILI9881C_COMMAND_INSTR(0x3d, 0x00),
+ ILI9881C_COMMAND_INSTR(0x3e, 0x00),
+ ILI9881C_COMMAND_INSTR(0x3f, 0x00),
+ ILI9881C_COMMAND_INSTR(0x40, 0x00),
+ ILI9881C_COMMAND_INSTR(0x41, 0x00),
+ ILI9881C_COMMAND_INSTR(0x42, 0x00),
+ ILI9881C_COMMAND_INSTR(0x43, 0x00),
+ ILI9881C_COMMAND_INSTR(0x44, 0x00),
+ ILI9881C_COMMAND_INSTR(0x50, 0x10),
+ ILI9881C_COMMAND_INSTR(0x51, 0x32),
+ ILI9881C_COMMAND_INSTR(0x52, 0x54),
+ ILI9881C_COMMAND_INSTR(0x53, 0x76),
+ ILI9881C_COMMAND_INSTR(0x54, 0x98),
+ ILI9881C_COMMAND_INSTR(0x55, 0xba),
+ ILI9881C_COMMAND_INSTR(0x56, 0x10),
+ ILI9881C_COMMAND_INSTR(0x57, 0x32),
+ ILI9881C_COMMAND_INSTR(0x58, 0x54),
+ ILI9881C_COMMAND_INSTR(0x59, 0x76),
+ ILI9881C_COMMAND_INSTR(0x5a, 0x98),
+ ILI9881C_COMMAND_INSTR(0x5b, 0xba),
+ ILI9881C_COMMAND_INSTR(0x5c, 0xdc),
+ ILI9881C_COMMAND_INSTR(0x5d, 0xfe),
+ ILI9881C_COMMAND_INSTR(0x5e, 0x00),
+ ILI9881C_COMMAND_INSTR(0x5f, 0x0e),
+ ILI9881C_COMMAND_INSTR(0x60, 0x0f),
+ ILI9881C_COMMAND_INSTR(0x61, 0x0c),
+ ILI9881C_COMMAND_INSTR(0x62, 0x0d),
+ ILI9881C_COMMAND_INSTR(0x63, 0x06),
+ ILI9881C_COMMAND_INSTR(0x64, 0x07),
+ ILI9881C_COMMAND_INSTR(0x65, 0x02),
+ ILI9881C_COMMAND_INSTR(0x66, 0x02),
+ ILI9881C_COMMAND_INSTR(0x67, 0x02),
+ ILI9881C_COMMAND_INSTR(0x68, 0x02),
+ ILI9881C_COMMAND_INSTR(0x69, 0x01),
+ ILI9881C_COMMAND_INSTR(0x6a, 0x00),
+ ILI9881C_COMMAND_INSTR(0x6b, 0x02),
+ ILI9881C_COMMAND_INSTR(0x6c, 0x15),
+ ILI9881C_COMMAND_INSTR(0x6d, 0x14),
+ ILI9881C_COMMAND_INSTR(0x6e, 0x02),
+ ILI9881C_COMMAND_INSTR(0x6f, 0x02),
+ ILI9881C_COMMAND_INSTR(0x70, 0x02),
+ ILI9881C_COMMAND_INSTR(0x71, 0x02),
+ ILI9881C_COMMAND_INSTR(0x72, 0x02),
+ ILI9881C_COMMAND_INSTR(0x73, 0x02),
+ ILI9881C_COMMAND_INSTR(0x74, 0x02),
+ ILI9881C_COMMAND_INSTR(0x75, 0x0e),
+ ILI9881C_COMMAND_INSTR(0x76, 0x0f),
+ ILI9881C_COMMAND_INSTR(0x77, 0x0c),
+ ILI9881C_COMMAND_INSTR(0x78, 0x0d),
+ ILI9881C_COMMAND_INSTR(0x79, 0x06),
+ ILI9881C_COMMAND_INSTR(0x7a, 0x07),
+ ILI9881C_COMMAND_INSTR(0x7b, 0x02),
+ ILI9881C_COMMAND_INSTR(0x7c, 0x02),
+ ILI9881C_COMMAND_INSTR(0x7d, 0x02),
+ ILI9881C_COMMAND_INSTR(0x7e, 0x02),
+ ILI9881C_COMMAND_INSTR(0x7f, 0x01),
+ ILI9881C_COMMAND_INSTR(0x80, 0x00),
+ ILI9881C_COMMAND_INSTR(0x81, 0x02),
+ ILI9881C_COMMAND_INSTR(0x82, 0x14),
+ ILI9881C_COMMAND_INSTR(0x83, 0x15),
+ ILI9881C_COMMAND_INSTR(0x84, 0x02),
+ ILI9881C_COMMAND_INSTR(0x85, 0x02),
+ ILI9881C_COMMAND_INSTR(0x86, 0x02),
+ ILI9881C_COMMAND_INSTR(0x87, 0x02),
+ ILI9881C_COMMAND_INSTR(0x88, 0x02),
+ ILI9881C_COMMAND_INSTR(0x89, 0x02),
+ ILI9881C_COMMAND_INSTR(0x8a, 0x02),
+
+ ILI9881C_SWITCH_PAGE_INSTR(4),
+ ILI9881C_COMMAND_INSTR(0x38, 0x01),
+ ILI9881C_COMMAND_INSTR(0x39, 0x00),
+ ILI9881C_COMMAND_INSTR(0x6c, 0x15),
+ ILI9881C_COMMAND_INSTR(0x6e, 0x2a),
+ ILI9881C_COMMAND_INSTR(0x6f, 0x33),
+ ILI9881C_COMMAND_INSTR(0x3a, 0x94),
+ ILI9881C_COMMAND_INSTR(0x8d, 0x14),
+ ILI9881C_COMMAND_INSTR(0x87, 0xba),
+ ILI9881C_COMMAND_INSTR(0x26, 0x76),
+ ILI9881C_COMMAND_INSTR(0xb2, 0xd1),
+ ILI9881C_COMMAND_INSTR(0xb5, 0x06),
+ ILI9881C_COMMAND_INSTR(0x3b, 0x98),
+
+ ILI9881C_SWITCH_PAGE_INSTR(1),
+ ILI9881C_COMMAND_INSTR(0x22, 0x0a),
+ ILI9881C_COMMAND_INSTR(0x31, 0x00),
+ ILI9881C_COMMAND_INSTR(0x53, 0x71),
+ ILI9881C_COMMAND_INSTR(0x55, 0x8f),
+ ILI9881C_COMMAND_INSTR(0x40, 0x33),
+ ILI9881C_COMMAND_INSTR(0x50, 0x96),
+ ILI9881C_COMMAND_INSTR(0x51, 0x96),
+ ILI9881C_COMMAND_INSTR(0x60, 0x23),
+ ILI9881C_COMMAND_INSTR(0xa0, 0x08),
+ ILI9881C_COMMAND_INSTR(0xa1, 0x1d),
+ ILI9881C_COMMAND_INSTR(0xa2, 0x2a),
+ ILI9881C_COMMAND_INSTR(0xa3, 0x10),
+ ILI9881C_COMMAND_INSTR(0xa4, 0x15),
+ ILI9881C_COMMAND_INSTR(0xa5, 0x28),
+ ILI9881C_COMMAND_INSTR(0xa6, 0x1c),
+ ILI9881C_COMMAND_INSTR(0xa7, 0x1d),
+ ILI9881C_COMMAND_INSTR(0xa8, 0x7e),
+ ILI9881C_COMMAND_INSTR(0xa9, 0x1d),
+ ILI9881C_COMMAND_INSTR(0xaa, 0x29),
+ ILI9881C_COMMAND_INSTR(0xab, 0x6b),
+ ILI9881C_COMMAND_INSTR(0xac, 0x1a),
+ ILI9881C_COMMAND_INSTR(0xad, 0x18),
+ ILI9881C_COMMAND_INSTR(0xae, 0x4b),
+ ILI9881C_COMMAND_INSTR(0xaf, 0x20),
+ ILI9881C_COMMAND_INSTR(0xb0, 0x27),
+ ILI9881C_COMMAND_INSTR(0xb1, 0x50),
+ ILI9881C_COMMAND_INSTR(0xb2, 0x64),
+ ILI9881C_COMMAND_INSTR(0xb3, 0x39),
+ ILI9881C_COMMAND_INSTR(0xc0, 0x08),
+ ILI9881C_COMMAND_INSTR(0xc1, 0x1d),
+ ILI9881C_COMMAND_INSTR(0xc2, 0x2a),
+ ILI9881C_COMMAND_INSTR(0xc3, 0x10),
+ ILI9881C_COMMAND_INSTR(0xc4, 0x15),
+ ILI9881C_COMMAND_INSTR(0xc5, 0x28),
+ ILI9881C_COMMAND_INSTR(0xc6, 0x1c),
+ ILI9881C_COMMAND_INSTR(0xc7, 0x1d),
+ ILI9881C_COMMAND_INSTR(0xc8, 0x7e),
+ ILI9881C_COMMAND_INSTR(0xc9, 0x1d),
+ ILI9881C_COMMAND_INSTR(0xca, 0x29),
+ ILI9881C_COMMAND_INSTR(0xcb, 0x6b),
+ ILI9881C_COMMAND_INSTR(0xcc, 0x1a),
+ ILI9881C_COMMAND_INSTR(0xcd, 0x18),
+ ILI9881C_COMMAND_INSTR(0xce, 0x4b),
+ ILI9881C_COMMAND_INSTR(0xcf, 0x20),
+ ILI9881C_COMMAND_INSTR(0xd0, 0x27),
+ ILI9881C_COMMAND_INSTR(0xd1, 0x50),
+ ILI9881C_COMMAND_INSTR(0xd2, 0x64),
+ ILI9881C_COMMAND_INSTR(0xd3, 0x39),
+
+ ILI9881C_SWITCH_PAGE_INSTR(0),
+ ILI9881C_COMMAND_INSTR(0x3a, 0x77),
+ ILI9881C_COMMAND_INSTR(0x36, 0x00),
+};
+
static inline struct ili9881c *panel_to_ili9881c(struct drm_panel *panel)
{
return container_of(panel, struct ili9881c, panel);
@@ -2035,9 +2235,19 @@ static int ili9881c_prepare(struct drm_panel *panel)
int ret;
/* Power the panel */
+ if (ctx->iovcc) {
+ ret = regulator_enable(ctx->iovcc);
+ if (ret)
+ return ret;
+ }
+
+ msleep(5);
ret = regulator_enable(ctx->power);
- if (ret)
- return ret;
+ if (ret) {
+ mctx.accum_err = ret;
+ goto disable_iovcc;
+ }
+
msleep(5);
/* And reset it */
@@ -2074,6 +2284,9 @@ static int ili9881c_prepare(struct drm_panel *panel)
disable_power:
regulator_disable(ctx->power);
+disable_iovcc:
+ if (ctx->iovcc)
+ regulator_disable(ctx->iovcc);
return mctx.accum_err;
}
@@ -2085,6 +2298,8 @@ static int ili9881c_unprepare(struct drm_panel *panel)
mipi_dsi_dcs_set_display_off_multi(&mctx);
mipi_dsi_dcs_enter_sleep_mode_multi(&mctx);
regulator_disable(ctx->power);
+ if (ctx->iovcc)
+ regulator_disable(ctx->iovcc);
gpiod_set_value_cansleep(ctx->reset, 1);
return 0;
@@ -2260,6 +2475,23 @@ static const struct drm_display_mode bsd1218_a101kl68_default_mode = {
.height_mm = 170,
};
+static const struct drm_display_mode waveshare_7inch_a_mode = {
+ .clock = 83333,
+
+ .hdisplay = 720,
+ .hsync_start = 720 + 120,
+ .hsync_end = 720 + 120 + 100,
+ .htotal = 720 + 120 + 100 + 100,
+
+ .vdisplay = 1280,
+ .vsync_start = 1280 + 10,
+ .vsync_end = 1280 + 10 + 10,
+ .vtotal = 1280 + 10 + 10 + 10,
+
+ .width_mm = 85,
+ .height_mm = 154,
+};
+
static int ili9881c_get_modes(struct drm_panel *panel,
struct drm_connector *connector)
{
@@ -2329,6 +2561,11 @@ static int ili9881c_dsi_probe(struct mipi_dsi_device *dsi)
return dev_err_probe(&dsi->dev, PTR_ERR(ctx->power),
"Couldn't get our power regulator\n");
+ ctx->iovcc = devm_regulator_get_optional(&dsi->dev, "iovcc");
+ if (IS_ERR(ctx->iovcc))
+ return dev_err_probe(&dsi->dev, PTR_ERR(ctx->iovcc),
+ "Couldn't get our iovcc regulator\n");
+
ctx->reset = devm_gpiod_get_optional(&dsi->dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(ctx->reset))
return dev_err_probe(&dsi->dev, PTR_ERR(ctx->reset),
@@ -2454,6 +2691,15 @@ static const struct ili9881c_desc bsd1218_a101kl68_desc = {
.lanes = 4,
};
+static const struct ili9881c_desc waveshare_7inch_a_desc = {
+ .init = waveshare_7inch_a_init,
+ .init_length = ARRAY_SIZE(waveshare_7inch_a_init),
+ .mode = &waveshare_7inch_a_mode,
+ .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_HSE |
+ MIPI_DSI_MODE_LPM | MIPI_DSI_CLOCK_NON_CONTINUOUS,
+ .lanes = 2,
+};
+
static const struct of_device_id ili9881c_of_match[] = {
{ .compatible = "bananapi,lhr050h41", .data = &lhr050h41_desc },
{ .compatible = "bestar,bsd1218-a101kl68", .data = &bsd1218_a101kl68_desc },
@@ -2462,6 +2708,7 @@ static const struct of_device_id ili9881c_of_match[] = {
{ .compatible = "tdo,tl050hdv35", .data = &tl050hdv35_desc },
{ .compatible = "wanchanglong,w552946aaa", .data = &w552946aaa_desc },
{ .compatible = "wanchanglong,w552946aba", .data = &w552946aba_desc },
+ { .compatible = "waveshare,7.0-dsi-touch-a", .data = &waveshare_7inch_a_desc },
{ .compatible = "ampire,am8001280g", .data = &am8001280g_desc },
{ .compatible = "raspberrypi,dsi-5inch", &rpi_5inch_desc },
{ .compatible = "raspberrypi,dsi-7inch", &rpi_7inch_desc },
diff --git a/drivers/gpu/drm/panel/panel-jadard-jd9365da-h3.c b/drivers/gpu/drm/panel/panel-jadard-jd9365da-h3.c
index 7157b1299bfd..f6b04de1182e 100644
--- a/drivers/gpu/drm/panel/panel-jadard-jd9365da-h3.c
+++ b/drivers/gpu/drm/panel/panel-jadard-jd9365da-h3.c
@@ -2955,9 +2955,11 @@ static int jadard_dsi_probe(struct mipi_dsi_device *dsi)
dsi->format = desc->format;
dsi->lanes = desc->lanes;
if (!dsi->lanes) {
- dsi->lanes = drm_of_get_data_lanes_count_remote(dsi->dev.of_node, 0, -1, 2, 4);
- if (dsi->lanes < 0)
- return dsi->lanes;
+ ret = drm_of_get_data_lanes_count_remote(dsi->dev.of_node, 0, -1, 2, 4);
+ if (ret < 0)
+ return ret;
+ dsi->lanes = ret;
+
if (dsi->lanes == 4) {
if (!desc->mode_4ln) {
dev_err(&dsi->dev, "4-lane config is not supported\n");
diff --git a/drivers/gpu/drm/panel/panel-novatek-nt35532.c b/drivers/gpu/drm/panel/panel-novatek-nt35532.c
new file mode 100644
index 000000000000..184f61bca7ca
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-novatek-nt35532.c
@@ -0,0 +1,796 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree.
+ * Copyright (c) 2026 Cristian Cozzolino <cristian_ci@protonmail.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/regulator/consumer.h>
+
+#include <video/mipi_display.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_nt35532 {
+ struct drm_panel panel;
+ struct mipi_dsi_device *dsi;
+ struct regulator_bulk_data *supplies;
+ struct gpio_desc *reset_gpio;
+ const struct nt35532_panel_desc *desc;
+};
+
+struct nt35532_panel_desc {
+ const struct drm_display_mode *mode;
+ int (*on)(struct novatek_nt35532 *ctx);
+};
+
+static const struct regulator_bulk_data nt35532_supplies[] = {
+ { .supply = "vci" },
+ { .supply = "vddi" },
+ { .supply = "avee" },
+ { .supply = "avdd" },
+};
+
+static inline struct novatek_nt35532 *to_novatek_nt35532(struct drm_panel *panel)
+{
+ return container_of_const(panel, struct novatek_nt35532, panel);
+}
+
+static void nt35532_reset(struct novatek_nt35532 *ctx)
+{
+ gpiod_set_value_cansleep(ctx->reset_gpio, 0);
+ usleep_range(10000, 11000);
+ gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+ usleep_range(5000, 6000);
+ gpiod_set_value_cansleep(ctx->reset_gpio, 0);
+ usleep_range(10000, 11000);
+}
+
+static int rimob_panel_on(struct novatek_nt35532 *ctx)
+{
+ struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
+
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xff, 0x01);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x6e, 0x80);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x68, 0x13);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfb, 0x01);
+
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xff, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfb, 0x01);
+
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xff, 0x05);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfb, 0x01);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd7, 0x31);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd8, 0x7e);
+
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xff, 0x01);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfb, 0x01);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x01, 0x55);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x04, 0x0c);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x05, 0x3a);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x06, 0x50);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x07, 0xd0);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x0a, 0x0f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x0c, 0x06);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x0d, 0x6b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x0e, 0x6b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x0f, 0x70);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x10, 0x63);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x11, 0x3c);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x12, 0x5c);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x15, 0x60);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x16, 0x15);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x17, 0x15);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x5b, 0xca);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x5c, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x5d, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x5f, 0x1b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x60, 0xd5);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x61, 0xf0);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x6c, 0xab);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x6d, 0x44);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x6e, 0x80);
+
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xff, 0x05);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfb, 0x01);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x00, 0x3f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x01, 0x3f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x02, 0x3f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x03, 0x3f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x04, 0x38);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x05, 0x3f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x06, 0x3f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x07, 0x19);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x08, 0x1b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x09, 0x3f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x0a, 0x1d);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x0b, 0x17);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x0c, 0x3f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x0d, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x0e, 0x08);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x0f, 0x0c);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x10, 0x3f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x11, 0x10);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x12, 0x3f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x13, 0x3f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x14, 0x3f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x15, 0x3f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x16, 0x3f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x17, 0x3f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x18, 0x38);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x19, 0x18);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x1a, 0x1a);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x1b, 0x3f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x1c, 0x3f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x1d, 0x1c);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x1e, 0x16);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x1f, 0x3f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x20, 0x3f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x21, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x22, 0x06);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x23, 0x0a);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x24, 0x3f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x25, 0x0e);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x26, 0x3f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x27, 0x3f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x54, 0x08);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x55, 0x07);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x56, 0x1a);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x58, 0x19);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x59, 0x36);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x5a, 0x1b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x5b, 0x01);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x5c, 0x32);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x5e, 0x27);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x5f, 0x28);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x60, 0x2b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x61, 0x2c);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x62, 0x18);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x63, 0x01);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x64, 0x32);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x65, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x66, 0x44);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x67, 0x11);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x68, 0x01);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x69, 0x01);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x6a, 0x06);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x6b, 0x22);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x6c, 0x08);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x6d, 0x08);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x78, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x79, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x7e, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x7f, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x80, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x81, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8d, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8e, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8f, 0xc0);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x90, 0x73);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x91, 0x10);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x92, 0x09);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x96, 0x11);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x97, 0x14);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x98, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x99, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9a, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9b, 0x61);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9c, 0x15);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9d, 0x30);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9f, 0x0f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa2, 0xb0);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa7, 0x0a);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa9, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xaa, 0x70);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xab, 0xda);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xac, 0xff);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xae, 0xf4);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xaf, 0x40);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb0, 0x7f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb1, 0x16);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb2, 0x53);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb3, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb4, 0x2a);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb5, 0x3a);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb6, 0xf0);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbc, 0x85);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbd, 0xf8);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbe, 0x3b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbf, 0x13);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc0, 0x77);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc1, 0x77);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc2, 0x77);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc3, 0x77);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc4, 0x77);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc5, 0x77);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc6, 0x77);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc7, 0x77);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc8, 0xaa);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc9, 0x2a);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xca, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcb, 0xaa);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcc, 0x92);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcd, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xce, 0x18);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcf, 0x88);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd0, 0xaa);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd1, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd2, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd3, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd6, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xed, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xee, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xef, 0x70);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfa, 0x03);
+
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xff, 0x01);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfb, 0x01);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x75, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x76, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x77, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x78, 0x20);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x79, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x7a, 0x49);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x7b, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x7c, 0x66);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x7d, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x7e, 0x7d);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x7f, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x80, 0x91);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x81, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x82, 0xa3);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x83, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x84, 0xb3);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x85, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x86, 0xc1);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x87, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x88, 0xf1);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x89, 0x01);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8a, 0x18);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8b, 0x01);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8c, 0x54);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8d, 0x01);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8e, 0x85);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8f, 0x01);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x90, 0xd1);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x91, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x92, 0x0c);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x93, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x94, 0x0e);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x95, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x96, 0x43);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x97, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x98, 0x7d);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x99, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9a, 0xa2);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9b, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9c, 0xd7);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9d, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9e, 0xf8);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9f, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa0, 0x2b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa2, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa3, 0x3a);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa4, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa5, 0x4b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa6, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa7, 0x5d);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa9, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xaa, 0x73);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xab, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xac, 0x8e);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xad, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xae, 0xae);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xaf, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb0, 0xc9);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb1, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb2, 0xcd);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb3, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb4, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb5, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb6, 0x20);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb7, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb8, 0x49);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb9, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xba, 0x66);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbb, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbc, 0x7d);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbd, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbe, 0x91);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbf, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc0, 0xa3);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc1, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc2, 0xb3);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc3, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc4, 0xc1);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc5, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc6, 0xf1);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc7, 0x01);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc8, 0x18);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc9, 0x01);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xca, 0x54);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcb, 0x01);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcc, 0x85);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcd, 0x01);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xce, 0xd1);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcf, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd0, 0x0c);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd1, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd2, 0x0e);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd3, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd4, 0x43);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd5, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd6, 0x7d);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd7, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd8, 0xa2);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd9, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xda, 0xd7);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdb, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdc, 0xf8);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdd, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xde, 0x2b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdf, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe0, 0x3a);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe1, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe2, 0x4b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe3, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe4, 0x5d);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe5, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe6, 0x73);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe7, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe8, 0x8e);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe9, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xea, 0xae);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xeb, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xec, 0xc9);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xed, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xee, 0xcd);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xef, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf0, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf1, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf2, 0x20);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf3, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf4, 0x49);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf5, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf6, 0x66);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf7, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf8, 0x7d);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf9, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfa, 0x91);
+
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xff, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfb, 0x01);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x00, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x01, 0xa3);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x02, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x03, 0xb3);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x04, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x05, 0xc1);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x06, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x07, 0xf1);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x08, 0x01);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x09, 0x18);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x0a, 0x01);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x0b, 0x54);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x0c, 0x01);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x0d, 0x85);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x0e, 0x01);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x0f, 0xd1);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x10, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x11, 0x0c);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x12, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x13, 0x0e);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x14, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x15, 0x43);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x16, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x17, 0x7d);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x18, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x19, 0xa2);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x1a, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x1b, 0xd7);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x1c, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x1d, 0xf8);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x1e, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x1f, 0x2b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x20, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x21, 0x3a);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x22, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x23, 0x4b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x24, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x25, 0x5d);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x26, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x27, 0x73);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x28, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x29, 0x8e);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x2a, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x2b, 0xae);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x2d, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x2f, 0xc9);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x30, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x31, 0xcd);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x32, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x33, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x34, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x35, 0x20);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x36, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x37, 0x49);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x38, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x39, 0x66);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x3a, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x3b, 0x7d);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x3d, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x3f, 0x91);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x40, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x41, 0xa3);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x42, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x43, 0xb3);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x44, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x45, 0xc1);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x46, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x47, 0xf1);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x48, 0x01);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x49, 0x18);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x4a, 0x01);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x4b, 0x54);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x4c, 0x01);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x4d, 0x85);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x4e, 0x01);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x4f, 0xd1);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x50, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x51, 0x0c);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x52, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x53, 0x0e);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x54, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x55, 0x43);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x56, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x58, 0x7d);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x59, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x5a, 0xa2);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x5b, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x5c, 0xd7);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x5d, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x5e, 0xf8);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x5f, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x60, 0x2b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x61, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x62, 0x3a);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x63, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x64, 0x4b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x65, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x66, 0x5d);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x67, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x68, 0x73);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x69, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x6a, 0x8e);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x6b, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x6c, 0xae);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x6d, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x6e, 0xc9);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x6f, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x70, 0xcd);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x71, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x72, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x73, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x74, 0x20);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x75, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x76, 0x49);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x77, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x78, 0x66);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x79, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x7a, 0x7d);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x7b, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x7c, 0x91);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x7d, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x7e, 0xa3);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x7f, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x80, 0xb3);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x81, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x82, 0xc1);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x83, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x84, 0xf1);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x85, 0x01);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x86, 0x18);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x87, 0x01);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x88, 0x54);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x89, 0x01);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8a, 0x85);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8b, 0x01);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8c, 0xd1);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8d, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8e, 0x0c);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8f, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x90, 0x0e);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x91, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x92, 0x43);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x93, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x94, 0x7d);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x95, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x96, 0xa2);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x97, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x98, 0xd7);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x99, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9a, 0xf8);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9b, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9c, 0x2b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9d, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9e, 0x3a);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9f, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa0, 0x4b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa2, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa3, 0x5d);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa4, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa5, 0x73);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa6, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa7, 0x8e);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa9, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xaa, 0xae);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xab, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xac, 0xc9);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xad, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xae, 0xcd);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xaf, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb0, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb1, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb2, 0x20);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb3, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb4, 0x49);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb5, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb6, 0x66);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb7, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb8, 0x7d);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb9, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xba, 0x91);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbb, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbc, 0xa3);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbd, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbe, 0xb3);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbf, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc0, 0xc1);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc1, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc2, 0xf1);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc3, 0x01);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc4, 0x18);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc5, 0x01);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc6, 0x54);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc7, 0x01);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc8, 0x85);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc9, 0x01);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xca, 0xd1);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcb, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcc, 0x0c);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcd, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xce, 0x0e);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcf, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd0, 0x43);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd1, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd2, 0x7d);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd3, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd4, 0xa2);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd5, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd6, 0xd7);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd7, 0x02);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd8, 0xf8);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd9, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xda, 0x2b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdb, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdc, 0x3a);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdd, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xde, 0x4b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdf, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe0, 0x5d);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe1, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe2, 0x73);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe3, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe4, 0x8e);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe5, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe6, 0xae);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe7, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe8, 0xc9);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe9, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xea, 0xcd);
+
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xff, 0xee);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x02, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x40, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x02, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x41, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x02, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x42, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfb, 0x01);
+
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xff, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfb, 0x01);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xba, 0x03);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x35, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x36, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb0, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd3, 0x10);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd4, 0x0f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd5, 0x0f);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd6, 0x48);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd7, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd9, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, MIPI_DCS_EXIT_SLEEP_MODE, 0x00);
+ mipi_dsi_msleep(&dsi_ctx, 120);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_DISPLAY_ON, 0x00);
+ mipi_dsi_msleep(&dsi_ctx, 50);
+
+ return dsi_ctx.accum_err;
+}
+
+static int nt35532_off(struct novatek_nt35532 *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, 50);
+ mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
+ mipi_dsi_msleep(&dsi_ctx, 120);
+
+ return dsi_ctx.accum_err;
+}
+
+static int nt35532_prepare(struct drm_panel *panel)
+{
+ struct novatek_nt35532 *ctx = to_novatek_nt35532(panel);
+ struct device *dev = &ctx->dsi->dev;
+ int ret;
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(nt35532_supplies), ctx->supplies);
+ if (ret < 0) {
+ dev_err(dev, "Failed to enable regulators: %d\n", ret);
+ return ret;
+ }
+
+ nt35532_reset(ctx);
+
+ ret = ctx->desc->on(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(nt35532_supplies), ctx->supplies);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int nt35532_unprepare(struct drm_panel *panel)
+{
+ struct novatek_nt35532 *ctx = to_novatek_nt35532(panel);
+ struct device *dev = &ctx->dsi->dev;
+ int ret;
+
+ ret = nt35532_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(nt35532_supplies), ctx->supplies);
+
+ return 0;
+}
+
+static const struct drm_display_mode rimob_panel_mode = {
+ .clock = (1080 + 100 + 6 + 94) * (1920 + 15 + 6 + 10) * 60 / 1000,
+ .hdisplay = 1080,
+ .hsync_start = 1080 + 100,
+ .hsync_end = 1080 + 100 + 6,
+ .htotal = 1080 + 100 + 6 + 94,
+ .vdisplay = 1920,
+ .vsync_start = 1920 + 15,
+ .vsync_end = 1920 + 15 + 6,
+ .vtotal = 1920 + 15 + 6 + 10,
+ .width_mm = 68,
+ .height_mm = 121,
+ .type = DRM_MODE_TYPE_DRIVER,
+};
+
+static int nt35532_get_modes(struct drm_panel *panel,
+ struct drm_connector *connector)
+{
+ struct novatek_nt35532 *ctx = to_novatek_nt35532(panel);
+ const struct drm_display_mode *mode = ctx->desc->mode;
+
+ return drm_connector_helper_get_modes_fixed(connector, mode);
+}
+
+static const struct nt35532_panel_desc rimob_panel_desc = {
+ .mode = &rimob_panel_mode,
+ .on = rimob_panel_on,
+};
+
+static const struct drm_panel_funcs novatek_nt35532_panel_funcs = {
+ .prepare = nt35532_prepare,
+ .unprepare = nt35532_unprepare,
+ .get_modes = nt35532_get_modes,
+};
+
+static int nt35532_probe(struct mipi_dsi_device *dsi)
+{
+ struct device *dev = &dsi->dev;
+ struct novatek_nt35532 *ctx;
+ int ret;
+
+ ctx = devm_drm_panel_alloc(dev, struct novatek_nt35532, panel,
+ &novatek_nt35532_panel_funcs,
+ DRM_MODE_CONNECTOR_DSI);
+ if (IS_ERR(ctx))
+ return PTR_ERR(ctx);
+
+ ctx->desc = device_get_match_data(dev);
+
+ ret = devm_regulator_bulk_get_const(dev,
+ ARRAY_SIZE(nt35532_supplies),
+ nt35532_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 = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
+ MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_LPM;
+
+ 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");
+
+ drm_panel_add(&ctx->panel);
+
+ ret = mipi_dsi_attach(dsi);
+ if (ret < 0) {
+ drm_panel_remove(&ctx->panel);
+ return dev_err_probe(dev, ret, "Failed to attach to DSI host\n");
+ }
+
+ return 0;
+}
+
+static void nt35532_remove(struct mipi_dsi_device *dsi)
+{
+ struct novatek_nt35532 *ctx = mipi_dsi_get_drvdata(dsi);
+ int ret;
+
+ ret = mipi_dsi_detach(dsi);
+ if (ret < 0)
+ dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
+
+ drm_panel_remove(&ctx->panel);
+}
+
+static const struct of_device_id nt35532_of_match[] = {
+ { .compatible = "flipkart,rimob-panel-nt35532-cs", .data = &rimob_panel_desc },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, nt35532_of_match);
+
+static struct mipi_dsi_driver nt35532_driver = {
+ .probe = nt35532_probe,
+ .remove = nt35532_remove,
+ .driver = {
+ .name = "panel-novatek-nt35532",
+ .of_match_table = nt35532_of_match,
+ },
+};
+module_mipi_dsi_driver(nt35532_driver);
+
+MODULE_DESCRIPTION("DRM driver for Novatek NT35532-based 1080p video mode DSI panel");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c b/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c
index 3c3308fc55df..d21d93a0700e 100644
--- a/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c
+++ b/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c
@@ -44,14 +44,23 @@ static inline struct wuxga_nt_panel *to_wuxga_nt_panel(struct drm_panel *panel)
static int wuxga_nt_panel_on(struct wuxga_nt_panel *wuxga_nt)
{
- return mipi_dsi_turn_on_peripheral(wuxga_nt->dsi);
+ struct mipi_dsi_multi_context dsi_ctx = {
+ .dsi = wuxga_nt->dsi
+ };
+
+ mipi_dsi_turn_on_peripheral_multi(&dsi_ctx);
+ return dsi_ctx.accum_err;
}
static int wuxga_nt_panel_disable(struct drm_panel *panel)
{
struct wuxga_nt_panel *wuxga_nt = to_wuxga_nt_panel(panel);
+ struct mipi_dsi_multi_context dsi_ctx = {
+ .dsi = wuxga_nt->dsi
+ };
- return mipi_dsi_shutdown_peripheral(wuxga_nt->dsi);
+ mipi_dsi_shutdown_peripheral_multi(&dsi_ctx);
+ return dsi_ctx.accum_err;
}
static int wuxga_nt_panel_unprepare(struct drm_panel *panel)
@@ -94,15 +103,8 @@ static int wuxga_nt_panel_prepare(struct drm_panel *panel)
msleep(250);
ret = wuxga_nt_panel_on(wuxga_nt);
- if (ret < 0) {
- dev_err(panel->dev, "failed to set panel on: %d\n", ret);
- goto poweroff;
- }
-
- return 0;
-
-poweroff:
- regulator_disable(wuxga_nt->supply);
+ if (ret < 0)
+ regulator_disable(wuxga_nt->supply);
return ret;
}
diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
index b2708a1fe464..2fbb9dff0a34 100644
--- a/drivers/gpu/drm/panel/panel-simple.c
+++ b/drivers/gpu/drm/panel/panel-simple.c
@@ -1902,6 +1902,39 @@ static const struct panel_desc dataimage_scf0700c48ggu18 = {
.connector_type = DRM_MODE_CONNECTOR_DPI,
};
+static const struct display_timing displaytech_dt050btft_pts_timing = {
+ /* The TYP pixel clock are recalculated from tV * tH * 60 Hz */
+ .pixelclock = { 30000000, 33264000, 50000000 },
+ .hactive = { 800, 800, 800 },
+ .hfront_porch = { 16, 210, 354 },
+ /* Datasheet Figure 3 indicates, that tHPW is part of tHBP */
+ .hback_porch = { 41, 26, 6 },
+ .hsync_len = { 1, 20, 40 },
+ .vactive = { 480, 480, 480 },
+ .vfront_porch = { 7, 22, 147 },
+ /* Datasheet Figure 2 indicates, that tVPW is part of tVBP */
+ .vback_porch = { 22, 13, 3 },
+ .vsync_len = { 1, 10, 20 },
+ .flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW |
+ DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_PIXDATA_POSEDGE |
+ DISPLAY_FLAGS_SYNC_POSEDGE,
+};
+
+static const struct panel_desc displaytech_dt050btft_pts = {
+ .timings = &displaytech_dt050btft_pts_timing,
+ .num_timings = 1,
+ .bpc = 8,
+ .size = {
+ .width = 108,
+ .height = 65,
+ },
+ .bus_format = MEDIA_BUS_FMT_RGB888_1X24,
+ .bus_flags = DRM_BUS_FLAG_DE_HIGH |
+ DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE |
+ DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE,
+ .connector_type = DRM_MODE_CONNECTOR_DPI,
+};
+
static const struct display_timing dlc_dlc0700yzg_1_timing = {
.pixelclock = { 45000000, 51200000, 57000000 },
.hactive = { 1024, 1024, 1024 },
@@ -4603,6 +4636,32 @@ static const struct panel_desc starry_kr070pe2t = {
.connector_type = DRM_MODE_CONNECTOR_DPI,
};
+static const struct display_timing startek_kd070hdfld092_timing = {
+ .pixelclock = { 40800000, 51200000, 67200000 },
+ .hactive = { 1024, 1024, 1024 },
+ .hfront_porch = { 40, 160, 216 },
+ .hback_porch = { 30, 140, 140 },
+ .hsync_len = { 20, 20, 20 },
+ .vactive = { 600, 600, 600 },
+ .vfront_porch = { 2, 12, 177 },
+ .vback_porch = { 5, 20, 20 },
+ .vsync_len = { 3, 3, 3 },
+ .flags = DISPLAY_FLAGS_DE_HIGH,
+};
+
+static const struct panel_desc startek_kd070hdfld092 = {
+ .timings = &startek_kd070hdfld092_timing,
+ .num_timings = 1,
+ .bpc = 8,
+ .size = {
+ .width = 154,
+ .height = 86,
+ },
+ .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
+ .bus_flags = DRM_BUS_FLAG_DE_HIGH,
+ .connector_type = DRM_MODE_CONNECTOR_LVDS,
+};
+
static const struct display_timing startek_kd070wvfpa_mode = {
.pixelclock = { 25200000, 27200000, 30500000 },
.hactive = { 800, 800, 800 },
@@ -5656,6 +5715,9 @@ static const struct of_device_id platform_of_match[] = {
.compatible = "dataimage,scf0700c48ggu18",
.data = &dataimage_scf0700c48ggu18,
}, {
+ .compatible = "displaytech,dt050btft-pts",
+ .data = &displaytech_dt050btft_pts,
+ }, {
.compatible = "dlc,dlc0700yzg-1",
.data = &dlc_dlc0700yzg_1,
}, {
@@ -5965,6 +6027,9 @@ static const struct of_device_id platform_of_match[] = {
.compatible = "starry,kr070pe2t",
.data = &starry_kr070pe2t,
}, {
+ .compatible = "startek,kd070hdfld092",
+ .data = &startek_kd070hdfld092,
+ }, {
.compatible = "startek,kd070wvfpa",
.data = &startek_kd070wvfpa,
}, {
@@ -6317,6 +6382,39 @@ static const struct panel_desc_dsi osd101t2045_53ts = {
.lanes = 4,
};
+static const struct drm_display_mode tsd_tst070wsbe_196c_mode = {
+ .clock = 52477,
+ .hdisplay = 1024,
+ .hsync_start = 1024 + 160,
+ .hsync_end = 1024 + 160 + 12,
+ .htotal = 1024 + 160 + 160 + 12,
+ .vdisplay = 600,
+ .vsync_start = 600 + 12,
+ .vsync_end = 600 + 12 + 10,
+ .vtotal = 600 + 12 + 10 + 23,
+};
+
+static const struct panel_desc_dsi tsd_tst070wsbe_196c = {
+ .desc = {
+ .modes = &tsd_tst070wsbe_196c_mode,
+ .num_modes = 1,
+ .bpc = 8,
+ .size = {
+ .width = 190,
+ .height = 121,
+ },
+ .delay = {
+ .prepare = 20,
+ },
+ .connector_type = DRM_MODE_CONNECTOR_DSI,
+ },
+ .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM |
+ MIPI_DSI_MODE_VIDEO_BURST |
+ MIPI_DSI_MODE_VIDEO_SYNC_PULSE,
+ .format = MIPI_DSI_FMT_RGB888,
+ .lanes = 4,
+};
+
static const struct of_device_id dsi_of_match[] = {
{
.compatible = "auo,b080uan01",
@@ -6337,6 +6435,9 @@ static const struct of_device_id dsi_of_match[] = {
.compatible = "osddisplays,osd101t2045-53ts",
.data = &osd101t2045_53ts
}, {
+ .compatible = "team-source-display,tst070wsbe-196c",
+ .data = &tsd_tst070wsbe_196c
+ }, {
/* sentinel */
}
};
diff --git a/drivers/gpu/drm/panthor/panthor_device.c b/drivers/gpu/drm/panthor/panthor_device.c
index bc62a498a8a8..bd417d6ae8c0 100644
--- a/drivers/gpu/drm/panthor/panthor_device.c
+++ b/drivers/gpu/drm/panthor/panthor_device.c
@@ -19,40 +19,14 @@
#include "panthor_devfreq.h"
#include "panthor_device.h"
#include "panthor_fw.h"
+#include "panthor_fw_regs.h"
#include "panthor_gem.h"
#include "panthor_gpu.h"
#include "panthor_hw.h"
#include "panthor_mmu.h"
#include "panthor_pwr.h"
-#include "panthor_regs.h"
#include "panthor_sched.h"
-static int panthor_gpu_coherency_init(struct panthor_device *ptdev)
-{
- BUILD_BUG_ON(GPU_COHERENCY_NONE != DRM_PANTHOR_GPU_COHERENCY_NONE);
- BUILD_BUG_ON(GPU_COHERENCY_ACE_LITE != DRM_PANTHOR_GPU_COHERENCY_ACE_LITE);
- BUILD_BUG_ON(GPU_COHERENCY_ACE != DRM_PANTHOR_GPU_COHERENCY_ACE);
-
- /* Start with no coherency, and update it if the device is flagged coherent. */
- ptdev->gpu_info.selected_coherency = GPU_COHERENCY_NONE;
- ptdev->coherent = device_get_dma_attr(ptdev->base.dev) == DEV_DMA_COHERENT;
-
- if (!ptdev->coherent)
- return 0;
-
- /* Check if the ACE-Lite coherency protocol is actually supported by the GPU.
- * ACE protocol has never been supported for command stream frontend GPUs.
- */
- if ((gpu_read(ptdev, GPU_COHERENCY_FEATURES) &
- GPU_COHERENCY_PROT_BIT(ACE_LITE))) {
- ptdev->gpu_info.selected_coherency = GPU_COHERENCY_ACE_LITE;
- return 0;
- }
-
- drm_err(&ptdev->base, "Coherency not supported by the device");
- return -ENOTSUPP;
-}
-
static int panthor_clk_init(struct panthor_device *ptdev)
{
ptdev->clks.core = devm_clk_get(ptdev->base.dev, NULL);
diff --git a/drivers/gpu/drm/panthor/panthor_device.h b/drivers/gpu/drm/panthor/panthor_device.h
index 5cba272f9b4d..4e4607bca7cc 100644
--- a/drivers/gpu/drm/panthor/panthor_device.h
+++ b/drivers/gpu/drm/panthor/panthor_device.h
@@ -82,6 +82,9 @@ struct panthor_irq {
/** @ptdev: Panthor device */
struct panthor_device *ptdev;
+ /** @iomem: CPU mapping of IRQ base address */
+ void __iomem *iomem;
+
/** @irq: IRQ number. */
int irq;
@@ -488,6 +491,11 @@ panthor_exception_is_fault(u32 exception_code)
const char *panthor_exception_name(struct panthor_device *ptdev,
u32 exception_code);
+#define INT_RAWSTAT 0x0
+#define INT_CLEAR 0x4
+#define INT_MASK 0x8
+#define INT_STAT 0xc
+
/**
* PANTHOR_IRQ_HANDLER() - Define interrupt handlers and the interrupt
* registration function.
@@ -498,14 +506,13 @@ const char *panthor_exception_name(struct panthor_device *ptdev,
*
* void (*handler)(struct panthor_device *, u32 status);
*/
-#define PANTHOR_IRQ_HANDLER(__name, __reg_prefix, __handler) \
+#define PANTHOR_IRQ_HANDLER(__name, __handler) \
static irqreturn_t panthor_ ## __name ## _irq_raw_handler(int irq, void *data) \
{ \
struct panthor_irq *pirq = data; \
- struct panthor_device *ptdev = pirq->ptdev; \
enum panthor_irq_state old_state; \
\
- if (!gpu_read(ptdev, __reg_prefix ## _INT_STAT)) \
+ if (!gpu_read(pirq->iomem, INT_STAT)) \
return IRQ_NONE; \
\
guard(spinlock_irqsave)(&pirq->mask_lock); \
@@ -515,7 +522,7 @@ static irqreturn_t panthor_ ## __name ## _irq_raw_handler(int irq, void *data)
if (old_state != PANTHOR_IRQ_STATE_ACTIVE) \
return IRQ_NONE; \
\
- gpu_write(ptdev, __reg_prefix ## _INT_MASK, 0); \
+ gpu_write(pirq->iomem, INT_MASK, 0); \
return IRQ_WAKE_THREAD; \
} \
\
@@ -534,7 +541,7 @@ static irqreturn_t panthor_ ## __name ## _irq_threaded_handler(int irq, void *da
* right before the HW event kicks in. TLDR; it's all expected races we're \
* covered for. \
*/ \
- u32 status = gpu_read(ptdev, __reg_prefix ## _INT_RAWSTAT) & pirq->mask; \
+ u32 status = gpu_read(pirq->iomem, INT_RAWSTAT) & pirq->mask; \
\
if (!status) \
break; \
@@ -550,7 +557,7 @@ static irqreturn_t panthor_ ## __name ## _irq_threaded_handler(int irq, void *da
PANTHOR_IRQ_STATE_PROCESSING, \
PANTHOR_IRQ_STATE_ACTIVE); \
if (old_state == PANTHOR_IRQ_STATE_PROCESSING) \
- gpu_write(ptdev, __reg_prefix ## _INT_MASK, pirq->mask); \
+ gpu_write(pirq->iomem, INT_MASK, pirq->mask); \
} \
\
return ret; \
@@ -560,7 +567,7 @@ static inline void panthor_ ## __name ## _irq_suspend(struct panthor_irq *pirq)
{ \
scoped_guard(spinlock_irqsave, &pirq->mask_lock) { \
atomic_set(&pirq->state, PANTHOR_IRQ_STATE_SUSPENDING); \
- gpu_write(pirq->ptdev, __reg_prefix ## _INT_MASK, 0); \
+ gpu_write(pirq->iomem, INT_MASK, 0); \
} \
synchronize_irq(pirq->irq); \
atomic_set(&pirq->state, PANTHOR_IRQ_STATE_SUSPENDED); \
@@ -571,17 +578,18 @@ static inline void panthor_ ## __name ## _irq_resume(struct panthor_irq *pirq)
guard(spinlock_irqsave)(&pirq->mask_lock); \
\
atomic_set(&pirq->state, PANTHOR_IRQ_STATE_ACTIVE); \
- gpu_write(pirq->ptdev, __reg_prefix ## _INT_CLEAR, pirq->mask); \
- gpu_write(pirq->ptdev, __reg_prefix ## _INT_MASK, pirq->mask); \
+ gpu_write(pirq->iomem, INT_CLEAR, pirq->mask); \
+ gpu_write(pirq->iomem, INT_MASK, pirq->mask); \
} \
\
static int panthor_request_ ## __name ## _irq(struct panthor_device *ptdev, \
struct panthor_irq *pirq, \
- int irq, u32 mask) \
+ int irq, u32 mask, void __iomem *iomem) \
{ \
pirq->ptdev = ptdev; \
pirq->irq = irq; \
pirq->mask = mask; \
+ pirq->iomem = iomem; \
spin_lock_init(&pirq->mask_lock); \
panthor_ ## __name ## _irq_resume(pirq); \
\
@@ -603,7 +611,7 @@ static inline void panthor_ ## __name ## _irq_enable_events(struct panthor_irq *
* If the IRQ is suspended/suspending, the mask is restored at resume time. \
*/ \
if (atomic_read(&pirq->state) == PANTHOR_IRQ_STATE_ACTIVE) \
- gpu_write(pirq->ptdev, __reg_prefix ## _INT_MASK, pirq->mask); \
+ gpu_write(pirq->iomem, INT_MASK, pirq->mask); \
} \
\
static inline void panthor_ ## __name ## _irq_disable_events(struct panthor_irq *pirq, u32 mask)\
@@ -617,80 +625,80 @@ static inline void panthor_ ## __name ## _irq_disable_events(struct panthor_irq
* If the IRQ is suspended/suspending, the mask is restored at resume time. \
*/ \
if (atomic_read(&pirq->state) == PANTHOR_IRQ_STATE_ACTIVE) \
- gpu_write(pirq->ptdev, __reg_prefix ## _INT_MASK, pirq->mask); \
+ gpu_write(pirq->iomem, INT_MASK, pirq->mask); \
}
extern struct workqueue_struct *panthor_cleanup_wq;
-static inline void gpu_write(struct panthor_device *ptdev, u32 reg, u32 data)
+static inline void gpu_write(void __iomem *iomem, u32 reg, u32 data)
{
- writel(data, ptdev->iomem + reg);
+ writel(data, iomem + reg);
}
-static inline u32 gpu_read(struct panthor_device *ptdev, u32 reg)
+static inline u32 gpu_read(void __iomem *iomem, u32 reg)
{
- return readl(ptdev->iomem + reg);
+ return readl(iomem + reg);
}
-static inline u32 gpu_read_relaxed(struct panthor_device *ptdev, u32 reg)
+static inline u32 gpu_read_relaxed(void __iomem *iomem, u32 reg)
{
- return readl_relaxed(ptdev->iomem + reg);
+ return readl_relaxed(iomem + reg);
}
-static inline void gpu_write64(struct panthor_device *ptdev, u32 reg, u64 data)
+static inline void gpu_write64(void __iomem *iomem, u32 reg, u64 data)
{
- gpu_write(ptdev, reg, lower_32_bits(data));
- gpu_write(ptdev, reg + 4, upper_32_bits(data));
+ gpu_write(iomem, reg, lower_32_bits(data));
+ gpu_write(iomem, reg + 4, upper_32_bits(data));
}
-static inline u64 gpu_read64(struct panthor_device *ptdev, u32 reg)
+static inline u64 gpu_read64(void __iomem *iomem, u32 reg)
{
- return (gpu_read(ptdev, reg) | ((u64)gpu_read(ptdev, reg + 4) << 32));
+ return (gpu_read(iomem, reg) | ((u64)gpu_read(iomem, reg + 4) << 32));
}
-static inline u64 gpu_read64_relaxed(struct panthor_device *ptdev, u32 reg)
+static inline u64 gpu_read64_relaxed(void __iomem *iomem, u32 reg)
{
- return (gpu_read_relaxed(ptdev, reg) |
- ((u64)gpu_read_relaxed(ptdev, reg + 4) << 32));
+ return (gpu_read_relaxed(iomem, reg) |
+ ((u64)gpu_read_relaxed(iomem, reg + 4) << 32));
}
-static inline u64 gpu_read64_counter(struct panthor_device *ptdev, u32 reg)
+static inline u64 gpu_read64_counter(void __iomem *iomem, u32 reg)
{
u32 lo, hi1, hi2;
do {
- hi1 = gpu_read(ptdev, reg + 4);
- lo = gpu_read(ptdev, reg);
- hi2 = gpu_read(ptdev, reg + 4);
+ hi1 = gpu_read(iomem, reg + 4);
+ lo = gpu_read(iomem, reg);
+ hi2 = gpu_read(iomem, reg + 4);
} while (hi1 != hi2);
return lo | ((u64)hi2 << 32);
}
-#define gpu_read_poll_timeout(dev, reg, val, cond, delay_us, timeout_us) \
+#define gpu_read_poll_timeout(iomem, reg, val, cond, delay_us, timeout_us) \
read_poll_timeout(gpu_read, val, cond, delay_us, timeout_us, false, \
- dev, reg)
+ iomem, reg)
-#define gpu_read_poll_timeout_atomic(dev, reg, val, cond, delay_us, \
+#define gpu_read_poll_timeout_atomic(iomem, reg, val, cond, delay_us, \
timeout_us) \
read_poll_timeout_atomic(gpu_read, val, cond, delay_us, timeout_us, \
- false, dev, reg)
+ false, iomem, reg)
-#define gpu_read64_poll_timeout(dev, reg, val, cond, delay_us, timeout_us) \
+#define gpu_read64_poll_timeout(iomem, reg, val, cond, delay_us, timeout_us) \
read_poll_timeout(gpu_read64, val, cond, delay_us, timeout_us, false, \
- dev, reg)
+ iomem, reg)
-#define gpu_read64_poll_timeout_atomic(dev, reg, val, cond, delay_us, \
+#define gpu_read64_poll_timeout_atomic(iomem, reg, val, cond, delay_us, \
timeout_us) \
read_poll_timeout_atomic(gpu_read64, val, cond, delay_us, timeout_us, \
- false, dev, reg)
+ false, iomem, reg)
-#define gpu_read_relaxed_poll_timeout_atomic(dev, reg, val, cond, delay_us, \
+#define gpu_read_relaxed_poll_timeout_atomic(iomem, reg, val, cond, delay_us, \
timeout_us) \
read_poll_timeout_atomic(gpu_read_relaxed, val, cond, delay_us, \
- timeout_us, false, dev, reg)
+ timeout_us, false, iomem, reg)
-#define gpu_read64_relaxed_poll_timeout(dev, reg, val, cond, delay_us, \
+#define gpu_read64_relaxed_poll_timeout(iomem, reg, val, cond, delay_us, \
timeout_us) \
read_poll_timeout(gpu_read64_relaxed, val, cond, delay_us, timeout_us, \
- false, dev, reg)
+ false, iomem, reg)
#endif
diff --git a/drivers/gpu/drm/panthor/panthor_drv.c b/drivers/gpu/drm/panthor/panthor_drv.c
index 73fc983dc9b4..e8dc4096c1d2 100644
--- a/drivers/gpu/drm/panthor/panthor_drv.c
+++ b/drivers/gpu/drm/panthor/panthor_drv.c
@@ -31,12 +31,12 @@
#include "panthor_devfreq.h"
#include "panthor_device.h"
+#include "panthor_drv.h"
#include "panthor_fw.h"
#include "panthor_gem.h"
#include "panthor_gpu.h"
#include "panthor_heap.h"
#include "panthor_mmu.h"
-#include "panthor_regs.h"
#include "panthor_sched.h"
/**
@@ -839,7 +839,7 @@ static int panthor_query_timestamp_info(struct panthor_device *ptdev,
}
if (flags & DRM_PANTHOR_TIMESTAMP_GPU_OFFSET)
- arg->timestamp_offset = gpu_read64(ptdev, GPU_TIMESTAMP_OFFSET);
+ arg->timestamp_offset = panthor_gpu_get_timestamp_offset(ptdev);
else
arg->timestamp_offset = 0;
@@ -854,7 +854,7 @@ static int panthor_query_timestamp_info(struct panthor_device *ptdev,
query_start_time = 0;
if (flags & DRM_PANTHOR_TIMESTAMP_GPU)
- arg->current_timestamp = gpu_read64_counter(ptdev, GPU_TIMESTAMP);
+ arg->current_timestamp = panthor_gpu_get_timestamp(ptdev);
else
arg->current_timestamp = 0;
@@ -870,7 +870,7 @@ static int panthor_query_timestamp_info(struct panthor_device *ptdev,
}
if (flags & DRM_PANTHOR_TIMESTAMP_GPU_CYCLE_COUNT)
- arg->cycle_count = gpu_read64_counter(ptdev, GPU_CYCLE_COUNT);
+ arg->cycle_count = panthor_gpu_get_cycle_count(ptdev);
else
arg->cycle_count = 0;
diff --git a/drivers/gpu/drm/panthor/panthor_drv.h b/drivers/gpu/drm/panthor/panthor_drv.h
index 1bc7ddbad23e..b81f21ed5398 100644
--- a/drivers/gpu/drm/panthor/panthor_drv.h
+++ b/drivers/gpu/drm/panthor/panthor_drv.h
@@ -4,6 +4,8 @@
#ifndef __PANTHOR_DRV_H__
#define __PANTHOR_DRV_H__
+#include <linux/types.h>
+
extern bool panthor_transparent_hugepage;
#endif
diff --git a/drivers/gpu/drm/panthor/panthor_fw.c b/drivers/gpu/drm/panthor/panthor_fw.c
index be0da5b1f3ab..986151681b24 100644
--- a/drivers/gpu/drm/panthor/panthor_fw.c
+++ b/drivers/gpu/drm/panthor/panthor_fw.c
@@ -20,11 +20,11 @@
#include "panthor_device.h"
#include "panthor_fw.h"
+#include "panthor_fw_regs.h"
#include "panthor_gem.h"
#include "panthor_gpu.h"
#include "panthor_hw.h"
#include "panthor_mmu.h"
-#include "panthor_regs.h"
#include "panthor_sched.h"
#include "panthor_trace.h"
@@ -234,6 +234,9 @@ struct panthor_fw_iface {
* struct panthor_fw - Firmware management
*/
struct panthor_fw {
+ /** @iomem: CPU mapping of MCU_CONTROL iomem region */
+ void __iomem *iomem;
+
/** @vm: MCU VM. */
struct panthor_vm *vm;
@@ -1054,7 +1057,7 @@ static void panthor_fw_init_global_iface(struct panthor_device *ptdev)
GLB_CFG_POWEROFF_TIMER |
GLB_CFG_PROGRESS_TIMER);
- gpu_write(ptdev, CSF_DOORBELL(CSF_GLB_DOORBELL_ID), 1);
+ panthor_fw_ring_doorbell(ptdev, CSF_GLB_DOORBELL_ID);
/* Kick the watchdog. */
mod_delayed_work(ptdev->reset.wq, &ptdev->fw->watchdog.ping_work,
@@ -1069,7 +1072,7 @@ static void panthor_job_irq_handler(struct panthor_device *ptdev, u32 status)
if (tracepoint_enabled(gpu_job_irq))
start = ktime_get_ns();
- gpu_write(ptdev, JOB_INT_CLEAR, status);
+ gpu_write(ptdev->fw->irq.iomem, INT_CLEAR, status);
if (!ptdev->fw->booted && (status & JOB_INT_GLOBAL_IF))
ptdev->fw->booted = true;
@@ -1088,22 +1091,23 @@ static void panthor_job_irq_handler(struct panthor_device *ptdev, u32 status)
trace_gpu_job_irq(ptdev->base.dev, status, duration);
}
}
-PANTHOR_IRQ_HANDLER(job, JOB, panthor_job_irq_handler);
+PANTHOR_IRQ_HANDLER(job, panthor_job_irq_handler);
static int panthor_fw_start(struct panthor_device *ptdev)
{
+ struct panthor_fw *fw = ptdev->fw;
bool timedout = false;
ptdev->fw->booted = false;
panthor_job_irq_enable_events(&ptdev->fw->irq, ~0);
panthor_job_irq_resume(&ptdev->fw->irq);
- gpu_write(ptdev, MCU_CONTROL, MCU_CONTROL_AUTO);
+ gpu_write(fw->iomem, MCU_CONTROL, MCU_CONTROL_AUTO);
if (!wait_event_timeout(ptdev->fw->req_waitqueue,
ptdev->fw->booted,
msecs_to_jiffies(1000))) {
if (!ptdev->fw->booted &&
- !(gpu_read(ptdev, JOB_INT_STAT) & JOB_INT_GLOBAL_IF))
+ !(gpu_read(fw->irq.iomem, INT_STAT) & JOB_INT_GLOBAL_IF))
timedout = true;
}
@@ -1114,7 +1118,7 @@ static int panthor_fw_start(struct panthor_device *ptdev)
[MCU_STATUS_HALT] = "halt",
[MCU_STATUS_FATAL] = "fatal",
};
- u32 status = gpu_read(ptdev, MCU_STATUS);
+ u32 status = gpu_read(fw->iomem, MCU_STATUS);
drm_err(&ptdev->base, "Failed to boot MCU (status=%s)",
status < ARRAY_SIZE(status_str) ? status_str[status] : "unknown");
@@ -1126,10 +1130,11 @@ static int panthor_fw_start(struct panthor_device *ptdev)
static void panthor_fw_stop(struct panthor_device *ptdev)
{
+ struct panthor_fw *fw = ptdev->fw;
u32 status;
- gpu_write(ptdev, MCU_CONTROL, MCU_CONTROL_DISABLE);
- if (gpu_read_poll_timeout(ptdev, MCU_STATUS, status,
+ gpu_write(fw->iomem, MCU_CONTROL, MCU_CONTROL_DISABLE);
+ if (gpu_read_poll_timeout(fw->iomem, MCU_STATUS, status,
status == MCU_STATUS_DISABLED, 10, 100000))
drm_err(&ptdev->base, "Failed to stop MCU");
}
@@ -1139,7 +1144,7 @@ static bool panthor_fw_mcu_halted(struct panthor_device *ptdev)
struct panthor_fw_global_iface *glb_iface = panthor_fw_get_glb_iface(ptdev);
bool halted;
- halted = gpu_read(ptdev, MCU_STATUS) == MCU_STATUS_HALT;
+ halted = gpu_read(ptdev->fw->iomem, MCU_STATUS) == MCU_STATUS_HALT;
if (panthor_fw_has_glb_state(ptdev))
halted &= (GLB_STATE_GET(glb_iface->output->ack) == GLB_STATE_HALT);
@@ -1156,7 +1161,7 @@ static void panthor_fw_halt_mcu(struct panthor_device *ptdev)
else
panthor_fw_update_reqs(glb_iface, req, GLB_HALT, GLB_HALT);
- gpu_write(ptdev, CSF_DOORBELL(CSF_GLB_DOORBELL_ID), 1);
+ panthor_fw_ring_doorbell(ptdev, CSF_GLB_DOORBELL_ID);
}
static bool panthor_fw_wait_mcu_halted(struct panthor_device *ptdev)
@@ -1400,6 +1405,11 @@ int panthor_fw_csg_wait_acks(struct panthor_device *ptdev, u32 csg_slot,
return ret;
}
+void panthor_fw_ring_doorbell(struct panthor_device *ptdev, u32 doorbell_id)
+{
+ gpu_write(ptdev->iomem, CSF_DOORBELL(doorbell_id), 1);
+}
+
/**
* panthor_fw_ring_csg_doorbells() - Ring command stream group doorbells.
* @ptdev: Device.
@@ -1414,7 +1424,7 @@ void panthor_fw_ring_csg_doorbells(struct panthor_device *ptdev, u32 csg_mask)
struct panthor_fw_global_iface *glb_iface = panthor_fw_get_glb_iface(ptdev);
panthor_fw_toggle_reqs(glb_iface, doorbell_req, doorbell_ack, csg_mask);
- gpu_write(ptdev, CSF_DOORBELL(CSF_GLB_DOORBELL_ID), 1);
+ panthor_fw_ring_doorbell(ptdev, CSF_GLB_DOORBELL_ID);
}
static void panthor_fw_ping_work(struct work_struct *work)
@@ -1429,7 +1439,7 @@ static void panthor_fw_ping_work(struct work_struct *work)
return;
panthor_fw_toggle_reqs(glb_iface, req, ack, GLB_PING);
- gpu_write(ptdev, CSF_DOORBELL(CSF_GLB_DOORBELL_ID), 1);
+ panthor_fw_ring_doorbell(ptdev, CSF_GLB_DOORBELL_ID);
ret = panthor_fw_glb_wait_acks(ptdev, GLB_PING, &acked, 100);
if (ret) {
@@ -1456,6 +1466,7 @@ int panthor_fw_init(struct panthor_device *ptdev)
if (!fw)
return -ENOMEM;
+ fw->iomem = ptdev->iomem + MCU_CONTROL_BASE;
ptdev->fw = fw;
init_waitqueue_head(&fw->req_waitqueue);
INIT_LIST_HEAD(&fw->sections);
@@ -1465,7 +1476,8 @@ int panthor_fw_init(struct panthor_device *ptdev)
if (irq <= 0)
return -ENODEV;
- ret = panthor_request_job_irq(ptdev, &fw->irq, irq, 0);
+ ret = panthor_request_job_irq(ptdev, &fw->irq, irq, 0,
+ ptdev->iomem + JOB_INT_BASE);
if (ret) {
drm_err(&ptdev->base, "failed to request job irq");
return ret;
diff --git a/drivers/gpu/drm/panthor/panthor_fw.h b/drivers/gpu/drm/panthor/panthor_fw.h
index fbdc21469ba3..a99a9b6f4825 100644
--- a/drivers/gpu/drm/panthor/panthor_fw.h
+++ b/drivers/gpu/drm/panthor/panthor_fw.h
@@ -500,6 +500,7 @@ int panthor_fw_csg_wait_acks(struct panthor_device *ptdev, u32 csg_id, u32 req_m
int panthor_fw_glb_wait_acks(struct panthor_device *ptdev, u32 req_mask, u32 *acked,
u32 timeout_ms);
+void panthor_fw_ring_doorbell(struct panthor_device *ptdev, u32 doorbell_id);
void panthor_fw_ring_csg_doorbells(struct panthor_device *ptdev, u32 csg_slot);
struct panthor_kernel_bo *
diff --git a/drivers/gpu/drm/panthor/panthor_fw_regs.h b/drivers/gpu/drm/panthor/panthor_fw_regs.h
new file mode 100644
index 000000000000..b2e59cfc22b0
--- /dev/null
+++ b/drivers/gpu/drm/panthor/panthor_fw_regs.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 or MIT */
+/* Copyright 2026 ARM Limited. All rights reserved. */
+
+#ifndef __PANTHOR_FW_REGS_H__
+#define __PANTHOR_FW_REGS_H__
+
+#define MCU_CONTROL_BASE 0x700
+
+#define MCU_CONTROL 0x0
+#define MCU_CONTROL_ENABLE 1
+#define MCU_CONTROL_AUTO 2
+#define MCU_CONTROL_DISABLE 0
+
+#define MCU_STATUS 0x4
+#define MCU_STATUS_DISABLED 0
+#define MCU_STATUS_ENABLED 1
+#define MCU_STATUS_HALT 2
+#define MCU_STATUS_FATAL 3
+
+#define JOB_INT_BASE 0x1000
+#define JOB_INT_GLOBAL_IF BIT(31)
+#define JOB_INT_CSG_IF(x) BIT(x)
+
+#define CSF_GPU_LATEST_FLUSH_ID 0x10000
+
+#define CSF_DOORBELL(i) (0x80000 + ((i) * 0x10000))
+#define CSF_GLB_DOORBELL_ID 0
+
+#endif /* __PANTHOR_FW_REGS_H__ */
diff --git a/drivers/gpu/drm/panthor/panthor_gpu.c b/drivers/gpu/drm/panthor/panthor_gpu.c
index 2ab444ee8c71..e52c5675981f 100644
--- a/drivers/gpu/drm/panthor/panthor_gpu.c
+++ b/drivers/gpu/drm/panthor/panthor_gpu.c
@@ -19,8 +19,8 @@
#include "panthor_device.h"
#include "panthor_gpu.h"
+#include "panthor_gpu_regs.h"
#include "panthor_hw.h"
-#include "panthor_regs.h"
#define CREATE_TRACE_POINTS
#include "panthor_trace.h"
@@ -29,6 +29,9 @@
* struct panthor_gpu - GPU block management data.
*/
struct panthor_gpu {
+ /** @iomem: CPU mapping of GPU_CONTROL iomem region */
+ void __iomem *iomem;
+
/** @irq: GPU irq. */
struct panthor_irq irq;
@@ -56,12 +59,13 @@ struct panthor_gpu {
static void panthor_gpu_coherency_set(struct panthor_device *ptdev)
{
- gpu_write(ptdev, GPU_COHERENCY_PROTOCOL,
+ gpu_write(ptdev->gpu->iomem, GPU_COHERENCY_PROTOCOL,
ptdev->gpu_info.selected_coherency);
}
static void panthor_gpu_l2_config_set(struct panthor_device *ptdev)
{
+ struct panthor_gpu *gpu = ptdev->gpu;
const struct panthor_soc_data *data = ptdev->soc_data;
u32 l2_config;
u32 i;
@@ -75,26 +79,28 @@ static void panthor_gpu_l2_config_set(struct panthor_device *ptdev)
}
for (i = 0; i < ARRAY_SIZE(data->asn_hash); i++)
- gpu_write(ptdev, GPU_ASN_HASH(i), data->asn_hash[i]);
+ gpu_write(gpu->iomem, GPU_ASN_HASH(i), data->asn_hash[i]);
- l2_config = gpu_read(ptdev, GPU_L2_CONFIG);
+ l2_config = gpu_read(gpu->iomem, GPU_L2_CONFIG);
l2_config |= GPU_L2_CONFIG_ASN_HASH_ENABLE;
- gpu_write(ptdev, GPU_L2_CONFIG, l2_config);
+ gpu_write(gpu->iomem, GPU_L2_CONFIG, l2_config);
}
static void panthor_gpu_irq_handler(struct panthor_device *ptdev, u32 status)
{
- gpu_write(ptdev, GPU_INT_CLEAR, status);
+ struct panthor_gpu *gpu = ptdev->gpu;
+
+ gpu_write(gpu->irq.iomem, INT_CLEAR, status);
if (tracepoint_enabled(gpu_power_status) && (status & GPU_POWER_INTERRUPTS_MASK))
trace_gpu_power_status(ptdev->base.dev,
- gpu_read64(ptdev, SHADER_READY),
- gpu_read64(ptdev, TILER_READY),
- gpu_read64(ptdev, L2_READY));
+ gpu_read64(gpu->iomem, SHADER_READY),
+ gpu_read64(gpu->iomem, TILER_READY),
+ gpu_read64(gpu->iomem, L2_READY));
if (status & GPU_IRQ_FAULT) {
- u32 fault_status = gpu_read(ptdev, GPU_FAULT_STATUS);
- u64 address = gpu_read64(ptdev, GPU_FAULT_ADDR);
+ u32 fault_status = gpu_read(gpu->iomem, GPU_FAULT_STATUS);
+ u64 address = gpu_read64(gpu->iomem, GPU_FAULT_ADDR);
drm_warn(&ptdev->base, "GPU Fault 0x%08x (%s) at 0x%016llx\n",
fault_status, panthor_exception_name(ptdev, fault_status & 0xFF),
@@ -110,7 +116,7 @@ static void panthor_gpu_irq_handler(struct panthor_device *ptdev, u32 status)
}
spin_unlock(&ptdev->gpu->reqs_lock);
}
-PANTHOR_IRQ_HANDLER(gpu, GPU, panthor_gpu_irq_handler);
+PANTHOR_IRQ_HANDLER(gpu, panthor_gpu_irq_handler);
/**
* panthor_gpu_unplug() - Called when the GPU is unplugged.
@@ -147,6 +153,7 @@ int panthor_gpu_init(struct panthor_device *ptdev)
if (!gpu)
return -ENOMEM;
+ gpu->iomem = ptdev->iomem + GPU_CONTROL_BASE;
spin_lock_init(&gpu->reqs_lock);
init_waitqueue_head(&gpu->reqs_acked);
mutex_init(&gpu->cache_flush_lock);
@@ -162,7 +169,9 @@ int panthor_gpu_init(struct panthor_device *ptdev)
if (irq < 0)
return irq;
- ret = panthor_request_gpu_irq(ptdev, &ptdev->gpu->irq, irq, GPU_INTERRUPTS_MASK);
+ ret = panthor_request_gpu_irq(ptdev, &ptdev->gpu->irq, irq,
+ GPU_INTERRUPTS_MASK,
+ ptdev->iomem + GPU_INT_BASE);
if (ret)
return ret;
@@ -201,10 +210,11 @@ int panthor_gpu_block_power_off(struct panthor_device *ptdev,
u32 pwroff_reg, u32 pwrtrans_reg,
u64 mask, u32 timeout_us)
{
+ struct panthor_gpu *gpu = ptdev->gpu;
u32 val;
int ret;
- ret = gpu_read64_relaxed_poll_timeout(ptdev, pwrtrans_reg, val,
+ ret = gpu_read64_relaxed_poll_timeout(gpu->iomem, pwrtrans_reg, val,
!(mask & val), 100, timeout_us);
if (ret) {
drm_err(&ptdev->base,
@@ -213,9 +223,9 @@ int panthor_gpu_block_power_off(struct panthor_device *ptdev,
return ret;
}
- gpu_write64(ptdev, pwroff_reg, mask);
+ gpu_write64(gpu->iomem, pwroff_reg, mask);
- ret = gpu_read64_relaxed_poll_timeout(ptdev, pwrtrans_reg, val,
+ ret = gpu_read64_relaxed_poll_timeout(gpu->iomem, pwrtrans_reg, val,
!(mask & val), 100, timeout_us);
if (ret) {
drm_err(&ptdev->base,
@@ -244,10 +254,11 @@ int panthor_gpu_block_power_on(struct panthor_device *ptdev,
u32 pwron_reg, u32 pwrtrans_reg,
u32 rdy_reg, u64 mask, u32 timeout_us)
{
+ struct panthor_gpu *gpu = ptdev->gpu;
u32 val;
int ret;
- ret = gpu_read64_relaxed_poll_timeout(ptdev, pwrtrans_reg, val,
+ ret = gpu_read64_relaxed_poll_timeout(gpu->iomem, pwrtrans_reg, val,
!(mask & val), 100, timeout_us);
if (ret) {
drm_err(&ptdev->base,
@@ -256,9 +267,9 @@ int panthor_gpu_block_power_on(struct panthor_device *ptdev,
return ret;
}
- gpu_write64(ptdev, pwron_reg, mask);
+ gpu_write64(gpu->iomem, pwron_reg, mask);
- ret = gpu_read64_relaxed_poll_timeout(ptdev, rdy_reg, val,
+ ret = gpu_read64_relaxed_poll_timeout(gpu->iomem, rdy_reg, val,
(mask & val) == val,
100, timeout_us);
if (ret) {
@@ -317,6 +328,7 @@ int panthor_gpu_l2_power_on(struct panthor_device *ptdev)
int panthor_gpu_flush_caches(struct panthor_device *ptdev,
u32 l2, u32 lsc, u32 other)
{
+ struct panthor_gpu *gpu = ptdev->gpu;
unsigned long flags;
int ret = 0;
@@ -326,7 +338,7 @@ int panthor_gpu_flush_caches(struct panthor_device *ptdev,
spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags);
if (!(ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED)) {
ptdev->gpu->pending_reqs |= GPU_IRQ_CLEAN_CACHES_COMPLETED;
- gpu_write(ptdev, GPU_CMD, GPU_FLUSH_CACHES(l2, lsc, other));
+ gpu_write(gpu->iomem, GPU_CMD, GPU_FLUSH_CACHES(l2, lsc, other));
} else {
ret = -EIO;
}
@@ -340,7 +352,7 @@ int panthor_gpu_flush_caches(struct panthor_device *ptdev,
msecs_to_jiffies(100))) {
spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags);
if ((ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED) != 0 &&
- !(gpu_read(ptdev, GPU_INT_RAWSTAT) & GPU_IRQ_CLEAN_CACHES_COMPLETED))
+ !(gpu_read(gpu->irq.iomem, INT_RAWSTAT) & GPU_IRQ_CLEAN_CACHES_COMPLETED))
ret = -ETIMEDOUT;
else
ptdev->gpu->pending_reqs &= ~GPU_IRQ_CLEAN_CACHES_COMPLETED;
@@ -363,6 +375,7 @@ int panthor_gpu_flush_caches(struct panthor_device *ptdev,
*/
int panthor_gpu_soft_reset(struct panthor_device *ptdev)
{
+ struct panthor_gpu *gpu = ptdev->gpu;
bool timedout = false;
unsigned long flags;
@@ -370,8 +383,8 @@ int panthor_gpu_soft_reset(struct panthor_device *ptdev)
if (!drm_WARN_ON(&ptdev->base,
ptdev->gpu->pending_reqs & GPU_IRQ_RESET_COMPLETED)) {
ptdev->gpu->pending_reqs |= GPU_IRQ_RESET_COMPLETED;
- gpu_write(ptdev, GPU_INT_CLEAR, GPU_IRQ_RESET_COMPLETED);
- gpu_write(ptdev, GPU_CMD, GPU_SOFT_RESET);
+ gpu_write(gpu->irq.iomem, INT_CLEAR, GPU_IRQ_RESET_COMPLETED);
+ gpu_write(gpu->iomem, GPU_CMD, GPU_SOFT_RESET);
}
spin_unlock_irqrestore(&ptdev->gpu->reqs_lock, flags);
@@ -380,7 +393,7 @@ int panthor_gpu_soft_reset(struct panthor_device *ptdev)
msecs_to_jiffies(100))) {
spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags);
if ((ptdev->gpu->pending_reqs & GPU_IRQ_RESET_COMPLETED) != 0 &&
- !(gpu_read(ptdev, GPU_INT_RAWSTAT) & GPU_IRQ_RESET_COMPLETED))
+ !(gpu_read(gpu->irq.iomem, INT_RAWSTAT) & GPU_IRQ_RESET_COMPLETED))
timedout = true;
else
ptdev->gpu->pending_reqs &= ~GPU_IRQ_RESET_COMPLETED;
@@ -427,3 +440,43 @@ void panthor_gpu_resume(struct panthor_device *ptdev)
panthor_hw_l2_power_on(ptdev);
}
+u64 panthor_gpu_get_timestamp(struct panthor_device *ptdev)
+{
+ return gpu_read64_counter(ptdev->gpu->iomem, GPU_TIMESTAMP);
+}
+
+u64 panthor_gpu_get_timestamp_offset(struct panthor_device *ptdev)
+{
+ return gpu_read64(ptdev->gpu->iomem, GPU_TIMESTAMP_OFFSET);
+}
+
+u64 panthor_gpu_get_cycle_count(struct panthor_device *ptdev)
+{
+ return gpu_read64_counter(ptdev->gpu->iomem, GPU_CYCLE_COUNT);
+}
+
+int panthor_gpu_coherency_init(struct panthor_device *ptdev)
+{
+ BUILD_BUG_ON(GPU_COHERENCY_NONE != DRM_PANTHOR_GPU_COHERENCY_NONE);
+ BUILD_BUG_ON(GPU_COHERENCY_ACE_LITE != DRM_PANTHOR_GPU_COHERENCY_ACE_LITE);
+ BUILD_BUG_ON(GPU_COHERENCY_ACE != DRM_PANTHOR_GPU_COHERENCY_ACE);
+
+ /* Start with no coherency, and update it if the device is flagged coherent. */
+ ptdev->gpu_info.selected_coherency = GPU_COHERENCY_NONE;
+ ptdev->coherent = device_get_dma_attr(ptdev->base.dev) == DEV_DMA_COHERENT;
+
+ if (!ptdev->coherent)
+ return 0;
+
+ /* Check if the ACE-Lite coherency protocol is actually supported by the GPU.
+ * ACE protocol has never been supported for command stream frontend GPUs.
+ */
+ if ((gpu_read(ptdev->gpu->iomem, GPU_COHERENCY_FEATURES) &
+ GPU_COHERENCY_PROT_BIT(ACE_LITE))) {
+ ptdev->gpu_info.selected_coherency = GPU_COHERENCY_ACE_LITE;
+ return 0;
+ }
+
+ drm_err(&ptdev->base, "Coherency not supported by the device");
+ return -ENOTSUPP;
+}
diff --git a/drivers/gpu/drm/panthor/panthor_gpu.h b/drivers/gpu/drm/panthor/panthor_gpu.h
index 12c263a39928..f615feb05609 100644
--- a/drivers/gpu/drm/panthor/panthor_gpu.h
+++ b/drivers/gpu/drm/panthor/panthor_gpu.h
@@ -54,4 +54,10 @@ int panthor_gpu_soft_reset(struct panthor_device *ptdev);
void panthor_gpu_power_changed_off(struct panthor_device *ptdev);
int panthor_gpu_power_changed_on(struct panthor_device *ptdev);
+u64 panthor_gpu_get_timestamp(struct panthor_device *ptdev);
+u64 panthor_gpu_get_timestamp_offset(struct panthor_device *ptdev);
+u64 panthor_gpu_get_cycle_count(struct panthor_device *ptdev);
+
+int panthor_gpu_coherency_init(struct panthor_device *ptdev);
+
#endif
diff --git a/drivers/gpu/drm/panthor/panthor_gpu_regs.h b/drivers/gpu/drm/panthor/panthor_gpu_regs.h
new file mode 100644
index 000000000000..4c5b953796e4
--- /dev/null
+++ b/drivers/gpu/drm/panthor/panthor_gpu_regs.h
@@ -0,0 +1,119 @@
+/* SPDX-License-Identifier: GPL-2.0 or MIT */
+/* Copyright 2026 ARM Limited. All rights reserved. */
+
+#ifndef __PANTHOR_GPU_REGS_H__
+#define __PANTHOR_GPU_REGS_H__
+
+#define GPU_CONTROL_BASE 0x0
+
+#define GPU_ID 0x0
+#define GPU_ARCH_MAJOR(x) ((x) >> 28)
+#define GPU_ARCH_MINOR(x) (((x) & GENMASK(27, 24)) >> 24)
+#define GPU_ARCH_REV(x) (((x) & GENMASK(23, 20)) >> 20)
+#define GPU_PROD_MAJOR(x) (((x) & GENMASK(19, 16)) >> 16)
+#define GPU_VER_MAJOR(x) (((x) & GENMASK(15, 12)) >> 12)
+#define GPU_VER_MINOR(x) (((x) & GENMASK(11, 4)) >> 4)
+#define GPU_VER_STATUS(x) ((x) & GENMASK(3, 0))
+
+#define GPU_L2_FEATURES 0x4
+#define GPU_L2_FEATURES_LINE_SIZE(x) (1 << ((x) & GENMASK(7, 0)))
+
+#define GPU_CORE_FEATURES 0x8
+
+#define GPU_TILER_FEATURES 0xC
+#define GPU_MEM_FEATURES 0x10
+#define GROUPS_L2_COHERENT BIT(0)
+
+#define GPU_MMU_FEATURES 0x14
+#define GPU_MMU_FEATURES_VA_BITS(x) ((x) & GENMASK(7, 0))
+#define GPU_MMU_FEATURES_PA_BITS(x) (((x) >> 8) & GENMASK(7, 0))
+#define GPU_AS_PRESENT 0x18
+#define GPU_CSF_ID 0x1C
+
+#define GPU_INT_BASE 0x20
+#define GPU_IRQ_FAULT BIT(0)
+#define GPU_IRQ_PROTM_FAULT BIT(1)
+#define GPU_IRQ_RESET_COMPLETED BIT(8)
+#define GPU_IRQ_POWER_CHANGED BIT(9)
+#define GPU_IRQ_POWER_CHANGED_ALL BIT(10)
+#define GPU_IRQ_CLEAN_CACHES_COMPLETED BIT(17)
+#define GPU_IRQ_DOORBELL_MIRROR BIT(18)
+#define GPU_IRQ_MCU_STATUS_CHANGED BIT(19)
+#define GPU_CMD 0x30
+#define GPU_CMD_DEF(type, payload) ((type) | ((payload) << 8))
+#define GPU_SOFT_RESET GPU_CMD_DEF(1, 1)
+#define GPU_HARD_RESET GPU_CMD_DEF(1, 2)
+#define CACHE_CLEAN BIT(0)
+#define CACHE_INV BIT(1)
+#define GPU_FLUSH_CACHES(l2, lsc, oth) \
+ GPU_CMD_DEF(4, ((l2) << 0) | ((lsc) << 4) | ((oth) << 8))
+
+#define GPU_STATUS 0x34
+#define GPU_STATUS_ACTIVE BIT(0)
+#define GPU_STATUS_PWR_ACTIVE BIT(1)
+#define GPU_STATUS_PAGE_FAULT BIT(4)
+#define GPU_STATUS_PROTM_ACTIVE BIT(7)
+#define GPU_STATUS_DBG_ENABLED BIT(8)
+
+#define GPU_FAULT_STATUS 0x3C
+#define GPU_FAULT_ADDR 0x40
+#define GPU_L2_CONFIG 0x48
+#define GPU_L2_CONFIG_ASN_HASH_ENABLE BIT(24)
+
+#define GPU_PWR_KEY 0x50
+#define GPU_PWR_KEY_UNLOCK 0x2968A819
+#define GPU_PWR_OVERRIDE0 0x54
+#define GPU_PWR_OVERRIDE1 0x58
+
+#define GPU_FEATURES 0x60
+#define GPU_FEATURES_RAY_INTERSECTION BIT(2)
+#define GPU_FEATURES_RAY_TRAVERSAL BIT(5)
+
+#define GPU_TIMESTAMP_OFFSET 0x88
+#define GPU_CYCLE_COUNT 0x90
+#define GPU_TIMESTAMP 0x98
+
+#define GPU_THREAD_MAX_THREADS 0xA0
+#define GPU_THREAD_MAX_WORKGROUP_SIZE 0xA4
+#define GPU_THREAD_MAX_BARRIER_SIZE 0xA8
+#define GPU_THREAD_FEATURES 0xAC
+
+#define GPU_TEXTURE_FEATURES(n) (0xB0 + ((n) * 4))
+
+#define GPU_SHADER_PRESENT 0x100
+#define GPU_TILER_PRESENT 0x110
+#define GPU_L2_PRESENT 0x120
+
+#define SHADER_READY 0x140
+#define TILER_READY 0x150
+#define L2_READY 0x160
+
+#define SHADER_PWRON 0x180
+#define TILER_PWRON 0x190
+#define L2_PWRON 0x1A0
+
+#define SHADER_PWROFF 0x1C0
+#define TILER_PWROFF 0x1D0
+#define L2_PWROFF 0x1E0
+
+#define SHADER_PWRTRANS 0x200
+#define TILER_PWRTRANS 0x210
+#define L2_PWRTRANS 0x220
+
+#define SHADER_PWRACTIVE 0x240
+#define TILER_PWRACTIVE 0x250
+#define L2_PWRACTIVE 0x260
+
+#define GPU_REVID 0x280
+
+#define GPU_ASN_HASH(n) (0x2C0 + ((n) * 4))
+
+#define GPU_COHERENCY_FEATURES 0x300
+#define GPU_COHERENCY_PROT_BIT(name) BIT(GPU_COHERENCY_ ## name)
+
+#define GPU_COHERENCY_PROTOCOL 0x304
+#define GPU_COHERENCY_ACE_LITE 0
+#define GPU_COHERENCY_ACE 1
+#define GPU_COHERENCY_NONE 31
+
+#endif /* __PANTHOR_GPU_REGS_H__ */
diff --git a/drivers/gpu/drm/panthor/panthor_heap.c b/drivers/gpu/drm/panthor/panthor_heap.c
index 1ee30dc7066f..99311abdf1e9 100644
--- a/drivers/gpu/drm/panthor/panthor_heap.c
+++ b/drivers/gpu/drm/panthor/panthor_heap.c
@@ -9,9 +9,9 @@
#include "panthor_device.h"
#include "panthor_gem.h"
+#include "panthor_gpu_regs.h"
#include "panthor_heap.h"
#include "panthor_mmu.h"
-#include "panthor_regs.h"
/*
* The GPU heap context is an opaque structure used by the GPU to track the
diff --git a/drivers/gpu/drm/panthor/panthor_hw.c b/drivers/gpu/drm/panthor/panthor_hw.c
index d135aa6724fa..7e315708ca7c 100644
--- a/drivers/gpu/drm/panthor/panthor_hw.c
+++ b/drivers/gpu/drm/panthor/panthor_hw.c
@@ -8,9 +8,10 @@
#include "panthor_device.h"
#include "panthor_gpu.h"
+#include "panthor_gpu_regs.h"
#include "panthor_hw.h"
#include "panthor_pwr.h"
-#include "panthor_regs.h"
+#include "panthor_pwr_regs.h"
#define GPU_PROD_ID_MAKE(arch_major, prod_major) \
(((arch_major) << 24) | (prod_major))
@@ -194,35 +195,42 @@ static int panthor_gpu_info_init(struct panthor_device *ptdev)
{
unsigned int i;
- ptdev->gpu_info.csf_id = gpu_read(ptdev, GPU_CSF_ID);
- ptdev->gpu_info.gpu_rev = gpu_read(ptdev, GPU_REVID);
- ptdev->gpu_info.core_features = gpu_read(ptdev, GPU_CORE_FEATURES);
- ptdev->gpu_info.l2_features = gpu_read(ptdev, GPU_L2_FEATURES);
- ptdev->gpu_info.tiler_features = gpu_read(ptdev, GPU_TILER_FEATURES);
- ptdev->gpu_info.mem_features = gpu_read(ptdev, GPU_MEM_FEATURES);
- ptdev->gpu_info.mmu_features = gpu_read(ptdev, GPU_MMU_FEATURES);
- ptdev->gpu_info.thread_features = gpu_read(ptdev, GPU_THREAD_FEATURES);
- ptdev->gpu_info.max_threads = gpu_read(ptdev, GPU_THREAD_MAX_THREADS);
- ptdev->gpu_info.thread_max_workgroup_size = gpu_read(ptdev, GPU_THREAD_MAX_WORKGROUP_SIZE);
- ptdev->gpu_info.thread_max_barrier_size = gpu_read(ptdev, GPU_THREAD_MAX_BARRIER_SIZE);
- ptdev->gpu_info.coherency_features = gpu_read(ptdev, GPU_COHERENCY_FEATURES);
+ void __iomem *gpu_iomem = ptdev->iomem + GPU_CONTROL_BASE;
+
+ ptdev->gpu_info.csf_id = gpu_read(gpu_iomem, GPU_CSF_ID);
+ ptdev->gpu_info.gpu_rev = gpu_read(gpu_iomem, GPU_REVID);
+ ptdev->gpu_info.core_features = gpu_read(gpu_iomem, GPU_CORE_FEATURES);
+ ptdev->gpu_info.l2_features = gpu_read(gpu_iomem, GPU_L2_FEATURES);
+ ptdev->gpu_info.tiler_features = gpu_read(gpu_iomem, GPU_TILER_FEATURES);
+ ptdev->gpu_info.mem_features = gpu_read(gpu_iomem, GPU_MEM_FEATURES);
+ ptdev->gpu_info.mmu_features = gpu_read(gpu_iomem, GPU_MMU_FEATURES);
+ ptdev->gpu_info.thread_features = gpu_read(gpu_iomem, GPU_THREAD_FEATURES);
+ ptdev->gpu_info.max_threads = gpu_read(gpu_iomem, GPU_THREAD_MAX_THREADS);
+ ptdev->gpu_info.thread_max_workgroup_size =
+ gpu_read(gpu_iomem, GPU_THREAD_MAX_WORKGROUP_SIZE);
+ ptdev->gpu_info.thread_max_barrier_size =
+ gpu_read(gpu_iomem, GPU_THREAD_MAX_BARRIER_SIZE);
+ ptdev->gpu_info.coherency_features = gpu_read(gpu_iomem, GPU_COHERENCY_FEATURES);
for (i = 0; i < 4; i++)
- ptdev->gpu_info.texture_features[i] = gpu_read(ptdev, GPU_TEXTURE_FEATURES(i));
+ ptdev->gpu_info.texture_features[i] =
+ gpu_read(gpu_iomem, GPU_TEXTURE_FEATURES(i));
- ptdev->gpu_info.as_present = gpu_read(ptdev, GPU_AS_PRESENT);
+ ptdev->gpu_info.as_present = gpu_read(gpu_iomem, GPU_AS_PRESENT);
/* Introduced in arch 11.x */
- ptdev->gpu_info.gpu_features = gpu_read64(ptdev, GPU_FEATURES);
+ ptdev->gpu_info.gpu_features = gpu_read64(gpu_iomem, GPU_FEATURES);
if (panthor_hw_has_pwr_ctrl(ptdev)) {
+ void __iomem *pwr_iomem = gpu_iomem + PWR_CONTROL_BASE;
+
/* Introduced in arch 14.x */
- ptdev->gpu_info.l2_present = gpu_read64(ptdev, PWR_L2_PRESENT);
- ptdev->gpu_info.tiler_present = gpu_read64(ptdev, PWR_TILER_PRESENT);
- ptdev->gpu_info.shader_present = gpu_read64(ptdev, PWR_SHADER_PRESENT);
+ ptdev->gpu_info.l2_present = gpu_read64(pwr_iomem, PWR_L2_PRESENT);
+ ptdev->gpu_info.tiler_present = gpu_read64(pwr_iomem, PWR_TILER_PRESENT);
+ ptdev->gpu_info.shader_present = gpu_read64(pwr_iomem, PWR_SHADER_PRESENT);
} else {
- ptdev->gpu_info.shader_present = gpu_read64(ptdev, GPU_SHADER_PRESENT);
- ptdev->gpu_info.tiler_present = gpu_read64(ptdev, GPU_TILER_PRESENT);
- ptdev->gpu_info.l2_present = gpu_read64(ptdev, GPU_L2_PRESENT);
+ ptdev->gpu_info.shader_present = gpu_read64(gpu_iomem, GPU_SHADER_PRESENT);
+ ptdev->gpu_info.tiler_present = gpu_read64(gpu_iomem, GPU_TILER_PRESENT);
+ ptdev->gpu_info.l2_present = gpu_read64(gpu_iomem, GPU_L2_PRESENT);
}
return overload_shader_present(ptdev);
@@ -287,7 +295,7 @@ static int panthor_hw_bind_device(struct panthor_device *ptdev)
static int panthor_hw_gpu_id_init(struct panthor_device *ptdev)
{
- ptdev->gpu_info.gpu_id = gpu_read(ptdev, GPU_ID);
+ ptdev->gpu_info.gpu_id = gpu_read(ptdev->iomem, GPU_ID);
if (!ptdev->gpu_info.gpu_id)
return -ENXIO;
diff --git a/drivers/gpu/drm/panthor/panthor_hw.h b/drivers/gpu/drm/panthor/panthor_hw.h
index 2c28aea82841..f797663893b2 100644
--- a/drivers/gpu/drm/panthor/panthor_hw.h
+++ b/drivers/gpu/drm/panthor/panthor_hw.h
@@ -5,7 +5,7 @@
#define __PANTHOR_HW_H__
#include "panthor_device.h"
-#include "panthor_regs.h"
+#include "panthor_gpu_regs.h"
/**
* struct panthor_hw_ops - HW operations that are specific to a GPU
diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c
index fc930ee158a5..a7ee14986849 100644
--- a/drivers/gpu/drm/panthor/panthor_mmu.c
+++ b/drivers/gpu/drm/panthor/panthor_mmu.c
@@ -33,9 +33,10 @@
#include "panthor_device.h"
#include "panthor_gem.h"
#include "panthor_gpu.h"
+#include "panthor_gpu_regs.h"
#include "panthor_heap.h"
#include "panthor_mmu.h"
-#include "panthor_regs.h"
+#include "panthor_mmu_regs.h"
#include "panthor_sched.h"
#define MAX_AS_SLOTS 32
@@ -54,6 +55,9 @@ struct panthor_as_slot {
* struct panthor_mmu - MMU related data
*/
struct panthor_mmu {
+ /** @iomem: CPU mapping of MMU_AS_CONTROL iomem region */
+ void __iomem *iomem;
+
/** @irq: The MMU irq. */
struct panthor_irq irq;
@@ -516,15 +520,15 @@ static void free_pt(void *cookie, void *data, size_t size)
static int wait_ready(struct panthor_device *ptdev, u32 as_nr)
{
+ struct panthor_mmu *mmu = ptdev->mmu;
int ret;
u32 val;
/* Wait for the MMU status to indicate there is no active command, in
* case one is pending.
*/
- ret = gpu_read_relaxed_poll_timeout_atomic(ptdev, AS_STATUS(as_nr), val,
- !(val & AS_STATUS_AS_ACTIVE),
- 10, 100000);
+ ret = gpu_read_relaxed_poll_timeout_atomic(mmu->iomem, AS_STATUS(as_nr), val,
+ !(val & AS_STATUS_AS_ACTIVE), 10, 100000);
if (ret) {
panthor_device_schedule_reset(ptdev);
@@ -541,7 +545,7 @@ static int as_send_cmd_and_wait(struct panthor_device *ptdev, u32 as_nr, u32 cmd
/* write AS_COMMAND when MMU is ready to accept another command */
status = wait_ready(ptdev, as_nr);
if (!status) {
- gpu_write(ptdev, AS_COMMAND(as_nr), cmd);
+ gpu_write(ptdev->mmu->iomem, AS_COMMAND(as_nr), cmd);
status = wait_ready(ptdev, as_nr);
}
@@ -584,17 +588,19 @@ static u32 panthor_mmu_as_fault_mask(struct panthor_device *ptdev, u32 as)
/* Forward declaration to call helpers within as_enable/disable */
static void panthor_mmu_irq_handler(struct panthor_device *ptdev, u32 status);
-PANTHOR_IRQ_HANDLER(mmu, MMU, panthor_mmu_irq_handler);
+PANTHOR_IRQ_HANDLER(mmu, panthor_mmu_irq_handler);
static int panthor_mmu_as_enable(struct panthor_device *ptdev, u32 as_nr,
u64 transtab, u64 transcfg, u64 memattr)
{
+ struct panthor_mmu *mmu = ptdev->mmu;
+
panthor_mmu_irq_enable_events(&ptdev->mmu->irq,
panthor_mmu_as_fault_mask(ptdev, as_nr));
- gpu_write64(ptdev, AS_TRANSTAB(as_nr), transtab);
- gpu_write64(ptdev, AS_MEMATTR(as_nr), memattr);
- gpu_write64(ptdev, AS_TRANSCFG(as_nr), transcfg);
+ gpu_write64(mmu->iomem, AS_TRANSTAB(as_nr), transtab);
+ gpu_write64(mmu->iomem, AS_MEMATTR(as_nr), memattr);
+ gpu_write64(mmu->iomem, AS_TRANSCFG(as_nr), transcfg);
return as_send_cmd_and_wait(ptdev, as_nr, AS_COMMAND_UPDATE);
}
@@ -602,6 +608,7 @@ static int panthor_mmu_as_enable(struct panthor_device *ptdev, u32 as_nr,
static int panthor_mmu_as_disable(struct panthor_device *ptdev, u32 as_nr,
bool recycle_slot)
{
+ struct panthor_mmu *mmu = ptdev->mmu;
struct panthor_vm *vm = ptdev->mmu->as.slots[as_nr].vm;
int ret;
@@ -629,9 +636,9 @@ static int panthor_mmu_as_disable(struct panthor_device *ptdev, u32 as_nr,
if (recycle_slot)
return 0;
- gpu_write64(ptdev, AS_TRANSTAB(as_nr), 0);
- gpu_write64(ptdev, AS_MEMATTR(as_nr), 0);
- gpu_write64(ptdev, AS_TRANSCFG(as_nr), AS_TRANSCFG_ADRMODE_UNMAPPED);
+ gpu_write64(mmu->iomem, AS_TRANSTAB(as_nr), 0);
+ gpu_write64(mmu->iomem, AS_MEMATTR(as_nr), 0);
+ gpu_write64(mmu->iomem, AS_TRANSCFG(as_nr), AS_TRANSCFG_ADRMODE_UNMAPPED);
return as_send_cmd_and_wait(ptdev, as_nr, AS_COMMAND_UPDATE);
}
@@ -784,7 +791,7 @@ out_enable_as:
*/
fault_mask = panthor_mmu_as_fault_mask(ptdev, as);
if (ptdev->mmu->as.faulty_mask & fault_mask) {
- gpu_write(ptdev, MMU_INT_CLEAR, fault_mask);
+ gpu_write(ptdev->mmu->irq.iomem, INT_CLEAR, fault_mask);
ptdev->mmu->as.faulty_mask &= ~fault_mask;
}
@@ -1731,7 +1738,7 @@ static int panthor_vm_lock_region(struct panthor_vm *vm, u64 start, u64 size)
mutex_lock(&ptdev->mmu->as.slots_lock);
if (vm->as.id >= 0 && size) {
/* Lock the region that needs to be updated */
- gpu_write64(ptdev, AS_LOCKADDR(vm->as.id),
+ gpu_write64(ptdev->mmu->iomem, AS_LOCKADDR(vm->as.id),
pack_region_range(ptdev, &start, &size));
/* If the lock succeeded, update the locked_region info. */
@@ -1780,6 +1787,7 @@ static void panthor_vm_unlock_region(struct panthor_vm *vm)
static void panthor_mmu_irq_handler(struct panthor_device *ptdev, u32 status)
{
+ struct panthor_mmu *mmu = ptdev->mmu;
bool has_unhandled_faults = false;
status = panthor_mmu_fault_mask(ptdev, status);
@@ -1792,8 +1800,8 @@ static void panthor_mmu_irq_handler(struct panthor_device *ptdev, u32 status)
u32 access_type;
u32 source_id;
- fault_status = gpu_read(ptdev, AS_FAULTSTATUS(as));
- addr = gpu_read64(ptdev, AS_FAULTADDRESS(as));
+ fault_status = gpu_read(mmu->iomem, AS_FAULTSTATUS(as));
+ addr = gpu_read64(mmu->iomem, AS_FAULTADDRESS(as));
/* decode the fault status */
exception_type = fault_status & 0xFF;
@@ -1824,7 +1832,7 @@ static void panthor_mmu_irq_handler(struct panthor_device *ptdev, u32 status)
* Note that COMPLETED irqs are never cleared, but this is fine
* because they are always masked.
*/
- gpu_write(ptdev, MMU_INT_CLEAR, mask);
+ gpu_write(mmu->irq.iomem, INT_CLEAR, mask);
if (ptdev->mmu->as.slots[as].vm)
ptdev->mmu->as.slots[as].vm->unhandled_fault = true;
@@ -3240,6 +3248,7 @@ int panthor_mmu_init(struct panthor_device *ptdev)
if (ret)
return ret;
+ mmu->iomem = ptdev->iomem + MMU_AS_BASE;
ptdev->mmu = mmu;
irq = platform_get_irq_byname(to_platform_device(ptdev->base.dev), "mmu");
@@ -3247,7 +3256,8 @@ int panthor_mmu_init(struct panthor_device *ptdev)
return -ENODEV;
ret = panthor_request_mmu_irq(ptdev, &mmu->irq, irq,
- panthor_mmu_fault_mask(ptdev, ~0));
+ panthor_mmu_fault_mask(ptdev, ~0),
+ ptdev->iomem + MMU_INT_BASE);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/panthor/panthor_mmu_regs.h b/drivers/gpu/drm/panthor/panthor_mmu_regs.h
new file mode 100644
index 000000000000..4e32ab931949
--- /dev/null
+++ b/drivers/gpu/drm/panthor/panthor_mmu_regs.h
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: GPL-2.0 or MIT */
+/* Copyright 2026 ARM Limited. All rights reserved. */
+
+#ifndef __PANTHOR_MMU_REGS_H__
+#define __PANTHOR_MMU_REGS_H__
+
+/* MMU regs */
+
+#define MMU_INT_BASE 0x2000
+
+/* AS_COMMAND register commands */
+
+#define MMU_AS_BASE 0x2400
+
+#define MMU_AS_SHIFT 6
+#define MMU_AS(as) ((as) << MMU_AS_SHIFT)
+
+#define AS_TRANSTAB(as) (MMU_AS(as) + 0x0)
+#define AS_MEMATTR(as) (MMU_AS(as) + 0x8)
+#define AS_MEMATTR_AARCH64_INNER_ALLOC_IMPL (2 << 2)
+#define AS_MEMATTR_AARCH64_INNER_ALLOC_EXPL(w, r) ((3 << 2) | \
+ ((w) ? BIT(0) : 0) | \
+ ((r) ? BIT(1) : 0))
+#define AS_MEMATTR_AARCH64_SH_MIDGARD_INNER (0 << 4)
+#define AS_MEMATTR_AARCH64_SH_CPU_INNER (1 << 4)
+#define AS_MEMATTR_AARCH64_SH_CPU_INNER_SHADER_COH (2 << 4)
+#define AS_MEMATTR_AARCH64_SHARED (0 << 6)
+#define AS_MEMATTR_AARCH64_INNER_OUTER_NC (1 << 6)
+#define AS_MEMATTR_AARCH64_INNER_OUTER_WB (2 << 6)
+#define AS_MEMATTR_AARCH64_FAULT (3 << 6)
+#define AS_LOCKADDR(as) (MMU_AS(as) + 0x10)
+#define AS_COMMAND(as) (MMU_AS(as) + 0x18)
+#define AS_COMMAND_NOP 0
+#define AS_COMMAND_UPDATE 1
+#define AS_COMMAND_LOCK 2
+#define AS_COMMAND_UNLOCK 3
+#define AS_COMMAND_FLUSH_PT 4
+#define AS_COMMAND_FLUSH_MEM 5
+#define AS_LOCK_REGION_MIN_SIZE (1ULL << 15)
+#define AS_FAULTSTATUS(as) (MMU_AS(as) + 0x1C)
+#define AS_FAULTSTATUS_ACCESS_TYPE_MASK (0x3 << 8)
+#define AS_FAULTSTATUS_ACCESS_TYPE_ATOMIC (0x0 << 8)
+#define AS_FAULTSTATUS_ACCESS_TYPE_EX (0x1 << 8)
+#define AS_FAULTSTATUS_ACCESS_TYPE_READ (0x2 << 8)
+#define AS_FAULTSTATUS_ACCESS_TYPE_WRITE (0x3 << 8)
+#define AS_FAULTADDRESS(as) (MMU_AS(as) + 0x20)
+#define AS_STATUS(as) (MMU_AS(as) + 0x28)
+#define AS_STATUS_AS_ACTIVE BIT(0)
+#define AS_TRANSCFG(as) (MMU_AS(as) + 0x30)
+#define AS_TRANSCFG_ADRMODE_UNMAPPED (1 << 0)
+#define AS_TRANSCFG_ADRMODE_IDENTITY (2 << 0)
+#define AS_TRANSCFG_ADRMODE_AARCH64_4K (6 << 0)
+#define AS_TRANSCFG_ADRMODE_AARCH64_64K (8 << 0)
+#define AS_TRANSCFG_INA_BITS(x) ((x) << 6)
+#define AS_TRANSCFG_OUTA_BITS(x) ((x) << 14)
+#define AS_TRANSCFG_SL_CONCAT BIT(22)
+#define AS_TRANSCFG_PTW_MEMATTR_NC (1 << 24)
+#define AS_TRANSCFG_PTW_MEMATTR_WB (2 << 24)
+#define AS_TRANSCFG_PTW_SH_NS (0 << 28)
+#define AS_TRANSCFG_PTW_SH_OS (2 << 28)
+#define AS_TRANSCFG_PTW_SH_IS (3 << 28)
+#define AS_TRANSCFG_PTW_RA BIT(30)
+#define AS_TRANSCFG_DISABLE_HIER_AP BIT(33)
+#define AS_TRANSCFG_DISABLE_AF_FAULT BIT(34)
+#define AS_TRANSCFG_WXN BIT(35)
+#define AS_TRANSCFG_XREADABLE BIT(36)
+#define AS_FAULTEXTRA(as) (MMU_AS(as) + 0x38)
+
+#endif /* __PANTHOR_MMU_REGS_H__ */
diff --git a/drivers/gpu/drm/panthor/panthor_pwr.c b/drivers/gpu/drm/panthor/panthor_pwr.c
index ed3b2b4479ca..7c7f424a1436 100644
--- a/drivers/gpu/drm/panthor/panthor_pwr.c
+++ b/drivers/gpu/drm/panthor/panthor_pwr.c
@@ -11,9 +11,10 @@
#include <drm/drm_print.h>
#include "panthor_device.h"
+#include "panthor_gpu_regs.h"
#include "panthor_hw.h"
#include "panthor_pwr.h"
-#include "panthor_regs.h"
+#include "panthor_pwr_regs.h"
#define PWR_INTERRUPTS_MASK \
(PWR_IRQ_POWER_CHANGED_SINGLE | \
@@ -39,6 +40,9 @@
* struct panthor_pwr - PWR_CONTROL block management data.
*/
struct panthor_pwr {
+ /** @iomem: CPU mapping of PWR_CONTROL iomem region */
+ void __iomem *iomem;
+
/** @irq: PWR irq. */
struct panthor_irq irq;
@@ -54,8 +58,10 @@ struct panthor_pwr {
static void panthor_pwr_irq_handler(struct panthor_device *ptdev, u32 status)
{
+ struct panthor_pwr *pwr = ptdev->pwr;
+
spin_lock(&ptdev->pwr->reqs_lock);
- gpu_write(ptdev, PWR_INT_CLEAR, status);
+ gpu_write(pwr->irq.iomem, INT_CLEAR, status);
if (unlikely(status & PWR_IRQ_COMMAND_NOT_ALLOWED))
drm_err(&ptdev->base, "PWR_IRQ: COMMAND_NOT_ALLOWED");
@@ -69,19 +75,23 @@ static void panthor_pwr_irq_handler(struct panthor_device *ptdev, u32 status)
}
spin_unlock(&ptdev->pwr->reqs_lock);
}
-PANTHOR_IRQ_HANDLER(pwr, PWR, panthor_pwr_irq_handler);
+PANTHOR_IRQ_HANDLER(pwr, panthor_pwr_irq_handler);
static void panthor_pwr_write_command(struct panthor_device *ptdev, u32 command, u64 args)
{
+ struct panthor_pwr *pwr = ptdev->pwr;
+
if (args)
- gpu_write64(ptdev, PWR_CMDARG, args);
+ gpu_write64(pwr->iomem, PWR_CMDARG, args);
- gpu_write(ptdev, PWR_COMMAND, command);
+ gpu_write(pwr->iomem, PWR_COMMAND, command);
}
static bool reset_irq_raised(struct panthor_device *ptdev)
{
- return gpu_read(ptdev, PWR_INT_RAWSTAT) & PWR_IRQ_RESET_COMPLETED;
+ struct panthor_pwr *pwr = ptdev->pwr;
+
+ return gpu_read(pwr->irq.iomem, INT_RAWSTAT) & PWR_IRQ_RESET_COMPLETED;
}
static bool reset_pending(struct panthor_device *ptdev)
@@ -91,12 +101,14 @@ static bool reset_pending(struct panthor_device *ptdev)
static int panthor_pwr_reset(struct panthor_device *ptdev, u32 reset_cmd)
{
+ struct panthor_pwr *pwr = ptdev->pwr;
+
scoped_guard(spinlock_irqsave, &ptdev->pwr->reqs_lock) {
if (reset_pending(ptdev)) {
drm_WARN(&ptdev->base, 1, "Reset already pending");
} else {
ptdev->pwr->pending_reqs |= PWR_IRQ_RESET_COMPLETED;
- gpu_write(ptdev, PWR_INT_CLEAR, PWR_IRQ_RESET_COMPLETED);
+ gpu_write(pwr->irq.iomem, INT_CLEAR, PWR_IRQ_RESET_COMPLETED);
panthor_pwr_write_command(ptdev, reset_cmd, 0);
}
}
@@ -181,11 +193,12 @@ static u8 get_domain_subdomain(struct panthor_device *ptdev, u32 domain)
static int panthor_pwr_domain_wait_transition(struct panthor_device *ptdev, u32 domain,
u32 timeout_us)
{
+ struct panthor_pwr *pwr = ptdev->pwr;
u32 pwrtrans_reg = get_domain_pwrtrans_reg(domain);
u64 val;
int ret = 0;
- ret = gpu_read64_poll_timeout(ptdev, pwrtrans_reg, val, !(PWR_ALL_CORES_MASK & val), 100,
+ ret = gpu_read64_poll_timeout(pwr->iomem, pwrtrans_reg, val, !(PWR_ALL_CORES_MASK & val), 100,
timeout_us);
if (ret) {
drm_err(&ptdev->base, "%s domain power in transition, pwrtrans(0x%llx)",
@@ -198,22 +211,25 @@ static int panthor_pwr_domain_wait_transition(struct panthor_device *ptdev, u32
static void panthor_pwr_debug_info_show(struct panthor_device *ptdev)
{
- drm_info(&ptdev->base, "GPU_FEATURES: 0x%016llx", gpu_read64(ptdev, GPU_FEATURES));
- drm_info(&ptdev->base, "PWR_STATUS: 0x%016llx", gpu_read64(ptdev, PWR_STATUS));
- drm_info(&ptdev->base, "L2_PRESENT: 0x%016llx", gpu_read64(ptdev, PWR_L2_PRESENT));
- drm_info(&ptdev->base, "L2_PWRTRANS: 0x%016llx", gpu_read64(ptdev, PWR_L2_PWRTRANS));
- drm_info(&ptdev->base, "L2_READY: 0x%016llx", gpu_read64(ptdev, PWR_L2_READY));
- drm_info(&ptdev->base, "TILER_PRESENT: 0x%016llx", gpu_read64(ptdev, PWR_TILER_PRESENT));
- drm_info(&ptdev->base, "TILER_PWRTRANS: 0x%016llx", gpu_read64(ptdev, PWR_TILER_PWRTRANS));
- drm_info(&ptdev->base, "TILER_READY: 0x%016llx", gpu_read64(ptdev, PWR_TILER_READY));
- drm_info(&ptdev->base, "SHADER_PRESENT: 0x%016llx", gpu_read64(ptdev, PWR_SHADER_PRESENT));
- drm_info(&ptdev->base, "SHADER_PWRTRANS: 0x%016llx", gpu_read64(ptdev, PWR_SHADER_PWRTRANS));
- drm_info(&ptdev->base, "SHADER_READY: 0x%016llx", gpu_read64(ptdev, PWR_SHADER_READY));
+ struct panthor_pwr *pwr = ptdev->pwr;
+
+ drm_info(&ptdev->base, "GPU_FEATURES: 0x%016llx", ptdev->gpu_info.gpu_features);
+ drm_info(&ptdev->base, "PWR_STATUS: 0x%016llx", gpu_read64(pwr->iomem, PWR_STATUS));
+ drm_info(&ptdev->base, "L2_PRESENT: 0x%016llx", gpu_read64(pwr->iomem, PWR_L2_PRESENT));
+ drm_info(&ptdev->base, "L2_PWRTRANS: 0x%016llx", gpu_read64(pwr->iomem, PWR_L2_PWRTRANS));
+ drm_info(&ptdev->base, "L2_READY: 0x%016llx", gpu_read64(pwr->iomem, PWR_L2_READY));
+ drm_info(&ptdev->base, "TILER_PRESENT: 0x%016llx", gpu_read64(pwr->iomem, PWR_TILER_PRESENT));
+ drm_info(&ptdev->base, "TILER_PWRTRANS: 0x%016llx", gpu_read64(pwr->iomem, PWR_TILER_PWRTRANS));
+ drm_info(&ptdev->base, "TILER_READY: 0x%016llx", gpu_read64(pwr->iomem, PWR_TILER_READY));
+ drm_info(&ptdev->base, "SHADER_PRESENT: 0x%016llx", gpu_read64(pwr->iomem, PWR_SHADER_PRESENT));
+ drm_info(&ptdev->base, "SHADER_PWRTRANS: 0x%016llx", gpu_read64(pwr->iomem, PWR_SHADER_PWRTRANS));
+ drm_info(&ptdev->base, "SHADER_READY: 0x%016llx", gpu_read64(pwr->iomem, PWR_SHADER_READY));
}
static int panthor_pwr_domain_transition(struct panthor_device *ptdev, u32 cmd, u32 domain,
u64 mask, u32 timeout_us)
{
+ struct panthor_pwr *pwr = ptdev->pwr;
u32 ready_reg = get_domain_ready_reg(domain);
u32 pwr_cmd = PWR_COMMAND_DEF(cmd, domain, get_domain_subdomain(ptdev, domain));
u64 expected_val = 0;
@@ -240,13 +256,13 @@ static int panthor_pwr_domain_transition(struct panthor_device *ptdev, u32 cmd,
return ret;
/* domain already in target state, return early */
- if ((gpu_read64(ptdev, ready_reg) & mask) == expected_val)
+ if ((gpu_read64(pwr->iomem, ready_reg) & mask) == expected_val)
return 0;
panthor_pwr_write_command(ptdev, pwr_cmd, mask);
- ret = gpu_read64_poll_timeout(ptdev, ready_reg, val, (mask & val) == expected_val, 100,
- timeout_us);
+ ret = gpu_read64_poll_timeout(pwr->iomem, ready_reg, val, (mask & val) == expected_val,
+ 100, timeout_us);
if (ret) {
drm_err(&ptdev->base,
"timeout waiting on %s power domain transition, cmd(0x%x), arg(0x%llx)",
@@ -278,8 +294,9 @@ static int panthor_pwr_domain_transition(struct panthor_device *ptdev, u32 cmd,
*/
static int retract_domain(struct panthor_device *ptdev, u32 domain)
{
+ struct panthor_pwr *pwr = ptdev->pwr;
const u32 pwr_cmd = PWR_COMMAND_DEF(PWR_COMMAND_RETRACT, domain, 0);
- const u64 pwr_status = gpu_read64(ptdev, PWR_STATUS);
+ const u64 pwr_status = gpu_read64(pwr->iomem, PWR_STATUS);
const u64 delegated_mask = PWR_STATUS_DOMAIN_DELEGATED(domain);
const u64 allow_mask = PWR_STATUS_DOMAIN_ALLOWED(domain);
u64 val;
@@ -288,8 +305,9 @@ static int retract_domain(struct panthor_device *ptdev, u32 domain)
if (drm_WARN_ON(&ptdev->base, domain == PWR_COMMAND_DOMAIN_L2))
return -EPERM;
- ret = gpu_read64_poll_timeout(ptdev, PWR_STATUS, val, !(PWR_STATUS_RETRACT_PENDING & val),
- 0, PWR_RETRACT_TIMEOUT_US);
+ ret = gpu_read64_poll_timeout(pwr->iomem, PWR_STATUS, val,
+ !(PWR_STATUS_RETRACT_PENDING & val), 0,
+ PWR_RETRACT_TIMEOUT_US);
if (ret) {
drm_err(&ptdev->base, "%s domain retract pending", get_domain_name(domain));
return ret;
@@ -306,7 +324,7 @@ static int retract_domain(struct panthor_device *ptdev, u32 domain)
* On successful retraction
* allow-flag will be set with delegated-flag being cleared.
*/
- ret = gpu_read64_poll_timeout(ptdev, PWR_STATUS, val,
+ ret = gpu_read64_poll_timeout(pwr->iomem, PWR_STATUS, val,
((delegated_mask | allow_mask) & val) == allow_mask, 10,
PWR_TRANSITION_TIMEOUT_US);
if (ret) {
@@ -332,8 +350,9 @@ static int retract_domain(struct panthor_device *ptdev, u32 domain)
*/
static int delegate_domain(struct panthor_device *ptdev, u32 domain)
{
+ struct panthor_pwr *pwr = ptdev->pwr;
const u32 pwr_cmd = PWR_COMMAND_DEF(PWR_COMMAND_DELEGATE, domain, 0);
- const u64 pwr_status = gpu_read64(ptdev, PWR_STATUS);
+ const u64 pwr_status = gpu_read64(pwr->iomem, PWR_STATUS);
const u64 allow_mask = PWR_STATUS_DOMAIN_ALLOWED(domain);
const u64 delegated_mask = PWR_STATUS_DOMAIN_DELEGATED(domain);
u64 val;
@@ -362,7 +381,7 @@ static int delegate_domain(struct panthor_device *ptdev, u32 domain)
* On successful delegation
* allow-flag will be cleared with delegated-flag being set.
*/
- ret = gpu_read64_poll_timeout(ptdev, PWR_STATUS, val,
+ ret = gpu_read64_poll_timeout(pwr->iomem, PWR_STATUS, val,
((delegated_mask | allow_mask) & val) == delegated_mask,
10, PWR_TRANSITION_TIMEOUT_US);
if (ret) {
@@ -410,7 +429,8 @@ err_retract_shader:
*/
static int panthor_pwr_domain_force_off(struct panthor_device *ptdev, u32 domain)
{
- const u64 domain_ready = gpu_read64(ptdev, get_domain_ready_reg(domain));
+ struct panthor_pwr *pwr = ptdev->pwr;
+ const u64 domain_ready = gpu_read64(pwr->iomem, get_domain_ready_reg(domain));
int ret;
/* Domain already powered down, early exit. */
@@ -454,6 +474,7 @@ int panthor_pwr_init(struct panthor_device *ptdev)
if (!pwr)
return -ENOMEM;
+ pwr->iomem = ptdev->iomem + PWR_CONTROL_BASE;
spin_lock_init(&pwr->reqs_lock);
init_waitqueue_head(&pwr->reqs_acked);
ptdev->pwr = pwr;
@@ -462,7 +483,9 @@ int panthor_pwr_init(struct panthor_device *ptdev)
if (irq < 0)
return irq;
- err = panthor_request_pwr_irq(ptdev, &pwr->irq, irq, PWR_INTERRUPTS_MASK);
+ err = panthor_request_pwr_irq(
+ ptdev, &pwr->irq, irq, PWR_INTERRUPTS_MASK,
+ pwr->iomem + PWR_INT_BASE);
if (err)
return err;
@@ -471,7 +494,9 @@ int panthor_pwr_init(struct panthor_device *ptdev)
int panthor_pwr_reset_soft(struct panthor_device *ptdev)
{
- if (!(gpu_read64(ptdev, PWR_STATUS) & PWR_STATUS_ALLOW_SOFT_RESET)) {
+ struct panthor_pwr *pwr = ptdev->pwr;
+
+ if (!(gpu_read64(pwr->iomem, PWR_STATUS) & PWR_STATUS_ALLOW_SOFT_RESET)) {
drm_err(&ptdev->base, "RESET_SOFT not allowed");
return -EOPNOTSUPP;
}
@@ -481,8 +506,9 @@ int panthor_pwr_reset_soft(struct panthor_device *ptdev)
void panthor_pwr_l2_power_off(struct panthor_device *ptdev)
{
+ struct panthor_pwr *pwr = ptdev->pwr;
const u64 l2_allow_mask = PWR_STATUS_DOMAIN_ALLOWED(PWR_COMMAND_DOMAIN_L2);
- const u64 pwr_status = gpu_read64(ptdev, PWR_STATUS);
+ const u64 pwr_status = gpu_read64(pwr->iomem, PWR_STATUS);
/* Abort if L2 power off constraints are not satisfied */
if (!(pwr_status & l2_allow_mask)) {
@@ -508,7 +534,8 @@ void panthor_pwr_l2_power_off(struct panthor_device *ptdev)
int panthor_pwr_l2_power_on(struct panthor_device *ptdev)
{
- const u32 pwr_status = gpu_read64(ptdev, PWR_STATUS);
+ struct panthor_pwr *pwr = ptdev->pwr;
+ const u32 pwr_status = gpu_read64(pwr->iomem, PWR_STATUS);
const u32 l2_allow_mask = PWR_STATUS_DOMAIN_ALLOWED(PWR_COMMAND_DOMAIN_L2);
int ret;
diff --git a/drivers/gpu/drm/panthor/panthor_pwr_regs.h b/drivers/gpu/drm/panthor/panthor_pwr_regs.h
new file mode 100644
index 000000000000..9cf7a715066f
--- /dev/null
+++ b/drivers/gpu/drm/panthor/panthor_pwr_regs.h
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: GPL-2.0 or MIT */
+/* Copyright 2026 ARM Limited. All rights reserved. */
+
+#ifndef __PANTHOR_PWR_REGS_H__
+#define __PANTHOR_PWR_REGS_H__
+
+#define PWR_CONTROL_BASE 0x800
+
+#define PWR_INT_BASE 0x0
+#define PWR_IRQ_POWER_CHANGED_SINGLE BIT(0)
+#define PWR_IRQ_POWER_CHANGED_ALL BIT(1)
+#define PWR_IRQ_DELEGATION_CHANGED BIT(2)
+#define PWR_IRQ_RESET_COMPLETED BIT(3)
+#define PWR_IRQ_RETRACT_COMPLETED BIT(4)
+#define PWR_IRQ_INSPECT_COMPLETED BIT(5)
+#define PWR_IRQ_COMMAND_NOT_ALLOWED BIT(30)
+#define PWR_IRQ_COMMAND_INVALID BIT(31)
+
+#define PWR_STATUS 0x20
+#define PWR_STATUS_ALLOW_L2 BIT_U64(0)
+#define PWR_STATUS_ALLOW_TILER BIT_U64(1)
+#define PWR_STATUS_ALLOW_SHADER BIT_U64(8)
+#define PWR_STATUS_ALLOW_BASE BIT_U64(14)
+#define PWR_STATUS_ALLOW_STACK BIT_U64(15)
+#define PWR_STATUS_DOMAIN_ALLOWED(x) BIT_U64(x)
+#define PWR_STATUS_DELEGATED_L2 BIT_U64(16)
+#define PWR_STATUS_DELEGATED_TILER BIT_U64(17)
+#define PWR_STATUS_DELEGATED_SHADER BIT_U64(24)
+#define PWR_STATUS_DELEGATED_BASE BIT_U64(30)
+#define PWR_STATUS_DELEGATED_STACK BIT_U64(31)
+#define PWR_STATUS_DELEGATED_SHIFT 16
+#define PWR_STATUS_DOMAIN_DELEGATED(x) BIT_U64((x) + PWR_STATUS_DELEGATED_SHIFT)
+#define PWR_STATUS_ALLOW_SOFT_RESET BIT_U64(33)
+#define PWR_STATUS_ALLOW_FAST_RESET BIT_U64(34)
+#define PWR_STATUS_POWER_PENDING BIT_U64(41)
+#define PWR_STATUS_RESET_PENDING BIT_U64(42)
+#define PWR_STATUS_RETRACT_PENDING BIT_U64(43)
+#define PWR_STATUS_INSPECT_PENDING BIT_U64(44)
+
+#define PWR_COMMAND 0x28
+#define PWR_COMMAND_POWER_UP 0x10
+#define PWR_COMMAND_POWER_DOWN 0x11
+#define PWR_COMMAND_DELEGATE 0x20
+#define PWR_COMMAND_RETRACT 0x21
+#define PWR_COMMAND_RESET_SOFT 0x31
+#define PWR_COMMAND_RESET_FAST 0x32
+#define PWR_COMMAND_INSPECT 0xF0
+#define PWR_COMMAND_DOMAIN_L2 0
+#define PWR_COMMAND_DOMAIN_TILER 1
+#define PWR_COMMAND_DOMAIN_SHADER 8
+#define PWR_COMMAND_DOMAIN_BASE 14
+#define PWR_COMMAND_DOMAIN_STACK 15
+#define PWR_COMMAND_SUBDOMAIN_RTU BIT(0)
+#define PWR_COMMAND_DEF(cmd, domain, subdomain) \
+ (((subdomain) << 16) | ((domain) << 8) | (cmd))
+
+#define PWR_CMDARG 0x30
+
+#define PWR_L2_PRESENT 0x100
+#define PWR_L2_READY 0x108
+#define PWR_L2_PWRTRANS 0x110
+#define PWR_L2_PWRACTIVE 0x118
+#define PWR_TILER_PRESENT 0x140
+#define PWR_TILER_READY 0x148
+#define PWR_TILER_PWRTRANS 0x150
+#define PWR_TILER_PWRACTIVE 0x158
+#define PWR_SHADER_PRESENT 0x200
+#define PWR_SHADER_READY 0x208
+#define PWR_SHADER_PWRTRANS 0x210
+#define PWR_SHADER_PWRACTIVE 0x218
+#define PWR_BASE_PRESENT 0x380
+#define PWR_BASE_READY 0x388
+#define PWR_BASE_PWRTRANS 0x390
+#define PWR_BASE_PWRACTIVE 0x398
+#define PWR_STACK_PRESENT 0x3c0
+#define PWR_STACK_READY 0x3c8
+#define PWR_STACK_PWRTRANS 0x3d0
+
+#endif /* __PANTHOR_PWR_REGS_H__ */
diff --git a/drivers/gpu/drm/panthor/panthor_regs.h b/drivers/gpu/drm/panthor/panthor_regs.h
deleted file mode 100644
index 08bf06c452d6..000000000000
--- a/drivers/gpu/drm/panthor/panthor_regs.h
+++ /dev/null
@@ -1,291 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 or MIT */
-/* Copyright 2018 Marty E. Plummer <hanetzer@startmail.com> */
-/* Copyright 2019 Linaro, Ltd, Rob Herring <robh@kernel.org> */
-/* Copyright 2023 Collabora ltd. */
-/*
- * Register definitions based on mali_kbase_gpu_regmap.h and
- * mali_kbase_gpu_regmap_csf.h
- * (C) COPYRIGHT 2010-2022 ARM Limited. All rights reserved.
- */
-#ifndef __PANTHOR_REGS_H__
-#define __PANTHOR_REGS_H__
-
-#define GPU_ID 0x0
-#define GPU_ARCH_MAJOR(x) ((x) >> 28)
-#define GPU_ARCH_MINOR(x) (((x) & GENMASK(27, 24)) >> 24)
-#define GPU_ARCH_REV(x) (((x) & GENMASK(23, 20)) >> 20)
-#define GPU_PROD_MAJOR(x) (((x) & GENMASK(19, 16)) >> 16)
-#define GPU_VER_MAJOR(x) (((x) & GENMASK(15, 12)) >> 12)
-#define GPU_VER_MINOR(x) (((x) & GENMASK(11, 4)) >> 4)
-#define GPU_VER_STATUS(x) ((x) & GENMASK(3, 0))
-
-#define GPU_L2_FEATURES 0x4
-#define GPU_L2_FEATURES_LINE_SIZE(x) (1 << ((x) & GENMASK(7, 0)))
-
-#define GPU_CORE_FEATURES 0x8
-
-#define GPU_TILER_FEATURES 0xC
-#define GPU_MEM_FEATURES 0x10
-#define GROUPS_L2_COHERENT BIT(0)
-
-#define GPU_MMU_FEATURES 0x14
-#define GPU_MMU_FEATURES_VA_BITS(x) ((x) & GENMASK(7, 0))
-#define GPU_MMU_FEATURES_PA_BITS(x) (((x) >> 8) & GENMASK(7, 0))
-#define GPU_AS_PRESENT 0x18
-#define GPU_CSF_ID 0x1C
-
-#define GPU_INT_RAWSTAT 0x20
-#define GPU_INT_CLEAR 0x24
-#define GPU_INT_MASK 0x28
-#define GPU_INT_STAT 0x2c
-#define GPU_IRQ_FAULT BIT(0)
-#define GPU_IRQ_PROTM_FAULT BIT(1)
-#define GPU_IRQ_RESET_COMPLETED BIT(8)
-#define GPU_IRQ_POWER_CHANGED BIT(9)
-#define GPU_IRQ_POWER_CHANGED_ALL BIT(10)
-#define GPU_IRQ_CLEAN_CACHES_COMPLETED BIT(17)
-#define GPU_IRQ_DOORBELL_MIRROR BIT(18)
-#define GPU_IRQ_MCU_STATUS_CHANGED BIT(19)
-#define GPU_CMD 0x30
-#define GPU_CMD_DEF(type, payload) ((type) | ((payload) << 8))
-#define GPU_SOFT_RESET GPU_CMD_DEF(1, 1)
-#define GPU_HARD_RESET GPU_CMD_DEF(1, 2)
-#define CACHE_CLEAN BIT(0)
-#define CACHE_INV BIT(1)
-#define GPU_FLUSH_CACHES(l2, lsc, oth) \
- GPU_CMD_DEF(4, ((l2) << 0) | ((lsc) << 4) | ((oth) << 8))
-
-#define GPU_STATUS 0x34
-#define GPU_STATUS_ACTIVE BIT(0)
-#define GPU_STATUS_PWR_ACTIVE BIT(1)
-#define GPU_STATUS_PAGE_FAULT BIT(4)
-#define GPU_STATUS_PROTM_ACTIVE BIT(7)
-#define GPU_STATUS_DBG_ENABLED BIT(8)
-
-#define GPU_FAULT_STATUS 0x3C
-#define GPU_FAULT_ADDR 0x40
-#define GPU_L2_CONFIG 0x48
-#define GPU_L2_CONFIG_ASN_HASH_ENABLE BIT(24)
-
-#define GPU_PWR_KEY 0x50
-#define GPU_PWR_KEY_UNLOCK 0x2968A819
-#define GPU_PWR_OVERRIDE0 0x54
-#define GPU_PWR_OVERRIDE1 0x58
-
-#define GPU_FEATURES 0x60
-#define GPU_FEATURES_RAY_INTERSECTION BIT(2)
-#define GPU_FEATURES_RAY_TRAVERSAL BIT(5)
-
-#define GPU_TIMESTAMP_OFFSET 0x88
-#define GPU_CYCLE_COUNT 0x90
-#define GPU_TIMESTAMP 0x98
-
-#define GPU_THREAD_MAX_THREADS 0xA0
-#define GPU_THREAD_MAX_WORKGROUP_SIZE 0xA4
-#define GPU_THREAD_MAX_BARRIER_SIZE 0xA8
-#define GPU_THREAD_FEATURES 0xAC
-
-#define GPU_TEXTURE_FEATURES(n) (0xB0 + ((n) * 4))
-
-#define GPU_SHADER_PRESENT 0x100
-#define GPU_TILER_PRESENT 0x110
-#define GPU_L2_PRESENT 0x120
-
-#define SHADER_READY 0x140
-#define TILER_READY 0x150
-#define L2_READY 0x160
-
-#define SHADER_PWRON 0x180
-#define TILER_PWRON 0x190
-#define L2_PWRON 0x1A0
-
-#define SHADER_PWROFF 0x1C0
-#define TILER_PWROFF 0x1D0
-#define L2_PWROFF 0x1E0
-
-#define SHADER_PWRTRANS 0x200
-#define TILER_PWRTRANS 0x210
-#define L2_PWRTRANS 0x220
-
-#define SHADER_PWRACTIVE 0x240
-#define TILER_PWRACTIVE 0x250
-#define L2_PWRACTIVE 0x260
-
-#define GPU_REVID 0x280
-
-#define GPU_ASN_HASH(n) (0x2C0 + ((n) * 4))
-
-#define GPU_COHERENCY_FEATURES 0x300
-#define GPU_COHERENCY_PROT_BIT(name) BIT(GPU_COHERENCY_ ## name)
-
-#define GPU_COHERENCY_PROTOCOL 0x304
-#define GPU_COHERENCY_ACE_LITE 0
-#define GPU_COHERENCY_ACE 1
-#define GPU_COHERENCY_NONE 31
-
-#define MCU_CONTROL 0x700
-#define MCU_CONTROL_ENABLE 1
-#define MCU_CONTROL_AUTO 2
-#define MCU_CONTROL_DISABLE 0
-
-#define MCU_STATUS 0x704
-#define MCU_STATUS_DISABLED 0
-#define MCU_STATUS_ENABLED 1
-#define MCU_STATUS_HALT 2
-#define MCU_STATUS_FATAL 3
-
-/* Job Control regs */
-#define JOB_INT_RAWSTAT 0x1000
-#define JOB_INT_CLEAR 0x1004
-#define JOB_INT_MASK 0x1008
-#define JOB_INT_STAT 0x100c
-#define JOB_INT_GLOBAL_IF BIT(31)
-#define JOB_INT_CSG_IF(x) BIT(x)
-
-/* MMU regs */
-#define MMU_INT_RAWSTAT 0x2000
-#define MMU_INT_CLEAR 0x2004
-#define MMU_INT_MASK 0x2008
-#define MMU_INT_STAT 0x200c
-
-/* AS_COMMAND register commands */
-
-#define MMU_BASE 0x2400
-#define MMU_AS_SHIFT 6
-#define MMU_AS(as) (MMU_BASE + ((as) << MMU_AS_SHIFT))
-
-#define AS_TRANSTAB(as) (MMU_AS(as) + 0x0)
-#define AS_MEMATTR(as) (MMU_AS(as) + 0x8)
-#define AS_MEMATTR_AARCH64_INNER_ALLOC_IMPL (2 << 2)
-#define AS_MEMATTR_AARCH64_INNER_ALLOC_EXPL(w, r) ((3 << 2) | \
- ((w) ? BIT(0) : 0) | \
- ((r) ? BIT(1) : 0))
-#define AS_MEMATTR_AARCH64_SH_MIDGARD_INNER (0 << 4)
-#define AS_MEMATTR_AARCH64_SH_CPU_INNER (1 << 4)
-#define AS_MEMATTR_AARCH64_SH_CPU_INNER_SHADER_COH (2 << 4)
-#define AS_MEMATTR_AARCH64_SHARED (0 << 6)
-#define AS_MEMATTR_AARCH64_INNER_OUTER_NC (1 << 6)
-#define AS_MEMATTR_AARCH64_INNER_OUTER_WB (2 << 6)
-#define AS_MEMATTR_AARCH64_FAULT (3 << 6)
-#define AS_LOCKADDR(as) (MMU_AS(as) + 0x10)
-#define AS_COMMAND(as) (MMU_AS(as) + 0x18)
-#define AS_COMMAND_NOP 0
-#define AS_COMMAND_UPDATE 1
-#define AS_COMMAND_LOCK 2
-#define AS_COMMAND_UNLOCK 3
-#define AS_COMMAND_FLUSH_PT 4
-#define AS_COMMAND_FLUSH_MEM 5
-#define AS_LOCK_REGION_MIN_SIZE (1ULL << 15)
-#define AS_FAULTSTATUS(as) (MMU_AS(as) + 0x1C)
-#define AS_FAULTSTATUS_ACCESS_TYPE_MASK (0x3 << 8)
-#define AS_FAULTSTATUS_ACCESS_TYPE_ATOMIC (0x0 << 8)
-#define AS_FAULTSTATUS_ACCESS_TYPE_EX (0x1 << 8)
-#define AS_FAULTSTATUS_ACCESS_TYPE_READ (0x2 << 8)
-#define AS_FAULTSTATUS_ACCESS_TYPE_WRITE (0x3 << 8)
-#define AS_FAULTADDRESS(as) (MMU_AS(as) + 0x20)
-#define AS_STATUS(as) (MMU_AS(as) + 0x28)
-#define AS_STATUS_AS_ACTIVE BIT(0)
-#define AS_TRANSCFG(as) (MMU_AS(as) + 0x30)
-#define AS_TRANSCFG_ADRMODE_UNMAPPED (1 << 0)
-#define AS_TRANSCFG_ADRMODE_IDENTITY (2 << 0)
-#define AS_TRANSCFG_ADRMODE_AARCH64_4K (6 << 0)
-#define AS_TRANSCFG_ADRMODE_AARCH64_64K (8 << 0)
-#define AS_TRANSCFG_INA_BITS(x) ((x) << 6)
-#define AS_TRANSCFG_OUTA_BITS(x) ((x) << 14)
-#define AS_TRANSCFG_SL_CONCAT BIT(22)
-#define AS_TRANSCFG_PTW_MEMATTR_NC (1 << 24)
-#define AS_TRANSCFG_PTW_MEMATTR_WB (2 << 24)
-#define AS_TRANSCFG_PTW_SH_NS (0 << 28)
-#define AS_TRANSCFG_PTW_SH_OS (2 << 28)
-#define AS_TRANSCFG_PTW_SH_IS (3 << 28)
-#define AS_TRANSCFG_PTW_RA BIT(30)
-#define AS_TRANSCFG_DISABLE_HIER_AP BIT(33)
-#define AS_TRANSCFG_DISABLE_AF_FAULT BIT(34)
-#define AS_TRANSCFG_WXN BIT(35)
-#define AS_TRANSCFG_XREADABLE BIT(36)
-#define AS_FAULTEXTRA(as) (MMU_AS(as) + 0x38)
-
-#define CSF_GPU_LATEST_FLUSH_ID 0x10000
-
-#define CSF_DOORBELL(i) (0x80000 + ((i) * 0x10000))
-#define CSF_GLB_DOORBELL_ID 0
-
-/* PWR Control registers */
-
-#define PWR_CONTROL_BASE 0x800
-#define PWR_CTRL_REG(x) (PWR_CONTROL_BASE + (x))
-
-#define PWR_INT_RAWSTAT PWR_CTRL_REG(0x0)
-#define PWR_INT_CLEAR PWR_CTRL_REG(0x4)
-#define PWR_INT_MASK PWR_CTRL_REG(0x8)
-#define PWR_INT_STAT PWR_CTRL_REG(0xc)
-#define PWR_IRQ_POWER_CHANGED_SINGLE BIT(0)
-#define PWR_IRQ_POWER_CHANGED_ALL BIT(1)
-#define PWR_IRQ_DELEGATION_CHANGED BIT(2)
-#define PWR_IRQ_RESET_COMPLETED BIT(3)
-#define PWR_IRQ_RETRACT_COMPLETED BIT(4)
-#define PWR_IRQ_INSPECT_COMPLETED BIT(5)
-#define PWR_IRQ_COMMAND_NOT_ALLOWED BIT(30)
-#define PWR_IRQ_COMMAND_INVALID BIT(31)
-
-#define PWR_STATUS PWR_CTRL_REG(0x20)
-#define PWR_STATUS_ALLOW_L2 BIT_U64(0)
-#define PWR_STATUS_ALLOW_TILER BIT_U64(1)
-#define PWR_STATUS_ALLOW_SHADER BIT_U64(8)
-#define PWR_STATUS_ALLOW_BASE BIT_U64(14)
-#define PWR_STATUS_ALLOW_STACK BIT_U64(15)
-#define PWR_STATUS_DOMAIN_ALLOWED(x) BIT_U64(x)
-#define PWR_STATUS_DELEGATED_L2 BIT_U64(16)
-#define PWR_STATUS_DELEGATED_TILER BIT_U64(17)
-#define PWR_STATUS_DELEGATED_SHADER BIT_U64(24)
-#define PWR_STATUS_DELEGATED_BASE BIT_U64(30)
-#define PWR_STATUS_DELEGATED_STACK BIT_U64(31)
-#define PWR_STATUS_DELEGATED_SHIFT 16
-#define PWR_STATUS_DOMAIN_DELEGATED(x) BIT_U64((x) + PWR_STATUS_DELEGATED_SHIFT)
-#define PWR_STATUS_ALLOW_SOFT_RESET BIT_U64(33)
-#define PWR_STATUS_ALLOW_FAST_RESET BIT_U64(34)
-#define PWR_STATUS_POWER_PENDING BIT_U64(41)
-#define PWR_STATUS_RESET_PENDING BIT_U64(42)
-#define PWR_STATUS_RETRACT_PENDING BIT_U64(43)
-#define PWR_STATUS_INSPECT_PENDING BIT_U64(44)
-
-#define PWR_COMMAND PWR_CTRL_REG(0x28)
-#define PWR_COMMAND_POWER_UP 0x10
-#define PWR_COMMAND_POWER_DOWN 0x11
-#define PWR_COMMAND_DELEGATE 0x20
-#define PWR_COMMAND_RETRACT 0x21
-#define PWR_COMMAND_RESET_SOFT 0x31
-#define PWR_COMMAND_RESET_FAST 0x32
-#define PWR_COMMAND_INSPECT 0xF0
-#define PWR_COMMAND_DOMAIN_L2 0
-#define PWR_COMMAND_DOMAIN_TILER 1
-#define PWR_COMMAND_DOMAIN_SHADER 8
-#define PWR_COMMAND_DOMAIN_BASE 14
-#define PWR_COMMAND_DOMAIN_STACK 15
-#define PWR_COMMAND_SUBDOMAIN_RTU BIT(0)
-#define PWR_COMMAND_DEF(cmd, domain, subdomain) \
- (((subdomain) << 16) | ((domain) << 8) | (cmd))
-
-#define PWR_CMDARG PWR_CTRL_REG(0x30)
-
-#define PWR_L2_PRESENT PWR_CTRL_REG(0x100)
-#define PWR_L2_READY PWR_CTRL_REG(0x108)
-#define PWR_L2_PWRTRANS PWR_CTRL_REG(0x110)
-#define PWR_L2_PWRACTIVE PWR_CTRL_REG(0x118)
-#define PWR_TILER_PRESENT PWR_CTRL_REG(0x140)
-#define PWR_TILER_READY PWR_CTRL_REG(0x148)
-#define PWR_TILER_PWRTRANS PWR_CTRL_REG(0x150)
-#define PWR_TILER_PWRACTIVE PWR_CTRL_REG(0x158)
-#define PWR_SHADER_PRESENT PWR_CTRL_REG(0x200)
-#define PWR_SHADER_READY PWR_CTRL_REG(0x208)
-#define PWR_SHADER_PWRTRANS PWR_CTRL_REG(0x210)
-#define PWR_SHADER_PWRACTIVE PWR_CTRL_REG(0x218)
-#define PWR_BASE_PRESENT PWR_CTRL_REG(0x380)
-#define PWR_BASE_READY PWR_CTRL_REG(0x388)
-#define PWR_BASE_PWRTRANS PWR_CTRL_REG(0x390)
-#define PWR_BASE_PWRACTIVE PWR_CTRL_REG(0x398)
-#define PWR_STACK_PRESENT PWR_CTRL_REG(0x3c0)
-#define PWR_STACK_READY PWR_CTRL_REG(0x3c8)
-#define PWR_STACK_PWRTRANS PWR_CTRL_REG(0x3d0)
-
-#endif
diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c
index 41d6369fa9c0..5b34032deff8 100644
--- a/drivers/gpu/drm/panthor/panthor_sched.c
+++ b/drivers/gpu/drm/panthor/panthor_sched.c
@@ -28,11 +28,12 @@
#include "panthor_devfreq.h"
#include "panthor_device.h"
#include "panthor_fw.h"
+#include "panthor_fw_regs.h"
#include "panthor_gem.h"
#include "panthor_gpu.h"
+#include "panthor_gpu_regs.h"
#include "panthor_heap.h"
#include "panthor_mmu.h"
-#include "panthor_regs.h"
#include "panthor_sched.h"
/**
@@ -3372,7 +3373,7 @@ queue_run_job(struct drm_sched_job *sched_job)
if (resume_tick)
sched_resume_tick(ptdev);
- gpu_write(ptdev, CSF_DOORBELL(queue->doorbell_id), 1);
+ panthor_fw_ring_doorbell(ptdev, queue->doorbell_id);
if (!sched->pm.has_ref &&
!(group->blocked_queues & BIT(job->queue_idx))) {
pm_runtime_get(ptdev->base.dev);
diff --git a/drivers/gpu/drm/renesas/rcar-du/rcar_du_encoder.c b/drivers/gpu/drm/renesas/rcar-du/rcar_du_encoder.c
index 32ea09d65d76..db2088529b48 100644
--- a/drivers/gpu/drm/renesas/rcar-du/rcar_du_encoder.c
+++ b/drivers/gpu/drm/renesas/rcar-du/rcar_du_encoder.c
@@ -142,7 +142,7 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu,
return PTR_ERR(connector);
}
- return drm_connector_attach_encoder(connector, &renc->base);
+ return 0;
}
void rcar_du_encoder_cleanup(struct rcar_du_device *rcdu)
diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_encoder.c b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_encoder.c
index d53068733c66..0e567b57a408 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_encoder.c
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_encoder.c
@@ -129,5 +129,5 @@ int rzg2l_du_encoder_init(struct rzg2l_du_device *rcdu,
return PTR_ERR(connector);
}
- return drm_connector_attach_encoder(connector, &renc->base);
+ return 0;
}
diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
index 40fd6e1eeab5..a2c864860075 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
@@ -1445,6 +1445,11 @@ static int rzg2l_mipi_dsi_probe(struct platform_device *pdev)
return dev_err_probe(dsi->dev, PTR_ERR(dsi->prstc),
"failed to get prst\n");
+ dsi->dcs_buf_virt = dmam_alloc_coherent(dsi->dev, RZG2L_DCS_BUF_SIZE,
+ &dsi->dcs_buf_phys, GFP_KERNEL);
+ if (!dsi->dcs_buf_virt)
+ return -ENOMEM;
+
platform_set_drvdata(pdev, dsi);
pm_runtime_enable(dsi->dev);
@@ -1477,11 +1482,6 @@ static int rzg2l_mipi_dsi_probe(struct platform_device *pdev)
if (ret < 0)
goto err_pm_disable;
- dsi->dcs_buf_virt = dma_alloc_coherent(dsi->host.dev, RZG2L_DCS_BUF_SIZE,
- &dsi->dcs_buf_phys, GFP_KERNEL);
- if (!dsi->dcs_buf_virt)
- return -ENOMEM;
-
return 0;
err_phy:
@@ -1496,8 +1496,6 @@ static void rzg2l_mipi_dsi_remove(struct platform_device *pdev)
{
struct rzg2l_mipi_dsi *dsi = platform_get_drvdata(pdev);
- dma_free_coherent(dsi->host.dev, RZG2L_DCS_BUF_SIZE, dsi->dcs_buf_virt,
- dsi->dcs_buf_phys);
mipi_dsi_host_unregister(&dsi->host);
pm_runtime_disable(&pdev->dev);
}
diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c
index a799069e2f63..1a2b9b68af6f 100644
--- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c
+++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c
@@ -583,6 +583,13 @@ shmob_drm_connector_init(struct shmob_drm_device *sdev,
drm_connector_helper_add(connector, &connector_helper_funcs);
+ ret = drm_connector_attach_encoder(connector, encoder);
+ if (ret < 0) {
+ drm_connector_cleanup(connector);
+ kfree(scon);
+ return ERR_PTR(ret);
+ }
+
return connector;
}
@@ -594,7 +601,6 @@ int shmob_drm_connector_create(struct shmob_drm_device *sdev,
struct drm_encoder *encoder)
{
struct drm_connector *connector;
- int ret;
if (sdev->pdata)
connector = shmob_drm_connector_init(sdev, encoder);
@@ -606,17 +612,9 @@ int shmob_drm_connector_create(struct shmob_drm_device *sdev,
return PTR_ERR(connector);
}
- ret = drm_connector_attach_encoder(connector, encoder);
- if (ret < 0)
- goto error;
-
connector->dpms = DRM_MODE_DPMS_OFF;
sdev->connector = connector;
return 0;
-
-error:
- drm_connector_cleanup(connector);
- return ret;
}
diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index 936e4558e93d..06072efd7fca 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -395,7 +395,7 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
goto err_cleanup_encoder;
}
- return drm_connector_attach_encoder(connector, dp->plat_data.encoder);
+ return 0;
err_cleanup_encoder:
dp->encoder.encoder.funcs->destroy(&dp->encoder.encoder);
return ret;
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c
index 892fbea9ae9c..190cce9530c8 100644
--- a/drivers/gpu/drm/rockchip/cdn-dp-core.c
+++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c
@@ -1024,8 +1024,6 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data)
return ret;
}
- drm_connector_attach_encoder(connector, encoder);
-
for (i = 0; i < dp->ports; i++) {
port = dp->port[i];
diff --git a/drivers/gpu/drm/rockchip/dw_dp-rockchip.c b/drivers/gpu/drm/rockchip/dw_dp-rockchip.c
index 81710e8f3fec..32bc73a1d5e4 100644
--- a/drivers/gpu/drm/rockchip/dw_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_dp-rockchip.c
@@ -111,7 +111,7 @@ static int dw_dp_rockchip_bind(struct device *dev, struct device *master, void *
return dev_err_probe(dev, PTR_ERR(connector),
"Failed to init bridge connector");
- return drm_connector_attach_encoder(connector, encoder);
+ return 0;
}
static const struct component_ops dw_dp_rockchip_component_ops = {
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index c78db7f8ab6c..f35484715c2d 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -603,7 +603,7 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
return dev_err_probe(hdmi->dev, PTR_ERR(connector),
"Failed to init bridge connector\n");
- return drm_connector_attach_encoder(connector, encoder);
+ return 0;
}
static void dw_hdmi_qp_rockchip_unbind(struct device *dev,
diff --git a/drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c
index 28e6fb09aae7..45a6dae4de31 100644
--- a/drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c
@@ -137,7 +137,7 @@ static int inno_hdmi_rockchip_bind(struct device *dev, struct device *master, vo
return ret;
}
- return drm_connector_attach_encoder(connector, encoder);
+ return 0;
}
static const struct component_ops inno_hdmi_rockchip_ops = {
diff --git a/drivers/gpu/drm/rockchip/rk3066_hdmi.c b/drivers/gpu/drm/rockchip/rk3066_hdmi.c
index 54a0f124c7e1..1996f8656612 100644
--- a/drivers/gpu/drm/rockchip/rk3066_hdmi.c
+++ b/drivers/gpu/drm/rockchip/rk3066_hdmi.c
@@ -731,8 +731,6 @@ rk3066_hdmi_register(struct drm_device *drm, struct rk3066_hdmi *hdmi)
return ret;
}
- drm_connector_attach_encoder(hdmi->connector, encoder);
-
return 0;
}
diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.c b/drivers/gpu/drm/rockchip/rockchip_lvds.c
index 75f898a10cbc..7a0c4fa29f2f 100644
--- a/drivers/gpu/drm/rockchip/rockchip_lvds.c
+++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c
@@ -628,12 +628,6 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master,
ret = PTR_ERR(connector);
goto err_free_bridge;
}
-
- ret = drm_connector_attach_encoder(connector, encoder);
- if (ret < 0) {
- drm_err(drm_dev, "failed to attach encoder: %d\n", ret);
- goto err_free_bridge;
- }
}
pm_runtime_enable(dev);
diff --git a/drivers/gpu/drm/rockchip/rockchip_rgb.c b/drivers/gpu/drm/rockchip/rockchip_rgb.c
index 5c0c6e2cc28d..add3123e5ce7 100644
--- a/drivers/gpu/drm/rockchip/rockchip_rgb.c
+++ b/drivers/gpu/drm/rockchip/rockchip_rgb.c
@@ -162,17 +162,8 @@ struct rockchip_rgb *rockchip_rgb_init(struct device *dev,
rgb->encoder.crtc_endpoint_id = endpoint_id;
- ret = drm_connector_attach_encoder(connector, encoder);
- if (ret < 0) {
- DRM_DEV_ERROR(drm_dev->dev,
- "failed to attach encoder: %d\n", ret);
- goto err_free_connector;
- }
-
return rgb;
-err_free_connector:
- drm_connector_cleanup(connector);
err_free_encoder:
drm_encoder_cleanup(encoder);
return ERR_PTR(ret);
diff --git a/drivers/gpu/drm/sysfb/corebootdrm.c b/drivers/gpu/drm/sysfb/corebootdrm.c
index 5dc6f3c76f7b..853da9a609df 100644
--- a/drivers/gpu/drm/sysfb/corebootdrm.c
+++ b/drivers/gpu/drm/sysfb/corebootdrm.c
@@ -4,6 +4,7 @@
#include <linux/coreboot.h>
#include <linux/minmax.h>
#include <linux/platform_device.h>
+#include <linux/pm.h>
#include <drm/clients/drm_client_setup.h>
#include <drm/drm_atomic.h>
@@ -18,6 +19,7 @@
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_gem_shmem_helper.h>
#include <drm/drm_managed.h>
+#include <drm/drm_modeset_helper.h>
#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
@@ -286,6 +288,24 @@ static struct drm_driver corebootdrm_drm_driver = {
* Coreboot driver
*/
+static int corebootdrm_pm_suspend(struct device *dev)
+{
+ struct corebootdrm_device *cdev = dev_get_drvdata(dev);
+ struct drm_device *drm = &cdev->sysfb.dev;
+
+ return drm_mode_config_helper_suspend(drm);
+}
+
+static int corebootdrm_pm_resume(struct device *dev)
+{
+ struct corebootdrm_device *cdev = dev_get_drvdata(dev);
+ struct drm_device *drm = &cdev->sysfb.dev;
+
+ return drm_mode_config_helper_resume(drm);
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(corebootdrm_pm_ops, corebootdrm_pm_suspend, corebootdrm_pm_resume);
+
static int corebootdrm_probe(struct platform_device *pdev)
{
const struct lb_framebuffer *fb = dev_get_platdata(&pdev->dev);
@@ -423,6 +443,7 @@ static void corebootdrm_remove(struct platform_device *pdev)
static struct platform_driver corebootdrm_platform_driver = {
.driver = {
.name = "coreboot-framebuffer",
+ .pm = pm_sleep_ptr(&corebootdrm_pm_ops),
},
.probe = corebootdrm_probe,
.remove = corebootdrm_remove,
diff --git a/drivers/gpu/drm/sysfb/efidrm.c b/drivers/gpu/drm/sysfb/efidrm.c
index a335c94a7bd7..1a1e36700976 100644
--- a/drivers/gpu/drm/sysfb/efidrm.c
+++ b/drivers/gpu/drm/sysfb/efidrm.c
@@ -5,6 +5,7 @@
#include <linux/limits.h>
#include <linux/platform_device.h>
#include <linux/sysfb.h>
+#include <linux/pm.h>
#include <drm/clients/drm_client_setup.h>
#include <drm/drm_atomic.h>
@@ -20,6 +21,7 @@
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_gem_shmem_helper.h>
#include <drm/drm_managed.h>
+#include <drm/drm_modeset_helper.h>
#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
@@ -371,6 +373,22 @@ static struct drm_driver efidrm_driver = {
* Platform driver
*/
+static int efidrm_pm_suspend(struct device *dev)
+{
+ struct drm_device *drm = dev_get_drvdata(dev);
+
+ return drm_mode_config_helper_suspend(drm);
+}
+
+static int efidrm_pm_resume(struct device *dev)
+{
+ struct drm_device *drm = dev_get_drvdata(dev);
+
+ return drm_mode_config_helper_resume(drm);
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(efidrm_pm_ops, efidrm_pm_suspend, efidrm_pm_resume);
+
static int efidrm_probe(struct platform_device *pdev)
{
struct efidrm_device *efi;
@@ -403,6 +421,7 @@ static void efidrm_remove(struct platform_device *pdev)
static struct platform_driver efidrm_platform_driver = {
.driver = {
.name = "efi-framebuffer",
+ .pm = pm_sleep_ptr(&efidrm_pm_ops),
},
.probe = efidrm_probe,
.remove = efidrm_remove,
diff --git a/drivers/gpu/drm/sysfb/ofdrm.c b/drivers/gpu/drm/sysfb/ofdrm.c
index 61c38bce8f64..819aed466727 100644
--- a/drivers/gpu/drm/sysfb/ofdrm.c
+++ b/drivers/gpu/drm/sysfb/ofdrm.c
@@ -4,6 +4,7 @@
#include <linux/of_address.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
+#include <linux/pm.h>
#include <drm/clients/drm_client_setup.h>
#include <drm/drm_atomic.h>
@@ -20,6 +21,7 @@
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_gem_shmem_helper.h>
#include <drm/drm_managed.h>
+#include <drm/drm_modeset_helper.h>
#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
@@ -1097,6 +1099,22 @@ static struct drm_driver ofdrm_driver = {
* Platform driver
*/
+static int ofdrm_pm_suspend(struct device *dev)
+{
+ struct drm_device *drm = dev_get_drvdata(dev);
+
+ return drm_mode_config_helper_suspend(drm);
+}
+
+static int ofdrm_pm_resume(struct device *dev)
+{
+ struct drm_device *drm = dev_get_drvdata(dev);
+
+ return drm_mode_config_helper_resume(drm);
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(ofdrm_pm_ops, ofdrm_pm_suspend, ofdrm_pm_resume);
+
static int ofdrm_probe(struct platform_device *pdev)
{
struct ofdrm_device *odev;
@@ -1136,6 +1154,7 @@ static struct platform_driver ofdrm_platform_driver = {
.driver = {
.name = "of-display",
.of_match_table = ofdrm_of_match_display,
+ .pm = pm_sleep_ptr(&ofdrm_pm_ops),
},
.probe = ofdrm_probe,
.remove = ofdrm_remove,
diff --git a/drivers/gpu/drm/sysfb/simpledrm.c b/drivers/gpu/drm/sysfb/simpledrm.c
index 7a95d2dacd9d..fc168920f2c6 100644
--- a/drivers/gpu/drm/sysfb/simpledrm.c
+++ b/drivers/gpu/drm/sysfb/simpledrm.c
@@ -8,6 +8,7 @@
#include <linux/of_reserved_mem.h>
#include <linux/platform_data/simplefb.h>
#include <linux/platform_device.h>
+#include <linux/pm.h>
#include <linux/pm_domain.h>
#include <linux/regulator/consumer.h>
@@ -24,6 +25,7 @@
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_gem_shmem_helper.h>
#include <drm/drm_managed.h>
+#include <drm/drm_modeset_helper.h>
#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
@@ -834,6 +836,24 @@ static struct drm_driver simpledrm_driver = {
* Platform driver
*/
+static int simpledrm_pm_suspend(struct device *dev)
+{
+ struct simpledrm_device *sdev = dev_get_drvdata(dev);
+ struct drm_device *drm = &sdev->sysfb.dev;
+
+ return drm_mode_config_helper_suspend(drm);
+}
+
+static int simpledrm_pm_resume(struct device *dev)
+{
+ struct simpledrm_device *sdev = dev_get_drvdata(dev);
+ struct drm_device *drm = &sdev->sysfb.dev;
+
+ return drm_mode_config_helper_resume(drm);
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(simpledrm_pm_ops, simpledrm_pm_suspend, simpledrm_pm_resume);
+
static int simpledrm_probe(struct platform_device *pdev)
{
struct simpledrm_device *sdev;
@@ -874,6 +894,7 @@ static struct platform_driver simpledrm_platform_driver = {
.driver = {
.name = "simple-framebuffer", /* connect to sysfb */
.of_match_table = simpledrm_of_match_table,
+ .pm = pm_sleep_ptr(&simpledrm_pm_ops),
},
.probe = simpledrm_probe,
.remove = simpledrm_remove,
diff --git a/drivers/gpu/drm/sysfb/vesadrm.c b/drivers/gpu/drm/sysfb/vesadrm.c
index dee3b4d6ec26..dbc317778d54 100644
--- a/drivers/gpu/drm/sysfb/vesadrm.c
+++ b/drivers/gpu/drm/sysfb/vesadrm.c
@@ -5,6 +5,7 @@
#include <linux/limits.h>
#include <linux/platform_device.h>
#include <linux/sysfb.h>
+#include <linux/pm.h>
#include <drm/clients/drm_client_setup.h>
#include <drm/drm_atomic.h>
@@ -21,6 +22,7 @@
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_gem_shmem_helper.h>
#include <drm/drm_managed.h>
+#include <drm/drm_modeset_helper.h>
#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
@@ -617,6 +619,22 @@ static struct drm_driver vesadrm_driver = {
* Platform driver
*/
+static int vesadrm_pm_suspend(struct device *dev)
+{
+ struct drm_device *drm = dev_get_drvdata(dev);
+
+ return drm_mode_config_helper_suspend(drm);
+}
+
+static int vesadrm_pm_resume(struct device *dev)
+{
+ struct drm_device *drm = dev_get_drvdata(dev);
+
+ return drm_mode_config_helper_resume(drm);
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(vesadrm_pm_ops, vesadrm_pm_suspend, vesadrm_pm_resume);
+
static int vesadrm_probe(struct platform_device *pdev)
{
struct vesadrm_device *vesa;
@@ -649,6 +667,7 @@ static void vesadrm_remove(struct platform_device *pdev)
static struct platform_driver vesadrm_platform_driver = {
.driver = {
.name = "vesa-framebuffer",
+ .pm = pm_sleep_ptr(&vesadrm_pm_ops),
},
.probe = vesadrm_probe,
.remove = vesadrm_remove,
diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c
index 0adcd4244a42..10f02f35c866 100644
--- a/drivers/gpu/drm/tegra/hdmi.c
+++ b/drivers/gpu/drm/tegra/hdmi.c
@@ -1576,8 +1576,6 @@ static int tegra_hdmi_init(struct host1x_client *client)
connector);
return PTR_ERR(connector);
}
-
- drm_connector_attach_encoder(connector, &hdmi->output.encoder);
} else {
drm_connector_init_with_ddc(drm, &hdmi->output.connector,
&tegra_hdmi_connector_funcs,
diff --git a/drivers/gpu/drm/tegra/rgb.c b/drivers/gpu/drm/tegra/rgb.c
index ff5a749710db..e67fbb2362e6 100644
--- a/drivers/gpu/drm/tegra/rgb.c
+++ b/drivers/gpu/drm/tegra/rgb.c
@@ -355,8 +355,6 @@ int tegra_dc_rgb_init(struct drm_device *drm, struct tegra_dc *dc)
connector);
return PTR_ERR(connector);
}
-
- drm_connector_attach_encoder(connector, &output->encoder);
}
err = tegra_output_init(drm, output);
diff --git a/drivers/gpu/drm/tests/drm_bridge_test.c b/drivers/gpu/drm/tests/drm_bridge_test.c
index 1f473d70e7e8..64b665580a88 100644
--- a/drivers/gpu/drm/tests/drm_bridge_test.c
+++ b/drivers/gpu/drm/tests/drm_bridge_test.c
@@ -173,8 +173,6 @@ drm_test_bridge_init(struct kunit *test, const struct drm_bridge_funcs *funcs)
if (IS_ERR(priv->connector))
return ERR_CAST(priv->connector);
- drm_connector_attach_encoder(priv->connector, enc);
-
drm_mode_config_reset(drm);
return priv;
diff --git a/drivers/gpu/drm/tidss/tidss_encoder.c b/drivers/gpu/drm/tidss/tidss_encoder.c
index db467bbcdb77..34db8d2a3792 100644
--- a/drivers/gpu/drm/tidss/tidss_encoder.c
+++ b/drivers/gpu/drm/tidss/tidss_encoder.c
@@ -123,12 +123,6 @@ int tidss_encoder_create(struct tidss_device *tidss,
return PTR_ERR(connector);
}
- ret = drm_connector_attach_encoder(connector, enc);
- if (ret) {
- dev_err(tidss->dev, "attaching encoder to connector failed\n");
- return ret;
- }
-
t_enc->connector = connector;
dev_dbg(tidss->dev, "Encoder create done\n");
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_encoder.c b/drivers/gpu/drm/tilcdc/tilcdc_encoder.c
index 680a2ac6ab59..ac4b5beb2dd5 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_encoder.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_encoder.c
@@ -35,12 +35,6 @@ int tilcdc_attach_bridge(struct drm_device *ddev, struct drm_bridge *bridge)
return PTR_ERR(connector);
}
- ret = drm_connector_attach_encoder(connector, &priv->encoder->base);
- if (ret) {
- drm_err(ddev, "attaching encoder to connector failed\n");
- return ret;
- }
-
priv->connector = connector;
return 0;
}
diff --git a/drivers/gpu/drm/tve200/tve200_drv.c b/drivers/gpu/drm/tve200/tve200_drv.c
index a048e37f1c2c..562f3f11812a 100644
--- a/drivers/gpu/drm/tve200/tve200_drv.c
+++ b/drivers/gpu/drm/tve200/tve200_drv.c
@@ -221,12 +221,16 @@ static int tve200_probe(struct platform_device *pdev)
ret = drm_dev_register(drm, 0);
if (ret < 0)
- goto clk_disable;
+ goto mode_config_cleanup;
drm_client_setup_with_fourcc(drm, DRM_FORMAT_RGB565);
return 0;
+mode_config_cleanup:
+ if (priv->panel)
+ drm_panel_bridge_remove(priv->bridge);
+ drm_mode_config_cleanup(drm);
clk_disable:
clk_disable_unprepare(priv->pclk);
dev_unref:
diff --git a/drivers/gpu/drm/verisilicon/vs_bridge.c b/drivers/gpu/drm/verisilicon/vs_bridge.c
index 17add75b8878..7a93049368db 100644
--- a/drivers/gpu/drm/verisilicon/vs_bridge.c
+++ b/drivers/gpu/drm/verisilicon/vs_bridge.c
@@ -365,7 +365,6 @@ struct vs_bridge *vs_bridge_init(struct drm_device *drm_dev,
ret = PTR_ERR(bridge->conn);
return ERR_PTR(ret);
}
- drm_connector_attach_encoder(bridge->conn, bridge->enc);
return bridge;
}
diff --git a/drivers/gpu/drm/verisilicon/vs_plane.c b/drivers/gpu/drm/verisilicon/vs_plane.c
index 2f3953e588a3..d81f7b8f4c65 100644
--- a/drivers/gpu/drm/verisilicon/vs_plane.c
+++ b/drivers/gpu/drm/verisilicon/vs_plane.c
@@ -6,13 +6,15 @@
#include <linux/errno.h>
#include <linux/printk.h>
+#include <drm/drm_atomic_state_helper.h>
#include <drm/drm_fb_dma_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_gem_dma_helper.h>
+#include <drm/drm_print.h>
#include "vs_plane.h"
-void drm_format_to_vs_format(u32 drm_format, struct vs_format *vs_format)
+int drm_format_to_vs_format(u32 drm_format, struct vs_format *vs_format)
{
switch (drm_format) {
case DRM_FORMAT_XRGB4444:
@@ -62,7 +64,7 @@ void drm_format_to_vs_format(u32 drm_format, struct vs_format *vs_format)
vs_format->color = VSDC_COLOR_FORMAT_A2R10G10B10;
break;
default:
- pr_warn("Unexpected drm format!\n");
+ return -EINVAL;
}
switch (drm_format) {
@@ -101,6 +103,8 @@ void drm_format_to_vs_format(u32 drm_format, struct vs_format *vs_format)
/* N/A for non-YUV formats */
vs_format->uv_swizzle = false;
+
+ return 0;
}
dma_addr_t vs_fb_get_dma_addr(struct drm_framebuffer *fb,
@@ -122,3 +126,49 @@ dma_addr_t vs_fb_get_dma_addr(struct drm_framebuffer *fb,
return dma_addr;
}
+
+struct drm_plane_state *vs_plane_duplicate_state(struct drm_plane *plane)
+{
+ struct vs_plane_state *vs_state, *vs_state_old;
+
+ if (drm_WARN_ON(plane->dev, !plane->state))
+ return NULL;
+
+ vs_state_old = to_vs_plane_state(plane->state);
+
+ vs_state = kzalloc_obj(*vs_state, GFP_KERNEL);
+ if (!vs_state)
+ return NULL;
+
+ __drm_atomic_helper_plane_duplicate_state(plane, &vs_state->base);
+
+ memcpy(&vs_state->format, &vs_state_old->format,
+ sizeof(struct vs_format));
+
+ return &vs_state->base;
+}
+
+void vs_plane_destroy_state(struct drm_plane *plane,
+ struct drm_plane_state *state)
+{
+ __drm_atomic_helper_plane_destroy_state(state);
+ kfree(state);
+}
+
+/* Called during init to allocate the plane's atomic state. */
+void vs_plane_reset(struct drm_plane *plane)
+{
+ struct vs_plane_state *vs_state;
+
+ if (plane->state) {
+ __drm_atomic_helper_plane_destroy_state(plane->state);
+ kfree(plane->state);
+ plane->state = NULL;
+ }
+
+ vs_state = kzalloc_obj(*vs_state, GFP_KERNEL);
+ if (!vs_state)
+ return;
+
+ __drm_atomic_helper_plane_reset(plane, &vs_state->base);
+}
diff --git a/drivers/gpu/drm/verisilicon/vs_plane.h b/drivers/gpu/drm/verisilicon/vs_plane.h
index 41875ea3d66a..f18c36ef4cd9 100644
--- a/drivers/gpu/drm/verisilicon/vs_plane.h
+++ b/drivers/gpu/drm/verisilicon/vs_plane.h
@@ -63,10 +63,26 @@ struct vs_format {
bool uv_swizzle;
};
-void drm_format_to_vs_format(u32 drm_format, struct vs_format *vs_format);
+struct vs_plane_state {
+ struct drm_plane_state base;
+
+ struct vs_format format;
+};
+
+static inline struct vs_plane_state *to_vs_plane_state(struct drm_plane_state *state)
+{
+ return container_of(state, struct vs_plane_state, base);
+}
+
+int drm_format_to_vs_format(u32 drm_format, struct vs_format *vs_format);
dma_addr_t vs_fb_get_dma_addr(struct drm_framebuffer *fb,
const struct drm_rect *src_rect);
+struct drm_plane_state *vs_plane_duplicate_state(struct drm_plane *plane);
+void vs_plane_destroy_state(struct drm_plane *plane,
+ struct drm_plane_state *state);
+void vs_plane_reset(struct drm_plane *plane);
+
struct drm_plane *vs_primary_plane_init(struct drm_device *dev, struct vs_dc *dc);
#endif /* _VS_PLANE_H_ */
diff --git a/drivers/gpu/drm/verisilicon/vs_primary_plane.c b/drivers/gpu/drm/verisilicon/vs_primary_plane.c
index f3bf18c0e168..1f2be41ae496 100644
--- a/drivers/gpu/drm/verisilicon/vs_primary_plane.c
+++ b/drivers/gpu/drm/verisilicon/vs_primary_plane.c
@@ -25,21 +25,32 @@ static int vs_primary_plane_atomic_check(struct drm_plane *plane,
{
struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
plane);
+ struct vs_plane_state *new_vs_plane_state = to_vs_plane_state(new_plane_state);
+ struct drm_framebuffer *fb = new_plane_state->fb;
struct drm_crtc *crtc = new_plane_state->crtc;
- struct drm_crtc_state *crtc_state;
+ struct drm_crtc_state *crtc_state = NULL;
+ int ret;
- if (!crtc)
+ if (crtc)
+ crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
+
+ ret = drm_atomic_helper_check_plane_state(new_plane_state,
+ crtc_state,
+ DRM_PLANE_NO_SCALING,
+ DRM_PLANE_NO_SCALING,
+ false, true);
+ if (ret)
+ return ret;
+
+ if (!new_plane_state->visible)
return 0;
- crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
- if (WARN_ON(!crtc_state))
- return -EINVAL;
+ ret = drm_format_to_vs_format(fb->format->format,
+ &new_vs_plane_state->format);
+ if (drm_WARN_ON_ONCE(plane->dev, ret))
+ return ret;
- return drm_atomic_helper_check_plane_state(new_plane_state,
- crtc_state,
- DRM_PLANE_NO_SCALING,
- DRM_PLANE_NO_SCALING,
- false, true);
+ return 0;
}
static void vs_primary_plane_commit(struct vs_dc *dc, unsigned int output)
@@ -88,11 +99,11 @@ static void vs_primary_plane_atomic_update(struct drm_plane *plane,
{
struct drm_plane_state *state = drm_atomic_get_new_plane_state(atomic_state,
plane);
+ struct vs_plane_state *vs_state = to_vs_plane_state(state);
struct drm_framebuffer *fb = state->fb;
struct drm_crtc *crtc = state->crtc;
struct vs_dc *dc;
struct vs_crtc *vcrtc;
- struct vs_format fmt;
unsigned int output;
dma_addr_t dma_addr;
@@ -105,16 +116,15 @@ static void vs_primary_plane_atomic_update(struct drm_plane *plane,
output = vcrtc->id;
dc = vcrtc->dc;
- drm_format_to_vs_format(state->fb->format->format, &fmt);
-
regmap_update_bits(dc->regs, VSDC_FB_CONFIG(output),
VSDC_FB_CONFIG_FMT_MASK,
- VSDC_FB_CONFIG_FMT(fmt.color));
+ VSDC_FB_CONFIG_FMT(vs_state->format.color));
regmap_update_bits(dc->regs, VSDC_FB_CONFIG(output),
VSDC_FB_CONFIG_SWIZZLE_MASK,
- VSDC_FB_CONFIG_SWIZZLE(fmt.swizzle));
+ VSDC_FB_CONFIG_SWIZZLE(vs_state->format.swizzle));
regmap_assign_bits(dc->regs, VSDC_FB_CONFIG(output),
- VSDC_FB_CONFIG_UV_SWIZZLE_EN, fmt.uv_swizzle);
+ VSDC_FB_CONFIG_UV_SWIZZLE_EN,
+ vs_state->format.uv_swizzle);
dma_addr = vs_fb_get_dma_addr(fb, &state->src);
@@ -145,10 +155,10 @@ static const struct drm_plane_helper_funcs vs_primary_plane_helper_funcs = {
};
static const struct drm_plane_funcs vs_primary_plane_funcs = {
- .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
- .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+ .atomic_destroy_state = vs_plane_destroy_state,
+ .atomic_duplicate_state = vs_plane_duplicate_state,
.disable_plane = drm_atomic_helper_disable_plane,
- .reset = drm_atomic_helper_plane_reset,
+ .reset = vs_plane_reset,
.update_plane = drm_atomic_helper_update_plane,
};
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
index 1b05dde2bef3..2224d7d91d1b 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
@@ -322,8 +322,6 @@ struct vmw_display_unit {
struct {
struct work_struct crc_generator_work;
- struct hrtimer timer;
- ktime_t period_ns;
/* protects concurrent access to the vblank handler */
atomic_t atomic_lock;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
index cd32b5e35199..af3e32174563 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
@@ -402,6 +402,7 @@ static const struct drm_crtc_helper_funcs vmw_ldu_crtc_helper_funcs = {
.atomic_flush = vmw_vkms_crtc_atomic_flush,
.atomic_enable = vmw_vkms_crtc_atomic_enable,
.atomic_disable = vmw_vkms_crtc_atomic_disable,
+ .handle_vblank_timeout = vmw_vkms_handle_vblank_timeout,
};
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
index b6148e437175..c83061cf7455 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
@@ -797,6 +797,7 @@ static const struct drm_crtc_helper_funcs vmw_sou_crtc_helper_funcs = {
.atomic_flush = vmw_vkms_crtc_atomic_flush,
.atomic_enable = vmw_vkms_crtc_atomic_enable,
.atomic_disable = vmw_sou_crtc_atomic_disable,
+ .handle_vblank_timeout = vmw_vkms_handle_vblank_timeout,
};
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
index 353495739c03..4139837f4caf 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
@@ -1515,6 +1515,7 @@ static const struct drm_crtc_helper_funcs vmw_stdu_crtc_helper_funcs = {
.atomic_flush = vmw_stdu_crtc_atomic_flush,
.atomic_enable = vmw_vkms_crtc_atomic_enable,
.atomic_disable = vmw_stdu_crtc_atomic_disable,
+ .handle_vblank_timeout = vmw_vkms_handle_vblank_timeout,
};
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c
index 1c59dec4c769..7b8163b5e501 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c
@@ -157,27 +157,19 @@ crc_generate_worker(struct work_struct *work)
drm_crtc_add_crc_entry(crtc, true, frame_start++, &crc32);
}
-static enum hrtimer_restart
-vmw_vkms_vblank_simulate(struct hrtimer *timer)
+bool
+vmw_vkms_handle_vblank_timeout(struct drm_crtc *crtc)
{
- struct vmw_display_unit *du = container_of(timer, struct vmw_display_unit, vkms.timer);
- struct drm_crtc *crtc = &du->crtc;
+ struct vmw_display_unit *du = vmw_crtc_to_du(crtc);
struct vmw_private *vmw = vmw_priv(crtc->dev);
bool has_surface = false;
- u64 ret_overrun;
bool locked, ret;
- ret_overrun = hrtimer_forward_now(&du->vkms.timer,
- du->vkms.period_ns);
- if (ret_overrun != 1)
- drm_dbg_driver(crtc->dev, "vblank timer missed %lld frames.\n",
- ret_overrun - 1);
-
locked = vmw_vkms_vblank_trylock(crtc);
ret = drm_crtc_handle_vblank(crtc);
WARN_ON(!ret);
if (!locked)
- return HRTIMER_RESTART;
+ return true;
has_surface = du->vkms.surface != NULL;
vmw_vkms_unlock(crtc);
@@ -200,7 +192,7 @@ vmw_vkms_vblank_simulate(struct hrtimer *timer)
drm_dbg_driver(crtc->dev, "Composer worker already queued\n");
}
- return HRTIMER_RESTART;
+ return true;
}
void
@@ -245,32 +237,12 @@ vmw_vkms_get_vblank_timestamp(struct drm_crtc *crtc,
ktime_t *vblank_time,
bool in_vblank_irq)
{
- struct drm_device *dev = crtc->dev;
- struct vmw_private *vmw = vmw_priv(dev);
- struct vmw_display_unit *du = vmw_crtc_to_du(crtc);
- struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc);
+ struct vmw_private *vmw = vmw_priv(crtc->dev);
if (!vmw->vkms_enabled)
return false;
- if (!READ_ONCE(vblank->enabled)) {
- *vblank_time = ktime_get();
- return true;
- }
-
- *vblank_time = READ_ONCE(du->vkms.timer.node.expires);
-
- if (WARN_ON(*vblank_time == vblank->time))
- return true;
-
- /*
- * To prevent races we roll the hrtimer forward before we do any
- * interrupt processing - this is how real hw works (the interrupt is
- * only generated after all the vblank registers are updated) and what
- * the vblank core expects. Therefore we need to always correct the
- * timestampe by one frame.
- */
- *vblank_time -= du->vkms.period_ns;
+ drm_crtc_vblank_get_vblank_timeout(crtc, vblank_time);
return true;
}
@@ -280,20 +252,11 @@ vmw_vkms_enable_vblank(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
struct vmw_private *vmw = vmw_priv(dev);
- struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc);
- struct vmw_display_unit *du = vmw_crtc_to_du(crtc);
if (!vmw->vkms_enabled)
return -EINVAL;
- drm_calc_timestamping_constants(crtc, &crtc->mode);
-
- hrtimer_setup(&du->vkms.timer, &vmw_vkms_vblank_simulate, CLOCK_MONOTONIC,
- HRTIMER_MODE_REL);
- du->vkms.period_ns = ktime_set(0, vblank->framedur_ns);
- hrtimer_start(&du->vkms.timer, du->vkms.period_ns, HRTIMER_MODE_REL);
-
- return 0;
+ return drm_crtc_vblank_start_timer(crtc);
}
void
@@ -305,9 +268,9 @@ vmw_vkms_disable_vblank(struct drm_crtc *crtc)
if (!vmw->vkms_enabled)
return;
- hrtimer_cancel(&du->vkms.timer);
+ drm_crtc_vblank_cancel_timer(crtc);
+
du->vkms.surface = NULL;
- du->vkms.period_ns = ktime_set(0, 0);
}
enum vmw_vkms_lock_state {
@@ -331,12 +294,15 @@ vmw_vkms_crtc_init(struct drm_crtc *crtc)
void
vmw_vkms_crtc_cleanup(struct drm_crtc *crtc)
{
+ struct vmw_private *vmw = vmw_priv(crtc->dev);
struct vmw_display_unit *du = vmw_crtc_to_du(crtc);
+ if (vmw->vkms_enabled)
+ drm_crtc_vblank_cancel_timer(crtc);
+
if (du->vkms.surface)
vmw_surface_unreference(&du->vkms.surface);
WARN_ON(work_pending(&du->vkms.crc_generator_work));
- hrtimer_cancel(&du->vkms.timer);
}
void
@@ -516,9 +482,13 @@ vmw_vkms_set_crc_surface(struct drm_crtc *crtc,
static inline u64
vmw_vkms_lock_max_wait_ns(struct vmw_display_unit *du)
{
- s64 nsecs = ktime_to_ns(du->vkms.period_ns);
+ struct drm_crtc *crtc = &du->crtc;
+ struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc);
+
+ if (!vblank || !vblank->framedur_ns)
+ return NSEC_PER_SEC / 60; /* disabled; assume 60 Hz */
- return (nsecs > 0) ? nsecs : 16666666;
+ return vblank->framedur_ns;
}
/**
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.h
index 825b31bf8d39..27bc846313ca 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.h
@@ -29,7 +29,6 @@
#ifndef VMWGFX_VKMS_H_
#define VMWGFX_VKMS_H_
-#include <linux/hrtimer_types.h>
#include <linux/types.h>
struct drm_atomic_commit;
@@ -45,6 +44,7 @@ bool vmw_vkms_modeset_lock_relaxed(struct drm_crtc *crtc);
bool vmw_vkms_vblank_trylock(struct drm_crtc *crtc);
void vmw_vkms_unlock(struct drm_crtc *crtc);
+bool vmw_vkms_handle_vblank_timeout(struct drm_crtc *crtc);
bool vmw_vkms_get_vblank_timestamp(struct drm_crtc *crtc,
int *max_error,
ktime_t *vblank_time,
diff --git a/drivers/gpu/drm/xe/xe_sync.c b/drivers/gpu/drm/xe/xe_sync.c
index 24d6d9af20d6..37866768d64c 100644
--- a/drivers/gpu/drm/xe/xe_sync.c
+++ b/drivers/gpu/drm/xe/xe_sync.c
@@ -376,7 +376,7 @@ xe_sync_in_fence_get(struct xe_sync_entry *sync, int num_sync,
xe_assert(vm->xe, current_fence == num_fence);
cf = dma_fence_array_create(num_fence, fences,
dma_fence_context_alloc(1),
- 1, false);
+ 1);
if (!cf)
goto err_out;
diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
index c3836f6eab35..43a578d9c067 100644
--- a/drivers/gpu/drm/xe/xe_vm.c
+++ b/drivers/gpu/drm/xe/xe_vm.c
@@ -3414,7 +3414,7 @@ collect_fences:
xe_assert(vm->xe, current_fence == n_fence);
dma_fence_array_init(cf, n_fence, fences, dma_fence_context_alloc(1),
- 1, false);
+ 1);
fence = &cf->base;
for_each_tile(tile, vm->xe, id) {
diff --git a/drivers/gpu/drm/xlnx/Kconfig b/drivers/gpu/drm/xlnx/Kconfig
index cfabf5e2a0bb..58c19e5a7e8f 100644
--- a/drivers/gpu/drm/xlnx/Kconfig
+++ b/drivers/gpu/drm/xlnx/Kconfig
@@ -3,8 +3,8 @@ config DRM_ZYNQMP_DPSUB
depends on ARCH_ZYNQMP || COMPILE_TEST
depends on COMMON_CLK && DRM && OF
depends on DMADEVICES
- depends on PHY_XILINX_ZYNQMP
- depends on XILINX_ZYNQMP_DPDMA
+ depends on PHY_XILINX_ZYNQMP || COMPILE_TEST
+ depends on XILINX_ZYNQMP_DPDMA || COMPILE_TEST
select DMA_ENGINE
select DRM_CLIENT_SELECTION
select DRM_DISPLAY_DP_HELPER
diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c b/drivers/gpu/drm/xlnx/zynqmp_disp.c
index 9a8f38230cb4..52a0712e39c4 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c
@@ -297,6 +297,36 @@ static const struct zynqmp_disp_format avbuf_vid_fmts[] = {
.buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16CI_420,
.swap = true,
.sf = scaling_factors_888,
+ }, {
+ .drm_fmt = DRM_FORMAT_P030,
+ .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16CI_420_10,
+ .swap = false,
+ .sf = scaling_factors_101010,
+ }, {
+ .drm_fmt = DRM_FORMAT_P230,
+ .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16CI_10,
+ .swap = false,
+ .sf = scaling_factors_101010,
+ }, {
+ .drm_fmt = DRM_FORMAT_Y8,
+ .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_MONO,
+ .swap = false,
+ .sf = scaling_factors_888,
+ }, {
+ .drm_fmt = DRM_FORMAT_XYYY2101010,
+ .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YONLY_10,
+ .swap = false,
+ .sf = scaling_factors_101010,
+ }, {
+ .drm_fmt = DRM_FORMAT_T430,
+ .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV24_10,
+ .swap = false,
+ .sf = scaling_factors_101010,
+ }, {
+ .drm_fmt = DRM_FORMAT_XVUY2101010,
+ .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YUV444_10,
+ .swap = false,
+ .sf = scaling_factors_101010,
},
};
@@ -687,6 +717,17 @@ static const u32 csc_sdtv_to_rgb_offsets[] = {
0x0, 0x1800, 0x1800
};
+/* In Y-only mode the single Y channel is on the third column */
+static const u16 csc_sdtv_to_rgb_yonly_matrix[] = {
+ 0x0, 0x0, 0x1000,
+ 0x0, 0x0, 0x1000,
+ 0x0, 0x0, 0x1000,
+};
+
+static const u32 csc_sdtv_to_rgb_yonly_offsets[] = {
+ 0x0, 0x0, 0x0
+};
+
/**
* zynqmp_disp_blend_set_output_format - Set the output format of the blender
* @disp: Display controller
@@ -836,7 +877,11 @@ static void zynqmp_disp_blend_layer_enable(struct zynqmp_disp *disp,
ZYNQMP_DISP_V_BLEND_LAYER_CONTROL(layer->id),
val);
- if (layer->drm_fmt->is_yuv) {
+ if (layer->drm_fmt->format == DRM_FORMAT_Y8 ||
+ layer->drm_fmt->format == DRM_FORMAT_XYYY2101010) {
+ coeffs = csc_sdtv_to_rgb_yonly_matrix;
+ offsets = csc_sdtv_to_rgb_yonly_offsets;
+ } else if (layer->drm_fmt->is_yuv) {
coeffs = csc_sdtv_to_rgb_matrix;
offsets = csc_sdtv_to_rgb_offsets;
} else {
@@ -1116,16 +1161,19 @@ int zynqmp_disp_layer_update(struct zynqmp_disp_layer *layer,
return 0;
for (i = 0; i < info->num_planes; i++) {
- unsigned int width = state->crtc_w / (i ? info->hsub : 1);
- unsigned int height = state->crtc_h / (i ? info->vsub : 1);
struct zynqmp_disp_layer_dma *dma = &layer->dmas[i];
struct dma_async_tx_descriptor *desc;
dma_addr_t dma_addr;
+ unsigned int width;
+ unsigned int height;
+
+ width = drm_format_info_plane_width(info, state->crtc_w, i);
+ height = drm_format_info_plane_height(info, state->crtc_h, i);
dma_addr = drm_fb_dma_get_gem_addr(state->fb, state, i);
dma->xt.numf = height;
- dma->sgl.size = width * info->cpp[i];
+ dma->sgl.size = drm_format_info_min_pitch(info, i, width);
dma->sgl.icg = state->fb->pitches[i] - dma->sgl.size;
dma->xt.src_start = dma_addr;
dma->xt.frame_size = 1;
diff --git a/drivers/gpu/drm/xlnx/zynqmp_kms.c b/drivers/gpu/drm/xlnx/zynqmp_kms.c
index dcb2fff54b63..d5f922450565 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_kms.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_kms.c
@@ -453,12 +453,6 @@ static int zynqmp_dpsub_kms_init(struct zynqmp_dpsub *dpsub)
goto err_encoder;
}
- ret = drm_connector_attach_encoder(connector, encoder);
- if (ret < 0) {
- dev_err(dpsub->dev, "failed to attach connector to encoder\n");
- goto err_encoder;
- }
-
return 0;
err_encoder:
diff --git a/include/drm/drm_debugfs_crc.h b/include/drm/drm_debugfs_crc.h
index 1b4c98c2f838..1cb71c03bf44 100644
--- a/include/drm/drm_debugfs_crc.h
+++ b/include/drm/drm_debugfs_crc.h
@@ -49,7 +49,7 @@ struct drm_crtc_crc_entry {
* @lock: protects the fields in this struct
* @source: name of the currently configured source of CRCs
* @opened: whether userspace has opened the data file for reading
- * @overflow: whether an overflow occured.
+ * @overflow: whether an overflow occurred
* @entries: array of entries, with size of %DRM_CRC_ENTRIES_NR
* @head: head of circular queue
* @tail: tail of circular queue
diff --git a/include/drm/drm_gpusvm.h b/include/drm/drm_gpusvm.h
index cd94bb2ee6ee..8a4d7134a9a7 100644
--- a/include/drm/drm_gpusvm.h
+++ b/include/drm/drm_gpusvm.h
@@ -140,12 +140,7 @@ struct drm_gpusvm_pages_flags {
* @state: DMA IOVA state for mapping.
* @state_offset: DMA IOVA offset for mapping.
* @notifier_seq: Notifier sequence number of the range's pages
- * @flags: Flags for range
- * @flags.migrate_devmem: Flag indicating whether the range can be migrated to device memory
- * @flags.unmapped: Flag indicating if the range has been unmapped
- * @flags.partial_unmap: Flag indicating if the range has been partially unmapped
- * @flags.has_devmem_pages: Flag indicating if the range has devmem pages
- * @flags.has_dma_mapping: Flag indicating if the range has a DMA mapping
+ * @flags: Flags for the range; see &struct drm_gpusvm_pages_flags
*/
struct drm_gpusvm_pages {
struct drm_pagemap_addr *dma_addr;
diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h
index 2ab651a36115..b429acde4f71 100644
--- a/include/drm/drm_mipi_dsi.h
+++ b/include/drm/drm_mipi_dsi.h
@@ -393,6 +393,7 @@ void mipi_dsi_dcs_set_page_address_multi(struct mipi_dsi_multi_context *ctx,
void mipi_dsi_dcs_set_tear_scanline_multi(struct mipi_dsi_multi_context *ctx,
u16 scanline);
void mipi_dsi_dcs_set_tear_off_multi(struct mipi_dsi_multi_context *ctx);
+void mipi_dsi_shutdown_peripheral_multi(struct mipi_dsi_multi_context *ctx);
/**
* mipi_dsi_generic_write_seq_multi - transmit data using a generic write packet
diff --git a/include/linux/dma-fence-array.h b/include/linux/dma-fence-array.h
index 370b3d2bba37..1b1d87579c38 100644
--- a/include/linux/dma-fence-array.h
+++ b/include/linux/dma-fence-array.h
@@ -81,13 +81,11 @@ to_dma_fence_array(struct dma_fence *fence)
struct dma_fence_array *dma_fence_array_alloc(int num_fences);
void dma_fence_array_init(struct dma_fence_array *array,
int num_fences, struct dma_fence **fences,
- u64 context, unsigned seqno,
- bool signal_on_any);
+ u64 context, unsigned seqno);
struct dma_fence_array *dma_fence_array_create(int num_fences,
struct dma_fence **fences,
- u64 context, unsigned seqno,
- bool signal_on_any);
+ u64 context, unsigned seqno);
bool dma_fence_match_context(struct dma_fence *fence, u64 context);
diff --git a/include/trace/events/amdxdna.h b/include/trace/events/amdxdna.h
index c6cb2da7b706..71da24267e52 100644
--- a/include/trace/events/amdxdna.h
+++ b/include/trace/events/amdxdna.h
@@ -30,26 +30,30 @@ TRACE_EVENT(amdxdna_debug_point,
);
TRACE_EVENT(xdna_job,
- TP_PROTO(struct drm_sched_job *sched_job, const char *name, const char *str, u64 seq),
+ TP_PROTO(struct drm_sched_job *sched_job, const char *name,
+ const char *str, u64 seq, u32 op),
- TP_ARGS(sched_job, name, str, seq),
+ TP_ARGS(sched_job, name, str, seq, op),
TP_STRUCT__entry(__string(name, name)
__string(str, str)
__field(u64, fence_context)
__field(u64, fence_seqno)
- __field(u64, seq)),
+ __field(u64, seq)
+ __field(u32, op)),
TP_fast_assign(__assign_str(name);
__assign_str(str);
__entry->fence_context = sched_job->s_fence->finished.context;
__entry->fence_seqno = sched_job->s_fence->finished.seqno;
- __entry->seq = seq;),
+ __entry->seq = seq;
+ __entry->op = op;),
- TP_printk("fence=(context:%llu, seqno:%lld), %s seq#:%lld %s",
+ TP_printk("fence=(context:%llu, seqno:%llu), %s seq#:%llu %s, op=%u",
__entry->fence_context, __entry->fence_seqno,
__get_str(name), __entry->seq,
- __get_str(str))
+ __get_str(str),
+ __entry->op)
);
DECLARE_EVENT_CLASS(xdna_mbox_msg,
@@ -81,18 +85,28 @@ DEFINE_EVENT(xdna_mbox_msg, mbox_set_head,
TP_ARGS(name, chann_id, opcode, id)
);
-TRACE_EVENT(mbox_irq_handle,
- TP_PROTO(char *name, int irq),
+DECLARE_EVENT_CLASS(xdna_mbox_name_id,
+ TP_PROTO(char *name, int irq),
- TP_ARGS(name, irq),
+ TP_ARGS(name, irq),
- TP_STRUCT__entry(__string(name, name)
- __field(int, irq)),
+ TP_STRUCT__entry(__string(name, name)
+ __field(int, irq)),
- TP_fast_assign(__assign_str(name);
- __entry->irq = irq;),
+ TP_fast_assign(__assign_str(name);
+ __entry->irq = irq;),
+
+ TP_printk("%s.%d", __get_str(name), __entry->irq)
+);
+
+DEFINE_EVENT(xdna_mbox_name_id, mbox_irq_handle,
+ TP_PROTO(char *name, int irq),
+ TP_ARGS(name, irq)
+);
- TP_printk("%s.%d", __get_str(name), __entry->irq)
+DEFINE_EVENT(xdna_mbox_name_id, mbox_rx_worker,
+ TP_PROTO(char *name, int irq),
+ TP_ARGS(name, irq)
);
#endif /* !defined(_TRACE_AMDXDNA_H) || defined(TRACE_HEADER_MULTI_READ) */
diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h
index 495462e44a17..bc7ef7684099 100644
--- a/include/uapi/drm/drm.h
+++ b/include/uapi/drm/drm.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: MIT */
/*
* Header for the Direct Rendering Manager
*
@@ -11,25 +12,6 @@
* Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
* All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _DRM_H_
diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h
index ac66fa93b5a3..15aa0a8f44b0 100644
--- a/include/uapi/drm/drm_fourcc.h
+++ b/include/uapi/drm/drm_fourcc.h
@@ -1,24 +1,6 @@
+/* SPDX-License-Identifier: MIT */
/*
* Copyright 2011 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef DRM_FOURCC_H
@@ -264,6 +246,7 @@ extern "C" {
#define DRM_FORMAT_XVUY8888 fourcc_code('X', 'V', 'U', 'Y') /* [31:0] X:Cr:Cb:Y 8:8:8:8 little endian */
#define DRM_FORMAT_VUY888 fourcc_code('V', 'U', '2', '4') /* [23:0] Cr:Cb:Y 8:8:8 little endian */
#define DRM_FORMAT_VUY101010 fourcc_code('V', 'U', '3', '0') /* Y followed by U then V, 10:10:10. Non-linear modifier only */
+#define DRM_FORMAT_XVUY2101010 fourcc_code('X', 'Y', '3', '0') /* [31:0] x:Cr:Cb:Y 2:10:10:10 little endian */
/*
* packed Y2xx indicate for each component, xx valid data occupy msb
@@ -379,6 +362,14 @@ extern "C" {
*/
#define DRM_FORMAT_P030 fourcc_code('P', '0', '3', '0') /* 2x2 subsampled Cr:Cb plane 10 bits per channel packed */
+/*
+ * 2 plane YCbCr422.
+ * 3 10 bit components and 2 padding bits packed into 4 bytes.
+ * index 0 = Y plane, [31:0] x:Y2:Y1:Y0 2:10:10:10 little endian
+ * index 1 = Cr:Cb plane, [63:0] x:Cr2:Cb2:Cr1:x:Cb1:Cr0:Cb0 [2:10:10:10:2:10:10:10] little endian
+ */
+#define DRM_FORMAT_P230 fourcc_code('P', '2', '3', '0') /* 2x1 subsampled Cr:Cb plane 10 bits per channel packed */
+
/* 3 plane non-subsampled (444) YCbCr
* 16 bits per component, but only 10 bits are used and 6 bits are padded
* index 0: Y plane, [15:0] Y:x [10:6] little endian
@@ -396,6 +387,15 @@ extern "C" {
#define DRM_FORMAT_Q401 fourcc_code('Q', '4', '0', '1')
/*
+ * 3 plane non-subsampled (444) YCbCr LSB aligned
+ * 10 bpc, 30 bits per sample image data in a single contiguous buffer.
+ * index 0: Y plane, [31:0] x:Y2:Y1:Y0 [2:10:10:10] little endian
+ * index 1: Cb plane, [31:0] x:Cb2:Cb1:Cb0 [2:10:10:10] little endian
+ * index 2: Cr plane, [31:0] x:Cr2:Cr1:Cr0 [2:10:10:10] little endian
+ */
+#define DRM_FORMAT_T430 fourcc_code('T', '4', '3', '0')
+
+/*
* 3 plane YCbCr LSB aligned
* In order to use these formats in a similar fashion to MSB aligned ones
* implementation can multiply the values by 2^6=64. For that reason the padding
@@ -451,6 +451,16 @@ extern "C" {
#define DRM_FORMAT_YUV444 fourcc_code('Y', 'U', '2', '4') /* non-subsampled Cb (1) and Cr (2) planes */
#define DRM_FORMAT_YVU444 fourcc_code('Y', 'V', '2', '4') /* non-subsampled Cr (1) and Cb (2) planes */
+/*
+ * Y-only (greyscale) formats
+ *
+ * The Y-only formats are handled similarly to the YCbCr formats in the display
+ * pipeline, with the Cb and Cr implicitly neutral (0.0 in nominal values). This
+ * also means that COLOR_RANGE property applies to the Y-only formats.
+ */
+
+#define DRM_FORMAT_Y8 fourcc_code('G', 'R', 'E', 'Y') /* 8-bit Y-only */
+#define DRM_FORMAT_XYYY2101010 fourcc_code('Y', 'P', 'A', '4') /* [31:0] x:Y2:Y1:Y0 2:10:10:10 little endian */
/*
* Format Modifiers:
diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
index a4bdc4bd11bc..381a3e857d4e 100644
--- a/include/uapi/drm/drm_mode.h
+++ b/include/uapi/drm/drm_mode.h
@@ -1,27 +1,10 @@
+/* SPDX-License-Identifier: MIT */
/*
* Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
* Copyright (c) 2007 Jakob Bornecrantz <wallbraker@gmail.com>
* Copyright (c) 2008 Red Hat Inc.
* Copyright (c) 2007-2008 Tungsten Graphics, Inc., Cedar Park, TX., USA
* Copyright (c) 2007-2008 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
*/
#ifndef _DRM_MODE_H
diff --git a/include/uapi/drm/drm_sarea.h b/include/uapi/drm/drm_sarea.h
index a951ced60ebe..1e38d028332d 100644
--- a/include/uapi/drm/drm_sarea.h
+++ b/include/uapi/drm/drm_sarea.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: MIT */
/**
* \file drm_sarea.h
* \brief SAREA definitions
@@ -8,25 +9,6 @@
/*
* Copyright 2002 Tungsten Graphics, Inc., Cedar Park, Texas.
* All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _DRM_SAREA_H_