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

drm/sun4i: hdmi: Switch to HDMI connector



The new HDMI connector infrastructure allows to remove some boilerplate,
especially to generate infoframes. Let's switch to it.

Reviewed-by: default avatarJernej Skrabec <jernej.skrabec@gmail.com>
Acked-by: default avatarSui Jingfeng <sui.jingfeng@linux.dev>
Reviewed-by: default avatarAndy Yan <andyshrk@163.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20240527-kms-hdmi-connector-state-v15-29-c5af16c3aae2@kernel.org


Signed-off-by: default avatarMaxime Ripard <mripard@kernel.org>
parent 65548c8f
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -18,6 +18,9 @@ if DRM_SUN4I
config DRM_SUN4I_HDMI
	tristate "Allwinner A10/A10s/A20/A31 HDMI Controller Support"
	depends on ARM || COMPILE_TEST
	select DRM_DISPLAY_HDMI_HELPER
	select DRM_DISPLAY_HDMI_STATE_HELPER
	select DRM_DISPLAY_HELPER
	default DRM_SUN4I
	help
	  Choose this option if you have an Allwinner A10/A10s/A20/A31
+54 −30
Original line number Diff line number Diff line
@@ -26,6 +26,9 @@
#include <drm/drm_probe_helper.h>
#include <drm/drm_simple_kms_helper.h>

#include <drm/display/drm_hdmi_helper.h>
#include <drm/display/drm_hdmi_state_helper.h>

#include "sun4i_backend.h"
#include "sun4i_crtc.h"
#include "sun4i_drv.h"
@@ -37,30 +40,24 @@
#define drm_connector_to_sun4i_hdmi(c)		\
	container_of_const(c, struct sun4i_hdmi, connector)

static int sun4i_hdmi_setup_avi_infoframes(struct sun4i_hdmi *hdmi,
					   struct drm_display_mode *mode)
static int sun4i_hdmi_write_infoframe(struct drm_connector *connector,
				      enum hdmi_infoframe_type type,
				      const u8 *buffer, size_t len)
{
	struct hdmi_avi_infoframe frame;
	u8 buffer[17];
	int i, ret;

	ret = drm_hdmi_avi_infoframe_from_display_mode(&frame,
						       &hdmi->connector, mode);
	if (ret < 0) {
		DRM_ERROR("Failed to get infoframes from mode\n");
		return ret;
	}
	struct sun4i_hdmi *hdmi = drm_connector_to_sun4i_hdmi(connector);
	int i;

	ret = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer));
	if (ret < 0) {
		DRM_ERROR("Failed to pack infoframes\n");
		return ret;
	if (type != HDMI_INFOFRAME_TYPE_AVI) {
		drm_err(connector->dev,
			"Unsupported infoframe type: %u\n", type);
		return 0;
	}

	for (i = 0; i < sizeof(buffer); i++)
	for (i = 0; i < len; i++)
		writeb(buffer[i], hdmi->base + SUN4I_HDMI_AVI_INFOFRAME_REG(i));

	return 0;

}

