drm-misc-next for v7.1:

UAPI Changes:
 
 amdxdna:
 - Add sensors ioctls
 
 Cross-subsystem Changes:
 
 dma-buf:
 - clean pages with helpers
 
 Documenatation:
 - devicetree: Add lxd vendor prefix
 
 Core Changes:
 
 buddy:
 - improve aligned allocations
 
 gem-shmem:
 - Track page accessed/dirty status across mmap/vmap
 
 ttm:
 - fix fence signalling
 
 Driver Changes:
 
 amdxdna:
 - provide NPU power estimate
 - support sensor for column utilization
 
 bridge:
 - anx7625: Fix USB Type-C handling
 - cdns-mhdp8546-core: Handle HDCP state in bridge atomic_check
 
 ivpu:
 - fixes
 
 loongson:
 - replace custom code with drm_gem_ttm_dumb_map_offset()
 
 mxsfb:
 - lcdif: report probing errors with dev_err_probe()
 
 panel:
 - ilitek-ili9882t: Allow GPIO calls to sleep
 - jadard: Support TAIGUAN XTI05101-01A
 - lxd: Support LXD M9189A plus DT bindings
 - mantix: Fix pixel clock; Clean up
 - motorola: Support Motorola Atrix 4G and Droid X2 plus DT bindings
 - novatek: Support Novatek/Tianma NT37700F plus DT bindings
 - renesas: Clean up
 - simple: Support EDT ET057023UDBA plus DT bindings; Support Powertip
   PH800480T032-ZHC19 plus DT bindings; Support Waveshare 13.3"
   - clean up DT bindings of various drivers
 
 panthor:
 - fix fence handling
 
 vc4:
 - check return value of platform_get_irq_byname()
 -----BEGIN PGP SIGNATURE-----
 
 iQFPBAABCgA5FiEEchf7rIzpz2NEoWjlaA3BHVMLeiMFAmmycX0bFIAAAAAABAAO
 bWFudTIsMi41KzEuMTIsMiwyAAoJEGgNwR1TC3ojt1cH/1OoLz0cc0wZ0VM/f8t/
 Ha81Ff4mVOS5j2x3V0m+SZrljKl4qgfTka6CYfhHn9aqVS27pkB2My4vtq6h3EXQ
 apfKIqhgMjVpJxin9fbSb29JGt+/NtuUEFbq+s356SF2L5RZ8fGEWmdETsNfItvj
 lLZOkvys/9MWRyCjO4pOD6kyJul2Bg+79hJ1H3IdE62WNyVM1FNVcMWIBsWdigBG
 o5wJv+RQ9sffD7zNiw122AI+Zr+elCeXekqMZghIP8Su+JkjfEMsr0AGpsqpvFbJ
 TsdFR52ZZR4fEzwZZnrn4gTGN3xPSUIpWcSXrOkm7gp5d4ZVE/X9diavrzJFb0vg
 uM8=
 =TJlw
 -----END PGP SIGNATURE-----

Merge tag 'drm-misc-next-2026-03-12' of https://gitlab.freedesktop.org/drm/misc/kernel into drm-next

drm-misc-next for v7.1:

UAPI Changes:

amdxdna:
- Add sensors ioctls

Cross-subsystem Changes:

dma-buf:
- clean pages with helpers

Documenatation:
- devicetree: Add lxd vendor prefix

Core Changes:

buddy:
- improve aligned allocations

gem-shmem:
- Track page accessed/dirty status across mmap/vmap

ttm:
- fix fence signalling

Driver Changes:

amdxdna:
- provide NPU power estimate
- support sensor for column utilization

bridge:
- anx7625: Fix USB Type-C handling
- cdns-mhdp8546-core: Handle HDCP state in bridge atomic_check

ivpu:
- fixes

loongson:
- replace custom code with drm_gem_ttm_dumb_map_offset()

mxsfb:
- lcdif: report probing errors with dev_err_probe()

panel:
- ilitek-ili9882t: Allow GPIO calls to sleep
- jadard: Support TAIGUAN XTI05101-01A
- lxd: Support LXD M9189A plus DT bindings
- mantix: Fix pixel clock; Clean up
- motorola: Support Motorola Atrix 4G and Droid X2 plus DT bindings
- novatek: Support Novatek/Tianma NT37700F plus DT bindings
- renesas: Clean up
- simple: Support EDT ET057023UDBA plus DT bindings; Support Powertip
  PH800480T032-ZHC19 plus DT bindings; Support Waveshare 13.3"
  - clean up DT bindings of various drivers

panthor:
- fix fence handling

vc4:
- check return value of platform_get_irq_byname()

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

From: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://patch.msgid.link/20260312075629.GA21234@linux.fritz.box
This commit is contained in:
Dave Airlie 2026-03-15 07:53:05 +10:00
commit d9a4a2021d
84 changed files with 2397 additions and 565 deletions

View File

@ -844,6 +844,12 @@ properties:
- google,sargo
- const: qcom,sdm670
- items:
- enum:
- google,bonito-tianma
- const: google,bonito
- const: qcom,sdm670
- items:
- enum:
- qcom,sdx55-mtp

View File

@ -20,11 +20,6 @@ properties:
reg:
maxItems: 1
backlight: true
port: true
power-supply: true
reset-gpios: true
required:
- compatible
- reg

View File

@ -41,8 +41,6 @@ properties:
panel-timing: true
port: true
additionalProperties: false
required:
- compatible
- data-mapping
@ -51,6 +49,8 @@ required:
- panel-timing
- port
additionalProperties: false
examples:
- |+
panel {

View File

@ -56,8 +56,6 @@ properties:
- port@0
- port@1
additionalProperties: false
required:
- compatible
- width-mm
@ -65,6 +63,8 @@ required:
- data-mapping
- panel-timing
additionalProperties: false
examples:
- |+
panel-lvds {

View File

@ -22,10 +22,10 @@ properties:
enable-gpios: true
port: true
additionalProperties: false
required:
- compatible
- power-supply
additionalProperties: false
...

View File

@ -22,10 +22,10 @@ properties:
backlight: true
port: true
additionalProperties: false
required:
- compatible
- power-supply
additionalProperties: false
...

View File

@ -33,8 +33,6 @@ properties:
vsp-supply:
description: Negative source voltage rail
port: true
required:
- compatible
- reg

View File

@ -54,8 +54,6 @@ required:
- vcc-supply
- iovcc-supply
additionalProperties: false
allOf:
- $ref: panel-common.yaml#
- if:
@ -68,6 +66,8 @@ allOf:
required:
- reset-gpios
additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>

View File

@ -34,10 +34,6 @@ properties:
maxItems: 1
description: Display data/command selection (D/CX)
backlight: true
reset-gpios: true
rotation: true
required:
- compatible
- reg

View File

@ -29,9 +29,6 @@ properties:
reg:
maxItems: 1
reset-gpios: true
port: true
vcc-supply:
description: Core voltage supply

View File

@ -40,8 +40,6 @@ properties:
spi-max-frequency:
const: 10000000
port: true
vci-supply:
description: Analog voltage supply (2.5 .. 3.3V)
@ -51,8 +49,6 @@ properties:
vddi-led-supply:
description: Voltage supply for the LED driver (1.65 .. 3.3 V)
unevaluatedProperties: false
required:
- compatible
- reg
@ -68,6 +64,8 @@ then:
required:
- port
unevaluatedProperties: false
examples:
- |+
#include <dt-bindings/gpio/gpio.h>

View File

@ -20,11 +20,6 @@ properties:
reg:
maxItems: 1
backlight: true
port: true
power-supply: true
reset-gpios: true
required:
- compatible
- reg

View File

@ -10,7 +10,7 @@ maintainers:
- Lin Huang <hl@rock-chips.com>
allOf:
- $ref: panel-common.yaml#
- $ref: panel-common-dual.yaml#
properties:
compatible:
@ -28,6 +28,9 @@ properties:
avee-supply:
description: The regulator that provides negative voltage
port: true
ports: true
required:
- compatible
- reg
@ -52,6 +55,27 @@ examples:
avee-supply = <&avee>;
backlight = <&backlight>;
enable-gpios = <&gpio1 13 GPIO_ACTIVE_HIGH>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
mipi_in_panel: endpoint {
remote-endpoint = <&mipi_out_panel>;
};
};
port@1 {
reg = <1>;
mipi1_in_panel: endpoint {
remote-endpoint = <&mipi1_out_panel>;
};
};
};
};
};

View File

@ -23,6 +23,7 @@ properties:
- melfas,lmfbx101117480
- radxa,display-10hd-ad001
- radxa,display-8hd-ad002
- taiguanck,xti05101-01a
- const: jadard,jd9365da-h3
reg:
@ -35,9 +36,8 @@ properties:
description: supply regulator for VCCIO, usually 1.8V
reset-gpios: true
backlight: true
rotation: true
port: true
required:

View File

@ -20,11 +20,6 @@ properties:
reg:
maxItems: 1
backlight: true
port: true
power-supply: true
reset-gpios: true
spi-3wire: true
required:

View File

@ -20,10 +20,6 @@ properties:
reg:
maxItems: 1
label: true
enable-gpios: true
port: true
spi-cpha: true
spi-cpol: true

View File

@ -0,0 +1,64 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/panel/lxd,m9189a.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: LXD M9189A DSI Display Panel
maintainers:
- Michael Tretter <m.tretter@pengutronix.de>
allOf:
- $ref: panel-common.yaml
properties:
compatible:
const: lxd,m9189a
reg:
maxItems: 1
standby-gpios:
description: GPIO used for the standby pin
maxItems: 1
reset-gpios: true
power-supply: true
backlight: true
port: true
required:
- compatible
- reg
- standby-gpios
- reset-gpios
- power-supply
- backlight
- port
additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
dsi {
#address-cells = <1>;
#size-cells = <0>;
panel@0 {
compatible = "lxd,m9189a";
reg = <0>;
backlight = <&backlight>;
reset-gpios = <&gpio3 25 GPIO_ACTIVE_LOW>;
standby-gpios = <&gpio5 22 GPIO_ACTIVE_LOW>;
power-supply = <&reg_display_3v3>;
port {
mipi_panel_in: endpoint {
remote-endpoint = <&mipi_dsi_out>;
};
};
};
};

View File

@ -47,8 +47,6 @@ properties:
panel-timing: true
port: true
additionalProperties: false
required:
- compatible
- data-mapping
@ -57,6 +55,8 @@ required:
- panel-timing
- port
additionalProperties: false
examples:
- |+

View File

