From 6d9c0eb22dc7c3fbe05bbb000a5d35d0fd1168ab Mon Sep 17 00:00:00 2001 From: Lionel Vitte Date: Thu, 14 Oct 2021 16:51:43 +0200 Subject: [PATCH 06/23] ARM 5.10.61-stm32mp1-r2 DRM --- drivers/gpu/drm/bridge/sii902x.c | 100 +++++++++- drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 172 ++++++++++++++---- drivers/gpu/drm/drm_atomic_state_helper.c | 1 + drivers/gpu/drm/drm_atomic_uapi.c | 4 + drivers/gpu/drm/drm_blend.c | 34 +++- drivers/gpu/drm/drm_mode_config.c | 6 + drivers/gpu/drm/drm_modes.c | 19 +- .../gpu/drm/panel/panel-orisetech-otm8009a.c | 119 +++++++----- drivers/gpu/drm/panel/panel-raydium-rm68200.c | 21 ++- drivers/gpu/drm/stm/drv.c | 5 + drivers/gpu/drm/stm/dw_mipi_dsi-stm.c | 20 +- drivers/gpu/drm/stm/ltdc.c | 169 +++++++++++------ drivers/input/touchscreen/edt-ft5x06.c | 18 +- drivers/input/touchscreen/goodix.c | 15 ++ include/drm/drm_blend.h | 1 + include/drm/drm_crtc.h | 12 ++ include/drm/drm_mode_config.h | 5 + include/uapi/drm/drm_mode.h | 34 ++++ 18 files changed, 591 insertions(+), 164 deletions(-) diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c index 89558e581..69208ead5 100644 --- a/drivers/gpu/drm/bridge/sii902x.c +++ b/drivers/gpu/drm/bridge/sii902x.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -162,6 +163,11 @@ #define SII902X_AUDIO_PORT_INDEX 3 +/* CEC device */ +#define SII902X_CEC_I2C_ADDR 0x30 + +#define SII902X_CEC_SETUP 0x8e + struct sii902x { struct i2c_client *i2c; struct regmap *regmap; @@ -170,6 +176,7 @@ struct sii902x { struct gpio_desc *reset_gpio; struct i2c_mux_core *i2cmux; struct regulator_bulk_data supplies[2]; + struct edid *edid; /* * Mutex protects audio and video functions from interfering * each other, by keeping their i2c command sequences atomic. @@ -280,6 +287,8 @@ static int sii902x_get_modes(struct drm_connector *connector) mutex_lock(&sii902x->mutex); + kfree(sii902x->edid); + sii902x->edid = NULL; edid = drm_get_edid(connector, sii902x->i2cmux->adapter[0]); drm_connector_update_edid_property(connector, edid); if (edid) { @@ -287,7 +296,7 @@ static int sii902x_get_modes(struct drm_connector *connector) output_mode = SII902X_SYS_CTRL_OUTPUT_HDMI; num = drm_add_edid_modes(connector, edid); - kfree(edid); + sii902x->edid = edid; } ret = drm_display_info_set_bus_formats(&connector->display_info, @@ -337,6 +346,7 @@ static void sii902x_bridge_disable(struct drm_bridge *bridge) static void sii902x_bridge_enable(struct drm_bridge *bridge) { struct sii902x *sii902x = bridge_to_sii902x(bridge); + u8 output_mode = SII902X_SYS_CTRL_OUTPUT_DVI; mutex_lock(&sii902x->mutex); @@ -346,6 +356,14 @@ static void sii902x_bridge_enable(struct drm_bridge *bridge) regmap_update_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA, SII902X_SYS_CTRL_PWR_DWN, 0); + if (sii902x->edid) { + if (drm_detect_hdmi_monitor(sii902x->edid)) + output_mode = SII902X_SYS_CTRL_OUTPUT_HDMI; + } + + regmap_update_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA, + SII902X_SYS_CTRL_OUTPUT_MODE, output_mode); + mutex_unlock(&sii902x->mutex); } @@ -960,6 +978,13 @@ static int sii902x_init(struct sii902x *sii902x) { struct device *dev = &sii902x->i2c->dev; unsigned int status = 0; + unsigned char data[2] = { SII902X_CEC_SETUP, 0}; + struct i2c_msg msg = { + .addr = SII902X_CEC_I2C_ADDR << 1, + .flags = 0, + .len = 2, + .buf = data, + }; u8 chipid[4]; int ret; @@ -982,13 +1007,22 @@ static int sii902x_init(struct sii902x *sii902x) return -EINVAL; } + /* + * By default, CEC must be disabled to allow other CEC devives + * to bypass the bridge. + */ + ret = i2c_transfer(sii902x->i2c->adapter, &msg, 1); + if (ret < 0) + dev_warn(&sii902x->i2c->dev, "Failed to disable CEC device!\n"); + /* Clear all pending interrupts */ regmap_read(sii902x->regmap, SII902X_INT_STATUS, &status); regmap_write(sii902x->regmap, SII902X_INT_STATUS, status); if (sii902x->i2c->irq > 0) { - regmap_write(sii902x->regmap, SII902X_INT_ENABLE, - SII902X_HOTPLUG_EVENT); + regmap_update_bits(sii902x->regmap, SII902X_INT_ENABLE, + SII902X_HOTPLUG_EVENT, + SII902X_HOTPLUG_EVENT); ret = devm_request_threaded_irq(dev, sii902x->i2c->irq, NULL, sii902x_interrupt, @@ -1087,6 +1121,65 @@ static int sii902x_remove(struct i2c_client *client) return 0; } +static int sii902x_pm_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sii902x *sii902x = i2c_get_clientdata(client); + + DRM_DEBUG_DRIVER("\n"); + + if (sii902x->reset_gpio) + gpiod_set_value(sii902x->reset_gpio, 1); + + regulator_bulk_disable(ARRAY_SIZE(sii902x->supplies), + sii902x->supplies); + + return 0; +} + +static int sii902x_pm_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sii902x *sii902x = i2c_get_clientdata(client); + unsigned char data[2] = { SII902X_CEC_SETUP, 0}; + struct i2c_msg msg = { + .addr = SII902X_CEC_I2C_ADDR << 1, + .flags = 0, + .len = 2, + .buf = data, + }; + int ret; + + DRM_DEBUG_DRIVER("\n"); + + ret = regulator_bulk_enable(ARRAY_SIZE(sii902x->supplies), + sii902x->supplies); + if (ret) { + DRM_ERROR("regulator_bulk_enable failed\n"); + return ret; + } + + if (sii902x->reset_gpio) + gpiod_set_value(sii902x->reset_gpio, 0); + + regmap_write(sii902x->regmap, SII902X_REG_TPI_RQB, 0x00); + + ret = i2c_transfer(client->adapter, &msg, 1); + if (ret < 0) + DRM_ERROR("Failed to disable CEC device!\n"); + + if (client->irq > 0) + regmap_update_bits(sii902x->regmap, SII902X_INT_ENABLE, + SII902X_HOTPLUG_EVENT, + SII902X_HOTPLUG_EVENT); + + return 0; +} + +static const struct dev_pm_ops sii902x_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(sii902x_pm_suspend, sii902x_pm_resume) +}; + static const struct of_device_id sii902x_dt_ids[] = { { .compatible = "sil,sii9022", }, { } @@ -1105,6 +1198,7 @@ static struct i2c_driver sii902x_driver = { .driver = { .name = "sii902x", .of_match_table = sii902x_dt_ids, + .pm = &sii902x_pm_ops, }, .id_table = sii902x_i2c_ids, }; diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c index 6b268f944..25b634911 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c @@ -213,6 +213,20 @@ #define DSI_INT_ST0 0xbc #define DSI_INT_ST1 0xc0 +#define GPRXE BIT(12) +#define GPRDE BIT(11) +#define GPTXE BIT(10) +#define GPWRE BIT(9) +#define GCWRE BIT(8) +#define DPIPLDWE BIT(7) +#define EOTPE BIT(6) +#define PSE BIT(5) +#define CRCE BIT(4) +#define ECCME BIT(3) +#define ECCSE BIT(2) +#define TOLPRX BIT(1) +#define TOHSTX BIT(0) + #define DSI_INT_MSK0 0xc4 #define DSI_INT_MSK1 0xc8 @@ -314,9 +328,7 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host, { struct dw_mipi_dsi *dsi = host_to_dsi(host); const struct dw_mipi_dsi_plat_data *pdata = dsi->plat_data; - struct drm_bridge *bridge; - struct drm_panel *panel; - int ret; + int ret = -ENODEV; if (device->lanes > dsi->plat_data->max_data_lanes) { dev_err(dsi->dev, "the number of data lanes(%u) is too many\n", @@ -329,22 +341,6 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host, dsi->format = device->format; dsi->mode_flags = device->mode_flags; - ret = drm_of_find_panel_or_bridge(host->dev->of_node, 1, 0, - &panel, &bridge); - if (ret) - return ret; - - if (panel) { - bridge = drm_panel_bridge_add_typed(panel, - DRM_MODE_CONNECTOR_DSI); - if (IS_ERR(bridge)) - return PTR_ERR(bridge); - } - - dsi->panel_bridge = bridge; - - drm_bridge_add(&dsi->bridge); - if (pdata->host_ops && pdata->host_ops->attach) { ret = pdata->host_ops->attach(pdata->priv_data, device); if (ret < 0) @@ -367,10 +363,6 @@ static int dw_mipi_dsi_host_detach(struct mipi_dsi_host *host, return ret; } - drm_of_panel_bridge_remove(host->dev->of_node, 1, 0); - - drm_bridge_remove(&dsi->bridge); - return 0; } @@ -431,6 +423,42 @@ static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val) return 0; } +static int dw_mipi_dsi_read_status(struct dw_mipi_dsi *dsi) +{ + u32 val; + + val = dsi_read(dsi, DSI_INT_ST1); + + if (val & GPRXE) + DRM_DEBUG_DRIVER("DSI Generic payload receive error\n"); + if (val & GPRDE) + DRM_DEBUG_DRIVER("DSI Generic payload read error\n"); + if (val & GPTXE) + DRM_DEBUG_DRIVER("DSI Generic payload transmit error\n"); + if (val & GPWRE) + DRM_DEBUG_DRIVER("DSI Generic payload write error\n"); + if (val & GCWRE) + DRM_DEBUG_DRIVER("DSI Generic command write error\n"); + if (val & DPIPLDWE) + DRM_DEBUG_DRIVER("DSI DPI payload write error\n"); + if (val & EOTPE) + DRM_DEBUG_DRIVER("DSI EoTp error\n"); + if (val & PSE) + DRM_DEBUG_DRIVER("DSI Packet size error\n"); + if (val & CRCE) + DRM_DEBUG_DRIVER("DSI CRC error\n"); + if (val & ECCME) + DRM_DEBUG_DRIVER("DSI ECC multi-bit error\n"); + if (val & ECCSE) + DRM_DEBUG_DRIVER("DSI ECC single-bit error\n"); + if (val & TOLPRX) + DRM_DEBUG_DRIVER("DSI Timeout low-power reception\n"); + if (val & TOHSTX) + DRM_DEBUG_DRIVER("DSI Timeout high-speed transmission\n"); + + return val; +} + static int dw_mipi_dsi_write(struct dw_mipi_dsi *dsi, const struct mipi_dsi_packet *packet) { @@ -460,6 +488,12 @@ static int dw_mipi_dsi_write(struct dw_mipi_dsi *dsi, "failed to get available write payload FIFO\n"); return ret; } + + val = dw_mipi_dsi_read_status(dsi); + if (val) { + dev_err(dsi->dev, "dsi status error 0x%0x\n", val); + return -EINVAL; + } } word = 0; @@ -493,6 +527,12 @@ static int dw_mipi_dsi_read(struct dw_mipi_dsi *dsi, return ret; } + val = dw_mipi_dsi_read_status(dsi); + if (val) { + dev_err(dsi->dev, "dsi status error 0x%0x\n", val); + return -EINVAL; + } + val = dsi_read(dsi, DSI_GEN_PLD_DATA); for (j = 0; j < 4 && j + i < len; j++) buf[i + j] = val >> (8 * j); @@ -507,6 +547,7 @@ static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host, struct dw_mipi_dsi *dsi = host_to_dsi(host); struct mipi_dsi_packet packet; int ret, nb_bytes; + int retry = 3; ret = mipi_dsi_create_packet(&packet, msg); if (ret) { @@ -518,24 +559,32 @@ static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host, if (dsi->slave) dw_mipi_message_config(dsi->slave, msg); - ret = dw_mipi_dsi_write(dsi, &packet); - if (ret) - return ret; - if (dsi->slave) { - ret = dw_mipi_dsi_write(dsi->slave, &packet); + while (retry--) { + ret = dw_mipi_dsi_write(dsi, &packet); if (ret) - return ret; - } + continue; - if (msg->rx_buf && msg->rx_len) { - ret = dw_mipi_dsi_read(dsi, msg); - if (ret) - return ret; - nb_bytes = msg->rx_len; - } else { - nb_bytes = packet.size; + if (dsi->slave) { + ret = dw_mipi_dsi_write(dsi->slave, &packet); + if (ret) + continue; + } + + if (msg->rx_buf && msg->rx_len) { + ret = dw_mipi_dsi_read(dsi, msg); + if (ret) + continue; + nb_bytes = msg->rx_len; + break; + } else { + nb_bytes = packet.size; + break; + } } + if (ret) + return ret; + return nb_bytes; } @@ -1105,6 +1154,9 @@ __dw_mipi_dsi_probe(struct platform_device *pdev, struct device *dev = &pdev->dev; struct reset_control *apb_rst; struct dw_mipi_dsi *dsi; + struct drm_bridge *bridge; + struct drm_panel *panel; + int i, nb_endpoints; int ret; dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL); @@ -1172,8 +1224,7 @@ __dw_mipi_dsi_probe(struct platform_device *pdev, ret = mipi_dsi_host_register(&dsi->dsi_host); if (ret) { dev_err(dev, "Failed to register MIPI host: %d\n", ret); - dw_mipi_dsi_debugfs_remove(dsi); - return ERR_PTR(ret); + goto err_pmr_enable; } dsi->bridge.driver_private = dsi; @@ -1182,11 +1233,54 @@ __dw_mipi_dsi_probe(struct platform_device *pdev, dsi->bridge.of_node = pdev->dev.of_node; #endif + /* Get number of endpoints */ + nb_endpoints = of_graph_get_endpoint_count(pdev->dev.of_node); + if (!nb_endpoints) { + ret = -ENODEV; + goto err_host_reg; + } + + for (i = 1; i < nb_endpoints; i++) { + ret = drm_of_find_panel_or_bridge(pdev->dev.of_node, i, 0, + &panel, &bridge); + if (!ret) + break; + else if (ret == -EPROBE_DEFER) + goto err_host_reg; + } + + /* check if an error is returned >> no panel or bridge detected */ + if (ret) + goto err_host_reg; + + if (panel) { + bridge = drm_panel_bridge_add_typed(panel, DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(bridge)) { + ret = PTR_ERR(bridge); + goto err_host_reg; + } + } + + dsi->panel_bridge = bridge; + + drm_bridge_add(&dsi->bridge); + return dsi; + +err_host_reg: + mipi_dsi_host_unregister(&dsi->dsi_host); + +err_pmr_enable: + pm_runtime_disable(dev); + dw_mipi_dsi_debugfs_remove(dsi); + + return ERR_PTR(ret); } static void __dw_mipi_dsi_remove(struct dw_mipi_dsi *dsi) { + drm_bridge_remove(&dsi->bridge); + drm_panel_bridge_remove(dsi->panel_bridge); mipi_dsi_host_unregister(&dsi->dsi_host); pm_runtime_disable(dsi->dev); diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c index 9ad740451..ae89e8134 100644 --- a/drivers/gpu/drm/drm_atomic_state_helper.c +++ b/drivers/gpu/drm/drm_atomic_state_helper.c @@ -72,6 +72,7 @@ __drm_atomic_helper_crtc_state_reset(struct drm_crtc_state *crtc_state, struct drm_crtc *crtc) { crtc_state->crtc = crtc; + crtc_state->bgcolor = drm_argb(16, 0xffff, 0, 0, 0); } EXPORT_SYMBOL(__drm_atomic_helper_crtc_state_reset); diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c index 25c269bc4..569f5d364 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -469,6 +469,8 @@ static int drm_atomic_crtc_set_property(struct drm_crtc *crtc, return -EFAULT; set_out_fence_for_crtc(state->state, crtc, fence_ptr); + } else if (property == config->bgcolor_property) { + state->bgcolor = val; } else if (crtc->funcs->atomic_set_property) { return crtc->funcs->atomic_set_property(crtc, state, property, val); } else { @@ -503,6 +505,8 @@ drm_atomic_crtc_get_property(struct drm_crtc *crtc, *val = (state->gamma_lut) ? state->gamma_lut->base.id : 0; else if (property == config->prop_out_fence_ptr) *val = 0; + else if (property == config->bgcolor_property) + *val = state->bgcolor; else if (crtc->funcs->atomic_get_property) return crtc->funcs->atomic_get_property(crtc, state, property, val); else diff --git a/drivers/gpu/drm/drm_blend.c b/drivers/gpu/drm/drm_blend.c index f1dcad96f..1e786abc6 100644 --- a/drivers/gpu/drm/drm_blend.c +++ b/drivers/gpu/drm/drm_blend.c @@ -185,6 +185,21 @@ * plane does not expose the "alpha" property, then this is * assumed to be 1.0 * + * BACKGROUND_COLOR: + * Defines the ARGB color of a full-screen layer that exists below all + * planes. This color will be used for pixels not covered by any plane + * and may also be blended with plane contents as allowed by a plane's + * alpha values. The background color defaults to black, and is assumed + * to be black for drivers that do not expose this property. Although + * background color isn't a plane, it is assumed that the color provided + * here undergoes the same pipe-level degamma/CSC/gamma transformations + * that planes undergo. Note that the color value provided here includes + * an alpha channel...non-opaque background color values are allowed, + * but are generally only honored in special cases (e.g., when a memory + * writeback connector is in use). + * + * This property is setup with drm_crtc_add_bgcolor_property(). + * * IN_FORMATS: * Blob property which contains the set of buffer format and modifier * pairs supported by this plane. The blob is a drm_format_modifier_blob @@ -192,8 +207,7 @@ * modifiers. Userspace cannot change this property. * * Note that all the property extensions described here apply either to the - * plane or the CRTC (e.g. for the background color, which currently is not - * exposed and assumed to be black). + * plane or the CRTC. */ /** @@ -609,3 +623,19 @@ int drm_plane_create_blend_mode_property(struct drm_plane *plane, return 0; } EXPORT_SYMBOL(drm_plane_create_blend_mode_property); + +/** + * drm_crtc_add_bgcolor_property - add background color property + * @crtc: drm crtc + * + * Adds the background color property to @crtc. The property defaults to + * solid black and will accept 64-bit ARGB values in the format generated by + * drm_argb(). + */ +void drm_crtc_add_bgcolor_property(struct drm_crtc *crtc) +{ + drm_object_attach_property(&crtc->base, + crtc->dev->mode_config.bgcolor_property, + drm_argb(16, 0xffff, 0, 0, 0)); +} +EXPORT_SYMBOL(drm_crtc_add_bgcolor_property); diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c index f1affc1bb..845091106 100644 --- a/drivers/gpu/drm/drm_mode_config.c +++ b/drivers/gpu/drm/drm_mode_config.c @@ -371,6 +371,12 @@ static int drm_mode_create_standard_properties(struct drm_device *dev) return -ENOMEM; dev->mode_config.modifiers_property = prop; + prop = drm_property_create_range(dev, 0, "BACKGROUND_COLOR", + 0, GENMASK_ULL(63, 0)); + if (!prop) + return -ENOMEM; + dev->mode_config.bgcolor_property = prop; + return 0; } diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index 511cde5c7..58ab4a543 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -127,7 +127,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. @@ -615,6 +615,15 @@ void drm_display_mode_from_videomode(const struct videomode *vm, dmode->flags |= DRM_MODE_FLAG_DBLSCAN; if (vm->flags & DISPLAY_FLAGS_DOUBLECLK) dmode->flags |= DRM_MODE_FLAG_DBLCLK; + if (vm->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE) + dmode->flags |= DRM_MODE_FLAG_PPIXDATA; + else if (vm->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE) + dmode->flags |= DRM_MODE_FLAG_NPIXDATA; + if (vm->flags & DISPLAY_FLAGS_DE_HIGH) + dmode->flags |= DRM_MODE_FLAG_PDE; + else if (vm->flags & DISPLAY_FLAGS_DE_LOW) + dmode->flags |= DRM_MODE_FLAG_NDE; + drm_mode_set_name(dmode); } EXPORT_SYMBOL_GPL(drm_display_mode_from_videomode); @@ -656,6 +665,14 @@ void drm_display_mode_to_videomode(const struct drm_display_mode *dmode, vm->flags |= DISPLAY_FLAGS_DOUBLESCAN; if (dmode->flags & DRM_MODE_FLAG_DBLCLK) vm->flags |= DISPLAY_FLAGS_DOUBLECLK; + if (dmode->flags & DRM_MODE_FLAG_PPIXDATA) + vm->flags |= DISPLAY_FLAGS_PIXDATA_POSEDGE; + else if (dmode->flags & DRM_MODE_FLAG_NPIXDATA) + vm->flags |= DISPLAY_FLAGS_PIXDATA_NEGEDGE; + if (dmode->flags & DRM_MODE_FLAG_PDE) + vm->flags |= DISPLAY_FLAGS_DE_HIGH; + else if (dmode->flags & DRM_MODE_FLAG_NDE) + vm->flags |= DISPLAY_FLAGS_DE_LOW; } EXPORT_SYMBOL_GPL(drm_display_mode_to_videomode); diff --git a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c index 6ac1accad..70b2bb72d 100644 --- a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c +++ b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c @@ -60,6 +60,9 @@ #define MCS_CMD2_ENA1 0xFF00 /* Enable Access Command2 "CMD2" */ #define MCS_CMD2_ENA2 0xFF80 /* Enable Access Orise Command2 */ +#define OTM8009A_HDISPLAY 480 +#define OTM8009A_VDISPLAY 800 + struct otm8009a { struct device *dev; struct drm_panel panel; @@ -70,19 +73,35 @@ struct otm8009a { bool enabled; }; -static const struct drm_display_mode default_mode = { - .clock = 29700, - .hdisplay = 480, - .hsync_start = 480 + 98, - .hsync_end = 480 + 98 + 32, - .htotal = 480 + 98 + 32 + 98, - .vdisplay = 800, - .vsync_start = 800 + 15, - .vsync_end = 800 + 15 + 10, - .vtotal = 800 + 15 + 10 + 14, - .flags = 0, - .width_mm = 52, - .height_mm = 86, +static const struct drm_display_mode modes[] = { + { /* 50 Hz, preferred */ + .clock = 29700, + .hdisplay = 480, + .hsync_start = 480 + 98, + .hsync_end = 480 + 98 + 32, + .htotal = 480 + 98 + 32 + 98, + .vdisplay = 800, + .vsync_start = 800 + 15, + .vsync_end = 800 + 15 + 10, + .vtotal = 800 + 15 + 10 + 14, + .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, + .width_mm = 52, + .height_mm = 86, + }, + { /* 60 Hz */ + .clock = 33000, + .hdisplay = 480, + .hsync_start = 480 + 70, + .hsync_end = 480 + 70 + 32, + .htotal = 480 + 70 + 32 + 72, + .vdisplay = 800, + .vsync_start = 800 + 15, + .vsync_end = 800 + 15 + 10, + .vtotal = 800 + 15 + 10 + 16, + .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, + .width_mm = 52, + .height_mm = 86, + }, }; static inline struct otm8009a *panel_to_otm8009a(struct drm_panel *panel) @@ -99,20 +118,6 @@ static void otm8009a_dcs_write_buf(struct otm8009a *ctx, const void *data, dev_warn(ctx->dev, "mipi dsi dcs write buffer failed\n"); } -static void otm8009a_dcs_write_buf_hs(struct otm8009a *ctx, const void *data, - size_t len) -{ - struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); - - /* data will be sent in dsi hs mode (ie. no lpm) */ - dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; - - otm8009a_dcs_write_buf(ctx, data, len); - - /* restore back the dsi lpm mode */ - dsi->mode_flags |= MIPI_DSI_MODE_LPM; -} - #define dcs_write_seq(ctx, seq...) \ ({ \ static const u8 d[] = { seq }; \ @@ -222,12 +227,11 @@ static int otm8009a_init_sequence(struct otm8009a *ctx) /* Default portrait 480x800 rgb24 */ dcs_write_seq(ctx, MIPI_DCS_SET_ADDRESS_MODE, 0x00); - ret = mipi_dsi_dcs_set_column_address(dsi, 0, - default_mode.hdisplay - 1); + ret = mipi_dsi_dcs_set_column_address(dsi, 0, OTM8009A_HDISPLAY - 1); if (ret) return ret; - ret = mipi_dsi_dcs_set_page_address(dsi, 0, default_mode.vdisplay - 1); + ret = mipi_dsi_dcs_set_page_address(dsi, 0, OTM8009A_VDISPLAY - 1); if (ret) return ret; @@ -351,24 +355,35 @@ static int otm8009a_get_modes(struct drm_panel *panel, struct drm_connector *connector) { struct drm_display_mode *mode; - - mode = drm_mode_duplicate(connector->dev, &default_mode); - if (!mode) { - dev_err(panel->dev, "failed to add mode %ux%u@%u\n", - default_mode.hdisplay, default_mode.vdisplay, - drm_mode_vrefresh(&default_mode)); - return -ENOMEM; + unsigned int num_modes = ARRAY_SIZE(modes); + unsigned int i; + + for (i = 0; i < num_modes; i++) { + mode = drm_mode_duplicate(connector->dev, &modes[i]); + if (!mode) { + dev_err(panel->dev, "failed to add mode %ux%u@%u\n", + modes[i].hdisplay, + modes[i].vdisplay, + drm_mode_vrefresh(&modes[i])); + return -ENOMEM; + } + + mode->type = DRM_MODE_TYPE_DRIVER; + + /* Setting first mode as preferred */ + if (!i) + mode->type |= DRM_MODE_TYPE_PREFERRED; + + drm_mode_set_name(mode); + drm_mode_probed_add(connector, mode); } - drm_mode_set_name(mode); - - mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; - drm_mode_probed_add(connector, mode); - connector->display_info.width_mm = mode->width_mm; connector->display_info.height_mm = mode->height_mm; + connector->display_info.bus_flags = DRM_BUS_FLAG_DE_HIGH | + DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE; - return 1; + return num_modes; } static const struct drm_panel_funcs otm8009a_drm_funcs = { @@ -400,7 +415,7 @@ static int otm8009a_backlight_update_status(struct backlight_device *bd) */ data[0] = MIPI_DCS_SET_DISPLAY_BRIGHTNESS; data[1] = bd->props.brightness; - otm8009a_dcs_write_buf_hs(ctx, data, ARRAY_SIZE(data)); + otm8009a_dcs_write_buf(ctx, data, ARRAY_SIZE(data)); /* set Brightness Control & Backlight on */ data[1] = 0x24; @@ -412,7 +427,7 @@ static int otm8009a_backlight_update_status(struct backlight_device *bd) /* Update Brightness Control & Backlight */ data[0] = MIPI_DCS_WRITE_CONTROL_DISPLAY; - otm8009a_dcs_write_buf_hs(ctx, data, ARRAY_SIZE(data)); + otm8009a_dcs_write_buf(ctx, data, ARRAY_SIZE(data)); return 0; } @@ -433,8 +448,18 @@ static int otm8009a_probe(struct mipi_dsi_device *dsi) ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(ctx->reset_gpio)) { - dev_err(dev, "cannot get reset-gpio\n"); - return PTR_ERR(ctx->reset_gpio); + ret = PTR_ERR(ctx->reset_gpio); + if (ret != -EPROBE_DEFER) + dev_err(dev, "cannot get reset GPIO: %d\n", ret); + return ret; + } + + /* Reset the panel to avoid visual artifacts */ + if (ctx->reset_gpio) { + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + msleep(20); + gpiod_set_value_cansleep(ctx->reset_gpio, 0); } ctx->supply = devm_regulator_get(dev, "power"); diff --git a/drivers/gpu/drm/panel/panel-raydium-rm68200.c b/drivers/gpu/drm/panel/panel-raydium-rm68200.c index f908eeafb..d5542266e 100644 --- a/drivers/gpu/drm/panel/panel-raydium-rm68200.c +++ b/drivers/gpu/drm/panel/panel-raydium-rm68200.c @@ -82,16 +82,16 @@ struct rm68200 { }; static const struct drm_display_mode default_mode = { - .clock = 52582, + .clock = 54000, .hdisplay = 720, - .hsync_start = 720 + 38, - .hsync_end = 720 + 38 + 8, - .htotal = 720 + 38 + 8 + 38, + .hsync_start = 720 + 48, + .hsync_end = 720 + 48 + 9, + .htotal = 720 + 48 + 9 + 48, .vdisplay = 1280, .vsync_start = 1280 + 12, - .vsync_end = 1280 + 12 + 4, - .vtotal = 1280 + 12 + 4 + 12, - .flags = 0, + .vsync_end = 1280 + 12 + 5, + .vtotal = 1280 + 12 + 5 + 12, + .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, .width_mm = 68, .height_mm = 122, }; @@ -347,6 +347,8 @@ static int rm68200_get_modes(struct drm_panel *panel, connector->display_info.width_mm = mode->width_mm; connector->display_info.height_mm = mode->height_mm; + connector->display_info.bus_flags = DRM_BUS_FLAG_DE_HIGH | + DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE; return 1; } @@ -372,7 +374,8 @@ static int rm68200_probe(struct mipi_dsi_device *dsi) ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(ctx->reset_gpio)) { ret = PTR_ERR(ctx->reset_gpio); - dev_err(dev, "cannot get reset GPIO: %d\n", ret); + if (ret != -EPROBE_DEFER) + dev_err(dev, "cannot get reset GPIO: %d\n", ret); return ret; } @@ -391,7 +394,7 @@ static int rm68200_probe(struct mipi_dsi_device *dsi) dsi->lanes = 2; dsi->format = MIPI_DSI_FMT_RGB888; dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | - MIPI_DSI_MODE_LPM; + MIPI_DSI_MODE_LPM | MIPI_DSI_CLOCK_NON_CONTINUOUS; drm_panel_init(&ctx->panel, dev, &rm68200_drm_funcs, DRM_MODE_CONNECTOR_DSI); diff --git a/drivers/gpu/drm/stm/drv.c b/drivers/gpu/drm/stm/drv.c index 411103f01..0f2383026 100644 --- a/drivers/gpu/drm/stm/drv.c +++ b/drivers/gpu/drm/stm/drv.c @@ -193,6 +193,11 @@ static int stm_drm_platform_probe(struct platform_device *pdev) if (ret) goto err_put; + ret = drm_fb_helper_remove_conflicting_framebuffers(NULL, "stmdrmfb", + false); + if (ret) + goto err_put; + ret = drm_dev_register(ddev, 0); if (ret) goto err_put; diff --git a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c index 2e1f26644..87f894ea3 100644 --- a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c +++ b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c @@ -309,14 +309,23 @@ dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode, return 0; } +#define DSI_PHY_DELAY(fp, vp, mbps) DIV_ROUND_UP((fp) * (mbps) + 1000 * (vp), 8000) + static int dw_mipi_dsi_phy_get_timing(void *priv_data, unsigned int lane_mbps, struct dw_mipi_dsi_dphy_timing *timing) { - timing->clk_hs2lp = 0x40; - timing->clk_lp2hs = 0x40; - timing->data_hs2lp = 0x40; - timing->data_lp2hs = 0x40; + /* + * From STM32MP157 datasheet, valid for STM32F469, STM32F7x9, STM32H747 + * phy_clkhs2lp_time = (272+136*UI)/(8*UI) + * phy_clklp2hs_time = (512+40*UI)/(8*UI) + * phy_hs2lp_time = (192+64*UI)/(8*UI) + * phy_lp2hs_time = (256+32*UI)/(8*UI) + */ + timing->clk_hs2lp = DSI_PHY_DELAY(272, 136, lane_mbps); + timing->clk_lp2hs = DSI_PHY_DELAY(512, 40, lane_mbps); + timing->data_hs2lp = DSI_PHY_DELAY(192, 64, lane_mbps); + timing->data_lp2hs = DSI_PHY_DELAY(256, 32, lane_mbps); return 0; } @@ -419,7 +428,8 @@ static int dw_mipi_dsi_stm_probe(struct platform_device *pdev) dsi->dsi = dw_mipi_dsi_probe(pdev, &dw_mipi_dsi_stm_plat_data); if (IS_ERR(dsi->dsi)) { ret = PTR_ERR(dsi->dsi); - DRM_ERROR("Failed to initialize mipi dsi host: %d\n", ret); + if (ret != -EPROBE_DEFER) + DRM_ERROR("Failed to initialize mipi dsi host: %d\n", ret); goto err_dsi_probe; } diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c index 62488ac14..a7c85a922 100644 --- a/drivers/gpu/drm/stm/ltdc.c +++ b/drivers/gpu/drm/stm/ltdc.c @@ -195,6 +195,11 @@ #define NB_PF 8 /* Max nb of HW pixel format */ +#define DRM_ARGB_TO_LTDC_RGB24(bgcolor) \ + ((u32)(DRM_ARGB_RED(bgcolor, 8) << 16 \ + | DRM_ARGB_GREEN(bgcolor, 8) << 8 \ + | DRM_ARGB_BLUE(bgcolor, 8))) + enum ltdc_pix_fmt { PF_NONE, /* RGB formats */ @@ -363,6 +368,15 @@ static inline u32 get_pixelformat_without_alpha(u32 drm) } } +/* + * All non-alpha color formats derived from native alpha color formats are + * either characterized by a FourCC format code + */ +static inline u32 is_xrgb(u32 drm) +{ + return ((drm & 'X') == 'X' || (drm & ('X' << 8)) == ('X' << 8)); +} + static irqreturn_t ltdc_irq_thread(int irq, void *arg) { struct drm_device *ddev = arg; @@ -430,7 +444,8 @@ static void ltdc_crtc_atomic_enable(struct drm_crtc *crtc, pm_runtime_get_sync(ddev->dev); /* Sets the background color value */ - reg_write(ldev->regs, LTDC_BCCR, BCCR_BCBLACK); + reg_write(ldev->regs, LTDC_BCCR, + DRM_ARGB_TO_LTDC_RGB24(crtc->state->bgcolor)); /* Enable IRQ */ reg_set(ldev->regs, LTDC_IER, IER_RRIE | IER_FUIE | IER_TERRIE); @@ -451,6 +466,9 @@ static void ltdc_crtc_atomic_disable(struct drm_crtc *crtc, drm_crtc_vblank_off(crtc); + /* Reset background color */ + reg_write(ldev->regs, LTDC_BCCR, BCCR_BCBLACK); + /* disable IRQ */ reg_clear(ldev->regs, LTDC_IER, IER_RRIE | IER_FUIE | IER_TERRIE); @@ -530,7 +548,6 @@ static void ltdc_crtc_mode_set_nofb(struct drm_crtc *crtc) struct drm_encoder *encoder = NULL; struct drm_bridge *bridge = NULL; struct drm_display_mode *mode = &crtc->state->adjusted_mode; - struct videomode vm; u32 hsync, vsync, accum_hbp, accum_vbp, accum_act_w, accum_act_h; u32 total_width, total_height; u32 bus_flags = 0; @@ -539,20 +556,17 @@ static void ltdc_crtc_mode_set_nofb(struct drm_crtc *crtc) /* get encoder from crtc */ drm_for_each_encoder(encoder, ddev) - if (encoder->crtc == crtc) - break; + if (encoder->crtc == crtc) break; if (encoder) { /* get bridge from encoder */ list_for_each_entry(bridge, &encoder->bridge_chain, chain_node) - if (bridge->encoder == encoder) - break; + if (bridge->encoder == encoder) break; /* Get the connector from encoder */ drm_connector_list_iter_begin(ddev, &iter); drm_for_each_connector_iter(connector, &iter) - if (connector->encoder == encoder) - break; + if (connector->encoder == encoder) break; drm_connector_list_iter_end(&iter); } @@ -569,31 +583,33 @@ static void ltdc_crtc_mode_set_nofb(struct drm_crtc *crtc) } } - drm_display_mode_to_videomode(mode, &vm); - DRM_DEBUG_DRIVER("CRTC:%d mode:%s\n", crtc->base.id, mode->name); - DRM_DEBUG_DRIVER("Video mode: %dx%d", vm.hactive, vm.vactive); + DRM_DEBUG_DRIVER("Video mode: %dx%d", mode->hdisplay, mode->vdisplay); DRM_DEBUG_DRIVER(" hfp %d hbp %d hsl %d vfp %d vbp %d vsl %d\n", - vm.hfront_porch, vm.hback_porch, vm.hsync_len, - vm.vfront_porch, vm.vback_porch, vm.vsync_len); + mode->hsync_start - mode->hdisplay, + mode->htotal - mode->hsync_end, + mode->hsync_end - mode->hsync_start, + mode->vsync_start - mode->vdisplay, + mode->vtotal - mode->vsync_end, + mode->vsync_end - mode->vsync_start); /* Convert video timings to ltdc timings */ - hsync = vm.hsync_len - 1; - vsync = vm.vsync_len - 1; - accum_hbp = hsync + vm.hback_porch; - accum_vbp = vsync + vm.vback_porch; - accum_act_w = accum_hbp + vm.hactive; - accum_act_h = accum_vbp + vm.vactive; - total_width = accum_act_w + vm.hfront_porch; - total_height = accum_act_h + vm.vfront_porch; + hsync = mode->hsync_end - mode->hsync_start - 1; + vsync = mode->vsync_end - mode->vsync_start - 1; + accum_hbp = mode->htotal - mode->hsync_start - 1; + accum_vbp = mode->vtotal - mode->vsync_start - 1; + accum_act_w = accum_hbp + mode->hdisplay; + accum_act_h = accum_vbp + mode->vdisplay; + total_width = mode->htotal - 1; + total_height = mode->vtotal - 1; /* Configures the HS, VS, DE and PC polarities. Default Active Low */ val = 0; - if (vm.flags & DISPLAY_FLAGS_HSYNC_HIGH) + if (mode->flags & DRM_MODE_FLAG_PHSYNC) val |= GCR_HSPOL; - if (vm.flags & DISPLAY_FLAGS_VSYNC_HIGH) + if (mode->flags & DRM_MODE_FLAG_PVSYNC) val |= GCR_VSPOL; if (bus_flags & DRM_BUS_FLAG_DE_LOW) @@ -753,22 +769,44 @@ static int ltdc_plane_atomic_check(struct drm_plane *plane, struct drm_plane_state *state) { struct drm_framebuffer *fb = state->fb; - u32 src_w, src_h; + struct drm_crtc_state *crtc_state; + struct drm_rect *src = &state->src; + struct drm_rect *dst = &state->dst; DRM_DEBUG_DRIVER("\n"); if (!fb) return 0; - /* convert src_ from 16:16 format */ - src_w = state->src_w >> 16; - src_h = state->src_h >> 16; + /* convert src from 16:16 format */ + src->x1 = state->src_x >> 16; + src->y1 = state->src_y >> 16; + src->x2 = (state->src_w >> 16) + src->x1 - 1; + src->y2 = (state->src_h >> 16) + src->y1 - 1; + + dst->x1 = state->crtc_x; + dst->y1 = state->crtc_y; + dst->x2 = state->crtc_w + dst->x1 - 1; + dst->y2 = state->crtc_h + dst->y1 - 1; + + DRM_DEBUG_DRIVER("plane:%d fb:%d (%dx%d)@(%d,%d) -> (%dx%d)@(%d,%d)\n", + plane->base.id, fb->base.id, + src->x2 - src->x1 + 1, src->y2 - src->y1 + 1, + src->x1, src->y1, + dst->x2 - dst->x1 + 1, dst->y2 - dst->y1 + 1, + dst->x1, dst->y1); + + crtc_state = drm_atomic_get_existing_crtc_state(state->state, + state->crtc); + /* destination coordinates do not have to exceed display sizes */ + if (crtc_state && (crtc_state->mode.hdisplay <= dst->x2 || + crtc_state->mode.vdisplay <= dst->y2)) + return -EINVAL; - /* Reject scaling */ - if (src_w != state->crtc_w || src_h != state->crtc_h) { - DRM_ERROR("Scaling is not supported"); + /* source sizes do not have to exceed destination sizes */ + if (dst->x2 - dst->x1 < src->x2 - src->x1 || + dst->y2 - dst->y1 < src->y2 - src->y1) return -EINVAL; - } return 0; } @@ -778,44 +816,37 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, { struct ltdc_device *ldev = plane_to_ltdc(plane); struct drm_plane_state *state = plane->state; + struct drm_rect *src = &state->src; + struct drm_rect *dst = &state->dst; struct drm_framebuffer *fb = state->fb; u32 lofs = plane->index * LAY_OFS; - u32 x0 = state->crtc_x; - u32 x1 = state->crtc_x + state->crtc_w - 1; - u32 y0 = state->crtc_y; - u32 y1 = state->crtc_y + state->crtc_h - 1; - u32 src_x, src_y, src_w, src_h; u32 val, pitch_in_bytes, line_length, paddr, ahbp, avbp, bpcr; + u32 bgcolor = DRM_ARGB_TO_LTDC_RGB24(state->crtc->state->bgcolor); enum ltdc_pix_fmt pf; + struct drm_rect dr; if (!state->crtc || !fb) { DRM_DEBUG_DRIVER("fb or crtc NULL"); return; } - /* convert src_ from 16:16 format */ - src_x = state->src_x >> 16; - src_y = state->src_y >> 16; - src_w = state->src_w >> 16; - src_h = state->src_h >> 16; - - DRM_DEBUG_DRIVER("plane:%d fb:%d (%dx%d)@(%d,%d) -> (%dx%d)@(%d,%d)\n", - plane->base.id, fb->base.id, - src_w, src_h, src_x, src_y, - state->crtc_w, state->crtc_h, - state->crtc_x, state->crtc_y); + /* compute final coordinates of frame buffer */ + dr.x1 = src->x1 + dst->x1; + dr.y1 = src->y1 + dst->y1; + dr.x2 = src->x2 + dst->x1; + dr.y2 = src->y2 + dst->y1; bpcr = reg_read(ldev->regs, LTDC_BPCR); ahbp = (bpcr & BPCR_AHBP) >> 16; avbp = bpcr & BPCR_AVBP; /* Configures the horizontal start and stop position */ - val = ((x1 + 1 + ahbp) << 16) + (x0 + 1 + ahbp); + val = ((dr.x2 + 1 + ahbp) << 16) + (dr.x1 + 1 + ahbp); reg_update_bits(ldev->regs, LTDC_L1WHPCR + lofs, LXWHPCR_WHSTPOS | LXWHPCR_WHSPPOS, val); /* Configures the vertical start and stop position */ - val = ((y1 + 1 + avbp) << 16) + (y0 + 1 + avbp); + val = ((dr.y2 + 1 + avbp) << 16) + (dr.y1 + 1 + avbp); reg_update_bits(ldev->regs, LTDC_L1WVPCR + lofs, LXWVPCR_WVSTPOS | LXWVPCR_WVSPPOS, val); @@ -834,14 +865,14 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, /* Configures the color frame buffer pitch in bytes & line length */ pitch_in_bytes = fb->pitches[0]; - line_length = fb->format->cpp[0] * - (x1 - x0 + 1) + (ldev->caps.bus_width >> 3) - 1; + line_length = fb->format->cpp[0] * (dr.x2 - dr.x1 + 1) + + (ldev->caps.bus_width >> 3) - 1; val = ((pitch_in_bytes << 16) | line_length); reg_update_bits(ldev->regs, LTDC_L1CFBLR + lofs, LXCFBLR_CFBLL | LXCFBLR_CFBP, val); /* Specifies the constant alpha value */ - val = CONSTA_MAX; + val = state->alpha >> 8; reg_update_bits(ldev->regs, LTDC_L1CACR + lofs, LXCACR_CONSTA, val); /* Specifies the blending factors */ @@ -849,16 +880,34 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, if (!fb->format->has_alpha) val = BF1_CA | BF2_1CA; - /* Manage hw-specific capabilities */ - if (ldev->caps.non_alpha_only_l1 && - plane->type != DRM_PLANE_TYPE_PRIMARY) - val = BF1_PAXCA | BF2_1PAXCA; + /* + * Manage hw-specific capabilities + * + * Depending on the hardware version, the background color can not be + * properly displayed with non-alpha color formats derived from native + * alpha color formats (such as XR24 or XR15) since the use of this + * pixel format generates a non transparent layer. As a workaround, + * the stage background color of the layer and the general background + * color need to be synced. + * + * This is done by activating for all XRGB color format the default + * color as the background color and then setting blending factor + * accordingly. + */ + if (ldev->caps.non_alpha_only_l1) { + if (is_xrgb(fb->format->format)) { + val = BF1_CA | BF2_1CA; + reg_write(ldev->regs, LTDC_L1DCCR + lofs, bgcolor); + } else { + val = BF1_PAXCA | BF2_1PAXCA; + } + } reg_update_bits(ldev->regs, LTDC_L1BFCR + lofs, LXBFCR_BF2 | LXBFCR_BF1, val); /* Configures the frame buffer line number */ - val = y1 - y0 + 1; + val = dr.y2 - dr.y1 + 1; reg_update_bits(ldev->regs, LTDC_L1CFBLNR + lofs, LXCFBLNR_CFBLN, val); /* Sets the FB address */ @@ -992,6 +1041,8 @@ static struct drm_plane *ltdc_plane_create(struct drm_device *ddev, drm_plane_helper_add(plane, <dc_plane_helper_funcs); + drm_plane_create_alpha_property(plane); + DRM_DEBUG_DRIVER("plane:%d created\n", plane->base.id); return plane; @@ -1019,6 +1070,8 @@ static int ltdc_crtc_init(struct drm_device *ddev, struct drm_crtc *crtc) return -EINVAL; } + drm_plane_create_zpos_immutable_property(primary, 0); + ret = drm_crtc_init_with_planes(ddev, crtc, primary, NULL, <dc_crtc_funcs, NULL); if (ret) { @@ -1028,6 +1081,7 @@ static int ltdc_crtc_init(struct drm_device *ddev, struct drm_crtc *crtc) drm_crtc_helper_add(crtc, <dc_crtc_helper_funcs); + drm_crtc_add_bgcolor_property(crtc); drm_mode_crtc_set_gamma_size(crtc, CLUT_SIZE); drm_crtc_enable_color_mgmt(crtc, 0, false, CLUT_SIZE); @@ -1041,6 +1095,7 @@ static int ltdc_crtc_init(struct drm_device *ddev, struct drm_crtc *crtc) DRM_ERROR("Can not create overlay plane %d\n", i); goto cleanup; } + drm_plane_create_zpos_immutable_property(overlay, i); } return 0; diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 6ff81d48d..1643ddf5f 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -30,6 +30,8 @@ #include #include +#include +#include #define WORK_REGISTER_THRESHOLD 0x00 #define WORK_REGISTER_REPORT_RATE 0x08 @@ -1074,6 +1076,8 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, const struct edt_i2c_chip_data *chip_data; struct edt_ft5x06_ts_data *tsdata; u8 buf[2] = { 0xfc, 0x00 }; + struct mipi_dsi_device *panel; + struct device_node *np; struct input_dev *input; unsigned long irq_flags; int error; @@ -1173,7 +1177,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, error = edt_ft5x06_ts_identify(client, tsdata, fw_version); if (error) { - dev_err(&client->dev, "touchscreen probe failed\n"); + dev_dbg(&client->dev, "touchscreen probe failed\n"); return error; } @@ -1242,6 +1246,18 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, if (error) return error; + np = of_parse_phandle(client->dev.of_node, "panel", 0); + if (np) { + panel = of_find_mipi_dsi_device_by_node(np); + of_node_put(np); + if (!panel) + return -EPROBE_DEFER; + + device_link_add(&client->dev, &panel->dev, DL_FLAG_STATELESS | + DL_FLAG_AUTOREMOVE_SUPPLIER); + put_device(&panel->dev); + } + edt_ft5x06_ts_prepare_debugfs(tsdata, dev_driver_string(&client->dev)); dev_dbg(&client->dev, diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c index a06385c55..388544f2d 100644 --- a/drivers/input/touchscreen/goodix.c +++ b/drivers/input/touchscreen/goodix.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -1153,6 +1154,8 @@ static int goodix_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct goodix_ts_data *ts; + struct mipi_dsi_device *panel; + struct device_node *np; int error; dev_dbg(&client->dev, "I2C Address: 0x%02x\n", client->addr); @@ -1252,6 +1255,17 @@ static int goodix_ts_probe(struct i2c_client *client, return error; } + np = of_parse_phandle(client->dev.of_node, "panel", 0); + if (np) { + panel = of_find_mipi_dsi_device_by_node(np); + of_node_put(np); + if (!panel) + return -EPROBE_DEFER; + device_link_add(&client->dev, &panel->dev, DL_FLAG_STATELESS | + DL_FLAG_AUTOREMOVE_SUPPLIER); + put_device(&panel->dev); + } + return 0; } @@ -1307,6 +1321,7 @@ static int __maybe_unused goodix_suspend(struct device *dev) * sooner, delay 58ms here. */ msleep(58); + return 0; } diff --git a/include/drm/drm_blend.h b/include/drm/drm_blend.h index 88bdfec3b..9e2538dd7 100644 --- a/include/drm/drm_blend.h +++ b/include/drm/drm_blend.h @@ -58,4 +58,5 @@ int drm_atomic_normalize_zpos(struct drm_device *dev, struct drm_atomic_state *state); int drm_plane_create_blend_mode_property(struct drm_plane *plane, unsigned int supported_modes); +void drm_crtc_add_bgcolor_property(struct drm_crtc *crtc); #endif diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 59b51a09c..d6808aca9 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -288,6 +288,18 @@ struct drm_crtc_state { */ struct drm_property_blob *gamma_lut; + /** + * @bgcolor: + * + * RGB value representing the pipe's background color. The background + * color (aka "canvas color") of a pipe is the color that will be used + * for pixels not covered by a plane, or covered by transparent pixels + * of a plane. The value here should be built via drm_argb(); + * individual color components can be extracted with desired precision + * via the DRM_ARGB_*() macros. + */ + u64 bgcolor; + /** * @target_vblank: * diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h index a18f73eb3..3e37a3a19 100644 --- a/include/drm/drm_mode_config.h +++ b/include/drm/drm_mode_config.h @@ -861,6 +861,11 @@ struct drm_mode_config { */ struct drm_property *hdcp_content_type_property; + /** + * @bgcolor_property: RGB background color for CRTC. + */ + struct drm_property *bgcolor_property; + /* dumb ioctl parameters */ uint32_t preferred_depth, prefer_shadow; diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index 863eda048..5042afb3d 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h @@ -97,6 +97,12 @@ extern "C" { #define DRM_MODE_FLAG_3D_TOP_AND_BOTTOM (7<<14) #define DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF (8<<14) +/* flags for polarity clock & data enable polarities */ +#define DRM_MODE_FLAG_PPIXDATA (1 << 19) +#define DRM_MODE_FLAG_NPIXDATA (1 << 20) +#define DRM_MODE_FLAG_PDE (1 << 21) +#define DRM_MODE_FLAG_NDE (1 << 22) + /* Picture aspect ratio options */ #define DRM_MODE_PICTURE_ASPECT_NONE 0 #define DRM_MODE_PICTURE_ASPECT_4_3 1 @@ -1030,6 +1036,34 @@ struct drm_mode_rect { __s32 y2; }; +/* + * Put ARGB values into a standard 64-bit representation that can be used + * for ioctl parameters, inter-driver commmunication, etc. If the component + * values being provided contain less than 16 bits of precision, they'll + * be shifted into the most significant bits. + */ +static inline __u64 +drm_argb(__u8 bpc, __u16 alpha, __u16 red, __u16 green, __u16 blue) +{ + int msb_shift = 16 - bpc; + + return (__u64)alpha << msb_shift << 48 | + (__u64)red << msb_shift << 32 | + (__u64)green << msb_shift << 16 | + (__u64)blue << msb_shift; +} + +/* + * Extract the specified number of bits of a specific color component from a + * standard 64-bit ARGB value. + */ +#define DRM_ARGB_COMP(c, shift, numbits) \ + (__u16)(((c) & 0xFFFFull << (shift)) >> ((shift) + 16 - (numbits))) +#define DRM_ARGB_BLUE(c, numbits) DRM_ARGB_COMP(c, 0, numbits) +#define DRM_ARGB_GREEN(c, numbits) DRM_ARGB_COMP(c, 16, numbits) +#define DRM_ARGB_RED(c, numbits) DRM_ARGB_COMP(c, 32, numbits) +#define DRM_ARGB_ALPHA(c, numbits) DRM_ARGB_COMP(c, 48, numbits) + #if defined(__cplusplus) } #endif -- 2.17.1