static void sun4i_hdmi_disable(struct drm_encoder *encoder,
@@ -83,14 +80,18 @@ static void sun4i_hdmi_enable(struct drm_encoder *encoder,
{
	struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
	struct sun4i_hdmi *hdmi = drm_encoder_to_sun4i_hdmi(encoder);
	struct drm_display_info *display = &hdmi->connector.display_info;
	struct drm_connector *connector = &hdmi->connector;
	struct drm_display_info *display = &connector->display_info;
	struct drm_connector_state *conn_state =
		drm_atomic_get_new_connector_state(state, connector);
	unsigned long long tmds_rate = conn_state->hdmi.tmds_char_rate;
	unsigned int x, y;
	u32 val = 0;

	DRM_DEBUG_DRIVER("Enabling the HDMI Output\n");

	clk_set_rate(hdmi->mod_clk, mode->crtc_clock * 1000);
	clk_set_rate(hdmi->tmds_clk, mode->crtc_clock * 1000);
	clk_set_rate(hdmi->mod_clk, tmds_rate);
	clk_set_rate(hdmi->tmds_clk, tmds_rate);

	/* Set input sync enable */
	writel(SUN4I_HDMI_UNKNOWN_INPUT_SYNC,
@@ -143,7 +144,8 @@ static void sun4i_hdmi_enable(struct drm_encoder *encoder,

	clk_prepare_enable(hdmi->tmds_clk);

	sun4i_hdmi_setup_avi_infoframes(hdmi, mode);
	drm_atomic_helper_connector_hdmi_update_infoframes(connector, state);

	val |= SUN4I_HDMI_PKT_CTRL_TYPE(0, SUN4I_HDMI_PKT_AVI);
	val |= SUN4I_HDMI_PKT_CTRL_TYPE(1, SUN4I_HDMI_PKT_END);
	writel(val, hdmi->base + SUN4I_HDMI_PKT_CTRL_REG(0));
@@ -196,7 +198,7 @@ static int sun4i_hdmi_connector_atomic_check(struct drm_connector *connector,
	enum drm_mode_status status;

	status = sun4i_hdmi_connector_clock_valid(connector, mode,
						  mode->clock * 1000);
						  conn_state->hdmi.tmds_char_rate);
	if (status != MODE_OK)
		return -EINVAL;

@@ -207,8 +209,11 @@ static enum drm_mode_status
sun4i_hdmi_connector_mode_valid(struct drm_connector *connector,
				struct drm_display_mode *mode)
{
	return sun4i_hdmi_connector_clock_valid(connector, mode,
						mode->clock * 1000);
	unsigned long long rate =
		drm_connector_hdmi_compute_mode_clock(mode, 8,
						      HDMI_COLORSPACE_RGB);

	return sun4i_hdmi_connector_clock_valid(connector, mode, rate);
}

static int sun4i_hdmi_get_modes(struct drm_connector *connector)
@@ -258,6 +263,11 @@ static struct i2c_adapter *sun4i_hdmi_get_ddc(struct device *dev)
	return ddc;
}

static const struct drm_connector_hdmi_funcs sun4i_hdmi_hdmi_connector_funcs = {
	.tmds_char_rate_valid	= sun4i_hdmi_connector_clock_valid,
	.write_infoframe	= sun4i_hdmi_write_infoframe,
};

static const struct drm_connector_helper_funcs sun4i_hdmi_connector_helper_funcs = {
	.atomic_check	= sun4i_hdmi_connector_atomic_check,
	.mode_valid	= sun4i_hdmi_connector_mode_valid,
@@ -279,11 +289,16 @@ sun4i_hdmi_connector_detect(struct drm_connector *connector, bool force)
	return connector_status_connected;
}

static void sun4i_hdmi_connector_reset(struct drm_connector *connector)
{
	drm_atomic_helper_connector_reset(connector);
	__drm_atomic_helper_connector_hdmi_reset(connector, connector->state);
}

static const struct drm_connector_funcs sun4i_hdmi_connector_funcs = {
	.detect			= sun4i_hdmi_connector_detect,
	.fill_modes		= drm_helper_probe_single_connector_modes,
	.destroy		= drm_connector_cleanup,
	.reset			= drm_atomic_helper_connector_reset,
	.reset			= sun4i_hdmi_connector_reset,
	.atomic_duplicate_state	= drm_atomic_helper_connector_duplicate_state,
	.atomic_destroy_state	= drm_atomic_helper_connector_destroy_state,
};
@@ -642,10 +657,19 @@ static int sun4i_hdmi_bind(struct device *dev, struct device *master,

	drm_connector_helper_add(&hdmi->connector,
				 &sun4i_hdmi_connector_helper_funcs);
	ret = drm_connector_init_with_ddc(drm, &hdmi->connector,
	ret = drmm_connector_hdmi_init(drm, &hdmi->connector,
				       /*
					* NOTE: Those are likely to be
					* wrong, but I couldn't find the
					* actual ones in the BSP.
					*/
				       "AW", "HDMI",
				       &sun4i_hdmi_connector_funcs,
				       &sun4i_hdmi_hdmi_connector_funcs,
				       DRM_MODE_CONNECTOR_HDMIA,
					  hdmi->ddc_i2c);
				       hdmi->ddc_i2c,
				       BIT(HDMI_COLORSPACE_RGB),
				       8);
	if (ret) {
		dev_err(dev,
			"Couldn't initialise the HDMI connector\n");