diff mbox series

[12/29] drm/omap: Expose DRM modes instead of timings in display devices

Message ID 20181205150022.24200-13-laurent.pinchart@ideasonboard.com (mailing list archive)
State New, archived
Headers show
Series omapdrm: Last large refactoring for drm_bridge transition | expand

Commit Message

Laurent Pinchart Dec. 5, 2018, 3 p.m. UTC
omap_dss_device operations expose fixed video timings through a
.get_timings() operation that return a single timing for the device. To
prepare for the move to drm_bridge, modify the API to instead add DRM
modes directly to the connector.

As this puts more burden on display devices, we also create a helper
function for panels to add a single DRM mode from the panel video
timings.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/gpu/drm/omapdrm/displays/panel-dpi.c  |  8 ++---
 .../gpu/drm/omapdrm/displays/panel-dsi-cm.c   | 10 +++---
 .../displays/panel-lgphilips-lb035q02.c       |  8 ++---
 .../omapdrm/displays/panel-nec-nl8048hl11.c   |  8 ++---
 .../displays/panel-sharp-ls037v7dw01.c        |  8 ++---
 .../omapdrm/displays/panel-sony-acx565akm.c   |  8 ++---
 .../omapdrm/displays/panel-tpo-td028ttec1.c   |  8 ++---
 .../omapdrm/displays/panel-tpo-td043mtea1.c   |  8 ++---
 drivers/gpu/drm/omapdrm/dss/display.c         | 22 +++++++++++++
 drivers/gpu/drm/omapdrm/dss/omapdss.h         |  8 +++--
 drivers/gpu/drm/omapdrm/dss/venc.c            | 12 ++++---
 drivers/gpu/drm/omapdrm/omap_connector.c      | 33 ++++++-------------
 12 files changed, 80 insertions(+), 61 deletions(-)

Comments

Sebastian Reichel Dec. 9, 2018, 10:02 p.m. UTC | #1
Hi,

On Wed, Dec 05, 2018 at 05:00:05PM +0200, Laurent Pinchart wrote:
> omap_dss_device operations expose fixed video timings through a
> .get_timings() operation that return a single timing for the device. To
> prepare for the move to drm_bridge, modify the API to instead add DRM
> modes directly to the connector.
> 
> As this puts more burden on display devices, we also create a helper
> function for panels to add a single DRM mode from the panel video
> timings.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---

Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.com>

-- Sebastian

