Commit c9e9ce0b authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge tag 'drm-misc-next-2022-03-03' of git://anongit.freedesktop.org/drm/drm-misc into drm-next


drm-misc-next for v5.18:

UAPI Changes:

Cross-subsystem Changes:
- Improve performance of some fbdev ops, in some cases up to 6x faster.

Core Changes:
- Some small DP fixes.
- Find panels in subnodes of OF devices, and add of_get_drm_panel_display_mode
  to retrieve mode.
- Add drm_object_property_get_default_value and use it for resetting
  zpos in plane state reset, removing the need for individual drivers
  to do it.
- Same for color encoding and color range props.
- Update panic handling todo doc.
- Add todo that format conversion helpers should be sped up similarly to fbdev ops.

Driver Changes:
- Add panel orientation property to simpledrm for quirked panels.
- Assorted small fixes to tiny/repaper, nouveau, stm, omap, ssd130x.
- Add crc support to stm/ltdc.
- Add MIPI DBI compatible SPI driver
- Assorted small fixes to tiny panels and bridge drivers.
- Add AST2600 support to aspeed.
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>

From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/48fabd78-ade9-f80b-c724-13726c7be69e@linux.intel.com
parents f298a2b9 701920ca
# SPDX-License-Identifier: (GPL-2.0-only or BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/panel/panel-mipi-dbi-spi.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MIPI DBI SPI Panel
maintainers:
- Noralf Trønnes <noralf@tronnes.org>
description: |
This binding is for display panels using a MIPI DBI compatible controller
in SPI mode.
The MIPI Alliance Standard for Display Bus Interface defines the electrical
and logical interfaces for display controllers historically used in mobile
phones. The standard defines 4 display architecture types and this binding is
for type 1 which has full frame memory. There are 3 interface types in the
standard and type C is the serial interface.
The standard defines the following interface signals for type C:
- Power:
- Vdd: Power supply for display module
- Vddi: Logic level supply for interface signals
Combined into one in this binding called: power-supply
- Interface:
- CSx: Chip select
- SCL: Serial clock
- Dout: Serial out
- Din: Serial in
- SDA: Bidrectional in/out
- D/CX: Data/command selection, high=data, low=command
Called dc-gpios in this binding.
- RESX: Reset when low
Called reset-gpios in this binding.
The type C interface has 3 options:
- Option 1: 9-bit mode and D/CX as the 9th bit
| Command | the next command or following data |
|<0><D7><D6><D5><D4><D3><D2><D1><D0>|<D/CX><D7><D6><D5><D4><D3><D2><D1><D0>|
- Option 2: 16-bit mode and D/CX as a 9th bit
| Command or data |
|<X><X><X><X><X><X><X><D/CX><D7><D6><D5><D4><D3><D2><D1><D0>|
- Option 3: 8-bit mode and D/CX as a separate interface line
| Command or data |
|<D7><D6><D5><D4><D3><D2><D1><D0>|
The panel resolution is specified using the panel-timing node properties
hactive (width) and vactive (height). The other mandatory panel-timing
properties should be set to zero except clock-frequency which can be
optionally set to inform about the actual pixel clock frequency.
If the panel is wired to the controller at an offset specify this using
hback-porch (x-offset) and vback-porch (y-offset).
allOf:
- $ref: panel-common.yaml#
- $ref: /schemas/spi/spi-peripheral-props.yaml#
properties:
compatible:
items:
- enum:
- sainsmart18
- const: panel-mipi-dbi-spi
write-only:
type: boolean
description:
Controller is not readable (ie. Din (MISO on the SPI interface) is not
wired up).
dc-gpios:
maxItems: 1
description: |
Controller data/command selection (D/CX) in 4-line SPI mode.
If not set, the controller is in 3-line SPI mode.
required:
- compatible
- reg
- panel-timing
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
spi {
#address-cells = <1>;
#size-cells = <0>;
display@0{
compatible = "sainsmart18", "panel-mipi-dbi-spi";
reg = <0>;
spi-max-frequency = <40000000>;
dc-gpios = <&gpio 24 GPIO_ACTIVE_HIGH>;
reset-gpios = <&gpio 25 GPIO_ACTIVE_HIGH>;
write-only;
backlight = <&backlight>;
width-mm = <35>;
height-mm = <28>;
panel-timing {
hactive = <160>;
vactive = <128>;
hback-porch = <0>;
vback-porch = <0>;
clock-frequency = <0>;
hfront-porch = <0>;
hsync-len = <0>;
vfront-porch = <0>;
vsync-len = <0>;
};
};
};
...
......@@ -241,6 +241,28 @@ Contact: Thomas Zimmermann <tzimmermann@suse.de>, Daniel Vetter
Level: Advanced
Benchmark and optimize blitting and format-conversion function
--------------------------------------------------------------
Drawing to dispay memory quickly is crucial for many applications'
performance.
On at least x86-64, sys_imageblit() is significantly slower than
cfb_imageblit(), even though both use the same blitting algorithm and
the latter is written for I/O memory. It turns out that cfb_imageblit()
uses movl instructions, while sys_imageblit apparently does not. This
seems to be a problem with gcc's optimizer. DRM's format-conversion
helpers might be subject to similar issues.
Benchmark and optimize fbdev's sys_() helpers and DRM's format-conversion
helpers. In cases that can be further optimized, maybe implement a different
algorithm. For micro-optimizations, use movl/movq instructions explicitly.
That might possibly require architecture-specific helpers (e.g., storel()
storeq()).
Contact: Thomas Zimmermann <tzimmermann@suse.de>
Level: Intermediate
drm_framebuffer_funcs and drm_mode_config_funcs.fb_create cleanup
-----------------------------------------------------------------
......@@ -475,8 +497,12 @@ This is a really varied tasks with lots of little bits and pieces:
achieved by using an IPI to the local processor.
* There's a massive confusion of different panic handlers. DRM fbdev emulation
helpers have one, but on top of that the fbcon code itself also has one. We
need to make sure that they stop fighting over each another.
helpers had their own (long removed), but on top of that the fbcon code itself
also has one. We need to make sure that they stop fighting over each other.
This is worked around by checking ``oops_in_progress`` at various entry points
into the DRM fbdev emulation helpers. A much cleaner approach here would be to
switch fbcon to the `threaded printk support
<https://lwn.net/Articles/800946/>`_.
* ``drm_can_sleep()`` is a mess. It hides real bugs in normal operations and
isn't a full solution for panic paths. We need to make sure that it only
......@@ -488,16 +514,15 @@ This is a really varied tasks with lots of little bits and pieces:
even spinlocks (because NMI and hardirq can panic too). We need to either
make sure to not call such paths, or trylock everything. Really tricky.
* For the above locking troubles reasons it's pretty much impossible to
attempt a synchronous modeset from panic handlers. The only thing we could
try to achive is an atomic ``set_base`` of the primary plane, and hope that
it shows up. Everything else probably needs to be delayed to some worker or
something else which happens later on. Otherwise it just kills the box
harder, prevent the panic from going out on e.g. netconsole.
* A clean solution would be an entirely separate panic output support in KMS,
bypassing the current fbcon support. See `[PATCH v2 0/3] drm: Add panic handling
<https://lore.kernel.org/dri-devel/20190311174218.51899-1-noralf@tronnes.org/>`_.
* There's also proposal for a simplied DRM console instead of the full-blown
fbcon and DRM fbdev emulation. Any kind of panic handling tricks should
obviously work for both console, in case we ever get kmslog merged.
* Encoding the actual oops and preceding dmesg in a QR might help with the
dread "important stuff scrolled away" problem. See `[RFC][PATCH] Oops messages
transfer using QR codes
<https://lore.kernel.org/lkml/1446217392-11981-1-git-send-email-alexandru.murtaza@intel.com/>`_
for some example code that could be reused.
Contact: Daniel Vetter
......
......@@ -6112,6 +6112,14 @@ T: git git://anongit.freedesktop.org/drm/drm-misc
F: Documentation/devicetree/bindings/display/multi-inno,mi0283qt.txt
F: drivers/gpu/drm/tiny/mi0283qt.c
 
