Unverified Commit ba8c0fae authored by Maxime Ripard's avatar Maxime Ripard
Browse files

drm/vc4: hdmi: Enable 10/12 bpc output



The BCM2711 supports higher bpc count than just 8, so let's support it in
our driver.

Signed-off-by: default avatarMaxime Ripard <maxime@cerno.tech>
Reviewed-by: default avatarDave Stevenson <dave.stevenson@raspberrypi.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20201215154243.540115-10-maxime@cerno.tech
parent 24169a2b
Loading
Loading
Loading
Loading
+69 −1
Original line number Diff line number Diff line
@@ -76,6 +76,17 @@
#define VC5_HDMI_VERTB_VSPO_SHIFT		16
#define VC5_HDMI_VERTB_VSPO_MASK		VC4_MASK(29, 16)

#define VC5_HDMI_DEEP_COLOR_CONFIG_1_INIT_PACK_PHASE_SHIFT	8
#define VC5_HDMI_DEEP_COLOR_CONFIG_1_INIT_PACK_PHASE_MASK	VC4_MASK(10, 8)

#define VC5_HDMI_DEEP_COLOR_CONFIG_1_COLOR_DEPTH_SHIFT		0
#define VC5_HDMI_DEEP_COLOR_CONFIG_1_COLOR_DEPTH_MASK		VC4_MASK(3, 0)

#define VC5_HDMI_GCP_CONFIG_GCP_ENABLE		BIT(31)

#define VC5_HDMI_GCP_WORD_1_GCP_SUBPACKET_BYTE_1_SHIFT	8
#define VC5_HDMI_GCP_WORD_1_GCP_SUBPACKET_BYTE_1_MASK	VC4_MASK(15, 8)

# define VC4_HD_M_SW_RST			BIT(2)
# define VC4_HD_M_ENABLE			BIT(0)

@@ -186,6 +197,8 @@ static void vc4_hdmi_connector_reset(struct drm_connector *connector)
	if (!new_state)
		return;

	new_state->base.max_bpc = 8;
	new_state->base.max_requested_bpc = 8;
	drm_atomic_helper_connector_tv_reset(connector);
}

@@ -232,12 +245,20 @@ static int vc4_hdmi_connector_init(struct drm_device *dev,
				    vc4_hdmi->ddc);
	drm_connector_helper_add(connector, &vc4_hdmi_connector_helper_funcs);

	/*
	 * Some of the properties below require access to state, like bpc.
	 * Allocate some default initial connector state with our reset helper.
	 */
	if (connector->funcs->reset)
		connector->funcs->reset(connector);

	/* Create and attach TV margin props to this connector. */
	ret = drm_mode_create_tv_margin_properties(dev);
	if (ret)
		return ret;

	drm_connector_attach_tv_margin_properties(connector);
	drm_connector_attach_max_bpc_property(connector, 8, 12);

	connector->polled = (DRM_CONNECTOR_POLL_CONNECT |
			     DRM_CONNECTOR_POLL_DISCONNECT);
@@ -506,6 +527,7 @@ static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable)
}

static void vc4_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
				 struct drm_connector_state *state,
				 struct drm_display_mode *mode)
{
	bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC;
@@ -549,7 +571,9 @@ static void vc4_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
	HDMI_WRITE(HDMI_VERTB0, vertb_even);
	HDMI_WRITE(HDMI_VERTB1, vertb);
}

static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
				 struct drm_connector_state *state,
				 struct drm_display_mode *mode)
{
	bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC;
@@ -569,6 +593,9 @@ static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
					mode->crtc_vsync_end -
					interlaced,
					VC4_HDMI_VERTB_VBP));
	unsigned char gcp;
	bool gcp_en;
	u32 reg;

	HDMI_WRITE(HDMI_VEC_INTERFACE_XBAR, 0x354021);
	HDMI_WRITE(HDMI_HORZA,
@@ -594,6 +621,39 @@ static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
	HDMI_WRITE(HDMI_VERTB0, vertb_even);
	HDMI_WRITE(HDMI_VERTB1, vertb);

	switch (state->max_bpc) {
	case 12:
		gcp = 6;
		gcp_en = true;
		break;
	case 10:
		gcp = 5;
		gcp_en = true;
		break;
	case 8:
	default:
		gcp = 4;
		gcp_en = false;
		break;
	}

	reg = HDMI_READ(HDMI_DEEP_COLOR_CONFIG_1);
	reg &= ~(VC5_HDMI_DEEP_COLOR_CONFIG_1_INIT_PACK_PHASE_MASK |
		 VC5_HDMI_DEEP_COLOR_CONFIG_1_COLOR_DEPTH_MASK);
	reg |= VC4_SET_FIELD(2, VC5_HDMI_DEEP_COLOR_CONFIG_1_INIT_PACK_PHASE) |
	       VC4_SET_FIELD(gcp, VC5_HDMI_DEEP_COLOR_CONFIG_1_COLOR_DEPTH);
	HDMI_WRITE(HDMI_DEEP_COLOR_CONFIG_1, reg);

	reg = HDMI_READ(HDMI_GCP_WORD_1);
	reg &= ~VC5_HDMI_GCP_WORD_1_GCP_SUBPACKET_BYTE_1_MASK;
	reg |= VC4_SET_FIELD(gcp, VC5_HDMI_GCP_WORD_1_GCP_SUBPACKET_BYTE_1);
	HDMI_WRITE(HDMI_GCP_WORD_1, reg);

	reg = HDMI_READ(HDMI_GCP_CONFIG);
	reg &= ~VC5_HDMI_GCP_CONFIG_GCP_ENABLE;
	reg |= gcp_en ? VC5_HDMI_GCP_CONFIG_GCP_ENABLE : 0;
	HDMI_WRITE(HDMI_GCP_CONFIG, reg);

	HDMI_WRITE(HDMI_CLOCK_STOP, 0);
}

