diff options
Diffstat (limited to 'drivers/gpu/drm/ingenic/ingenic-drm-drv.c')
-rw-r--r-- | drivers/gpu/drm/ingenic/ingenic-drm-drv.c | 60 |
1 files changed, 47 insertions, 13 deletions
diff --git a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c index 368bfef8b340..7bb31fbee29d 100644 --- a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c +++ b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c @@ -14,6 +14,7 @@ #include <linux/of_device.h> #include <linux/of_reserved_mem.h> #include <linux/platform_device.h> +#include <linux/pm.h> #include <linux/regmap.h> #include <drm/drm_atomic.h> @@ -190,15 +191,15 @@ static void ingenic_drm_crtc_update_timings(struct ingenic_drm *priv, { unsigned int vpe, vds, vde, vt, hpe, hds, hde, ht; - vpe = mode->vsync_end - mode->vsync_start; - vds = mode->vtotal - mode->vsync_start; - vde = vds + mode->vdisplay; - vt = vde + mode->vsync_start - mode->vdisplay; + vpe = mode->crtc_vsync_end - mode->crtc_vsync_start; + vds = mode->crtc_vtotal - mode->crtc_vsync_start; + vde = vds + mode->crtc_vdisplay; + vt = vde + mode->crtc_vsync_start - mode->crtc_vdisplay; - hpe = mode->hsync_end - mode->hsync_start; - hds = mode->htotal - mode->hsync_start; - hde = hds + mode->hdisplay; - ht = hde + mode->hsync_start - mode->hdisplay; + hpe = mode->crtc_hsync_end - mode->crtc_hsync_start; + hds = mode->crtc_htotal - mode->crtc_hsync_start; + hde = hds + mode->crtc_hdisplay; + ht = hde + mode->crtc_hsync_start - mode->crtc_hdisplay; regmap_write(priv->map, JZ_REG_LCD_VSYNC, 0 << JZ_LCD_VSYNC_VPS_OFFSET | @@ -333,7 +334,7 @@ static void ingenic_drm_crtc_atomic_flush(struct drm_crtc *crtc, struct drm_pending_vblank_event *event = crtc_state->event; if (drm_atomic_crtc_needs_modeset(crtc_state)) { - ingenic_drm_crtc_update_timings(priv, &crtc_state->mode); + ingenic_drm_crtc_update_timings(priv, &crtc_state->adjusted_mode); priv->update_clk_rate = true; } @@ -589,7 +590,7 @@ static void ingenic_drm_encoder_atomic_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode = &crtc_state->adjusted_mode; struct drm_connector *conn = conn_state->connector; struct drm_display_info *info = &conn->display_info; - unsigned int cfg; + unsigned int cfg, rgbcfg = 0; priv->panel_is_sharp = info->bus_flags & DRM_BUS_FLAG_SHARP_SIGNALS; @@ -626,6 +627,9 @@ static void ingenic_drm_encoder_atomic_mode_set(struct drm_encoder *encoder, case MEDIA_BUS_FMT_RGB888_1X24: cfg |= JZ_LCD_CFG_MODE_GENERIC_24BIT; break; + case MEDIA_BUS_FMT_RGB888_3X8_DELTA: + rgbcfg = JZ_LCD_RGBC_EVEN_GBR | JZ_LCD_RGBC_ODD_RGB; + fallthrough; case MEDIA_BUS_FMT_RGB888_3X8: cfg |= JZ_LCD_CFG_MODE_8BIT_SERIAL; break; @@ -636,6 +640,7 @@ static void ingenic_drm_encoder_atomic_mode_set(struct drm_encoder *encoder, } regmap_write(priv->map, JZ_REG_LCD_CFG, cfg); + regmap_write(priv->map, JZ_REG_LCD_RGBC, rgbcfg); } static int ingenic_drm_encoder_atomic_check(struct drm_encoder *encoder, @@ -643,6 +648,7 @@ static int ingenic_drm_encoder_atomic_check(struct drm_encoder *encoder, struct drm_connector_state *conn_state) { struct drm_display_info *info = &conn_state->connector->display_info; + struct drm_display_mode *mode = &crtc_state->adjusted_mode; if (info->num_bus_formats != 1) return -EINVAL; @@ -651,10 +657,23 @@ static int ingenic_drm_encoder_atomic_check(struct drm_encoder *encoder, return 0; switch (*info->bus_formats) { + case MEDIA_BUS_FMT_RGB888_3X8: + case MEDIA_BUS_FMT_RGB888_3X8_DELTA: + /* + * The LCD controller expects timing values in dot-clock ticks, + * which is 3x the timing values in pixels when using a 3x8-bit + * display; but it will count the display area size in pixels + * either way. Go figure. + */ + mode->crtc_clock = mode->clock * 3; + mode->crtc_hsync_start = mode->hsync_start * 3 - mode->hdisplay * 2; + mode->crtc_hsync_end = mode->hsync_end * 3 - mode->hdisplay * 2; + mode->crtc_hdisplay = mode->hdisplay; + mode->crtc_htotal = mode->htotal * 3 - mode->hdisplay * 2; + return 0; case MEDIA_BUS_FMT_RGB565_1X16: case MEDIA_BUS_FMT_RGB666_1X18: case MEDIA_BUS_FMT_RGB888_1X24: - case MEDIA_BUS_FMT_RGB888_3X8: return 0; default: return -EINVAL; @@ -755,8 +774,6 @@ static const struct drm_crtc_funcs ingenic_drm_crtc_funcs = { .enable_vblank = ingenic_drm_enable_vblank, .disable_vblank = ingenic_drm_disable_vblank, - - .gamma_set = drm_atomic_helper_legacy_gamma_set, }; static const struct drm_plane_helper_funcs ingenic_drm_plane_helper_funcs = { @@ -1167,6 +1184,22 @@ static int ingenic_drm_remove(struct platform_device *pdev) return 0; } +static int __maybe_unused ingenic_drm_suspend(struct device *dev) +{ + struct ingenic_drm *priv = dev_get_drvdata(dev); + + return drm_mode_config_helper_suspend(&priv->drm); +} + +static int __maybe_unused ingenic_drm_resume(struct device *dev) +{ + struct ingenic_drm *priv = dev_get_drvdata(dev); + + return drm_mode_config_helper_resume(&priv->drm); +} + +static SIMPLE_DEV_PM_OPS(ingenic_drm_pm_ops, ingenic_drm_suspend, ingenic_drm_resume); + static const u32 jz4740_formats[] = { DRM_FORMAT_XRGB1555, DRM_FORMAT_RGB565, @@ -1246,6 +1279,7 @@ MODULE_DEVICE_TABLE(of, ingenic_drm_of_match); static struct platform_driver ingenic_drm_driver = { .driver = { .name = "ingenic-drm", + .pm = pm_ptr(&ingenic_drm_pm_ops), .of_match_table = of_match_ptr(ingenic_drm_of_match), }, .probe = ingenic_drm_probe, |