DRM DRIVER FOR MIPI DBI compatible panels
M: Noralf Trønnes <noralf@tronnes.org>
S: Maintained
W: https://github.com/notro/panel-mipi-dbi/wiki
T: git git://anongit.freedesktop.org/drm/drm-misc
F: Documentation/devicetree/bindings/display/panel/panel-mipi-dbi-spi.yaml
F: drivers/gpu/drm/tiny/panel-mipi-dbi.c
DRM DRIVER FOR MSM ADRENO GPU
M: Rob Clark <robdclark@gmail.com>
M: Sean Paul <sean@poorly.run>
......
......@@ -12,6 +12,7 @@ struct aspeed_gfx {
struct regmap *scu;
u32 dac_reg;
u32 int_clr_reg;
u32 vga_scratch_reg;
u32 throd_val;
u32 scan_line_max;
......
......@@ -61,6 +61,7 @@
struct aspeed_gfx_config {
u32 dac_reg; /* DAC register in SCU */
u32 int_clear_reg; /* Interrupt clear register */
u32 vga_scratch_reg; /* VGA scratch register in SCU */
u32 throd_val; /* Default Threshold Seting */
u32 scan_line_max; /* Max memory size of one scan line */
......@@ -68,6 +69,7 @@ struct aspeed_gfx_config {
static const struct aspeed_gfx_config ast2400_config = {
.dac_reg = 0x2c,
.int_clear_reg = 0x60,
.vga_scratch_reg = 0x50,
.throd_val = CRT_THROD_LOW(0x1e) | CRT_THROD_HIGH(0x12),
.scan_line_max = 64,
......@@ -75,14 +77,24 @@ static const struct aspeed_gfx_config ast2400_config = {
static const struct aspeed_gfx_config ast2500_config = {
.dac_reg = 0x2c,
.int_clear_reg = 0x60,
.vga_scratch_reg = 0x50,
.throd_val = CRT_THROD_LOW(0x24) | CRT_THROD_HIGH(0x3c),
.scan_line_max = 128,
};
static const struct aspeed_gfx_config ast2600_config = {
.dac_reg = 0xc0,
.int_clear_reg = 0x68,
.vga_scratch_reg = 0x50,
.throd_val = CRT_THROD_LOW(0x50) | CRT_THROD_HIGH(0x70),
.scan_line_max = 128,
};
static const struct of_device_id aspeed_gfx_match[] = {
{ .compatible = "aspeed,ast2400-gfx", .data = &ast2400_config },
{ .compatible = "aspeed,ast2500-gfx", .data = &ast2500_config },
{ .compatible = "aspeed,ast2600-gfx", .data = &ast2600_config },
{ },
};
MODULE_DEVICE_TABLE(of, aspeed_gfx_match);
......@@ -120,7 +132,7 @@ static irqreturn_t aspeed_gfx_irq_handler(int irq, void *data)
if (reg & CRT_CTRL_VERTICAL_INTR_STS) {
drm_crtc_handle_vblank(&priv->pipe.crtc);
writel(reg, priv->base + CRT_CTRL1);
writel(reg, priv->base + priv->int_clr_reg);
return IRQ_HANDLED;
}
......@@ -148,6 +160,7 @@ static int aspeed_gfx_load(struct drm_device *drm)
config = match->data;
priv->dac_reg = config->dac_reg;
priv->int_clr_reg = config->int_clear_reg;
priv->vga_scratch_reg = config->vga_scratch_reg;
priv->throd_val = config->throd_val;
priv->scan_line_max = config->scan_line_max;
......
......@@ -253,6 +253,8 @@ static int anx7625_aux_trans(struct anx7625_data *ctx, u8 op, u32 address,
addrm = (address >> 8) & 0xFF;
addrh = (address >> 16) & 0xFF;
if (!is_write)
op &= ~DP_AUX_I2C_MOT;
cmd = DPCD_CMD(len, op);
/* Set command and length */
......@@ -2736,8 +2738,8 @@ static int anx7625_i2c_remove(struct i2c_client *client)
if (platform->hdcp_workqueue) {
cancel_delayed_work(&platform->hdcp_work);
flush_workqueue(platform->workqueue);
destroy_workqueue(platform->workqueue);
flush_workqueue(platform->hdcp_workqueue);
destroy_workqueue(platform->hdcp_workqueue);
}
if (!platform->pdata.low_power_mode)
......
......@@ -1284,6 +1284,7 @@ static const struct of_device_id cdns_dsi_of_match[] = {
{ .compatible = "cdns,dsi" },
{ },
};
MODULE_DEVICE_TABLE(of, cdns_dsi_of_match);
static struct platform_driver cdns_dsi_platform_driver = {
.probe = cdns_dsi_drm_probe,
......
......@@ -191,7 +191,6 @@ static const struct drm_bridge_funcs chipone_bridge_funcs = {
static int chipone_parse_dt(struct chipone *icn)
{
struct device *dev = icn->dev;
struct drm_panel *panel;
int ret;
icn->vdd1 = devm_regulator_get_optional(dev, "vdd1");
......@@ -227,11 +226,7 @@ static int chipone_parse_dt(struct chipone *icn)
return PTR_ERR(icn->enable_gpio);
}
ret = drm_of_find_panel_or_bridge(dev->of_node, 1, 0, &panel, NULL);
if (ret)
return ret;
icn->panel_bridge = devm_drm_panel_bridge_add(dev, panel);
icn->panel_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0);
if (IS_ERR(icn->panel_bridge))
return PTR_ERR(icn->panel_bridge);
......
......@@ -289,7 +289,7 @@
#define WORD_LENGTH_20BIT 2
#define WORD_LENGTH_24BIT 3
#define DEBUGFS_DIR_NAME "it6505-debugfs"
#define READ_BUFFER_SIZE 200
#define READ_BUFFER_SIZE 400
/* Vendor option */
#define HDCP_DESIRED 1
......@@ -3074,7 +3074,7 @@ static ssize_t receive_timing_debugfs_show(struct file *file, char __user *buf,
struct it6505 *it6505 = file->private_data;
struct drm_display_mode *vid = &it6505->video_info;
u8 read_buf[READ_BUFFER_SIZE];
u8 *str = read_buf, *end = read_buf + PAGE_SIZE;
u8 *str = read_buf, *end = read_buf + READ_BUFFER_SIZE;
ssize_t ret, count;
if (!it6505)
......
......@@ -332,17 +332,13 @@ static int nwl_dsi_config_dpi(struct nwl_dsi *dsi)
static int nwl_dsi_init_interrupts(struct nwl_dsi *dsi)
{
u32 irq_enable;
nwl_dsi_write(dsi, NWL_DSI_IRQ_MASK, 0xffffffff);
nwl_dsi_write(dsi, NWL_DSI_IRQ_MASK2, 0x7);
irq_enable = ~(u32)(NWL_DSI_TX_PKT_DONE_MASK |
NWL_DSI_RX_PKT_HDR_RCVD_MASK |
NWL_DSI_TX_FIFO_OVFLW_MASK |
NWL_DSI_HS_TX_TIMEOUT_MASK);
u32 irq_enable = ~(u32)(NWL_DSI_TX_PKT_DONE_MASK |
NWL_DSI_RX_PKT_HDR_RCVD_MASK |
NWL_DSI_TX_FIFO_OVFLW_MASK |
NWL_DSI_HS_TX_TIMEOUT_MASK);
nwl_dsi_write(dsi, NWL_DSI_IRQ_MASK, irq_enable);
nwl_dsi_write(dsi, NWL_DSI_IRQ_MASK2, 0x7);
return nwl_dsi_clear_error(dsi);
}
......
......@@ -208,16 +208,6 @@ bool drm_dp_128b132b_link_training_failed(const u8 link_status[DP_LINK_STATUS_SI
}
EXPORT_SYMBOL(drm_dp_128b132b_link_training_failed);
u8 drm_dp_get_adjust_request_post_cursor(const u8 link_status[DP_LINK_STATUS_SIZE],
unsigned int lane)
{
unsigned int offset = DP_ADJUST_REQUEST_POST_CURSOR2;
u8 value = dp_link_status(link_status, offset);
return (value >> (lane << 1)) & 0x3;
}
EXPORT_SYMBOL(drm_dp_get_adjust_request_post_cursor);
static int __8b10b_clock_recovery_delay_us(const struct drm_dp_aux *aux, u8 rd_interval)
{
if (rd_interval > 4)
......
......@@ -243,11 +243,36 @@ EXPORT_SYMBOL(drm_atomic_helper_crtc_destroy_state);
void __drm_atomic_helper_plane_state_reset(struct drm_plane_state *plane_state,
struct drm_plane *plane)
{
u64 val;
plane_state->plane = plane;
plane_state->rotation = DRM_MODE_ROTATE_0;
plane_state->alpha = DRM_BLEND_ALPHA_OPAQUE;
plane_state->pixel_blend_mode = DRM_MODE_BLEND_PREMULTI;
if (plane->color_encoding_property) {
if (!drm_object_property_get_default_value(&plane->base,
plane->color_encoding_property,
&val))
plane_state->color_encoding = val;
}
if (plane->color_range_property) {
if (!drm_object_property_get_default_value(&plane->base,
plane->color_range_property,
&val))
plane_state->color_range = val;
}
if (plane->zpos_property) {
if (!drm_object_property_get_default_value(&plane->base,
plane->zpos_property,
&val)) {
plane_state->zpos = val;
plane_state->normalized_zpos = val;
}
}
}
EXPORT_SYMBOL(__drm_atomic_helper_plane_state_reset);
......
......@@ -297,11 +297,26 @@ int drm_object_property_set_value(struct drm_mode_object *obj,
}
EXPORT_SYMBOL(drm_object_property_set_value);
static int __drm_object_property_get_prop_value(struct drm_mode_object *obj,
struct drm_property *property,
uint64_t *val)
{
int i;
for (i = 0; i < obj->properties->count; i++) {
if (obj->properties->properties[i] == property) {
*val = obj->properties->values[i];
return 0;
}
}
return -EINVAL;
}
static int __drm_object_property_get_value(struct drm_mode_object *obj,
struct drm_property *property,
uint64_t *val)
{
int i;
/* read-only properties bypass atomic mechanism and still store
* their value in obj->properties->values[].. mostly to avoid
......@@ -311,15 +326,7 @@ static int __drm_object_property_get_value(struct drm_mode_object *obj,
!(property->flags & DRM_MODE_PROP_IMMUTABLE))
return drm_atomic_get_property(obj, property, val);
for (i = 0; i < obj->properties->count; i++) {
if (obj->properties->properties[i] == property) {
*val = obj->properties->values[i];
return 0;
}
}
return -EINVAL;
return __drm_object_property_get_prop_value(obj, property, val);
}
/**
......@@ -348,6 +355,32 @@ int drm_object_property_get_value(struct drm_mode_object *obj,
}
EXPORT_SYMBOL(drm_object_property_get_value);
/**
* drm_object_property_get_default_value - retrieve the default value of a
* property when in atomic mode.
* @obj: drm mode object to get property value from
* @property: property to retrieve
* @val: storage for the property value
*
* This function retrieves the default state of the given property as passed in
* to drm_object_attach_property
*
* Only atomic drivers should call this function directly, as for non-atomic
* drivers it will return the current value.
*
* Returns:
* Zero on success, error code on failure.
*/
int drm_object_property_get_default_value(struct drm_mode_object *obj,
struct drm_property *property,
uint64_t *val)
{
WARN_ON(!drm_drv_uses_atomic_modeset(property->dev));
return __drm_object_property_get_prop_value(obj, property, val);
}
EXPORT_SYMBOL(drm_object_property_get_default_value);
/* helper for getconnector and getproperties ioctls */
int drm_mode_object_get_properties(struct drm_mode_object *obj, bool atomic,
uint32_t __user *prop_ptr,
......
......@@ -35,6 +35,7 @@
#include <linux/list_sort.h>
#include <linux/export.h>
#include <video/of_display_timing.h>
#include <video/of_videomode.h>
#include <video/videomode.h>
......@@ -127,7 +128,7 @@ EXPORT_SYMBOL(drm_mode_probed_add);
* according to the hdisplay, vdisplay, vrefresh.
* It is based from the VESA(TM) Coordinated Video Timing Generator by
* Graham Loveridge April 9, 2003 available at
* http://www.elo.utfsm.cl/~elo212/docs/CVTd6r1.xls
* http://www.elo.utfsm.cl/~elo212/docs/CVTd6r1.xls
*
* And it is copied from xf86CVTmode in xserver/hw/xfree86/modes/xf86cvt.c.
* What I have done is to translate it by using integer calculation.
......@@ -727,6 +728,54 @@ int of_get_drm_display_mode(struct device_node *np,
return 0;
}
EXPORT_SYMBOL_GPL(of_get_drm_display_mode);
/**
* of_get_drm_panel_display_mode - get a panel-timing drm_display_mode from devicetree
* @np: device_node with the panel-timing specification
* @dmode: will be set to the return value
* @bus_flags: information about pixelclk, sync and DE polarity
*
* The Device Tree properties width-mm and height-mm will be read and set on
* the display mode if they are present.
*
* Returns:
* Zero on success, negative error code on failure.
*/
int of_get_drm_panel_display_mode(struct device_node *np,
struct drm_display_mode *dmode, u32 *bus_flags)
{
u32 width_mm = 0, height_mm = 0;
struct display_timing timing;
struct videomode vm;
int ret;
ret = of_get_display_timing(np, "panel-timing", &timing);
if (ret)
return ret;
videomode_from_timing(&timing, &vm);
memset(dmode, 0, sizeof(*dmode));
drm_display_mode_from_videomode(&vm, dmode);
if (bus_flags)
drm_bus_flags_from_videomode(&vm, bus_flags);
ret = of_property_read_u32(np, "width-mm", &width_mm);
if (ret && ret != -EINVAL)
return ret;
ret = of_property_read_u32(np, "height-mm", &height_mm);
if (ret && ret != -EINVAL)
return ret;
dmode->width_mm = width_mm;
dmode->height_mm = height_mm;
drm_mode_debug_printmodeline(dmode);
return 0;
}
EXPORT_SYMBOL_GPL(of_get_drm_panel_display_mode);
#endif /* CONFIG_OF */
#endif /* CONFIG_VIDEOMODE_HELPERS */
......
......@@ -249,6 +249,21 @@ int drm_of_find_panel_or_bridge(const struct device_node *np,
if (panel)
*panel = NULL;
/**
* Devices can also be child nodes when we also control that device
* through the upstream device (ie, MIPI-DCS for a MIPI-DSI device).
*
* Lookup for a child node of the given parent that isn't either port
* or ports.
*/
for_each_available_child_of_node(np, remote) {
if (of_node_name_eq(remote, "port") ||
of_node_name_eq(remote, "ports"))
continue;
goto of_find_panel_or_bridge;
}
/*
* of_graph_get_remote_node() produces a noisy error message if port
* node isn't found and the absence of the port is a legit case here,
......@@ -259,6 +274,8 @@ int drm_of_find_panel_or_bridge(const struct device_node *np,
return -ENODEV;
remote = of_graph_get_remote_node(np, port, endpoint);
of_find_panel_or_bridge:
if (!remote)
return -ENODEV;
......
......@@ -48,6 +48,8 @@ static void mdp5_plane_destroy(struct drm_plane *plane)
static void mdp5_plane_install_properties(struct drm_plane *plane,
struct drm_mode_object *obj)
{
unsigned int zpos;
drm_plane_create_rotation_property(plane,
DRM_MODE_ROTATE_0,
DRM_MODE_ROTATE_0 |
......@@ -59,7 +61,12 @@ static void mdp5_plane_install_properties(struct drm_plane *plane,
BIT(DRM_MODE_BLEND_PIXEL_NONE) |
BIT(DRM_MODE_BLEND_PREMULTI) |
BIT(DRM_MODE_BLEND_COVERAGE));
drm_plane_create_zpos_property(plane, 1, 1, 255);
if (plane->type == DRM_PLANE_TYPE_PRIMARY)
zpos = STAGE_BASE;
else
zpos = STAGE0 + drm_plane_index(plane);
drm_plane_create_zpos_property(plane, zpos, 1, 255);
}
static void
......@@ -91,13 +98,6 @@ static void mdp5_plane_reset(struct drm_plane *plane)
kfree(to_mdp5_plane_state(plane->state));
mdp5_state = kzalloc(sizeof(*mdp5_state), GFP_KERNEL);
if (plane->type == DRM_PLANE_TYPE_PRIMARY)
mdp5_state->base.zpos = STAGE_BASE;
else
mdp5_state->base.zpos = STAGE0 + drm_plane_index(plane);
mdp5_state->base.normalized_zpos = mdp5_state->base.zpos;
__drm_atomic_helper_plane_reset(plane, &mdp5_state->base);
}
......
......@@ -635,8 +635,6 @@ nv50_wndw_reset(struct drm_plane *plane)
plane->funcs->atomic_destroy_state(plane, plane->state);
__drm_atomic_helper_plane_reset(plane, &asyw->state);
plane->state->zpos = nv50_wndw_zpos_default(plane);
plane->state->normalized_zpos = nv50_wndw_zpos_default(plane);
}
static void
......
/*
* Copyright © 2010 Intel Corporation
* Copyright © 2010 Francisco Jerez <currojerez@riseup.net>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
/* Modified by Ben Skeggs <bskeggs@redhat.com> to match kernel list APIs */
#ifndef _XORG_LIST_H_
#define _XORG_LIST_H_
/**
* @file Classic doubly-link circular list implementation.
* For real usage examples of the linked list, see the file test/list.c
*
* Example:
* We need to keep a list of struct foo in the parent struct bar, i.e. what
* we want is something like this.
*
* struct bar {
* ...
* struct foo *list_of_foos; -----> struct foo {}, struct foo {}, struct foo{}
* ...
* }
*
* We need one list head in bar and a list element in all list_of_foos (both are of
* data type 'struct list_head').
*
* struct bar {
* ...
* struct list_head list_of_foos;
* ...
* }
*
* struct foo {
* ...
* struct list_head entry;
* ...
* }
*
* Now we initialize the list head:
*
* struct bar bar;
* ...
* INIT_LIST_HEAD(&bar.list_of_foos);
*
* Then we create the first element and add it to this list:
*
* struct foo *foo = malloc(...);
* ....
* list_add(&foo->entry, &bar.list_of_foos);
*
* Repeat the above for each element you want to add to the list. Deleting
* works with the element itself.
* list_del(&foo->entry);
* free(foo);
*
* Note: calling list_del(&bar.list_of_foos) will set bar.list_of_foos to an empty
* list again.
*
* Looping through the list requires a 'struct foo' as iterator and the
* name of the field the subnodes use.
*
* struct foo *iterator;
* list_for_each_entry(iterator, &bar.list_of_foos, entry) {
* if (iterator->something == ...)
* ...
* }
*
* Note: You must not call list_del() on the iterator if you continue the
* loop. You need to run the safe for-each loop instead:
*
* struct foo *iterator, *next;
* list_for_each_entry_safe(iterator, next, &bar.list_of_foos, entry) {
* if (...)
* list_del(&iterator->entry);
* }
*
*/
/**
* The linkage struct for list nodes. This struct must be part of your
* to-be-linked struct. struct list_head is required for both the head of the
* list and for each list node.
*
* Position and name of the struct list_head field is irrelevant.
* There are no requirements that elements of a list are of the same type.
* There are no requirements for a list head, any struct list_head can be a list
* head.
*/
struct list_head {
struct list_head *next, *prev;
};
/**
* Initialize the list as an empty list.
*
* Example:
* INIT_LIST_HEAD(&bar->list_of_foos);
*
* @param The list to initialized.
*/
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
static inline void
INIT_LIST_HEAD(struct list_head *list)
{
list->next = list->prev = list;
}
static inline void
__list_add(struct list_head *entry,
struct list_head *prev, struct list_head *next)
{
next->prev = entry;
entry->next = next;
entry->prev = prev;
prev->next = entry;
}
/**
* Insert a new element after the given list head. The new element does not
* need to be initialised as empty list.
* The list changes from:
* head → some element → ...
* to
* head → new element → older element → ...
*
* Example:
* struct foo *newfoo = malloc(...);
* list_add(&newfoo->entry, &bar->list_of_foos);
*
* @param entry The new element to prepend to the list.
* @param head The existing list.
*/
static inline void
list_add(struct list_head *entry, struct list_head *head)
{
__list_add(entry, head, head->next);
}
/**
* Append a new element to the end of the list given with this list head.
*
* The list changes from:
* head → some element → ... → lastelement
* to
* head → some element → ... → lastelement → new element
*
* Example:
* struct foo *newfoo = malloc(...);
* list_add_tail(&newfoo->entry, &bar->list_of_foos);
*
* @param entry The new element to prepend to the list.
* @param head The existing list.
*/
static inline void
list_add_tail(struct list_head *entry, struct list_head *head)
{
__list_add(entry, head->prev, head);
}
static inline void
__list_del(struct list_head *prev, struct list_head *next)
{
next->prev = prev;
prev->next = next;
}
/**
* Remove the element from the list it is in. Using this function will reset
* the pointers to/from this element so it is removed from the list. It does
* NOT free the element itself or manipulate it otherwise.
*
* Using list_del on a pure list head (like in the example at the top of
* this file) will NOT remove the first element from
* the list but rather reset the list as empty list.
*
* Example:
* list_del(&foo->entry);
*
* @param entry The element to remove.
*/
static inline void
list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
}
static inline void
list_del_init(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
INIT_LIST_HEAD(entry);
}
static inline void list_move_tail(struct list_head *list,
struct list_head *head)
{
__list_del(list->prev, list->next);
list_add_tail(list, head);
}
/**
* Check if the list is empty.
*
* Example:
* list_empty(&bar->list_of_foos);
*
* @return True if the list contains one or more elements or False otherwise.
*/
static inline bool
list_empty(struct list_head *head)
{
return head->next == head;
}
/**
* Returns a pointer to the container of this list element.
*
* Example:
* struct foo* f;
* f = container_of(&foo->entry, struct foo, entry);
* assert(f == foo);
*
* @param ptr Pointer to the struct list_head.
* @param type Data type of the list element.
* @param member Member name of the struct list_head field in the list element.
* @return A pointer to the data struct containing the list head.
*/
#ifndef container_of
#define container_of(ptr, type, member) \
(type *)((char *)(ptr) - (char *) &((type *)0)->member)
#endif
/**
* Alias of container_of
*/
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)
/**
* Retrieve the first list entry for the given list pointer.
*
* Example:
* struct foo *first;
* first = list_first_entry(&bar->list_of_foos, struct foo, list_of_foos);
*
* @param ptr The list head
* @param type Data type of the list element to retrieve
* @param member Member name of the struct list_head field in the list element.
* @return A pointer to the first list element.
*/
#define list_first_entry(ptr, type, member) \
list_entry((ptr)->next, type, member)
/**
* Retrieve the last list entry for the given listpointer.
*
* Example:
* struct foo *first;
* first = list_last_entry(&bar->list_of_foos, struct foo, list_of_foos);
*
* @param ptr The list head
* @param type Data type of the list element to retrieve
* @param member Member name of the struct list_head field in the list element.
* @return A pointer to the last list element.
*/
#define list_last_entry(ptr, type, member) \
list_entry((ptr)->prev, type, member)
#define __container_of(ptr, sample, member) \
(void *)container_of((ptr), typeof(*(sample)), member)
/**
* Loop through the list given by head and set pos to struct in the list.
*
* Example:
* struct foo *iterator;
* list_for_each_entry(iterator, &bar->list_of_foos, entry) {
* [modify iterator]
* }
*
* This macro is not safe for node deletion. Use list_for_each_entry_safe
* instead.
*
* @param pos Iterator variable of the type of the list elements.
* @param head List head
* @param member Member name of the struct list_head in the list elements.
*
*/
#define list_for_each_entry(pos, head, member) \
for (pos = __container_of((head)->next, pos, member); \
&pos->member != (head); \
pos = __container_of(pos->member.next, pos, member))
/**
* Loop through the list, keeping a backup pointer to the element. This
* macro allows for the deletion of a list element while looping through the
* list.
*
* See list_for_each_entry for more details.
*/
#define list_for_each_entry_safe(pos, tmp, head, member) \
for (pos = __container_of((head)->next, pos, member), \
tmp = __container_of(pos->member.next, pos, member); \
&pos->member != (head); \
pos = tmp, tmp = __container_of(pos->member.next, tmp, member))
#define list_for_each_entry_reverse(pos, head, member) \
for (pos = __container_of((head)->prev, pos, member); \
&pos->member != (head); \
pos = __container_of(pos->member.prev, pos, member))
#define list_for_each_entry_continue(pos, head, member) \
for (pos = __container_of(pos->member.next, pos, member); \
&pos->member != (head); \
pos = __container_of(pos->member.next, pos, member))
#define list_for_each_entry_continue_reverse(pos, head, member) \
for (pos = __container_of(pos->member.prev, pos, member); \
&pos->member != (head); \
pos = __container_of(pos->member.prev, pos, member))
#define list_for_each_entry_from(pos, head, member) \
for (; \
&pos->member != (head); \
pos = __container_of(pos->member.next, pos, member))
#endif
......@@ -403,7 +403,6 @@ void omap_plane_install_properties(struct drm_plane *plane,
static void omap_plane_reset(struct drm_plane *plane)
{
struct omap_plane *omap_plane = to_omap_plane(plane);
struct omap_plane_state *omap_state;
if (plane->state)
......@@ -414,15 +413,6 @@ static void omap_plane_reset(struct drm_plane *plane)
return;
__drm_atomic_helper_plane_reset(plane, &omap_state->base);
/*
* Set the zpos default depending on whether we are a primary or overlay
* plane.
*/
plane->state->zpos = plane->type == DRM_PLANE_TYPE_PRIMARY
? 0 : omap_plane->id;
plane->state->color_encoding = DRM_COLOR_YCBCR_BT601;
plane->state->color_range = DRM_COLOR_YCBCR_FULL_RANGE;
}
static struct drm_plane_state *
......@@ -533,6 +523,7 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
unsigned int num_planes = dispc_get_num_ovls(priv->dispc);
struct drm_plane *plane;
struct omap_plane *omap_plane;
unsigned int zpos;
int ret;
u32 nformats;
const u32 *formats;
......@@ -564,7 +555,16 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
drm_plane_helper_add(plane, &omap_plane_helper_funcs);
omap_plane_install_properties(plane, &plane->base);
drm_plane_create_zpos_property(plane, 0, 0, num_planes - 1);
/*
* Set the zpos default depending on whether we are a primary or overlay
* plane.
*/
if (plane->type == DRM_PLANE_TYPE_PRIMARY)
zpos = 0;
else
zpos = omap_plane->id;
drm_plane_create_zpos_property(plane, zpos, 0, num_planes - 1);
drm_plane_create_alpha_property(plane);
drm_plane_create_blend_mode_property(plane, BIT(DRM_MODE_BLEND_PREMULTI) |
BIT(DRM_MODE_BLEND_COVERAGE));
......
......@@ -3058,6 +3058,7 @@ static const struct drm_display_mode rocktech_rk101ii01d_ct_mode = {
static const struct panel_desc rocktech_rk101ii01d_ct = {
.modes = &rocktech_rk101ii01d_ct_mode,
.bpc = 8,
.num_modes = 1,
.size = {
.width = 217,
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment