1469 lines
46 KiB
Diff
1469 lines
46 KiB
Diff
From 6d9c0eb22dc7c3fbe05bbb000a5d35d0fd1168ab Mon Sep 17 00:00:00 2001
|
|
From: Lionel Vitte <lionel.vitte@st.com>
|
|
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 <linux/i2c-mux.h>
|
|
#include <linux/i2c.h>
|
|
#include <linux/module.h>
|
|
+#include <linux/pm_runtime.h>
|
|
#include <linux/regmap.h>
|
|
#include <linux/regulator/consumer.h>
|
|
#include <linux/clk.h>
|
|
@@ -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 <linux/uaccess.h>
|
|
|
|
#include <asm/unaligned.h>
|
|
+#include <linux/of_device.h>
|
|
+#include <drm/drm_mipi_dsi.h>
|
|
|
|
#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 <linux/input/touchscreen.h>
|
|
#include <linux/module.h>
|
|
#include <linux/delay.h>
|
|
+#include <drm/drm_mipi_dsi.h>
|
|
#include <linux/irq.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/regulator/consumer.h>
|
|
@@ -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
|
|
|