1

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: Jernej Skrabec <jernej.skrabec@gmail.com>
Acked-by: Sui Jingfeng <sui.jingfeng@linux.dev>
Reviewed-by: Andy Yan <andyshrk@163.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20240527-kms-hdmi-connector-state-v15-29-c5af16c3aae2@kernel.org
Signed-off-by: Maxime Ripard <mripard@kernel.org>
This commit is contained in:
Maxime Ripard 2024-05-27 15:58:18 +02:00
parent 65548c8ff0
commit ea64761a54
No known key found for this signature in database
GPG Key ID: 275FCE19A23DBE76
2 changed files with 57 additions and 30 deletions

View File

@ -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

View File

@ -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;
struct sun4i_hdmi *hdmi = drm_connector_to_sun4i_hdmi(connector);
int i;
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;
if (type != HDMI_INFOFRAME_TYPE_AVI) {
drm_err(connector->dev,
"Unsupported infoframe type: %u\n", type);
return 0;
}
ret = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer));
if (ret < 0) {
DRM_ERROR("Failed to pack infoframes\n");
return ret;
}
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,
&sun4i_hdmi_connector_funcs,
DRM_MODE_CONNECTOR_HDMIA,
hdmi->ddc_i2c);
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,
BIT(HDMI_COLORSPACE_RGB),
8);
if (ret) {
dev_err(dev,
"Couldn't initialise the HDMI connector\n");