drm-misc-next for v6.12:

UAPI Changes:
 
 devfs:
 - support device numbers up to MINORBITS limit
 
 Core Changes:
 
 ci:
 - increase job timeout
 
 devfs:
 - use XArray for minor ids
 
 displayport:
 - mst: GUID improvements
 
 docs:
 - add fixes and cleanups
 
 panic:
 - optionally display QR code
 
 Driver Changes:
 
 amdgpu:
 - faster vblank disabling
 - GUID improvements
 
 gm12u320
 - convert to struct drm_edid
 
 host1x:
 - fix syncpoint IRQ during resume
 - use iommu_paging_domain_alloc()
 
 imx:
 - ipuv3: convert to struct drm_edid
 
 omapdrm:
 - improve error handling
 
 panel:
 - add support for BOE TV101WUM-LL2 plus DT bindings
 - novatek-nt35950: improve error handling
 - nv3051d: improve error handling
 - panel-edp: add support for BOE NE140WUM-N6G; revert support for
   SDC ATNA45AF01
 - visionox-vtdr6130: improve error handling; use
   devm_regulator_bulk_get_const()
 
 renesas:
 - rz-du: add support for RZ/G2UL plus DT bindings
 
 sti:
 - convert to struct drm_edid
 
 tegra:
 - gr3d: improve PM domain handling
 - convert to struct drm_edid
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCgAdFiEEchf7rIzpz2NEoWjlaA3BHVMLeiMFAmbQiVAACgkQaA3BHVML
 eiNgVggAqN5f9i0Rbk5tTfasBBSq0qiNE3X7mHDFQsAY+iGRJUzuYlIjjATSunsB
 HnqcA0aoT3CaBpl1drRTg1wCWRXBZrnAG2mgVa/eGBjrSH2i2d9IgxcNT2XvQkI5
 K4Ac2Ulpr+57d8nHmeEjztQusD2vaDtNH7b6pU2wNmZkiqUCbzcLn9GuL9OF8tSh
 6EApiPExbBASQeV0+xVt7mbtasclzFf8wukQXlK8zlWDeHTTTRibBwRy1txyqdG3
 qnBCabVTorgah81vBezXegrro4yQ1ITo5A1ZTYYJroA70mqMN5cm5kYasIb1zqXP
 f/xXGLB/a96bV9zqEFhWGInlEqGthA==
 =1fX2
 -----END PGP SIGNATURE-----

Merge tag 'drm-misc-next-2024-08-29' of https://gitlab.freedesktop.org/drm/misc/kernel into drm-next

drm-misc-next for v6.12:

UAPI Changes:

devfs:
- support device numbers up to MINORBITS limit

Core Changes:

ci:
- increase job timeout

devfs:
- use XArray for minor ids

displayport:
- mst: GUID improvements

docs:
- add fixes and cleanups

panic:
- optionally display QR code

Driver Changes:

amdgpu:
- faster vblank disabling
- GUID improvements

gm12u320
- convert to struct drm_edid

host1x:
- fix syncpoint IRQ during resume
- use iommu_paging_domain_alloc()

imx:
- ipuv3: convert to struct drm_edid

omapdrm:
- improve error handling

panel:
- add support for BOE TV101WUM-LL2 plus DT bindings
- novatek-nt35950: improve error handling
- nv3051d: improve error handling
- panel-edp: add support for BOE NE140WUM-N6G; revert support for
  SDC ATNA45AF01
- visionox-vtdr6130: improve error handling; use
  devm_regulator_bulk_get_const()

renesas:
- rz-du: add support for RZ/G2UL plus DT bindings

sti:
- convert to struct drm_edid

tegra:
- gr3d: improve PM domain handling
- convert to struct drm_edid

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

From: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://patchwork.freedesktop.org/patch/msgid/20240829144654.GA145538@linux.fritz.box
This commit is contained in:
Dave Airlie 2024-08-30 11:53:54 +10:00
commit 4f7d8da5e3
59 changed files with 2364 additions and 872 deletions

View File

@ -0,0 +1,63 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/panel/boe,tv101wum-ll2.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: BOE TV101WUM-LL2 DSI Display Panel
maintainers:
- Neil Armstrong <neil.armstrong@linaro.org>
allOf:
- $ref: panel-common.yaml#
properties:
compatible:
const: boe,tv101wum-ll2
reg:
maxItems: 1
description: DSI virtual channel
backlight: true
reset-gpios: true
vsp-supply: true
vsn-supply: true
port: true
rotation: true
required:
- compatible
- reg
- reset-gpios
- vsp-supply
- vsn-supply
- port
additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
dsi {
#address-cells = <1>;
#size-cells = <0>;
panel@0 {
compatible = "boe,tv101wum-ll2";
reg = <0>;
vsn-supply = <&vsn_lcd>;
vsp-supply = <&vsp_lcd>;
reset-gpios = <&pio 45 GPIO_ACTIVE_LOW>;
port {
panel_in: endpoint {
remote-endpoint = <&dsi_out>;
};
};
};
};
...

View File

@ -18,6 +18,7 @@ properties:
compatible:
oneOf:
- enum:
- renesas,r9a07g043u-du # RZ/G2UL
- renesas,r9a07g044-du # RZ/G2{L,LC}
- items:
- enum:
@ -60,9 +61,6 @@ properties:
$ref: /schemas/graph.yaml#/properties/port
unevaluatedProperties: false
required:
- port@0
unevaluatedProperties: false
renesas,vsps:
@ -88,6 +86,34 @@ required:
additionalProperties: false
allOf:
- if:
properties:
compatible:
contains:
const: renesas,r9a07g043u-du
then:
properties:
ports:
properties:
port@0:
description: DPI
required:
- port@0
else:
properties:
ports:
properties:
port@0:
description: DSI
port@1:
description: DPI
required:
- port@0
- port@1
examples:
# RZ/G2L DU
- |

View File

@ -7343,10 +7343,10 @@ F: drivers/gpu/drm/udl/
DRM DRIVER FOR VIRTUAL KERNEL MODESETTING (VKMS)
M: Rodrigo Siqueira <rodrigosiqueiramelo@gmail.com>
M: Melissa Wen <melissa.srw@gmail.com>
M: Maíra Canal <mairacanal@riseup.net>
R: Haneen Mohammed <hamohammed.sa@gmail.com>
R: Daniel Vetter <daniel@ffwll.ch>
R: Melissa Wen <melissa.srw@gmail.com>
L: dri-devel@lists.freedesktop.org
S: Maintained
T: git https://gitlab.freedesktop.org/drm/misc/kernel.git

View File

@ -8,7 +8,7 @@
#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/idr.h>
#include <linux/xarray.h>
#include <drm/drm_accel.h>
#include <drm/drm_auth.h>
@ -18,8 +18,7 @@
#include <drm/drm_ioctl.h>
#include <drm/drm_print.h>
static DEFINE_SPINLOCK(accel_minor_lock);
static struct idr accel_minors_idr;
DEFINE_XARRAY_ALLOC(accel_minors_xa);
static struct dentry *accel_debugfs_root;
@ -117,99 +116,6 @@ void accel_set_device_instance_params(struct device *kdev, int index)
kdev->type = &accel_sysfs_device_minor;
}
/**
* accel_minor_alloc() - Allocates a new accel minor
*
* This function access the accel minors idr and allocates from it
* a new id to represent a new accel minor
*
* Return: A new id on success or error code in case idr_alloc failed
*/
int accel_minor_alloc(void)
{
unsigned long flags;
int r;
spin_lock_irqsave(&accel_minor_lock, flags);
r = idr_alloc(&accel_minors_idr, NULL, 0, ACCEL_MAX_MINORS, GFP_NOWAIT);
spin_unlock_irqrestore(&accel_minor_lock, flags);
return r;
}
/**
* accel_minor_remove() - Remove an accel minor
* @index: The minor id to remove.
*
* This function access the accel minors idr and removes from
* it the member with the id that is passed to this function.
*/
void accel_minor_remove(int index)
{
unsigned long flags;
spin_lock_irqsave(&accel_minor_lock, flags);
idr_remove(&accel_minors_idr, index);
spin_unlock_irqrestore(&accel_minor_lock, flags);
}
/**
* accel_minor_replace() - Replace minor pointer in accel minors idr.
* @minor: Pointer to the new minor.
* @index: The minor id to replace.
*
* This function access the accel minors idr structure and replaces the pointer
* that is associated with an existing id. Because the minor pointer can be
* NULL, we need to explicitly pass the index.
*
* Return: 0 for success, negative value for error
*/
void accel_minor_replace(struct drm_minor *minor, int index)
{
unsigned long flags;
spin_lock_irqsave(&accel_minor_lock, flags);
idr_replace(&accel_minors_idr, minor, index);
spin_unlock_irqrestore(&accel_minor_lock, flags);
}
/*
* Looks up the given minor-ID and returns the respective DRM-minor object. The
* refence-count of the underlying device is increased so you must release this
* object with accel_minor_release().
*
* The object can be only a drm_minor that represents an accel device.
*
* As long as you hold this minor, it is guaranteed that the object and the
* minor->dev pointer will stay valid! However, the device may get unplugged and
* unregistered while you hold the minor.
*/
static struct drm_minor *accel_minor_acquire(unsigned int minor_id)
{
struct drm_minor *minor;
unsigned long flags;
spin_lock_irqsave(&accel_minor_lock, flags);
minor = idr_find(&accel_minors_idr, minor_id);
if (minor)
drm_dev_get(minor->dev);
spin_unlock_irqrestore(&accel_minor_lock, flags);
if (!minor) {
return ERR_PTR(-ENODEV);
} else if (drm_dev_is_unplugged(minor->dev)) {
drm_dev_put(minor->dev);
return ERR_PTR(-ENODEV);
}
return minor;
}
static void accel_minor_release(struct drm_minor *minor)
{
drm_dev_put(minor->dev);
}
/**
* accel_open - open method for ACCEL file
* @inode: device inode
@ -227,7 +133,7 @@ int accel_open(struct inode *inode, struct file *filp)
struct drm_minor *minor;
int retcode;
minor = accel_minor_acquire(iminor(inode));
minor = drm_minor_acquire(&accel_minors_xa, iminor(inode));
if (IS_ERR(minor))
return PTR_ERR(minor);
@ -246,7 +152,7 @@ int accel_open(struct inode *inode, struct file *filp)
err_undo:
atomic_dec(&dev->open_count);
accel_minor_release(minor);
drm_minor_release(minor);
return retcode;
}
EXPORT_SYMBOL_GPL(accel_open);
@ -257,7 +163,7 @@ static int accel_stub_open(struct inode *inode, struct file *filp)
struct drm_minor *minor;
int err;
minor = accel_minor_acquire(iminor(inode));
minor = drm_minor_acquire(&accel_minors_xa, iminor(inode));
if (IS_ERR(minor))
return PTR_ERR(minor);
@ -274,7 +180,7 @@ static int accel_stub_open(struct inode *inode, struct file *filp)
err = 0;
out:
accel_minor_release(minor);
drm_minor_release(minor);
return err;
}
@ -290,15 +196,13 @@ void accel_core_exit(void)
unregister_chrdev(ACCEL_MAJOR, "accel");
debugfs_remove(accel_debugfs_root);
accel_sysfs_destroy();
idr_destroy(&accel_minors_idr);
WARN_ON(!xa_empty(&accel_minors_xa));
}
int __init accel_core_init(void)
{
int ret;
idr_init(&accel_minors_idr);
ret = accel_sysfs_init();
if (ret < 0) {
DRM_ERROR("Cannot create ACCEL class: %d\n", ret);

View File

@ -149,6 +149,37 @@ config DRM_PANIC_SCREEN
or by writing to /sys/module/drm/parameters/panic_screen sysfs entry
Default is "user"
config DRM_PANIC_SCREEN_QR_CODE
bool "Add a panic screen with a QR code"
depends on DRM_PANIC && RUST
help
This option adds a QR code generator, and a panic screen with a QR
code. The QR code will contain the last lines of kmsg and other debug
information. This should be easier for the user to report a kernel
panic, with all debug information available.
To use this panic screen, also set DRM_PANIC_SCREEN to "qr_code"
config DRM_PANIC_SCREEN_QR_CODE_URL
string "Base URL of the QR code in the panic screen"
depends on DRM_PANIC_SCREEN_QR_CODE
help
This option sets the base URL to report the kernel panic. If it's set
the QR code will contain the URL and the kmsg compressed with zlib as
a URL parameter. If it's empty, the QR code will contain the kmsg as
uncompressed text only.
There is a demo code in javascript, to decode and uncompress the kmsg
data from the URL parameter at https://github.com/kdj0c/panic_report
config DRM_PANIC_SCREEN_QR_VERSION
int "Maximum version (size) of the QR code."
depends on DRM_PANIC_SCREEN_QR_CODE
default 40
help
This option limits the version (or size) of the QR code. QR code
version ranges from Version 1 (21x21) to Version 40 (177x177).
Smaller QR code are easier to read, but will contain less debugging
data. Default is 40.
config DRM_DEBUG_DP_MST_TOPOLOGY_REFS
bool "Enable refcount backtrace history in the DP MST helpers"
depends on STACKTRACE_SUPPORT

View File

@ -89,6 +89,7 @@ drm-$(CONFIG_DRM_PRIVACY_SCREEN) += \
drm_privacy_screen_x86.o
drm-$(CONFIG_DRM_ACCEL) += ../../accel/drm_accel.o
drm-$(CONFIG_DRM_PANIC) += drm_panic.o
drm-$(CONFIG_DRM_PANIC_SCREEN_QR_CODE) += drm_panic_qr.o
obj-$(CONFIG_DRM) += drm.o
obj-$(CONFIG_DRM_PANEL_ORIENTATION_QUIRKS) += drm_panel_orientation_quirks.o

View File

@ -2579,9 +2579,9 @@ static int dm_late_init(void *handle)
static void resume_mst_branch_status(struct drm_dp_mst_topology_mgr *mgr)
{
u8 buf[UUID_SIZE];
guid_t guid;
int ret;
u8 guid[16];
u64 tmp64;
mutex_lock(&mgr->lock);
if (!mgr->mst_primary)
@ -2602,26 +2602,27 @@ static void resume_mst_branch_status(struct drm_dp_mst_topology_mgr *mgr)
}
/* Some hubs forget their guids after they resume */
ret = drm_dp_dpcd_read(mgr->aux, DP_GUID, guid, 16);
if (ret != 16) {
ret = drm_dp_dpcd_read(mgr->aux, DP_GUID, buf, sizeof(buf));
if (ret != sizeof(buf)) {
drm_dbg_kms(mgr->dev, "dpcd read failed - undocked during suspend?\n");
goto out_fail;
}
if (memchr_inv(guid, 0, 16) == NULL) {
tmp64 = get_jiffies_64();
memcpy(&guid[0], &tmp64, sizeof(u64));
memcpy(&guid[8], &tmp64, sizeof(u64));
import_guid(&guid, buf);
ret = drm_dp_dpcd_write(mgr->aux, DP_GUID, guid, 16);
if (guid_is_null(&guid)) {
guid_gen(&guid);
export_guid(buf, &guid);
if (ret != 16) {
ret = drm_dp_dpcd_write(mgr->aux, DP_GUID, buf, sizeof(buf));
if (ret != sizeof(buf)) {
drm_dbg_kms(mgr->dev, "check mstb guid failed - undocked during suspend?\n");
goto out_fail;
}
}
memcpy(mgr->mst_primary->guid, guid, 16);
guid_copy(&mgr->mst_primary->guid, &guid);
out_fail:
mutex_unlock(&mgr->lock);
@ -4947,12 +4948,6 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
if (psr_feature_enabled)
amdgpu_dm_set_psr_caps(link);
/* TODO: Fix vblank control helpers to delay PSR entry to allow this when
* PSR is also supported.
*/
if (link->psr_settings.psr_feature_enabled)
adev_to_drm(adev)->vblank_disable_immediate = false;
}
}
amdgpu_set_panel_orientation(&aconnector->base);
@ -8248,13 +8243,67 @@ static int amdgpu_dm_encoder_init(struct drm_device *dev,
static void manage_dm_interrupts(struct amdgpu_device *adev,
struct amdgpu_crtc *acrtc,
bool enable)
struct dm_crtc_state *acrtc_state)
{
if (enable)
drm_crtc_vblank_on(&acrtc->base);
else
/*
* We have no guarantee that the frontend index maps to the same
* backend index - some even map to more than one.
*
* TODO: Use a different interrupt or check DC itself for the mapping.
*/
int irq_type =
amdgpu_display_crtc_idx_to_irq_type(
adev,
acrtc->crtc_id);
struct drm_vblank_crtc_config config = {0};
struct dc_crtc_timing *timing;
int offdelay;
if (acrtc_state) {
if (amdgpu_ip_version(adev, DCE_HWIP, 0) <
IP_VERSION(3, 5, 0) ||
acrtc_state->stream->link->psr_settings.psr_version <
DC_PSR_VERSION_UNSUPPORTED) {
timing = &acrtc_state->stream->timing;
/* at least 2 frames */
offdelay = DIV64_U64_ROUND_UP((u64)20 *
timing->v_total *
timing->h_total,
timing->pix_clk_100hz);
config.offdelay_ms = offdelay ?: 30;
} else {
config.disable_immediate = true;
}
drm_crtc_vblank_on_config(&acrtc->base,
&config);
amdgpu_irq_get(
adev,
&adev->pageflip_irq,
irq_type);
#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
amdgpu_irq_get(
adev,
&adev->vline0_irq,
irq_type);
#endif
} else {
#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
amdgpu_irq_put(
adev,
&adev->vline0_irq,
irq_type);
#endif
amdgpu_irq_put(
adev,
&adev->pageflip_irq,
irq_type);
drm_crtc_vblank_off(&acrtc->base);
}
}
static void dm_update_pflip_irq_state(struct amdgpu_device *adev,
struct amdgpu_crtc *acrtc)
@ -9305,7 +9354,7 @@ static void amdgpu_dm_commit_streams(struct drm_atomic_state *state,
if (old_crtc_state->active &&
(!new_crtc_state->active ||
drm_atomic_crtc_needs_modeset(new_crtc_state))) {
manage_dm_interrupts(adev, acrtc, false);
manage_dm_interrupts(adev, acrtc, NULL);
dc_stream_release(dm_old_crtc_state->stream);
}
}
@ -9821,7 +9870,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
drm_atomic_crtc_needs_modeset(new_crtc_state))) {
dc_stream_retain(dm_new_crtc_state->stream);
acrtc->dm_irq_params.stream = dm_new_crtc_state->stream;
manage_dm_interrupts(adev, acrtc, true);
manage_dm_interrupts(adev, acrtc, dm_new_crtc_state);
}
/* Handle vrr on->off / off->on transitions */
amdgpu_dm_handle_vrr_transition(dm_old_crtc_state, dm_new_crtc_state);

