summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy Green <andy.green@linaro.org>2015-06-17 18:23:57 +0800
committerGuodong Xu <guodong.xu@linaro.org>2015-08-19 14:09:24 +0800
commit3772527ca2133b1f31deeae9671bf1cc2485e470 (patch)
treeb6a5ccfda6d254424b8c19a2ff5c24c09da0cfbf
parent06e7847f21b26f84aac38ad7ba499f20c7603f4a (diff)
V3 drm hisi provide canned 720p if no other mode
This creates a canned DRM mode for 720p60, and in the event there is no usable mode left after DRM checks validity, the canned mode will be used. This is helpful in two cases 1) No EDID appeared, but the device supports the fallback mode 2) An EDID appeared, but it does not list any acceptable mode. However, the device does actually support the fallback mode. It's implemented by adding a new optional connector func callback which is called in the event we are left with no valid modes. Connectors may handle the "fallback_mode" callback and add a fallback mode to use rather than the DRM default of 1024 x 768. In the case no EDID came but you forced your mode with video= on the kernel commandline, normally DRM will attempt to synthesize appropriate mode timings. But these very seldom work with HDMI monitors. In the case a mode was forced that does not exist in the EDID already but a fallback mode exists, this patch makes it choose the fallback mode and ignore the mode forcing. You can test "no EDID" by shorting HDMI connector p16 (SDA) to p17 (0V) Signed-off-by: Andy Green <andy.green@linaro.org>
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c10
-rw-r--r--drivers/gpu/drm/drm_probe_helper.c21
-rw-r--r--drivers/gpu/drm/hisilicon/hisi_drm_dsi.c43
-rw-r--r--include/drm/drm_crtc.h2
4 files changed, 69 insertions, 7 deletions
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 0c0c39bac23d..767adfcb8a37 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -1262,6 +1262,16 @@ struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *f
}
create_mode:
+ /*
+ * Synthetic mode timing is very unlikely to work on HDMI. Instead
+ * if there is a fallback mode, give up on trying to guess the forced
+ * mode timing and just let the forced mode deal with it.
+ */
+ if (fb_helper_conn->connector->funcs->fallback_mode) {
+ pr_err("%s: preferring fallback mode\n", __func__);
+ return NULL;
+ }
+
mode = drm_mode_create_from_cmdline_mode(fb_helper_conn->connector->dev,
cmdline_mode);
list_add(&mode->head, &fb_helper_conn->connector->modes);
diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c
index 6857e9ad6339..f240a689e92f 100644
--- a/drivers/gpu/drm/drm_probe_helper.c
+++ b/drivers/gpu/drm/drm_probe_helper.c
@@ -155,11 +155,15 @@ static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connect
count = (*connector_funcs->get_modes)(connector);
}
- if (count == 0 && connector->status == connector_status_connected)
+ if (count == 0 && connector->status == connector_status_connected &&
+ !connector->funcs->fallback_mode)
count = drm_add_modes_noedid(connector, 1024, 768);
- count += drm_helper_probe_add_cmdline_mode(connector);
- if (count == 0)
- goto prune;
+
+ if (count || !connector->funcs->fallback_mode) {
+ count += drm_helper_probe_add_cmdline_mode(connector);
+ if (count == 0)
+ goto prune;
+ }
drm_mode_connector_list_update(connector, merge_type_bits);
@@ -183,8 +187,13 @@ static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connect
prune:
drm_mode_prune_invalid(dev, &connector->modes, verbose_prune);
- if (list_empty(&connector->modes))
- return 0;
+ if (list_empty(&connector->modes)) {
+ if (!connector->funcs->fallback_mode)
+ return 0;
+ if (connector->funcs->fallback_mode(connector))
+ return 0;
+ count = 1;
+ }
list_for_each_entry(mode, &connector->modes, head)
mode->vrefresh = drm_mode_vrefresh(mode);
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
index 369252dbbead..fcc1edb3ffd4 100644
--- a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
@@ -140,6 +140,34 @@ struct dsi_phy_seq_info dphy_seq_info[] = {
{ 1000000, 1500000, 0, 0 }
};
+/*
+ * Canned 720p60 mode for use if no whitelisted modes
+ * available (due to no EDID or EDID contains no whitelisted
+ * mode)
+ *
+ * Detailed mode: Clock 74.250 MHz, 735 mm x 420 mm
+ * 1280 1390 1430 1650 hborder 0
+ * 720 725 730 750 vborder 0
+ * +hsync +vsync
+ */
+
+static struct drm_display_mode mode_720p_canned = {
+ .name = "720p60",
+ .type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER,
+ .clock = 74250,
+ .hdisplay = 1280,
+ .hsync_start = 1390,
+ .hsync_end = 1430,
+ .htotal = 1650,
+ .vdisplay = 720,
+ .vsync_start = 725,
+ .vsync_end = 730,
+ .vtotal = 750,
+ .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC,
+ .width_mm = 735,
+ .height_mm = 420,
+};
+
static inline void set_reg(u8 *addr, u32 val, u32 bw, u32 bs)
{
u32 mask = (1 << bw) - 1;
@@ -857,11 +885,24 @@ static void hisi_dsi_connector_destroy(struct drm_connector *connector)
drm_connector_cleanup(connector);
}
+static int hisi_dsi_fallback_mode(struct drm_connector *connector)
+{
+ struct drm_display_mode *mode = kmalloc(sizeof(*mode), GFP_KERNEL);
+
+ pr_info("%s: adding canned fallback 720p mode\n", __func__);
+ memcpy(mode, &mode_720p_canned, sizeof(*mode));
+
+ list_add_tail(&mode->head, &connector->modes);
+
+ return 0;
+}
+
static struct drm_connector_funcs hisi_dsi_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = hisi_dsi_detect,
- .destroy = hisi_dsi_connector_destroy
+ .destroy = hisi_dsi_connector_destroy,
+ .fallback_mode = hisi_dsi_fallback_mode,
};
static int hisi_dsi_get_modes(struct drm_connector *connector)
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index c40070a92d6b..2b47aa1c5def 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -411,6 +411,8 @@ struct drm_connector_funcs {
uint64_t val);
void (*destroy)(struct drm_connector *connector);
void (*force)(struct drm_connector *connector);
+ /* optional mode connector wants to fall back to instead of 1024x768 */
+ int (*fallback_mode)(struct drm_connector *connector);
};
/**