From 867633919b4c29eb75abf3b61099d59b946c6318 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Fri, 20 Dec 2019 08:12:42 +0000
Subject: [PATCH 20/59] WIP/1000: drm/rockchip: dw_hdmi: add 10-bit rgb bus
 format

---
 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 42 +++++++++++++++++++++
 drivers/gpu/drm/rockchip/rockchip_drm_drv.h |  1 +
 2 files changed, 43 insertions(+)

diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index a50218412fb0..8134add505e0 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -85,6 +85,8 @@ struct rockchip_hdmi {
 	struct phy *phy;
 };
 
+#define to_crtc_state(x)	container_of(x, struct drm_crtc_state, x)
+
 static struct rockchip_hdmi *to_rockchip_hdmi(struct drm_bridge *bridge)
 {
 	return container_of(bridge, struct rockchip_hdmi, bridge);
@@ -349,6 +351,11 @@ dw_hdmi_rockchip_bridge_mode_set(struct drm_bridge *bridge,
 				 const struct drm_display_mode *adjusted_mode)
 {
 	struct rockchip_hdmi *hdmi = to_rockchip_hdmi(bridge);
+	struct drm_crtc_state *crtc_state = to_crtc_state(adjusted_mode);
+	struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
+
+	if (hdmi->phy)
+		phy_set_bus_width(hdmi->phy, s->bus_width);
 
 	clk_set_rate(hdmi->ref_clk, adjusted_mode->clock * 1000);
 }
@@ -388,6 +395,17 @@ static bool is_rgb(u32 format)
 {
 	switch (format) {
 	case MEDIA_BUS_FMT_RGB888_1X24:
+	case MEDIA_BUS_FMT_RGB101010_1X30:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool is_10bit(u32 format)
+{
+	switch (format) {
+	case MEDIA_BUS_FMT_RGB101010_1X30:
 		return true;
 	default:
 		return false;
@@ -401,9 +419,24 @@ dw_hdmi_rockchip_bridge_atomic_check(struct drm_bridge *bridge,
 				     struct drm_connector_state *conn_state)
 {
 	struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
+	struct drm_atomic_state *state = bridge_state->base.state;
+	struct drm_crtc_state *old_crtc_state;
+	struct rockchip_crtc_state *old_state;
+	u32 format = bridge_state->output_bus_cfg.format;
 
 	s->output_mode = ROCKCHIP_OUT_MODE_AAAA;
 	s->output_type = DRM_MODE_CONNECTOR_HDMIA;
+	s->output_bpc = 10;
+	s->bus_format = format;
+	s->bus_width = is_10bit(format) ? 10 : 8;
+
+	old_crtc_state = drm_atomic_get_old_crtc_state(state, conn_state->crtc);
+	if (old_crtc_state && !crtc_state->mode_changed) {
+		old_state = to_rockchip_crtc_state(old_crtc_state);
+		if (s->bus_format != old_state->bus_format ||
+		    s->bus_width != old_state->bus_width)
+			crtc_state->mode_changed = true;
+	}
 
 	return 0;
 }
@@ -415,10 +448,19 @@ static u32 *dw_hdmi_rockchip_get_input_bus_fmts(struct drm_bridge *bridge,
 					u32 output_fmt,
 					unsigned int *num_input_fmts)
 {
+	struct rockchip_hdmi *hdmi = to_rockchip_hdmi(bridge);
+	struct drm_encoder *encoder = bridge->encoder;
 	u32 *input_fmt;
+	bool has_10bit = true;
 
 	*num_input_fmts = 0;
 
+	if (drm_of_encoder_active_endpoint_id(hdmi->dev->of_node, encoder))
+		has_10bit = false;
+
+	if (!has_10bit && is_10bit(output_fmt))
+		return NULL;
+
 	if (!is_rgb(output_fmt))
 		return NULL;
 
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
index c183e82a42a5..98040929412c 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -53,6 +53,7 @@ struct rockchip_crtc_state {
 	u32 bus_format;
 	u32 bus_flags;
 	int color_space;
+	int bus_width;
 };
 #define to_rockchip_crtc_state(s) \
 		container_of(s, struct rockchip_crtc_state, base)
-- 
2.34.1