>  drivers/gpu/drm/omapdrm/displays/panel-dpi.c  |  8 ++---
>  .../gpu/drm/omapdrm/displays/panel-dsi-cm.c   | 10 +++---
>  .../displays/panel-lgphilips-lb035q02.c       |  8 ++---
>  .../omapdrm/displays/panel-nec-nl8048hl11.c   |  8 ++---
>  .../displays/panel-sharp-ls037v7dw01.c        |  8 ++---
>  .../omapdrm/displays/panel-sony-acx565akm.c   |  8 ++---
>  .../omapdrm/displays/panel-tpo-td028ttec1.c   |  8 ++---
>  .../omapdrm/displays/panel-tpo-td043mtea1.c   |  8 ++---
>  drivers/gpu/drm/omapdrm/dss/display.c         | 22 +++++++++++++
>  drivers/gpu/drm/omapdrm/dss/omapdss.h         |  8 +++--
>  drivers/gpu/drm/omapdrm/dss/venc.c            | 12 ++++---
>  drivers/gpu/drm/omapdrm/omap_connector.c      | 33 ++++++-------------
>  12 files changed, 80 insertions(+), 61 deletions(-)
> 
> diff --git a/drivers/gpu/drm/omapdrm/displays/panel-dpi.c b/drivers/gpu/drm/omapdrm/displays/panel-dpi.c
> index c9d736f5eac0..2bda6d4fdb16 100644
> --- a/drivers/gpu/drm/omapdrm/displays/panel-dpi.c
> +++ b/drivers/gpu/drm/omapdrm/displays/panel-dpi.c
> @@ -68,12 +68,12 @@ static void panel_dpi_disable(struct omap_dss_device *dssdev)
>  	regulator_disable(ddata->vcc_supply);
>  }
>  
> -static void panel_dpi_get_timings(struct omap_dss_device *dssdev,
> -				  struct videomode *vm)
> +static int panel_dpi_get_modes(struct omap_dss_device *dssdev,
> +			       struct drm_connector *connector)
>  {
>  	struct panel_drv_data *ddata = to_panel_data(dssdev);
>  
> -	*vm = ddata->vm;
> +	return omapdss_display_get_modes(connector, &ddata->vm);
>  }
>  
>  static const struct omap_dss_device_ops panel_dpi_ops = {
> @@ -83,7 +83,7 @@ static const struct omap_dss_device_ops panel_dpi_ops = {
>  	.enable		= panel_dpi_enable,
>  	.disable	= panel_dpi_disable,
>  
> -	.get_timings	= panel_dpi_get_timings,
> +	.get_modes	= panel_dpi_get_modes,
>  };
>  
>  static int panel_dpi_probe_of(struct platform_device *pdev)
> diff --git a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c
> index ffbf20e6ebe9..9cd9ab487a24 100644
> --- a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c
> +++ b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c
> @@ -24,6 +24,8 @@
>  #include <linux/of_device.h>
>  #include <linux/regulator/consumer.h>
>  
> +#include <drm/drm_connector.h>
> +
>  #include <video/mipi_display.h>
>  #include <video/of_display_timing.h>
>  
> @@ -1110,12 +1112,12 @@ static void dsicm_ulps_work(struct work_struct *work)
>  	mutex_unlock(&ddata->lock);
>  }
>  
> -static void dsicm_get_timings(struct omap_dss_device *dssdev,
> -			      struct videomode *vm)
> +static int dsicm_get_modes(struct omap_dss_device *dssdev,
> +			   struct drm_connector *connector)
>  {
>  	struct panel_drv_data *ddata = to_panel_data(dssdev);
>  
> -	*vm = ddata->vm;
> +	return omapdss_display_get_modes(connector, &ddata->vm);
>  }
>  
>  static int dsicm_check_timings(struct omap_dss_device *dssdev,
> @@ -1156,7 +1158,7 @@ static const struct omap_dss_device_ops dsicm_ops = {
>  	.enable		= dsicm_enable,
>  	.disable	= dsicm_disable,
>  
> -	.get_timings	= dsicm_get_timings,
> +	.get_modes	= dsicm_get_modes,
>  	.check_timings	= dsicm_check_timings,
>  };
>  
> diff --git a/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c b/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c
> index e043cab0a0c9..e05b7f80416e 100644
> --- a/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c
> +++ b/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c
> @@ -139,12 +139,12 @@ static void lb035q02_disable(struct omap_dss_device *dssdev)
>  		gpiod_set_value_cansleep(ddata->enable_gpio, 0);
>  }
>  
> -static void lb035q02_get_timings(struct omap_dss_device *dssdev,
> -				 struct videomode *vm)
> +static int lb035q02_get_modes(struct omap_dss_device *dssdev,
> +			      struct drm_connector *connector)
>  {
>  	struct panel_drv_data *ddata = to_panel_data(dssdev);
>  
> -	*vm = ddata->vm;
> +	return omapdss_display_get_modes(connector, &ddata->vm);
>  }
>  
>  static const struct omap_dss_device_ops lb035q02_ops = {
> @@ -154,7 +154,7 @@ static const struct omap_dss_device_ops lb035q02_ops = {
>  	.enable		= lb035q02_enable,
>  	.disable	= lb035q02_disable,
>  
> -	.get_timings	= lb035q02_get_timings,
> +	.get_modes	= lb035q02_get_modes,
>  };
>  
>  static int lb035q02_probe_of(struct spi_device *spi)
> diff --git a/drivers/gpu/drm/omapdrm/displays/panel-nec-nl8048hl11.c b/drivers/gpu/drm/omapdrm/displays/panel-nec-nl8048hl11.c
> index 44fd6134317d..cf2127837e67 100644
> --- a/drivers/gpu/drm/omapdrm/displays/panel-nec-nl8048hl11.c
> +++ b/drivers/gpu/drm/omapdrm/displays/panel-nec-nl8048hl11.c
> @@ -132,12 +132,12 @@ static void nec_8048_disable(struct omap_dss_device *dssdev)
>  	gpiod_set_value_cansleep(ddata->res_gpio, 0);
>  }
>  
> -static void nec_8048_get_timings(struct omap_dss_device *dssdev,
> -				 struct videomode *vm)
> +static int nec_8048_get_modes(struct omap_dss_device *dssdev,
> +			      struct drm_connector *connector)
>  {
>  	struct panel_drv_data *ddata = to_panel_data(dssdev);
>  
> -	*vm = ddata->vm;
> +	return omapdss_display_get_modes(connector, &ddata->vm);
>  }
>  
>  static const struct omap_dss_device_ops nec_8048_ops = {
> @@ -147,7 +147,7 @@ static const struct omap_dss_device_ops nec_8048_ops = {
>  	.enable		= nec_8048_enable,
>  	.disable	= nec_8048_disable,
>  
> -	.get_timings	= nec_8048_get_timings,
> +	.get_modes	= nec_8048_get_modes,
>  };
>  
>  static int nec_8048_probe(struct spi_device *spi)
> diff --git a/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c b/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c
> index 907abf8ef4e6..30320cee1e56 100644
> --- a/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c
> +++ b/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c
> @@ -111,12 +111,12 @@ static void sharp_ls_post_disable(struct omap_dss_device *dssdev)
>  		regulator_disable(ddata->vcc);
>  }
>  
> -static void sharp_ls_get_timings(struct omap_dss_device *dssdev,
> -				 struct videomode *vm)
> +static int sharp_ls_get_modes(struct omap_dss_device *dssdev,
> +			      struct drm_connector *connector)
>  {
>  	struct panel_drv_data *ddata = to_panel_data(dssdev);
>  
> -	*vm = ddata->vm;
> +	return omapdss_display_get_modes(connector, &ddata->vm);
>  }
>  
>  static const struct omap_dss_device_ops sharp_ls_ops = {
> @@ -128,7 +128,7 @@ static const struct omap_dss_device_ops sharp_ls_ops = {
>  	.disable	= sharp_ls_disable,
>  	.post_disable	= sharp_ls_post_disable,
>  
> -	.get_timings	= sharp_ls_get_timings,
> +	.get_modes	= sharp_ls_get_modes,
>  };
>  
>  static  int sharp_ls_get_gpio_of(struct device *dev, int index, int val,
> diff --git a/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c b/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c
> index eeaea752f171..8debe77f92ff 100644
> --- a/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c
> +++ b/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c
> @@ -596,12 +596,12 @@ static void acx565akm_disable(struct omap_dss_device *dssdev)
>  	mutex_unlock(&ddata->mutex);
>  }
>  
> -static void acx565akm_get_timings(struct omap_dss_device *dssdev,
> -				  struct videomode *vm)
> +static int acx565akm_get_modes(struct omap_dss_device *dssdev,
> +			       struct drm_connector *connector)
>  {
>  	struct panel_drv_data *ddata = to_panel_data(dssdev);
>  
> -	*vm = ddata->vm;
> +	return omapdss_display_get_modes(connector, &ddata->vm);
>  }
>  
>  static const struct omap_dss_device_ops acx565akm_ops = {
> @@ -611,7 +611,7 @@ static const struct omap_dss_device_ops acx565akm_ops = {
>  	.enable		= acx565akm_enable,
>  	.disable	= acx565akm_disable,
>  
> -	.get_timings	= acx565akm_get_timings,
> +	.get_modes	= acx565akm_get_modes,
>  };
>  
>  static int acx565akm_probe(struct spi_device *spi)
> diff --git a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c
> index f1a5c14407a4..c8b15f19a166 100644
> --- a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c
> +++ b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c
> @@ -272,12 +272,12 @@ static void td028ttec1_panel_disable(struct omap_dss_device *dssdev)
>  	jbt_reg_write_1(ddata, JBT_REG_POWER_ON_OFF, 0x00);
>  }
>  
> -static void td028ttec1_panel_get_timings(struct omap_dss_device *dssdev,
> -					 struct videomode *vm)
> +static int td028ttec1_panel_get_modes(struct omap_dss_device *dssdev,
> +				      struct drm_connector *connector)
>  {
>  	struct panel_drv_data *ddata = to_panel_data(dssdev);
>  
> -	*vm = ddata->vm;
> +	return omapdss_display_get_modes(connector, &ddata->vm);
>  }
>  
>  static const struct omap_dss_device_ops td028ttec1_ops = {
> @@ -287,7 +287,7 @@ static const struct omap_dss_device_ops td028ttec1_ops = {
>  	.enable		= td028ttec1_panel_enable,
>  	.disable	= td028ttec1_panel_disable,
>  
> -	.get_timings	= td028ttec1_panel_get_timings,
> +	.get_modes	= td028ttec1_panel_get_modes,
>  };
>  
>  static int td028ttec1_panel_probe(struct spi_device *spi)
> diff --git a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td043mtea1.c b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td043mtea1.c
> index 996a16736d10..9ecc4c7bee67 100644
> --- a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td043mtea1.c
> +++ b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td043mtea1.c
> @@ -347,12 +347,12 @@ static void tpo_td043_disable(struct omap_dss_device *dssdev)
>  		tpo_td043_power_off(ddata);
>  }
>  
> -static void tpo_td043_get_timings(struct omap_dss_device *dssdev,
> -				  struct videomode *vm)
> +static int tpo_td043_get_modes(struct omap_dss_device *dssdev,
> +			       struct drm_connector *connector)
>  {
>  	struct panel_drv_data *ddata = to_panel_data(dssdev);
>  
> -	*vm = ddata->vm;
> +	return omapdss_display_get_modes(connector, &ddata->vm);
>  }
>  
>  static const struct omap_dss_device_ops tpo_td043_ops = {
> @@ -362,7 +362,7 @@ static const struct omap_dss_device_ops tpo_td043_ops = {
>  	.enable		= tpo_td043_enable,
>  	.disable	= tpo_td043_disable,
>  
> -	.get_timings	= tpo_td043_get_timings,
> +	.get_modes	= tpo_td043_get_modes,
>  };
>  
>  static int tpo_td043_probe(struct spi_device *spi)
> diff --git a/drivers/gpu/drm/omapdrm/dss/display.c b/drivers/gpu/drm/omapdrm/dss/display.c
> index 34b2a4ef63a4..398964358386 100644
> --- a/drivers/gpu/drm/omapdrm/dss/display.c
> +++ b/drivers/gpu/drm/omapdrm/dss/display.c
> @@ -23,6 +23,9 @@
>  #include <linux/kernel.h>
>  #include <linux/of.h>
>  
> +#include <drm/drm_connector.h>
> +#include <drm/drm_modes.h>
> +
>  #include "omapdss.h"
>  
>  static int disp_num_counter;
> @@ -58,3 +61,22 @@ struct omap_dss_device *omapdss_display_get(struct omap_dss_device *output)
>  	return omapdss_device_get(output);
>  }
>  EXPORT_SYMBOL_GPL(omapdss_display_get);
> +
> +int omapdss_display_get_modes(struct drm_connector *connector,
> +			      const struct videomode *vm)
> +{
> +	struct drm_display_mode *mode;
> +
> +	mode = drm_mode_create(connector->dev);
> +	if (!mode)
> +		return 0;
> +
> +	drm_display_mode_from_videomode(vm, mode);
> +
> +	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
> +	drm_mode_set_name(mode);
> +	drm_mode_probed_add(connector, mode);
> +
> +	return 1;
> +}
> +EXPORT_SYMBOL_GPL(omapdss_display_get_modes);
> diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h
> index 723a9b5060f5..3be8d3153d1a 100644
> --- a/drivers/gpu/drm/omapdrm/dss/omapdss.h
> +++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h
> @@ -67,6 +67,7 @@ struct dss_lcd_mgr_config;
>  struct snd_aes_iec958;
>  struct snd_cea_861_aud_if;
>  struct hdmi_avi_infoframe;
> +struct drm_connector;
>  
>  enum omap_display_type {
>  	OMAP_DISPLAY_TYPE_NONE		= 0,
> @@ -366,8 +367,6 @@ struct omap_dss_device_ops {
>  
>  	int (*check_timings)(struct omap_dss_device *dssdev,
>  			     struct videomode *vm);
> -	void (*get_timings)(struct omap_dss_device *dssdev,
> -			    struct videomode *vm);
>  	void (*set_timings)(struct omap_dss_device *dssdev,
>  			    const struct videomode *vm);
>  
> @@ -381,6 +380,9 @@ struct omap_dss_device_ops {
>  
>  	int (*read_edid)(struct omap_dss_device *dssdev, u8 *buf, int len);
>  
> +	int (*get_modes)(struct omap_dss_device *dssdev,
> +			 struct drm_connector *connector);
> +
>  	union {
>  		const struct omapdss_hdmi_ops hdmi;
>  		const struct omapdss_dsi_ops dsi;
> @@ -476,6 +478,8 @@ static inline bool omapdss_is_initialized(void)
>  	while ((d = omapdss_device_get_next(d, OMAP_DSS_DEVICE_TYPE_DISPLAY)) != NULL)
>  void omapdss_display_init(struct omap_dss_device *dssdev);
>  struct omap_dss_device *omapdss_display_get(struct omap_dss_device *output);
> +int omapdss_display_get_modes(struct drm_connector *connector,
> +			      const struct videomode *vm);
>  
>  void omapdss_device_register(struct omap_dss_device *dssdev);
>  void omapdss_device_unregister(struct omap_dss_device *dssdev);
> diff --git a/drivers/gpu/drm/omapdrm/dss/venc.c b/drivers/gpu/drm/omapdrm/dss/venc.c
> index 3fc776c45c4f..cefefe6d6fcb 100644
> --- a/drivers/gpu/drm/omapdrm/dss/venc.c
> +++ b/drivers/gpu/drm/omapdrm/dss/venc.c
> @@ -548,14 +548,17 @@ static void venc_display_disable(struct omap_dss_device *dssdev)
>  	mutex_unlock(&venc->venc_lock);
>  }
>  
> -static void venc_get_timings(struct omap_dss_device *dssdev,
> -			     struct videomode *vm)
> +static int venc_get_modes(struct omap_dss_device *dssdev,
> +			  struct drm_connector *connector)
>  {
>  	struct venc_device *venc = dssdev_to_venc(dssdev);
> +	int r;
>  
>  	mutex_lock(&venc->venc_lock);
> -	*vm = venc->vm;
> +	r = omapdss_display_get_modes(connector, &venc->vm);
>  	mutex_unlock(&venc->venc_lock);
> +
> +	return r;
>  }
>  
>  static void venc_set_timings(struct omap_dss_device *dssdev,
> @@ -690,8 +693,9 @@ static const struct omap_dss_device_ops venc_ops = {
>  	.disable = venc_display_disable,
>  
>  	.check_timings = venc_check_timings,
> -	.get_timings = venc_get_timings,
>  	.set_timings = venc_set_timings,
> +
> +	.get_modes = venc_get_modes,
>  };
>  
>  /* -----------------------------------------------------------------------------
> diff --git a/drivers/gpu/drm/omapdrm/omap_connector.c b/drivers/gpu/drm/omapdrm/omap_connector.c
> index b81302c4bf9e..93b31bf07d05 100644
> --- a/drivers/gpu/drm/omapdrm/omap_connector.c
> +++ b/drivers/gpu/drm/omapdrm/omap_connector.c
> @@ -212,8 +212,6 @@ static int omap_connector_get_modes(struct drm_connector *connector)
>  {
>  	struct omap_connector *omap_connector = to_omap_connector(connector);
>  	struct omap_dss_device *dssdev;
> -	struct drm_display_mode *mode;
> -	struct videomode vm = {0};
>  
>  	DBG("%s", omap_connector->display->name);
>  
> @@ -238,31 +236,20 @@ static int omap_connector_get_modes(struct drm_connector *connector)
>  					 &connector->display_info.height_mm);
>  
>  	/*
> -	 * Iterate over the pipeline to find the first device that can provide
> -	 * timing information. If we can't find any, we just let the KMS core
> -	 * add the default modes.
> +	 * If the display pipeline reports modes (e.g. with a fixed resolution
> +	 * panel or an analog TV output), query it.
>  	 */
>  	for (dssdev = omap_connector->display; dssdev; dssdev = dssdev->src) {
> -		if (dssdev->ops->get_timings)
> -			break;
> +		if (dssdev->ops->get_modes)
> +			return dssdev->ops->get_modes(dssdev, connector);
>  	}
> -	if (!dssdev)
> -		return 0;
> -
> -	/* Add a single mode corresponding to the fixed panel timings. */
> -	mode = drm_mode_create(connector->dev);
> -	if (!mode)
> -		return 0;
> -
> -	dssdev->ops->get_timings(dssdev, &vm);
> -
> -	drm_display_mode_from_videomode(&vm, mode);
>  
> -	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
> -	drm_mode_set_name(mode);
> -	drm_mode_probed_add(connector, mode);
> -
> -	return 1;
> +	/*
> +	 * We can't retrieve modes, which can happen for instance for a DVI or
> +	 * VGA output with the DDC bus unconnected. The KMS core will add the
> +	 * default modes.
> +	 */
> +	return 0;
>  }
>  
>  static int omap_connector_mode_valid(struct drm_connector *connector,
> -- 
> Regards,
> 
> Laurent Pinchart
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
diff mbox series

Patch

diff --git a/drivers/gpu/drm/omapdrm/displays/panel-dpi.c b/drivers/gpu/drm/omapdrm/displays/panel-dpi.c
index c9d736f5eac0..2bda6d4fdb16 100644
--- a/drivers/gpu/drm/omapdrm/displays/panel-dpi.c
+++ b/drivers/gpu/drm/omapdrm/displays/panel-dpi.c
@@ -68,12 +68,12 @@  static void panel_dpi_disable(struct omap_dss_device *dssdev)
 	regulator_disable(ddata->vcc_supply);
 }
 
-static void panel_dpi_get_timings(struct omap_dss_device *dssdev,
-				  struct videomode *vm)
+static int panel_dpi_get_modes(struct omap_dss_device *dssdev,
+			       struct drm_connector *connector)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
 
-	*vm = ddata->vm;
+	return omapdss_display_get_modes(connector, &ddata->vm);
 }
 
 static const struct omap_dss_device_ops panel_dpi_ops = {
@@ -83,7 +83,7 @@  static const struct omap_dss_device_ops panel_dpi_ops = {
 	.enable		= panel_dpi_enable,
 	.disable	= panel_dpi_disable,
 
-	.get_timings	= panel_dpi_get_timings,
+	.get_modes	= panel_dpi_get_modes,
 };
 
 static int panel_dpi_probe_of(struct platform_device *pdev)
diff --git a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c
index ffbf20e6ebe9..9cd9ab487a24 100644
--- a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c
+++ b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c
@@ -24,6 +24,8 @@ 
 #include <linux/of_device.h>
 #include <linux/regulator/consumer.h>
 
+#include <drm/drm_connector.h>
+
 #include <video/mipi_display.h>
 #include <video/of_display_timing.h>
 
@@ -1110,12 +1112,12 @@  static void dsicm_ulps_work(struct work_struct *work)
 	mutex_unlock(&ddata->lock);
 }
 
-static void dsicm_get_timings(struct omap_dss_device *dssdev,
-			      struct videomode *vm)
+static int dsicm_get_modes(struct omap_dss_device *dssdev,
+			   struct drm_connector *connector)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
 
-	*vm = ddata->vm;
+	return omapdss_display_get_modes(connector, &ddata->vm);
 }
 
 static int dsicm_check_timings(struct omap_dss_device *dssdev,
@@ -1156,7 +1158,7 @@  static const struct omap_dss_device_ops dsicm_ops = {
 	.enable		= dsicm_enable,
 	.disable	= dsicm_disable,
 
-	.get_timings	= dsicm_get_timings,
+	.get_modes	= dsicm_get_modes,
 	.check_timings	= dsicm_check_timings,
 };
 
diff --git a/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c b/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c
index e043cab0a0c9..e05b7f80416e 100644
--- a/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c
+++ b/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c
@@ -139,12 +139,12 @@  static void lb035q02_disable(struct omap_dss_device *dssdev)
 		gpiod_set_value_cansleep(ddata->enable_gpio, 0);
 }
 
-static void lb035q02_get_timings(struct omap_dss_device *dssdev,
-				 struct videomode *vm)
+static int lb035q02_get_modes(struct omap_dss_device *dssdev,
+			      struct drm_connector *connector)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
 
-	*vm = ddata->vm;
+	return omapdss_display_get_modes(connector, &ddata->vm);
 }
 
 static const struct omap_dss_device_ops lb035q02_ops = {
@@ -154,7 +154,7 @@  static const struct omap_dss_device_ops lb035q02_ops = {
 	.enable		= lb035q02_enable,
 	.disable	= lb035q02_disable,
 
-	.get_timings	= lb035q02_get_timings,
+	.get_modes	= lb035q02_get_modes,
 };
 
 static int lb035q02_probe_of(struct spi_device *spi)
diff --git a/drivers/gpu/drm/omapdrm/displays/panel-nec-nl8048hl11.c b/drivers/gpu/drm/omapdrm/displays/panel-nec-nl8048hl11.c
index 44fd6134317d..cf2127837e67 100644
--- a/drivers/gpu/drm/omapdrm/displays/panel-nec-nl8048hl11.c
+++ b/drivers/gpu/drm/omapdrm/displays/panel-nec-nl8048hl11.c
@@ -132,12 +132,12 @@  static void nec_8048_disable(struct omap_dss_device *dssdev)
 	gpiod_set_value_cansleep(ddata->res_gpio, 0);
 }
 
-static void nec_8048_get_timings(struct omap_dss_device *dssdev,
-				 struct videomode *vm)
+static int nec_8048_get_modes(struct omap_dss_device *dssdev,
+			      struct drm_connector *connector)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
 
-	*vm = ddata->vm;
+	return omapdss_display_get_modes(connector, &ddata->vm);
 }
 
 static const struct omap_dss_device_ops nec_8048_ops = {
@@ -147,7 +147,7 @@  static const struct omap_dss_device_ops nec_8048_ops = {
 	.enable		= nec_8048_enable,
 	.disable	= nec_8048_disable,
 
-	.get_timings	= nec_8048_get_timings,
+	.get_modes	= nec_8048_get_modes,
 };
 
 static int nec_8048_probe(struct spi_device *spi)
diff --git a/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c b/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c
index 907abf8ef4e6..30320cee1e56 100644
--- a/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c
+++ b/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c
@@ -111,12 +111,12 @@  static void sharp_ls_post_disable(struct omap_dss_device *dssdev)
 		regulator_disable(ddata->vcc);
 }
 
