Merge tag 'drm-misc-next-2023-01-12' of git://anongit.freedesktop.org/drm/drm-misc into drm-next

drm-misc-next for v6.3:

UAPI Changes:

 * fourcc: Document Open Source user waiver

Cross-subsystem Changes:

 * firmware: fix color-format selection for system framebuffers

Core Changes:

 * format-helper: Add conversion from XRGB8888 to various sysfb formats;
   Make XRGB8888 the only driver-emulated legacy format

 * fb-helper: Avoid blank consoles from selecting an incorrect color format

 * probe-helper: Enable/disable HPD on connectors plus driver updates

 * Use drm_dbg_ helpers in several places

 * docs: Document defaults for CRTC backgrounds; Document use of drm_minor

Driver Changes:

 * arm/hdlcd: Use new debugfs helpers

 * gud: Use new debugfs helpers

 * panel: Support Visionox VTDR6130 AMOLED DSI; Support Himax HX8394; Convert
   many drivers to common generic DSI write-sequence helper

 * v3d: Do not opencode drm_gem_object_lookup()

 * vc4: Various HVS an CRTC fixes

 * vkms: Fix SEGFAULT from incorrect GEM-buffer mapping

 * Convert various drivers to i2c probe_new()

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

From: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://patchwork.freedesktop.org/patch/msgid/Y8ADeSzZDj+tpibF@linux-uq9g
This commit is contained in:
Dave Airlie
2023-01-16 15:33:22 +10:00
81 changed files with 3115 additions and 1346 deletions

View File

@@ -0,0 +1,76 @@
# SPDX-License-Identifier: (GPL-2.0-only or BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/panel/himax,hx8394.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Himax HX8394 MIPI-DSI LCD panel controller
maintainers:
- Ondrej Jirman <megi@xff.cz>
- Javier Martinez Canillas <javierm@redhat.com>
description:
Device tree bindings for panels based on the Himax HX8394 controller,
such as the HannStar HSD060BHW4 720x1440 TFT LCD panel connected with
a MIPI-DSI video interface.
allOf:
- $ref: panel-common.yaml#
properties:
compatible:
items:
- enum:
- hannstar,hsd060bhw4
- const: himax,hx8394
reg: true
reset-gpios: true
backlight: true
port: true
vcc-supply:
description: Panel power supply
iovcc-supply:
description: I/O voltage supply
required:
- compatible
- reg
- reset-gpios
- backlight
- port
- vcc-supply
- iovcc-supply
additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
dsi {
#address-cells = <1>;
#size-cells = <0>;
panel@0 {
compatible = "hannstar,hsd060bhw4", "himax,hx8394";
reg = <0>;
vcc-supply = <&reg_2v8_p>;
iovcc-supply = <&reg_1v8_p>;
reset-gpios = <&gpio3 13 GPIO_ACTIVE_LOW>;
backlight = <&backlight>;
port {
mipi_in_panel: endpoint {
remote-endpoint = <&mipi_out_panel>;
};
};
};
};
...

View File

@@ -0,0 +1,53 @@
# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/panel/visionox,vtdr6130.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Visionox VTDR6130 AMOLED DSI Panel
maintainers:
- Neil Armstrong <neil.armstrong@linaro.org>
allOf:
- $ref: panel-common.yaml#
properties:
compatible:
const: visionox,vtdr6130
vddio-supply: true
vci-supply: true
vdd-supply: true
port: true
reset-gpios: true
additionalProperties: false
required:
- compatible
- vddio-supply
- vci-supply
- vdd-supply
- reset-gpios
- port
examples:
- |
#include <dt-bindings/gpio/gpio.h>
panel {
compatible = "visionox,vtdr6130";
vddio-supply = <&vreg_l12b_1p8>;
vci-supply = <&vreg_l13b_3p0>;
vdd-supply = <&vreg_l11b_1p2>;
reset-gpios = <&tlmm 133 GPIO_ACTIVE_LOW>;
port {
panel0_in: endpoint {
remote-endpoint = <&dsi0_out>;
};
};
};
...

View File

@@ -222,6 +222,7 @@ Code Seq# Include File Comments
'a' 00-0F drivers/crypto/qat/qat_common/adf_cfg_common.h conflict! qat driver 'a' 00-0F drivers/crypto/qat/qat_common/adf_cfg_common.h conflict! qat driver
'b' 00-FF conflict! bit3 vme host bridge 'b' 00-FF conflict! bit3 vme host bridge
<mailto:natalia@nikhefk.nikhef.nl> <mailto:natalia@nikhefk.nikhef.nl>
'b' 00-0F linux/dma-buf.h conflict!
'c' all linux/cm4000_cs.h conflict! 'c' all linux/cm4000_cs.h conflict!
'c' 00-7F linux/comstats.h conflict! 'c' 00-7F linux/comstats.h conflict!
'c' 00-7F linux/coda.h conflict! 'c' 00-7F linux/coda.h conflict!

View File

@@ -6550,6 +6550,14 @@ S: Maintained
T: git git://anongit.freedesktop.org/drm/drm-misc T: git git://anongit.freedesktop.org/drm/drm-misc
F: drivers/gpu/drm/tiny/gm12u320.c F: drivers/gpu/drm/tiny/gm12u320.c
DRM DRIVER FOR HIMAX HX8394 MIPI-DSI LCD panels
M: Ondrej Jirman <megi@xff.cz>
M: Javier Martinez Canillas <javierm@redhat.com>
S: Maintained
T: git git://anongit.freedesktop.org/drm/drm-misc
F: Documentation/devicetree/bindings/display/panel/himax,hx8394.yaml
F: drivers/gpu/drm/panel/panel-himax-hx8394.c
DRM DRIVER FOR HX8357D PANELS DRM DRIVER FOR HX8357D PANELS
M: Emma Anholt <emma@anholt.net> M: Emma Anholt <emma@anholt.net>
S: Maintained S: Maintained
@@ -7009,7 +7017,6 @@ M: Xinliang Liu <xinliang.liu@linaro.org>
M: Tian Tao <tiantao6@hisilicon.com> M: Tian Tao <tiantao6@hisilicon.com>
R: John Stultz <jstultz@google.com> R: John Stultz <jstultz@google.com>
R: Xinwei Kong <kong.kongxinwei@hisilicon.com> R: Xinwei Kong <kong.kongxinwei@hisilicon.com>
R: Chen Feng <puck.chen@hisilicon.com>
L: dri-devel@lists.freedesktop.org L: dri-devel@lists.freedesktop.org
S: Maintained S: Maintained
T: git git://anongit.freedesktop.org/drm/drm-misc T: git git://anongit.freedesktop.org/drm/drm-misc

View File

@@ -27,25 +27,56 @@ static const struct simplefb_format formats[] = SIMPLEFB_FORMATS;
__init bool sysfb_parse_mode(const struct screen_info *si, __init bool sysfb_parse_mode(const struct screen_info *si,
struct simplefb_platform_data *mode) struct simplefb_platform_data *mode)
{ {
const struct simplefb_format *f;
__u8 type; __u8 type;
u32 bits_per_pixel;
unsigned int i; unsigned int i;
type = si->orig_video_isVGA; type = si->orig_video_isVGA;
if (type != VIDEO_TYPE_VLFB && type != VIDEO_TYPE_EFI) if (type != VIDEO_TYPE_VLFB && type != VIDEO_TYPE_EFI)
return false; return false;
/*
* The meaning of depth and bpp for direct-color formats is
* inconsistent:
*
* - DRM format info specifies depth as the number of color
* bits; including alpha, but not including filler bits.
* - Linux' EFI platform code computes lfb_depth from the
* individual color channels, including the reserved bits.
* - VBE 1.1 defines lfb_depth for XRGB1555 as 16, but later
* versions use 15.
* - On the kernel command line, 'bpp' of 32 is usually
* XRGB8888 including the filler bits, but 15 is XRGB1555
* not including the filler bit.
*
* It's not easily possible to fix this in struct screen_info,
* as this could break UAPI. The best solution is to compute
* bits_per_pixel here and ignore lfb_depth. In the loop below,
* ignore simplefb formats with alpha bits, as EFI and VESA
* don't specify alpha channels.
*/
if (si->lfb_depth > 8) {
bits_per_pixel = max(max3(si->red_size + si->red_pos,
si->green_size + si->green_pos,
si->blue_size + si->blue_pos),
si->rsvd_size + si->rsvd_pos);
} else {
bits_per_pixel = si->lfb_depth;
}
for (i = 0; i < ARRAY_SIZE(formats); ++i) { for (i = 0; i < ARRAY_SIZE(formats); ++i) {
f = &formats[i]; const struct simplefb_format *f = &formats[i];
if (si->lfb_depth == f->bits_per_pixel &&
if (f->transp.length)
continue; /* transparent formats are unsupported by VESA/EFI */
if (bits_per_pixel == f->bits_per_pixel &&
si->red_size == f->red.length && si->red_size == f->red.length &&
si->red_pos == f->red.offset && si->red_pos == f->red.offset &&
si->green_size == f->green.length && si->green_size == f->green.length &&
si->green_pos == f->green.offset && si->green_pos == f->green.offset &&
si->blue_size == f->blue.length && si->blue_size == f->blue.length &&
si->blue_pos == f->blue.offset && si->blue_pos == f->blue.offset) {
si->rsvd_size == f->transp.length &&
si->rsvd_pos == f->transp.offset) {
mode->format = f->name; mode->format = f->name;
mode->width = si->lfb_width; mode->width = si->lfb_width;
mode->height = si->lfb_height; mode->height = si->lfb_height;

View File

@@ -12,7 +12,6 @@ menuconfig DRM
select HDMI select HDMI
select FB_CMDLINE select FB_CMDLINE
select I2C select I2C
select I2C_ALGOBIT
select DMA_SHARED_BUFFER select DMA_SHARED_BUFFER
select SYNC_FILE select SYNC_FILE
# gallium uses SYS_kcmp for os_same_file_description() to de-duplicate # gallium uses SYS_kcmp for os_same_file_description() to de-duplicate

View File

@@ -13,6 +13,8 @@ config DRM_AMDGPU
select DRM_TTM_HELPER select DRM_TTM_HELPER
select POWER_SUPPLY select POWER_SUPPLY
select HWMON select HWMON
select I2C
select I2C_ALGOBIT
select BACKLIGHT_CLASS_DEVICE select BACKLIGHT_CLASS_DEVICE
select INTERVAL_TREE select INTERVAL_TREE
select DRM_BUDDY select DRM_BUDDY

View File

@@ -195,8 +195,8 @@ static int hdlcd_setup_mode_config(struct drm_device *drm)
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
static int hdlcd_show_underrun_count(struct seq_file *m, void *arg) static int hdlcd_show_underrun_count(struct seq_file *m, void *arg)
{ {
struct drm_info_node *node = (struct drm_info_node *)m->private; struct drm_debugfs_entry *entry = m->private;
struct drm_device *drm = node->minor->dev; struct drm_device *drm = entry->dev;
struct hdlcd_drm_private *hdlcd = drm_to_hdlcd_priv(drm); struct hdlcd_drm_private *hdlcd = drm_to_hdlcd_priv(drm);
seq_printf(m, "underrun : %d\n", atomic_read(&hdlcd->buffer_underrun_count)); seq_printf(m, "underrun : %d\n", atomic_read(&hdlcd->buffer_underrun_count));
@@ -208,8 +208,8 @@ static int hdlcd_show_underrun_count(struct seq_file *m, void *arg)
static int hdlcd_show_pxlclock(struct seq_file *m, void *arg) static int hdlcd_show_pxlclock(struct seq_file *m, void *arg)
{ {
struct drm_info_node *node = (struct drm_info_node *)m->private; struct drm_debugfs_entry *entry = m->private;
struct drm_device *drm = node->minor->dev; struct drm_device *drm = entry->dev;
struct hdlcd_drm_private *hdlcd = drm_to_hdlcd_priv(drm); struct hdlcd_drm_private *hdlcd = drm_to_hdlcd_priv(drm);
unsigned long clkrate = clk_get_rate(hdlcd->clk); unsigned long clkrate = clk_get_rate(hdlcd->clk);
unsigned long mode_clock = hdlcd->crtc.mode.crtc_clock * 1000; unsigned long mode_clock = hdlcd->crtc.mode.crtc_clock * 1000;
@@ -219,17 +219,10 @@ static int hdlcd_show_pxlclock(struct seq_file *m, void *arg)
return 0; return 0;
} }
static struct drm_info_list hdlcd_debugfs_list[] = { static struct drm_debugfs_info hdlcd_debugfs_list[] = {
{ "interrupt_count", hdlcd_show_underrun_count, 0 }, { "interrupt_count", hdlcd_show_underrun_count, 0 },
{ "clocks", hdlcd_show_pxlclock, 0 }, { "clocks", hdlcd_show_pxlclock, 0 },
}; };
static void hdlcd_debugfs_init(struct drm_minor *minor)
{
drm_debugfs_create_files(hdlcd_debugfs_list,
ARRAY_SIZE(hdlcd_debugfs_list),
minor->debugfs_root, minor);
}
#endif #endif
DEFINE_DRM_GEM_DMA_FOPS(fops); DEFINE_DRM_GEM_DMA_FOPS(fops);
@@ -237,9 +230,6 @@ DEFINE_DRM_GEM_DMA_FOPS(fops);
static const struct drm_driver hdlcd_driver = { static const struct drm_driver hdlcd_driver = {
.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
DRM_GEM_DMA_DRIVER_OPS, DRM_GEM_DMA_DRIVER_OPS,
#ifdef CONFIG_DEBUG_FS
.debugfs_init = hdlcd_debugfs_init,
#endif
.fops = &fops, .fops = &fops,
.name = "hdlcd", .name = "hdlcd",
.desc = "ARM HDLCD Controller DRM", .desc = "ARM HDLCD Controller DRM",
@@ -303,6 +293,10 @@ static int hdlcd_drm_bind(struct device *dev)
drm_mode_config_reset(drm); drm_mode_config_reset(drm);
drm_kms_helper_poll_init(drm); drm_kms_helper_poll_init(drm);
#ifdef CONFIG_DEBUG_FS
drm_debugfs_add_files(drm, hdlcd_debugfs_list, ARRAY_SIZE(hdlcd_debugfs_list));
#endif
ret = drm_dev_register(drm, 0); ret = drm_dev_register(drm, 0);
if (ret) if (ret)
goto err_register; goto err_register;

View File

@@ -4,6 +4,8 @@ config DRM_AST
depends on DRM && PCI && MMU depends on DRM && PCI && MMU
select DRM_GEM_SHMEM_HELPER select DRM_GEM_SHMEM_HELPER
select DRM_KMS_HELPER select DRM_KMS_HELPER
select I2C
select I2C_ALGOBIT
help help
Say yes for experimental AST GPU driver. Do not enable Say yes for experimental AST GPU driver. Do not enable
this driver without having a working -modesetting, this driver without having a working -modesetting,

View File

@@ -357,15 +357,16 @@ struct drm_bridge *devm_drm_panel_bridge_add_typed(struct device *dev,
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
bridge = drm_panel_bridge_add_typed(panel, connector_type); bridge = drm_panel_bridge_add_typed(panel, connector_type);
if (!IS_ERR(bridge)) { if (IS_ERR(bridge)) {
*ptr = bridge;
devres_add(dev, ptr);
} else {
devres_free(ptr); devres_free(ptr);
return bridge;
} }
bridge->pre_enable_prev_first = panel->prepare_prev_first; bridge->pre_enable_prev_first = panel->prepare_prev_first;
*ptr = bridge;
devres_add(dev, ptr);
return bridge; return bridge;
} }
EXPORT_SYMBOL(devm_drm_panel_bridge_add_typed); EXPORT_SYMBOL(devm_drm_panel_bridge_add_typed);

View File

@@ -450,8 +450,8 @@ static int drm_atomic_helper_crtc_normalize_zpos(struct drm_crtc *crtc,
int i, n = 0; int i, n = 0;
int ret = 0; int ret = 0;
DRM_DEBUG_ATOMIC("[CRTC:%d:%s] calculating normalized zpos values\n", drm_dbg_atomic(dev, "[CRTC:%d:%s] calculating normalized zpos values\n",
crtc->base.id, crtc->name); crtc->base.id, crtc->name);
states = kmalloc_array(total_planes, sizeof(*states), GFP_KERNEL); states = kmalloc_array(total_planes, sizeof(*states), GFP_KERNEL);
if (!states) if (!states)
@@ -469,9 +469,8 @@ static int drm_atomic_helper_crtc_normalize_zpos(struct drm_crtc *crtc,
goto done; goto done;
} }
states[n++] = plane_state; states[n++] = plane_state;
DRM_DEBUG_ATOMIC("[PLANE:%d:%s] processing zpos value %d\n", drm_dbg_atomic(dev, "[PLANE:%d:%s] processing zpos value %d\n",
plane->base.id, plane->name, plane->base.id, plane->name, plane_state->zpos);
plane_state->zpos);
} }
sort(states, n, sizeof(*states), drm_atomic_state_zpos_cmp, NULL); sort(states, n, sizeof(*states), drm_atomic_state_zpos_cmp, NULL);
@@ -480,8 +479,8 @@ static int drm_atomic_helper_crtc_normalize_zpos(struct drm_crtc *crtc,
plane = states[i]->plane; plane = states[i]->plane;
states[i]->normalized_zpos = i; states[i]->normalized_zpos = i;
DRM_DEBUG_ATOMIC("[PLANE:%d:%s] normalized zpos value %d\n", drm_dbg_atomic(dev, "[PLANE:%d:%s] normalized zpos value %d\n",
plane->base.id, plane->name, i); plane->base.id, plane->name, i);
} }
crtc_state->zpos_changed = true; crtc_state->zpos_changed = true;

View File

@@ -128,14 +128,7 @@ static void drm_bridge_connector_hpd_cb(void *cb_data,
drm_kms_helper_hotplug_event(dev); drm_kms_helper_hotplug_event(dev);
} }
/** static void drm_bridge_connector_enable_hpd(struct drm_connector *connector)
* drm_bridge_connector_enable_hpd - Enable hot-plug detection for the connector
* @connector: The DRM bridge connector
*
* This function enables hot-plug detection for the given bridge connector.
* This is typically used by display drivers in their resume handler.
*/
void drm_bridge_connector_enable_hpd(struct drm_connector *connector)
{ {
struct drm_bridge_connector *bridge_connector = struct drm_bridge_connector *bridge_connector =
to_drm_bridge_connector(connector); to_drm_bridge_connector(connector);
@@ -145,17 +138,8 @@ void drm_bridge_connector_enable_hpd(struct drm_connector *connector)
drm_bridge_hpd_enable(hpd, drm_bridge_connector_hpd_cb, drm_bridge_hpd_enable(hpd, drm_bridge_connector_hpd_cb,
bridge_connector); bridge_connector);
} }
EXPORT_SYMBOL_GPL(drm_bridge_connector_enable_hpd);
/** static void drm_bridge_connector_disable_hpd(struct drm_connector *connector)
* drm_bridge_connector_disable_hpd - Disable hot-plug detection for the
* connector
* @connector: The DRM bridge connector
*
* This function disables hot-plug detection for the given bridge connector.
* This is typically used by display drivers in their suspend handler.
*/
void drm_bridge_connector_disable_hpd(struct drm_connector *connector)
{ {
struct drm_bridge_connector *bridge_connector = struct drm_bridge_connector *bridge_connector =
to_drm_bridge_connector(connector); to_drm_bridge_connector(connector);
@@ -164,7 +148,6 @@ void drm_bridge_connector_disable_hpd(struct drm_connector *connector)
if (hpd) if (hpd)
drm_bridge_hpd_disable(hpd); drm_bridge_hpd_disable(hpd);
} }
EXPORT_SYMBOL_GPL(drm_bridge_connector_disable_hpd);
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
* Bridge Connector Functions * Bridge Connector Functions
@@ -305,6 +288,8 @@ static int drm_bridge_connector_get_modes(struct drm_connector *connector)
static const struct drm_connector_helper_funcs drm_bridge_connector_helper_funcs = { static const struct drm_connector_helper_funcs drm_bridge_connector_helper_funcs = {
.get_modes = drm_bridge_connector_get_modes, .get_modes = drm_bridge_connector_get_modes,
/* No need for .mode_valid(), the bridges are checked by the core. */ /* No need for .mode_valid(), the bridges are checked by the core. */
.enable_hpd = drm_bridge_connector_enable_hpd,
.disable_hpd = drm_bridge_connector_disable_hpd,
}; };
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
@@ -387,10 +372,8 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
connector_type, ddc); connector_type, ddc);
drm_connector_helper_add(connector, &drm_bridge_connector_helper_funcs); drm_connector_helper_add(connector, &drm_bridge_connector_helper_funcs);
if (bridge_connector->bridge_hpd) { if (bridge_connector->bridge_hpd)
connector->polled = DRM_CONNECTOR_POLL_HPD; connector->polled = DRM_CONNECTOR_POLL_HPD;
drm_bridge_connector_enable_hpd(connector);
}
else if (bridge_connector->bridge_detect) else if (bridge_connector->bridge_detect)
connector->polled = DRM_CONNECTOR_POLL_CONNECT connector->polled = DRM_CONNECTOR_POLL_CONNECT
| DRM_CONNECTOR_POLL_DISCONNECT; | DRM_CONNECTOR_POLL_DISCONNECT;

View File

@@ -207,7 +207,7 @@ void drm_debugfs_create_files(const struct drm_info_list *files, int count,
tmp->minor = minor; tmp->minor = minor;
tmp->dent = debugfs_create_file(files[i].name, tmp->dent = debugfs_create_file(files[i].name,
S_IFREG | S_IRUGO, root, tmp, 0444, root, tmp,
&drm_debugfs_fops); &drm_debugfs_fops);
tmp->info_ent = &files[i]; tmp->info_ent = &files[i];
@@ -246,7 +246,7 @@ int drm_debugfs_init(struct drm_minor *minor, int minor_id,
dev->driver->debugfs_init(minor); dev->driver->debugfs_init(minor);
list_for_each_entry_safe(entry, tmp, &dev->debugfs_list, list) { list_for_each_entry_safe(entry, tmp, &dev->debugfs_list, list) {
debugfs_create_file(entry->file.name, S_IFREG | S_IRUGO, debugfs_create_file(entry->file.name, 0444,
minor->debugfs_root, entry, &drm_debugfs_entry_fops); minor->debugfs_root, entry, &drm_debugfs_entry_fops);
list_del(&entry->list); list_del(&entry->list);
} }
@@ -263,7 +263,7 @@ void drm_debugfs_late_register(struct drm_device *dev)
return; return;
list_for_each_entry_safe(entry, tmp, &dev->debugfs_list, list) { list_for_each_entry_safe(entry, tmp, &dev->debugfs_list, list) {
debugfs_create_file(entry->file.name, S_IFREG | S_IRUGO, debugfs_create_file(entry->file.name, 0444,
minor->debugfs_root, entry, &drm_debugfs_entry_fops); minor->debugfs_root, entry, &drm_debugfs_entry_fops);
list_del(&entry->list); list_del(&entry->list);
} }
@@ -508,15 +508,15 @@ void drm_debugfs_connector_add(struct drm_connector *connector)
connector->debugfs_entry = root; connector->debugfs_entry = root;
/* force */ /* force */
debugfs_create_file("force", S_IRUGO | S_IWUSR, root, connector, debugfs_create_file("force", 0644, root, connector,
&drm_connector_fops); &drm_connector_fops);
/* edid */ /* edid */
debugfs_create_file("edid_override", S_IRUGO | S_IWUSR, root, connector, debugfs_create_file("edid_override", 0644, root, connector,
&drm_edid_fops); &drm_edid_fops);
/* vrr range */ /* vrr range */
debugfs_create_file("vrr_range", S_IRUGO, root, connector, debugfs_create_file("vrr_range", 0444, root, connector,
&vrr_range_fops); &vrr_range_fops);
/* max bpc */ /* max bpc */

View File

@@ -1726,117 +1726,132 @@ unlock:
} }
EXPORT_SYMBOL(drm_fb_helper_pan_display); EXPORT_SYMBOL(drm_fb_helper_pan_display);
/* static uint32_t drm_fb_helper_find_format(struct drm_fb_helper *fb_helper, const uint32_t *formats,
* Allocates the backing storage and sets up the fbdev info structure through size_t format_count, uint32_t bpp, uint32_t depth)
* the ->fb_probe callback. {
*/ struct drm_device *dev = fb_helper->dev;
static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, uint32_t format;
int preferred_bpp) size_t i;
/*
* Do not consider YUV or other complicated formats
* for framebuffers. This means only legacy formats
* are supported (fmt->depth is a legacy field), but
* the framebuffer emulation can only deal with such
* formats, specifically RGB/BGA formats.
*/
format = drm_mode_legacy_fb_format(bpp, depth);
if (!format)
goto err;
for (i = 0; i < format_count; ++i) {
if (formats[i] == format)
return format;
}
err:
/* We found nothing. */
drm_warn(dev, "bpp/depth value of %u/%u not supported\n", bpp, depth);
return DRM_FORMAT_INVALID;
}
static uint32_t drm_fb_helper_find_color_mode_format(struct drm_fb_helper *fb_helper,
const uint32_t *formats, size_t format_count,
unsigned int color_mode)
{
struct drm_device *dev = fb_helper->dev;
uint32_t bpp, depth;
switch (color_mode) {
case 1:
case 2:
case 4:
case 8:
case 16:
case 24:
bpp = depth = color_mode;
break;
case 15:
bpp = 16;
depth = 15;
break;
case 32:
bpp = 32;
depth = 24;
break;
default:
drm_info(dev, "unsupported color mode of %d\n", color_mode);
return DRM_FORMAT_INVALID;
}
return drm_fb_helper_find_format(fb_helper, formats, format_count, bpp, depth);
}
static int __drm_fb_helper_find_sizes(struct drm_fb_helper *fb_helper, int preferred_bpp,
struct drm_fb_helper_surface_size *sizes)
{ {
struct drm_client_dev *client = &fb_helper->client; struct drm_client_dev *client = &fb_helper->client;
struct drm_device *dev = fb_helper->dev; struct drm_device *dev = fb_helper->dev;
struct drm_mode_config *config = &dev->mode_config;
int ret = 0;
int crtc_count = 0; int crtc_count = 0;
struct drm_connector_list_iter conn_iter; struct drm_connector_list_iter conn_iter;
struct drm_fb_helper_surface_size sizes;
struct drm_connector *connector; struct drm_connector *connector;
struct drm_mode_set *mode_set; struct drm_mode_set *mode_set;
int best_depth = 0; uint32_t surface_format = DRM_FORMAT_INVALID;
const struct drm_format_info *info;
memset(&sizes, 0, sizeof(struct drm_fb_helper_surface_size)); memset(sizes, 0, sizeof(*sizes));
sizes.surface_depth = 24; sizes->fb_width = (u32)-1;
sizes.surface_bpp = 32; sizes->fb_height = (u32)-1;
sizes.fb_width = (u32)-1;
sizes.fb_height = (u32)-1;
/*
* If driver picks 8 or 16 by default use that for both depth/bpp
* to begin with
*/
if (preferred_bpp != sizes.surface_bpp)
sizes.surface_depth = sizes.surface_bpp = preferred_bpp;
drm_connector_list_iter_begin(fb_helper->dev, &conn_iter);
drm_client_for_each_connector_iter(connector, &conn_iter) {
struct drm_cmdline_mode *cmdline_mode;
cmdline_mode = &connector->cmdline_mode;
if (cmdline_mode->bpp_specified) {
switch (cmdline_mode->bpp) {
case 8:
sizes.surface_depth = sizes.surface_bpp = 8;
break;
case 15:
sizes.surface_depth = 15;
sizes.surface_bpp = 16;
break;
case 16:
sizes.surface_depth = sizes.surface_bpp = 16;
break;
case 24:
sizes.surface_depth = sizes.surface_bpp = 24;
break;
case 32:
sizes.surface_depth = 24;
sizes.surface_bpp = 32;
break;
}
break;
}
}
drm_connector_list_iter_end(&conn_iter);
/*
* If we run into a situation where, for example, the primary plane
* supports RGBA5551 (16 bpp, depth 15) but not RGB565 (16 bpp, depth
* 16) we need to scale down the depth of the sizes we request.
*/
mutex_lock(&client->modeset_mutex);
drm_client_for_each_modeset(mode_set, client) { drm_client_for_each_modeset(mode_set, client) {
struct drm_crtc *crtc = mode_set->crtc; struct drm_crtc *crtc = mode_set->crtc;
struct drm_plane *plane = crtc->primary; struct drm_plane *plane = crtc->primary;
int j;
drm_dbg_kms(dev, "test CRTC %u primary plane\n", drm_crtc_index(crtc)); drm_dbg_kms(dev, "test CRTC %u primary plane\n", drm_crtc_index(crtc));
for (j = 0; j < plane->format_count; j++) { drm_connector_list_iter_begin(fb_helper->dev, &conn_iter);
const struct drm_format_info *fmt; drm_client_for_each_connector_iter(connector, &conn_iter) {
struct drm_cmdline_mode *cmdline_mode = &connector->cmdline_mode;
fmt = drm_format_info(plane->format_types[j]); if (!cmdline_mode->bpp_specified)
/*
* Do not consider YUV or other complicated formats
* for framebuffers. This means only legacy formats
* are supported (fmt->depth is a legacy field) but
* the framebuffer emulation can only deal with such
* formats, specifically RGB/BGA formats.
*/
if (fmt->depth == 0)
continue; continue;
/* We found a perfect fit, great */ surface_format = drm_fb_helper_find_color_mode_format(fb_helper,
if (fmt->depth == sizes.surface_depth) { plane->format_types,
best_depth = fmt->depth; plane->format_count,
break; cmdline_mode->bpp);
} if (surface_format != DRM_FORMAT_INVALID)
break; /* found supported format */
/* Skip depths above what we're looking for */
if (fmt->depth > sizes.surface_depth)
continue;
/* Best depth found so far */
if (fmt->depth > best_depth)
best_depth = fmt->depth;
} }
drm_connector_list_iter_end(&conn_iter);
if (surface_format != DRM_FORMAT_INVALID)
break; /* found supported format */
/* try preferred color mode */
surface_format = drm_fb_helper_find_color_mode_format(fb_helper,
plane->format_types,
plane->format_count,
preferred_bpp);
if (surface_format != DRM_FORMAT_INVALID)
break; /* found supported format */
} }
if (sizes.surface_depth != best_depth && best_depth) {
drm_info(dev, "requested bpp %d, scaled depth down to %d", if (surface_format == DRM_FORMAT_INVALID) {
sizes.surface_bpp, best_depth); /*
sizes.surface_depth = best_depth; * If none of the given color modes works, fall back
* to XRGB8888. Drivers are expected to provide this
* format for compatibility with legacy applications.
*/
drm_warn(dev, "No compatible format found\n");
surface_format = drm_driver_legacy_fb_format(dev, 32, 24);
} }
info = drm_format_info(surface_format);
sizes->surface_bpp = drm_format_info_bpp(info, 0);
sizes->surface_depth = info->depth;
/* first up get a count of crtcs now in use and new min/maxes width/heights */ /* first up get a count of crtcs now in use and new min/maxes width/heights */
crtc_count = 0; crtc_count = 0;
drm_client_for_each_modeset(mode_set, client) { drm_client_for_each_modeset(mode_set, client) {
@@ -1858,8 +1873,10 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
x = mode_set->x; x = mode_set->x;
y = mode_set->y; y = mode_set->y;
sizes.surface_width = max_t(u32, desired_mode->hdisplay + x, sizes.surface_width); sizes->surface_width =
sizes.surface_height = max_t(u32, desired_mode->vdisplay + y, sizes.surface_height); max_t(u32, desired_mode->hdisplay + x, sizes->surface_width);
sizes->surface_height =
max_t(u32, desired_mode->vdisplay + y, sizes->surface_height);
for (j = 0; j < mode_set->num_connectors; j++) { for (j = 0; j < mode_set->num_connectors; j++) {
struct drm_connector *connector = mode_set->connectors[j]; struct drm_connector *connector = mode_set->connectors[j];
@@ -1875,28 +1892,63 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
} }
if (lasth) if (lasth)
sizes.fb_width = min_t(u32, desired_mode->hdisplay + x, sizes.fb_width); sizes->fb_width = min_t(u32, desired_mode->hdisplay + x, sizes->fb_width);
if (lastv) if (lastv)
sizes.fb_height = min_t(u32, desired_mode->vdisplay + y, sizes.fb_height); sizes->fb_height = min_t(u32, desired_mode->vdisplay + y, sizes->fb_height);
} }
mutex_unlock(&client->modeset_mutex);
if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) { if (crtc_count == 0 || sizes->fb_width == -1 || sizes->fb_height == -1) {
drm_info(dev, "Cannot find any crtc or sizes\n"); drm_info(dev, "Cannot find any crtc or sizes\n");
/* First time: disable all crtc's.. */
if (!fb_helper->deferred_setup)
drm_client_modeset_commit(client);
return -EAGAIN; return -EAGAIN;
} }
return 0;
}
static int drm_fb_helper_find_sizes(struct drm_fb_helper *fb_helper, int preferred_bpp,
struct drm_fb_helper_surface_size *sizes)
{
struct drm_client_dev *client = &fb_helper->client;
struct drm_device *dev = fb_helper->dev;
struct drm_mode_config *config = &dev->mode_config;
int ret;
mutex_lock(&client->modeset_mutex);
ret = __drm_fb_helper_find_sizes(fb_helper, preferred_bpp, sizes);
mutex_unlock(&client->modeset_mutex);
if (ret)
return ret;
/* Handle our overallocation */ /* Handle our overallocation */
sizes.surface_height *= drm_fbdev_overalloc; sizes->surface_height *= drm_fbdev_overalloc;
sizes.surface_height /= 100; sizes->surface_height /= 100;
if (sizes.surface_height > config->max_height) { if (sizes->surface_height > config->max_height) {
drm_dbg_kms(dev, "Fbdev over-allocation too large; clamping height to %d\n", drm_dbg_kms(dev, "Fbdev over-allocation too large; clamping height to %d\n",
config->max_height); config->max_height);
sizes.surface_height = config->max_height; sizes->surface_height = config->max_height;
}
return 0;
}
/*
* Allocates the backing storage and sets up the fbdev info structure through
* the ->fb_probe callback.
*/
static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
int preferred_bpp)
{
struct drm_client_dev *client = &fb_helper->client;
struct drm_fb_helper_surface_size sizes;
int ret;
ret = drm_fb_helper_find_sizes(fb_helper, preferred_bpp, &sizes);
if (ret) {
/* First time: disable all crtc's.. */
if (!fb_helper->deferred_setup)
drm_client_modeset_commit(client);
return ret;
} }
#if IS_ENABLED(CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM) #if IS_ENABLED(CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM)

View File

@@ -245,10 +245,10 @@ void drm_file_free(struct drm_file *file)
dev = file->minor->dev; dev = file->minor->dev;
DRM_DEBUG("comm=\"%s\", pid=%d, dev=0x%lx, open_count=%d\n", drm_dbg_core(dev, "comm=\"%s\", pid=%d, dev=0x%lx, open_count=%d\n",
current->comm, task_pid_nr(current), current->comm, task_pid_nr(current),
(long)old_encode_dev(file->minor->kdev->devt), (long)old_encode_dev(file->minor->kdev->devt),
atomic_read(&dev->open_count)); atomic_read(&dev->open_count));
#ifdef CONFIG_DRM_LEGACY #ifdef CONFIG_DRM_LEGACY
if (drm_core_check_feature(dev, DRIVER_LEGACY) && if (drm_core_check_feature(dev, DRIVER_LEGACY) &&
@@ -340,8 +340,8 @@ int drm_open_helper(struct file *filp, struct drm_minor *minor)
dev->switch_power_state != DRM_SWITCH_POWER_DYNAMIC_OFF) dev->switch_power_state != DRM_SWITCH_POWER_DYNAMIC_OFF)
return -EINVAL; return -EINVAL;
DRM_DEBUG("comm=\"%s\", pid=%d, minor=%d\n", current->comm, drm_dbg_core(dev, "comm=\"%s\", pid=%d, minor=%d\n",
task_pid_nr(current), minor->index); current->comm, task_pid_nr(current), minor->index);
priv = drm_file_alloc(minor); priv = drm_file_alloc(minor);
if (IS_ERR(priv)) if (IS_ERR(priv))
@@ -450,11 +450,11 @@ EXPORT_SYMBOL(drm_open);
void drm_lastclose(struct drm_device * dev) void drm_lastclose(struct drm_device * dev)
{ {
DRM_DEBUG("\n"); drm_dbg_core(dev, "\n");
if (dev->driver->lastclose) if (dev->driver->lastclose)
dev->driver->lastclose(dev); dev->driver->lastclose(dev);
DRM_DEBUG("driver lastclose completed\n"); drm_dbg_core(dev, "driver lastclose completed\n");
if (drm_core_check_feature(dev, DRIVER_LEGACY)) if (drm_core_check_feature(dev, DRIVER_LEGACY))
drm_legacy_dev_reinit(dev); drm_legacy_dev_reinit(dev);
@@ -485,7 +485,7 @@ int drm_release(struct inode *inode, struct file *filp)
if (drm_dev_needs_global_mutex(dev)) if (drm_dev_needs_global_mutex(dev))
mutex_lock(&drm_global_mutex); mutex_lock(&drm_global_mutex);
DRM_DEBUG("open_count = %d\n", atomic_read(&dev->open_count)); drm_dbg_core(dev, "open_count = %d\n", atomic_read(&dev->open_count));
drm_close_helper(filp); drm_close_helper(filp);

View File

@@ -322,7 +322,7 @@ EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb332);
static void drm_fb_xrgb8888_to_rgb565_line(void *dbuf, const void *sbuf, unsigned int pixels) static void drm_fb_xrgb8888_to_rgb565_line(void *dbuf, const void *sbuf, unsigned int pixels)
{ {
u16 *dbuf16 = dbuf; __le16 *dbuf16 = dbuf;
const __le32 *sbuf32 = sbuf; const __le32 *sbuf32 = sbuf;
unsigned int x; unsigned int x;
u16 val16; u16 val16;
@@ -333,14 +333,15 @@ static void drm_fb_xrgb8888_to_rgb565_line(void *dbuf, const void *sbuf, unsigne
val16 = ((pix & 0x00F80000) >> 8) | val16 = ((pix & 0x00F80000) >> 8) |
((pix & 0x0000FC00) >> 5) | ((pix & 0x0000FC00) >> 5) |
((pix & 0x000000F8) >> 3); ((pix & 0x000000F8) >> 3);
dbuf16[x] = val16; dbuf16[x] = cpu_to_le16(val16);
} }
} }
/* TODO: implement this helper as conversion to RGB565|BIG_ENDIAN */
static void drm_fb_xrgb8888_to_rgb565_swab_line(void *dbuf, const void *sbuf, static void drm_fb_xrgb8888_to_rgb565_swab_line(void *dbuf, const void *sbuf,
unsigned int pixels) unsigned int pixels)
{ {
u16 *dbuf16 = dbuf; __le16 *dbuf16 = dbuf;
const __le32 *sbuf32 = sbuf; const __le32 *sbuf32 = sbuf;
unsigned int x; unsigned int x;
u16 val16; u16 val16;
@@ -351,7 +352,7 @@ static void drm_fb_xrgb8888_to_rgb565_swab_line(void *dbuf, const void *sbuf,
val16 = ((pix & 0x00F80000) >> 8) | val16 = ((pix & 0x00F80000) >> 8) |
((pix & 0x0000FC00) >> 5) | ((pix & 0x0000FC00) >> 5) |
((pix & 0x000000F8) >> 3); ((pix & 0x000000F8) >> 3);
dbuf16[x] = swab16(val16); dbuf16[x] = cpu_to_le16(swab16(val16));
} }
} }
@@ -395,6 +396,161 @@ void drm_fb_xrgb8888_to_rgb565(struct iosys_map *dst, const unsigned int *dst_pi
} }
EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565); EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565);
static void drm_fb_xrgb8888_to_xrgb1555_line(void *dbuf, const void *sbuf, unsigned int pixels)
{
__le16 *dbuf16 = dbuf;
const __le32 *sbuf32 = sbuf;
unsigned int x;
u16 val16;
u32 pix;
for (x = 0; x < pixels; x++) {
pix = le32_to_cpu(sbuf32[x]);
val16 = ((pix & 0x00f80000) >> 9) |
((pix & 0x0000f800) >> 6) |
((pix & 0x000000f8) >> 3);
dbuf16[x] = cpu_to_le16(val16);
}
}
/**
* drm_fb_xrgb8888_to_xrgb1555 - Convert XRGB8888 to XRGB1555 clip buffer
* @dst: Array of XRGB1555 destination buffers
* @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
* within @dst; can be NULL if scanlines are stored next to each other.
* @src: Array of XRGB8888 source buffer
* @fb: DRM framebuffer
* @clip: Clip rectangle area to copy
*
* This function copies parts of a framebuffer to display memory and converts
* the color format during the process. The parameters @dst, @dst_pitch and
* @src refer to arrays. Each array must have at least as many entries as
* there are planes in @fb's format. Each entry stores the value for the
* format's respective color plane at the same index.
*
* This function does not apply clipping on @dst (i.e. the destination is at the
* top-left corner).
*
* Drivers can use this function for XRGB1555 devices that don't support
* XRGB8888 natively.
*/
void drm_fb_xrgb8888_to_xrgb1555(struct iosys_map *dst, const unsigned int *dst_pitch,
const struct iosys_map *src, const struct drm_framebuffer *fb,
const struct drm_rect *clip)
{
static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
2,
};
drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
drm_fb_xrgb8888_to_xrgb1555_line);
}
EXPORT_SYMBOL(drm_fb_xrgb8888_to_xrgb1555);
static void drm_fb_xrgb8888_to_argb1555_line(void *dbuf, const void *sbuf, unsigned int pixels)
{
__le16 *dbuf16 = dbuf;
const __le32 *sbuf32 = sbuf;
unsigned int x;
u16 val16;
u32 pix;
for (x = 0; x < pixels; x++) {
pix = le32_to_cpu(sbuf32[x]);
val16 = BIT(15) | /* set alpha bit */
((pix & 0x00f80000) >> 9) |
((pix & 0x0000f800) >> 6) |
((pix & 0x000000f8) >> 3);
dbuf16[x] = cpu_to_le16(val16);
}
}
/**
* drm_fb_xrgb8888_to_argb1555 - Convert XRGB8888 to ARGB1555 clip buffer
* @dst: Array of ARGB1555 destination buffers
* @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
* within @dst; can be NULL if scanlines are stored next to each other.
* @src: Array of XRGB8888 source buffer
* @fb: DRM framebuffer
* @clip: Clip rectangle area to copy
*
* This function copies parts of a framebuffer to display memory and converts
* the color format during the process. The parameters @dst, @dst_pitch and
* @src refer to arrays. Each array must have at least as many entries as
* there are planes in @fb's format. Each entry stores the value for the
* format's respective color plane at the same index.
*
* This function does not apply clipping on @dst (i.e. the destination is at the
* top-left corner).
*
* Drivers can use this function for ARGB1555 devices that don't support
* XRGB8888 natively. It sets an opaque alpha channel as part of the conversion.
*/
void drm_fb_xrgb8888_to_argb1555(struct iosys_map *dst, const unsigned int *dst_pitch,
const struct iosys_map *src, const struct drm_framebuffer *fb,
const struct drm_rect *clip)
{
static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
2,
};
drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
drm_fb_xrgb8888_to_argb1555_line);
}
EXPORT_SYMBOL(drm_fb_xrgb8888_to_argb1555);
static void drm_fb_xrgb8888_to_rgba5551_line(void *dbuf, const void *sbuf, unsigned int pixels)
{
__le16 *dbuf16 = dbuf;
const __le32 *sbuf32 = sbuf;
unsigned int x;
u16 val16;
u32 pix;
for (x = 0; x < pixels; x++) {
pix = le32_to_cpu(sbuf32[x]);
val16 = ((pix & 0x00f80000) >> 8) |
((pix & 0x0000f800) >> 5) |
((pix & 0x000000f8) >> 2) |
BIT(0); /* set alpha bit */
dbuf16[x] = cpu_to_le16(val16);
}
}
/**
* drm_fb_xrgb8888_to_rgba5551 - Convert XRGB8888 to RGBA5551 clip buffer
* @dst: Array of RGBA5551 destination buffers
* @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
* within @dst; can be NULL if scanlines are stored next to each other.
* @src: Array of XRGB8888 source buffer
* @fb: DRM framebuffer
* @clip: Clip rectangle area to copy
*
* This function copies parts of a framebuffer to display memory and converts
* the color format during the process. The parameters @dst, @dst_pitch and
* @src refer to arrays. Each array must have at least as many entries as
* there are planes in @fb's format. Each entry stores the value for the
* format's respective color plane at the same index.
*
* This function does not apply clipping on @dst (i.e. the destination is at the
* top-left corner).
*
* Drivers can use this function for RGBA5551 devices that don't support
* XRGB8888 natively. It sets an opaque alpha channel as part of the conversion.
*/
void drm_fb_xrgb8888_to_rgba5551(struct iosys_map *dst, const unsigned int *dst_pitch,
const struct iosys_map *src, const struct drm_framebuffer *fb,
const struct drm_rect *clip)
{
static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
2,
};
drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
drm_fb_xrgb8888_to_rgba5551_line);
}
EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgba5551);
static void drm_fb_xrgb8888_to_rgb888_line(void *dbuf, const void *sbuf, unsigned int pixels) static void drm_fb_xrgb8888_to_rgb888_line(void *dbuf, const void *sbuf, unsigned int pixels)
{ {
u8 *dbuf8 = dbuf; u8 *dbuf8 = dbuf;
@@ -404,6 +560,7 @@ static void drm_fb_xrgb8888_to_rgb888_line(void *dbuf, const void *sbuf, unsigne
for (x = 0; x < pixels; x++) { for (x = 0; x < pixels; x++) {
pix = le32_to_cpu(sbuf32[x]); pix = le32_to_cpu(sbuf32[x]);
/* write blue-green-red to output in little endianness */
*dbuf8++ = (pix & 0x000000FF) >> 0; *dbuf8++ = (pix & 0x000000FF) >> 0;
*dbuf8++ = (pix & 0x0000FF00) >> 8; *dbuf8++ = (pix & 0x0000FF00) >> 8;
*dbuf8++ = (pix & 0x00FF0000) >> 16; *dbuf8++ = (pix & 0x00FF0000) >> 16;
@@ -444,64 +601,53 @@ void drm_fb_xrgb8888_to_rgb888(struct iosys_map *dst, const unsigned int *dst_pi
} }
EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb888); EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb888);
static void drm_fb_rgb565_to_xrgb8888_line(void *dbuf, const void *sbuf, unsigned int pixels) static void drm_fb_xrgb8888_to_argb8888_line(void *dbuf, const void *sbuf, unsigned int pixels)
{ {
__le32 *dbuf32 = dbuf; __le32 *dbuf32 = dbuf;
const __le16 *sbuf16 = sbuf; const __le32 *sbuf32 = sbuf;
unsigned int x; unsigned int x;
u32 pix;
for (x = 0; x < pixels; x++) { for (x = 0; x < pixels; x++) {
u16 val16 = le16_to_cpu(sbuf16[x]); pix = le32_to_cpu(sbuf32[x]);
u32 val32 = ((val16 & 0xf800) << 8) | pix |= GENMASK(31, 24); /* fill alpha bits */
((val16 & 0x07e0) << 5) |
((val16 & 0x001f) << 3);
val32 = 0xff000000 | val32 |
((val32 >> 3) & 0x00070007) |
((val32 >> 2) & 0x00000300);
dbuf32[x] = cpu_to_le32(val32);
}
}
static void drm_fb_rgb565_to_xrgb8888(struct iosys_map *dst, const unsigned int *dst_pitch,
const struct iosys_map *src,
const struct drm_framebuffer *fb,
const struct drm_rect *clip)
{
static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
4,
};
drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
drm_fb_rgb565_to_xrgb8888_line);
}
static void drm_fb_rgb888_to_xrgb8888_line(void *dbuf, const void *sbuf, unsigned int pixels)
{
__le32 *dbuf32 = dbuf;
const u8 *sbuf8 = sbuf;
unsigned int x;
for (x = 0; x < pixels; x++) {
u8 r = *sbuf8++;
u8 g = *sbuf8++;
u8 b = *sbuf8++;
u32 pix = 0xff000000 | (r << 16) | (g << 8) | b;
dbuf32[x] = cpu_to_le32(pix); dbuf32[x] = cpu_to_le32(pix);
} }
} }
static void drm_fb_rgb888_to_xrgb8888(struct iosys_map *dst, const unsigned int *dst_pitch, /**
const struct iosys_map *src, * drm_fb_xrgb8888_to_argb8888 - Convert XRGB8888 to ARGB8888 clip buffer
const struct drm_framebuffer *fb, * @dst: Array of ARGB8888 destination buffers
const struct drm_rect *clip) * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
* within @dst; can be NULL if scanlines are stored next to each other.
* @src: Array of XRGB8888 source buffer
* @fb: DRM framebuffer
* @clip: Clip rectangle area to copy
*
* This function copies parts of a framebuffer to display memory and converts the
* color format during the process. The parameters @dst, @dst_pitch and @src refer
* to arrays. Each array must have at least as many entries as there are planes in
* @fb's format. Each entry stores the value for the format's respective color plane
* at the same index.
*
* This function does not apply clipping on @dst (i.e. the destination is at the
* top-left corner).
*
* Drivers can use this function for ARGB8888 devices that don't support XRGB8888
* natively. It sets an opaque alpha channel as part of the conversion.
*/
void drm_fb_xrgb8888_to_argb8888(struct iosys_map *dst, const unsigned int *dst_pitch,
const struct iosys_map *src, const struct drm_framebuffer *fb,
const struct drm_rect *clip)
{ {
static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
4, 4,
}; };
drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
drm_fb_rgb888_to_xrgb8888_line); drm_fb_xrgb8888_to_argb8888_line);
} }
EXPORT_SYMBOL(drm_fb_xrgb8888_to_argb8888);
static void drm_fb_xrgb8888_to_xrgb2101010_line(void *dbuf, const void *sbuf, unsigned int pixels) static void drm_fb_xrgb8888_to_xrgb2101010_line(void *dbuf, const void *sbuf, unsigned int pixels)
{ {
@@ -555,6 +701,59 @@ void drm_fb_xrgb8888_to_xrgb2101010(struct iosys_map *dst, const unsigned int *d
} }
EXPORT_SYMBOL(drm_fb_xrgb8888_to_xrgb2101010); EXPORT_SYMBOL(drm_fb_xrgb8888_to_xrgb2101010);
static void drm_fb_xrgb8888_to_argb2101010_line(void *dbuf, const void *sbuf, unsigned int pixels)
{
__le32 *dbuf32 = dbuf;
const __le32 *sbuf32 = sbuf;
unsigned int x;
u32 val32;
u32 pix;
for (x = 0; x < pixels; x++) {
pix = le32_to_cpu(sbuf32[x]);
val32 = ((pix & 0x000000ff) << 2) |
((pix & 0x0000ff00) << 4) |
((pix & 0x00ff0000) << 6);
pix = GENMASK(31, 30) | /* set alpha bits */
val32 | ((val32 >> 8) & 0x00300c03);
*dbuf32++ = cpu_to_le32(pix);
}
}
/**
* drm_fb_xrgb8888_to_argb2101010 - Convert XRGB8888 to ARGB2101010 clip buffer
* @dst: Array of ARGB2101010 destination buffers
* @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
* within @dst; can be NULL if scanlines are stored next to each other.
* @src: Array of XRGB8888 source buffers
* @fb: DRM framebuffer
* @clip: Clip rectangle area to copy
*
* This function copies parts of a framebuffer to display memory and converts
* the color format during the process. The parameters @dst, @dst_pitch and
* @src refer to arrays. Each array must have at least as many entries as
* there are planes in @fb's format. Each entry stores the value for the
* format's respective color plane at the same index.
*
* This function does not apply clipping on @dst (i.e. the destination is at the
* top-left corner).
*
* Drivers can use this function for ARGB2101010 devices that don't support XRGB8888
* natively.
*/
void drm_fb_xrgb8888_to_argb2101010(struct iosys_map *dst, const unsigned int *dst_pitch,
const struct iosys_map *src, const struct drm_framebuffer *fb,
const struct drm_rect *clip)
{
static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
4,
};
drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
drm_fb_xrgb8888_to_argb2101010_line);
}
EXPORT_SYMBOL(drm_fb_xrgb8888_to_argb2101010);
static void drm_fb_xrgb8888_to_gray8_line(void *dbuf, const void *sbuf, unsigned int pixels) static void drm_fb_xrgb8888_to_gray8_line(void *dbuf, const void *sbuf, unsigned int pixels)
{ {
u8 *dbuf8 = dbuf; u8 *dbuf8 = dbuf;
@@ -641,50 +840,41 @@ int drm_fb_blit(struct iosys_map *dst, const unsigned int *dst_pitch, uint32_t d
{ {
uint32_t fb_format = fb->format->format; uint32_t fb_format = fb->format->format;
/* treat alpha channel like filler bits */ if (fb_format == dst_format) {
if (fb_format == DRM_FORMAT_ARGB8888)
fb_format = DRM_FORMAT_XRGB8888;
if (dst_format == DRM_FORMAT_ARGB8888)
dst_format = DRM_FORMAT_XRGB8888;
if (fb_format == DRM_FORMAT_ARGB2101010)
fb_format = DRM_FORMAT_XRGB2101010;
if (dst_format == DRM_FORMAT_ARGB2101010)
dst_format = DRM_FORMAT_XRGB2101010;
if (dst_format == fb_format) {
drm_fb_memcpy(dst, dst_pitch, src, fb, clip); drm_fb_memcpy(dst, dst_pitch, src, fb, clip);
return 0; return 0;
} else if (fb_format == (dst_format | DRM_FORMAT_BIG_ENDIAN)) {
} else if (dst_format == DRM_FORMAT_RGB565) { drm_fb_swab(dst, dst_pitch, src, fb, clip, false);
if (fb_format == DRM_FORMAT_XRGB8888) { return 0;
} else if (fb_format == (dst_format & ~DRM_FORMAT_BIG_ENDIAN)) {
drm_fb_swab(dst, dst_pitch, src, fb, clip, false);
return 0;
} else if (fb_format == DRM_FORMAT_XRGB8888) {
if (dst_format == DRM_FORMAT_RGB565) {
drm_fb_xrgb8888_to_rgb565(dst, dst_pitch, src, fb, clip, false); drm_fb_xrgb8888_to_rgb565(dst, dst_pitch, src, fb, clip, false);
return 0; return 0;
} } else if (dst_format == DRM_FORMAT_XRGB1555) {
} else if (dst_format == (DRM_FORMAT_RGB565 | DRM_FORMAT_BIG_ENDIAN)) { drm_fb_xrgb8888_to_xrgb1555(dst, dst_pitch, src, fb, clip);
if (fb_format == DRM_FORMAT_RGB565) {
drm_fb_swab(dst, dst_pitch, src, fb, clip, false);
return 0; return 0;
} } else if (dst_format == DRM_FORMAT_ARGB1555) {
} else if (dst_format == DRM_FORMAT_RGB888) { drm_fb_xrgb8888_to_argb1555(dst, dst_pitch, src, fb, clip);
if (fb_format == DRM_FORMAT_XRGB8888) { return 0;
} else if (dst_format == DRM_FORMAT_RGBA5551) {
drm_fb_xrgb8888_to_rgba5551(dst, dst_pitch, src, fb, clip);
return 0;
} else if (dst_format == DRM_FORMAT_RGB888) {
drm_fb_xrgb8888_to_rgb888(dst, dst_pitch, src, fb, clip); drm_fb_xrgb8888_to_rgb888(dst, dst_pitch, src, fb, clip);
return 0; return 0;
} } else if (dst_format == DRM_FORMAT_ARGB8888) {
} else if (dst_format == DRM_FORMAT_XRGB8888) { drm_fb_xrgb8888_to_argb8888(dst, dst_pitch, src, fb, clip);
if (fb_format == DRM_FORMAT_RGB888) {
drm_fb_rgb888_to_xrgb8888(dst, dst_pitch, src, fb, clip);
return 0; return 0;
} else if (fb_format == DRM_FORMAT_RGB565) { } else if (dst_format == DRM_FORMAT_XRGB2101010) {
drm_fb_rgb565_to_xrgb8888(dst, dst_pitch, src, fb, clip);
return 0;
}
} else if (dst_format == DRM_FORMAT_XRGB2101010) {
if (fb_format == DRM_FORMAT_XRGB8888) {
drm_fb_xrgb8888_to_xrgb2101010(dst, dst_pitch, src, fb, clip); drm_fb_xrgb8888_to_xrgb2101010(dst, dst_pitch, src, fb, clip);
return 0; return 0;
} } else if (dst_format == DRM_FORMAT_ARGB2101010) {
} else if (dst_format == DRM_FORMAT_BGRX8888) { drm_fb_xrgb8888_to_argb2101010(dst, dst_pitch, src, fb, clip);
if (fb_format == DRM_FORMAT_XRGB8888) { return 0;
} else if (dst_format == DRM_FORMAT_BGRX8888) {
drm_fb_swab(dst, dst_pitch, src, fb, clip, false); drm_fb_swab(dst, dst_pitch, src, fb, clip, false);
return 0; return 0;
} }
@@ -805,6 +995,39 @@ void drm_fb_xrgb8888_to_mono(struct iosys_map *dst, const unsigned int *dst_pitc
} }
EXPORT_SYMBOL(drm_fb_xrgb8888_to_mono); EXPORT_SYMBOL(drm_fb_xrgb8888_to_mono);
static uint32_t drm_fb_nonalpha_fourcc(uint32_t fourcc)
{
/* only handle formats with depth != 0 and alpha channel */
switch (fourcc) {
case DRM_FORMAT_ARGB1555:
return DRM_FORMAT_XRGB1555;
case DRM_FORMAT_ABGR1555:
return DRM_FORMAT_XBGR1555;
case DRM_FORMAT_RGBA5551:
return DRM_FORMAT_RGBX5551;
case DRM_FORMAT_BGRA5551:
return DRM_FORMAT_BGRX5551;
case DRM_FORMAT_ARGB8888:
return DRM_FORMAT_XRGB8888;
case DRM_FORMAT_ABGR8888:
return DRM_FORMAT_XBGR8888;
case DRM_FORMAT_RGBA8888:
return DRM_FORMAT_RGBX8888;
case DRM_FORMAT_BGRA8888:
return DRM_FORMAT_BGRX8888;
case DRM_FORMAT_ARGB2101010:
return DRM_FORMAT_XRGB2101010;
case DRM_FORMAT_ABGR2101010:
return DRM_FORMAT_XBGR2101010;
case DRM_FORMAT_RGBA1010102:
return DRM_FORMAT_RGBX1010102;
case DRM_FORMAT_BGRA1010102:
return DRM_FORMAT_BGRX1010102;
}
return fourcc;
}
static bool is_listed_fourcc(const uint32_t *fourccs, size_t nfourccs, uint32_t fourcc) static bool is_listed_fourcc(const uint32_t *fourccs, size_t nfourccs, uint32_t fourcc)
{ {
const uint32_t *fourccs_end = fourccs + nfourccs; const uint32_t *fourccs_end = fourccs + nfourccs;
@@ -817,73 +1040,48 @@ static bool is_listed_fourcc(const uint32_t *fourccs, size_t nfourccs, uint32_t
return false; return false;
} }
static const uint32_t conv_from_xrgb8888[] = {
DRM_FORMAT_XRGB8888,
DRM_FORMAT_ARGB8888,
DRM_FORMAT_XRGB2101010,
DRM_FORMAT_ARGB2101010,
DRM_FORMAT_RGB565,
DRM_FORMAT_RGB888,
};
static const uint32_t conv_from_rgb565_888[] = {
DRM_FORMAT_XRGB8888,
DRM_FORMAT_ARGB8888,
};
static bool is_conversion_supported(uint32_t from, uint32_t to)
{
switch (from) {
case DRM_FORMAT_XRGB8888:
case DRM_FORMAT_ARGB8888:
return is_listed_fourcc(conv_from_xrgb8888, ARRAY_SIZE(conv_from_xrgb8888), to);
case DRM_FORMAT_RGB565:
case DRM_FORMAT_RGB888:
return is_listed_fourcc(conv_from_rgb565_888, ARRAY_SIZE(conv_from_rgb565_888), to);
case DRM_FORMAT_XRGB2101010:
return to == DRM_FORMAT_ARGB2101010;
case DRM_FORMAT_ARGB2101010:
return to == DRM_FORMAT_XRGB2101010;
default:
return false;
}
}
/** /**
* drm_fb_build_fourcc_list - Filters a list of supported color formats against * drm_fb_build_fourcc_list - Filters a list of supported color formats against
* the device's native formats * the device's native formats
* @dev: DRM device * @dev: DRM device
* @native_fourccs: 4CC codes of natively supported color formats * @native_fourccs: 4CC codes of natively supported color formats
* @native_nfourccs: The number of entries in @native_fourccs * @native_nfourccs: The number of entries in @native_fourccs
* @driver_fourccs: 4CC codes of all driver-supported color formats
* @driver_nfourccs: The number of entries in @driver_fourccs
* @fourccs_out: Returns 4CC codes of supported color formats * @fourccs_out: Returns 4CC codes of supported color formats
* @nfourccs_out: The number of available entries in @fourccs_out * @nfourccs_out: The number of available entries in @fourccs_out
* *
* This function create a list of supported color format from natively * This function create a list of supported color format from natively
* supported formats and the emulated formats. * supported formats and additional emulated formats.
* At a minimum, most userspace programs expect at least support for * At a minimum, most userspace programs expect at least support for
* XRGB8888 on the primary plane. Devices that have to emulate the * XRGB8888 on the primary plane. Devices that have to emulate the
* format, and possibly others, can use drm_fb_build_fourcc_list() to * format, and possibly others, can use drm_fb_build_fourcc_list() to
* create a list of supported color formats. The returned list can * create a list of supported color formats. The returned list can
* be handed over to drm_universal_plane_init() et al. Native formats * be handed over to drm_universal_plane_init() et al. Native formats
* will go before emulated formats. Other heuristics might be applied * will go before emulated formats. Native formats with alpha channel
* will be replaced by such without, as primary planes usually don't
* support alpha. Other heuristics might be applied
* to optimize the order. Formats near the beginning of the list are * to optimize the order. Formats near the beginning of the list are
* usually preferred over formats near the end of the list. Formats * usually preferred over formats near the end of the list.
* without conversion helpers will be skipped. New drivers should only
* pass in XRGB8888 and avoid exposing additional emulated formats.
* *
* Returns: * Returns:
* The number of color-formats 4CC codes returned in @fourccs_out. * The number of color-formats 4CC codes returned in @fourccs_out.
*/ */
size_t drm_fb_build_fourcc_list(struct drm_device *dev, size_t drm_fb_build_fourcc_list(struct drm_device *dev,
const u32 *native_fourccs, size_t native_nfourccs, const u32 *native_fourccs, size_t native_nfourccs,
const u32 *driver_fourccs, size_t driver_nfourccs,
u32 *fourccs_out, size_t nfourccs_out) u32 *fourccs_out, size_t nfourccs_out)
{ {
/*
* XRGB8888 is the default fallback format for most of userspace
* and it's currently the only format that should be emulated for
* the primary plane. Only if there's ever another default fallback,
* it should be added here.
*/
static const uint32_t extra_fourccs[] = {
DRM_FORMAT_XRGB8888,
};
static const size_t extra_nfourccs = ARRAY_SIZE(extra_fourccs);
u32 *fourccs = fourccs_out; u32 *fourccs = fourccs_out;
const u32 *fourccs_end = fourccs_out + nfourccs_out; const u32 *fourccs_end = fourccs_out + nfourccs_out;
uint32_t native_format = 0;
size_t i; size_t i;
/* /*
@@ -891,7 +1089,12 @@ size_t drm_fb_build_fourcc_list(struct drm_device *dev,
*/ */
for (i = 0; i < native_nfourccs; ++i) { for (i = 0; i < native_nfourccs; ++i) {
u32 fourcc = native_fourccs[i]; /*
* Several DTs, boot loaders and firmware report native
* alpha formats that are non-alpha formats instead. So
* replace alpha formats by non-alpha formats.
*/
u32 fourcc = drm_fb_nonalpha_fourcc(native_fourccs[i]);
if (is_listed_fourcc(fourccs_out, fourccs - fourccs_out, fourcc)) { if (is_listed_fourcc(fourccs_out, fourccs - fourccs_out, fourcc)) {
continue; /* skip duplicate entries */ continue; /* skip duplicate entries */
@@ -902,14 +1105,6 @@ size_t drm_fb_build_fourcc_list(struct drm_device *dev,
drm_dbg_kms(dev, "adding native format %p4cc\n", &fourcc); drm_dbg_kms(dev, "adding native format %p4cc\n", &fourcc);
/*
* There should only be one native format with the current API.
* This API needs to be refactored to correctly support arbitrary
* sets of native formats, since it needs to report which native
* format to use for each emulated format.
*/
if (!native_format)
native_format = fourcc;
*fourccs = fourcc; *fourccs = fourcc;
++fourccs; ++fourccs;
} }
@@ -918,17 +1113,14 @@ size_t drm_fb_build_fourcc_list(struct drm_device *dev,
* The extra formats, emulated by the driver, go second. * The extra formats, emulated by the driver, go second.
*/ */
for (i = 0; (i < driver_nfourccs) && (fourccs < fourccs_end); ++i) { for (i = 0; (i < extra_nfourccs) && (fourccs < fourccs_end); ++i) {
u32 fourcc = driver_fourccs[i]; u32 fourcc = extra_fourccs[i];
if (is_listed_fourcc(fourccs_out, fourccs - fourccs_out, fourcc)) { if (is_listed_fourcc(fourccs_out, fourccs - fourccs_out, fourcc)) {
continue; /* skip duplicate and native entries */ continue; /* skip duplicate and native entries */
} else if (fourccs == fourccs_end) { } else if (fourccs == fourccs_end) {
drm_warn(dev, "Ignoring emulated format %p4cc\n", &fourcc); drm_warn(dev, "Ignoring emulated format %p4cc\n", &fourcc);
continue; /* end of available output buffer */ continue; /* end of available output buffer */
} else if (!is_conversion_supported(fourcc, native_format)) {
drm_dbg_kms(dev, "Unsupported emulated format %p4cc\n", &fourcc);
continue; /* format is not supported for conversion */
} }
drm_dbg_kms(dev, "adding emulated format %p4cc\n", &fourcc); drm_dbg_kms(dev, "adding emulated format %p4cc\n", &fourcc);

View File

@@ -477,8 +477,8 @@ drm_gem_dma_prime_import_sg_table(struct drm_device *dev,
dma_obj->dma_addr = sg_dma_address(sgt->sgl); dma_obj->dma_addr = sg_dma_address(sgt->sgl);
dma_obj->sgt = sgt; dma_obj->sgt = sgt;
DRM_DEBUG_PRIME("dma_addr = %pad, size = %zu\n", &dma_obj->dma_addr, drm_dbg_prime(dev, "dma_addr = %pad, size = %zu\n", &dma_obj->dma_addr,
attach->dmabuf->size); attach->dmabuf->size);
return &dma_obj->base; return &dma_obj->base;
} }

View File

@@ -766,7 +766,7 @@ drm_gem_shmem_prime_import_sg_table(struct drm_device *dev,
shmem->sgt = sgt; shmem->sgt = sgt;
DRM_DEBUG_PRIME("size = %zu\n", size); drm_dbg_prime(dev, "size = %zu\n", size);
return &shmem->base; return &shmem->base;
} }

View File

@@ -972,6 +972,7 @@ long drm_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{ {
unsigned int nr = DRM_IOCTL_NR(cmd); unsigned int nr = DRM_IOCTL_NR(cmd);
struct drm_file *file_priv = filp->private_data; struct drm_file *file_priv = filp->private_data;
struct drm_device *dev = file_priv->minor->dev;
drm_ioctl_compat_t *fn; drm_ioctl_compat_t *fn;
int ret; int ret;
@@ -986,14 +987,14 @@ long drm_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
if (!fn) if (!fn)
return drm_ioctl(filp, cmd, arg); return drm_ioctl(filp, cmd, arg);
DRM_DEBUG("comm=\"%s\", pid=%d, dev=0x%lx, auth=%d, %s\n", drm_dbg_core(dev, "comm=\"%s\", pid=%d, dev=0x%lx, auth=%d, %s\n",
current->comm, task_pid_nr(current), current->comm, task_pid_nr(current),
(long)old_encode_dev(file_priv->minor->kdev->devt), (long)old_encode_dev(file_priv->minor->kdev->devt),
file_priv->authenticated, file_priv->authenticated,
drm_compat_ioctls[nr].name); drm_compat_ioctls[nr].name);
ret = (*fn)(filp, cmd, arg); ret = (*fn)(filp, cmd, arg);
if (ret) if (ret)
DRM_DEBUG("ret = %d\n", ret); drm_dbg_core(dev, "ret = %d\n", ret);
return ret; return ret;
} }
EXPORT_SYMBOL(drm_compat_ioctl); EXPORT_SYMBOL(drm_compat_ioctl);

View File

@@ -440,7 +440,7 @@ done:
int drm_noop(struct drm_device *dev, void *data, int drm_noop(struct drm_device *dev, void *data,
struct drm_file *file_priv) struct drm_file *file_priv)
{ {
DRM_DEBUG("\n"); drm_dbg_core(dev, "\n");
return 0; return 0;
} }
EXPORT_SYMBOL(drm_noop); EXPORT_SYMBOL(drm_noop);
@@ -856,16 +856,16 @@ long drm_ioctl(struct file *filp,
out_size = 0; out_size = 0;
ksize = max(max(in_size, out_size), drv_size); ksize = max(max(in_size, out_size), drv_size);
DRM_DEBUG("comm=\"%s\" pid=%d, dev=0x%lx, auth=%d, %s\n", drm_dbg_core(dev, "comm=\"%s\" pid=%d, dev=0x%lx, auth=%d, %s\n",
current->comm, task_pid_nr(current), current->comm, task_pid_nr(current),
(long)old_encode_dev(file_priv->minor->kdev->devt), (long)old_encode_dev(file_priv->minor->kdev->devt),
file_priv->authenticated, ioctl->name); file_priv->authenticated, ioctl->name);
/* Do not trust userspace, use our own definition */ /* Do not trust userspace, use our own definition */
func = ioctl->func; func = ioctl->func;
if (unlikely(!func)) { if (unlikely(!func)) {
DRM_DEBUG("no function\n"); drm_dbg_core(dev, "no function\n");
retcode = -EINVAL; retcode = -EINVAL;
goto err_i1; goto err_i1;
} }
@@ -894,16 +894,17 @@ long drm_ioctl(struct file *filp,
err_i1: err_i1:
if (!ioctl) if (!ioctl)
DRM_DEBUG("invalid ioctl: comm=\"%s\", pid=%d, dev=0x%lx, auth=%d, cmd=0x%02x, nr=0x%02x\n", drm_dbg_core(dev,
current->comm, task_pid_nr(current), "invalid ioctl: comm=\"%s\", pid=%d, dev=0x%lx, auth=%d, cmd=0x%02x, nr=0x%02x\n",
(long)old_encode_dev(file_priv->minor->kdev->devt), current->comm, task_pid_nr(current),
file_priv->authenticated, cmd, nr); (long)old_encode_dev(file_priv->minor->kdev->devt),
file_priv->authenticated, cmd, nr);
if (kdata != stack_kdata) if (kdata != stack_kdata)
kfree(kdata); kfree(kdata);
if (retcode) if (retcode)
DRM_DEBUG("comm=\"%s\", pid=%d, ret=%d\n", current->comm, drm_dbg_core(dev, "comm=\"%s\", pid=%d, ret=%d\n",
task_pid_nr(current), retcode); current->comm, task_pid_nr(current), retcode);
return retcode; return retcode;
} }
EXPORT_SYMBOL(drm_ioctl); EXPORT_SYMBOL(drm_ioctl);

View File

@@ -213,11 +213,11 @@ static struct drm_master *drm_lease_create(struct drm_master *lessor, struct idr
int id; int id;
void *entry; void *entry;
DRM_DEBUG_LEASE("lessor %d\n", lessor->lessee_id); drm_dbg_lease(dev, "lessor %d\n", lessor->lessee_id);
lessee = drm_master_create(lessor->dev); lessee = drm_master_create(lessor->dev);
if (!lessee) { if (!lessee) {
DRM_DEBUG_LEASE("drm_master_create failed\n"); drm_dbg_lease(dev, "drm_master_create failed\n");
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
} }
@@ -231,7 +231,7 @@ static struct drm_master *drm_lease_create(struct drm_master *lessor, struct idr
error = -EBUSY; error = -EBUSY;
if (error != 0) { if (error != 0) {
DRM_DEBUG_LEASE("object %d failed %d\n", object, error); drm_dbg_lease(dev, "object %d failed %d\n", object, error);
goto out_lessee; goto out_lessee;
} }
} }
@@ -249,7 +249,8 @@ static struct drm_master *drm_lease_create(struct drm_master *lessor, struct idr
/* Move the leases over */ /* Move the leases over */
lessee->leases = *leases; lessee->leases = *leases;
DRM_DEBUG_LEASE("new lessee %d %p, lessor %d %p\n", lessee->lessee_id, lessee, lessor->lessee_id, lessor); drm_dbg_lease(dev, "new lessee %d %p, lessor %d %p\n",
lessee->lessee_id, lessee, lessor->lessee_id, lessor);
mutex_unlock(&dev->mode_config.idr_mutex); mutex_unlock(&dev->mode_config.idr_mutex);
return lessee; return lessee;
@@ -268,7 +269,7 @@ void drm_lease_destroy(struct drm_master *master)
mutex_lock(&dev->mode_config.idr_mutex); mutex_lock(&dev->mode_config.idr_mutex);
DRM_DEBUG_LEASE("drm_lease_destroy %d\n", master->lessee_id); drm_dbg_lease(dev, "drm_lease_destroy %d\n", master->lessee_id);
/* This master is referenced by all lessees, hence it cannot be destroyed /* This master is referenced by all lessees, hence it cannot be destroyed
* until all of them have been * until all of them have been
@@ -277,7 +278,8 @@ void drm_lease_destroy(struct drm_master *master)
/* Remove this master from the lessee idr in the owner */ /* Remove this master from the lessee idr in the owner */
if (master->lessee_id != 0) { if (master->lessee_id != 0) {
DRM_DEBUG_LEASE("remove master %d from device list of lessees\n", master->lessee_id); drm_dbg_lease(dev, "remove master %d from device list of lessees\n",
master->lessee_id);
idr_remove(&(drm_lease_owner(master)->lessee_idr), master->lessee_id); idr_remove(&(drm_lease_owner(master)->lessee_idr), master->lessee_id);
} }
@@ -292,7 +294,7 @@ void drm_lease_destroy(struct drm_master *master)
drm_master_put(&master->lessor); drm_master_put(&master->lessor);
} }
DRM_DEBUG_LEASE("drm_lease_destroy done %d\n", master->lessee_id); drm_dbg_lease(dev, "drm_lease_destroy done %d\n", master->lessee_id);
} }
static void _drm_lease_revoke(struct drm_master *top) static void _drm_lease_revoke(struct drm_master *top)
@@ -308,7 +310,8 @@ static void _drm_lease_revoke(struct drm_master *top)
* the tree is fully connected, we can do this without recursing * the tree is fully connected, we can do this without recursing
*/ */
for (;;) { for (;;) {
DRM_DEBUG_LEASE("revoke leases for %p %d\n", master, master->lessee_id); drm_dbg_lease(master->dev, "revoke leases for %p %d\n",
master, master->lessee_id);
/* Evacuate the lease */ /* Evacuate the lease */
idr_for_each_entry(&master->leases, entry, object) idr_for_each_entry(&master->leases, entry, object)
@@ -408,7 +411,7 @@ static int fill_object_idr(struct drm_device *dev,
ret = validate_lease(dev, object_count, objects, universal_planes); ret = validate_lease(dev, object_count, objects, universal_planes);
if (ret) { if (ret) {
DRM_DEBUG_LEASE("lease validation failed\n"); drm_dbg_lease(dev, "lease validation failed\n");
goto out_free_objects; goto out_free_objects;
} }
@@ -418,7 +421,7 @@ static int fill_object_idr(struct drm_device *dev,
struct drm_mode_object *obj = objects[o]; struct drm_mode_object *obj = objects[o];
u32 object_id = objects[o]->id; u32 object_id = objects[o]->id;
DRM_DEBUG_LEASE("Adding object %d to lease\n", object_id); drm_dbg_lease(dev, "Adding object %d to lease\n", object_id);
/* /*
* We're using an IDR to hold the set of leased * We're using an IDR to hold the set of leased
@@ -430,8 +433,8 @@ static int fill_object_idr(struct drm_device *dev,
*/ */
ret = idr_alloc(leases, &drm_lease_idr_object , object_id, object_id + 1, GFP_KERNEL); ret = idr_alloc(leases, &drm_lease_idr_object , object_id, object_id + 1, GFP_KERNEL);
if (ret < 0) { if (ret < 0) {
DRM_DEBUG_LEASE("Object %d cannot be inserted into leases (%d)\n", drm_dbg_lease(dev, "Object %d cannot be inserted into leases (%d)\n",
object_id, ret); object_id, ret);
goto out_free_objects; goto out_free_objects;
} }
if (obj->type == DRM_MODE_OBJECT_CRTC && !universal_planes) { if (obj->type == DRM_MODE_OBJECT_CRTC && !universal_planes) {
@@ -439,15 +442,15 @@ static int fill_object_idr(struct drm_device *dev,
ret = idr_alloc(leases, &drm_lease_idr_object, crtc->primary->base.id, crtc->primary->base.id + 1, GFP_KERNEL); ret = idr_alloc(leases, &drm_lease_idr_object, crtc->primary->base.id, crtc->primary->base.id + 1, GFP_KERNEL);
if (ret < 0) { if (ret < 0) {
DRM_DEBUG_LEASE("Object primary plane %d cannot be inserted into leases (%d)\n", drm_dbg_lease(dev, "Object primary plane %d cannot be inserted into leases (%d)\n",
object_id, ret); object_id, ret);
goto out_free_objects; goto out_free_objects;
} }
if (crtc->cursor) { if (crtc->cursor) {
ret = idr_alloc(leases, &drm_lease_idr_object, crtc->cursor->base.id, crtc->cursor->base.id + 1, GFP_KERNEL); ret = idr_alloc(leases, &drm_lease_idr_object, crtc->cursor->base.id, crtc->cursor->base.id + 1, GFP_KERNEL);
if (ret < 0) { if (ret < 0) {
DRM_DEBUG_LEASE("Object cursor plane %d cannot be inserted into leases (%d)\n", drm_dbg_lease(dev, "Object cursor plane %d cannot be inserted into leases (%d)\n",
object_id, ret); object_id, ret);
goto out_free_objects; goto out_free_objects;
} }
} }
@@ -490,14 +493,14 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev,
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (cl->flags && (cl->flags & ~(O_CLOEXEC | O_NONBLOCK))) { if (cl->flags && (cl->flags & ~(O_CLOEXEC | O_NONBLOCK))) {
DRM_DEBUG_LEASE("invalid flags\n"); drm_dbg_lease(dev, "invalid flags\n");
return -EINVAL; return -EINVAL;
} }
lessor = drm_file_get_master(lessor_priv); lessor = drm_file_get_master(lessor_priv);
/* Do not allow sub-leases */ /* Do not allow sub-leases */
if (lessor->lessor) { if (lessor->lessor) {
DRM_DEBUG_LEASE("recursive leasing not allowed\n"); drm_dbg_lease(dev, "recursive leasing not allowed\n");
ret = -EINVAL; ret = -EINVAL;
goto out_lessor; goto out_lessor;
} }
@@ -520,7 +523,7 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev,
object_count, object_ids); object_count, object_ids);
kfree(object_ids); kfree(object_ids);
if (ret) { if (ret) {
DRM_DEBUG_LEASE("lease object lookup failed: %i\n", ret); drm_dbg_lease(dev, "lease object lookup failed: %i\n", ret);
idr_destroy(&leases); idr_destroy(&leases);
goto out_lessor; goto out_lessor;
} }
@@ -534,7 +537,7 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev,
goto out_lessor; goto out_lessor;
} }
DRM_DEBUG_LEASE("Creating lease\n"); drm_dbg_lease(dev, "Creating lease\n");
/* lessee will take the ownership of leases */ /* lessee will take the ownership of leases */
lessee = drm_lease_create(lessor, &leases); lessee = drm_lease_create(lessor, &leases);
@@ -545,7 +548,7 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev,
} }
/* Clone the lessor file to create a new file for us */ /* Clone the lessor file to create a new file for us */
DRM_DEBUG_LEASE("Allocating lease file\n"); drm_dbg_lease(dev, "Allocating lease file\n");
lessee_file = file_clone_open(lessor_file); lessee_file = file_clone_open(lessor_file);
if (IS_ERR(lessee_file)) { if (IS_ERR(lessee_file)) {
ret = PTR_ERR(lessee_file); ret = PTR_ERR(lessee_file);
@@ -560,7 +563,7 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev,
lessee_priv->authenticated = 1; lessee_priv->authenticated = 1;
/* Pass fd back to userspace */ /* Pass fd back to userspace */
DRM_DEBUG_LEASE("Returning fd %d id %d\n", fd, lessee->lessee_id); drm_dbg_lease(dev, "Returning fd %d id %d\n", fd, lessee->lessee_id);
cl->fd = fd; cl->fd = fd;
cl->lessee_id = lessee->lessee_id; cl->lessee_id = lessee->lessee_id;
@@ -568,7 +571,7 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev,
fd_install(fd, lessee_file); fd_install(fd, lessee_file);
drm_master_put(&lessor); drm_master_put(&lessor);
DRM_DEBUG_LEASE("drm_mode_create_lease_ioctl succeeded\n"); drm_dbg_lease(dev, "drm_mode_create_lease_ioctl succeeded\n");
return 0; return 0;
out_lessee: out_lessee:
@@ -579,7 +582,7 @@ out_leases:
out_lessor: out_lessor:
drm_master_put(&lessor); drm_master_put(&lessor);
DRM_DEBUG_LEASE("drm_mode_create_lease_ioctl failed: %d\n", ret); drm_dbg_lease(dev, "drm_mode_create_lease_ioctl failed: %d\n", ret);
return ret; return ret;
} }
@@ -601,7 +604,7 @@ int drm_mode_list_lessees_ioctl(struct drm_device *dev,
return -EOPNOTSUPP; return -EOPNOTSUPP;
lessor = drm_file_get_master(lessor_priv); lessor = drm_file_get_master(lessor_priv);
DRM_DEBUG_LEASE("List lessees for %d\n", lessor->lessee_id); drm_dbg_lease(dev, "List lessees for %d\n", lessor->lessee_id);
mutex_lock(&dev->mode_config.idr_mutex); mutex_lock(&dev->mode_config.idr_mutex);
@@ -610,7 +613,8 @@ int drm_mode_list_lessees_ioctl(struct drm_device *dev,
/* Only list un-revoked leases */ /* Only list un-revoked leases */
if (!idr_is_empty(&lessee->leases)) { if (!idr_is_empty(&lessee->leases)) {
if (count_lessees > count) { if (count_lessees > count) {
DRM_DEBUG_LEASE("Add lessee %d\n", lessee->lessee_id); drm_dbg_lease(dev, "Add lessee %d\n",
lessee->lessee_id);
ret = put_user(lessee->lessee_id, lessee_ids + count); ret = put_user(lessee->lessee_id, lessee_ids + count);
if (ret) if (ret)
break; break;
@@ -619,7 +623,7 @@ int drm_mode_list_lessees_ioctl(struct drm_device *dev,
} }
} }
DRM_DEBUG_LEASE("Lessor leases to %d\n", count); drm_dbg_lease(dev, "Lessor leases to %d\n", count);
if (ret == 0) if (ret == 0)
arg->count_lessees = count; arg->count_lessees = count;
@@ -651,7 +655,7 @@ int drm_mode_get_lease_ioctl(struct drm_device *dev,
return -EOPNOTSUPP; return -EOPNOTSUPP;
lessee = drm_file_get_master(lessee_priv); lessee = drm_file_get_master(lessee_priv);
DRM_DEBUG_LEASE("get lease for %d\n", lessee->lessee_id); drm_dbg_lease(dev, "get lease for %d\n", lessee->lessee_id);
mutex_lock(&dev->mode_config.idr_mutex); mutex_lock(&dev->mode_config.idr_mutex);
@@ -665,7 +669,7 @@ int drm_mode_get_lease_ioctl(struct drm_device *dev,
count = 0; count = 0;
idr_for_each_entry(object_idr, entry, object) { idr_for_each_entry(object_idr, entry, object) {
if (count_objects > count) { if (count_objects > count) {
DRM_DEBUG_LEASE("adding object %d\n", object); drm_dbg_lease(dev, "adding object %d\n", object);
ret = put_user(object, object_ids + count); ret = put_user(object, object_ids + count);
if (ret) if (ret)
break; break;
@@ -696,7 +700,7 @@ int drm_mode_revoke_lease_ioctl(struct drm_device *dev,
struct drm_master *lessee; struct drm_master *lessee;
int ret = 0; int ret = 0;
DRM_DEBUG_LEASE("revoke lease for %d\n", arg->lessee_id); drm_dbg_lease(dev, "revoke lease for %d\n", arg->lessee_id);
/* Can't lease without MODESET */ /* Can't lease without MODESET */
if (!drm_core_check_feature(dev, DRIVER_MODESET)) if (!drm_core_check_feature(dev, DRIVER_MODESET))

View File

@@ -46,6 +46,11 @@
* properties that specify how the pixels are positioned and blended, like * properties that specify how the pixels are positioned and blended, like
* rotation or Z-position. All these properties are stored in &drm_plane_state. * rotation or Z-position. All these properties are stored in &drm_plane_state.
* *
* Unless explicitly specified (via CRTC property or otherwise), the active area
* of a CRTC will be black by default. This means portions of the active area
* which are not covered by a plane will be black, and alpha blending of any
* planes with the CRTC background will blend with black at the lowest zpos.
*
* To create a plane, a KMS drivers allocates and zeroes an instances of * To create a plane, a KMS drivers allocates and zeroes an instances of
* &struct drm_plane (possibly as part of a larger structure) and registers it * &struct drm_plane (possibly as part of a larger structure) and registers it
* with a call to drm_universal_plane_init(). * with a call to drm_universal_plane_init().

View File

@@ -250,6 +250,12 @@ void drm_kms_helper_poll_enable(struct drm_device *dev)
drm_connector_list_iter_begin(dev, &conn_iter); drm_connector_list_iter_begin(dev, &conn_iter);
drm_for_each_connector_iter(connector, &conn_iter) { drm_for_each_connector_iter(connector, &conn_iter) {
const struct drm_connector_helper_funcs *funcs =
connector->helper_private;
if (funcs && funcs->enable_hpd)
funcs->enable_hpd(connector);
if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT | if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT |
DRM_CONNECTOR_POLL_DISCONNECT)) DRM_CONNECTOR_POLL_DISCONNECT))
poll = true; poll = true;
@@ -802,6 +808,30 @@ bool drm_kms_helper_is_poll_worker(void)
} }
EXPORT_SYMBOL(drm_kms_helper_is_poll_worker); EXPORT_SYMBOL(drm_kms_helper_is_poll_worker);
static void drm_kms_helper_poll_disable_fini(struct drm_device *dev, bool fini)
{
struct drm_connector *connector;
struct drm_connector_list_iter conn_iter;
if (!dev->mode_config.poll_enabled)
return;
if (fini)
dev->mode_config.poll_enabled = false;
drm_connector_list_iter_begin(dev, &conn_iter);
drm_for_each_connector_iter(connector, &conn_iter) {
const struct drm_connector_helper_funcs *funcs =
connector->helper_private;
if (funcs && funcs->disable_hpd)
funcs->disable_hpd(connector);
}
drm_connector_list_iter_end(&conn_iter);
cancel_delayed_work_sync(&dev->mode_config.output_poll_work);
}
/** /**
* drm_kms_helper_poll_disable - disable output polling * drm_kms_helper_poll_disable - disable output polling
* @dev: drm_device * @dev: drm_device
@@ -818,9 +848,7 @@ EXPORT_SYMBOL(drm_kms_helper_is_poll_worker);
*/ */
void drm_kms_helper_poll_disable(struct drm_device *dev) void drm_kms_helper_poll_disable(struct drm_device *dev)
{ {
if (!dev->mode_config.poll_enabled) drm_kms_helper_poll_disable_fini(dev, false);
return;
cancel_delayed_work_sync(&dev->mode_config.output_poll_work);
} }
EXPORT_SYMBOL(drm_kms_helper_poll_disable); EXPORT_SYMBOL(drm_kms_helper_poll_disable);
@@ -858,11 +886,7 @@ EXPORT_SYMBOL(drm_kms_helper_poll_init);
*/ */
void drm_kms_helper_poll_fini(struct drm_device *dev) void drm_kms_helper_poll_fini(struct drm_device *dev)
{ {
if (!dev->mode_config.poll_enabled) drm_kms_helper_poll_disable_fini(dev, true);
return;
dev->mode_config.poll_enabled = false;
cancel_delayed_work_sync(&dev->mode_config.output_poll_work);
} }
EXPORT_SYMBOL(drm_kms_helper_poll_fini); EXPORT_SYMBOL(drm_kms_helper_poll_fini);

View File

@@ -3,6 +3,8 @@ config DRM_GMA500
tristate "Intel GMA500/600/3600/3650 KMS Framebuffer" tristate "Intel GMA500/600/3600/3650 KMS Framebuffer"
depends on DRM && PCI && X86 && MMU depends on DRM && PCI && X86 && MMU
select DRM_KMS_HELPER select DRM_KMS_HELPER
select I2C
select I2C_ALGOBIT
# GMA500 depends on ACPI_VIDEO when ACPI is enabled, just like i915 # GMA500 depends on ACPI_VIDEO when ACPI is enabled, just like i915
select ACPI_VIDEO if ACPI select ACPI_VIDEO if ACPI
select BACKLIGHT_CLASS_DEVICE if ACPI select BACKLIGHT_CLASS_DEVICE if ACPI

View File

@@ -325,8 +325,8 @@ static struct drm_gem_object *gud_gem_prime_import(struct drm_device *drm, struc
static int gud_stats_debugfs(struct seq_file *m, void *data) static int gud_stats_debugfs(struct seq_file *m, void *data)
{ {
struct drm_info_node *node = m->private; struct drm_debugfs_entry *entry = m->private;
struct gud_device *gdrm = to_gud_device(node->minor->dev); struct gud_device *gdrm = to_gud_device(entry->dev);
char buf[10]; char buf[10];
string_get_size(gdrm->bulk_len, 1, STRING_UNITS_2, buf, sizeof(buf)); string_get_size(gdrm->bulk_len, 1, STRING_UNITS_2, buf, sizeof(buf));
@@ -352,16 +352,6 @@ static int gud_stats_debugfs(struct seq_file *m, void *data)
return 0; return 0;
} }
static const struct drm_info_list gud_debugfs_list[] = {
{ "stats", gud_stats_debugfs, 0, NULL },
};
static void gud_debugfs_init(struct drm_minor *minor)
{
drm_debugfs_create_files(gud_debugfs_list, ARRAY_SIZE(gud_debugfs_list),
minor->debugfs_root, minor);
}
static const struct drm_simple_display_pipe_funcs gud_pipe_funcs = { static const struct drm_simple_display_pipe_funcs gud_pipe_funcs = {
.check = gud_pipe_check, .check = gud_pipe_check,
.update = gud_pipe_update, .update = gud_pipe_update,
@@ -386,7 +376,6 @@ static const struct drm_driver gud_drm_driver = {
.fops = &gud_fops, .fops = &gud_fops,
DRM_GEM_SHMEM_DRIVER_OPS, DRM_GEM_SHMEM_DRIVER_OPS,
.gem_prime_import = gud_gem_prime_import, .gem_prime_import = gud_gem_prime_import,
.debugfs_init = gud_debugfs_init,
.name = "gud", .name = "gud",
.desc = "Generic USB Display", .desc = "Generic USB Display",
@@ -623,6 +612,8 @@ static int gud_probe(struct usb_interface *intf, const struct usb_device_id *id)
if (!gdrm->dmadev) if (!gdrm->dmadev)
dev_warn(dev, "buffer sharing not supported"); dev_warn(dev, "buffer sharing not supported");
drm_debugfs_add_file(drm, "stats", gud_stats_debugfs, NULL);
ret = drm_dev_register(drm, 0); ret = drm_dev_register(drm, 0);
if (ret) { if (ret) {
put_device(gdrm->dmadev); put_device(gdrm->dmadev);

View File

@@ -7,6 +7,8 @@ config DRM_HISI_HIBMC
select DRM_VRAM_HELPER select DRM_VRAM_HELPER
select DRM_TTM select DRM_TTM
select DRM_TTM_HELPER select DRM_TTM_HELPER
select I2C
select I2C_ALGOBIT
help help
Choose this option if you have a Hisilicon Hibmc soc chipset. Choose this option if you have a Hisilicon Hibmc soc chipset.
If M is selected the module will be called hibmc-drm. If M is selected the module will be called hibmc-drm.

View File

@@ -386,7 +386,7 @@ static const struct drm_encoder_slave_funcs ch7006_encoder_funcs = {
/* I2C driver functions */ /* I2C driver functions */
static int ch7006_probe(struct i2c_client *client, const struct i2c_device_id *id) static int ch7006_probe(struct i2c_client *client)
{ {
uint8_t addr = CH7006_VERSION_ID; uint8_t addr = CH7006_VERSION_ID;
uint8_t val; uint8_t val;
@@ -495,7 +495,7 @@ static const struct dev_pm_ops ch7006_pm_ops = {
static struct drm_i2c_encoder_driver ch7006_driver = { static struct drm_i2c_encoder_driver ch7006_driver = {
.i2c_driver = { .i2c_driver = {
.probe = ch7006_probe, .probe_new = ch7006_probe,
.remove = ch7006_remove, .remove = ch7006_remove,
.driver = { .driver = {

View File

@@ -350,7 +350,7 @@ static const struct drm_encoder_slave_funcs sil164_encoder_funcs = {
/* I2C driver functions */ /* I2C driver functions */
static int static int
sil164_probe(struct i2c_client *client, const struct i2c_device_id *id) sil164_probe(struct i2c_client *client)
{ {
int vendor = sil164_read(client, SIL164_VENDOR_HI) << 8 | int vendor = sil164_read(client, SIL164_VENDOR_HI) << 8 |
sil164_read(client, SIL164_VENDOR_LO); sil164_read(client, SIL164_VENDOR_LO);
@@ -420,7 +420,7 @@ MODULE_DEVICE_TABLE(i2c, sil164_ids);
static struct drm_i2c_encoder_driver sil164_driver = { static struct drm_i2c_encoder_driver sil164_driver = {
.i2c_driver = { .i2c_driver = {
.probe = sil164_probe, .probe_new = sil164_probe,
.driver = { .driver = {
.name = "sil164", .name = "sil164",
}, },

View File

@@ -375,8 +375,7 @@ static void tda9950_cec_del(void *data)
cec_delete_adapter(priv->adap); cec_delete_adapter(priv->adap);
} }
static int tda9950_probe(struct i2c_client *client, static int tda9950_probe(struct i2c_client *client)
const struct i2c_device_id *id)
{ {
struct tda9950_glue *glue = client->dev.platform_data; struct tda9950_glue *glue = client->dev.platform_data;
struct device *dev = &client->dev; struct device *dev = &client->dev;
@@ -493,7 +492,7 @@ static struct i2c_device_id tda9950_ids[] = {
MODULE_DEVICE_TABLE(i2c, tda9950_ids); MODULE_DEVICE_TABLE(i2c, tda9950_ids);
static struct i2c_driver tda9950_driver = { static struct i2c_driver tda9950_driver = {
.probe = tda9950_probe, .probe_new = tda9950_probe,
.remove = tda9950_remove, .remove = tda9950_remove,
.driver = { .driver = {
.name = "tda9950", .name = "tda9950",

View File

@@ -2059,7 +2059,7 @@ static const struct component_ops tda998x_ops = {
}; };
static int static int
tda998x_probe(struct i2c_client *client, const struct i2c_device_id *id) tda998x_probe(struct i2c_client *client)
{ {
int ret; int ret;
@@ -2099,7 +2099,7 @@ static const struct i2c_device_id tda998x_ids[] = {
MODULE_DEVICE_TABLE(i2c, tda998x_ids); MODULE_DEVICE_TABLE(i2c, tda998x_ids);
static struct i2c_driver tda998x_driver = { static struct i2c_driver tda998x_driver = {
.probe = tda998x_probe, .probe_new = tda998x_probe,
.remove = tda998x_remove, .remove = tda998x_remove,
.driver = { .driver = {
.name = "tda998x", .name = "tda998x",

View File

@@ -18,6 +18,8 @@ config DRM_I915
select DRM_PANEL select DRM_PANEL
select DRM_MIPI_DSI select DRM_MIPI_DSI
select RELAY select RELAY
select I2C
select I2C_ALGOBIT
select IRQ_WORK select IRQ_WORK
# i915 depends on ACPI_VIDEO when ACPI is enabled # i915 depends on ACPI_VIDEO when ACPI is enabled
# but for select to work, need to select ACPI_VIDEO's dependencies, ick # but for select to work, need to select ACPI_VIDEO's dependencies, ick

View File

@@ -253,11 +253,8 @@ static int dcss_dev_suspend(struct device *dev)
{ {
struct dcss_dev *dcss = dcss_drv_dev_to_dcss(dev); struct dcss_dev *dcss = dcss_drv_dev_to_dcss(dev);
struct drm_device *ddev = dcss_drv_dev_to_drm(dev); struct drm_device *ddev = dcss_drv_dev_to_drm(dev);
struct dcss_kms_dev *kms = container_of(ddev, struct dcss_kms_dev, base);
int ret; int ret;
drm_bridge_connector_disable_hpd(kms->connector);
drm_mode_config_helper_suspend(ddev); drm_mode_config_helper_suspend(ddev);
if (pm_runtime_suspended(dev)) if (pm_runtime_suspended(dev))
@@ -276,7 +273,6 @@ static int dcss_dev_resume(struct device *dev)
{ {
struct dcss_dev *dcss = dcss_drv_dev_to_dcss(dev); struct dcss_dev *dcss = dcss_drv_dev_to_dcss(dev);
struct drm_device *ddev = dcss_drv_dev_to_drm(dev); struct drm_device *ddev = dcss_drv_dev_to_drm(dev);
struct dcss_kms_dev *kms = container_of(ddev, struct dcss_kms_dev, base);
if (pm_runtime_suspended(dev)) { if (pm_runtime_suspended(dev)) {
drm_mode_config_helper_resume(ddev); drm_mode_config_helper_resume(ddev);
@@ -291,8 +287,6 @@ static int dcss_dev_resume(struct device *dev)
drm_mode_config_helper_resume(ddev); drm_mode_config_helper_resume(ddev);
drm_bridge_connector_enable_hpd(kms->connector);
return 0; return 0;
} }

View File

@@ -74,8 +74,6 @@ static int dcss_drv_platform_probe(struct platform_device *pdev)
dcss_shutoff: dcss_shutoff:
dcss_dev_destroy(mdrv->dcss); dcss_dev_destroy(mdrv->dcss);
dev_set_drvdata(dev, NULL);
err: err:
kfree(mdrv); kfree(mdrv);
return err; return err;
@@ -85,14 +83,9 @@ static int dcss_drv_platform_remove(struct platform_device *pdev)
{ {
struct dcss_drv *mdrv = dev_get_drvdata(&pdev->dev); struct dcss_drv *mdrv = dev_get_drvdata(&pdev->dev);
if (!mdrv)
return 0;
dcss_kms_detach(mdrv->kms); dcss_kms_detach(mdrv->kms);
dcss_dev_destroy(mdrv->dcss); dcss_dev_destroy(mdrv->dcss);
dev_set_drvdata(&pdev->dev, NULL);
kfree(mdrv); kfree(mdrv);
return 0; return 0;

View File

@@ -150,7 +150,6 @@ struct dcss_kms_dev *dcss_kms_attach(struct dcss_dev *dcss)
return kms; return kms;
cleanup_crtc: cleanup_crtc:
drm_bridge_connector_disable_hpd(kms->connector);
drm_kms_helper_poll_fini(drm); drm_kms_helper_poll_fini(drm);
dcss_crtc_deinit(crtc, drm); dcss_crtc_deinit(crtc, drm);
@@ -166,7 +165,6 @@ void dcss_kms_detach(struct dcss_kms_dev *kms)
struct drm_device *drm = &kms->base; struct drm_device *drm = &kms->base;
drm_dev_unregister(drm); drm_dev_unregister(drm);
drm_bridge_connector_disable_hpd(kms->connector);
drm_kms_helper_poll_fini(drm); drm_kms_helper_poll_fini(drm);
drm_atomic_helper_shutdown(drm); drm_atomic_helper_shutdown(drm);
drm_crtc_vblank_off(&kms->crtc.base); drm_crtc_vblank_off(&kms->crtc.base);

View File

@@ -718,7 +718,7 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
dw_plat_data = &meson_dw_hdmi->dw_plat_data; dw_plat_data = &meson_dw_hdmi->dw_plat_data;
ret = devm_regulator_get_enable_optional(dev, "hdmi"); ret = devm_regulator_get_enable_optional(dev, "hdmi");
if (ret != -ENODEV) if (ret < 0)
return ret; return ret;
meson_dw_hdmi->hdmitx_apb = devm_reset_control_get_exclusive(dev, meson_dw_hdmi->hdmitx_apb = devm_reset_control_get_exclusive(dev,

View File

@@ -4,6 +4,8 @@ config DRM_MGAG200
depends on DRM && PCI && MMU depends on DRM && PCI && MMU
select DRM_GEM_SHMEM_HELPER select DRM_GEM_SHMEM_HELPER
select DRM_KMS_HELPER select DRM_KMS_HELPER
select I2C
select I2C_ALGOBIT
help help
This is a KMS driver for Matrox G200 chips. It supports the original This is a KMS driver for Matrox G200 chips. It supports the original
MGA G200 desktop chips and the server variants. It requires 0.3.0 MGA G200 desktop chips and the server variants. It requires 0.3.0

View File

@@ -203,8 +203,6 @@ int msm_hdmi_modeset_init(struct hdmi *hdmi,
goto fail; goto fail;
} }
drm_bridge_connector_enable_hpd(hdmi->connector);
ret = msm_hdmi_hpd_enable(hdmi->bridge); ret = msm_hdmi_hpd_enable(hdmi->bridge);
if (ret < 0) { if (ret < 0) {
DRM_DEV_ERROR(&hdmi->pdev->dev, "failed to enable HPD: %d\n", ret); DRM_DEV_ERROR(&hdmi->pdev->dev, "failed to enable HPD: %d\n", ret);

View File

@@ -78,14 +78,12 @@ static const struct mxsfb_devdata mxsfb_devdata[] = {
void mxsfb_enable_axi_clk(struct mxsfb_drm_private *mxsfb) void mxsfb_enable_axi_clk(struct mxsfb_drm_private *mxsfb)
{ {
if (mxsfb->clk_axi) clk_prepare_enable(mxsfb->clk_axi);
clk_prepare_enable(mxsfb->clk_axi);
} }
void mxsfb_disable_axi_clk(struct mxsfb_drm_private *mxsfb) void mxsfb_disable_axi_clk(struct mxsfb_drm_private *mxsfb)
{ {
if (mxsfb->clk_axi) clk_disable_unprepare(mxsfb->clk_axi);
clk_disable_unprepare(mxsfb->clk_axi);
} }
static struct drm_framebuffer * static struct drm_framebuffer *
@@ -235,9 +233,9 @@ static int mxsfb_load(struct drm_device *drm,
if (IS_ERR(mxsfb->clk)) if (IS_ERR(mxsfb->clk))
return PTR_ERR(mxsfb->clk); return PTR_ERR(mxsfb->clk);
mxsfb->clk_axi = devm_clk_get(drm->dev, "axi"); mxsfb->clk_axi = devm_clk_get_optional(drm->dev, "axi");
if (IS_ERR(mxsfb->clk_axi)) if (IS_ERR(mxsfb->clk_axi))
mxsfb->clk_axi = NULL; return PTR_ERR(mxsfb->clk_axi);
mxsfb->clk_disp_axi = devm_clk_get(drm->dev, "disp_axi"); mxsfb->clk_disp_axi = devm_clk_get(drm->dev, "disp_axi");
if (IS_ERR(mxsfb->clk_disp_axi)) if (IS_ERR(mxsfb->clk_disp_axi))

View File

@@ -10,6 +10,8 @@ config DRM_NOUVEAU
select DRM_KMS_HELPER select DRM_KMS_HELPER
select DRM_TTM select DRM_TTM
select DRM_TTM_HELPER select DRM_TTM_HELPER
select I2C
select I2C_ALGOBIT
select BACKLIGHT_CLASS_DEVICE if DRM_NOUVEAU_BACKLIGHT select BACKLIGHT_CLASS_DEVICE if DRM_NOUVEAU_BACKLIGHT
select X86_PLATFORM_DEVICES if ACPI && X86 select X86_PLATFORM_DEVICES if ACPI && X86
select ACPI_WMI if ACPI && X86 select ACPI_WMI if ACPI && X86

View File

@@ -545,44 +545,6 @@ static void omap_modeset_fini(struct drm_device *ddev)
drm_mode_config_cleanup(ddev); drm_mode_config_cleanup(ddev);
} }
/*
* Enable the HPD in external components if supported
*/
static void omap_modeset_enable_external_hpd(struct drm_device *ddev)
{
struct omap_drm_private *priv = ddev->dev_private;
unsigned int i;
for (i = 0; i < priv->num_pipes; i++) {
struct drm_connector *connector = priv->pipes[i].connector;
if (!connector)
continue;
if (priv->pipes[i].output->bridge)
drm_bridge_connector_enable_hpd(connector);
}
}
/*
* Disable the HPD in external components if supported
*/
static void omap_modeset_disable_external_hpd(struct drm_device *ddev)
{
struct omap_drm_private *priv = ddev->dev_private;
unsigned int i;
for (i = 0; i < priv->num_pipes; i++) {
struct drm_connector *connector = priv->pipes[i].connector;
if (!connector)
continue;
if (priv->pipes[i].output->bridge)
drm_bridge_connector_disable_hpd(connector);
}
}
/* /*
* drm ioctl funcs * drm ioctl funcs
*/ */
@@ -782,7 +744,6 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev)
omap_fbdev_init(ddev); omap_fbdev_init(ddev);
drm_kms_helper_poll_init(ddev); drm_kms_helper_poll_init(ddev);
omap_modeset_enable_external_hpd(ddev);
/* /*
* Register the DRM device with the core and the connectors with * Register the DRM device with the core and the connectors with
@@ -795,7 +756,6 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev)
return 0; return 0;
err_cleanup_helpers: err_cleanup_helpers:
omap_modeset_disable_external_hpd(ddev);
drm_kms_helper_poll_fini(ddev); drm_kms_helper_poll_fini(ddev);
omap_fbdev_fini(ddev); omap_fbdev_fini(ddev);
@@ -822,7 +782,6 @@ static void omapdrm_cleanup(struct omap_drm_private *priv)
drm_dev_unregister(ddev); drm_dev_unregister(ddev);
omap_modeset_disable_external_hpd(ddev);
drm_kms_helper_poll_fini(ddev); drm_kms_helper_poll_fini(ddev);
omap_fbdev_fini(ddev); omap_fbdev_fini(ddev);

View File

@@ -154,6 +154,18 @@ config DRM_PANEL_FEIYANG_FY07024DI26A30D
Say Y if you want to enable support for panels based on the Say Y if you want to enable support for panels based on the
Feiyang FY07024DI26A30-D MIPI-DSI interface. Feiyang FY07024DI26A30-D MIPI-DSI interface.
config DRM_PANEL_HIMAX_HX8394
tristate "HIMAX HX8394 MIPI-DSI LCD panels"
depends on OF
depends on DRM_MIPI_DSI
depends on BACKLIGHT_CLASS_DEVICE
help
Say Y if you want to enable support for panels based on the
Himax HX8394 controller, such as the HannStar HSD060BHW4
720x1440 TFT LCD panel that uses a MIPI-DSI interface.
If M is selected the module will be called panel-himax-hx8394.
config DRM_PANEL_ILITEK_IL9322 config DRM_PANEL_ILITEK_IL9322
tristate "Ilitek ILI9322 320x240 QVGA panels" tristate "Ilitek ILI9322 320x240 QVGA panels"
depends on OF && SPI depends on OF && SPI
@@ -726,6 +738,14 @@ config DRM_PANEL_VISIONOX_RM69299
Say Y here if you want to enable support for Visionox Say Y here if you want to enable support for Visionox
RM69299 DSI Video Mode panel. RM69299 DSI Video Mode panel.
config DRM_PANEL_VISIONOX_VTDR6130
tristate "Visionox VTDR6130"
depends on OF
depends on DRM_MIPI_DSI
help
Say Y here if you want to enable support for Visionox
VTDR6130 1080x2400 AMOLED DSI panel.
config DRM_PANEL_WIDECHIPS_WS2401 config DRM_PANEL_WIDECHIPS_WS2401
tristate "Widechips WS2401 DPI panel driver" tristate "Widechips WS2401 DPI panel driver"
depends on SPI && GPIOLIB depends on SPI && GPIOLIB

View File

@@ -13,6 +13,7 @@ obj-$(CONFIG_DRM_PANEL_EBBG_FT8719) += panel-ebbg-ft8719.o
obj-$(CONFIG_DRM_PANEL_ELIDA_KD35T133) += panel-elida-kd35t133.o obj-$(CONFIG_DRM_PANEL_ELIDA_KD35T133) += panel-elida-kd35t133.o
obj-$(CONFIG_DRM_PANEL_FEIXIN_K101_IM2BA02) += panel-feixin-k101-im2ba02.o obj-$(CONFIG_DRM_PANEL_FEIXIN_K101_IM2BA02) += panel-feixin-k101-im2ba02.o
obj-$(CONFIG_DRM_PANEL_FEIYANG_FY07024DI26A30D) += panel-feiyang-fy07024di26a30d.o obj-$(CONFIG_DRM_PANEL_FEIYANG_FY07024DI26A30D) += panel-feiyang-fy07024di26a30d.o
obj-$(CONFIG_DRM_PANEL_HIMAX_HX8394) += panel-himax-hx8394.o
obj-$(CONFIG_DRM_PANEL_ILITEK_IL9322) += panel-ilitek-ili9322.o obj-$(CONFIG_DRM_PANEL_ILITEK_IL9322) += panel-ilitek-ili9322.o
obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9341) += panel-ilitek-ili9341.o obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9341) += panel-ilitek-ili9341.o
obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9881C) += panel-ilitek-ili9881c.o obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9881C) += panel-ilitek-ili9881c.o
@@ -74,5 +75,6 @@ obj-$(CONFIG_DRM_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o
obj-$(CONFIG_DRM_PANEL_TPO_TPG110) += panel-tpo-tpg110.o obj-$(CONFIG_DRM_PANEL_TPO_TPG110) += panel-tpo-tpg110.o
obj-$(CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA) += panel-truly-nt35597.o obj-$(CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA) += panel-truly-nt35597.o
obj-$(CONFIG_DRM_PANEL_VISIONOX_RM69299) += panel-visionox-rm69299.o obj-$(CONFIG_DRM_PANEL_VISIONOX_RM69299) += panel-visionox-rm69299.o
obj-$(CONFIG_DRM_PANEL_VISIONOX_VTDR6130) += panel-visionox-vtdr6130.o
obj-$(CONFIG_DRM_PANEL_WIDECHIPS_WS2401) += panel-widechips-ws2401.o obj-$(CONFIG_DRM_PANEL_WIDECHIPS_WS2401) += panel-widechips-ws2401.o
obj-$(CONFIG_DRM_PANEL_XINPENG_XPP055C272) += panel-xinpeng-xpp055c272.o obj-$(CONFIG_DRM_PANEL_XINPENG_XPP055C272) += panel-xinpeng-xpp055c272.o

View File

@@ -24,22 +24,6 @@ static inline struct tm5p5_nt35596 *to_tm5p5_nt35596(struct drm_panel *panel)
return container_of(panel, struct tm5p5_nt35596, panel); return container_of(panel, struct tm5p5_nt35596, panel);
} }
#define dsi_generic_write_seq(dsi, seq...) do { \
static const u8 d[] = { seq }; \
int ret; \
ret = mipi_dsi_generic_write(dsi, d, ARRAY_SIZE(d)); \
if (ret < 0) \
return ret; \
} while (0)
#define dsi_dcs_write_seq(dsi, seq...) do { \
static const u8 d[] = { seq }; \
int ret; \
ret = mipi_dsi_dcs_write_buffer(dsi, d, ARRAY_SIZE(d)); \
if (ret < 0) \
return ret; \
} while (0)
static void tm5p5_nt35596_reset(struct tm5p5_nt35596 *ctx) static void tm5p5_nt35596_reset(struct tm5p5_nt35596 *ctx)
{ {
gpiod_set_value_cansleep(ctx->reset_gpio, 1); gpiod_set_value_cansleep(ctx->reset_gpio, 1);
@@ -54,46 +38,46 @@ static int tm5p5_nt35596_on(struct tm5p5_nt35596 *ctx)
{ {
struct mipi_dsi_device *dsi = ctx->dsi; struct mipi_dsi_device *dsi = ctx->dsi;
dsi_generic_write_seq(dsi, 0xff, 0x05); mipi_dsi_generic_write_seq(dsi, 0xff, 0x05);
dsi_generic_write_seq(dsi, 0xfb, 0x01); mipi_dsi_generic_write_seq(dsi, 0xfb, 0x01);
dsi_generic_write_seq(dsi, 0xc5, 0x31); mipi_dsi_generic_write_seq(dsi, 0xc5, 0x31);
dsi_generic_write_seq(dsi, 0xff, 0x04); mipi_dsi_generic_write_seq(dsi, 0xff, 0x04);
dsi_generic_write_seq(dsi, 0x01, 0x84); mipi_dsi_generic_write_seq(dsi, 0x01, 0x84);
dsi_generic_write_seq(dsi, 0x05, 0x25); mipi_dsi_generic_write_seq(dsi, 0x05, 0x25);
dsi_generic_write_seq(dsi, 0x06, 0x01); mipi_dsi_generic_write_seq(dsi, 0x06, 0x01);
dsi_generic_write_seq(dsi, 0x07, 0x20); mipi_dsi_generic_write_seq(dsi, 0x07, 0x20);
dsi_generic_write_seq(dsi, 0x08, 0x06); mipi_dsi_generic_write_seq(dsi, 0x08, 0x06);
dsi_generic_write_seq(dsi, 0x09, 0x08); mipi_dsi_generic_write_seq(dsi, 0x09, 0x08);
dsi_generic_write_seq(dsi, 0x0a, 0x10); mipi_dsi_generic_write_seq(dsi, 0x0a, 0x10);
dsi_generic_write_seq(dsi, 0x0b, 0x10); mipi_dsi_generic_write_seq(dsi, 0x0b, 0x10);
dsi_generic_write_seq(dsi, 0x0c, 0x10); mipi_dsi_generic_write_seq(dsi, 0x0c, 0x10);
dsi_generic_write_seq(dsi, 0x0d, 0x14); mipi_dsi_generic_write_seq(dsi, 0x0d, 0x14);
dsi_generic_write_seq(dsi, 0x0e, 0x14); mipi_dsi_generic_write_seq(dsi, 0x0e, 0x14);
dsi_generic_write_seq(dsi, 0x0f, 0x14); mipi_dsi_generic_write_seq(dsi, 0x0f, 0x14);
dsi_generic_write_seq(dsi, 0x10, 0x14); mipi_dsi_generic_write_seq(dsi, 0x10, 0x14);
dsi_generic_write_seq(dsi, 0x11, 0x14); mipi_dsi_generic_write_seq(dsi, 0x11, 0x14);
dsi_generic_write_seq(dsi, 0x12, 0x14); mipi_dsi_generic_write_seq(dsi, 0x12, 0x14);
dsi_generic_write_seq(dsi, 0x17, 0xf3); mipi_dsi_generic_write_seq(dsi, 0x17, 0xf3);
dsi_generic_write_seq(dsi, 0x18, 0xc0); mipi_dsi_generic_write_seq(dsi, 0x18, 0xc0);
dsi_generic_write_seq(dsi, 0x19, 0xc0); mipi_dsi_generic_write_seq(dsi, 0x19, 0xc0);
dsi_generic_write_seq(dsi, 0x1a, 0xc0); mipi_dsi_generic_write_seq(dsi, 0x1a, 0xc0);
dsi_generic_write_seq(dsi, 0x1b, 0xb3); mipi_dsi_generic_write_seq(dsi, 0x1b, 0xb3);
dsi_generic_write_seq(dsi, 0x1c, 0xb3); mipi_dsi_generic_write_seq(dsi, 0x1c, 0xb3);
dsi_generic_write_seq(dsi, 0x1d, 0xb3); mipi_dsi_generic_write_seq(dsi, 0x1d, 0xb3);
dsi_generic_write_seq(dsi, 0x1e, 0xb3); mipi_dsi_generic_write_seq(dsi, 0x1e, 0xb3);
dsi_generic_write_seq(dsi, 0x1f, 0xb3); mipi_dsi_generic_write_seq(dsi, 0x1f, 0xb3);
dsi_generic_write_seq(dsi, 0x20, 0xb3); mipi_dsi_generic_write_seq(dsi, 0x20, 0xb3);
dsi_generic_write_seq(dsi, 0xfb, 0x01); mipi_dsi_generic_write_seq(dsi, 0xfb, 0x01);
dsi_generic_write_seq(dsi, 0xff, 0x00); mipi_dsi_generic_write_seq(dsi, 0xff, 0x00);
dsi_generic_write_seq(dsi, 0xfb, 0x01); mipi_dsi_generic_write_seq(dsi, 0xfb, 0x01);
dsi_generic_write_seq(dsi, 0x35, 0x01); mipi_dsi_generic_write_seq(dsi, 0x35, 0x01);
dsi_generic_write_seq(dsi, 0xd3, 0x06); mipi_dsi_generic_write_seq(dsi, 0xd3, 0x06);
dsi_generic_write_seq(dsi, 0xd4, 0x04); mipi_dsi_generic_write_seq(dsi, 0xd4, 0x04);
dsi_generic_write_seq(dsi, 0x5e, 0x0d); mipi_dsi_generic_write_seq(dsi, 0x5e, 0x0d);
dsi_generic_write_seq(dsi, 0x11, 0x00); mipi_dsi_generic_write_seq(dsi, 0x11, 0x00);
msleep(100); msleep(100);
dsi_generic_write_seq(dsi, 0x29, 0x00); mipi_dsi_generic_write_seq(dsi, 0x29, 0x00);
dsi_generic_write_seq(dsi, 0x53, 0x24); mipi_dsi_generic_write_seq(dsi, 0x53, 0x24);
return 0; return 0;
} }
@@ -117,7 +101,7 @@ static int tm5p5_nt35596_off(struct tm5p5_nt35596 *ctx)
return ret; return ret;
} }
dsi_dcs_write_seq(dsi, 0x4f, 0x01); mipi_dsi_dcs_write_seq(dsi, 0x4f, 0x01);
return 0; return 0;
} }

View File

@@ -43,14 +43,6 @@ struct boe_bf060y8m_aj0 *to_boe_bf060y8m_aj0(struct drm_panel *panel)
return container_of(panel, struct boe_bf060y8m_aj0, panel); return container_of(panel, struct boe_bf060y8m_aj0, panel);
} }
#define dsi_dcs_write_seq(dsi, seq...) do { \
static const u8 d[] = { seq }; \
int ret; \
ret = mipi_dsi_dcs_write_buffer(dsi, d, ARRAY_SIZE(d)); \
if (ret < 0) \
return ret; \
} while (0)
static void boe_bf060y8m_aj0_reset(struct boe_bf060y8m_aj0 *boe) static void boe_bf060y8m_aj0_reset(struct boe_bf060y8m_aj0 *boe)
{ {
gpiod_set_value_cansleep(boe->reset_gpio, 0); gpiod_set_value_cansleep(boe->reset_gpio, 0);
@@ -67,12 +59,12 @@ static int boe_bf060y8m_aj0_on(struct boe_bf060y8m_aj0 *boe)
struct device *dev = &dsi->dev; struct device *dev = &dsi->dev;
int ret; int ret;
dsi_dcs_write_seq(dsi, 0xb0, 0xa5, 0x00); mipi_dsi_dcs_write_seq(dsi, 0xb0, 0xa5, 0x00);
dsi_dcs_write_seq(dsi, 0xb2, 0x00, 0x4c); mipi_dsi_dcs_write_seq(dsi, 0xb2, 0x00, 0x4c);
dsi_dcs_write_seq(dsi, MIPI_DCS_SET_3D_CONTROL, 0x10); mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_3D_CONTROL, 0x10);
dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_POWER_SAVE, DCS_ALLOW_HBM_RANGE); mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_POWER_SAVE, DCS_ALLOW_HBM_RANGE);
dsi_dcs_write_seq(dsi, 0xf8, mipi_dsi_dcs_write_seq(dsi, 0xf8,
0x00, 0x08, 0x10, 0x00, 0x22, 0x00, 0x00, 0x2d); 0x00, 0x08, 0x10, 0x00, 0x22, 0x00, 0x00, 0x2d);
ret = mipi_dsi_dcs_exit_sleep_mode(dsi); ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
if (ret < 0) { if (ret < 0) {
@@ -81,17 +73,17 @@ static int boe_bf060y8m_aj0_on(struct boe_bf060y8m_aj0 *boe)
} }
msleep(30); msleep(30);
dsi_dcs_write_seq(dsi, 0xb0, 0xa5, 0x00); mipi_dsi_dcs_write_seq(dsi, 0xb0, 0xa5, 0x00);
dsi_dcs_write_seq(dsi, 0xc0, mipi_dsi_dcs_write_seq(dsi, 0xc0,
0x08, 0x48, 0x65, 0x33, 0x33, 0x33, 0x08, 0x48, 0x65, 0x33, 0x33, 0x33,
0x2a, 0x31, 0x39, 0x20, 0x09); 0x2a, 0x31, 0x39, 0x20, 0x09);
dsi_dcs_write_seq(dsi, 0xc1, 0x00, 0x00, 0x00, 0x1f, 0x1f, mipi_dsi_dcs_write_seq(dsi, 0xc1, 0x00, 0x00, 0x00, 0x1f, 0x1f,
0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f,
0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f); 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f);
dsi_dcs_write_seq(dsi, 0xe2, 0x20, 0x04, 0x10, 0x12, 0x92, mipi_dsi_dcs_write_seq(dsi, 0xe2, 0x20, 0x04, 0x10, 0x12, 0x92,
0x4f, 0x8f, 0x44, 0x84, 0x83, 0x83, 0x83, 0x4f, 0x8f, 0x44, 0x84, 0x83, 0x83, 0x83,
0x5c, 0x5c, 0x5c); 0x5c, 0x5c, 0x5c);
dsi_dcs_write_seq(dsi, 0xde, 0x01, 0x2c, 0x00, 0x77, 0x3e); mipi_dsi_dcs_write_seq(dsi, 0xde, 0x01, 0x2c, 0x00, 0x77, 0x3e);
msleep(30); msleep(30);

View File

@@ -1891,7 +1891,8 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('C', 'M', 'N', 0x1247, &delay_200_500_e80_d50, "N120ACA-EA1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1247, &delay_200_500_e80_d50, "N120ACA-EA1"),
EDP_PANEL_ENTRY('I', 'V', 'O', 0x057d, &delay_200_500_e200, "R140NWF5 RH"), EDP_PANEL_ENTRY('I', 'V', 'O', 0x057d, &delay_200_500_e200, "R140NWF5 RH"),
EDP_PANEL_ENTRY('I', 'V', 'O', 0x854b, &delay_200_500_p2e100, "M133NW4J-R3"), EDP_PANEL_ENTRY('I', 'V', 'O', 0x854a, &delay_200_500_p2e100, "M133NW4J"),
EDP_PANEL_ENTRY('I', 'V', 'O', 0x854b, &delay_200_500_p2e100, "R133NW4K-R0"),
EDP_PANEL_ENTRY('K', 'D', 'B', 0x0624, &kingdisplay_kd116n21_30nv_a010.delay, "116N21-30NV-A010"), EDP_PANEL_ENTRY('K', 'D', 'B', 0x0624, &kingdisplay_kd116n21_30nv_a010.delay, "116N21-30NV-A010"),
EDP_PANEL_ENTRY('K', 'D', 'B', 0x1120, &delay_200_500_e80_d50, "116N29-30NK-C007"), EDP_PANEL_ENTRY('K', 'D', 'B', 0x1120, &delay_200_500_e80_d50, "116N29-30NK-C007"),

View File

@@ -51,14 +51,6 @@ static inline struct kd35t133 *panel_to_kd35t133(struct drm_panel *panel)
return container_of(panel, struct kd35t133, panel); return container_of(panel, struct kd35t133, panel);
} }
#define dsi_dcs_write_seq(dsi, cmd, seq...) do { \
static const u8 b[] = { cmd, seq }; \
int ret; \
ret = mipi_dsi_dcs_write_buffer(dsi, b, ARRAY_SIZE(b)); \
if (ret < 0) \
return ret; \
} while (0)
static int kd35t133_init_sequence(struct kd35t133 *ctx) static int kd35t133_init_sequence(struct kd35t133 *ctx)
{ {
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
@@ -68,25 +60,25 @@ static int kd35t133_init_sequence(struct kd35t133 *ctx)
* Init sequence was supplied by the panel vendor with minimal * Init sequence was supplied by the panel vendor with minimal
* documentation. * documentation.
*/ */
dsi_dcs_write_seq(dsi, KD35T133_CMD_POSITIVEGAMMA, mipi_dsi_dcs_write_seq(dsi, KD35T133_CMD_POSITIVEGAMMA,
0x00, 0x13, 0x18, 0x04, 0x0f, 0x06, 0x3a, 0x56, 0x00, 0x13, 0x18, 0x04, 0x0f, 0x06, 0x3a, 0x56,
0x4d, 0x03, 0x0a, 0x06, 0x30, 0x3e, 0x0f); 0x4d, 0x03, 0x0a, 0x06, 0x30, 0x3e, 0x0f);
dsi_dcs_write_seq(dsi, KD35T133_CMD_NEGATIVEGAMMA, mipi_dsi_dcs_write_seq(dsi, KD35T133_CMD_NEGATIVEGAMMA,
0x00, 0x13, 0x18, 0x01, 0x11, 0x06, 0x38, 0x34, 0x00, 0x13, 0x18, 0x01, 0x11, 0x06, 0x38, 0x34,
0x4d, 0x06, 0x0d, 0x0b, 0x31, 0x37, 0x0f); 0x4d, 0x06, 0x0d, 0x0b, 0x31, 0x37, 0x0f);
dsi_dcs_write_seq(dsi, KD35T133_CMD_POWERCONTROL1, 0x18, 0x17); mipi_dsi_dcs_write_seq(dsi, KD35T133_CMD_POWERCONTROL1, 0x18, 0x17);
dsi_dcs_write_seq(dsi, KD35T133_CMD_POWERCONTROL2, 0x41); mipi_dsi_dcs_write_seq(dsi, KD35T133_CMD_POWERCONTROL2, 0x41);
dsi_dcs_write_seq(dsi, KD35T133_CMD_VCOMCONTROL, 0x00, 0x1a, 0x80); mipi_dsi_dcs_write_seq(dsi, KD35T133_CMD_VCOMCONTROL, 0x00, 0x1a, 0x80);
dsi_dcs_write_seq(dsi, MIPI_DCS_SET_ADDRESS_MODE, 0x48); mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_ADDRESS_MODE, 0x48);
dsi_dcs_write_seq(dsi, MIPI_DCS_SET_PIXEL_FORMAT, 0x55); mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_PIXEL_FORMAT, 0x55);
dsi_dcs_write_seq(dsi, KD35T133_CMD_INTERFACEMODECTRL, 0x00); mipi_dsi_dcs_write_seq(dsi, KD35T133_CMD_INTERFACEMODECTRL, 0x00);
dsi_dcs_write_seq(dsi, KD35T133_CMD_FRAMERATECTRL, 0xa0); mipi_dsi_dcs_write_seq(dsi, KD35T133_CMD_FRAMERATECTRL, 0xa0);
dsi_dcs_write_seq(dsi, KD35T133_CMD_DISPLAYINVERSIONCTRL, 0x02); mipi_dsi_dcs_write_seq(dsi, KD35T133_CMD_DISPLAYINVERSIONCTRL, 0x02);
dsi_dcs_write_seq(dsi, KD35T133_CMD_DISPLAYFUNCTIONCTRL, mipi_dsi_dcs_write_seq(dsi, KD35T133_CMD_DISPLAYFUNCTIONCTRL,
0x20, 0x02); 0x20, 0x02);
dsi_dcs_write_seq(dsi, KD35T133_CMD_SETIMAGEFUNCTION, 0x00); mipi_dsi_dcs_write_seq(dsi, KD35T133_CMD_SETIMAGEFUNCTION, 0x00);
dsi_dcs_write_seq(dsi, KD35T133_CMD_ADJUSTCONTROL3, mipi_dsi_dcs_write_seq(dsi, KD35T133_CMD_ADJUSTCONTROL3,
0xa9, 0x51, 0x2c, 0x82); 0xa9, 0x51, 0x2c, 0x82);
mipi_dsi_dcs_write(dsi, MIPI_DCS_ENTER_INVERT_MODE, NULL, 0); mipi_dsi_dcs_write(dsi, MIPI_DCS_ENTER_INVERT_MODE, NULL, 0);
dev_dbg(dev, "Panel init sequence done\n"); dev_dbg(dev, "Panel init sequence done\n");

View File

@@ -0,0 +1,451 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Driver for panels based on Himax HX8394 controller, such as:
*
* - HannStar HSD060BHW4 5.99" MIPI-DSI panel
*
* Copyright (C) 2021 Kamil Trzciński
*
* Based on drivers/gpu/drm/panel/panel-sitronix-st7703.c
* Copyright (C) Purism SPC 2019
*/
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/media-bus-format.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/regulator/consumer.h>
#include <video/mipi_display.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
#define DRV_NAME "panel-himax-hx8394"
/* Manufacturer specific commands sent via DSI, listed in HX8394-F datasheet */
#define HX8394_CMD_SETSEQUENCE 0xb0
#define HX8394_CMD_SETPOWER 0xb1
#define HX8394_CMD_SETDISP 0xb2
#define HX8394_CMD_SETCYC 0xb4
#define HX8394_CMD_SETVCOM 0xb6
#define HX8394_CMD_SETTE 0xb7
#define HX8394_CMD_SETSENSOR 0xb8
#define HX8394_CMD_SETEXTC 0xb9
#define HX8394_CMD_SETMIPI 0xba
#define HX8394_CMD_SETOTP 0xbb
#define HX8394_CMD_SETREGBANK 0xbd
#define HX8394_CMD_UNKNOWN1 0xc0
#define HX8394_CMD_SETDGCLUT 0xc1
#define HX8394_CMD_SETID 0xc3
#define HX8394_CMD_SETDDB 0xc4
#define HX8394_CMD_UNKNOWN2 0xc6
#define HX8394_CMD_SETCABC 0xc9
#define HX8394_CMD_SETCABCGAIN 0xca
#define HX8394_CMD_SETPANEL 0xcc
#define HX8394_CMD_SETOFFSET 0xd2
#define HX8394_CMD_SETGIP0 0xd3
#define HX8394_CMD_UNKNOWN3 0xd4
#define HX8394_CMD_SETGIP1 0xd5
#define HX8394_CMD_SETGIP2 0xd6
#define HX8394_CMD_SETGPO 0xd6
#define HX8394_CMD_SETSCALING 0xdd
#define HX8394_CMD_SETIDLE 0xdf
#define HX8394_CMD_SETGAMMA 0xe0
#define HX8394_CMD_SETCHEMODE_DYN 0xe4
#define HX8394_CMD_SETCHE 0xe5
#define HX8394_CMD_SETCESEL 0xe6
#define HX8394_CMD_SET_SP_CMD 0xe9
#define HX8394_CMD_SETREADINDEX 0xfe
#define HX8394_CMD_GETSPIREAD 0xff
struct hx8394 {
struct device *dev;
struct drm_panel panel;
struct gpio_desc *reset_gpio;
struct regulator *vcc;
struct regulator *iovcc;
bool prepared;
const struct hx8394_panel_desc *desc;
};
struct hx8394_panel_desc {
const struct drm_display_mode *mode;
unsigned int lanes;
unsigned long mode_flags;
enum mipi_dsi_pixel_format format;
int (*init_sequence)(struct hx8394 *ctx);
};
static inline struct hx8394 *panel_to_hx8394(struct drm_panel *panel)
{
return container_of(panel, struct hx8394, panel);
}
static int hsd060bhw4_init_sequence(struct hx8394 *ctx)
{
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
/* 5.19.8 SETEXTC: Set extension command (B9h) */
mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETEXTC,
0xff, 0x83, 0x94);
/* 5.19.2 SETPOWER: Set power (B1h) */
mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETPOWER,
0x48, 0x11, 0x71, 0x09, 0x32, 0x24, 0x71, 0x31, 0x55, 0x30);
/* 5.19.9 SETMIPI: Set MIPI control (BAh) */
mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETMIPI,
0x63, 0x03, 0x68, 0x6b, 0xb2, 0xc0);
/* 5.19.3 SETDISP: Set display related register (B2h) */
mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETDISP,
0x00, 0x80, 0x78, 0x0c, 0x07);
/* 5.19.4 SETCYC: Set display waveform cycles (B4h) */
mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETCYC,
0x12, 0x63, 0x12, 0x63, 0x12, 0x63, 0x01, 0x0c, 0x7c, 0x55,
0x00, 0x3f, 0x12, 0x6b, 0x12, 0x6b, 0x12, 0x6b, 0x01, 0x0c,
0x7c);
/* 5.19.19 SETGIP0: Set GIP Option0 (D3h) */
mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGIP0,
0x00, 0x00, 0x00, 0x00, 0x3c, 0x1c, 0x00, 0x00, 0x32, 0x10,
0x09, 0x00, 0x09, 0x32, 0x15, 0xad, 0x05, 0xad, 0x32, 0x00,
0x00, 0x00, 0x00, 0x37, 0x03, 0x0b, 0x0b, 0x37, 0x00, 0x00,
0x00, 0x0c, 0x40);
/* 5.19.20 Set GIP Option1 (D5h) */
mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGIP1,
0x19, 0x19, 0x18, 0x18, 0x1b, 0x1b, 0x1a, 0x1a, 0x00, 0x01,
0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x20, 0x21, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x24, 0x25, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18);
/* 5.19.21 Set GIP Option2 (D6h) */
mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGIP2,
0x18, 0x18, 0x19, 0x19, 0x1b, 0x1b, 0x1a, 0x1a, 0x07, 0x06,
0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x25, 0x24, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x21, 0x20, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18);
/* 5.19.25 SETGAMMA: Set gamma curve related setting (E0h) */
mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGAMMA,
0x00, 0x04, 0x0c, 0x12, 0x14, 0x18, 0x1a, 0x18, 0x31, 0x3f,
0x4d, 0x4c, 0x54, 0x65, 0x6b, 0x70, 0x7f, 0x82, 0x7e, 0x8a,
0x99, 0x4a, 0x48, 0x49, 0x4b, 0x4a, 0x4c, 0x4b, 0x7f, 0x00,
0x04, 0x0c, 0x11, 0x13, 0x17, 0x1a, 0x18, 0x31,
0x3f, 0x4d, 0x4c, 0x54, 0x65, 0x6b, 0x70, 0x7f,
0x82, 0x7e, 0x8a, 0x99, 0x4a, 0x48, 0x49, 0x4b,
0x4a, 0x4c, 0x4b, 0x7f);
/* 5.19.17 SETPANEL (CCh) */
mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETPANEL,
0x0b);
/* Unknown command, not listed in the HX8394-F datasheet */
mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN1,
0x1f, 0x31);
/* 5.19.5 SETVCOM: Set VCOM voltage (B6h) */
mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETVCOM,
0x7d, 0x7d);
/* Unknown command, not listed in the HX8394-F datasheet */
mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN3,
0x02);
/* 5.19.11 Set register bank (BDh) */
mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETREGBANK,
0x01);
/* 5.19.2 SETPOWER: Set power (B1h) */
mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETPOWER,
0x00);
/* 5.19.11 Set register bank (BDh) */
mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETREGBANK,
0x00);
/* Unknown command, not listed in the HX8394-F datasheet */
mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN3,
0xed);
return 0;
}
static const struct drm_display_mode hsd060bhw4_mode = {
.hdisplay = 720,
.hsync_start = 720 + 40,
.hsync_end = 720 + 40 + 46,
.htotal = 720 + 40 + 46 + 40,
.vdisplay = 1440,
.vsync_start = 1440 + 9,
.vsync_end = 1440 + 9 + 7,
.vtotal = 1440 + 9 + 7 + 7,
.clock = 74250,
.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
.width_mm = 68,
.height_mm = 136,
};
static const struct hx8394_panel_desc hsd060bhw4_desc = {
.mode = &hsd060bhw4_mode,
.lanes = 4,
.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST,
.format = MIPI_DSI_FMT_RGB888,
.init_sequence = hsd060bhw4_init_sequence,
};
static int hx8394_enable(struct drm_panel *panel)
{
struct hx8394 *ctx = panel_to_hx8394(panel);
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
int ret;
ret = ctx->desc->init_sequence(ctx);
if (ret) {
dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret);
return ret;
}
ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
if (ret) {
dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret);
return ret;
}
/* Panel is operational 120 msec after reset */
msleep(120);
ret = mipi_dsi_dcs_set_display_on(dsi);
if (ret) {
dev_err(ctx->dev, "Failed to turn on the display: %d\n", ret);
goto sleep_in;
}
return 0;
sleep_in:
/* This will probably fail, but let's try orderly power off anyway. */
ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
if (!ret)
msleep(50);
return ret;
}
static int hx8394_disable(struct drm_panel *panel)
{
struct hx8394 *ctx = panel_to_hx8394(panel);
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
int ret;
ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
if (ret) {
dev_err(ctx->dev, "Failed to enter sleep mode: %d\n", ret);
return ret;
}
msleep(50); /* about 3 frames */
return 0;
}
static int hx8394_unprepare(struct drm_panel *panel)
{
struct hx8394 *ctx = panel_to_hx8394(panel);
if (!ctx->prepared)
return 0;
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
regulator_disable(ctx->iovcc);
regulator_disable(ctx->vcc);
ctx->prepared = false;
return 0;
}
static int hx8394_prepare(struct drm_panel *panel)
{
struct hx8394 *ctx = panel_to_hx8394(panel);
int ret;
if (ctx->prepared)
return 0;
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
ret = regulator_enable(ctx->vcc);
if (ret) {
dev_err(ctx->dev, "Failed to enable vcc supply: %d\n", ret);
return ret;
}
ret = regulator_enable(ctx->iovcc);
if (ret) {
dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret);
goto disable_vcc;
}
gpiod_set_value_cansleep(ctx->reset_gpio, 0);
msleep(180);
ctx->prepared = true;
return 0;
disable_vcc:
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
regulator_disable(ctx->vcc);
return ret;
}
static int hx8394_get_modes(struct drm_panel *panel,
struct drm_connector *connector)
{
struct hx8394 *ctx = panel_to_hx8394(panel);
struct drm_display_mode *mode;
mode = drm_mode_duplicate(connector->dev, ctx->desc->mode);
if (!mode) {
dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n",
ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
drm_mode_vrefresh(ctx->desc->mode));
return -ENOMEM;
}
drm_mode_set_name(mode);
mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
connector->display_info.width_mm = mode->width_mm;
connector->display_info.height_mm = mode->height_mm;
drm_mode_probed_add(connector, mode);
return 1;
}
static const struct drm_panel_funcs hx8394_drm_funcs = {
.disable = hx8394_disable,
.unprepare = hx8394_unprepare,
.prepare = hx8394_prepare,
.enable = hx8394_enable,
.get_modes = hx8394_get_modes,
};
static int hx8394_probe(struct mipi_dsi_device *dsi)
{
struct device *dev = &dsi->dev;
struct hx8394 *ctx;
int ret;
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(ctx->reset_gpio))
return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
"Failed to get reset gpio\n");
mipi_dsi_set_drvdata(dsi, ctx);
ctx->dev = dev;
ctx->desc = of_device_get_match_data(dev);
dsi->mode_flags = ctx->desc->mode_flags;
dsi->format = ctx->desc->format;
dsi->lanes = ctx->desc->lanes;
ctx->vcc = devm_regulator_get(dev, "vcc");
if (IS_ERR(ctx->vcc))
return dev_err_probe(dev, PTR_ERR(ctx->vcc),
"Failed to request vcc regulator\n");
ctx->iovcc = devm_regulator_get(dev, "iovcc");
if (IS_ERR(ctx->iovcc))
return dev_err_probe(dev, PTR_ERR(ctx->iovcc),
"Failed to request iovcc regulator\n");
drm_panel_init(&ctx->panel, dev, &hx8394_drm_funcs,
DRM_MODE_CONNECTOR_DSI);
ret = drm_panel_of_backlight(&ctx->panel);
if (ret)
return ret;
drm_panel_add(&ctx->panel);
ret = mipi_dsi_attach(dsi);
if (ret < 0) {
dev_err_probe(dev, ret, "mipi_dsi_attach failed\n");
drm_panel_remove(&ctx->panel);
return ret;
}
dev_dbg(dev, "%ux%u@%u %ubpp dsi %udl - ready\n",
ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
drm_mode_vrefresh(ctx->desc->mode),
mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes);
return 0;
}
static void hx8394_shutdown(struct mipi_dsi_device *dsi)
{
struct hx8394 *ctx = mipi_dsi_get_drvdata(dsi);
int ret;
ret = drm_panel_disable(&ctx->panel);
if (ret < 0)
dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret);
ret = drm_panel_unprepare(&ctx->panel);
if (ret < 0)
dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret);
}
static void hx8394_remove(struct mipi_dsi_device *dsi)
{
struct hx8394 *ctx = mipi_dsi_get_drvdata(dsi);
int ret;
hx8394_shutdown(dsi);
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 hx8394_of_match[] = {
{ .compatible = "hannstar,hsd060bhw4", .data = &hsd060bhw4_desc },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, hx8394_of_match);
static struct mipi_dsi_driver hx8394_driver = {
.probe = hx8394_probe,
.remove = hx8394_remove,
.shutdown = hx8394_shutdown,
.driver = {
.name = DRV_NAME,
.of_match_table = hx8394_of_match,
},
};
module_mipi_dsi_driver(hx8394_driver);
MODULE_AUTHOR("Kamil Trzciński <ayufan@ayufan.eu>");
MODULE_DESCRIPTION("DRM driver for Himax HX8394 based MIPI DSI panels");
MODULE_LICENSE("GPL");

View File

@@ -29,22 +29,6 @@ static inline struct jdi_fhd_r63452 *to_jdi_fhd_r63452(struct drm_panel *panel)
return container_of(panel, struct jdi_fhd_r63452, panel); return container_of(panel, struct jdi_fhd_r63452, panel);
} }
#define dsi_generic_write_seq(dsi, seq...) do { \
static const u8 d[] = { seq }; \
int ret; \
ret = mipi_dsi_generic_write(dsi, d, ARRAY_SIZE(d)); \
if (ret < 0) \
return ret; \
} while (0)
#define dsi_dcs_write_seq(dsi, seq...) do { \
static const u8 d[] = { seq }; \
int ret; \
ret = mipi_dsi_dcs_write_buffer(dsi, d, ARRAY_SIZE(d)); \
if (ret < 0) \
return ret; \
} while (0)
static void jdi_fhd_r63452_reset(struct jdi_fhd_r63452 *ctx) static void jdi_fhd_r63452_reset(struct jdi_fhd_r63452 *ctx)
{ {
gpiod_set_value_cansleep(ctx->reset_gpio, 0); gpiod_set_value_cansleep(ctx->reset_gpio, 0);
@@ -63,12 +47,12 @@ static int jdi_fhd_r63452_on(struct jdi_fhd_r63452 *ctx)
dsi->mode_flags |= MIPI_DSI_MODE_LPM; dsi->mode_flags |= MIPI_DSI_MODE_LPM;
dsi_generic_write_seq(dsi, 0xb0, 0x00); mipi_dsi_generic_write_seq(dsi, 0xb0, 0x00);
dsi_generic_write_seq(dsi, 0xd6, 0x01); mipi_dsi_generic_write_seq(dsi, 0xd6, 0x01);
dsi_generic_write_seq(dsi, 0xec, mipi_dsi_generic_write_seq(dsi, 0xec,
0x64, 0xdc, 0xec, 0x3b, 0x52, 0x00, 0x0b, 0x0b, 0x64, 0xdc, 0xec, 0x3b, 0x52, 0x00, 0x0b, 0x0b,
0x13, 0x15, 0x68, 0x0b, 0xb5); 0x13, 0x15, 0x68, 0x0b, 0xb5);
dsi_generic_write_seq(dsi, 0xb0, 0x03); mipi_dsi_generic_write_seq(dsi, 0xb0, 0x03);
ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK); ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
if (ret < 0) { if (ret < 0) {
@@ -76,7 +60,7 @@ static int jdi_fhd_r63452_on(struct jdi_fhd_r63452 *ctx)
return ret; return ret;
} }
dsi_dcs_write_seq(dsi, MIPI_DCS_SET_ADDRESS_MODE, 0x00); mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_ADDRESS_MODE, 0x00);
ret = mipi_dsi_dcs_set_pixel_format(dsi, 0x77); ret = mipi_dsi_dcs_set_pixel_format(dsi, 0x77);
if (ret < 0) { if (ret < 0) {
@@ -108,10 +92,10 @@ static int jdi_fhd_r63452_on(struct jdi_fhd_r63452 *ctx)
return ret; return ret;
} }
dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x24); mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x24);
dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_POWER_SAVE, 0x00); mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_POWER_SAVE, 0x00);
dsi_dcs_write_seq(dsi, MIPI_DCS_SET_CABC_MIN_BRIGHTNESS, 0x00); mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_CABC_MIN_BRIGHTNESS, 0x00);
dsi_dcs_write_seq(dsi, 0x84, 0x00); mipi_dsi_dcs_write_seq(dsi, 0x84, 0x00);
ret = mipi_dsi_dcs_set_display_on(dsi); ret = mipi_dsi_dcs_set_display_on(dsi);
if (ret < 0) { if (ret < 0) {
@@ -127,10 +111,10 @@ static int jdi_fhd_r63452_on(struct jdi_fhd_r63452 *ctx)
} }
msleep(80); msleep(80);
dsi_generic_write_seq(dsi, 0xb0, 0x04); mipi_dsi_generic_write_seq(dsi, 0xb0, 0x04);
dsi_dcs_write_seq(dsi, 0x84, 0x00); mipi_dsi_dcs_write_seq(dsi, 0x84, 0x00);
dsi_generic_write_seq(dsi, 0xc8, 0x11); mipi_dsi_generic_write_seq(dsi, 0xc8, 0x11);
dsi_generic_write_seq(dsi, 0xb0, 0x03); mipi_dsi_generic_write_seq(dsi, 0xb0, 0x03);
return 0; return 0;
} }
@@ -143,12 +127,12 @@ static int jdi_fhd_r63452_off(struct jdi_fhd_r63452 *ctx)
dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
dsi_generic_write_seq(dsi, 0xb0, 0x00); mipi_dsi_generic_write_seq(dsi, 0xb0, 0x00);
dsi_generic_write_seq(dsi, 0xd6, 0x01); mipi_dsi_generic_write_seq(dsi, 0xd6, 0x01);
dsi_generic_write_seq(dsi, 0xec, mipi_dsi_generic_write_seq(dsi, 0xec,
0x64, 0xdc, 0xec, 0x3b, 0x52, 0x00, 0x0b, 0x0b, 0x64, 0xdc, 0xec, 0x3b, 0x52, 0x00, 0x0b, 0x0b,
0x13, 0x15, 0x68, 0x0b, 0x95); 0x13, 0x15, 0x68, 0x0b, 0x95);
dsi_generic_write_seq(dsi, 0xb0, 0x03); mipi_dsi_generic_write_seq(dsi, 0xb0, 0x03);
ret = mipi_dsi_dcs_set_display_off(dsi); ret = mipi_dsi_dcs_set_display_off(dsi);
if (ret < 0) { if (ret < 0) {

View File

@@ -244,14 +244,6 @@ struct ltk050h3146w *panel_to_ltk050h3146w(struct drm_panel *panel)
return container_of(panel, struct ltk050h3146w, panel); return container_of(panel, struct ltk050h3146w, panel);
} }
#define dsi_dcs_write_seq(dsi, cmd, seq...) do { \
static const u8 b[] = { cmd, seq }; \
int ret; \
ret = mipi_dsi_dcs_write_buffer(dsi, b, ARRAY_SIZE(b)); \
if (ret < 0) \
return ret; \
} while (0)
static int ltk050h3146w_init_sequence(struct ltk050h3146w *ctx) static int ltk050h3146w_init_sequence(struct ltk050h3146w *ctx)
{ {
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
@@ -261,55 +253,55 @@ static int ltk050h3146w_init_sequence(struct ltk050h3146w *ctx)
* Init sequence was supplied by the panel vendor without much * Init sequence was supplied by the panel vendor without much
* documentation. * documentation.
*/ */
dsi_dcs_write_seq(dsi, 0xdf, 0x93, 0x65, 0xf8); mipi_dsi_dcs_write_seq(dsi, 0xdf, 0x93, 0x65, 0xf8);
dsi_dcs_write_seq(dsi, 0xb0, 0x01, 0x03, 0x02, 0x00, 0x64, 0x06, mipi_dsi_dcs_write_seq(dsi, 0xb0, 0x01, 0x03, 0x02, 0x00, 0x64, 0x06,
0x01); 0x01);
dsi_dcs_write_seq(dsi, 0xb2, 0x00, 0xb5); mipi_dsi_dcs_write_seq(dsi, 0xb2, 0x00, 0xb5);
dsi_dcs_write_seq(dsi, 0xb3, 0x00, 0xb5); mipi_dsi_dcs_write_seq(dsi, 0xb3, 0x00, 0xb5);
dsi_dcs_write_seq(dsi, 0xb7, 0x00, 0xbf, 0x00, 0x00, 0xbf, 0x00); mipi_dsi_dcs_write_seq(dsi, 0xb7, 0x00, 0xbf, 0x00, 0x00, 0xbf, 0x00);
dsi_dcs_write_seq(dsi, 0xb9, 0x00, 0xc4, 0x23, 0x07); mipi_dsi_dcs_write_seq(dsi, 0xb9, 0x00, 0xc4, 0x23, 0x07);
dsi_dcs_write_seq(dsi, 0xbb, 0x02, 0x01, 0x24, 0x00, 0x28, 0x0f, mipi_dsi_dcs_write_seq(dsi, 0xbb, 0x02, 0x01, 0x24, 0x00, 0x28, 0x0f,
0x28, 0x04, 0xcc, 0xcc, 0xcc); 0x28, 0x04, 0xcc, 0xcc, 0xcc);
dsi_dcs_write_seq(dsi, 0xbc, 0x0f, 0x04); mipi_dsi_dcs_write_seq(dsi, 0xbc, 0x0f, 0x04);
dsi_dcs_write_seq(dsi, 0xbe, 0x1e, 0xf2); mipi_dsi_dcs_write_seq(dsi, 0xbe, 0x1e, 0xf2);
dsi_dcs_write_seq(dsi, 0xc0, 0x26, 0x03); mipi_dsi_dcs_write_seq(dsi, 0xc0, 0x26, 0x03);
dsi_dcs_write_seq(dsi, 0xc1, 0x00, 0x12); mipi_dsi_dcs_write_seq(dsi, 0xc1, 0x00, 0x12);
dsi_dcs_write_seq(dsi, 0xc3, 0x04, 0x02, 0x02, 0x76, 0x01, 0x80, mipi_dsi_dcs_write_seq(dsi, 0xc3, 0x04, 0x02, 0x02, 0x76, 0x01, 0x80,
0x80); 0x80);
dsi_dcs_write_seq(dsi, 0xc4, 0x24, 0x80, 0xb4, 0x81, 0x12, 0x0f, mipi_dsi_dcs_write_seq(dsi, 0xc4, 0x24, 0x80, 0xb4, 0x81, 0x12, 0x0f,
0x16, 0x00, 0x00); 0x16, 0x00, 0x00);
dsi_dcs_write_seq(dsi, 0xc8, 0x7f, 0x72, 0x67, 0x5d, 0x5d, 0x50, mipi_dsi_dcs_write_seq(dsi, 0xc8, 0x7f, 0x72, 0x67, 0x5d, 0x5d, 0x50,
0x56, 0x41, 0x59, 0x57, 0x55, 0x70, 0x5b, 0x5f, 0x56, 0x41, 0x59, 0x57, 0x55, 0x70, 0x5b, 0x5f,
0x4f, 0x47, 0x38, 0x23, 0x08, 0x7f, 0x72, 0x67, 0x4f, 0x47, 0x38, 0x23, 0x08, 0x7f, 0x72, 0x67,
0x5d, 0x5d, 0x50, 0x56, 0x41, 0x59, 0x57, 0x55, 0x5d, 0x5d, 0x50, 0x56, 0x41, 0x59, 0x57, 0x55,
0x70, 0x5b, 0x5f, 0x4f, 0x47, 0x38, 0x23, 0x08); 0x70, 0x5b, 0x5f, 0x4f, 0x47, 0x38, 0x23, 0x08);
dsi_dcs_write_seq(dsi, 0xd0, 0x1e, 0x1f, 0x57, 0x58, 0x48, 0x4a, mipi_dsi_dcs_write_seq(dsi, 0xd0, 0x1e, 0x1f, 0x57, 0x58, 0x48, 0x4a,
0x44, 0x46, 0x40, 0x1f, 0x42, 0x1f, 0x1f, 0x1f, 0x44, 0x46, 0x40, 0x1f, 0x42, 0x1f, 0x1f, 0x1f,
0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f); 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f);
dsi_dcs_write_seq(dsi, 0xd1, 0x1e, 0x1f, 0x57, 0x58, 0x49, 0x4b, mipi_dsi_dcs_write_seq(dsi, 0xd1, 0x1e, 0x1f, 0x57, 0x58, 0x49, 0x4b,
0x45, 0x47, 0x41, 0x1f, 0x43, 0x1f, 0x1f, 0x1f, 0x45, 0x47, 0x41, 0x1f, 0x43, 0x1f, 0x1f, 0x1f,
0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f); 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f);
dsi_dcs_write_seq(dsi, 0xd2, 0x1f, 0x1e, 0x17, 0x18, 0x07, 0x05, mipi_dsi_dcs_write_seq(dsi, 0xd2, 0x1f, 0x1e, 0x17, 0x18, 0x07, 0x05,
0x0b, 0x09, 0x03, 0x1f, 0x01, 0x1f, 0x1f, 0x1f, 0x0b, 0x09, 0x03, 0x1f, 0x01, 0x1f, 0x1f, 0x1f,
0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f); 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f);
dsi_dcs_write_seq(dsi, 0xd3, 0x1f, 0x1e, 0x17, 0x18, 0x06, 0x04, mipi_dsi_dcs_write_seq(dsi, 0xd3, 0x1f, 0x1e, 0x17, 0x18, 0x06, 0x04,
0x0a, 0x08, 0x02, 0x1f, 0x00, 0x1f, 0x1f, 0x1f, 0x0a, 0x08, 0x02, 0x1f, 0x00, 0x1f, 0x1f, 0x1f,
0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f); 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f);
dsi_dcs_write_seq(dsi, 0xd4, 0x00, 0x00, 0x00, 0x0c, 0x06, 0x20, mipi_dsi_dcs_write_seq(dsi, 0xd4, 0x00, 0x00, 0x00, 0x0c, 0x06, 0x20,
0x01, 0x02, 0x00, 0x60, 0x15, 0xb0, 0x30, 0x03, 0x01, 0x02, 0x00, 0x60, 0x15, 0xb0, 0x30, 0x03,
0x04, 0x00, 0x60, 0x72, 0x0a, 0x00, 0x60, 0x08); 0x04, 0x00, 0x60, 0x72, 0x0a, 0x00, 0x60, 0x08);
dsi_dcs_write_seq(dsi, 0xd5, 0x00, 0x06, 0x06, 0x00, 0x30, 0x00, mipi_dsi_dcs_write_seq(dsi, 0xd5, 0x00, 0x06, 0x06, 0x00, 0x30, 0x00,
0x00, 0x00, 0x00, 0x00, 0xbc, 0x50, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x50, 0x00, 0x05,
0x21, 0x00, 0x60); 0x21, 0x00, 0x60);
dsi_dcs_write_seq(dsi, 0xdd, 0x2c, 0xa3, 0x00); mipi_dsi_dcs_write_seq(dsi, 0xdd, 0x2c, 0xa3, 0x00);
dsi_dcs_write_seq(dsi, 0xde, 0x02); mipi_dsi_dcs_write_seq(dsi, 0xde, 0x02);
dsi_dcs_write_seq(dsi, 0xb2, 0x32, 0x1c); mipi_dsi_dcs_write_seq(dsi, 0xb2, 0x32, 0x1c);
dsi_dcs_write_seq(dsi, 0xb7, 0x3b, 0x70, 0x00, 0x04); mipi_dsi_dcs_write_seq(dsi, 0xb7, 0x3b, 0x70, 0x00, 0x04);
dsi_dcs_write_seq(dsi, 0xc1, 0x11); mipi_dsi_dcs_write_seq(dsi, 0xc1, 0x11);
dsi_dcs_write_seq(dsi, 0xbb, 0x21, 0x22, 0x23, 0x24, 0x36, 0x37); mipi_dsi_dcs_write_seq(dsi, 0xbb, 0x21, 0x22, 0x23, 0x24, 0x36, 0x37);
dsi_dcs_write_seq(dsi, 0xc2, 0x20, 0x38, 0x1e, 0x84); mipi_dsi_dcs_write_seq(dsi, 0xc2, 0x20, 0x38, 0x1e, 0x84);
dsi_dcs_write_seq(dsi, 0xde, 0x00); mipi_dsi_dcs_write_seq(dsi, 0xde, 0x00);
ret = mipi_dsi_dcs_set_tear_on(dsi, 1); ret = mipi_dsi_dcs_set_tear_on(dsi, 1);
if (ret < 0) { if (ret < 0) {

View File

@@ -45,14 +45,6 @@ static inline struct mantix *panel_to_mantix(struct drm_panel *panel)
return container_of(panel, struct mantix, panel); return container_of(panel, struct mantix, panel);
} }
#define dsi_generic_write_seq(dsi, seq...) do { \
static const u8 d[] = { seq }; \
int ret; \
ret = mipi_dsi_generic_write(dsi, d, ARRAY_SIZE(d)); \
if (ret < 0) \
return ret; \
} while (0)
static int mantix_init_sequence(struct mantix *ctx) static int mantix_init_sequence(struct mantix *ctx)
{ {
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
@@ -61,18 +53,18 @@ static int mantix_init_sequence(struct mantix *ctx)
/* /*
* Init sequence was supplied by the panel vendor. * Init sequence was supplied by the panel vendor.
*/ */
dsi_generic_write_seq(dsi, MANTIX_CMD_OTP_STOP_RELOAD_MIPI, 0x5A); mipi_dsi_generic_write_seq(dsi, MANTIX_CMD_OTP_STOP_RELOAD_MIPI, 0x5A);
dsi_generic_write_seq(dsi, MANTIX_CMD_INT_CANCEL, 0x03); mipi_dsi_generic_write_seq(dsi, MANTIX_CMD_INT_CANCEL, 0x03);
dsi_generic_write_seq(dsi, MANTIX_CMD_OTP_STOP_RELOAD_MIPI, 0x5A, 0x03); mipi_dsi_generic_write_seq(dsi, MANTIX_CMD_OTP_STOP_RELOAD_MIPI, 0x5A, 0x03);
dsi_generic_write_seq(dsi, 0x80, 0xA9, 0x00); mipi_dsi_generic_write_seq(dsi, 0x80, 0xA9, 0x00);
dsi_generic_write_seq(dsi, MANTIX_CMD_OTP_STOP_RELOAD_MIPI, 0x5A, 0x09); mipi_dsi_generic_write_seq(dsi, MANTIX_CMD_OTP_STOP_RELOAD_MIPI, 0x5A, 0x09);
dsi_generic_write_seq(dsi, 0x80, 0x64, 0x00, 0x64, 0x00, 0x00); mipi_dsi_generic_write_seq(dsi, 0x80, 0x64, 0x00, 0x64, 0x00, 0x00);
msleep(20); msleep(20);
dsi_generic_write_seq(dsi, MANTIX_CMD_SPI_FINISH, 0xA5); mipi_dsi_generic_write_seq(dsi, MANTIX_CMD_SPI_FINISH, 0xA5);
dsi_generic_write_seq(dsi, MANTIX_CMD_OTP_STOP_RELOAD_MIPI, 0x00, 0x2F); mipi_dsi_generic_write_seq(dsi, MANTIX_CMD_OTP_STOP_RELOAD_MIPI, 0x00, 0x2F);
msleep(20); msleep(20);
dev_dbg(dev, "Panel init sequence done\n"); dev_dbg(dev, "Panel init sequence done\n");

View File

@@ -89,14 +89,6 @@ static inline struct nt35950 *to_nt35950(struct drm_panel *panel)
return container_of(panel, struct nt35950, panel); return container_of(panel, struct nt35950, panel);
} }
#define dsi_dcs_write_seq(dsi, seq...) do { \
static const u8 d[] = { seq }; \
int ret; \
ret = mipi_dsi_dcs_write_buffer(dsi, d, ARRAY_SIZE(d)); \
if (ret < 0) \
return ret; \
} while (0)
static void nt35950_reset(struct nt35950 *nt) static void nt35950_reset(struct nt35950 *nt)
{ {
gpiod_set_value_cansleep(nt->reset_gpio, 1); gpiod_set_value_cansleep(nt->reset_gpio, 1);
@@ -338,7 +330,7 @@ static int nt35950_on(struct nt35950 *nt)
return ret; return ret;
/* Unknown command */ /* Unknown command */
dsi_dcs_write_seq(dsi, 0xd4, 0x88, 0x88); mipi_dsi_dcs_write_seq(dsi, 0xd4, 0x88, 0x88);
/* CMD2 Page 7 */ /* CMD2 Page 7 */
ret = nt35950_set_cmd2_page(nt, 7); ret = nt35950_set_cmd2_page(nt, 7);
@@ -346,10 +338,10 @@ static int nt35950_on(struct nt35950 *nt)
return ret; return ret;
/* Enable SubPixel Rendering */ /* Enable SubPixel Rendering */
dsi_dcs_write_seq(dsi, MCS_PARAM_SPR_EN, 0x01); mipi_dsi_dcs_write_seq(dsi, MCS_PARAM_SPR_EN, 0x01);
/* SPR Mode: YYG Rainbow-RGB */ /* SPR Mode: YYG Rainbow-RGB */
dsi_dcs_write_seq(dsi, MCS_PARAM_SPR_MODE, MCS_SPR_MODE_YYG_RAINBOW_RGB); mipi_dsi_dcs_write_seq(dsi, MCS_PARAM_SPR_MODE, MCS_SPR_MODE_YYG_RAINBOW_RGB);
/* CMD3 */ /* CMD3 */
ret = nt35950_inject_black_image(nt); ret = nt35950_inject_black_image(nt);

View File

@@ -202,8 +202,7 @@ static const struct drm_panel_funcs lcd_olinuxino_funcs = {
.get_modes = lcd_olinuxino_get_modes, .get_modes = lcd_olinuxino_get_modes,
}; };
static int lcd_olinuxino_probe(struct i2c_client *client, static int lcd_olinuxino_probe(struct i2c_client *client)
const struct i2c_device_id *id)
{ {
struct device *dev = &client->dev; struct device *dev = &client->dev;
struct lcd_olinuxino *lcd; struct lcd_olinuxino *lcd;
@@ -309,7 +308,7 @@ static struct i2c_driver lcd_olinuxino_driver = {
.name = "lcd_olinuxino", .name = "lcd_olinuxino",
.of_match_table = lcd_olinuxino_of_ids, .of_match_table = lcd_olinuxino_of_ids,
}, },
.probe = lcd_olinuxino_probe, .probe_new = lcd_olinuxino_probe,
.remove = lcd_olinuxino_remove, .remove = lcd_olinuxino_remove,
}; };

View File

@@ -362,8 +362,7 @@ static const struct drm_panel_funcs rpi_touchscreen_funcs = {
.get_modes = rpi_touchscreen_get_modes, .get_modes = rpi_touchscreen_get_modes,
}; };
static int rpi_touchscreen_probe(struct i2c_client *i2c, static int rpi_touchscreen_probe(struct i2c_client *i2c)
const struct i2c_device_id *id)
{ {
struct device *dev = &i2c->dev; struct device *dev = &i2c->dev;
struct rpi_touchscreen *ts; struct rpi_touchscreen *ts;
@@ -491,7 +490,7 @@ static struct i2c_driver rpi_touchscreen_driver = {
.name = "rpi_touchscreen", .name = "rpi_touchscreen",
.of_match_table = rpi_touchscreen_of_ids, .of_match_table = rpi_touchscreen_of_ids,
}, },
.probe = rpi_touchscreen_probe, .probe_new = rpi_touchscreen_probe,
.remove = rpi_touchscreen_remove, .remove = rpi_touchscreen_remove,
}; };

View File

@@ -28,14 +28,6 @@ s6e88a0_ams452ef01 *to_s6e88a0_ams452ef01(struct drm_panel *panel)
return container_of(panel, struct s6e88a0_ams452ef01, panel); return container_of(panel, struct s6e88a0_ams452ef01, panel);
} }
#define dsi_dcs_write_seq(dsi, seq...) do { \
static const u8 d[] = { seq }; \
int ret; \
ret = mipi_dsi_dcs_write_buffer(dsi, d, ARRAY_SIZE(d)); \
if (ret < 0) \
return ret; \
} while (0)
static void s6e88a0_ams452ef01_reset(struct s6e88a0_ams452ef01 *ctx) static void s6e88a0_ams452ef01_reset(struct s6e88a0_ams452ef01 *ctx)
{ {
gpiod_set_value_cansleep(ctx->reset_gpio, 1); gpiod_set_value_cansleep(ctx->reset_gpio, 1);
@@ -54,8 +46,8 @@ static int s6e88a0_ams452ef01_on(struct s6e88a0_ams452ef01 *ctx)
dsi->mode_flags |= MIPI_DSI_MODE_LPM; dsi->mode_flags |= MIPI_DSI_MODE_LPM;
dsi_dcs_write_seq(dsi, 0xf0, 0x5a, 0x5a); // enable LEVEL2 commands mipi_dsi_dcs_write_seq(dsi, 0xf0, 0x5a, 0x5a); // enable LEVEL2 commands
dsi_dcs_write_seq(dsi, 0xcc, 0x4c); // set Pixel Clock Divider polarity mipi_dsi_dcs_write_seq(dsi, 0xcc, 0x4c); // set Pixel Clock Divider polarity
ret = mipi_dsi_dcs_exit_sleep_mode(dsi); ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
if (ret < 0) { if (ret < 0) {
@@ -65,23 +57,23 @@ static int s6e88a0_ams452ef01_on(struct s6e88a0_ams452ef01 *ctx)
msleep(120); msleep(120);
// set default brightness/gama // set default brightness/gama
dsi_dcs_write_seq(dsi, 0xca, mipi_dsi_dcs_write_seq(dsi, 0xca,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, // V255 RR,GG,BB 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, // V255 RR,GG,BB
0x80, 0x80, 0x80, // V203 R,G,B 0x80, 0x80, 0x80, // V203 R,G,B
0x80, 0x80, 0x80, // V151 R,G,B 0x80, 0x80, 0x80, // V151 R,G,B
0x80, 0x80, 0x80, // V87 R,G,B 0x80, 0x80, 0x80, // V87 R,G,B
0x80, 0x80, 0x80, // V51 R,G,B 0x80, 0x80, 0x80, // V51 R,G,B
0x80, 0x80, 0x80, // V35 R,G,B 0x80, 0x80, 0x80, // V35 R,G,B
0x80, 0x80, 0x80, // V23 R,G,B 0x80, 0x80, 0x80, // V23 R,G,B
0x80, 0x80, 0x80, // V11 R,G,B 0x80, 0x80, 0x80, // V11 R,G,B
0x6b, 0x68, 0x71, // V3 R,G,B 0x6b, 0x68, 0x71, // V3 R,G,B
0x00, 0x00, 0x00); // V1 R,G,B 0x00, 0x00, 0x00); // V1 R,G,B
// set default Amoled Off Ratio // set default Amoled Off Ratio
dsi_dcs_write_seq(dsi, 0xb2, 0x40, 0x0a, 0x17, 0x00, 0x0a); mipi_dsi_dcs_write_seq(dsi, 0xb2, 0x40, 0x0a, 0x17, 0x00, 0x0a);
dsi_dcs_write_seq(dsi, 0xb6, 0x2c, 0x0b); // set default elvss voltage mipi_dsi_dcs_write_seq(dsi, 0xb6, 0x2c, 0x0b); // set default elvss voltage
dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_POWER_SAVE, 0x00); mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_POWER_SAVE, 0x00);
dsi_dcs_write_seq(dsi, 0xf7, 0x03); // gamma/aor update mipi_dsi_dcs_write_seq(dsi, 0xf7, 0x03); // gamma/aor update
dsi_dcs_write_seq(dsi, 0xf0, 0xa5, 0xa5); // disable LEVEL2 commands mipi_dsi_dcs_write_seq(dsi, 0xf0, 0xa5, 0xa5); // disable LEVEL2 commands
ret = mipi_dsi_dcs_set_display_on(dsi); ret = mipi_dsi_dcs_set_display_on(dsi);
if (ret < 0) { if (ret < 0) {

View File

@@ -34,14 +34,6 @@ struct sofef00_panel *to_sofef00_panel(struct drm_panel *panel)
return container_of(panel, struct sofef00_panel, panel); return container_of(panel, struct sofef00_panel, panel);
} }
#define dsi_dcs_write_seq(dsi, seq...) do { \
static const u8 d[] = { seq }; \
int ret; \
ret = mipi_dsi_dcs_write_buffer(dsi, d, ARRAY_SIZE(d)); \
if (ret < 0) \
return ret; \
} while (0)
static void sofef00_panel_reset(struct sofef00_panel *ctx) static void sofef00_panel_reset(struct sofef00_panel *ctx)
{ {
gpiod_set_value_cansleep(ctx->reset_gpio, 0); gpiod_set_value_cansleep(ctx->reset_gpio, 0);
@@ -67,7 +59,7 @@ static int sofef00_panel_on(struct sofef00_panel *ctx)
} }
usleep_range(10000, 11000); usleep_range(10000, 11000);
dsi_dcs_write_seq(dsi, 0xf0, 0x5a, 0x5a); mipi_dsi_dcs_write_seq(dsi, 0xf0, 0x5a, 0x5a);
ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK); ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
if (ret < 0) { if (ret < 0) {
@@ -75,13 +67,13 @@ static int sofef00_panel_on(struct sofef00_panel *ctx)
return ret; return ret;
} }
dsi_dcs_write_seq(dsi, 0xf0, 0xa5, 0xa5); mipi_dsi_dcs_write_seq(dsi, 0xf0, 0xa5, 0xa5);
dsi_dcs_write_seq(dsi, 0xf0, 0x5a, 0x5a); mipi_dsi_dcs_write_seq(dsi, 0xf0, 0x5a, 0x5a);
dsi_dcs_write_seq(dsi, 0xb0, 0x07); mipi_dsi_dcs_write_seq(dsi, 0xb0, 0x07);
dsi_dcs_write_seq(dsi, 0xb6, 0x12); mipi_dsi_dcs_write_seq(dsi, 0xb6, 0x12);
dsi_dcs_write_seq(dsi, 0xf0, 0xa5, 0xa5); mipi_dsi_dcs_write_seq(dsi, 0xf0, 0xa5, 0xa5);
dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x20); mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x20);
dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_POWER_SAVE, 0x00); mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_POWER_SAVE, 0x00);
ret = mipi_dsi_dcs_set_display_on(dsi); ret = mipi_dsi_dcs_set_display_on(dsi);
if (ret < 0) { if (ret < 0) {

View File

@@ -32,12 +32,6 @@ static inline struct sharp_ls060 *to_sharp_ls060(struct drm_panel *panel)
return container_of(panel, struct sharp_ls060, panel); return container_of(panel, struct sharp_ls060, panel);
} }
#define dsi_dcs_write_seq(dsi, seq...) ({ \
static const u8 d[] = { seq }; \
\
mipi_dsi_dcs_write_buffer(dsi, d, ARRAY_SIZE(d)); \
})
static void sharp_ls060_reset(struct sharp_ls060 *ctx) static void sharp_ls060_reset(struct sharp_ls060 *ctx)
{ {
gpiod_set_value_cansleep(ctx->reset_gpio, 0); gpiod_set_value_cansleep(ctx->reset_gpio, 0);
@@ -56,17 +50,8 @@ static int sharp_ls060_on(struct sharp_ls060 *ctx)
dsi->mode_flags |= MIPI_DSI_MODE_LPM; dsi->mode_flags |= MIPI_DSI_MODE_LPM;
ret = dsi_dcs_write_seq(dsi, 0xbb, 0x13); mipi_dsi_dcs_write_seq(dsi, 0xbb, 0x13);
if (ret < 0) { mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_MEMORY_START);
dev_err(dev, "Failed to send command: %d\n", ret);
return ret;
}
ret = dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_MEMORY_START);
if (ret < 0) {
dev_err(dev, "Failed to send command: %d\n", ret);
return ret;
}
ret = mipi_dsi_dcs_exit_sleep_mode(dsi); ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
if (ret < 0) { if (ret < 0) {

View File

@@ -73,14 +73,6 @@ static inline struct st7703 *panel_to_st7703(struct drm_panel *panel)
return container_of(panel, struct st7703, panel); return container_of(panel, struct st7703, panel);
} }
#define dsi_generic_write_seq(dsi, seq...) do { \
static const u8 d[] = { seq }; \
int ret; \
ret = mipi_dsi_generic_write(dsi, d, ARRAY_SIZE(d)); \
if (ret < 0) \
return ret; \
} while (0)
static int jh057n_init_sequence(struct st7703 *ctx) static int jh057n_init_sequence(struct st7703 *ctx)
{ {
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
@@ -90,50 +82,50 @@ static int jh057n_init_sequence(struct st7703 *ctx)
* resemble the ST7703 but the number of parameters often don't match * resemble the ST7703 but the number of parameters often don't match
* so it's likely a clone. * so it's likely a clone.
*/ */
dsi_generic_write_seq(dsi, ST7703_CMD_SETEXTC, mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETEXTC,
0xF1, 0x12, 0x83); 0xF1, 0x12, 0x83);
dsi_generic_write_seq(dsi, ST7703_CMD_SETRGBIF, mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETRGBIF,
0x10, 0x10, 0x05, 0x05, 0x03, 0xFF, 0x00, 0x00, 0x10, 0x10, 0x05, 0x05, 0x03, 0xFF, 0x00, 0x00,
0x00, 0x00); 0x00, 0x00);
dsi_generic_write_seq(dsi, ST7703_CMD_SETSCR, mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETSCR,
0x73, 0x73, 0x50, 0x50, 0x00, 0x00, 0x08, 0x70, 0x73, 0x73, 0x50, 0x50, 0x00, 0x00, 0x08, 0x70,
0x00); 0x00);
dsi_generic_write_seq(dsi, ST7703_CMD_SETVDC, 0x4E); mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETVDC, 0x4E);
dsi_generic_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0B); mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0B);
dsi_generic_write_seq(dsi, ST7703_CMD_SETCYC, 0x80); mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETCYC, 0x80);
dsi_generic_write_seq(dsi, ST7703_CMD_SETDISP, 0xF0, 0x12, 0x30); mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETDISP, 0xF0, 0x12, 0x30);
dsi_generic_write_seq(dsi, ST7703_CMD_SETEQ, mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETEQ,
0x07, 0x07, 0x0B, 0x0B, 0x03, 0x0B, 0x00, 0x00, 0x07, 0x07, 0x0B, 0x0B, 0x03, 0x0B, 0x00, 0x00,
0x00, 0x00, 0xFF, 0x00, 0xC0, 0x10); 0x00, 0x00, 0xFF, 0x00, 0xC0, 0x10);
dsi_generic_write_seq(dsi, ST7703_CMD_SETBGP, 0x08, 0x08); mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETBGP, 0x08, 0x08);
msleep(20); msleep(20);
dsi_generic_write_seq(dsi, ST7703_CMD_SETVCOM, 0x3F, 0x3F); mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETVCOM, 0x3F, 0x3F);
dsi_generic_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00); mipi_dsi_generic_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
dsi_generic_write_seq(dsi, ST7703_CMD_SETGIP1, mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETGIP1,
0x82, 0x10, 0x06, 0x05, 0x9E, 0x0A, 0xA5, 0x12, 0x82, 0x10, 0x06, 0x05, 0x9E, 0x0A, 0xA5, 0x12,
0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38, 0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38,
0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00,
0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88, 0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64, 0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64,
0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
dsi_generic_write_seq(dsi, ST7703_CMD_SETGIP2, mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETGIP2,
0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13,
0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00, 0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0A,
0xA5, 0x00, 0x00, 0x00, 0x00); 0xA5, 0x00, 0x00, 0x00, 0x00);
dsi_generic_write_seq(dsi, ST7703_CMD_SETGAMMA, mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETGAMMA,
0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41, 0x37, 0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41, 0x37,
0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10, 0x11, 0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10, 0x11,
0x18, 0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41, 0x18, 0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41,
0x37, 0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10, 0x37, 0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10,
0x11, 0x18); 0x11, 0x18);
return 0; return 0;
} }
@@ -162,15 +154,6 @@ static const struct st7703_panel_desc jh057n00900_panel_desc = {
.init_sequence = jh057n_init_sequence, .init_sequence = jh057n_init_sequence,
}; };
#define dsi_dcs_write_seq(dsi, cmd, seq...) do { \
static const u8 d[] = { seq }; \
int ret; \
ret = mipi_dsi_dcs_write(dsi, cmd, d, ARRAY_SIZE(d)); \
if (ret < 0) \
return ret; \
} while (0)
static int xbd599_init_sequence(struct st7703 *ctx) static int xbd599_init_sequence(struct st7703 *ctx)
{ {
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
@@ -180,154 +163,154 @@ static int xbd599_init_sequence(struct st7703 *ctx)
*/ */
/* Magic sequence to unlock user commands below. */ /* Magic sequence to unlock user commands below. */
dsi_dcs_write_seq(dsi, ST7703_CMD_SETEXTC, 0xF1, 0x12, 0x83); mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETEXTC, 0xF1, 0x12, 0x83);
dsi_dcs_write_seq(dsi, ST7703_CMD_SETMIPI, mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETMIPI,
0x33, /* VC_main = 0, Lane_Number = 3 (4 lanes) */ 0x33, /* VC_main = 0, Lane_Number = 3 (4 lanes) */
0x81, /* DSI_LDO_SEL = 1.7V, RTERM = 90 Ohm */ 0x81, /* DSI_LDO_SEL = 1.7V, RTERM = 90 Ohm */
0x05, /* IHSRX = x6 (Low High Speed driving ability) */ 0x05, /* IHSRX = x6 (Low High Speed driving ability) */
0xF9, /* TX_CLK_SEL = fDSICLK/16 */ 0xF9, /* TX_CLK_SEL = fDSICLK/16 */
0x0E, /* HFP_OSC (min. HFP number in DSI mode) */ 0x0E, /* HFP_OSC (min. HFP number in DSI mode) */
0x0E, /* HBP_OSC (min. HBP number in DSI mode) */ 0x0E, /* HBP_OSC (min. HBP number in DSI mode) */
/* The rest is undocumented in ST7703 datasheet */ /* The rest is undocumented in ST7703 datasheet */
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x44, 0x25, 0x00, 0x91, 0x0a, 0x00, 0x00, 0x02, 0x44, 0x25, 0x00, 0x91, 0x0a, 0x00, 0x00, 0x02,
0x4F, 0x11, 0x00, 0x00, 0x37); 0x4F, 0x11, 0x00, 0x00, 0x37);
dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER_EXT, mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER_EXT,
0x25, /* PCCS = 2, ECP_DC_DIV = 1/4 HSYNC */ 0x25, /* PCCS = 2, ECP_DC_DIV = 1/4 HSYNC */
0x22, /* DT = 15ms XDK_ECP = x2 */ 0x22, /* DT = 15ms XDK_ECP = x2 */
0x20, /* PFM_DC_DIV = /1 */ 0x20, /* PFM_DC_DIV = /1 */
0x03 /* ECP_SYNC_EN = 1, VGX_SYNC_EN = 1 */); 0x03 /* ECP_SYNC_EN = 1, VGX_SYNC_EN = 1 */);
/* RGB I/F porch timing */ /* RGB I/F porch timing */
dsi_dcs_write_seq(dsi, ST7703_CMD_SETRGBIF, mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETRGBIF,
0x10, /* VBP_RGB_GEN */ 0x10, /* VBP_RGB_GEN */
0x10, /* VFP_RGB_GEN */ 0x10, /* VFP_RGB_GEN */
0x05, /* DE_BP_RGB_GEN */ 0x05, /* DE_BP_RGB_GEN */
0x05, /* DE_FP_RGB_GEN */ 0x05, /* DE_FP_RGB_GEN */
/* The rest is undocumented in ST7703 datasheet */ /* The rest is undocumented in ST7703 datasheet */
0x03, 0xFF, 0x03, 0xFF,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00); 0x00, 0x00);
/* Source driving settings. */ /* Source driving settings. */
dsi_dcs_write_seq(dsi, ST7703_CMD_SETSCR, mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETSCR,
0x73, /* N_POPON */ 0x73, /* N_POPON */
0x73, /* N_NOPON */ 0x73, /* N_NOPON */
0x50, /* I_POPON */ 0x50, /* I_POPON */
0x50, /* I_NOPON */ 0x50, /* I_NOPON */
0x00, /* SCR[31,24] */ 0x00, /* SCR[31,24] */
0xC0, /* SCR[23,16] */ 0xC0, /* SCR[23,16] */
0x08, /* SCR[15,8] */ 0x08, /* SCR[15,8] */
0x70, /* SCR[7,0] */ 0x70, /* SCR[7,0] */
0x00 /* Undocumented */); 0x00 /* Undocumented */);
/* NVDDD_SEL = -1.8V, VDDD_SEL = out of range (possibly 1.9V?) */ /* NVDDD_SEL = -1.8V, VDDD_SEL = out of range (possibly 1.9V?) */
dsi_dcs_write_seq(dsi, ST7703_CMD_SETVDC, 0x4E); mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETVDC, 0x4E);
/* /*
* SS_PANEL = 1 (reverse scan), GS_PANEL = 0 (normal scan) * SS_PANEL = 1 (reverse scan), GS_PANEL = 0 (normal scan)
* REV_PANEL = 1 (normally black panel), BGR_PANEL = 1 (BGR) * REV_PANEL = 1 (normally black panel), BGR_PANEL = 1 (BGR)
*/ */
dsi_dcs_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0B); mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0B);
/* Zig-Zag Type C column inversion. */ /* Zig-Zag Type C column inversion. */
dsi_dcs_write_seq(dsi, ST7703_CMD_SETCYC, 0x80); mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETCYC, 0x80);
/* Set display resolution. */ /* Set display resolution. */
dsi_dcs_write_seq(dsi, ST7703_CMD_SETDISP, mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETDISP,
0xF0, /* NL = 240 */ 0xF0, /* NL = 240 */
0x12, /* RES_V_LSB = 0, BLK_CON = VSSD, 0x12, /* RES_V_LSB = 0, BLK_CON = VSSD,
* RESO_SEL = 720RGB * RESO_SEL = 720RGB
*/ */
0xF0 /* WHITE_GND_EN = 1 (GND), 0xF0 /* WHITE_GND_EN = 1 (GND),
* WHITE_FRAME_SEL = 7 frames, * WHITE_FRAME_SEL = 7 frames,
* ISC = 0 frames * ISC = 0 frames
*/); */);
dsi_dcs_write_seq(dsi, ST7703_CMD_SETEQ, mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETEQ,
0x00, /* PNOEQ */ 0x00, /* PNOEQ */
0x00, /* NNOEQ */ 0x00, /* NNOEQ */
0x0B, /* PEQGND */ 0x0B, /* PEQGND */
0x0B, /* NEQGND */ 0x0B, /* NEQGND */
0x10, /* PEQVCI */ 0x10, /* PEQVCI */
0x10, /* NEQVCI */ 0x10, /* NEQVCI */
0x00, /* PEQVCI1 */ 0x00, /* PEQVCI1 */
0x00, /* NEQVCI1 */ 0x00, /* NEQVCI1 */
0x00, /* reserved */ 0x00, /* reserved */
0x00, /* reserved */ 0x00, /* reserved */
0xFF, /* reserved */ 0xFF, /* reserved */
0x00, /* reserved */ 0x00, /* reserved */
0xC0, /* ESD_DET_DATA_WHITE = 1, ESD_WHITE_EN = 1 */ 0xC0, /* ESD_DET_DATA_WHITE = 1, ESD_WHITE_EN = 1 */
0x10 /* SLPIN_OPTION = 1 (no need vsync after sleep-in) 0x10 /* SLPIN_OPTION = 1 (no need vsync after sleep-in)
* VEDIO_NO_CHECK_EN = 0 * VEDIO_NO_CHECK_EN = 0
* ESD_WHITE_GND_EN = 0 * ESD_WHITE_GND_EN = 0
* ESD_DET_TIME_SEL = 0 frames * ESD_DET_TIME_SEL = 0 frames
*/); */);
/* Undocumented command. */ /* Undocumented command. */
dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_C6, 0x01, 0x00, 0xFF, 0xFF, 0x00); mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_C6, 0x01, 0x00, 0xFF, 0xFF, 0x00);
dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER, mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER,
0x74, /* VBTHS, VBTLS: VGH = 17V, VBL = -11V */ 0x74, /* VBTHS, VBTLS: VGH = 17V, VBL = -11V */
0x00, /* FBOFF_VGH = 0, FBOFF_VGL = 0 */ 0x00, /* FBOFF_VGH = 0, FBOFF_VGL = 0 */
0x32, /* VRP */ 0x32, /* VRP */
0x32, /* VRN */ 0x32, /* VRN */
0x77, /* reserved */ 0x77, /* reserved */
0xF1, /* APS = 1 (small), 0xF1, /* APS = 1 (small),
* VGL_DET_EN = 1, VGH_DET_EN = 1, * VGL_DET_EN = 1, VGH_DET_EN = 1,
* VGL_TURBO = 1, VGH_TURBO = 1 * VGL_TURBO = 1, VGH_TURBO = 1
*/ */
0xFF, /* VGH1_L_DIV, VGL1_L_DIV (1.5MHz) */ 0xFF, /* VGH1_L_DIV, VGL1_L_DIV (1.5MHz) */
0xFF, /* VGH1_R_DIV, VGL1_R_DIV (1.5MHz) */ 0xFF, /* VGH1_R_DIV, VGL1_R_DIV (1.5MHz) */
0xCC, /* VGH2_L_DIV, VGL2_L_DIV (2.6MHz) */ 0xCC, /* VGH2_L_DIV, VGL2_L_DIV (2.6MHz) */
0xCC, /* VGH2_R_DIV, VGL2_R_DIV (2.6MHz) */ 0xCC, /* VGH2_R_DIV, VGL2_R_DIV (2.6MHz) */
0x77, /* VGH3_L_DIV, VGL3_L_DIV (4.5MHz) */ 0x77, /* VGH3_L_DIV, VGL3_L_DIV (4.5MHz) */
0x77 /* VGH3_R_DIV, VGL3_R_DIV (4.5MHz) */); 0x77 /* VGH3_R_DIV, VGL3_R_DIV (4.5MHz) */);
/* Reference voltage. */ /* Reference voltage. */
dsi_dcs_write_seq(dsi, ST7703_CMD_SETBGP, mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETBGP,
0x07, /* VREF_SEL = 4.2V */ 0x07, /* VREF_SEL = 4.2V */
0x07 /* NVREF_SEL = 4.2V */); 0x07 /* NVREF_SEL = 4.2V */);
msleep(20); msleep(20);
dsi_dcs_write_seq(dsi, ST7703_CMD_SETVCOM, mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETVCOM,
0x2C, /* VCOMDC_F = -0.67V */ 0x2C, /* VCOMDC_F = -0.67V */
0x2C /* VCOMDC_B = -0.67V */); 0x2C /* VCOMDC_B = -0.67V */);
/* Undocumented command. */ /* Undocumented command. */
dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00); mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
/* This command is to set forward GIP timing. */ /* This command is to set forward GIP timing. */
dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP1, mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP1,
0x82, 0x10, 0x06, 0x05, 0xA2, 0x0A, 0xA5, 0x12, 0x82, 0x10, 0x06, 0x05, 0xA2, 0x0A, 0xA5, 0x12,
0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38, 0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38,
0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00,
0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88, 0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64, 0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64,
0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
/* This command is to set backward GIP timing. */ /* This command is to set backward GIP timing. */
dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP2, mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP2,
0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13,
0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00, 0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0A,
0xA5, 0x00, 0x00, 0x00, 0x00); 0xA5, 0x00, 0x00, 0x00, 0x00);
/* Adjust the gamma characteristics of the panel. */ /* Adjust the gamma characteristics of the panel. */
dsi_dcs_write_seq(dsi, ST7703_CMD_SETGAMMA, mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGAMMA,
0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41, 0x35, 0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41, 0x35,
0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12, 0x12, 0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12, 0x12,
0x18, 0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41, 0x18, 0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41,
0x35, 0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12, 0x35, 0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12,
0x12, 0x18); 0x12, 0x18);
return 0; return 0;
} }
@@ -499,7 +482,7 @@ static int allpixelson_set(void *data, u64 val)
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
dev_dbg(ctx->dev, "Setting all pixels on\n"); dev_dbg(ctx->dev, "Setting all pixels on\n");
dsi_generic_write_seq(dsi, ST7703_CMD_ALL_PIXEL_ON); mipi_dsi_generic_write_seq(dsi, ST7703_CMD_ALL_PIXEL_ON);
msleep(val * 1000); msleep(val * 1000);
/* Reset the panel to get video back */ /* Reset the panel to get video back */
drm_panel_disable(&ctx->panel); drm_panel_disable(&ctx->panel);

View File

@@ -33,14 +33,6 @@ struct truly_nt35521 *to_truly_nt35521(struct drm_panel *panel)
return container_of(panel, struct truly_nt35521, panel); return container_of(panel, struct truly_nt35521, panel);
} }
#define dsi_generic_write_seq(dsi, seq...) do { \
static const u8 d[] = { seq }; \
int ret; \
ret = mipi_dsi_generic_write(dsi, d, ARRAY_SIZE(d)); \
if (ret < 0) \
return ret; \
} while (0)
static void truly_nt35521_reset(struct truly_nt35521 *ctx) static void truly_nt35521_reset(struct truly_nt35521 *ctx)
{ {
gpiod_set_value_cansleep(ctx->reset_gpio, 1); gpiod_set_value_cansleep(ctx->reset_gpio, 1);
@@ -59,200 +51,200 @@ static int truly_nt35521_on(struct truly_nt35521 *ctx)
dsi->mode_flags |= MIPI_DSI_MODE_LPM; dsi->mode_flags |= MIPI_DSI_MODE_LPM;
dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x00); mipi_dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x00);
dsi_generic_write_seq(dsi, 0xff, 0xaa, 0x55, 0xa5, 0x80); mipi_dsi_generic_write_seq(dsi, 0xff, 0xaa, 0x55, 0xa5, 0x80);
dsi_generic_write_seq(dsi, 0x6f, 0x11, 0x00); mipi_dsi_generic_write_seq(dsi, 0x6f, 0x11, 0x00);
dsi_generic_write_seq(dsi, 0xf7, 0x20, 0x00); mipi_dsi_generic_write_seq(dsi, 0xf7, 0x20, 0x00);
dsi_generic_write_seq(dsi, 0x6f, 0x01); mipi_dsi_generic_write_seq(dsi, 0x6f, 0x01);
dsi_generic_write_seq(dsi, 0xb1, 0x21); mipi_dsi_generic_write_seq(dsi, 0xb1, 0x21);
dsi_generic_write_seq(dsi, 0xbd, 0x01, 0xa0, 0x10, 0x08, 0x01); mipi_dsi_generic_write_seq(dsi, 0xbd, 0x01, 0xa0, 0x10, 0x08, 0x01);
dsi_generic_write_seq(dsi, 0xb8, 0x01, 0x02, 0x0c, 0x02); mipi_dsi_generic_write_seq(dsi, 0xb8, 0x01, 0x02, 0x0c, 0x02);
dsi_generic_write_seq(dsi, 0xbb, 0x11, 0x11); mipi_dsi_generic_write_seq(dsi, 0xbb, 0x11, 0x11);
dsi_generic_write_seq(dsi, 0xbc, 0x00, 0x00); mipi_dsi_generic_write_seq(dsi, 0xbc, 0x00, 0x00);
dsi_generic_write_seq(dsi, 0xb6, 0x02); mipi_dsi_generic_write_seq(dsi, 0xb6, 0x02);
dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x01); mipi_dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x01);
dsi_generic_write_seq(dsi, 0xb0, 0x09, 0x09); mipi_dsi_generic_write_seq(dsi, 0xb0, 0x09, 0x09);
dsi_generic_write_seq(dsi, 0xb1, 0x09, 0x09); mipi_dsi_generic_write_seq(dsi, 0xb1, 0x09, 0x09);
dsi_generic_write_seq(dsi, 0xbc, 0x8c, 0x00); mipi_dsi_generic_write_seq(dsi, 0xbc, 0x8c, 0x00);
dsi_generic_write_seq(dsi, 0xbd, 0x8c, 0x00); mipi_dsi_generic_write_seq(dsi, 0xbd, 0x8c, 0x00);
dsi_generic_write_seq(dsi, 0xca, 0x00); mipi_dsi_generic_write_seq(dsi, 0xca, 0x00);
dsi_generic_write_seq(dsi, 0xc0, 0x04); mipi_dsi_generic_write_seq(dsi, 0xc0, 0x04);
dsi_generic_write_seq(dsi, 0xbe, 0xb5); mipi_dsi_generic_write_seq(dsi, 0xbe, 0xb5);
dsi_generic_write_seq(dsi, 0xb3, 0x35, 0x35); mipi_dsi_generic_write_seq(dsi, 0xb3, 0x35, 0x35);
dsi_generic_write_seq(dsi, 0xb4, 0x25, 0x25); mipi_dsi_generic_write_seq(dsi, 0xb4, 0x25, 0x25);
dsi_generic_write_seq(dsi, 0xb9, 0x43, 0x43); mipi_dsi_generic_write_seq(dsi, 0xb9, 0x43, 0x43);
dsi_generic_write_seq(dsi, 0xba, 0x24, 0x24); mipi_dsi_generic_write_seq(dsi, 0xba, 0x24, 0x24);
dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x02); mipi_dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x02);
dsi_generic_write_seq(dsi, 0xee, 0x03); mipi_dsi_generic_write_seq(dsi, 0xee, 0x03);
dsi_generic_write_seq(dsi, 0xb0, mipi_dsi_generic_write_seq(dsi, 0xb0,
0x00, 0xb2, 0x00, 0xb3, 0x00, 0xb6, 0x00, 0xc3, 0x00, 0xb2, 0x00, 0xb3, 0x00, 0xb6, 0x00, 0xc3,
0x00, 0xce, 0x00, 0xe1, 0x00, 0xf3, 0x01, 0x11); 0x00, 0xce, 0x00, 0xe1, 0x00, 0xf3, 0x01, 0x11);
dsi_generic_write_seq(dsi, 0xb1, mipi_dsi_generic_write_seq(dsi, 0xb1,
0x01, 0x2e, 0x01, 0x5c, 0x01, 0x82, 0x01, 0xc3, 0x01, 0x2e, 0x01, 0x5c, 0x01, 0x82, 0x01, 0xc3,
0x01, 0xfe, 0x02, 0x00, 0x02, 0x37, 0x02, 0x77); 0x01, 0xfe, 0x02, 0x00, 0x02, 0x37, 0x02, 0x77);
dsi_generic_write_seq(dsi, 0xb2, mipi_dsi_generic_write_seq(dsi, 0xb2,
0x02, 0xa1, 0x02, 0xd7, 0x02, 0xfe, 0x03, 0x2c, 0x02, 0xa1, 0x02, 0xd7, 0x02, 0xfe, 0x03, 0x2c,
0x03, 0x4b, 0x03, 0x63, 0x03, 0x8f, 0x03, 0x90); 0x03, 0x4b, 0x03, 0x63, 0x03, 0x8f, 0x03, 0x90);
dsi_generic_write_seq(dsi, 0xb3, 0x03, 0x96, 0x03, 0x98); mipi_dsi_generic_write_seq(dsi, 0xb3, 0x03, 0x96, 0x03, 0x98);
dsi_generic_write_seq(dsi, 0xb4, mipi_dsi_generic_write_seq(dsi, 0xb4,
0x00, 0x81, 0x00, 0x8b, 0x00, 0x9c, 0x00, 0xa9, 0x00, 0x81, 0x00, 0x8b, 0x00, 0x9c, 0x00, 0xa9,
0x00, 0xb5, 0x00, 0xcb, 0x00, 0xdf, 0x01, 0x02); 0x00, 0xb5, 0x00, 0xcb, 0x00, 0xdf, 0x01, 0x02);
dsi_generic_write_seq(dsi, 0xb5, mipi_dsi_generic_write_seq(dsi, 0xb5,
0x01, 0x1f, 0x01, 0x51, 0x01, 0x7a, 0x01, 0xbf, 0x01, 0x1f, 0x01, 0x51, 0x01, 0x7a, 0x01, 0xbf,
0x01, 0xfa, 0x01, 0xfc, 0x02, 0x34, 0x02, 0x76); 0x01, 0xfa, 0x01, 0xfc, 0x02, 0x34, 0x02, 0x76);
dsi_generic_write_seq(dsi, 0xb6, mipi_dsi_generic_write_seq(dsi, 0xb6,
0x02, 0x9f, 0x02, 0xd7, 0x02, 0xfc, 0x03, 0x2c, 0x02, 0x9f, 0x02, 0xd7, 0x02, 0xfc, 0x03, 0x2c,
0x03, 0x4a, 0x03, 0x63, 0x03, 0x8f, 0x03, 0xa2); 0x03, 0x4a, 0x03, 0x63, 0x03, 0x8f, 0x03, 0xa2);
dsi_generic_write_seq(dsi, 0xb7, 0x03, 0xb8, 0x03, 0xba); mipi_dsi_generic_write_seq(dsi, 0xb7, 0x03, 0xb8, 0x03, 0xba);
dsi_generic_write_seq(dsi, 0xb8, mipi_dsi_generic_write_seq(dsi, 0xb8,
0x00, 0x01, 0x00, 0x02, 0x00, 0x0e, 0x00, 0x2a, 0x00, 0x01, 0x00, 0x02, 0x00, 0x0e, 0x00, 0x2a,
0x00, 0x41, 0x00, 0x67, 0x00, 0x87, 0x00, 0xb9); 0x00, 0x41, 0x00, 0x67, 0x00, 0x87, 0x00, 0xb9);
dsi_generic_write_seq(dsi, 0xb9, mipi_dsi_generic_write_seq(dsi, 0xb9,
0x00, 0xe2, 0x01, 0x22, 0x01, 0x54, 0x01, 0xa3, 0x00, 0xe2, 0x01, 0x22, 0x01, 0x54, 0x01, 0xa3,
0x01, 0xe6, 0x01, 0xe7, 0x02, 0x24, 0x02, 0x67); 0x01, 0xe6, 0x01, 0xe7, 0x02, 0x24, 0x02, 0x67);
dsi_generic_write_seq(dsi, 0xba, mipi_dsi_generic_write_seq(dsi, 0xba,
0x02, 0x93, 0x02, 0xcd, 0x02, 0xf6, 0x03, 0x31, 0x02, 0x93, 0x02, 0xcd, 0x02, 0xf6, 0x03, 0x31,
0x03, 0x6c, 0x03, 0xe9, 0x03, 0xef, 0x03, 0xf4); 0x03, 0x6c, 0x03, 0xe9, 0x03, 0xef, 0x03, 0xf4);
dsi_generic_write_seq(dsi, 0xbb, 0x03, 0xf6, 0x03, 0xf7); mipi_dsi_generic_write_seq(dsi, 0xbb, 0x03, 0xf6, 0x03, 0xf7);
dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x03); mipi_dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x03);
dsi_generic_write_seq(dsi, 0xb0, 0x22, 0x00); mipi_dsi_generic_write_seq(dsi, 0xb0, 0x22, 0x00);
dsi_generic_write_seq(dsi, 0xb1, 0x22, 0x00); mipi_dsi_generic_write_seq(dsi, 0xb1, 0x22, 0x00);
dsi_generic_write_seq(dsi, 0xb2, 0x05, 0x00, 0x60, 0x00, 0x00); mipi_dsi_generic_write_seq(dsi, 0xb2, 0x05, 0x00, 0x60, 0x00, 0x00);
dsi_generic_write_seq(dsi, 0xb3, 0x05, 0x00, 0x60, 0x00, 0x00); mipi_dsi_generic_write_seq(dsi, 0xb3, 0x05, 0x00, 0x60, 0x00, 0x00);
dsi_generic_write_seq(dsi, 0xb4, 0x05, 0x00, 0x60, 0x00, 0x00); mipi_dsi_generic_write_seq(dsi, 0xb4, 0x05, 0x00, 0x60, 0x00, 0x00);
dsi_generic_write_seq(dsi, 0xb5, 0x05, 0x00, 0x60, 0x00, 0x00); mipi_dsi_generic_write_seq(dsi, 0xb5, 0x05, 0x00, 0x60, 0x00, 0x00);
dsi_generic_write_seq(dsi, 0xba, 0x53, 0x00, 0x60, 0x00, 0x00); mipi_dsi_generic_write_seq(dsi, 0xba, 0x53, 0x00, 0x60, 0x00, 0x00);
dsi_generic_write_seq(dsi, 0xbb, 0x53, 0x00, 0x60, 0x00, 0x00); mipi_dsi_generic_write_seq(dsi, 0xbb, 0x53, 0x00, 0x60, 0x00, 0x00);
dsi_generic_write_seq(dsi, 0xbc, 0x53, 0x00, 0x60, 0x00, 0x00); mipi_dsi_generic_write_seq(dsi, 0xbc, 0x53, 0x00, 0x60, 0x00, 0x00);
dsi_generic_write_seq(dsi, 0xbd, 0x53, 0x00, 0x60, 0x00, 0x00); mipi_dsi_generic_write_seq(dsi, 0xbd, 0x53, 0x00, 0x60, 0x00, 0x00);
dsi_generic_write_seq(dsi, 0xc0, 0x00, 0x34, 0x00, 0x00); mipi_dsi_generic_write_seq(dsi, 0xc0, 0x00, 0x34, 0x00, 0x00);
dsi_generic_write_seq(dsi, 0xc1, 0x00, 0x00, 0x34, 0x00); mipi_dsi_generic_write_seq(dsi, 0xc1, 0x00, 0x00, 0x34, 0x00);
dsi_generic_write_seq(dsi, 0xc2, 0x00, 0x00, 0x34, 0x00); mipi_dsi_generic_write_seq(dsi, 0xc2, 0x00, 0x00, 0x34, 0x00);
dsi_generic_write_seq(dsi, 0xc3, 0x00, 0x00, 0x34, 0x00); mipi_dsi_generic_write_seq(dsi, 0xc3, 0x00, 0x00, 0x34, 0x00);
dsi_generic_write_seq(dsi, 0xc4, 0x60); mipi_dsi_generic_write_seq(dsi, 0xc4, 0x60);
dsi_generic_write_seq(dsi, 0xc5, 0xc0); mipi_dsi_generic_write_seq(dsi, 0xc5, 0xc0);
dsi_generic_write_seq(dsi, 0xc6, 0x00); mipi_dsi_generic_write_seq(dsi, 0xc6, 0x00);
dsi_generic_write_seq(dsi, 0xc7, 0x00); mipi_dsi_generic_write_seq(dsi, 0xc7, 0x00);
dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x05); mipi_dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x05);
dsi_generic_write_seq(dsi, 0xb0, 0x17, 0x06); mipi_dsi_generic_write_seq(dsi, 0xb0, 0x17, 0x06);
dsi_generic_write_seq(dsi, 0xb1, 0x17, 0x06); mipi_dsi_generic_write_seq(dsi, 0xb1, 0x17, 0x06);
dsi_generic_write_seq(dsi, 0xb2, 0x17, 0x06); mipi_dsi_generic_write_seq(dsi, 0xb2, 0x17, 0x06);
dsi_generic_write_seq(dsi, 0xb3, 0x17, 0x06); mipi_dsi_generic_write_seq(dsi, 0xb3, 0x17, 0x06);
dsi_generic_write_seq(dsi, 0xb4, 0x17, 0x06); mipi_dsi_generic_write_seq(dsi, 0xb4, 0x17, 0x06);
dsi_generic_write_seq(dsi, 0xb5, 0x17, 0x06); mipi_dsi_generic_write_seq(dsi, 0xb5, 0x17, 0x06);
dsi_generic_write_seq(dsi, 0xb6, 0x17, 0x06); mipi_dsi_generic_write_seq(dsi, 0xb6, 0x17, 0x06);
dsi_generic_write_seq(dsi, 0xb7, 0x17, 0x06); mipi_dsi_generic_write_seq(dsi, 0xb7, 0x17, 0x06);
dsi_generic_write_seq(dsi, 0xb8, 0x00); mipi_dsi_generic_write_seq(dsi, 0xb8, 0x00);
dsi_generic_write_seq(dsi, 0xb9, 0x00, 0x03); mipi_dsi_generic_write_seq(dsi, 0xb9, 0x00, 0x03);
dsi_generic_write_seq(dsi, 0xba, 0x00, 0x00); mipi_dsi_generic_write_seq(dsi, 0xba, 0x00, 0x00);
dsi_generic_write_seq(dsi, 0xbb, 0x02, 0x03); mipi_dsi_generic_write_seq(dsi, 0xbb, 0x02, 0x03);
dsi_generic_write_seq(dsi, 0xbc, 0x02, 0x03); mipi_dsi_generic_write_seq(dsi, 0xbc, 0x02, 0x03);
dsi_generic_write_seq(dsi, 0xbd, 0x03, 0x03, 0x00, 0x03, 0x03); mipi_dsi_generic_write_seq(dsi, 0xbd, 0x03, 0x03, 0x00, 0x03, 0x03);
dsi_generic_write_seq(dsi, 0xc0, 0x0b); mipi_dsi_generic_write_seq(dsi, 0xc0, 0x0b);
dsi_generic_write_seq(dsi, 0xc1, 0x09); mipi_dsi_generic_write_seq(dsi, 0xc1, 0x09);
dsi_generic_write_seq(dsi, 0xc2, 0xa6); mipi_dsi_generic_write_seq(dsi, 0xc2, 0xa6);
dsi_generic_write_seq(dsi, 0xc3, 0x05); mipi_dsi_generic_write_seq(dsi, 0xc3, 0x05);
dsi_generic_write_seq(dsi, 0xc4, 0x00); mipi_dsi_generic_write_seq(dsi, 0xc4, 0x00);
dsi_generic_write_seq(dsi, 0xc5, 0x02); mipi_dsi_generic_write_seq(dsi, 0xc5, 0x02);
dsi_generic_write_seq(dsi, 0xc6, 0x22); mipi_dsi_generic_write_seq(dsi, 0xc6, 0x22);
dsi_generic_write_seq(dsi, 0xc7, 0x03); mipi_dsi_generic_write_seq(dsi, 0xc7, 0x03);
dsi_generic_write_seq(dsi, 0xc8, 0x07, 0x20); mipi_dsi_generic_write_seq(dsi, 0xc8, 0x07, 0x20);
dsi_generic_write_seq(dsi, 0xc9, 0x03, 0x20); mipi_dsi_generic_write_seq(dsi, 0xc9, 0x03, 0x20);
dsi_generic_write_seq(dsi, 0xca, 0x01, 0x60); mipi_dsi_generic_write_seq(dsi, 0xca, 0x01, 0x60);
dsi_generic_write_seq(dsi, 0xcb, 0x01, 0x60); mipi_dsi_generic_write_seq(dsi, 0xcb, 0x01, 0x60);
dsi_generic_write_seq(dsi, 0xcc, 0x00, 0x00, 0x02); mipi_dsi_generic_write_seq(dsi, 0xcc, 0x00, 0x00, 0x02);
dsi_generic_write_seq(dsi, 0xcd, 0x00, 0x00, 0x02); mipi_dsi_generic_write_seq(dsi, 0xcd, 0x00, 0x00, 0x02);
dsi_generic_write_seq(dsi, 0xce, 0x00, 0x00, 0x02); mipi_dsi_generic_write_seq(dsi, 0xce, 0x00, 0x00, 0x02);
dsi_generic_write_seq(dsi, 0xcf, 0x00, 0x00, 0x02); mipi_dsi_generic_write_seq(dsi, 0xcf, 0x00, 0x00, 0x02);
dsi_generic_write_seq(dsi, 0xd1, 0x00, 0x05, 0x01, 0x07, 0x10); mipi_dsi_generic_write_seq(dsi, 0xd1, 0x00, 0x05, 0x01, 0x07, 0x10);
dsi_generic_write_seq(dsi, 0xd2, 0x10, 0x05, 0x05, 0x03, 0x10); mipi_dsi_generic_write_seq(dsi, 0xd2, 0x10, 0x05, 0x05, 0x03, 0x10);
dsi_generic_write_seq(dsi, 0xd3, 0x20, 0x00, 0x43, 0x07, 0x10); mipi_dsi_generic_write_seq(dsi, 0xd3, 0x20, 0x00, 0x43, 0x07, 0x10);
dsi_generic_write_seq(dsi, 0xd4, 0x30, 0x00, 0x43, 0x07, 0x10); mipi_dsi_generic_write_seq(dsi, 0xd4, 0x30, 0x00, 0x43, 0x07, 0x10);
dsi_generic_write_seq(dsi, 0xd0, mipi_dsi_generic_write_seq(dsi, 0xd0,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
dsi_generic_write_seq(dsi, 0xd5, mipi_dsi_generic_write_seq(dsi, 0xd5,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00); 0x00, 0x00, 0x00);
dsi_generic_write_seq(dsi, 0xd6, mipi_dsi_generic_write_seq(dsi, 0xd6,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00); 0x00, 0x00, 0x00);
dsi_generic_write_seq(dsi, 0xd7, mipi_dsi_generic_write_seq(dsi, 0xd7,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00); 0x00, 0x00, 0x00);
dsi_generic_write_seq(dsi, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00); mipi_dsi_generic_write_seq(dsi, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00);
dsi_generic_write_seq(dsi, 0xe5, 0x06); mipi_dsi_generic_write_seq(dsi, 0xe5, 0x06);
dsi_generic_write_seq(dsi, 0xe6, 0x06); mipi_dsi_generic_write_seq(dsi, 0xe6, 0x06);
dsi_generic_write_seq(dsi, 0xe7, 0x00); mipi_dsi_generic_write_seq(dsi, 0xe7, 0x00);
dsi_generic_write_seq(dsi, 0xe8, 0x06); mipi_dsi_generic_write_seq(dsi, 0xe8, 0x06);
dsi_generic_write_seq(dsi, 0xe9, 0x06); mipi_dsi_generic_write_seq(dsi, 0xe9, 0x06);
dsi_generic_write_seq(dsi, 0xea, 0x06); mipi_dsi_generic_write_seq(dsi, 0xea, 0x06);
dsi_generic_write_seq(dsi, 0xeb, 0x00); mipi_dsi_generic_write_seq(dsi, 0xeb, 0x00);
dsi_generic_write_seq(dsi, 0xec, 0x00); mipi_dsi_generic_write_seq(dsi, 0xec, 0x00);
dsi_generic_write_seq(dsi, 0xed, 0x30); mipi_dsi_generic_write_seq(dsi, 0xed, 0x30);
dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x06); mipi_dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x06);
dsi_generic_write_seq(dsi, 0xb0, 0x31, 0x31); mipi_dsi_generic_write_seq(dsi, 0xb0, 0x31, 0x31);
dsi_generic_write_seq(dsi, 0xb1, 0x31, 0x31); mipi_dsi_generic_write_seq(dsi, 0xb1, 0x31, 0x31);
dsi_generic_write_seq(dsi, 0xb2, 0x2d, 0x2e); mipi_dsi_generic_write_seq(dsi, 0xb2, 0x2d, 0x2e);
dsi_generic_write_seq(dsi, 0xb3, 0x31, 0x34); mipi_dsi_generic_write_seq(dsi, 0xb3, 0x31, 0x34);
dsi_generic_write_seq(dsi, 0xb4, 0x29, 0x2a); mipi_dsi_generic_write_seq(dsi, 0xb4, 0x29, 0x2a);
dsi_generic_write_seq(dsi, 0xb5, 0x12, 0x10); mipi_dsi_generic_write_seq(dsi, 0xb5, 0x12, 0x10);
dsi_generic_write_seq(dsi, 0xb6, 0x18, 0x16); mipi_dsi_generic_write_seq(dsi, 0xb6, 0x18, 0x16);
dsi_generic_write_seq(dsi, 0xb7, 0x00, 0x02); mipi_dsi_generic_write_seq(dsi, 0xb7, 0x00, 0x02);
dsi_generic_write_seq(dsi, 0xb8, 0x08, 0x31); mipi_dsi_generic_write_seq(dsi, 0xb8, 0x08, 0x31);
dsi_generic_write_seq(dsi, 0xb9, 0x31, 0x31); mipi_dsi_generic_write_seq(dsi, 0xb9, 0x31, 0x31);
dsi_generic_write_seq(dsi, 0xba, 0x31, 0x31); mipi_dsi_generic_write_seq(dsi, 0xba, 0x31, 0x31);
dsi_generic_write_seq(dsi, 0xbb, 0x31, 0x08); mipi_dsi_generic_write_seq(dsi, 0xbb, 0x31, 0x08);
dsi_generic_write_seq(dsi, 0xbc, 0x03, 0x01); mipi_dsi_generic_write_seq(dsi, 0xbc, 0x03, 0x01);
dsi_generic_write_seq(dsi, 0xbd, 0x17, 0x19); mipi_dsi_generic_write_seq(dsi, 0xbd, 0x17, 0x19);
dsi_generic_write_seq(dsi, 0xbe, 0x11, 0x13); mipi_dsi_generic_write_seq(dsi, 0xbe, 0x11, 0x13);
dsi_generic_write_seq(dsi, 0xbf, 0x2a, 0x29); mipi_dsi_generic_write_seq(dsi, 0xbf, 0x2a, 0x29);
dsi_generic_write_seq(dsi, 0xc0, 0x34, 0x31); mipi_dsi_generic_write_seq(dsi, 0xc0, 0x34, 0x31);
dsi_generic_write_seq(dsi, 0xc1, 0x2e, 0x2d); mipi_dsi_generic_write_seq(dsi, 0xc1, 0x2e, 0x2d);
dsi_generic_write_seq(dsi, 0xc2, 0x31, 0x31); mipi_dsi_generic_write_seq(dsi, 0xc2, 0x31, 0x31);
dsi_generic_write_seq(dsi, 0xc3, 0x31, 0x31); mipi_dsi_generic_write_seq(dsi, 0xc3, 0x31, 0x31);
dsi_generic_write_seq(dsi, 0xc4, 0x31, 0x31); mipi_dsi_generic_write_seq(dsi, 0xc4, 0x31, 0x31);
dsi_generic_write_seq(dsi, 0xc5, 0x31, 0x31); mipi_dsi_generic_write_seq(dsi, 0xc5, 0x31, 0x31);
dsi_generic_write_seq(dsi, 0xc6, 0x2e, 0x2d); mipi_dsi_generic_write_seq(dsi, 0xc6, 0x2e, 0x2d);
dsi_generic_write_seq(dsi, 0xc7, 0x31, 0x34); mipi_dsi_generic_write_seq(dsi, 0xc7, 0x31, 0x34);
dsi_generic_write_seq(dsi, 0xc8, 0x29, 0x2a); mipi_dsi_generic_write_seq(dsi, 0xc8, 0x29, 0x2a);
dsi_generic_write_seq(dsi, 0xc9, 0x17, 0x19); mipi_dsi_generic_write_seq(dsi, 0xc9, 0x17, 0x19);
dsi_generic_write_seq(dsi, 0xca, 0x11, 0x13); mipi_dsi_generic_write_seq(dsi, 0xca, 0x11, 0x13);
dsi_generic_write_seq(dsi, 0xcb, 0x03, 0x01); mipi_dsi_generic_write_seq(dsi, 0xcb, 0x03, 0x01);
dsi_generic_write_seq(dsi, 0xcc, 0x08, 0x31); mipi_dsi_generic_write_seq(dsi, 0xcc, 0x08, 0x31);
dsi_generic_write_seq(dsi, 0xcd, 0x31, 0x31); mipi_dsi_generic_write_seq(dsi, 0xcd, 0x31, 0x31);
dsi_generic_write_seq(dsi, 0xce, 0x31, 0x31); mipi_dsi_generic_write_seq(dsi, 0xce, 0x31, 0x31);
dsi_generic_write_seq(dsi, 0xcf, 0x31, 0x08); mipi_dsi_generic_write_seq(dsi, 0xcf, 0x31, 0x08);
dsi_generic_write_seq(dsi, 0xd0, 0x00, 0x02); mipi_dsi_generic_write_seq(dsi, 0xd0, 0x00, 0x02);
dsi_generic_write_seq(dsi, 0xd1, 0x12, 0x10); mipi_dsi_generic_write_seq(dsi, 0xd1, 0x12, 0x10);
dsi_generic_write_seq(dsi, 0xd2, 0x18, 0x16); mipi_dsi_generic_write_seq(dsi, 0xd2, 0x18, 0x16);
dsi_generic_write_seq(dsi, 0xd3, 0x2a, 0x29); mipi_dsi_generic_write_seq(dsi, 0xd3, 0x2a, 0x29);
dsi_generic_write_seq(dsi, 0xd4, 0x34, 0x31); mipi_dsi_generic_write_seq(dsi, 0xd4, 0x34, 0x31);
dsi_generic_write_seq(dsi, 0xd5, 0x2d, 0x2e); mipi_dsi_generic_write_seq(dsi, 0xd5, 0x2d, 0x2e);
dsi_generic_write_seq(dsi, 0xd6, 0x31, 0x31); mipi_dsi_generic_write_seq(dsi, 0xd6, 0x31, 0x31);
dsi_generic_write_seq(dsi, 0xd7, 0x31, 0x31); mipi_dsi_generic_write_seq(dsi, 0xd7, 0x31, 0x31);
dsi_generic_write_seq(dsi, 0xe5, 0x31, 0x31); mipi_dsi_generic_write_seq(dsi, 0xe5, 0x31, 0x31);
dsi_generic_write_seq(dsi, 0xe6, 0x31, 0x31); mipi_dsi_generic_write_seq(dsi, 0xe6, 0x31, 0x31);
dsi_generic_write_seq(dsi, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00); mipi_dsi_generic_write_seq(dsi, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00);
dsi_generic_write_seq(dsi, 0xd9, 0x00, 0x00, 0x00, 0x00, 0x00); mipi_dsi_generic_write_seq(dsi, 0xd9, 0x00, 0x00, 0x00, 0x00, 0x00);
dsi_generic_write_seq(dsi, 0xe7, 0x00); mipi_dsi_generic_write_seq(dsi, 0xe7, 0x00);
dsi_generic_write_seq(dsi, 0x6f, 0x02); mipi_dsi_generic_write_seq(dsi, 0x6f, 0x02);
dsi_generic_write_seq(dsi, 0xf7, 0x47); mipi_dsi_generic_write_seq(dsi, 0xf7, 0x47);
dsi_generic_write_seq(dsi, 0x6f, 0x0a); mipi_dsi_generic_write_seq(dsi, 0x6f, 0x0a);
dsi_generic_write_seq(dsi, 0xf7, 0x02); mipi_dsi_generic_write_seq(dsi, 0xf7, 0x02);
dsi_generic_write_seq(dsi, 0x6f, 0x17); mipi_dsi_generic_write_seq(dsi, 0x6f, 0x17);
dsi_generic_write_seq(dsi, 0xf4, 0x60); mipi_dsi_generic_write_seq(dsi, 0xf4, 0x60);
dsi_generic_write_seq(dsi, 0x6f, 0x01); mipi_dsi_generic_write_seq(dsi, 0x6f, 0x01);
dsi_generic_write_seq(dsi, 0xf9, 0x46); mipi_dsi_generic_write_seq(dsi, 0xf9, 0x46);
dsi_generic_write_seq(dsi, 0x6f, 0x11); mipi_dsi_generic_write_seq(dsi, 0x6f, 0x11);
dsi_generic_write_seq(dsi, 0xf3, 0x01); mipi_dsi_generic_write_seq(dsi, 0xf3, 0x01);
dsi_generic_write_seq(dsi, 0x35, 0x00); mipi_dsi_generic_write_seq(dsi, 0x35, 0x00);
dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x00); mipi_dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x00);
dsi_generic_write_seq(dsi, 0xd9, 0x02, 0x03, 0x00); mipi_dsi_generic_write_seq(dsi, 0xd9, 0x02, 0x03, 0x00);
dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x00, 0x00); mipi_dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x00, 0x00);
dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x00); mipi_dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x00);
dsi_generic_write_seq(dsi, 0xb1, 0x6c, 0x21); mipi_dsi_generic_write_seq(dsi, 0xb1, 0x6c, 0x21);
dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x00, 0x00); mipi_dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x00, 0x00);
dsi_generic_write_seq(dsi, 0x35, 0x00); mipi_dsi_generic_write_seq(dsi, 0x35, 0x00);
ret = mipi_dsi_dcs_exit_sleep_mode(dsi); ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
if (ret < 0) { if (ret < 0) {
@@ -268,7 +260,7 @@ static int truly_nt35521_on(struct truly_nt35521 *ctx)
} }
usleep_range(1000, 2000); usleep_range(1000, 2000);
dsi_generic_write_seq(dsi, 0x53, 0x24); mipi_dsi_generic_write_seq(dsi, 0x53, 0x24);
return 0; return 0;
} }

View File

@@ -0,0 +1,358 @@
// SPDX-License-Identifier: GPL-2.0-only
// Copyright (c) 2023, Linaro Limited
#include <linux/backlight.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h>
#include <linux/module.h>
#include <linux/of.h>
#include <drm/display/drm_dsc.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
#include <video/mipi_display.h>
struct visionox_vtdr6130 {
struct drm_panel panel;
struct mipi_dsi_device *dsi;
struct gpio_desc *reset_gpio;
struct regulator_bulk_data supplies[3];
bool prepared;
};
static inline struct visionox_vtdr6130 *to_visionox_vtdr6130(struct drm_panel *panel)
{
return container_of(panel, struct visionox_vtdr6130, panel);
}
static void visionox_vtdr6130_reset(struct visionox_vtdr6130 *ctx)
{
gpiod_set_value_cansleep(ctx->reset_gpio, 0);
usleep_range(10000, 11000);
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
usleep_range(10000, 11000);
gpiod_set_value_cansleep(ctx->reset_gpio, 0);
usleep_range(10000, 11000);
}
static int visionox_vtdr6130_on(struct visionox_vtdr6130 *ctx)
{
struct mipi_dsi_device *dsi = ctx->dsi;
struct device *dev = &dsi->dev;
int ret;
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_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,
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,
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);
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);
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);
return 0;
}
static int visionox_vtdr6130_off(struct visionox_vtdr6130 *ctx)
{
struct mipi_dsi_device *dsi = ctx->dsi;
struct device *dev = &dsi->dev;
int ret;
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);
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;
}
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;
if (ctx->prepared)
return 0;
ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies),
ctx->supplies);
if (ret < 0)
return ret;
visionox_vtdr6130_reset(ctx);
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);
return ret;
}
ctx->prepared = true;
return 0;
}
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;
if (!ctx->prepared)
return 0;
ret = visionox_vtdr6130_off(ctx);
if (ret < 0)
dev_err(dev, "Failed to un-initialize panel: %d\n", ret);
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
ctx->prepared = false;
return 0;
}
static const struct drm_display_mode visionox_vtdr6130_mode = {
.clock = (1080 + 20 + 2 + 20) * (2400 + 20 + 2 + 18) * 144 / 1000,
.hdisplay = 1080,
.hsync_start = 1080 + 20,
.hsync_end = 1080 + 20 + 2,
.htotal = 1080 + 20 + 2 + 20,
.vdisplay = 2400,
.vsync_start = 2400 + 20,
.vsync_end = 2400 + 20 + 2,
.vtotal = 2400 + 20 + 2 + 18,
.width_mm = 71,
.height_mm = 157,
};
static int visionox_vtdr6130_get_modes(struct drm_panel *panel,
struct drm_connector *connector)
{
struct drm_display_mode *mode;
mode = drm_mode_duplicate(connector->dev, &visionox_vtdr6130_mode);
if (!mode)
return -ENOMEM;
drm_mode_set_name(mode);
mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
connector->display_info.width_mm = mode->width_mm;
connector->display_info.height_mm = mode->height_mm;
drm_mode_probed_add(connector, mode);
return 1;
}
static const struct drm_panel_funcs visionox_vtdr6130_panel_funcs = {
.prepare = visionox_vtdr6130_prepare,
.unprepare = visionox_vtdr6130_unprepare,
.get_modes = visionox_vtdr6130_get_modes,
};
static int visionox_vtdr6130_bl_update_status(struct backlight_device *bl)
{
struct mipi_dsi_device *dsi = bl_get_data(bl);
u16 brightness = backlight_get_brightness(bl);
/* Panel needs big-endian order of brightness value */
u8 payload[2] = { brightness >> 8, brightness & 0xff };
int ret;
ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_BRIGHTNESS,
payload, sizeof(payload));
if (ret < 0)
return ret;
return 0;
}
static const struct backlight_ops visionox_vtdr6130_bl_ops = {
.update_status = visionox_vtdr6130_bl_update_status,
};
static struct backlight_device *
visionox_vtdr6130_create_backlight(struct mipi_dsi_device *dsi)
{
struct device *dev = &dsi->dev;
const struct backlight_properties props = {
.type = BACKLIGHT_RAW,
.brightness = 4095,
.max_brightness = 4095,
};
return devm_backlight_device_register(dev, dev_name(dev), dev, dsi,
&visionox_vtdr6130_bl_ops, &props);
}
static int visionox_vtdr6130_probe(struct mipi_dsi_device *dsi)
{
struct device *dev = &dsi->dev;
struct visionox_vtdr6130 *ctx;
int ret;
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
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);
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_NO_EOT_PACKET |
MIPI_DSI_CLOCK_NON_CONTINUOUS;
drm_panel_init(&ctx->panel, dev, &visionox_vtdr6130_panel_funcs,
DRM_MODE_CONNECTOR_DSI);
ctx->panel.backlight = visionox_vtdr6130_create_backlight(dsi);
if (IS_ERR(ctx->panel.backlight))
return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight),
"Failed to create backlight\n");
drm_panel_add(&ctx->panel);
ret = mipi_dsi_attach(dsi);
if (ret < 0) {
dev_err(dev, "Failed to attach to DSI host: %d\n", ret);
drm_panel_remove(&ctx->panel);
return ret;
}
return 0;
}
static void visionox_vtdr6130_remove(struct mipi_dsi_device *dsi)
{
struct visionox_vtdr6130 *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 visionox_vtdr6130_of_match[] = {
{ .compatible = "visionox,vtdr6130" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, visionox_vtdr6130_of_match);
static struct mipi_dsi_driver visionox_vtdr6130_driver = {
.probe = visionox_vtdr6130_probe,
.remove = visionox_vtdr6130_remove,
.driver = {
.name = "panel-visionox-vtdr6130",
.of_match_table = visionox_vtdr6130_of_match,
},
};
module_mipi_dsi_driver(visionox_vtdr6130_driver);
MODULE_AUTHOR("Neil Armstrong <neil.armstrong@linaro.org>");
MODULE_DESCRIPTION("Panel driver for the Visionox VTDR6130 AMOLED DSI panel");
MODULE_LICENSE("GPL");

View File

@@ -60,14 +60,6 @@ static inline struct xpp055c272 *panel_to_xpp055c272(struct drm_panel *panel)
return container_of(panel, struct xpp055c272, panel); return container_of(panel, struct xpp055c272, panel);
} }
#define dsi_generic_write_seq(dsi, cmd, seq...) do { \
static const u8 b[] = { cmd, seq }; \
int ret; \
ret = mipi_dsi_dcs_write_buffer(dsi, b, ARRAY_SIZE(b)); \
if (ret < 0) \
return ret; \
} while (0)
static int xpp055c272_init_sequence(struct xpp055c272 *ctx) static int xpp055c272_init_sequence(struct xpp055c272 *ctx)
{ {
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
@@ -77,60 +69,60 @@ static int xpp055c272_init_sequence(struct xpp055c272 *ctx)
* Init sequence was supplied by the panel vendor without much * Init sequence was supplied by the panel vendor without much
* documentation. * documentation.
*/ */
dsi_generic_write_seq(dsi, XPP055C272_CMD_SETEXTC, 0xf1, 0x12, 0x83); mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETEXTC, 0xf1, 0x12, 0x83);
dsi_generic_write_seq(dsi, XPP055C272_CMD_SETMIPI, mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETMIPI,
0x33, 0x81, 0x05, 0xf9, 0x0e, 0x0e, 0x00, 0x00, 0x33, 0x81, 0x05, 0xf9, 0x0e, 0x0e, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x25,
0x00, 0x91, 0x0a, 0x00, 0x00, 0x02, 0x4f, 0x01, 0x00, 0x91, 0x0a, 0x00, 0x00, 0x02, 0x4f, 0x01,
0x00, 0x00, 0x37); 0x00, 0x00, 0x37);
dsi_generic_write_seq(dsi, XPP055C272_CMD_SETPOWER_EXT, 0x25); mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETPOWER_EXT, 0x25);
dsi_generic_write_seq(dsi, XPP055C272_CMD_SETPCR, 0x02, 0x11, 0x00); mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETPCR, 0x02, 0x11, 0x00);
dsi_generic_write_seq(dsi, XPP055C272_CMD_SETRGBIF, mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETRGBIF,
0x0c, 0x10, 0x0a, 0x50, 0x03, 0xff, 0x00, 0x00, 0x0c, 0x10, 0x0a, 0x50, 0x03, 0xff, 0x00, 0x00,
0x00, 0x00); 0x00, 0x00);
dsi_generic_write_seq(dsi, XPP055C272_CMD_SETSCR, mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETSCR,
0x73, 0x73, 0x50, 0x50, 0x00, 0x00, 0x08, 0x70, 0x73, 0x73, 0x50, 0x50, 0x00, 0x00, 0x08, 0x70,
0x00); 0x00);
dsi_generic_write_seq(dsi, XPP055C272_CMD_SETVDC, 0x46); mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETVDC, 0x46);
dsi_generic_write_seq(dsi, XPP055C272_CMD_SETPANEL, 0x0b); mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETPANEL, 0x0b);
dsi_generic_write_seq(dsi, XPP055C272_CMD_SETCYC, 0x80); mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETCYC, 0x80);
dsi_generic_write_seq(dsi, XPP055C272_CMD_SETDISP, 0xc8, 0x12, 0x30); mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETDISP, 0xc8, 0x12, 0x30);
dsi_generic_write_seq(dsi, XPP055C272_CMD_SETEQ, mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETEQ,
0x07, 0x07, 0x0B, 0x0B, 0x03, 0x0B, 0x00, 0x00, 0x07, 0x07, 0x0B, 0x0B, 0x03, 0x0B, 0x00, 0x00,
0x00, 0x00, 0xFF, 0x00, 0xC0, 0x10); 0x00, 0x00, 0xFF, 0x00, 0xC0, 0x10);
dsi_generic_write_seq(dsi, XPP055C272_CMD_SETPOWER, mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETPOWER,
0x53, 0x00, 0x1e, 0x1e, 0x77, 0xe1, 0xcc, 0xdd, 0x53, 0x00, 0x1e, 0x1e, 0x77, 0xe1, 0xcc, 0xdd,
0x67, 0x77, 0x33, 0x33); 0x67, 0x77, 0x33, 0x33);
dsi_generic_write_seq(dsi, XPP055C272_CMD_SETECO, 0x00, 0x00, 0xff, mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETECO, 0x00, 0x00, 0xff,
0xff, 0x01, 0xff); 0xff, 0x01, 0xff);
dsi_generic_write_seq(dsi, XPP055C272_CMD_SETBGP, 0x09, 0x09); mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETBGP, 0x09, 0x09);
msleep(20); msleep(20);
dsi_generic_write_seq(dsi, XPP055C272_CMD_SETVCOM, 0x87, 0x95); mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETVCOM, 0x87, 0x95);
dsi_generic_write_seq(dsi, XPP055C272_CMD_SETGIP1, mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETGIP1,
0xc2, 0x10, 0x05, 0x05, 0x10, 0x05, 0xa0, 0x12, 0xc2, 0x10, 0x05, 0x05, 0x10, 0x05, 0xa0, 0x12,
0x31, 0x23, 0x3f, 0x81, 0x0a, 0xa0, 0x37, 0x18, 0x31, 0x23, 0x3f, 0x81, 0x0a, 0xa0, 0x37, 0x18,
0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80,
0x01, 0x00, 0x00, 0x00, 0x48, 0xf8, 0x86, 0x42, 0x01, 0x00, 0x00, 0x00, 0x48, 0xf8, 0x86, 0x42,
0x08, 0x88, 0x88, 0x80, 0x88, 0x88, 0x88, 0x58, 0x08, 0x88, 0x88, 0x80, 0x88, 0x88, 0x88, 0x58,
0xf8, 0x87, 0x53, 0x18, 0x88, 0x88, 0x81, 0x88, 0xf8, 0x87, 0x53, 0x18, 0x88, 0x88, 0x81, 0x88,
0x88, 0x88, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
dsi_generic_write_seq(dsi, XPP055C272_CMD_SETGIP2, mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETGIP2,
0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x1f, 0x88, 0x81, 0x35, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x88, 0x81, 0x35,
0x78, 0x88, 0x88, 0x85, 0x88, 0x88, 0x88, 0x0f, 0x78, 0x88, 0x88, 0x85, 0x88, 0x88, 0x88, 0x0f,
0x88, 0x80, 0x24, 0x68, 0x88, 0x88, 0x84, 0x88, 0x88, 0x80, 0x24, 0x68, 0x88, 0x88, 0x84, 0x88,
0x88, 0x88, 0x23, 0x10, 0x00, 0x00, 0x1c, 0x00, 0x88, 0x88, 0x23, 0x10, 0x00, 0x00, 0x1c, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x05,
0xa0, 0x00, 0x00, 0x00, 0x00); 0xa0, 0x00, 0x00, 0x00, 0x00);
dsi_generic_write_seq(dsi, XPP055C272_CMD_SETGAMMA, mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETGAMMA,
0x00, 0x06, 0x08, 0x2a, 0x31, 0x3f, 0x38, 0x36, 0x00, 0x06, 0x08, 0x2a, 0x31, 0x3f, 0x38, 0x36,
0x07, 0x0c, 0x0d, 0x11, 0x13, 0x12, 0x13, 0x11, 0x07, 0x0c, 0x0d, 0x11, 0x13, 0x12, 0x13, 0x11,
0x18, 0x00, 0x06, 0x08, 0x2a, 0x31, 0x3f, 0x38, 0x18, 0x00, 0x06, 0x08, 0x2a, 0x31, 0x3f, 0x38,
0x36, 0x07, 0x0c, 0x0d, 0x11, 0x13, 0x12, 0x13, 0x36, 0x07, 0x0c, 0x0d, 0x11, 0x13, 0x12, 0x13,
0x11, 0x18); 0x11, 0x18);
msleep(60); msleep(60);

View File

@@ -15,6 +15,8 @@ config DRM_RADEON
select HWMON select HWMON
select BACKLIGHT_CLASS_DEVICE select BACKLIGHT_CLASS_DEVICE
select INTERVAL_TREE select INTERVAL_TREE
select I2C
select I2C_ALGOBIT
# radeon depends on ACPI_VIDEO when ACPI is enabled, for select to work # radeon depends on ACPI_VIDEO when ACPI is enabled, for select to work
# ACPI_VIDEO's dependencies must also be selected. # ACPI_VIDEO's dependencies must also be selected.
select INPUT if ACPI select INPUT if ACPI

View File

@@ -32,16 +32,41 @@ struct convert_to_rgb565_result {
const u16 expected_swab[TEST_BUF_SIZE]; const u16 expected_swab[TEST_BUF_SIZE];
}; };
struct convert_to_xrgb1555_result {
unsigned int dst_pitch;
const u16 expected[TEST_BUF_SIZE];
};
struct convert_to_argb1555_result {
unsigned int dst_pitch;
const u16 expected[TEST_BUF_SIZE];
};
struct convert_to_rgba5551_result {
unsigned int dst_pitch;
const u16 expected[TEST_BUF_SIZE];
};
struct convert_to_rgb888_result { struct convert_to_rgb888_result {
unsigned int dst_pitch; unsigned int dst_pitch;
const u8 expected[TEST_BUF_SIZE]; const u8 expected[TEST_BUF_SIZE];
}; };
struct convert_to_argb8888_result {
unsigned int dst_pitch;
const u32 expected[TEST_BUF_SIZE];
};
struct convert_to_xrgb2101010_result { struct convert_to_xrgb2101010_result {
unsigned int dst_pitch; unsigned int dst_pitch;
const u32 expected[TEST_BUF_SIZE]; const u32 expected[TEST_BUF_SIZE];
}; };
struct convert_to_argb2101010_result {
unsigned int dst_pitch;
const u32 expected[TEST_BUF_SIZE];
};
struct convert_xrgb8888_case { struct convert_xrgb8888_case {
const char *name; const char *name;
unsigned int pitch; unsigned int pitch;
@@ -50,8 +75,13 @@ struct convert_xrgb8888_case {
struct convert_to_gray8_result gray8_result; struct convert_to_gray8_result gray8_result;
struct convert_to_rgb332_result rgb332_result; struct convert_to_rgb332_result rgb332_result;
struct convert_to_rgb565_result rgb565_result; struct convert_to_rgb565_result rgb565_result;
struct convert_to_xrgb1555_result xrgb1555_result;
struct convert_to_argb1555_result argb1555_result;
struct convert_to_rgba5551_result rgba5551_result;
struct convert_to_rgb888_result rgb888_result; struct convert_to_rgb888_result rgb888_result;
struct convert_to_argb8888_result argb8888_result;
struct convert_to_xrgb2101010_result xrgb2101010_result; struct convert_to_xrgb2101010_result xrgb2101010_result;
struct convert_to_argb2101010_result argb2101010_result;
}; };
static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { static struct convert_xrgb8888_case convert_xrgb8888_cases[] = {
@@ -73,14 +103,34 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = {
.expected = { 0xF800 }, .expected = { 0xF800 },
.expected_swab = { 0x00F8 }, .expected_swab = { 0x00F8 },
}, },
.xrgb1555_result = {
.dst_pitch = 0,
.expected = { 0x7C00 },
},
.argb1555_result = {
.dst_pitch = 0,
.expected = { 0xFC00 },
},
.rgba5551_result = {
.dst_pitch = 0,
.expected = { 0xF801 },
},
.rgb888_result = { .rgb888_result = {
.dst_pitch = 0, .dst_pitch = 0,
.expected = { 0x00, 0x00, 0xFF }, .expected = { 0x00, 0x00, 0xFF },
}, },
.argb8888_result = {
.dst_pitch = 0,
.expected = { 0xFFFF0000 },
},
.xrgb2101010_result = { .xrgb2101010_result = {
.dst_pitch = 0, .dst_pitch = 0,
.expected = { 0x3FF00000 }, .expected = { 0x3FF00000 },
}, },
.argb2101010_result = {
.dst_pitch = 0,
.expected = { 0xFFF00000 },
},
}, },
{ {
.name = "single_pixel_clip_rectangle", .name = "single_pixel_clip_rectangle",
@@ -103,14 +153,34 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = {
.expected = { 0xF800 }, .expected = { 0xF800 },
.expected_swab = { 0x00F8 }, .expected_swab = { 0x00F8 },
}, },
.xrgb1555_result = {
.dst_pitch = 0,
.expected = { 0x7C00 },
},
.argb1555_result = {
.dst_pitch = 0,
.expected = { 0xFC00 },
},
.rgba5551_result = {
.dst_pitch = 0,
.expected = { 0xF801 },
},
.rgb888_result = { .rgb888_result = {
.dst_pitch = 0, .dst_pitch = 0,
.expected = { 0x00, 0x00, 0xFF }, .expected = { 0x00, 0x00, 0xFF },
}, },
.argb8888_result = {
.dst_pitch = 0,
.expected = { 0xFFFF0000 },
},
.xrgb2101010_result = { .xrgb2101010_result = {
.dst_pitch = 0, .dst_pitch = 0,
.expected = { 0x3FF00000 }, .expected = { 0x3FF00000 },
}, },
.argb2101010_result = {
.dst_pitch = 0,
.expected = { 0xFFF00000 },
},
}, },
{ {
/* Well known colors: White, black, red, green, blue, magenta, /* Well known colors: White, black, red, green, blue, magenta,
@@ -160,6 +230,33 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = {
0xE0FF, 0xFF07, 0xE0FF, 0xFF07,
}, },
}, },
.xrgb1555_result = {
.dst_pitch = 0,
.expected = {
0x7FFF, 0x0000,
0x7C00, 0x03E0,
0x001F, 0x7C1F,
0x7FE0, 0x03FF,
},
},
.argb1555_result = {
.dst_pitch = 0,
.expected = {
0xFFFF, 0x8000,
0xFC00, 0x83E0,
0x801F, 0xFC1F,
0xFFE0, 0x83FF,
},
},
.rgba5551_result = {
.dst_pitch = 0,
.expected = {
0xFFFF, 0x0001,
0xF801, 0x07C1,
0x003F, 0xF83F,
0xFFC1, 0x07FF,
},
},
.rgb888_result = { .rgb888_result = {
.dst_pitch = 0, .dst_pitch = 0,
.expected = { .expected = {
@@ -169,6 +266,15 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = {
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
}, },
}, },
.argb8888_result = {
.dst_pitch = 0,
.expected = {
0xFFFFFFFF, 0xFF000000,
0xFFFF0000, 0xFF00FF00,
0xFF0000FF, 0xFFFF00FF,
0xFFFFFF00, 0xFF00FFFF,
},
},
.xrgb2101010_result = { .xrgb2101010_result = {
.dst_pitch = 0, .dst_pitch = 0,
.expected = { .expected = {
@@ -178,6 +284,15 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = {
0x3FFFFC00, 0x000FFFFF, 0x3FFFFC00, 0x000FFFFF,
}, },
}, },
.argb2101010_result = {
.dst_pitch = 0,
.expected = {
0xFFFFFFFF, 0xC0000000,
0xFFF00000, 0xC00FFC00,
0xC00003FF, 0xFFF003FF,
0xFFFFFC00, 0xC00FFFFF,
},
},
}, },
{ {
/* Randomly picked colors. Full buffer within the clip area. */ /* Randomly picked colors. Full buffer within the clip area. */
@@ -218,6 +333,30 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = {
0x00A8, 0x8E6B, 0x330A, 0x0000, 0x0000, 0x00A8, 0x8E6B, 0x330A, 0x0000, 0x0000,
}, },
}, },
.xrgb1555_result = {
.dst_pitch = 10,
.expected = {
0x0513, 0x0920, 0x5400, 0x0000, 0x0000,
0x35CE, 0x0513, 0x0920, 0x0000, 0x0000,
0x5400, 0x35CE, 0x0513, 0x0000, 0x0000,
},
},
.argb1555_result = {
.dst_pitch = 10,
.expected = {
0x8513, 0x8920, 0xD400, 0x0000, 0x0000,
0xB5CE, 0x8513, 0x8920, 0x0000, 0x0000,
0xD400, 0xB5CE, 0x8513, 0x0000, 0x0000,
},
},
.rgba5551_result = {
.dst_pitch = 10,
.expected = {
0x0A27, 0x1241, 0xA801, 0x0000, 0x0000,
0x6B9D, 0x0A27, 0x1241, 0x0000, 0x0000,
0xA801, 0x6B9D, 0x0A27, 0x0000, 0x0000,
},
},
.rgb888_result = { .rgb888_result = {
.dst_pitch = 15, .dst_pitch = 15,
.expected = { .expected = {
@@ -229,6 +368,14 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
}, },
}, },
.argb8888_result = {
.dst_pitch = 20,
.expected = {
0xFF0E449C, 0xFF114D05, 0xFFA80303, 0x00000000, 0x00000000,
0xFF6C7073, 0xFF0E449C, 0xFF114D05, 0x00000000, 0x00000000,
0xFFA80303, 0xFF6C7073, 0xFF0E449C, 0x00000000, 0x00000000,
},
},
.xrgb2101010_result = { .xrgb2101010_result = {
.dst_pitch = 20, .dst_pitch = 20,
.expected = { .expected = {
@@ -237,6 +384,14 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = {
0x2A20300C, 0x1B1705CD, 0x03844672, 0x00000000, 0x00000000, 0x2A20300C, 0x1B1705CD, 0x03844672, 0x00000000, 0x00000000,
}, },
}, },
.argb2101010_result = {
.dst_pitch = 20,
.expected = {
0xC3844672, 0xC444D414, 0xEA20300C, 0x00000000, 0x00000000,
0xDB1705CD, 0xC3844672, 0xC444D414, 0x00000000, 0x00000000,
0xEA20300C, 0xDB1705CD, 0xC3844672, 0x00000000, 0x00000000,
},
},
}, },
}; };
@@ -264,7 +419,22 @@ static size_t conversion_buf_size(u32 dst_format, unsigned int dst_pitch,
return dst_pitch * drm_rect_height(clip); return dst_pitch * drm_rect_height(clip);
} }
static u32 *le32buf_to_cpu(struct kunit *test, const u32 *buf, size_t buf_size) static u16 *le16buf_to_cpu(struct kunit *test, const __le16 *buf, size_t buf_size)
{
u16 *dst = NULL;
int n;
dst = kunit_kzalloc(test, sizeof(*dst) * buf_size, GFP_KERNEL);
if (!dst)
return NULL;
for (n = 0; n < buf_size; n++)
dst[n] = le16_to_cpu(buf[n]);
return dst;
}
static u32 *le32buf_to_cpu(struct kunit *test, const __le32 *buf, size_t buf_size)
{ {
u32 *dst = NULL; u32 *dst = NULL;
int n; int n;
@@ -279,6 +449,21 @@ static u32 *le32buf_to_cpu(struct kunit *test, const u32 *buf, size_t buf_size)
return dst; return dst;
} }
static __le32 *cpubuf_to_le32(struct kunit *test, const u32 *buf, size_t buf_size)
{
__le32 *dst = NULL;
int n;
dst = kunit_kzalloc(test, sizeof(*dst) * buf_size, GFP_KERNEL);
if (!dst)
return NULL;
for (n = 0; n < buf_size; n++)
dst[n] = cpu_to_le32(buf[n]);
return dst;
}
static void convert_xrgb8888_case_desc(struct convert_xrgb8888_case *t, static void convert_xrgb8888_case_desc(struct convert_xrgb8888_case *t,
char *desc) char *desc)
{ {
@@ -293,8 +478,8 @@ static void drm_test_fb_xrgb8888_to_gray8(struct kunit *test)
const struct convert_xrgb8888_case *params = test->param_value; const struct convert_xrgb8888_case *params = test->param_value;
const struct convert_to_gray8_result *result = &params->gray8_result; const struct convert_to_gray8_result *result = &params->gray8_result;
size_t dst_size; size_t dst_size;
__u8 *buf = NULL; u8 *buf = NULL;
__u32 *xrgb8888 = NULL; __le32 *xrgb8888 = NULL;
struct iosys_map dst, src; struct iosys_map dst, src;
struct drm_framebuffer fb = { struct drm_framebuffer fb = {
@@ -310,7 +495,7 @@ static void drm_test_fb_xrgb8888_to_gray8(struct kunit *test)
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf);
iosys_map_set_vaddr(&dst, buf); iosys_map_set_vaddr(&dst, buf);
xrgb8888 = le32buf_to_cpu(test, params->xrgb8888, TEST_BUF_SIZE); xrgb8888 = cpubuf_to_le32(test, params->xrgb8888, TEST_BUF_SIZE);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888);
iosys_map_set_vaddr(&src, xrgb8888); iosys_map_set_vaddr(&src, xrgb8888);
@@ -323,8 +508,8 @@ static void drm_test_fb_xrgb8888_to_rgb332(struct kunit *test)
const struct convert_xrgb8888_case *params = test->param_value; const struct convert_xrgb8888_case *params = test->param_value;
const struct convert_to_rgb332_result *result = &params->rgb332_result; const struct convert_to_rgb332_result *result = &params->rgb332_result;
size_t dst_size; size_t dst_size;
__u8 *buf = NULL; u8 *buf = NULL;
__u32 *xrgb8888 = NULL; __le32 *xrgb8888 = NULL;
struct iosys_map dst, src; struct iosys_map dst, src;
struct drm_framebuffer fb = { struct drm_framebuffer fb = {
@@ -340,7 +525,7 @@ static void drm_test_fb_xrgb8888_to_rgb332(struct kunit *test)
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf);
iosys_map_set_vaddr(&dst, buf); iosys_map_set_vaddr(&dst, buf);
xrgb8888 = le32buf_to_cpu(test, params->xrgb8888, TEST_BUF_SIZE); xrgb8888 = cpubuf_to_le32(test, params->xrgb8888, TEST_BUF_SIZE);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888);
iosys_map_set_vaddr(&src, xrgb8888); iosys_map_set_vaddr(&src, xrgb8888);
@@ -353,8 +538,8 @@ static void drm_test_fb_xrgb8888_to_rgb565(struct kunit *test)
const struct convert_xrgb8888_case *params = test->param_value; const struct convert_xrgb8888_case *params = test->param_value;
const struct convert_to_rgb565_result *result = &params->rgb565_result; const struct convert_to_rgb565_result *result = &params->rgb565_result;
size_t dst_size; size_t dst_size;
__u16 *buf = NULL; u16 *buf = NULL;
__u32 *xrgb8888 = NULL; __le32 *xrgb8888 = NULL;
struct iosys_map dst, src; struct iosys_map dst, src;
struct drm_framebuffer fb = { struct drm_framebuffer fb = {
@@ -370,24 +555,120 @@ static void drm_test_fb_xrgb8888_to_rgb565(struct kunit *test)
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf);
iosys_map_set_vaddr(&dst, buf); iosys_map_set_vaddr(&dst, buf);
xrgb8888 = le32buf_to_cpu(test, params->xrgb8888, TEST_BUF_SIZE); xrgb8888 = cpubuf_to_le32(test, params->xrgb8888, TEST_BUF_SIZE);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888);
iosys_map_set_vaddr(&src, xrgb8888); iosys_map_set_vaddr(&src, xrgb8888);
drm_fb_xrgb8888_to_rgb565(&dst, &result->dst_pitch, &src, &fb, &params->clip, false); drm_fb_xrgb8888_to_rgb565(&dst, &result->dst_pitch, &src, &fb, &params->clip, false);
buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16));
KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size);
buf = dst.vaddr; /* restore original value of buf */
drm_fb_xrgb8888_to_rgb565(&dst, &result->dst_pitch, &src, &fb, &params->clip, true); drm_fb_xrgb8888_to_rgb565(&dst, &result->dst_pitch, &src, &fb, &params->clip, true);
buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16));
KUNIT_EXPECT_MEMEQ(test, buf, result->expected_swab, dst_size); KUNIT_EXPECT_MEMEQ(test, buf, result->expected_swab, dst_size);
} }
static void drm_test_fb_xrgb8888_to_xrgb1555(struct kunit *test)
{
const struct convert_xrgb8888_case *params = test->param_value;
const struct convert_to_xrgb1555_result *result = &params->xrgb1555_result;
size_t dst_size;
u16 *buf = NULL;
__le32 *xrgb8888 = NULL;
struct iosys_map dst, src;
struct drm_framebuffer fb = {
.format = drm_format_info(DRM_FORMAT_XRGB8888),
.pitches = { params->pitch, 0, 0 },
};
dst_size = conversion_buf_size(DRM_FORMAT_XRGB1555, result->dst_pitch,
&params->clip);
KUNIT_ASSERT_GT(test, dst_size, 0);
buf = kunit_kzalloc(test, dst_size, GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf);
iosys_map_set_vaddr(&dst, buf);
xrgb8888 = cpubuf_to_le32(test, params->xrgb8888, TEST_BUF_SIZE);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888);
iosys_map_set_vaddr(&src, xrgb8888);
drm_fb_xrgb8888_to_xrgb1555(&dst, &result->dst_pitch, &src, &fb, &params->clip);
buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16));
KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected, dst_size), 0);
}
static void drm_test_fb_xrgb8888_to_argb1555(struct kunit *test)
{
const struct convert_xrgb8888_case *params = test->param_value;
const struct convert_to_argb1555_result *result = &params->argb1555_result;
size_t dst_size;
u16 *buf = NULL;
__le32 *xrgb8888 = NULL;
struct iosys_map dst, src;
struct drm_framebuffer fb = {
.format = drm_format_info(DRM_FORMAT_XRGB8888),
.pitches = { params->pitch, 0, 0 },
};
dst_size = conversion_buf_size(DRM_FORMAT_ARGB1555, result->dst_pitch,
&params->clip);
KUNIT_ASSERT_GT(test, dst_size, 0);
buf = kunit_kzalloc(test, dst_size, GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf);
iosys_map_set_vaddr(&dst, buf);
xrgb8888 = cpubuf_to_le32(test, params->xrgb8888, TEST_BUF_SIZE);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888);
iosys_map_set_vaddr(&src, xrgb8888);
drm_fb_xrgb8888_to_argb1555(&dst, &result->dst_pitch, &src, &fb, &params->clip);
buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16));
KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected, dst_size), 0);
}
static void drm_test_fb_xrgb8888_to_rgba5551(struct kunit *test)
{
const struct convert_xrgb8888_case *params = test->param_value;
const struct convert_to_rgba5551_result *result = &params->rgba5551_result;
size_t dst_size;
u16 *buf = NULL;
__le32 *xrgb8888 = NULL;
struct iosys_map dst, src;
struct drm_framebuffer fb = {
.format = drm_format_info(DRM_FORMAT_XRGB8888),
.pitches = { params->pitch, 0, 0 },
};
dst_size = conversion_buf_size(DRM_FORMAT_RGBA5551, result->dst_pitch,
&params->clip);
KUNIT_ASSERT_GT(test, dst_size, 0);
buf = kunit_kzalloc(test, dst_size, GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf);
iosys_map_set_vaddr(&dst, buf);
xrgb8888 = cpubuf_to_le32(test, params->xrgb8888, TEST_BUF_SIZE);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888);
iosys_map_set_vaddr(&src, xrgb8888);
drm_fb_xrgb8888_to_rgba5551(&dst, &result->dst_pitch, &src, &fb, &params->clip);
buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16));
KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected, dst_size), 0);
}
static void drm_test_fb_xrgb8888_to_rgb888(struct kunit *test) static void drm_test_fb_xrgb8888_to_rgb888(struct kunit *test)
{ {
const struct convert_xrgb8888_case *params = test->param_value; const struct convert_xrgb8888_case *params = test->param_value;
const struct convert_to_rgb888_result *result = &params->rgb888_result; const struct convert_to_rgb888_result *result = &params->rgb888_result;
size_t dst_size; size_t dst_size;
__u8 *buf = NULL; u8 *buf = NULL;
__u32 *xrgb8888 = NULL; __le32 *xrgb8888 = NULL;
struct iosys_map dst, src; struct iosys_map dst, src;
struct drm_framebuffer fb = { struct drm_framebuffer fb = {
@@ -403,21 +684,56 @@ static void drm_test_fb_xrgb8888_to_rgb888(struct kunit *test)
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf);
iosys_map_set_vaddr(&dst, buf); iosys_map_set_vaddr(&dst, buf);
xrgb8888 = le32buf_to_cpu(test, params->xrgb8888, TEST_BUF_SIZE); xrgb8888 = cpubuf_to_le32(test, params->xrgb8888, TEST_BUF_SIZE);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888);
iosys_map_set_vaddr(&src, xrgb8888); iosys_map_set_vaddr(&src, xrgb8888);
/*
* RGB888 expected results are already in little-endian
* order, so there's no need to convert the test output.
*/
drm_fb_xrgb8888_to_rgb888(&dst, &result->dst_pitch, &src, &fb, &params->clip); drm_fb_xrgb8888_to_rgb888(&dst, &result->dst_pitch, &src, &fb, &params->clip);
KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size);
} }
static void drm_test_fb_xrgb8888_to_argb8888(struct kunit *test)
{
const struct convert_xrgb8888_case *params = test->param_value;
const struct convert_to_argb8888_result *result = &params->argb8888_result;
size_t dst_size;
u32 *buf = NULL;
__le32 *xrgb8888 = NULL;
struct iosys_map dst, src;
struct drm_framebuffer fb = {
.format = drm_format_info(DRM_FORMAT_XRGB8888),
.pitches = { params->pitch, 0, 0 },
};
dst_size = conversion_buf_size(DRM_FORMAT_ARGB8888,
result->dst_pitch, &params->clip);
KUNIT_ASSERT_GT(test, dst_size, 0);
buf = kunit_kzalloc(test, dst_size, GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf);
iosys_map_set_vaddr(&dst, buf);
xrgb8888 = cpubuf_to_le32(test, params->xrgb8888, TEST_BUF_SIZE);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888);
iosys_map_set_vaddr(&src, xrgb8888);
drm_fb_xrgb8888_to_argb8888(&dst, &result->dst_pitch, &src, &fb, &params->clip);
buf = le32buf_to_cpu(test, (__force const __le32 *)buf, dst_size / sizeof(u32));
KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected, dst_size), 0);
}
static void drm_test_fb_xrgb8888_to_xrgb2101010(struct kunit *test) static void drm_test_fb_xrgb8888_to_xrgb2101010(struct kunit *test)
{ {
const struct convert_xrgb8888_case *params = test->param_value; const struct convert_xrgb8888_case *params = test->param_value;
const struct convert_to_xrgb2101010_result *result = &params->xrgb2101010_result; const struct convert_to_xrgb2101010_result *result = &params->xrgb2101010_result;
size_t dst_size; size_t dst_size;
__u32 *buf = NULL; u32 *buf = NULL;
__u32 *xrgb8888 = NULL; __le32 *xrgb8888 = NULL;
struct iosys_map dst, src; struct iosys_map dst, src;
struct drm_framebuffer fb = { struct drm_framebuffer fb = {
@@ -433,7 +749,7 @@ static void drm_test_fb_xrgb8888_to_xrgb2101010(struct kunit *test)
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf);
iosys_map_set_vaddr(&dst, buf); iosys_map_set_vaddr(&dst, buf);
xrgb8888 = le32buf_to_cpu(test, params->xrgb8888, TEST_BUF_SIZE); xrgb8888 = cpubuf_to_le32(test, params->xrgb8888, TEST_BUF_SIZE);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888);
iosys_map_set_vaddr(&src, xrgb8888); iosys_map_set_vaddr(&src, xrgb8888);
@@ -442,12 +758,48 @@ static void drm_test_fb_xrgb8888_to_xrgb2101010(struct kunit *test)
KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size);
} }
static void drm_test_fb_xrgb8888_to_argb2101010(struct kunit *test)
{
const struct convert_xrgb8888_case *params = test->param_value;
const struct convert_to_argb2101010_result *result = &params->argb2101010_result;
size_t dst_size;
u32 *buf = NULL;
__le32 *xrgb8888 = NULL;
struct iosys_map dst, src;
struct drm_framebuffer fb = {
.format = drm_format_info(DRM_FORMAT_XRGB8888),
.pitches = { params->pitch, 0, 0 },
};
dst_size = conversion_buf_size(DRM_FORMAT_ARGB2101010,
result->dst_pitch, &params->clip);
KUNIT_ASSERT_GT(test, dst_size, 0);
buf = kunit_kzalloc(test, dst_size, GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf);
iosys_map_set_vaddr(&dst, buf);
xrgb8888 = cpubuf_to_le32(test, params->xrgb8888, TEST_BUF_SIZE);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888);
iosys_map_set_vaddr(&src, xrgb8888);
drm_fb_xrgb8888_to_argb2101010(&dst, &result->dst_pitch, &src, &fb, &params->clip);
buf = le32buf_to_cpu(test, (__force const __le32 *)buf, dst_size / sizeof(u32));
KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected, dst_size), 0);
}
static struct kunit_case drm_format_helper_test_cases[] = { static struct kunit_case drm_format_helper_test_cases[] = {
KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_gray8, convert_xrgb8888_gen_params), KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_gray8, convert_xrgb8888_gen_params),
KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_rgb332, convert_xrgb8888_gen_params), KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_rgb332, convert_xrgb8888_gen_params),
KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_rgb565, convert_xrgb8888_gen_params), KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_rgb565, convert_xrgb8888_gen_params),
KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_xrgb1555, convert_xrgb8888_gen_params),
KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_argb1555, convert_xrgb8888_gen_params),
KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_rgba5551, convert_xrgb8888_gen_params),
KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_rgb888, convert_xrgb8888_gen_params), KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_rgb888, convert_xrgb8888_gen_params),
KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_argb8888, convert_xrgb8888_gen_params),
KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_xrgb2101010, convert_xrgb8888_gen_params), KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_xrgb2101010, convert_xrgb8888_gen_params),
KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_argb2101010, convert_xrgb8888_gen_params),
{} {}
}; };

View File

@@ -754,24 +754,6 @@ static void ofdrm_crtc_state_destroy(struct ofdrm_crtc_state *ofdrm_crtc_state)
kfree(ofdrm_crtc_state); kfree(ofdrm_crtc_state);
} }
/*
* Support all formats of OF display and maybe more; in order
* of preference. The display's update function will do any
* conversion necessary.
*
* TODO: Add blit helpers for remaining formats and uncomment
* constants.
*/
static const uint32_t ofdrm_primary_plane_formats[] = {
DRM_FORMAT_XRGB8888,
DRM_FORMAT_RGB565,
//DRM_FORMAT_XRGB1555,
//DRM_FORMAT_C8,
/* Big-endian formats below */
DRM_FORMAT_BGRX8888,
DRM_FORMAT_RGB565 | DRM_FORMAT_BIG_ENDIAN,
};
static const uint64_t ofdrm_primary_plane_format_modifiers[] = { static const uint64_t ofdrm_primary_plane_format_modifiers[] = {
DRM_FORMAT_MOD_LINEAR, DRM_FORMAT_MOD_LINEAR,
DRM_FORMAT_MOD_INVALID DRM_FORMAT_MOD_INVALID
@@ -1290,8 +1272,6 @@ static struct ofdrm_device *ofdrm_device_create(struct drm_driver *drv,
/* Primary plane */ /* Primary plane */
nformats = drm_fb_build_fourcc_list(dev, &format->format, 1, nformats = drm_fb_build_fourcc_list(dev, &format->format, 1,
ofdrm_primary_plane_formats,
ARRAY_SIZE(ofdrm_primary_plane_formats),
odev->formats, ARRAY_SIZE(odev->formats)); odev->formats, ARRAY_SIZE(odev->formats));
primary_plane = &odev->primary_plane; primary_plane = &odev->primary_plane;
@@ -1372,6 +1352,7 @@ static int ofdrm_probe(struct platform_device *pdev)
{ {
struct ofdrm_device *odev; struct ofdrm_device *odev;
struct drm_device *dev; struct drm_device *dev;
unsigned int color_mode;
int ret; int ret;
odev = ofdrm_device_create(&ofdrm_driver, pdev); odev = ofdrm_device_create(&ofdrm_driver, pdev);
@@ -1383,7 +1364,11 @@ static int ofdrm_probe(struct platform_device *pdev)
if (ret) if (ret)
return ret; return ret;
drm_fbdev_generic_setup(dev, drm_format_info_bpp(odev->format, 0)); color_mode = drm_format_info_bpp(odev->format, 0);
if (color_mode == 16)
color_mode = odev->format->depth; // can be 15 or 16
drm_fbdev_generic_setup(dev, color_mode);
return 0; return 0;
} }

View File

@@ -446,25 +446,6 @@ static int simpledrm_device_init_regulators(struct simpledrm_device *sdev)
* Modesetting * Modesetting
*/ */
/*
* Support all formats of simplefb and maybe more; in order
* of preference. The display's update function will do any
* conversion necessary.
*
* TODO: Add blit helpers for remaining formats and uncomment
* constants.
*/
static const uint32_t simpledrm_primary_plane_formats[] = {
DRM_FORMAT_XRGB8888,
DRM_FORMAT_ARGB8888,
DRM_FORMAT_RGB565,
//DRM_FORMAT_XRGB1555,
//DRM_FORMAT_ARGB1555,
DRM_FORMAT_RGB888,
DRM_FORMAT_XRGB2101010,
DRM_FORMAT_ARGB2101010,
};
static const uint64_t simpledrm_primary_plane_format_modifiers[] = { static const uint64_t simpledrm_primary_plane_format_modifiers[] = {
DRM_FORMAT_MOD_LINEAR, DRM_FORMAT_MOD_LINEAR,
DRM_FORMAT_MOD_INVALID DRM_FORMAT_MOD_INVALID
@@ -745,8 +726,6 @@ static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv,
/* Primary plane */ /* Primary plane */
nformats = drm_fb_build_fourcc_list(dev, &format->format, 1, nformats = drm_fb_build_fourcc_list(dev, &format->format, 1,
simpledrm_primary_plane_formats,
ARRAY_SIZE(simpledrm_primary_plane_formats),
sdev->formats, ARRAY_SIZE(sdev->formats)); sdev->formats, ARRAY_SIZE(sdev->formats));
primary_plane = &sdev->primary_plane; primary_plane = &sdev->primary_plane;
@@ -823,6 +802,7 @@ static int simpledrm_probe(struct platform_device *pdev)
{ {
struct simpledrm_device *sdev; struct simpledrm_device *sdev;
struct drm_device *dev; struct drm_device *dev;
unsigned int color_mode;
int ret; int ret;
sdev = simpledrm_device_create(&simpledrm_driver, pdev); sdev = simpledrm_device_create(&simpledrm_driver, pdev);
@@ -834,7 +814,11 @@ static int simpledrm_probe(struct platform_device *pdev)
if (ret) if (ret)
return ret; return ret;
drm_fbdev_generic_setup(dev, drm_format_info_bpp(sdev->format, 0)); color_mode = drm_format_info_bpp(sdev->format, 0);
if (color_mode == 16)
color_mode = sdev->format->depth; // can be 15 or 16
drm_fbdev_generic_setup(dev, color_mode);
return 0; return 0;
} }

View File

@@ -861,7 +861,6 @@ v3d_submit_tfu_ioctl(struct drm_device *dev, void *data,
job->args = *args; job->args = *args;
spin_lock(&file_priv->table_lock);
for (job->base.bo_count = 0; for (job->base.bo_count = 0;
job->base.bo_count < ARRAY_SIZE(args->bo_handles); job->base.bo_count < ARRAY_SIZE(args->bo_handles);
job->base.bo_count++) { job->base.bo_count++) {
@@ -870,20 +869,16 @@ v3d_submit_tfu_ioctl(struct drm_device *dev, void *data,
if (!args->bo_handles[job->base.bo_count]) if (!args->bo_handles[job->base.bo_count])
break; break;
bo = idr_find(&file_priv->object_idr, bo = drm_gem_object_lookup(file_priv, args->bo_handles[job->base.bo_count]);
args->bo_handles[job->base.bo_count]);
if (!bo) { if (!bo) {
DRM_DEBUG("Failed to look up GEM BO %d: %d\n", DRM_DEBUG("Failed to look up GEM BO %d: %d\n",
job->base.bo_count, job->base.bo_count,
args->bo_handles[job->base.bo_count]); args->bo_handles[job->base.bo_count]);
ret = -ENOENT; ret = -ENOENT;
spin_unlock(&file_priv->table_lock);
goto fail; goto fail;
} }
drm_gem_object_get(bo);
job->base.bo[job->base.bo_count] = bo; job->base.bo[job->base.bo_count] = bo;
} }
spin_unlock(&file_priv->table_lock);
ret = v3d_lock_bo_reservations(&job->base, &acquire_ctx); ret = v3d_lock_bo_reservations(&job->base, &acquire_ctx);
if (ret) if (ret)

View File

@@ -335,8 +335,14 @@ static void vc4_crtc_config_pv(struct drm_crtc *crtc, struct drm_encoder *encode
bool is_dsi = (vc4_encoder->type == VC4_ENCODER_TYPE_DSI0 || bool is_dsi = (vc4_encoder->type == VC4_ENCODER_TYPE_DSI0 ||
vc4_encoder->type == VC4_ENCODER_TYPE_DSI1); vc4_encoder->type == VC4_ENCODER_TYPE_DSI1);
bool is_dsi1 = vc4_encoder->type == VC4_ENCODER_TYPE_DSI1; bool is_dsi1 = vc4_encoder->type == VC4_ENCODER_TYPE_DSI1;
bool is_vec = vc4_encoder->type == VC4_ENCODER_TYPE_VEC;
u32 format = is_dsi1 ? PV_CONTROL_FORMAT_DSIV_24 : PV_CONTROL_FORMAT_24; u32 format = is_dsi1 ? PV_CONTROL_FORMAT_DSIV_24 : PV_CONTROL_FORMAT_24;
u8 ppc = pv_data->pixels_per_clock; u8 ppc = pv_data->pixels_per_clock;
u16 vert_bp = mode->crtc_vtotal - mode->crtc_vsync_end;
u16 vert_sync = mode->crtc_vsync_end - mode->crtc_vsync_start;
u16 vert_fp = mode->crtc_vsync_start - mode->crtc_vdisplay;
bool debug_dump_regs = false; bool debug_dump_regs = false;
int idx; int idx;
@@ -364,49 +370,60 @@ static void vc4_crtc_config_pv(struct drm_crtc *crtc, struct drm_encoder *encode
VC4_SET_FIELD(mode->hdisplay * pixel_rep / ppc, VC4_SET_FIELD(mode->hdisplay * pixel_rep / ppc,
PV_HORZB_HACTIVE)); PV_HORZB_HACTIVE));
CRTC_WRITE(PV_VERTA,
VC4_SET_FIELD(mode->crtc_vtotal - mode->crtc_vsync_end +
interlace,
PV_VERTA_VBP) |
VC4_SET_FIELD(mode->crtc_vsync_end - mode->crtc_vsync_start,
PV_VERTA_VSYNC));
CRTC_WRITE(PV_VERTB,
VC4_SET_FIELD(mode->crtc_vsync_start - mode->crtc_vdisplay,
PV_VERTB_VFP) |
VC4_SET_FIELD(mode->crtc_vdisplay, PV_VERTB_VACTIVE));
if (interlace) { if (interlace) {
bool odd_field_first = false;
u32 field_delay = mode->htotal * pixel_rep / (2 * ppc);
u16 vert_bp_even = vert_bp;
u16 vert_fp_even = vert_fp;
if (is_vec) {
/* VEC (composite output) */
++field_delay;
if (mode->htotal == 858) {
/* 525-line mode (NTSC or PAL-M) */
odd_field_first = true;
}
}
if (odd_field_first)
++vert_fp_even;
else
++vert_bp;
CRTC_WRITE(PV_VERTA_EVEN, CRTC_WRITE(PV_VERTA_EVEN,
VC4_SET_FIELD(mode->crtc_vtotal - VC4_SET_FIELD(vert_bp_even, PV_VERTA_VBP) |
mode->crtc_vsync_end, VC4_SET_FIELD(vert_sync, PV_VERTA_VSYNC));
PV_VERTA_VBP) |
VC4_SET_FIELD(mode->crtc_vsync_end -
mode->crtc_vsync_start,
PV_VERTA_VSYNC));
CRTC_WRITE(PV_VERTB_EVEN, CRTC_WRITE(PV_VERTB_EVEN,
VC4_SET_FIELD(mode->crtc_vsync_start - VC4_SET_FIELD(vert_fp_even, PV_VERTB_VFP) |
mode->crtc_vdisplay,
PV_VERTB_VFP) |
VC4_SET_FIELD(mode->crtc_vdisplay, PV_VERTB_VACTIVE)); VC4_SET_FIELD(mode->crtc_vdisplay, PV_VERTB_VACTIVE));
/* We set up first field even mode for HDMI. VEC's /* We set up first field even mode for HDMI and VEC's PAL.
* NTSC mode would want first field odd instead, once * For NTSC, we need first field odd.
* we support it (to do so, set ODD_FIRST and put the
* delay in VSYNCD_EVEN instead).
*/ */
CRTC_WRITE(PV_V_CONTROL, CRTC_WRITE(PV_V_CONTROL,
PV_VCONTROL_CONTINUOUS | PV_VCONTROL_CONTINUOUS |
(is_dsi ? PV_VCONTROL_DSI : 0) | (is_dsi ? PV_VCONTROL_DSI : 0) |
PV_VCONTROL_INTERLACE | PV_VCONTROL_INTERLACE |
VC4_SET_FIELD(mode->htotal * pixel_rep / (2 * ppc), (odd_field_first
PV_VCONTROL_ODD_DELAY)); ? PV_VCONTROL_ODD_FIRST
CRTC_WRITE(PV_VSYNCD_EVEN, 0); : VC4_SET_FIELD(field_delay,
PV_VCONTROL_ODD_DELAY)));
CRTC_WRITE(PV_VSYNCD_EVEN,
(odd_field_first ? field_delay : 0));
} else { } else {
CRTC_WRITE(PV_V_CONTROL, CRTC_WRITE(PV_V_CONTROL,
PV_VCONTROL_CONTINUOUS | PV_VCONTROL_CONTINUOUS |
(is_dsi ? PV_VCONTROL_DSI : 0)); (is_dsi ? PV_VCONTROL_DSI : 0));
CRTC_WRITE(PV_VSYNCD_EVEN, 0);
} }
CRTC_WRITE(PV_VERTA,
VC4_SET_FIELD(vert_bp, PV_VERTA_VBP) |
VC4_SET_FIELD(vert_sync, PV_VERTA_VSYNC));
CRTC_WRITE(PV_VERTB,
VC4_SET_FIELD(vert_fp, PV_VERTB_VFP) |
VC4_SET_FIELD(mode->crtc_vdisplay, PV_VERTB_VACTIVE));
if (is_dsi) if (is_dsi)
CRTC_WRITE(PV_HACT_ACT, mode->hdisplay * pixel_rep); CRTC_WRITE(PV_HACT_ACT, mode->hdisplay * pixel_rep);

View File

@@ -24,7 +24,6 @@
#include <linux/component.h> #include <linux/component.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/dmaengine.h> #include <linux/dmaengine.h>
#include <linux/i2c.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>

View File

@@ -1307,11 +1307,12 @@ static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
VC4_SET_FIELD(mode->crtc_vdisplay, VC5_HDMI_VERTA_VAL)); VC4_SET_FIELD(mode->crtc_vdisplay, VC5_HDMI_VERTA_VAL));
u32 vertb = (VC4_SET_FIELD(mode->htotal >> (2 - pixel_rep), u32 vertb = (VC4_SET_FIELD(mode->htotal >> (2 - pixel_rep),
VC5_HDMI_VERTB_VSPO) | VC5_HDMI_VERTB_VSPO) |
VC4_SET_FIELD(mode->crtc_vtotal - mode->crtc_vsync_end, VC4_SET_FIELD(mode->crtc_vtotal - mode->crtc_vsync_end +
interlaced,
VC4_HDMI_VERTB_VBP)); VC4_HDMI_VERTB_VBP));
u32 vertb_even = (VC4_SET_FIELD(0, VC5_HDMI_VERTB_VSPO) | u32 vertb_even = (VC4_SET_FIELD(0, VC5_HDMI_VERTB_VSPO) |
VC4_SET_FIELD(mode->crtc_vtotal - VC4_SET_FIELD(mode->crtc_vtotal -
mode->crtc_vsync_end - interlaced, mode->crtc_vsync_end,
VC4_HDMI_VERTB_VBP)); VC4_HDMI_VERTB_VBP));
unsigned long flags; unsigned long flags;
unsigned char gcp; unsigned char gcp;

View File

@@ -370,28 +370,30 @@ static int vc4_hvs_init_channel(struct vc4_hvs *hvs, struct drm_crtc *crtc,
* mode. * mode.
*/ */
dispctrl = SCALER_DISPCTRLX_ENABLE; dispctrl = SCALER_DISPCTRLX_ENABLE;
dispbkgndx = HVS_READ(SCALER_DISPBKGNDX(chan));
if (!vc4->is_vc5) if (!vc4->is_vc5) {
dispctrl |= VC4_SET_FIELD(mode->hdisplay, dispctrl |= VC4_SET_FIELD(mode->hdisplay,
SCALER_DISPCTRLX_WIDTH) | SCALER_DISPCTRLX_WIDTH) |
VC4_SET_FIELD(mode->vdisplay, VC4_SET_FIELD(mode->vdisplay,
SCALER_DISPCTRLX_HEIGHT) | SCALER_DISPCTRLX_HEIGHT) |
(oneshot ? SCALER_DISPCTRLX_ONESHOT : 0); (oneshot ? SCALER_DISPCTRLX_ONESHOT : 0);
else dispbkgndx |= SCALER_DISPBKGND_AUTOHS;
} else {
dispctrl |= VC4_SET_FIELD(mode->hdisplay, dispctrl |= VC4_SET_FIELD(mode->hdisplay,
SCALER5_DISPCTRLX_WIDTH) | SCALER5_DISPCTRLX_WIDTH) |
VC4_SET_FIELD(mode->vdisplay, VC4_SET_FIELD(mode->vdisplay,
SCALER5_DISPCTRLX_HEIGHT) | SCALER5_DISPCTRLX_HEIGHT) |
(oneshot ? SCALER5_DISPCTRLX_ONESHOT : 0); (oneshot ? SCALER5_DISPCTRLX_ONESHOT : 0);
dispbkgndx &= ~SCALER5_DISPBKGND_BCK2BCK;
}
HVS_WRITE(SCALER_DISPCTRLX(chan), dispctrl); HVS_WRITE(SCALER_DISPCTRLX(chan), dispctrl);
dispbkgndx = HVS_READ(SCALER_DISPBKGNDX(chan));
dispbkgndx &= ~SCALER_DISPBKGND_GAMMA; dispbkgndx &= ~SCALER_DISPBKGND_GAMMA;
dispbkgndx &= ~SCALER_DISPBKGND_INTERLACE; dispbkgndx &= ~SCALER_DISPBKGND_INTERLACE;
HVS_WRITE(SCALER_DISPBKGNDX(chan), dispbkgndx | HVS_WRITE(SCALER_DISPBKGNDX(chan), dispbkgndx |
SCALER_DISPBKGND_AUTOHS |
((!vc4->is_vc5) ? SCALER_DISPBKGND_GAMMA : 0) | ((!vc4->is_vc5) ? SCALER_DISPBKGND_GAMMA : 0) |
(interlace ? SCALER_DISPBKGND_INTERLACE : 0)); (interlace ? SCALER_DISPBKGND_INTERLACE : 0));
@@ -568,6 +570,8 @@ void vc4_hvs_atomic_flush(struct drm_crtc *crtc,
bool enable_bg_fill = false; bool enable_bg_fill = false;
u32 __iomem *dlist_start = vc4->hvs->dlist + vc4_state->mm.start; u32 __iomem *dlist_start = vc4->hvs->dlist + vc4_state->mm.start;
u32 __iomem *dlist_next = dlist_start; u32 __iomem *dlist_next = dlist_start;
unsigned int zpos = 0;
bool found = false;
int idx; int idx;
if (!drm_dev_enter(dev, &idx)) { if (!drm_dev_enter(dev, &idx)) {
@@ -575,29 +579,43 @@ void vc4_hvs_atomic_flush(struct drm_crtc *crtc,
return; return;
} }
if (vc4_state->assigned_channel == VC4_HVS_CHANNEL_DISABLED)
return;
if (debug_dump_regs) { if (debug_dump_regs) {
DRM_INFO("CRTC %d HVS before:\n", drm_crtc_index(crtc)); DRM_INFO("CRTC %d HVS before:\n", drm_crtc_index(crtc));
vc4_hvs_dump_state(hvs); vc4_hvs_dump_state(hvs);
} }
/* Copy all the active planes' dlist contents to the hardware dlist. */ /* Copy all the active planes' dlist contents to the hardware dlist. */
drm_atomic_crtc_for_each_plane(plane, crtc) { do {
/* Is this the first active plane? */ found = false;
if (dlist_next == dlist_start) {
/* We need to enable background fill when a plane drm_atomic_crtc_for_each_plane(plane, crtc) {
* could be alpha blending from the background, i.e. if (plane->state->normalized_zpos != zpos)
* where no other plane is underneath. It suffices to continue;
* consider the first active plane here since we set
* needs_bg_fill such that either the first plane /* Is this the first active plane? */
* already needs it or all planes on top blend from if (dlist_next == dlist_start) {
* the first or a lower plane. /* We need to enable background fill when a plane
*/ * could be alpha blending from the background, i.e.
vc4_plane_state = to_vc4_plane_state(plane->state); * where no other plane is underneath. It suffices to
enable_bg_fill = vc4_plane_state->needs_bg_fill; * consider the first active plane here since we set
* needs_bg_fill such that either the first plane
* already needs it or all planes on top blend from
* the first or a lower plane.
*/
vc4_plane_state = to_vc4_plane_state(plane->state);
enable_bg_fill = vc4_plane_state->needs_bg_fill;
}
dlist_next += vc4_plane_write_dlist(plane, dlist_next);
found = true;
} }
dlist_next += vc4_plane_write_dlist(plane, dlist_next); zpos++;
} } while (found);
writel(SCALER_CTL0_END, dlist_next); writel(SCALER_CTL0_END, dlist_next);
dlist_next++; dlist_next++;
@@ -658,7 +676,8 @@ void vc4_hvs_mask_underrun(struct vc4_hvs *hvs, int channel)
return; return;
dispctrl = HVS_READ(SCALER_DISPCTRL); dispctrl = HVS_READ(SCALER_DISPCTRL);
dispctrl &= ~SCALER_DISPCTRL_DSPEISLUR(channel); dispctrl &= ~(hvs->vc4->is_vc5 ? SCALER5_DISPCTRL_DSPEISLUR(channel) :
SCALER_DISPCTRL_DSPEISLUR(channel));
HVS_WRITE(SCALER_DISPCTRL, dispctrl); HVS_WRITE(SCALER_DISPCTRL, dispctrl);
@@ -675,7 +694,8 @@ void vc4_hvs_unmask_underrun(struct vc4_hvs *hvs, int channel)
return; return;
dispctrl = HVS_READ(SCALER_DISPCTRL); dispctrl = HVS_READ(SCALER_DISPCTRL);
dispctrl |= SCALER_DISPCTRL_DSPEISLUR(channel); dispctrl |= (hvs->vc4->is_vc5 ? SCALER5_DISPCTRL_DSPEISLUR(channel) :
SCALER_DISPCTRL_DSPEISLUR(channel));
HVS_WRITE(SCALER_DISPSTAT, HVS_WRITE(SCALER_DISPSTAT,
SCALER_DISPSTAT_EUFLOW(channel)); SCALER_DISPSTAT_EUFLOW(channel));
@@ -701,6 +721,7 @@ static irqreturn_t vc4_hvs_irq_handler(int irq, void *data)
int channel; int channel;
u32 control; u32 control;
u32 status; u32 status;
u32 dspeislur;
/* /*
* NOTE: We don't need to protect the register access using * NOTE: We don't need to protect the register access using
@@ -717,9 +738,11 @@ static irqreturn_t vc4_hvs_irq_handler(int irq, void *data)
control = HVS_READ(SCALER_DISPCTRL); control = HVS_READ(SCALER_DISPCTRL);
for (channel = 0; channel < SCALER_CHANNELS_COUNT; channel++) { for (channel = 0; channel < SCALER_CHANNELS_COUNT; channel++) {
dspeislur = vc4->is_vc5 ? SCALER5_DISPCTRL_DSPEISLUR(channel) :
SCALER_DISPCTRL_DSPEISLUR(channel);
/* Interrupt masking is not always honored, so check it here. */ /* Interrupt masking is not always honored, so check it here. */
if (status & SCALER_DISPSTAT_EUFLOW(channel) && if (status & SCALER_DISPSTAT_EUFLOW(channel) &&
control & SCALER_DISPCTRL_DSPEISLUR(channel)) { control & dspeislur) {
vc4_hvs_mask_underrun(hvs, channel); vc4_hvs_mask_underrun(hvs, channel);
vc4_hvs_report_underrun(dev); vc4_hvs_report_underrun(dev);
@@ -806,7 +829,7 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data)
struct vc4_hvs *hvs = NULL; struct vc4_hvs *hvs = NULL;
int ret; int ret;
u32 dispctrl; u32 dispctrl;
u32 reg; u32 reg, top;
hvs = __vc4_hvs_alloc(vc4, NULL); hvs = __vc4_hvs_alloc(vc4, NULL);
if (IS_ERR(hvs)) if (IS_ERR(hvs))
@@ -899,22 +922,102 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data)
SCALER_DISPCTRL_DISPEIRQ(1) | SCALER_DISPCTRL_DISPEIRQ(1) |
SCALER_DISPCTRL_DISPEIRQ(2); SCALER_DISPCTRL_DISPEIRQ(2);
dispctrl &= ~(SCALER_DISPCTRL_DMAEIRQ | if (!vc4->is_vc5)
SCALER_DISPCTRL_SLVWREIRQ | dispctrl &= ~(SCALER_DISPCTRL_DMAEIRQ |
SCALER_DISPCTRL_SLVRDEIRQ | SCALER_DISPCTRL_SLVWREIRQ |
SCALER_DISPCTRL_DSPEIEOF(0) | SCALER_DISPCTRL_SLVRDEIRQ |
SCALER_DISPCTRL_DSPEIEOF(1) | SCALER_DISPCTRL_DSPEIEOF(0) |
SCALER_DISPCTRL_DSPEIEOF(2) | SCALER_DISPCTRL_DSPEIEOF(1) |
SCALER_DISPCTRL_DSPEIEOLN(0) | SCALER_DISPCTRL_DSPEIEOF(2) |
SCALER_DISPCTRL_DSPEIEOLN(1) | SCALER_DISPCTRL_DSPEIEOLN(0) |
SCALER_DISPCTRL_DSPEIEOLN(2) | SCALER_DISPCTRL_DSPEIEOLN(1) |
SCALER_DISPCTRL_DSPEISLUR(0) | SCALER_DISPCTRL_DSPEIEOLN(2) |
SCALER_DISPCTRL_DSPEISLUR(1) | SCALER_DISPCTRL_DSPEISLUR(0) |
SCALER_DISPCTRL_DSPEISLUR(2) | SCALER_DISPCTRL_DSPEISLUR(1) |
SCALER_DISPCTRL_SCLEIRQ); SCALER_DISPCTRL_DSPEISLUR(2) |
SCALER_DISPCTRL_SCLEIRQ);
else
dispctrl &= ~(SCALER_DISPCTRL_DMAEIRQ |
SCALER5_DISPCTRL_SLVEIRQ |
SCALER5_DISPCTRL_DSPEIEOF(0) |
SCALER5_DISPCTRL_DSPEIEOF(1) |
SCALER5_DISPCTRL_DSPEIEOF(2) |
SCALER5_DISPCTRL_DSPEIEOLN(0) |
SCALER5_DISPCTRL_DSPEIEOLN(1) |
SCALER5_DISPCTRL_DSPEIEOLN(2) |
SCALER5_DISPCTRL_DSPEISLUR(0) |
SCALER5_DISPCTRL_DSPEISLUR(1) |
SCALER5_DISPCTRL_DSPEISLUR(2) |
SCALER_DISPCTRL_SCLEIRQ);
/* Set AXI panic mode.
* VC4 panics when < 2 lines in FIFO.
* VC5 panics when less than 1 line in the FIFO.
*/
dispctrl &= ~(SCALER_DISPCTRL_PANIC0_MASK |
SCALER_DISPCTRL_PANIC1_MASK |
SCALER_DISPCTRL_PANIC2_MASK);
dispctrl |= VC4_SET_FIELD(2, SCALER_DISPCTRL_PANIC0);
dispctrl |= VC4_SET_FIELD(2, SCALER_DISPCTRL_PANIC1);
dispctrl |= VC4_SET_FIELD(2, SCALER_DISPCTRL_PANIC2);
HVS_WRITE(SCALER_DISPCTRL, dispctrl); HVS_WRITE(SCALER_DISPCTRL, dispctrl);
/* Recompute Composite Output Buffer (COB) allocations for the displays
*/
if (!vc4->is_vc5) {
/* The COB is 20736 pixels, or just over 10 lines at 2048 wide.
* The bottom 2048 pixels are full 32bpp RGBA (intended for the
* TXP composing RGBA to memory), whilst the remainder are only
* 24bpp RGB.
*
* Assign 3 lines to channels 1 & 2, and just over 4 lines to
* channel 0.
*/
#define VC4_COB_SIZE 20736
#define VC4_COB_LINE_WIDTH 2048
#define VC4_COB_NUM_LINES 3
reg = 0;
top = VC4_COB_LINE_WIDTH * VC4_COB_NUM_LINES;
reg |= (top - 1) << 16;
HVS_WRITE(SCALER_DISPBASE2, reg);
reg = top;
top += VC4_COB_LINE_WIDTH * VC4_COB_NUM_LINES;
reg |= (top - 1) << 16;
HVS_WRITE(SCALER_DISPBASE1, reg);
reg = top;
top = VC4_COB_SIZE;
reg |= (top - 1) << 16;
HVS_WRITE(SCALER_DISPBASE0, reg);
} else {
/* The COB is 44416 pixels, or 10.8 lines at 4096 wide.
* The bottom 4096 pixels are full RGBA (intended for the TXP
* composing RGBA to memory), whilst the remainder are only
* RGB. Addressing is always pixel wide.
*
* Assign 3 lines of 4096 to channels 1 & 2, and just over 4
* lines. to channel 0.
*/
#define VC5_COB_SIZE 44416
#define VC5_COB_LINE_WIDTH 4096
#define VC5_COB_NUM_LINES 3
reg = 0;
top = VC5_COB_LINE_WIDTH * VC5_COB_NUM_LINES;
reg |= top << 16;
HVS_WRITE(SCALER_DISPBASE2, reg);
top += 16;
reg = top;
top += VC5_COB_LINE_WIDTH * VC5_COB_NUM_LINES;
reg |= top << 16;
HVS_WRITE(SCALER_DISPBASE1, reg);
top += 16;
reg = top;
top = VC5_COB_SIZE;
reg |= top << 16;
HVS_WRITE(SCALER_DISPBASE0, reg);
}
ret = devm_request_irq(dev, platform_get_irq(pdev, 0), ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
vc4_hvs_irq_handler, 0, "vc4 hvs", drm); vc4_hvs_irq_handler, 0, "vc4 hvs", drm);
if (ret) if (ret)

View File

@@ -1074,6 +1074,7 @@ int vc4_kms_load(struct drm_device *dev)
dev->mode_config.helper_private = &vc4_mode_config_helpers; dev->mode_config.helper_private = &vc4_mode_config_helpers;
dev->mode_config.preferred_depth = 24; dev->mode_config.preferred_depth = 24;
dev->mode_config.async_page_flip = true; dev->mode_config.async_page_flip = true;
dev->mode_config.normalize_zpos = true;
ret = vc4_ctm_obj_init(vc4); ret = vc4_ctm_obj_init(vc4);
if (ret) if (ret)

View File

@@ -65,78 +65,176 @@ static const struct hvs_format {
.drm = DRM_FORMAT_RGB565, .drm = DRM_FORMAT_RGB565,
.hvs = HVS_PIXEL_FORMAT_RGB565, .hvs = HVS_PIXEL_FORMAT_RGB565,
.pixel_order = HVS_PIXEL_ORDER_XRGB, .pixel_order = HVS_PIXEL_ORDER_XRGB,
.pixel_order_hvs5 = HVS_PIXEL_ORDER_XRGB,
}, },
{ {
.drm = DRM_FORMAT_BGR565, .drm = DRM_FORMAT_BGR565,
.hvs = HVS_PIXEL_FORMAT_RGB565, .hvs = HVS_PIXEL_FORMAT_RGB565,
.pixel_order = HVS_PIXEL_ORDER_XBGR, .pixel_order = HVS_PIXEL_ORDER_XBGR,
.pixel_order_hvs5 = HVS_PIXEL_ORDER_XBGR,
}, },
{ {
.drm = DRM_FORMAT_ARGB1555, .drm = DRM_FORMAT_ARGB1555,
.hvs = HVS_PIXEL_FORMAT_RGBA5551, .hvs = HVS_PIXEL_FORMAT_RGBA5551,
.pixel_order = HVS_PIXEL_ORDER_ABGR, .pixel_order = HVS_PIXEL_ORDER_ABGR,
.pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB,
}, },
{ {
.drm = DRM_FORMAT_XRGB1555, .drm = DRM_FORMAT_XRGB1555,
.hvs = HVS_PIXEL_FORMAT_RGBA5551, .hvs = HVS_PIXEL_FORMAT_RGBA5551,
.pixel_order = HVS_PIXEL_ORDER_ABGR, .pixel_order = HVS_PIXEL_ORDER_ABGR,
.pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB,
}, },
{ {
.drm = DRM_FORMAT_RGB888, .drm = DRM_FORMAT_RGB888,
.hvs = HVS_PIXEL_FORMAT_RGB888, .hvs = HVS_PIXEL_FORMAT_RGB888,
.pixel_order = HVS_PIXEL_ORDER_XRGB, .pixel_order = HVS_PIXEL_ORDER_XRGB,
.pixel_order_hvs5 = HVS_PIXEL_ORDER_XRGB,
}, },
{ {
.drm = DRM_FORMAT_BGR888, .drm = DRM_FORMAT_BGR888,
.hvs = HVS_PIXEL_FORMAT_RGB888, .hvs = HVS_PIXEL_FORMAT_RGB888,
.pixel_order = HVS_PIXEL_ORDER_XBGR, .pixel_order = HVS_PIXEL_ORDER_XBGR,
.pixel_order_hvs5 = HVS_PIXEL_ORDER_XBGR,
}, },
{ {
.drm = DRM_FORMAT_YUV422, .drm = DRM_FORMAT_YUV422,
.hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_3PLANE, .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_3PLANE,
.pixel_order = HVS_PIXEL_ORDER_XYCBCR, .pixel_order = HVS_PIXEL_ORDER_XYCBCR,
.pixel_order_hvs5 = HVS_PIXEL_ORDER_XYCBCR,
}, },
{ {
.drm = DRM_FORMAT_YVU422, .drm = DRM_FORMAT_YVU422,
.hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_3PLANE, .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_3PLANE,
.pixel_order = HVS_PIXEL_ORDER_XYCRCB, .pixel_order = HVS_PIXEL_ORDER_XYCRCB,
.pixel_order_hvs5 = HVS_PIXEL_ORDER_XYCRCB,
}, },
{ {
.drm = DRM_FORMAT_YUV420, .drm = DRM_FORMAT_YUV420,
.hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE, .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE,
.pixel_order = HVS_PIXEL_ORDER_XYCBCR, .pixel_order = HVS_PIXEL_ORDER_XYCBCR,
.pixel_order_hvs5 = HVS_PIXEL_ORDER_XYCBCR,
}, },
{ {
.drm = DRM_FORMAT_YVU420, .drm = DRM_FORMAT_YVU420,
.hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE, .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE,
.pixel_order = HVS_PIXEL_ORDER_XYCRCB, .pixel_order = HVS_PIXEL_ORDER_XYCRCB,
.pixel_order_hvs5 = HVS_PIXEL_ORDER_XYCRCB,
}, },
{ {
.drm = DRM_FORMAT_NV12, .drm = DRM_FORMAT_NV12,
.hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE, .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE,
.pixel_order = HVS_PIXEL_ORDER_XYCBCR, .pixel_order = HVS_PIXEL_ORDER_XYCBCR,
.pixel_order_hvs5 = HVS_PIXEL_ORDER_XYCBCR,
}, },
{ {
.drm = DRM_FORMAT_NV21, .drm = DRM_FORMAT_NV21,
.hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE, .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE,
.pixel_order = HVS_PIXEL_ORDER_XYCRCB, .pixel_order = HVS_PIXEL_ORDER_XYCRCB,
.pixel_order_hvs5 = HVS_PIXEL_ORDER_XYCRCB,
}, },
{ {
.drm = DRM_FORMAT_NV16, .drm = DRM_FORMAT_NV16,
.hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_2PLANE, .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_2PLANE,
.pixel_order = HVS_PIXEL_ORDER_XYCBCR, .pixel_order = HVS_PIXEL_ORDER_XYCBCR,
.pixel_order_hvs5 = HVS_PIXEL_ORDER_XYCBCR,
}, },
{ {
.drm = DRM_FORMAT_NV61, .drm = DRM_FORMAT_NV61,
.hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_2PLANE, .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_2PLANE,
.pixel_order = HVS_PIXEL_ORDER_XYCRCB, .pixel_order = HVS_PIXEL_ORDER_XYCRCB,
.pixel_order_hvs5 = HVS_PIXEL_ORDER_XYCRCB,
}, },
{ {
.drm = DRM_FORMAT_P030, .drm = DRM_FORMAT_P030,
.hvs = HVS_PIXEL_FORMAT_YCBCR_10BIT, .hvs = HVS_PIXEL_FORMAT_YCBCR_10BIT,
.pixel_order = HVS_PIXEL_ORDER_XYCBCR, .pixel_order_hvs5 = HVS_PIXEL_ORDER_XYCBCR,
.hvs5_only = true, .hvs5_only = true,
}, },
{
.drm = DRM_FORMAT_XRGB2101010,
.hvs = HVS_PIXEL_FORMAT_RGBA1010102,
.pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB,
.hvs5_only = true,
},
{
.drm = DRM_FORMAT_ARGB2101010,
.hvs = HVS_PIXEL_FORMAT_RGBA1010102,
.pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB,
.hvs5_only = true,
},
{
.drm = DRM_FORMAT_ABGR2101010,
.hvs = HVS_PIXEL_FORMAT_RGBA1010102,
.pixel_order_hvs5 = HVS_PIXEL_ORDER_ABGR,
.hvs5_only = true,
},
{
.drm = DRM_FORMAT_XBGR2101010,
.hvs = HVS_PIXEL_FORMAT_RGBA1010102,
.pixel_order_hvs5 = HVS_PIXEL_ORDER_ABGR,
.hvs5_only = true,
},
{
.drm = DRM_FORMAT_RGB332,
.hvs = HVS_PIXEL_FORMAT_RGB332,
.pixel_order = HVS_PIXEL_ORDER_ARGB,
.pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB,
},
{
.drm = DRM_FORMAT_BGR233,
.hvs = HVS_PIXEL_FORMAT_RGB332,
.pixel_order = HVS_PIXEL_ORDER_ABGR,
.pixel_order_hvs5 = HVS_PIXEL_ORDER_ABGR,
},
{
.drm = DRM_FORMAT_XRGB4444,
.hvs = HVS_PIXEL_FORMAT_RGBA4444,
.pixel_order = HVS_PIXEL_ORDER_ABGR,
.pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB,
},
{
.drm = DRM_FORMAT_ARGB4444,
.hvs = HVS_PIXEL_FORMAT_RGBA4444,
.pixel_order = HVS_PIXEL_ORDER_ABGR,
.pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB,
},
{
.drm = DRM_FORMAT_XBGR4444,
.hvs = HVS_PIXEL_FORMAT_RGBA4444,
.pixel_order = HVS_PIXEL_ORDER_ARGB,
.pixel_order_hvs5 = HVS_PIXEL_ORDER_ABGR,
},
{
.drm = DRM_FORMAT_ABGR4444,
.hvs = HVS_PIXEL_FORMAT_RGBA4444,
.pixel_order = HVS_PIXEL_ORDER_ARGB,
.pixel_order_hvs5 = HVS_PIXEL_ORDER_ABGR,
},
{
.drm = DRM_FORMAT_BGRX4444,
.hvs = HVS_PIXEL_FORMAT_RGBA4444,
.pixel_order = HVS_PIXEL_ORDER_RGBA,
.pixel_order_hvs5 = HVS_PIXEL_ORDER_BGRA,
},
{
.drm = DRM_FORMAT_BGRA4444,
.hvs = HVS_PIXEL_FORMAT_RGBA4444,
.pixel_order = HVS_PIXEL_ORDER_RGBA,
.pixel_order_hvs5 = HVS_PIXEL_ORDER_BGRA,
},
{
.drm = DRM_FORMAT_RGBX4444,
.hvs = HVS_PIXEL_FORMAT_RGBA4444,
.pixel_order = HVS_PIXEL_ORDER_BGRA,
.pixel_order_hvs5 = HVS_PIXEL_ORDER_RGBA,
},
{
.drm = DRM_FORMAT_RGBA4444,
.hvs = HVS_PIXEL_FORMAT_RGBA4444,
.pixel_order = HVS_PIXEL_ORDER_BGRA,
.pixel_order_hvs5 = HVS_PIXEL_ORDER_RGBA,
},
}; };
static const struct hvs_format *vc4_get_hvs_format(u32 drm_format) static const struct hvs_format *vc4_get_hvs_format(u32 drm_format)
@@ -1001,15 +1099,10 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
vc4_dlist_write(vc4_state, 0xc0c0c0c0); vc4_dlist_write(vc4_state, 0xc0c0c0c0);
} else { } else {
u32 hvs_pixel_order = format->pixel_order;
if (format->pixel_order_hvs5)
hvs_pixel_order = format->pixel_order_hvs5;
/* Control word */ /* Control word */
vc4_dlist_write(vc4_state, vc4_dlist_write(vc4_state,
SCALER_CTL0_VALID | SCALER_CTL0_VALID |
(hvs_pixel_order << SCALER_CTL0_ORDER_SHIFT) | (format->pixel_order_hvs5 << SCALER_CTL0_ORDER_SHIFT) |
(hvs_format << SCALER_CTL0_PIXEL_FORMAT_SHIFT) | (hvs_format << SCALER_CTL0_PIXEL_FORMAT_SHIFT) |
VC4_SET_FIELD(tiling, SCALER_CTL0_TILING) | VC4_SET_FIELD(tiling, SCALER_CTL0_TILING) |
(vc4_state->is_unity ? (vc4_state->is_unity ?
@@ -1488,6 +1581,16 @@ static bool vc4_format_mod_supported(struct drm_plane *plane,
case DRM_FORMAT_BGRX1010102: case DRM_FORMAT_BGRX1010102:
case DRM_FORMAT_RGBA1010102: case DRM_FORMAT_RGBA1010102:
case DRM_FORMAT_BGRA1010102: case DRM_FORMAT_BGRA1010102:
case DRM_FORMAT_XRGB4444:
case DRM_FORMAT_ARGB4444:
case DRM_FORMAT_XBGR4444:
case DRM_FORMAT_ABGR4444:
case DRM_FORMAT_RGBX4444:
case DRM_FORMAT_RGBA4444:
case DRM_FORMAT_BGRX4444:
case DRM_FORMAT_BGRA4444:
case DRM_FORMAT_RGB332:
case DRM_FORMAT_BGR233:
case DRM_FORMAT_YUV422: case DRM_FORMAT_YUV422:
case DRM_FORMAT_YVU422: case DRM_FORMAT_YVU422:
case DRM_FORMAT_YUV420: case DRM_FORMAT_YUV420:
@@ -1568,9 +1671,14 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev,
DRM_COLOR_YCBCR_BT709, DRM_COLOR_YCBCR_BT709,
DRM_COLOR_YCBCR_LIMITED_RANGE); DRM_COLOR_YCBCR_LIMITED_RANGE);
if (type == DRM_PLANE_TYPE_PRIMARY)
drm_plane_create_zpos_immutable_property(plane, 0);
return plane; return plane;
} }
#define VC4_NUM_OVERLAY_PLANES 16
int vc4_plane_create_additional_planes(struct drm_device *drm) int vc4_plane_create_additional_planes(struct drm_device *drm)
{ {
struct drm_plane *cursor_plane; struct drm_plane *cursor_plane;
@@ -1586,24 +1694,35 @@ int vc4_plane_create_additional_planes(struct drm_device *drm)
* modest number of planes to expose, that should hopefully * modest number of planes to expose, that should hopefully
* still cover any sane usecase. * still cover any sane usecase.
*/ */
for (i = 0; i < 16; i++) { for (i = 0; i < VC4_NUM_OVERLAY_PLANES; i++) {
struct drm_plane *plane = struct drm_plane *plane =
vc4_plane_init(drm, DRM_PLANE_TYPE_OVERLAY, vc4_plane_init(drm, DRM_PLANE_TYPE_OVERLAY,
GENMASK(drm->mode_config.num_crtc - 1, 0)); GENMASK(drm->mode_config.num_crtc - 1, 0));
if (IS_ERR(plane)) if (IS_ERR(plane))
continue; continue;
/* Create zpos property. Max of all the overlays + 1 primary +
* 1 cursor plane on a crtc.
*/
drm_plane_create_zpos_property(plane, i + 1, 1,
VC4_NUM_OVERLAY_PLANES + 1);
} }
drm_for_each_crtc(crtc, drm) { drm_for_each_crtc(crtc, drm) {
/* Set up the legacy cursor after overlay initialization, /* Set up the legacy cursor after overlay initialization,
* since we overlay planes on the CRTC in the order they were * since the zpos fallback is that planes are rendered by plane
* initialized. * ID order, and that then puts the cursor on top.
*/ */
cursor_plane = vc4_plane_init(drm, DRM_PLANE_TYPE_CURSOR, cursor_plane = vc4_plane_init(drm, DRM_PLANE_TYPE_CURSOR,
drm_crtc_mask(crtc)); drm_crtc_mask(crtc));
if (!IS_ERR(cursor_plane)) { if (!IS_ERR(cursor_plane)) {
crtc->cursor = cursor_plane; crtc->cursor = cursor_plane;
drm_plane_create_zpos_property(cursor_plane,
VC4_NUM_OVERLAY_PLANES + 1,
1,
VC4_NUM_OVERLAY_PLANES + 1);
} }
} }

View File

@@ -220,6 +220,12 @@
#define SCALER_DISPCTRL 0x00000000 #define SCALER_DISPCTRL 0x00000000
/* Global register for clock gating the HVS */ /* Global register for clock gating the HVS */
# define SCALER_DISPCTRL_ENABLE BIT(31) # define SCALER_DISPCTRL_ENABLE BIT(31)
# define SCALER_DISPCTRL_PANIC0_MASK VC4_MASK(25, 24)
# define SCALER_DISPCTRL_PANIC0_SHIFT 24
# define SCALER_DISPCTRL_PANIC1_MASK VC4_MASK(27, 26)
# define SCALER_DISPCTRL_PANIC1_SHIFT 26
# define SCALER_DISPCTRL_PANIC2_MASK VC4_MASK(29, 28)
# define SCALER_DISPCTRL_PANIC2_SHIFT 28
# define SCALER_DISPCTRL_DSP3_MUX_MASK VC4_MASK(19, 18) # define SCALER_DISPCTRL_DSP3_MUX_MASK VC4_MASK(19, 18)
# define SCALER_DISPCTRL_DSP3_MUX_SHIFT 18 # define SCALER_DISPCTRL_DSP3_MUX_SHIFT 18
@@ -228,15 +234,21 @@
* always enabled. * always enabled.
*/ */
# define SCALER_DISPCTRL_DSPEISLUR(x) BIT(13 + (x)) # define SCALER_DISPCTRL_DSPEISLUR(x) BIT(13 + (x))
# define SCALER5_DISPCTRL_DSPEISLUR(x) BIT(9 + ((x) * 4))
/* Enables Display 0 end-of-line-N contribution to /* Enables Display 0 end-of-line-N contribution to
* SCALER_DISPSTAT_IRQDISP0 * SCALER_DISPSTAT_IRQDISP0
*/ */
# define SCALER_DISPCTRL_DSPEIEOLN(x) BIT(8 + ((x) * 2)) # define SCALER_DISPCTRL_DSPEIEOLN(x) BIT(8 + ((x) * 2))
# define SCALER5_DISPCTRL_DSPEIEOLN(x) BIT(8 + ((x) * 4))
/* Enables Display 0 EOF contribution to SCALER_DISPSTAT_IRQDISP0 */ /* Enables Display 0 EOF contribution to SCALER_DISPSTAT_IRQDISP0 */
# define SCALER_DISPCTRL_DSPEIEOF(x) BIT(7 + ((x) * 2)) # define SCALER_DISPCTRL_DSPEIEOF(x) BIT(7 + ((x) * 2))
# define SCALER5_DISPCTRL_DSPEIEOF(x) BIT(7 + ((x) * 4))
# define SCALER_DISPCTRL_SLVRDEIRQ BIT(6) # define SCALER5_DISPCTRL_DSPEIVST(x) BIT(6 + ((x) * 4))
# define SCALER_DISPCTRL_SLVWREIRQ BIT(5)
# define SCALER_DISPCTRL_SLVRDEIRQ BIT(6) /* HVS4 only */
# define SCALER_DISPCTRL_SLVWREIRQ BIT(5) /* HVS4 only */
# define SCALER5_DISPCTRL_SLVEIRQ BIT(5)
# define SCALER_DISPCTRL_DMAEIRQ BIT(4) # define SCALER_DISPCTRL_DMAEIRQ BIT(4)
/* Enables interrupt generation on the enabled EOF/EOLN/EISLUR /* Enables interrupt generation on the enabled EOF/EOLN/EISLUR
* bits and short frames.. * bits and short frames..
@@ -360,6 +372,7 @@
#define SCALER_DISPBKGND0 0x00000044 #define SCALER_DISPBKGND0 0x00000044
# define SCALER_DISPBKGND_AUTOHS BIT(31) # define SCALER_DISPBKGND_AUTOHS BIT(31)
# define SCALER5_DISPBKGND_BCK2BCK BIT(31)
# define SCALER_DISPBKGND_INTERLACE BIT(30) # define SCALER_DISPBKGND_INTERLACE BIT(30)
# define SCALER_DISPBKGND_GAMMA BIT(29) # define SCALER_DISPBKGND_GAMMA BIT(29)
# define SCALER_DISPBKGND_TESTMODE_MASK VC4_MASK(28, 25) # define SCALER_DISPBKGND_TESTMODE_MASK VC4_MASK(28, 25)
@@ -835,16 +848,19 @@ enum hvs_pixel_format {
/* Note: the LSB is the rightmost character shown. Only valid for /* Note: the LSB is the rightmost character shown. Only valid for
* HVS_PIXEL_FORMAT_RGB8888, not RGB888. * HVS_PIXEL_FORMAT_RGB8888, not RGB888.
*/ */
/* For modes 332, 4444, 555, 5551, 6666, 8888, 10:10:10:2 */
#define HVS_PIXEL_ORDER_RGBA 0 #define HVS_PIXEL_ORDER_RGBA 0
#define HVS_PIXEL_ORDER_BGRA 1 #define HVS_PIXEL_ORDER_BGRA 1
#define HVS_PIXEL_ORDER_ARGB 2 #define HVS_PIXEL_ORDER_ARGB 2
#define HVS_PIXEL_ORDER_ABGR 3 #define HVS_PIXEL_ORDER_ABGR 3
/* For modes 666 and 888 (4 & 5) */
#define HVS_PIXEL_ORDER_XBRG 0 #define HVS_PIXEL_ORDER_XBRG 0
#define HVS_PIXEL_ORDER_XRBG 1 #define HVS_PIXEL_ORDER_XRBG 1
#define HVS_PIXEL_ORDER_XRGB 2 #define HVS_PIXEL_ORDER_XRGB 2
#define HVS_PIXEL_ORDER_XBGR 3 #define HVS_PIXEL_ORDER_XBGR 3
/* For YCbCr modes (8-12, and 17) */
#define HVS_PIXEL_ORDER_XYCBCR 0 #define HVS_PIXEL_ORDER_XYCBCR 0
#define HVS_PIXEL_ORDER_XYCRCB 1 #define HVS_PIXEL_ORDER_XYCRCB 1
#define HVS_PIXEL_ORDER_YXCBCR 2 #define HVS_PIXEL_ORDER_YXCBCR 2

View File

@@ -613,7 +613,9 @@ static void vc4_vec_encoder_enable(struct drm_encoder *encoder,
VEC_WRITE(VEC_CLMP0_START, 0xac); VEC_WRITE(VEC_CLMP0_START, 0xac);
VEC_WRITE(VEC_CLMP0_END, 0xec); VEC_WRITE(VEC_CLMP0_END, 0xec);
VEC_WRITE(VEC_CONFIG2, VEC_WRITE(VEC_CONFIG2,
VEC_CONFIG2_UV_DIG_DIS | VEC_CONFIG2_RGB_DIG_DIS); VEC_CONFIG2_UV_DIG_DIS |
VEC_CONFIG2_RGB_DIG_DIS |
((adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) ? 0 : VEC_CONFIG2_PROG_SCAN));
VEC_WRITE(VEC_CONFIG3, VEC_CONFIG3_HORIZ_LEN_STD); VEC_WRITE(VEC_CONFIG3, VEC_CONFIG3_HORIZ_LEN_STD);
VEC_WRITE(VEC_DAC_CONFIG, vec->variant->dac_config); VEC_WRITE(VEC_DAC_CONFIG, vec->variant->dac_config);

View File

@@ -160,10 +160,44 @@ static int vkms_plane_atomic_check(struct drm_plane *plane,
return 0; return 0;
} }
static int vkms_prepare_fb(struct drm_plane *plane,
struct drm_plane_state *state)
{
struct drm_shadow_plane_state *shadow_plane_state;
struct drm_framebuffer *fb = state->fb;
int ret;
if (!fb)
return 0;
shadow_plane_state = to_drm_shadow_plane_state(state);
ret = drm_gem_plane_helper_prepare_fb(plane, state);
if (ret)
return ret;
return drm_gem_fb_vmap(fb, shadow_plane_state->map, shadow_plane_state->data);
}
static void vkms_cleanup_fb(struct drm_plane *plane,
struct drm_plane_state *state)
{
struct drm_shadow_plane_state *shadow_plane_state;
struct drm_framebuffer *fb = state->fb;
if (!fb)
return;
shadow_plane_state = to_drm_shadow_plane_state(state);
drm_gem_fb_vunmap(fb, shadow_plane_state->map);
}
static const struct drm_plane_helper_funcs vkms_primary_helper_funcs = { static const struct drm_plane_helper_funcs vkms_primary_helper_funcs = {
.atomic_update = vkms_plane_atomic_update, .atomic_update = vkms_plane_atomic_update,
.atomic_check = vkms_plane_atomic_check, .atomic_check = vkms_plane_atomic_check,
DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, .prepare_fb = vkms_prepare_fb,
.cleanup_fb = vkms_cleanup_fb,
}; };
struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev, struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev,

View File

@@ -10,8 +10,6 @@ struct drm_connector;
struct drm_device; struct drm_device;
struct drm_encoder; struct drm_encoder;
void drm_bridge_connector_enable_hpd(struct drm_connector *connector);
void drm_bridge_connector_disable_hpd(struct drm_connector *connector);
struct drm_connector *drm_bridge_connector_init(struct drm_device *drm, struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
struct drm_encoder *encoder); struct drm_encoder *encoder);

View File

@@ -86,9 +86,22 @@ struct drm_info_node {
* core. * core.
*/ */
struct drm_debugfs_info { struct drm_debugfs_info {
/** @name: File name */
const char *name; const char *name;
/**
* @show:
*
* Show callback. &seq_file->private will be set to the &struct
* drm_debugfs_entry corresponding to the instance of this info
* on a given &struct drm_device.
*/
int (*show)(struct seq_file*, void*); int (*show)(struct seq_file*, void*);
/** @driver_features: Required driver features for this entry. */
u32 driver_features; u32 driver_features;
/** @data: Driver-private data, should not be device-specific. */
void *data; void *data;
}; };
@@ -99,8 +112,13 @@ struct drm_debugfs_info {
* drm_debugfs_info on a &struct drm_device. * drm_debugfs_info on a &struct drm_device.
*/ */
struct drm_debugfs_entry { struct drm_debugfs_entry {
/** @dev: &struct drm_device for this node. */
struct drm_device *dev; struct drm_device *dev;
/** @file: Template for this node. */
struct drm_debugfs_info file; struct drm_debugfs_info file;
/** @list: Linked list of all device nodes. */
struct list_head list; struct list_head list;
}; };

View File

@@ -87,10 +87,23 @@ struct drm_device {
*/ */
void *dev_private; void *dev_private;
/** @primary: Primary node */ /**
* @primary:
*
* Primary node. Drivers should not interact with this
* directly. debugfs interfaces can be registered with
* drm_debugfs_add_file(), and sysfs should be directly added on the
* hardware (and not character device node) struct device @dev.
*/
struct drm_minor *primary; struct drm_minor *primary;
/** @render: Render node */ /**
* @render:
*
* Render node. Drivers should not interact with this directly ever.
* Drivers should not expose any additional interfaces in debugfs or
* sysfs on this node.
*/
struct drm_minor *render; struct drm_minor *render;
/** @accel: Compute Acceleration node */ /** @accel: Compute Acceleration node */

View File

@@ -30,12 +30,27 @@ void drm_fb_xrgb8888_to_rgb332(struct iosys_map *dst, const unsigned int *dst_pi
void drm_fb_xrgb8888_to_rgb565(struct iosys_map *dst, const unsigned int *dst_pitch, void drm_fb_xrgb8888_to_rgb565(struct iosys_map *dst, const unsigned int *dst_pitch,
const struct iosys_map *src, const struct drm_framebuffer *fb, const struct iosys_map *src, const struct drm_framebuffer *fb,
const struct drm_rect *clip, bool swab); const struct drm_rect *clip, bool swab);
void drm_fb_xrgb8888_to_xrgb1555(struct iosys_map *dst, const unsigned int *dst_pitch,
const struct iosys_map *src, const struct drm_framebuffer *fb,
const struct drm_rect *clip);
void drm_fb_xrgb8888_to_argb1555(struct iosys_map *dst, const unsigned int *dst_pitch,
const struct iosys_map *src, const struct drm_framebuffer *fb,
const struct drm_rect *clip);
void drm_fb_xrgb8888_to_rgba5551(struct iosys_map *dst, const unsigned int *dst_pitch,
const struct iosys_map *src, const struct drm_framebuffer *fb,
const struct drm_rect *clip);
void drm_fb_xrgb8888_to_rgb888(struct iosys_map *dst, const unsigned int *dst_pitch, void drm_fb_xrgb8888_to_rgb888(struct iosys_map *dst, const unsigned int *dst_pitch,
const struct iosys_map *src, const struct drm_framebuffer *fb, const struct iosys_map *src, const struct drm_framebuffer *fb,
const struct drm_rect *clip); const struct drm_rect *clip);
void drm_fb_xrgb8888_to_argb8888(struct iosys_map *dst, const unsigned int *dst_pitch,
const struct iosys_map *src, const struct drm_framebuffer *fb,
const struct drm_rect *clip);
void drm_fb_xrgb8888_to_xrgb2101010(struct iosys_map *dst, const unsigned int *dst_pitch, void drm_fb_xrgb8888_to_xrgb2101010(struct iosys_map *dst, const unsigned int *dst_pitch,
const struct iosys_map *src, const struct drm_framebuffer *fb, const struct iosys_map *src, const struct drm_framebuffer *fb,
const struct drm_rect *clip); const struct drm_rect *clip);
void drm_fb_xrgb8888_to_argb2101010(struct iosys_map *dst, const unsigned int *dst_pitch,
const struct iosys_map *src, const struct drm_framebuffer *fb,
const struct drm_rect *clip);
void drm_fb_xrgb8888_to_gray8(struct iosys_map *dst, const unsigned int *dst_pitch, void drm_fb_xrgb8888_to_gray8(struct iosys_map *dst, const unsigned int *dst_pitch,
const struct iosys_map *src, const struct drm_framebuffer *fb, const struct iosys_map *src, const struct drm_framebuffer *fb,
const struct drm_rect *clip); const struct drm_rect *clip);
@@ -50,7 +65,6 @@ void drm_fb_xrgb8888_to_mono(struct iosys_map *dst, const unsigned int *dst_pitc
size_t drm_fb_build_fourcc_list(struct drm_device *dev, size_t drm_fb_build_fourcc_list(struct drm_device *dev,
const u32 *native_fourccs, size_t native_nfourccs, const u32 *native_fourccs, size_t native_nfourccs,
const u32 *extra_fourccs, size_t extra_nfourccs,
u32 *fourccs_out, size_t nfourccs_out); u32 *fourccs_out, size_t nfourccs_out);
#endif /* __LINUX_DRM_FORMAT_HELPER_H */ #endif /* __LINUX_DRM_FORMAT_HELPER_H */

View File

@@ -297,21 +297,42 @@ int mipi_dsi_dcs_set_display_brightness(struct mipi_dsi_device *dsi,
int mipi_dsi_dcs_get_display_brightness(struct mipi_dsi_device *dsi, int mipi_dsi_dcs_get_display_brightness(struct mipi_dsi_device *dsi,
u16 *brightness); u16 *brightness);
/**
* mipi_dsi_generic_write_seq - transmit data using a generic write packet
* @dsi: DSI peripheral device
* @seq: buffer containing the payload
*/
#define mipi_dsi_generic_write_seq(dsi, seq...) \
do { \
static const u8 d[] = { seq }; \
struct device *dev = &dsi->dev; \
int ret; \
ret = mipi_dsi_generic_write(dsi, d, ARRAY_SIZE(d)); \
if (ret < 0) { \
dev_err_ratelimited(dev, "transmit data failed: %d\n", \
ret); \
return ret; \
} \
} while (0)
/** /**
* mipi_dsi_dcs_write_seq - transmit a DCS command with payload * mipi_dsi_dcs_write_seq - transmit a DCS command with payload
* @dsi: DSI peripheral device * @dsi: DSI peripheral device
* @cmd: Command * @cmd: Command
* @seq: buffer containing data to be transmitted * @seq: buffer containing data to be transmitted
*/ */
#define mipi_dsi_dcs_write_seq(dsi, cmd, seq...) do { \ #define mipi_dsi_dcs_write_seq(dsi, cmd, seq...) \
static const u8 d[] = { cmd, seq }; \ do { \
struct device *dev = &dsi->dev; \ static const u8 d[] = { cmd, seq }; \
int ret; \ struct device *dev = &dsi->dev; \
ret = mipi_dsi_dcs_write_buffer(dsi, d, ARRAY_SIZE(d)); \ int ret; \
if (ret < 0) { \ ret = mipi_dsi_dcs_write_buffer(dsi, d, ARRAY_SIZE(d)); \
dev_err_ratelimited(dev, "sending command %#02x failed: %d\n", cmd, ret); \ if (ret < 0) { \
return ret; \ dev_err_ratelimited( \
} \ dev, "sending command %#02x failed: %d\n", \
cmd, ret); \
return ret; \
} \
} while (0) } while (0)
/** /**

View File

@@ -1143,6 +1143,28 @@ struct drm_connector_helper_funcs {
*/ */
void (*cleanup_writeback_job)(struct drm_writeback_connector *connector, void (*cleanup_writeback_job)(struct drm_writeback_connector *connector,
struct drm_writeback_job *job); struct drm_writeback_job *job);
/**
* @enable_hpd:
*
* Enable hot-plug detection for the connector.
*
* This operation is optional.
*
* This callback is used by the drm_kms_helper_poll_enable() helpers.
*/
void (*enable_hpd)(struct drm_connector *connector);
/**
* @disable_hpd:
*
* Disable hot-plug detection for the connector.
*
* This operation is optional.
*
* This callback is used by the drm_kms_helper_poll_disable() helpers.
*/
void (*disable_hpd)(struct drm_connector *connector);
}; };
/** /**

View File

@@ -88,6 +88,18 @@ extern "C" {
* *
* The authoritative list of format modifier codes is found in * The authoritative list of format modifier codes is found in
* `include/uapi/drm/drm_fourcc.h` * `include/uapi/drm/drm_fourcc.h`
*
* Open Source User Waiver
* -----------------------
*
* Because this is the authoritative source for pixel formats and modifiers
* referenced by GL, Vulkan extensions and other standards and hence used both
* by open source and closed source driver stacks, the usual requirement for an
* upstream in-kernel or open source userspace user does not apply.
*
* To ensure, as much as feasible, compatibility across stacks and avoid
* confusion with incompatible enumerations stakeholders for all relevant driver
* stacks should approve additions.
*/ */
#define fourcc_code(a, b, c, d) ((__u32)(a) | ((__u32)(b) << 8) | \ #define fourcc_code(a, b, c, d) ((__u32)(a) | ((__u32)(b) << 8) | \