Skip to content

Commit

Permalink
drm/sun4i: hdmi: Switch to HDMI connector
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Maxime Ripard committed May 28, 2024
1 parent 65548c8 commit ea64761
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 30 deletions.
3 changes: 3 additions & 0 deletions drivers/gpu/drm/sun4i/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
84 changes: 54 additions & 30 deletions drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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;

Expand All @@ -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)
Expand Down Expand Up @@ -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,
Expand All @@ -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,
};
Expand Down Expand Up @@ -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");
Expand Down

0 comments on commit ea64761

Please sign in to comment.