@@ -731,7 +791,7 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
		   VC4_HDMI_SCHEDULER_CONTROL_IGNORE_VSYNC_PREDICTS);

	if (vc4_hdmi->variant->set_timings)
		vc4_hdmi->variant->set_timings(vc4_hdmi, mode);
		vc4_hdmi->variant->set_timings(vc4_hdmi, conn_state, mode);
}

static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder,
@@ -852,6 +912,14 @@ static int vc4_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
		pixel_rate = mode->clock * 1000;
	}

	if (conn_state->max_bpc == 12) {
		pixel_rate = pixel_rate * 150;
		do_div(pixel_rate, 100);
	} else if (conn_state->max_bpc == 10) {
		pixel_rate = pixel_rate * 125;
		do_div(pixel_rate, 100);
	}

	if (mode->flags & DRM_MODE_FLAG_DBLCLK)
		pixel_rate = pixel_rate * 2;

+1 −0
Original line number Diff line number Diff line
@@ -77,6 +77,7 @@ struct vc4_hdmi_variant {

	/* Callback to configure the video timings in the HDMI block */
	void (*set_timings)(struct vc4_hdmi *vc4_hdmi,
			    struct drm_connector_state *state,
			    struct drm_display_mode *mode);

	/* Callback to initialize the PHY according to the connector state */
+9 −0
Original line number Diff line number Diff line
@@ -59,9 +59,12 @@ enum vc4_hdmi_field {
	 */
	HDMI_CTS_0,
	HDMI_CTS_1,
	HDMI_DEEP_COLOR_CONFIG_1,
	HDMI_DVP_CTL,
	HDMI_FIFO_CTL,
	HDMI_FRAME_COUNT,
	HDMI_GCP_CONFIG,
	HDMI_GCP_WORD_1,
	HDMI_HORZA,
	HDMI_HORZB,
	HDMI_HOTPLUG,
@@ -229,6 +232,9 @@ static const struct vc4_hdmi_register __maybe_unused vc5_hdmi_hdmi0_fields[] = {
	VC4_HDMI_REG(HDMI_VERTB1, 0x0f8),
	VC4_HDMI_REG(HDMI_MAI_CHANNEL_MAP, 0x09c),
	VC4_HDMI_REG(HDMI_MAI_CONFIG, 0x0a0),
	VC4_HDMI_REG(HDMI_DEEP_COLOR_CONFIG_1, 0x170),
	VC4_HDMI_REG(HDMI_GCP_CONFIG, 0x178),
	VC4_HDMI_REG(HDMI_GCP_WORD_1, 0x17c),
	VC4_HDMI_REG(HDMI_HOTPLUG, 0x1a8),

	VC5_DVP_REG(HDMI_CLOCK_STOP, 0x0bc),
@@ -305,6 +311,9 @@ static const struct vc4_hdmi_register __maybe_unused vc5_hdmi_hdmi1_fields[] = {
	VC4_HDMI_REG(HDMI_VERTB1, 0x0f8),
	VC4_HDMI_REG(HDMI_MAI_CHANNEL_MAP, 0x09c),
	VC4_HDMI_REG(HDMI_MAI_CONFIG, 0x0a0),
	VC4_HDMI_REG(HDMI_DEEP_COLOR_CONFIG_1, 0x170),
	VC4_HDMI_REG(HDMI_GCP_CONFIG, 0x178),
	VC4_HDMI_REG(HDMI_GCP_WORD_1, 0x17c),
	VC4_HDMI_REG(HDMI_HOTPLUG, 0x1a8),

	VC5_DVP_REG(HDMI_CLOCK_STOP, 0x0bc),