diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c index 3ce391c239b0..b300998dce7d 100644 --- a/drivers/gpu/drm/imx/imx-ldb.c +++ b/drivers/gpu/drm/imx/imx-ldb.c @@ -319,18 +319,6 @@ static void imx_ldb_encoder_disable(struct drm_encoder *encoder) struct imx_ldb *ldb = imx_ldb_ch->ldb; int mux, ret; - /* - * imx_ldb_encoder_disable is called by - * drm_helper_disable_unused_functions without - * the encoder being enabled before. - */ - if (imx_ldb_ch == &ldb->channel[0] && - (ldb->ldb_ctrl & LDB_CH0_MODE_EN_MASK) == 0) - return; - else if (imx_ldb_ch == &ldb->channel[1] && - (ldb->ldb_ctrl & LDB_CH1_MODE_EN_MASK) == 0) - return; - drm_panel_disable(imx_ldb_ch->panel); if (imx_ldb_ch == &ldb->channel[0]) diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3-plane.c index d5864ed4d772..6a97e396fce3 100644 --- a/drivers/gpu/drm/imx/ipuv3-plane.c +++ b/drivers/gpu/drm/imx/ipuv3-plane.c @@ -50,6 +50,12 @@ static const uint32_t ipu_plane_formats[] = { DRM_FORMAT_YVYU, DRM_FORMAT_YUV420, DRM_FORMAT_YVU420, + DRM_FORMAT_YUV422, + DRM_FORMAT_YVU422, + DRM_FORMAT_YUV444, + DRM_FORMAT_YVU444, + DRM_FORMAT_NV12, + DRM_FORMAT_NV16, DRM_FORMAT_RGB565, }; @@ -64,13 +70,14 @@ drm_plane_state_to_eba(struct drm_plane_state *state) { struct drm_framebuffer *fb = state->fb; struct drm_gem_cma_object *cma_obj; + int x = state->src_x >> 16; + int y = state->src_y >> 16; cma_obj = drm_fb_cma_get_gem_obj(fb, 0); BUG_ON(!cma_obj); - return cma_obj->paddr + fb->offsets[0] + - fb->pitches[0] * (state->src_y >> 16) + - (fb->bits_per_pixel >> 3) * (state->src_x >> 16); + return cma_obj->paddr + fb->offsets[0] + fb->pitches[0] * y + + drm_format_plane_cpp(fb->pixel_format, 0) * x; } static inline unsigned long @@ -79,13 +86,17 @@ drm_plane_state_to_ubo(struct drm_plane_state *state) struct drm_framebuffer *fb = state->fb; struct drm_gem_cma_object *cma_obj; unsigned long eba = drm_plane_state_to_eba(state); + int x = state->src_x >> 16; + int y = state->src_y >> 16; cma_obj = drm_fb_cma_get_gem_obj(fb, 1); BUG_ON(!cma_obj); - return cma_obj->paddr + fb->offsets[1] + - fb->pitches[1] * (state->src_y >> 16) / 2 + - (state->src_x >> 16) / 2 - eba; + x /= drm_format_horz_chroma_subsampling(fb->pixel_format); + y /= drm_format_vert_chroma_subsampling(fb->pixel_format); + + return cma_obj->paddr + fb->offsets[1] + fb->pitches[1] * y + + drm_format_plane_cpp(fb->pixel_format, 1) * x - eba; } static inline unsigned long @@ -94,69 +105,17 @@ drm_plane_state_to_vbo(struct drm_plane_state *state) struct drm_framebuffer *fb = state->fb; struct drm_gem_cma_object *cma_obj; unsigned long eba = drm_plane_state_to_eba(state); + int x = state->src_x >> 16; + int y = state->src_y >> 16; cma_obj = drm_fb_cma_get_gem_obj(fb, 2); BUG_ON(!cma_obj); - return cma_obj->paddr + fb->offsets[2] + - fb->pitches[2] * (state->src_y >> 16) / 2 + - (state->src_x >> 16) / 2 - eba; -} + x /= drm_format_horz_chroma_subsampling(fb->pixel_format); + y /= drm_format_vert_chroma_subsampling(fb->pixel_format); -static void ipu_plane_atomic_set_base(struct ipu_plane *ipu_plane) -{ - struct drm_plane *plane = &ipu_plane->base; - struct drm_plane_state *state = plane->state; - struct drm_crtc_state *crtc_state = state->crtc->state; - struct drm_framebuffer *fb = state->fb; - unsigned long eba, ubo, vbo; - int active; - - eba = drm_plane_state_to_eba(state); - - switch (fb->pixel_format) { - case DRM_FORMAT_YUV420: - case DRM_FORMAT_YVU420: - if (!drm_atomic_crtc_needs_modeset(crtc_state)) - break; - - /* - * Multiplanar formats have to meet the following restrictions: - * - The (up to) three plane addresses are EBA, EBA+UBO, EBA+VBO - * - EBA, UBO and VBO are a multiple of 8 - * - UBO and VBO are unsigned and not larger than 0xfffff8 - * - Only EBA may be changed while scanout is active - * - The strides of U and V planes must be identical. - */ - ubo = drm_plane_state_to_ubo(state); - vbo = drm_plane_state_to_vbo(state); - - if (fb->pixel_format == DRM_FORMAT_YUV420) - ipu_cpmem_set_yuv_planar_full(ipu_plane->ipu_ch, - fb->pitches[1], ubo, vbo); - else - ipu_cpmem_set_yuv_planar_full(ipu_plane->ipu_ch, - fb->pitches[1], vbo, ubo); - - dev_dbg(ipu_plane->base.dev->dev, - "phy = %lu %lu %lu, x = %d, y = %d", eba, ubo, vbo, - state->src_x >> 16, state->src_y >> 16); - break; - default: - dev_dbg(ipu_plane->base.dev->dev, "phys = %lu, x = %d, y = %d", - eba, state->src_x >> 16, state->src_y >> 16); - - break; - } - - if (!drm_atomic_crtc_needs_modeset(crtc_state)) { - active = ipu_idmac_get_current_buffer(ipu_plane->ipu_ch); - ipu_cpmem_set_buffer(ipu_plane->ipu_ch, !active, eba); - ipu_idmac_select_buffer(ipu_plane->ipu_ch, !active); - } else { - ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 0, eba); - ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 1, eba); - } + return cma_obj->paddr + fb->offsets[2] + fb->pitches[2] * y + + drm_format_plane_cpp(fb->pixel_format, 2) * x - eba; } void ipu_plane_put_resources(struct ipu_plane *ipu_plane) @@ -339,6 +298,10 @@ static int ipu_plane_atomic_check(struct drm_plane *plane, switch (fb->pixel_format) { case DRM_FORMAT_YUV420: case DRM_FORMAT_YVU420: + case DRM_FORMAT_YUV422: + case DRM_FORMAT_YVU422: + case DRM_FORMAT_YUV444: + case DRM_FORMAT_YVU444: /* * Multiplanar formats have to meet the following restrictions: * - The (up to) three plane addresses are EBA, EBA+UBO, EBA+VBO @@ -347,27 +310,34 @@ static int ipu_plane_atomic_check(struct drm_plane *plane, * - Only EBA may be changed while scanout is active * - The strides of U and V planes must be identical. */ - ubo = drm_plane_state_to_ubo(state); vbo = drm_plane_state_to_vbo(state); - if ((ubo & 0x7) || (vbo & 0x7)) + if (vbo & 0x7 || vbo > 0xfffff8) return -EINVAL; - if ((ubo > 0xfffff8) || (vbo > 0xfffff8)) - return -EINVAL; - - if (old_fb && - (old_fb->pixel_format == DRM_FORMAT_YUV420 || - old_fb->pixel_format == DRM_FORMAT_YVU420)) { - old_ubo = drm_plane_state_to_ubo(old_state); + if (old_fb && (fb->pixel_format == old_fb->pixel_format)) { old_vbo = drm_plane_state_to_vbo(old_state); - if (ubo != old_ubo || vbo != old_vbo) - return -EINVAL; + if (vbo != old_vbo) + crtc_state->mode_changed = true; } if (fb->pitches[1] != fb->pitches[2]) return -EINVAL; + /* fall-through */ + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV16: + ubo = drm_plane_state_to_ubo(state); + + if (ubo & 0x7 || ubo > 0xfffff8) + return -EINVAL; + + if (old_fb && (fb->pixel_format == old_fb->pixel_format)) { + old_ubo = drm_plane_state_to_ubo(old_state); + if (ubo != old_ubo) + crtc_state->mode_changed = true; + } + if (fb->pitches[1] < 1 || fb->pitches[1] > 16384) return -EINVAL; @@ -399,15 +369,19 @@ static void ipu_plane_atomic_update(struct drm_plane *plane, { struct ipu_plane *ipu_plane = to_ipu_plane(plane); struct drm_plane_state *state = plane->state; + struct drm_crtc_state *crtc_state = state->crtc->state; + struct drm_framebuffer *fb = state->fb; + unsigned long eba, ubo, vbo; enum ipu_color_space ics; + int active; - if (old_state->fb) { - struct drm_crtc_state *crtc_state = state->crtc->state; + eba = drm_plane_state_to_eba(state); - if (!drm_atomic_crtc_needs_modeset(crtc_state)) { - ipu_plane_atomic_set_base(ipu_plane); - return; - } + if (old_state->fb && !drm_atomic_crtc_needs_modeset(crtc_state)) { + active = ipu_idmac_get_current_buffer(ipu_plane->ipu_ch); + ipu_cpmem_set_buffer(ipu_plane->ipu_ch, !active, eba); + ipu_idmac_select_buffer(ipu_plane->ipu_ch, !active); + return; } switch (ipu_plane->dp_flow) { @@ -451,7 +425,45 @@ static void ipu_plane_atomic_update(struct drm_plane *plane, ipu_cpmem_set_high_priority(ipu_plane->ipu_ch); ipu_idmac_set_double_buffer(ipu_plane->ipu_ch, 1); ipu_cpmem_set_stride(ipu_plane->ipu_ch, state->fb->pitches[0]); - ipu_plane_atomic_set_base(ipu_plane); + switch (fb->pixel_format) { + case DRM_FORMAT_YUV420: + case DRM_FORMAT_YVU420: + case DRM_FORMAT_YUV422: + case DRM_FORMAT_YVU422: + case DRM_FORMAT_YUV444: + case DRM_FORMAT_YVU444: + ubo = drm_plane_state_to_ubo(state); + vbo = drm_plane_state_to_vbo(state); + if (fb->pixel_format == DRM_FORMAT_YVU420 || + fb->pixel_format == DRM_FORMAT_YVU422 || + fb->pixel_format == DRM_FORMAT_YVU444) + swap(ubo, vbo); + + ipu_cpmem_set_yuv_planar_full(ipu_plane->ipu_ch, + fb->pitches[1], ubo, vbo); + + dev_dbg(ipu_plane->base.dev->dev, + "phy = %lu %lu %lu, x = %d, y = %d", eba, ubo, vbo, + state->src_x >> 16, state->src_y >> 16); + break; + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV16: + ubo = drm_plane_state_to_ubo(state); + + ipu_cpmem_set_yuv_planar_full(ipu_plane->ipu_ch, + fb->pitches[1], ubo, ubo); + + dev_dbg(ipu_plane->base.dev->dev, + "phy = %lu %lu, x = %d, y = %d", eba, ubo, + state->src_x >> 16, state->src_y >> 16); + break; + default: + dev_dbg(ipu_plane->base.dev->dev, "phys = %lu, x = %d, y = %d", + eba, state->src_x >> 16, state->src_y >> 16); + break; + } + ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 0, eba); + ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 1, eba); ipu_plane_enable(ipu_plane); } diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c index b9539f7c5e9a..97218af4fe75 100644 --- a/drivers/gpu/ipu-v3/ipu-common.c +++ b/drivers/gpu/ipu-v3/ipu-common.c @@ -88,6 +88,8 @@ enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc) case DRM_FORMAT_YVU420: case DRM_FORMAT_YUV422: case DRM_FORMAT_YVU422: + case DRM_FORMAT_YUV444: + case DRM_FORMAT_YVU444: case DRM_FORMAT_NV12: case DRM_FORMAT_NV21: case DRM_FORMAT_NV16: @@ -1284,8 +1286,11 @@ static int ipu_irq_init(struct ipu_soc *ipu) return ret; } - for (i = 0; i < IPU_NUM_IRQS; i += 32) + /* Mask and clear all interrupts */ + for (i = 0; i < IPU_NUM_IRQS; i += 32) { ipu_cm_write(ipu, 0, IPU_INT_CTRL(i / 32)); + ipu_cm_write(ipu, ~unused[i / 32], IPU_INT_STAT(i / 32)); + } for (i = 0; i < IPU_NUM_IRQS; i += 32) { gc = irq_get_domain_generic_chip(ipu->domain, i); diff --git a/drivers/gpu/ipu-v3/ipu-cpmem.c b/drivers/gpu/ipu-v3/ipu-cpmem.c index fcb7dc86167b..4b2b67113d92 100644 --- a/drivers/gpu/ipu-v3/ipu-cpmem.c +++ b/drivers/gpu/ipu-v3/ipu-cpmem.c @@ -417,42 +417,6 @@ void ipu_cpmem_set_yuv_planar_full(struct ipuv3_channel *ch, } EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar_full); -void ipu_cpmem_set_yuv_planar(struct ipuv3_channel *ch, - u32 pixel_format, int stride, int height) -{ - int fourcc, u_offset, v_offset; - int uv_stride = 0; - - fourcc = v4l2_pix_fmt_to_drm_fourcc(pixel_format); - switch (fourcc) { - case DRM_FORMAT_YUV420: - uv_stride = stride / 2; - u_offset = stride * height; - v_offset = u_offset + (uv_stride * height / 2); - break; - case DRM_FORMAT_YVU420: - uv_stride = stride / 2; - v_offset = stride * height; - u_offset = v_offset + (uv_stride * height / 2); - break; - case DRM_FORMAT_YUV422: - uv_stride = stride / 2; - u_offset = stride * height; - v_offset = u_offset + (uv_stride * height); - break; - case DRM_FORMAT_NV12: - case DRM_FORMAT_NV16: - uv_stride = stride; - u_offset = stride * height; - v_offset = 0; - break; - default: - return; - } - ipu_cpmem_set_yuv_planar_full(ch, uv_stride, u_offset, v_offset); -} -EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar); - static const struct ipu_rgb def_xrgb_32 = { .red = { .offset = 16, .length = 8, }, .green = { .offset = 8, .length = 8, }, @@ -590,6 +554,13 @@ int ipu_cpmem_set_fmt(struct ipuv3_channel *ch, u32 drm_fourcc) /* burst size */ ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31); break; + case DRM_FORMAT_YUV444: + case DRM_FORMAT_YVU444: + /* pix format */ + ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0); + /* burst size */ + ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31); + break; case DRM_FORMAT_NV12: /* pix format */ ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 4); diff --git a/drivers/gpu/ipu-v3/ipu-csi.c b/drivers/gpu/ipu-v3/ipu-csi.c index d6e5ded24418..63c7292f427a 100644 --- a/drivers/gpu/ipu-v3/ipu-csi.c +++ b/drivers/gpu/ipu-v3/ipu-csi.c @@ -529,6 +529,22 @@ void ipu_csi_set_window(struct ipu_csi *csi, struct v4l2_rect *w) } EXPORT_SYMBOL_GPL(ipu_csi_set_window); +void ipu_csi_set_downsize(struct ipu_csi *csi, bool horiz, bool vert) +{ + unsigned long flags; + u32 reg; + + spin_lock_irqsave(&csi->lock, flags); + + reg = ipu_csi_read(csi, CSI_OUT_FRM_CTRL); + reg &= ~(CSI_HORI_DOWNSIZE_EN | CSI_VERT_DOWNSIZE_EN); + reg |= (horiz ? CSI_HORI_DOWNSIZE_EN : 0) | + (vert ? CSI_VERT_DOWNSIZE_EN : 0); + ipu_csi_write(csi, reg, CSI_OUT_FRM_CTRL); + + spin_unlock_irqrestore(&csi->lock, flags); +} + void ipu_csi_set_test_generator(struct ipu_csi *csi, bool active, u32 r_value, u32 g_value, u32 b_value, u32 pix_clk) diff --git a/drivers/gpu/ipu-v3/ipu-di.c b/drivers/gpu/ipu-v3/ipu-di.c index a8d87ddd8a17..d2f1bd9d3deb 100644 --- a/drivers/gpu/ipu-v3/ipu-di.c +++ b/drivers/gpu/ipu-v3/ipu-di.c @@ -535,7 +535,7 @@ int ipu_di_adjust_videomode(struct ipu_di *di, struct videomode *mode) return -EINVAL; } - dev_warn(di->ipu->dev, "videomode adapted for IPU restrictions\n"); + dev_dbg(di->ipu->dev, "videomode adapted for IPU restrictions\n"); return 0; } EXPORT_SYMBOL_GPL(ipu_di_adjust_videomode); diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h index 173073eb6aaf..53cd07ccaa4c 100644 --- a/include/video/imx-ipu-v3.h +++ b/include/video/imx-ipu-v3.h @@ -247,8 +247,6 @@ void ipu_cpmem_set_yuv_planar_full(struct ipuv3_channel *ch, unsigned int uv_stride, unsigned int u_offset, unsigned int v_offset); -void ipu_cpmem_set_yuv_planar(struct ipuv3_channel *ch, - u32 pixel_format, int stride, int height); int ipu_cpmem_set_fmt(struct ipuv3_channel *ch, u32 drm_fourcc); int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image); void ipu_cpmem_dump(struct ipuv3_channel *ch); @@ -320,6 +318,7 @@ int ipu_csi_init_interface(struct ipu_csi *csi, bool ipu_csi_is_interlaced(struct ipu_csi *csi); void ipu_csi_get_window(struct ipu_csi *csi, struct v4l2_rect *w); void ipu_csi_set_window(struct ipu_csi *csi, struct v4l2_rect *w); +void ipu_csi_set_downsize(struct ipu_csi *csi, bool horiz, bool vert); void ipu_csi_set_test_generator(struct ipu_csi *csi, bool active, u32 r_value, u32 g_value, u32 b_value, u32 pix_clk);