-static void sharp_ls_get_timings(struct omap_dss_device *dssdev,
-				 struct videomode *vm)
+static int sharp_ls_get_modes(struct omap_dss_device *dssdev,
+			      struct drm_connector *connector)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
 
-	*vm = ddata->vm;
+	return omapdss_display_get_modes(connector, &ddata->vm);
 }
 
 static const struct omap_dss_device_ops sharp_ls_ops = {
@@ -128,7 +128,7 @@  static const struct omap_dss_device_ops sharp_ls_ops = {
 	.disable	= sharp_ls_disable,
 	.post_disable	= sharp_ls_post_disable,
 
-	.get_timings	= sharp_ls_get_timings,
+	.get_modes	= sharp_ls_get_modes,
 };
 
 static  int sharp_ls_get_gpio_of(struct device *dev, int index, int val,
diff --git a/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c b/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c
index eeaea752f171..8debe77f92ff 100644
--- a/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c
+++ b/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c
@@ -596,12 +596,12 @@  static void acx565akm_disable(struct omap_dss_device *dssdev)
 	mutex_unlock(&ddata->mutex);
 }
 
-static void acx565akm_get_timings(struct omap_dss_device *dssdev,
-				  struct videomode *vm)
+static int acx565akm_get_modes(struct omap_dss_device *dssdev,
+			       struct drm_connector *connector)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
 
-	*vm = ddata->vm;
+	return omapdss_display_get_modes(connector, &ddata->vm);
 }
 
 static const struct omap_dss_device_ops acx565akm_ops = {
@@ -611,7 +611,7 @@  static const struct omap_dss_device_ops acx565akm_ops = {
 	.enable		= acx565akm_enable,
 	.disable	= acx565akm_disable,
 
-	.get_timings	= acx565akm_get_timings,
+	.get_modes	= acx565akm_get_modes,
 };
 
 static int acx565akm_probe(struct spi_device *spi)
diff --git a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c
index f1a5c14407a4..c8b15f19a166 100644
--- a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c
+++ b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c
@@ -272,12 +272,12 @@  static void td028ttec1_panel_disable(struct omap_dss_device *dssdev)
 	jbt_reg_write_1(ddata, JBT_REG_POWER_ON_OFF, 0x00);
 }
 