View File

@ -10,6 +10,7 @@
.lava-test:
extends:
- .test-rules
timeout: "1h30m"
script:
# Note: Build dir (and thus install) may be dirty due to GIT_STRATEGY
- rm -rf install
@ -71,6 +72,7 @@
- .baremetal-test-arm64
- .use-debian/baremetal_arm64_test
- .test-rules
timeout: "1h30m"
variables:
FDO_CI_CONCURRENT: 10
HWCI_TEST_SCRIPT: "/install/igt_runner.sh"
@ -215,7 +217,6 @@ panfrost:rk3399:
extends:
- .lava-igt:x86_64
stage: i915
timeout: "1h30m"
variables:
DRIVER_NAME: i915
DTB: ""
@ -414,6 +415,7 @@ panfrost:g12b:
virtio_gpu:none:
stage: software-driver
timeout: "1h30m"
variables:
CROSVM_GALLIUM_DRIVER: llvmpipe
DRIVER_NAME: virtio_gpu
@ -436,6 +438,7 @@ virtio_gpu:none:
vkms:none:
stage: software-driver
timeout: "1h30m"
variables:
DRIVER_NAME: vkms
GPU_VERSION: none

View File

@ -89,7 +89,7 @@ static int drm_dp_send_enum_path_resources(struct drm_dp_mst_topology_mgr *mgr,
struct drm_dp_mst_branch *mstb,
struct drm_dp_mst_port *port);
static bool drm_dp_validate_guid(struct drm_dp_mst_topology_mgr *mgr,
u8 *guid);
guid_t *guid);
static int drm_dp_mst_register_i2c_bus(struct drm_dp_mst_port *port);
static void drm_dp_mst_unregister_i2c_bus(struct drm_dp_mst_port *port);
@ -801,7 +801,7 @@ static bool drm_dp_sideband_parse_link_address(const struct drm_dp_mst_topology_
int idx = 1;
int i;
memcpy(repmsg->u.link_addr.guid, &raw->msg[idx], 16);
import_guid(&repmsg->u.link_addr.guid, &raw->msg[idx]);
idx += 16;
repmsg->u.link_addr.nports = raw->msg[idx] & 0xf;
idx++;
@ -829,7 +829,7 @@ static bool drm_dp_sideband_parse_link_address(const struct drm_dp_mst_topology_
idx++;
if (idx > raw->curlen)
goto fail_len;
memcpy(repmsg->u.link_addr.ports[i].peer_guid, &raw->msg[idx], 16);
import_guid(&repmsg->u.link_addr.ports[i].peer_guid, &raw->msg[idx]);
idx += 16;
if (idx > raw->curlen)
goto fail_len;
@ -1029,7 +1029,7 @@ static bool drm_dp_sideband_parse_reply(const struct drm_dp_mst_topology_mgr *mg
msg->req_type = (raw->msg[0] & 0x7f);
if (msg->reply_type == DP_SIDEBAND_REPLY_NAK) {
memcpy(msg->u.nak.guid, &raw->msg[1], 16);
import_guid(&msg->u.nak.guid, &raw->msg[1]);
msg->u.nak.reason = raw->msg[17];
msg->u.nak.nak_data = raw->msg[18];
return false;
@ -1078,7 +1078,7 @@ drm_dp_sideband_parse_connection_status_notify(const struct drm_dp_mst_topology_
if (idx > raw->curlen)
goto fail_len;
memcpy(msg->u.conn_stat.guid, &raw->msg[idx], 16);
import_guid(&msg->u.conn_stat.guid, &raw->msg[idx]);
idx += 16;
if (idx > raw->curlen)
goto fail_len;
@ -1107,7 +1107,7 @@ static bool drm_dp_sideband_parse_resource_status_notify(const struct drm_dp_mst
if (idx > raw->curlen)
goto fail_len;
memcpy(msg->u.resource_stat.guid, &raw->msg[idx], 16);
import_guid(&msg->u.resource_stat.guid, &raw->msg[idx]);
idx += 16;
if (idx > raw->curlen)
goto fail_len;
@ -2174,20 +2174,24 @@ ssize_t drm_dp_mst_dpcd_write(struct drm_dp_aux *aux,
offset, size, buffer);
}
static int drm_dp_check_mstb_guid(struct drm_dp_mst_branch *mstb, u8 *guid)
static int drm_dp_check_mstb_guid(struct drm_dp_mst_branch *mstb, guid_t *guid)
{
int ret = 0;
memcpy(mstb->guid, guid, 16);
guid_copy(&mstb->guid, guid);
if (!drm_dp_validate_guid(mstb->mgr, &mstb->guid)) {
u8 buf[UUID_SIZE];
export_guid(buf, &mstb->guid);
if (!drm_dp_validate_guid(mstb->mgr, mstb->guid)) {
if (mstb->port_parent) {
ret = drm_dp_send_dpcd_write(mstb->mgr,
mstb->port_parent,
DP_GUID, 16, mstb->guid);
DP_GUID, sizeof(buf), buf);
} else {
ret = drm_dp_dpcd_write(mstb->mgr->aux,
DP_GUID, mstb->guid, 16);
DP_GUID, buf, sizeof(buf));
}
}
@ -2567,9 +2571,9 @@ out:
return mstb;
}
static struct drm_dp_mst_branch *get_mst_branch_device_by_guid_helper(
struct drm_dp_mst_branch *mstb,
const uint8_t *guid)
static struct drm_dp_mst_branch *
get_mst_branch_device_by_guid_helper(struct drm_dp_mst_branch *mstb,
const guid_t *guid)
{
struct drm_dp_mst_branch *found_mstb;
struct drm_dp_mst_port *port;
@ -2577,10 +2581,9 @@ static struct drm_dp_mst_branch *get_mst_branch_device_by_guid_helper(
if (!mstb)
return NULL;
if (memcmp(mstb->guid, guid, 16) == 0)
if (guid_equal(&mstb->guid, guid))
return mstb;
list_for_each_entry(port, &mstb->ports, next) {
found_mstb = get_mst_branch_device_by_guid_helper(port->mstb, guid);
@ -2593,7 +2596,7 @@ static struct drm_dp_mst_branch *get_mst_branch_device_by_guid_helper(
static struct drm_dp_mst_branch *
drm_dp_get_mst_branch_device_by_guid(struct drm_dp_mst_topology_mgr *mgr,
const uint8_t *guid)
const guid_t *guid)
{
struct drm_dp_mst_branch *mstb;
int ret;
@ -2695,17 +2698,12 @@ static void drm_dp_mst_queue_probe_work(struct drm_dp_mst_topology_mgr *mgr)
}
static bool drm_dp_validate_guid(struct drm_dp_mst_topology_mgr *mgr,
u8 *guid)
guid_t *guid)
{
u64 salt;
if (memchr_inv(guid, 0, 16))
if (!guid_is_null(guid))
return true;
salt = get_jiffies_64();
memcpy(&guid[0], &salt, sizeof(u64));
memcpy(&guid[8], &salt, sizeof(u64));
guid_gen(guid);
return false;
}
@ -2945,7 +2943,7 @@ static int drm_dp_send_link_address(struct drm_dp_mst_topology_mgr *mgr,
drm_dbg_kms(mgr->dev, "link address reply: %d\n", reply->nports);
drm_dp_dump_link_address(mgr, reply);
ret = drm_dp_check_mstb_guid(mstb, reply->guid);
ret = drm_dp_check_mstb_guid(mstb, &reply->guid);
if (ret) {
char buf[64];
@ -3799,8 +3797,9 @@ EXPORT_SYMBOL(drm_dp_mst_topology_mgr_suspend);
int drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr,
bool sync)
{
u8 buf[UUID_SIZE];
guid_t guid;
int ret;
u8 guid[16];
mutex_lock(&mgr->lock);
if (!mgr->mst_primary)
@ -3821,13 +3820,15 @@ int drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr,
}
/* Some hubs forget their guids after they resume */
ret = drm_dp_dpcd_read(mgr->aux, DP_GUID, guid, 16);
if (ret != 16) {
ret = drm_dp_dpcd_read(mgr->aux, DP_GUID, buf, sizeof(buf));
if (ret != sizeof(buf)) {
drm_dbg_kms(mgr->dev, "dpcd read failed - undocked during suspend?\n");
goto out_fail;
}
ret = drm_dp_check_mstb_guid(mgr->mst_primary, guid);
import_guid(&guid, buf);
ret = drm_dp_check_mstb_guid(mgr->mst_primary, &guid);
if (ret) {
drm_dbg_kms(mgr->dev, "check mstb failed - undocked during suspend?\n");
goto out_fail;
@ -4005,12 +4006,12 @@ drm_dp_mst_process_up_req(struct drm_dp_mst_topology_mgr *mgr,
bool hotplug = false, dowork = false;
if (hdr->broadcast) {
const u8 *guid = NULL;
const guid_t *guid = NULL;
if (msg->req_type == DP_CONNECTION_STATUS_NOTIFY)
guid = msg->u.conn_stat.guid;
guid = &msg->u.conn_stat.guid;
else if (msg->req_type == DP_RESOURCE_STATUS_NOTIFY)
guid = msg->u.resource_stat.guid;
guid = &msg->u.resource_stat.guid;
if (guid)
mstb = drm_dp_get_mst_branch_device_by_guid(mgr, guid);
@ -5598,7 +5599,6 @@ EXPORT_SYMBOL(drm_dp_mst_atomic_check_mgr);
* drm_dp_atomic_release_time_slots()
*
* Returns:
*
* 0 if the new state is valid, negative error code otherwise.
*/
int drm_dp_mst_atomic_check(struct drm_atomic_state *state)
@ -5635,7 +5635,6 @@ EXPORT_SYMBOL(drm_dp_mst_topology_state_funcs);
* topology object.
*
* RETURNS:
*
* The MST topology state or error pointer.
*/
struct drm_dp_mst_topology_state *drm_atomic_get_mst_topology_state(struct drm_atomic_state *state,
@ -5655,7 +5654,6 @@ EXPORT_SYMBOL(drm_atomic_get_mst_topology_state);
* topology object.
*
* Returns:
*
* The old MST topology state, or NULL if there's no topology state for this MST mgr
* in the global atomic state
*/
@ -5680,7 +5678,6 @@ EXPORT_SYMBOL(drm_atomic_get_old_mst_topology_state);
* topology object.
*
* Returns:
*
* The new MST topology state, or NULL if there's no topology state for this MST mgr
* in the global atomic state
*/

View File

@ -63,7 +63,6 @@ EXPORT_SYMBOL(__drm_crtc_commit_free);
* hardware and flipped to.
*
* Returns:
*
* 0 on success, a negative error code otherwise.
*/
int drm_crtc_commit_wait(struct drm_crtc_commit *commit)
@ -337,7 +336,6 @@ EXPORT_SYMBOL(__drm_atomic_state_free);
* not created by userspace through an IOCTL call.
*
* Returns:
*
* Either the allocated state or the error code encoded into the pointer. When
* the error is EDEADLK then the w/w mutex code has detected a deadlock and the
* entire atomic sequence must be restarted. All other errors are fatal.
@ -518,7 +516,6 @@ static int drm_atomic_connector_check(struct drm_connector *connector,
* is consistent.
*
* Returns:
*
* Either the allocated state or the error code encoded into the pointer. When
* the error is EDEADLK then the w/w mutex code has detected a deadlock and the
* entire atomic sequence must be restarted. All other errors are fatal.
@ -828,7 +825,6 @@ EXPORT_SYMBOL(drm_atomic_private_obj_fini);
* object lock to make sure that the state is consistent.
*
* RETURNS:
*
* Either the allocated state or the error code encoded into a pointer.
*/
struct drm_private_state *
@ -1061,7 +1057,6 @@ EXPORT_SYMBOL(drm_atomic_get_new_crtc_for_encoder);
* make sure that the state is consistent.
*
* Returns:
*
* Either the allocated state or the error code encoded into the pointer. When
* the error is EDEADLK then the w/w mutex code has detected a deadlock and the
* entire atomic sequence must be restarted. All other errors are fatal.
@ -1169,7 +1164,6 @@ static void drm_atomic_connector_print_state(struct drm_printer *p,
* state is consistent.
*
* Returns:
*
* Either the allocated state or the error code encoded into the pointer. When
* the error is EDEADLK then the w/w mutex code has detected a deadlock and the
* entire atomic sequence must be restarted.

View File

@ -2266,7 +2266,6 @@ crtc_or_fake_commit(struct drm_atomic_state *state, struct drm_crtc *crtc)
* automatically.
*
* Returns:
*
* 0 on success. -EBUSY when userspace schedules nonblocking commits too fast,
* -ENOMEM on allocation failures and -EINTR when a signal is pending.
*/
@ -3009,7 +3008,6 @@ EXPORT_SYMBOL(drm_atomic_helper_cleanup_planes);
* don't pass the right state structures to the callbacks.
*
* Returns:
*
* Returns 0 on success. Can return -ERESTARTSYS when @stall is true and the
* waiting for the previous commits has been interrupted.
*/

View File

@ -320,10 +320,14 @@ drm_edid_load_firmware(struct drm_connector *connector)
bool drm_panic_is_enabled(struct drm_device *dev);
void drm_panic_register(struct drm_device *dev);
void drm_panic_unregister(struct drm_device *dev);
void drm_panic_init(void);
void drm_panic_exit(void);
#else
static inline bool drm_panic_is_enabled(struct drm_device *dev) { return false; }
static inline void drm_panic_register(struct drm_device *dev) {}
static inline void drm_panic_unregister(struct drm_device *dev) {}
static inline void drm_panic_init(void) {}
static inline void drm_panic_exit(void) {}
#endif
#endif /* __DRM_CRTC_INTERNAL_H__ */

View File

@ -34,6 +34,7 @@
#include <linux/pseudo_fs.h>
#include <linux/slab.h>
#include <linux/srcu.h>
#include <linux/xarray.h>
#include <drm/drm_accel.h>
#include <drm/drm_cache.h>
@ -54,8 +55,7 @@ MODULE_AUTHOR("Gareth Hughes, Leif Delgass, José Fonseca, Jon Smirl");
MODULE_DESCRIPTION("DRM shared core routines");
MODULE_LICENSE("GPL and additional rights");
static DEFINE_SPINLOCK(drm_minor_lock);
static struct idr drm_minors_idr;
DEFINE_XARRAY_ALLOC(drm_minors_xa);
/*
* If the drm core fails to init for whatever reason,
@ -83,6 +83,18 @@ DEFINE_STATIC_SRCU(drm_unplug_srcu);
* registered and unregistered dynamically according to device-state.
*/
static struct xarray *drm_minor_get_xa(enum drm_minor_type type)
{
if (type == DRM_MINOR_PRIMARY || type == DRM_MINOR_RENDER)
return &drm_minors_xa;
#if IS_ENABLED(CONFIG_DRM_ACCEL)
else if (type == DRM_MINOR_ACCEL)
return &accel_minors_xa;
#endif
else
return ERR_PTR(-EOPNOTSUPP);
}
static struct drm_minor **drm_minor_get_slot(struct drm_device *dev,
enum drm_minor_type type)
{
@ -101,25 +113,31 @@ static struct drm_minor **drm_minor_get_slot(struct drm_device *dev,
static void drm_minor_alloc_release(struct drm_device *dev, void *data)
{
struct drm_minor *minor = data;
unsigned long flags;
WARN_ON(dev != minor->dev);
put_device(minor->kdev);
if (minor->type == DRM_MINOR_ACCEL) {
accel_minor_remove(minor->index);
} else {
spin_lock_irqsave(&drm_minor_lock, flags);
idr_remove(&drm_minors_idr, minor->index);
spin_unlock_irqrestore(&drm_minor_lock, flags);
}
xa_erase(drm_minor_get_xa(minor->type), minor->index);
}
/*
* DRM used to support 64 devices, for backwards compatibility we need to maintain the
* minor allocation scheme where minors 0-63 are primary nodes, 64-127 are control nodes,
* and 128-191 are render nodes.
* After reaching the limit, we're allocating minors dynamically - first-come, first-serve.
* Accel nodes are using a distinct major, so the minors are allocated in continuous 0-MAX
* range.
*/
#define DRM_MINOR_LIMIT(t) ({ \
typeof(t) _t = (t); \
_t == DRM_MINOR_ACCEL ? XA_LIMIT(0, ACCEL_MAX_MINORS) : XA_LIMIT(64 * _t, 64 * _t + 63); \
})
#define DRM_EXTENDED_MINOR_LIMIT XA_LIMIT(192, (1 << MINORBITS) - 1)
static int drm_minor_alloc(struct drm_device *dev, enum drm_minor_type type)
{
struct drm_minor *minor;
unsigned long flags;
int r;
minor = drmm_kzalloc(dev, sizeof(*minor), GFP_KERNEL);
@ -129,25 +147,14 @@ static int drm_minor_alloc(struct drm_device *dev, enum drm_minor_type type)
minor->type = type;
minor->dev = dev;
idr_preload(GFP_KERNEL);
if (type == DRM_MINOR_ACCEL) {
r = accel_minor_alloc();
} else {
spin_lock_irqsave(&drm_minor_lock, flags);
r = idr_alloc(&drm_minors_idr,
NULL,
64 * type,
64 * (type + 1),
GFP_NOWAIT);
spin_unlock_irqrestore(&drm_minor_lock, flags);
}
idr_preload_end();
r = xa_alloc(drm_minor_get_xa(type), &minor->index,
NULL, DRM_MINOR_LIMIT(type), GFP_KERNEL);
if (r == -EBUSY && (type == DRM_MINOR_PRIMARY || type == DRM_MINOR_RENDER))
r = xa_alloc(&drm_minors_xa, &minor->index,
NULL, DRM_EXTENDED_MINOR_LIMIT, GFP_KERNEL);
if (r < 0)
return r;
minor->index = r;
r = drmm_add_action_or_reset(dev, drm_minor_alloc_release, minor);
if (r)
return r;
@ -163,7 +170,7 @@ static int drm_minor_alloc(struct drm_device *dev, enum drm_minor_type type)
static int drm_minor_register(struct drm_device *dev, enum drm_minor_type type)
{
struct drm_minor *minor;
unsigned long flags;
void *entry;
int ret;
DRM_DEBUG("\n");
@ -186,13 +193,12 @@ static int drm_minor_register(struct drm_device *dev, enum drm_minor_type type)
goto err_debugfs;
/* replace NULL with @minor so lookups will succeed from now on */
if (minor->type == DRM_MINOR_ACCEL) {
accel_minor_replace(minor, minor->index);
} else {
spin_lock_irqsave(&drm_minor_lock, flags);
idr_replace(&drm_minors_idr, minor, minor->index);
spin_unlock_irqrestore(&drm_minor_lock, flags);
entry = xa_store(drm_minor_get_xa(type), minor->index, minor, GFP_KERNEL);
if (xa_is_err(entry)) {
ret = xa_err(entry);
goto err_debugfs;
}
WARN_ON(entry);
DRM_DEBUG("new minor registered %d\n", minor->index);
return 0;
@ -205,20 +211,13 @@ err_debugfs:
static void drm_minor_unregister(struct drm_device *dev, enum drm_minor_type type)
{
struct drm_minor *minor;
unsigned long flags;
minor = *drm_minor_get_slot(dev, type);
if (!minor || !device_is_registered(minor->kdev))
return;
/* replace @minor with NULL so lookups will fail from now on */
if (minor->type == DRM_MINOR_ACCEL) {
accel_minor_replace(NULL, minor->index);
} else {
spin_lock_irqsave(&drm_minor_lock, flags);
idr_replace(&drm_minors_idr, NULL, minor->index);
spin_unlock_irqrestore(&drm_minor_lock, flags);
}
xa_store(drm_minor_get_xa(type), minor->index, NULL, GFP_KERNEL);
device_del(minor->kdev);
dev_set_drvdata(minor->kdev, NULL); /* safety belt */
@ -234,16 +233,15 @@ static void drm_minor_unregister(struct drm_device *dev, enum drm_minor_type typ
* minor->dev pointer will stay valid! However, the device may get unplugged and
* unregistered while you hold the minor.
*/
struct drm_minor *drm_minor_acquire(unsigned int minor_id)
struct drm_minor *drm_minor_acquire(struct xarray *minor_xa, unsigned int minor_id)
{
struct drm_minor *minor;
unsigned long flags;
spin_lock_irqsave(&drm_minor_lock, flags);
minor = idr_find(&drm_minors_idr, minor_id);
xa_lock(minor_xa);
minor = xa_load(minor_xa, minor_id);
if (minor)
drm_dev_get(minor->dev);
spin_unlock_irqrestore(&drm_minor_lock, flags);
xa_unlock(minor_xa);
if (!minor) {
return ERR_PTR(-ENODEV);
@ -1036,7 +1034,7 @@ static int drm_stub_open(struct inode *inode, struct file *filp)
DRM_DEBUG("\n");
minor = drm_minor_acquire(iminor(inode));
minor = drm_minor_acquire(&drm_minors_xa, iminor(inode));
if (IS_ERR(minor))
return PTR_ERR(minor);
@ -1067,11 +1065,12 @@ static const struct file_operations drm_stub_fops = {
static void drm_core_exit(void)
{
drm_privacy_screen_lookup_exit();
drm_panic_exit();
accel_core_exit();
unregister_chrdev(DRM_MAJOR, "drm");
debugfs_remove(drm_debugfs_root);
drm_sysfs_destroy();
idr_destroy(&drm_minors_idr);
WARN_ON(!xa_empty(&drm_minors_xa));
drm_connector_ida_destroy();
}
@ -1080,7 +1079,6 @@ static int __init drm_core_init(void)
int ret;
drm_connector_ida_init();
idr_init(&drm_minors_idr);
drm_memcpy_init_early();
ret = drm_sysfs_init();
@ -1099,6 +1097,8 @@ static int __init drm_core_init(void)
if (ret < 0)
goto error;
drm_panic_init();
drm_privacy_screen_lookup_init();
drm_core_init_complete = true;

View File

@ -347,7 +347,6 @@ int drm_open_helper(struct file *filp, struct drm_minor *minor)
* resources for it. It also calls the &drm_driver.open driver callback.
*
* RETURNS:
*
* 0 on success or negative errno value on failure.
*/
int drm_open(struct inode *inode, struct file *filp)
@ -356,7 +355,7 @@ int drm_open(struct inode *inode, struct file *filp)
struct drm_minor *minor;
int retcode;
minor = drm_minor_acquire(iminor(inode));
minor = drm_minor_acquire(&drm_minors_xa, iminor(inode));
if (IS_ERR(minor))
return PTR_ERR(minor);
@ -406,7 +405,6 @@ static void drm_lastclose(struct drm_device *dev)
* in-kernel DRM client.
*
* RETURNS:
*
* Always succeeds and returns 0.
*/
int drm_release(struct inode *inode, struct file *filp)
@ -477,7 +475,6 @@ void drm_file_update_pid(struct drm_file *filp)
* then restores the active in-kernel DRM client.
*
* RETURNS:
*
* Always succeeds and returns 0.
*/
int drm_release_noglobal(struct inode *inode, struct file *filp)
@ -520,7 +517,6 @@ EXPORT_SYMBOL(drm_release_noglobal);
* safety.
*
* RETURNS:
*
* Number of bytes read (always aligned to full events, and can be 0) or a
* negative error code on failure.
*/
@ -606,7 +602,6 @@ EXPORT_SYMBOL(drm_read);
* See also drm_read().
*
* RETURNS:
*
* Mask of POLL flags indicating the current status of the file.
*/
__poll_t drm_poll(struct file *filp, struct poll_table_struct *wait)
@ -644,7 +639,6 @@ EXPORT_SYMBOL(drm_poll);
* already hold &drm_device.event_lock.
*
* RETURNS:
*
* 0 on success or a negative error code on failure.
*/
int drm_event_reserve_init_locked(struct drm_device *dev,
@ -686,7 +680,6 @@ EXPORT_SYMBOL(drm_event_reserve_init_locked);
* drm_event_reserve_init_locked() instead.
*
* RETURNS:
*
* 0 on success or a negative error code on failure.
*/
int drm_event_reserve_init(struct drm_device *dev,

View File

@ -689,7 +689,6 @@ static int objects_lookup(struct drm_file *filp, u32 *handle, int count,
* For a single handle lookup, use drm_gem_object_lookup().
*
* Returns:
*
* @objs filled in with GEM object pointers. Returned GEM objects need to be
* released with drm_gem_object_put(). -ENOENT is returned on a lookup
* failure. 0 is returned on success.
@ -737,12 +736,11 @@ EXPORT_SYMBOL(drm_gem_objects_lookup);
* @filp: DRM file private date
* @handle: userspace handle
*
* Returns:
* If looking up an array of handles, use drm_gem_objects_lookup().
*
* Returns:
* A reference to the object named by the handle if such exists on @filp, NULL
* otherwise.
*
* If looking up an array of handles, use drm_gem_objects_lookup().
*/
struct drm_gem_object *
drm_gem_object_lookup(struct drm_file *filp, u32 handle)
@ -763,7 +761,6 @@ EXPORT_SYMBOL(drm_gem_object_lookup);
* @timeout: timeout value in jiffies or zero to return immediately
*
* Returns:
*
* Returns -ERESTARTSYS if interrupted, 0 if the wait timed out, or
* greater than 0 on success.
*/

View File

@ -80,10 +80,6 @@ void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv);
void drm_prime_remove_buf_handle(struct drm_prime_file_private *prime_fpriv,
uint32_t handle);
/* drm_drv.c */
struct drm_minor *drm_minor_acquire(unsigned int minor_id);
void drm_minor_release(struct drm_minor *minor);
/* drm_managed.c */
void drm_managed_release(struct drm_device *dev);
void drmm_add_final_kfree(struct drm_device *dev, void *container);

View File

@ -539,7 +539,6 @@ static int fill_analog_mode(struct drm_device *dev,
* to reach those resolutions.
*
* Returns:
*
* A pointer to the mode, allocated with drm_mode_create(). Returns NULL
* on error.
*/

View File

@ -18,6 +18,8 @@
#include <linux/overflow.h>
#include <linux/printk.h>
#include <linux/types.h>
#include <linux/utsname.h>
#include <linux/zlib.h>
#include <drm/drm_drv.h>
#include <drm/drm_fourcc.h>
@ -26,6 +28,7 @@
#include <drm/drm_panic.h>
#include <drm/drm_plane.h>
#include <drm/drm_print.h>
#include <drm/drm_rect.h>
#include "drm_crtc_internal.h"
@ -85,7 +88,7 @@ static struct drm_panic_line panic_msg[] = {
PANIC_LINE(""), /* will be replaced by the panic description */
};
#define PANIC_MSG_LINES ARRAY_SIZE(panic_msg)
static const size_t panic_msg_lines = ARRAY_SIZE(panic_msg);
static const struct drm_panic_line logo_ascii[] = {
PANIC_LINE(" .--. _"),
@ -97,7 +100,7 @@ static const struct drm_panic_line logo_ascii[] = {
PANIC_LINE(" \\___)=(___/"),
};
#define PANIC_LOGO_LINES ARRAY_SIZE(logo_ascii)
static const size_t logo_ascii_lines = ARRAY_SIZE(logo_ascii);
#if defined(CONFIG_LOGO) && !defined(MODULE)
static const struct linux_logo *logo_mono;
@ -257,20 +260,20 @@ static bool drm_panic_is_pixel_fg(const u8 *sbuf8, unsigned int spitch, int x, i
static void drm_panic_blit16(struct iosys_map *dmap, unsigned int dpitch,
const u8 *sbuf8, unsigned int spitch,
unsigned int height, unsigned int width,
u16 fg16)
unsigned int scale, u16 fg16)
{
unsigned int y, x;
for (y = 0; y < height; y++)
for (x = 0; x < width; x++)
if (drm_panic_is_pixel_fg(sbuf8, spitch, x, y))
if (drm_panic_is_pixel_fg(sbuf8, spitch, x / scale, y / scale))
iosys_map_wr(dmap, y * dpitch + x * sizeof(u16), u16, fg16);
}
static void drm_panic_blit24(struct iosys_map *dmap, unsigned int dpitch,
const u8 *sbuf8, unsigned int spitch,
unsigned int height, unsigned int width,
u32 fg32)
unsigned int scale, u32 fg32)
{
unsigned int y, x;
@ -278,7 +281,7 @@ static void drm_panic_blit24(struct iosys_map *dmap, unsigned int dpitch,
for (x = 0; x < width; x++) {
u32 off = y * dpitch + x * 3;
if (drm_panic_is_pixel_fg(sbuf8, spitch, x, y)) {
if (drm_panic_is_pixel_fg(sbuf8, spitch, x / scale, y / scale)) {
/* write blue-green-red to output in little endianness */
iosys_map_wr(dmap, off, u8, (fg32 & 0x000000FF) >> 0);
iosys_map_wr(dmap, off + 1, u8, (fg32 & 0x0000FF00) >> 8);
@ -291,24 +294,25 @@ static void drm_panic_blit24(struct iosys_map *dmap, unsigned int dpitch,
static void drm_panic_blit32(struct iosys_map *dmap, unsigned int dpitch,
const u8 *sbuf8, unsigned int spitch,
unsigned int height, unsigned int width,
u32 fg32)
unsigned int scale, u32 fg32)
{
unsigned int y, x;
for (y = 0; y < height; y++)
for (x = 0; x < width; x++)
if (drm_panic_is_pixel_fg(sbuf8, spitch, x, y))
if (drm_panic_is_pixel_fg(sbuf8, spitch, x / scale, y / scale))
iosys_map_wr(dmap, y * dpitch + x * sizeof(u32), u32, fg32);
}
static void drm_panic_blit_pixel(struct drm_scanout_buffer *sb, struct drm_rect *clip,
const u8 *sbuf8, unsigned int spitch, u32 fg_color)
const u8 *sbuf8, unsigned int spitch, unsigned int scale,
u32 fg_color)
{
unsigned int y, x;
for (y = 0; y < drm_rect_height(clip); y++)
for (x = 0; x < drm_rect_width(clip); x++)
if (drm_panic_is_pixel_fg(sbuf8, spitch, x, y))
if (drm_panic_is_pixel_fg(sbuf8, spitch, x / scale, y / scale))
sb->set_pixel(sb, clip->x1 + x, clip->y1 + y, fg_color);
}
@ -318,18 +322,22 @@ static void drm_panic_blit_pixel(struct drm_scanout_buffer *sb, struct drm_rect
* @clip: destination rectangle
* @sbuf8: source buffer, in monochrome format, 8 pixels per byte.
* @spitch: source pitch in bytes
* @scale: integer scale, source buffer is scale time smaller than destination
* rectangle
* @fg_color: foreground color, in destination format
*
* This can be used to draw a font character, which is a monochrome image, to a
* framebuffer in other supported format.
*/
static void drm_panic_blit(struct drm_scanout_buffer *sb, struct drm_rect *clip,
const u8 *sbuf8, unsigned int spitch, u32 fg_color)
const u8 *sbuf8, unsigned int spitch,
unsigned int scale, u32 fg_color)
{
struct iosys_map map;
if (sb->set_pixel)
return drm_panic_blit_pixel(sb, clip, sbuf8, spitch, fg_color);
return drm_panic_blit_pixel(sb, clip, sbuf8, spitch, scale, fg_color);
map = sb->map[0];
iosys_map_incr(&map, clip->y1 * sb->pitch[0] + clip->x1 * sb->format->cpp[0]);
@ -337,15 +345,15 @@ static void drm_panic_blit(struct drm_scanout_buffer *sb, struct drm_rect *clip,
switch (sb->format->cpp[0]) {
case 2:
drm_panic_blit16(&map, sb->pitch[0], sbuf8, spitch,
drm_rect_height(clip), drm_rect_width(clip), fg_color);
drm_rect_height(clip), drm_rect_width(clip), scale, fg_color);
break;
case 3:
drm_panic_blit24(&map, sb->pitch[0], sbuf8, spitch,
drm_rect_height(clip), drm_rect_width(clip), fg_color);
drm_rect_height(clip), drm_rect_width(clip), scale, fg_color);
break;
case 4:
drm_panic_blit32(&map, sb->pitch[0], sbuf8, spitch,
drm_rect_height(clip), drm_rect_width(clip), fg_color);
drm_rect_height(clip), drm_rect_width(clip), scale, fg_color);
break;
default:
WARN_ONCE(1, "Can't blit with pixel width %d\n", sb->format->cpp[0]);
@ -485,37 +493,50 @@ static void draw_txt_rectangle(struct drm_scanout_buffer *sb,
for (j = 0; j < line_len; j++) {
src = get_char_bitmap(font, msg[i].txt[j], font_pitch);
rec.x2 = rec.x1 + font->width;
drm_panic_blit(sb, &rec, src, font_pitch, color);
drm_panic_blit(sb, &rec, src, font_pitch, 1, color);
rec.x1 += font->width;
}
}
}
static void drm_panic_logo_rect(struct drm_rect *rect, const struct font_desc *font)
{
if (logo_mono) {
drm_rect_init(rect, 0, 0, logo_mono->width, logo_mono->height);
} else {
int logo_width = get_max_line_len(logo_ascii, logo_ascii_lines) * font->width;
drm_rect_init(rect, 0, 0, logo_width, logo_ascii_lines * font->height);
}
}
static void drm_panic_logo_draw(struct drm_scanout_buffer *sb, struct drm_rect *rect,
const struct font_desc *font, u32 fg_color)
{
if (logo_mono)
drm_panic_blit(sb, rect, logo_mono->data,
DIV_ROUND_UP(drm_rect_width(rect), 8), 1, fg_color);
else
draw_txt_rectangle(sb, font, logo_ascii, logo_ascii_lines, false, rect,
fg_color);
}
static void draw_panic_static_user(struct drm_scanout_buffer *sb)
{
u32 fg_color = convert_from_xrgb8888(CONFIG_DRM_PANIC_FOREGROUND_COLOR, sb->format->format);
u32 bg_color = convert_from_xrgb8888(CONFIG_DRM_PANIC_BACKGROUND_COLOR, sb->format->format);
const struct font_desc *font = get_default_font(sb->width, sb->height, NULL, NULL);
struct drm_rect r_screen, r_logo, r_msg;
unsigned int logo_width, logo_height;
unsigned int msg_width, msg_height;
if (!font)
return;
r_screen = DRM_RECT_INIT(0, 0, sb->width, sb->height);
drm_panic_logo_rect(&r_logo, font);
if (logo_mono) {
logo_width = logo_mono->width;
logo_height = logo_mono->height;
} else {
logo_width = get_max_line_len(logo_ascii, PANIC_LOGO_LINES) * font->width;
logo_height = PANIC_LOGO_LINES * font->height;
}
r_logo = DRM_RECT_INIT(0, 0, logo_width, logo_height);
msg_width = min(get_max_line_len(panic_msg, PANIC_MSG_LINES) * font->width, sb->width);
msg_height = min(PANIC_MSG_LINES * font->height, sb->height);
msg_width = min(get_max_line_len(panic_msg, panic_msg_lines) * font->width, sb->width);
msg_height = min(panic_msg_lines * font->height, sb->height);
r_msg = DRM_RECT_INIT(0, 0, msg_width, msg_height);
/* Center the panic message */
@ -524,16 +545,10 @@ static void draw_panic_static_user(struct drm_scanout_buffer *sb)
/* Fill with the background color, and draw text on top */
drm_panic_fill(sb, &r_screen, bg_color);
if ((r_msg.x1 >= logo_width || r_msg.y1 >= logo_height) &&
logo_width <= sb->width && logo_height <= sb->height) {
if (logo_mono)
drm_panic_blit(sb, &r_logo, logo_mono->data, DIV_ROUND_UP(logo_width, 8),
fg_color);
else
draw_txt_rectangle(sb, font, logo_ascii, PANIC_LOGO_LINES, false, &r_logo,
fg_color);
}
draw_txt_rectangle(sb, font, panic_msg, PANIC_MSG_LINES, true, &r_msg, fg_color);
if (!drm_rect_overlap(&r_logo, &r_msg))
drm_panic_logo_draw(sb, &r_logo, font, fg_color);
draw_txt_rectangle(sb, font, panic_msg, panic_msg_lines, true, &r_msg, fg_color);
}
/*
@ -615,6 +630,233 @@ static void draw_panic_static_kmsg(struct drm_scanout_buffer *sb)
}
}
#if defined(CONFIG_DRM_PANIC_SCREEN_QR_CODE)
/*
* It is unwise to allocate memory in the panic callback, so the buffers are
* pre-allocated. Only 2 buffers and the zlib workspace are needed.
* Two buffers are enough, using the following buffer usage:
* 1) kmsg messages are dumped in buffer1
* 2) kmsg is zlib-compressed into buffer2
* 3) compressed kmsg is encoded as QR-code Numeric stream in buffer1
* 4) QR-code image is generated in buffer2
* The Max QR code size is V40, 177x177, 4071 bytes for image, 2956 bytes for
* data segments.
*
* Typically, ~7500 bytes of kmsg, are compressed into 2800 bytes, which fits in
* a V40 QR-code (177x177).
*
* If CONFIG_DRM_PANIC_SCREEN_QR_CODE_URL is not set, the kmsg data will be put
* directly in the QR code.
* 1) kmsg messages are dumped in buffer1
* 2) kmsg message is encoded as byte stream in buffer2
* 3) QR-code image is generated in buffer1
*/
static uint panic_qr_version = CONFIG_DRM_PANIC_SCREEN_QR_VERSION;
module_param(panic_qr_version, uint, 0644);
MODULE_PARM_DESC(panic_qr_version, "maximum version (size) of the QR code");
#define MAX_QR_DATA 2956
#define MAX_ZLIB_RATIO 3
#define QR_BUFFER1_SIZE (MAX_ZLIB_RATIO * MAX_QR_DATA) /* Must also be > 4071 */
#define QR_BUFFER2_SIZE 4096
#define QR_MARGIN 4 /* 4 modules of foreground color around the qr code */
/* Compression parameters */
#define COMPR_LEVEL 6
#define WINDOW_BITS 12
#define MEM_LEVEL 4
static char *qrbuf1;
static char *qrbuf2;
static struct z_stream_s stream;
static void __init drm_panic_qr_init(void)
{
qrbuf1 = kmalloc(QR_BUFFER1_SIZE, GFP_KERNEL);
qrbuf2 = kmalloc(QR_BUFFER2_SIZE, GFP_KERNEL);
stream.workspace = kmalloc(zlib_deflate_workspacesize(WINDOW_BITS, MEM_LEVEL),
GFP_KERNEL);
}
static void drm_panic_qr_exit(void)
{
kfree(qrbuf1);
qrbuf1 = NULL;
kfree(qrbuf2);
qrbuf2 = NULL;
kfree(stream.workspace);
stream.workspace = NULL;
}
extern size_t drm_panic_qr_max_data_size(u8 version, size_t url_len);
extern u8 drm_panic_qr_generate(const char *url, u8 *data, size_t data_len, size_t data_size,
u8 *tmp, size_t tmp_size);
static int drm_panic_get_qr_code_url(u8 **qr_image)
{
struct kmsg_dump_iter iter;
char url[256];
size_t kmsg_len, max_kmsg_size;
char *kmsg;
int max_qr_data_size, url_len;
url_len = snprintf(url, sizeof(url), CONFIG_DRM_PANIC_SCREEN_QR_CODE_URL "?a=%s&v=%s&zl=",
utsname()->machine, utsname()->release);
max_qr_data_size = drm_panic_qr_max_data_size(panic_qr_version, url_len);
max_kmsg_size = min(MAX_ZLIB_RATIO * max_qr_data_size, QR_BUFFER1_SIZE);
/* get kmsg to buffer 1 */
kmsg_dump_rewind(&iter);
kmsg_dump_get_buffer(&iter, false, qrbuf1, max_kmsg_size, &kmsg_len);
if (!kmsg_len)
return -ENODATA;
kmsg = qrbuf1;
try_again:
if (zlib_deflateInit2(&stream, COMPR_LEVEL, Z_DEFLATED, WINDOW_BITS,
MEM_LEVEL, Z_DEFAULT_STRATEGY) != Z_OK)
return -EINVAL;
stream.next_in = kmsg;
stream.avail_in = kmsg_len;
stream.total_in = 0;
stream.next_out = qrbuf2;
stream.avail_out = QR_BUFFER2_SIZE;
stream.total_out = 0;
if (zlib_deflate(&stream, Z_FINISH) != Z_STREAM_END)
return -EINVAL;
if (zlib_deflateEnd(&stream) != Z_OK)
return -EINVAL;
if (stream.total_out > max_qr_data_size) {
/* too much data for the QR code, so skip the first line and try again */
kmsg = strchr(kmsg, '\n');
if (!kmsg)
return -EINVAL;
/* skip the first \n */
kmsg += 1;
kmsg_len = strlen(kmsg);
goto try_again;
}
*qr_image = qrbuf2;
/* generate qr code image in buffer2 */
return drm_panic_qr_generate(url, qrbuf2, stream.total_out, QR_BUFFER2_SIZE,
qrbuf1, QR_BUFFER1_SIZE);
}
static int drm_panic_get_qr_code_raw(u8 **qr_image)
{
struct kmsg_dump_iter iter;
size_t kmsg_len;
size_t max_kmsg_size = min(drm_panic_qr_max_data_size(panic_qr_version, 0),
QR_BUFFER1_SIZE);
kmsg_dump_rewind(&iter);
kmsg_dump_get_buffer(&iter, false, qrbuf1, max_kmsg_size, &kmsg_len);
if (!kmsg_len)
return -ENODATA;
*qr_image = qrbuf1;
return drm_panic_qr_generate(NULL, qrbuf1, kmsg_len, QR_BUFFER1_SIZE,
qrbuf2, QR_BUFFER2_SIZE);
}
static int drm_panic_get_qr_code(u8 **qr_image)
{
if (strlen(CONFIG_DRM_PANIC_SCREEN_QR_CODE_URL) > 0)
return drm_panic_get_qr_code_url(qr_image);
else
return drm_panic_get_qr_code_raw(qr_image);
}
/*
* Draw the panic message at the center of the screen, with a QR Code
*/
static int _draw_panic_static_qr_code(struct drm_scanout_buffer *sb)
{
u32 fg_color = convert_from_xrgb8888(CONFIG_DRM_PANIC_FOREGROUND_COLOR, sb->format->format);
u32 bg_color = convert_from_xrgb8888(CONFIG_DRM_PANIC_BACKGROUND_COLOR, sb->format->format);
const struct font_desc *font = get_default_font(sb->width, sb->height, NULL, NULL);
struct drm_rect r_screen, r_logo, r_msg, r_qr, r_qr_canvas;
unsigned int max_qr_size, scale;
unsigned int msg_width, msg_height;
int qr_width, qr_canvas_width, qr_pitch, v_margin;
u8 *qr_image;
if (!font || !qrbuf1 || !qrbuf2 || !stream.workspace)
return -ENOMEM;
r_screen = DRM_RECT_INIT(0, 0, sb->width, sb->height);
drm_panic_logo_rect(&r_logo, font);
msg_width = min(get_max_line_len(panic_msg, panic_msg_lines) * font->width, sb->width);
msg_height = min(panic_msg_lines * font->height, sb->height);
r_msg = DRM_RECT_INIT(0, 0, msg_width, msg_height);
max_qr_size = min(3 * sb->width / 4, 3 * sb->height / 4);
qr_width = drm_panic_get_qr_code(&qr_image);
if (qr_width <= 0)
return -ENOSPC;
qr_canvas_width = qr_width + QR_MARGIN * 2;
scale = max_qr_size / qr_canvas_width;
/* QR code is not readable if not scaled at least by 2 */
if (scale < 2)
return -ENOSPC;
pr_debug("QR width %d and scale %d\n", qr_width, scale);
r_qr_canvas = DRM_RECT_INIT(0, 0, qr_canvas_width * scale, qr_canvas_width * scale);
v_margin = (sb->height - drm_rect_height(&r_qr_canvas) - drm_rect_height(&r_msg)) / 5;
drm_rect_translate(&r_qr_canvas, (sb->width - r_qr_canvas.x2) / 2, 2 * v_margin);
r_qr = DRM_RECT_INIT(r_qr_canvas.x1 + QR_MARGIN * scale, r_qr_canvas.y1 + QR_MARGIN * scale,
qr_width * scale, qr_width * scale);
/* Center the panic message */
drm_rect_translate(&r_msg, (sb->width - r_msg.x2) / 2,
3 * v_margin + drm_rect_height(&r_qr_canvas));
/* Fill with the background color, and draw text on top */
drm_panic_fill(sb, &r_screen, bg_color);
if (!drm_rect_overlap(&r_logo, &r_msg) && !drm_rect_overlap(&r_logo, &r_qr))
drm_panic_logo_draw(sb, &r_logo, font, fg_color);
draw_txt_rectangle(sb, font, panic_msg, panic_msg_lines, true, &r_msg, fg_color);
/* Draw the qr code */
qr_pitch = DIV_ROUND_UP(qr_width, 8);
drm_panic_fill(sb, &r_qr_canvas, fg_color);
drm_panic_fill(sb, &r_qr, bg_color);
drm_panic_blit(sb, &r_qr, qr_image, qr_pitch, scale, fg_color);
return 0;
}
static void draw_panic_static_qr_code(struct drm_scanout_buffer *sb)
{
if (_draw_panic_static_qr_code(sb))
draw_panic_static_user(sb);
}
#else
static void draw_panic_static_qr_code(struct drm_scanout_buffer *sb)
{
draw_panic_static_user(sb);
}
static void drm_panic_qr_init(void) {};
static void drm_panic_qr_exit(void) {};
#endif
/*
* drm_panic_is_format_supported()
* @format: a fourcc color code
@ -633,6 +875,8 @@ static void draw_panic_dispatch(struct drm_scanout_buffer *sb)
{
if (!strcmp(drm_panic_screen, "kmsg")) {
draw_panic_static_kmsg(sb);
} else if (!strcmp(drm_panic_screen, "qr_code")) {
draw_panic_static_qr_code(sb);
} else {
draw_panic_static_user(sb);
}
@ -643,7 +887,7 @@ static void drm_panic_set_description(const char *description)
u32 len;
if (description) {
struct drm_panic_line *desc_line = &panic_msg[PANIC_MSG_LINES - 1];
struct drm_panic_line *desc_line = &panic_msg[panic_msg_lines - 1];
desc_line->txt = description;
len = strlen(description);
@ -656,7 +900,7 @@ static void drm_panic_set_description(const char *description)
static void drm_panic_clear_description(void)
{
struct drm_panic_line *desc_line = &panic_msg[PANIC_MSG_LINES - 1];
struct drm_panic_line *desc_line = &panic_msg[panic_msg_lines - 1];
desc_line->len = 0;
desc_line->txt = NULL;
@ -802,3 +1046,19 @@ void drm_panic_unregister(struct drm_device *dev)
kmsg_dump_unregister(&plane->kmsg_panic);
}
}
/**
* drm_panic_init() - initialize DRM panic.
*/
void __init drm_panic_init(void)
{
drm_panic_qr_init();
}
/**
* drm_panic_exit() - Free the resources taken by drm_panic_exit()
*/
void drm_panic_exit(void)
{
drm_panic_qr_exit();
}

File diff suppressed because it is too large Load Diff

View File

@ -85,7 +85,6 @@ static u32 clip_scaled(int src, int dst, int *clip)
* factors from @src to @dst.
*
* RETURNS:
*
* %true if rectangle @dst is still visible after being clipped,
* %false otherwise.
*/

View File

@ -686,7 +686,6 @@ EXPORT_SYMBOL(drm_calc_timestamping_constants);
* drm_atomic_helper_calc_timestamping_constants().
*
* Returns:
*
* Returns true on success, and false on failure, i.e. when no accurate
* timestamp could be acquired.
*/
@ -831,7 +830,6 @@ EXPORT_SYMBOL(drm_crtc_vblank_helper_get_vblank_timestamp_internal);
* drm_atomic_helper_calc_timestamping_constants().
*
* Returns:
*
* Returns true on success, and false on failure, i.e. when no accurate
* timestamp could be acquired.
*/

View File

@ -89,7 +89,6 @@ __i915_gem_object_unset_pages(struct drm_i915_gem_object *obj);
* @handle: userspace handle
*
* Returns:
*
* A pointer to the object named by the handle if such exists on @filp, NULL
* otherwise. This object is only valid whilst under the RCU read lock, and
* note carefully the object may be in the process of being destroyed.

View File

@ -418,7 +418,6 @@ out_unpin:
* For an untiled surface, this removes any existing fence.
*
* Returns:
*
* 0 on success, negative error code on failure.
*/
int i915_vma_pin_fence(struct i915_vma *vma)

View File

@ -389,7 +389,6 @@ void i915_vma_unpin_iomap(struct i915_vma *vma);
* i915_vma_unpin_fence().
*
* Returns:
*
* True if the vma has a fence, false otherwise.
*/
int __must_check i915_vma_pin_fence(struct i915_vma *vma);

View File

@ -34,7 +34,7 @@ struct imx_parallel_display_encoder {
struct imx_parallel_display {
struct device *dev;
void *edid;
const struct drm_edid *drm_edid;
u32 bus_format;
u32 bus_flags;
struct drm_display_mode mode;
@ -62,9 +62,9 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector)
if (num_modes > 0)
return num_modes;
if (imxpd->edid) {
drm_connector_update_edid_property(connector, imxpd->edid);
num_modes = drm_add_edid_modes(connector, imxpd->edid);
if (imxpd->drm_edid) {
drm_edid_connector_update(connector, imxpd->drm_edid);
num_modes = drm_edid_connector_add_modes(connector);
}
if (np) {
@ -331,7 +331,7 @@ static int imx_pd_probe(struct platform_device *pdev)
edidp = of_get_property(np, "edid", &edid_len);
if (edidp)
imxpd->edid = devm_kmemdup(dev, edidp, edid_len, GFP_KERNEL);
imxpd->drm_edid = drm_edid_alloc(edidp, edid_len);
ret = of_property_read_string(np, "interface-pix-fmt", &fmt);
if (!ret) {
@ -355,7 +355,11 @@ static int imx_pd_probe(struct platform_device *pdev)
static void imx_pd_remove(struct platform_device *pdev)
{
struct imx_parallel_display *imxpd = platform_get_drvdata(pdev);
component_del(&pdev->dev, &imx_pd_ops);
drm_edid_free(imxpd->drm_edid);
}
static const struct of_device_id imx_pd_dt_ids[] = {

View File

@ -695,6 +695,10 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev)
soc = soc_device_match(omapdrm_soc_devices);
priv->omaprev = soc ? (uintptr_t)soc->data : 0;
priv->wq = alloc_ordered_workqueue("omapdrm", 0);
if (!priv->wq) {
ret = -ENOMEM;
goto err_alloc_workqueue;
}
mutex_init(&priv->list_lock);
INIT_LIST_HEAD(&priv->obj_list);
@ -753,6 +757,7 @@ err_gem_deinit:
drm_mode_config_cleanup(ddev);
omap_gem_deinit(ddev);
destroy_workqueue(priv->wq);
err_alloc_workqueue:
omap_disconnect_pipelines(ddev);
drm_dev_put(ddev);
return ret;

View File

@ -87,6 +87,15 @@ config DRM_PANEL_BOE_TV101WUM_NL6
Say Y here if you want to support for BOE TV101WUM and AUO KD101N80
45NA WUXGA PANEL DSI Video Mode panel
config DRM_PANEL_BOE_TV101WUM_LL2
tristate "BOE TV101WUM LL2 1200x1920 panel"
depends on OF
depends on DRM_MIPI_DSI
depends on BACKLIGHT_CLASS_DEVICE
help
Say Y here if you want to support for BOE TV101WUM-LL2
WUXGA PANEL DSI Video Mode panel
config DRM_PANEL_EBBG_FT8719
tristate "EBBG FT8719 panel driver"
depends on OF

View File

@ -6,6 +6,7 @@ obj-$(CONFIG_DRM_PANEL_AUO_A030JTN01) += panel-auo-a030jtn01.o
obj-$(CONFIG_DRM_PANEL_BOE_BF060Y8M_AJ0) += panel-boe-bf060y8m-aj0.o
obj-$(CONFIG_DRM_PANEL_BOE_HIMAX8279D) += panel-boe-himax8279d.o
obj-$(CONFIG_DRM_PANEL_BOE_TH101MB31UIG002_28A) += panel-boe-th101mb31ig002-28a.o
obj-$(CONFIG_DRM_PANEL_BOE_TV101WUM_LL2) += panel-boe-tv101wum-ll2.o
obj-$(CONFIG_DRM_PANEL_BOE_TV101WUM_NL6) += panel-boe-tv101wum-nl6.o
obj-$(CONFIG_DRM_PANEL_DSI_CM) += panel-dsi-cm.o
obj-$(CONFIG_DRM_PANEL_LVDS) += panel-lvds.o

View File

@ -0,0 +1,241 @@
// SPDX-License-Identifier: GPL-2.0-only
// Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree:
// Copyright (c) 2013, The Linux Foundation. All rights reserved.
// Copyright (c) 2024, Neil Armstrong <neil.armstrong@linaro.org>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/regulator/consumer.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
#include <drm/drm_probe_helper.h>
struct boe_tv101wum_ll2 {
struct drm_panel panel;
struct mipi_dsi_device *dsi;
struct gpio_desc *reset_gpio;
struct regulator_bulk_data *supplies;
};
static const struct regulator_bulk_data boe_tv101wum_ll2_supplies[] = {
{ .supply = "vsp" },
{ .supply = "vsn" },
};
static inline struct boe_tv101wum_ll2 *to_boe_tv101wum_ll2(struct drm_panel *panel)
{
return container_of(panel, struct boe_tv101wum_ll2, panel);
}
static void boe_tv101wum_ll2_reset(struct boe_tv101wum_ll2 *ctx)
{
gpiod_set_value_cansleep(ctx->reset_gpio, 0);
usleep_range(5000, 6000);
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
usleep_range(5000, 6000);
gpiod_set_value_cansleep(ctx->reset_gpio, 0);
msleep(120);
}
static int boe_tv101wum_ll2_on(struct boe_tv101wum_ll2 *ctx)
{
struct mipi_dsi_device *dsi = ctx->dsi;
struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
dsi->mode_flags |= MIPI_DSI_MODE_LPM;
mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
mipi_dsi_msleep(&dsi_ctx, 120);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x50, 0x5a, 0x0e);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x80, 0xff, 0x81, 0x68, 0x6c, 0x22,
0x6d, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x50, 0x5a, 0x23);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x90, 0x00, 0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x94, 0x2c, 0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x50, 0x5a, 0x19);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xa2, 0x38);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x50, 0x5a, 0x0c);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x80, 0xfd);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x50, 0x00);
mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
mipi_dsi_msleep(&dsi_ctx, 20);
return dsi_ctx.accum_err;
}
static void boe_tv101wum_ll2_off(struct boe_tv101wum_ll2 *ctx)
{
struct mipi_dsi_device *dsi = ctx->dsi;
struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
mipi_dsi_msleep(&dsi_ctx, 70);
mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
mipi_dsi_msleep(&dsi_ctx, 20);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x04, 0x5a);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x05, 0x5a);
mipi_dsi_msleep(&dsi_ctx, 150);
}
static int boe_tv101wum_ll2_prepare(struct drm_panel *panel)
{
struct boe_tv101wum_ll2 *ctx = to_boe_tv101wum_ll2(panel);
int ret;
ret = regulator_bulk_enable(ARRAY_SIZE(boe_tv101wum_ll2_supplies),
ctx->supplies);
if (ret < 0)
return ret;
boe_tv101wum_ll2_reset(ctx);
ret = boe_tv101wum_ll2_on(ctx);
if (ret < 0) {
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
regulator_bulk_disable(ARRAY_SIZE(boe_tv101wum_ll2_supplies),
ctx->supplies);
return ret;
}
return 0;
}
static int boe_tv101wum_ll2_unprepare(struct drm_panel *panel)
{
struct boe_tv101wum_ll2 *ctx = to_boe_tv101wum_ll2(panel);
/* Ignore errors on failure, in any case set gpio and disable regulators */
boe_tv101wum_ll2_off(ctx);
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
regulator_bulk_disable(ARRAY_SIZE(boe_tv101wum_ll2_supplies),
ctx->supplies);
return 0;
}
static const struct drm_display_mode boe_tv101wum_ll2_mode = {
.clock = (1200 + 27 + 8 + 12) * (1920 + 155 + 8 + 32) * 60 / 1000,
.hdisplay = 1200,
.hsync_start = 1200 + 27,
.hsync_end = 1200 + 27 + 8,
.htotal = 1200 + 27 + 8 + 12,
.vdisplay = 1920,
.vsync_start = 1920 + 155,
.vsync_end = 1920 + 155 + 8,
.vtotal = 1920 + 155 + 8 + 32,
.width_mm = 136,
.height_mm = 217,
.type = DRM_MODE_TYPE_DRIVER,
};
static int boe_tv101wum_ll2_get_modes(struct drm_panel *panel,
struct drm_connector *connector)
{
/* We do not set display_info.bpc since unset value is bpc=8 by default */
return drm_connector_helper_get_modes_fixed(connector, &boe_tv101wum_ll2_mode);
}
static const struct drm_panel_funcs boe_tv101wum_ll2_panel_funcs = {
.prepare = boe_tv101wum_ll2_prepare,
.unprepare = boe_tv101wum_ll2_unprepare,
.get_modes = boe_tv101wum_ll2_get_modes,
};
static int boe_tv101wum_ll2_probe(struct mipi_dsi_device *dsi)
{
struct device *dev = &dsi->dev;
struct boe_tv101wum_ll2 *ctx;
int ret;
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
ret = devm_regulator_bulk_get_const(&dsi->dev,
ARRAY_SIZE(boe_tv101wum_ll2_supplies),
boe_tv101wum_ll2_supplies,
&ctx->supplies);
if (ret < 0)
return ret;
ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(ctx->reset_gpio))
return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
"Failed to get reset-gpios\n");
ctx->dsi = dsi;
mipi_dsi_set_drvdata(dsi, ctx);
dsi->lanes = 4;
dsi->format = MIPI_DSI_FMT_RGB888;
dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
MIPI_DSI_MODE_VIDEO_HSE;
drm_panel_init(&ctx->panel, dev, &boe_tv101wum_ll2_panel_funcs,
DRM_MODE_CONNECTOR_DSI);
ctx->panel.prepare_prev_first = true;
ret = drm_panel_of_backlight(&ctx->panel);
if (ret)
return dev_err_probe(dev, ret, "Failed to get backlight\n");
drm_panel_add(&ctx->panel);
ret = mipi_dsi_attach(dsi);
if (ret < 0) {
drm_panel_remove(&ctx->panel);
return dev_err_probe(dev, ret, "Failed to attach to DSI host\n");
}
return 0;
}
static void boe_tv101wum_ll2_remove(struct mipi_dsi_device *dsi)
{
struct boe_tv101wum_ll2 *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 boe_tv101wum_ll2_of_match[] = {
{ .compatible = "boe,tv101wum-ll2" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, boe_tv101wum_ll2_of_match);
static struct mipi_dsi_driver boe_tv101wum_ll2_driver = {
.probe = boe_tv101wum_ll2_probe,
.remove = boe_tv101wum_ll2_remove,
.driver = {
.name = "panel-boe-tv101wum_ll2",
.of_match_table = boe_tv101wum_ll2_of_match,
},
};
module_mipi_dsi_driver(boe_tv101wum_ll2_driver);
MODULE_DESCRIPTION("DRM driver for BOE TV101WUM-LL2 Panel");
MODULE_LICENSE("GPL");

View File

@ -1911,6 +1911,7 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b34, &delay_200_500_e80, "NV122WUM-N41"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b43, &delay_200_500_e200, "NV140FHM-T09"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b56, &delay_200_500_e80, "NT140FHM-N47"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b66, &delay_200_500_e80, "NE140WUM-N6G"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0c20, &delay_200_500_e80, "NT140FHM-N47"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0cb6, &delay_200_500_e200, "NT116WHM-N44"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0cfa, &delay_200_500_e50, "NV116WHM-A4D"),
@ -1977,8 +1978,6 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('L', 'G', 'D', 0x05af, &delay_200_500_e200_d200, "Unknown"),
EDP_PANEL_ENTRY('L', 'G', 'D', 0x05f1, &delay_200_500_e200_d200, "Unknown"),
EDP_PANEL_ENTRY('S', 'D', 'C', 0x416d, &delay_100_500_e200, "ATNA45AF01"),
EDP_PANEL_ENTRY('S', 'H', 'P', 0x1511, &delay_200_500_e50, "LQ140M1JW48"),
EDP_PANEL_ENTRY('S', 'H', 'P', 0x1523, &delay_80_500_e50, "LQ140M1JW46"),
EDP_PANEL_ENTRY('S', 'H', 'P', 0x153a, &delay_200_500_e50, "LQ140T1JH01"),

View File

@ -47,195 +47,196 @@ static inline struct panel_nv3051d *panel_to_panelnv3051d(struct drm_panel *pane
static int panel_nv3051d_init_sequence(struct panel_nv3051d *ctx)
{
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
struct mipi_dsi_multi_context dsi_ctx = {.dsi = dsi};
/*
* Init sequence was supplied by device vendor with no
* documentation.
*/
mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x30);
mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x52);
mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x01);
mipi_dsi_dcs_write_seq(dsi, 0xE3, 0x00);
mipi_dsi_dcs_write_seq(dsi, 0x03, 0x40);
mipi_dsi_dcs_write_seq(dsi, 0x04, 0x00);
mipi_dsi_dcs_write_seq(dsi, 0x05, 0x03);
mipi_dsi_dcs_write_seq(dsi, 0x24, 0x12);
mipi_dsi_dcs_write_seq(dsi, 0x25, 0x1E);
mipi_dsi_dcs_write_seq(dsi, 0x26, 0x28);
mipi_dsi_dcs_write_seq(dsi, 0x27, 0x52);
mipi_dsi_dcs_write_seq(dsi, 0x28, 0x57);
mipi_dsi_dcs_write_seq(dsi, 0x29, 0x01);
mipi_dsi_dcs_write_seq(dsi, 0x2A, 0xDF);
mipi_dsi_dcs_write_seq(dsi, 0x38, 0x9C);
mipi_dsi_dcs_write_seq(dsi, 0x39, 0xA7);
mipi_dsi_dcs_write_seq(dsi, 0x3A, 0x53);
mipi_dsi_dcs_write_seq(dsi, 0x44, 0x00);
mipi_dsi_dcs_write_seq(dsi, 0x49, 0x3C);
mipi_dsi_dcs_write_seq(dsi, 0x59, 0xFE);
mipi_dsi_dcs_write_seq(dsi, 0x5C, 0x00);
mipi_dsi_dcs_write_seq(dsi, 0x91, 0x77);
mipi_dsi_dcs_write_seq(dsi, 0x92, 0x77);
mipi_dsi_dcs_write_seq(dsi, 0xA0, 0x55);
mipi_dsi_dcs_write_seq(dsi, 0xA1, 0x50);
mipi_dsi_dcs_write_seq(dsi, 0xA4, 0x9C);
mipi_dsi_dcs_write_seq(dsi, 0xA7, 0x02);
mipi_dsi_dcs_write_seq(dsi, 0xA8, 0x01);
mipi_dsi_dcs_write_seq(dsi, 0xA9, 0x01);
mipi_dsi_dcs_write_seq(dsi, 0xAA, 0xFC);
mipi_dsi_dcs_write_seq(dsi, 0xAB, 0x28);
mipi_dsi_dcs_write_seq(dsi, 0xAC, 0x06);
mipi_dsi_dcs_write_seq(dsi, 0xAD, 0x06);
mipi_dsi_dcs_write_seq(dsi, 0xAE, 0x06);
mipi_dsi_dcs_write_seq(dsi, 0xAF, 0x03);
mipi_dsi_dcs_write_seq(dsi, 0xB0, 0x08);
mipi_dsi_dcs_write_seq(dsi, 0xB1, 0x26);
mipi_dsi_dcs_write_seq(dsi, 0xB2, 0x28);
mipi_dsi_dcs_write_seq(dsi, 0xB3, 0x28);
mipi_dsi_dcs_write_seq(dsi, 0xB4, 0x33);
mipi_dsi_dcs_write_seq(dsi, 0xB5, 0x08);
mipi_dsi_dcs_write_seq(dsi, 0xB6, 0x26);
mipi_dsi_dcs_write_seq(dsi, 0xB7, 0x08);
mipi_dsi_dcs_write_seq(dsi, 0xB8, 0x26);
mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x30);
mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x52);
mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x02);
mipi_dsi_dcs_write_seq(dsi, 0xB1, 0x0E);
mipi_dsi_dcs_write_seq(dsi, 0xD1, 0x0E);
mipi_dsi_dcs_write_seq(dsi, 0xB4, 0x29);
mipi_dsi_dcs_write_seq(dsi, 0xD4, 0x2B);
mipi_dsi_dcs_write_seq(dsi, 0xB2, 0x0C);
mipi_dsi_dcs_write_seq(dsi, 0xD2, 0x0A);
mipi_dsi_dcs_write_seq(dsi, 0xB3, 0x28);
mipi_dsi_dcs_write_seq(dsi, 0xD3, 0x28);
mipi_dsi_dcs_write_seq(dsi, 0xB6, 0x11);
mipi_dsi_dcs_write_seq(dsi, 0xD6, 0x0D);
mipi_dsi_dcs_write_seq(dsi, 0xB7, 0x32);
mipi_dsi_dcs_write_seq(dsi, 0xD7, 0x30);
mipi_dsi_dcs_write_seq(dsi, 0xC1, 0x04);
mipi_dsi_dcs_write_seq(dsi, 0xE1, 0x06);
mipi_dsi_dcs_write_seq(dsi, 0xB8, 0x0A);
mipi_dsi_dcs_write_seq(dsi, 0xD8, 0x0A);
mipi_dsi_dcs_write_seq(dsi, 0xB9, 0x01);
mipi_dsi_dcs_write_seq(dsi, 0xD9, 0x01);
mipi_dsi_dcs_write_seq(dsi, 0xBD, 0x13);
mipi_dsi_dcs_write_seq(dsi, 0xDD, 0x13);
mipi_dsi_dcs_write_seq(dsi, 0xBC, 0x11);
mipi_dsi_dcs_write_seq(dsi, 0xDC, 0x11);
mipi_dsi_dcs_write_seq(dsi, 0xBB, 0x0F);
mipi_dsi_dcs_write_seq(dsi, 0xDB, 0x0F);
mipi_dsi_dcs_write_seq(dsi, 0xBA, 0x0F);
mipi_dsi_dcs_write_seq(dsi, 0xDA, 0x0F);
mipi_dsi_dcs_write_seq(dsi, 0xBE, 0x18);
mipi_dsi_dcs_write_seq(dsi, 0xDE, 0x18);
mipi_dsi_dcs_write_seq(dsi, 0xBF, 0x0F);
mipi_dsi_dcs_write_seq(dsi, 0xDF, 0x0F);
mipi_dsi_dcs_write_seq(dsi, 0xC0, 0x17);
mipi_dsi_dcs_write_seq(dsi, 0xE0, 0x17);
mipi_dsi_dcs_write_seq(dsi, 0xB5, 0x3B);
mipi_dsi_dcs_write_seq(dsi, 0xD5, 0x3C);
mipi_dsi_dcs_write_seq(dsi, 0xB0, 0x0B);
mipi_dsi_dcs_write_seq(dsi, 0xD0, 0x0C);
mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x30);
mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x52);
mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x03);
mipi_dsi_dcs_write_seq(dsi, 0x00, 0x2A);
mipi_dsi_dcs_write_seq(dsi, 0x01, 0x2A);
mipi_dsi_dcs_write_seq(dsi, 0x02, 0x2A);
mipi_dsi_dcs_write_seq(dsi, 0x03, 0x2A);
mipi_dsi_dcs_write_seq(dsi, 0x04, 0x61);
mipi_dsi_dcs_write_seq(dsi, 0x05, 0x80);
mipi_dsi_dcs_write_seq(dsi, 0x06, 0xC7);
mipi_dsi_dcs_write_seq(dsi, 0x07, 0x01);
mipi_dsi_dcs_write_seq(dsi, 0x08, 0x82);
mipi_dsi_dcs_write_seq(dsi, 0x09, 0x83);
mipi_dsi_dcs_write_seq(dsi, 0x30, 0x2A);
mipi_dsi_dcs_write_seq(dsi, 0x31, 0x2A);
mipi_dsi_dcs_write_seq(dsi, 0x32, 0x2A);
mipi_dsi_dcs_write_seq(dsi, 0x33, 0x2A);
mipi_dsi_dcs_write_seq(dsi, 0x34, 0x61);
mipi_dsi_dcs_write_seq(dsi, 0x35, 0xC5);
mipi_dsi_dcs_write_seq(dsi, 0x36, 0x80);
mipi_dsi_dcs_write_seq(dsi, 0x37, 0x23);
mipi_dsi_dcs_write_seq(dsi, 0x40, 0x82);
mipi_dsi_dcs_write_seq(dsi, 0x41, 0x83);
mipi_dsi_dcs_write_seq(dsi, 0x42, 0x80);
mipi_dsi_dcs_write_seq(dsi, 0x43, 0x81);
mipi_dsi_dcs_write_seq(dsi, 0x44, 0x11);
mipi_dsi_dcs_write_seq(dsi, 0x45, 0xF2);
mipi_dsi_dcs_write_seq(dsi, 0x46, 0xF1);
mipi_dsi_dcs_write_seq(dsi, 0x47, 0x11);
mipi_dsi_dcs_write_seq(dsi, 0x48, 0xF4);
mipi_dsi_dcs_write_seq(dsi, 0x49, 0xF3);
mipi_dsi_dcs_write_seq(dsi, 0x50, 0x02);
mipi_dsi_dcs_write_seq(dsi, 0x51, 0x01);
mipi_dsi_dcs_write_seq(dsi, 0x52, 0x04);
mipi_dsi_dcs_write_seq(dsi, 0x53, 0x03);
mipi_dsi_dcs_write_seq(dsi, 0x54, 0x11);
mipi_dsi_dcs_write_seq(dsi, 0x55, 0xF6);
mipi_dsi_dcs_write_seq(dsi, 0x56, 0xF5);
mipi_dsi_dcs_write_seq(dsi, 0x57, 0x11);
mipi_dsi_dcs_write_seq(dsi, 0x58, 0xF8);
mipi_dsi_dcs_write_seq(dsi, 0x59, 0xF7);
mipi_dsi_dcs_write_seq(dsi, 0x7E, 0x02);
mipi_dsi_dcs_write_seq(dsi, 0x7F, 0x80);
mipi_dsi_dcs_write_seq(dsi, 0xE0, 0x5A);
mipi_dsi_dcs_write_seq(dsi, 0xB1, 0x00);
mipi_dsi_dcs_write_seq(dsi, 0xB4, 0x0E);
mipi_dsi_dcs_write_seq(dsi, 0xB5, 0x0F);
mipi_dsi_dcs_write_seq(dsi, 0xB6, 0x04);
mipi_dsi_dcs_write_seq(dsi, 0xB7, 0x07);
mipi_dsi_dcs_write_seq(dsi, 0xB8, 0x06);
mipi_dsi_dcs_write_seq(dsi, 0xB9, 0x05);
mipi_dsi_dcs_write_seq(dsi, 0xBA, 0x0F);
mipi_dsi_dcs_write_seq(dsi, 0xC7, 0x00);
mipi_dsi_dcs_write_seq(dsi, 0xCA, 0x0E);
mipi_dsi_dcs_write_seq(dsi, 0xCB, 0x0F);
mipi_dsi_dcs_write_seq(dsi, 0xCC, 0x04);
mipi_dsi_dcs_write_seq(dsi, 0xCD, 0x07);
mipi_dsi_dcs_write_seq(dsi, 0xCE, 0x06);
mipi_dsi_dcs_write_seq(dsi, 0xCF, 0x05);
mipi_dsi_dcs_write_seq(dsi, 0xD0, 0x0F);
mipi_dsi_dcs_write_seq(dsi, 0x81, 0x0F);
mipi_dsi_dcs_write_seq(dsi, 0x84, 0x0E);
mipi_dsi_dcs_write_seq(dsi, 0x85, 0x0F);
mipi_dsi_dcs_write_seq(dsi, 0x86, 0x07);
mipi_dsi_dcs_write_seq(dsi, 0x87, 0x04);
mipi_dsi_dcs_write_seq(dsi, 0x88, 0x05);
mipi_dsi_dcs_write_seq(dsi, 0x89, 0x06);
mipi_dsi_dcs_write_seq(dsi, 0x8A, 0x00);
mipi_dsi_dcs_write_seq(dsi, 0x97, 0x0F);
mipi_dsi_dcs_write_seq(dsi, 0x9A, 0x0E);
mipi_dsi_dcs_write_seq(dsi, 0x9B, 0x0F);
mipi_dsi_dcs_write_seq(dsi, 0x9C, 0x07);
mipi_dsi_dcs_write_seq(dsi, 0x9D, 0x04);
mipi_dsi_dcs_write_seq(dsi, 0x9E, 0x05);
mipi_dsi_dcs_write_seq(dsi, 0x9F, 0x06);
mipi_dsi_dcs_write_seq(dsi, 0xA0, 0x00);
mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x30);
mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x52);
mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x02);
mipi_dsi_dcs_write_seq(dsi, 0x01, 0x01);
mipi_dsi_dcs_write_seq(dsi, 0x02, 0xDA);
mipi_dsi_dcs_write_seq(dsi, 0x03, 0xBA);
mipi_dsi_dcs_write_seq(dsi, 0x04, 0xA8);
mipi_dsi_dcs_write_seq(dsi, 0x05, 0x9A);
mipi_dsi_dcs_write_seq(dsi, 0x06, 0x70);
mipi_dsi_dcs_write_seq(dsi, 0x07, 0xFF);
mipi_dsi_dcs_write_seq(dsi, 0x08, 0x91);
mipi_dsi_dcs_write_seq(dsi, 0x09, 0x90);
mipi_dsi_dcs_write_seq(dsi, 0x0A, 0xFF);
mipi_dsi_dcs_write_seq(dsi, 0x0B, 0x8F);
mipi_dsi_dcs_write_seq(dsi, 0x0C, 0x60);
mipi_dsi_dcs_write_seq(dsi, 0x0D, 0x58);
mipi_dsi_dcs_write_seq(dsi, 0x0E, 0x48);
mipi_dsi_dcs_write_seq(dsi, 0x0F, 0x38);
mipi_dsi_dcs_write_seq(dsi, 0x10, 0x2B);
mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x30);
mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x52);
mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x00);
mipi_dsi_dcs_write_seq(dsi, 0x36, 0x02);
mipi_dsi_dcs_write_seq(dsi, 0x3A, 0x70);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xFF, 0x30);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xFF, 0x52);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xFF, 0x01);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xE3, 0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x03, 0x40);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x04, 0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x05, 0x03);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x24, 0x12);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x25, 0x1E);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x26, 0x28);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x27, 0x52);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x28, 0x57);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x29, 0x01);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2A, 0xDF);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x38, 0x9C);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x39, 0xA7);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3A, 0x53);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x44, 0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x49, 0x3C);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x59, 0xFE);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5C, 0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x91, 0x77);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x92, 0x77);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xA0, 0x55);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xA1, 0x50);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xA4, 0x9C);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xA7, 0x02);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xA8, 0x01);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xA9, 0x01);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xAA, 0xFC);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xAB, 0x28);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xAC, 0x06);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xAD, 0x06);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xAE, 0x06);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xAF, 0x03);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB0, 0x08);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB1, 0x26);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB2, 0x28);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB3, 0x28);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB4, 0x33);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB5, 0x08);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB6, 0x26);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB7, 0x08);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB8, 0x26);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xFF, 0x30);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xFF, 0x52);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xFF, 0x02);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB1, 0x0E);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xD1, 0x0E);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB4, 0x29);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xD4, 0x2B);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB2, 0x0C);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xD2, 0x0A);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB3, 0x28);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xD3, 0x28);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB6, 0x11);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xD6, 0x0D);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB7, 0x32);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xD7, 0x30);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xC1, 0x04);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xE1, 0x06);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB8, 0x0A);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xD8, 0x0A);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB9, 0x01);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xD9, 0x01);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xBD, 0x13);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xDD, 0x13);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xBC, 0x11);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xDC, 0x11);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xBB, 0x0F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xDB, 0x0F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xBA, 0x0F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xDA, 0x0F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xBE, 0x18);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xDE, 0x18);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xBF, 0x0F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xDF, 0x0F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xC0, 0x17);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xE0, 0x17);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB5, 0x3B);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xD5, 0x3C);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB0, 0x0B);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xD0, 0x0C);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xFF, 0x30);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xFF, 0x52);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xFF, 0x03);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x2A);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x01, 0x2A);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x02, 0x2A);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x03, 0x2A);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x04, 0x61);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x05, 0x80);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x06, 0xC7);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x07, 0x01);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x08, 0x82);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x09, 0x83);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x30, 0x2A);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x31, 0x2A);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x32, 0x2A);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x33, 0x2A);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x34, 0x61);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x35, 0xC5);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x36, 0x80);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x37, 0x23);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x40, 0x82);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x41, 0x83);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x42, 0x80);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x43, 0x81);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x44, 0x11);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x45, 0xF2);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x46, 0xF1);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x47, 0x11);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x48, 0xF4);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x49, 0xF3);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x50, 0x02);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x51, 0x01);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x52, 0x04);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x53, 0x03);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x54, 0x11);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x55, 0xF6);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x56, 0xF5);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x57, 0x11);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x58, 0xF8);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x59, 0xF7);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7E, 0x02);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7F, 0x80);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xE0, 0x5A);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB1, 0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB4, 0x0E);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB5, 0x0F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB6, 0x04);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB7, 0x07);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB8, 0x06);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB9, 0x05);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xBA, 0x0F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xC7, 0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xCA, 0x0E);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xCB, 0x0F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xCC, 0x04);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xCD, 0x07);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xCE, 0x06);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xCF, 0x05);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xD0, 0x0F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x81, 0x0F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x84, 0x0E);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x85, 0x0F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x86, 0x07);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x87, 0x04);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x88, 0x05);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x89, 0x06);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x8A, 0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x97, 0x0F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x9A, 0x0E);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x9B, 0x0F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x9C, 0x07);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x9D, 0x04);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x9E, 0x05);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x9F, 0x06);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xA0, 0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xFF, 0x30);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xFF, 0x52);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xFF, 0x02);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x01, 0x01);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x02, 0xDA);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x03, 0xBA);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x04, 0xA8);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x05, 0x9A);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x06, 0x70);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x07, 0xFF);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x08, 0x91);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x09, 0x90);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0A, 0xFF);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0B, 0x8F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0C, 0x60);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0D, 0x58);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0E, 0x48);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0F, 0x38);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x10, 0x2B);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xFF, 0x30);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xFF, 0x52);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xFF, 0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x36, 0x02);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3A, 0x70);
dev_dbg(ctx->dev, "Panel init sequence done\n");

