Commit ea64761a authored by Maxime Ripard's avatar Maxime Ripard

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.orgSigned-off-by: default avatarMaxime Ripard <mripard@kernel.org>
parent 65548c8f
...@@ -18,6 +18,9 @@ if DRM_SUN4I ...@@ -18,6 +18,9 @@ if DRM_SUN4I
config DRM_SUN4I_HDMI config DRM_SUN4I_HDMI
tristate "Allwinner A10/A10s/A20/A31 HDMI Controller Support" tristate "Allwinner A10/A10s/A20/A31 HDMI Controller Support"
depends on ARM || COMPILE_TEST depends on ARM || COMPILE_TEST
select DRM_DISPLAY_HDMI_HELPER
select DRM_DISPLAY_HDMI_STATE_HELPER
select DRM_DISPLAY_HELPER
default DRM_SUN4I default DRM_SUN4I
help help
Choose this option if you have an Allwinner A10/A10s/A20/A31 Choose this option if you have an Allwinner A10/A10s/A20/A31
......
...@@ -26,6 +26,9 @@ ...@@ -26,6 +26,9 @@
#include <drm/drm_probe_helper.h> #include <drm/drm_probe_helper.h>
#include <drm/drm_simple_kms_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_backend.h"
#include "sun4i_crtc.h" #include "sun4i_crtc.h"
#include "sun4i_drv.h" #include "sun4i_drv.h"
...@@ -37,30 +40,24 @@ ...@@ -37,30 +40,24 @@
#define drm_connector_to_sun4i_hdmi(c) \ #define drm_connector_to_sun4i_hdmi(c) \
container_of_const(c, struct sun4i_hdmi, connector) container_of_const(c, struct sun4i_hdmi, connector)
static int sun4i_hdmi_setup_avi_infoframes(struct sun4i_hdmi *hdmi, static int sun4i_hdmi_write_infoframe(struct drm_connector *connector,
struct drm_display_mode *mode) enum hdmi_infoframe_type type,
const u8 *buffer, size_t len)
{ {
struct hdmi_avi_infoframe frame; struct sun4i_hdmi *hdmi = drm_connector_to_sun4i_hdmi(connector);
u8 buffer[17]; int i;
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;
}
ret = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer)); if (type != HDMI_INFOFRAME_TYPE_AVI) {
if (ret < 0) { drm_err(connector->dev,
DRM_ERROR("Failed to pack infoframes\n"); "Unsupported infoframe type: %u\n", type);
return ret; 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)); writeb(buffer[i], hdmi->base + SUN4I_HDMI_AVI_INFOFRAME_REG(i));
return 0; return 0;
} }
static void sun4i_hdmi_disable(struct drm_encoder *encoder, static void sun4i_hdmi_disable(struct drm_encoder *encoder,
...@@ -83,14 +80,18 @@ static void sun4i_hdmi_enable(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 drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
struct sun4i_hdmi *hdmi = drm_encoder_to_sun4i_hdmi(encoder); 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; unsigned int x, y;
u32 val = 0; u32 val = 0;
DRM_DEBUG_DRIVER("Enabling the HDMI Output\n"); DRM_DEBUG_DRIVER("Enabling the HDMI Output\n");
clk_set_rate(hdmi->mod_clk, mode->crtc_clock * 1000); clk_set_rate(hdmi->mod_clk, tmds_rate);
clk_set_rate(hdmi->tmds_clk, mode->crtc_clock * 1000); clk_set_rate(hdmi->tmds_clk, tmds_rate);
/* Set input sync enable */ /* Set input sync enable */
writel(SUN4I_HDMI_UNKNOWN_INPUT_SYNC, writel(SUN4I_HDMI_UNKNOWN_INPUT_SYNC,
...@@ -143,7 +144,8 @@ static void sun4i_hdmi_enable(struct drm_encoder *encoder, ...@@ -143,7 +144,8 @@ static void sun4i_hdmi_enable(struct drm_encoder *encoder,
clk_prepare_enable(hdmi->tmds_clk); 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(0, SUN4I_HDMI_PKT_AVI);
val |= SUN4I_HDMI_PKT_CTRL_TYPE(1, SUN4I_HDMI_PKT_END); val |= SUN4I_HDMI_PKT_CTRL_TYPE(1, SUN4I_HDMI_PKT_END);
writel(val, hdmi->base + SUN4I_HDMI_PKT_CTRL_REG(0)); 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, ...@@ -196,7 +198,7 @@ static int sun4i_hdmi_connector_atomic_check(struct drm_connector *connector,
enum drm_mode_status status; enum drm_mode_status status;
status = sun4i_hdmi_connector_clock_valid(connector, mode, status = sun4i_hdmi_connector_clock_valid(connector, mode,
mode->clock * 1000); conn_state->hdmi.tmds_char_rate);
if (status != MODE_OK) if (status != MODE_OK)
return -EINVAL; return -EINVAL;
...@@ -207,8 +209,11 @@ static enum drm_mode_status ...@@ -207,8 +209,11 @@ static enum drm_mode_status
sun4i_hdmi_connector_mode_valid(struct drm_connector *connector, sun4i_hdmi_connector_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode) struct drm_display_mode *mode)
{ {
return sun4i_hdmi_connector_clock_valid(connector, mode, unsigned long long rate =
mode->clock * 1000); 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) 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) ...@@ -258,6 +263,11 @@ static struct i2c_adapter *sun4i_hdmi_get_ddc(struct device *dev)
return ddc; 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 = { static const struct drm_connector_helper_funcs sun4i_hdmi_connector_helper_funcs = {
.atomic_check = sun4i_hdmi_connector_atomic_check, .atomic_check = sun4i_hdmi_connector_atomic_check,
.mode_valid = sun4i_hdmi_connector_mode_valid, .mode_valid = sun4i_hdmi_connector_mode_valid,
...@@ -279,11 +289,16 @@ sun4i_hdmi_connector_detect(struct drm_connector *connector, bool force) ...@@ -279,11 +289,16 @@ sun4i_hdmi_connector_detect(struct drm_connector *connector, bool force)
return connector_status_connected; 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 = { static const struct drm_connector_funcs sun4i_hdmi_connector_funcs = {
.detect = sun4i_hdmi_connector_detect, .detect = sun4i_hdmi_connector_detect,
.fill_modes = drm_helper_probe_single_connector_modes, .fill_modes = drm_helper_probe_single_connector_modes,
.destroy = drm_connector_cleanup, .reset = sun4i_hdmi_connector_reset,
.reset = drm_atomic_helper_connector_reset,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_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, ...@@ -642,10 +657,19 @@ static int sun4i_hdmi_bind(struct device *dev, struct device *master,
drm_connector_helper_add(&hdmi->connector, drm_connector_helper_add(&hdmi->connector,
&sun4i_hdmi_connector_helper_funcs); &sun4i_hdmi_connector_helper_funcs);
ret = drm_connector_init_with_ddc(drm, &hdmi->connector, ret = drmm_connector_hdmi_init(drm, &hdmi->connector,
&sun4i_hdmi_connector_funcs, /*
DRM_MODE_CONNECTOR_HDMIA, * NOTE: Those are likely to be
hdmi->ddc_i2c); * 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) { if (ret) {
dev_err(dev, dev_err(dev,
"Couldn't initialise the HDMI connector\n"); "Couldn't initialise the HDMI connector\n");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment