Based on: *2dc8224e37/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c* https://lore.kernel.org/all/20241016-b4-rk3588-bridge-upstream-v10-1-87ef92a6d14e@collabora.com/ *a52dffaa46/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c*a52dffaa46/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c*a52dffaa46/drivers/gpu/drm/rockchip/rockchip_vop2_reg.cSigned-off-by: Liangbin Lian <jjm2473@gmail.com>
259 lines
7.7 KiB
Diff
259 lines
7.7 KiB
Diff
--- a/drivers/gpu/drm/bridge/synopsys/Kconfig
|
|
+++ b/drivers/gpu/drm/bridge/synopsys/Kconfig
|
|
@@ -46,6 +46,14 @@ config DRM_DW_HDMI_CEC
|
|
Support the CE interface which is part of the Synopsys
|
|
Designware HDMI block.
|
|
|
|
+config DRM_DW_HDMI_QP
|
|
+ tristate
|
|
+ select DRM_DISPLAY_HDMI_HELPER
|
|
+ select DRM_DISPLAY_HDMI_STATE_HELPER
|
|
+ select DRM_DISPLAY_HELPER
|
|
+ select DRM_KMS_HELPER
|
|
+ select REGMAP_MMIO
|
|
+
|
|
config DRM_DW_MIPI_DSI
|
|
tristate
|
|
select DRM_KMS_HELPER
|
|
--- a/drivers/gpu/drm/bridge/synopsys/Makefile
|
|
+++ b/drivers/gpu/drm/bridge/synopsys/Makefile
|
|
@@ -5,4 +5,6 @@ obj-$(CONFIG_DRM_DW_HDMI_GP_AUDIO) += dw
|
|
obj-$(CONFIG_DRM_DW_HDMI_I2S_AUDIO) += dw-hdmi-i2s-audio.o
|
|
obj-$(CONFIG_DRM_DW_HDMI_CEC) += dw-hdmi-cec.o
|
|
|
|
+obj-$(CONFIG_DRM_DW_HDMI_QP) += dw-hdmi-qp.o
|
|
+
|
|
obj-$(CONFIG_DRM_DW_MIPI_DSI) += dw-mipi-dsi.o
|
|
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
|
|
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
|
|
@@ -17,7 +17,7 @@
|
|
|
|
#include <drm/bridge/dw_hdmi_qp.h>
|
|
#include <drm/display/drm_hdmi_helper.h>
|
|
-#include <drm/display/drm_hdmi_state_helper.h>
|
|
+//#include <drm/display/drm_hdmi_state_helper.h>
|
|
#include <drm/drm_atomic.h>
|
|
#include <drm/drm_atomic_helper.h>
|
|
#include <drm/drm_bridge.h>
|
|
@@ -292,89 +292,18 @@ static struct i2c_adapter *dw_hdmi_qp_i2
|
|
return adap;
|
|
}
|
|
|
|
-static int dw_hdmi_qp_config_avi_infoframe(struct dw_hdmi_qp *hdmi,
|
|
- const u8 *buffer, size_t len)
|
|
-{
|
|
- u32 val, i, j;
|
|
-
|
|
- if (len != HDMI_INFOFRAME_SIZE(AVI)) {
|
|
- dev_err(hdmi->dev, "failed to configure avi infoframe\n");
|
|
- return -EINVAL;
|
|
- }
|
|
-
|
|
- /*
|
|
- * DW HDMI QP IP uses a different byte format from standard AVI info
|
|
- * frames, though generally the bits are in the correct bytes.
|
|
- */
|
|
- val = buffer[1] << 8 | buffer[2] << 16;
|
|
- dw_hdmi_qp_write(hdmi, val, PKT_AVI_CONTENTS0);
|
|
-
|
|
- for (i = 0; i < 4; i++) {
|
|
- for (j = 0; j < 4; j++) {
|
|
- if (i * 4 + j >= 14)
|
|
- break;
|
|
- if (!j)
|
|
- val = buffer[i * 4 + j + 3];
|
|
- val |= buffer[i * 4 + j + 3] << (8 * j);
|
|
- }
|
|
-
|
|
- dw_hdmi_qp_write(hdmi, val, PKT_AVI_CONTENTS1 + i * 4);
|
|
- }
|
|
-
|
|
- dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_AVI_FIELDRATE, PKTSCHED_PKT_CONFIG1);
|
|
-
|
|
- dw_hdmi_qp_mod(hdmi, PKTSCHED_AVI_TX_EN | PKTSCHED_GCP_TX_EN,
|
|
- PKTSCHED_AVI_TX_EN | PKTSCHED_GCP_TX_EN, PKTSCHED_PKT_EN);
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static int dw_hdmi_qp_config_drm_infoframe(struct dw_hdmi_qp *hdmi,
|
|
- const u8 *buffer, size_t len)
|
|
-{
|
|
- u32 val, i;
|
|
-
|
|
- if (len != HDMI_INFOFRAME_SIZE(DRM)) {
|
|
- dev_err(hdmi->dev, "failed to configure drm infoframe\n");
|
|
- return -EINVAL;
|
|
- }
|
|
-
|
|
- dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_DRMI_TX_EN, PKTSCHED_PKT_EN);
|
|
-
|
|
- val = buffer[1] << 8 | buffer[2] << 16;
|
|
- dw_hdmi_qp_write(hdmi, val, PKT_DRMI_CONTENTS0);
|
|
-
|
|
- for (i = 0; i <= buffer[2]; i++) {
|
|
- if (i % 4 == 0)
|
|
- val = buffer[3 + i];
|
|
- val |= buffer[3 + i] << ((i % 4) * 8);
|
|
-
|
|
- if ((i % 4 == 3) || i == buffer[2])
|
|
- dw_hdmi_qp_write(hdmi, val,
|
|
- PKT_DRMI_CONTENTS1 + ((i / 4) * 4));
|
|
- }
|
|
-
|
|
- dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_DRMI_FIELDRATE, PKTSCHED_PKT_CONFIG1);
|
|
- dw_hdmi_qp_mod(hdmi, PKTSCHED_DRMI_TX_EN, PKTSCHED_DRMI_TX_EN,
|
|
- PKTSCHED_PKT_EN);
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
static int dw_hdmi_qp_bridge_atomic_check(struct drm_bridge *bridge,
|
|
struct drm_bridge_state *bridge_state,
|
|
struct drm_crtc_state *crtc_state,
|
|
struct drm_connector_state *conn_state)
|
|
{
|
|
struct dw_hdmi_qp *hdmi = bridge->driver_private;
|
|
- int ret;
|
|
|
|
- ret = drm_atomic_helper_connector_hdmi_check(conn_state->connector,
|
|
- conn_state->state);
|
|
- if (ret)
|
|
- dev_dbg(hdmi->dev, "%s failed: %d\n", __func__, ret);
|
|
+ dev_dbg(hdmi->dev, "input format 0x%04x, output format 0x%04x\n",
|
|
+ bridge_state->input_bus_cfg.format,
|
|
+ bridge_state->output_bus_cfg.format);
|
|
|
|
- return ret;
|
|
+ return 0;
|
|
}
|
|
|
|
static void dw_hdmi_qp_bridge_atomic_enable(struct drm_bridge *bridge,
|
|
@@ -395,8 +324,7 @@ static void dw_hdmi_qp_bridge_atomic_ena
|
|
return;
|
|
|
|
if (connector->display_info.is_hdmi) {
|
|
- dev_dbg(hdmi->dev, "%s mode=HDMI rate=%llu\n",
|
|
- __func__, conn_state->hdmi.tmds_char_rate);
|
|
+ dev_dbg(hdmi->dev, "%s mode=HDMI\n", __func__);
|
|
op_mode = 0;
|
|
} else {
|
|
dev_dbg(hdmi->dev, "%s mode=DVI\n", __func__);
|
|
@@ -408,7 +336,7 @@ static void dw_hdmi_qp_bridge_atomic_ena
|
|
dw_hdmi_qp_mod(hdmi, HDCP2_BYPASS, HDCP2_BYPASS, HDCP2LOGIC_CONFIG0);
|
|
dw_hdmi_qp_mod(hdmi, op_mode, OPMODE_DVI, LINK_CONFIG0);
|
|
|
|
- drm_atomic_helper_connector_hdmi_update_infoframes(connector, state);
|
|
+ //drm_atomic_helper_connector_hdmi_update_infoframes(connector, state);
|
|
}
|
|
|
|
static void dw_hdmi_qp_bridge_atomic_disable(struct drm_bridge *bridge,
|
|
@@ -441,6 +369,26 @@ dw_hdmi_qp_bridge_edid_read(struct drm_b
|
|
return drm_edid;
|
|
}
|
|
|
|
+
|
|
+static unsigned long long
|
|
+dw_hdmi_encoder_compute_mode_clock(const struct drm_display_mode *mode,
|
|
+ unsigned int bpc,
|
|
+ enum hdmi_colorspace fmt)
|
|
+{
|
|
+ unsigned long long clock = mode->clock * 1000ULL;
|
|
+
|
|
+ if (mode->flags & DRM_MODE_FLAG_DBLCLK)
|
|
+ clock = clock * 2;
|
|
+
|
|
+ if (fmt == HDMI_COLORSPACE_YUV422)
|
|
+ bpc = 8;
|
|
+
|
|
+ clock = clock * bpc;
|
|
+ do_div(clock, 8);
|
|
+
|
|
+ return clock;
|
|
+}
|
|
+
|
|
static enum drm_mode_status
|
|
dw_hdmi_qp_bridge_mode_valid(struct drm_bridge *bridge,
|
|
const struct drm_display_info *info,
|
|
@@ -449,7 +397,7 @@ dw_hdmi_qp_bridge_mode_valid(struct drm_
|
|
struct dw_hdmi_qp *hdmi = bridge->driver_private;
|
|
unsigned long long rate;
|
|
|
|
- rate = drm_hdmi_compute_mode_clock(mode, 8, HDMI_COLORSPACE_RGB);
|
|
+ rate = dw_hdmi_encoder_compute_mode_clock(mode, 8, HDMI_COLORSPACE_RGB);
|
|
if (rate > HDMI14_MAX_TMDSCLK) {
|
|
dev_dbg(hdmi->dev, "Unsupported mode clock: %d\n", mode->clock);
|
|
return MODE_CLOCK_HIGH;
|
|
@@ -458,49 +406,6 @@ dw_hdmi_qp_bridge_mode_valid(struct drm_
|
|
return MODE_OK;
|
|
}
|
|
|
|
-static int dw_hdmi_qp_bridge_clear_infoframe(struct drm_bridge *bridge,
|
|
- enum hdmi_infoframe_type type)
|
|
-{
|
|
- struct dw_hdmi_qp *hdmi = bridge->driver_private;
|
|
-
|
|
- switch (type) {
|
|
- case HDMI_INFOFRAME_TYPE_AVI:
|
|
- dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_AVI_TX_EN | PKTSCHED_GCP_TX_EN,
|
|
- PKTSCHED_PKT_EN);
|
|
- break;
|
|
-
|
|
- case HDMI_INFOFRAME_TYPE_DRM:
|
|
- dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_DRMI_TX_EN, PKTSCHED_PKT_EN);
|
|
- break;
|
|
-
|
|
- default:
|
|
- dev_dbg(hdmi->dev, "Unsupported infoframe type %x\n", type);
|
|
- }
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static int dw_hdmi_qp_bridge_write_infoframe(struct drm_bridge *bridge,
|
|
- enum hdmi_infoframe_type type,
|
|
- const u8 *buffer, size_t len)
|
|
-{
|
|
- struct dw_hdmi_qp *hdmi = bridge->driver_private;
|
|
-
|
|
- dw_hdmi_qp_bridge_clear_infoframe(bridge, type);
|
|
-
|
|
- switch (type) {
|
|
- case HDMI_INFOFRAME_TYPE_AVI:
|
|
- return dw_hdmi_qp_config_avi_infoframe(hdmi, buffer, len);
|
|
-
|
|
- case HDMI_INFOFRAME_TYPE_DRM:
|
|
- return dw_hdmi_qp_config_drm_infoframe(hdmi, buffer, len);
|
|
-
|
|
- default:
|
|
- dev_dbg(hdmi->dev, "Unsupported infoframe type %x\n", type);
|
|
- return 0;
|
|
- }
|
|
-}
|
|
-
|
|
static const struct drm_bridge_funcs dw_hdmi_qp_bridge_funcs = {
|
|
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
|
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
|
@@ -511,8 +416,6 @@ static const struct drm_bridge_funcs dw_
|
|
.detect = dw_hdmi_qp_bridge_detect,
|
|
.edid_read = dw_hdmi_qp_bridge_edid_read,
|
|
.mode_valid = dw_hdmi_qp_bridge_mode_valid,
|
|
- .hdmi_clear_infoframe = dw_hdmi_qp_bridge_clear_infoframe,
|
|
- .hdmi_write_infoframe = dw_hdmi_qp_bridge_write_infoframe,
|
|
};
|
|
|
|
static irqreturn_t dw_hdmi_qp_main_hardirq(int irq, void *dev_id)
|
|
@@ -611,12 +514,9 @@ struct dw_hdmi_qp *dw_hdmi_qp_bind(struc
|
|
hdmi->bridge.funcs = &dw_hdmi_qp_bridge_funcs;
|
|
hdmi->bridge.ops = DRM_BRIDGE_OP_DETECT |
|
|
DRM_BRIDGE_OP_EDID |
|
|
- DRM_BRIDGE_OP_HDMI |
|
|
DRM_BRIDGE_OP_HPD;
|
|
hdmi->bridge.of_node = pdev->dev.of_node;
|
|
hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
|
|
- hdmi->bridge.vendor = "Synopsys";
|
|
- hdmi->bridge.product = "DW HDMI QP TX";
|
|
|
|
hdmi->bridge.ddc = dw_hdmi_qp_i2c_adapter(hdmi);
|
|
if (IS_ERR(hdmi->bridge.ddc))
|