View File

@ -100,106 +100,87 @@ static void nt35950_reset(struct nt35950 *nt)
/*
* nt35950_set_cmd2_page - Select manufacturer control (CMD2) page
* @dsi_ctx: context for mipi_dsi functions
* @nt: Main driver structure
* @page: Page number (0-7)
*
* Return: Number of transferred bytes or negative number on error
*/
static int nt35950_set_cmd2_page(struct nt35950 *nt, u8 page)
static void nt35950_set_cmd2_page(struct mipi_dsi_multi_context *dsi_ctx,
struct nt35950 *nt, u8 page)
{
const u8 mauc_cmd2_page[] = { MCS_CMD_MAUCCTR, 0x55, 0xaa, 0x52,
0x08, page };
int ret;
ret = mipi_dsi_dcs_write_buffer(nt->dsi[0], mauc_cmd2_page,
mipi_dsi_dcs_write_buffer_multi(dsi_ctx, mauc_cmd2_page,
ARRAY_SIZE(mauc_cmd2_page));
if (ret < 0)
return ret;
if (!dsi_ctx->accum_err)
nt->last_page = page;
return 0;
}
/*
* nt35950_set_data_compression - Set data compression mode
* @dsi_ctx: context for mipi_dsi functions
* @nt: Main driver structure
* @comp_mode: Compression mode
*
* Return: Number of transferred bytes or negative number on error
*/
static int nt35950_set_data_compression(struct nt35950 *nt, u8 comp_mode)
static void nt35950_set_data_compression(struct mipi_dsi_multi_context *dsi_ctx,
struct nt35950 *nt, u8 comp_mode)
{
u8 cmd_data_compression[] = { MCS_PARAM_DATA_COMPRESSION, comp_mode };
u8 cmd_vesa_dsc_on[] = { MCS_PARAM_VESA_DSC_ON, !!comp_mode };
u8 cmd_vesa_dsc_setting[] = { MCS_PARAM_VESA_DSC_SETTING, 0x03 };
u8 last_page = nt->last_page;
int ret;
/* Set CMD2 Page 0 if we're not there yet */
if (last_page != 0) {
ret = nt35950_set_cmd2_page(nt, 0);
if (ret < 0)
return ret;
}
if (last_page != 0)
nt35950_set_cmd2_page(dsi_ctx, nt, 0);
ret = mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd_data_compression,
mipi_dsi_dcs_write_buffer_multi(dsi_ctx, cmd_data_compression,
ARRAY_SIZE(cmd_data_compression));
if (ret < 0)
return ret;
ret = mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd_vesa_dsc_on,
mipi_dsi_dcs_write_buffer_multi(dsi_ctx, cmd_vesa_dsc_on,
ARRAY_SIZE(cmd_vesa_dsc_on));
if (ret < 0)
return ret;
/* Set the vesa dsc setting on Page 4 */
ret = nt35950_set_cmd2_page(nt, 4);
if (ret < 0)
return ret;
nt35950_set_cmd2_page(dsi_ctx, nt, 4);
/* Display Stream Compression setting, always 0x03 */
ret = mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd_vesa_dsc_setting,
mipi_dsi_dcs_write_buffer_multi(dsi_ctx, cmd_vesa_dsc_setting,
ARRAY_SIZE(cmd_vesa_dsc_setting));
if (ret < 0)
return ret;
/* Get back to the previously set page */
return nt35950_set_cmd2_page(nt, last_page);
nt35950_set_cmd2_page(dsi_ctx, nt, last_page);
}
/*
* nt35950_set_scaler - Enable/disable resolution upscaling
* @nt: Main driver structure
* @dsi_ctx: context for mipi_dsi functions
* @scale_up: Scale up function control
*
* Return: Number of transferred bytes or negative number on error
*/
static int nt35950_set_scaler(struct nt35950 *nt, u8 scale_up)
static void nt35950_set_scaler(struct mipi_dsi_multi_context *dsi_ctx,
u8 scale_up)
{
u8 cmd_scaler[] = { MCS_PARAM_SCALER_FUNCTION, scale_up };
return mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd_scaler,
mipi_dsi_dcs_write_buffer_multi(dsi_ctx, cmd_scaler,
ARRAY_SIZE(cmd_scaler));
}
/*
* nt35950_set_scale_mode - Resolution upscaling mode
* @nt: Main driver structure
* @dsi_ctx: context for mipi_dsi functions
* @mode: Scaler mode (MCS_DATA_COMPRESSION_*)
*
* Return: Number of transferred bytes or negative number on error
*/
static int nt35950_set_scale_mode(struct nt35950 *nt, u8 mode)
static void nt35950_set_scale_mode(struct mipi_dsi_multi_context *dsi_ctx,
u8 mode)
{
u8 cmd_scaler[] = { MCS_PARAM_SCALEUP_MODE, mode };
return mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd_scaler,
mipi_dsi_dcs_write_buffer_multi(dsi_ctx, cmd_scaler,
ARRAY_SIZE(cmd_scaler));
}
/*
* nt35950_inject_black_image - Display a completely black image
* @nt: Main driver structure
* @dsi_ctx: context for mipi_dsi functions
*
* After IC setup, the attached panel may show random data
* due to driveric behavior changes (resolution, compression,
@ -208,43 +189,34 @@ static int nt35950_set_scale_mode(struct nt35950 *nt, u8 mode)
* the display.
* It makes sense to push a black image before sending the sleep-out
* and display-on commands.
*
* Return: Number of transferred bytes or negative number on error
*/
static int nt35950_inject_black_image(struct nt35950 *nt)
static void nt35950_inject_black_image(struct mipi_dsi_multi_context *dsi_ctx)
{
const u8 cmd0_black_img[] = { 0x6f, 0x01 };
const u8 cmd1_black_img[] = { 0xf3, 0x10 };
u8 cmd_test[] = { 0xff, 0xaa, 0x55, 0xa5, 0x80 };
int ret;
/* Enable test command */
ret = mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd_test, ARRAY_SIZE(cmd_test));
if (ret < 0)
return ret;
mipi_dsi_dcs_write_buffer_multi(dsi_ctx, cmd_test, ARRAY_SIZE(cmd_test));
/* Send a black image */
ret = mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd0_black_img,
mipi_dsi_dcs_write_buffer_multi(dsi_ctx, cmd0_black_img,
ARRAY_SIZE(cmd0_black_img));
if (ret < 0)
return ret;
ret = mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd1_black_img,
mipi_dsi_dcs_write_buffer_multi(dsi_ctx, cmd1_black_img,
ARRAY_SIZE(cmd1_black_img));
if (ret < 0)
return ret;
/* Disable test command */
cmd_test[ARRAY_SIZE(cmd_test) - 1] = 0x00;
return mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd_test, ARRAY_SIZE(cmd_test));
mipi_dsi_dcs_write_buffer_multi(dsi_ctx, cmd_test, ARRAY_SIZE(cmd_test));
}
/*
* nt35950_set_dispout - Set Display Output register parameters
* @nt: Main driver structure
*
* Return: Number of transferred bytes or negative number on error
* @dsi_ctx: context for mipi_dsi functions
*/
static int nt35950_set_dispout(struct nt35950 *nt)
static void nt35950_set_dispout(struct mipi_dsi_multi_context *dsi_ctx,
struct nt35950 *nt)
{
u8 cmd_dispout[] = { MCS_PARAM_DISP_OUTPUT_CTRL, 0x00 };
const struct nt35950_panel_mode *mode_data = nt->desc->mode_data;
@ -254,7 +226,7 @@ static int nt35950_set_dispout(struct nt35950 *nt)
if (mode_data[nt->cur_mode].enable_sram)
cmd_dispout[1] |= MCS_DISP_OUT_SRAM_EN;
return mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd_dispout,
mipi_dsi_dcs_write_buffer_multi(dsi_ctx, cmd_dispout,
ARRAY_SIZE(cmd_dispout));
}
@ -284,78 +256,47 @@ static int nt35950_on(struct nt35950 *nt)
{
const struct nt35950_panel_mode *mode_data = nt->desc->mode_data;
struct mipi_dsi_device *dsi = nt->dsi[0];
struct device *dev = &dsi->dev;
int ret;
struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
nt->cur_mode = nt35950_get_current_mode(nt);
nt->dsi[0]->mode_flags |= MIPI_DSI_MODE_LPM;
nt->dsi[1]->mode_flags |= MIPI_DSI_MODE_LPM;
ret = nt35950_set_cmd2_page(nt, 0);
if (ret < 0)
return ret;
nt35950_set_cmd2_page(&dsi_ctx, nt, 0);
nt35950_set_data_compression(&dsi_ctx, nt, mode_data[nt->cur_mode].compression);
nt35950_set_scale_mode(&dsi_ctx, mode_data[nt->cur_mode].scaler_mode);
nt35950_set_scaler(&dsi_ctx, mode_data[nt->cur_mode].scaler_on);
nt35950_set_dispout(&dsi_ctx, nt);
ret = nt35950_set_data_compression(nt, mode_data[nt->cur_mode].compression);
if (ret < 0)
return ret;
ret = nt35950_set_scale_mode(nt, mode_data[nt->cur_mode].scaler_mode);
if (ret < 0)
return ret;
ret = nt35950_set_scaler(nt, mode_data[nt->cur_mode].scaler_on);
if (ret < 0)
return ret;
ret = nt35950_set_dispout(nt);
if (ret < 0)
return ret;
ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
if (ret < 0) {
dev_err(dev, "Failed to set tear on: %d\n", ret);
return ret;
}
ret = mipi_dsi_dcs_set_tear_scanline(dsi, 0);
if (ret < 0) {
dev_err(dev, "Failed to set tear scanline: %d\n", ret);
return ret;
}
mipi_dsi_dcs_set_tear_on_multi(&dsi_ctx, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
mipi_dsi_dcs_set_tear_scanline_multi(&dsi_ctx, 0);
/* CMD2 Page 1 */
ret = nt35950_set_cmd2_page(nt, 1);
if (ret < 0)
return ret;
nt35950_set_cmd2_page(&dsi_ctx, nt, 1);
/* Unknown command */
mipi_dsi_dcs_write_seq(dsi, 0xd4, 0x88, 0x88);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xd4, 0x88, 0x88);
/* CMD2 Page 7 */
ret = nt35950_set_cmd2_page(nt, 7);
if (ret < 0)
return ret;
nt35950_set_cmd2_page(&dsi_ctx, nt, 7);
/* Enable SubPixel Rendering */
mipi_dsi_dcs_write_seq(dsi, MCS_PARAM_SPR_EN, 0x01);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MCS_PARAM_SPR_EN, 0x01);
/* SPR Mode: YYG Rainbow-RGB */
mipi_dsi_dcs_write_seq(dsi, MCS_PARAM_SPR_MODE, MCS_SPR_MODE_YYG_RAINBOW_RGB);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MCS_PARAM_SPR_MODE,
MCS_SPR_MODE_YYG_RAINBOW_RGB);
/* CMD3 */
ret = nt35950_inject_black_image(nt);
if (ret < 0)
return ret;
nt35950_inject_black_image(&dsi_ctx);
mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
mipi_dsi_msleep(&dsi_ctx, 120);
ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
if (ret < 0)
return ret;
msleep(120);
mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
mipi_dsi_msleep(&dsi_ctx, 120);
ret = mipi_dsi_dcs_set_display_on(dsi);
if (ret < 0)
return ret;
msleep(120);
if (dsi_ctx.accum_err)
return dsi_ctx.accum_err;
nt->dsi[0]->mode_flags &= ~MIPI_DSI_MODE_LPM;
nt->dsi[1]->mode_flags &= ~MIPI_DSI_MODE_LPM;
@ -363,30 +304,19 @@ static int nt35950_on(struct nt35950 *nt)
return 0;
}
static int nt35950_off(struct nt35950 *nt)
static void nt35950_off(struct nt35950 *nt)
{
struct device *dev = &nt->dsi[0]->dev;
int ret;
struct mipi_dsi_device *dsi = nt->dsi[0];
struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
ret = mipi_dsi_dcs_set_display_off(nt->dsi[0]);
if (ret < 0) {
dev_err(dev, "Failed to set display off: %d\n", ret);
goto set_lpm;
}
usleep_range(10000, 11000);
mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
mipi_dsi_usleep_range(&dsi_ctx, 10000, 11000);
ret = mipi_dsi_dcs_enter_sleep_mode(nt->dsi[0]);
if (ret < 0) {
dev_err(dev, "Failed to enter sleep mode: %d\n", ret);
goto set_lpm;
}
msleep(150);
mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
mipi_dsi_msleep(&dsi_ctx, 150);
set_lpm:
nt->dsi[0]->mode_flags |= MIPI_DSI_MODE_LPM;
nt->dsi[1]->mode_flags |= MIPI_DSI_MODE_LPM;
return 0;
}
static int nt35950_sharp_init_vregs(struct nt35950 *nt, struct device *dev)
@ -427,7 +357,6 @@ static int nt35950_sharp_init_vregs(struct nt35950 *nt, struct device *dev)
static int nt35950_prepare(struct drm_panel *panel)
{
struct nt35950 *nt = to_nt35950(panel);
struct device *dev = &nt->dsi[0]->dev;
int ret;
ret = regulator_enable(nt->vregs[0].consumer);
@ -452,10 +381,6 @@ static int nt35950_prepare(struct drm_panel *panel)
nt35950_reset(nt);
ret = nt35950_on(nt);
if (ret < 0) {
dev_err(dev, "Failed to initialize panel: %d\n", ret);
goto end;
}
end:
if (ret < 0) {
@ -469,12 +394,8 @@ end:
static int nt35950_unprepare(struct drm_panel *panel)
{
struct nt35950 *nt = to_nt35950(panel);
struct device *dev = &nt->dsi[0]->dev;
int ret;
ret = nt35950_off(nt);
if (ret < 0)
dev_err(dev, "Failed to deinitialize panel: %d\n", ret);
nt35950_off(nt);
gpiod_set_value_cansleep(nt->reset_gpio, 0);
regulator_bulk_disable(ARRAY_SIZE(nt->vregs), nt->vregs);

View File

@ -19,7 +19,13 @@ struct visionox_vtdr6130 {
struct drm_panel panel;
struct mipi_dsi_device *dsi;
struct gpio_desc *reset_gpio;
struct regulator_bulk_data supplies[3];
struct regulator_bulk_data *supplies;
};
static const struct regulator_bulk_data visionox_vtdr6130_supplies[] = {
{ .supply = "vddio" },
{ .supply = "vci" },
{ .supply = "vdd" },
};
static inline struct visionox_vtdr6130 *to_visionox_vtdr6130(struct drm_panel *panel)
@ -40,123 +46,106 @@ static void visionox_vtdr6130_reset(struct visionox_vtdr6130 *ctx)
static int visionox_vtdr6130_on(struct visionox_vtdr6130 *ctx)
{
struct mipi_dsi_device *dsi = ctx->dsi;
struct device *dev = &dsi->dev;
int ret;
struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
dsi->mode_flags |= MIPI_DSI_MODE_LPM;
ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
if (ret)
return ret;
mipi_dsi_dcs_set_tear_on_multi(&dsi_ctx, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x20);
mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_DISPLAY_BRIGHTNESS, 0x00, 0x00);
mipi_dsi_dcs_write_seq(dsi, 0x59, 0x09);
mipi_dsi_dcs_write_seq(dsi, 0x6c, 0x01);
mipi_dsi_dcs_write_seq(dsi, 0x6d, 0x00);
mipi_dsi_dcs_write_seq(dsi, 0x6f, 0x01);
mipi_dsi_dcs_write_seq(dsi, 0x70,
0x12, 0x00, 0x00, 0xab, 0x30, 0x80, 0x09, 0x60, 0x04,
0x38, 0x00, 0x28, 0x02, 0x1c, 0x02, 0x1c, 0x02, 0x00,
0x02, 0x0e, 0x00, 0x20, 0x03, 0xdd, 0x00, 0x07, 0x00,
0x0c, 0x02, 0x77, 0x02, 0x8b, 0x18, 0x00, 0x10, 0xf0,
0x07, 0x10, 0x20, 0x00, 0x06, 0x0f, 0x0f, 0x33, 0x0e,
0x1c, 0x2a, 0x38, 0x46, 0x54, 0x62, 0x69, 0x70, 0x77,
0x79, 0x7b, 0x7d, 0x7e, 0x02, 0x02, 0x22, 0x00, 0x2a,
0x40, 0x2a, 0xbe, 0x3a, 0xfc, 0x3a, 0xfa, 0x3a, 0xf8,
0x3b, 0x38, 0x3b, 0x78, 0x3b, 0xb6, 0x4b, 0xb6, 0x4b,
0xf4, 0x4b, 0xf4, 0x6c, 0x34, 0x84, 0x74, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00);
mipi_dsi_dcs_write_seq(dsi, 0xf0, 0xaa, 0x10);
mipi_dsi_dcs_write_seq(dsi, 0xb1,
0x01, 0x38, 0x00, 0x14, 0x00, 0x1c, 0x00, 0x01, 0x66,
0x00, 0x14, 0x00, 0x14, 0x00, 0x01, 0x66, 0x00, 0x14,
mipi_dsi_dcs_write_seq_multi(&dsi_ctx,
MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x20);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx,
MIPI_DCS_SET_DISPLAY_BRIGHTNESS, 0x00,
0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x59, 0x09);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6c, 0x01);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6d, 0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x01);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x70, 0x12, 0x00, 0x00, 0xab,
0x30, 0x80, 0x09, 0x60, 0x04, 0x38, 0x00,
0x28, 0x02, 0x1c, 0x02, 0x1c, 0x02, 0x00,
0x02, 0x0e, 0x00, 0x20, 0x03, 0xdd, 0x00,
0x07, 0x00, 0x0c, 0x02, 0x77, 0x02, 0x8b,
0x18, 0x00, 0x10, 0xf0, 0x07, 0x10, 0x20,
0x00, 0x06, 0x0f, 0x0f, 0x33, 0x0e, 0x1c,
0x2a, 0x38, 0x46, 0x54, 0x62, 0x69, 0x70,
0x77, 0x79, 0x7b, 0x7d, 0x7e, 0x02, 0x02,
0x22, 0x00, 0x2a, 0x40, 0x2a, 0xbe, 0x3a,
0xfc, 0x3a, 0xfa, 0x3a, 0xf8, 0x3b, 0x38,
0x3b, 0x78, 0x3b, 0xb6, 0x4b, 0xb6, 0x4b,
0xf4, 0x4b, 0xf4, 0x6c, 0x34, 0x84, 0x74,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf0, 0xaa, 0x10);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb1, 0x01, 0x38, 0x00, 0x14,
0x00, 0x1c, 0x00, 0x01, 0x66, 0x00, 0x14,
0x00, 0x14, 0x00, 0x01, 0x66, 0x00, 0x14,
0x05, 0xcc, 0x00);
mipi_dsi_dcs_write_seq(dsi, 0xf0, 0xaa, 0x13);
mipi_dsi_dcs_write_seq(dsi, 0xce,
0x09, 0x11, 0x09, 0x11, 0x08, 0xc1, 0x07, 0xfa, 0x05,
0xa4, 0x00, 0x3c, 0x00, 0x34, 0x00, 0x24, 0x00, 0x0c,
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf0, 0xaa, 0x13);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xce, 0x09, 0x11, 0x09, 0x11,
0x08, 0xc1, 0x07, 0xfa, 0x05, 0xa4, 0x00,
0x3c, 0x00, 0x34, 0x00, 0x24, 0x00, 0x0c,
0x00, 0x0c, 0x04, 0x00, 0x35);
mipi_dsi_dcs_write_seq(dsi, 0xf0, 0xaa, 0x14);
mipi_dsi_dcs_write_seq(dsi, 0xb2, 0x03, 0x33);
mipi_dsi_dcs_write_seq(dsi, 0xb4,
0x00, 0x33, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00,
0x3e, 0x00, 0x00);
mipi_dsi_dcs_write_seq(dsi, 0xb5,
0x00, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x06, 0x01);
mipi_dsi_dcs_write_seq(dsi, 0xb9, 0x00, 0x00, 0x08, 0x09, 0x09, 0x09);
mipi_dsi_dcs_write_seq(dsi, 0xbc,
0x10, 0x00, 0x00, 0x06, 0x11, 0x09, 0x3b, 0x09, 0x47,
0x09, 0x47, 0x00);
mipi_dsi_dcs_write_seq(dsi, 0xbe,
0x10, 0x10, 0x00, 0x08, 0x22, 0x09, 0x19, 0x09, 0x25,
0x09, 0x25, 0x00);
mipi_dsi_dcs_write_seq(dsi, 0xff, 0x5a, 0x80);
mipi_dsi_dcs_write_seq(dsi, 0x65, 0x14);
mipi_dsi_dcs_write_seq(dsi, 0xfa, 0x08, 0x08, 0x08);
mipi_dsi_dcs_write_seq(dsi, 0xff, 0x5a, 0x81);
mipi_dsi_dcs_write_seq(dsi, 0x65, 0x05);
mipi_dsi_dcs_write_seq(dsi, 0xf3, 0x0f);
mipi_dsi_dcs_write_seq(dsi, 0xf0, 0xaa, 0x00);
mipi_dsi_dcs_write_seq(dsi, 0xff, 0x5a, 0x82);
mipi_dsi_dcs_write_seq(dsi, 0xf9, 0x00);
mipi_dsi_dcs_write_seq(dsi, 0xff, 0x51, 0x83);
mipi_dsi_dcs_write_seq(dsi, 0x65, 0x04);
mipi_dsi_dcs_write_seq(dsi, 0xf8, 0x00);
mipi_dsi_dcs_write_seq(dsi, 0xff, 0x5a, 0x00);
mipi_dsi_dcs_write_seq(dsi, 0x65, 0x01);
mipi_dsi_dcs_write_seq(dsi, 0xf4, 0x9a);
mipi_dsi_dcs_write_seq(dsi, 0xff, 0x5a, 0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf0, 0xaa, 0x14);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb2, 0x03, 0x33);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb4, 0x00, 0x33, 0x00, 0x00,
0x00, 0x3e, 0x00, 0x00, 0x00, 0x3e, 0x00,
0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb5, 0x00, 0x09, 0x09, 0x09,
0x09, 0x09, 0x09, 0x06, 0x01);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb9, 0x00, 0x00, 0x08, 0x09,
0x09, 0x09);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xbc, 0x10, 0x00, 0x00, 0x06,
0x11, 0x09, 0x3b, 0x09, 0x47, 0x09, 0x47,
0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xbe, 0x10, 0x10, 0x00, 0x08,
0x22, 0x09, 0x19, 0x09, 0x25, 0x09, 0x25,
0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x5a, 0x80);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x65, 0x14);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfa, 0x08, 0x08, 0x08);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x5a, 0x81);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x65, 0x05);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf3, 0x0f);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf0, 0xaa, 0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x5a, 0x82);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf9, 0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x51, 0x83);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x65, 0x04);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf8, 0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x5a, 0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x65, 0x01);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf4, 0x9a);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x5a, 0x00);
ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
if (ret < 0) {
dev_err(dev, "Failed to exit sleep mode: %d\n", ret);
return ret;
}
msleep(120);
mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
mipi_dsi_msleep(&dsi_ctx, 120);
ret = mipi_dsi_dcs_set_display_on(dsi);
if (ret < 0) {
dev_err(dev, "Failed to set display on: %d\n", ret);
return ret;
}
msleep(20);
mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
mipi_dsi_msleep(&dsi_ctx, 20);
return 0;
return dsi_ctx.accum_err;
}
static int visionox_vtdr6130_off(struct visionox_vtdr6130 *ctx)
static void visionox_vtdr6130_off(struct visionox_vtdr6130 *ctx)
{
struct mipi_dsi_device *dsi = ctx->dsi;
struct device *dev = &dsi->dev;
int ret;
struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
ret = mipi_dsi_dcs_set_display_off(dsi);
if (ret < 0) {
dev_err(dev, "Failed to set display off: %d\n", ret);
return ret;
}
msleep(20);
mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
mipi_dsi_msleep(&dsi_ctx, 20);
ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
if (ret < 0) {
dev_err(dev, "Failed to enter sleep mode: %d\n", ret);
return ret;
}
msleep(120);
return 0;
mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
mipi_dsi_msleep(&dsi_ctx, 120);
}
static int visionox_vtdr6130_prepare(struct drm_panel *panel)
{
struct visionox_vtdr6130 *ctx = to_visionox_vtdr6130(panel);
struct device *dev = &ctx->dsi->dev;
int ret;
ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies),
ret = regulator_bulk_enable(ARRAY_SIZE(visionox_vtdr6130_supplies),
ctx->supplies);
if (ret < 0)
return ret;
@ -165,9 +154,9 @@ static int visionox_vtdr6130_prepare(struct drm_panel *panel)
ret = visionox_vtdr6130_on(ctx);
if (ret < 0) {
dev_err(dev, "Failed to initialize panel: %d\n", ret);
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
regulator_bulk_disable(ARRAY_SIZE(visionox_vtdr6130_supplies),
ctx->supplies);
return ret;
}
@ -177,16 +166,13 @@ static int visionox_vtdr6130_prepare(struct drm_panel *panel)
static int visionox_vtdr6130_unprepare(struct drm_panel *panel)
{
struct visionox_vtdr6130 *ctx = to_visionox_vtdr6130(panel);
struct device *dev = &ctx->dsi->dev;
int ret;
ret = visionox_vtdr6130_off(ctx);
if (ret < 0)
dev_err(dev, "Failed to un-initialize panel: %d\n", ret);
visionox_vtdr6130_off(ctx);
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
regulator_bulk_disable(ARRAY_SIZE(visionox_vtdr6130_supplies),
ctx->supplies);
return 0;
}
@ -266,12 +252,10 @@ static int visionox_vtdr6130_probe(struct mipi_dsi_device *dsi)
if (!ctx)
return -ENOMEM;
ctx->supplies[0].supply = "vddio";
ctx->supplies[1].supply = "vci";
ctx->supplies[2].supply = "vdd";
ret = devm_regulator_bulk_get(&dsi->dev, ARRAY_SIZE(ctx->supplies),
ctx->supplies);
ret = devm_regulator_bulk_get_const(&dsi->dev,
ARRAY_SIZE(visionox_vtdr6130_supplies),
visionox_vtdr6130_supplies,
&ctx->supplies);
if (ret < 0)
return ret;