-static void td028ttec1_panel_get_timings(struct omap_dss_device *dssdev,
-					 struct videomode *vm)
+static int td028ttec1_panel_get_modes(struct omap_dss_device *dssdev,
+				      struct drm_connector *connector)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
 
-	*vm = ddata->vm;
+	return omapdss_display_get_modes(connector, &ddata->vm);
 }
 
 static const struct omap_dss_device_ops td028ttec1_ops = {
@@ -287,7 +287,7 @@  static const struct omap_dss_device_ops td028ttec1_ops = {
 	.enable		= td028ttec1_panel_enable,
 	.disable	= td028ttec1_panel_disable,
 
-	.get_timings	= td028ttec1_panel_get_timings,
+	.get_modes	= td028ttec1_panel_get_modes,
 };
 
 static int td028ttec1_panel_probe(struct spi_device *spi)
diff --git a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td043mtea1.c b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td043mtea1.c
index 996a16736d10..9ecc4c7bee67 100644
--- a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td043mtea1.c
+++ b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td043mtea1.c
@@ -347,12 +347,12 @@  static void tpo_td043_disable(struct omap_dss_device *dssdev)
 		tpo_td043_power_off(ddata);
 }
 
-static void tpo_td043_get_timings(struct omap_dss_device *dssdev,
-				  struct videomode *vm)
+static int tpo_td043_get_modes(struct omap_dss_device *dssdev,
+			       struct drm_connector *connector)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
 
