Commit 818182dd authored by Dave Airlie's avatar Dave Airlie

Merge tag 'imx-drm-next-2018-12-03' of git://git.pengutronix.de/git/pza/linux into drm-next

drm/imx: update image-convert with fixes for multi-tiled scaling

Update the ipu-v3 mem2mem image-convert code, with some fixes for race
conditions, alignment issues, and visual artifacts due to tile alignment
and scaling factor issues when scaling images larger than hardware
limitations in multiple tiles. This will allow the V4L2 mem2mem scaler
driver to write output images larger than 1024x1024 pixels.

Also switch drm/imx source files to SPDX license identifiers, constify
struct clk_ops in imx-tve, and add a timeout warning to the busy wait in
ipu_plane_disable().
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>

From: Philipp Zabel <p.zabel@pengutronix.de>
Link: https://patchwork.freedesktop.org/patch/msgid/1543835266.5647.1.camel@pengutronix.de
parents 167bfe53 97c78f4d
// SPDX-License-Identifier: GPL-2.0
/* Copyright (C) 2011-2013 Freescale Semiconductor, Inc. /* Copyright (C) 2011-2013 Freescale Semiconductor, Inc.
* *
* derived from imx-hdmi.c(renamed to bridge/dw_hdmi.c now) * derived from imx-hdmi.c(renamed to bridge/dw_hdmi.c now)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
......
// SPDX-License-Identifier: GPL-2.0+
/* /*
* Freescale i.MX drm driver * Freescale i.MX drm driver
* *
* Copyright (C) 2011 Sascha Hauer, Pengutronix * Copyright (C) 2011 Sascha Hauer, Pengutronix
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/ */
#include <linux/component.h> #include <linux/component.h>
#include <linux/device.h> #include <linux/device.h>
......
// SPDX-License-Identifier: GPL-2.0+
/* /*
* i.MX drm driver - LVDS display bridge * i.MX drm driver - LVDS display bridge
* *
* Copyright (C) 2012 Sascha Hauer, Pengutronix * Copyright (C) 2012 Sascha Hauer, Pengutronix
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/ */
#include <linux/module.h> #include <linux/module.h>
......
// SPDX-License-Identifier: GPL-2.0+
/* /*
* i.MX drm driver - Television Encoder (TVEv2) * i.MX drm driver - Television Encoder (TVEv2)
* *
* Copyright (C) 2013 Philipp Zabel, Pengutronix * Copyright (C) 2013 Philipp Zabel, Pengutronix
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/ */
#include <linux/clk.h> #include <linux/clk.h>
...@@ -442,7 +434,7 @@ static int clk_tve_di_set_rate(struct clk_hw *hw, unsigned long rate, ...@@ -442,7 +434,7 @@ static int clk_tve_di_set_rate(struct clk_hw *hw, unsigned long rate,
return 0; return 0;
} }
static struct clk_ops clk_tve_di_ops = { static const struct clk_ops clk_tve_di_ops = {
.round_rate = clk_tve_di_round_rate, .round_rate = clk_tve_di_round_rate,
.set_rate = clk_tve_di_set_rate, .set_rate = clk_tve_di_set_rate,
.recalc_rate = clk_tve_di_recalc_rate, .recalc_rate = clk_tve_di_recalc_rate,
......
// SPDX-License-Identifier: GPL-2.0+
/* /*
* i.MX IPUv3 Graphics driver * i.MX IPUv3 Graphics driver
* *
* Copyright (C) 2011 Sascha Hauer, Pengutronix * Copyright (C) 2011 Sascha Hauer, Pengutronix
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/ */
#include <linux/component.h> #include <linux/component.h>
#include <linux/module.h> #include <linux/module.h>
......
// SPDX-License-Identifier: GPL-2.0+
/* /*
* i.MX IPUv3 DP Overlay Planes * i.MX IPUv3 DP Overlay Planes
* *
* Copyright (C) 2013 Philipp Zabel, Pengutronix * Copyright (C) 2013 Philipp Zabel, Pengutronix
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/ */
#include <drm/drmP.h> #include <drm/drmP.h>
...@@ -236,9 +228,15 @@ static void ipu_plane_enable(struct ipu_plane *ipu_plane) ...@@ -236,9 +228,15 @@ static void ipu_plane_enable(struct ipu_plane *ipu_plane)
void ipu_plane_disable(struct ipu_plane *ipu_plane, bool disable_dp_channel) void ipu_plane_disable(struct ipu_plane *ipu_plane, bool disable_dp_channel)
{ {
int ret;
DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
ipu_idmac_wait_busy(ipu_plane->ipu_ch, 50); ret = ipu_idmac_wait_busy(ipu_plane->ipu_ch, 50);
if (ret == -ETIMEDOUT) {
DRM_ERROR("[PLANE:%d] IDMAC timeout\n",
ipu_plane->base.base.id);
}
if (ipu_plane->dp && disable_dp_channel) if (ipu_plane->dp && disable_dp_channel)
ipu_dp_disable_channel(ipu_plane->dp, false); ipu_dp_disable_channel(ipu_plane->dp, false);
......
// SPDX-License-Identifier: GPL-2.0+
/* /*
* i.MX drm driver - parallel display implementation * i.MX drm driver - parallel display implementation
* *
* Copyright (C) 2012 Sascha Hauer, Pengutronix * Copyright (C) 2012 Sascha Hauer, Pengutronix
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/ */
#include <linux/component.h> #include <linux/component.h>
......
...@@ -259,6 +259,8 @@ EXPORT_SYMBOL_GPL(ipu_cpmem_set_high_priority); ...@@ -259,6 +259,8 @@ EXPORT_SYMBOL_GPL(ipu_cpmem_set_high_priority);
void ipu_cpmem_set_buffer(struct ipuv3_channel *ch, int bufnum, dma_addr_t buf) void ipu_cpmem_set_buffer(struct ipuv3_channel *ch, int bufnum, dma_addr_t buf)
{ {
WARN_ON_ONCE(buf & 0x7);
if (bufnum) if (bufnum)
ipu_ch_param_write_field(ch, IPU_FIELD_EBA1, buf >> 3); ipu_ch_param_write_field(ch, IPU_FIELD_EBA1, buf >> 3);
else else
...@@ -268,6 +270,8 @@ EXPORT_SYMBOL_GPL(ipu_cpmem_set_buffer); ...@@ -268,6 +270,8 @@ EXPORT_SYMBOL_GPL(ipu_cpmem_set_buffer);
void ipu_cpmem_set_uv_offset(struct ipuv3_channel *ch, u32 u_off, u32 v_off) void ipu_cpmem_set_uv_offset(struct ipuv3_channel *ch, u32 u_off, u32 v_off)
{ {
WARN_ON_ONCE((u_off & 0x7) || (v_off & 0x7));
ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_off / 8); ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_off / 8);
ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_off / 8); ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_off / 8);
} }
...@@ -435,6 +439,8 @@ void ipu_cpmem_set_yuv_planar_full(struct ipuv3_channel *ch, ...@@ -435,6 +439,8 @@ void ipu_cpmem_set_yuv_planar_full(struct ipuv3_channel *ch,
unsigned int uv_stride, unsigned int uv_stride,
unsigned int u_offset, unsigned int v_offset) unsigned int u_offset, unsigned int v_offset)
{ {
WARN_ON_ONCE((u_offset & 0x7) || (v_offset & 0x7));
ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, uv_stride - 1); ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, uv_stride - 1);
ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_offset / 8); ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_offset / 8);
ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_offset / 8); ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_offset / 8);
...@@ -739,9 +745,11 @@ int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image) ...@@ -739,9 +745,11 @@ int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image)
switch (pix->pixelformat) { switch (pix->pixelformat) {
case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YUV420:
offset = Y_OFFSET(pix, image->rect.left, image->rect.top); offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
u_offset = U_OFFSET(pix, image->rect.left, u_offset = image->u_offset ?
image->u_offset : U_OFFSET(pix, image->rect.left,
image->rect.top) - offset; image->rect.top) - offset;
v_offset = V_OFFSET(pix, image->rect.left, v_offset = image->v_offset ?
image->v_offset : V_OFFSET(pix, image->rect.left,
image->rect.top) - offset; image->rect.top) - offset;
ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2, ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2,
...@@ -749,19 +757,23 @@ int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image) ...@@ -749,19 +757,23 @@ int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image)
break; break;
case V4L2_PIX_FMT_YVU420: case V4L2_PIX_FMT_YVU420:
offset = Y_OFFSET(pix, image->rect.left, image->rect.top); offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
u_offset = U_OFFSET(pix, image->rect.left, u_offset = image->u_offset ?
image->u_offset : V_OFFSET(pix, image->rect.left,
image->rect.top) - offset; image->rect.top) - offset;
v_offset = V_OFFSET(pix, image->rect.left, v_offset = image->v_offset ?
image->v_offset : U_OFFSET(pix, image->rect.left,
image->rect.top) - offset; image->rect.top) - offset;
ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2, ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2,
v_offset, u_offset); u_offset, v_offset);
break; break;
case V4L2_PIX_FMT_YUV422P: case V4L2_PIX_FMT_YUV422P:
offset = Y_OFFSET(pix, image->rect.left, image->rect.top); offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
u_offset = U2_OFFSET(pix, image->rect.left, u_offset = image->u_offset ?
image->u_offset : U2_OFFSET(pix, image->rect.left,
image->rect.top) - offset; image->rect.top) - offset;
v_offset = V2_OFFSET(pix, image->rect.left, v_offset = image->v_offset ?
image->v_offset : V2_OFFSET(pix, image->rect.left,
image->rect.top) - offset; image->rect.top) - offset;
ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2, ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2,
...@@ -769,18 +781,20 @@ int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image) ...@@ -769,18 +781,20 @@ int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image)
break; break;
case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_NV12:
offset = Y_OFFSET(pix, image->rect.left, image->rect.top); offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
u_offset = UV_OFFSET(pix, image->rect.left, u_offset = image->u_offset ?
image->u_offset : UV_OFFSET(pix, image->rect.left,
image->rect.top) - offset; image->rect.top) - offset;
v_offset = 0; v_offset = image->v_offset ? image->v_offset : 0;
ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline, ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline,
u_offset, v_offset); u_offset, v_offset);
break; break;
case V4L2_PIX_FMT_NV16: case V4L2_PIX_FMT_NV16:
offset = Y_OFFSET(pix, image->rect.left, image->rect.top); offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
u_offset = UV2_OFFSET(pix, image->rect.left, u_offset = image->u_offset ?
image->u_offset : UV2_OFFSET(pix, image->rect.left,
image->rect.top) - offset; image->rect.top) - offset;
v_offset = 0; v_offset = image->v_offset ? image->v_offset : 0;
ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline, ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline,
u_offset, v_offset); u_offset, v_offset);
......
...@@ -442,24 +442,27 @@ int ipu_ic_task_graphics_init(struct ipu_ic *ic, ...@@ -442,24 +442,27 @@ int ipu_ic_task_graphics_init(struct ipu_ic *ic,
} }
EXPORT_SYMBOL_GPL(ipu_ic_task_graphics_init); EXPORT_SYMBOL_GPL(ipu_ic_task_graphics_init);
int ipu_ic_task_init(struct ipu_ic *ic, int ipu_ic_task_init_rsc(struct ipu_ic *ic,
int in_width, int in_height, int in_width, int in_height,
int out_width, int out_height, int out_width, int out_height,
enum ipu_color_space in_cs, enum ipu_color_space in_cs,
enum ipu_color_space out_cs) enum ipu_color_space out_cs,
u32 rsc)
{ {
struct ipu_ic_priv *priv = ic->priv; struct ipu_ic_priv *priv = ic->priv;
u32 reg, downsize_coeff, resize_coeff; u32 downsize_coeff, resize_coeff;
unsigned long flags; unsigned long flags;
int ret = 0; int ret = 0;
if (!rsc) {
/* Setup vertical resizing */ /* Setup vertical resizing */
ret = calc_resize_coeffs(ic, in_height, out_height, ret = calc_resize_coeffs(ic, in_height, out_height,
&resize_coeff, &downsize_coeff); &resize_coeff, &downsize_coeff);
if (ret) if (ret)
return ret; return ret;
reg = (downsize_coeff << 30) | (resize_coeff << 16); rsc = (downsize_coeff << 30) | (resize_coeff << 16);
/* Setup horizontal resizing */ /* Setup horizontal resizing */
ret = calc_resize_coeffs(ic, in_width, out_width, ret = calc_resize_coeffs(ic, in_width, out_width,
...@@ -467,11 +470,12 @@ int ipu_ic_task_init(struct ipu_ic *ic, ...@@ -467,11 +470,12 @@ int ipu_ic_task_init(struct ipu_ic *ic,
if (ret) if (ret)
return ret; return ret;
reg |= (downsize_coeff << 14) | resize_coeff; rsc |= (downsize_coeff << 14) | resize_coeff;
}
spin_lock_irqsave(&priv->lock, flags); spin_lock_irqsave(&priv->lock, flags);
ipu_ic_write(ic, reg, ic->reg->rsc); ipu_ic_write(ic, rsc, ic->reg->rsc);
/* Setup color space conversion */ /* Setup color space conversion */
ic->in_cs = in_cs; ic->in_cs = in_cs;
...@@ -487,6 +491,16 @@ int ipu_ic_task_init(struct ipu_ic *ic, ...@@ -487,6 +491,16 @@ int ipu_ic_task_init(struct ipu_ic *ic,
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irqrestore(&priv->lock, flags);
return ret; return ret;
} }
int ipu_ic_task_init(struct ipu_ic *ic,
int in_width, int in_height,
int out_width, int out_height,
enum ipu_color_space in_cs,
enum ipu_color_space out_cs)
{
return ipu_ic_task_init_rsc(ic, in_width, in_height, out_width,
out_height, in_cs, out_cs, 0);
}
EXPORT_SYMBOL_GPL(ipu_ic_task_init); EXPORT_SYMBOL_GPL(ipu_ic_task_init);
int ipu_ic_task_idma_init(struct ipu_ic *ic, struct ipuv3_channel *channel, int ipu_ic_task_idma_init(struct ipu_ic *ic, struct ipuv3_channel *channel,
......
This diff is collapsed.
...@@ -246,6 +246,9 @@ struct ipu_image { ...@@ -246,6 +246,9 @@ struct ipu_image {
struct v4l2_rect rect; struct v4l2_rect rect;
dma_addr_t phys0; dma_addr_t phys0;
dma_addr_t phys1; dma_addr_t phys1;
/* chroma plane offset overrides */
u32 u_offset;
u32 v_offset;
}; };
void ipu_cpmem_zero(struct ipuv3_channel *ch); void ipu_cpmem_zero(struct ipuv3_channel *ch);
...@@ -387,6 +390,12 @@ int ipu_ic_task_init(struct ipu_ic *ic, ...@@ -387,6 +390,12 @@ int ipu_ic_task_init(struct ipu_ic *ic,
int out_width, int out_height, int out_width, int out_height,
enum ipu_color_space in_cs, enum ipu_color_space in_cs,
enum ipu_color_space out_cs); enum ipu_color_space out_cs);
int ipu_ic_task_init_rsc(struct ipu_ic *ic,
int in_width, int in_height,
int out_width, int out_height,
enum ipu_color_space in_cs,
enum ipu_color_space out_cs,
u32 rsc);
int ipu_ic_task_graphics_init(struct ipu_ic *ic, int ipu_ic_task_graphics_init(struct ipu_ic *ic,
enum ipu_color_space in_g_cs, enum ipu_color_space in_g_cs,
bool galpha_en, u32 galpha, bool galpha_en, u32 galpha,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment