summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRicardo Salveti de Araujo <ricardo.salveti@canonical.com>2011-09-01 08:08:09 +0100
committerAndy Green <andy.green@linaro.org>2011-09-01 08:08:09 +0100
commitb92253bd99ed8e56033808b7031fc0973dea709f (patch)
treec4a5c97fb91a04b26cce8f4a5a87c5a70e7a1fa8
parent15d2a95ade13bbac1b86b4a0d0b646cae3d17141 (diff)
drm/omap: add common scaled modes
The idea behind it is just to add more modes, and add them with reduced blanking, so we have more choices while probing the EDID. It tries to identify what would be the native mode for the monitor, and add the scaler modes that would be compatible with it, but with reduced blanking. With that it can get more compatible modes with OMAP pixel clock. Signed-off-by: Ricardo Salveti de Araujo <ricardo.salveti@canonical.com>
-rw-r--r--drivers/staging/omapdrm/omap_connector.c107
1 files changed, 107 insertions, 0 deletions
diff --git a/drivers/staging/omapdrm/omap_connector.c b/drivers/staging/omapdrm/omap_connector.c
index c1071c171bd..77f209e52b2 100644
--- a/drivers/staging/omapdrm/omap_connector.c
+++ b/drivers/staging/omapdrm/omap_connector.c
@@ -32,6 +32,7 @@
struct omap_connector {
struct drm_connector base;
struct omap_dss_device *dssdev;
+ struct drm_display_mode *native_mode;
};
static inline void copy_timings_omap_to_drm(struct drm_display_mode *mode,
@@ -118,6 +119,104 @@ static void omap_connector_destroy(struct drm_connector *connector)
omap_dss_put_device(dssdev);
}
+static struct drm_display_mode * omap_connector_native_mode(
+ struct drm_connector *connector)
+{
+ struct omap_connector *omap_connector = to_omap_connector(connector);
+ struct drm_device *dev = connector->dev;
+ struct drm_display_mode *mode, *largest = NULL;
+ int high_w = 0, high_h = 0, high_v = 0;
+
+ list_for_each_entry(mode, &omap_connector->base.probed_modes, head) {
+ mode->vrefresh = drm_mode_vrefresh(mode);
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+ continue;
+
+ /* Use preferred mode if there is one */
+ if (mode->type & DRM_MODE_TYPE_PREFERRED) {
+ DBG("native mode from preferred: %dx%d@%d",
+ mode->hdisplay, mode->vdisplay, mode->vrefresh);
+ return drm_mode_duplicate(dev, mode);
+ }
+
+ /* Otherwise, take the resolution with the largest width, then
+ * height, then vertical refresh
+ */
+ if (mode->hdisplay < high_w)
+ continue;
+
+ if (mode->hdisplay == high_w && mode->vdisplay < high_h)
+ continue;
+
+ if (mode->hdisplay == high_w && mode->vdisplay == high_h &&
+ mode->vrefresh < high_v)
+ continue;
+
+ high_w = mode->hdisplay;
+ high_h = mode->vdisplay;
+ high_v = mode->vrefresh;
+ largest = mode;
+ }
+
+ DBG("native mode from largest: %dx%d@%d", high_w, high_h, high_v);
+ return largest ? drm_mode_duplicate(dev, largest) : NULL;
+}
+
+struct moderec {
+ int hdisplay;
+ int vdisplay;
+};
+
+static struct moderec scaler_modes[] = {
+ { 1920, 1200 },
+ { 1920, 1080 },
+ { 1680, 1050 },
+ { 1600, 1200 },
+ { 1400, 1050 },
+ { 1400, 900 },
+ { 1280, 1024 },
+ { 1280, 960 },
+ { 1280, 720 },
+ { 1152, 768 },
+ { 1024, 768 },
+ { 800, 600 },
+ { 720, 480 },
+ { 640, 480 },
+ {}
+};
+
+static int omap_connector_scaler_modes_add(struct drm_connector *connector)
+{
+ struct omap_connector *omap_connector = to_omap_connector(connector);
+ struct drm_display_mode *native = omap_connector->native_mode, *m;
+ struct drm_device *dev = connector->dev;
+ struct moderec *mode = &scaler_modes[0];
+ int modes = 0;
+
+ if (!native)
+ return 0;
+
+ while (mode->hdisplay) {
+ if (mode->hdisplay <= native->hdisplay &&
+ mode->vdisplay <= native->vdisplay) {
+ m = drm_cvt_mode(dev, mode->hdisplay, mode->vdisplay,
+ 60, true, false, false);
+ if (!m)
+ continue;
+
+ m->type |= DRM_MODE_TYPE_DRIVER;
+
+ DBG("adding scaler mode: %dx%d@%d", mode->hdisplay,
+ mode->vdisplay, drm_mode_vrefresh(m));
+ drm_mode_probed_add(connector, m);
+ modes++;
+ }
+ mode++;
+ }
+
+ return modes;
+}
+
#define MAX_EDID 256
static int omap_connector_get_modes(struct drm_connector *connector)
@@ -130,6 +229,11 @@ static int omap_connector_get_modes(struct drm_connector *connector)
DBG("%s", omap_connector->dssdev->name);
+ if (omap_connector->native_mode) {
+ drm_mode_destroy(dev, omap_connector->native_mode);
+ omap_connector->native_mode = NULL;
+ }
+
/* if display exposes EDID, then we parse that in the normal way to
* build table of supported modes.. otherwise (ie. fixed resolution
* LCD panels) we just return a single mode corresponding to the
@@ -142,6 +246,9 @@ static int omap_connector_get_modes(struct drm_connector *connector)
drm_edid_is_valid(edid)) {
drm_mode_connector_update_edid_property(connector, edid);
n = drm_add_edid_modes(connector, edid);
+ omap_connector->native_mode =
+ omap_connector_native_mode(connector);
+ n += omap_connector_scaler_modes_add(connector);
kfree(connector->display_info.raw_edid);
connector->display_info.raw_edid = edid;
} else {