View File

@ -60,14 +60,6 @@ config DRM_RCAR_MIPI_DSI
select DRM_MIPI_DSI
select RESET_CONTROLLER
config DRM_RZG2L_MIPI_DSI
tristate "RZ/G2L MIPI DSI Encoder Support"
depends on DRM && DRM_BRIDGE && OF
depends on ARCH_RENESAS || COMPILE_TEST
select DRM_MIPI_DSI
help
Enable support for the RZ/G2L Display Unit embedded MIPI DSI encoders.
config DRM_RCAR_VSP
bool "R-Car DU VSP Compositor Support" if ARM
default y if ARM64

View File

@ -14,5 +14,3 @@ obj-$(CONFIG_DRM_RCAR_DU) += rcar-du-drm.o
obj-$(CONFIG_DRM_RCAR_DW_HDMI) += rcar_dw_hdmi.o
obj-$(CONFIG_DRM_RCAR_LVDS) += rcar_lvds.o
obj-$(CONFIG_DRM_RCAR_MIPI_DSI) += rcar_mipi_dsi.o
obj-$(CONFIG_DRM_RZG2L_MIPI_DSI) += rzg2l_mipi_dsi.o

View File

@ -10,3 +10,11 @@ config DRM_RZG2L_DU
help
Choose this option if you have an RZ/G2L alike chipset.
If M is selected the module will be called rzg2l-du-drm.
config DRM_RZG2L_MIPI_DSI
tristate "RZ/G2L MIPI DSI Encoder Support"
depends on DRM && DRM_BRIDGE && OF
depends on ARCH_RENESAS || COMPILE_TEST
select DRM_MIPI_DSI
help
Enable support for the RZ/G2L Display Unit embedded MIPI DSI encoders.

