diff options
-rw-r--r-- | drivers/gpu/drm/imx/imx-drm-core.c | 21 | ||||
-rw-r--r-- | drivers/gpu/drm/imx/imx-ldb.c | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/imx/ipuv3-crtc.c | 11 | ||||
-rw-r--r-- | drivers/gpu/drm/imx/ipuv3-plane.c | 115 | ||||
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-dc.c | 5 | ||||
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-di.c | 7 | ||||
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-dp.c | 25 | ||||
-rw-r--r-- | include/video/imx-ipu-v3.h | 2 |
8 files changed, 167 insertions, 24 deletions
diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c index 877d45eeb78e..76819a8ac37f 100644 --- a/drivers/gpu/drm/imx/imx-drm-core.c +++ b/drivers/gpu/drm/imx/imx-drm-core.c @@ -81,6 +81,7 @@ static void imx_drm_atomic_commit_tail(struct drm_atomic_state *state) struct drm_plane_state *old_plane_state, *new_plane_state; bool plane_disabling = false; int i; + bool fence_cookie = dma_fence_begin_signalling(); drm_atomic_helper_commit_modeset_disables(dev, state); @@ -111,6 +112,7 @@ static void imx_drm_atomic_commit_tail(struct drm_atomic_state *state) } drm_atomic_helper_commit_hw_done(state); + dma_fence_end_signalling(fence_cookie); } static const struct drm_mode_config_helper_funcs imx_drm_mode_config_helpers = { @@ -145,9 +147,26 @@ static const struct drm_ioctl_desc imx_drm_ioctls[] = { /* none so far */ }; +static int imx_drm_dumb_create(struct drm_file *file_priv, + struct drm_device *drm, + struct drm_mode_create_dumb *args) +{ + u32 width = args->width; + int ret; + + args->width = ALIGN(width, 8); + + ret = drm_gem_cma_dumb_create(file_priv, drm, args); + if (ret) + return ret; + + args->width = width; + return ret; +} + static const struct drm_driver imx_drm_driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC, - DRM_GEM_CMA_DRIVER_OPS, + DRM_GEM_CMA_DRIVER_OPS_WITH_DUMB_CREATE(imx_drm_dumb_create), .ioctls = imx_drm_ioctls, .num_ioctls = ARRAY_SIZE(imx_drm_ioctls), .fops = &imx_drm_driver_fops, diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c index ffdc492c5bc5..53132ddf9587 100644 --- a/drivers/gpu/drm/imx/imx-ldb.c +++ b/drivers/gpu/drm/imx/imx-ldb.c @@ -274,6 +274,11 @@ imx_ldb_encoder_atomic_mode_set(struct drm_encoder *encoder, "%s: mode exceeds 85 MHz pixel clock\n", __func__); } + if (!IS_ALIGNED(mode->hdisplay, 8)) { + dev_warn(ldb->dev, + "%s: hdisplay does not align to 8 byte\n", __func__); + } + if (dual) { serial_clk = 3500UL * mode->clock; imx_ldb_set_clock(ldb, mux, 0, serial_clk, di_clk); diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c index e6431a227feb..9c8829f945b2 100644 --- a/drivers/gpu/drm/imx/ipuv3-crtc.c +++ b/drivers/gpu/drm/imx/ipuv3-crtc.c @@ -305,10 +305,19 @@ static void ipu_crtc_mode_set_nofb(struct drm_crtc *crtc) sig_cfg.vsync_pin = imx_crtc_state->di_vsync_pin; drm_display_mode_to_videomode(mode, &sig_cfg.mode); + if (!IS_ALIGNED(sig_cfg.mode.hactive, 8)) { + unsigned int new_hactive = ALIGN(sig_cfg.mode.hactive, 8); + + dev_warn(ipu_crtc->dev, "8-pixel align hactive %d -> %d\n", + sig_cfg.mode.hactive, new_hactive); + + sig_cfg.mode.hfront_porch = new_hactive - sig_cfg.mode.hactive; + sig_cfg.mode.hactive = new_hactive; + } ipu_dc_init_sync(ipu_crtc->dc, ipu_crtc->di, mode->flags & DRM_MODE_FLAG_INTERLACE, - imx_crtc_state->bus_format, mode->hdisplay); + imx_crtc_state->bus_format, sig_cfg.mode.hactive); ipu_di_init_sync_panel(ipu_crtc->di, &sig_cfg); } diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3-plane.c index fa5009705365..8710f55d2579 100644 --- a/drivers/gpu/drm/imx/ipuv3-plane.c +++ b/drivers/gpu/drm/imx/ipuv3-plane.c @@ -30,12 +30,17 @@ to_ipu_plane_state(struct drm_plane_state *p) return container_of(p, struct ipu_plane_state, base); } +static unsigned int ipu_src_rect_width(const struct drm_plane_state *state) +{ + return ALIGN(drm_rect_width(&state->src) >> 16, 8); +} + static inline struct ipu_plane *to_ipu_plane(struct drm_plane *p) { return container_of(p, struct ipu_plane, base); } -static const uint32_t ipu_plane_formats[] = { +static const uint32_t ipu_plane_all_formats[] = { DRM_FORMAT_ARGB1555, DRM_FORMAT_XRGB1555, DRM_FORMAT_ABGR1555, @@ -72,6 +77,31 @@ static const uint32_t ipu_plane_formats[] = { DRM_FORMAT_BGRX8888_A8, }; +static const uint32_t ipu_plane_rgb_formats[] = { + DRM_FORMAT_ARGB1555, + DRM_FORMAT_XRGB1555, + DRM_FORMAT_ABGR1555, + DRM_FORMAT_XBGR1555, + DRM_FORMAT_RGBA5551, + DRM_FORMAT_BGRA5551, + DRM_FORMAT_ARGB4444, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_ABGR8888, + DRM_FORMAT_XBGR8888, + DRM_FORMAT_RGBA8888, + DRM_FORMAT_RGBX8888, + DRM_FORMAT_BGRA8888, + DRM_FORMAT_BGRX8888, + DRM_FORMAT_RGB565, + DRM_FORMAT_RGB565_A8, + DRM_FORMAT_BGR565_A8, + DRM_FORMAT_RGB888_A8, + DRM_FORMAT_BGR888_A8, + DRM_FORMAT_RGBX8888_A8, + DRM_FORMAT_BGRX8888_A8, +}; + static const uint64_t ipu_format_modifiers[] = { DRM_FORMAT_MOD_LINEAR, DRM_FORMAT_MOD_INVALID @@ -264,7 +294,6 @@ void ipu_plane_disable_deferred(struct drm_plane *plane) ipu_plane_disable(ipu_plane, false); } } -EXPORT_SYMBOL_GPL(ipu_plane_disable_deferred); static void ipu_plane_state_reset(struct drm_plane *plane) { @@ -284,6 +313,8 @@ static void ipu_plane_state_reset(struct drm_plane *plane) __drm_atomic_helper_plane_reset(plane, &ipu_state->base); ipu_state->base.zpos = zpos; ipu_state->base.normalized_zpos = zpos; + ipu_state->base.color_encoding = DRM_COLOR_YCBCR_BT601; + ipu_state->base.color_range = DRM_COLOR_YCBCR_LIMITED_RANGE; } } @@ -320,10 +351,11 @@ static bool ipu_plane_format_mod_supported(struct drm_plane *plane, if (modifier == DRM_FORMAT_MOD_LINEAR) return true; - /* without a PRG there are no supported modifiers */ - if (!ipu_prg_present(ipu)) - return false; - + /* + * Without a PRG the possible modifiers list only includes the linear + * modifier, so we always take the early return from this function and + * only end up here if the PRG is present. + */ return ipu_prg_format_supported(ipu, format, modifier); } @@ -415,6 +447,12 @@ static int ipu_plane_atomic_check(struct drm_plane *plane, if (old_fb && fb->pitches[0] != old_fb->pitches[0]) crtc_state->mode_changed = true; + if (ALIGN(fb->width, 8) * fb->format->cpp[0] > + fb->pitches[0] + fb->offsets[0]) { + dev_warn(dev, "pitch is not big enough for 8 pixels alignment"); + return -EINVAL; + } + switch (fb->format->format) { case DRM_FORMAT_YUV420: case DRM_FORMAT_YVU420: @@ -590,12 +628,31 @@ static void ipu_plane_atomic_update(struct drm_plane *plane, if (ipu_state->use_pre) { axi_id = ipu_chan_assign_axi_id(ipu_plane->dma); ipu_prg_channel_configure(ipu_plane->ipu_ch, axi_id, - drm_rect_width(&new_state->src) >> 16, + ipu_src_rect_width(new_state), drm_rect_height(&new_state->src) >> 16, fb->pitches[0], fb->format->format, fb->modifier, &eba); } + if (!old_state->fb || + old_state->fb->format->format != fb->format->format || + old_state->color_encoding != new_state->color_encoding || + old_state->color_range != new_state->color_range) { + ics = ipu_drm_fourcc_to_colorspace(fb->format->format); + switch (ipu_plane->dp_flow) { + case IPU_DP_FLOW_SYNC_BG: + ipu_dp_setup_channel(ipu_plane->dp, new_state->color_encoding, + new_state->color_range, ics, + IPUV3_COLORSPACE_RGB); + break; + case IPU_DP_FLOW_SYNC_FG: + ipu_dp_setup_channel(ipu_plane->dp, new_state->color_encoding, + new_state->color_range, ics, + IPUV3_COLORSPACE_UNKNOWN); + break; + } + } + if (old_state->fb && !drm_atomic_crtc_needs_modeset(crtc_state)) { /* nothing to do if PRE is used */ if (ipu_state->use_pre) @@ -615,17 +672,20 @@ static void ipu_plane_atomic_update(struct drm_plane *plane, ics = ipu_drm_fourcc_to_colorspace(fb->format->format); switch (ipu_plane->dp_flow) { case IPU_DP_FLOW_SYNC_BG: - ipu_dp_setup_channel(ipu_plane->dp, ics, IPUV3_COLORSPACE_RGB); + ipu_dp_setup_channel(ipu_plane->dp, DRM_COLOR_YCBCR_BT601, + DRM_COLOR_YCBCR_LIMITED_RANGE, ics, + IPUV3_COLORSPACE_RGB); break; case IPU_DP_FLOW_SYNC_FG: - ipu_dp_setup_channel(ipu_plane->dp, ics, - IPUV3_COLORSPACE_UNKNOWN); + ipu_dp_setup_channel(ipu_plane->dp, DRM_COLOR_YCBCR_BT601, + DRM_COLOR_YCBCR_LIMITED_RANGE, ics, + IPUV3_COLORSPACE_UNKNOWN); break; } ipu_dmfc_config_wait4eot(ipu_plane->dmfc, drm_rect_width(dst)); - width = drm_rect_width(&new_state->src) >> 16; + width = ipu_src_rect_width(new_state); height = drm_rect_height(&new_state->src) >> 16; info = drm_format_info(fb->format->format); ipu_calculate_bursts(width, info->cpp[0], fb->pitches[0], @@ -690,7 +750,7 @@ static void ipu_plane_atomic_update(struct drm_plane *plane, ipu_cpmem_zero(ipu_plane->alpha_ch); ipu_cpmem_set_resolution(ipu_plane->alpha_ch, - drm_rect_width(&new_state->src) >> 16, + ipu_src_rect_width(new_state), drm_rect_height(&new_state->src) >> 16); ipu_cpmem_set_format_passthrough(ipu_plane->alpha_ch, 8); ipu_cpmem_set_high_priority(ipu_plane->alpha_ch); @@ -821,7 +881,6 @@ int ipu_planes_assign_pre(struct drm_device *dev, return 0; } -EXPORT_SYMBOL_GPL(ipu_planes_assign_pre); struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu, int dma, int dp, unsigned int possible_crtcs, @@ -830,16 +889,28 @@ struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu, struct ipu_plane *ipu_plane; const uint64_t *modifiers = ipu_format_modifiers; unsigned int zpos = (type == DRM_PLANE_TYPE_PRIMARY) ? 0 : 1; + unsigned int format_count; + const uint32_t *formats; int ret; DRM_DEBUG_KMS("channel %d, dp flow %d, possible_crtcs=0x%x\n", dma, dp, possible_crtcs); + if (dp == IPU_DP_FLOW_SYNC_BG || dp == IPU_DP_FLOW_SYNC_FG) { + formats = ipu_plane_all_formats; + format_count = ARRAY_SIZE(ipu_plane_all_formats); + } else { + formats = ipu_plane_rgb_formats; + format_count = ARRAY_SIZE(ipu_plane_rgb_formats); + } + + if (ipu_prg_present(ipu)) + modifiers = pre_format_modifiers; + ipu_plane = drmm_universal_plane_alloc(dev, struct ipu_plane, base, possible_crtcs, &ipu_plane_funcs, - ipu_plane_formats, - ARRAY_SIZE(ipu_plane_formats), - modifiers, type, NULL); + formats, format_count, modifiers, + type, NULL); if (IS_ERR(ipu_plane)) { DRM_ERROR("failed to allocate and initialize %s plane\n", zpos ? "overlay" : "primary"); @@ -850,9 +921,6 @@ struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu, ipu_plane->dma = dma; ipu_plane->dp_flow = dp; - if (ipu_prg_present(ipu)) - modifiers = pre_format_modifiers; - drm_plane_helper_add(&ipu_plane->base, &ipu_plane_helper_funcs); if (dp == IPU_DP_FLOW_SYNC_BG || dp == IPU_DP_FLOW_SYNC_FG) @@ -864,6 +932,15 @@ struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu, if (ret) return ERR_PTR(ret); + ret = drm_plane_create_color_properties(&ipu_plane->base, + BIT(DRM_COLOR_YCBCR_BT601) | + BIT(DRM_COLOR_YCBCR_BT709), + BIT(DRM_COLOR_YCBCR_LIMITED_RANGE), + DRM_COLOR_YCBCR_BT601, + DRM_COLOR_YCBCR_LIMITED_RANGE); + if (ret) + return ERR_PTR(ret); + ret = ipu_plane_get_resources(dev, ipu_plane); if (ret) { DRM_ERROR("failed to get %s plane resources: %pe\n", diff --git a/drivers/gpu/ipu-v3/ipu-dc.c b/drivers/gpu/ipu-v3/ipu-dc.c index 34b4075a6a8e..ca96b235491a 100644 --- a/drivers/gpu/ipu-v3/ipu-dc.c +++ b/drivers/gpu/ipu-v3/ipu-dc.c @@ -167,6 +167,11 @@ int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced, dc->di = ipu_di_get_num(di); + if (!IS_ALIGNED(width, 8)) { + dev_warn(priv->dev, + "%s: hactive does not align to 8 byte\n", __func__); + } + map = ipu_bus_format_to_map(bus_format); /* diff --git a/drivers/gpu/ipu-v3/ipu-di.c b/drivers/gpu/ipu-v3/ipu-di.c index e617f60afeea..666223c6bec4 100644 --- a/drivers/gpu/ipu-v3/ipu-di.c +++ b/drivers/gpu/ipu-v3/ipu-di.c @@ -506,6 +506,13 @@ int ipu_di_adjust_videomode(struct ipu_di *di, struct videomode *mode) { u32 diff; + if (!IS_ALIGNED(mode->hactive, 8) && + mode->hfront_porch < ALIGN(mode->hactive, 8) - mode->hactive) { + dev_err(di->ipu->dev, "hactive %d is not aligned to 8 and front porch is too small to compensate\n", + mode->hactive); + return -EINVAL; + } + if (mode->vfront_porch >= 2) return 0; diff --git a/drivers/gpu/ipu-v3/ipu-dp.c b/drivers/gpu/ipu-v3/ipu-dp.c index 8f67e985f26a..6a558205db96 100644 --- a/drivers/gpu/ipu-v3/ipu-dp.c +++ b/drivers/gpu/ipu-v3/ipu-dp.c @@ -10,6 +10,7 @@ #include <linux/io.h> #include <linux/err.h> +#include <drm/drm_color_mgmt.h> #include <video/imx-ipu-v3.h> #include "ipu-prv.h" @@ -125,6 +126,8 @@ int ipu_dp_set_window_pos(struct ipu_dp *dp, u16 x_pos, u16 y_pos) EXPORT_SYMBOL_GPL(ipu_dp_set_window_pos); static void ipu_dp_csc_init(struct ipu_flow *flow, + enum drm_color_encoding ycbcr_enc, + enum drm_color_range range, enum ipu_color_space in, enum ipu_color_space out, u32 place) @@ -148,7 +151,18 @@ static void ipu_dp_csc_init(struct ipu_flow *flow, flow->base + DP_CSC_0); writel(0x200 | (2 << 14) | (0x200 << 16) | (2 << 30), flow->base + DP_CSC_1); + } else if (ycbcr_enc == DRM_COLOR_YCBCR_BT709) { + /* Rec.709 limited range */ + writel(0x095 | (0x000 << 16), flow->base + DP_CSC_A_0); + writel(0x0e5 | (0x095 << 16), flow->base + DP_CSC_A_1); + writel(0x3e5 | (0x3bc << 16), flow->base + DP_CSC_A_2); + writel(0x095 | (0x10e << 16), flow->base + DP_CSC_A_3); + writel(0x000 | (0x3e10 << 16) | (1 << 30), + flow->base + DP_CSC_0); + writel(0x09a | (1 << 14) | (0x3dbe << 16) | (1 << 30), + flow->base + DP_CSC_1); } else { + /* BT.601 limited range */ writel(0x095 | (0x000 << 16), flow->base + DP_CSC_A_0); writel(0x0cc | (0x095 << 16), flow->base + DP_CSC_A_1); writel(0x3ce | (0x398 << 16), flow->base + DP_CSC_A_2); @@ -165,6 +179,8 @@ static void ipu_dp_csc_init(struct ipu_flow *flow, } int ipu_dp_setup_channel(struct ipu_dp *dp, + enum drm_color_encoding ycbcr_enc, + enum drm_color_range range, enum ipu_color_space in, enum ipu_color_space out) { @@ -183,7 +199,8 @@ int ipu_dp_setup_channel(struct ipu_dp *dp, * foreground and background are of same colorspace, put * colorspace converter after combining unit. */ - ipu_dp_csc_init(flow, flow->foreground.in_cs, flow->out_cs, + ipu_dp_csc_init(flow, ycbcr_enc, range, + flow->foreground.in_cs, flow->out_cs, DP_COM_CONF_CSC_DEF_BOTH); } else { if (flow->foreground.in_cs == IPUV3_COLORSPACE_UNKNOWN || @@ -192,10 +209,12 @@ int ipu_dp_setup_channel(struct ipu_dp *dp, * foreground identical to output, apply color * conversion on background */ - ipu_dp_csc_init(flow, flow->background.in_cs, + ipu_dp_csc_init(flow, ycbcr_enc, range, + flow->background.in_cs, flow->out_cs, DP_COM_CONF_CSC_DEF_BG); else - ipu_dp_csc_init(flow, flow->foreground.in_cs, + ipu_dp_csc_init(flow, ycbcr_enc, range, + flow->foreground.in_cs, flow->out_cs, DP_COM_CONF_CSC_DEF_FG); } diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h index d1b3889f74d8..c422a403c099 100644 --- a/include/video/imx-ipu-v3.h +++ b/include/video/imx-ipu-v3.h @@ -17,6 +17,7 @@ #include <linux/bitmap.h> #include <linux/fb.h> #include <linux/of.h> +#include <drm/drm_color_mgmt.h> #include <media/v4l2-mediabus.h> #include <video/videomode.h> @@ -330,6 +331,7 @@ int ipu_dp_enable_channel(struct ipu_dp *dp); void ipu_dp_disable_channel(struct ipu_dp *dp, bool sync); void ipu_dp_disable(struct ipu_soc *ipu); int ipu_dp_setup_channel(struct ipu_dp *dp, + enum drm_color_encoding ycbcr_enc, enum drm_color_range range, enum ipu_color_space in, enum ipu_color_space out); int ipu_dp_set_window_pos(struct ipu_dp *, u16 x_pos, u16 y_pos); int ipu_dp_set_global_alpha(struct ipu_dp *dp, bool enable, u8 alpha, |