@ -44,8 +44,6 @@ properties:
panel-timing: true
port: true
additionalProperties: false
required:
- compatible
- vcc-supply
@ -55,6 +53,8 @@ required:
- panel-timing
- port
additionalProperties: false
examples:
- |+
panel {

View File

@ -0,0 +1,69 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/panel/motorola,mot-panel.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Atrix 4G and Droid X2 DSI Display Panel
maintainers:
- Svyatoslav Ryhel <clamor95@gmail.com>
description:
Atrix 4G and Droid X2 use the same 540x960 DSI video mode panel. Exact
panel vendor and model are unknown hence generic compatible based on the
board name "Mot" is used.
allOf:
- $ref: panel-common.yaml#
properties:
compatible:
items:
- const: motorola,mot-panel
reg:
maxItems: 1
vdd-supply:
description: Regulator for main power supply.
vddio-supply:
description: Regulator for 1.8V IO power supply.
backlight: true
reset-gpios: true
port: true
required:
- compatible
additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
dsi {
#address-cells = <1>;
#size-cells = <0>;
panel@0 {
compatible = "motorola,mot-panel";
reg = <0>;
reset-gpios = <&gpio 35 GPIO_ACTIVE_LOW>;
vdd-supply = <&vdd_5v0_panel>;
vddio-supply = <&vdd_1v8_vio>;
backlight = <&backlight>;
port {
panel_in: endpoint {
remote-endpoint = <&dsi_out>;
};
};
};
};
...

View File

@ -24,10 +24,6 @@ properties:
reg:
maxItems: 1
label: true
port: true
reset-gpios: true
spi-max-frequency:
maximum: 10000000

View File

@ -37,9 +37,6 @@ properties:
vddio-supply:
description: regulator that supplies the I/O voltage
rotation: true
backlight: true
required:
- compatible
- reg

View File

@ -47,9 +47,6 @@ properties:
vddneg-supply:
description: phandle of the negative boost supply regulator
port: true
backlight: true
required:
- compatible
- reg

View File

@ -31,12 +31,12 @@ properties:
reset-gpios:
maxItems: 1
additionalProperties: false
required:
- compatible
- reg
additionalProperties: false
examples:
- |
dsi {

View File

@ -49,6 +49,8 @@ properties:
- lg,lh500wx1-sd03
# Lincoln LCD197 5" 1080x1920 LCD panel
- lincolntech,lcd197
# Novatek NT37700F 1080x2160 AMOLED panel
- novatek,nt37700f
# One Stop Displays OSD101T2587-53TS 10.1" 1920x1200 panel
- osddisplays,osd101t2587-53ts
# Panasonic 10" WUXGA TFT LCD panel

View File

@ -103,6 +103,8 @@ properties:
- dlc,dlc1010gig
# Emerging Display Technology Corp. 3.5" QVGA TFT LCD panel
- edt,et035012dm6
# Emerging Display Technology Corp. 5.7" 24-bit VGA TFT LCD panel
- edt,et057023udba
# Emerging Display Technology Corp. 5.7" VGA TFT LCD panel
- edt,et057090dhu
- edt,et070080dh6
@ -266,6 +268,8 @@ properties:
- powertip,ph128800t006-zhc01
# POWERTIP PH800480T013-IDF2 7.0" WVGA TFT LCD panel
- powertip,ph800480t013-idf02
# POWERTIP PH800480T032-ZHC19 7.0" WVGA TFT LCD panel
- powertip,ph800480t032-zhc19
# PrimeView PM070WL4 7.0" 800x480 TFT LCD panel
- primeview,pm070wl4
# QiaoDian XianShi Corporation 4"3 TFT LCD panel

View File

@ -21,11 +21,11 @@ properties:
backlight: true
port: true
additionalProperties: false
required:
- compatible
- power-supply
- backlight
additionalProperties: false
...

View File

@ -33,13 +33,13 @@ properties:
reset-gpios:
maxItems: 1
additionalProperties: false
required:
- compatible
- power-supply
- reg
additionalProperties: false
examples:
- |
dsi {

View File

@ -34,8 +34,6 @@ properties:
vddio-supply:
description: I/O voltage rail
port: true
required:
- compatible
- reg

View File

@ -43,13 +43,13 @@ properties:
no-hpd: true
hpd-gpios: true
additionalProperties: false
required:
- compatible
- enable-gpios
- power-supply
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/qcom,rpmh.h>

View File

@ -20,10 +20,6 @@ properties:
reg:
maxItems: 1
display-timings: true
port: true
reset-gpios: true
vdd3-supply:
description: core voltage supply

View File

@ -31,8 +31,6 @@ properties:
configuration.
maxItems: 1
reset-gpios: true
vci-supply:
description: regulator that supplies the VCI analog voltage
usually around 3.0 V
@ -41,8 +39,6 @@ properties:
description: regulator that supplies the VCCIO voltage usually
around 1.8 V
backlight: true
spi-cpha: true
spi-cpol: true
@ -50,8 +46,6 @@ properties:
spi-max-frequency:
maximum: 1200000
port: true
required:
- compatible
- reg

View File

@ -23,8 +23,6 @@ properties:
reg:
maxItems: 1
reset-gpios: true
vci-supply:
description: regulator that supplies the VCI analog voltage
usually around 3.0 V
@ -33,8 +31,6 @@ properties:
description: regulator that supplies the VCCIO voltage usually
around 1.8 V
backlight: true
spi-cpha: true
spi-cpol: true
@ -44,8 +40,6 @@ properties:
maximum 300 ns minimum cycle which gives around 3 MHz max frequency
maximum: 3000000
port: true
required:
- compatible
- reg

View File

@ -30,8 +30,6 @@ properties:
configuration.
maxItems: 1
reset-gpios: true
vci-supply:
description: regulator that supplies the VCI analog voltage
usually around 3.0 V
@ -40,8 +38,6 @@ properties:
description: regulator that supplies the VCCIO voltage usually
around 1.8 V
backlight: true
spi-cpha: true
spi-cpol: true
@ -49,8 +45,6 @@ properties:
spi-max-frequency:
maximum: 1200000
port: true
required:
- compatible
- reg

View File

@ -44,6 +44,8 @@ properties:
vmipi-supply:
description: VMIPI supply, usually 1.8v.
port: true
required:
- compatible
- reg
@ -65,6 +67,12 @@ examples:
power-supply = <&display_3v3_supply>;
reset-gpios = <&gpf0 4 GPIO_ACTIVE_LOW>;
backlight = <&backlight>;
port {
panel_in: endpoint {
remote-endpoint = <&mdss_dsi0_out>;
};
};
};
};

View File

@ -22,10 +22,6 @@ properties:
reg:
maxItems: 1
reset-gpios: true
port: true
vdd3-supply:
description: VDD regulator

View File

@ -21,8 +21,6 @@ properties:
reg:
maxItems: 1
reset-gpios: true
port: true
default-brightness: true
max-brightness: true

View File

@ -41,8 +41,6 @@ properties:
panel-timing: true
port: true
additionalProperties: false
required:
- compatible
- port
@ -51,6 +49,8 @@ required:
- height-mm
- panel-timing
additionalProperties: false
examples:
- |+
panel {

View File

@ -49,12 +49,6 @@ properties:
If not set, the controller is in 3-line SPI mode.
Disallowed for DSI.
port: true
reset-gpios: true
rotation: true
backlight: true
required:
- compatible
- reg

View File

@ -24,12 +24,6 @@ properties:
reg:
maxItems: 1
reset-gpios: true
power-supply: true
backlight: true
port: true
rotation: true
spi-cpha: true
spi-cpol: true

View File

@ -20,10 +20,6 @@ properties:
reg:
maxItems: 1
label: true
reset-gpios: true
port: true
required:
- compatible
- port

View File

@ -31,8 +31,6 @@ properties:
power-supply: true
additionalProperties: false
required:
- compatible
- enable-gpios
@ -42,6 +40,8 @@ required:
- port
- power-supply
additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>

View File

@ -25,11 +25,6 @@ properties:
reg:
maxItems: 1
label: true
reset-gpios: true
backlight: true
port: true
spi-cpha: true
spi-cpol: true

View File

@ -25,8 +25,6 @@ properties:
port: true
reset-gpios: true
additionalProperties: false
required:
- compatible
- reg
@ -35,6 +33,8 @@ required:
- reset-gpios
- port
additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>

View File

@ -36,8 +36,6 @@ properties:
port: true
reset-gpios: true
additionalProperties: false
required:
- compatible
- reg
@ -46,6 +44,8 @@ required:
- reset-gpios
- port
additionalProperties: false
examples:
- |
dsi {

View File

@ -26,8 +26,6 @@ properties:
port: true
reset-gpios: true
additionalProperties: false
required:
- compatible
- reg
@ -37,6 +35,8 @@ required:
- reset-gpios
- port
additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>

View File

@ -973,6 +973,8 @@ patternProperties:
description: Liebherr-Werk Nenzing GmbH
"^lxa,.*":
description: Linux Automation GmbH
"^lxd,.*":
description: LXD Research & Display, LLC
"^m5stack,.*":
description: M5Stack
"^macnica,.*":
@ -1610,6 +1612,8 @@ patternProperties:
"^synopsys,.*":
description: Synopsys, Inc. (deprecated, use snps)
deprecated: true
"^taiguanck,.*":
description: Shenzhen Top Group Technology Co., Ltd.
"^taos,.*":
description: Texas Advanced Optoelectronic Solutions Inc.
"^tbs,.*":

View File

@ -8059,6 +8059,12 @@ F: Documentation/devicetree/bindings/display/lvds.yaml
F: Documentation/devicetree/bindings/display/panel/panel-lvds.yaml
F: drivers/gpu/drm/panel/panel-lvds.c
DRM DRIVER FOR LXD M9189A PANELS
M: Michael Tretter <m.tretter@pengutronix.de>
S: Maintained
F: Documentation/devicetree/bindings/display/panel/lxd,m9189a.yaml
F: drivers/gpu/drm/panel/panel-lxd-m9189a.c
DRM DRIVER FOR MANTIX MLAF057WE51 PANELS
M: Guido Günther <agx@sigxcpu.org>
R: Purism Kernel Team <kernel@puri.sm>
@ -8916,11 +8922,11 @@ R: Christian Koenig <christian.koenig@amd.com>
L: dri-devel@lists.freedesktop.org
S: Maintained
T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
F: drivers/gpu/drm_buddy.c
F: drivers/gpu/buddy.c
F: drivers/gpu/drm/drm_buddy.c
F: drivers/gpu/tests/gpu_buddy_test.c
F: include/linux/gpu_buddy.h
F: include/drm/drm_buddy.h
F: include/linux/gpu_buddy.h
DRM AUTOMATED TESTING
M: Helen Koike <helen.fornazier@gmail.com>
@ -12985,7 +12991,6 @@ F: drivers/crypto/intel/ixp4xx/ixp4xx_crypto.c
INTEL KEEM BAY DRM DRIVER
M: Anitha Chrisanthus <anitha.chrisanthus@intel.com>
M: Edmund Dea <edmund.j.dea@intel.com>
S: Maintained
F: Documentation/devicetree/bindings/display/intel,keembay-display.yaml
F: drivers/gpu/drm/kmb/

View File

@ -10,6 +10,7 @@
#include <drm/drm_managed.h>
#include <drm/drm_print.h>
#include <drm/gpu_scheduler.h>
#include <linux/amd-pmf-io.h>
#include <linux/cleanup.h>
#include <linux/errno.h>
#include <linux/firmware.h>
@ -791,6 +792,55 @@ static int aie2_get_clock_metadata(struct amdxdna_client *client,
return ret;
}
static int aie2_get_sensors(struct amdxdna_client *client,
struct amdxdna_drm_get_info *args)
{
struct amdxdna_dev_hdl *ndev = client->xdna->dev_handle;
struct amdxdna_drm_query_sensor sensor = {};
struct amd_pmf_npu_metrics npu_metrics;
u32 sensors_count = 0, i;
int ret;
ret = AIE2_GET_PMF_NPU_METRICS(&npu_metrics);
if (ret)
return ret;
sensor.type = AMDXDNA_SENSOR_TYPE_POWER;
sensor.input = npu_metrics.npu_power;
sensor.unitm = -3;
scnprintf(sensor.label, sizeof(sensor.label), "Total Power");
scnprintf(sensor.units, sizeof(sensor.units), "mW");
if (copy_to_user(u64_to_user_ptr(args->buffer), &sensor, sizeof(sensor)))
return -EFAULT;
sensors_count++;
if (args->buffer_size <= sensors_count * sizeof(sensor))
goto out;
for (i = 0; i < min_t(u32, ndev->total_col, 8); i++) {
memset(&sensor, 0, sizeof(sensor));
sensor.input = npu_metrics.npu_busy[i];
sensor.type = AMDXDNA_SENSOR_TYPE_COLUMN_UTILIZATION;
sensor.unitm = 0;
scnprintf(sensor.label, sizeof(sensor.label), "Column %d Utilization", i);
scnprintf(sensor.units, sizeof(sensor.units), "%%");
if (copy_to_user(u64_to_user_ptr(args->buffer) + sensors_count * sizeof(sensor),
&sensor, sizeof(sensor)))
return -EFAULT;
sensors_count++;
if (args->buffer_size <= sensors_count * sizeof(sensor))
goto out;
}
out:
args->buffer_size = sensors_count * sizeof(sensor);
return 0;
}
static int aie2_hwctx_status_cb(struct amdxdna_hwctx *hwctx, void *arg)
{
struct amdxdna_drm_hwctx_entry *tmp __free(kfree) = NULL;
@ -994,6 +1044,9 @@ static int aie2_get_info(struct amdxdna_client *client, struct amdxdna_drm_get_i
case DRM_AMDXDNA_QUERY_CLOCK_METADATA:
ret = aie2_get_clock_metadata(client, args);
break;
case DRM_AMDXDNA_QUERY_SENSORS:
ret = aie2_get_sensors(client, args);
break;
case DRM_AMDXDNA_QUERY_HW_CONTEXTS:
ret = aie2_get_hwctx_status(client, args);
break;

View File

@ -7,6 +7,7 @@
#define _AIE2_PCI_H_
#include <drm/amdxdna_accel.h>
#include <linux/limits.h>
#include <linux/semaphore.h>
#include "amdxdna_mailbox.h"
@ -46,6 +47,33 @@
pci_resource_len(NDEV2PDEV(_ndev), (_ndev)->xdna->dev_info->mbox_bar); \
})
#if IS_ENABLED(CONFIG_AMD_PMF)
#define AIE2_GET_PMF_NPU_METRICS(metrics) amd_pmf_get_npu_data(metrics)
#define AIE2_GET_PMF_NPU_DATA(field, val) \
({ \
struct amd_pmf_npu_metrics _npu_metrics; \
int _ret; \
\
_ret = amd_pmf_get_npu_data(&_npu_metrics); \
val = _ret ? U32_MAX : _npu_metrics.field; \
(_ret); \
})
#else
#define AIE2_GET_PMF_NPU_METRICS(metrics) \
({ \
typeof(metrics) _m = metrics; \
memset(_m, 0xff, sizeof(*_m)); \
(-EOPNOTSUPP); \
})
#define SENSOR_DEFAULT_npu_power U32_MAX
#define AIE2_GET_PMF_NPU_DATA(field, val) \
({ \
val = SENSOR_DEFAULT_##field; \
(-EOPNOTSUPP); \
})
#endif
enum aie2_smu_reg_idx {
SMU_CMD_REG = 0,
SMU_ARG_REG,

View File

@ -35,9 +35,10 @@ MODULE_FIRMWARE("amdnpu/17f0_11/npu_7.sbin");
* 0.4: Support getting resource information
* 0.5: Support getting telemetry data
* 0.6: Support preemption
* 0.7: Support getting power and utilization data
*/
#define AMDXDNA_DRIVER_MAJOR 0
#define AMDXDNA_DRIVER_MINOR 6
#define AMDXDNA_DRIVER_MINOR 7
/*
* Bind the driver base on (vendor_id, device_id) pair and later use the
@ -358,5 +359,6 @@ static struct pci_driver amdxdna_pci_driver = {
module_pci_driver(amdxdna_pci_driver);
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS("AMD_PMF");
MODULE_AUTHOR("XRT Team <runtimeca39d@amd.com>");
MODULE_DESCRIPTION("amdxdna driver");

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2020-2023 Intel Corporation
* Copyright (C) 2020-2026 Intel Corporation
*/
#include <linux/dma-buf.h>
@ -31,7 +31,7 @@ static inline void ivpu_dbg_bo(struct ivpu_device *vdev, struct ivpu_bo *bo, con
"%6s: bo %8p size %9zu ctx %d vpu_addr %9llx pages %d sgt %d mmu_mapped %d wc %d imported %d\n",
action, bo, ivpu_bo_size(bo), bo->ctx_id, bo->vpu_addr,
(bool)bo->base.pages, (bool)bo->base.sgt, bo->mmu_mapped, bo->base.map_wc,
(bool)drm_gem_is_imported(&bo->base.base));
drm_gem_is_imported(&bo->base.base));
}
static inline int ivpu_bo_lock(struct ivpu_bo *bo)
@ -48,7 +48,7 @@ static struct sg_table *ivpu_bo_map_attachment(struct ivpu_device *vdev, struct
{
struct sg_table *sgt;
drm_WARN_ON(&vdev->drm, !bo->base.base.import_attach);
drm_WARN_ON(&vdev->drm, !drm_gem_is_imported(&bo->base.base));
ivpu_bo_lock(bo);
@ -81,7 +81,7 @@ int __must_check ivpu_bo_bind(struct ivpu_bo *bo)
ivpu_dbg_bo(vdev, bo, "bind");
if (bo->base.base.import_attach)
if (drm_gem_is_imported(&bo->base.base))
sgt = ivpu_bo_map_attachment(vdev, bo);
else
sgt = drm_gem_shmem_get_pages_sgt(&bo->base);
@ -157,7 +157,7 @@ static void ivpu_bo_unbind_locked(struct ivpu_bo *bo)
}
if (bo->base.sgt) {
if (bo->base.base.import_attach) {
if (drm_gem_is_imported(&bo->base.base)) {
dma_buf_unmap_attachment(bo->base.base.import_attach,
bo->base.sgt, DMA_BIDIRECTIONAL);
} else {
@ -195,7 +195,7 @@ struct drm_gem_object *ivpu_gem_create_object(struct drm_device *dev, size_t siz
if (size == 0 || !PAGE_ALIGNED(size))
return ERR_PTR(-EINVAL);
bo = kzalloc(sizeof(*bo), GFP_KERNEL);
bo = kzalloc_obj(*bo);
if (!bo)
return ERR_PTR(-ENOMEM);

View File

@ -121,12 +121,6 @@
#define VPU_50XX_HOST_SS_AON_PWR_ISLAND_STATUS_DLY 0x0003006cu
#define VPU_50XX_HOST_SS_AON_PWR_ISLAND_STATUS_DLY_STATUS_DLY_MASK GENMASK(7, 0)
#define VPU_40XX_HOST_SS_AON_RETENTION0 0x0003000cu
#define VPU_40XX_HOST_SS_AON_RETENTION1 0x00030010u
#define VPU_40XX_HOST_SS_AON_RETENTION2 0x00030014u
#define VPU_40XX_HOST_SS_AON_RETENTION3 0x00030018u
#define VPU_40XX_HOST_SS_AON_RETENTION4 0x0003001cu
#define VPU_40XX_HOST_SS_AON_IDLE_GEN 0x00030200u
#define VPU_40XX_HOST_SS_AON_IDLE_GEN_EN_MASK BIT_MASK(0)
#define VPU_40XX_HOST_SS_AON_IDLE_GEN_HW_PG_EN_MASK BIT_MASK(1)

View File

@ -931,7 +931,6 @@ static int soc_cpu_boot_40xx(struct ivpu_device *vdev)
static int soc_cpu_boot_60xx(struct ivpu_device *vdev)
{
REGV_WR64(VPU_40XX_HOST_SS_AON_RETENTION1, vdev->fw->mem_bp->vpu_addr);
soc_cpu_set_entry_point_40xx(vdev, vdev->fw->cold_boot_entry_point);
return 0;

View File

@ -329,10 +329,7 @@ static struct dma_buf *cma_heap_allocate(struct dma_heap *heap,
struct page *page = cma_pages;
while (nr_clear_pages > 0) {
void *vaddr = kmap_local_page(page);
clear_page(vaddr);
kunmap_local(vaddr);
clear_highpage(page);
/*
* Avoid wasting time zeroing memory if the process
* has been killed by SIGKILL.
@ -343,7 +340,7 @@ static struct dma_buf *cma_heap_allocate(struct dma_heap *heap,
nr_clear_pages--;
}
} else {
memset(page_address(cma_pages), 0, size);
clear_pages(page_address(cma_pages), pagecount);
}
buffer->pages = kmalloc_objs(*buffer->pages, pagecount);

View File

@ -53,6 +53,25 @@ gpu_buddy_block_is_split(struct gpu_buddy_block *block)
return gpu_buddy_block_state(block) == GPU_BUDDY_SPLIT;
}
static unsigned int gpu_buddy_block_offset_alignment(struct gpu_buddy_block *block)
{
u64 offset = gpu_buddy_block_offset(block);
if (!offset)
/*
* __ffs64(0) is undefined; offset 0 is maximally aligned, so return
* a value greater than any possible alignment.
*/
return 64 + 1;
return __ffs64(offset);
}
RB_DECLARE_CALLBACKS_MAX(static, gpu_buddy_augment_cb,
struct gpu_buddy_block, rb,
unsigned int, subtree_max_alignment,
gpu_buddy_block_offset_alignment);
static struct gpu_buddy_block *gpu_block_alloc(struct gpu_buddy *mm,
struct gpu_buddy_block *parent,
unsigned int order,
@ -106,26 +125,42 @@ static bool rbtree_is_empty(struct rb_root *root)
return RB_EMPTY_ROOT(root);
}
static bool gpu_buddy_block_offset_less(const struct gpu_buddy_block *block,
const struct gpu_buddy_block *node)
{
return gpu_buddy_block_offset(block) < gpu_buddy_block_offset(node);
}
static bool rbtree_block_offset_less(struct rb_node *block,
const struct rb_node *node)
{
return gpu_buddy_block_offset_less(rbtree_get_free_block(block),
rbtree_get_free_block(node));
}
static void rbtree_insert(struct gpu_buddy *mm,
struct gpu_buddy_block *block,
enum gpu_buddy_free_tree tree)
{
rb_add(&block->rb,
&mm->free_trees[tree][gpu_buddy_block_order(block)],
rbtree_block_offset_less);
struct rb_node **link, *parent = NULL;
unsigned int block_alignment, order;
struct gpu_buddy_block *node;
struct rb_root *root;
order = gpu_buddy_block_order(block);
block_alignment = gpu_buddy_block_offset_alignment(block);
root = &mm->free_trees[tree][order];
link = &root->rb_node;
while (*link) {
parent = *link;
node = rbtree_get_free_block(parent);
/*
* Manual augmentation update during insertion traversal. Required
* because rb_insert_augmented() only calls rotate callback during
* rotations. This ensures all ancestors on the insertion path have
* correct subtree_max_alignment values.
*/
if (node->subtree_max_alignment < block_alignment)
node->subtree_max_alignment = block_alignment;
if (gpu_buddy_block_offset(block) < gpu_buddy_block_offset(node))
link = &parent->rb_left;
else
link = &parent->rb_right;
}
block->subtree_max_alignment = block_alignment;
rb_link_node(&block->rb, parent, link);
rb_insert_augmented(&block->rb, root, &gpu_buddy_augment_cb);
}
static void rbtree_remove(struct gpu_buddy *mm,
@ -138,7 +173,7 @@ static void rbtree_remove(struct gpu_buddy *mm,
tree = get_block_tree(block);
root = &mm->free_trees[tree][order];
rb_erase(&block->rb, root);
rb_erase_augmented(&block->rb, root, &gpu_buddy_augment_cb);
RB_CLEAR_NODE(&block->rb);
}
@ -811,6 +846,127 @@ alloc_from_freetree(struct gpu_buddy *mm,
return ERR_PTR(err);
}
static bool
gpu_buddy_can_offset_align(u64 size, u64 min_block_size)
{
return size < min_block_size && is_power_of_2(size);
}
static bool gpu_buddy_subtree_can_satisfy(struct rb_node *node,
unsigned int alignment)
{
struct gpu_buddy_block *block;
block = rbtree_get_free_block(node);
return block->subtree_max_alignment >= alignment;
}
static struct gpu_buddy_block *
gpu_buddy_find_block_aligned(struct gpu_buddy *mm,
enum gpu_buddy_free_tree tree,
unsigned int order,
unsigned int alignment,
unsigned long flags)
{
struct rb_root *root = &mm->free_trees[tree][order];
struct rb_node *rb = root->rb_node;
while (rb) {
struct gpu_buddy_block *block = rbtree_get_free_block(rb);
struct rb_node *left_node = rb->rb_left, *right_node = rb->rb_right;
if (right_node) {
if (gpu_buddy_subtree_can_satisfy(right_node, alignment)) {
rb = right_node;
continue;
}
}
if (gpu_buddy_block_offset_alignment(block) >= alignment)
return block;
if (left_node) {
if (gpu_buddy_subtree_can_satisfy(left_node, alignment)) {
rb = left_node;
continue;
}
}
break;
}
return NULL;
}
static struct gpu_buddy_block *
gpu_buddy_offset_aligned_allocation(struct gpu_buddy *mm,
u64 size,
u64 min_block_size,
unsigned long flags)
{
struct gpu_buddy_block *block = NULL;
unsigned int order, tmp, alignment;
struct gpu_buddy_block *buddy;
enum gpu_buddy_free_tree tree;
unsigned long pages;
int err;
alignment = ilog2(min_block_size);
pages = size >> ilog2(mm->chunk_size);
order = fls(pages) - 1;
tree = (flags & GPU_BUDDY_CLEAR_ALLOCATION) ?
GPU_BUDDY_CLEAR_TREE : GPU_BUDDY_DIRTY_TREE;
for (tmp = order; tmp <= mm->max_order; ++tmp) {
block = gpu_buddy_find_block_aligned(mm, tree, tmp,
alignment, flags);
if (!block) {
tree = (tree == GPU_BUDDY_CLEAR_TREE) ?
GPU_BUDDY_DIRTY_TREE : GPU_BUDDY_CLEAR_TREE;
block = gpu_buddy_find_block_aligned(mm, tree, tmp,
alignment, flags);
}
if (block)
break;
}
if (!block)
return ERR_PTR(-ENOSPC);
while (gpu_buddy_block_order(block) > order) {
struct gpu_buddy_block *left, *right;
err = split_block(mm, block);
if (unlikely(err))
goto err_undo;
left = block->left;
right = block->right;
if (gpu_buddy_block_offset_alignment(right) >= alignment)
block = right;
else
block = left;
}
return block;
err_undo:
/*
* We really don't want to leave around a bunch of split blocks, since
* bigger is better, so make sure we merge everything back before we
* free the allocated blocks.
*/
buddy = __get_buddy(block);
if (buddy &&
(gpu_buddy_block_is_free(block) &&
gpu_buddy_block_is_free(buddy)))
__gpu_buddy_free(mm, block, false);
return ERR_PTR(err);
}
static int __alloc_range(struct gpu_buddy *mm,
struct list_head *dfs,
u64 start, u64 size,
@ -1080,6 +1236,7 @@ EXPORT_SYMBOL(gpu_buddy_block_trim);
static struct gpu_buddy_block *
__gpu_buddy_alloc_blocks(struct gpu_buddy *mm,
u64 start, u64 end,
u64 size, u64 min_block_size,
unsigned int order,
unsigned long flags)
{
@ -1087,6 +1244,11 @@ __gpu_buddy_alloc_blocks(struct gpu_buddy *mm,
/* Allocate traversing within the range */
return __gpu_buddy_alloc_range_bias(mm, start, end,
order, flags);
else if (size < min_block_size)
/* Allocate from an offset-aligned region without size rounding */
return gpu_buddy_offset_aligned_allocation(mm, size,
min_block_size,
flags);
else
/* Allocate from freetree */
return alloc_from_freetree(mm, order, flags);
@ -1158,8 +1320,11 @@ int gpu_buddy_alloc_blocks(struct gpu_buddy *mm,
if (flags & GPU_BUDDY_CONTIGUOUS_ALLOCATION) {
size = roundup_pow_of_two(size);
min_block_size = size;
/* Align size value to min_block_size */
} else if (!IS_ALIGNED(size, min_block_size)) {
/*
* Normalize the requested size to min_block_size for regular allocations.
* Offset-aligned allocations intentionally skip size rounding.
*/
} else if (!gpu_buddy_can_offset_align(size, min_block_size)) {
size = round_up(size, min_block_size);
}
@ -1179,43 +1344,60 @@ int gpu_buddy_alloc_blocks(struct gpu_buddy *mm,
do {
order = min(order, (unsigned int)fls(pages) - 1);
BUG_ON(order > mm->max_order);
BUG_ON(order < min_order);
/*
* Regular allocations must not allocate blocks smaller than min_block_size.
* Offset-aligned allocations deliberately bypass this constraint.
*/
BUG_ON(size >= min_block_size && order < min_order);
do {
unsigned int fallback_order;
block = __gpu_buddy_alloc_blocks(mm, start,
end,
size,
min_block_size,
order,
flags);
if (!IS_ERR(block))
break;
if (order-- == min_order) {
/* Try allocation through force merge method */
if (mm->clear_avail &&
!__force_merge(mm, start, end, min_order)) {
block = __gpu_buddy_alloc_blocks(mm, start,
end,
min_order,
flags);
if (!IS_ERR(block)) {
order = min_order;
break;
}
}
/*
* Try contiguous block allocation through
* try harder method.
*/
if (flags & GPU_BUDDY_CONTIGUOUS_ALLOCATION &&
!(flags & GPU_BUDDY_RANGE_ALLOCATION))
return __alloc_contig_try_harder(mm,
original_size,
original_min_size,
blocks);
err = -ENOSPC;
goto err_free;
if (size < min_block_size) {
fallback_order = order;
} else if (order == min_order) {
fallback_order = min_order;
} else {
order--;
continue;
}
/* Try allocation through force merge method */
if (mm->clear_avail &&
!__force_merge(mm, start, end, fallback_order)) {
block = __gpu_buddy_alloc_blocks(mm, start,
end,
size,
min_block_size,
fallback_order,
flags);
if (!IS_ERR(block)) {
order = fallback_order;
break;
}
}
/*
* Try contiguous block allocation through
* try harder method.
*/
if (flags & GPU_BUDDY_CONTIGUOUS_ALLOCATION &&
!(flags & GPU_BUDDY_RANGE_ALLOCATION))
return __alloc_contig_try_harder(mm,
original_size,
original_min_size,
blocks);
err = -ENOSPC;
goto err_free;
} while (1);
mark_allocated(mm, block);

View File

@ -34,7 +34,8 @@ config DRM_ANALOGIX_ANX7625
tristate "Analogix Anx7625 MIPI to DP interface support"
depends on DRM
depends on OF
depends on TYPEC || !TYPEC
depends on TYPEC
depends on USB_ROLE_SWITCH
select DRM_DISPLAY_DP_HELPER
select DRM_DISPLAY_HDCP_HELPER
select DRM_DISPLAY_HELPER

View File

@ -1363,6 +1363,18 @@ static void anx7625_configure_hpd(struct anx7625_data *ctx)
anx7625_hpd_timer_config(ctx);
}
static bool anx7625_need_pd(struct anx7625_data *ctx)
{
struct fwnode_handle *fwnode;
fwnode = device_get_named_child_node(ctx->dev, "connector");
if (!fwnode)
return false;
fwnode_handle_put(fwnode);
return true;
}
static int anx7625_ocm_loading_check(struct anx7625_data *ctx)
{
int ret;
@ -1378,7 +1390,7 @@ static int anx7625_ocm_loading_check(struct anx7625_data *ctx)
if ((ret & FLASH_LOAD_STA_CHK) != FLASH_LOAD_STA_CHK)
return -ENODEV;
if (!ctx->typec_port)
if (!anx7625_need_pd(ctx))
anx7625_disable_pd_protocol(ctx);
anx7625_configure_hpd(ctx);
@ -1483,7 +1495,6 @@ static void anx7625_start_dp_work(struct anx7625_data *ctx)
DRM_DEV_DEBUG_DRIVER(dev, "Secure OCM version=%02x\n", ret);
}
#if IS_REACHABLE(CONFIG_TYPEC)
static u8 anx7625_checksum(u8 *buf, u8 len)
{
u8 ret = 0;
@ -1567,6 +1578,9 @@ static void anx7625_typec_set_status(struct anx7625_data *ctx,
unsigned int intr_status,
unsigned int intr_vector)
{
if (!ctx->typec_port)
return;
if (intr_vector & CC_STATUS)
anx7625_typec_set_orientation(ctx);
if (intr_vector & DATA_ROLE_STATUS) {
@ -1635,22 +1649,6 @@ static void anx7625_typec_unregister(struct anx7625_data *ctx)
usb_role_switch_put(ctx->role_sw);
typec_unregister_port(ctx->typec_port);
}
#else
static void anx7625_typec_set_status(struct anx7625_data *ctx,
unsigned int intr_status,
unsigned int intr_vector)
{
}
static int anx7625_typec_register(struct anx7625_data *ctx)
{
return 0;
}
static void anx7625_typec_unregister(struct anx7625_data *ctx)
{
}
#endif
static int anx7625_read_hpd_status_p0(struct anx7625_data *ctx)
{
@ -2924,12 +2922,7 @@ static int anx7625_i2c_probe(struct i2c_client *client)
}
if (!platform->pdata.low_power_mode) {
struct fwnode_handle *fwnode;
fwnode = device_get_named_child_node(dev, "connector");
if (fwnode)
fwnode_handle_put(fwnode);
else
if (!anx7625_need_pd(platform))
anx7625_disable_pd_protocol(platform);
anx7625_configure_hpd(platform);

View File

@ -739,12 +739,8 @@ static void cdns_mhdp_fw_cb(const struct firmware *fw, void *context)
spin_lock(&mhdp->start_lock);
bridge_attached = mhdp->bridge_attached;
spin_unlock(&mhdp->start_lock);
if (bridge_attached) {
if (mhdp->connector.dev)
drm_kms_helper_hotplug_event(mhdp->bridge.dev);
else
drm_bridge_hpd_notify(&mhdp->bridge, cdns_mhdp_detect(mhdp));
}
if (bridge_attached)
drm_bridge_hpd_notify(&mhdp->bridge, cdns_mhdp_detect(mhdp));
}
static int cdns_mhdp_load_firmware(struct cdns_mhdp_device *mhdp)
@ -782,7 +778,7 @@ static ssize_t cdns_mhdp_transfer(struct drm_dp_aux *aux,
if (!ret)
continue;
dev_err(mhdp->dev,
dev_dbg(mhdp->dev,
"Failed to write DPCD addr %u\n",
msg->address + i);
@ -792,7 +788,7 @@ static ssize_t cdns_mhdp_transfer(struct drm_dp_aux *aux,
ret = cdns_mhdp_dpcd_read(mhdp, msg->address,
msg->buffer, msg->size);
if (ret) {
dev_err(mhdp->dev,
dev_dbg(mhdp->dev,
"Failed to read DPCD addr %u\n",
msg->address);
@ -1444,56 +1440,6 @@ static const struct drm_edid *cdns_mhdp_edid_read(struct cdns_mhdp_device *mhdp,
return drm_edid_read_custom(connector, cdns_mhdp_get_edid_block, mhdp);
}
static int cdns_mhdp_get_modes(struct drm_connector *connector)
{
struct cdns_mhdp_device *mhdp = connector_to_mhdp(connector);
const struct drm_edid *drm_edid;
int num_modes;
if (!mhdp->plugged)
return 0;
drm_edid = cdns_mhdp_edid_read(mhdp, connector);
drm_edid_connector_update(connector, drm_edid);
if (!drm_edid) {
dev_err(mhdp->dev, "Failed to read EDID\n");
return 0;
}
num_modes = drm_edid_connector_add_modes(connector);
drm_edid_free(drm_edid);
/*
* HACK: Warn about unsupported display formats until we deal
* with them correctly.
*/
if (connector->display_info.color_formats &&
!(connector->display_info.color_formats &
mhdp->display_fmt.color_format))
dev_warn(mhdp->dev,
"%s: No supported color_format found (0x%08x)\n",
__func__, connector->display_info.color_formats);
if (connector->display_info.bpc &&
connector->display_info.bpc < mhdp->display_fmt.bpc)
dev_warn(mhdp->dev, "%s: Display bpc only %d < %d\n",
__func__, connector->display_info.bpc,
mhdp->display_fmt.bpc);
return num_modes;
}
static int cdns_mhdp_connector_detect(struct drm_connector *conn,
struct drm_modeset_acquire_ctx *ctx,
bool force)
{
struct cdns_mhdp_device *mhdp = connector_to_mhdp(conn);
return cdns_mhdp_detect(mhdp);
}
static u32 cdns_mhdp_get_bpp(struct cdns_mhdp_display_fmt *fmt)
{
u32 bpp;
@ -1547,114 +1493,6 @@ bool cdns_mhdp_bandwidth_ok(struct cdns_mhdp_device *mhdp,
return true;
}
static
enum drm_mode_status cdns_mhdp_mode_valid(struct drm_connector *conn,
const struct drm_display_mode *mode)
{
struct cdns_mhdp_device *mhdp = connector_to_mhdp(conn);
mutex_lock(&mhdp->link_mutex);
if (!cdns_mhdp_bandwidth_ok(mhdp, mode, mhdp->link.num_lanes,
mhdp->link.rate)) {
mutex_unlock(&mhdp->link_mutex);
return MODE_CLOCK_HIGH;
}
mutex_unlock(&mhdp->link_mutex);
return MODE_OK;
}
static int cdns_mhdp_connector_atomic_check(struct drm_connector *conn,
struct drm_atomic_state *state)
{
struct cdns_mhdp_device *mhdp = connector_to_mhdp(conn);
struct drm_connector_state *old_state, *new_state;
struct drm_crtc_state *crtc_state;
u64 old_cp, new_cp;
if (!mhdp->hdcp_supported)
return 0;
old_state = drm_atomic_get_old_connector_state(state, conn);
new_state = drm_atomic_get_new_connector_state(state, conn);
old_cp = old_state->content_protection;
new_cp = new_state->content_protection;
if (old_state->hdcp_content_type != new_state->hdcp_content_type &&
new_cp != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
new_state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
goto mode_changed;
}
if (!new_state->crtc) {
if (old_cp == DRM_MODE_CONTENT_PROTECTION_ENABLED)
new_state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
return 0;
}
if (old_cp == new_cp ||
(old_cp == DRM_MODE_CONTENT_PROTECTION_DESIRED &&
new_cp == DRM_MODE_CONTENT_PROTECTION_ENABLED))
return 0;
mode_changed:
crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc);
crtc_state->mode_changed = true;
return 0;
}
static const struct drm_connector_helper_funcs cdns_mhdp_conn_helper_funcs = {
.detect_ctx = cdns_mhdp_connector_detect,
.get_modes = cdns_mhdp_get_modes,
.mode_valid = cdns_mhdp_mode_valid,
.atomic_check = cdns_mhdp_connector_atomic_check,
};
static const struct drm_connector_funcs cdns_mhdp_conn_funcs = {
.fill_modes = drm_helper_probe_single_connector_modes,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
.reset = drm_atomic_helper_connector_reset,
.destroy = drm_connector_cleanup,
};
static int cdns_mhdp_connector_init(struct cdns_mhdp_device *mhdp)
{
u32 bus_format = MEDIA_BUS_FMT_RGB121212_1X36;
struct drm_connector *conn = &mhdp->connector;
struct drm_bridge *bridge = &mhdp->bridge;
int ret;
conn->polled = DRM_CONNECTOR_POLL_HPD;
ret = drm_connector_init(bridge->dev, conn, &cdns_mhdp_conn_funcs,
DRM_MODE_CONNECTOR_DisplayPort);
if (ret) {
dev_err(mhdp->dev, "Failed to initialize connector with drm\n");
return ret;
}
drm_connector_helper_add(conn, &cdns_mhdp_conn_helper_funcs);
ret = drm_display_info_set_bus_formats(&conn->display_info,
&bus_format, 1);
if (ret)
return ret;
ret = drm_connector_attach_encoder(conn, bridge->encoder);
if (ret) {
dev_err(mhdp->dev, "Failed to attach connector to encoder\n");
return ret;
}
if (mhdp->hdcp_supported)
ret = drm_connector_attach_content_protection_property(conn, true);
return ret;
}
static int cdns_mhdp_attach(struct drm_bridge *bridge,
struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
@ -1671,9 +1509,11 @@ static int cdns_mhdp_attach(struct drm_bridge *bridge,
return ret;
if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) {
ret = cdns_mhdp_connector_init(mhdp);
if (ret)
goto aux_unregister;
ret = -EINVAL;
dev_err(mhdp->dev,
"Connector initialisation not supported in bridge_attach %d\n",
ret);
goto aux_unregister;
}
spin_lock(&mhdp->start_lock);
@ -1915,17 +1755,25 @@ static void cdns_mhdp_atomic_enable(struct drm_bridge *bridge,
struct cdns_mhdp_device *mhdp = bridge_to_mhdp(bridge);
struct cdns_mhdp_bridge_state *mhdp_state;
struct drm_crtc_state *crtc_state;
struct drm_connector *connector;
struct drm_connector_state *conn_state;
struct drm_bridge_state *new_state;
const struct drm_display_mode *mode;
u32 resp;
int ret;
int ret = 0;
dev_dbg(mhdp->dev, "bridge enable\n");
mutex_lock(&mhdp->link_mutex);
mhdp->connector = drm_atomic_get_new_connector_for_encoder(state,
bridge->encoder);
if (WARN_ON(!mhdp->connector))
goto out;
conn_state = drm_atomic_get_new_connector_state(state, mhdp->connector);
if (WARN_ON(!conn_state))
goto out;
if (mhdp->plugged && !mhdp->link_up) {
ret = cdns_mhdp_link_up(mhdp);
if (ret < 0)
@ -1945,15 +1793,6 @@ static void cdns_mhdp_atomic_enable(struct drm_bridge *bridge,
cdns_mhdp_reg_write(mhdp, CDNS_DPTX_CAR,
resp | CDNS_VIF_CLK_EN | CDNS_VIF_CLK_RSTN);
connector = drm_atomic_get_new_connector_for_encoder(state,
bridge->encoder);
if (WARN_ON(!connector))
goto out;
conn_state = drm_atomic_get_new_connector_state(state, connector);
if (WARN_ON(!conn_state))
goto out;
if (mhdp->hdcp_supported &&
mhdp->hw_state == MHDP_HW_READY &&
conn_state->content_protection ==
@ -2030,6 +1869,7 @@ static void cdns_mhdp_atomic_disable(struct drm_bridge *bridge,
if (mhdp->info && mhdp->info->ops && mhdp->info->ops->disable)
mhdp->info->ops->disable(mhdp);
mhdp->connector = NULL;
mutex_unlock(&mhdp->link_mutex);
}
@ -2122,6 +1962,10 @@ static int cdns_mhdp_atomic_check(struct drm_bridge *bridge,
{
struct cdns_mhdp_device *mhdp = bridge_to_mhdp(bridge);
const struct drm_display_mode *mode = &crtc_state->adjusted_mode;
struct drm_connector_state *old_state, *new_state;
struct drm_atomic_state *state = crtc_state->state;
struct drm_connector *conn = mhdp->connector;
u64 old_cp, new_cp;
mutex_lock(&mhdp->link_mutex);
@ -2141,6 +1985,25 @@ static int cdns_mhdp_atomic_check(struct drm_bridge *bridge,
if (mhdp->info)
bridge_state->input_bus_cfg.flags = *mhdp->info->input_bus_flags;
if (conn && mhdp->hdcp_supported) {
old_state = drm_atomic_get_old_connector_state(state, conn);
new_state = drm_atomic_get_new_connector_state(state, conn);
old_cp = old_state->content_protection;
new_cp = new_state->content_protection;
if (old_state->hdcp_content_type != new_state->hdcp_content_type &&
new_cp != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
new_state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc);
crtc_state->mode_changed = true;
}
if (!new_state->crtc) {
if (old_cp == DRM_MODE_CONTENT_PROTECTION_ENABLED)
new_state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
}
}
mutex_unlock(&mhdp->link_mutex);
return 0;
}
@ -2161,6 +2024,25 @@ static const struct drm_edid *cdns_mhdp_bridge_edid_read(struct drm_bridge *brid
return cdns_mhdp_edid_read(mhdp, connector);
}
static enum drm_mode_status
cdns_mhdp_bridge_mode_valid(struct drm_bridge *bridge,
const struct drm_display_info *info,
const struct drm_display_mode *mode)
{
struct cdns_mhdp_device *mhdp = bridge_to_mhdp(bridge);
mutex_lock(&mhdp->link_mutex);
if (!cdns_mhdp_bandwidth_ok(mhdp, mode, mhdp->link.num_lanes,
mhdp->link.rate)) {
mutex_unlock(&mhdp->link_mutex);
return MODE_CLOCK_HIGH;
}
mutex_unlock(&mhdp->link_mutex);
return MODE_OK;
}
static const struct drm_bridge_funcs cdns_mhdp_bridge_funcs = {
.atomic_enable = cdns_mhdp_atomic_enable,
.atomic_disable = cdns_mhdp_atomic_disable,
@ -2175,6 +2057,7 @@ static const struct drm_bridge_funcs cdns_mhdp_bridge_funcs = {
.edid_read = cdns_mhdp_bridge_edid_read,
.hpd_enable = cdns_mhdp_bridge_hpd_enable,
.hpd_disable = cdns_mhdp_bridge_hpd_disable,
.mode_valid = cdns_mhdp_bridge_mode_valid,
};
static bool cdns_mhdp_detect_hpd(struct cdns_mhdp_device *mhdp, bool *hpd_pulse)
@ -2296,7 +2179,7 @@ static void cdns_mhdp_modeset_retry_fn(struct work_struct *work)
mhdp = container_of(work, typeof(*mhdp), modeset_retry_work);
conn = &mhdp->connector;
conn = mhdp->connector;
/* Grab the locks before changing connector property */
mutex_lock(&conn->dev->mode_config.mutex);
@ -2370,17 +2253,9 @@ static void cdns_mhdp_hpd_work(struct work_struct *work)
struct cdns_mhdp_device *mhdp = container_of(work,
struct cdns_mhdp_device,
hpd_work);
int ret;
cdns_mhdp_update_link_status(mhdp);
ret = cdns_mhdp_update_link_status(mhdp);
if (mhdp->connector.dev) {
if (ret < 0)
schedule_work(&mhdp->modeset_retry_work);
else
drm_kms_helper_hotplug_event(mhdp->bridge.dev);
} else {
drm_bridge_hpd_notify(&mhdp->bridge, cdns_mhdp_detect(mhdp));
}
drm_bridge_hpd_notify(&mhdp->bridge, cdns_mhdp_detect(mhdp));
}
static int cdns_mhdp_probe(struct platform_device *pdev)

View File

@ -375,7 +375,7 @@ struct cdns_mhdp_device {
*/
struct mutex link_mutex;
struct drm_connector connector;
struct drm_connector *connector;
struct drm_bridge bridge;
struct cdns_mhdp_link link;

View File

@ -394,7 +394,7 @@ static int _cdns_mhdp_hdcp_disable(struct cdns_mhdp_device *mhdp)
int ret;
dev_dbg(mhdp->dev, "[%s:%d] HDCP is being disabled...\n",
mhdp->connector.name, mhdp->connector.base.id);
mhdp->connector->name, mhdp->connector->base.id);
ret = cdns_mhdp_hdcp_set_config(mhdp, 0, false);
@ -436,6 +436,10 @@ static int cdns_mhdp_hdcp_check_link(struct cdns_mhdp_device *mhdp)
int ret = 0;
mutex_lock(&mhdp->hdcp.mutex);
if (!mhdp->connector)
goto out;
if (mhdp->hdcp.value == DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
goto out;
@ -445,7 +449,7 @@ static int cdns_mhdp_hdcp_check_link(struct cdns_mhdp_device *mhdp)
dev_err(mhdp->dev,
"[%s:%d] HDCP link failed, retrying authentication\n",
mhdp->connector.name, mhdp->connector.base.id);
mhdp->connector->name, mhdp->connector->base.id);
ret = _cdns_mhdp_hdcp_disable(mhdp);
if (ret) {
@ -487,13 +491,19 @@ static void cdns_mhdp_hdcp_prop_work(struct work_struct *work)
struct cdns_mhdp_device *mhdp = container_of(hdcp,
struct cdns_mhdp_device,
hdcp);
struct drm_device *dev = mhdp->connector.dev;
struct drm_device *dev = NULL;
struct drm_connector_state *state;
if (mhdp->connector)
dev = mhdp->connector->dev;
if (!dev)
return;
drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
mutex_lock(&mhdp->hdcp.mutex);
if (mhdp->hdcp.value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
state = mhdp->connector.state;
state = mhdp->connector->state;
state->content_protection = mhdp->hdcp.value;
}
mutex_unlock(&mhdp->hdcp.mutex);

View File

@ -265,6 +265,8 @@ void drm_gem_shmem_put_pages_locked(struct drm_gem_shmem_object *shmem)
shmem->pages_mark_dirty_on_put,
shmem->pages_mark_accessed_on_put);
shmem->pages = NULL;
shmem->pages_mark_accessed_on_put = false;
shmem->pages_mark_dirty_on_put = false;
}
}
EXPORT_SYMBOL_GPL(drm_gem_shmem_put_pages_locked);
@ -397,6 +399,8 @@ int drm_gem_shmem_vmap_locked(struct drm_gem_shmem_object *shmem,
} else {
iosys_map_set_vaddr(map, shmem->vaddr);
refcount_set(&shmem->vmap_use_count, 1);
shmem->pages_mark_accessed_on_put = true;
shmem->pages_mark_dirty_on_put = true;
}
}
@ -550,59 +554,59 @@ int drm_gem_shmem_dumb_create(struct drm_file *file, struct drm_device *dev,
}
EXPORT_SYMBOL_GPL(drm_gem_shmem_dumb_create);
static bool drm_gem_shmem_try_map_pmd(struct vm_fault *vmf, unsigned long addr,
struct page *page)
static vm_fault_t drm_gem_shmem_try_insert_pfn_pmd(struct vm_fault *vmf, unsigned long pfn)
{
#ifdef CONFIG_ARCH_SUPPORTS_PMD_PFNMAP
unsigned long pfn = page_to_pfn(page);
unsigned long paddr = pfn << PAGE_SHIFT;
bool aligned = (addr & ~PMD_MASK) == (paddr & ~PMD_MASK);
bool aligned = (vmf->address & ~PMD_MASK) == (paddr & ~PMD_MASK);
if (aligned &&
pmd_none(*vmf->pmd) &&
folio_test_pmd_mappable(page_folio(page))) {
if (aligned && pmd_none(*vmf->pmd)) {
/* Read-only mapping; split upon write fault */
pfn &= PMD_MASK >> PAGE_SHIFT;
if (vmf_insert_pfn_pmd(vmf, pfn, false) == VM_FAULT_NOPAGE)
return true;
return vmf_insert_pfn_pmd(vmf, pfn, false);
}
#endif
return false;
return 0;
}
static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf)
{
struct vm_area_struct *vma = vmf->vma;
struct drm_gem_object *obj = vma->vm_private_data;
struct drm_device *dev = obj->dev;
struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
loff_t num_pages = obj->size >> PAGE_SHIFT;
vm_fault_t ret;
vm_fault_t ret = VM_FAULT_SIGBUS;
struct page **pages = shmem->pages;
pgoff_t page_offset;
pgoff_t page_offset = vmf->pgoff - vma->vm_pgoff; /* page offset within VMA */
struct page *page;
struct folio *folio;
unsigned long pfn;
/* Offset to faulty address in the VMA. */
page_offset = vmf->pgoff - vma->vm_pgoff;
dma_resv_lock(obj->resv, NULL);
dma_resv_lock(shmem->base.resv, NULL);
if (page_offset >= num_pages ||
drm_WARN_ON_ONCE(obj->dev, !shmem->pages) ||
shmem->madv < 0) {
ret = VM_FAULT_SIGBUS;
if (page_offset >= num_pages || drm_WARN_ON_ONCE(dev, !shmem->pages) ||
shmem->madv < 0)
goto out;
}
if (drm_gem_shmem_try_map_pmd(vmf, vmf->address, pages[page_offset])) {
ret = VM_FAULT_NOPAGE;
page = pages[page_offset];
if (drm_WARN_ON_ONCE(dev, !page))
goto out;
}
folio = page_folio(page);
pfn = page_to_pfn(pages[page_offset]);
ret = vmf_insert_pfn(vma, vmf->address, pfn);
pfn = page_to_pfn(page);
out:
dma_resv_unlock(shmem->base.resv);
if (folio_test_pmd_mappable(folio))
ret = drm_gem_shmem_try_insert_pfn_pmd(vmf, pfn);
if (ret != VM_FAULT_NOPAGE)
ret = vmf_insert_pfn(vma, vmf->address, pfn);
if (ret == VM_FAULT_NOPAGE)
folio_mark_accessed(folio);
out:
dma_resv_unlock(obj->resv);
return ret;
}
@ -641,10 +645,29 @@ static void drm_gem_shmem_vm_close(struct vm_area_struct *vma)
drm_gem_vm_close(vma);
}
static vm_fault_t drm_gem_shmem_pfn_mkwrite(struct vm_fault *vmf)
{
struct vm_area_struct *vma = vmf->vma;
struct drm_gem_object *obj = vma->vm_private_data;
struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
loff_t num_pages = obj->size >> PAGE_SHIFT;
pgoff_t page_offset = vmf->pgoff - vma->vm_pgoff; /* page offset within VMA */
if (drm_WARN_ON(obj->dev, !shmem->pages || page_offset >= num_pages))
return VM_FAULT_SIGBUS;
file_update_time(vma->vm_file);
folio_mark_dirty(page_folio(shmem->pages[page_offset]));
return 0;
}
const struct vm_operations_struct drm_gem_shmem_vm_ops = {
.fault = drm_gem_shmem_fault,
.open = drm_gem_shmem_vm_open,
.close = drm_gem_shmem_vm_close,
.pfn_mkwrite = drm_gem_shmem_pfn_mkwrite,
};
EXPORT_SYMBOL_GPL(drm_gem_shmem_vm_ops);

View File

@ -25,7 +25,10 @@
static void pvr_gem_object_free(struct drm_gem_object *obj)
{
drm_gem_shmem_object_free(obj);
struct drm_gem_shmem_object *shmem_obj = to_drm_gem_shmem_obj(obj);
shmem_obj->pages_mark_dirty_on_put = true;
drm_gem_shmem_free(shmem_obj);
}
static struct dma_buf *pvr_gem_export(struct drm_gem_object *obj, int flags)
@ -363,7 +366,6 @@ pvr_gem_object_create(struct pvr_device *pvr_dev, size_t size, u64 flags)
if (IS_ERR(shmem_obj))
return ERR_CAST(shmem_obj);
shmem_obj->pages_mark_dirty_on_put = true;
shmem_obj->map_wc = !(flags & PVR_BO_CPU_CACHED);
pvr_obj = shmem_gem_to_pvr_gem(shmem_obj);
pvr_obj->flags = flags;

View File

@ -13,6 +13,7 @@
#include <drm/drm_drv.h>
#include <drm/drm_fbdev_ttm.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_gem_ttm_helper.h>
#include <drm/drm_ioctl.h>
#include <drm/drm_modeset_helper.h>
#include <drm/drm_print.h>
@ -45,7 +46,7 @@ static const struct drm_driver lsdc_drm_driver = {
.debugfs_init = lsdc_debugfs_init,
.dumb_create = lsdc_dumb_create,
.dumb_map_offset = lsdc_dumb_map_offset,
.dumb_map_offset = drm_gem_ttm_dumb_map_offset,
.gem_prime_import_sg_table = lsdc_prime_import_sg_table,
DRM_FBDEV_TTM_DRIVER_OPS,
};

View File

@ -234,21 +234,6 @@ int lsdc_dumb_create(struct drm_file *file, struct drm_device *ddev,
return 0;
}
int lsdc_dumb_map_offset(struct drm_file *filp, struct drm_device *ddev,
u32 handle, uint64_t *offset)
{
struct drm_gem_object *gobj;
gobj = drm_gem_object_lookup(filp, handle);
if (!gobj)
return -ENOENT;
*offset = drm_vma_node_offset_addr(&gobj->vma_node);
drm_gem_object_put(gobj);
return 0;
}
void lsdc_gem_init(struct drm_device *ddev)
{

View File

@ -14,10 +14,6 @@ lsdc_prime_import_sg_table(struct drm_device *ddev,
struct dma_buf_attachment *attach,
struct sg_table *sg);
int lsdc_dumb_map_offset(struct drm_file *file,
struct drm_device *dev,
u32 handle,
uint64_t *offset);
int lsdc_dumb_create(struct drm_file *file,
struct drm_device *ddev,

View File

@ -149,15 +149,17 @@ static int lcdif_load(struct drm_device *drm)
lcdif->clk = devm_clk_get(drm->dev, "pix");
if (IS_ERR(lcdif->clk))
return PTR_ERR(lcdif->clk);
return dev_err_probe(drm->dev, PTR_ERR(lcdif->clk), "Failed to get pix clock\n");
lcdif->clk_axi = devm_clk_get(drm->dev, "axi");
if (IS_ERR(lcdif->clk_axi))
return PTR_ERR(lcdif->clk_axi);
return dev_err_probe(drm->dev, PTR_ERR(lcdif->clk_axi),
"Failed to get axi clock\n");
lcdif->clk_disp_axi = devm_clk_get(drm->dev, "disp_axi");
if (IS_ERR(lcdif->clk_disp_axi))
return PTR_ERR(lcdif->clk_disp_axi);
return dev_err_probe(drm->dev, PTR_ERR(lcdif->clk_disp_axi),
"Failed to get disp_axi clock\n");
platform_set_drvdata(pdev, drm);

View File

@ -443,6 +443,15 @@ config DRM_PANEL_LG_SW43408
pixel. It provides a MIPI DSI interface to the host and has a
built-in LED backlight.
config DRM_PANEL_LXD_M9189A
tristate "LXD M9189A MIPI-DSI LCD panel"
depends on OF
depends on DRM_MIPI_DSI
depends on BACKLIGHT_CLASS_DEVICE
help
Say Y if you want to enable support for the LXD M9189A 4-Lane
1024x600 MIPI DSI panel.
config DRM_PANEL_MAGNACHIP_D53E6EA8966
tristate "Magnachip D53E6EA8966 DSI panel"
depends on OF && SPI
@ -465,6 +474,18 @@ config DRM_PANEL_MANTIX_MLAF057WE51
has a resolution of 720x1440 pixels, a built in backlight and touch
controller.
config DRM_PANEL_MOTOROLA_MOT
tristate "Atrix 4G and Droid X2 540x960 DSI video mode panel"
depends on OF
depends on DRM_MIPI_DSI
depends on BACKLIGHT_CLASS_DEVICE
select VIDEOMODE_HELPERS
help
Say Y here if you want to enable support for the LCD panel module
for Motorola Atrix 4G or Droid X2. Exact panel vendor and model are
unknown. The panel has a 540x960 resolution and uses 24 bit RGB per
pixel.
config DRM_PANEL_NEC_NL8048HL11
tristate "NEC NL8048HL11 RGB panel"
depends on GPIOLIB && OF && SPI
@ -554,6 +575,15 @@ config DRM_PANEL_NOVATEK_NT36672E
LCD panel module. The panel has a resolution of 1080x2408 and uses 24 bit
RGB per pixel.
config DRM_PANEL_NOVATEK_NT37700F
tristate "Novatek NT37700F DSI panel"
depends on OF
depends on DRM_MIPI_DSI
depends on BACKLIGHT_CLASS_DEVICE
help
Say Y here if you want to enable support for Novatek NT37700F DSI
panel module. The panel has a resolution of 1080x2160.
config DRM_PANEL_NOVATEK_NT37801
tristate "Novatek NT37801/NT37810 AMOLED DSI panel"
depends on OF
@ -689,6 +719,7 @@ config DRM_PANEL_RENESAS_R61307
depends on OF
depends on DRM_MIPI_DSI
depends on BACKLIGHT_CLASS_DEVICE
select VIDEOMODE_HELPERS
help
Say Y here if you want to enable support for KOE tx13d100vm0eaa
IPS-LCD module with Renesas R69328 IC. The panel has a 1024x768
@ -702,6 +733,7 @@ config DRM_PANEL_RENESAS_R69328
depends on OF
depends on DRM_MIPI_DSI
depends on BACKLIGHT_CLASS_DEVICE
select VIDEOMODE_HELPERS
help
Say Y here if you want to enable support for JDI dx12d100vm0eaa
IPS-LCD module with Renesas R69328 IC. The panel has a 720x1280

View File

@ -44,7 +44,9 @@ obj-$(CONFIG_DRM_PANEL_LG_LB035Q02) += panel-lg-lb035q02.o
obj-$(CONFIG_DRM_PANEL_LG_LD070WX3) += panel-lg-ld070wx3.o
obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o
obj-$(CONFIG_DRM_PANEL_LG_SW43408) += panel-lg-sw43408.o
obj-$(CONFIG_DRM_PANEL_LXD_M9189A) += panel-lxd-m9189a.o
obj-$(CONFIG_DRM_PANEL_MAGNACHIP_D53E6EA8966) += panel-magnachip-d53e6ea8966.o
obj-$(CONFIG_DRM_PANEL_MOTOROLA_MOT) += panel-motorola-mot.o
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
@ -54,6 +56,7 @@ obj-$(CONFIG_DRM_PANEL_NOVATEK_NT35950) += panel-novatek-nt35950.o
obj-$(CONFIG_DRM_PANEL_NOVATEK_NT36523) += panel-novatek-nt36523.o
obj-$(CONFIG_DRM_PANEL_NOVATEK_NT36672A) += panel-novatek-nt36672a.o
obj-$(CONFIG_DRM_PANEL_NOVATEK_NT36672E) += panel-novatek-nt36672e.o
obj-$(CONFIG_DRM_PANEL_NOVATEK_NT37700F) += panel-novatek-nt37700f.o
obj-$(CONFIG_DRM_PANEL_NOVATEK_NT37801) += panel-novatek-nt37801.o
obj-$(CONFIG_DRM_PANEL_NOVATEK_NT39016) += panel-novatek-nt39016.o
obj-$(CONFIG_DRM_PANEL_MANTIX_MLAF057WE51) += panel-mantix-mlaf057we51.o

View File

@ -592,7 +592,7 @@ static int ili9882t_unprepare(struct drm_panel *panel)
{
struct ili9882t *ili = to_ili9882t(panel);
gpiod_set_value(ili->enable_gpio, 0);
gpiod_set_value_cansleep(ili->enable_gpio, 0);
usleep_range(1000, 2000);
regulator_disable(ili->avee);
regulator_disable(ili->avdd);
@ -608,7 +608,7 @@ static int ili9882t_prepare(struct drm_panel *panel)
struct ili9882t *ili = to_ili9882t(panel);
int ret;
gpiod_set_value(ili->enable_gpio, 0);
gpiod_set_value_cansleep(ili->enable_gpio, 0);
usleep_range(1000, 1500);
ret = regulator_enable(ili->pp3300);
@ -638,11 +638,11 @@ static int ili9882t_prepare(struct drm_panel *panel)
}
usleep_range(1000, 2000);
gpiod_set_value(ili->enable_gpio, 1);
gpiod_set_value_cansleep(ili->enable_gpio, 1);
usleep_range(1000, 2000);
gpiod_set_value(ili->enable_gpio, 0);
gpiod_set_value_cansleep(ili->enable_gpio, 0);
msleep(50);
gpiod_set_value(ili->enable_gpio, 1);
gpiod_set_value_cansleep(ili->enable_gpio, 1);
usleep_range(6000, 10000);
ret = ili->desc->init(ili);
@ -652,7 +652,7 @@ static int ili9882t_prepare(struct drm_panel *panel)
return 0;
poweroff:
gpiod_set_value(ili->enable_gpio, 0);
gpiod_set_value_cansleep(ili->enable_gpio, 0);
regulator_disable(ili->avee);
poweroffavdd:
regulator_disable(ili->avdd);
@ -793,7 +793,7 @@ static int ili9882t_add(struct ili9882t *ili)
return PTR_ERR(ili->enable_gpio);
}
gpiod_set_value(ili->enable_gpio, 0);
gpiod_set_value_cansleep(ili->enable_gpio, 0);
err = of_drm_get_panel_orientation(dev->of_node, &ili->orientation);
if (err < 0) {

View File

@ -1366,6 +1366,246 @@ static const struct jadard_panel_desc anbernic_rgds_display_desc = {
MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM,
};
static int taiguan_xti05101_01a_init_cmds(struct jadard *jadard)
{
struct mipi_dsi_multi_context dsi_ctx = { .dsi = jadard->dsi };
jd9365da_switch_page(&dsi_ctx, 0x00);
jadard_enable_standard_cmds(&dsi_ctx);
jd9365da_switch_page(&dsi_ctx, 0x01);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0c, 0x74);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x17, 0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x18, 0xd7);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x19, 0x01);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1a, 0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1b, 0xd7);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1c, 0x01);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x24, 0xfe);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x37, 0x19);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x35, 0x28);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x38, 0x05);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x39, 0x08);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3a, 0x12);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3c, 0x78);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3d, 0xff);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3e, 0xff);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3f, 0x7f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x40, 0x06);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x41, 0xa0);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x43, 0x1e);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x44, 0x0b);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x55, 0x02);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x57, 0x6a);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x59, 0x0a);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5a, 0x2e);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5b, 0x1a);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5c, 0x15);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5d, 0x7f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5e, 0x58);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5f, 0x46);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x60, 0x39);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x61, 0x35);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x62, 0x27);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x63, 0x2b);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x64, 0x16);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x65, 0x30);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x66, 0x2e);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x67, 0x2f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x68, 0x4d);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x69, 0x3c);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6a, 0x43);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6b, 0x36);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6c, 0x31);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6d, 0x24);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6e, 0x14);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x02);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x70, 0x7f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x71, 0x58);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x72, 0x46);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x73, 0x39);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x74, 0x35);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x75, 0x27);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x76, 0x2b);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x77, 0x16);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x78, 0x30);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x79, 0x2e);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7a, 0x2f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7b, 0x4d);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7c, 0x3c);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7d, 0x43);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7e, 0x36);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7f, 0x31);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x80, 0x24);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x81, 0x14);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x82, 0x02);
jd9365da_switch_page(&dsi_ctx, 0x02);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x52);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x01, 0x5f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x02, 0x5f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x03, 0x50);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x04, 0x77);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x05, 0x57);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x06, 0x5f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x07, 0x4e);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x08, 0x4c);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x09, 0x5f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0a, 0x4a);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0b, 0x48);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0c, 0x5f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0d, 0x46);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0e, 0x44);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0f, 0x40);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x10, 0x5f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x11, 0x5f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x12, 0x5f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x13, 0x5f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x14, 0x5f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x15, 0x5f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x16, 0x53);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x17, 0x5f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x18, 0x5f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x19, 0x51);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1a, 0x77);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1b, 0x57);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1c, 0x5f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1d, 0x4f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1e, 0x4d);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1f, 0x5f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x20, 0x4b);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x21, 0x49);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x22, 0x5f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x23, 0x47);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x24, 0x45);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x25, 0x41);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x26, 0x5f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x27, 0x5f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x28, 0x5f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x29, 0x5f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2a, 0x5f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2b, 0x5f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2c, 0x13);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2d, 0x1f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2e, 0x1f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2f, 0x01);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x30, 0x17);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x31, 0x17);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x32, 0x1f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x33, 0x0d);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x34, 0x0f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x35, 0x1f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x36, 0x05);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x37, 0x07);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x38, 0x1f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x39, 0x09);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3a, 0x0b);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3b, 0x11);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3c, 0x1f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3d, 0x1f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3e, 0x1f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3f, 0x1f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x40, 0x1f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x41, 0x1f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x42, 0x12);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x43, 0x1f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x44, 0x1f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x45, 0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x46, 0x17);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x47, 0x17);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x48, 0x1f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x49, 0x0c);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4a, 0x0e);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4b, 0x1f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4c, 0x04);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4d, 0x06);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4e, 0x1f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4f, 0x08);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x50, 0x0a);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x51, 0x10);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x52, 0x1f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x53, 0x1f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x54, 0x1f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x55, 0x1f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x56, 0x1f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x57, 0x1f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x58, 0x40);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5b, 0x10);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5c, 0x06);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5d, 0x40);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5e, 0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5f, 0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x60, 0x40);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x61, 0x03);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x62, 0x04);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x63, 0x6c);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x64, 0x6c);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x65, 0x75);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x66, 0x08);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x67, 0xb4);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x68, 0x08);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x69, 0x6c);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6a, 0x6c);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6b, 0x0c);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6d, 0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6e, 0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x88);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x75, 0xbb);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x76, 0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x77, 0x05);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x78, 0x2a);
jd9365da_switch_page(&dsi_ctx, 0x04);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x0e);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x02, 0xb3);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x09, 0x61);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0e, 0x48);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2b, 0x0f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x37, 0x58);
jd9365da_switch_page(&dsi_ctx, 0x00);
mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
mipi_dsi_msleep(&dsi_ctx, 120);
mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
mipi_dsi_msleep(&dsi_ctx, 20);
return dsi_ctx.accum_err;
};
static const struct jadard_panel_desc taiguan_xti05101_01a_desc = {
.mode = {
.clock = (800 + 24 + 24 + 24) * (1280 + 30 + 4 + 8) * 60 / 1000,
.hdisplay = 800,
.hsync_start = 800 + 24,
.hsync_end = 800 + 24 + 24,
.htotal = 800 + 24 + 24 + 24,
.vdisplay = 1280,
.vsync_start = 1280 + 30,
.vsync_end = 1280 + 30 + 4,
.vtotal = 1280 + 30 + 4 + 8,
.width_mm = 135,
.height_mm = 216,
.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
},
.lanes = 4,
.format = MIPI_DSI_FMT_RGB888,
.init = taiguan_xti05101_01a_init_cmds,
.lp11_before_reset = true,
.reset_before_power_off_vcioo = true,
.vcioo_to_lp11_delay_ms = 5,
.lp11_to_reset_delay_ms = 10,
.backlight_off_to_display_off_delay_ms = 3,
.display_off_to_enter_sleep_delay_ms = 50,
.enter_sleep_to_reset_down_delay_ms = 100,
};
static int jadard_dsi_probe(struct mipi_dsi_device *dsi)
{
struct device *dev = &dsi->dev;
@ -1463,6 +1703,10 @@ static const struct of_device_id jadard_of_match[] = {
.compatible = "radxa,display-8hd-ad002",
.data = &radxa_display_8hd_ad002_desc
},
{
.compatible = "taiguanck,xti05101-01a",
.data = &taiguan_xti05101_01a_desc
},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, jadard_of_match);