View File

@ -6,3 +6,5 @@ rzg2l-du-drm-y := rzg2l_du_crtc.o \
rzg2l-du-drm-$(CONFIG_VIDEO_RENESAS_VSP1) += rzg2l_du_vsp.o
obj-$(CONFIG_DRM_RZG2L_DU) += rzg2l-du-drm.o
obj-$(CONFIG_DRM_RZG2L_MIPI_DSI) += rzg2l_mipi_dsi.o

View File

@ -28,6 +28,7 @@
#include "rzg2l_du_vsp.h"
#define DU_MCR0 0x00
#define DU_MCR0_DPI_OE BIT(0)
#define DU_MCR0_DI_EN BIT(8)
#define DU_DITR0 0x10
@ -216,9 +217,14 @@ static void rzg2l_du_crtc_put(struct rzg2l_du_crtc *rcrtc)
static void rzg2l_du_start_stop(struct rzg2l_du_crtc *rcrtc, bool start)
{
struct rzg2l_du_crtc_state *rstate = to_rzg2l_crtc_state(rcrtc->crtc.state);
struct rzg2l_du_device *rcdu = rcrtc->dev;
u32 val = DU_MCR0_DI_EN;
writel(start ? DU_MCR0_DI_EN : 0, rcdu->mmio + DU_MCR0);
if (rstate->outputs & BIT(RZG2L_DU_OUTPUT_DPAD0))
val |= DU_MCR0_DPI_OE;
writel(start ? val : 0, rcdu->mmio + DU_MCR0);
}
static void rzg2l_du_crtc_start(struct rzg2l_du_crtc *rcrtc)

