mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 01:32:21 +02:00
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. -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEuXvWqAysSYEJGuVH/lWMcqZwE8MFAmn8fBIACgkQ/lWMcqZw E8OlSw/+JbotgRTp5I3EwGtOiUoEZF1n20vkwZ5+olbEhP5wVft+Kf5MbD2/Hmja GEL/3lxXgbvA1QOXFsED+q5UlKwtmEb3jTj+K83CXZ/YHT8Fk+lFCpNR3dGWWpal 3CAk+Xe2MYdhBe4Sce04rKYfI7D7R2p1xrvfGDO/4Z1WicI1P2BhgV+6K2buhNJ3 2FOFRLTQaBdUa/52PgP45lEvQveI5E2UHyjOk2dDEU/uE6JeMHOQzk4d/1VFY+6s hjgC5Mzw1eRZeX3LgSsSaCZ4/vKOXUg950oMAbmGeucyPoIm2+dOt6k/bRMTolJt wXDGmh69dJliHm5801riqaEBWwMV0JEt3WBcqAiNycIAitsjf9jACkWMfoXz03At 34qTWxWReXaQXL32ooFD2ZIZhiBSNNbZu50P5xhOAcE2F0siPH8dLSSaamSEKX5P T+gklhoXnMljgBz/wRKW5oUC1EQrylsc2C3/vvXHopYDPFhHZ77v1m33x5mXu8jn XvUPjMIIx62dBueGtYcODQEOhfvweeg+XWUJ0uJ1SDfqtTDjkw2oEnNqEbYOwaIF BR8YjQn3QI5FAFt9VbilQ9lL7XBGgjT4kV8iX4qGedSwKLAzu/b+P3FyTtvNnY71 vYldKKmhVogzHO97JzVvWq3l6H6dush1REgprGCDAISUesk55g4= =kWIv -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
f96538285c
30
Documentation/ABI/obsolete/sysfs-driver-ivpu
Normal file
30
Documentation/ABI/obsolete/sysfs-driver-ivpu
Normal file
|
|
@ -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
|
||||
65
Documentation/ABI/testing/sysfs-driver-ivpu
Normal file
65
Documentation/ABI/testing/sysfs-driver-ivpu
Normal file
|
|
@ -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.
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ properties:
|
|||
- algoltek,ag6311
|
||||
- asl-tek,cs5263
|
||||
- dumb-vga-dac
|
||||
- mstar,tsumu88adt3-lf-1
|
||||
- parade,ps185hdm
|
||||
- radxa,ra620
|
||||
- realtek,rtd2171
|
||||
|
|
|
|||
|
|
@ -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>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
...
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,.*":
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
13
MAINTAINERS
13
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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 @@ aie2_sched_job_run(struct drm_sched_job *sched_job)
|
|||
} 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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
280
drivers/accel/amdxdna/amdxdna_cbuf.c
Normal file
280
drivers/accel/amdxdna/amdxdna_cbuf.c
Normal file
|
|
@ -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);
|
||||
}
|
||||
18
drivers/accel/amdxdna/amdxdna_cbuf.h
Normal file
18
drivers/accel/amdxdna/amdxdna_cbuf.h
Normal file
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
129
drivers/accel/amdxdna/amdxdna_debugfs.c
Normal file
129
drivers/accel/amdxdna/amdxdna_debugfs.c
Normal file
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
18
drivers/accel/amdxdna/amdxdna_debugfs.h
Normal file
18
drivers/accel/amdxdna/amdxdna_debugfs.h
Normal file
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -307,18 +307,6 @@ 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);
|
||||
|
||||
if (enable)
|
||||
val = REG_SET_FLD(VPU_40XX_HOST_SS_AON_PWR_ISLAND_EN0, CSS_CPU, val);
|
||||
else
|
||||
val = REG_CLR_FLD(VPU_40XX_HOST_SS_AON_PWR_ISLAND_EN0, CSS_CPU, val);
|
||||
|
||||
REGV_WR32(VPU_40XX_HOST_SS_AON_PWR_ISLAND_EN0, val);
|
||||
}
|
||||
|
||||
static void pwr_island_drive_40xx(struct ivpu_device *vdev, bool enable)
|
||||
{
|
||||
u32 val = REGV_RD32(VPU_37XX_HOST_SS_AON_PWR_ISLAND_EN0);
|
||||
|
||||
|
|
@ -330,6 +318,18 @@ static void pwr_island_drive_40xx(struct ivpu_device *vdev, bool enable)
|
|||
REGV_WR32(VPU_37XX_HOST_SS_AON_PWR_ISLAND_EN0, val);
|
||||
}
|
||||
|
||||
static void pwr_island_drive_40xx(struct ivpu_device *vdev, bool enable)
|
||||
{
|
||||
u32 val = REGV_RD32(VPU_40XX_HOST_SS_AON_PWR_ISLAND_EN0);
|
||||
|
||||
if (enable)
|
||||
val = REG_SET_FLD(VPU_40XX_HOST_SS_AON_PWR_ISLAND_EN0, CSS_CPU, val);
|
||||
else
|
||||
val = REG_CLR_FLD(VPU_40XX_HOST_SS_AON_PWR_ISLAND_EN0, CSS_CPU, val);
|
||||
|
||||
REGV_WR32(VPU_40XX_HOST_SS_AON_PWR_ISLAND_EN0, val);
|
||||
}
|
||||
|
||||
static void pwr_island_enable(struct ivpu_device *vdev)
|
||||
{
|
||||
if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*
|
||||
* The npu_max_frequency shows maximum frequency in MHz of the NPU's data
|
||||
* processing unit
|
||||
* 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.
|
||||
*
|
||||
* 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
|
||||
npu_max_frequency_mhz_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
|
||||
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 = ivpu_hw_dpu_max_freq_get(vdev);
|
||||
u32 freq_mhz = ivpu_hw_btrs_pll_ratio_to_mhz(vdev, vdev->hw->pll.min_ratio);
|
||||
|
||||
return sysfs_emit(buf, "%lu\n", freq / HZ_PER_MHZ);
|
||||
return sysfs_emit(buf, "%u\n", freq_mhz);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RO(npu_max_frequency_mhz);
|
||||
static DEVICE_ATTR_RO(hw_min_freq);
|
||||
|
||||
/**
|
||||
* 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)
|
||||
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 = 0;
|
||||
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
|
||||
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_mhz;
|
||||
int ret;
|
||||
|
||||
ret = kstrtou32(buf, 10, &freq_mhz);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ivpu_hw_btrs_cfg_min_freq_set(vdev, freq_mhz);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
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_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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -604,6 +604,16 @@ enum vpu_ipc_msg_type {
|
|||
* This command has no payload
|
||||
*/
|
||||
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.
|
||||
|
|
@ -766,6 +776,11 @@ enum vpu_ipc_msg_type {
|
|||
* This command has no payload
|
||||
*/
|
||||
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.
|
||||
|
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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]);
|
||||
|
|
|
|||
|
|
@ -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]);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -270,6 +270,11 @@ static const struct of_device_id simple_bridge_match[] = {
|
|||
.data = &(const struct simple_bridge_info) {
|
||||
.connector_type = DRM_MODE_CONNECTOR_HDMIA,
|
||||
},
|
||||
}, {
|
||||
.compatible = "mstar,tsumu88adt3-lf-1",
|
||||
.data = &(const struct simple_bridge_info) {
|
||||
.connector_type = DRM_MODE_CONNECTOR_HDMIA,
|
||||
},
|
||||
}, {
|
||||
.compatible = "parade,ps185hdm",
|
||||
.data = &(const struct simple_bridge_info) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
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, mask, 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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -93,18 +93,6 @@ void etnaviv_gem_describe_objects(struct etnaviv_drm_private *priv,
|
|||
#define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
|
||||
#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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
333
drivers/gpu/drm/panel/panel-chipwealth-ch13726a.c
Normal file
333
drivers/gpu/drm/panel/panel-chipwealth-ch13726a.c
Normal file
|
|
@ -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");
|
||||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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 },
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user