summaryrefslogtreecommitdiff
path: root/drivers/staging/imx-drm/ipu-v3
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/imx-drm/ipu-v3')
-rw-r--r--drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h4
-rw-r--r--drivers/staging/imx-drm/ipu-v3/ipu-common.c175
-rw-r--r--drivers/staging/imx-drm/ipu-v3/ipu-dc.c13
-rw-r--r--drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c8
-rw-r--r--drivers/staging/imx-drm/ipu-v3/ipu-dp.c2
5 files changed, 153 insertions, 49 deletions
diff --git a/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h b/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h
index 74c022e..4826b5c 100644
--- a/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h
+++ b/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h
@@ -97,6 +97,7 @@ void ipu_idmac_put(struct ipuv3_channel *);
int ipu_idmac_enable_channel(struct ipuv3_channel *channel);
int ipu_idmac_disable_channel(struct ipuv3_channel *channel);
+int ipu_idmac_wait_busy(struct ipuv3_channel *channel, int ms);
void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel,
bool doublebuffer);
@@ -283,7 +284,7 @@ int ipu_cpmem_set_format_passthrough(struct ipu_ch_param __iomem *p,
int width);
int ipu_cpmem_set_format_rgb(struct ipu_ch_param __iomem *,
- struct ipu_rgb *rgb);
+ const struct ipu_rgb *rgb);
static inline void ipu_cpmem_interlaced_scan(struct ipu_ch_param *p,
int stride)
@@ -303,6 +304,7 @@ int ipu_cpmem_set_fmt(struct ipu_ch_param __iomem *cpmem, u32 pixelformat);
int ipu_cpmem_set_image(struct ipu_ch_param __iomem *cpmem,
struct ipu_image *image);
+enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc);
enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat);
static inline void ipu_cpmem_set_burstsize(struct ipu_ch_param __iomem *p,
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
index ba464e5..7a22ce6 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
@@ -30,6 +30,8 @@
#include <linux/irqdomain.h>
#include <linux/of_device.h>
+#include <drm/drm_fourcc.h>
+
#include "imx-ipu-v3.h"
#include "ipu-prv.h"
@@ -139,7 +141,7 @@ u32 ipu_ch_param_read_field(struct ipu_ch_param __iomem *base, u32 wbs)
EXPORT_SYMBOL_GPL(ipu_ch_param_read_field);
int ipu_cpmem_set_format_rgb(struct ipu_ch_param __iomem *p,
- struct ipu_rgb *rgb)
+ const struct ipu_rgb *rgb)
{
int bpp = 0, npb = 0, ro, go, bo, to;
@@ -282,7 +284,7 @@ void ipu_cpmem_set_yuv_planar(struct ipu_ch_param __iomem *p, u32 pixel_format,
}
EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar);
-static struct ipu_rgb def_rgb_32 = {
+static const struct ipu_rgb def_rgb_32 = {
.red = { .offset = 16, .length = 8, },
.green = { .offset = 8, .length = 8, },
.blue = { .offset = 0, .length = 8, },
@@ -290,31 +292,31 @@ static struct ipu_rgb def_rgb_32 = {
.bits_per_pixel = 32,
};
-static struct ipu_rgb def_bgr_32 = {
- .red = { .offset = 16, .length = 8, },
+static const struct ipu_rgb def_bgr_32 = {
+ .red = { .offset = 0, .length = 8, },
.green = { .offset = 8, .length = 8, },
- .blue = { .offset = 0, .length = 8, },
+ .blue = { .offset = 16, .length = 8, },
.transp = { .offset = 24, .length = 8, },
.bits_per_pixel = 32,
};
-static struct ipu_rgb def_rgb_24 = {
- .red = { .offset = 0, .length = 8, },
+static const struct ipu_rgb def_rgb_24 = {
+ .red = { .offset = 16, .length = 8, },
.green = { .offset = 8, .length = 8, },
- .blue = { .offset = 16, .length = 8, },
+ .blue = { .offset = 0, .length = 8, },
.transp = { .offset = 0, .length = 0, },
.bits_per_pixel = 24,
};
-static struct ipu_rgb def_bgr_24 = {
- .red = { .offset = 16, .length = 8, },
+static const struct ipu_rgb def_bgr_24 = {
+ .red = { .offset = 0, .length = 8, },
.green = { .offset = 8, .length = 8, },
- .blue = { .offset = 0, .length = 8, },
+ .blue = { .offset = 16, .length = 8, },
.transp = { .offset = 0, .length = 0, },
.bits_per_pixel = 24,
};
-static struct ipu_rgb def_rgb_16 = {
+static const struct ipu_rgb def_rgb_16 = {
.red = { .offset = 11, .length = 5, },
.green = { .offset = 5, .length = 6, },
.blue = { .offset = 0, .length = 5, },
@@ -322,6 +324,14 @@ static struct ipu_rgb def_rgb_16 = {
.bits_per_pixel = 16,
};
+static const struct ipu_rgb def_bgr_16 = {
+ .red = { .offset = 0, .length = 5, },
+ .green = { .offset = 5, .length = 6, },
+ .blue = { .offset = 11, .length = 5, },
+ .transp = { .offset = 0, .length = 0, },
+ .bits_per_pixel = 16,
+};
+
#define Y_OFFSET(pix, x, y) ((x) + pix->width * (y))
#define U_OFFSET(pix, x, y) ((pix->width * pix->height) + \
(pix->width * (y) / 4) + (x) / 2)
@@ -329,17 +339,17 @@ static struct ipu_rgb def_rgb_16 = {
(pix->width * pix->height / 4) + \
(pix->width * (y) / 4) + (x) / 2)
-int ipu_cpmem_set_fmt(struct ipu_ch_param __iomem *cpmem, u32 pixelformat)
+int ipu_cpmem_set_fmt(struct ipu_ch_param __iomem *cpmem, u32 drm_fourcc)
{
- switch (pixelformat) {
- case V4L2_PIX_FMT_YUV420:
- case V4L2_PIX_FMT_YVU420:
+ switch (drm_fourcc) {
+ case DRM_FORMAT_YUV420:
+ case DRM_FORMAT_YVU420:
/* pix format */
ipu_ch_param_write_field(cpmem, IPU_FIELD_PFS, 2);
/* burst size */
ipu_ch_param_write_field(cpmem, IPU_FIELD_NPB, 63);
break;
- case V4L2_PIX_FMT_UYVY:
+ case DRM_FORMAT_UYVY:
/* bits/pixel */
ipu_ch_param_write_field(cpmem, IPU_FIELD_BPP, 3);
/* pix format */
@@ -347,7 +357,7 @@ int ipu_cpmem_set_fmt(struct ipu_ch_param __iomem *cpmem, u32 pixelformat)
/* burst size */
ipu_ch_param_write_field(cpmem, IPU_FIELD_NPB, 31);
break;
- case V4L2_PIX_FMT_YUYV:
+ case DRM_FORMAT_YUYV:
/* bits/pixel */
ipu_ch_param_write_field(cpmem, IPU_FIELD_BPP, 3);
/* pix format */
@@ -355,20 +365,25 @@ int ipu_cpmem_set_fmt(struct ipu_ch_param __iomem *cpmem, u32 pixelformat)
/* burst size */
ipu_ch_param_write_field(cpmem, IPU_FIELD_NPB, 31);
break;
- case V4L2_PIX_FMT_RGB32:
- ipu_cpmem_set_format_rgb(cpmem, &def_rgb_32);
+ case DRM_FORMAT_ABGR8888:
+ case DRM_FORMAT_XBGR8888:
+ ipu_cpmem_set_format_rgb(cpmem, &def_bgr_32);
break;
- case V4L2_PIX_FMT_RGB565:
- ipu_cpmem_set_format_rgb(cpmem, &def_rgb_16);
+ case DRM_FORMAT_ARGB8888:
+ case DRM_FORMAT_XRGB8888:
+ ipu_cpmem_set_format_rgb(cpmem, &def_rgb_32);
break;
- case V4L2_PIX_FMT_BGR32:
- ipu_cpmem_set_format_rgb(cpmem, &def_bgr_32);
+ case DRM_FORMAT_BGR888:
+ ipu_cpmem_set_format_rgb(cpmem, &def_bgr_24);
break;
- case V4L2_PIX_FMT_RGB24:
+ case DRM_FORMAT_RGB888:
ipu_cpmem_set_format_rgb(cpmem, &def_rgb_24);
break;
- case V4L2_PIX_FMT_BGR24:
- ipu_cpmem_set_format_rgb(cpmem, &def_bgr_24);
+ case DRM_FORMAT_RGB565:
+ ipu_cpmem_set_format_rgb(cpmem, &def_rgb_16);
+ break;
+ case DRM_FORMAT_BGR565:
+ ipu_cpmem_set_format_rgb(cpmem, &def_bgr_16);
break;
default:
return -EINVAL;
@@ -378,6 +393,79 @@ int ipu_cpmem_set_fmt(struct ipu_ch_param __iomem *cpmem, u32 pixelformat)
}
EXPORT_SYMBOL_GPL(ipu_cpmem_set_fmt);
+/*
+ * The V4L2 spec defines packed RGB formats in memory byte order, which from
+ * point of view of the IPU corresponds to little-endian words with the first
+ * component in the least significant bits.
+ * The DRM pixel formats and IPU internal representation are ordered the other
+ * way around, with the first named component ordered at the most significant
+ * bits. Further, V4L2 formats are not well defined:
+ * http://linuxtv.org/downloads/v4l-dvb-apis/packed-rgb.html
+ * We choose the interpretation which matches GStreamer behavior.
+ */
+static int v4l2_pix_fmt_to_drm_fourcc(u32 pixelformat)
+{
+ switch (pixelformat) {
+ case V4L2_PIX_FMT_RGB565:
+ /*
+ * Here we choose the 'corrected' interpretation of RGBP, a
+ * little-endian 16-bit word with the red component at the most
+ * significant bits:
+ * g[2:0]b[4:0] r[4:0]g[5:3] <=> [16:0] R:G:B
+ */
+ return DRM_FORMAT_RGB565;
+ case V4L2_PIX_FMT_BGR24:
+ /* B G R <=> [24:0] R:G:B */
+ return DRM_FORMAT_RGB888;
+ case V4L2_PIX_FMT_RGB24:
+ /* R G B <=> [24:0] B:G:R */
+ return DRM_FORMAT_BGR888;
+ case V4L2_PIX_FMT_BGR32:
+ /* B G R A <=> [32:0] A:B:G:R */
+ return DRM_FORMAT_XRGB8888;
+ case V4L2_PIX_FMT_RGB32:
+ /* R G B A <=> [32:0] A:B:G:R */
+ return DRM_FORMAT_XBGR8888;
+ case V4L2_PIX_FMT_UYVY:
+ return DRM_FORMAT_UYVY;
+ case V4L2_PIX_FMT_YUYV:
+ return DRM_FORMAT_YUYV;
+ case V4L2_PIX_FMT_YUV420:
+ return DRM_FORMAT_YUV420;
+ case V4L2_PIX_FMT_YVU420:
+ return DRM_FORMAT_YVU420;
+ }
+
+ return -EINVAL;
+}
+
+enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc)
+{
+ switch (drm_fourcc) {
+ case DRM_FORMAT_RGB565:
+ case DRM_FORMAT_BGR565:
+ case DRM_FORMAT_RGB888:
+ case DRM_FORMAT_BGR888:
+ case DRM_FORMAT_XRGB8888:
+ case DRM_FORMAT_XBGR8888:
+ case DRM_FORMAT_RGBX8888:
+ case DRM_FORMAT_BGRX8888:
+ case DRM_FORMAT_ARGB8888:
+ case DRM_FORMAT_ABGR8888:
+ case DRM_FORMAT_RGBA8888:
+ case DRM_FORMAT_BGRA8888:
+ return IPUV3_COLORSPACE_RGB;
+ case DRM_FORMAT_YUYV:
+ case DRM_FORMAT_UYVY:
+ case DRM_FORMAT_YUV420:
+ case DRM_FORMAT_YVU420:
+ return IPUV3_COLORSPACE_YUV;
+ default:
+ return IPUV3_COLORSPACE_UNKNOWN;
+ }
+}
+EXPORT_SYMBOL_GPL(ipu_drm_fourcc_to_colorspace);
+
int ipu_cpmem_set_image(struct ipu_ch_param __iomem *cpmem,
struct ipu_image *image)
{
@@ -392,7 +480,7 @@ int ipu_cpmem_set_image(struct ipu_ch_param __iomem *cpmem,
image->rect.height);
ipu_cpmem_set_stride(cpmem, pix->bytesperline);
- ipu_cpmem_set_fmt(cpmem, pix->pixelformat);
+ ipu_cpmem_set_fmt(cpmem, v4l2_pix_fmt_to_drm_fourcc(pix->pixelformat));
switch (pix->pixelformat) {
case V4L2_PIX_FMT_YUV420:
@@ -476,7 +564,7 @@ struct ipuv3_channel *ipu_idmac_get(struct ipu_soc *ipu, unsigned num)
goto out;
}
- channel->busy = 1;
+ channel->busy = true;
channel->num = num;
out:
@@ -494,7 +582,7 @@ void ipu_idmac_put(struct ipuv3_channel *channel)
mutex_lock(&ipu->channel_lock);
- channel->busy = 0;
+ channel->busy = false;
mutex_unlock(&ipu->channel_lock);
}
@@ -610,24 +698,29 @@ int ipu_idmac_enable_channel(struct ipuv3_channel *channel)
}
EXPORT_SYMBOL_GPL(ipu_idmac_enable_channel);
-int ipu_idmac_disable_channel(struct ipuv3_channel *channel)
+int ipu_idmac_wait_busy(struct ipuv3_channel *channel, int ms)
{
struct ipu_soc *ipu = channel->ipu;
- u32 val;
- unsigned long flags;
unsigned long timeout;
- timeout = jiffies + msecs_to_jiffies(50);
+ timeout = jiffies + msecs_to_jiffies(ms);
while (ipu_idmac_read(ipu, IDMAC_CHA_BUSY(channel->num)) &
idma_mask(channel->num)) {
- if (time_after(jiffies, timeout)) {
- dev_warn(ipu->dev, "disabling busy idmac channel %d\n",
- channel->num);
- break;
- }
+ if (time_after(jiffies, timeout))
+ return -ETIMEDOUT;
cpu_relax();
}
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_wait_busy);
+
+int ipu_idmac_disable_channel(struct ipuv3_channel *channel)
+{
+ struct ipu_soc *ipu = channel->ipu;
+ u32 val;
+ unsigned long flags;
+
spin_lock_irqsave(&ipu->lock, flags);
/* Disable DMA channel(s) */
@@ -888,7 +981,7 @@ static const struct ipu_platform_reg client_reg[] = {
.dc = 5,
.dp = IPU_DP_FLOW_SYNC_BG,
.dma[0] = IPUV3_CHANNEL_MEM_BG_SYNC,
- .dma[1] = -EINVAL,
+ .dma[1] = IPUV3_CHANNEL_MEM_FG_SYNC,
},
.name = "imx-ipuv3-crtc",
}, {
@@ -913,7 +1006,7 @@ static int ipu_add_subdevice_pdata(struct device *dev,
pdev = platform_device_register_data(dev, reg->name, ipu_client_id++,
&reg->pdata, sizeof(struct ipu_platform_reg));
- return pdev ? 0 : -EINVAL;
+ return PTR_ERR_OR_ZERO(pdev);
}
static int ipu_add_client_devices(struct ipu_soc *ipu)
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dc.c b/drivers/staging/imx-drm/ipu-v3/ipu-dc.c
index 21bf1c8..d0e3bc3 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-dc.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-dc.c
@@ -91,6 +91,7 @@ enum ipu_dc_map {
IPU_DC_MAP_RGB565,
IPU_DC_MAP_GBR24, /* TVEv2 */
IPU_DC_MAP_BGR666,
+ IPU_DC_MAP_BGR24,
};
struct ipu_dc {
@@ -152,6 +153,8 @@ static int ipu_pixfmt_to_map(u32 fmt)
return IPU_DC_MAP_GBR24;
case V4L2_PIX_FMT_BGR666:
return IPU_DC_MAP_BGR666;
+ case V4L2_PIX_FMT_BGR24:
+ return IPU_DC_MAP_BGR24;
default:
return -EINVAL;
}
@@ -313,7 +316,7 @@ struct ipu_dc *ipu_dc_get(struct ipu_soc *ipu, int channel)
return ERR_PTR(-EBUSY);
}
- dc->in_use = 1;
+ dc->in_use = true;
mutex_unlock(&priv->mutex);
@@ -326,7 +329,7 @@ void ipu_dc_put(struct ipu_dc *dc)
struct ipu_dc_priv *priv = dc->priv;
mutex_lock(&priv->mutex);
- dc->in_use = 0;
+ dc->in_use = false;
mutex_unlock(&priv->mutex);
}
EXPORT_SYMBOL_GPL(ipu_dc_put);
@@ -395,6 +398,12 @@ int ipu_dc_init(struct ipu_soc *ipu, struct device *dev,
ipu_dc_map_config(priv, IPU_DC_MAP_BGR666, 1, 11, 0xfc); /* green */
ipu_dc_map_config(priv, IPU_DC_MAP_BGR666, 2, 17, 0xfc); /* red */
+ /* bgr24 */
+ ipu_dc_map_clear(priv, IPU_DC_MAP_BGR24);
+ ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 2, 7, 0xff); /* red */
+ ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 1, 15, 0xff); /* green */
+ ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 0, 23, 0xff); /* blue */
+
return 0;
}
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c b/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c
index 2e97c33..98070dd 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c
@@ -307,13 +307,13 @@ int ipu_dmfc_alloc_bandwidth(struct dmfc_channel *dmfc,
goto out;
}
- /* Always allocate at least 128*4 bytes (2 slots) */
- if (slots < 2)
- slots = 2;
-
/* For the MEM_BG channel, first try to allocate twice the slots */
if (dmfc->data->ipu_channel == IPUV3_CHANNEL_MEM_BG_SYNC)
segment = dmfc_find_slots(priv, slots * 2);
+ else if (slots < 2)
+ /* Always allocate at least 128*4 bytes (2 slots) */
+ slots = 2;
+
if (segment >= 0)
slots *= 2;
else
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dp.c b/drivers/staging/imx-drm/ipu-v3/ipu-dp.c
index 231afd6..58f87c8 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-dp.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-dp.c
@@ -325,7 +325,7 @@ int ipu_dp_init(struct ipu_soc *ipu, struct device *dev, unsigned long base)
mutex_init(&priv->mutex);
for (i = 0; i < IPUV3_NUM_FLOWS; i++) {
- priv->flow[i].foreground.foreground = 1;
+ priv->flow[i].foreground.foreground = true;
priv->flow[i].base = priv->base + ipu_dp_flow_base[i];
priv->flow[i].priv = priv;
}