@@ -110,6 +110,8 @@ static int tilcdc_unload(struct drm_device *dev)
{
struct tilcdc_drm_private *priv = dev->dev_private;
+ tilcdc_remove_external_encoders(dev);
+
drm_fbdev_cma_fini(priv->fbdev);
drm_kms_helper_poll_fini(dev);
drm_mode_config_cleanup(dev);
@@ -267,13 +269,13 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
if ((priv->num_encoders == 0) || (priv->num_connectors == 0)) {
dev_err(dev->dev, "no encoders/connectors found\n");
ret = -ENXIO;
- goto fail_component_cleanup;
+ goto fail_external_cleanup;
}
ret = drm_vblank_init(dev, 1);
if (ret < 0) {
dev_err(dev->dev, "failed to initialize vblank\n");
- goto fail_component_cleanup;
+ goto fail_external_cleanup;
}
pm_runtime_get_sync(dev->dev);
@@ -318,6 +320,9 @@ fail_component_cleanup:
if (priv->is_componentized)
component_unbind_all(dev->dev, dev);
+fail_external_cleanup:
+ tilcdc_remove_external_encoders(dev);
+
fail_cpufreq_unregister:
pm_runtime_disable(dev->dev);
#ifdef CONFIG_CPU_FREQ
@@ -85,6 +85,7 @@ struct tilcdc_drm_private {
unsigned int num_connectors;
struct drm_connector *connectors[8];
+ struct drm_connector_helper_funcs *connector_funcs[8];
bool is_componentized;
};
@@ -27,12 +27,34 @@ static const struct tilcdc_panel_info panel_info_tda998x = {
.raster_order = 0,
};
+static int tilcdc_external_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ struct tilcdc_drm_private *priv = connector->dev->dev_private;
+ int ret, i;
+
+ ret = tilcdc_crtc_mode_valid(priv->crtc, mode);
+ if (ret != MODE_OK)
+ return ret;
+
+ for (i = 0; i < priv->num_connectors &&
+ priv->connectors[i] != connector; i++);
+
+ BUG_ON(priv->connectors[i] != connector);
+
+ if (priv->connector_funcs[i]->mode_valid)
+ return priv->connector_funcs[i]->mode_valid(connector, mode);
+
+ return MODE_OK;
+}
+
static int tilcdc_add_external_encoder(struct drm_device *dev, int *bpp,
struct drm_connector *connector)
{
struct tilcdc_drm_private *priv = dev->dev_private;
+ struct drm_connector_helper_funcs *connector_funcs;
- priv->connectors[priv->num_connectors++] = connector;
+ priv->connectors[priv->num_connectors] = connector;
priv->encoders[priv->num_encoders++] = connector->encoder;
/* Only tda998x is supported at the moment. */
@@ -40,6 +62,14 @@ static int tilcdc_add_external_encoder(struct drm_device *dev, int *bpp,
tilcdc_crtc_set_panel_info(priv->crtc, &panel_info_tda998x);
*bpp = panel_info_tda998x.bpp;
+ priv->connector_funcs[priv->num_connectors] = connector->helper_private;
+ connector_funcs = devm_kzalloc(dev->dev, sizeof(*connector_funcs),
+ GFP_KERNEL);
+ *connector_funcs = *priv->connector_funcs[priv->num_connectors];
+ connector_funcs->mode_valid = tilcdc_external_mode_valid;
+ connector->helper_private = connector_funcs;
+ priv->num_connectors++;
+
dev_dbg(dev->dev, "External encoder '%s' connected\n",
connector->encoder->name);
@@ -68,6 +98,17 @@ int tilcdc_add_external_encoders(struct drm_device *dev, int *bpp)
return 0;
}
+void tilcdc_remove_external_encoders(struct drm_device *dev)
+{
+ struct tilcdc_drm_private *priv = dev->dev_private;
+ int i;
+
+ for (i = 0; i < priv->num_connectors; i++)
+ if (priv->connector_funcs[i])
+ priv->connectors[i]->helper_private =
+ priv->connector_funcs[i];
+}
+
static int dev_match_of(struct device *dev, void *data)
{
return dev->of_node == data;
@@ -19,6 +19,7 @@
#define __TILCDC_EXTERNAL_H__
int tilcdc_add_external_encoders(struct drm_device *dev, int *bpp);
+void tilcdc_remove_external_encoders(struct drm_device *dev);
int tilcdc_get_external_components(struct device *dev,
struct component_match **match);
#endif /* __TILCDC_SLAVE_H__ */
Hijack external connectors helper funcs to filter modes. TILCDC crtc wants to have its say on which modes are valid. There appears to be no trivial way to do that directly from crtc. This patch goes and hijacks the external connectors helper functions and puts its own mode_valid() function there. The original mode_valid() function is still called if the mode is found suitable and the original helper funcs pointer is restored when TILCDC is unloaded. Signed-off-by: Jyri Sarha <jsarha@ti.com> --- This patch applies on top of my "[PATCH v3 0/7] Use DRM component API in tilcdc to connect to tda998x"-patch set[1]. I am too new to DRM to know if what I am doing here is acceptable or not. And I am too new to TILCDC to know if there is not someting fundamentally wrong with it and that is why need to do this. The code would certainly look nicer if there would be a mode_valid func in crtc_helper_funcs too. Would such a patch be accepted? Best regards, Jyri [1]http://www.spinics.net/lists/linux-omap/msg116923.html drivers/gpu/drm/tilcdc/tilcdc_drv.c | 9 +++++-- drivers/gpu/drm/tilcdc/tilcdc_drv.h | 1 + drivers/gpu/drm/tilcdc/tilcdc_external.c | 43 +++++++++++++++++++++++++++++++- drivers/gpu/drm/tilcdc/tilcdc_external.h | 1 + 4 files changed, 51 insertions(+), 3 deletions(-)