summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/arm/malidp_planes.c2
-rw-r--r--drivers/gpu/drm/bridge/Kconfig8
-rw-r--r--drivers/gpu/drm/bridge/Makefile1
-rw-r--r--drivers/gpu/drm/bridge/adv7511/adv7511.h27
-rw-r--r--drivers/gpu/drm/bridge/adv7511/adv7511_cec.c116
-rw-r--r--drivers/gpu/drm/bridge/adv7511/adv7511_drv.c19
-rw-r--r--drivers/gpu/drm/bridge/fsl-ldb.c342
-rw-r--r--drivers/gpu/drm/bridge/ite-it6505.c29
-rw-r--r--drivers/gpu/drm/bridge/tc358767.c2
-rw-r--r--drivers/gpu/drm/bridge/ti-tfp410.c12
-rw-r--r--drivers/gpu/drm/display/Kconfig6
-rw-r--r--drivers/gpu/drm/display/drm_dp_mst_topology.c5
-rw-r--r--drivers/gpu/drm/drm_atomic_uapi.c47
-rw-r--r--drivers/gpu/drm/drm_edid.c65
-rw-r--r--drivers/gpu/drm/drm_gem_atomic_helper.c73
-rw-r--r--drivers/gpu/drm/drm_plane.c14
-rw-r--r--drivers/gpu/drm/nouveau/dispnv50/wndw.c5
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_debugfs.c12
-rw-r--r--drivers/gpu/drm/panel/panel-simple.c40
-rw-r--r--drivers/gpu/drm/rockchip/analogix_dp-rockchip.c32
-rw-r--r--drivers/gpu/drm/rockchip/cdn-dp-core.c20
-rw-r--r--drivers/gpu/drm/rockchip/cdn-dp-core.h2
-rw-r--r--drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c17
-rw-r--r--drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c38
-rw-r--r--drivers/gpu/drm/rockchip/inno_hdmi.c40
-rw-r--r--drivers/gpu/drm/rockchip/rk3066_hdmi.c40
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_drv.c93
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_drv.h17
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_vop.c24
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_vop.h1
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_lvds.c26
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_vop_reg.c11
-rw-r--r--drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c7
-rw-r--r--drivers/gpu/drm/vc4/vc4_bo.c8
-rw-r--r--drivers/gpu/drm/vc4/vc4_plane.c7
35 files changed, 881 insertions, 327 deletions
diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c
index 81d9f5004025..338cec4a3fff 100644
--- a/drivers/gpu/drm/arm/malidp_planes.c
+++ b/drivers/gpu/drm/arm/malidp_planes.c
@@ -344,7 +344,7 @@ static bool malidp_check_pages_threshold(struct malidp_plane_state *ms,
else
sgt = obj->funcs->get_sg_table(obj);
- if (!sgt)
+ if (IS_ERR(sgt))
return false;
sgl = sgt->sgl;
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index ef9f1b0d91bf..da3441830d46 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -75,6 +75,14 @@ config DRM_DISPLAY_CONNECTOR
on ARM-based platforms. Saying Y here when this driver is not needed
will not cause any issue.
+config DRM_FSL_LDB
+ tristate "Freescale i.MX8MP LDB bridge"
+ depends on OF
+ select DRM_KMS_HELPER
+ select DRM_PANEL_BRIDGE
+ help
+ Support for i.MX8MP DPI-to-LVDS on-SoC encoder.
+
config DRM_ITE_IT6505
tristate "ITE IT6505 DisplayPort bridge"
depends on OF
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index b0edf2022fa0..f6c0a95de549 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -4,6 +4,7 @@ obj-$(CONFIG_DRM_CHIPONE_ICN6211) += chipone-icn6211.o
obj-$(CONFIG_DRM_CHRONTEL_CH7033) += chrontel-ch7033.o
obj-$(CONFIG_DRM_CROS_EC_ANX7688) += cros-ec-anx7688.o
obj-$(CONFIG_DRM_DISPLAY_CONNECTOR) += display-connector.o
+obj-$(CONFIG_DRM_FSL_LDB) += fsl-ldb.o
obj-$(CONFIG_DRM_ITE_IT6505) += ite-it6505.o
obj-$(CONFIG_DRM_LONTIUM_LT8912B) += lontium-lt8912b.o
obj-$(CONFIG_DRM_LONTIUM_LT9211) += lontium-lt9211.o
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511.h b/drivers/gpu/drm/bridge/adv7511/adv7511.h
index 6a882891d91c..9e3bb8a8ee40 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511.h
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511.h
@@ -209,10 +209,16 @@
#define ADV7511_REG_CEC_TX_ENABLE 0x11
#define ADV7511_REG_CEC_TX_RETRY 0x12
#define ADV7511_REG_CEC_TX_LOW_DRV_CNT 0x14
-#define ADV7511_REG_CEC_RX_FRAME_HDR 0x15
-#define ADV7511_REG_CEC_RX_FRAME_DATA0 0x16
-#define ADV7511_REG_CEC_RX_FRAME_LEN 0x25
-#define ADV7511_REG_CEC_RX_ENABLE 0x26
+#define ADV7511_REG_CEC_RX1_FRAME_HDR 0x15
+#define ADV7511_REG_CEC_RX1_FRAME_DATA0 0x16
+#define ADV7511_REG_CEC_RX1_FRAME_LEN 0x25
+#define ADV7511_REG_CEC_RX_STATUS 0x26
+#define ADV7511_REG_CEC_RX2_FRAME_HDR 0x27
+#define ADV7511_REG_CEC_RX2_FRAME_DATA0 0x28
+#define ADV7511_REG_CEC_RX2_FRAME_LEN 0x37
+#define ADV7511_REG_CEC_RX3_FRAME_HDR 0x38
+#define ADV7511_REG_CEC_RX3_FRAME_DATA0 0x39
+#define ADV7511_REG_CEC_RX3_FRAME_LEN 0x48
#define ADV7511_REG_CEC_RX_BUFFERS 0x4a
#define ADV7511_REG_CEC_LOG_ADDR_MASK 0x4b
#define ADV7511_REG_CEC_LOG_ADDR_0_1 0x4c
@@ -220,6 +226,18 @@
#define ADV7511_REG_CEC_CLK_DIV 0x4e
#define ADV7511_REG_CEC_SOFT_RESET 0x50
+static const u8 ADV7511_REG_CEC_RX_FRAME_HDR[] = {
+ ADV7511_REG_CEC_RX1_FRAME_HDR,
+ ADV7511_REG_CEC_RX2_FRAME_HDR,
+ ADV7511_REG_CEC_RX3_FRAME_HDR,
+};
+
+static const u8 ADV7511_REG_CEC_RX_FRAME_LEN[] = {
+ ADV7511_REG_CEC_RX1_FRAME_LEN,
+ ADV7511_REG_CEC_RX2_FRAME_LEN,
+ ADV7511_REG_CEC_RX3_FRAME_LEN,
+};
+
#define ADV7533_REG_CEC_OFFSET 0x70
enum adv7511_input_clock {
@@ -335,6 +353,7 @@ struct adv7511 {
struct regmap *regmap;
struct regmap *regmap_cec;
+ unsigned int reg_cec_offset;
enum drm_connector_status status;
bool powered;
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c b/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c
index 28d9becc939c..399f625a50c8 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c
@@ -17,12 +17,12 @@
#define ADV7511_INT1_CEC_MASK \
(ADV7511_INT1_CEC_TX_READY | ADV7511_INT1_CEC_TX_ARBIT_LOST | \
- ADV7511_INT1_CEC_TX_RETRY_TIMEOUT | ADV7511_INT1_CEC_RX_READY1)
+ ADV7511_INT1_CEC_TX_RETRY_TIMEOUT | ADV7511_INT1_CEC_RX_READY1 | \
+ ADV7511_INT1_CEC_RX_READY2 | ADV7511_INT1_CEC_RX_READY3)
static void adv_cec_tx_raw_status(struct adv7511 *adv7511, u8 tx_raw_status)
{
- unsigned int offset = adv7511->type == ADV7533 ?
- ADV7533_REG_CEC_OFFSET : 0;
+ unsigned int offset = adv7511->reg_cec_offset;
unsigned int val;
if (regmap_read(adv7511->regmap_cec,
@@ -71,26 +71,16 @@ static void adv_cec_tx_raw_status(struct adv7511 *adv7511, u8 tx_raw_status)
}
}
-void adv7511_cec_irq_process(struct adv7511 *adv7511, unsigned int irq1)
+static void adv7511_cec_rx(struct adv7511 *adv7511, int rx_buf)
{
- unsigned int offset = adv7511->type == ADV7533 ?
- ADV7533_REG_CEC_OFFSET : 0;
- const u32 irq_tx_mask = ADV7511_INT1_CEC_TX_READY |
- ADV7511_INT1_CEC_TX_ARBIT_LOST |
- ADV7511_INT1_CEC_TX_RETRY_TIMEOUT;
+ unsigned int offset = adv7511->reg_cec_offset;
struct cec_msg msg = {};
unsigned int len;
unsigned int val;
u8 i;
- if (irq1 & irq_tx_mask)
- adv_cec_tx_raw_status(adv7511, irq1);
-
- if (!(irq1 & ADV7511_INT1_CEC_RX_READY1))
- return;
-
if (regmap_read(adv7511->regmap_cec,
- ADV7511_REG_CEC_RX_FRAME_LEN + offset, &len))
+ ADV7511_REG_CEC_RX_FRAME_LEN[rx_buf] + offset, &len))
return;
msg.len = len & 0x1f;
@@ -103,23 +93,80 @@ void adv7511_cec_irq_process(struct adv7511 *adv7511, unsigned int irq1)
for (i = 0; i < msg.len; i++) {
regmap_read(adv7511->regmap_cec,
- i + ADV7511_REG_CEC_RX_FRAME_HDR + offset, &val);
+ i + ADV7511_REG_CEC_RX_FRAME_HDR[rx_buf] + offset,
+ &val);
msg.msg[i] = val;
}
- /* toggle to re-enable rx 1 */
- regmap_write(adv7511->regmap_cec,
- ADV7511_REG_CEC_RX_BUFFERS + offset, 1);
- regmap_write(adv7511->regmap_cec,
- ADV7511_REG_CEC_RX_BUFFERS + offset, 0);
+ /* Toggle RX Ready Clear bit to re-enable this RX buffer */
+ regmap_update_bits(adv7511->regmap_cec,
+ ADV7511_REG_CEC_RX_BUFFERS + offset, BIT(rx_buf),
+ BIT(rx_buf));
+ regmap_update_bits(adv7511->regmap_cec,
+ ADV7511_REG_CEC_RX_BUFFERS + offset, BIT(rx_buf), 0);
+
cec_received_msg(adv7511->cec_adap, &msg);
}
+void adv7511_cec_irq_process(struct adv7511 *adv7511, unsigned int irq1)
+{
+ unsigned int offset = adv7511->reg_cec_offset;
+ const u32 irq_tx_mask = ADV7511_INT1_CEC_TX_READY |
+ ADV7511_INT1_CEC_TX_ARBIT_LOST |
+ ADV7511_INT1_CEC_TX_RETRY_TIMEOUT;
+ const u32 irq_rx_mask = ADV7511_INT1_CEC_RX_READY1 |
+ ADV7511_INT1_CEC_RX_READY2 |
+ ADV7511_INT1_CEC_RX_READY3;
+ unsigned int rx_status;
+ int rx_order[3] = { -1, -1, -1 };
+ int i;
+
+ if (irq1 & irq_tx_mask)
+ adv_cec_tx_raw_status(adv7511, irq1);
+
+ if (!(irq1 & irq_rx_mask))
+ return;
+
+ if (regmap_read(adv7511->regmap_cec,
+ ADV7511_REG_CEC_RX_STATUS + offset, &rx_status))
+ return;
+
+ /*
+ * ADV7511_REG_CEC_RX_STATUS[5:0] contains the reception order of RX
+ * buffers 0, 1, and 2 in bits [1:0], [3:2], and [5:4] respectively.
+ * The values are to be interpreted as follows:
+ *
+ * 0 = buffer unused
+ * 1 = buffer contains oldest received frame (if applicable)
+ * 2 = buffer contains second oldest received frame (if applicable)
+ * 3 = buffer contains third oldest received frame (if applicable)
+ *
+ * Fill rx_order with the sequence of RX buffer indices to
+ * read from in order, where -1 indicates that there are no
+ * more buffers to process.
+ */
+ for (i = 0; i < 3; i++) {
+ unsigned int timestamp = (rx_status >> (2 * i)) & 0x3;
+
+ if (timestamp)
+ rx_order[timestamp - 1] = i;
+ }
+
+ /* Read CEC RX buffers in the appropriate order as prescribed above */
+ for (i = 0; i < 3; i++) {
+ int rx_buf = rx_order[i];
+
+ if (rx_buf < 0)
+ break;
+
+ adv7511_cec_rx(adv7511, rx_buf);
+ }
+}
+
static int adv7511_cec_adap_enable(struct cec_adapter *adap, bool enable)
{
struct adv7511 *adv7511 = cec_get_drvdata(adap);
- unsigned int offset = adv7511->type == ADV7533 ?
- ADV7533_REG_CEC_OFFSET : 0;
+ unsigned int offset = adv7511->reg_cec_offset;
if (adv7511->i2c_cec == NULL)
return -EIO;
@@ -129,11 +176,11 @@ static int adv7511_cec_adap_enable(struct cec_adapter *adap, bool enable)
regmap_update_bits(adv7511->regmap_cec,
ADV7511_REG_CEC_CLK_DIV + offset,
0x03, 0x01);
- /* legacy mode and clear all rx buffers */
+ /* non-legacy mode and clear all rx buffers */
regmap_write(adv7511->regmap_cec,
- ADV7511_REG_CEC_RX_BUFFERS + offset, 0x07);
+ ADV7511_REG_CEC_RX_BUFFERS + offset, 0x0f);
regmap_write(adv7511->regmap_cec,
- ADV7511_REG_CEC_RX_BUFFERS + offset, 0);
+ ADV7511_REG_CEC_RX_BUFFERS + offset, 0x08);
/* initially disable tx */
regmap_update_bits(adv7511->regmap_cec,
ADV7511_REG_CEC_TX_ENABLE + offset, 1, 0);
@@ -141,7 +188,7 @@ static int adv7511_cec_adap_enable(struct cec_adapter *adap, bool enable)
/* tx: ready */
/* tx: arbitration lost */
/* tx: retry timeout */
- /* rx: ready 1 */
+ /* rx: ready 1-3 */
regmap_update_bits(adv7511->regmap,
ADV7511_REG_INT_ENABLE(1), 0x3f,
ADV7511_INT1_CEC_MASK);
@@ -165,8 +212,7 @@ static int adv7511_cec_adap_enable(struct cec_adapter *adap, bool enable)
static int adv7511_cec_adap_log_addr(struct cec_adapter *adap, u8 addr)
{
struct adv7511 *adv7511 = cec_get_drvdata(adap);
- unsigned int offset = adv7511->type == ADV7533 ?
- ADV7533_REG_CEC_OFFSET : 0;
+ unsigned int offset = adv7511->reg_cec_offset;
unsigned int i, free_idx = ADV7511_MAX_ADDRS;
if (!adv7511->cec_enabled_adap)
@@ -235,8 +281,7 @@ static int adv7511_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
u32 signal_free_time, struct cec_msg *msg)
{
struct adv7511 *adv7511 = cec_get_drvdata(adap);
- unsigned int offset = adv7511->type == ADV7533 ?
- ADV7533_REG_CEC_OFFSET : 0;
+ unsigned int offset = adv7511->reg_cec_offset;
u8 len = msg->len;
unsigned int i;
@@ -289,8 +334,7 @@ static int adv7511_cec_parse_dt(struct device *dev, struct adv7511 *adv7511)
int adv7511_cec_init(struct device *dev, struct adv7511 *adv7511)
{
- unsigned int offset = adv7511->type == ADV7533 ?
- ADV7533_REG_CEC_OFFSET : 0;
+ unsigned int offset = adv7511->reg_cec_offset;
int ret = adv7511_cec_parse_dt(dev, adv7511);
if (ret)
@@ -310,9 +354,9 @@ int adv7511_cec_init(struct device *dev, struct adv7511 *adv7511)
regmap_write(adv7511->regmap_cec,
ADV7511_REG_CEC_SOFT_RESET + offset, 0x00);
- /* legacy mode */
+ /* non-legacy mode - use all three RX buffers */
regmap_write(adv7511->regmap_cec,
- ADV7511_REG_CEC_RX_BUFFERS + offset, 0x00);
+ ADV7511_REG_CEC_RX_BUFFERS + offset, 0x08);
regmap_write(adv7511->regmap_cec,
ADV7511_REG_CEC_CLK_DIV + offset,
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
index b3f10c54e064..5bb9300040dd 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
@@ -1027,14 +1027,19 @@ static bool adv7511_cec_register_volatile(struct device *dev, unsigned int reg)
struct i2c_client *i2c = to_i2c_client(dev);
struct adv7511 *adv7511 = i2c_get_clientdata(i2c);
- if (adv7511->type == ADV7533 || adv7511->type == ADV7535)
- reg -= ADV7533_REG_CEC_OFFSET;
+ reg -= adv7511->reg_cec_offset;
switch (reg) {
- case ADV7511_REG_CEC_RX_FRAME_HDR:
- case ADV7511_REG_CEC_RX_FRAME_DATA0...
- ADV7511_REG_CEC_RX_FRAME_DATA0 + 14:
- case ADV7511_REG_CEC_RX_FRAME_LEN:
+ case ADV7511_REG_CEC_RX1_FRAME_HDR:
+ case ADV7511_REG_CEC_RX1_FRAME_DATA0 ... ADV7511_REG_CEC_RX1_FRAME_DATA0 + 14:
+ case ADV7511_REG_CEC_RX1_FRAME_LEN:
+ case ADV7511_REG_CEC_RX2_FRAME_HDR:
+ case ADV7511_REG_CEC_RX2_FRAME_DATA0 ... ADV7511_REG_CEC_RX2_FRAME_DATA0 + 14:
+ case ADV7511_REG_CEC_RX2_FRAME_LEN:
+ case ADV7511_REG_CEC_RX3_FRAME_HDR:
+ case ADV7511_REG_CEC_RX3_FRAME_DATA0 ... ADV7511_REG_CEC_RX3_FRAME_DATA0 + 14:
+ case ADV7511_REG_CEC_RX3_FRAME_LEN:
+ case ADV7511_REG_CEC_RX_STATUS:
case ADV7511_REG_CEC_RX_BUFFERS:
case ADV7511_REG_CEC_TX_LOW_DRV_CNT:
return true;
@@ -1073,6 +1078,8 @@ static int adv7511_init_cec_regmap(struct adv7511 *adv)
ret = adv7533_patch_cec_registers(adv);
if (ret)
goto err;
+
+ adv->reg_cec_offset = ADV7533_REG_CEC_OFFSET;
}
return 0;
diff --git a/drivers/gpu/drm/bridge/fsl-ldb.c b/drivers/gpu/drm/bridge/fsl-ldb.c
new file mode 100644
index 000000000000..b2675c769a55
--- /dev/null
+++ b/drivers/gpu/drm/bridge/fsl-ldb.c
@@ -0,0 +1,342 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2022 Marek Vasut <marex@denx.de>
+ */
+
+#include <linux/clk.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_of.h>
+#include <drm/drm_panel.h>
+
+#define LDB_CTRL 0x5c
+#define LDB_CTRL_CH0_ENABLE BIT(0)
+#define LDB_CTRL_CH0_DI_SELECT BIT(1)
+#define LDB_CTRL_CH1_ENABLE BIT(2)
+#define LDB_CTRL_CH1_DI_SELECT BIT(3)
+#define LDB_CTRL_SPLIT_MODE BIT(4)
+#define LDB_CTRL_CH0_DATA_WIDTH BIT(5)
+#define LDB_CTRL_CH0_BIT_MAPPING BIT(6)
+#define LDB_CTRL_CH1_DATA_WIDTH BIT(7)
+#define LDB_CTRL_CH1_BIT_MAPPING BIT(8)
+#define LDB_CTRL_DI0_VSYNC_POLARITY BIT(9)
+#define LDB_CTRL_DI1_VSYNC_POLARITY BIT(10)
+#define LDB_CTRL_REG_CH0_FIFO_RESET BIT(11)
+#define LDB_CTRL_REG_CH1_FIFO_RESET BIT(12)
+#define LDB_CTRL_ASYNC_FIFO_ENABLE BIT(24)
+#define LDB_CTRL_ASYNC_FIFO_THRESHOLD_MASK GENMASK(27, 25)
+
+#define LVDS_CTRL 0x128
+#define LVDS_CTRL_CH0_EN BIT(0)
+#define LVDS_CTRL_CH1_EN BIT(1)
+#define LVDS_CTRL_VBG_EN BIT(2)
+#define LVDS_CTRL_HS_EN BIT(3)
+#define LVDS_CTRL_PRE_EMPH_EN BIT(4)
+#define LVDS_CTRL_PRE_EMPH_ADJ(n) (((n) & 0x7) << 5)
+#define LVDS_CTRL_PRE_EMPH_ADJ_MASK GENMASK(7, 5)
+#define LVDS_CTRL_CM_ADJ(n) (((n) & 0x7) << 8)
+#define LVDS_CTRL_CM_ADJ_MASK GENMASK(10, 8)
+#define LVDS_CTRL_CC_ADJ(n) (((n) & 0x7) << 11)
+#define LVDS_CTRL_CC_ADJ_MASK GENMASK(13, 11)
+#define LVDS_CTRL_SLEW_ADJ(n) (((n) & 0x7) << 14)
+#define LVDS_CTRL_SLEW_ADJ_MASK GENMASK(16, 14)
+#define LVDS_CTRL_VBG_ADJ(n) (((n) & 0x7) << 17)
+#define LVDS_CTRL_VBG_ADJ_MASK GENMASK(19, 17)
+
+struct fsl_ldb {
+ struct device *dev;
+ struct drm_bridge bridge;
+ struct drm_bridge *panel_bridge;
+ struct clk *clk;
+ struct regmap *regmap;
+ bool lvds_dual_link;
+};
+
+static inline struct fsl_ldb *to_fsl_ldb(struct drm_bridge *bridge)
+{
+ return container_of(bridge, struct fsl_ldb, bridge);
+}
+
+static int fsl_ldb_attach(struct drm_bridge *bridge,
+ enum drm_bridge_attach_flags flags)
+{
+ struct fsl_ldb *fsl_ldb = to_fsl_ldb(bridge);
+
+ return drm_bridge_attach(bridge->encoder, fsl_ldb->panel_bridge,
+ bridge, flags);
+}
+
+static int fsl_ldb_atomic_check(struct drm_bridge *bridge,
+ struct drm_bridge_state *bridge_state,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state)
+{
+ /* Invert DE signal polarity. */
+ bridge_state->input_bus_cfg.flags &= ~(DRM_BUS_FLAG_DE_LOW |
+ DRM_BUS_FLAG_DE_HIGH);
+ if (bridge_state->output_bus_cfg.flags & DRM_BUS_FLAG_DE_LOW)
+ bridge_state->input_bus_cfg.flags |= DRM_BUS_FLAG_DE_HIGH;
+ else if (bridge_state->output_bus_cfg.flags & DRM_BUS_FLAG_DE_HIGH)
+ bridge_state->input_bus_cfg.flags |= DRM_BUS_FLAG_DE_LOW;
+
+ return 0;
+}
+
+static void fsl_ldb_atomic_enable(struct drm_bridge *bridge,
+ struct drm_bridge_state *old_bridge_state)
+{
+ struct fsl_ldb *fsl_ldb = to_fsl_ldb(bridge);
+ struct drm_atomic_state *state = old_bridge_state->base.state;
+ const struct drm_bridge_state *bridge_state;
+ const struct drm_crtc_state *crtc_state;
+ const struct drm_display_mode *mode;
+ struct drm_connector *connector;
+ struct drm_crtc *crtc;
+ bool lvds_format_24bpp;
+ bool lvds_format_jeida;
+ u32 reg;
+
+ /* Get the LVDS format from the bridge state. */
+ bridge_state = drm_atomic_get_new_bridge_state(state, bridge);
+
+ switch (bridge_state->output_bus_cfg.format) {
+ case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
+ lvds_format_24bpp = false;
+ lvds_format_jeida = true;
+ break;
+ case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA:
+ lvds_format_24bpp = true;
+ lvds_format_jeida = true;
+ break;
+ case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:
+ lvds_format_24bpp = true;
+ lvds_format_jeida = false;
+ break;
+ default:
+ /*
+ * Some bridges still don't set the correct LVDS bus pixel
+ * format, use SPWG24 default format until those are fixed.
+ */
+ lvds_format_24bpp = true;
+ lvds_format_jeida = false;
+ dev_warn(fsl_ldb->dev,
+ "Unsupported LVDS bus format 0x%04x, please check output bridge driver. Falling back to SPWG24.\n",
+ bridge_state->output_bus_cfg.format);
+ break;
+ }
+
+ /*
+ * Retrieve the CRTC adjusted mode. This requires a little dance to go
+ * from the bridge to the encoder, to the connector and to the CRTC.
+ */
+ connector = drm_atomic_get_new_connector_for_encoder(state,
+ bridge->encoder);
+ crtc = drm_atomic_get_new_connector_state(state, connector)->crtc;
+ crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
+ mode = &crtc_state->adjusted_mode;
+
+ if (fsl_ldb->lvds_dual_link)
+ clk_set_rate(fsl_ldb->clk, mode->clock * 3500);
+ else
+ clk_set_rate(fsl_ldb->clk, mode->clock * 7000);
+ clk_prepare_enable(fsl_ldb->clk);
+
+ /* Program LDB_CTRL */
+ reg = LDB_CTRL_CH0_ENABLE;
+
+ if (fsl_ldb->lvds_dual_link)
+ reg |= LDB_CTRL_CH1_ENABLE;
+
+ if (lvds_format_24bpp) {
+ reg |= LDB_CTRL_CH0_DATA_WIDTH;
+ if (fsl_ldb->lvds_dual_link)
+ reg |= LDB_CTRL_CH1_DATA_WIDTH;
+ }
+
+ if (lvds_format_jeida) {
+ reg |= LDB_CTRL_CH0_BIT_MAPPING;
+ if (fsl_ldb->lvds_dual_link)
+ reg |= LDB_CTRL_CH1_BIT_MAPPING;
+ }
+
+ if (mode->flags & DRM_MODE_FLAG_PVSYNC) {
+ reg |= LDB_CTRL_DI0_VSYNC_POLARITY;
+ if (fsl_ldb->lvds_dual_link)
+ reg |= LDB_CTRL_DI1_VSYNC_POLARITY;
+ }
+
+ regmap_write(fsl_ldb->regmap, LDB_CTRL, reg);
+
+ /* Program LVDS_CTRL */
+ reg = LVDS_CTRL_CC_ADJ(2) | LVDS_CTRL_PRE_EMPH_EN |
+ LVDS_CTRL_PRE_EMPH_ADJ(3) | LVDS_CTRL_VBG_EN;
+ regmap_write(fsl_ldb->regmap, LVDS_CTRL, reg);
+
+ /* Wait for VBG to stabilize. */
+ usleep_range(15, 20);
+
+ reg |= LVDS_CTRL_CH0_EN;
+ if (fsl_ldb->lvds_dual_link)
+ reg |= LVDS_CTRL_CH1_EN;
+
+ regmap_write(fsl_ldb->regmap, LVDS_CTRL, reg);
+}
+
+static void fsl_ldb_atomic_disable(struct drm_bridge *bridge,
+ struct drm_bridge_state *old_bridge_state)
+{
+ struct fsl_ldb *fsl_ldb = to_fsl_ldb(bridge);
+
+ /* Stop both channels. */
+ regmap_write(fsl_ldb->regmap, LVDS_CTRL, 0);
+ regmap_write(fsl_ldb->regmap, LDB_CTRL, 0);
+
+ clk_disable_unprepare(fsl_ldb->clk);
+}
+
+#define MAX_INPUT_SEL_FORMATS 1
+static u32 *
+fsl_ldb_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
+ struct drm_bridge_state *bridge_state,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state,
+ u32 output_fmt,
+ unsigned int *num_input_fmts)
+{
+ u32 *input_fmts;
+
+ *num_input_fmts = 0;
+
+ input_fmts = kcalloc(MAX_INPUT_SEL_FORMATS, sizeof(*input_fmts),
+ GFP_KERNEL);
+ if (!input_fmts)
+ return NULL;
+
+ input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X24;
+ *num_input_fmts = MAX_INPUT_SEL_FORMATS;
+
+ return input_fmts;
+}
+
+static enum drm_mode_status
+fsl_ldb_mode_valid(struct drm_bridge *bridge,
+ const struct drm_display_info *info,
+ const struct drm_display_mode *mode)
+{
+ struct fsl_ldb *fsl_ldb = to_fsl_ldb(bridge);
+
+ if (mode->clock > (fsl_ldb->lvds_dual_link ? 80000 : 160000))
+ return MODE_CLOCK_HIGH;
+
+ return MODE_OK;
+}
+
+static const struct drm_bridge_funcs funcs = {
+ .attach = fsl_ldb_attach,
+ .atomic_check = fsl_ldb_atomic_check,
+ .atomic_enable = fsl_ldb_atomic_enable,
+ .atomic_disable = fsl_ldb_atomic_disable,
+ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
+ .atomic_get_input_bus_fmts = fsl_ldb_atomic_get_input_bus_fmts,
+ .atomic_reset = drm_atomic_helper_bridge_reset,
+ .mode_valid = fsl_ldb_mode_valid,
+};
+
+static int fsl_ldb_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *panel_node;
+ struct device_node *port1, *port2;
+ struct drm_panel *panel;
+ struct fsl_ldb *fsl_ldb;
+ int dual_link;
+
+ fsl_ldb = devm_kzalloc(dev, sizeof(*fsl_ldb), GFP_KERNEL);
+ if (!fsl_ldb)
+ return -ENOMEM;
+
+ fsl_ldb->dev = &pdev->dev;
+ fsl_ldb->bridge.funcs = &funcs;
+ fsl_ldb->bridge.of_node = dev->of_node;
+
+ fsl_ldb->clk = devm_clk_get(dev, "ldb");
+ if (IS_ERR(fsl_ldb->clk))
+ return PTR_ERR(fsl_ldb->clk);
+
+ fsl_ldb->regmap = syscon_node_to_regmap(dev->of_node->parent);
+ if (IS_ERR(fsl_ldb->regmap))
+ return PTR_ERR(fsl_ldb->regmap);
+
+ /* Locate the panel DT node. */
+ panel_node = of_graph_get_remote_node(dev->of_node, 1, 0);
+ if (!panel_node)
+ return -ENXIO;
+
+ panel = of_drm_find_panel(panel_node);
+ of_node_put(panel_node);
+ if (IS_ERR(panel))
+ return PTR_ERR(panel);
+
+ fsl_ldb->panel_bridge = devm_drm_panel_bridge_add(dev, panel);
+ if (IS_ERR(fsl_ldb->panel_bridge))
+ return PTR_ERR(fsl_ldb->panel_bridge);
+
+ /* Determine whether this is dual-link configuration */
+ port1 = of_graph_get_port_by_id(dev->of_node, 1);
+ port2 = of_graph_get_port_by_id(dev->of_node, 2);
+ dual_link = drm_of_lvds_get_dual_link_pixel_order(port1, port2);
+ of_node_put(port1);
+ of_node_put(port2);
+
+ if (dual_link == DRM_LVDS_DUAL_LINK_EVEN_ODD_PIXELS) {
+ dev_err(dev, "LVDS channel pixel swap not supported.\n");
+ return -EINVAL;
+ }
+
+ if (dual_link == DRM_LVDS_DUAL_LINK_ODD_EVEN_PIXELS)
+ fsl_ldb->lvds_dual_link = true;
+
+ platform_set_drvdata(pdev, fsl_ldb);
+
+ drm_bridge_add(&fsl_ldb->bridge);
+
+ return 0;
+}
+
+static int fsl_ldb_remove(struct platform_device *pdev)
+{
+ struct fsl_ldb *fsl_ldb = platform_get_drvdata(pdev);
+
+ drm_bridge_remove(&fsl_ldb->bridge);
+
+ return 0;
+}
+
+static const struct of_device_id fsl_ldb_match[] = {
+ { .compatible = "fsl,imx8mp-ldb", },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, fsl_ldb_match);
+
+static struct platform_driver fsl_ldb_driver = {
+ .probe = fsl_ldb_probe,
+ .remove = fsl_ldb_remove,
+ .driver = {
+ .name = "fsl-ldb",
+ .of_match_table = fsl_ldb_match,
+ },
+};
+module_platform_driver(fsl_ldb_driver);
+
+MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
+MODULE_DESCRIPTION("Freescale i.MX8MP LDB");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/bridge/ite-it6505.c b/drivers/gpu/drm/bridge/ite-it6505.c
index 8fed30df08b0..4b673c4792d7 100644
--- a/drivers/gpu/drm/bridge/ite-it6505.c
+++ b/drivers/gpu/drm/bridge/ite-it6505.c
@@ -737,8 +737,9 @@ static int it6505_drm_dp_link_probe(struct drm_dp_aux *aux,
return 0;
}
-static int it6505_drm_dp_link_power_up(struct drm_dp_aux *aux,
- struct it6505_drm_dp_link *link)
+static int it6505_drm_dp_link_set_power(struct drm_dp_aux *aux,
+ struct it6505_drm_dp_link *link,
+ u8 mode)
{
u8 value;
int err;
@@ -752,18 +753,20 @@ static int it6505_drm_dp_link_power_up(struct drm_dp_aux *aux,
return err;
value &= ~DP_SET_POWER_MASK;
- value |= DP_SET_POWER_D0;
+ value |= mode;
err = drm_dp_dpcd_writeb(aux, DP_SET_POWER, value);
if (err < 0)
return err;
- /*
- * According to the DP 1.1 specification, a "Sink Device must exit the
- * power saving state within 1 ms" (Section 2.5.3.1, Table 5-52, "Sink
- * Control Field" (register 0x600).
- */
- usleep_range(1000, 2000);
+ if (mode == DP_SET_POWER_D0) {
+ /*
+ * According to the DP 1.1 specification, a "Sink Device must
+ * exit the power saving state within 1 ms" (Section 2.5.3.1,
+ * Table 5-52, "Sink Control Field" (register 0x600).
+ */
+ usleep_range(1000, 2000);
+ }
return 0;
}
@@ -2624,7 +2627,8 @@ static enum drm_connector_status it6505_detect(struct it6505 *it6505)
if (it6505_get_sink_hpd_status(it6505)) {
it6505_aux_on(it6505);
it6505_drm_dp_link_probe(&it6505->aux, &it6505->link);
- it6505_drm_dp_link_power_up(&it6505->aux, &it6505->link);
+ it6505_drm_dp_link_set_power(&it6505->aux, &it6505->link,
+ DP_SET_POWER_D0);
it6505->auto_train_retry = AUTO_TRAIN_RETRY;
if (it6505->dpcd[0] == 0) {
@@ -2960,8 +2964,11 @@ static void it6505_bridge_atomic_disable(struct drm_bridge *bridge,
DRM_DEV_DEBUG_DRIVER(dev, "start");
- if (it6505->powered)
+ if (it6505->powered) {
it6505_video_disable(it6505);
+ it6505_drm_dp_link_set_power(&it6505->aux, &it6505->link,
+ DP_SET_POWER_D3);
+ }
}
static enum drm_connector_status
diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c
index b20b38661002..7dde71313b84 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -1955,7 +1955,7 @@ static int tc_probe_edp_bridge_endpoint(struct tc_data *tc)
tc->bridge.ops |= DRM_BRIDGE_OP_DETECT;
tc->bridge.ops |= DRM_BRIDGE_OP_EDID;
- return ret;
+ return 0;
}
static int tc_probe_bridge_endpoint(struct tc_data *tc)
diff --git a/drivers/gpu/drm/bridge/ti-tfp410.c b/drivers/gpu/drm/bridge/ti-tfp410.c
index ba3fa2a9b8a4..756b3e6e776b 100644
--- a/drivers/gpu/drm/bridge/ti-tfp410.c
+++ b/drivers/gpu/drm/bridge/ti-tfp410.c
@@ -341,13 +341,11 @@ static int tfp410_init(struct device *dev, bool i2c)
return 0;
}
-static int tfp410_fini(struct device *dev)
+static void tfp410_fini(struct device *dev)
{
struct tfp410 *dvi = dev_get_drvdata(dev);
drm_bridge_remove(&dvi->bridge);
-
- return 0;
}
static int tfp410_probe(struct platform_device *pdev)
@@ -357,7 +355,9 @@ static int tfp410_probe(struct platform_device *pdev)
static int tfp410_remove(struct platform_device *pdev)
{
- return tfp410_fini(&pdev->dev);
+ tfp410_fini(&pdev->dev);
+
+ return 0;
}
static const struct of_device_id tfp410_match[] = {
@@ -394,7 +394,9 @@ static int tfp410_i2c_probe(struct i2c_client *client,
static int tfp410_i2c_remove(struct i2c_client *client)
{
- return tfp410_fini(&client->dev);
+ tfp410_fini(&client->dev);
+
+ return 0;
}
static const struct i2c_device_id tfp410_i2c_ids[] = {
diff --git a/drivers/gpu/drm/display/Kconfig b/drivers/gpu/drm/display/Kconfig
index f84f1b0cd23f..1b6e6af37546 100644
--- a/drivers/gpu/drm/display/Kconfig
+++ b/drivers/gpu/drm/display/Kconfig
@@ -31,7 +31,8 @@ config DRM_DISPLAY_HDMI_HELPER
config DRM_DP_AUX_CHARDEV
bool "DRM DP AUX Interface"
- depends on DRM
+ depends on DRM && DRM_DISPLAY_HELPER
+ select DRM_DISPLAY_DP_HELPER
help
Choose this option to enable a /dev/drm_dp_auxN node that allows to
read and write values to arbitrary DPCD registers on the DP aux
@@ -39,7 +40,8 @@ config DRM_DP_AUX_CHARDEV
config DRM_DP_CEC
bool "Enable DisplayPort CEC-Tunneling-over-AUX HDMI support"
- depends on DRM
+ depends on DRM && DRM_DISPLAY_HELPER
+ select DRM_DISPLAY_DP_HELPER
select CEC_CORE
help
Choose this option if you want to enable HDMI CEC support for
diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c b/drivers/gpu/drm/display/drm_dp_mst_topology.c
index 8526aae75c6d..9aa2c20904e3 100644
--- a/drivers/gpu/drm/display/drm_dp_mst_topology.c
+++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c
@@ -3557,10 +3557,9 @@ static int drm_dp_send_dpcd_read(struct drm_dp_mst_topology_mgr *mgr,
if (ret < 0)
goto fail_free;
- /* DPCD read should never be NACKed */
if (txmsg->reply.reply_type == 1) {
- drm_err(mgr->dev, "mstb %p port %d: DPCD read on addr 0x%x for %d bytes NAKed\n",
- mstb, port->port_num, offset, size);
+ drm_dbg_kms(mgr->dev, "mstb %p port %d: DPCD read on addr 0x%x for %d bytes NAKed\n",
+ mstb, port->port_num, offset, size);
ret = -EIO;
goto fail_free;
}
diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c
index c6394ba13b24..434f3d4cb8a2 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -255,43 +255,6 @@ drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state,
EXPORT_SYMBOL(drm_atomic_set_fb_for_plane);
/**
- * drm_atomic_set_fence_for_plane - set fence for plane
- * @plane_state: atomic state object for the plane
- * @fence: dma_fence to use for the plane
- *
- * Helper to setup the plane_state fence in case it is not set yet.
- * By using this drivers doesn't need to worry if the user choose
- * implicit or explicit fencing.
- *
- * This function will not set the fence to the state if it was set
- * via explicit fencing interfaces on the atomic ioctl. In that case it will
- * drop the reference to the fence as we are not storing it anywhere.
- * Otherwise, if &drm_plane_state.fence is not set this function we just set it
- * with the received implicit fence. In both cases this function consumes a
- * reference for @fence.
- *
- * This way explicit fencing can be used to overrule implicit fencing, which is
- * important to make explicit fencing use-cases work: One example is using one
- * buffer for 2 screens with different refresh rates. Implicit fencing will
- * clamp rendering to the refresh rate of the slower screen, whereas explicit
- * fence allows 2 independent render and display loops on a single buffer. If a
- * driver allows obeys both implicit and explicit fences for plane updates, then
- * it will break all the benefits of explicit fencing.
- */
-void
-drm_atomic_set_fence_for_plane(struct drm_plane_state *plane_state,
- struct dma_fence *fence)
-{
- if (plane_state->fence) {
- dma_fence_put(fence);
- return;
- }
-
- plane_state->fence = fence;
-}
-EXPORT_SYMBOL(drm_atomic_set_fence_for_plane);
-
-/**
* drm_atomic_set_crtc_for_connector - set CRTC for connector
* @conn_state: atomic state object for the connector
* @crtc: CRTC to use for the connector
@@ -1077,10 +1040,10 @@ int drm_atomic_set_property(struct drm_atomic_state *state,
*
* As a contrast, with implicit fencing the kernel keeps track of any
* ongoing rendering, and automatically ensures that the atomic update waits
- * for any pending rendering to complete. For shared buffers represented with
- * a &struct dma_buf this is tracked in &struct dma_resv.
- * Implicit syncing is how Linux traditionally worked (e.g. DRI2/3 on X.org),
- * whereas explicit fencing is what Android wants.
+ * for any pending rendering to complete. This is usually tracked in &struct
+ * dma_resv which can also contain mandatory kernel fences. Implicit syncing
+ * is how Linux traditionally worked (e.g. DRI2/3 on X.org), whereas explicit
+ * fencing is what Android wants.
*
* "IN_FENCE_FD”:
* Use this property to pass a fence that DRM should wait on before
@@ -1095,7 +1058,7 @@ int drm_atomic_set_property(struct drm_atomic_state *state,
*
* On the driver side the fence is stored on the @fence parameter of
* &struct drm_plane_state. Drivers which also support implicit fencing
- * should set the implicit fence using drm_atomic_set_fence_for_plane(),
+ * should extract the implicit fence using drm_gem_plane_helper_prepare_fb(),
* to make sure there's consistent behaviour between drivers in precedence
* of implicit vs. explicit fencing.
*
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 7a8482b75071..bc43e1b32092 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -1610,7 +1610,7 @@ static void edid_header_fix(void *edid)
/**
* drm_edid_header_is_valid - sanity check the header of the base EDID block
- * @raw_edid: pointer to raw base EDID block
+ * @_edid: pointer to raw base EDID block
*
* Sanity check the header of the base EDID block.
*
@@ -1827,7 +1827,7 @@ static void edid_block_dump(const char *level, const void *block, int block_num)
/**
* drm_edid_block_valid - Sanity check the EDID block (base or extension)
- * @raw_edid: pointer to raw EDID block
+ * @_block: pointer to raw EDID block
* @block_num: type of block to validate (0 for base, extension otherwise)
* @print_bad_edid: if true, dump bad EDID blocks to the console
* @edid_corrupt: if true, the header or checksum is invalid
@@ -2112,8 +2112,8 @@ static enum edid_block_status edid_block_read(void *block, unsigned int block_nu
/**
* drm_do_get_edid - get EDID data using a custom EDID block read function
* @connector: connector we're probing
- * @get_edid_block: EDID block read function
- * @data: private data passed to the block read function
+ * @read_block: EDID block read function
+ * @context: private data passed to the block read function
*
* When the I2C adapter connected to the DDC bus is hidden behind a device that
* exposes a different interface to read EDID blocks this function can be used
@@ -2384,13 +2384,9 @@ static u32 edid_get_quirks(const struct edid *edid)
#define MODE_SIZE(m) ((m)->hdisplay * (m)->vdisplay)
#define MODE_REFRESH_DIFF(c,t) (abs((c) - (t)))
-/**
- * edid_fixup_preferred - set preferred modes based on quirk list
- * @connector: has mode list to fix up
- * @quirks: quirks list
- *
- * Walk the mode list for @connector, clearing the preferred status
- * on existing modes and setting it anew for the right mode ala @quirks.
+/*
+ * Walk the mode list for connector, clearing the preferred status on existing
+ * modes and setting it anew for the right mode ala quirks.
*/
static void edid_fixup_preferred(struct drm_connector *connector,
u32 quirks)
@@ -2659,10 +2655,7 @@ drm_gtf2_2j(const struct edid *edid)
return descriptor ? descriptor->data.other_data.data.range.formula.gtf2.j : 0;
}
-/**
- * standard_timing_level - get std. timing level(CVT/GTF/DMT)
- * @edid: EDID block to scan
- */
+/* Get standard timing level (CVT/GTF/DMT). */
static int standard_timing_level(const struct edid *edid)
{
if (edid->revision >= 2) {
@@ -2696,12 +2689,7 @@ static int drm_mode_hsync(const struct drm_display_mode *mode)
return DIV_ROUND_CLOSEST(mode->clock, mode->htotal);
}
-/**
- * drm_mode_std - convert standard mode info (width, height, refresh) into mode
- * @connector: connector of for the EDID block
- * @edid: EDID block to scan
- * @t: standard timing params
- *
+/*
* Take the standard timing params (in this case width, aspect, and refresh)
* and convert them into a real mode using CVT/GTF/DMT.
*/
@@ -2857,15 +2845,10 @@ drm_mode_do_interlace_quirk(struct drm_display_mode *mode,
mode->flags |= DRM_MODE_FLAG_INTERLACE;
}
-/**
- * drm_mode_detailed - create a new mode from an EDID detailed timing section
- * @dev: DRM device (needed to create new mode)
- * @edid: EDID block
- * @timing: EDID detailed timing info
- * @quirks: quirks to apply
- *
- * An EDID detailed timing block contains enough info for us to create and
- * return a new struct drm_display_mode.
+/*
+ * Create a new mode from an EDID detailed timing section. An EDID detailed
+ * timing block contains enough info for us to create and return a new struct
+ * drm_display_mode.
*/
static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev,
const struct edid *edid,
@@ -3247,13 +3230,10 @@ do_established_modes(const struct detailed_timing *timing, void *c)
closure->modes += drm_est3_modes(closure->connector, timing);
}
-/**
- * add_established_modes - get est. modes from EDID and add them
- * @connector: connector to add mode(s) to
- * @edid: EDID block to scan
- *
- * Each EDID block contains a bitmap of the supported "established modes" list
- * (defined above). Tease them out and add them to the global modes list.
+/*
+ * Get established modes from EDID and add them. Each EDID block contains a
+ * bitmap of the supported "established modes" list (defined above). Tease them
+ * out and add them to the global modes list.
*/
static int
add_established_modes(struct drm_connector *connector, const struct edid *edid)
@@ -3311,13 +3291,10 @@ do_standard_modes(const struct detailed_timing *timing, void *c)
}
}
-/**
- * add_standard_modes - get std. modes from EDID and add them
- * @connector: connector to add mode(s) to
- * @edid: EDID block to scan
- *
- * Standard modes can be calculated using the appropriate standard (DMT,
- * GTF or CVT. Grab them from @edid and add them to the list.
+/*
+ * Get standard modes from EDID and add them. Standard modes can be calculated
+ * using the appropriate standard (DMT, GTF, or CVT). Grab them from EDID and
+ * add them to the list.
*/
static int
add_standard_modes(struct drm_connector *connector, const struct edid *edid)
diff --git a/drivers/gpu/drm/drm_gem_atomic_helper.c b/drivers/gpu/drm/drm_gem_atomic_helper.c
index a6d89aed0bda..a5026f617739 100644
--- a/drivers/gpu/drm/drm_gem_atomic_helper.c
+++ b/drivers/gpu/drm/drm_gem_atomic_helper.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <linux/dma-resv.h>
+#include <linux/dma-fence-chain.h>
#include <drm/drm_atomic_state_helper.h>
#include <drm/drm_atomic_uapi.h>
@@ -137,29 +138,67 @@
*
* This function is the default implementation for GEM drivers of
* &drm_plane_helper_funcs.prepare_fb if no callback is provided.
- *
- * See drm_atomic_set_fence_for_plane() for a discussion of implicit and
- * explicit fencing in atomic modeset updates.
*/
-int drm_gem_plane_helper_prepare_fb(struct drm_plane *plane, struct drm_plane_state *state)
+int drm_gem_plane_helper_prepare_fb(struct drm_plane *plane,
+ struct drm_plane_state *state)
{
- struct drm_gem_object *obj;
- struct dma_fence *fence;
+ struct dma_fence *fence = dma_fence_get(state->fence);
+ enum dma_resv_usage usage;
+ size_t i;
int ret;
if (!state->fb)
return 0;
- obj = drm_gem_fb_get_obj(state->fb, 0);
- ret = dma_resv_get_singleton(obj->resv, DMA_RESV_USAGE_WRITE, &fence);
- if (ret)
- return ret;
-
- /* TODO: drm_atomic_set_fence_for_plane() should be changed to be able
- * to handle more fences in general for multiple BOs per fb.
+ /*
+ * Only add the kernel fences here if there is already a fence set via
+ * explicit fencing interfaces on the atomic ioctl.
+ *
+ * This way explicit fencing can be used to overrule implicit fencing,
+ * which is important to make explicit fencing use-cases work: One
+ * example is using one buffer for 2 screens with different refresh
+ * rates. Implicit fencing will clamp rendering to the refresh rate of
+ * the slower screen, whereas explicit fence allows 2 independent
+ * render and display loops on a single buffer. If a driver allows
+ * obeys both implicit and explicit fences for plane updates, then it
+ * will break all the benefits of explicit fencing.
*/
- drm_atomic_set_fence_for_plane(state, fence);
+ usage = fence ? DMA_RESV_USAGE_KERNEL : DMA_RESV_USAGE_WRITE;
+
+ for (i = 0; i < state->fb->format->num_planes; ++i) {
+ struct drm_gem_object *obj = drm_gem_fb_get_obj(state->fb, i);
+ struct dma_fence *new;
+
+ if (WARN_ON_ONCE(!obj))
+ continue;
+
+ ret = dma_resv_get_singleton(obj->resv, usage, &new);
+ if (ret)
+ goto error;
+
+ if (new && fence) {
+ struct dma_fence_chain *chain = dma_fence_chain_alloc();
+
+ if (!chain) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ dma_fence_chain_init(chain, fence, new, 1);
+ fence = &chain->base;
+
+ } else if (new) {
+ fence = new;
+ }
+ }
+
+ dma_fence_put(state->fence);
+ state->fence = fence;
return 0;
+
+error:
+ dma_fence_put(fence);
+ return ret;
}
EXPORT_SYMBOL_GPL(drm_gem_plane_helper_prepare_fb);
@@ -168,13 +207,13 @@ EXPORT_SYMBOL_GPL(drm_gem_plane_helper_prepare_fb);
* @pipe: Simple display pipe
* @plane_state: Plane state
*
- * This function uses drm_gem_plane_helper_prepare_fb() to extract the exclusive fence
- * from &drm_gem_object.resv and attaches it to plane state for the atomic
+ * This function uses drm_gem_plane_helper_prepare_fb() to extract the fences
+ * from &drm_gem_object.resv and attaches them to the plane state for the atomic
* helper to wait on. This is necessary to correctly implement implicit
* synchronization for any buffers shared as a struct &dma_buf. Drivers can use
* this as their &drm_simple_display_pipe_funcs.prepare_fb callback.
*
- * See drm_atomic_set_fence_for_plane() for a discussion of implicit and
+ * See drm_gem_plane_helper_prepare_fb() for a discussion of implicit and
* explicit fencing in atomic modeset updates.
*/
int drm_gem_simple_display_pipe_prepare_fb(struct drm_simple_display_pipe *pipe,
diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c
index bf0daa8d9bbd..726f2f163c26 100644
--- a/drivers/gpu/drm/drm_plane.c
+++ b/drivers/gpu/drm/drm_plane.c
@@ -247,6 +247,13 @@ static int __drm_universal_plane_init(struct drm_device *dev,
if (WARN_ON(config->num_total_plane >= 32))
return -EINVAL;
+ /*
+ * First driver to need more than 64 formats needs to fix this. Each
+ * format is encoded as a bit and the current code only supports a u64.
+ */
+ if (WARN_ON(format_count > 64))
+ return -EINVAL;
+
WARN_ON(drm_drv_uses_atomic_modeset(dev) &&
(!funcs->atomic_destroy_state ||
!funcs->atomic_duplicate_state));
@@ -268,13 +275,6 @@ static int __drm_universal_plane_init(struct drm_device *dev,
return -ENOMEM;
}
- /*
- * First driver to need more than 64 formats needs to fix this. Each
- * format is encoded as a bit and the current code only supports a u64.
- */
- if (WARN_ON(format_count > 64))
- return -EINVAL;
-
if (format_modifiers) {
const uint64_t *temp_modifiers = format_modifiers;
diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndw.c b/drivers/gpu/drm/nouveau/dispnv50/wndw.c
index 8642b84ea20c..bb8a4601e0d9 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/wndw.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/wndw.c
@@ -32,6 +32,7 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
+#include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_fourcc.h>
#include "nouveau_bo.h"
@@ -558,9 +559,7 @@ nv50_wndw_prepare_fb(struct drm_plane *plane, struct drm_plane_state *state)
asyw->image.handle[0] = ctxdma->object.handle;
}
- ret = dma_resv_get_singleton(nvbo->bo.base.resv,
- DMA_RESV_USAGE_WRITE,
- &asyw->state.fence);
+ ret = drm_gem_plane_helper_prepare_fb(plane, state);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/nouveau/nouveau_debugfs.c b/drivers/gpu/drm/nouveau/nouveau_debugfs.c
index 1cbe01048b93..2a36d1ca8fda 100644
--- a/drivers/gpu/drm/nouveau/nouveau_debugfs.c
+++ b/drivers/gpu/drm/nouveau/nouveau_debugfs.c
@@ -255,19 +255,13 @@ nouveau_drm_debugfs_init(struct drm_minor *minor)
int
nouveau_debugfs_init(struct nouveau_drm *drm)
{
- int ret;
-
drm->debugfs = kzalloc(sizeof(*drm->debugfs), GFP_KERNEL);
if (!drm->debugfs)
return -ENOMEM;
- ret = nvif_object_ctor(&drm->client.device.object, "debugfsCtrl", 0,
- NVIF_CLASS_CONTROL, NULL, 0,
- &drm->debugfs->ctrl);
- if (ret)
- return ret;
-
- return 0;
+ return nvif_object_ctor(&drm->client.device.object, "debugfsCtrl", 0,
+ NVIF_CLASS_CONTROL, NULL, 0,
+ &drm->debugfs->ctrl);
}
void
diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
index 595396f57632..4a2e580a2f7b 100644
--- a/drivers/gpu/drm/panel/panel-simple.c
+++ b/drivers/gpu/drm/panel/panel-simple.c
@@ -720,7 +720,7 @@ static const struct drm_display_mode ampire_am_1280800n3tzqw_t00h_mode = {
static const struct panel_desc ampire_am_1280800n3tzqw_t00h = {
.modes = &ampire_am_1280800n3tzqw_t00h_mode,
.num_modes = 1,
- .bpc = 6,
+ .bpc = 8,
.size = {
.width = 217,
.height = 136,
@@ -3310,6 +3310,41 @@ static const struct panel_desc starry_kr070pe2t = {
.connector_type = DRM_MODE_CONNECTOR_DPI,
};
+static const struct display_timing startek_kd070wvfpa_mode = {
+ .pixelclock = { 25200000, 27200000, 30500000 },
+ .hactive = { 800, 800, 800 },
+ .hfront_porch = { 19, 44, 115 },
+ .hback_porch = { 5, 16, 101 },
+ .hsync_len = { 1, 2, 100 },
+ .vactive = { 480, 480, 480 },
+ .vfront_porch = { 5, 43, 67 },
+ .vback_porch = { 5, 5, 67 },
+ .vsync_len = { 1, 2, 66 },
+ .flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW |
+ DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_PIXDATA_POSEDGE |
+ DISPLAY_FLAGS_SYNC_POSEDGE,
+};
+
+static const struct panel_desc startek_kd070wvfpa = {
+ .timings = &startek_kd070wvfpa_mode,
+ .num_timings = 1,
+ .bpc = 8,
+ .size = {
+ .width = 152,
+ .height = 91,
+ },
+ .delay = {
+ .prepare = 20,
+ .enable = 200,
+ .disable = 200,
+ },
+ .bus_format = MEDIA_BUS_FMT_RGB888_1X24,
+ .connector_type = DRM_MODE_CONNECTOR_DPI,
+ .bus_flags = DRM_BUS_FLAG_DE_HIGH |
+ DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE |
+ DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE,
+};
+
static const struct display_timing tsd_tst043015cmhx_timing = {
.pixelclock = { 5000000, 9000000, 12000000 },
.hactive = { 480, 480, 480 },
@@ -4020,6 +4055,9 @@ static const struct of_device_id platform_of_match[] = {
.compatible = "starry,kr070pe2t",
.data = &starry_kr070pe2t,
}, {
+ .compatible = "startek,kd070wvfpa",
+ .data = &startek_kd070wvfpa,
+ }, {
.compatible = "team-source-display,tst043015cmhx",
.data = &tsd_tst043015cmhx,
}, {
diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index f7e3fb94ed04..70be64ca0a00 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -40,8 +40,6 @@
#define PSR_WAIT_LINE_FLAG_TIMEOUT_MS 100
-#define to_dp(nm) container_of(nm, struct rockchip_dp_device, nm)
-
/**
* struct rockchip_dp_chip_data - splite the grf setting of kind of chips
* @lcdsel_grf_reg: grf register offset of lcdc select
@@ -59,7 +57,7 @@ struct rockchip_dp_chip_data {
struct rockchip_dp_device {
struct drm_device *drm_dev;
struct device *dev;
- struct drm_encoder encoder;
+ struct rockchip_encoder encoder;
struct drm_display_mode mode;
struct clk *pclk;
@@ -73,6 +71,18 @@ struct rockchip_dp_device {
struct analogix_dp_plat_data plat_data;
};
+static struct rockchip_dp_device *encoder_to_dp(struct drm_encoder *encoder)
+{
+ struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder);
+
+ return container_of(rkencoder, struct rockchip_dp_device, encoder);
+}
+
+static struct rockchip_dp_device *pdata_encoder_to_dp(struct analogix_dp_plat_data *plat_data)
+{
+ return container_of(plat_data, struct rockchip_dp_device, plat_data);
+}
+
static int rockchip_dp_pre_init(struct rockchip_dp_device *dp)
{
reset_control_assert(dp->rst);
@@ -84,7 +94,7 @@ static int rockchip_dp_pre_init(struct rockchip_dp_device *dp)
static int rockchip_dp_poweron_start(struct analogix_dp_plat_data *plat_data)
{
- struct rockchip_dp_device *dp = to_dp(plat_data);
+ struct rockchip_dp_device *dp = pdata_encoder_to_dp(plat_data);
int ret;
ret = clk_prepare_enable(dp->pclk);
@@ -105,7 +115,7 @@ static int rockchip_dp_poweron_start(struct analogix_dp_plat_data *plat_data)
static int rockchip_dp_powerdown(struct analogix_dp_plat_data *plat_data)
{
- struct rockchip_dp_device *dp = to_dp(plat_data);
+ struct rockchip_dp_device *dp = pdata_encoder_to_dp(plat_data);
clk_disable_unprepare(dp->pclk);
@@ -166,7 +176,7 @@ struct drm_crtc *rockchip_dp_drm_get_new_crtc(struct drm_encoder *encoder,
static void rockchip_dp_drm_encoder_enable(struct drm_encoder *encoder,
struct drm_atomic_state *state)
{
- struct rockchip_dp_device *dp = to_dp(encoder);
+ struct rockchip_dp_device *dp = encoder_to_dp(encoder);
struct drm_crtc *crtc;
struct drm_crtc_state *old_crtc_state;
int ret;
@@ -208,7 +218,7 @@ static void rockchip_dp_drm_encoder_enable(struct drm_encoder *encoder,
static void rockchip_dp_drm_encoder_disable(struct drm_encoder *encoder,
struct drm_atomic_state *state)
{
- struct rockchip_dp_device *dp = to_dp(encoder);
+ struct rockchip_dp_device *dp = encoder_to_dp(encoder);
struct drm_crtc *crtc;
struct drm_crtc_state *new_crtc_state = NULL;
int ret;
@@ -297,7 +307,7 @@ static int rockchip_dp_of_probe(struct rockchip_dp_device *dp)
static int rockchip_dp_drm_create_encoder(struct rockchip_dp_device *dp)
{
- struct drm_encoder *encoder = &dp->encoder;
+ struct drm_encoder *encoder = &dp->encoder.encoder;
struct drm_device *drm_dev = dp->drm_dev;
struct device *dev = dp->dev;
int ret;
@@ -333,7 +343,7 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
return ret;
}
- dp->plat_data.encoder = &dp->encoder;
+ dp->plat_data.encoder = &dp->encoder.encoder;
ret = analogix_dp_bind(dp->adp, drm_dev);
if (ret)
@@ -341,7 +351,7 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
return 0;
err_cleanup_encoder:
- dp->encoder.funcs->destroy(&dp->encoder);
+ dp->encoder.encoder.funcs->destroy(&dp->encoder.encoder);
return ret;
}
@@ -351,7 +361,7 @@ static void rockchip_dp_unbind(struct device *dev, struct device *master,
struct rockchip_dp_device *dp = dev_get_drvdata(dev);
analogix_dp_unbind(dp->adp);
- dp->encoder.funcs->destroy(&dp->encoder);
+ dp->encoder.encoder.funcs->destroy(&dp->encoder.encoder);
}
static const struct component_ops rockchip_dp_component_ops = {
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c
index 2857d3f68730..c204e9b95c1f 100644
--- a/drivers/gpu/drm/rockchip/cdn-dp-core.c
+++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c
@@ -26,11 +26,17 @@
#include "cdn-dp-reg.h"
#include "rockchip_drm_vop.h"
-#define connector_to_dp(c) \
- container_of(c, struct cdn_dp_device, connector)
+static inline struct cdn_dp_device *connector_to_dp(struct drm_connector *connector)
+{
+ return container_of(connector, struct cdn_dp_device, connector);
+}
-#define encoder_to_dp(c) \
- container_of(c, struct cdn_dp_device, encoder)
+static inline struct cdn_dp_device *encoder_to_dp(struct drm_encoder *encoder)
+{
+ struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder);
+
+ return container_of(rkencoder, struct cdn_dp_device, encoder);
+}
#define GRF_SOC_CON9 0x6224
#define DP_SEL_VOP_LIT BIT(12)
@@ -48,7 +54,7 @@ struct cdn_dp_data {
u8 max_phy;
};
-struct cdn_dp_data rk3399_cdn_dp = {
+static struct cdn_dp_data rk3399_cdn_dp = {
.max_phy = 2,
};
@@ -1050,7 +1056,7 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data)
INIT_WORK(&dp->event_work, cdn_dp_pd_event_work);
- encoder = &dp->encoder;
+ encoder = &dp->encoder.encoder;
encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev,
dev->of_node);
@@ -1115,7 +1121,7 @@ err_free_encoder:
static void cdn_dp_unbind(struct device *dev, struct device *master, void *data)
{
struct cdn_dp_device *dp = dev_get_drvdata(dev);
- struct drm_encoder *encoder = &dp->encoder;
+ struct drm_encoder *encoder = &dp->encoder.encoder;
struct drm_connector *connector = &dp->connector;
cancel_work_sync(&dp->event_work);
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h
index cd6c3089e35c..5b2fed1f5f55 100644
--- a/drivers/gpu/drm/rockchip/cdn-dp-core.h
+++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h
@@ -66,7 +66,7 @@ struct cdn_dp_device {
struct device *dev;
struct drm_device *drm_dev;
struct drm_connector connector;
- struct drm_encoder encoder;
+ struct rockchip_encoder encoder;
struct drm_display_mode mode;
struct platform_device *audio_pdev;
struct work_struct event_work;
diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
index 4ed7a6868197..110e83aad9bb 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
@@ -181,8 +181,6 @@
#define HIWORD_UPDATE(val, mask) (val | (mask) << 16)
-#define to_dsi(nm) container_of(nm, struct dw_mipi_dsi_rockchip, nm)
-
enum {
DW_DSI_USAGE_IDLE,
DW_DSI_USAGE_DSI,
@@ -236,7 +234,7 @@ struct rockchip_dw_dsi_chip_data {
struct dw_mipi_dsi_rockchip {
struct device *dev;
- struct drm_encoder encoder;
+ struct rockchip_encoder encoder;
void __iomem *base;
struct regmap *grf_regmap;
@@ -271,6 +269,13 @@ struct dw_mipi_dsi_rockchip {
bool dsi_bound;
};
+static struct dw_mipi_dsi_rockchip *to_dsi(struct drm_encoder *encoder)
+{
+ struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder);
+
+ return container_of(rkencoder, struct dw_mipi_dsi_rockchip, encoder);
+}
+
struct dphy_pll_parameter_map {
unsigned int max_mbps;
u8 hsfreqrange;
@@ -770,7 +775,7 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
int ret, mux;
mux = drm_of_encoder_active_endpoint_id(dsi->dev->of_node,
- &dsi->encoder);
+ &dsi->encoder.encoder);
if (mux < 0)
return;
@@ -801,7 +806,7 @@ dw_mipi_dsi_encoder_helper_funcs = {
static int rockchip_dsi_drm_create_encoder(struct dw_mipi_dsi_rockchip *dsi,
struct drm_device *drm_dev)
{
- struct drm_encoder *encoder = &dsi->encoder;
+ struct drm_encoder *encoder = &dsi->encoder.encoder;
int ret;
encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev,
@@ -959,7 +964,7 @@ static int dw_mipi_dsi_rockchip_bind(struct device *dev,
goto out_pll_clk;
}
- ret = dw_mipi_dsi_bind(dsi->dmd, &dsi->encoder);
+ ret = dw_mipi_dsi_bind(dsi->dmd, &dsi->encoder.encoder);
if (ret) {
DRM_DEV_ERROR(dev, "Failed to bind: %d\n", ret);
goto out_pll_clk;
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index 8677c8271678..912181429880 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -67,15 +67,20 @@ struct rockchip_hdmi_chip_data {
struct rockchip_hdmi {
struct device *dev;
struct regmap *regmap;
- struct drm_encoder encoder;
+ struct rockchip_encoder encoder;
const struct rockchip_hdmi_chip_data *chip_data;
- struct clk *vpll_clk;
+ struct clk *ref_clk;
struct clk *grf_clk;
struct dw_hdmi *hdmi;
struct phy *phy;
};
-#define to_rockchip_hdmi(x) container_of(x, struct rockchip_hdmi, x)
+static struct rockchip_hdmi *to_rockchip_hdmi(struct drm_encoder *encoder)
+{
+ struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder);
+
+ return container_of(rkencoder, struct rockchip_hdmi, encoder);
+}
static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = {
{
@@ -196,14 +201,15 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi)
return PTR_ERR(hdmi->regmap);
}
- hdmi->vpll_clk = devm_clk_get(hdmi->dev, "vpll");
- if (PTR_ERR(hdmi->vpll_clk) == -ENOENT) {
- hdmi->vpll_clk = NULL;
- } else if (PTR_ERR(hdmi->vpll_clk) == -EPROBE_DEFER) {
+ hdmi->ref_clk = devm_clk_get_optional(hdmi->dev, "ref");
+ if (!hdmi->ref_clk)
+ hdmi->ref_clk = devm_clk_get_optional(hdmi->dev, "vpll");
+
+ if (PTR_ERR(hdmi->ref_clk) == -EPROBE_DEFER) {
return -EPROBE_DEFER;
- } else if (IS_ERR(hdmi->vpll_clk)) {
- DRM_DEV_ERROR(hdmi->dev, "failed to get vpll clock\n");
- return PTR_ERR(hdmi->vpll_clk);
+ } else if (IS_ERR(hdmi->ref_clk)) {
+ DRM_DEV_ERROR(hdmi->dev, "failed to get reference clock\n");
+ return PTR_ERR(hdmi->ref_clk);
}
hdmi->grf_clk = devm_clk_get(hdmi->dev, "grf");
@@ -257,7 +263,7 @@ static void dw_hdmi_rockchip_encoder_mode_set(struct drm_encoder *encoder,
{
struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);
- clk_set_rate(hdmi->vpll_clk, adj_mode->clock * 1000);
+ clk_set_rate(hdmi->ref_clk, adj_mode->clock * 1000);
}
static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder)
@@ -511,7 +517,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
hdmi->dev = &pdev->dev;
hdmi->chip_data = plat_data->phy_data;
plat_data->phy_data = hdmi;
- encoder = &hdmi->encoder;
+ encoder = &hdmi->encoder.encoder;
encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
/*
@@ -537,9 +543,9 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
return ret;
}
- ret = clk_prepare_enable(hdmi->vpll_clk);
+ ret = clk_prepare_enable(hdmi->ref_clk);
if (ret) {
- DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI vpll: %d\n",
+ DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI reference clock: %d\n",
ret);
return ret;
}
@@ -558,7 +564,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
if (IS_ERR(hdmi->hdmi)) {
ret = PTR_ERR(hdmi->hdmi);
drm_encoder_cleanup(encoder);
- clk_disable_unprepare(hdmi->vpll_clk);
+ clk_disable_unprepare(hdmi->ref_clk);
}
return ret;
@@ -570,7 +576,7 @@ static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
struct rockchip_hdmi *hdmi = dev_get_drvdata(dev);
dw_hdmi_unbind(hdmi->hdmi);
- clk_disable_unprepare(hdmi->vpll_clk);
+ clk_disable_unprepare(hdmi->ref_clk);
}
static const struct component_ops dw_hdmi_rockchip_ops = {
diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c
index 046e8ec2a71c..87b2243ea23e 100644
--- a/drivers/gpu/drm/rockchip/inno_hdmi.c
+++ b/drivers/gpu/drm/rockchip/inno_hdmi.c
@@ -26,11 +26,8 @@
#include "inno_hdmi.h"
-#define to_inno_hdmi(x) container_of(x, struct inno_hdmi, x)
-
struct hdmi_data_info {
int vic;
- bool sink_is_hdmi;
bool sink_has_audio;
unsigned int enc_in_format;
unsigned int enc_out_format;
@@ -56,7 +53,7 @@ struct inno_hdmi {
void __iomem *regs;
struct drm_connector connector;
- struct drm_encoder encoder;
+ struct rockchip_encoder encoder;
struct inno_hdmi_i2c *i2c;
struct i2c_adapter *ddc;
@@ -67,6 +64,18 @@ struct inno_hdmi {
struct drm_display_mode previous_mode;
};
+static struct inno_hdmi *encoder_to_inno_hdmi(struct drm_encoder *encoder)
+{
+ struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder);
+
+ return container_of(rkencoder, struct inno_hdmi, encoder);
+}
+
+static struct inno_hdmi *connector_to_inno_hdmi(struct drm_connector *connector)
+{
+ return container_of(connector, struct inno_hdmi, connector);
+}
+
enum {
CSC_ITU601_16_235_TO_RGB_0_255_8BIT,
CSC_ITU601_0_255_TO_RGB_0_255_8BIT,
@@ -433,6 +442,8 @@ static int inno_hdmi_config_video_timing(struct inno_hdmi *hdmi,
static int inno_hdmi_setup(struct inno_hdmi *hdmi,
struct drm_display_mode *mode)
{
+ struct drm_display_info *display = &hdmi->connector.display_info;
+
hdmi->hdmi_data.vic = drm_match_cea_mode(mode);
hdmi->hdmi_data.enc_in_format = HDMI_COLORSPACE_RGB;
@@ -452,13 +463,13 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi,
/* Set HDMI Mode */
hdmi_writeb(hdmi, HDMI_HDCP_CTRL,
- v_HDMI_DVI(hdmi->hdmi_data.sink_is_hdmi));
+ v_HDMI_DVI(display->is_hdmi));
inno_hdmi_config_video_timing(hdmi, mode);
inno_hdmi_config_video_csc(hdmi);
- if (hdmi->hdmi_data.sink_is_hdmi) {
+ if (display->is_hdmi) {
inno_hdmi_config_video_avi(hdmi, mode);
inno_hdmi_config_video_vsi(hdmi, mode);
}
@@ -483,7 +494,7 @@ static void inno_hdmi_encoder_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adj_mode)
{
- struct inno_hdmi *hdmi = to_inno_hdmi(encoder);
+ struct inno_hdmi *hdmi = encoder_to_inno_hdmi(encoder);
inno_hdmi_setup(hdmi, adj_mode);
@@ -493,14 +504,14 @@ static void inno_hdmi_encoder_mode_set(struct drm_encoder *encoder,
static void inno_hdmi_encoder_enable(struct drm_encoder *encoder)
{
- struct inno_hdmi *hdmi = to_inno_hdmi(encoder);
+ struct inno_hdmi *hdmi = encoder_to_inno_hdmi(encoder);
inno_hdmi_set_pwr_mode(hdmi, NORMAL);
}
static void inno_hdmi_encoder_disable(struct drm_encoder *encoder)
{
- struct inno_hdmi *hdmi = to_inno_hdmi(encoder);
+ struct inno_hdmi *hdmi = encoder_to_inno_hdmi(encoder);
inno_hdmi_set_pwr_mode(hdmi, LOWER_PWR);
}
@@ -536,7 +547,7 @@ static struct drm_encoder_helper_funcs inno_hdmi_encoder_helper_funcs = {
static enum drm_connector_status
inno_hdmi_connector_detect(struct drm_connector *connector, bool force)
{
- struct inno_hdmi *hdmi = to_inno_hdmi(connector);
+ struct inno_hdmi *hdmi = connector_to_inno_hdmi(connector);
return (hdmi_readb(hdmi, HDMI_STATUS) & m_HOTPLUG) ?
connector_status_connected : connector_status_disconnected;
@@ -544,7 +555,7 @@ inno_hdmi_connector_detect(struct drm_connector *connector, bool force)
static int inno_hdmi_connector_get_modes(struct drm_connector *connector)
{
- struct inno_hdmi *hdmi = to_inno_hdmi(connector);
+ struct inno_hdmi *hdmi = connector_to_inno_hdmi(connector);
struct edid *edid;
int ret = 0;
@@ -553,7 +564,6 @@ static int inno_hdmi_connector_get_modes(struct drm_connector *connector)
edid = drm_get_edid(connector, hdmi->ddc);
if (edid) {
- hdmi->hdmi_data.sink_is_hdmi = drm_detect_hdmi_monitor(edid);
hdmi->hdmi_data.sink_has_audio = drm_detect_monitor_audio(edid);
drm_connector_update_edid_property(connector, edid);
ret = drm_add_edid_modes(connector, edid);
@@ -599,7 +609,7 @@ static struct drm_connector_helper_funcs inno_hdmi_connector_helper_funcs = {
static int inno_hdmi_register(struct drm_device *drm, struct inno_hdmi *hdmi)
{
- struct drm_encoder *encoder = &hdmi->encoder;
+ struct drm_encoder *encoder = &hdmi->encoder.encoder;
struct device *dev = hdmi->dev;
encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
@@ -879,7 +889,7 @@ static int inno_hdmi_bind(struct device *dev, struct device *master,
return 0;
err_cleanup_hdmi:
hdmi->connector.funcs->destroy(&hdmi->connector);
- hdmi->encoder.funcs->destroy(&hdmi->encoder);
+ hdmi->encoder.encoder.funcs->destroy(&hdmi->encoder.encoder);
err_put_adapter:
i2c_put_adapter(hdmi->ddc);
err_disable_clk:
@@ -893,7 +903,7 @@ static void inno_hdmi_unbind(struct device *dev, struct device *master,
struct inno_hdmi *hdmi = dev_get_drvdata(dev);
hdmi->connector.funcs->destroy(&hdmi->connector);
- hdmi->encoder.funcs->destroy(&hdmi->encoder);
+ hdmi->encoder.encoder.funcs->destroy(&hdmi->encoder.encoder);
i2c_put_adapter(hdmi->ddc);
clk_disable_unprepare(hdmi->pclk);
diff --git a/drivers/gpu/drm/rockchip/rk3066_hdmi.c b/drivers/gpu/drm/rockchip/rk3066_hdmi.c
index 1c546c3a8998..c8c3612a4fe2 100644
--- a/drivers/gpu/drm/rockchip/rk3066_hdmi.c
+++ b/drivers/gpu/drm/rockchip/rk3066_hdmi.c
@@ -22,7 +22,6 @@
struct hdmi_data_info {
int vic; /* The CEA Video ID (VIC) of the current drm display mode. */
- bool sink_is_hdmi;
unsigned int enc_out_format;
unsigned int colorimetry;
};
@@ -47,7 +46,7 @@ struct rk3066_hdmi {
void __iomem *regs;
struct drm_connector connector;
- struct drm_encoder encoder;
+ struct rockchip_encoder encoder;
struct rk3066_hdmi_i2c *i2c;
struct i2c_adapter *ddc;
@@ -58,7 +57,17 @@ struct rk3066_hdmi {
struct drm_display_mode previous_mode;
};
-#define to_rk3066_hdmi(x) container_of(x, struct rk3066_hdmi, x)
+static struct rk3066_hdmi *encoder_to_rk3066_hdmi(struct drm_encoder *encoder)
+{
+ struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder);
+
+ return container_of(rkencoder, struct rk3066_hdmi, encoder);
+}
+
+static struct rk3066_hdmi *connector_to_rk3066_hdmi(struct drm_connector *connector)
+{
+ return container_of(connector, struct rk3066_hdmi, connector);
+}
static inline u8 hdmi_readb(struct rk3066_hdmi *hdmi, u16 offset)
{
@@ -317,6 +326,8 @@ static void rk3066_hdmi_config_phy(struct rk3066_hdmi *hdmi)
static int rk3066_hdmi_setup(struct rk3066_hdmi *hdmi,
struct drm_display_mode *mode)
{
+ struct drm_display_info *display = &hdmi->connector.display_info;
+
hdmi->hdmi_data.vic = drm_match_cea_mode(mode);
hdmi->hdmi_data.enc_out_format = HDMI_COLORSPACE_RGB;
@@ -349,7 +360,7 @@ static int rk3066_hdmi_setup(struct rk3066_hdmi *hdmi,
rk3066_hdmi_config_video_timing(hdmi, mode);
- if (hdmi->hdmi_data.sink_is_hdmi) {
+ if (display->is_hdmi) {
hdmi_modb(hdmi, HDMI_HDCP_CTRL, HDMI_VIDEO_MODE_MASK,
HDMI_VIDEO_MODE_HDMI);
rk3066_hdmi_config_avi(hdmi, mode);
@@ -380,7 +391,7 @@ rk3066_hdmi_encoder_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adj_mode)
{
- struct rk3066_hdmi *hdmi = to_rk3066_hdmi(encoder);
+ struct rk3066_hdmi *hdmi = encoder_to_rk3066_hdmi(encoder);
/* Store the display mode for plugin/DPMS poweron events. */
memcpy(&hdmi->previous_mode, adj_mode, sizeof(hdmi->previous_mode));
@@ -388,7 +399,7 @@ rk3066_hdmi_encoder_mode_set(struct drm_encoder *encoder,
static void rk3066_hdmi_encoder_enable(struct drm_encoder *encoder)
{
- struct rk3066_hdmi *hdmi = to_rk3066_hdmi(encoder);
+ struct rk3066_hdmi *hdmi = encoder_to_rk3066_hdmi(encoder);
int mux, val;
mux = drm_of_encoder_active_endpoint_id(hdmi->dev->of_node, encoder);
@@ -407,7 +418,7 @@ static void rk3066_hdmi_encoder_enable(struct drm_encoder *encoder)
static void rk3066_hdmi_encoder_disable(struct drm_encoder *encoder)
{
- struct rk3066_hdmi *hdmi = to_rk3066_hdmi(encoder);
+ struct rk3066_hdmi *hdmi = encoder_to_rk3066_hdmi(encoder);
DRM_DEV_DEBUG(hdmi->dev, "hdmi encoder disable\n");
@@ -455,7 +466,7 @@ struct drm_encoder_helper_funcs rk3066_hdmi_encoder_helper_funcs = {
static enum drm_connector_status
rk3066_hdmi_connector_detect(struct drm_connector *connector, bool force)
{
- struct rk3066_hdmi *hdmi = to_rk3066_hdmi(connector);
+ struct rk3066_hdmi *hdmi = connector_to_rk3066_hdmi(connector);
return (hdmi_readb(hdmi, HDMI_HPG_MENS_STA) & HDMI_HPG_IN_STATUS_HIGH) ?
connector_status_connected : connector_status_disconnected;
@@ -463,7 +474,7 @@ rk3066_hdmi_connector_detect(struct drm_connector *connector, bool force)
static int rk3066_hdmi_connector_get_modes(struct drm_connector *connector)
{
- struct rk3066_hdmi *hdmi = to_rk3066_hdmi(connector);
+ struct rk3066_hdmi *hdmi = connector_to_rk3066_hdmi(connector);
struct edid *edid;
int ret = 0;
@@ -472,7 +483,6 @@ static int rk3066_hdmi_connector_get_modes(struct drm_connector *connector)
edid = drm_get_edid(connector, hdmi->ddc);
if (edid) {
- hdmi->hdmi_data.sink_is_hdmi = drm_detect_hdmi_monitor(edid);
drm_connector_update_edid_property(connector, edid);
ret = drm_add_edid_modes(connector, edid);
kfree(edid);
@@ -496,9 +506,9 @@ rk3066_hdmi_connector_mode_valid(struct drm_connector *connector,
static struct drm_encoder *
rk3066_hdmi_connector_best_encoder(struct drm_connector *connector)
{
- struct rk3066_hdmi *hdmi = to_rk3066_hdmi(connector);
+ struct rk3066_hdmi *hdmi = connector_to_rk3066_hdmi(connector);
- return &hdmi->encoder;
+ return &hdmi->encoder.encoder;
}
static int
@@ -538,7 +548,7 @@ struct drm_connector_helper_funcs rk3066_hdmi_connector_helper_funcs = {
static int
rk3066_hdmi_register(struct drm_device *drm, struct rk3066_hdmi *hdmi)
{
- struct drm_encoder *encoder = &hdmi->encoder;
+ struct drm_encoder *encoder = &hdmi->encoder.encoder;
struct device *dev = hdmi->dev;
encoder->possible_crtcs =
@@ -816,7 +826,7 @@ static int rk3066_hdmi_bind(struct device *dev, struct device *master,
err_cleanup_hdmi:
hdmi->connector.funcs->destroy(&hdmi->connector);
- hdmi->encoder.funcs->destroy(&hdmi->encoder);
+ hdmi->encoder.encoder.funcs->destroy(&hdmi->encoder.encoder);
err_disable_i2c:
i2c_put_adapter(hdmi->ddc);
err_disable_hclk:
@@ -831,7 +841,7 @@ static void rk3066_hdmi_unbind(struct device *dev, struct device *master,
struct rk3066_hdmi *hdmi = dev_get_drvdata(dev);
hdmi->connector.funcs->destroy(&hdmi->connector);
- hdmi->encoder.funcs->destroy(&hdmi->encoder);
+ hdmi->encoder.encoder.funcs->destroy(&hdmi->encoder.encoder);
i2c_put_adapter(hdmi->ddc);
clk_disable_unprepare(hdmi->hclk);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
index 4eaeb430c83a..0dc09d92d92d 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
@@ -7,7 +7,6 @@
*/
#include <linux/dma-mapping.h>
-#include <linux/dma-iommu.h>
#include <linux/pm_runtime.h>
#include <linux/module.h>
#include <linux/of_graph.h>
@@ -34,7 +33,6 @@
#define DRIVER_MAJOR 1
#define DRIVER_MINOR 0
-static bool is_support_iommu = true;
static const struct drm_driver rockchip_drm_driver;
/*
@@ -48,7 +46,7 @@ int rockchip_drm_dma_attach_device(struct drm_device *drm_dev,
struct rockchip_drm_private *private = drm_dev->dev_private;
int ret;
- if (!is_support_iommu)
+ if (!private->domain)
return 0;
ret = iommu_attach_device(private->domain, dev);
@@ -64,12 +62,22 @@ void rockchip_drm_dma_detach_device(struct drm_device *drm_dev,
struct device *dev)
{
struct rockchip_drm_private *private = drm_dev->dev_private;
- struct iommu_domain *domain = private->domain;
- if (!is_support_iommu)
+ if (!private->domain)
return;
- iommu_detach_device(domain, dev);
+ iommu_detach_device(private->domain, dev);
+}
+
+void rockchip_drm_dma_init_device(struct drm_device *drm_dev,
+ struct device *dev)
+{
+ struct rockchip_drm_private *private = drm_dev->dev_private;
+
+ if (!device_iommu_mapped(dev))
+ private->iommu_dev = ERR_PTR(-ENODEV);
+ else if (!private->iommu_dev)
+ private->iommu_dev = dev;
}
static int rockchip_drm_init_iommu(struct drm_device *drm_dev)
@@ -78,10 +86,10 @@ static int rockchip_drm_init_iommu(struct drm_device *drm_dev)
struct iommu_domain_geometry *geometry;
u64 start, end;
- if (!is_support_iommu)
+ if (IS_ERR_OR_NULL(private->iommu_dev))
return 0;
- private->domain = iommu_domain_alloc(&platform_bus_type);
+ private->domain = iommu_domain_alloc(private->iommu_dev->bus);
if (!private->domain)
return -ENOMEM;
@@ -101,7 +109,7 @@ static void rockchip_iommu_cleanup(struct drm_device *drm_dev)
{
struct rockchip_drm_private *private = drm_dev->dev_private;
- if (!is_support_iommu)
+ if (!private->domain)
return;
drm_mm_takedown(&private->mm);
@@ -137,25 +145,25 @@ static int rockchip_drm_bind(struct device *dev)
drm_dev->dev_private = private;
- ret = rockchip_drm_init_iommu(drm_dev);
- if (ret)
- goto err_free;
-
ret = drmm_mode_config_init(drm_dev);
if (ret)
- goto err_iommu_cleanup;
+ goto err_free;
rockchip_drm_mode_config_init(drm_dev);
/* Try to bind all sub drivers. */
ret = component_bind_all(dev, drm_dev);
if (ret)
- goto err_iommu_cleanup;
+ goto err_free;
- ret = drm_vblank_init(drm_dev, drm_dev->mode_config.num_crtc);
+ ret = rockchip_drm_init_iommu(drm_dev);
if (ret)
goto err_unbind_all;
+ ret = drm_vblank_init(drm_dev, drm_dev->mode_config.num_crtc);
+ if (ret)
+ goto err_iommu_cleanup;
+
drm_mode_config_reset(drm_dev);
/* init kms poll for handling hpd */
@@ -170,10 +178,10 @@ static int rockchip_drm_bind(struct device *dev)
return 0;
err_kms_helper_poll_fini:
drm_kms_helper_poll_fini(drm_dev);
-err_unbind_all:
- component_unbind_all(dev, drm_dev);
err_iommu_cleanup:
rockchip_iommu_cleanup(drm_dev);
+err_unbind_all:
+ component_unbind_all(dev, drm_dev);
err_free:
drm_dev_put(drm_dev);
return ret;
@@ -237,6 +245,39 @@ static struct platform_driver *rockchip_sub_drivers[MAX_ROCKCHIP_SUB_DRIVERS];
static int num_rockchip_sub_drivers;
/*
+ * Get the endpoint id of the remote endpoint of the given encoder. This
+ * information is used by the VOP2 driver to identify the encoder.
+ *
+ * @rkencoder: The encoder to get the remote endpoint id from
+ * @np: The encoder device node
+ * @port: The number of the port leading to the VOP2
+ * @reg: The endpoint number leading to the VOP2
+ */
+int rockchip_drm_encoder_set_crtc_endpoint_id(struct rockchip_encoder *rkencoder,
+ struct device_node *np, int port, int reg)
+{
+ struct of_endpoint ep;
+ struct device_node *en, *ren;
+ int ret;
+
+ en = of_graph_get_endpoint_by_regs(np, port, reg);
+ if (!en)
+ return -ENOENT;
+
+ ren = of_graph_get_remote_endpoint(en);
+ if (!ren)
+ return -ENOENT;
+
+ ret = of_graph_parse_endpoint(ren, &ep);
+ if (ret)
+ return ret;
+
+ rkencoder->crtc_endpoint_id = ep.id;
+
+ return 0;
+}
+
+/*
* Check if a vop endpoint is leading to a rockchip subdriver or bridge.
* Should be called from the component bind stage of the drivers
* to ensure that all subdrivers are probed.
@@ -342,8 +383,6 @@ static int rockchip_drm_platform_of_probe(struct device *dev)
return -ENODEV;
for (i = 0;; i++) {
- struct device_node *iommu;
-
port = of_parse_phandle(np, "ports", i);
if (!port)
break;
@@ -353,21 +392,7 @@ static int rockchip_drm_platform_of_probe(struct device *dev)
continue;
}
- iommu = of_parse_phandle(port->parent, "iommus", 0);
- if (!iommu || !of_device_is_available(iommu)) {
- DRM_DEV_DEBUG(dev,
- "no iommu attached for %pOF, using non-iommu buffers\n",
- port->parent);
- /*
- * if there is a crtc not support iommu, force set all
- * crtc use non-iommu buffer.
- */
- is_support_iommu = false;
- }
-
found = true;
-
- of_node_put(iommu);
of_node_put(port);
}
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
index 143a48330f84..a27ab928e1d2 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -44,16 +44,25 @@ struct rockchip_crtc_state {
*/
struct rockchip_drm_private {
struct iommu_domain *domain;
+ struct device *iommu_dev;
struct mutex mm_lock;
struct drm_mm mm;
};
+struct rockchip_encoder {
+ int crtc_endpoint_id;
+ struct drm_encoder encoder;
+};
+
int rockchip_drm_dma_attach_device(struct drm_device *drm_dev,
struct device *dev);
void rockchip_drm_dma_detach_device(struct drm_device *drm_dev,
struct device *dev);
+void rockchip_drm_dma_init_device(struct drm_device *drm_dev,
+ struct device *dev);
int rockchip_drm_wait_vact_end(struct drm_crtc *crtc, unsigned int mstimeout);
-
+int rockchip_drm_encoder_set_crtc_endpoint_id(struct rockchip_encoder *rencoder,
+ struct device_node *np, int port, int reg);
int rockchip_drm_endpoint_is_subdriver(struct device_node *ep);
extern struct platform_driver cdn_dp_driver;
extern struct platform_driver dw_hdmi_rockchip_pltfm_driver;
@@ -63,4 +72,10 @@ extern struct platform_driver rockchip_dp_driver;
extern struct platform_driver rockchip_lvds_driver;
extern struct platform_driver vop_platform_driver;
extern struct platform_driver rk3066_hdmi_driver;
+
+static inline struct rockchip_encoder *to_rockchip_encoder(struct drm_encoder *encoder)
+{
+ return container_of(encoder, struct rockchip_encoder, encoder);
+}
+
#endif /* _ROCKCHIP_DRM_DRV_H_ */
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index 3e8d9e2d1b67..74562d40f639 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -262,6 +262,18 @@ static bool has_rb_swapped(uint32_t format)
}
}
+static bool has_uv_swapped(uint32_t format)
+{
+ switch (format) {
+ case DRM_FORMAT_NV21:
+ case DRM_FORMAT_NV61:
+ case DRM_FORMAT_NV42:
+ return true;
+ default:
+ return false;
+ }
+}
+
static enum vop_data_format vop_convert_format(uint32_t format)
{
switch (format) {
@@ -277,10 +289,13 @@ static enum vop_data_format vop_convert_format(uint32_t format)
case DRM_FORMAT_BGR565:
return VOP_FMT_RGB565;
case DRM_FORMAT_NV12:
+ case DRM_FORMAT_NV21:
return VOP_FMT_YUV420SP;
case DRM_FORMAT_NV16:
+ case DRM_FORMAT_NV61:
return VOP_FMT_YUV422SP;
case DRM_FORMAT_NV24:
+ case DRM_FORMAT_NV42:
return VOP_FMT_YUV444SP;
default:
DRM_ERROR("unsupported format[%08x]\n", format);
@@ -899,7 +914,7 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
unsigned long offset;
dma_addr_t dma_addr;
uint32_t val;
- bool rb_swap;
+ bool rb_swap, uv_swap;
int win_index = VOP_WIN_TO_INDEX(vop_win);
int format;
int is_yuv = fb->format->is_yuv;
@@ -988,6 +1003,9 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
y2r_coefficients[i],
bt601_yuv2rgb[i]);
}
+
+ uv_swap = has_uv_swapped(fb->format->format);
+ VOP_WIN_SET(vop, win, uv_swap, uv_swap);
}
if (win->phy->scl)
@@ -2118,10 +2136,10 @@ static int vop_bind(struct device *dev, struct device *master, void *data)
vop_win_init(vop);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- vop->len = resource_size(res);
vop->regs = devm_ioremap_resource(dev, res);
if (IS_ERR(vop->regs))
return PTR_ERR(vop->regs);
+ vop->len = resource_size(res);
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (res) {
@@ -2175,6 +2193,8 @@ static int vop_bind(struct device *dev, struct device *master, void *data)
}
}
+ rockchip_drm_dma_init_device(drm_dev, dev);
+
return 0;
err_disable_pm_runtime:
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
index 857d97cdc67c..3aa95fdd427d 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
@@ -166,6 +166,7 @@ struct vop_win_phy {
struct vop_reg gate;
struct vop_reg format;
struct vop_reg rb_swap;
+ struct vop_reg uv_swap;
struct vop_reg act_info;
struct vop_reg dsp_info;
struct vop_reg dsp_st;
diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.c b/drivers/gpu/drm/rockchip/rockchip_lvds.c
index 997b7d46a2d1..5a284332ec49 100644
--- a/drivers/gpu/drm/rockchip/rockchip_lvds.c
+++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c
@@ -36,12 +36,6 @@
struct rockchip_lvds;
-#define connector_to_lvds(c) \
- container_of(c, struct rockchip_lvds, connector)
-
-#define encoder_to_lvds(c) \
- container_of(c, struct rockchip_lvds, encoder)
-
/**
* struct rockchip_lvds_soc_data - rockchip lvds Soc private data
* @probe: LVDS platform probe function
@@ -65,10 +59,22 @@ struct rockchip_lvds {
struct drm_panel *panel;
struct drm_bridge *bridge;
struct drm_connector connector;
- struct drm_encoder encoder;
+ struct rockchip_encoder encoder;
struct dev_pin_info *pins;
};
+static inline struct rockchip_lvds *connector_to_lvds(struct drm_connector *connector)
+{
+ return container_of(connector, struct rockchip_lvds, connector);
+}
+
+static inline struct rockchip_lvds *encoder_to_lvds(struct drm_encoder *encoder)
+{
+ struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder);
+
+ return container_of(rkencoder, struct rockchip_lvds, encoder);
+}
+
static inline void rk3288_writel(struct rockchip_lvds *lvds, u32 offset,
u32 val)
{
@@ -599,7 +605,7 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master,
goto err_put_remote;
}
- encoder = &lvds->encoder;
+ encoder = &lvds->encoder.encoder;
encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev,
dev->of_node);
@@ -674,10 +680,10 @@ static void rockchip_lvds_unbind(struct device *dev, struct device *master,
const struct drm_encoder_helper_funcs *encoder_funcs;
encoder_funcs = lvds->soc_data->helper_funcs;
- encoder_funcs->disable(&lvds->encoder);
+ encoder_funcs->disable(&lvds->encoder.encoder);
pm_runtime_disable(dev);
drm_connector_cleanup(&lvds->connector);
- drm_encoder_cleanup(&lvds->encoder);
+ drm_encoder_cleanup(&lvds->encoder.encoder);
}
static const struct component_ops rockchip_lvds_component_ops = {
diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
index 798b542e5916..d03dd0402923 100644
--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
+++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
@@ -46,8 +46,11 @@ static const uint32_t formats_win_full[] = {
DRM_FORMAT_RGB565,
DRM_FORMAT_BGR565,
DRM_FORMAT_NV12,
+ DRM_FORMAT_NV21,
DRM_FORMAT_NV16,
+ DRM_FORMAT_NV61,
DRM_FORMAT_NV24,
+ DRM_FORMAT_NV42,
};
static const uint64_t format_modifiers_win_full[] = {
@@ -272,6 +275,7 @@ static const struct vop_win_phy px30_win0_data = {
.enable = VOP_REG(PX30_WIN0_CTRL0, 0x1, 0),
.format = VOP_REG(PX30_WIN0_CTRL0, 0x7, 1),
.rb_swap = VOP_REG(PX30_WIN0_CTRL0, 0x1, 12),
+ .uv_swap = VOP_REG(PX30_WIN0_CTRL0, 0x1, 15),
.act_info = VOP_REG(PX30_WIN0_ACT_INFO, 0xffffffff, 0),
.dsp_info = VOP_REG(PX30_WIN0_DSP_INFO, 0xffffffff, 0),
.dsp_st = VOP_REG(PX30_WIN0_DSP_ST, 0xffffffff, 0),
@@ -291,6 +295,7 @@ static const struct vop_win_phy px30_win1_data = {
.enable = VOP_REG(PX30_WIN1_CTRL0, 0x1, 0),
.format = VOP_REG(PX30_WIN1_CTRL0, 0x7, 4),
.rb_swap = VOP_REG(PX30_WIN1_CTRL0, 0x1, 12),
+ .uv_swap = VOP_REG(PX30_WIN1_CTRL0, 0x1, 15),
.dsp_info = VOP_REG(PX30_WIN1_DSP_INFO, 0xffffffff, 0),
.dsp_st = VOP_REG(PX30_WIN1_DSP_ST, 0xffffffff, 0),
.yrgb_mst = VOP_REG(PX30_WIN1_MST, 0xffffffff, 0),
@@ -368,6 +373,7 @@ static const struct vop_win_phy rk3066_win0_data = {
.enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 0),
.format = VOP_REG(RK3066_SYS_CTRL1, 0x7, 4),
.rb_swap = VOP_REG(RK3066_SYS_CTRL1, 0x1, 19),
+ .uv_swap = VOP_REG(RK3066_SYS_CTRL1, 0x1, 22),
.act_info = VOP_REG(RK3066_WIN0_ACT_INFO, 0x1fff1fff, 0),
.dsp_info = VOP_REG(RK3066_WIN0_DSP_INFO, 0x0fff0fff, 0),
.dsp_st = VOP_REG(RK3066_WIN0_DSP_ST, 0x1fff1fff, 0),
@@ -386,6 +392,7 @@ static const struct vop_win_phy rk3066_win1_data = {
.enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 1),
.format = VOP_REG(RK3066_SYS_CTRL1, 0x7, 7),
.rb_swap = VOP_REG(RK3066_SYS_CTRL1, 0x1, 23),
+ .uv_swap = VOP_REG(RK3066_SYS_CTRL1, 0x1, 26),
.act_info = VOP_REG(RK3066_WIN1_ACT_INFO, 0x1fff1fff, 0),
.dsp_info = VOP_REG(RK3066_WIN1_DSP_INFO, 0x0fff0fff, 0),
.dsp_st = VOP_REG(RK3066_WIN1_DSP_ST, 0x1fff1fff, 0),
@@ -489,6 +496,7 @@ static const struct vop_win_phy rk3188_win0_data = {
.enable = VOP_REG(RK3188_SYS_CTRL, 0x1, 0),
.format = VOP_REG(RK3188_SYS_CTRL, 0x7, 3),
.rb_swap = VOP_REG(RK3188_SYS_CTRL, 0x1, 15),
+ .uv_swap = VOP_REG(RK3188_SYS_CTRL, 0x1, 18),
.act_info = VOP_REG(RK3188_WIN0_ACT_INFO, 0x1fff1fff, 0),
.dsp_info = VOP_REG(RK3188_WIN0_DSP_INFO, 0x0fff0fff, 0),
.dsp_st = VOP_REG(RK3188_WIN0_DSP_ST, 0x1fff1fff, 0),
@@ -619,6 +627,7 @@ static const struct vop_win_phy rk3288_win01_data = {
.enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0),
.format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1),
.rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12),
+ .uv_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 15),
.act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0),
.dsp_info = VOP_REG(RK3288_WIN0_DSP_INFO, 0x0fff0fff, 0),
.dsp_st = VOP_REG(RK3288_WIN0_DSP_ST, 0x1fff1fff, 0),
@@ -753,6 +762,7 @@ static const struct vop_win_phy rk3368_win01_data = {
.enable = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 0),
.format = VOP_REG(RK3368_WIN0_CTRL0, 0x7, 1),
.rb_swap = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 12),
+ .uv_swap = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 15),
.x_mir_en = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 21),
.y_mir_en = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 22),
.act_info = VOP_REG(RK3368_WIN0_ACT_INFO, 0x1fff1fff, 0),
@@ -902,6 +912,7 @@ static const struct vop_win_phy rk3399_win01_data = {
.enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0),
.format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1),
.rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12),
+ .uv_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 15),
.x_mir_en = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 21),
.y_mir_en = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 22),
.act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0),
diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
index 527c7b2474da..b4dfa166eccd 100644
--- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
+++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
@@ -1193,8 +1193,8 @@ err_remove_dsi_host:
err_unprotect_clk:
clk_rate_exclusive_put(dsi->mod_clk);
err_attach_clk:
- if (!IS_ERR(dsi->bus_clk))
- regmap_mmio_detach_clk(dsi->regs);
+ regmap_mmio_detach_clk(dsi->regs);
+
return ret;
}
@@ -1207,8 +1207,7 @@ static int sun6i_dsi_remove(struct platform_device *pdev)
mipi_dsi_host_unregister(&dsi->host);
clk_rate_exclusive_put(dsi->mod_clk);
- if (!IS_ERR(dsi->bus_clk))
- regmap_mmio_detach_clk(dsi->regs);
+ regmap_mmio_detach_clk(dsi->regs);
return 0;
}
diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c
index e451cc5bcfac..49c0f2ac868b 100644
--- a/drivers/gpu/drm/vc4/vc4_bo.c
+++ b/drivers/gpu/drm/vc4/vc4_bo.c
@@ -738,19 +738,13 @@ static const struct drm_gem_object_funcs vc4_gem_object_funcs = {
static int vc4_grab_bin_bo(struct vc4_dev *vc4, struct vc4_file *vc4file)
{
- int ret;
-
if (!vc4->v3d)
return -ENODEV;
if (vc4file->bin_bo_used)
return 0;
- ret = vc4_v3d_bin_bo_get(vc4, &vc4file->bin_bo_used);
- if (ret)
- return ret;
-
- return 0;
+ return vc4_v3d_bin_bo_get(vc4, &vc4file->bin_bo_used);
}
int vc4_create_bo_ioctl(struct drm_device *dev, void *data,
diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
index 920a9eefe426..b3438f4a81ce 100644
--- a/drivers/gpu/drm/vc4/vc4_plane.c
+++ b/drivers/gpu/drm/vc4/vc4_plane.c
@@ -1350,7 +1350,6 @@ static int vc4_prepare_fb(struct drm_plane *plane,
struct drm_plane_state *state)
{
struct vc4_bo *bo;
- int ret;
if (!state->fb)
return 0;
@@ -1362,11 +1361,7 @@ static int vc4_prepare_fb(struct drm_plane *plane,
if (plane->state->fb == state->fb)
return 0;
- ret = vc4_bo_inc_usecnt(bo);
- if (ret)
- return ret;
-
- return 0;
+ return vc4_bo_inc_usecnt(bo);
}
static void vc4_cleanup_fb(struct drm_plane *plane,