summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2022-03-04 06:41:52 +0300
committerDave Airlie <airlied@redhat.com>2022-03-04 06:41:57 +0300
commitc9e9ce0b6f85ac330adee912745048a0af5f315d (patch)
treeac5475f48d638f63fc8c1fee1c5d48d2a6d64c33
parentf298a2b94c7bca7f664b99d374cf3e5d79bf9327 (diff)
parent701920ca9822eb63b420b3bcb627f2c1ec759903 (diff)
downloadlinux-c9e9ce0b6f85ac330adee912745048a0af5f315d.tar.xz
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: Dave 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
-rw-r--r--Documentation/devicetree/bindings/display/panel/panel-mipi-dbi-spi.yaml126
-rw-r--r--Documentation/gpu/todo.rst47
-rw-r--r--MAINTAINERS8
-rw-r--r--drivers/gpu/drm/aspeed/aspeed_gfx.h1
-rw-r--r--drivers/gpu/drm/aspeed/aspeed_gfx_drv.c15
-rw-r--r--drivers/gpu/drm/bridge/analogix/anx7625.c6
-rw-r--r--drivers/gpu/drm/bridge/cdns-dsi.c1
-rw-r--r--drivers/gpu/drm/bridge/chipone-icn6211.c7
-rw-r--r--drivers/gpu/drm/bridge/ite-it6505.c4
-rw-r--r--drivers/gpu/drm/bridge/nwl-dsi.c14
-rw-r--r--drivers/gpu/drm/dp/drm_dp.c10
-rw-r--r--drivers/gpu/drm/drm_atomic_state_helper.c25
-rw-r--r--drivers/gpu/drm/drm_mode_object.c53
-rw-r--r--drivers/gpu/drm/drm_modes.c51
-rw-r--r--drivers/gpu/drm/drm_of.c17
-rw-r--r--drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c16
-rw-r--r--drivers/gpu/drm/nouveau/dispnv50/wndw.c2
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/list.h353
-rw-r--r--drivers/gpu/drm/omapdrm/omap_plane.c22
-rw-r--r--drivers/gpu/drm/panel/panel-simple.c1
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_drv.c2
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c2
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_issues.h2
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_mmu.c2
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_regs.h2
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_plane.c1
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_vsp.c1
-rw-r--r--drivers/gpu/drm/solomon/ssd130x.c2
-rw-r--r--drivers/gpu/drm/sti/sti_cursor.c2
-rw-r--r--drivers/gpu/drm/sti/sti_gdp.c2
-rw-r--r--drivers/gpu/drm/sti/sti_hqvdp.c2
-rw-r--r--drivers/gpu/drm/sti/sti_plane.c6
-rw-r--r--drivers/gpu/drm/sti/sti_plane.h1
-rw-r--r--drivers/gpu/drm/stm/ltdc.c107
-rw-r--r--drivers/gpu/drm/stm/ltdc.h3
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_layer.c16
-rw-r--r--drivers/gpu/drm/tegra/dp.c11
-rw-r--r--drivers/gpu/drm/tiny/Kconfig15
-rw-r--r--drivers/gpu/drm/tiny/Makefile1
-rw-r--r--drivers/gpu/drm/tiny/panel-mipi-dbi.c398
-rw-r--r--drivers/gpu/drm/tiny/repaper.c24
-rw-r--r--drivers/gpu/drm/tiny/simpledrm.c3
-rw-r--r--drivers/gpu/drm/v3d/v3d_sched.c40
-rw-r--r--drivers/video/fbdev/core/cfbimgblt.c107
-rw-r--r--drivers/video/fbdev/core/sysfillrect.c16
-rw-r--r--drivers/video/fbdev/core/sysimgblt.c49
-rw-r--r--include/drm/dp/drm_dp_helper.h4
-rw-r--r--include/drm/drm_mipi_dbi.h8
-rw-r--r--include/drm/drm_mode_object.h7
-rw-r--r--include/drm/drm_modes.h8
50 files changed, 1051 insertions, 572 deletions
diff --git a/Documentation/devicetree/bindings/display/panel/panel-mipi-dbi-spi.yaml b/Documentation/devicetree/bindings/display/panel/panel-mipi-dbi-spi.yaml
new file mode 100644
index 000000000000..f29789994b18
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/panel-mipi-dbi-spi.yaml
@@ -0,0 +1,126 @@
+# 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>;
+ };
+ };
+ };
+
+...
diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst
index 7bf7f2111696..127e76ee0b2d 100644
--- a/Documentation/gpu/todo.rst
+++ b/Documentation/gpu/todo.rst
@@ -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
diff --git a/MAINTAINERS b/MAINTAINERS
index e0ad1bc5b9d4..18d799bb66ec 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -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>
diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx.h b/drivers/gpu/drm/aspeed/aspeed_gfx.h
index 96501152bafa..4e6a442c3886 100644
--- a/drivers/gpu/drm/aspeed/aspeed_gfx.h
+++ b/drivers/gpu/drm/aspeed/aspeed_gfx.h
@@ -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;
diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c b/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c
index 13f496473b9e..7780b72de9e8 100644
--- a/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c
+++ b/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c
@@ -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;
diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c
index 633618bafd75..31ecf5626f1d 100644
--- a/drivers/gpu/drm/bridge/analogix/anx7625.c
+++ b/drivers/gpu/drm/bridge/analogix/anx7625.c
@@ -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)
diff --git a/drivers/gpu/drm/bridge/cdns-dsi.c b/drivers/gpu/drm/bridge/cdns-dsi.c
index d8a15c459b42..829e1a144656 100644
--- a/drivers/gpu/drm/bridge/cdns-dsi.c
+++ b/drivers/gpu/drm/bridge/cdns-dsi.c
@@ -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,
diff --git a/drivers/gpu/drm/bridge/chipone-icn6211.c b/drivers/gpu/drm/bridge/chipone-icn6211.c
index e8f36dca56b3..d9b7f48b99fb 100644
--- a/drivers/gpu/drm/bridge/chipone-icn6211.c
+++ b/drivers/gpu/drm/bridge/chipone-icn6211.c
@@ -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);
diff --git a/drivers/gpu/drm/bridge/ite-it6505.c b/drivers/gpu/drm/bridge/ite-it6505.c
index fb16a176822d..f2f101220ade 100644
--- a/drivers/gpu/drm/bridge/ite-it6505.c
+++ b/drivers/gpu/drm/bridge/ite-it6505.c
@@ -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)
diff --git a/drivers/gpu/drm/bridge/nwl-dsi.c b/drivers/gpu/drm/bridge/nwl-dsi.c
index 963a6794735f..d5945501a5ee 100644
--- a/drivers/gpu/drm/bridge/nwl-dsi.c
+++ b/drivers/gpu/drm/bridge/nwl-dsi.c
@@ -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);
}
diff --git a/drivers/gpu/drm/dp/drm_dp.c b/drivers/gpu/drm/dp/drm_dp.c
index e159b81800d4..703972ae14c6 100644
--- a/drivers/gpu/drm/dp/drm_dp.c
+++ b/drivers/gpu/drm/dp/drm_dp.c
@@ -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)
diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c
index ddcf5c2c8e6a..3b6d3bdbd099 100644
--- a/drivers/gpu/drm/drm_atomic_state_helper.c
+++ b/drivers/gpu/drm/drm_atomic_state_helper.c
@@ -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);
diff --git a/drivers/gpu/drm/drm_mode_object.c b/drivers/gpu/drm/drm_mode_object.c
index 86d9e907c0b2..ba1608effc0f 100644
--- a/drivers/gpu/drm/drm_mode_object.c
+++ b/drivers/gpu/drm/drm_mode_object.c
@@ -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,
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index 96b13e36293c..3f819c7a021b 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -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 */
diff --git a/drivers/gpu/drm/drm_of.c b/drivers/gpu/drm/drm_of.c
index 59d368ea006b..9d90cd75c457 100644
--- a/drivers/gpu/drm/drm_of.c
+++ b/drivers/gpu/drm/drm_of.c
@@ -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;
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c
index c6b69afcbac8..5d8ac84c510b 100644
--- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c
@@ -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);
}
diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndw.c b/drivers/gpu/drm/nouveau/dispnv50/wndw.c
index 133c8736426a..0c1a2ea0ed04 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/wndw.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/wndw.c
@@ -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
diff --git a/drivers/gpu/drm/nouveau/include/nvif/list.h b/drivers/gpu/drm/nouveau/include/nvif/list.h
deleted file mode 100644
index 8af5d144ecb0..000000000000
--- a/drivers/gpu/drm/nouveau/include/nvif/list.h
+++ /dev/null
@@ -1,353 +0,0 @@
-/*
- * 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
diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c
index b35205c4e979..b83d91ec030a 100644
--- a/drivers/gpu/drm/omapdrm/omap_plane.c
+++ b/drivers/gpu/drm/omapdrm/omap_plane.c
@@ -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));
diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
index c324a3ed34b9..c09eb5ad65fc 100644
--- a/drivers/gpu/drm/panel/panel-simple.c
+++ b/drivers/gpu/drm/panel/panel-simple.c
@@ -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,
diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c
index 96bb5a465627..94b6f0a19c83 100644
--- a/drivers/gpu/drm/panfrost/panfrost_drv.c
+++ b/drivers/gpu/drm/panfrost/panfrost_drv.c
@@ -562,7 +562,7 @@ static int panfrost_probe(struct platform_device *pdev)
pfdev->coherent = device_get_dma_attr(&pdev->dev) == DEV_DMA_COHERENT;
- /* Allocate and initialze the DRM device. */
+ /* Allocate and initialize the DRM device. */
ddev = drm_dev_alloc(&panfrost_drm_driver, &pdev->dev);
if (IS_ERR(ddev))
return PTR_ERR(ddev);
diff --git a/drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c b/drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c
index b0142341e223..77e7cb6d1ae3 100644
--- a/drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c
+++ b/drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+// SPDX-License-Identifier: GPL-2.0
/* Copyright (C) 2019 Arm Ltd.
*
* Based on msm_gem_freedreno.c:
diff --git a/drivers/gpu/drm/panfrost/panfrost_issues.h b/drivers/gpu/drm/panfrost/panfrost_issues.h
index 8e59d765bf19..501a76c5e95f 100644
--- a/drivers/gpu/drm/panfrost/panfrost_issues.h
+++ b/drivers/gpu/drm/panfrost/panfrost_issues.h
@@ -14,7 +14,7 @@
*/
enum panfrost_hw_issue {
/* Need way to guarantee that all previously-translated memory accesses
- * are commited */
+ * are committed */
HW_ISSUE_6367,
/* On job complete with non-done the cache is not flushed */
diff --git a/drivers/gpu/drm/panfrost/panfrost_mmu.c b/drivers/gpu/drm/panfrost/panfrost_mmu.c
index 39562f2d11a4..d3f82b26a631 100644
--- a/drivers/gpu/drm/panfrost/panfrost_mmu.c
+++ b/drivers/gpu/drm/panfrost/panfrost_mmu.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0
/* Copyright 2019 Linaro, Ltd, Rob Herring <robh@kernel.org> */
#include <drm/panfrost_drm.h>
diff --git a/drivers/gpu/drm/panfrost/panfrost_regs.h b/drivers/gpu/drm/panfrost/panfrost_regs.h
index 16e776cc82ea..0b6cd8fdcb47 100644
--- a/drivers/gpu/drm/panfrost/panfrost_regs.h
+++ b/drivers/gpu/drm/panfrost/panfrost_regs.h
@@ -293,7 +293,7 @@
#define AS_FAULTADDRESS_LO(as) (MMU_AS(as) + 0x20) /* (RO) Fault Address for address space n, low word */
#define AS_FAULTADDRESS_HI(as) (MMU_AS(as) + 0x24) /* (RO) Fault Address for address space n, high word */
#define AS_STATUS(as) (MMU_AS(as) + 0x28) /* (RO) Status flags for address space n */
-/* Additional Bifrost AS regsiters */
+/* Additional Bifrost AS registers */
#define AS_TRANSCFG_LO(as) (MMU_AS(as) + 0x30) /* (RW) Translation table configuration for address space n, low word */
#define AS_TRANSCFG_HI(as) (MMU_AS(as) + 0x34) /* (RW) Translation table configuration for address space n, high word */
#define AS_FAULTEXTRA_LO(as) (MMU_AS(as) + 0x38) /* (RO) Secondary fault address for address space n, low word */
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/rcar-du/rcar_du_plane.c
index 22aeeb1cc1fb..5c1c7bb04f3f 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_plane.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.c
@@ -704,7 +704,6 @@ static void rcar_du_plane_reset(struct drm_plane *plane)
state->hwindex = -1;
state->source = RCAR_DU_PLANE_MEMORY;
state->colorkey = RCAR_DU_COLORKEY_NONE;
- state->state.zpos = plane->type == DRM_PLANE_TYPE_PRIMARY ? 0 : 1;
}
static int rcar_du_plane_atomic_set_property(struct drm_plane *plane,
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
index 32530d698e75..8eb9b2b097ae 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
@@ -353,7 +353,6 @@ static void rcar_du_vsp_plane_reset(struct drm_plane *plane)
return;
__drm_atomic_helper_plane_reset(plane, &state->state);
- state->state.zpos = plane->type == DRM_PLANE_TYPE_PRIMARY ? 0 : 1;
}
static const struct drm_plane_funcs rcar_du_vsp_plane_funcs = {
diff --git a/drivers/gpu/drm/solomon/ssd130x.c b/drivers/gpu/drm/solomon/ssd130x.c
index 92c1902f53e4..ce4dc20412e0 100644
--- a/drivers/gpu/drm/solomon/ssd130x.c
+++ b/drivers/gpu/drm/solomon/ssd130x.c
@@ -579,7 +579,7 @@ static const struct drm_simple_display_pipe_funcs ssd130x_pipe_funcs = {
static int ssd130x_connector_get_modes(struct drm_connector *connector)
{
struct ssd130x_device *ssd130x = drm_to_ssd130x(connector->dev);
- struct drm_display_mode *mode = &ssd130x->mode;
+ struct drm_display_mode *mode;
struct device *dev = ssd130x->dev;
mode = drm_mode_duplicate(connector->dev, &ssd130x->mode);
diff --git a/drivers/gpu/drm/sti/sti_cursor.c b/drivers/gpu/drm/sti/sti_cursor.c
index 1d6051b4f6fe..414c9973aa6d 100644
--- a/drivers/gpu/drm/sti/sti_cursor.c
+++ b/drivers/gpu/drm/sti/sti_cursor.c
@@ -351,7 +351,7 @@ static const struct drm_plane_funcs sti_cursor_plane_helpers_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
.destroy = drm_plane_cleanup,
- .reset = sti_plane_reset,
+ .reset = drm_atomic_helper_plane_reset,
.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
.late_register = sti_cursor_late_register,
diff --git a/drivers/gpu/drm/sti/sti_gdp.c b/drivers/gpu/drm/sti/sti_gdp.c
index d1a35d97bc45..3db3768a3241 100644
--- a/drivers/gpu/drm/sti/sti_gdp.c
+++ b/drivers/gpu/drm/sti/sti_gdp.c
@@ -905,7 +905,7 @@ static const struct drm_plane_funcs sti_gdp_plane_helpers_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
.destroy = drm_plane_cleanup,
- .reset = sti_plane_reset,
+ .reset = drm_atomic_helper_plane_reset,
.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
.late_register = sti_gdp_late_register,
diff --git a/drivers/gpu/drm/sti/sti_hqvdp.c b/drivers/gpu/drm/sti/sti_hqvdp.c
index 3c61ba8b43e0..2201a50353eb 100644
--- a/drivers/gpu/drm/sti/sti_hqvdp.c
+++ b/drivers/gpu/drm/sti/sti_hqvdp.c
@@ -1283,7 +1283,7 @@ static const struct drm_plane_funcs sti_hqvdp_plane_helpers_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
.destroy = drm_plane_cleanup,
- .reset = sti_plane_reset,
+ .reset = drm_atomic_helper_plane_reset,
.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
.late_register = sti_hqvdp_late_register,
diff --git a/drivers/gpu/drm/sti/sti_plane.c b/drivers/gpu/drm/sti/sti_plane.c
index 3da4a46df2f2..173409cdb99e 100644
--- a/drivers/gpu/drm/sti/sti_plane.c
+++ b/drivers/gpu/drm/sti/sti_plane.c
@@ -112,12 +112,6 @@ static int sti_plane_get_default_zpos(enum drm_plane_type type)
return 0;
}
-void sti_plane_reset(struct drm_plane *plane)
-{
- drm_atomic_helper_plane_reset(plane);
- plane->state->zpos = sti_plane_get_default_zpos(plane->type);
-}
-
static void sti_plane_attach_zorder_property(struct drm_plane *drm_plane,
enum drm_plane_type type)
{
diff --git a/drivers/gpu/drm/sti/sti_plane.h b/drivers/gpu/drm/sti/sti_plane.h
index 065ffffbfb4a..8e33e629d9b0 100644
--- a/drivers/gpu/drm/sti/sti_plane.h
+++ b/drivers/gpu/drm/sti/sti_plane.h
@@ -81,5 +81,4 @@ void sti_plane_update_fps(struct sti_plane *plane,
void sti_plane_init_property(struct sti_plane *plane,
enum drm_plane_type type);
-void sti_plane_reset(struct drm_plane *plane);
#endif
diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c
index 5eeb32c9c9ce..17cc050207f4 100644
--- a/drivers/gpu/drm/stm/ltdc.c
+++ b/drivers/gpu/drm/stm/ltdc.c
@@ -77,6 +77,7 @@
#define LTDC_CPSR 0x0044 /* Current Position Status */
#define LTDC_CDSR 0x0048 /* Current Display Status */
#define LTDC_EDCR 0x0060 /* External Display Control */
+#define LTDC_CCRCR 0x007C /* Computed CRC value */
#define LTDC_FUT 0x0090 /* Fifo underrun Threshold */
/* Layer register offsets */
@@ -121,6 +122,7 @@
#define GCR_LTDCEN BIT(0) /* LTDC ENable */
#define GCR_DEN BIT(16) /* Dither ENable */
+#define GCR_CRCEN BIT(19) /* CRC ENable */
#define GCR_PCPOL BIT(28) /* Pixel Clock POLarity-Inverted */
#define GCR_DEPOL BIT(29) /* Data Enable POLarity-High */
#define GCR_VSPOL BIT(30) /* Vertical Synchro POLarity-High */
@@ -227,6 +229,13 @@
#define NB_PF 8 /* Max nb of HW pixel format */
+/*
+ * Skip the first value and the second in case CRC was enabled during
+ * the thread irq. This is to be sure CRC value is relevant for the
+ * frame.
+ */
+#define CRC_SKIP_FRAMES 2
+
enum ltdc_pix_fmt {
PF_NONE,
/* RGB formats */
@@ -624,7 +633,8 @@ static inline void ltdc_set_ycbcr_config(struct drm_plane *plane, u32 drm_pix_fm
break;
default:
/* RGB or not a YCbCr supported format */
- break;
+ DRM_ERROR("Unsupported pixel format: %u\n", drm_pix_fmt);
+ return;
}
/* Enable limited range */
@@ -664,6 +674,26 @@ static inline void ltdc_set_ycbcr_coeffs(struct drm_plane *plane)
ltdc_ycbcr2rgb_coeffs[enc][ran][1]);
}
+static inline void ltdc_irq_crc_handle(struct ltdc_device *ldev,
+ struct drm_crtc *crtc)
+{
+ u32 crc;
+ int ret;
+
+ if (ldev->crc_skip_count < CRC_SKIP_FRAMES) {
+ ldev->crc_skip_count++;
+ return;
+ }
+
+ /* Get the CRC of the frame */
+ ret = regmap_read(ldev->regmap, LTDC_CCRCR, &crc);
+ if (ret)
+ return;
+
+ /* Report to DRM the CRC (hw dependent feature) */
+ drm_crtc_add_crc_entry(crtc, true, drm_crtc_accurate_vblank_count(crtc), &crc);
+}
+
static irqreturn_t ltdc_irq_thread(int irq, void *arg)
{
struct drm_device *ddev = arg;
@@ -671,9 +701,14 @@ static irqreturn_t ltdc_irq_thread(int irq, void *arg)
struct drm_crtc *crtc = drm_crtc_from_index(ddev, 0);
/* Line IRQ : trigger the vblank event */
- if (ldev->irq_status & ISR_LIF)
+ if (ldev->irq_status & ISR_LIF) {
drm_crtc_handle_vblank(crtc);
+ /* Early return if CRC is not active */
+ if (ldev->crc_active)
+ ltdc_irq_crc_handle(ldev, crtc);
+ }
+
/* Save FIFO Underrun & Transfer Error status */
mutex_lock(&ldev->err_lock);
if (ldev->irq_status & ISR_FUIF)
@@ -1079,6 +1114,48 @@ static void ltdc_crtc_disable_vblank(struct drm_crtc *crtc)
regmap_clear_bits(ldev->regmap, LTDC_IER, IER_LIE);
}
+static int ltdc_crtc_set_crc_source(struct drm_crtc *crtc, const char *source)
+{
+ struct ltdc_device *ldev = crtc_to_ltdc(crtc);
+ int ret;
+
+ DRM_DEBUG_DRIVER("\n");
+
+ if (!crtc)
+ return -ENODEV;
+
+ if (source && strcmp(source, "auto") == 0) {
+ ldev->crc_active = true;
+ ret = regmap_set_bits(ldev->regmap, LTDC_GCR, GCR_CRCEN);
+ } else if (!source) {
+ ldev->crc_active = false;
+ ret = regmap_clear_bits(ldev->regmap, LTDC_GCR, GCR_CRCEN);
+ } else {
+ ret = -EINVAL;
+ }
+
+ ldev->crc_skip_count = 0;
+ return ret;
+}
+
+static int ltdc_crtc_verify_crc_source(struct drm_crtc *crtc,
+ const char *source, size_t *values_cnt)
+{
+ DRM_DEBUG_DRIVER("\n");
+
+ if (!crtc)
+ return -ENODEV;
+
+ if (source && strcmp(source, "auto") != 0) {
+ DRM_DEBUG_DRIVER("Unknown CRC source %s for %s\n",
+ source, crtc->name);
+ return -EINVAL;
+ }
+
+ *values_cnt = 1;
+ return 0;
+}
+
static const struct drm_crtc_funcs ltdc_crtc_funcs = {
.destroy = drm_crtc_cleanup,
.set_config = drm_atomic_helper_set_config,
@@ -1091,6 +1168,20 @@ static const struct drm_crtc_funcs ltdc_crtc_funcs = {
.get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp,
};
+static const struct drm_crtc_funcs ltdc_crtc_with_crc_support_funcs = {
+ .destroy = drm_crtc_cleanup,
+ .set_config = drm_atomic_helper_set_config,
+ .page_flip = drm_atomic_helper_page_flip,
+ .reset = drm_atomic_helper_crtc_reset,
+ .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
+ .enable_vblank = ltdc_crtc_enable_vblank,
+ .disable_vblank = ltdc_crtc_disable_vblank,
+ .get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp,
+ .set_crc_source = ltdc_crtc_set_crc_source,
+ .verify_crc_source = ltdc_crtc_verify_crc_source,
+};
+
/*
* DRM_PLANE
*/
@@ -1478,8 +1569,13 @@ static int ltdc_crtc_init(struct drm_device *ddev, struct drm_crtc *crtc)
drm_plane_create_zpos_immutable_property(primary, 0);
- ret = drm_crtc_init_with_planes(ddev, crtc, primary, NULL,
- &ltdc_crtc_funcs, NULL);
+ /* Init CRTC according to its hardware features */
+ if (ldev->caps.crc)
+ ret = drm_crtc_init_with_planes(ddev, crtc, primary, NULL,
+ &ltdc_crtc_with_crc_support_funcs, NULL);
+ else
+ ret = drm_crtc_init_with_planes(ddev, crtc, primary, NULL,
+ &ltdc_crtc_funcs, NULL);
if (ret) {
DRM_ERROR("Can not initialize CRTC\n");
goto cleanup;
@@ -1629,6 +1725,7 @@ static int ltdc_get_caps(struct drm_device *ddev)
ldev->caps.ycbcr_input = false;
ldev->caps.ycbcr_output = false;
ldev->caps.plane_reg_shadow = false;
+ ldev->caps.crc = false;
break;
case HWVER_20101:
ldev->caps.layer_ofs = LAY_OFS_0;
@@ -1643,6 +1740,7 @@ static int ltdc_get_caps(struct drm_device *ddev)
ldev->caps.ycbcr_input = false;
ldev->caps.ycbcr_output = false;
ldev->caps.plane_reg_shadow = false;
+ ldev->caps.crc = false;
break;
case HWVER_40100:
ldev->caps.layer_ofs = LAY_OFS_1;
@@ -1657,6 +1755,7 @@ static int ltdc_get_caps(struct drm_device *ddev)
ldev->caps.ycbcr_input = true;
ldev->caps.ycbcr_output = true;
ldev->caps.plane_reg_shadow = true;
+ ldev->caps.crc = true;
break;
default:
return -ENODEV;
diff --git a/drivers/gpu/drm/stm/ltdc.h b/drivers/gpu/drm/stm/ltdc.h
index 6968d1ca5149..59fc5d1bbbab 100644
--- a/drivers/gpu/drm/stm/ltdc.h
+++ b/drivers/gpu/drm/stm/ltdc.h
@@ -27,6 +27,7 @@ struct ltdc_caps {
bool ycbcr_input; /* ycbcr input converter supported */
bool ycbcr_output; /* ycbcr output converter supported */
bool plane_reg_shadow; /* plane shadow registers ability */
+ bool crc; /* cyclic redundancy check supported */
};
#define LTDC_MAX_LAYER 4
@@ -46,6 +47,8 @@ struct ltdc_device {
u32 irq_status;
struct fps_info plane_fpsi[LTDC_MAX_LAYER];
struct drm_atomic_state *suspend_state;
+ int crc_skip_count;
+ bool crc_active;
};
int ltdc_load(struct drm_device *ddev);
diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c
index 929e95f86b5b..6d43080791a0 100644
--- a/drivers/gpu/drm/sun4i/sun4i_layer.c
+++ b/drivers/gpu/drm/sun4i/sun4i_layer.c
@@ -18,7 +18,6 @@
static void sun4i_backend_layer_reset(struct drm_plane *plane)
{
- struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
struct sun4i_layer_state *state;
if (plane->state) {
@@ -31,10 +30,8 @@ static void sun4i_backend_layer_reset(struct drm_plane *plane)
}
state = kzalloc(sizeof(*state), GFP_KERNEL);
- if (state) {
+ if (state)
__drm_atomic_helper_plane_reset(plane, &state->state);
- plane->state->zpos = layer->id;
- }
}
static struct drm_plane_state *
@@ -192,7 +189,8 @@ static const uint64_t sun4i_layer_modifiers[] = {
static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
struct sun4i_backend *backend,
- enum drm_plane_type type)
+ enum drm_plane_type type,
+ unsigned int id)
{
const uint64_t *modifiers = sun4i_layer_modifiers;
const uint32_t *formats = sun4i_layer_formats;
@@ -204,6 +202,7 @@ static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
if (!layer)
return ERR_PTR(-ENOMEM);
+ layer->id = id;
layer->backend = backend;
if (IS_ERR_OR_NULL(backend->frontend)) {
@@ -226,8 +225,8 @@ static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
&sun4i_backend_layer_helper_funcs);
drm_plane_create_alpha_property(&layer->plane);
- drm_plane_create_zpos_property(&layer->plane, 0, 0,
- SUN4I_BACKEND_NUM_LAYERS - 1);
+ drm_plane_create_zpos_property(&layer->plane, layer->id,
+ 0, SUN4I_BACKEND_NUM_LAYERS - 1);
return layer;
}
@@ -249,14 +248,13 @@ struct drm_plane **sun4i_layers_init(struct drm_device *drm,
enum drm_plane_type type = i ? DRM_PLANE_TYPE_OVERLAY : DRM_PLANE_TYPE_PRIMARY;
struct sun4i_layer *layer;
- layer = sun4i_layer_init_one(drm, backend, type);
+ layer = sun4i_layer_init_one(drm, backend, type, i);
if (IS_ERR(layer)) {
dev_err(drm->dev, "Couldn't initialize %s plane\n",
i ? "overlay" : "primary");
return ERR_CAST(layer);
}
- layer->id = i;
planes[i] = &layer->plane;
}
diff --git a/drivers/gpu/drm/tegra/dp.c b/drivers/gpu/drm/tegra/dp.c
index e4369e5b2943..7295975e5733 100644
--- a/drivers/gpu/drm/tegra/dp.c
+++ b/drivers/gpu/drm/tegra/dp.c
@@ -549,6 +549,15 @@ static void drm_dp_link_get_adjustments(struct drm_dp_link *link,
{
struct drm_dp_link_train_set *adjust = &link->train.adjust;
unsigned int i;
+ u8 post_cursor;
+ int err;
+
+ err = drm_dp_dpcd_read(link->aux, DP_ADJUST_REQUEST_POST_CURSOR2,
+ &post_cursor, sizeof(post_cursor));
+ if (err < 0) {
+ DRM_ERROR("failed to read post_cursor2: %d\n", err);
+ post_cursor = 0;
+ }
for (i = 0; i < link->lanes; i++) {
adjust->voltage_swing[i] =
@@ -560,7 +569,7 @@ static void drm_dp_link_get_adjustments(struct drm_dp_link *link,
DP_TRAIN_PRE_EMPHASIS_SHIFT;
adjust->post_cursor[i] =
- drm_dp_get_adjust_request_post_cursor(status, i);
+ (post_cursor >> (i << 1)) & 0x3;
}
}
diff --git a/drivers/gpu/drm/tiny/Kconfig b/drivers/gpu/drm/tiny/Kconfig
index 712e0004e96e..627d637a1e7e 100644
--- a/drivers/gpu/drm/tiny/Kconfig
+++ b/drivers/gpu/drm/tiny/Kconfig
@@ -51,6 +51,21 @@ config DRM_GM12U320
This is a KMS driver for projectors which use the GM12U320 chipset
for video transfer over USB2/3, such as the Acer C120 mini projector.
+config DRM_PANEL_MIPI_DBI
+ tristate "DRM support for MIPI DBI compatible panels"
+ depends on DRM && SPI
+ select DRM_KMS_HELPER
+ select DRM_GEM_CMA_HELPER
+ select DRM_MIPI_DBI
+ select BACKLIGHT_CLASS_DEVICE
+ select VIDEOMODE_HELPERS
+ help
+ Say Y here if you want to enable support for MIPI DBI compatible
+ panels. The controller command setup can be provided using a
+ firmware file. For more information see
+ https://github.com/notro/panel-mipi-dbi/wiki.
+ To compile this driver as a module, choose M here.
+
config DRM_SIMPLEDRM
tristate "Simple framebuffer driver"
depends on DRM && MMU
diff --git a/drivers/gpu/drm/tiny/Makefile b/drivers/gpu/drm/tiny/Makefile
index 5d5505d40e7b..1d9d6227e7ab 100644
--- a/drivers/gpu/drm/tiny/Makefile
+++ b/drivers/gpu/drm/tiny/Makefile
@@ -4,6 +4,7 @@ obj-$(CONFIG_DRM_ARCPGU) += arcpgu.o
obj-$(CONFIG_DRM_BOCHS) += bochs.o
obj-$(CONFIG_DRM_CIRRUS_QEMU) += cirrus.o
obj-$(CONFIG_DRM_GM12U320) += gm12u320.o
+obj-$(CONFIG_DRM_PANEL_MIPI_DBI) += panel-mipi-dbi.o
obj-$(CONFIG_DRM_SIMPLEDRM) += simpledrm.o
obj-$(CONFIG_TINYDRM_HX8357D) += hx8357d.o
obj-$(CONFIG_TINYDRM_ILI9163) += ili9163.o
diff --git a/drivers/gpu/drm/tiny/panel-mipi-dbi.c b/drivers/gpu/drm/tiny/panel-mipi-dbi.c
new file mode 100644
index 000000000000..7f8c6c51387f
--- /dev/null
+++ b/drivers/gpu/drm/tiny/panel-mipi-dbi.c
@@ -0,0 +1,398 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * DRM driver for MIPI DBI compatible display panels
+ *
+ * Copyright 2022 Noralf Trønnes
+ */
+
+#include <linux/backlight.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_gem_atomic_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_managed.h>
+#include <drm/drm_mipi_dbi.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_modeset_helper.h>
+
+#include <video/mipi_display.h>
+
+static const u8 panel_mipi_dbi_magic[15] = { 'M', 'I', 'P', 'I', ' ', 'D', 'B', 'I',
+ 0, 0, 0, 0, 0, 0, 0 };
+
+/*
+ * The display controller configuration is stored in a firmware file.
+ * The Device Tree 'compatible' property value with a '.bin' suffix is passed
+ * to request_firmware() to fetch this file.
+ */
+struct panel_mipi_dbi_config {
+ /* Magic string: panel_mipi_dbi_magic */
+ u8 magic[15];
+
+ /* Config file format version */
+ u8 file_format_version;
+
+ /*
+ * MIPI commands to execute when the display pipeline is enabled.
+ * This is used to configure the display controller.
+ *
+ * The commands are stored in a byte array with the format:
+ * command, num_parameters, [ parameter, ...], command, ...
+ *
+ * Some commands require a pause before the next command can be received.
+ * Inserting a delay in the command sequence is done by using the NOP command with one
+ * parameter: delay in miliseconds (the No Operation command is part of the MIPI Display
+ * Command Set where it has no parameters).
+ *
+ * Example:
+ * command 0x11
+ * sleep 120ms
+ * command 0xb1 parameters 0x01, 0x2c, 0x2d
+ * command 0x29
+ *
+ * Byte sequence:
+ * 0x11 0x00
+ * 0x00 0x01 0x78
+ * 0xb1 0x03 0x01 0x2c 0x2d
+ * 0x29 0x00
+ */
+ u8 commands[];
+};
+
+struct panel_mipi_dbi_commands {
+ const u8 *buf;
+ size_t len;
+};
+
+static struct panel_mipi_dbi_commands *
+panel_mipi_dbi_check_commands(struct device *dev, const struct firmware *fw)
+{
+ const struct panel_mipi_dbi_config *config = (struct panel_mipi_dbi_config *)fw->data;
+ struct panel_mipi_dbi_commands *commands;
+ size_t size = fw->size, commands_len;
+ unsigned int i = 0;
+
+ if (size < sizeof(*config) + 2) { /* At least 1 command */
+ dev_err(dev, "config: file size=%zu is too small\n", size);
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (memcmp(config->magic, panel_mipi_dbi_magic, sizeof(config->magic))) {
+ dev_err(dev, "config: Bad magic: %15ph\n", config->magic);
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (config->file_format_version != 1) {
+ dev_err(dev, "config: version=%u is not supported\n", config->file_format_version);
+ return ERR_PTR(-EINVAL);
+ }
+
+ drm_dev_dbg(dev, DRM_UT_DRIVER, "size=%zu version=%u\n", size, config->file_format_version);
+
+ commands_len = size - sizeof(*config);
+
+ while ((i + 1) < commands_len) {
+ u8 command = config->commands[i++];
+ u8 num_parameters = config->commands[i++];
+ const u8 *parameters = &config->commands[i];
+
+ i += num_parameters;
+ if (i > commands_len) {
+ dev_err(dev, "config: command=0x%02x num_parameters=%u overflows\n",
+ command, num_parameters);
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (command == 0x00 && num_parameters == 1)
+ drm_dev_dbg(dev, DRM_UT_DRIVER, "sleep %ums\n", parameters[0]);
+ else
+ drm_dev_dbg(dev, DRM_UT_DRIVER, "command %02x %*ph\n",
+ command, num_parameters, parameters);
+ }
+
+ if (i != commands_len) {
+ dev_err(dev, "config: malformed command array\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ commands = devm_kzalloc(dev, sizeof(*commands), GFP_KERNEL);
+ if (!commands)
+ return ERR_PTR(-ENOMEM);
+
+ commands->len = commands_len;
+ commands->buf = devm_kmemdup(dev, config->commands, commands->len, GFP_KERNEL);
+ if (!commands->buf)
+ return ERR_PTR(-ENOMEM);
+
+ return commands;
+}
+
+static struct panel_mipi_dbi_commands *panel_mipi_dbi_commands_from_fw(struct device *dev)
+{
+ struct panel_mipi_dbi_commands *commands;
+ const struct firmware *fw;
+ const char *compatible;
+ char fw_name[40];
+ int ret;
+
+ ret = of_property_read_string_index(dev->of_node, "compatible", 0, &compatible);
+ if (ret)
+ return ERR_PTR(ret);
+
+ snprintf(fw_name, sizeof(fw_name), "%s.bin", compatible);
+ ret = request_firmware(&fw, fw_name, dev);
+ if (ret) {
+ dev_err(dev, "No config file found for compatible '%s' (error=%d)\n",
+ compatible, ret);
+
+ return ERR_PTR(ret);
+ }
+
+ commands = panel_mipi_dbi_check_commands(dev, fw);
+ release_firmware(fw);
+
+ return commands;
+}
+
+static void panel_mipi_dbi_commands_execute(struct mipi_dbi *dbi,
+ struct panel_mipi_dbi_commands *commands)
+{
+ unsigned int i = 0;
+
+ if (!commands)
+ return;
+
+ while (i < commands->len) {
+ u8 command = commands->buf[i++];
+ u8 num_parameters = commands->buf[i++];
+ const u8 *parameters = &commands->buf[i];
+
+ if (command == 0x00 && num_parameters == 1)
+ msleep(parameters[0]);
+ else if (num_parameters)
+ mipi_dbi_command_stackbuf(dbi, command, parameters, num_parameters);
+ else
+ mipi_dbi_command(dbi, command);
+
+ i += num_parameters;
+ }
+}
+
+static void panel_mipi_dbi_enable(struct drm_simple_display_pipe *pipe,
+ struct drm_crtc_state *crtc_state,
+ struct drm_plane_state *plane_state)
+{
+ struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(pipe->crtc.dev);
+ struct mipi_dbi *dbi = &dbidev->dbi;
+ int ret, idx;
+
+ if (!drm_dev_enter(pipe->crtc.dev, &idx))
+ return;
+
+ drm_dbg(pipe->crtc.dev, "\n");
+
+ ret = mipi_dbi_poweron_conditional_reset(dbidev);
+ if (ret < 0)
+ goto out_exit;
+ if (!ret)
+ panel_mipi_dbi_commands_execute(dbi, dbidev->driver_private);
+
+ mipi_dbi_enable_flush(dbidev, crtc_state, plane_state);
+out_exit:
+ drm_dev_exit(idx);
+}
+
+static const struct drm_simple_display_pipe_funcs panel_mipi_dbi_pipe_funcs = {
+ .enable = panel_mipi_dbi_enable,
+ .disable = mipi_dbi_pipe_disable,
+ .update = mipi_dbi_pipe_update,
+};
+
+DEFINE_DRM_GEM_CMA_FOPS(panel_mipi_dbi_fops);
+
+static const struct drm_driver panel_mipi_dbi_driver = {
+ .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
+ .fops = &panel_mipi_dbi_fops,
+ DRM_GEM_CMA_DRIVER_OPS_VMAP,
+ .debugfs_init = mipi_dbi_debugfs_init,
+ .name = "panel-mipi-dbi",
+ .desc = "MIPI DBI compatible display panel",
+ .date = "20220103",
+ .major = 1,
+ .minor = 0,
+};
+
+static int panel_mipi_dbi_get_mode(struct mipi_dbi_dev *dbidev, struct drm_display_mode *mode)
+{
+ struct device *dev = dbidev->drm.dev;
+ u16 hback_porch, vback_porch;
+ int ret;
+
+ ret = of_get_drm_panel_display_mode(dev->of_node, mode, NULL);
+ if (ret) {
+ dev_err(dev, "%pOF: failed to get panel-timing (error=%d)\n", dev->of_node, ret);
+ return ret;
+ }
+
+ mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+
+ hback_porch = mode->htotal - mode->hsync_end;
+ vback_porch = mode->vtotal - mode->vsync_end;
+
+ /*
+ * Make sure width and height are set and that only back porch and
+ * pixelclock are set in the other timing values. Also check that
+ * width and height don't exceed the 16-bit value specified by MIPI DCS.
+ */
+ if (!mode->hdisplay || !mode->vdisplay || mode->flags ||
+ mode->hsync_end > mode->hdisplay || (hback_porch + mode->hdisplay) > 0xffff ||
+ mode->vsync_end > mode->vdisplay || (vback_porch + mode->vdisplay) > 0xffff) {
+ dev_err(dev, "%pOF: panel-timing out of bounds\n", dev->of_node);
+ return -EINVAL;
+ }
+
+ /* The driver doesn't use the pixel clock but it is mandatory so fake one if not set */
+ if (!mode->clock)
+ mode->clock = mode->htotal * mode->vtotal * 60 / 1000;
+
+ dbidev->top_offset = vback_porch;
+ dbidev->left_offset = hback_porch;
+
+ return 0;
+}
+
+static int panel_mipi_dbi_spi_probe(struct spi_device *spi)
+{
+ struct device *dev = &spi->dev;
+ struct drm_display_mode mode;
+ struct mipi_dbi_dev *dbidev;
+ struct drm_device *drm;
+ struct mipi_dbi *dbi;
+ struct gpio_desc *dc;
+ int ret;
+
+ dbidev = devm_drm_dev_alloc(dev, &panel_mipi_dbi_driver, struct mipi_dbi_dev, drm);
+ if (IS_ERR(dbidev))
+ return PTR_ERR(dbidev);
+
+ dbi = &dbidev->dbi;
+ drm = &dbidev->drm;
+
+ ret = panel_mipi_dbi_get_mode(dbidev, &mode);
+ if (ret)
+ return ret;
+
+ dbidev->regulator = devm_regulator_get(dev, "power");
+ if (IS_ERR(dbidev->regulator))
+ return dev_err_probe(dev, PTR_ERR(dbidev->regulator),
+ "Failed to get regulator 'power'\n");
+
+ dbidev->backlight = devm_of_find_backlight(dev);
+ if (IS_ERR(dbidev->backlight))
+ return dev_err_probe(dev, PTR_ERR(dbidev->backlight), "Failed to get backlight\n");
+
+ dbi->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(dbi->reset))
+ return dev_err_probe(dev, PTR_ERR(dbi->reset), "Failed to get GPIO 'reset'\n");
+
+ dc = devm_gpiod_get_optional(dev, "dc", GPIOD_OUT_LOW);
+ if (IS_ERR(dc))
+ return dev_err_probe(dev, PTR_ERR(dc), "Failed to get GPIO 'dc'\n");
+
+ ret = mipi_dbi_spi_init(spi, dbi, dc);
+ if (ret)
+ return ret;
+
+ if (device_property_present(dev, "write-only"))
+ dbi->read_commands = NULL;
+
+ dbidev->driver_private = panel_mipi_dbi_commands_from_fw(dev);
+ if (IS_ERR(dbidev->driver_private))
+ return PTR_ERR(dbidev->driver_private);
+
+ ret = mipi_dbi_dev_init(dbidev, &panel_mipi_dbi_pipe_funcs, &mode, 0);
+ if (ret)
+ return ret;
+
+ drm_mode_config_reset(drm);
+
+ ret = drm_dev_register(drm, 0);
+ if (ret)
+ return ret;
+
+ spi_set_drvdata(spi, drm);
+
+ drm_fbdev_generic_setup(drm, 0);
+
+ return 0;
+}
+
+static int panel_mipi_dbi_spi_remove(struct spi_device *spi)
+{
+ struct drm_device *drm = spi_get_drvdata(spi);
+
+ drm_dev_unplug(drm);
+ drm_atomic_helper_shutdown(drm);
+
+ return 0;
+}
+
+static void panel_mipi_dbi_spi_shutdown(struct spi_device *spi)
+{
+ drm_atomic_helper_shutdown(spi_get_drvdata(spi));
+}
+
+static int __maybe_unused panel_mipi_dbi_pm_suspend(struct device *dev)
+{
+ return drm_mode_config_helper_suspend(dev_get_drvdata(dev));
+}
+
+static int __maybe_unused panel_mipi_dbi_pm_resume(struct device *dev)
+{
+ drm_mode_config_helper_resume(dev_get_drvdata(dev));
+
+ return 0;
+}
+
+static const struct dev_pm_ops panel_mipi_dbi_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(panel_mipi_dbi_pm_suspend, panel_mipi_dbi_pm_resume)
+};
+
+static const struct of_device_id panel_mipi_dbi_spi_of_match[] = {
+ { .compatible = "panel-mipi-dbi-spi" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, panel_mipi_dbi_spi_of_match);
+
+static const struct spi_device_id panel_mipi_dbi_spi_id[] = {
+ { "panel-mipi-dbi-spi", 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(spi, panel_mipi_dbi_spi_id);
+
+static struct spi_driver panel_mipi_dbi_spi_driver = {
+ .driver = {
+ .name = "panel-mipi-dbi-spi",
+ .owner = THIS_MODULE,
+ .of_match_table = panel_mipi_dbi_spi_of_match,
+ .pm = &panel_mipi_dbi_pm_ops,
+ },
+ .id_table = panel_mipi_dbi_spi_id,
+ .probe = panel_mipi_dbi_spi_probe,
+ .remove = panel_mipi_dbi_spi_remove,
+ .shutdown = panel_mipi_dbi_spi_shutdown,
+};
+module_spi_driver(panel_mipi_dbi_spi_driver);
+
+MODULE_DESCRIPTION("MIPI DBI compatible display panel driver");
+MODULE_AUTHOR("Noralf Trønnes");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/tiny/repaper.c b/drivers/gpu/drm/tiny/repaper.c
index 97a775c48cea..5c74e236b16d 100644
--- a/drivers/gpu/drm/tiny/repaper.c
+++ b/drivers/gpu/drm/tiny/repaper.c
@@ -508,26 +508,6 @@ static void repaper_get_temperature(struct repaper_epd *epd)
epd->factored_stage_time = epd->stage_time * factor10x / 10;
}
-static void repaper_gray8_to_mono_reversed(u8 *buf, u32 width, u32 height)
-{
- u8 *gray8 = buf, *mono = buf;
- int y, xb, i;
-
- for (y = 0; y < height; y++)
- for (xb = 0; xb < width / 8; xb++) {
- u8 byte = 0x00;
-
- for (i = 0; i < 8; i++) {
- int x = xb * 8 + i;
-
- byte >>= 1;
- if (gray8[y * width + x] >> 7)
- byte |= BIT(7);
- }
- *mono++ = byte;
- }
-}
-
static int repaper_fb_dirty(struct drm_framebuffer *fb)
{
struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
@@ -560,12 +540,10 @@ static int repaper_fb_dirty(struct drm_framebuffer *fb)
if (ret)
goto out_free;
- drm_fb_xrgb8888_to_gray8(buf, 0, cma_obj->vaddr, fb, &clip);
+ drm_fb_xrgb8888_to_mono_reversed(buf, 0, cma_obj->vaddr, fb, &clip);
drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);
- repaper_gray8_to_mono_reversed(buf, fb->width, fb->height);
-
if (epd->partial) {
repaper_frame_data_repeat(epd, buf, epd->current_frame,
REPAPER_NORMAL);
diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c
index d191e87a37b5..f5b8e864a5cd 100644
--- a/drivers/gpu/drm/tiny/simpledrm.c
+++ b/drivers/gpu/drm/tiny/simpledrm.c
@@ -810,6 +810,9 @@ static int simpledrm_device_init_modeset(struct simpledrm_device *sdev)
if (ret)
return ret;
drm_connector_helper_add(connector, &simpledrm_connector_helper_funcs);
+ drm_connector_set_panel_orientation_with_quirk(connector,
+ DRM_MODE_PANEL_ORIENTATION_UNKNOWN,
+ mode->hdisplay, mode->vdisplay);
formats = simpledrm_device_formats(sdev, &nformats);
diff --git a/drivers/gpu/drm/v3d/v3d_sched.c b/drivers/gpu/drm/v3d/v3d_sched.c
index 39459ae96f30..06238e6d7f5c 100644
--- a/drivers/gpu/drm/v3d/v3d_sched.c
+++ b/drivers/gpu/drm/v3d/v3d_sched.c
@@ -392,34 +392,24 @@ v3d_sched_init(struct v3d_dev *v3d)
hw_jobs_limit, job_hang_limit,
msecs_to_jiffies(hang_limit_ms), NULL,
NULL, "v3d_bin", v3d->drm.dev);
- if (ret) {
- dev_err(v3d->drm.dev, "Failed to create bin scheduler: %d.", ret);
+ if (ret)
return ret;
- }
ret = drm_sched_init(&v3d->queue[V3D_RENDER].sched,
&v3d_render_sched_ops,
hw_jobs_limit, job_hang_limit,
msecs_to_jiffies(hang_limit_ms), NULL,
NULL, "v3d_render", v3d->drm.dev);
- if (ret) {
- dev_err(v3d->drm.dev, "Failed to create render scheduler: %d.",
- ret);
- v3d_sched_fini(v3d);
- return ret;
- }
+ if (ret)
+ goto fail;
ret = drm_sched_init(&v3d->queue[V3D_TFU].sched,
&v3d_tfu_sched_ops,
hw_jobs_limit, job_hang_limit,
msecs_to_jiffies(hang_limit_ms), NULL,
NULL, "v3d_tfu", v3d->drm.dev);
- if (ret) {
- dev_err(v3d->drm.dev, "Failed to create TFU scheduler: %d.",
- ret);
- v3d_sched_fini(v3d);
- return ret;
- }
+ if (ret)
+ goto fail;
if (v3d_has_csd(v3d)) {
ret = drm_sched_init(&v3d->queue[V3D_CSD].sched,
@@ -427,27 +417,23 @@ v3d_sched_init(struct v3d_dev *v3d)
hw_jobs_limit, job_hang_limit,
msecs_to_jiffies(hang_limit_ms), NULL,
NULL, "v3d_csd", v3d->drm.dev);
- if (ret) {
- dev_err(v3d->drm.dev, "Failed to create CSD scheduler: %d.",
- ret);
- v3d_sched_fini(v3d);
- return ret;
- }
+ if (ret)
+ goto fail;
ret = drm_sched_init(&v3d->queue[V3D_CACHE_CLEAN].sched,
&v3d_cache_clean_sched_ops,
hw_jobs_limit, job_hang_limit,
msecs_to_jiffies(hang_limit_ms), NULL,
NULL, "v3d_cache_clean", v3d->drm.dev);
- if (ret) {
- dev_err(v3d->drm.dev, "Failed to create CACHE_CLEAN scheduler: %d.",
- ret);
- v3d_sched_fini(v3d);
- return ret;
- }
+ if (ret)
+ goto fail;
}
return 0;
+
+fail:
+ v3d_sched_fini(v3d);
+ return ret;
}
void
diff --git a/drivers/video/fbdev/core/cfbimgblt.c b/drivers/video/fbdev/core/cfbimgblt.c
index a2bb276a8b24..7361cfabdd85 100644
--- a/drivers/video/fbdev/core/cfbimgblt.c
+++ b/drivers/video/fbdev/core/cfbimgblt.c
@@ -16,15 +16,15 @@
* must be laid out exactly in the same format as the framebuffer. Yes I know
* their are cards with hardware that coverts images of various depths to the
* framebuffer depth. But not every card has this. All images must be rounded
- * up to the nearest byte. For example a bitmap 12 bits wide must be two
- * bytes width.
+ * up to the nearest byte. For example a bitmap 12 bits wide must be two
+ * bytes width.
*
- * Tony:
- * Incorporate mask tables similar to fbcon-cfb*.c in 2.4 API. This speeds
+ * Tony:
+ * Incorporate mask tables similar to fbcon-cfb*.c in 2.4 API. This speeds
* up the code significantly.
- *
+ *
* Code for depths not multiples of BITS_PER_LONG is still kludgy, which is
- * still processed a bit at a time.
+ * still processed a bit at a time.
*
* Also need to add code to deal with cards endians that are different than
* the native cpu endians. I also need to deal with MSB position in the word.
@@ -72,8 +72,8 @@ static const u32 cfb_tab32[] = {
#define FB_WRITEL fb_writel
#define FB_READL fb_readl
-static inline void color_imageblit(const struct fb_image *image,
- struct fb_info *p, u8 __iomem *dst1,
+static inline void color_imageblit(const struct fb_image *image,
+ struct fb_info *p, u8 __iomem *dst1,
u32 start_index,
u32 pitch_index)
{
@@ -92,7 +92,7 @@ static inline void color_imageblit(const struct fb_image *image,
dst = (u32 __iomem *) dst1;
shift = 0;
val = 0;
-
+
if (start_index) {
u32 start_mask = ~fb_shifted_pixels_mask_u32(p,
start_index, bswapmask);
@@ -109,8 +109,8 @@ static inline void color_imageblit(const struct fb_image *image,
val |= FB_SHIFT_HIGH(p, color, shift ^ bswapmask);
if (shift >= null_bits) {
FB_WRITEL(val, dst++);
-
- val = (shift == null_bits) ? 0 :
+
+ val = (shift == null_bits) ? 0 :
FB_SHIFT_LOW(p, color, 32 - shift);
}
shift += bpp;
@@ -134,9 +134,9 @@ static inline void color_imageblit(const struct fb_image *image,
}
}
-static inline void slow_imageblit(const struct fb_image *image, struct fb_info *p,
+static inline void slow_imageblit(const struct fb_image *image, struct fb_info *p,
u8 __iomem *dst1, u32 fgcolor,
- u32 bgcolor,
+ u32 bgcolor,
u32 start_index,
u32 pitch_index)
{
@@ -172,7 +172,7 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info *
l--;
color = (*s & (1 << l)) ? fgcolor : bgcolor;
val |= FB_SHIFT_HIGH(p, color, shift ^ bswapmask);
-
+
/* Did the bitshift spill bits to the next long? */
if (shift >= null_bits) {
FB_WRITEL(val, dst++);
@@ -191,16 +191,16 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info *
FB_WRITEL((FB_READL(dst) & end_mask) | val, dst);
}
-
+
dst1 += pitch;
- src += spitch;
+ src += spitch;
if (pitch_index) {
dst2 += pitch;
dst1 = (u8 __iomem *)((long __force)dst2 & ~(sizeof(u32) - 1));
start_index += pitch_index;
start_index &= 32 - 1;
}
-
+
}
}
@@ -212,29 +212,35 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info *
* fix->line_legth is divisible by 4;
* beginning and end of a scanline is dword aligned
*/
-static inline void fast_imageblit(const struct fb_image *image, struct fb_info *p,
- u8 __iomem *dst1, u32 fgcolor,
- u32 bgcolor)
+static inline void fast_imageblit(const struct fb_image *image, struct fb_info *p,
+ u8 __iomem *dst1, u32 fgcolor,
+ u32 bgcolor)
{
u32 fgx = fgcolor, bgx = bgcolor, bpp = p->var.bits_per_pixel;
u32 ppw = 32/bpp, spitch = (image->width + 7)/8;
- u32 bit_mask, end_mask, eorx, shift;
+ u32 bit_mask, eorx;
const char *s = image->data, *src;
u32 __iomem *dst;
const u32 *tab = NULL;
+ size_t tablen;
+ u32 colortab[16];
int i, j, k;
switch (bpp) {
case 8:
tab = fb_be_math(p) ? cfb_tab8_be : cfb_tab8_le;
+ tablen = 16;
break;
case 16:
tab = fb_be_math(p) ? cfb_tab16_be : cfb_tab16_le;
+ tablen = 4;
break;
case 32:
- default:
tab = cfb_tab32;
+ tablen = 2;
break;
+ default:
+ return;
}
for (i = ppw-1; i--; ) {
@@ -243,25 +249,52 @@ static inline void fast_imageblit(const struct fb_image *image, struct fb_info *
fgx |= fgcolor;
bgx |= bgcolor;
}
-
+
bit_mask = (1 << ppw) - 1;
eorx = fgx ^ bgx;
k = image->width/ppw;
+ for (i = 0; i < tablen; ++i)
+ colortab[i] = (tab[i] & eorx) ^ bgx;
+
for (i = image->height; i--; ) {
- dst = (u32 __iomem *) dst1, shift = 8; src = s;
-
- for (j = k; j--; ) {
- shift -= ppw;
- end_mask = tab[(*src >> shift) & bit_mask];
- FB_WRITEL((end_mask & eorx)^bgx, dst++);
- if (!shift) { shift = 8; src++; }
+ dst = (u32 __iomem *)dst1;
+ src = s;
+
+ switch (ppw) {
+ case 4: /* 8 bpp */
+ for (j = k; j; j -= 2, ++src) {
+ FB_WRITEL(colortab[(*src >> 4) & bit_mask], dst++);
+ FB_WRITEL(colortab[(*src >> 0) & bit_mask], dst++);
+ }
+ break;
+ case 2: /* 16 bpp */
+ for (j = k; j; j -= 4, ++src) {
+ FB_WRITEL(colortab[(*src >> 6) & bit_mask], dst++);
+ FB_WRITEL(colortab[(*src >> 4) & bit_mask], dst++);
+ FB_WRITEL(colortab[(*src >> 2) & bit_mask], dst++);
+ FB_WRITEL(colortab[(*src >> 0) & bit_mask], dst++);
+ }
+ break;
+ case 1: /* 32 bpp */
+ for (j = k; j; j -= 8, ++src) {
+ FB_WRITEL(colortab[(*src >> 7) & bit_mask], dst++);
+ FB_WRITEL(colortab[(*src >> 6) & bit_mask], dst++);
+ FB_WRITEL(colortab[(*src >> 5) & bit_mask], dst++);
+ FB_WRITEL(colortab[(*src >> 4) & bit_mask], dst++);
+ FB_WRITEL(colortab[(*src >> 3) & bit_mask], dst++);
+ FB_WRITEL(colortab[(*src >> 2) & bit_mask], dst++);
+ FB_WRITEL(colortab[(*src >> 1) & bit_mask], dst++);
+ FB_WRITEL(colortab[(*src >> 0) & bit_mask], dst++);
+ }
+ break;
}
+
dst1 += p->fix.line_length;
s += spitch;
}
-}
-
+}
+
void cfb_imageblit(struct fb_info *p, const struct fb_image *image)
{
u32 fgcolor, bgcolor, start_index, bitstart, pitch_index = 0;
@@ -292,13 +325,13 @@ void cfb_imageblit(struct fb_info *p, const struct fb_image *image)
} else {
fgcolor = image->fg_color;
bgcolor = image->bg_color;
- }
-
- if (32 % bpp == 0 && !start_index && !pitch_index &&
+ }
+
+ if (32 % bpp == 0 && !start_index && !pitch_index &&
((width & (32/bpp-1)) == 0) &&
- bpp >= 8 && bpp <= 32)
+ bpp >= 8 && bpp <= 32)
fast_imageblit(image, p, dst1, fgcolor, bgcolor);
- else
+ else
slow_imageblit(image, p, dst1, fgcolor, bgcolor,
start_index, pitch_index);
} else
diff --git a/drivers/video/fbdev/core/sysfillrect.c b/drivers/video/fbdev/core/sysfillrect.c
index 33ee3d34f9d2..bcdcaeae6538 100644
--- a/drivers/video/fbdev/core/sysfillrect.c
+++ b/drivers/video/fbdev/core/sysfillrect.c
@@ -50,19 +50,9 @@ bitfill_aligned(struct fb_info *p, unsigned long *dst, int dst_idx,
/* Main chunk */
n /= bits;
- while (n >= 8) {
- *dst++ = pat;
- *dst++ = pat;
- *dst++ = pat;
- *dst++ = pat;
- *dst++ = pat;
- *dst++ = pat;
- *dst++ = pat;
- *dst++ = pat;
- n -= 8;
- }
- while (n--)
- *dst++ = pat;
+ memset_l(dst, pat, n);
+ dst += n;
+
/* Trailing bits */
if (last)
*dst = comp(pat, *dst, last);
diff --git a/drivers/video/fbdev/core/sysimgblt.c b/drivers/video/fbdev/core/sysimgblt.c
index a4d05b1b17d7..722c327a381b 100644
--- a/drivers/video/fbdev/core/sysimgblt.c
+++ b/drivers/video/fbdev/core/sysimgblt.c
@@ -188,23 +188,29 @@ static void fast_imageblit(const struct fb_image *image, struct fb_info *p,
{
u32 fgx = fgcolor, bgx = bgcolor, bpp = p->var.bits_per_pixel;
u32 ppw = 32/bpp, spitch = (image->width + 7)/8;
- u32 bit_mask, end_mask, eorx, shift;
+ u32 bit_mask, eorx;
const char *s = image->data, *src;
u32 *dst;
- const u32 *tab = NULL;
+ const u32 *tab;
+ size_t tablen;
+ u32 colortab[16];
int i, j, k;
switch (bpp) {
case 8:
tab = fb_be_math(p) ? cfb_tab8_be : cfb_tab8_le;
+ tablen = 16;
break;
case 16:
tab = fb_be_math(p) ? cfb_tab16_be : cfb_tab16_le;
+ tablen = 4;
break;
case 32:
- default:
tab = cfb_tab32;
+ tablen = 2;
break;
+ default:
+ return;
}
for (i = ppw-1; i--; ) {
@@ -218,19 +224,40 @@ static void fast_imageblit(const struct fb_image *image, struct fb_info *p,
eorx = fgx ^ bgx;
k = image->width/ppw;
+ for (i = 0; i < tablen; ++i)
+ colortab[i] = (tab[i] & eorx) ^ bgx;
+
for (i = image->height; i--; ) {
dst = dst1;
- shift = 8;
src = s;
- for (j = k; j--; ) {
- shift -= ppw;
- end_mask = tab[(*src >> shift) & bit_mask];
- *dst++ = (end_mask & eorx) ^ bgx;
- if (!shift) {
- shift = 8;
- src++;
+ switch (ppw) {
+ case 4: /* 8 bpp */
+ for (j = k; j; j -= 2, ++src) {
+ *dst++ = colortab[(*src >> 4) & bit_mask];
+ *dst++ = colortab[(*src >> 0) & bit_mask];
+ }
+ break;
+ case 2: /* 16 bpp */
+ for (j = k; j; j -= 4, ++src) {
+ *dst++ = colortab[(*src >> 6) & bit_mask];
+ *dst++ = colortab[(*src >> 4) & bit_mask];
+ *dst++ = colortab[(*src >> 2) & bit_mask];
+ *dst++ = colortab[(*src >> 0) & bit_mask];
+ }
+ break;
+ case 1: /* 32 bpp */
+ for (j = k; j; j -= 8, ++src) {
+ *dst++ = colortab[(*src >> 7) & bit_mask];
+ *dst++ = colortab[(*src >> 6) & bit_mask];
+ *dst++ = colortab[(*src >> 5) & bit_mask];
+ *dst++ = colortab[(*src >> 4) & bit_mask];
+ *dst++ = colortab[(*src >> 3) & bit_mask];
+ *dst++ = colortab[(*src >> 2) & bit_mask];
+ *dst++ = colortab[(*src >> 1) & bit_mask];
+ *dst++ = colortab[(*src >> 0) & bit_mask];
}
+ break;
}
dst1 += p->fix.line_length;
s += spitch;
diff --git a/include/drm/dp/drm_dp_helper.h b/include/drm/dp/drm_dp_helper.h
index 69487bd8ed56..51e02cf75277 100644
--- a/include/drm/dp/drm_dp_helper.h
+++ b/include/drm/dp/drm_dp_helper.h
@@ -456,7 +456,7 @@ struct drm_panel;
#define DP_FEC_CAPABILITY_1 0x091 /* 2.0 */
/* DP-HDMI2.1 PCON DSC ENCODER SUPPORT */
-#define DP_PCON_DSC_ENCODER_CAP_SIZE 0xC /* 0x9E - 0x92 */
+#define DP_PCON_DSC_ENCODER_CAP_SIZE 0xD /* 0x92 through 0x9E */
#define DP_PCON_DSC_ENCODER 0x092
# define DP_PCON_DSC_ENCODER_SUPPORTED (1 << 0)
# define DP_PCON_DSC_PPS_ENC_OVERRIDE (1 << 1)
@@ -1530,8 +1530,6 @@ u8 drm_dp_get_adjust_request_pre_emphasis(const u8 link_status[DP_LINK_STATUS_SI
int lane);
u8 drm_dp_get_adjust_tx_ffe_preset(const u8 link_status[DP_LINK_STATUS_SIZE],
int lane);
-u8 drm_dp_get_adjust_request_post_cursor(const u8 link_status[DP_LINK_STATUS_SIZE],
- unsigned int lane);
#define DP_BRANCH_OUI_HEADER_SIZE 0xc
#define DP_RECEIVER_CAP_SIZE 0xf
diff --git a/include/drm/drm_mipi_dbi.h b/include/drm/drm_mipi_dbi.h
index 6fe13cce2670..dad2f187b64b 100644
--- a/include/drm/drm_mipi_dbi.h
+++ b/include/drm/drm_mipi_dbi.h
@@ -130,6 +130,14 @@ struct mipi_dbi_dev {
* @dbi: MIPI DBI interface
*/
struct mipi_dbi dbi;
+
+ /**
+ * @driver_private: Driver private data.
+ * Necessary for drivers with private data since devm_drm_dev_alloc()
+ * can't allocate structures that embed a structure which then again
+ * embeds drm_device.
+ */
+ void *driver_private;
};
static inline struct mipi_dbi_dev *drm_to_mipi_dbi_dev(struct drm_device *drm)
diff --git a/include/drm/drm_mode_object.h b/include/drm/drm_mode_object.h
index c34a3e8030e1..912f1e415685 100644
--- a/include/drm/drm_mode_object.h
+++ b/include/drm/drm_mode_object.h
@@ -98,6 +98,10 @@ struct drm_object_properties {
* Hence atomic drivers should not use drm_object_property_set_value()
* and drm_object_property_get_value() on mutable objects, i.e. those
* without the DRM_MODE_PROP_IMMUTABLE flag set.
+ *
+ * For atomic drivers the default value of properties is stored in this
+ * array, so drm_object_property_get_default_value can be used to
+ * retrieve it.
*/
uint64_t values[DRM_OBJECT_MAX_PROPERTY];
};
@@ -126,6 +130,9 @@ int drm_object_property_set_value(struct drm_mode_object *obj,
int drm_object_property_get_value(struct drm_mode_object *obj,
struct drm_property *property,
uint64_t *value);
+int drm_object_property_get_default_value(struct drm_mode_object *obj,
+ struct drm_property *property,
+ uint64_t *val);
void drm_object_attach_property(struct drm_mode_object *obj,
struct drm_property *property,
diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h
index 29ba4adf0c53..2fa6b2c33b3f 100644
--- a/include/drm/drm_modes.h
+++ b/include/drm/drm_modes.h
@@ -466,6 +466,8 @@ void drm_bus_flags_from_videomode(const struct videomode *vm, u32 *bus_flags);
int of_get_drm_display_mode(struct device_node *np,
struct drm_display_mode *dmode, u32 *bus_flags,
int index);
+int of_get_drm_panel_display_mode(struct device_node *np,
+ struct drm_display_mode *dmode, u32 *bus_flags);
#else
static inline int of_get_drm_display_mode(struct device_node *np,
struct drm_display_mode *dmode,
@@ -473,6 +475,12 @@ static inline int of_get_drm_display_mode(struct device_node *np,
{
return -EINVAL;
}
+
+static inline int of_get_drm_panel_display_mode(struct device_node *np,
+ struct drm_display_mode *dmode, u32 *bus_flags)
+{
+ return -EINVAL;
+}
#endif
void drm_mode_set_name(struct drm_display_mode *mode);