View File

@ -25,6 +25,16 @@
* Device Information
*/
static const struct rzg2l_du_device_info rzg2l_du_r9a07g043u_info = {
.channels_mask = BIT(0),
.routes = {
[RZG2L_DU_OUTPUT_DPAD0] = {
.possible_outputs = BIT(0),
.port = 0,
},
},
};
static const struct rzg2l_du_device_info rzg2l_du_r9a07g044_info = {
.channels_mask = BIT(0),
.routes = {
@ -40,6 +50,7 @@ static const struct rzg2l_du_device_info rzg2l_du_r9a07g044_info = {
};
static const struct of_device_id rzg2l_du_of_table[] = {
{ .compatible = "renesas,r9a07g043u-du", .data = &rzg2l_du_r9a07g043u_info },
{ .compatible = "renesas,r9a07g044-du", .data = &rzg2l_du_r9a07g044_info },
{ /* sentinel */ }
};

View File

@ -183,7 +183,8 @@ static int rzg2l_du_encoders_init(struct rzg2l_du_device *rcdu)
/* Find the output route corresponding to the port number. */
for (i = 0; i < RZG2L_DU_OUTPUT_MAX; ++i) {
if (rcdu->info->routes[i].port == ep.port) {
if (rcdu->info->routes[i].possible_outputs &&
rcdu->info->routes[i].port == ep.port) {
output = i;
break;
}

View File

@ -974,28 +974,32 @@ static const struct drm_bridge_funcs sti_hdmi_bridge_funcs = {
static int sti_hdmi_connector_get_modes(struct drm_connector *connector)
{
const struct drm_display_info *info = &connector->display_info;
struct sti_hdmi_connector *hdmi_connector
= to_sti_hdmi_connector(connector);
struct sti_hdmi *hdmi = hdmi_connector->hdmi;
struct edid *edid;
const struct drm_edid *drm_edid;
int count;
DRM_DEBUG_DRIVER("\n");
edid = drm_get_edid(connector, hdmi->ddc_adapt);
if (!edid)
drm_edid = drm_edid_read(connector);
drm_edid_connector_update(connector, drm_edid);
cec_notifier_set_phys_addr(hdmi->notifier,
connector->display_info.source_physical_address);
if (!drm_edid)
goto fail;
cec_notifier_set_phys_addr_from_edid(hdmi->notifier, edid);
count = drm_add_edid_modes(connector, edid);
drm_connector_update_edid_property(connector, edid);
count = drm_edid_connector_add_modes(connector);
DRM_DEBUG_KMS("%s : %dx%d cm\n",
(connector->display_info.is_hdmi ? "hdmi monitor" : "dvi monitor"),
edid->width_cm, edid->height_cm);
info->is_hdmi ? "hdmi monitor" : "dvi monitor",
info->width_mm / 10, info->height_mm / 10);
kfree(edid);
drm_edid_free(drm_edid);
return count;
fail:

View File

@ -133,7 +133,7 @@ struct tegra_output {
struct drm_bridge *bridge;
struct drm_panel *panel;
struct i2c_adapter *ddc;
const struct edid *edid;
const struct drm_edid *drm_edid;
struct cec_notifier *cec;
unsigned int hpd_irq;
struct gpio_desc *hpd_gpio;

View File

@ -46,6 +46,7 @@ struct gr3d {
unsigned int nclocks;
struct reset_control_bulk_data resets[RST_GR3D_MAX];
unsigned int nresets;
struct dev_pm_domain_list *pd_list;
DECLARE_BITMAP(addr_regs, GR3D_NUM_REGS);
};
@ -369,18 +370,12 @@ static int gr3d_power_up_legacy_domain(struct device *dev, const char *name,
return 0;
}
static void gr3d_del_link(void *link)
{
device_link_del(link);
}
static int gr3d_init_power(struct device *dev, struct gr3d *gr3d)
{
static const char * const opp_genpd_names[] = { "3d0", "3d1", NULL };
const u32 link_flags = DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME;
struct device **opp_virt_devs, *pd_dev;
struct device_link *link;
unsigned int i;
struct dev_pm_domain_attach_data pd_data = {
.pd_names = (const char *[]) { "3d0", "3d1" },
.num_pd_names = 2,
};
int err;
err = of_count_phandle_with_args(dev->of_node, "power-domains",
@ -414,29 +409,10 @@ static int gr3d_init_power(struct device *dev, struct gr3d *gr3d)
if (dev->pm_domain)
return 0;
err = devm_pm_opp_attach_genpd(dev, opp_genpd_names, &opp_virt_devs);
if (err)
err = dev_pm_domain_attach_list(dev, &pd_data, &gr3d->pd_list);
if (err < 0)
return err;
for (i = 0; opp_genpd_names[i]; i++) {
pd_dev = opp_virt_devs[i];
if (!pd_dev) {
dev_err(dev, "failed to get %s power domain\n",
opp_genpd_names[i]);
return -EINVAL;
}
link = device_link_add(dev, pd_dev, link_flags);
if (!link) {
dev_err(dev, "failed to link to %s\n", dev_name(pd_dev));
return -EINVAL;
}
err = devm_add_action_or_reset(dev, gr3d_del_link, link);
if (err)
return err;
}
return 0;
}
@ -527,13 +503,13 @@ static int gr3d_probe(struct platform_device *pdev)
err = devm_tegra_core_dev_init_opp_table_common(&pdev->dev);
if (err)
return err;
goto err;
err = host1x_client_register(&gr3d->client.base);
if (err < 0) {
dev_err(&pdev->dev, "failed to register host1x client: %d\n",
err);
return err;
goto err;
}
/* initialize address register map */
@ -541,6 +517,9 @@ static int gr3d_probe(struct platform_device *pdev)
set_bit(gr3d_addr_regs[i], gr3d->addr_regs);
return 0;
err:
dev_pm_domain_detach_list(gr3d->pd_list);
return err;
}
static void gr3d_remove(struct platform_device *pdev)
@ -549,6 +528,7 @@ static void gr3d_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
host1x_client_unregister(&gr3d->client.base);
dev_pm_domain_detach_list(gr3d->pd_list);
}
static int __maybe_unused gr3d_runtime_suspend(struct device *dev)

View File

@ -521,12 +521,11 @@ static void tegra_shared_plane_atomic_disable(struct drm_plane *plane,
static inline u32 compute_phase_incr(fixed20_12 in, unsigned int out)
{
u64 tmp, tmp1, tmp2;
u64 tmp, tmp1;
tmp = (u64)dfixed_trunc(in);
tmp2 = (u64)out;
tmp1 = (tmp << NFB) + (tmp2 >> 1);
do_div(tmp1, tmp2);
tmp1 = (tmp << NFB) + ((u64)out >> 1);
do_div(tmp1, out);
return lower_32_bits(tmp1);
}

View File

@ -21,7 +21,7 @@
int tegra_output_connector_get_modes(struct drm_connector *connector)
{
struct tegra_output *output = connector_to_output(connector);
struct edid *edid = NULL;
const struct drm_edid *drm_edid;
int err = 0;
/*
@ -34,18 +34,17 @@ int tegra_output_connector_get_modes(struct drm_connector *connector)
return err;
}
if (output->edid)
edid = kmemdup(output->edid, sizeof(*edid), GFP_KERNEL);
if (output->drm_edid)
drm_edid = drm_edid_dup(output->drm_edid);
else if (output->ddc)
edid = drm_get_edid(connector, output->ddc);
drm_edid = drm_edid_read_ddc(connector, output->ddc);
cec_notifier_set_phys_addr_from_edid(output->cec, edid);
drm_connector_update_edid_property(connector, edid);
drm_edid_connector_update(connector, drm_edid);
cec_notifier_set_phys_addr(output->cec,
connector->display_info.source_physical_address);
if (edid) {
err = drm_add_edid_modes(connector, edid);
kfree(edid);
}
err = drm_edid_connector_add_modes(connector);
drm_edid_free(drm_edid);
return err;
}
@ -98,6 +97,7 @@ static irqreturn_t hpd_irq(int irq, void *data)
int tegra_output_probe(struct tegra_output *output)
{
struct device_node *ddc, *panel;
const void *edid;
unsigned long flags;
int err, size;
@ -124,8 +124,6 @@ int tegra_output_probe(struct tegra_output *output)
return PTR_ERR(output->panel);
}
output->edid = of_get_property(output->of_node, "nvidia,edid", &size);
ddc = of_parse_phandle(output->of_node, "nvidia,ddc-i2c-bus", 0);
if (ddc) {
output->ddc = of_get_i2c_adapter_by_node(ddc);
@ -137,6 +135,9 @@ int tegra_output_probe(struct tegra_output *output)
}
}
edid = of_get_property(output->of_node, "nvidia,edid", &size);
output->drm_edid = drm_edid_alloc(edid, size);
output->hpd_gpio = devm_fwnode_gpiod_get(output->dev,
of_fwnode_handle(output->of_node),
"nvidia,hpd",
@ -187,6 +188,8 @@ put_i2c:
if (output->ddc)
i2c_put_adapter(output->ddc);
drm_edid_free(output->drm_edid);
return err;
}
@ -197,6 +200,8 @@ void tegra_output_remove(struct tegra_output *output)
if (output->ddc)
i2c_put_adapter(output->ddc);
drm_edid_free(output->drm_edid);
}
int tegra_output_init(struct drm_device *drm, struct tegra_output *output)

View File

@ -464,7 +464,7 @@ static int gm12u320_set_ecomode(struct gm12u320_device *gm12u320)
* Note this assumes this driver is only ever used with the Acer C120, if we
* add support for other devices the vendor and model should be parameterized.
*/
static struct edid gm12u320_edid = {
static const struct edid gm12u320_edid = {
.header = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 },
.mfg_id = { 0x04, 0x72 }, /* "ACR" */
.prod_code = { 0x20, 0xc1 }, /* C120h */
@ -523,8 +523,15 @@ static struct edid gm12u320_edid = {
static int gm12u320_conn_get_modes(struct drm_connector *connector)
{
drm_connector_update_edid_property(connector, &gm12u320_edid);
return drm_add_edid_modes(connector, &gm12u320_edid);
const struct drm_edid *drm_edid;
int count;
drm_edid = drm_edid_alloc(&gm12u320_edid, sizeof(gm12u320_edid));
drm_edid_connector_update(connector, drm_edid);
count = drm_edid_connector_add_modes(connector);
drm_edid_free(drm_edid);
return count;
}
static const struct drm_connector_helper_funcs gm12u320_conn_helper_funcs = {

View File

@ -404,9 +404,10 @@ static struct iommu_domain *host1x_iommu_attach(struct host1x *host)
if (err < 0)
goto put_group;
host->domain = iommu_domain_alloc(&platform_bus_type);
if (!host->domain) {
err = -ENOMEM;
host->domain = iommu_paging_domain_alloc(host->dev);
if (IS_ERR(host->domain)) {
err = PTR_ERR(host->domain);
host->domain = NULL;
goto put_cache;
}

View File

@ -9,6 +9,7 @@
#include <linux/device.h>
#include <linux/iommu.h>
#include <linux/iova.h>
#include <linux/irqreturn.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
@ -81,6 +82,7 @@ struct host1x_intr_ops {
void (*disable_syncpt_intr)(struct host1x *host, unsigned int id);
void (*disable_all_syncpt_intrs)(struct host1x *host);
int (*free_syncpt_irq)(struct host1x *host);
irqreturn_t (*isr)(int irq, void *dev_id);
};
struct host1x_sid_entry {

View File

@ -6,18 +6,11 @@
* Copyright (c) 2010-2013, NVIDIA Corporation.
*/
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/io.h>
#include "../intr.h"
#include "../dev.h"
struct host1x_intr_irq_data {
struct host1x *host;
u32 offset;
};
static irqreturn_t syncpt_thresh_isr(int irq, void *dev_id)
{
struct host1x_intr_irq_data *irq_data = dev_id;
@ -54,7 +47,8 @@ static void host1x_intr_disable_all_syncpt_intrs(struct host1x *host)
}
}
static void intr_hw_init(struct host1x *host, u32 cpm)
static int
host1x_intr_init_host_sync(struct host1x *host, u32 cpm)
{
#if HOST1X_HW < 6
/* disable the ip_busy_timeout. this prevents write drops */
@ -85,32 +79,6 @@ static void intr_hw_init(struct host1x *host, u32 cpm)
host1x_sync_writel(host, irq_index, HOST1X_SYNC_SYNCPT_INTR_DEST(id));
}
#endif
}
static int
host1x_intr_init_host_sync(struct host1x *host, u32 cpm)
{
int err, i;
struct host1x_intr_irq_data *irq_data;
irq_data = devm_kcalloc(host->dev, host->num_syncpt_irqs, sizeof(irq_data[0]), GFP_KERNEL);
if (!irq_data)
return -ENOMEM;
host1x_hw_intr_disable_all_syncpt_intrs(host);
for (i = 0; i < host->num_syncpt_irqs; i++) {
irq_data[i].host = host;
irq_data[i].offset = i;
err = devm_request_irq(host->dev, host->syncpt_irqs[i],
syncpt_thresh_isr, IRQF_SHARED,
"host1x_syncpt", &irq_data[i]);
if (err < 0)
return err;
}
intr_hw_init(host, cpm);
return 0;
}
@ -144,4 +112,5 @@ static const struct host1x_intr_ops host1x_intr_ops = {
.enable_syncpt_intr = host1x_intr_enable_syncpt_intr,
.disable_syncpt_intr = host1x_intr_disable_syncpt_intr,
.disable_all_syncpt_intrs = host1x_intr_disable_all_syncpt_intrs,
.isr = syncpt_thresh_isr,
};

View File

@ -6,7 +6,7 @@
*/
#include <linux/clk.h>
#include <linux/interrupt.h>
#include "dev.h"
#include "fence.h"
#include "intr.h"
@ -100,7 +100,9 @@ void host1x_intr_handle_interrupt(struct host1x *host, unsigned int id)
int host1x_intr_init(struct host1x *host)
{
struct host1x_intr_irq_data *irq_data;
unsigned int id;
int i, err;
mutex_init(&host->intr_mutex);
@ -111,6 +113,23 @@ int host1x_intr_init(struct host1x *host)
INIT_LIST_HEAD(&syncpt->fences.list);
}
irq_data = devm_kcalloc(host->dev, host->num_syncpt_irqs, sizeof(irq_data[0]), GFP_KERNEL);
if (!irq_data)
return -ENOMEM;
host1x_hw_intr_disable_all_syncpt_intrs(host);
for (i = 0; i < host->num_syncpt_irqs; i++) {
irq_data[i].host = host;
irq_data[i].offset = i;
err = devm_request_irq(host->dev, host->syncpt_irqs[i],
host->intr_op->isr, IRQF_SHARED,
"host1x_syncpt", &irq_data[i]);
if (err < 0)
return err;
}
return 0;
}

View File

@ -11,6 +11,11 @@
struct host1x;
struct host1x_syncpt_fence;
struct host1x_intr_irq_data {
struct host1x *host;
u32 offset;
};
/* Initialize host1x sync point interrupt */
int host1x_intr_init(struct host1x *host);

View File

@ -244,18 +244,18 @@ struct drm_dp_mst_branch {
bool link_address_sent;
/* global unique identifier to identify branch devices */
u8 guid[16];
guid_t guid;
};
struct drm_dp_nak_reply {
u8 guid[16];
guid_t guid;
u8 reason;
u8 nak_data;
};
struct drm_dp_link_address_ack_reply {
u8 guid[16];
guid_t guid;
u8 nports;
struct drm_dp_link_addr_reply_port {
bool input_port;
@ -265,7 +265,7 @@ struct drm_dp_link_address_ack_reply {
bool ddps;
bool legacy_device_plug_status;
u8 dpcd_revision;
u8 peer_guid[16];
guid_t peer_guid;
u8 num_sdp_streams;
u8 num_sdp_stream_sinks;
} ports[16];
@ -348,7 +348,7 @@ struct drm_dp_allocate_payload_ack_reply {
};
struct drm_dp_connection_status_notify {
u8 guid[16];
guid_t guid;
u8 port_number;
bool legacy_device_plug_status;
bool displayport_device_plug_status;
@ -425,7 +425,7 @@ struct drm_dp_query_payload {
struct drm_dp_resource_status_notify {
u8 port_number;
u8 guid[16];
guid_t guid;
u16 available_pbn;
};

View File

@ -51,11 +51,10 @@
#if IS_ENABLED(CONFIG_DRM_ACCEL)
extern struct xarray accel_minors_xa;
void accel_core_exit(void);
int accel_core_init(void);
void accel_minor_remove(int index);
int accel_minor_alloc(void);
void accel_minor_replace(struct drm_minor *minor, int index);
void accel_set_device_instance_params(struct device *kdev, int index);
int accel_open(struct inode *inode, struct file *filp);
void accel_debugfs_init(struct drm_device *dev);
@ -73,19 +72,6 @@ static inline int __init accel_core_init(void)
return 0;
}
static inline void accel_minor_remove(int index)
{
}
static inline int accel_minor_alloc(void)
{
return -EOPNOTSUPP;
}
static inline void accel_minor_replace(struct drm_minor *minor, int index)
{
}
static inline void accel_set_device_instance_params(struct device *kdev, int index)
{
}

View File

@ -460,7 +460,7 @@ struct drm_atomic_state {
*
* Used for signaling unbound planes/connectors.
* When a connector or plane is not bound to any CRTC, it's still important
* to preserve linearity to prevent the atomic states from being freed to early.
* to preserve linearity to prevent the atomic states from being freed too early.
*
* This commit (if set) is not bound to any CRTC, but will be completed when
* drm_atomic_helper_commit_hw_done() is called.

View File

@ -45,6 +45,8 @@ struct drm_printer;
struct device;
struct file;
extern struct xarray drm_minors_xa;
/*
* FIXME: Not sure we want to have drm_minor here in the end, but to avoid
* header include loops we need it here for now.
@ -434,6 +436,9 @@ static inline bool drm_is_accel_client(const struct drm_file *file_priv)
void drm_file_update_pid(struct drm_file *);
struct drm_minor *drm_minor_acquire(struct xarray *minors_xa, unsigned int minor_id);
void drm_minor_release(struct drm_minor *minor);
int drm_open(struct inode *inode, struct file *filp);
int drm_open_helper(struct file *filp, struct drm_minor *minor);
ssize_t drm_read(struct file *filp, char __user *buffer,

View File

@ -238,6 +238,21 @@ static inline void drm_rect_fp_to_int(struct drm_rect *dst,
drm_rect_height(src) >> 16);
}
/**
* drm_rect_overlap - Check if two rectangles overlap
* @a: first rectangle
* @b: second rectangle
*
* RETURNS:
* %true if the rectangles overlap, %false otherwise.
*/
static inline bool drm_rect_overlap(const struct drm_rect *a,
const struct drm_rect *b)
{
return (a->x2 > b->x1 && b->x2 > a->x1 &&
a->y2 > b->y1 && b->y2 > a->y1);
}
bool drm_rect_intersect(struct drm_rect *r, const struct drm_rect *clip);
bool drm_rect_clip_scaled(struct drm_rect *src, struct drm_rect *dst,
const struct drm_rect *clip);

View File

@ -222,7 +222,7 @@ struct ttm_lru_walk {
struct ttm_operation_ctx *ctx;
/** @ticket: The struct ww_acquire_ctx if any. */
struct ww_acquire_ctx *ticket;
/** @tryock_only: Only use trylock for locking. */
/** @trylock_only: Only use trylock for locking. */
bool trylock_only;
};