diff options
Diffstat (limited to 'drivers')
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 = &ire_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, |