-	*vm = ddata->vm;
+	return omapdss_display_get_modes(connector, &ddata->vm);
 }
 
 static const struct omap_dss_device_ops tpo_td043_ops = {
@@ -362,7 +362,7 @@  static const struct omap_dss_device_ops tpo_td043_ops = {
 	.enable		= tpo_td043_enable,
 	.disable	= tpo_td043_disable,
 
-	.get_timings	= tpo_td043_get_timings,
+	.get_modes	= tpo_td043_get_modes,
 };
 
 static int tpo_td043_probe(struct spi_device *spi)
diff --git a/drivers/gpu/drm/omapdrm/dss/display.c b/drivers/gpu/drm/omapdrm/dss/display.c
index 34b2a4ef63a4..398964358386 100644
--- a/drivers/gpu/drm/omapdrm/dss/display.c
+++ b/drivers/gpu/drm/omapdrm/dss/display.c
@@ -23,6 +23,9 @@ 
 #include <linux/kernel.h>
 #include <linux/of.h>
 
+#include <drm/drm_connector.h>
+#include <drm/drm_modes.h>
+
 #include "omapdss.h"
 
 static int disp_num_counter;
@@ -58,3 +61,22 @@  struct omap_dss_device *omapdss_display_get(struct omap_dss_device *output)
 	return omapdss_device_get(output);
 }
 EXPORT_SYMBOL_GPL(omapdss_display_get);
