@@ -31,6 +31,7 @@
struct lt9611uxc {
struct device *dev;
struct drm_bridge bridge;
+ struct drm_connector connector;
struct regmap *regmap;
/* Protects all accesses to registers by stopping the on-chip MCU */
@@ -105,6 +106,11 @@ static struct lt9611uxc *bridge_to_lt9611uxc(struct drm_bridge *bridge)
return container_of(bridge, struct lt9611uxc, bridge);
}
+static struct lt9611uxc *connector_to_lt9611uxc(struct drm_connector *connector)
+{
+ return container_of(connector, struct lt9611uxc, connector);
+}
+
static void lt9611uxc_lock(struct lt9611uxc *lt9611uxc)
{
mutex_lock(<9611uxc->ocm_lock);
@@ -246,6 +252,75 @@ static struct mipi_dsi_device *lt9611uxc_attach_dsi(struct lt9611uxc *lt9611uxc,
return dsi;
}
+static int lt9611uxc_connector_get_modes(struct drm_connector *connector)
+{
+ struct lt9611uxc *lt9611uxc = connector_to_lt9611uxc(connector);
+ unsigned int count;
+ struct edid *edid;
+
+ if (lt9611uxc->bridge.ops & DRM_BRIDGE_OP_MODES)
+ return lt9611uxc->bridge.funcs->get_modes(<9611uxc->bridge, connector);
+
+ edid = lt9611uxc->bridge.funcs->get_edid(<9611uxc->bridge, connector);
+ drm_connector_update_edid_property(connector, edid);
+ count = drm_add_edid_modes(connector, edid);
+ kfree(edid);
+
+ return count;
+}
+
+static enum drm_connector_status lt9611uxc_connector_detect(struct drm_connector *connector,
+ bool force)
+{
+ struct lt9611uxc *lt9611uxc = connector_to_lt9611uxc(connector);
+
+ return lt9611uxc->bridge.funcs->detect(<9611uxc->bridge);
+}
+
+static enum drm_mode_status lt9611uxc_connector_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ struct lt9611uxc_mode *lt9611uxc_mode = lt9611uxc_find_mode(mode);
+
+ return lt9611uxc_mode ? MODE_OK : MODE_BAD;
+}
+
+static const struct drm_connector_helper_funcs lt9611uxc_bridge_connector_helper_funcs = {
+ .get_modes = lt9611uxc_connector_get_modes,
+ .mode_valid = lt9611uxc_connector_mode_valid,
+};
+
+static const struct drm_connector_funcs lt9611uxc_bridge_connector_funcs = {
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .detect = lt9611uxc_connector_detect,
+ .destroy = drm_connector_cleanup,
+ .reset = drm_atomic_helper_connector_reset,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static int lt9611uxc_connector_init(struct drm_bridge *bridge, struct lt9611uxc *lt9611uxc)
+{
+ int ret;
+
+ if (!bridge->encoder) {
+ DRM_ERROR("Parent encoder object not found");
+ return -ENODEV;
+ }
+
+ drm_connector_helper_add(<9611uxc->connector,
+ <9611uxc_bridge_connector_helper_funcs);
+ ret = drm_connector_init(bridge->dev, <9611uxc->connector,
+ <9611uxc_bridge_connector_funcs,
+ DRM_MODE_CONNECTOR_HDMIA);
+ if (ret) {
+ DRM_ERROR("Failed to initialize connector with drm\n");
+ return ret;
+ }
+
+ return drm_connector_attach_encoder(<9611uxc->connector, bridge->encoder);
+}
+
static void lt9611uxc_bridge_detach(struct drm_bridge *bridge)
{
struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge);
@@ -266,8 +341,9 @@ static int lt9611uxc_bridge_attach(struct drm_bridge *bridge,
int ret;
if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) {
- dev_err(lt9611uxc->dev, "This bridge driver does not support providing connector!");
- return -EINVAL;
+ ret = lt9611uxc_connector_init(bridge, lt9611uxc);
+ if (ret < 0)
+ return ret;
}
/* Attach primary DSI */
As the MSM driver does not specify DRM_BRIDGE_ATTACH_NO_CONNECTOR to bridges, support working without this flag for now. Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org> --- drivers/gpu/drm/bridge/lontium-lt9611uxc.c | 80 +++++++++++++++++++++- 1 file changed, 78 insertions(+), 2 deletions(-)