@@ -665,15 +665,24 @@ connector_state_get_mode(const struct drm_connector_state *conn_state)
static enum drm_mode_status
hdmi_clock_valid(const struct drm_connector *connector,
const struct drm_display_mode *mode,
unsigned long long clock)
{
+ const struct drm_connector_hdmi_funcs *funcs = connector->hdmi.funcs;
const struct drm_display_info *info = &connector->display_info;
if (info->max_tmds_clock && clock > info->max_tmds_clock * 1000)
return MODE_CLOCK_HIGH;
+ if (funcs && funcs->tmds_char_rate_valid) {
+ enum drm_mode_status status;
+
+ status = funcs->tmds_char_rate_valid(connector, mode, clock);
+ if (status != MODE_OK)
+ return status;
+ }
+
return MODE_OK;
}
static int
hdmi_compute_clock(const struct drm_connector *connector,
@@ -455,10 +455,11 @@ EXPORT_SYMBOL(drmm_connector_init);
/**
* drmm_connector_hdmi_init - Init a preallocated HDMI connector
* @dev: DRM device
* @connector: A pointer to the HDMI connector to init
* @funcs: callbacks for this connector
+ * @hdmi_funcs: HDMI-related callbacks for this connector
* @connector_type: user visible type of the connector
* @ddc: optional pointer to the associated ddc adapter
* @supported_formats: Bitmask of @hdmi_colorspace listing supported output formats
* @max_bpc: Maximum bits per char the HDMI connector supports
*
@@ -474,10 +475,11 @@ EXPORT_SYMBOL(drmm_connector_init);
* Zero on success, error code on failure.
*/
int drmm_connector_hdmi_init(struct drm_device *dev,
struct drm_connector *connector,
const struct drm_connector_funcs *funcs,
+ const struct drm_connector_hdmi_funcs *hdmi_funcs,
int connector_type,
struct i2c_adapter *ddc,
unsigned long supported_formats,
unsigned int max_bpc)
{
@@ -510,10 +512,12 @@ int drmm_connector_hdmi_init(struct drm_device *dev,
connector->max_bpc = max_bpc;
if (max_bpc > 8)
drm_connector_attach_hdr_output_metadata_property(connector);
+ connector->hdmi.funcs = hdmi_funcs;
+
return 0;
}
EXPORT_SYMBOL(drmm_connector_hdmi_init);
/**
@@ -108,10 +108,13 @@ static int set_connector_edid(struct kunit *test, struct drm_connector *connecto
KUNIT_ASSERT_GT(test, ret, 0);
return 0;
}
+static const struct drm_connector_hdmi_funcs dummy_connector_hdmi_funcs = {
+};
+
static int dummy_connector_get_modes(struct drm_connector *connector)
{
struct drm_atomic_helper_connector_hdmi_priv *priv =
connector_to_priv(connector);
const struct drm_edid *edid;
@@ -190,10 +193,11 @@ drm_atomic_helper_connector_hdmi_init(struct kunit *test,
enc->possible_crtcs = drm_crtc_mask(priv->crtc);
conn = &priv->connector;
ret = drmm_connector_hdmi_init(drm, conn,
&dummy_connector_funcs,
+ &dummy_connector_hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
NULL,
formats,
max_bpc);
KUNIT_ASSERT_EQ(test, ret, 0);
@@ -20,10 +20,13 @@ struct drm_connector_init_priv {
struct drm_device drm;
struct drm_connector connector;
struct i2c_adapter ddc;
};
+static const struct drm_connector_hdmi_funcs dummy_hdmi_funcs = {
+};
+
static const struct drm_connector_funcs dummy_funcs = {
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.reset = drm_atomic_helper_connector_reset,
};
@@ -185,10 +188,11 @@ static void drm_test_connector_hdmi_init_valid(struct kunit *test)
struct drm_connector_init_priv *priv = test->priv;
int ret;
ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
+ &dummy_hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
&priv->ddc,
BIT(HDMI_COLORSPACE_RGB),
8);
KUNIT_EXPECT_EQ(test, ret, 0);
@@ -203,10 +207,11 @@ static void drm_test_connector_hdmi_init_null_ddc(struct kunit *test)
struct drm_connector_init_priv *priv = test->priv;
int ret;
ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
+ &dummy_hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
NULL,
BIT(HDMI_COLORSPACE_RGB),
8);
KUNIT_EXPECT_EQ(test, ret, 0);
@@ -221,10 +226,11 @@ static void drm_test_connector_hdmi_init_bpc_invalid(struct kunit *test)
struct drm_connector_init_priv *priv = test->priv;
int ret;
ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
+ &dummy_hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
&priv->ddc,
BIT(HDMI_COLORSPACE_RGB),
9);
KUNIT_EXPECT_LT(test, ret, 0);
@@ -239,10 +245,11 @@ static void drm_test_connector_hdmi_init_bpc_null(struct kunit *test)
struct drm_connector_init_priv *priv = test->priv;
int ret;
ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
+ &dummy_hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
&priv->ddc,
BIT(HDMI_COLORSPACE_RGB),
0);
KUNIT_EXPECT_LT(test, ret, 0);
@@ -261,10 +268,11 @@ static void drm_test_connector_hdmi_init_bpc_8(struct kunit *test)
uint64_t val;
int ret;
ret = drmm_connector_hdmi_init(&priv->drm, connector,
&dummy_funcs,
+ &dummy_hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
&priv->ddc,
BIT(HDMI_COLORSPACE_RGB),
8);
KUNIT_EXPECT_EQ(test, ret, 0);
@@ -295,10 +303,11 @@ static void drm_test_connector_hdmi_init_bpc_10(struct kunit *test)
uint64_t val;
int ret;
ret = drmm_connector_hdmi_init(&priv->drm, connector,
&dummy_funcs,
+ &dummy_hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
&priv->ddc,
BIT(HDMI_COLORSPACE_RGB),
10);
KUNIT_EXPECT_EQ(test, ret, 0);
@@ -329,10 +338,11 @@ static void drm_test_connector_hdmi_init_bpc_12(struct kunit *test)
uint64_t val;
int ret;
ret = drmm_connector_hdmi_init(&priv->drm, connector,
&dummy_funcs,
+ &dummy_hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
&priv->ddc,
BIT(HDMI_COLORSPACE_RGB),
12);
KUNIT_EXPECT_EQ(test, ret, 0);
@@ -359,10 +369,11 @@ static void drm_test_connector_hdmi_init_formats_empty(struct kunit *test)
struct drm_connector_init_priv *priv = test->priv;
int ret;
ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
+ &dummy_hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
&priv->ddc,
0,
8);
KUNIT_EXPECT_LT(test, ret, 0);
@@ -377,10 +388,11 @@ static void drm_test_connector_hdmi_init_formats_no_rgb(struct kunit *test)
struct drm_connector_init_priv *priv = test->priv;
int ret;
ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
+ &dummy_hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
&priv->ddc,
BIT(HDMI_COLORSPACE_YUV422),
8);
KUNIT_EXPECT_LT(test, ret, 0);
@@ -396,10 +408,11 @@ static void drm_test_connector_hdmi_init_type_valid(struct kunit *test)
unsigned int connector_type = *(unsigned int *)test->param_value;
int ret;
ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
+ &dummy_hdmi_funcs,
connector_type,
&priv->ddc,
BIT(HDMI_COLORSPACE_RGB),
8);
KUNIT_EXPECT_EQ(test, ret, 0);
@@ -429,10 +442,11 @@ static void drm_test_connector_hdmi_init_type_invalid(struct kunit *test)
unsigned int connector_type = *(unsigned int *)test->param_value;
int ret;
ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
&dummy_funcs,
+ &dummy_hdmi_funcs,
connector_type,
&priv->ddc,
BIT(HDMI_COLORSPACE_RGB),
8);
KUNIT_EXPECT_LT(test, ret, 0);
@@ -1056,10 +1056,34 @@ struct drm_connector_state {
*/
unsigned long long tmds_char_rate;
} hdmi;
};
+/**
+ * struct drm_connector_hdmi_funcs - drm_hdmi_connector control functions
+ */
+struct drm_connector_hdmi_funcs {
+ /**
+ * @tmds_char_rate_valid:
+ *
+ * This callback is invoked at atomic_check time to figure out
+ * whether a particular TMDS character rate is supported by the
+ * driver.
+ *
+ * The @tmds_char_rate_valid callback is optional.
+ *
+ * Returns:
+ *
+ * Either &drm_mode_status.MODE_OK or one of the failure reasons
+ * in &enum drm_mode_status.
+ */
+ enum drm_mode_status
+ (*tmds_char_rate_valid)(const struct drm_connector *connector,
+ const struct drm_display_mode *mode,
+ unsigned long long tmds_rate);
+};
+
/**
* struct drm_connector_funcs - control connectors on a given device
*
* Each CRTC may have one or more connectors attached to it. The functions
* below allow the core DRM code to control connectors, enumerate available modes,
@@ -1924,10 +1948,15 @@ struct drm_connector {
/**
* @supported_formats: Bitmask of @hdmi_colorspace
* supported by the controller.
*/
unsigned long supported_formats;
+
+ /**
+ * @funcs: HDMI connector Control Functions
+ */
+ const struct drm_connector_hdmi_funcs *funcs;
} hdmi;
};
#define obj_to_connector(x) container_of(x, struct drm_connector, base)
@@ -1946,10 +1975,11 @@ int drmm_connector_init(struct drm_device *dev,
int connector_type,
struct i2c_adapter *ddc);
int drmm_connector_hdmi_init(struct drm_device *dev,
struct drm_connector *connector,
const struct drm_connector_funcs *funcs,
+ const struct drm_connector_hdmi_funcs *hdmi_funcs,
int connector_type,
struct i2c_adapter *ddc,
unsigned long supported_formats,
unsigned int max_bpc);
void drm_connector_attach_edid_property(struct drm_connector *connector);