+
+int omapdss_display_get_modes(struct drm_connector *connector,
+			      const struct videomode *vm)
+{
+	struct drm_display_mode *mode;
+
+	mode = drm_mode_create(connector->dev);
+	if (!mode)
+		return 0;
+
+	drm_display_mode_from_videomode(vm, mode);
+
+	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+	drm_mode_set_name(mode);
+	drm_mode_probed_add(connector, mode);
+
+	return 1;
+}
+EXPORT_SYMBOL_GPL(omapdss_display_get_modes);
diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h
index 723a9b5060f5..3be8d3153d1a 100644
--- a/drivers/gpu/drm/omapdrm/dss/omapdss.h
+++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h
@@ -67,6 +67,7 @@  struct dss_lcd_mgr_config;
 struct snd_aes_iec958;
 struct snd_cea_861_aud_if;
 struct hdmi_avi_infoframe;
+struct drm_connector;
 
 enum omap_display_type {
 	OMAP_DISPLAY_TYPE_NONE		= 0,
@@ -366,8 +367,6 @@  struct omap_dss_device_ops {
 
 	int (*check_timings)(struct omap_dss_device *dssdev,
 			     struct videomode *vm);
-	void (*get_timings)(struct omap_dss_device *dssdev,
-			    struct videomode *vm);
 	void (*set_timings)(struct omap_dss_device *dssdev,
 			    const struct videomode *vm);
 
@@ -381,6 +380,9 @@  struct omap_dss_device_ops {
 
 	int (*read_edid)(struct omap_dss_device *dssdev, u8 *buf, int len);
 
+	int (*get_modes)(struct omap_dss_device *dssdev,
+			 struct drm_connector *connector);
+
 	union {
 		const struct omapdss_hdmi_ops hdmi;
 		const struct omapdss_dsi_ops dsi;
@@ -476,6 +478,8 @@  static inline bool omapdss_is_initialized(void)
 	while ((d = omapdss_device_get_next(d, OMAP_DSS_DEVICE_TYPE_DISPLAY)) != NULL)
 void omapdss_display_init(struct omap_dss_device *dssdev);
 struct omap_dss_device *omapdss_display_get(struct omap_dss_device *output);
+int omapdss_display_get_modes(struct drm_connector *connector,
+			      const struct videomode *vm);
 
 void omapdss_device_register(struct omap_dss_device *dssdev);
 void omapdss_device_unregister(struct omap_dss_device *dssdev);
diff --git a/drivers/gpu/drm/omapdrm/dss/venc.c b/drivers/gpu/drm/omapdrm/dss/venc.c
index 3fc776c45c4f..cefefe6d6fcb 100644
--- a/drivers/gpu/drm/omapdrm/dss/venc.c
+++ b/drivers/gpu/drm/omapdrm/dss/venc.c
@@ -548,14 +548,17 @@  static void venc_display_disable(struct omap_dss_device *dssdev)
 	mutex_unlock(&venc->venc_lock);
 }
 
-static void venc_get_timings(struct omap_dss_device *dssdev,
-			     struct videomode *vm)
+static int venc_get_modes(struct omap_dss_device *dssdev,
+			  struct drm_connector *connector)
 {
 	struct venc_device *venc = dssdev_to_venc(dssdev);
+	int r;
 
 	mutex_lock(&venc->venc_lock);
-	*vm = venc->vm;
+	r = omapdss_display_get_modes(connector, &venc->vm);
 	mutex_unlock(&venc->venc_lock);
+
+	return r;
 }
 
 static void venc_set_timings(struct omap_dss_device *dssdev,
@@ -690,8 +693,9 @@  static const struct omap_dss_device_ops venc_ops = {
 	.disable = venc_display_disable,
 
 	.check_timings = venc_check_timings,
-	.get_timings = venc_get_timings,
 	.set_timings = venc_set_timings,
+
+	.get_modes = venc_get_modes,
 };
 
 /* -----------------------------------------------------------------------------
diff --git a/drivers/gpu/drm/omapdrm/omap_connector.c b/drivers/gpu/drm/omapdrm/omap_connector.c
index b81302c4bf9e..93b31bf07d05 100644
--- a/drivers/gpu/drm/omapdrm/omap_connector.c
+++ b/drivers/gpu/drm/omapdrm/omap_connector.c
@@ -212,8 +212,6 @@  static int omap_connector_get_modes(struct drm_connector *connector)
 {
 	struct omap_connector *omap_connector = to_omap_connector(connector);
 	struct omap_dss_device *dssdev;
-	struct drm_display_mode *mode;
-	struct videomode vm = {0};
 
 	DBG("%s", omap_connector->display->name);
 
@@ -238,31 +236,20 @@  static int omap_connector_get_modes(struct drm_connector *connector)
 					 &connector->display_info.height_mm);
 
 	/*
-	 * Iterate over the pipeline to find the first device that can provide
-	 * timing information. If we can't find any, we just let the KMS core
-	 * add the default modes.
+	 * If the display pipeline reports modes (e.g. with a fixed resolution
+	 * panel or an analog TV output), query it.
 	 */
 	for (dssdev = omap_connector->display; dssdev; dssdev = dssdev->src) {
-		if (dssdev->ops->get_timings)
-			break;
+		if (dssdev->ops->get_modes)
+			return dssdev->ops->get_modes(dssdev, connector);
 	}
-	if (!dssdev)
-		return 0;
-
-	/* Add a single mode corresponding to the fixed panel timings. */
-	mode = drm_mode_create(connector->dev);
-	if (!mode)
-		return 0;
-
-	dssdev->ops->get_timings(dssdev, &vm);
-
-	drm_display_mode_from_videomode(&vm, mode);
 
-	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
-	drm_mode_set_name(mode);
-	drm_mode_probed_add(connector, mode);
-
-	return 1;
+	/*
+	 * We can't retrieve modes, which can happen for instance for a DVI or
+	 * VGA output with the DDC bus unconnected. The KMS core will add the
+	 * default modes.
+	 */
+	return 0;
 }
 
 static int omap_connector_mode_valid(struct drm_connector *connector,