View File

@ -0,0 +1,243 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree.
* Copyright (c) 2024 Luca Weiss <luca.weiss@fairphone.com>
*/
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/regulator/consumer.h>
#include <linux/types.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
#include <drm/drm_probe_helper.h>
/* Manufacturer specific DSI commands */
#define EK79007AD3_GAMMA1 0x80
#define EK79007AD3_GAMMA2 0x81
#define EK79007AD3_GAMMA3 0x82
#define EK79007AD3_GAMMA4 0x83
#define EK79007AD3_GAMMA5 0x84
#define EK79007AD3_GAMMA6 0x85
#define EK79007AD3_GAMMA7 0x86
#define EK79007AD3_PANEL_CTRL3 0xB2
struct m9189_panel {
struct drm_panel panel;
struct mipi_dsi_device *dsi;
struct regulator *supply;
struct gpio_desc *reset_gpio;
struct gpio_desc *standby_gpio;
};
static inline struct m9189_panel *to_m9189_panel(struct drm_panel *panel)
{
return container_of(panel, struct m9189_panel, panel);
}
static void m9189_reset(struct m9189_panel *m9189)
{
gpiod_set_value_cansleep(m9189->reset_gpio, 0);
msleep(20);
gpiod_set_value_cansleep(m9189->reset_gpio, 1);
msleep(30);
gpiod_set_value_cansleep(m9189->reset_gpio, 0);
msleep(55);
}
static int m9189_on(struct m9189_panel *m9189)
{
struct mipi_dsi_multi_context ctx = { .dsi = m9189->dsi };
ctx.dsi->mode_flags |= MIPI_DSI_MODE_LPM;
/* Gamma 2.2 */
mipi_dsi_dcs_write_seq_multi(&ctx, EK79007AD3_GAMMA1, 0x48);
mipi_dsi_dcs_write_seq_multi(&ctx, EK79007AD3_GAMMA2, 0xB8);
mipi_dsi_dcs_write_seq_multi(&ctx, EK79007AD3_GAMMA3, 0x88);
mipi_dsi_dcs_write_seq_multi(&ctx, EK79007AD3_GAMMA4, 0x88);
mipi_dsi_dcs_write_seq_multi(&ctx, EK79007AD3_GAMMA5, 0x58);
mipi_dsi_dcs_write_seq_multi(&ctx, EK79007AD3_GAMMA6, 0xD2);
mipi_dsi_dcs_write_seq_multi(&ctx, EK79007AD3_GAMMA7, 0x88);
mipi_dsi_msleep(&ctx, 50);
/* 4 Lanes */
mipi_dsi_generic_write_multi(&ctx, (u8[]){ EK79007AD3_PANEL_CTRL3, 0x70 }, 2);
mipi_dsi_dcs_exit_sleep_mode_multi(&ctx);
mipi_dsi_msleep(&ctx, 120);
mipi_dsi_dcs_set_display_on_multi(&ctx);
mipi_dsi_msleep(&ctx, 120);
return ctx.accum_err;
}
static int m9189_disable(struct drm_panel *panel)
{
struct m9189_panel *m9189 = to_m9189_panel(panel);
struct mipi_dsi_multi_context ctx = { .dsi = m9189->dsi };
ctx.dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
mipi_dsi_dcs_enter_sleep_mode_multi(&ctx);
mipi_dsi_msleep(&ctx, 120);
gpiod_set_value_cansleep(m9189->standby_gpio, 1);
return ctx.accum_err;
}
static int m9189_prepare(struct drm_panel *panel)
{
struct m9189_panel *m9189 = to_m9189_panel(panel);
struct device *dev = &m9189->dsi->dev;
int ret;
ret = regulator_enable(m9189->supply);
if (ret < 0) {
dev_err(dev, "Failed to enable regulators: %d\n", ret);
return ret;
}
gpiod_set_value_cansleep(m9189->standby_gpio, 0);
msleep(20);
m9189_reset(m9189);
ret = m9189_on(m9189);
if (ret < 0) {
dev_err(dev, "Failed to initialize panel: %d\n", ret);
gpiod_set_value_cansleep(m9189->reset_gpio, 1);
regulator_disable(m9189->supply);
return ret;
}
return 0;
}
static int m9189_unprepare(struct drm_panel *panel)
{
struct m9189_panel *m9189 = to_m9189_panel(panel);
gpiod_set_value_cansleep(m9189->standby_gpio, 1);
msleep(50);
gpiod_set_value_cansleep(m9189->reset_gpio, 1);
regulator_disable(m9189->supply);
return 0;
}
static const struct drm_display_mode m9189_mode = {
.clock = (1024 + 160 + 160 + 10) * (600 + 12 + 23 + 1) * 60 / 1000,
.hdisplay = 1024,
.hsync_start = 1024 + 160,
.hsync_end = 1024 + 160 + 160,
.htotal = 1024 + 160 + 160 + 10,
.vdisplay = 600,
.vsync_start = 600 + 12,
.vsync_end = 600 + 12 + 23,
.vtotal = 600 + 12 + 23 + 1,
.width_mm = 154,
.height_mm = 86,
};
static int m9189_get_modes(struct drm_panel *panel,
struct drm_connector *connector)
{
return drm_connector_helper_get_modes_fixed(connector, &m9189_mode);
}
static const struct drm_panel_funcs m9189_panel_funcs = {
.prepare = m9189_prepare,
.unprepare = m9189_unprepare,
.disable = m9189_disable,
.get_modes = m9189_get_modes,
};
static int lxd_m9189_probe(struct mipi_dsi_device *dsi)
{
struct device *dev = &dsi->dev;
struct m9189_panel *m9189;
int ret;
m9189 = devm_kzalloc(dev, sizeof(*m9189), GFP_KERNEL);
if (!m9189)
return -ENOMEM;
m9189->supply = devm_regulator_get(dev, "power");
if (IS_ERR(m9189->supply))
return dev_err_probe(dev, PTR_ERR(m9189->supply),
"Failed to get power-supply\n");
m9189->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(m9189->reset_gpio))
return dev_err_probe(dev, PTR_ERR(m9189->reset_gpio),
"Failed to get reset-gpios\n");
m9189->standby_gpio = devm_gpiod_get(dev, "standby", GPIOD_OUT_LOW);
if (IS_ERR(m9189->standby_gpio))
return dev_err_probe(dev, PTR_ERR(m9189->standby_gpio),
"Failed to get standby-gpios\n");
m9189->dsi = dsi;
mipi_dsi_set_drvdata(dsi, m9189);
dsi->lanes = 4;
dsi->format = MIPI_DSI_FMT_RGB888;
dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST;
drm_panel_init(&m9189->panel, dev, &m9189_panel_funcs,
DRM_MODE_CONNECTOR_DSI);
m9189->panel.prepare_prev_first = true;
ret = drm_panel_of_backlight(&m9189->panel);
if (ret)
return dev_err_probe(dev, ret, "Failed to get backlight\n");
drm_panel_add(&m9189->panel);
ret = mipi_dsi_attach(dsi);
if (ret < 0) {
dev_err_probe(dev, ret, "Failed to attach to DSI host\n");
drm_panel_remove(&m9189->panel);
return ret;
}
return 0;
}
static void lxd_m9189_remove(struct mipi_dsi_device *dsi)
{
struct m9189_panel *m9189 = 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(&m9189->panel);
}
static const struct of_device_id lxd_m9189_of_match[] = {
{ .compatible = "lxd,m9189a" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, lxd_m9189_of_match);
static struct mipi_dsi_driver lxd_m9189_driver = {
.probe = lxd_m9189_probe,
.remove = lxd_m9189_remove,
.driver = {
.name = "panel-lxd-m9189a",
.of_match_table = lxd_m9189_of_match,
},
};
module_mipi_dsi_driver(lxd_m9189_driver);
MODULE_DESCRIPTION("DRM driver for LXD M9189A MIPI-DSI panels");
MODULE_LICENSE("GPL");

View File

@ -168,7 +168,7 @@ static const struct drm_display_mode default_mode_mantix = {
.vsync_start = 1440 + 130,
.vsync_end = 1440 + 130 + 8,
.vtotal = 1440 + 130 + 8 + 106,
.clock = 85298,
.clock = 81237,
.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
.width_mm = 65,
.height_mm = 130,
@ -183,7 +183,7 @@ static const struct drm_display_mode default_mode_ys = {
.vsync_start = 1440 + 175,
.vsync_end = 1440 + 175 + 8,
.vtotal = 1440 + 175 + 8 + 50,
.clock = 85298,
.clock = 80706,
.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
.width_mm = 65,
.height_mm = 130,
@ -295,20 +295,10 @@ static int mantix_probe(struct mipi_dsi_device *dsi)
return 0;
}
static void mantix_shutdown(struct mipi_dsi_device *dsi)
{
struct mantix *ctx = mipi_dsi_get_drvdata(dsi);
drm_panel_unprepare(&ctx->panel);
drm_panel_disable(&ctx->panel);
}
static void mantix_remove(struct mipi_dsi_device *dsi)
{
struct mantix *ctx = mipi_dsi_get_drvdata(dsi);
mantix_shutdown(dsi);
mipi_dsi_detach(dsi);
drm_panel_remove(&ctx->panel);
}
@ -323,7 +313,6 @@ MODULE_DEVICE_TABLE(of, mantix_of_match);
static struct mipi_dsi_driver mantix_driver = {
.probe = mantix_probe,
.remove = mantix_remove,
.shutdown = mantix_shutdown,
.driver = {
.name = DRV_NAME,
.of_match_table = mantix_of_match,

View File

@ -0,0 +1,244 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/array_size.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/gpio/consumer.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/property.h>
#include <linux/regulator/consumer.h>
#include <video/mipi_display.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
#include <drm/drm_probe_helper.h>
static const struct regulator_bulk_data mot_panel_supplies[] = {
{ .supply = "vddio" }, { .supply = "vdd" },
};
struct mot_panel {
struct drm_panel panel;
struct mipi_dsi_device *dsi;
struct gpio_desc *reset_gpio;
struct regulator_bulk_data *supplies;
};
static inline struct mot_panel *to_mot_panel(struct drm_panel *panel)
{
return container_of(panel, struct mot_panel, panel);
}
static void mot_panel_reset(struct mot_panel *priv)
{
gpiod_set_value_cansleep(priv->reset_gpio, 1);
usleep_range(50000, 51000);
gpiod_set_value_cansleep(priv->reset_gpio, 0);
usleep_range(10000, 11000);
}
static void mot_es2(struct mipi_dsi_multi_context *ctx)
{
mipi_dsi_generic_write_seq_multi(ctx, 0x55, 0x01);
mipi_dsi_dcs_exit_sleep_mode_multi(ctx);
mipi_dsi_msleep(ctx, 120);
mipi_dsi_generic_write_seq_multi(ctx, 0xf4, 0x00, 0xbb, 0x46, 0x53, 0x0c, 0x49,
0x74, 0x29, 0x12, 0x15, 0x2f, 0x2f, 0x04);
mipi_dsi_generic_write_seq_multi(ctx, 0xf8, 0x4b, 0x04, 0x10, 0x1a, 0x2c, 0x2c,
0x2c, 0x2c, 0x14, 0x12);
mipi_dsi_generic_write_seq_multi(ctx, 0xb5, 0x03, 0x7f, 0x00, 0x80, 0xc7, 0x00);
mipi_dsi_generic_write_seq_multi(ctx, 0xb7, 0x66, 0xf6, 0x46, 0x9f, 0x90, 0x99,
0xff, 0x80, 0x6d, 0x01);
/* Gamma R */
mipi_dsi_generic_write_seq_multi(ctx, 0xf9, 0x04);
mipi_dsi_generic_write_seq_multi(ctx, 0xfa, 0x00, 0x2f, 0x30, 0x12, 0x0e, 0x0c,
0x22, 0x27, 0x31, 0x2e, 0x07, 0x0f);
mipi_dsi_generic_write_seq_multi(ctx, 0xfb, 0x00, 0x2f, 0x30, 0x12, 0x0e, 0x0c,
0x22, 0x27, 0x31, 0x2e, 0x07, 0x0f);
/* Gamma G */
mipi_dsi_generic_write_seq_multi(ctx, 0xf9, 0x02);
mipi_dsi_generic_write_seq_multi(ctx, 0xfa, 0x00, 0x2f, 0x37, 0x15, 0x15, 0x11,
0x1f, 0x25, 0x2d, 0x2a, 0x05, 0x0f);
mipi_dsi_generic_write_seq_multi(ctx, 0xfb, 0x00, 0x2f, 0x37, 0x15, 0x15, 0x11,
0x1f, 0x25, 0x2d, 0x2a, 0x05, 0x0f);
/* Gamma B */
mipi_dsi_generic_write_seq_multi(ctx, 0xf9, 0x01);
mipi_dsi_generic_write_seq_multi(ctx, 0xfa, 0x00, 0x2f, 0x3f, 0x16, 0x1f, 0x15,
0x1f, 0x25, 0x2d, 0x2b, 0x06, 0x0b);
mipi_dsi_generic_write_seq_multi(ctx, 0xfb, 0x00, 0x2f, 0x3f, 0x16, 0x1f, 0x15,
0x1f, 0x25, 0x2d, 0x2b, 0x06, 0x0b);
/* Gamma W */
mipi_dsi_generic_write_seq_multi(ctx, 0xf9, 0x20);
mipi_dsi_generic_write_seq_multi(ctx, 0xfa, 0x00, 0x2f, 0x34, 0x15, 0x1a, 0x11,
0x1f, 0x23, 0x2d, 0x29, 0x02, 0x08);
mipi_dsi_generic_write_seq_multi(ctx, 0xfb, 0x00, 0x2f, 0x34, 0x15, 0x1a, 0x11,
0x1f, 0x23, 0x2d, 0x29, 0x02, 0x08);
mipi_dsi_generic_write_seq_multi(ctx, 0x53, 0x2c);
mipi_dsi_generic_write_seq_multi(ctx, 0x35, 0x00);
}
static int mot_panel_prepare(struct drm_panel *panel)
{
struct mot_panel *priv = to_mot_panel(panel);
struct mipi_dsi_multi_context ctx = { .dsi = priv->dsi };
struct device *dev = panel->dev;
int ret;
ret = regulator_bulk_enable(ARRAY_SIZE(mot_panel_supplies), priv->supplies);
if (ret < 0) {
dev_err(dev, "failed to enable power supplies: %d\n", ret);
return ret;
}
mot_panel_reset(priv);
mipi_dsi_generic_write_seq_multi(&ctx, 0xf0, 0x5a, 0x5a);
mipi_dsi_generic_write_seq_multi(&ctx, 0xf1, 0x5a, 0x5a);
mipi_dsi_generic_write_seq_multi(&ctx, 0xd0, 0x8e);
mot_es2(&ctx);
mipi_dsi_dcs_set_display_on_multi(&ctx);
mipi_dsi_msleep(&ctx, 20);
return ctx.accum_err;
}
static int mot_panel_disable(struct drm_panel *panel)
{
struct mot_panel *priv = to_mot_panel(panel);
struct mipi_dsi_multi_context ctx = { .dsi = priv->dsi };
mipi_dsi_dcs_set_display_off_multi(&ctx);
mipi_dsi_dcs_enter_sleep_mode_multi(&ctx);
mipi_dsi_msleep(&ctx, 70);
return ctx.accum_err;
}
static int mot_panel_unprepare(struct drm_panel *panel)
{
struct mot_panel *priv = to_mot_panel(panel);
usleep_range(10000, 11000);
gpiod_set_value_cansleep(priv->reset_gpio, 1);
usleep_range(5000, 6000);
regulator_bulk_disable(ARRAY_SIZE(mot_panel_supplies), priv->supplies);
return 0;
}
static const struct drm_display_mode mot_panel_mode = {
.clock = (540 + 32 + 32 + 16) * (960 + 12 + 12 + 8) * 60 / 1000,
.hdisplay = 540,
.hsync_start = 540 + 32,
.hsync_end = 540 + 32 + 32,
.htotal = 540 + 32 + 32 + 16,
.vdisplay = 960,
.vsync_start = 960 + 12,
.vsync_end = 960 + 12 + 12,
.vtotal = 960 + 12 + 12 + 8,
.width_mm = 51,
.height_mm = 91,
.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
};
static int mot_panel_get_modes(struct drm_panel *panel,
struct drm_connector *connector)
{
return drm_connector_helper_get_modes_fixed(connector, &mot_panel_mode);
}
static const struct drm_panel_funcs mot_panel_panel_funcs = {
.prepare = mot_panel_prepare,
.disable = mot_panel_disable,
.unprepare = mot_panel_unprepare,
.get_modes = mot_panel_get_modes,
};
static int mot_panel_probe(struct mipi_dsi_device *dsi)
{
struct device *dev = &dsi->dev;
struct mot_panel *priv;
int ret;
priv = devm_drm_panel_alloc(dev, struct mot_panel, panel,
&mot_panel_panel_funcs,
DRM_MODE_CONNECTOR_DSI);
if (IS_ERR(priv))
return PTR_ERR(priv);
ret = devm_regulator_bulk_get_const(dev, ARRAY_SIZE(mot_panel_supplies),
mot_panel_supplies, &priv->supplies);
if (ret < 0)
return dev_err_probe(dev, ret, "failed to get supplies\n");
priv->reset_gpio = devm_gpiod_get_optional(dev, "reset",
GPIOD_OUT_HIGH);
if (IS_ERR(priv->reset_gpio))
return dev_err_probe(dev, PTR_ERR(priv->reset_gpio),
"failed to get reset gpios\n");
priv->dsi = dsi;
mipi_dsi_set_drvdata(dsi, priv);
dsi->lanes = 2;
dsi->format = MIPI_DSI_FMT_RGB888;
dsi->mode_flags = MIPI_DSI_MODE_LPM;
ret = drm_panel_of_backlight(&priv->panel);
if (ret < 0)
return dev_err_probe(dev, ret, "failed to get backlight\n");
drm_panel_add(&priv->panel);
ret = devm_mipi_dsi_attach(dev, dsi);
if (ret < 0) {
drm_panel_remove(&priv->panel);
return dev_err_probe(dev, ret, "failed to attach to DSI host\n");
}
return 0;
}
static void mot_panel_remove(struct mipi_dsi_device *dsi)
{
struct mot_panel *priv = mipi_dsi_get_drvdata(dsi);
drm_panel_remove(&priv->panel);
}
static const struct of_device_id mot_panel_of_match[] = {
{ .compatible = "motorola,mot-panel" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, mot_panel_of_match);
static struct mipi_dsi_driver mot_panel_driver = {
.driver = {
.name = "panel-motorola-mot",
.of_match_table = mot_panel_of_match,
},
.probe = mot_panel_probe,
.remove = mot_panel_remove,
};
module_mipi_dsi_driver(mot_panel_driver);
MODULE_AUTHOR("Svyatoslav Ryhel <clamor95@gmail.com>");
MODULE_DESCRIPTION("Motorola MOT panel driver");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,299 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2024, The Linux Foundation. All rights reserved.
* Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree:
* Copyright (c) 2013, The Linux Foundation. All rights reserved.
*/
#include <linux/backlight.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/regulator/consumer.h>
#include <linux/of.h>
#include <video/mipi_display.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
#include <drm/drm_probe_helper.h>
struct nt37700f_tianma {
struct drm_panel panel;
struct mipi_dsi_device *dsi;
struct regulator *supply;
struct gpio_desc *reset_gpio;
};
static inline
struct nt37700f_tianma *to_nt37700f_tianma(struct drm_panel *panel)
{
return container_of(panel, struct nt37700f_tianma, panel);
}
static void nt37700f_tianma_reset(struct nt37700f_tianma *ctx)
{
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
usleep_range(1000, 2000);
gpiod_set_value_cansleep(ctx->reset_gpio, 0);
usleep_range(10000, 11000);
}
#define nt37700f_tianma_panel_switch_page(ctx, page) \
mipi_dsi_dcs_write_seq_multi((ctx), 0xf0, 0x55, 0xaa, 0x52, 0x08, (page))
static int nt37700f_tianma_on(struct nt37700f_tianma *ctx)
{
struct mipi_dsi_device *dsi = ctx->dsi;
struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
nt37700f_tianma_panel_switch_page(&dsi_ctx, 0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc0, 0x56);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xca, 0x52);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x06);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb5, 0x2b, 0x1a);
nt37700f_tianma_panel_switch_page(&dsi_ctx, 0x01);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcd, 0x04, 0x82);
nt37700f_tianma_panel_switch_page(&dsi_ctx, 0x02);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcc, 0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0xaa, 0x55, 0xa5, 0x80);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x55);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf6, 0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x56);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf6, 0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0xaa, 0x55, 0xa5, 0x81);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x07);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf3, 0x07);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x05);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf3, 0x25);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x90, 0x01);
mipi_dsi_dcs_set_column_address_multi(&dsi_ctx, 0x0000, 1080 - 1);
mipi_dsi_dcs_set_page_address_multi(&dsi_ctx, 0x0000, 2160 - 1);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x20);
mipi_dsi_dcs_set_tear_on_multi(&dsi_ctx, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
nt37700f_tianma_panel_switch_page(&dsi_ctx, 0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc0, 0x56);
nt37700f_tianma_panel_switch_page(&dsi_ctx, 0x02);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcd, 0x00);
nt37700f_tianma_panel_switch_page(&dsi_ctx, 0x04);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xd0, 0x11, 0x64);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x09);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb1, 0x20);
mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
mipi_dsi_msleep(&dsi_ctx, 120);
mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
return dsi_ctx.accum_err;
}
static int nt37700f_tianma_disable(struct drm_panel *panel)
{
struct nt37700f_tianma *ctx = to_nt37700f_tianma(panel);
struct mipi_dsi_device *dsi = ctx->dsi;
struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
mipi_dsi_msleep(&dsi_ctx, 50);
mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
mipi_dsi_msleep(&dsi_ctx, 100);
return dsi_ctx.accum_err;
}
static int nt37700f_tianma_prepare(struct drm_panel *panel)
{
struct nt37700f_tianma *ctx = to_nt37700f_tianma(panel);
struct device *dev = &ctx->dsi->dev;
int ret;
ret = regulator_enable(ctx->supply);
if (ret < 0) {
dev_err(dev, "Failed to enable power supply: %d\n", ret);
return ret;
}
nt37700f_tianma_reset(ctx);
ret = nt37700f_tianma_on(ctx);
if (ret < 0) {
dev_err(dev, "Failed to initialize panel: %d\n", ret);
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
return ret;
}
return 0;
}
static int nt37700f_tianma_unprepare(struct drm_panel *panel)
{
struct nt37700f_tianma *ctx = to_nt37700f_tianma(panel);
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
regulator_disable(ctx->supply);
return 0;
}
static const struct drm_display_mode nt37700f_tianma_mode = {
.clock = (1080 + 32 + 32 + 98) * (2160 + 32 + 4 + 98) * 60 / 1000,
.hdisplay = 1080,
.hsync_start = 1080 + 32,
.hsync_end = 1080 + 32 + 32,
.htotal = 1080 + 32 + 32 + 98,
.vdisplay = 2160,
.vsync_start = 2160 + 32,
.vsync_end = 2160 + 32 + 4,
.vtotal = 2160 + 32 + 4 + 98,
.width_mm = 69,
.height_mm = 137,
.type = DRM_MODE_TYPE_DRIVER,
};
static int nt37700f_tianma_get_modes(struct drm_panel *panel,
struct drm_connector *connector)
{
return drm_connector_helper_get_modes_fixed(connector, &nt37700f_tianma_mode);
}
static const struct drm_panel_funcs nt37700f_tianma_panel_funcs = {
.prepare = nt37700f_tianma_prepare,
.unprepare = nt37700f_tianma_unprepare,
.disable = nt37700f_tianma_disable,
.get_modes = nt37700f_tianma_get_modes,
};
static int nt37700f_tianma_bl_update_status(struct backlight_device *bl)
{
struct mipi_dsi_device *dsi = bl_get_data(bl);
u16 brightness = backlight_get_brightness(bl);
int ret;
dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
ret = mipi_dsi_dcs_set_display_brightness_large(dsi, brightness);
if (ret < 0)
return ret;
dsi->mode_flags |= MIPI_DSI_MODE_LPM;
return 0;
}
static int nt37700f_tianma_bl_get_brightness(struct backlight_device *bl)
{
struct mipi_dsi_device *dsi = bl_get_data(bl);
u16 brightness;
int ret;
dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
ret = mipi_dsi_dcs_get_display_brightness_large(dsi, &brightness);
if (ret < 0)
return ret;
dsi->mode_flags |= MIPI_DSI_MODE_LPM;
return brightness;
}
static const struct backlight_ops nt37700f_tianma_bl_ops = {
.update_status = nt37700f_tianma_bl_update_status,
.get_brightness = nt37700f_tianma_bl_get_brightness,
};
static struct backlight_device *
nt37700f_tianma_create_backlight(struct mipi_dsi_device *dsi)
{
struct device *dev = &dsi->dev;
const struct backlight_properties props = {
.type = BACKLIGHT_RAW,
.brightness = 2047,
.max_brightness = 2047,
};
return devm_backlight_device_register(dev, dev_name(dev), dev, dsi,
&nt37700f_tianma_bl_ops, &props);
}
static int nt37700f_tianma_probe(struct mipi_dsi_device *dsi)
{
struct device *dev = &dsi->dev;
struct nt37700f_tianma *ctx;
int ret;
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
ctx->supply = devm_regulator_get(dev, "power");
if (IS_ERR(ctx->supply))
return dev_err_probe(dev, PTR_ERR(ctx->supply),
"Failed to get power-supply\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");
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_BURST |
MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM;
drm_panel_init(&ctx->panel, dev, &nt37700f_tianma_panel_funcs,
DRM_MODE_CONNECTOR_DSI);
ctx->panel.prepare_prev_first = true;
ctx->panel.backlight = nt37700f_tianma_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) {
drm_panel_remove(&ctx->panel);
return dev_err_probe(dev, ret, "Failed to attach to DSI host\n");
}
return 0;
}
static void nt37700f_tianma_remove(struct mipi_dsi_device *dsi)
{
struct nt37700f_tianma *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 nt37700f_tianma_of_match[] = {
{ .compatible = "novatek,nt37700f" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, nt37700f_tianma_of_match);
static struct mipi_dsi_driver nt37700f_tianma_driver = {
.probe = nt37700f_tianma_probe,
.remove = nt37700f_tianma_remove,
.driver = {
.name = "panel-novatek-nt37700f",
.of_match_table = nt37700f_tianma_of_match,
},
};
module_mipi_dsi_driver(nt37700f_tianma_driver);
MODULE_DESCRIPTION("DRM driver for nt37700f cmd mode dsi tianma panel");
MODULE_LICENSE("GPL");

View File

@ -14,6 +14,7 @@
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
#include <drm/drm_probe_helper.h>
#define R61307_MACP 0xb0 /* Manufacturer CMD Protect */
#define R61307_MACP_ON 0x03
@ -34,8 +35,6 @@ struct renesas_r61307 {
struct gpio_desc *reset_gpio;
bool prepared;
bool dig_cont_adj;
bool inversion;
u32 gamma;
@ -91,9 +90,6 @@ static int renesas_r61307_prepare(struct drm_panel *panel)
struct device *dev = &priv->dsi->dev;
int ret;
if (priv->prepared)
return 0;
ret = regulator_enable(priv->vcc_supply);
if (ret) {
dev_err(dev, "failed to enable vcc power supply\n");
@ -112,7 +108,6 @@ static int renesas_r61307_prepare(struct drm_panel *panel)
renesas_r61307_reset(priv);
priv->prepared = true;
return 0;
}
@ -155,7 +150,7 @@ static int renesas_r61307_enable(struct drm_panel *panel)
mipi_dsi_dcs_set_display_on_multi(&ctx);
mipi_dsi_msleep(&ctx, 50);
return 0;
return ctx.accum_err;
}
static int renesas_r61307_disable(struct drm_panel *panel)
@ -167,16 +162,13 @@ static int renesas_r61307_disable(struct drm_panel *panel)
mipi_dsi_msleep(&ctx, 100);
mipi_dsi_dcs_enter_sleep_mode_multi(&ctx);
return 0;
return ctx.accum_err;
}
static int renesas_r61307_unprepare(struct drm_panel *panel)
{
struct renesas_r61307 *priv = to_renesas_r61307(panel);
if (!priv->prepared)
return 0;
usleep_range(10000, 11000);
gpiod_set_value_cansleep(priv->reset_gpio, 1);
@ -186,7 +178,6 @@ static int renesas_r61307_unprepare(struct drm_panel *panel)
usleep_range(2000, 3000);
regulator_disable(priv->vcc_supply);
priv->prepared = false;
return 0;
}
@ -202,25 +193,13 @@ static const struct drm_display_mode renesas_r61307_mode = {
.vtotal = 1024 + 24 + 8 + 2,
.width_mm = 76,
.height_mm = 101,
.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
};
static int renesas_r61307_get_modes(struct drm_panel *panel,
struct drm_connector *connector)
{
struct drm_display_mode *mode;
mode = drm_mode_duplicate(connector->dev, &renesas_r61307_mode);
if (!mode)
return -ENOMEM;
drm_mode_set_name(mode);
mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
connector->display_info.width_mm = mode->width_mm;
connector->display_info.height_mm = mode->height_mm;
drm_mode_probed_add(connector, mode);
return 1;
return drm_connector_helper_get_modes_fixed(connector, &renesas_r61307_mode);
}
static const struct drm_panel_funcs renesas_r61307_panel_funcs = {
@ -259,7 +238,7 @@ static int renesas_r61307_probe(struct mipi_dsi_device *dsi)
return dev_err_probe(dev, PTR_ERR(priv->reset_gpio),
"Failed to get reset gpios\n");
if (device_property_read_bool(dev, "renesas,inversion"))
if (device_property_read_bool(dev, "renesas,column-inversion"))
priv->inversion = true;
if (device_property_read_bool(dev, "renesas,contrast"))
@ -282,7 +261,7 @@ static int renesas_r61307_probe(struct mipi_dsi_device *dsi)
drm_panel_add(&priv->panel);
ret = mipi_dsi_attach(dsi);
ret = devm_mipi_dsi_attach(dev, dsi);
if (ret) {
drm_panel_remove(&priv->panel);
return dev_err_probe(dev, ret, "Failed to attach to DSI host\n");
@ -294,11 +273,6 @@ static int renesas_r61307_probe(struct mipi_dsi_device *dsi)
static void renesas_r61307_remove(struct mipi_dsi_device *dsi)
{
struct renesas_r61307 *priv = mipi_dsi_get_drvdata(dsi);
int ret;
ret = mipi_dsi_detach(dsi);
if (ret)
dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
drm_panel_remove(&priv->panel);
}

View File

@ -14,6 +14,7 @@
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
#include <drm/drm_probe_helper.h>
#define R69328_MACP 0xb0 /* Manufacturer Access CMD Protect */
#define R69328_MACP_ON 0x03
@ -32,8 +33,6 @@ struct renesas_r69328 {
struct regulator *vdd_supply;
struct regulator *vddio_supply;
struct gpio_desc *reset_gpio;
bool prepared;
};
static inline struct renesas_r69328 *to_renesas_r69328(struct drm_panel *panel)
@ -55,9 +54,6 @@ static int renesas_r69328_prepare(struct drm_panel *panel)
struct device *dev = &priv->dsi->dev;
int ret;
if (priv->prepared)
return 0;
ret = regulator_enable(priv->vdd_supply);
if (ret) {
dev_err(dev, "failed to enable vdd power supply\n");
@ -76,7 +72,6 @@ static int renesas_r69328_prepare(struct drm_panel *panel)
renesas_r69328_reset(priv);
priv->prepared = true;
return 0;
}
@ -122,7 +117,7 @@ static int renesas_r69328_enable(struct drm_panel *panel)
mipi_dsi_dcs_set_display_on_multi(&ctx);
mipi_dsi_msleep(&ctx, 50);
return 0;
return ctx.accum_err;
}
static int renesas_r69328_disable(struct drm_panel *panel)
@ -134,16 +129,13 @@ static int renesas_r69328_disable(struct drm_panel *panel)
mipi_dsi_msleep(&ctx, 60);
mipi_dsi_dcs_enter_sleep_mode_multi(&ctx);
return 0;
return ctx.accum_err;
}
static int renesas_r69328_unprepare(struct drm_panel *panel)
{
struct renesas_r69328 *priv = to_renesas_r69328(panel);
if (!priv->prepared)
return 0;
gpiod_set_value_cansleep(priv->reset_gpio, 1);
usleep_range(5000, 6000);
@ -151,7 +143,6 @@ static int renesas_r69328_unprepare(struct drm_panel *panel)
regulator_disable(priv->vddio_supply);
regulator_disable(priv->vdd_supply);
priv->prepared = false;
return 0;
}
@ -167,25 +158,13 @@ static const struct drm_display_mode renesas_r69328_mode = {
.vtotal = 1280 + 6 + 3 + 1,
.width_mm = 59,
.height_mm = 105,
.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
};
static int renesas_r69328_get_modes(struct drm_panel *panel,
struct drm_connector *connector)
{
struct drm_display_mode *mode;
mode = drm_mode_duplicate(connector->dev, &renesas_r69328_mode);
if (!mode)
return -ENOMEM;
drm_mode_set_name(mode);
mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
connector->display_info.width_mm = mode->width_mm;
connector->display_info.height_mm = mode->height_mm;
drm_mode_probed_add(connector, mode);
return 1;
return drm_connector_helper_get_modes_fixed(connector, &renesas_r69328_mode);
}
static const struct drm_panel_funcs renesas_r69328_panel_funcs = {
@ -238,7 +217,7 @@ static int renesas_r69328_probe(struct mipi_dsi_device *dsi)
drm_panel_add(&priv->panel);
ret = mipi_dsi_attach(dsi);
ret = devm_mipi_dsi_attach(dev, dsi);
if (ret) {
drm_panel_remove(&priv->panel);
return dev_err_probe(dev, ret, "Failed to attach to DSI host\n");
@ -250,11 +229,6 @@ static int renesas_r69328_probe(struct mipi_dsi_device *dsi)
static void renesas_r69328_remove(struct mipi_dsi_device *dsi)
{
struct renesas_r69328 *priv = mipi_dsi_get_drvdata(dsi);
int ret;
ret = mipi_dsi_detach(dsi);
if (ret)
dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
drm_panel_remove(&priv->panel);
}

View File

@ -2096,6 +2096,35 @@ static const struct panel_desc edt_et057090dhu = {
.connector_type = DRM_MODE_CONNECTOR_DPI,
};
static const struct display_timing edt_et057023udba_timing = {
.pixelclock = { 23200000, 24190000, 39640000 },
.hactive = { 640, 640, 640 },
.hfront_porch = { 20, 40, 200 },
.hback_porch = { 87, 40, 1 },
.hsync_len = { 1, 48, 87 },
.vactive = { 480, 480, 480 },
.vfront_porch = { 5, 13, 200 },
.vback_porch = { 31, 31, 29 },
.vsync_len = { 1, 1, 3 },
.flags = DISPLAY_FLAGS_VSYNC_LOW | DISPLAY_FLAGS_HSYNC_LOW |
DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_PIXDATA_POSEDGE |
DISPLAY_FLAGS_SYNC_POSEDGE,
};
static const struct panel_desc edt_et057023udba = {
.timings = &edt_et057023udba_timing,
.num_timings = 1,
.bpc = 8,
.size = {
.width = 115,
.height = 86,
},
.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE |
DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE,
.connector_type = DRM_MODE_CONNECTOR_DPI,
};
static const struct drm_display_mode edt_etm0700g0dh6_mode = {
.clock = 33260,
.hdisplay = 800,
@ -4046,6 +4075,33 @@ static const struct panel_desc powertip_ph800480t013_idf02 = {
.connector_type = DRM_MODE_CONNECTOR_DPI,
};
static const struct drm_display_mode powertip_ph800480t032_zhc19_mode = {
.clock = 27200,
.hdisplay = 800,
.hsync_start = 800 + 52,
.hsync_end = 800 + 52 + 2,
.htotal = 800 + 52 + 2 + 44,
.vdisplay = 480,
.vsync_start = 480 + 7,
.vsync_end = 480 + 7 + 2,
.vtotal = 480 + 7 + 2 + 2,
};
static const struct panel_desc powertip_ph800480t032_zhc19 = {
.modes = &powertip_ph800480t032_zhc19_mode,
.num_modes = 1,
.bpc = 8,
.size = {
.width = 152,
.height = 91,
},
.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
.bus_flags = DRM_BUS_FLAG_DE_HIGH |
DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE |
DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE,
.connector_type = DRM_MODE_CONNECTOR_DPI,
};
static const struct drm_display_mode primeview_pm070wl4_mode = {
.clock = 32000,
.hdisplay = 800,
@ -4976,6 +5032,33 @@ static const struct panel_desc vl050_8048nt_c01 = {
.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE,
};
static const struct drm_display_mode waveshare_133inch_mode = {
.clock = 148500,
.hdisplay = 1920,
.hsync_start = 1920 + 88,
.hsync_end = 1920 + 88 + 44,
.htotal = 1920 + 88 + 44 + 148,
.vdisplay = 1080,
.vsync_start = 1080 + 4,
.vsync_end = 1080 + 4 + 5,
.vtotal = 1080 + 4 + 5 + 36,
.flags = DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_PHSYNC,
};
static const struct panel_desc waveshare_133inch = {
.modes = &waveshare_133inch_mode,
.num_modes = 1,
.bpc = 8,
.size = {
.width = 293,
.height = 163,
},
.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
.connector_type = DRM_MODE_CONNECTOR_DPI,
.bus_flags = DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE |
DRM_BUS_FLAG_SYNC_SAMPLE_POSEDGE,
};
static const struct drm_display_mode winstar_wf35ltiacd_mode = {
.clock = 6410,
.hdisplay = 320,
@ -5225,6 +5308,9 @@ static const struct of_device_id platform_of_match[] = {
}, {
.compatible = "edt,etm0430g0dh6",
.data = &edt_etm0430g0dh6,
}, {
.compatible = "edt,et057023udba",
.data = &edt_et057023udba,
}, {
.compatible = "edt,et057090dhu",
.data = &edt_et057090dhu,
@ -5456,6 +5542,9 @@ static const struct of_device_id platform_of_match[] = {
}, {
.compatible = "powertip,ph800480t013-idf02",
.data = &powertip_ph800480t013_idf02,
}, {
.compatible = "powertip,ph800480t032-zhc19",
.data = &powertip_ph800480t032_zhc19,
}, {
.compatible = "primeview,pm070wl4",
.data = &primeview_pm070wl4,
@ -5573,6 +5662,9 @@ static const struct of_device_id platform_of_match[] = {
}, {
.compatible = "vxt,vl050-8048nt-c01",
.data = &vl050_8048nt_c01,
}, {
.compatible = "waveshare,13.3inch-panel",
.data = &waveshare_133inch,
}, {
.compatible = "winstar,wf35ltiacd",
.data = &winstar_wf35ltiacd,

View File

@ -3916,7 +3916,7 @@ static void job_release(struct kref *ref)
if (job->base.s_fence)
drm_sched_job_cleanup(&job->base);
if (job->done_fence && job->done_fence->ops)
if (dma_fence_was_initialized(job->done_fence))
dma_fence_put(job->done_fence);
else
dma_fence_free(job->done_fence);

View File

@ -222,10 +222,8 @@ static void ttm_bo_flush_all_fences(struct ttm_buffer_object *bo)
struct dma_fence *fence;
dma_resv_iter_begin(&cursor, resv, DMA_RESV_USAGE_BOOKKEEP);
dma_resv_for_each_fence_unlocked(&cursor, fence) {
if (!fence->ops->signaled)
dma_fence_enable_sw_signaling(fence);
}
dma_resv_for_each_fence_unlocked(&cursor, fence)
dma_fence_enable_sw_signaling(fence);
dma_resv_iter_end(&cursor);
}

View File

@ -2449,17 +2449,23 @@ static int vc4_hdmi_hotplug_init(struct vc4_hdmi *vc4_hdmi)
int ret;
if (vc4_hdmi->variant->external_irq_controller) {
unsigned int hpd_con = platform_get_irq_byname(pdev, "hpd-connected");
unsigned int hpd_rm = platform_get_irq_byname(pdev, "hpd-removed");
int hpd = platform_get_irq_byname(pdev, "hpd-connected");
ret = devm_request_threaded_irq(&pdev->dev, hpd_con,
if (hpd < 0)
return hpd;
ret = devm_request_threaded_irq(&pdev->dev, hpd,
NULL,
vc4_hdmi_hpd_irq_thread, IRQF_ONESHOT,
"vc4 hdmi hpd connected", vc4_hdmi);
if (ret)
return ret;
ret = devm_request_threaded_irq(&pdev->dev, hpd_rm,
hpd = platform_get_irq_byname(pdev, "hpd-removed");
if (hpd < 0)
return hpd;
ret = devm_request_threaded_irq(&pdev->dev, hpd,
NULL,
vc4_hdmi_hpd_irq_thread, IRQF_ONESHOT,
"vc4 hdmi hpd disconnected", vc4_hdmi);

View File

@ -21,6 +21,170 @@ static inline u64 get_size(int order, u64 chunk_size)
return (1 << order) * chunk_size;
}
static void gpu_test_buddy_subtree_offset_alignment_stress(struct kunit *test)
{
struct gpu_buddy_block *block;
struct rb_node *node = NULL;
const u64 mm_size = SZ_2M;
const u64 alignments[] = {
SZ_1M,
SZ_512K,
SZ_256K,
SZ_128K,
SZ_64K,
SZ_32K,
SZ_16K,
SZ_8K,
};
struct list_head allocated[ARRAY_SIZE(alignments)];
unsigned int i, max_subtree_align = 0;
int ret, tree, order;
struct gpu_buddy mm;
KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_init(&mm, mm_size, SZ_4K),
"buddy_init failed\n");
for (i = 0; i < ARRAY_SIZE(allocated); i++)
INIT_LIST_HEAD(&allocated[i]);
/*
* Exercise subtree_max_alignment tracking by allocating blocks with descending
* alignment constraints and freeing them in reverse order. This verifies that
* free-tree augmentation correctly propagates the maximum offset alignment
* present in each subtree at every stage.
*/
for (i = 0; i < ARRAY_SIZE(alignments); i++) {
struct gpu_buddy_block *root = NULL;
unsigned int expected;
u64 align;
align = alignments[i];
expected = ilog2(align) - 1;
for (;;) {
ret = gpu_buddy_alloc_blocks(&mm,
0, mm_size,
SZ_4K, align,
&allocated[i],
0);
if (ret)
break;
block = list_last_entry(&allocated[i],
struct gpu_buddy_block,
link);
KUNIT_EXPECT_TRUE(test, IS_ALIGNED(gpu_buddy_block_offset(block), align));
}
for (order = mm.max_order; order >= 0 && !root; order--) {
for (tree = 0; tree < 2; tree++) {
node = mm.free_trees[tree][order].rb_node;
if (node) {
root = container_of(node,
struct gpu_buddy_block,
rb);
break;
}
}
}
KUNIT_ASSERT_NOT_NULL(test, root);
KUNIT_EXPECT_EQ(test, root->subtree_max_alignment, expected);
}
for (i = ARRAY_SIZE(alignments); i-- > 0; ) {
gpu_buddy_free_list(&mm, &allocated[i], 0);
for (order = 0; order <= mm.max_order; order++) {
for (tree = 0; tree < 2; tree++) {
node = mm.free_trees[tree][order].rb_node;
if (!node)
continue;
block = container_of(node, struct gpu_buddy_block, rb);
max_subtree_align = max(max_subtree_align,
block->subtree_max_alignment);
}
}
KUNIT_EXPECT_GE(test, max_subtree_align, ilog2(alignments[i]));
}
gpu_buddy_fini(&mm);
}
static void gpu_test_buddy_offset_aligned_allocation(struct kunit *test)
{
struct gpu_buddy_block *block, *tmp;
int num_blocks, i, count = 0;
LIST_HEAD(allocated);
struct gpu_buddy mm;
u64 mm_size = SZ_4M;
LIST_HEAD(freed);
KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_init(&mm, mm_size, SZ_4K),
"buddy_init failed\n");
num_blocks = mm_size / SZ_256K;
/*
* Allocate multiple sizes under a fixed offset alignment.
* Ensures alignment handling is independent of allocation size and
* exercises subtree max-alignment pruning for small requests.
*/
for (i = 0; i < num_blocks; i++)
KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size, SZ_8K, SZ_256K,
&allocated, 0),
"buddy_alloc hit an error size=%u\n", SZ_8K);
list_for_each_entry(block, &allocated, link) {
/* Ensure the allocated block uses the expected 8 KB size */
KUNIT_EXPECT_EQ(test, gpu_buddy_block_size(&mm, block), SZ_8K);
/* Ensure the block starts at a 256 KB-aligned offset for proper alignment */
KUNIT_EXPECT_TRUE(test, IS_ALIGNED(gpu_buddy_block_offset(block), SZ_256K));
}
gpu_buddy_free_list(&mm, &allocated, 0);
for (i = 0; i < num_blocks; i++)
KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size, SZ_16K, SZ_256K,
&allocated, 0),
"buddy_alloc hit an error size=%u\n", SZ_16K);
list_for_each_entry(block, &allocated, link) {
/* Ensure the allocated block uses the expected 16 KB size */
KUNIT_EXPECT_EQ(test, gpu_buddy_block_size(&mm, block), SZ_16K);
/* Ensure the block starts at a 256 KB-aligned offset for proper alignment */
KUNIT_EXPECT_TRUE(test, IS_ALIGNED(gpu_buddy_block_offset(block), SZ_256K));
}
/*
* Free alternating aligned blocks to introduce fragmentation.
* Ensures offset-aligned allocations remain valid after frees and
* verifies subtree max-alignment metadata is correctly maintained.
*/
list_for_each_entry_safe(block, tmp, &allocated, link) {
if (count % 2 == 0)
list_move_tail(&block->link, &freed);
count++;
}
gpu_buddy_free_list(&mm, &freed, 0);
for (i = 0; i < num_blocks / 2; i++)
KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size, SZ_16K, SZ_256K,
&allocated, 0),
"buddy_alloc hit an error size=%u\n", SZ_16K);
/*
* Allocate with offset alignment after all slots are used; must fail.
* Confirms that no aligned offsets remain.
*/
KUNIT_ASSERT_TRUE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size, SZ_16K, SZ_256K,
&allocated, 0),
"buddy_alloc hit an error size=%u\n", SZ_16K);
gpu_buddy_free_list(&mm, &allocated, 0);
gpu_buddy_fini(&mm);
}
static void gpu_test_buddy_fragmentation_performance(struct kunit *test)
{
struct gpu_buddy_block *block, *tmp;
@ -362,6 +526,332 @@ static void gpu_test_buddy_alloc_range_bias(struct kunit *test)
gpu_buddy_fini(&mm);
}
static void gpu_test_buddy_alloc_range(struct kunit *test)
{
GPU_RND_STATE(prng, random_seed);
struct gpu_buddy_block *block;
struct gpu_buddy mm;
u32 mm_size, total;
LIST_HEAD(blocks);
LIST_HEAD(tmp);
u32 ps = SZ_4K;
int ret;
mm_size = SZ_16M;
KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_init(&mm, mm_size, ps),
"buddy_init failed\n");
/*
* Basic exact-range allocation.
* Allocate the entire mm as one exact range (start + size == end).
* This is the simplest case exercising __gpu_buddy_alloc_range.
*/
ret = gpu_buddy_alloc_blocks(&mm, 0, mm_size, mm_size, ps, &blocks, 0);
KUNIT_ASSERT_EQ_MSG(test, ret, 0,
"exact-range alloc of full mm failed\n");
total = 0;
list_for_each_entry(block, &blocks, link) {
u64 offset = gpu_buddy_block_offset(block);
u64 bsize = gpu_buddy_block_size(&mm, block);
KUNIT_EXPECT_TRUE_MSG(test, offset + bsize <= (u64)mm_size,
"block [%llx, %llx) outside mm\n", offset, offset + bsize);
total += (u32)bsize;
}
KUNIT_EXPECT_EQ(test, total, mm_size);
KUNIT_EXPECT_EQ(test, mm.avail, 0ULL);
/* Full mm should be exhausted */
ret = gpu_buddy_alloc_blocks(&mm, 0, ps, ps, ps, &tmp, 0);
KUNIT_EXPECT_NE_MSG(test, ret, 0, "alloc should fail when mm is full\n");
gpu_buddy_free_list(&mm, &blocks, 0);
KUNIT_EXPECT_EQ(test, mm.avail, (u64)mm_size);
gpu_buddy_fini(&mm);
/*
* Exact-range allocation of sub-ranges.
* Split the mm into four equal quarters and allocate each as an exact
* range. Validates splitting and non-overlapping exact allocations.
*/
KUNIT_ASSERT_FALSE(test, gpu_buddy_init(&mm, mm_size, ps));
{
u32 quarter = mm_size / 4;
int i;
for (i = 0; i < 4; i++) {
u32 start = i * quarter;
u32 end = start + quarter;
ret = gpu_buddy_alloc_blocks(&mm, start, end, quarter, ps, &blocks, 0);
KUNIT_ASSERT_EQ_MSG(test, ret, 0,
"exact-range alloc quarter %d [%x, %x) failed\n",
i, start, end);
}
KUNIT_EXPECT_EQ(test, mm.avail, 0ULL);
gpu_buddy_free_list(&mm, &blocks, 0);
}
gpu_buddy_fini(&mm);
/*
* Minimum chunk-size exact range at various offsets.
* Allocate single-page exact ranges at the start, middle and end.
*/
KUNIT_ASSERT_FALSE(test, gpu_buddy_init(&mm, mm_size, ps));
ret = gpu_buddy_alloc_blocks(&mm, 0, ps, ps, ps, &blocks, 0);
KUNIT_ASSERT_EQ(test, ret, 0);
ret = gpu_buddy_alloc_blocks(&mm, mm_size / 2, mm_size / 2 + ps, ps, ps, &blocks, 0);
KUNIT_ASSERT_EQ(test, ret, 0);
ret = gpu_buddy_alloc_blocks(&mm, mm_size - ps, mm_size, ps, ps, &blocks, 0);
KUNIT_ASSERT_EQ(test, ret, 0);
total = 0;
list_for_each_entry(block, &blocks, link)
total += (u32)gpu_buddy_block_size(&mm, block);
KUNIT_EXPECT_EQ(test, total, 3 * ps);
gpu_buddy_free_list(&mm, &blocks, 0);
gpu_buddy_fini(&mm);
/*
* Non power-of-two mm size (multiple roots).
* Exact-range allocations that span root boundaries must still work.
*/
mm_size = SZ_4M + SZ_2M + SZ_1M; /* 7 MiB, three roots */
KUNIT_ASSERT_FALSE(test, gpu_buddy_init(&mm, mm_size, ps));
KUNIT_EXPECT_GT(test, mm.n_roots, 1U);
/* Allocate first 4M root exactly */
ret = gpu_buddy_alloc_blocks(&mm, 0, SZ_4M, SZ_4M, ps, &blocks, 0);
KUNIT_ASSERT_EQ(test, ret, 0);
/* Allocate second root (4M-6M) exactly */
ret = gpu_buddy_alloc_blocks(&mm, SZ_4M, SZ_4M + SZ_2M, SZ_2M, ps, &blocks, 0);
KUNIT_ASSERT_EQ(test, ret, 0);
/* Allocate third root (6M-7M) exactly */
ret = gpu_buddy_alloc_blocks(&mm, SZ_4M + SZ_2M, mm_size, SZ_1M, ps, &blocks, 0);
KUNIT_ASSERT_EQ(test, ret, 0);
KUNIT_EXPECT_EQ(test, mm.avail, 0ULL);
gpu_buddy_free_list(&mm, &blocks, 0);
/* Cross-root exact-range: the entire non-pot mm */
ret = gpu_buddy_alloc_blocks(&mm, 0, mm_size, mm_size, ps, &blocks, 0);
KUNIT_ASSERT_EQ(test, ret, 0);
KUNIT_EXPECT_EQ(test, mm.avail, 0ULL);
gpu_buddy_free_list(&mm, &blocks, 0);
gpu_buddy_fini(&mm);
/*
* Randomized exact-range allocations.
* Divide the mm into N random-sized, contiguous, page-aligned slices
* and allocate each as an exact range in random order.
*/
mm_size = SZ_16M;
KUNIT_ASSERT_FALSE(test, gpu_buddy_init(&mm, mm_size, ps));
{
#define N_RAND_RANGES 16
u32 ranges[N_RAND_RANGES + 1]; /* boundaries */
u32 order_arr[N_RAND_RANGES];
u32 remaining = mm_size;
int i;
ranges[0] = 0;
for (i = 0; i < N_RAND_RANGES - 1; i++) {
u32 max_chunk = remaining - (N_RAND_RANGES - 1 - i) * ps;
u32 sz = max(round_up(prandom_u32_state(&prng) % max_chunk, ps), ps);
ranges[i + 1] = ranges[i] + sz;
remaining -= sz;
}
ranges[N_RAND_RANGES] = mm_size;
/* Create a random order */
for (i = 0; i < N_RAND_RANGES; i++)
order_arr[i] = i;
for (i = N_RAND_RANGES - 1; i > 0; i--) {
u32 j = prandom_u32_state(&prng) % (i + 1);
u32 tmp_val = order_arr[i];
order_arr[i] = order_arr[j];
order_arr[j] = tmp_val;
}
for (i = 0; i < N_RAND_RANGES; i++) {
u32 idx = order_arr[i];
u32 start = ranges[idx];
u32 end = ranges[idx + 1];
u32 sz = end - start;
ret = gpu_buddy_alloc_blocks(&mm, start, end, sz, ps, &blocks, 0);
KUNIT_ASSERT_EQ_MSG(test, ret, 0,
"random exact-range [%x, %x) sz=%x failed\n",
start, end, sz);
}
KUNIT_EXPECT_EQ(test, mm.avail, 0ULL);
gpu_buddy_free_list(&mm, &blocks, 0);
#undef N_RAND_RANGES
}
gpu_buddy_fini(&mm);
/*
* Negative case - partially allocated range.
* Allocate the first half, then try to exact-range allocate the full
* mm. This must fail because the first half is already occupied.
*/
mm_size = SZ_16M;
KUNIT_ASSERT_FALSE(test, gpu_buddy_init(&mm, mm_size, ps));
ret = gpu_buddy_alloc_blocks(&mm, 0, mm_size / 2, mm_size / 2, ps, &blocks, 0);
KUNIT_ASSERT_EQ(test, ret, 0);
ret = gpu_buddy_alloc_blocks(&mm, 0, mm_size, mm_size, ps, &tmp, 0);
KUNIT_EXPECT_NE_MSG(test, ret, 0,
"exact-range alloc should fail when range is partially used\n");
/* Also try the already-occupied sub-range directly */
ret = gpu_buddy_alloc_blocks(&mm, 0, mm_size / 2, mm_size / 2, ps, &tmp, 0);
KUNIT_EXPECT_NE_MSG(test, ret, 0,
"double alloc of same exact range should fail\n");
/* The free second half should still be allocatable */
ret = gpu_buddy_alloc_blocks(&mm, mm_size / 2, mm_size, mm_size / 2, ps, &blocks, 0);
KUNIT_ASSERT_EQ(test, ret, 0);
KUNIT_EXPECT_EQ(test, mm.avail, 0ULL);
gpu_buddy_free_list(&mm, &blocks, 0);
gpu_buddy_fini(&mm);
/*
* Negative case - checkerboard partial allocation.
* Allocate every other page-sized chunk in a small mm, then try to
* exact-range allocate a range covering two pages (one allocated, one
* free). This must fail.
*/
mm_size = SZ_64K;
KUNIT_ASSERT_FALSE(test, gpu_buddy_init(&mm, mm_size, ps));
{
u32 off;
for (off = 0; off < mm_size; off += 2 * ps) {
ret = gpu_buddy_alloc_blocks(&mm, off, off + ps, ps, ps, &blocks, 0);
KUNIT_ASSERT_EQ(test, ret, 0);
}
/* Try exact range over a pair [allocated, free] */
ret = gpu_buddy_alloc_blocks(&mm, 0, 2 * ps, 2 * ps, ps, &tmp, 0);
KUNIT_EXPECT_NE_MSG(test, ret, 0,
"exact-range over partially allocated pair should fail\n");
/* The free pages individually should still work */
ret = gpu_buddy_alloc_blocks(&mm, ps, 2 * ps, ps, ps, &blocks, 0);
KUNIT_ASSERT_EQ(test, ret, 0);
gpu_buddy_free_list(&mm, &blocks, 0);
}
gpu_buddy_fini(&mm);
/* Negative case - misaligned start/end/size */
mm_size = SZ_16M;
KUNIT_ASSERT_FALSE(test, gpu_buddy_init(&mm, mm_size, ps));
/* start not aligned to chunk_size */
ret = gpu_buddy_alloc_blocks(&mm, ps / 2, ps / 2 + ps, ps, ps, &tmp, 0);
KUNIT_EXPECT_NE(test, ret, 0);
/* size not aligned */
ret = gpu_buddy_alloc_blocks(&mm, 0, ps + 1, ps + 1, ps, &tmp, 0);
KUNIT_EXPECT_NE(test, ret, 0);
/* end exceeds mm size */
ret = gpu_buddy_alloc_blocks(&mm, mm_size, mm_size + ps, ps, ps, &tmp, 0);
KUNIT_EXPECT_NE(test, ret, 0);
gpu_buddy_fini(&mm);
/*
* Free and re-allocate the same exact range.
* This exercises merge-on-free followed by exact-range re-split.
*/
mm_size = SZ_16M;
KUNIT_ASSERT_FALSE(test, gpu_buddy_init(&mm, mm_size, ps));
{
int i;
for (i = 0; i < 5; i++) {
ret = gpu_buddy_alloc_blocks(&mm, SZ_4M, SZ_4M + SZ_2M,
SZ_2M, ps, &blocks, 0);
KUNIT_ASSERT_EQ_MSG(test, ret, 0,
"re-alloc iteration %d failed\n", i);
total = 0;
list_for_each_entry(block, &blocks, link) {
u64 offset = gpu_buddy_block_offset(block);
u64 bsize = gpu_buddy_block_size(&mm, block);
KUNIT_EXPECT_GE(test, offset, (u64)SZ_4M);
KUNIT_EXPECT_LE(test, offset + bsize, (u64)(SZ_4M + SZ_2M));
total += (u32)bsize;
}
KUNIT_EXPECT_EQ(test, total, SZ_2M);
gpu_buddy_free_list(&mm, &blocks, 0);
}
KUNIT_EXPECT_EQ(test, mm.avail, (u64)mm_size);
}
gpu_buddy_fini(&mm);
/*
* Various power-of-two exact ranges within a large mm.
* Allocate non-overlapping power-of-two exact ranges at their natural
* alignment, validating that the allocator handles different orders.
*/
mm_size = SZ_16M;
KUNIT_ASSERT_FALSE(test, gpu_buddy_init(&mm, mm_size, ps));
/* Allocate 4K at offset 0 */
ret = gpu_buddy_alloc_blocks(&mm, 0, SZ_4K, SZ_4K, ps, &blocks, 0);
KUNIT_ASSERT_EQ(test, ret, 0);
/* Allocate 64K at offset 64K */
ret = gpu_buddy_alloc_blocks(&mm, SZ_64K, SZ_64K + SZ_64K, SZ_64K, ps, &blocks, 0);
KUNIT_ASSERT_EQ(test, ret, 0);
/* Allocate 1M at offset 1M */
ret = gpu_buddy_alloc_blocks(&mm, SZ_1M, SZ_1M + SZ_1M, SZ_1M, ps, &blocks, 0);
KUNIT_ASSERT_EQ(test, ret, 0);
/* Allocate 4M at offset 4M */
ret = gpu_buddy_alloc_blocks(&mm, SZ_4M, SZ_4M + SZ_4M, SZ_4M, ps, &blocks, 0);
KUNIT_ASSERT_EQ(test, ret, 0);
total = 0;
list_for_each_entry(block, &blocks, link)
total += (u32)gpu_buddy_block_size(&mm, block);
KUNIT_EXPECT_EQ(test, total, SZ_4K + SZ_64K + SZ_1M + SZ_4M);
gpu_buddy_free_list(&mm, &blocks, 0);
gpu_buddy_fini(&mm);
}
static void gpu_test_buddy_alloc_clear(struct kunit *test)
{
unsigned long n_pages, total, i = 0;
@ -909,9 +1399,12 @@ static struct kunit_case gpu_buddy_tests[] = {
KUNIT_CASE(gpu_test_buddy_alloc_pathological),
KUNIT_CASE(gpu_test_buddy_alloc_contiguous),
KUNIT_CASE(gpu_test_buddy_alloc_clear),
KUNIT_CASE(gpu_test_buddy_alloc_range),
KUNIT_CASE(gpu_test_buddy_alloc_range_bias),
KUNIT_CASE_SLOW(gpu_test_buddy_fragmentation_performance),
KUNIT_CASE(gpu_test_buddy_alloc_exceeds_max_order),
KUNIT_CASE(gpu_test_buddy_offset_aligned_allocation),
KUNIT_CASE(gpu_test_buddy_subtree_offset_alignment_stress),
{}
};

View File

@ -11,6 +11,7 @@
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/rbtree.h>
#include <linux/rbtree_augmented.h>
/**
* GPU_BUDDY_RANGE_ALLOCATION - Allocate within a specific address range
@ -128,6 +129,7 @@ struct gpu_buddy_block {
};
/* private: */
struct list_head tmp_link;
unsigned int subtree_max_alignment;
};
/* Order-zero must be at least SZ_4K */

View File

@ -353,7 +353,8 @@ struct amdxdna_drm_query_clock_metadata {
};
enum amdxdna_sensor_type {
AMDXDNA_SENSOR_TYPE_POWER
AMDXDNA_SENSOR_TYPE_POWER,
AMDXDNA_SENSOR_TYPE_COLUMN_UTILIZATION
};
/**