diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 164dfb34799eb2..483174cfe8be6b 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -229,6 +229,7 @@ static void modehack_handler(struct work_struct *work) struct drm_display_mode *mode1, *mode_first = NULL, *mode2 = NULL; bool next = false; char *envp[2]; + int ret; if (!modehack_set.crtc) return; @@ -254,6 +255,7 @@ static void modehack_handler(struct work_struct *work) if (next) { next = false; mode2 = mode1; + break; } next = drm_mode_equal(&modehack_set.crtc->mode, mode1); } @@ -271,7 +273,11 @@ static void modehack_handler(struct work_struct *work) modehack_set.num_connectors = 1; drm_helper_connector_dpms(connector, DRM_MODE_DPMS_STANDBY); - drm_crtc_helper_set_config(&modehack_set); + ret = drm_crtc_helper_set_config(&modehack_set); + if (ret) { + modehack_set.crtc->mode = *mode2; /* skip this mode */ + goto bail; + } drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); envp[0] = "SOURCE=hotkey"; diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_ade.c b/drivers/gpu/drm/hisilicon/hisi_drm_ade.c index 22e5b66ef7bfca..87c2a45af90b29 100644 --- a/drivers/gpu/drm/hisilicon/hisi_drm_ade.c +++ b/drivers/gpu/drm/hisilicon/hisi_drm_ade.c @@ -342,6 +342,17 @@ static bool hisi_drm_crtc_mode_fixup(struct drm_crtc *crtc, pr_info("%s: pixel clock: req %dkHz -> actual: %dkHz\n", __func__, mode->clock, adj_mode->clock); + /* adjust 720p timings to let output more stable */ + if (mode->hdisplay == 1280 && mode->vdisplay == 720 && + mode->vrefresh == 60) + { + adj_mode->hsync_start = 1500; + adj_mode->hsync_end = 1540; + adj_mode->vsync_start = 740; + adj_mode->vsync_end = 745; + } + + DRM_DEBUG_DRIVER("mode_fixup exit successfully.\n"); return true; } @@ -354,14 +365,14 @@ static void hisi_drm_crtc_mode_prepare(struct drm_crtc *crtc) static int hisi_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode, + struct drm_display_mode *adj_mode, int x, int y, struct drm_framebuffer *old_fb) { struct hisi_drm_ade_crtc *crtc_ade = to_hisi_crtc(crtc); DRM_DEBUG_DRIVER("mode_set enter successfully.\n"); - crtc_ade->dmode = mode; + crtc_ade->dmode = adj_mode; DRM_DEBUG_DRIVER("mode_set exit successfully.\n"); return 0; } diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c index a44bc39dfd1316..1be1d2450eb5ac 100644 --- a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c +++ b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c @@ -154,6 +154,7 @@ struct dsi_phy_seq_info dphy_seq_info[] = { static struct drm_display_mode mode_720p_canned = { .name = "720p60", + .vrefresh = 60, .type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER, .clock = 74250, .hdisplay = 1280, @@ -169,6 +170,50 @@ static struct drm_display_mode mode_720p_canned = { .height_mm = 420, }; +/* + * 800x600@60 works well, so add to defaut modes + */ +static struct drm_display_mode mode_800x600_canned = { + .name = "800x600", + .vrefresh = 60, + .clock = 40000, + .hdisplay = 800, + .hsync_start = 840, + .hsync_end = 968, + .htotal = 1056, + .vdisplay = 600, + .vsync_start = 601, + .vsync_end = 605, + .vtotal = 628, + .type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER, + .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC, + .width_mm = 735, + .height_mm = 420, +}; + +static int hisi_get_default_modes(struct drm_connector *connector) +{ + struct drm_display_mode *mode; + + /* 1280x720@60: 720P */ + mode = drm_mode_duplicate(connector->dev, &mode_720p_canned); + if (!mode) { + DRM_ERROR("failed to create a new display mode\n"); + } + + drm_mode_probed_add(connector, mode); + + /* 800x600@60 */ + mode = drm_mode_duplicate(connector->dev, &mode_800x600_canned); + if (!mode) { + DRM_ERROR("failed to create a new display mode\n"); + } + + drm_mode_probed_add(connector, mode); + + return 2; +} + static inline void set_reg(u8 *addr, u32 val, u32 bw, u32 bs) { u32 mask = (1 << bw) - 1; @@ -795,14 +840,14 @@ static void hisi_drm_encoder_dpms(struct drm_encoder *encoder, int mode) static bool hisi_drm_encoder_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) + struct drm_display_mode *adj_mode) { struct drm_encoder_slave_funcs *sfuncs = get_slave_funcs(encoder); bool ret = true; DRM_DEBUG_DRIVER("enter.\n"); if (sfuncs->mode_fixup) - ret = sfuncs->mode_fixup(encoder, mode, adjusted_mode); + ret = sfuncs->mode_fixup(encoder, mode, adj_mode); DRM_DEBUG_DRIVER("exit success.ret=%d\n", ret); @@ -811,7 +856,7 @@ hisi_drm_encoder_mode_fixup(struct drm_encoder *encoder, static void hisi_drm_encoder_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) + struct drm_display_mode *adj_mode) { struct hisi_dsi *dsi = encoder_to_dsi(encoder); struct videomode *vm = &dsi->vm; @@ -819,17 +864,17 @@ static void hisi_drm_encoder_mode_set(struct drm_encoder *encoder, u32 dphy_freq_kHz; DRM_DEBUG_DRIVER("enter.\n"); - vm->pixelclock = adjusted_mode->clock; - dsi->nominal_pixel_clock_kHz = mode->clock; - - vm->hactive = mode->hdisplay; - vm->vactive = mode->vdisplay; - vm->vfront_porch = mode->vsync_start - mode->vdisplay; - vm->vback_porch = mode->vtotal - mode->vsync_end; - vm->vsync_len = mode->vsync_end - mode->vsync_start; - vm->hfront_porch = mode->hsync_start - mode->hdisplay; - vm->hback_porch = mode->htotal - mode->hsync_end; - vm->hsync_len = mode->hsync_end - mode->hsync_start; + vm->pixelclock = adj_mode->clock; + dsi->nominal_pixel_clock_kHz = adj_mode->clock; + + vm->hactive = adj_mode->hdisplay; + vm->vactive = adj_mode->vdisplay; + vm->vfront_porch = adj_mode->vsync_start - adj_mode->vdisplay; + vm->vback_porch = adj_mode->vtotal - adj_mode->vsync_end; + vm->vsync_len = adj_mode->vsync_end - adj_mode->vsync_start; + vm->hfront_porch = adj_mode->hsync_start - adj_mode->hdisplay; + vm->hback_porch = adj_mode->htotal - adj_mode->hsync_end; + vm->hsync_len = adj_mode->hsync_end - adj_mode->hsync_start; dsi->lanes = 3 + !!(vm->pixelclock >= 115000); @@ -851,7 +896,7 @@ static void hisi_drm_encoder_mode_set(struct drm_encoder *encoder, vm->flags |= DISPLAY_FLAGS_VSYNC_LOW; if (sfuncs->mode_set) - sfuncs->mode_set(encoder, mode, adjusted_mode); + sfuncs->mode_set(encoder, mode, adj_mode); DRM_DEBUG_DRIVER("exit success: pixelclk=%dkHz, dphy_freq_kHz=%dkHz\n", (u32)vm->pixelclock, dphy_freq_kHz); } @@ -906,6 +951,7 @@ static void hisi_dsi_connector_destroy(struct drm_connector *connector) drm_connector_cleanup(connector); } +#if 0 static int hisi_dsi_fallback_mode(struct drm_connector *connector) { struct drm_display_mode *mode = kmalloc(sizeof(*mode), GFP_KERNEL); @@ -917,13 +963,14 @@ static int hisi_dsi_fallback_mode(struct drm_connector *connector) return 0; } +#endif 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, - .fallback_mode = hisi_dsi_fallback_mode, + /* .fallback_mode = hisi_dsi_fallback_mode, */ }; static int hisi_dsi_get_modes(struct drm_connector *connector) @@ -937,6 +984,10 @@ static int hisi_dsi_get_modes(struct drm_connector *connector) DRM_DEBUG_DRIVER("enter.\n"); if (sfuncs->get_modes) count = sfuncs->get_modes(encoder, connector); + + /* always add modes which work well on most mornitors */ + count += hisi_get_default_modes(connector); + DRM_DEBUG_DRIVER("exit success. count=%d\n", count); return count; } @@ -959,6 +1010,14 @@ static int hisi_drm_connector_mode_valid(struct drm_connector *connector, struct drm_encoder *encoder = &dsi->base.base; struct drm_encoder_slave_funcs *sfuncs = get_slave_funcs(encoder); int ret = MODE_OK; + int vrate; + + if (mode->flags & DRM_MODE_FLAG_INTERLACE) + return MODE_NO_INTERLACE; + + /* pixel clock support range is (1190494208/64 Hz, 1190494208Hz) */ + if (mode->clock < 18602 || mode->clock > 1190494) + return MODE_CLOCK_RANGE; if (sfuncs->mode_valid) { ret = sfuncs->mode_valid(encoder, mode); @@ -966,6 +1025,23 @@ static int hisi_drm_connector_mode_valid(struct drm_connector *connector, return ret; } + /* + * some work well modes which want to add prefer type + * others will clear prefer + */ + vrate = mode->vrefresh = drm_mode_vrefresh(mode); + if ((mode->hdisplay == 1920 && mode->vdisplay == 1200 && vrate == 59) || + (mode->hdisplay == 1920 && mode->vdisplay == 1080) || + (mode->hdisplay == 1680 && mode->vdisplay == 1050 && vrate == 59) || + (mode->hdisplay == 1280 && mode->vdisplay == 1024 && vrate == 60) || + (mode->hdisplay == 1280 && mode->vdisplay == 720 && + (vrate == 60 || vrate == 59 || vrate == 50)) || + (mode->hdisplay == 800 && mode->vdisplay == 600 && vrate == 60)) + mode->type |= DRM_MODE_TYPE_PREFERRED; + else + mode->type &= ~DRM_MODE_TYPE_PREFERRED; + + DRM_DEBUG_DRIVER("exit success. ret=%d\n", ret); return ret; }