aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/platform/vivid
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/platform/vivid')
-rw-r--r--drivers/media/platform/vivid/vivid-core.c93
-rw-r--r--drivers/media/platform/vivid/vivid-core.h8
-rw-r--r--drivers/media/platform/vivid/vivid-ctrls.c2
-rw-r--r--drivers/media/platform/vivid/vivid-kthread-cap.c125
-rw-r--r--drivers/media/platform/vivid/vivid-sdr-cap.c66
-rw-r--r--drivers/media/platform/vivid/vivid-tpg.c1082
-rw-r--r--drivers/media/platform/vivid/vivid-tpg.h112
-rw-r--r--drivers/media/platform/vivid/vivid-vid-cap.c180
-rw-r--r--drivers/media/platform/vivid/vivid-vid-common.c378
-rw-r--r--drivers/media/platform/vivid/vivid-vid-out.c85
10 files changed, 1615 insertions, 516 deletions
diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c
index a7e033a5d291..d33f16495dbc 100644
--- a/drivers/media/platform/vivid/vivid-core.c
+++ b/drivers/media/platform/vivid/vivid-core.c
@@ -26,6 +26,7 @@
#include <linux/vmalloc.h>
#include <linux/font.h>
#include <linux/mutex.h>
+#include <linux/platform_device.h>
#include <linux/videodev2.h>
#include <linux/v4l2-dv-timings.h>
#include <media/videobuf2-vmalloc.h>
@@ -618,7 +619,23 @@ static const struct v4l2_ioctl_ops vivid_ioctl_ops = {
Initialization and module stuff
------------------------------------------------------------------*/
-static int __init vivid_create_instance(int inst)
+static void vivid_dev_release(struct v4l2_device *v4l2_dev)
+{
+ struct vivid_dev *dev = container_of(v4l2_dev, struct vivid_dev, v4l2_dev);
+
+ vivid_free_controls(dev);
+ v4l2_device_unregister(&dev->v4l2_dev);
+ vfree(dev->scaled_line);
+ vfree(dev->blended_line);
+ vfree(dev->edid);
+ vfree(dev->bitmap_cap);
+ vfree(dev->bitmap_out);
+ tpg_free(&dev->tpg);
+ kfree(dev->query_dv_timings_qmenu);
+ kfree(dev);
+}
+
+static int vivid_create_instance(struct platform_device *pdev, int inst)
{
static const struct v4l2_dv_timings def_dv_timings =
V4L2_DV_BT_CEA_1280X720P60;
@@ -646,9 +663,12 @@ static int __init vivid_create_instance(int inst)
/* register v4l2_device */
snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name),
"%s-%03d", VIVID_MODULE_NAME, inst);
- ret = v4l2_device_register(NULL, &dev->v4l2_dev);
- if (ret)
- goto free_dev;
+ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+ if (ret) {
+ kfree(dev);
+ return ret;
+ }
+ dev->v4l2_dev.release = vivid_dev_release;
/* start detecting feature set */
@@ -1256,15 +1276,8 @@ unreg_dev:
video_unregister_device(&dev->vbi_cap_dev);
video_unregister_device(&dev->vid_out_dev);
video_unregister_device(&dev->vid_cap_dev);
- vivid_free_controls(dev);
- v4l2_device_unregister(&dev->v4l2_dev);
free_dev:
- vfree(dev->scaled_line);
- vfree(dev->blended_line);
- vfree(dev->edid);
- tpg_free(&dev->tpg);
- kfree(dev->query_dv_timings_qmenu);
- kfree(dev);
+ v4l2_device_put(&dev->v4l2_dev);
return ret;
}
@@ -1274,7 +1287,7 @@ free_dev:
will succeed. This is limited to the maximum number of devices that
videodev supports, which is equal to VIDEO_NUM_DEVICES.
*/
-static int __init vivid_init(void)
+static int vivid_probe(struct platform_device *pdev)
{
const struct font_desc *font = find_font("VGA8x16");
int ret = 0, i;
@@ -1289,7 +1302,7 @@ static int __init vivid_init(void)
n_devs = clamp_t(unsigned, n_devs, 1, VIVID_MAX_DEVS);
for (i = 0; i < n_devs; i++) {
- ret = vivid_create_instance(i);
+ ret = vivid_create_instance(pdev, i);
if (ret) {
/* If some instantiations succeeded, keep driver */
if (i)
@@ -1309,7 +1322,7 @@ static int __init vivid_init(void)
return ret;
}
-static void __exit vivid_exit(void)
+static int vivid_remove(struct platform_device *pdev)
{
struct vivid_dev *dev;
unsigned i;
@@ -1358,18 +1371,48 @@ static void __exit vivid_exit(void)
unregister_framebuffer(&dev->fb_info);
vivid_fb_release_buffers(dev);
}
- v4l2_device_unregister(&dev->v4l2_dev);
- vivid_free_controls(dev);
- vfree(dev->scaled_line);
- vfree(dev->blended_line);
- vfree(dev->edid);
- vfree(dev->bitmap_cap);
- vfree(dev->bitmap_out);
- tpg_free(&dev->tpg);
- kfree(dev->query_dv_timings_qmenu);
- kfree(dev);
+ v4l2_device_put(&dev->v4l2_dev);
vivid_devs[i] = NULL;
}
+ return 0;
+}
+
+static void vivid_pdev_release(struct device *dev)
+{
+}
+
+static struct platform_device vivid_pdev = {
+ .name = "vivid",
+ .dev.release = vivid_pdev_release,
+};
+
+static struct platform_driver vivid_pdrv = {
+ .probe = vivid_probe,
+ .remove = vivid_remove,
+ .driver = {
+ .name = "vivid",
+ },
+};
+
+static int __init vivid_init(void)
+{
+ int ret;
+
+ ret = platform_device_register(&vivid_pdev);
+ if (ret)
+ return ret;
+
+ ret = platform_driver_register(&vivid_pdrv);
+ if (ret)
+ platform_device_unregister(&vivid_pdev);
+
+ return ret;
+}
+
+static void __exit vivid_exit(void)
+{
+ platform_driver_unregister(&vivid_pdrv);
+ platform_device_unregister(&vivid_pdev);
}
module_init(vivid_init);
diff --git a/drivers/media/platform/vivid/vivid-core.h b/drivers/media/platform/vivid/vivid-core.h
index 4b497df4b6a4..9e15aee9a52e 100644
--- a/drivers/media/platform/vivid/vivid-core.h
+++ b/drivers/media/platform/vivid/vivid-core.h
@@ -79,12 +79,14 @@ extern unsigned vivid_debug;
struct vivid_fmt {
const char *name;
u32 fourcc; /* v4l2 format id */
- u8 depth;
bool is_yuv;
bool can_do_overlay;
+ u8 vdownsampling[TPG_MAX_PLANES];
u32 alpha_mask;
u8 planes;
- u32 data_offset[2];
+ u8 buffers;
+ u32 data_offset[TPG_MAX_PLANES];
+ u32 bit_depth[TPG_MAX_PLANES];
};
extern struct vivid_fmt vivid_formats[];
@@ -332,7 +334,7 @@ struct vivid_dev {
u32 ycbcr_enc_out;
u32 quantization_out;
u32 service_set_out;
- u32 bytesperline_out[2];
+ unsigned bytesperline_out[TPG_MAX_PLANES];
unsigned tv_field_out;
unsigned tv_audio_output;
bool vbi_out_have_wss;
diff --git a/drivers/media/platform/vivid/vivid-ctrls.c b/drivers/media/platform/vivid/vivid-ctrls.c
index 32a798f2d953..2b9070098b08 100644
--- a/drivers/media/platform/vivid/vivid-ctrls.c
+++ b/drivers/media/platform/vivid/vivid-ctrls.c
@@ -818,7 +818,7 @@ static int vivid_vid_out_s_ctrl(struct v4l2_ctrl *ctrl)
dev->dvi_d_out = ctrl->val == V4L2_DV_TX_MODE_DVI_D;
if (!vivid_is_hdmi_out(dev))
break;
- if (!dev->dvi_d_out && (bt->standards & V4L2_DV_BT_STD_CEA861)) {
+ if (!dev->dvi_d_out && (bt->flags & V4L2_DV_FL_IS_CE_VIDEO)) {
if (bt->width == 720 && bt->height <= 576)
dev->colorspace_out = V4L2_COLORSPACE_SMPTE170M;
else
diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.c b/drivers/media/platform/vivid/vivid-kthread-cap.c
index 39a67cfae120..1727f5453f0b 100644
--- a/drivers/media/platform/vivid/vivid-kthread-cap.c
+++ b/drivers/media/platform/vivid/vivid-kthread-cap.c
@@ -229,14 +229,29 @@ static void vivid_precalc_copy_rects(struct vivid_dev *dev)
dev->loop_vid_overlay_cap.left, dev->loop_vid_overlay_cap.top);
}
+static void *plane_vaddr(struct tpg_data *tpg, struct vivid_buffer *buf,
+ unsigned p, unsigned bpl[TPG_MAX_PLANES], unsigned h)
+{
+ unsigned i;
+ void *vbuf;
+
+ if (p == 0 || tpg_g_buffers(tpg) > 1)
+ return vb2_plane_vaddr(&buf->vb, p);
+ vbuf = vb2_plane_vaddr(&buf->vb, 0);
+ for (i = 0; i < p; i++)
+ vbuf += bpl[i] * h / tpg->vdownsampling[i];
+ return vbuf;
+}
+
static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf,
struct vivid_buffer *vid_cap_buf)
{
bool blank = dev->must_blank[vid_cap_buf->vb.v4l2_buf.index];
struct tpg_data *tpg = &dev->tpg;
struct vivid_buffer *vid_out_buf = NULL;
- unsigned pixsize = tpg_g_twopixelsize(tpg, p) / 2;
- unsigned img_width = dev->compose_cap.width;
+ unsigned vdiv = dev->fmt_out->vdownsampling[p];
+ unsigned twopixsize = tpg_g_twopixelsize(tpg, p);
+ unsigned img_width = tpg_hdiv(tpg, p, dev->compose_cap.width);
unsigned img_height = dev->compose_cap.height;
unsigned stride_cap = tpg->bytesperline[p];
unsigned stride_out = dev->bytesperline_out[p];
@@ -255,6 +270,7 @@ static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf,
unsigned vid_overlay_fract_part = 0;
unsigned vid_overlay_y = 0;
unsigned vid_overlay_error = 0;
+ unsigned vid_cap_left = tpg_hdiv(tpg, p, dev->loop_vid_cap.left);
unsigned vid_cap_right;
bool quick;
@@ -269,25 +285,29 @@ static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf,
vid_cap_buf->vb.v4l2_buf.field = vid_out_buf->vb.v4l2_buf.field;
- voutbuf = vb2_plane_vaddr(&vid_out_buf->vb, p) +
- vid_out_buf->vb.v4l2_planes[p].data_offset;
- voutbuf += dev->loop_vid_out.left * pixsize + dev->loop_vid_out.top * stride_out;
- vcapbuf += dev->compose_cap.left * pixsize + dev->compose_cap.top * stride_cap;
+ voutbuf = plane_vaddr(tpg, vid_out_buf, p,
+ dev->bytesperline_out, dev->fmt_out_rect.height);
+ if (p < dev->fmt_out->buffers)
+ voutbuf += vid_out_buf->vb.v4l2_planes[p].data_offset;
+ voutbuf += tpg_hdiv(tpg, p, dev->loop_vid_out.left) +
+ (dev->loop_vid_out.top / vdiv) * stride_out;
+ vcapbuf += tpg_hdiv(tpg, p, dev->compose_cap.left) +
+ (dev->compose_cap.top / vdiv) * stride_cap;
if (dev->loop_vid_copy.width == 0 || dev->loop_vid_copy.height == 0) {
/*
* If there is nothing to copy, then just fill the capture window
* with black.
*/
- for (y = 0; y < hmax; y++, vcapbuf += stride_cap)
- memcpy(vcapbuf, tpg->black_line[p], img_width * pixsize);
+ for (y = 0; y < hmax / vdiv; y++, vcapbuf += stride_cap)
+ memcpy(vcapbuf, tpg->black_line[p], img_width);
return 0;
}
if (dev->overlay_out_enabled &&
dev->loop_vid_overlay.width && dev->loop_vid_overlay.height) {
vosdbuf = dev->video_vbase;
- vosdbuf += dev->loop_fb_copy.left * pixsize +
+ vosdbuf += (dev->loop_fb_copy.left * twopixsize) / 2 +
dev->loop_fb_copy.top * stride_osd;
vid_overlay_int_part = dev->loop_vid_overlay.height /
dev->loop_vid_overlay_cap.height;
@@ -295,12 +315,12 @@ static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf,
dev->loop_vid_overlay_cap.height;
}
- vid_cap_right = dev->loop_vid_cap.left + dev->loop_vid_cap.width;
+ vid_cap_right = tpg_hdiv(tpg, p, dev->loop_vid_cap.left + dev->loop_vid_cap.width);
/* quick is true if no video scaling is needed */
quick = dev->loop_vid_out.width == dev->loop_vid_cap.width;
dev->cur_scaled_line = dev->loop_vid_out.height;
- for (y = 0; y < hmax; y++, vcapbuf += stride_cap) {
+ for (y = 0; y < hmax; y += vdiv, vcapbuf += stride_cap) {
/* osdline is true if this line requires overlay blending */
bool osdline = vosdbuf && y >= dev->loop_vid_overlay_cap.top &&
y < dev->loop_vid_overlay_cap.top + dev->loop_vid_overlay_cap.height;
@@ -311,34 +331,34 @@ static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf,
*/
if (y < dev->loop_vid_cap.top ||
y >= dev->loop_vid_cap.top + dev->loop_vid_cap.height) {
- memcpy(vcapbuf, tpg->black_line[p], img_width * pixsize);
+ memcpy(vcapbuf, tpg->black_line[p], img_width);
continue;
}
/* fill the left border with black */
if (dev->loop_vid_cap.left)
- memcpy(vcapbuf, tpg->black_line[p], dev->loop_vid_cap.left * pixsize);
+ memcpy(vcapbuf, tpg->black_line[p], vid_cap_left);
/* fill the right border with black */
if (vid_cap_right < img_width)
- memcpy(vcapbuf + vid_cap_right * pixsize,
- tpg->black_line[p], (img_width - vid_cap_right) * pixsize);
+ memcpy(vcapbuf + vid_cap_right, tpg->black_line[p],
+ img_width - vid_cap_right);
if (quick && !osdline) {
- memcpy(vcapbuf + dev->loop_vid_cap.left * pixsize,
+ memcpy(vcapbuf + vid_cap_left,
voutbuf + vid_out_y * stride_out,
- dev->loop_vid_cap.width * pixsize);
+ tpg_hdiv(tpg, p, dev->loop_vid_cap.width));
goto update_vid_out_y;
}
if (dev->cur_scaled_line == vid_out_y) {
- memcpy(vcapbuf + dev->loop_vid_cap.left * pixsize,
- dev->scaled_line,
- dev->loop_vid_cap.width * pixsize);
+ memcpy(vcapbuf + vid_cap_left, dev->scaled_line,
+ tpg_hdiv(tpg, p, dev->loop_vid_cap.width));
goto update_vid_out_y;
}
if (!osdline) {
scale_line(voutbuf + vid_out_y * stride_out, dev->scaled_line,
- dev->loop_vid_out.width, dev->loop_vid_cap.width,
+ tpg_hdiv(tpg, p, dev->loop_vid_out.width),
+ tpg_hdiv(tpg, p, dev->loop_vid_cap.width),
tpg_g_twopixelsize(tpg, p));
} else {
/*
@@ -346,7 +366,8 @@ static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf,
* loop_vid_overlay rectangle.
*/
unsigned offset =
- (dev->loop_vid_overlay.left - dev->loop_vid_copy.left) * pixsize;
+ ((dev->loop_vid_overlay.left - dev->loop_vid_copy.left) *
+ twopixsize) / 2;
u8 *osd = vosdbuf + vid_overlay_y * stride_osd;
scale_line(voutbuf + vid_out_y * stride_out, dev->blended_line,
@@ -356,18 +377,17 @@ static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf,
blend_line(dev, vid_overlay_y + dev->loop_vid_overlay.top,
dev->loop_vid_overlay.left,
dev->blended_line + offset, osd,
- dev->loop_vid_overlay.width, pixsize);
+ dev->loop_vid_overlay.width, twopixsize / 2);
else
memcpy(dev->blended_line + offset,
- osd, dev->loop_vid_overlay.width * pixsize);
+ osd, (dev->loop_vid_overlay.width * twopixsize) / 2);
scale_line(dev->blended_line, dev->scaled_line,
dev->loop_vid_copy.width, dev->loop_vid_cap.width,
tpg_g_twopixelsize(tpg, p));
}
dev->cur_scaled_line = vid_out_y;
- memcpy(vcapbuf + dev->loop_vid_cap.left * pixsize,
- dev->scaled_line,
- dev->loop_vid_cap.width * pixsize);
+ memcpy(vcapbuf + vid_cap_left, dev->scaled_line,
+ tpg_hdiv(tpg, p, dev->loop_vid_cap.width));
update_vid_out_y:
if (osdline) {
@@ -380,21 +400,22 @@ update_vid_out_y:
}
vid_out_y += vid_out_int_part;
vid_out_error += vid_out_fract_part;
- if (vid_out_error >= dev->loop_vid_cap.height) {
- vid_out_error -= dev->loop_vid_cap.height;
+ if (vid_out_error >= dev->loop_vid_cap.height / vdiv) {
+ vid_out_error -= dev->loop_vid_cap.height / vdiv;
vid_out_y++;
}
}
if (!blank)
return 0;
- for (; y < img_height; y++, vcapbuf += stride_cap)
- memcpy(vcapbuf, tpg->contrast_line[p], img_width * pixsize);
+ for (; y < img_height; y += vdiv, vcapbuf += stride_cap)
+ memcpy(vcapbuf, tpg->contrast_line[p], img_width);
return 0;
}
static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf)
{
+ struct tpg_data *tpg = &dev->tpg;
unsigned factor = V4L2_FIELD_HAS_T_OR_B(dev->field_cap) ? 2 : 1;
unsigned line_height = 16 / factor;
bool is_tv = vivid_is_sdtv_cap(dev);
@@ -427,7 +448,7 @@ static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf)
* standards.
*/
buf->vb.v4l2_buf.field = ((dev->vid_cap_seq_count & 1) ^ is_60hz) ?
- V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM;
+ V4L2_FIELD_BOTTOM : V4L2_FIELD_TOP;
/*
* The sequence counter counts frames, not fields. So divide
* by two.
@@ -436,27 +457,29 @@ static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf)
} else {
buf->vb.v4l2_buf.field = dev->field_cap;
}
- tpg_s_field(&dev->tpg, buf->vb.v4l2_buf.field);
- tpg_s_perc_fill_blank(&dev->tpg, dev->must_blank[buf->vb.v4l2_buf.index]);
+ tpg_s_field(tpg, buf->vb.v4l2_buf.field,
+ dev->field_cap == V4L2_FIELD_ALTERNATE);
+ tpg_s_perc_fill_blank(tpg, dev->must_blank[buf->vb.v4l2_buf.index]);
vivid_precalc_copy_rects(dev);
- for (p = 0; p < tpg_g_planes(&dev->tpg); p++) {
- void *vbuf = vb2_plane_vaddr(&buf->vb, p);
+ for (p = 0; p < tpg_g_planes(tpg); p++) {
+ void *vbuf = plane_vaddr(tpg, buf, p,
+ tpg->bytesperline, tpg->buf_height);
/*
* The first plane of a multiplanar format has a non-zero
* data_offset. This helps testing whether the application
* correctly supports non-zero data offsets.
*/
- if (dev->fmt_cap->data_offset[p]) {
+ if (p < tpg_g_buffers(tpg) && dev->fmt_cap->data_offset[p]) {
memset(vbuf, dev->fmt_cap->data_offset[p] & 0xff,
dev->fmt_cap->data_offset[p]);
vbuf += dev->fmt_cap->data_offset[p];
}
- tpg_calc_text_basep(&dev->tpg, basep, p, vbuf);
+ tpg_calc_text_basep(tpg, basep, p, vbuf);
if (!is_loop || vivid_copy_buffer(dev, p, vbuf, buf))
- tpg_fillbuffer(&dev->tpg, vivid_get_std_cap(dev), p, vbuf);
+ tpg_fill_plane_buffer(tpg, vivid_get_std_cap(dev), p, vbuf);
}
dev->must_blank[buf->vb.v4l2_buf.index] = false;
@@ -475,12 +498,12 @@ static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf)
(dev->field_cap == V4L2_FIELD_ALTERNATE) ?
(buf->vb.v4l2_buf.field == V4L2_FIELD_TOP ?
" top" : " bottom") : "");
- tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str);
+ tpg_gen_text(tpg, basep, line++ * line_height, 16, str);
}
if (dev->osd_mode == 0) {
snprintf(str, sizeof(str), " %dx%d, input %d ",
dev->src_rect.width, dev->src_rect.height, dev->input);
- tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str);
+ tpg_gen_text(tpg, basep, line++ * line_height, 16, str);
gain = v4l2_ctrl_g_ctrl(dev->gain);
mutex_lock(dev->ctrl_hdl_user_vid.lock);
@@ -490,38 +513,38 @@ static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf)
dev->contrast->cur.val,
dev->saturation->cur.val,
dev->hue->cur.val);
- tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str);
+ tpg_gen_text(tpg, basep, line++ * line_height, 16, str);
snprintf(str, sizeof(str),
" autogain %d, gain %3d, alpha 0x%02x ",
dev->autogain->cur.val, gain, dev->alpha->cur.val);
mutex_unlock(dev->ctrl_hdl_user_vid.lock);
- tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str);
+ tpg_gen_text(tpg, basep, line++ * line_height, 16, str);
mutex_lock(dev->ctrl_hdl_user_aud.lock);
snprintf(str, sizeof(str),
" volume %3d, mute %d ",
dev->volume->cur.val, dev->mute->cur.val);
mutex_unlock(dev->ctrl_hdl_user_aud.lock);
- tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str);
+ tpg_gen_text(tpg, basep, line++ * line_height, 16, str);
mutex_lock(dev->ctrl_hdl_user_gen.lock);
snprintf(str, sizeof(str), " int32 %d, int64 %lld, bitmask %08x ",
dev->int32->cur.val,
*dev->int64->p_cur.p_s64,
dev->bitmask->cur.val);
- tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str);
+ tpg_gen_text(tpg, basep, line++ * line_height, 16, str);
snprintf(str, sizeof(str), " boolean %d, menu %s, string \"%s\" ",
dev->boolean->cur.val,
dev->menu->qmenu[dev->menu->cur.val],
dev->string->p_cur.p_char);
- tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str);
+ tpg_gen_text(tpg, basep, line++ * line_height, 16, str);
snprintf(str, sizeof(str), " integer_menu %lld, value %d ",
dev->int_menu->qmenu_int[dev->int_menu->cur.val],
dev->int_menu->cur.val);
mutex_unlock(dev->ctrl_hdl_user_gen.lock);
- tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str);
+ tpg_gen_text(tpg, basep, line++ * line_height, 16, str);
if (dev->button_pressed) {
dev->button_pressed--;
snprintf(str, sizeof(str), " button pressed!");
- tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str);
+ tpg_gen_text(tpg, basep, line++ * line_height, 16, str);
}
}
@@ -585,6 +608,12 @@ static void vivid_overlay(struct vivid_dev *dev, struct vivid_buffer *buf)
bool quick = dev->bitmap_cap == NULL && dev->clipcount_cap == 0;
int x, y, w, out_x = 0;
+ /*
+ * Overlay support is only supported for formats that have a twopixelsize
+ * that's >= 2. Warn and bail out if that's not the case.
+ */
+ if (WARN_ON(pixsize == 0))
+ return;
if ((dev->overlay_cap_field == V4L2_FIELD_TOP ||
dev->overlay_cap_field == V4L2_FIELD_BOTTOM) &&
dev->overlay_cap_field != buf->vb.v4l2_buf.field)
diff --git a/drivers/media/platform/vivid/vivid-sdr-cap.c b/drivers/media/platform/vivid/vivid-sdr-cap.c
index 4af55f18829f..caf131666e37 100644
--- a/drivers/media/platform/vivid/vivid-sdr-cap.c
+++ b/drivers/media/platform/vivid/vivid-sdr-cap.c
@@ -27,6 +27,7 @@
#include <media/v4l2-common.h>
#include <media/v4l2-event.h>
#include <media/v4l2-dv-timings.h>
+#include <linux/fixp-arith.h>
#include "vivid-core.h"
#include "vivid-ctrls.h"
@@ -423,40 +424,19 @@ int vidioc_g_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f)
return 0;
}
-#define FIXP_FRAC (1 << 15)
-#define FIXP_PI ((int)(FIXP_FRAC * 3.141592653589))
-
-/* cos() from cx88 driver: cx88-dsp.c */
-static s32 fixp_cos(unsigned int x)
-{
- u32 t2, t4, t6, t8;
- u16 period = x / FIXP_PI;
-
- if (period % 2)
- return -fixp_cos(x - FIXP_PI);
- x = x % FIXP_PI;
- if (x > FIXP_PI/2)
- return -fixp_cos(FIXP_PI/2 - (x % (FIXP_PI/2)));
- /* Now x is between 0 and FIXP_PI/2.
- * To calculate cos(x) we use it's Taylor polinom. */
- t2 = x*x/FIXP_FRAC/2;
- t4 = t2*x/FIXP_FRAC*x/FIXP_FRAC/3/4;
- t6 = t4*x/FIXP_FRAC*x/FIXP_FRAC/5/6;
- t8 = t6*x/FIXP_FRAC*x/FIXP_FRAC/7/8;
- return FIXP_FRAC-t2+t4-t6+t8;
-}
-
-static inline s32 fixp_sin(unsigned int x)
-{
- return -fixp_cos(x + (FIXP_PI / 2));
-}
+#define FIXP_N (15)
+#define FIXP_FRAC (1 << FIXP_N)
+#define FIXP_2PI ((int)(2 * 3.141592653589 * FIXP_FRAC))
void vivid_sdr_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf)
{
u8 *vbuf = vb2_plane_vaddr(&buf->vb, 0);
unsigned long i;
unsigned long plane_size = vb2_plane_size(&buf->vb, 0);
- int fixp_src_phase_step, fixp_i, fixp_q;
+ s32 src_phase_step;
+ s32 mod_phase_step;
+ s32 fixp_i;
+ s32 fixp_q;
/*
* TODO: Generated beep tone goes very crackly when sample rate is
@@ -466,28 +446,36 @@ void vivid_sdr_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf)
/* calculate phase step */
#define BEEP_FREQ 1000 /* 1kHz beep */
- fixp_src_phase_step = DIV_ROUND_CLOSEST(2 * FIXP_PI * BEEP_FREQ,
+ src_phase_step = DIV_ROUND_CLOSEST(FIXP_2PI * BEEP_FREQ,
dev->sdr_adc_freq);
for (i = 0; i < plane_size; i += 2) {
- dev->sdr_fixp_mod_phase += fixp_cos(dev->sdr_fixp_src_phase);
- dev->sdr_fixp_src_phase += fixp_src_phase_step;
+ mod_phase_step = fixp_cos32_rad(dev->sdr_fixp_src_phase,
+ FIXP_2PI) >> (31 - FIXP_N);
+
+ dev->sdr_fixp_src_phase += src_phase_step;
+ dev->sdr_fixp_mod_phase += mod_phase_step / 4;
/*
* Transfer phases to [0 / 2xPI] in order to avoid variable
* overflow and make it suitable for cosine implementation
* used, which does not support negative angles.
*/
- while (dev->sdr_fixp_mod_phase < (0 * FIXP_PI))
- dev->sdr_fixp_mod_phase += (2 * FIXP_PI);
- while (dev->sdr_fixp_mod_phase > (2 * FIXP_PI))
- dev->sdr_fixp_mod_phase -= (2 * FIXP_PI);
+ while (dev->sdr_fixp_mod_phase < FIXP_2PI)
+ dev->sdr_fixp_mod_phase += FIXP_2PI;
+ while (dev->sdr_fixp_mod_phase > FIXP_2PI)
+ dev->sdr_fixp_mod_phase -= FIXP_2PI;
+
+ while (dev->sdr_fixp_src_phase > FIXP_2PI)
+ dev->sdr_fixp_src_phase -= FIXP_2PI;
- while (dev->sdr_fixp_src_phase > (2 * FIXP_PI))
- dev->sdr_fixp_src_phase -= (2 * FIXP_PI);
+ fixp_i = fixp_cos32_rad(dev->sdr_fixp_mod_phase, FIXP_2PI);
+ fixp_q = fixp_sin32_rad(dev->sdr_fixp_mod_phase, FIXP_2PI);
- fixp_i = fixp_cos(dev->sdr_fixp_mod_phase);
- fixp_q = fixp_sin(dev->sdr_fixp_mod_phase);
+ /* Normalize fraction values represented with 32 bit precision
+ * to fixed point representation with FIXP_N bits */
+ fixp_i >>= (31 - FIXP_N);
+ fixp_q >>= (31 - FIXP_N);
/* convert 'fixp float' to u8 */
/* u8 = X * 127.5f + 127.5f; where X is float [-1.0 / +1.0] */
diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c
index 34493f435d5a..cb766eb154e7 100644
--- a/drivers/media/platform/vivid/vivid-tpg.c
+++ b/drivers/media/platform/vivid/vivid-tpg.c
@@ -35,7 +35,10 @@ const char * const tpg_pattern_strings[] = {
"100% Green",
"100% Blue",
"16x16 Checkers",
+ "2x2 Checkers",
"1x1 Checkers",
+ "2x2 Red/Green Checkers",
+ "1x1 Red/Green Checkers",
"Alternating Hor Lines",
"Alternating Vert Lines",
"One Pixel Wide Cross",
@@ -120,15 +123,20 @@ int tpg_alloc(struct tpg_data *tpg, unsigned max_w)
tpg->max_line_width = max_w;
for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++) {
for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
- unsigned pixelsz = plane ? 1 : 4;
+ unsigned pixelsz = plane ? 2 : 4;
tpg->lines[pat][plane] = vzalloc(max_w * 2 * pixelsz);
if (!tpg->lines[pat][plane])
return -ENOMEM;
+ if (plane == 0)
+ continue;
+ tpg->downsampled_lines[pat][plane] = vzalloc(max_w * 2 * pixelsz);
+ if (!tpg->downsampled_lines[pat][plane])
+ return -ENOMEM;
}
}
for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
- unsigned pixelsz = plane ? 1 : 4;
+ unsigned pixelsz = plane ? 2 : 4;
tpg->contrast_line[plane] = vzalloc(max_w * pixelsz);
if (!tpg->contrast_line[plane])
@@ -152,6 +160,10 @@ void tpg_free(struct tpg_data *tpg)
for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
vfree(tpg->lines[pat][plane]);
tpg->lines[pat][plane] = NULL;
+ if (plane == 0)
+ continue;
+ vfree(tpg->downsampled_lines[pat][plane]);
+ tpg->downsampled_lines[pat][plane] = NULL;
}
for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
vfree(tpg->contrast_line[plane]);
@@ -167,14 +179,38 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc)
{
tpg->fourcc = fourcc;
tpg->planes = 1;
+ tpg->buffers = 1;
tpg->recalc_colors = true;
+ tpg->interleaved = false;
+ tpg->vdownsampling[0] = 1;
+ tpg->hdownsampling[0] = 1;
+ tpg->hmask[0] = ~0;
+ tpg->hmask[1] = ~0;
+ tpg->hmask[2] = ~0;
+
switch (fourcc) {
+ case V4L2_PIX_FMT_SBGGR8:
+ case V4L2_PIX_FMT_SGBRG8:
+ case V4L2_PIX_FMT_SGRBG8:
+ case V4L2_PIX_FMT_SRGGB8:
+ tpg->interleaved = true;
+ tpg->vdownsampling[1] = 1;
+ tpg->hdownsampling[1] = 1;
+ tpg->planes = 2;
+ /* fall through */
+ case V4L2_PIX_FMT_RGB332:
case V4L2_PIX_FMT_RGB565:
case V4L2_PIX_FMT_RGB565X:
+ case V4L2_PIX_FMT_RGB444:
+ case V4L2_PIX_FMT_XRGB444:
+ case V4L2_PIX_FMT_ARGB444:
case V4L2_PIX_FMT_RGB555:
case V4L2_PIX_FMT_XRGB555:
case V4L2_PIX_FMT_ARGB555:
case V4L2_PIX_FMT_RGB555X:
+ case V4L2_PIX_FMT_XRGB555X:
+ case V4L2_PIX_FMT_ARGB555X:
+ case V4L2_PIX_FMT_BGR666:
case V4L2_PIX_FMT_RGB24:
case V4L2_PIX_FMT_BGR24:
case V4L2_PIX_FMT_RGB32:
@@ -183,16 +219,72 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc)
case V4L2_PIX_FMT_XBGR32:
case V4L2_PIX_FMT_ARGB32:
case V4L2_PIX_FMT_ABGR32:
+ case V4L2_PIX_FMT_GREY:
tpg->is_yuv = false;
break;
+ case V4L2_PIX_FMT_YUV444:
+ case V4L2_PIX_FMT_YUV555:
+ case V4L2_PIX_FMT_YUV565:
+ case V4L2_PIX_FMT_YUV32:
+ tpg->is_yuv = true;
+ break;
+ case V4L2_PIX_FMT_YUV420M:
+ case V4L2_PIX_FMT_YVU420M:
+ tpg->buffers = 3;
+ /* fall through */
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_YVU420:
+ tpg->vdownsampling[1] = 2;
+ tpg->vdownsampling[2] = 2;
+ tpg->hdownsampling[1] = 2;
+ tpg->hdownsampling[2] = 2;
+ tpg->planes = 3;
+ tpg->is_yuv = true;
+ break;
+ case V4L2_PIX_FMT_YUV422P:
+ tpg->vdownsampling[1] = 1;
+ tpg->vdownsampling[2] = 1;
+ tpg->hdownsampling[1] = 2;
+ tpg->hdownsampling[2] = 2;
+ tpg->planes = 3;
+ tpg->is_yuv = true;
+ break;
case V4L2_PIX_FMT_NV16M:
case V4L2_PIX_FMT_NV61M:
+ tpg->buffers = 2;
+ /* fall through */
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_NV61:
+ tpg->vdownsampling[1] = 1;
+ tpg->hdownsampling[1] = 1;
+ tpg->hmask[1] = ~1;
tpg->planes = 2;
- /* fall-through */
+ tpg->is_yuv = true;
+ break;
+ case V4L2_PIX_FMT_NV12M:
+ case V4L2_PIX_FMT_NV21M:
+ tpg->buffers = 2;
+ /* fall through */
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV21:
+ tpg->vdownsampling[1] = 2;
+ tpg->hdownsampling[1] = 1;
+ tpg->hmask[1] = ~1;
+ tpg->planes = 2;
+ tpg->is_yuv = true;
+ break;
+ case V4L2_PIX_FMT_NV24:
+ case V4L2_PIX_FMT_NV42:
+ tpg->vdownsampling[1] = 1;
+ tpg->hdownsampling[1] = 1;
+ tpg->planes = 2;
+ tpg->is_yuv = true;
+ break;
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_UYVY:
case V4L2_PIX_FMT_YVYU:
case V4L2_PIX_FMT_VYUY:
+ tpg->hmask[0] = ~1;
tpg->is_yuv = true;
break;
default:
@@ -200,35 +292,75 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc)
}
switch (fourcc) {
+ case V4L2_PIX_FMT_RGB332:
+ tpg->twopixelsize[0] = 2;
+ break;
case V4L2_PIX_FMT_RGB565:
case V4L2_PIX_FMT_RGB565X:
+ case V4L2_PIX_FMT_RGB444:
+ case V4L2_PIX_FMT_XRGB444:
+ case V4L2_PIX_FMT_ARGB444:
case V4L2_PIX_FMT_RGB555:
case V4L2_PIX_FMT_XRGB555:
case V4L2_PIX_FMT_ARGB555:
case V4L2_PIX_FMT_RGB555X:
+ case V4L2_PIX_FMT_XRGB555X:
+ case V4L2_PIX_FMT_ARGB555X:
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_UYVY:
case V4L2_PIX_FMT_YVYU:
case V4L2_PIX_FMT_VYUY:
+ case V4L2_PIX_FMT_YUV444:
+ case V4L2_PIX_FMT_YUV555:
+ case V4L2_PIX_FMT_YUV565:
tpg->twopixelsize[0] = 2 * 2;
break;
case V4L2_PIX_FMT_RGB24:
case V4L2_PIX_FMT_BGR24:
tpg->twopixelsize[0] = 2 * 3;
break;
+ case V4L2_PIX_FMT_BGR666:
case V4L2_PIX_FMT_RGB32:
case V4L2_PIX_FMT_BGR32:
case V4L2_PIX_FMT_XRGB32:
case V4L2_PIX_FMT_XBGR32:
case V4L2_PIX_FMT_ARGB32:
case V4L2_PIX_FMT_ABGR32:
+ case V4L2_PIX_FMT_YUV32:
tpg->twopixelsize[0] = 2 * 4;
break;
+ case V4L2_PIX_FMT_GREY:
+ tpg->twopixelsize[0] = 2;
+ break;
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV21:
+ case V4L2_PIX_FMT_NV12M:
+ case V4L2_PIX_FMT_NV21M:
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_NV61:
case V4L2_PIX_FMT_NV16M:
case V4L2_PIX_FMT_NV61M:
+ case V4L2_PIX_FMT_SBGGR8:
+ case V4L2_PIX_FMT_SGBRG8:
+ case V4L2_PIX_FMT_SGRBG8:
+ case V4L2_PIX_FMT_SRGGB8:
tpg->twopixelsize[0] = 2;
tpg->twopixelsize[1] = 2;
break;
+ case V4L2_PIX_FMT_YUV422P:
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_YVU420:
+ case V4L2_PIX_FMT_YUV420M:
+ case V4L2_PIX_FMT_YVU420M:
+ tpg->twopixelsize[0] = 2;
+ tpg->twopixelsize[1] = 2;
+ tpg->twopixelsize[2] = 2;
+ break;
+ case V4L2_PIX_FMT_NV24:
+ case V4L2_PIX_FMT_NV42:
+ tpg->twopixelsize[0] = 2;
+ tpg->twopixelsize[1] = 4;
+ break;
}
return true;
}
@@ -267,7 +399,8 @@ void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height,
tpg->compose.width = width;
tpg->compose.height = tpg->buf_height;
for (p = 0; p < tpg->planes; p++)
- tpg->bytesperline[p] = width * tpg->twopixelsize[p] / 2;
+ tpg->bytesperline[p] = (width * tpg->twopixelsize[p]) /
+ (2 * tpg->hdownsampling[p]);
tpg->recalc_square_border = true;
}
@@ -347,9 +480,9 @@ static void color_to_ycbcr(struct tpg_data *tpg, int r, int g, int b,
{ COEFF(0.5, 224), COEFF(-0.445, 224), COEFF(-0.055, 224) },
};
static const int bt2020[3][3] = {
- { COEFF(0.2726, 219), COEFF(0.6780, 219), COEFF(0.0593, 219) },
+ { COEFF(0.2627, 219), COEFF(0.6780, 219), COEFF(0.0593, 219) },
{ COEFF(-0.1396, 224), COEFF(-0.3604, 224), COEFF(0.5, 224) },
- { COEFF(0.5, 224), COEFF(-0.4629, 224), COEFF(-0.0405, 224) },
+ { COEFF(0.5, 224), COEFF(-0.4598, 224), COEFF(-0.0402, 224) },
};
bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;
unsigned y_offset = full ? 0 : 16;
@@ -524,10 +657,10 @@ static void precalculate_color(struct tpg_data *tpg, int k)
g <<= 4;
b <<= 4;
}
- if (tpg->qual == TPG_QUAL_GRAY) {
+ if (tpg->qual == TPG_QUAL_GRAY || tpg->fourcc == V4L2_PIX_FMT_GREY) {
/* Rec. 709 Luma function */
/* (0.2126, 0.7152, 0.0722) * (255 * 256) */
- r = g = b = ((13879 * r + 46688 * g + 4713 * b) >> 16) + (16 << 4);
+ r = g = b = (13879 * r + 46688 * g + 4713 * b) >> 16;
}
/*
@@ -601,9 +734,29 @@ static void precalculate_color(struct tpg_data *tpg, int k)
cb = clamp(cb, 16 << 4, 240 << 4);
cr = clamp(cr, 16 << 4, 240 << 4);
}
- tpg->colors[k][0] = clamp(y >> 4, 1, 254);
- tpg->colors[k][1] = clamp(cb >> 4, 1, 254);
- tpg->colors[k][2] = clamp(cr >> 4, 1, 254);
+ y = clamp(y >> 4, 1, 254);
+ cb = clamp(cb >> 4, 1, 254);
+ cr = clamp(cr >> 4, 1, 254);
+ switch (tpg->fourcc) {
+ case V4L2_PIX_FMT_YUV444:
+ y >>= 4;
+ cb >>= 4;
+ cr >>= 4;
+ break;
+ case V4L2_PIX_FMT_YUV555:
+ y >>= 3;
+ cb >>= 3;
+ cr >>= 3;
+ break;
+ case V4L2_PIX_FMT_YUV565:
+ y >>= 3;
+ cb >>= 2;
+ cr >>= 3;
+ break;
+ }
+ tpg->colors[k][0] = y;
+ tpg->colors[k][1] = cb;
+ tpg->colors[k][2] = cr;
} else {
if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) {
r = (r * 219) / 255 + (16 << 4);
@@ -611,20 +764,39 @@ static void precalculate_color(struct tpg_data *tpg, int k)
b = (b * 219) / 255 + (16 << 4);
}
switch (tpg->fourcc) {
+ case V4L2_PIX_FMT_RGB332:
+ r >>= 9;
+ g >>= 9;
+ b >>= 10;
+ break;
case V4L2_PIX_FMT_RGB565:
case V4L2_PIX_FMT_RGB565X:
r >>= 7;
g >>= 6;
b >>= 7;
break;
+ case V4L2_PIX_FMT_RGB444:
+ case V4L2_PIX_FMT_XRGB444:
+ case V4L2_PIX_FMT_ARGB444:
+ r >>= 8;
+ g >>= 8;
+ b >>= 8;
+ break;
case V4L2_PIX_FMT_RGB555:
case V4L2_PIX_FMT_XRGB555:
case V4L2_PIX_FMT_ARGB555:
case V4L2_PIX_FMT_RGB555X:
+ case V4L2_PIX_FMT_XRGB555X:
+ case V4L2_PIX_FMT_ARGB555X:
r >>= 7;
g >>= 7;
b >>= 7;
break;
+ case V4L2_PIX_FMT_BGR666:
+ r >>= 6;
+ g >>= 6;
+ b >>= 6;
+ break;
default:
r >>= 4;
g >>= 4;
@@ -665,31 +837,120 @@ static void gen_twopix(struct tpg_data *tpg,
b_v = tpg->colors[color][2]; /* B or precalculated V */
switch (tpg->fourcc) {
+ case V4L2_PIX_FMT_GREY:
+ buf[0][offset] = r_y;
+ break;
+ case V4L2_PIX_FMT_YUV422P:
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_YUV420M:
+ buf[0][offset] = r_y;
+ if (odd) {
+ buf[1][0] = (buf[1][0] + g_u) / 2;
+ buf[2][0] = (buf[2][0] + b_v) / 2;
+ buf[1][1] = buf[1][0];
+ buf[2][1] = buf[2][0];
+ break;
+ }
+ buf[1][0] = g_u;
+ buf[2][0] = b_v;
+ break;
+ case V4L2_PIX_FMT_YVU420:
+ case V4L2_PIX_FMT_YVU420M:
+ buf[0][offset] = r_y;
+ if (odd) {
+ buf[1][0] = (buf[1][0] + b_v) / 2;
+ buf[2][0] = (buf[2][0] + g_u) / 2;
+ buf[1][1] = buf[1][0];
+ buf[2][1] = buf[2][0];
+ break;
+ }
+ buf[1][0] = b_v;
+ buf[2][0] = g_u;
+ break;
+
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV12M:
+ case V4L2_PIX_FMT_NV16:
case V4L2_PIX_FMT_NV16M:
buf[0][offset] = r_y;
- buf[1][offset] = odd ? b_v : g_u;
+ if (odd) {
+ buf[1][0] = (buf[1][0] + g_u) / 2;
+ buf[1][1] = (buf[1][1] + b_v) / 2;
+ break;
+ }
+ buf[1][0] = g_u;
+ buf[1][1] = b_v;
break;
+ case V4L2_PIX_FMT_NV21:
+ case V4L2_PIX_FMT_NV21M:
+ case V4L2_PIX_FMT_NV61:
case V4L2_PIX_FMT_NV61M:
buf[0][offset] = r_y;
- buf[1][offset] = odd ? g_u : b_v;
+ if (odd) {
+ buf[1][0] = (buf[1][0] + b_v) / 2;
+ buf[1][1] = (buf[1][1] + g_u) / 2;
+ break;
+ }
+ buf[1][0] = b_v;
+ buf[1][1] = g_u;
+ break;
+
+ case V4L2_PIX_FMT_NV24:
+ buf[0][offset] = r_y;
+ buf[1][2 * offset] = g_u;
+ buf[1][2 * offset + 1] = b_v;
+ break;
+
+ case V4L2_PIX_FMT_NV42:
+ buf[0][offset] = r_y;
+ buf[1][2 * offset] = b_v;
+ buf[1][2 * offset + 1] = g_u;
break;
case V4L2_PIX_FMT_YUYV:
buf[0][offset] = r_y;
- buf[0][offset + 1] = odd ? b_v : g_u;
+ if (odd) {
+ buf[0][1] = (buf[0][1] + g_u) / 2;
+ buf[0][3] = (buf[0][3] + b_v) / 2;
+ break;
+ }
+ buf[0][1] = g_u;
+ buf[0][3] = b_v;
break;
case V4L2_PIX_FMT_UYVY:
- buf[0][offset] = odd ? b_v : g_u;
buf[0][offset + 1] = r_y;
+ if (odd) {
+ buf[0][0] = (buf[0][0] + g_u) / 2;
+ buf[0][2] = (buf[0][2] + b_v) / 2;
+ break;
+ }
+ buf[0][0] = g_u;
+ buf[0][2] = b_v;
break;
case V4L2_PIX_FMT_YVYU:
buf[0][offset] = r_y;
- buf[0][offset + 1] = odd ? g_u : b_v;
+ if (odd) {
+ buf[0][1] = (buf[0][1] + b_v) / 2;
+ buf[0][3] = (buf[0][3] + g_u) / 2;
+ break;
+ }
+ buf[0][1] = b_v;
+ buf[0][3] = g_u;
break;
case V4L2_PIX_FMT_VYUY:
- buf[0][offset] = odd ? g_u : b_v;
buf[0][offset + 1] = r_y;
+ if (odd) {
+ buf[0][0] = (buf[0][0] + b_v) / 2;
+ buf[0][2] = (buf[0][2] + g_u) / 2;
+ break;
+ }
+ buf[0][0] = b_v;
+ buf[0][2] = g_u;
+ break;
+ case V4L2_PIX_FMT_RGB332:
+ buf[0][offset] = (r_y << 5) | (g_u << 2) | b_v;
break;
+ case V4L2_PIX_FMT_YUV565:
case V4L2_PIX_FMT_RGB565:
buf[0][offset] = (g_u << 5) | b_v;
buf[0][offset + 1] = (r_y << 3) | (g_u >> 3);
@@ -698,15 +959,29 @@ static void gen_twopix(struct tpg_data *tpg,
buf[0][offset] = (r_y << 3) | (g_u >> 3);
buf[0][offset + 1] = (g_u << 5) | b_v;
break;
+ case V4L2_PIX_FMT_RGB444:
+ case V4L2_PIX_FMT_XRGB444:
+ alpha = 0;
+ /* fall through */
+ case V4L2_PIX_FMT_YUV444:
+ case V4L2_PIX_FMT_ARGB444:
+ buf[0][offset] = (g_u << 4) | b_v;
+ buf[0][offset + 1] = (alpha & 0xf0) | r_y;
+ break;
case V4L2_PIX_FMT_RGB555:
case V4L2_PIX_FMT_XRGB555:
alpha = 0;
/* fall through */
+ case V4L2_PIX_FMT_YUV555:
case V4L2_PIX_FMT_ARGB555:
buf[0][offset] = (g_u << 5) | b_v;
buf[0][offset + 1] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
break;
case V4L2_PIX_FMT_RGB555X:
+ case V4L2_PIX_FMT_XRGB555X:
+ alpha = 0;
+ /* fall through */
+ case V4L2_PIX_FMT_ARGB555X:
buf[0][offset] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
buf[0][offset + 1] = (g_u << 5) | b_v;
break;
@@ -720,10 +995,17 @@ static void gen_twopix(struct tpg_data *tpg,
buf[0][offset + 1] = g_u;
buf[0][offset + 2] = r_y;
break;
+ case V4L2_PIX_FMT_BGR666:
+ buf[0][offset] = (b_v << 2) | (g_u >> 4);
+ buf[0][offset + 1] = (g_u << 4) | (r_y >> 2);
+ buf[0][offset + 2] = r_y << 6;
+ buf[0][offset + 3] = 0;
+ break;
case V4L2_PIX_FMT_RGB32:
case V4L2_PIX_FMT_XRGB32:
alpha = 0;
/* fall through */
+ case V4L2_PIX_FMT_YUV32:
case V4L2_PIX_FMT_ARGB32:
buf[0][offset] = alpha;
buf[0][offset + 1] = r_y;
@@ -740,15 +1022,47 @@ static void gen_twopix(struct tpg_data *tpg,
buf[0][offset + 2] = r_y;
buf[0][offset + 3] = alpha;
break;
+ case V4L2_PIX_FMT_SBGGR8:
+ buf[0][offset] = odd ? g_u : b_v;
+ buf[1][offset] = odd ? r_y : g_u;
+ break;
+ case V4L2_PIX_FMT_SGBRG8:
+ buf[0][offset] = odd ? b_v : g_u;
+ buf[1][offset] = odd ? g_u : r_y;
+ break;
+ case V4L2_PIX_FMT_SGRBG8:
+ buf[0][offset] = odd ? r_y : g_u;
+ buf[1][offset] = odd ? g_u : b_v;
+ break;
+ case V4L2_PIX_FMT_SRGGB8:
+ buf[0][offset] = odd ? g_u : r_y;
+ buf[1][offset] = odd ? b_v : g_u;
+ break;
+ }
+}
+
+unsigned tpg_g_interleaved_plane(const struct tpg_data *tpg, unsigned buf_line)
+{
+ switch (tpg->fourcc) {
+ case V4L2_PIX_FMT_SBGGR8:
+ case V4L2_PIX_FMT_SGBRG8:
+ case V4L2_PIX_FMT_SGRBG8:
+ case V4L2_PIX_FMT_SRGGB8:
+ return buf_line & 1;
+ default:
+ return 0;
}
}
/* Return how many pattern lines are used by the current pattern. */
-static unsigned tpg_get_pat_lines(struct tpg_data *tpg)
+static unsigned tpg_get_pat_lines(const struct tpg_data *tpg)
{
switch (tpg->pattern) {
case TPG_PAT_CHECKERS_16X16:
+ case TPG_PAT_CHECKERS_2X2:
case TPG_PAT_CHECKERS_1X1:
+ case TPG_PAT_COLOR_CHECKERS_2X2:
+ case TPG_PAT_COLOR_CHECKERS_1X1:
case TPG_PAT_ALTERNATING_HLINES:
case TPG_PAT_CROSS_1_PIXEL:
case TPG_PAT_CROSS_2_PIXELS:
@@ -763,14 +1077,18 @@ static unsigned tpg_get_pat_lines(struct tpg_data *tpg)
}
/* Which pattern line should be used for the given frame line. */
-static unsigned tpg_get_pat_line(struct tpg_data *tpg, unsigned line)
+static unsigned tpg_get_pat_line(const struct tpg_data *tpg, unsigned line)
{
switch (tpg->pattern) {
case TPG_PAT_CHECKERS_16X16:
return (line >> 4) & 1;
case TPG_PAT_CHECKERS_1X1:
+ case TPG_PAT_COLOR_CHECKERS_1X1:
case TPG_PAT_ALTERNATING_HLINES:
return line & 1;
+ case TPG_PAT_CHECKERS_2X2:
+ case TPG_PAT_COLOR_CHECKERS_2X2:
+ return (line & 2) >> 1;
case TPG_PAT_100_COLORSQUARES:
case TPG_PAT_100_HCOLORBAR:
return (line * 8) / tpg->src_height;
@@ -789,7 +1107,8 @@ static unsigned tpg_get_pat_line(struct tpg_data *tpg, unsigned line)
* Which color should be used for the given pattern line and X coordinate.
* Note: x is in the range 0 to 2 * tpg->src_width.
*/
-static enum tpg_color tpg_get_color(struct tpg_data *tpg, unsigned pat_line, unsigned x)
+static enum tpg_color tpg_get_color(const struct tpg_data *tpg,
+ unsigned pat_line, unsigned x)
{
/* Maximum number of bars are TPG_COLOR_MAX - otherwise, the input print code
should be modified */
@@ -836,6 +1155,15 @@ static enum tpg_color tpg_get_color(struct tpg_data *tpg, unsigned pat_line, uns
case TPG_PAT_CHECKERS_1X1:
return ((x & 1) ^ (pat_line & 1)) ?
TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
+ case TPG_PAT_COLOR_CHECKERS_1X1:
+ return ((x & 1) ^ (pat_line & 1)) ?
+ TPG_COLOR_100_RED : TPG_COLOR_100_BLUE;
+ case TPG_PAT_CHECKERS_2X2:
+ return (((x >> 1) & 1) ^ (pat_line & 1)) ?
+ TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
+ case TPG_PAT_COLOR_CHECKERS_2X2:
+ return (((x >> 1) & 1) ^ (pat_line & 1)) ?
+ TPG_COLOR_100_RED : TPG_COLOR_100_BLUE;
case TPG_PAT_ALTERNATING_HLINES:
return pat_line ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
case TPG_PAT_ALTERNATING_VLINES:
@@ -948,6 +1276,7 @@ static void tpg_calculate_square_border(struct tpg_data *tpg)
static void tpg_precalculate_line(struct tpg_data *tpg)
{
enum tpg_color contrast;
+ u8 pix[TPG_MAX_PLANES][8];
unsigned pat;
unsigned p;
unsigned x;
@@ -974,7 +1303,6 @@ static void tpg_precalculate_line(struct tpg_data *tpg)
for (x = 0; x < tpg->scaled_width * 2; x += 2) {
unsigned real_x = src_x;
enum tpg_color color1, color2;
- u8 pix[TPG_MAX_PLANES][8];
real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
color1 = tpg_get_color(tpg, pat, real_x);
@@ -1001,39 +1329,53 @@ static void tpg_precalculate_line(struct tpg_data *tpg)
gen_twopix(tpg, pix, tpg->hflip ? color1 : color2, 1);
for (p = 0; p < tpg->planes; p++) {
unsigned twopixsize = tpg->twopixelsize[p];
- u8 *pos = tpg->lines[pat][p] + x * twopixsize / 2;
+ unsigned hdiv = tpg->hdownsampling[p];
+ u8 *pos = tpg->lines[pat][p] + tpg_hdiv(tpg, p, x);
- memcpy(pos, pix[p], twopixsize);
+ memcpy(pos, pix[p], twopixsize / hdiv);
}
}
}
- for (x = 0; x < tpg->scaled_width; x += 2) {
- u8 pix[TPG_MAX_PLANES][8];
- gen_twopix(tpg, pix, contrast, 0);
- gen_twopix(tpg, pix, contrast, 1);
- for (p = 0; p < tpg->planes; p++) {
- unsigned twopixsize = tpg->twopixelsize[p];
- u8 *pos = tpg->contrast_line[p] + x * twopixsize / 2;
+ if (tpg->vdownsampling[tpg->planes - 1] > 1) {
+ unsigned pat_lines = tpg_get_pat_lines(tpg);
- memcpy(pos, pix[p], twopixsize);
+ for (pat = 0; pat < pat_lines; pat++) {
+ unsigned next_pat = (pat + 1) % pat_lines;
+
+ for (p = 1; p < tpg->planes; p++) {
+ unsigned w = tpg_hdiv(tpg, p, tpg->scaled_width * 2);
+ u8 *pos1 = tpg->lines[pat][p];
+ u8 *pos2 = tpg->lines[next_pat][p];
+ u8 *dest = tpg->downsampled_lines[pat][p];
+
+ for (x = 0; x < w; x++, pos1++, pos2++, dest++)
+ *dest = ((u16)*pos1 + (u16)*pos2) / 2;
+ }
}
}
- for (x = 0; x < tpg->scaled_width; x += 2) {
- u8 pix[TPG_MAX_PLANES][8];
- gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 0);
- gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 1);
- for (p = 0; p < tpg->planes; p++) {
- unsigned twopixsize = tpg->twopixelsize[p];
- u8 *pos = tpg->black_line[p] + x * twopixsize / 2;
+ gen_twopix(tpg, pix, contrast, 0);
+ gen_twopix(tpg, pix, contrast, 1);
+ for (p = 0; p < tpg->planes; p++) {
+ unsigned twopixsize = tpg->twopixelsize[p];
+ u8 *pos = tpg->contrast_line[p];
+ for (x = 0; x < tpg->scaled_width; x += 2, pos += twopixsize)
+ memcpy(pos, pix[p], twopixsize);
+ }
+
+ gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 0);
+ gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 1);
+ for (p = 0; p < tpg->planes; p++) {
+ unsigned twopixsize = tpg->twopixelsize[p];
+ u8 *pos = tpg->black_line[p];
+
+ for (x = 0; x < tpg->scaled_width; x += 2, pos += twopixsize)
memcpy(pos, pix[p], twopixsize);
- }
}
- for (x = 0; x < tpg->scaled_width * 2; x += 2) {
- u8 pix[TPG_MAX_PLANES][8];
+ for (x = 0; x < tpg->scaled_width * 2; x += 2) {
gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 0);
gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 1);
for (p = 0; p < tpg->planes; p++) {
@@ -1043,6 +1385,7 @@ static void tpg_precalculate_line(struct tpg_data *tpg)
memcpy(pos, pix[p], twopixsize);
}
}
+
gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 0);
gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 1);
gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 0);
@@ -1052,8 +1395,8 @@ static void tpg_precalculate_line(struct tpg_data *tpg)
/* need this to do rgb24 rendering */
typedef struct { u16 __; u8 _; } __packed x24;
-void tpg_gen_text(struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
- int y, int x, char *text)
+void tpg_gen_text(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
+ int y, int x, char *text)
{
int line;
unsigned step = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
@@ -1083,24 +1426,37 @@ void tpg_gen_text(struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
div = 2;
for (p = 0; p < tpg->planes; p++) {
- /* Print stream time */
+ unsigned vdiv = tpg->vdownsampling[p];
+ unsigned hdiv = tpg->hdownsampling[p];
+
+ /* Print text */
#define PRINTSTR(PIXTYPE) do { \
PIXTYPE fg; \
PIXTYPE bg; \
memcpy(&fg, tpg->textfg[p], sizeof(PIXTYPE)); \
memcpy(&bg, tpg->textbg[p], sizeof(PIXTYPE)); \
\
- for (line = first; line < 16; line += step) { \
+ for (line = first; line < 16; line += vdiv * step) { \
int l = tpg->vflip ? 15 - line : line; \
- PIXTYPE *pos = (PIXTYPE *)(basep[p][line & 1] + \
- ((y * step + l) / div) * tpg->bytesperline[p] + \
- x * sizeof(PIXTYPE)); \
+ PIXTYPE *pos = (PIXTYPE *)(basep[p][(line / vdiv) & 1] + \
+ ((y * step + l) / (vdiv * div)) * tpg->bytesperline[p] + \
+ (x / hdiv) * sizeof(PIXTYPE)); \
unsigned s; \
\
for (s = 0; s < len; s++) { \
u8 chr = font8x16[text[s] * 16 + line]; \
\
- if (tpg->hflip) { \
+ if (hdiv == 2 && tpg->hflip) { \
+ pos[3] = (chr & (0x01 << 6) ? fg : bg); \
+ pos[2] = (chr & (0x01 << 4) ? fg : bg); \
+ pos[1] = (chr & (0x01 << 2) ? fg : bg); \
+ pos[0] = (chr & (0x01 << 0) ? fg : bg); \
+ } else if (hdiv == 2) { \
+ pos[0] = (chr & (0x01 << 7) ? fg : bg); \
+ pos[1] = (chr & (0x01 << 5) ? fg : bg); \
+ pos[2] = (chr & (0x01 << 3) ? fg : bg); \
+ pos[3] = (chr & (0x01 << 1) ? fg : bg); \
+ } else if (tpg->hflip) { \
pos[7] = (chr & (0x01 << 7) ? fg : bg); \
pos[6] = (chr & (0x01 << 6) ? fg : bg); \
pos[5] = (chr & (0x01 << 5) ? fg : bg); \
@@ -1120,7 +1476,7 @@ void tpg_gen_text(struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
pos[7] = (chr & (0x01 << 0) ? fg : bg); \
} \
\
- pos += tpg->hflip ? -8 : 8; \
+ pos += (tpg->hflip ? -8 : 8) / hdiv; \
} \
} \
} while (0)
@@ -1187,7 +1543,7 @@ void tpg_update_mv_step(struct tpg_data *tpg)
}
/* Map the line number relative to the crop rectangle to a frame line number */
-static unsigned tpg_calc_frameline(struct tpg_data *tpg, unsigned src_y,
+static unsigned tpg_calc_frameline(const struct tpg_data *tpg, unsigned src_y,
unsigned field)
{
switch (field) {
@@ -1204,7 +1560,7 @@ static unsigned tpg_calc_frameline(struct tpg_data *tpg, unsigned src_y,
* Map the line number relative to the compose rectangle to a destination
* buffer line number.
*/
-static unsigned tpg_calc_buffer_line(struct tpg_data *tpg, unsigned y,
+static unsigned tpg_calc_buffer_line(const struct tpg_data *tpg, unsigned y,
unsigned field)
{
y += tpg->compose.top;
@@ -1265,6 +1621,10 @@ static void tpg_recalc(struct tpg_data *tpg)
V4L2_QUANTIZATION_LIM_RANGE;
break;
}
+ } else if (tpg->colorspace == V4L2_COLORSPACE_BT2020) {
+ /* R'G'B' BT.2020 is limited range */
+ tpg->real_quantization =
+ V4L2_QUANTIZATION_LIM_RANGE;
}
}
tpg_precalculate_colors(tpg);
@@ -1283,191 +1643,388 @@ void tpg_calc_text_basep(struct tpg_data *tpg,
u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf)
{
unsigned stride = tpg->bytesperline[p];
+ unsigned h = tpg->buf_height;
tpg_recalc(tpg);
basep[p][0] = vbuf;
basep[p][1] = vbuf;
+ h /= tpg->vdownsampling[p];
if (tpg->field == V4L2_FIELD_SEQ_TB)
- basep[p][1] += tpg->buf_height * stride / 2;
+ basep[p][1] += h * stride / 2;
else if (tpg->field == V4L2_FIELD_SEQ_BT)
- basep[p][0] += tpg->buf_height * stride / 2;
+ basep[p][0] += h * stride / 2;
+ if (p == 0 && tpg->interleaved)
+ tpg_calc_text_basep(tpg, basep, 1, vbuf);
}
-void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf)
+static int tpg_pattern_avg(const struct tpg_data *tpg,
+ unsigned pat1, unsigned pat2)
{
- bool is_tv = std;
- bool is_60hz = is_tv && (std & V4L2_STD_525_60);
- unsigned mv_hor_old = tpg->mv_hor_count % tpg->src_width;
- unsigned mv_hor_new = (tpg->mv_hor_count + tpg->mv_hor_step) % tpg->src_width;
- unsigned mv_vert_old = tpg->mv_vert_count % tpg->src_height;
- unsigned mv_vert_new = (tpg->mv_vert_count + tpg->mv_vert_step) % tpg->src_height;
+ unsigned pat_lines = tpg_get_pat_lines(tpg);
+
+ if (pat1 == (pat2 + 1) % pat_lines)
+ return pat2;
+ if (pat2 == (pat1 + 1) % pat_lines)
+ return pat1;
+ return -1;
+}
+
+/*
+ * This struct contains common parameters used by both the drawing of the
+ * test pattern and the drawing of the extras (borders, square, etc.)
+ */
+struct tpg_draw_params {
+ /* common data */
+ bool is_tv;
+ bool is_60hz;
+ unsigned twopixsize;
+ unsigned img_width;
+ unsigned stride;
+ unsigned hmax;
+ unsigned frame_line;
+ unsigned frame_line_next;
+
+ /* test pattern */
+ unsigned mv_hor_old;
+ unsigned mv_hor_new;
+ unsigned mv_vert_old;
+ unsigned mv_vert_new;
+
+ /* extras */
unsigned wss_width;
- unsigned f;
- int hmax = (tpg->compose.height * tpg->perc_fill) / 100;
- int h;
- unsigned twopixsize = tpg->twopixelsize[p];
- unsigned img_width = tpg->compose.width * twopixsize / 2;
- unsigned line_offset;
- unsigned left_pillar_width = 0;
- unsigned right_pillar_start = img_width;
- unsigned stride = tpg->bytesperline[p];
- unsigned factor = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
- u8 *orig_vbuf = vbuf;
+ unsigned wss_random_offset;
+ unsigned sav_eav_f;
+ unsigned left_pillar_width;
+ unsigned right_pillar_start;
+};
- /* Coarse scaling with Bresenham */
- unsigned int_part = (tpg->crop.height / factor) / tpg->compose.height;
- unsigned fract_part = (tpg->crop.height / factor) % tpg->compose.height;
- unsigned src_y = 0;
- unsigned error = 0;
+static void tpg_fill_params_pattern(const struct tpg_data *tpg, unsigned p,
+ struct tpg_draw_params *params)
+{
+ params->mv_hor_old =
+ tpg_hscale_div(tpg, p, tpg->mv_hor_count % tpg->src_width);
+ params->mv_hor_new =
+ tpg_hscale_div(tpg, p, (tpg->mv_hor_count + tpg->mv_hor_step) %
+ tpg->src_width);
+ params->mv_vert_old = tpg->mv_vert_count % tpg->src_height;
+ params->mv_vert_new =
+ (tpg->mv_vert_count + tpg->mv_vert_step) % tpg->src_height;
+}
- tpg_recalc(tpg);
+static void tpg_fill_params_extras(const struct tpg_data *tpg,
+ unsigned p,
+ struct tpg_draw_params *params)
+{
+ unsigned left_pillar_width = 0;
+ unsigned right_pillar_start = params->img_width;
+
+ params->wss_width = tpg->crop.left < tpg->src_width / 2 ?
+ tpg->src_width / 2 - tpg->crop.left : 0;
+ if (params->wss_width > tpg->crop.width)
+ params->wss_width = tpg->crop.width;
+ params->wss_width = tpg_hscale_div(tpg, p, params->wss_width);
+ params->wss_random_offset =
+ params->twopixsize * prandom_u32_max(tpg->src_width / 2);
- mv_hor_old = (mv_hor_old * tpg->scaled_width / tpg->src_width) & ~1;
- mv_hor_new = (mv_hor_new * tpg->scaled_width / tpg->src_width) & ~1;
- wss_width = tpg->crop.left < tpg->src_width / 2 ?
- tpg->src_width / 2 - tpg->crop.left : 0;
- if (wss_width > tpg->crop.width)
- wss_width = tpg->crop.width;
- wss_width = wss_width * tpg->scaled_width / tpg->src_width;
-
- vbuf += tpg->compose.left * twopixsize / 2;
- line_offset = tpg->crop.left * tpg->scaled_width / tpg->src_width;
- line_offset = (line_offset & ~1) * twopixsize / 2;
if (tpg->crop.left < tpg->border.left) {
left_pillar_width = tpg->border.left - tpg->crop.left;
if (left_pillar_width > tpg->crop.width)
left_pillar_width = tpg->crop.width;
- left_pillar_width = (left_pillar_width * tpg->scaled_width) / tpg->src_width;
- left_pillar_width = (left_pillar_width & ~1) * twopixsize / 2;
+ left_pillar_width = tpg_hscale_div(tpg, p, left_pillar_width);
}
- if (tpg->crop.left + tpg->crop.width > tpg->border.left + tpg->border.width) {
- right_pillar_start = tpg->border.left + tpg->border.width - tpg->crop.left;
- right_pillar_start = (right_pillar_start * tpg->scaled_width) / tpg->src_width;
- right_pillar_start = (right_pillar_start & ~1) * twopixsize / 2;
- if (right_pillar_start > img_width)
- right_pillar_start = img_width;
+ params->left_pillar_width = left_pillar_width;
+
+ if (tpg->crop.left + tpg->crop.width >
+ tpg->border.left + tpg->border.width) {
+ right_pillar_start =
+ tpg->border.left + tpg->border.width - tpg->crop.left;
+ right_pillar_start =
+ tpg_hscale_div(tpg, p, right_pillar_start);
+ if (right_pillar_start > params->img_width)
+ right_pillar_start = params->img_width;
}
+ params->right_pillar_start = right_pillar_start;
- f = tpg->field == (is_60hz ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);
+ params->sav_eav_f = tpg->field ==
+ (params->is_60hz ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);
+}
- for (h = 0; h < tpg->compose.height; h++) {
- bool even;
- bool fill_blank = false;
- unsigned frame_line;
- unsigned buf_line;
- unsigned pat_line_old;
- unsigned pat_line_new;
- u8 *linestart_older;
- u8 *linestart_newer;
- u8 *linestart_top;
- u8 *linestart_bottom;
-
- frame_line = tpg_calc_frameline(tpg, src_y, tpg->field);
- even = !(frame_line & 1);
- buf_line = tpg_calc_buffer_line(tpg, h, tpg->field);
- src_y += int_part;
- error += fract_part;
- if (error >= tpg->compose.height) {
- error -= tpg->compose.height;
- src_y++;
- }
+static void tpg_fill_plane_extras(const struct tpg_data *tpg,
+ const struct tpg_draw_params *params,
+ unsigned p, unsigned h, u8 *vbuf)
+{
+ unsigned twopixsize = params->twopixsize;
+ unsigned img_width = params->img_width;
+ unsigned frame_line = params->frame_line;
+ const struct v4l2_rect *sq = &tpg->square;
+ const struct v4l2_rect *b = &tpg->border;
+ const struct v4l2_rect *c = &tpg->crop;
+
+ if (params->is_tv && !params->is_60hz &&
+ frame_line == 0 && params->wss_width) {
+ /*
+ * Replace the first half of the top line of a 50 Hz frame
+ * with random data to simulate a WSS signal.
+ */
+ u8 *wss = tpg->random_line[p] + params->wss_random_offset;
- if (h >= hmax) {
- if (hmax == tpg->compose.height)
- continue;
- if (!tpg->perc_fill_blank)
- continue;
- fill_blank = true;
- }
+ memcpy(vbuf, wss, params->wss_width);
+ }
+
+ if (tpg->show_border && frame_line >= b->top &&
+ frame_line < b->top + b->height) {
+ unsigned bottom = b->top + b->height - 1;
+ unsigned left = params->left_pillar_width;
+ unsigned right = params->right_pillar_start;
- if (tpg->vflip)
- frame_line = tpg->src_height - frame_line - 1;
-
- if (fill_blank) {
- linestart_older = tpg->contrast_line[p];
- linestart_newer = tpg->contrast_line[p];
- } else if (tpg->qual != TPG_QUAL_NOISE &&
- (frame_line < tpg->border.top ||
- frame_line >= tpg->border.top + tpg->border.height)) {
- linestart_older = tpg->black_line[p];
- linestart_newer = tpg->black_line[p];
- } else if (tpg->pattern == TPG_PAT_NOISE || tpg->qual == TPG_QUAL_NOISE) {
- linestart_older = tpg->random_line[p] +
- twopixsize * prandom_u32_max(tpg->src_width / 2);
- linestart_newer = tpg->random_line[p] +
- twopixsize * prandom_u32_max(tpg->src_width / 2);
+ if (frame_line == b->top || frame_line == b->top + 1 ||
+ frame_line == bottom || frame_line == bottom - 1) {
+ memcpy(vbuf + left, tpg->contrast_line[p],
+ right - left);
} else {
- pat_line_old = tpg_get_pat_line(tpg,
- (frame_line + mv_vert_old) % tpg->src_height);
- pat_line_new = tpg_get_pat_line(tpg,
- (frame_line + mv_vert_new) % tpg->src_height);
- linestart_older = tpg->lines[pat_line_old][p] +
- mv_hor_old * twopixsize / 2;
- linestart_newer = tpg->lines[pat_line_new][p] +
- mv_hor_new * twopixsize / 2;
- linestart_older += line_offset;
- linestart_newer += line_offset;
+ if (b->left >= c->left &&
+ b->left < c->left + c->width)
+ memcpy(vbuf + left,
+ tpg->contrast_line[p], twopixsize);
+ if (b->left + b->width > c->left &&
+ b->left + b->width <= c->left + c->width)
+ memcpy(vbuf + right - twopixsize,
+ tpg->contrast_line[p], twopixsize);
}
- if (is_60hz) {
- linestart_top = linestart_newer;
- linestart_bottom = linestart_older;
- } else {
- linestart_top = linestart_older;
- linestart_bottom = linestart_newer;
+ }
+ if (tpg->qual != TPG_QUAL_NOISE && frame_line >= b->top &&
+ frame_line < b->top + b->height) {
+ memcpy(vbuf, tpg->black_line[p], params->left_pillar_width);
+ memcpy(vbuf + params->right_pillar_start, tpg->black_line[p],
+ img_width - params->right_pillar_start);
+ }
+ if (tpg->show_square && frame_line >= sq->top &&
+ frame_line < sq->top + sq->height &&
+ sq->left < c->left + c->width &&
+ sq->left + sq->width >= c->left) {
+ unsigned left = sq->left;
+ unsigned width = sq->width;
+
+ if (c->left > left) {
+ width -= c->left - left;
+ left = c->left;
}
+ if (c->left + c->width < left + width)
+ width -= left + width - c->left - c->width;
+ left -= c->left;
+ left = tpg_hscale_div(tpg, p, left);
+ width = tpg_hscale_div(tpg, p, width);
+ memcpy(vbuf + left, tpg->contrast_line[p], width);
+ }
+ if (tpg->insert_sav) {
+ unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width / 3);
+ u8 *p = vbuf + offset;
+ unsigned vact = 0, hact = 0;
+
+ p[0] = 0xff;
+ p[1] = 0;
+ p[2] = 0;
+ p[3] = 0x80 | (params->sav_eav_f << 6) |
+ (vact << 5) | (hact << 4) |
+ ((hact ^ vact) << 3) |
+ ((hact ^ params->sav_eav_f) << 2) |
+ ((params->sav_eav_f ^ vact) << 1) |
+ (hact ^ vact ^ params->sav_eav_f);
+ }
+ if (tpg->insert_eav) {
+ unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width * 2 / 3);
+ u8 *p = vbuf + offset;
+ unsigned vact = 0, hact = 1;
+
+ p[0] = 0xff;
+ p[1] = 0;
+ p[2] = 0;
+ p[3] = 0x80 | (params->sav_eav_f << 6) |
+ (vact << 5) | (hact << 4) |
+ ((hact ^ vact) << 3) |
+ ((hact ^ params->sav_eav_f) << 2) |
+ ((params->sav_eav_f ^ vact) << 1) |
+ (hact ^ vact ^ params->sav_eav_f);
+ }
+}
- switch (tpg->field) {
- case V4L2_FIELD_INTERLACED:
- case V4L2_FIELD_INTERLACED_TB:
- case V4L2_FIELD_SEQ_TB:
- case V4L2_FIELD_SEQ_BT:
- if (even)
- memcpy(vbuf + buf_line * stride, linestart_top, img_width);
- else
- memcpy(vbuf + buf_line * stride, linestart_bottom, img_width);
- break;
- case V4L2_FIELD_INTERLACED_BT:
- if (even)
- memcpy(vbuf + buf_line * stride, linestart_bottom, img_width);
- else
- memcpy(vbuf + buf_line * stride, linestart_top, img_width);
- break;
- case V4L2_FIELD_TOP:
- memcpy(vbuf + buf_line * stride, linestart_top, img_width);
- break;
- case V4L2_FIELD_BOTTOM:
- memcpy(vbuf + buf_line * stride, linestart_bottom, img_width);
- break;
- case V4L2_FIELD_NONE:
- default:
- memcpy(vbuf + buf_line * stride, linestart_older, img_width);
- break;
- }
+static void tpg_fill_plane_pattern(const struct tpg_data *tpg,
+ const struct tpg_draw_params *params,
+ unsigned p, unsigned h, u8 *vbuf)
+{
+ unsigned twopixsize = params->twopixsize;
+ unsigned img_width = params->img_width;
+ unsigned mv_hor_old = params->mv_hor_old;
+ unsigned mv_hor_new = params->mv_hor_new;
+ unsigned mv_vert_old = params->mv_vert_old;
+ unsigned mv_vert_new = params->mv_vert_new;
+ unsigned frame_line = params->frame_line;
+ unsigned frame_line_next = params->frame_line_next;
+ unsigned line_offset = tpg_hscale_div(tpg, p, tpg->crop.left);
+ bool even;
+ bool fill_blank = false;
+ unsigned pat_line_old;
+ unsigned pat_line_new;
+ u8 *linestart_older;
+ u8 *linestart_newer;
+ u8 *linestart_top;
+ u8 *linestart_bottom;
+
+ even = !(frame_line & 1);
+
+ if (h >= params->hmax) {
+ if (params->hmax == tpg->compose.height)
+ return;
+ if (!tpg->perc_fill_blank)
+ return;
+ fill_blank = true;
+ }
- if (is_tv && !is_60hz && frame_line == 0 && wss_width) {
- /*
- * Replace the first half of the top line of a 50 Hz frame
- * with random data to simulate a WSS signal.
- */
- u8 *wss = tpg->random_line[p] +
+ if (tpg->vflip) {
+ frame_line = tpg->src_height - frame_line - 1;
+ frame_line_next = tpg->src_height - frame_line_next - 1;
+ }
+
+ if (fill_blank) {
+ linestart_older = tpg->contrast_line[p];
+ linestart_newer = tpg->contrast_line[p];
+ } else if (tpg->qual != TPG_QUAL_NOISE &&
+ (frame_line < tpg->border.top ||
+ frame_line >= tpg->border.top + tpg->border.height)) {
+ linestart_older = tpg->black_line[p];
+ linestart_newer = tpg->black_line[p];
+ } else if (tpg->pattern == TPG_PAT_NOISE || tpg->qual == TPG_QUAL_NOISE) {
+ linestart_older = tpg->random_line[p] +
+ twopixsize * prandom_u32_max(tpg->src_width / 2);
+ linestart_newer = tpg->random_line[p] +
twopixsize * prandom_u32_max(tpg->src_width / 2);
+ } else {
+ unsigned frame_line_old =
+ (frame_line + mv_vert_old) % tpg->src_height;
+ unsigned frame_line_new =
+ (frame_line + mv_vert_new) % tpg->src_height;
+ unsigned pat_line_next_old;
+ unsigned pat_line_next_new;
- memcpy(vbuf + buf_line * stride, wss, wss_width * twopixsize / 2);
+ pat_line_old = tpg_get_pat_line(tpg, frame_line_old);
+ pat_line_new = tpg_get_pat_line(tpg, frame_line_new);
+ linestart_older = tpg->lines[pat_line_old][p] + mv_hor_old;
+ linestart_newer = tpg->lines[pat_line_new][p] + mv_hor_new;
+
+ if (tpg->vdownsampling[p] > 1 && frame_line != frame_line_next) {
+ int avg_pat;
+
+ /*
+ * Now decide whether we need to use downsampled_lines[].
+ * That's necessary if the two lines use different patterns.
+ */
+ pat_line_next_old = tpg_get_pat_line(tpg,
+ (frame_line_next + mv_vert_old) % tpg->src_height);
+ pat_line_next_new = tpg_get_pat_line(tpg,
+ (frame_line_next + mv_vert_new) % tpg->src_height);
+
+ switch (tpg->field) {
+ case V4L2_FIELD_INTERLACED:
+ case V4L2_FIELD_INTERLACED_BT:
+ case V4L2_FIELD_INTERLACED_TB:
+ avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_new);
+ if (avg_pat < 0)
+ break;
+ linestart_older = tpg->downsampled_lines[avg_pat][p] + mv_hor_old;
+ linestart_newer = linestart_older;
+ break;
+ case V4L2_FIELD_NONE:
+ case V4L2_FIELD_TOP:
+ case V4L2_FIELD_BOTTOM:
+ case V4L2_FIELD_SEQ_BT:
+ case V4L2_FIELD_SEQ_TB:
+ avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_next_old);
+ if (avg_pat >= 0)
+ linestart_older = tpg->downsampled_lines[avg_pat][p] +
+ mv_hor_old;
+ avg_pat = tpg_pattern_avg(tpg, pat_line_new, pat_line_next_new);
+ if (avg_pat >= 0)
+ linestart_newer = tpg->downsampled_lines[avg_pat][p] +
+ mv_hor_new;
+ break;
+ }
}
+ linestart_older += line_offset;
+ linestart_newer += line_offset;
+ }
+ if (tpg->field_alternate) {
+ linestart_top = linestart_bottom = linestart_older;
+ } else if (params->is_60hz) {
+ linestart_top = linestart_newer;
+ linestart_bottom = linestart_older;
+ } else {
+ linestart_top = linestart_older;
+ linestart_bottom = linestart_newer;
+ }
+
+ switch (tpg->field) {
+ case V4L2_FIELD_INTERLACED:
+ case V4L2_FIELD_INTERLACED_TB:
+ case V4L2_FIELD_SEQ_TB:
+ case V4L2_FIELD_SEQ_BT:
+ if (even)
+ memcpy(vbuf, linestart_top, img_width);
+ else
+ memcpy(vbuf, linestart_bottom, img_width);
+ break;
+ case V4L2_FIELD_INTERLACED_BT:
+ if (even)
+ memcpy(vbuf, linestart_bottom, img_width);
+ else
+ memcpy(vbuf, linestart_top, img_width);
+ break;
+ case V4L2_FIELD_TOP:
+ memcpy(vbuf, linestart_top, img_width);
+ break;
+ case V4L2_FIELD_BOTTOM:
+ memcpy(vbuf, linestart_bottom, img_width);
+ break;
+ case V4L2_FIELD_NONE:
+ default:
+ memcpy(vbuf, linestart_older, img_width);
+ break;
}
+}
+
+void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std,
+ unsigned p, u8 *vbuf)
+{
+ struct tpg_draw_params params;
+ unsigned factor = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
+
+ /* Coarse scaling with Bresenham */
+ unsigned int_part = (tpg->crop.height / factor) / tpg->compose.height;
+ unsigned fract_part = (tpg->crop.height / factor) % tpg->compose.height;
+ unsigned src_y = 0;
+ unsigned error = 0;
+ unsigned h;
+
+ tpg_recalc(tpg);
+
+ params.is_tv = std;
+ params.is_60hz = std & V4L2_STD_525_60;
+ params.twopixsize = tpg->twopixelsize[p];
+ params.img_width = tpg_hdiv(tpg, p, tpg->compose.width);
+ params.stride = tpg->bytesperline[p];
+ params.hmax = (tpg->compose.height * tpg->perc_fill) / 100;
+
+ tpg_fill_params_pattern(tpg, p, &params);
+ tpg_fill_params_extras(tpg, p, &params);
+
+ vbuf += tpg_hdiv(tpg, p, tpg->compose.left);
- vbuf = orig_vbuf;
- vbuf += tpg->compose.left * twopixsize / 2;
- src_y = 0;
- error = 0;
for (h = 0; h < tpg->compose.height; h++) {
- unsigned frame_line = tpg_calc_frameline(tpg, src_y, tpg->field);
- unsigned buf_line = tpg_calc_buffer_line(tpg, h, tpg->field);
- const struct v4l2_rect *sq = &tpg->square;
- const struct v4l2_rect *b = &tpg->border;
- const struct v4l2_rect *c = &tpg->crop;
+ unsigned buf_line;
+ params.frame_line = tpg_calc_frameline(tpg, src_y, tpg->field);
+ params.frame_line_next = params.frame_line;
+ buf_line = tpg_calc_buffer_line(tpg, h, tpg->field);
src_y += int_part;
error += fract_part;
if (error >= tpg->compose.height) {
@@ -1475,80 +2032,61 @@ void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf)
src_y++;
}
- if (tpg->show_border && frame_line >= b->top &&
- frame_line < b->top + b->height) {
- unsigned bottom = b->top + b->height - 1;
- unsigned left = left_pillar_width;
- unsigned right = right_pillar_start;
+ /*
+ * For line-interleaved formats determine the 'plane'
+ * based on the buffer line.
+ */
+ if (tpg_g_interleaved(tpg))
+ p = tpg_g_interleaved_plane(tpg, buf_line);
- if (frame_line == b->top || frame_line == b->top + 1 ||
- frame_line == bottom || frame_line == bottom - 1) {
- memcpy(vbuf + buf_line * stride + left, tpg->contrast_line[p],
- right - left);
+ if (tpg->vdownsampling[p] > 1) {
+ /*
+ * When doing vertical downsampling the field setting
+ * matters: for SEQ_BT/TB we downsample each field
+ * separately (i.e. lines 0+2 are combined, as are
+ * lines 1+3), for the other field settings we combine
+ * odd and even lines. Doing that for SEQ_BT/TB would
+ * be really weird.
+ */
+ if (tpg->field == V4L2_FIELD_SEQ_BT ||
+ tpg->field == V4L2_FIELD_SEQ_TB) {
+ unsigned next_src_y = src_y;
+
+ if ((h & 3) >= 2)
+ continue;
+ next_src_y += int_part;
+ if (error + fract_part >= tpg->compose.height)
+ next_src_y++;
+ params.frame_line_next =
+ tpg_calc_frameline(tpg, next_src_y, tpg->field);
} else {
- if (b->left >= c->left &&
- b->left < c->left + c->width)
- memcpy(vbuf + buf_line * stride + left,
- tpg->contrast_line[p], twopixsize);
- if (b->left + b->width > c->left &&
- b->left + b->width <= c->left + c->width)
- memcpy(vbuf + buf_line * stride + right - twopixsize,
- tpg->contrast_line[p], twopixsize);
+ if (h & 1)
+ continue;
+ params.frame_line_next =
+ tpg_calc_frameline(tpg, src_y, tpg->field);
}
+
+ buf_line /= tpg->vdownsampling[p];
}
- if (tpg->qual != TPG_QUAL_NOISE && frame_line >= b->top &&
- frame_line < b->top + b->height) {
- memcpy(vbuf + buf_line * stride, tpg->black_line[p], left_pillar_width);
- memcpy(vbuf + buf_line * stride + right_pillar_start, tpg->black_line[p],
- img_width - right_pillar_start);
- }
- if (tpg->show_square && frame_line >= sq->top &&
- frame_line < sq->top + sq->height &&
- sq->left < c->left + c->width &&
- sq->left + sq->width >= c->left) {
- unsigned left = sq->left;
- unsigned width = sq->width;
-
- if (c->left > left) {
- width -= c->left - left;
- left = c->left;
- }
- if (c->left + c->width < left + width)
- width -= left + width - c->left - c->width;
- left -= c->left;
- left = (left * tpg->scaled_width) / tpg->src_width;
- left = (left & ~1) * twopixsize / 2;
- width = (width * tpg->scaled_width) / tpg->src_width;
- width = (width & ~1) * twopixsize / 2;
- memcpy(vbuf + buf_line * stride + left, tpg->contrast_line[p], width);
- }
- if (tpg->insert_sav) {
- unsigned offset = (tpg->compose.width / 6) * twopixsize;
- u8 *p = vbuf + buf_line * stride + offset;
- unsigned vact = 0, hact = 0;
-
- p[0] = 0xff;
- p[1] = 0;
- p[2] = 0;
- p[3] = 0x80 | (f << 6) | (vact << 5) | (hact << 4) |
- ((hact ^ vact) << 3) |
- ((hact ^ f) << 2) |
- ((f ^ vact) << 1) |
- (hact ^ vact ^ f);
- }
- if (tpg->insert_eav) {
- unsigned offset = (tpg->compose.width / 6) * 2 * twopixsize;
- u8 *p = vbuf + buf_line * stride + offset;
- unsigned vact = 0, hact = 1;
-
- p[0] = 0xff;
- p[1] = 0;
- p[2] = 0;
- p[3] = 0x80 | (f << 6) | (vact << 5) | (hact << 4) |
- ((hact ^ vact) << 3) |
- ((hact ^ f) << 2) |
- ((f ^ vact) << 1) |
- (hact ^ vact ^ f);
- }
+ tpg_fill_plane_pattern(tpg, &params, p, h,
+ vbuf + buf_line * params.stride);
+ tpg_fill_plane_extras(tpg, &params, p, h,
+ vbuf + buf_line * params.stride);
+ }
+}
+
+void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf)
+{
+ unsigned offset = 0;
+ unsigned i;
+
+ if (tpg->buffers > 1) {
+ tpg_fill_plane_buffer(tpg, std, p, vbuf);
+ return;
+ }
+
+ for (i = 0; i < tpg_g_planes(tpg); i++) {
+ tpg_fill_plane_buffer(tpg, std, i, vbuf + offset);
+ offset += tpg_calc_plane_size(tpg, i);
}
}
diff --git a/drivers/media/platform/vivid/vivid-tpg.h b/drivers/media/platform/vivid/vivid-tpg.h
index bd8b1c760b3f..a50cd2e2535b 100644
--- a/drivers/media/platform/vivid/vivid-tpg.h
+++ b/drivers/media/platform/vivid/vivid-tpg.h
@@ -41,7 +41,10 @@ enum tpg_pattern {
TPG_PAT_GREEN,
TPG_PAT_BLUE,
TPG_PAT_CHECKERS_16X16,
+ TPG_PAT_CHECKERS_2X2,
TPG_PAT_CHECKERS_1X1,
+ TPG_PAT_COLOR_CHECKERS_2X2,
+ TPG_PAT_COLOR_CHECKERS_1X1,
TPG_PAT_ALTERNATING_HLINES,
TPG_PAT_ALTERNATING_VLINES,
TPG_PAT_CROSS_1_PIXEL,
@@ -87,7 +90,7 @@ enum tpg_move_mode {
extern const char * const tpg_aspect_strings[];
-#define TPG_MAX_PLANES 2
+#define TPG_MAX_PLANES 3
#define TPG_MAX_PAT_LINES 8
struct tpg_data {
@@ -98,6 +101,7 @@ struct tpg_data {
/* Scaled output frame size */
unsigned scaled_width;
u32 field;
+ bool field_alternate;
/* crop coordinates are frame-based */
struct v4l2_rect crop;
/* compose coordinates are format-based */
@@ -134,7 +138,16 @@ struct tpg_data {
enum tpg_pixel_aspect pix_aspect;
unsigned rgb_range;
unsigned real_rgb_range;
+ unsigned buffers;
unsigned planes;
+ bool interleaved;
+ u8 vdownsampling[TPG_MAX_PLANES];
+ u8 hdownsampling[TPG_MAX_PLANES];
+ /*
+ * horizontal positions must be ANDed with this value to enforce
+ * correct boundaries for packed YUYV values.
+ */
+ unsigned hmask[TPG_MAX_PLANES];
/* Used to store the colors in native format, either RGB or YUV */
u8 colors[TPG_COLOR_MAX][3];
u8 textfg[TPG_MAX_PLANES][8], textbg[TPG_MAX_PLANES][8];
@@ -168,6 +181,7 @@ struct tpg_data {
/* Used to store TPG_MAX_PAT_LINES lines, each with up to two planes */
unsigned max_line_width;
u8 *lines[TPG_MAX_PAT_LINES][TPG_MAX_PLANES];
+ u8 *downsampled_lines[TPG_MAX_PAT_LINES][TPG_MAX_PLANES];
u8 *random_line[TPG_MAX_PLANES];
u8 *contrast_line[TPG_MAX_PLANES];
u8 *black_line[TPG_MAX_PLANES];
@@ -180,11 +194,15 @@ void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height,
u32 field);
void tpg_set_font(const u8 *f);
-void tpg_gen_text(struct tpg_data *tpg,
+void tpg_gen_text(const struct tpg_data *tpg,
u8 *basep[TPG_MAX_PLANES][2], int y, int x, char *text);
void tpg_calc_text_basep(struct tpg_data *tpg,
u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf);
-void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf);
+unsigned tpg_g_interleaved_plane(const struct tpg_data *tpg, unsigned buf_line);
+void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std,
+ unsigned p, u8 *vbuf);
+void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std,
+ unsigned p, u8 *vbuf);
bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc);
void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop,
const struct v4l2_rect *compose);
@@ -323,9 +341,19 @@ static inline u32 tpg_g_quantization(const struct tpg_data *tpg)
return tpg->quantization;
}
+static inline unsigned tpg_g_buffers(const struct tpg_data *tpg)
+{
+ return tpg->buffers;
+}
+
static inline unsigned tpg_g_planes(const struct tpg_data *tpg)
{
- return tpg->planes;
+ return tpg->interleaved ? 1 : tpg->planes;
+}
+
+static inline bool tpg_g_interleaved(const struct tpg_data *tpg)
+{
+ return tpg->interleaved;
}
static inline unsigned tpg_g_twopixelsize(const struct tpg_data *tpg, unsigned plane)
@@ -333,6 +361,24 @@ static inline unsigned tpg_g_twopixelsize(const struct tpg_data *tpg, unsigned p
return tpg->twopixelsize[plane];
}
+static inline unsigned tpg_hdiv(const struct tpg_data *tpg,
+ unsigned plane, unsigned x)
+{
+ return ((x / tpg->hdownsampling[plane]) & tpg->hmask[plane]) *
+ tpg->twopixelsize[plane] / 2;
+}
+
+static inline unsigned tpg_hscale(const struct tpg_data *tpg, unsigned x)
+{
+ return (x * tpg->scaled_width) / tpg->src_width;
+}
+
+static inline unsigned tpg_hscale_div(const struct tpg_data *tpg,
+ unsigned plane, unsigned x)
+{
+ return tpg_hdiv(tpg, plane, tpg_hscale(tpg, x));
+}
+
static inline unsigned tpg_g_bytesperline(const struct tpg_data *tpg, unsigned plane)
{
return tpg->bytesperline[plane];
@@ -340,7 +386,60 @@ static inline unsigned tpg_g_bytesperline(const struct tpg_data *tpg, unsigned p
static inline void tpg_s_bytesperline(struct tpg_data *tpg, unsigned plane, unsigned bpl)
{
- tpg->bytesperline[plane] = bpl;
+ unsigned p;
+
+ if (tpg->buffers > 1) {
+ tpg->bytesperline[plane] = bpl;
+ return;
+ }
+
+ for (p = 0; p < tpg_g_planes(tpg); p++) {
+ unsigned plane_w = bpl * tpg->twopixelsize[p] / tpg->twopixelsize[0];
+
+ tpg->bytesperline[p] = plane_w / tpg->hdownsampling[p];
+ }
+}
+
+
+static inline unsigned tpg_g_line_width(const struct tpg_data *tpg, unsigned plane)
+{
+ unsigned w = 0;
+ unsigned p;
+
+ if (tpg->buffers > 1)
+ return tpg_g_bytesperline(tpg, plane);
+ for (p = 0; p < tpg_g_planes(tpg); p++) {
+ unsigned plane_w = tpg_g_bytesperline(tpg, p);
+
+ w += plane_w / tpg->vdownsampling[p];
+ }
+ return w;
+}
+
+static inline unsigned tpg_calc_line_width(const struct tpg_data *tpg,
+ unsigned plane, unsigned bpl)
+{
+ unsigned w = 0;
+ unsigned p;
+
+ if (tpg->buffers > 1)
+ return bpl;
+ for (p = 0; p < tpg_g_planes(tpg); p++) {
+ unsigned plane_w = bpl * tpg->twopixelsize[p] / tpg->twopixelsize[0];
+
+ plane_w /= tpg->hdownsampling[p];
+ w += plane_w / tpg->vdownsampling[p];
+ }
+ return w;
+}
+
+static inline unsigned tpg_calc_plane_size(const struct tpg_data *tpg, unsigned plane)
+{
+ if (plane >= tpg_g_planes(tpg))
+ return 0;
+
+ return tpg_g_bytesperline(tpg, plane) * tpg->buf_height /
+ tpg->vdownsampling[plane];
}
static inline void tpg_s_buf_height(struct tpg_data *tpg, unsigned h)
@@ -348,9 +447,10 @@ static inline void tpg_s_buf_height(struct tpg_data *tpg, unsigned h)
tpg->buf_height = h;
}
-static inline void tpg_s_field(struct tpg_data *tpg, unsigned field)
+static inline void tpg_s_field(struct tpg_data *tpg, unsigned field, bool alternate)
{
tpg->field = field;
+ tpg->field_alternate = alternate;
}
static inline void tpg_s_perc_fill(struct tpg_data *tpg,
diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c
index 867a29a6d18f..dab5990f45a0 100644
--- a/drivers/media/platform/vivid/vivid-vid-cap.c
+++ b/drivers/media/platform/vivid/vivid-vid-cap.c
@@ -42,20 +42,26 @@ static const struct vivid_fmt formats_ovl[] = {
{
.name = "RGB565 (LE)",
.fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */
- .depth = 16,
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
.planes = 1,
+ .buffers = 1,
},
{
.name = "XRGB555 (LE)",
.fourcc = V4L2_PIX_FMT_XRGB555, /* gggbbbbb arrrrrgg */
- .depth = 16,
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
.planes = 1,
+ .buffers = 1,
},
{
.name = "ARGB555 (LE)",
.fourcc = V4L2_PIX_FMT_ARGB555, /* gggbbbbb arrrrrgg */
- .depth = 16,
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
.planes = 1,
+ .buffers = 1,
},
};
@@ -94,7 +100,7 @@ static int vid_cap_queue_setup(struct vb2_queue *vq, const struct v4l2_format *f
unsigned sizes[], void *alloc_ctxs[])
{
struct vivid_dev *dev = vb2_get_drv_priv(vq);
- unsigned planes = tpg_g_planes(&dev->tpg);
+ unsigned buffers = tpg_g_buffers(&dev->tpg);
unsigned h = dev->fmt_cap_rect.height;
unsigned p;
@@ -127,39 +133,36 @@ static int vid_cap_queue_setup(struct vb2_queue *vq, const struct v4l2_format *f
mp = &fmt->fmt.pix_mp;
/*
* Check if the number of planes in the specified format match
- * the number of planes in the current format. You can't mix that.
+ * the number of buffers in the current format. You can't mix that.
*/
- if (mp->num_planes != planes)
+ if (mp->num_planes != buffers)
return -EINVAL;
vfmt = vivid_get_format(dev, mp->pixelformat);
- for (p = 0; p < planes; p++) {
+ for (p = 0; p < buffers; p++) {
sizes[p] = mp->plane_fmt[p].sizeimage;
- if (sizes[0] < tpg_g_bytesperline(&dev->tpg, 0) * h +
+ if (sizes[p] < tpg_g_line_width(&dev->tpg, p) * h +
vfmt->data_offset[p])
return -EINVAL;
}
} else {
- for (p = 0; p < planes; p++)
- sizes[p] = tpg_g_bytesperline(&dev->tpg, p) * h +
+ for (p = 0; p < buffers; p++)
+ sizes[p] = tpg_g_line_width(&dev->tpg, p) * h +
dev->fmt_cap->data_offset[p];
}
if (vq->num_buffers + *nbuffers < 2)
*nbuffers = 2 - vq->num_buffers;
- *nplanes = planes;
+ *nplanes = buffers;
/*
* videobuf2-vmalloc allocator is context-less so no need to set
* alloc_ctxs array.
*/
- if (planes == 2)
- dprintk(dev, 1, "%s, count=%d, sizes=%u, %u\n", __func__,
- *nbuffers, sizes[0], sizes[1]);
- else
- dprintk(dev, 1, "%s, count=%d, size=%u\n", __func__,
- *nbuffers, sizes[0]);
+ dprintk(dev, 1, "%s: count=%d\n", __func__, *nbuffers);
+ for (p = 0; p < buffers; p++)
+ dprintk(dev, 1, "%s: size[%u]=%u\n", __func__, p, sizes[p]);
return 0;
}
@@ -168,7 +171,7 @@ static int vid_cap_buf_prepare(struct vb2_buffer *vb)
{
struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
unsigned long size;
- unsigned planes = tpg_g_planes(&dev->tpg);
+ unsigned buffers = tpg_g_buffers(&dev->tpg);
unsigned p;
dprintk(dev, 1, "%s\n", __func__);
@@ -184,13 +187,13 @@ static int vid_cap_buf_prepare(struct vb2_buffer *vb)
dev->buf_prepare_error = false;
return -EINVAL;
}
- for (p = 0; p < planes; p++) {
- size = tpg_g_bytesperline(&dev->tpg, p) * dev->fmt_cap_rect.height +
+ for (p = 0; p < buffers; p++) {
+ size = tpg_g_line_width(&dev->tpg, p) * dev->fmt_cap_rect.height +
dev->fmt_cap->data_offset[p];
- if (vb2_plane_size(vb, 0) < size) {
+ if (vb2_plane_size(vb, p) < size) {
dprintk(dev, 1, "%s data will not fit into plane %u (%lu < %lu)\n",
- __func__, p, vb2_plane_size(vb, 0), size);
+ __func__, p, vb2_plane_size(vb, p), size);
return -EINVAL;
}
@@ -441,7 +444,7 @@ void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls)
*/
if (keep_controls || !dev->colorspace)
break;
- if (bt->standards & V4L2_DV_BT_STD_CEA861) {
+ if (bt->flags & V4L2_DV_FL_IS_CE_VIDEO) {
if (bt->width == 720 && bt->height <= 576)
v4l2_ctrl_s_ctrl(dev->colorspace, VIVID_CS_170M);
else
@@ -526,11 +529,11 @@ int vivid_g_fmt_vid_cap(struct file *file, void *priv,
mp->colorspace = vivid_colorspace_cap(dev);
mp->ycbcr_enc = vivid_ycbcr_enc_cap(dev);
mp->quantization = vivid_quantization_cap(dev);
- mp->num_planes = dev->fmt_cap->planes;
+ mp->num_planes = dev->fmt_cap->buffers;
for (p = 0; p < mp->num_planes; p++) {
mp->plane_fmt[p].bytesperline = tpg_g_bytesperline(&dev->tpg, p);
mp->plane_fmt[p].sizeimage =
- mp->plane_fmt[p].bytesperline * mp->height +
+ tpg_g_line_width(&dev->tpg, p) * mp->height +
dev->fmt_cap->data_offset[p];
}
return 0;
@@ -596,18 +599,19 @@ int vivid_try_fmt_vid_cap(struct file *file, void *priv,
/* This driver supports custom bytesperline values */
- /* Calculate the minimum supported bytesperline value */
- bytesperline = (mp->width * fmt->depth) >> 3;
- /* Calculate the maximum supported bytesperline value */
- max_bpl = (MAX_ZOOM * MAX_WIDTH * fmt->depth) >> 3;
- mp->num_planes = fmt->planes;
+ mp->num_planes = fmt->buffers;
for (p = 0; p < mp->num_planes; p++) {
+ /* Calculate the minimum supported bytesperline value */
+ bytesperline = (mp->width * fmt->bit_depth[p]) >> 3;
+ /* Calculate the maximum supported bytesperline value */
+ max_bpl = (MAX_ZOOM * MAX_WIDTH * fmt->bit_depth[p]) >> 3;
+
if (pfmt[p].bytesperline > max_bpl)
pfmt[p].bytesperline = max_bpl;
if (pfmt[p].bytesperline < bytesperline)
pfmt[p].bytesperline = bytesperline;
- pfmt[p].sizeimage = pfmt[p].bytesperline * mp->height +
- fmt->data_offset[p];
+ pfmt[p].sizeimage = tpg_calc_line_width(&dev->tpg, p, pfmt[p].bytesperline) *
+ mp->height + fmt->data_offset[p];
memset(pfmt[p].reserved, 0, sizeof(pfmt[p].reserved));
}
mp->colorspace = vivid_colorspace_cap(dev);
@@ -627,6 +631,7 @@ int vivid_s_fmt_vid_cap(struct file *file, void *priv,
struct vb2_queue *q = &dev->vb_vid_cap_q;
int ret = vivid_try_fmt_vid_cap(file, priv, f);
unsigned factor = 1;
+ unsigned p;
unsigned i;
if (ret < 0)
@@ -729,13 +734,15 @@ int vivid_s_fmt_vid_cap(struct file *file, void *priv,
dev->fmt_cap_rect.width = mp->width;
dev->fmt_cap_rect.height = mp->height;
tpg_s_buf_height(&dev->tpg, mp->height);
- tpg_s_bytesperline(&dev->tpg, 0, mp->plane_fmt[0].bytesperline);
- if (tpg_g_planes(&dev->tpg) > 1)
- tpg_s_bytesperline(&dev->tpg, 1, mp->plane_fmt[1].bytesperline);
+ tpg_s_fourcc(&dev->tpg, dev->fmt_cap->fourcc);
+ for (p = 0; p < tpg_g_buffers(&dev->tpg); p++)
+ tpg_s_bytesperline(&dev->tpg, p, mp->plane_fmt[p].bytesperline);
dev->field_cap = mp->field;
- tpg_s_field(&dev->tpg, dev->field_cap);
+ if (dev->field_cap == V4L2_FIELD_ALTERNATE)
+ tpg_s_field(&dev->tpg, V4L2_FIELD_TOP, true);
+ else
+ tpg_s_field(&dev->tpg, dev->field_cap, false);
tpg_s_crop_compose(&dev->tpg, &dev->crop_cap, &dev->compose_cap);
- tpg_s_fourcc(&dev->tpg, dev->fmt_cap->fourcc);
if (vivid_is_sdtv_cap(dev))
dev->tv_field_cap = mp->field;
tpg_update_mv_step(&dev->tpg);
@@ -1012,8 +1019,12 @@ int vivid_vid_cap_cropcap(struct file *file, void *priv,
int vidioc_enum_fmt_vid_overlay(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
+ struct vivid_dev *dev = video_drvdata(file);
const struct vivid_fmt *fmt;
+ if (dev->multiplanar)
+ return -ENOTTY;
+
if (f->index >= ARRAY_SIZE(formats_ovl))
return -EINVAL;
@@ -1032,6 +1043,9 @@ int vidioc_g_fmt_vid_overlay(struct file *file, void *priv,
struct v4l2_window *win = &f->fmt.win;
unsigned clipcount = win->clipcount;
+ if (dev->multiplanar)
+ return -ENOTTY;
+
win->w.top = dev->overlay_cap_top;
win->w.left = dev->overlay_cap_left;
win->w.width = compose->width;
@@ -1063,6 +1077,9 @@ int vidioc_try_fmt_vid_overlay(struct file *file, void *priv,
struct v4l2_window *win = &f->fmt.win;
int i, j;
+ if (dev->multiplanar)
+ return -ENOTTY;
+
win->w.left = clamp_t(int, win->w.left,
-dev->fb_cap.fmt.width, dev->fb_cap.fmt.width);
win->w.top = clamp_t(int, win->w.top,
@@ -1150,6 +1167,9 @@ int vivid_vid_cap_overlay(struct file *file, void *fh, unsigned i)
{
struct vivid_dev *dev = video_drvdata(file);
+ if (dev->multiplanar)
+ return -ENOTTY;
+
if (i && dev->fb_vbase_cap == NULL)
return -EINVAL;
@@ -1169,6 +1189,9 @@ int vivid_vid_cap_g_fbuf(struct file *file, void *fh,
{
struct vivid_dev *dev = video_drvdata(file);
+ if (dev->multiplanar)
+ return -ENOTTY;
+
*a = dev->fb_cap;
a->capability = V4L2_FBUF_CAP_BITMAP_CLIPPING |
V4L2_FBUF_CAP_LIST_CLIPPING;
@@ -1185,6 +1208,9 @@ int vivid_vid_cap_s_fbuf(struct file *file, void *fh,
struct vivid_dev *dev = video_drvdata(file);
const struct vivid_fmt *fmt;
+ if (dev->multiplanar)
+ return -ENOTTY;
+
if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO))
return -EPERM;
@@ -1202,7 +1228,7 @@ int vivid_vid_cap_s_fbuf(struct file *file, void *fh,
fmt = vivid_get_format(dev, a->fmt.pixelformat);
if (!fmt || !fmt->can_do_overlay)
return -EINVAL;
- if (a->fmt.bytesperline < (a->fmt.width * fmt->depth) / 8)
+ if (a->fmt.bytesperline < (a->fmt.width * fmt->bit_depth[0]) / 8)
return -EINVAL;
if (a->fmt.height * a->fmt.bytesperline < a->fmt.sizeimage)
return -EINVAL;
@@ -1332,7 +1358,7 @@ int vidioc_s_input(struct file *file, void *priv, unsigned i)
v4l2_ctrl_s_ctrl(dev->colorspace, VIVID_CS_170M);
break;
case HDMI:
- if (bt->standards & V4L2_DV_BT_STD_CEA861) {
+ if (bt->flags & V4L2_DV_FL_IS_CE_VIDEO) {
if (dev->src_rect.width == 720 && dev->src_rect.height <= 576)
v4l2_ctrl_s_ctrl(dev->colorspace, VIVID_CS_170M);
else
@@ -1552,6 +1578,65 @@ int vivid_vid_cap_s_std(struct file *file, void *priv, v4l2_std_id id)
return 0;
}
+static void find_aspect_ratio(u32 width, u32 height,
+ u32 *num, u32 *denom)
+{
+ if (!(height % 3) && ((height * 4 / 3) == width)) {
+ *num = 4;
+ *denom = 3;
+ } else if (!(height % 9) && ((height * 16 / 9) == width)) {
+ *num = 16;
+ *denom = 9;
+ } else if (!(height % 10) && ((height * 16 / 10) == width)) {
+ *num = 16;
+ *denom = 10;
+ } else if (!(height % 4) && ((height * 5 / 4) == width)) {
+ *num = 5;
+ *denom = 4;
+ } else if (!(height % 9) && ((height * 15 / 9) == width)) {
+ *num = 15;
+ *denom = 9;
+ } else { /* default to 16:9 */
+ *num = 16;
+ *denom = 9;
+ }
+}
+
+static bool valid_cvt_gtf_timings(struct v4l2_dv_timings *timings)
+{
+ struct v4l2_bt_timings *bt = &timings->bt;
+ u32 total_h_pixel;
+ u32 total_v_lines;
+ u32 h_freq;
+
+ if (!v4l2_valid_dv_timings(timings, &vivid_dv_timings_cap,
+ NULL, NULL))
+ return false;
+
+ total_h_pixel = V4L2_DV_BT_FRAME_WIDTH(bt);
+ total_v_lines = V4L2_DV_BT_FRAME_HEIGHT(bt);
+
+ h_freq = (u32)bt->pixelclock / total_h_pixel;
+
+ if (bt->standards == 0 || (bt->standards & V4L2_DV_BT_STD_CVT)) {
+ if (v4l2_detect_cvt(total_v_lines, h_freq, bt->vsync,
+ bt->polarities, timings))
+ return true;
+ }
+
+ if (bt->standards == 0 || (bt->standards & V4L2_DV_BT_STD_GTF)) {
+ struct v4l2_fract aspect_ratio;
+
+ find_aspect_ratio(bt->width, bt->height,
+ &aspect_ratio.numerator,
+ &aspect_ratio.denominator);
+ if (v4l2_detect_gtf(total_v_lines, h_freq, bt->vsync,
+ bt->polarities, aspect_ratio, timings))
+ return true;
+ }
+ return false;
+}
+
int vivid_vid_cap_s_dv_timings(struct file *file, void *_fh,
struct v4l2_dv_timings *timings)
{
@@ -1559,13 +1644,16 @@ int vivid_vid_cap_s_dv_timings(struct file *file, void *_fh,
if (!vivid_is_hdmi_cap(dev))
return -ENODATA;
- if (vb2_is_busy(&dev->vb_vid_cap_q))
- return -EBUSY;
if (!v4l2_find_dv_timings_cap(timings, &vivid_dv_timings_cap,
- 0, NULL, NULL))
+ 0, NULL, NULL) &&
+ !valid_cvt_gtf_timings(timings))
return -EINVAL;
+
if (v4l2_match_dv_timings(timings, &dev->dv_timings_cap, 0))
return 0;
+ if (vb2_is_busy(&dev->vb_vid_cap_q))
+ return -EBUSY;
+
dev->dv_timings_cap = *timings;
vivid_update_format_cap(dev, false);
return 0;
@@ -1663,18 +1751,14 @@ int vidioc_enum_frameintervals(struct file *file, void *priv,
return -EINVAL;
if (!vivid_is_webcam(dev)) {
- static const struct v4l2_fract step = { 1, 1 };
-
if (fival->index)
return -EINVAL;
if (fival->width < MIN_WIDTH || fival->width > MAX_WIDTH * MAX_ZOOM)
return -EINVAL;
if (fival->height < MIN_HEIGHT || fival->height > MAX_HEIGHT * MAX_ZOOM)
return -EINVAL;
- fival->type = V4L2_FRMIVAL_TYPE_CONTINUOUS;
- fival->stepwise.min = tpf_min;
- fival->stepwise.max = tpf_max;
- fival->stepwise.step = step;
+ fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+ fival->discrete = dev->timeperframe_vid_cap;
return 0;
}
diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c
index 6bef1e6d6788..aa446271ad34 100644
--- a/drivers/media/platform/vivid/vivid-vid-common.c
+++ b/drivers/media/platform/vivid/vivid-vid-common.c
@@ -33,8 +33,9 @@ const struct v4l2_dv_timings_cap vivid_dv_timings_cap = {
.type = V4L2_DV_BT_656_1120,
/* keep this initialization for compatibility with GCC < 4.4.6 */
.reserved = { 0 },
- V4L2_INIT_BT_TIMINGS(0, MAX_WIDTH, 0, MAX_HEIGHT, 25000000, 600000000,
- V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT,
+ V4L2_INIT_BT_TIMINGS(0, MAX_WIDTH, 0, MAX_HEIGHT, 14000000, 775000000,
+ V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
+ V4L2_DV_BT_STD_CVT | V4L2_DV_BT_STD_GTF,
V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_INTERLACED)
};
@@ -46,145 +47,435 @@ struct vivid_fmt vivid_formats[] = {
{
.name = "4:2:2, packed, YUYV",
.fourcc = V4L2_PIX_FMT_YUYV,
- .depth = 16,
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
.is_yuv = true,
.planes = 1,
- .data_offset = { PLANE0_DATA_OFFSET, 0 },
+ .buffers = 1,
+ .data_offset = { PLANE0_DATA_OFFSET },
},
{
.name = "4:2:2, packed, UYVY",
.fourcc = V4L2_PIX_FMT_UYVY,
- .depth = 16,
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
.is_yuv = true,
.planes = 1,
+ .buffers = 1,
},
{
.name = "4:2:2, packed, YVYU",
.fourcc = V4L2_PIX_FMT_YVYU,
- .depth = 16,
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
.is_yuv = true,
.planes = 1,
+ .buffers = 1,
},
{
.name = "4:2:2, packed, VYUY",
.fourcc = V4L2_PIX_FMT_VYUY,
- .depth = 16,
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
+ .is_yuv = true,
+ .planes = 1,
+ .buffers = 1,
+ },
+ {
+ .name = "YUV 4:2:2 triplanar",
+ .fourcc = V4L2_PIX_FMT_YUV422P,
+ .vdownsampling = { 1, 1, 1 },
+ .bit_depth = { 8, 4, 4 },
+ .is_yuv = true,
+ .planes = 3,
+ .buffers = 1,
+ },
+ {
+ .name = "YUV 4:2:0 triplanar",
+ .fourcc = V4L2_PIX_FMT_YUV420,
+ .vdownsampling = { 1, 2, 2 },
+ .bit_depth = { 8, 4, 4 },
+ .is_yuv = true,
+ .planes = 3,
+ .buffers = 1,
+ },
+ {
+ .name = "YVU 4:2:0 triplanar",
+ .fourcc = V4L2_PIX_FMT_YVU420,
+ .vdownsampling = { 1, 2, 2 },
+ .bit_depth = { 8, 4, 4 },
+ .is_yuv = true,
+ .planes = 3,
+ .buffers = 1,
+ },
+ {
+ .name = "YUV 4:2:0 biplanar",
+ .fourcc = V4L2_PIX_FMT_NV12,
+ .vdownsampling = { 1, 2 },
+ .bit_depth = { 8, 8 },
+ .is_yuv = true,
+ .planes = 2,
+ .buffers = 1,
+ },
+ {
+ .name = "YVU 4:2:0 biplanar",
+ .fourcc = V4L2_PIX_FMT_NV21,
+ .vdownsampling = { 1, 2 },
+ .bit_depth = { 8, 8 },
+ .is_yuv = true,
+ .planes = 2,
+ .buffers = 1,
+ },
+ {
+ .name = "YUV 4:2:2 biplanar",
+ .fourcc = V4L2_PIX_FMT_NV16,
+ .vdownsampling = { 1, 1 },
+ .bit_depth = { 8, 8 },
+ .is_yuv = true,
+ .planes = 2,
+ .buffers = 1,
+ },
+ {
+ .name = "YVU 4:2:2 biplanar",
+ .fourcc = V4L2_PIX_FMT_NV61,
+ .vdownsampling = { 1, 1 },
+ .bit_depth = { 8, 8 },
+ .is_yuv = true,
+ .planes = 2,
+ .buffers = 1,
+ },
+ {
+ .name = "YUV 4:4:4 biplanar",
+ .fourcc = V4L2_PIX_FMT_NV24,
+ .vdownsampling = { 1, 1 },
+ .bit_depth = { 8, 16 },
+ .is_yuv = true,
+ .planes = 2,
+ .buffers = 1,
+ },
+ {
+ .name = "YVU 4:4:4 biplanar",
+ .fourcc = V4L2_PIX_FMT_NV42,
+ .vdownsampling = { 1, 1 },
+ .bit_depth = { 8, 16 },
+ .is_yuv = true,
+ .planes = 2,
+ .buffers = 1,
+ },
+ {
+ .name = "YUV555 (LE)",
+ .fourcc = V4L2_PIX_FMT_YUV555, /* uuuvvvvv ayyyyyuu */
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
+ .planes = 1,
+ .buffers = 1,
+ .alpha_mask = 0x8000,
+ },
+ {
+ .name = "YUV565 (LE)",
+ .fourcc = V4L2_PIX_FMT_YUV565, /* uuuvvvvv yyyyyuuu */
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
+ .planes = 1,
+ .buffers = 1,
+ },
+ {
+ .name = "YUV444",
+ .fourcc = V4L2_PIX_FMT_YUV444, /* uuuuvvvv aaaayyyy */
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
+ .planes = 1,
+ .buffers = 1,
+ .alpha_mask = 0xf000,
+ },
+ {
+ .name = "YUV32 (LE)",
+ .fourcc = V4L2_PIX_FMT_YUV32, /* ayuv */
+ .vdownsampling = { 1 },
+ .bit_depth = { 32 },
+ .planes = 1,
+ .buffers = 1,
+ .alpha_mask = 0x000000ff,
+ },
+ {
+ .name = "Monochrome",
+ .fourcc = V4L2_PIX_FMT_GREY,
+ .vdownsampling = { 1 },
+ .bit_depth = { 8 },
.is_yuv = true,
.planes = 1,
+ .buffers = 1,
+ },
+ {
+ .name = "RGB332",
+ .fourcc = V4L2_PIX_FMT_RGB332, /* rrrgggbb */
+ .vdownsampling = { 1 },
+ .bit_depth = { 8 },
+ .planes = 1,
+ .buffers = 1,
},
{
.name = "RGB565 (LE)",
.fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */
- .depth = 16,
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
.planes = 1,
+ .buffers = 1,
.can_do_overlay = true,
},
{
.name = "RGB565 (BE)",
.fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */
- .depth = 16,
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
.planes = 1,
+ .buffers = 1,
.can_do_overlay = true,
},
{
+ .name = "RGB444",
+ .fourcc = V4L2_PIX_FMT_RGB444, /* xxxxrrrr ggggbbbb */
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
+ .planes = 1,
+ .buffers = 1,
+ },
+ {
+ .name = "XRGB444",
+ .fourcc = V4L2_PIX_FMT_XRGB444, /* xxxxrrrr ggggbbbb */
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
+ .planes = 1,
+ .buffers = 1,
+ },
+ {
+ .name = "ARGB444",
+ .fourcc = V4L2_PIX_FMT_ARGB444, /* aaaarrrr ggggbbbb */
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
+ .planes = 1,
+ .buffers = 1,
+ .alpha_mask = 0x00f0,
+ },
+ {
.name = "RGB555 (LE)",
- .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */
- .depth = 16,
+ .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb xrrrrrgg */
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
.planes = 1,
+ .buffers = 1,
.can_do_overlay = true,
},
{
.name = "XRGB555 (LE)",
- .fourcc = V4L2_PIX_FMT_XRGB555, /* gggbbbbb arrrrrgg */
- .depth = 16,
+ .fourcc = V4L2_PIX_FMT_XRGB555, /* gggbbbbb xrrrrrgg */
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
.planes = 1,
+ .buffers = 1,
.can_do_overlay = true,
},
{
.name = "ARGB555 (LE)",
.fourcc = V4L2_PIX_FMT_ARGB555, /* gggbbbbb arrrrrgg */
- .depth = 16,
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
.planes = 1,
+ .buffers = 1,
.can_do_overlay = true,
.alpha_mask = 0x8000,
},
{
.name = "RGB555 (BE)",
- .fourcc = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */
- .depth = 16,
+ .fourcc = V4L2_PIX_FMT_RGB555X, /* xrrrrrgg gggbbbbb */
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
.planes = 1,
- .can_do_overlay = true,
+ .buffers = 1,
+ },
+ {
+ .name = "XRGB555 (BE)",
+ .fourcc = V4L2_PIX_FMT_XRGB555X, /* xrrrrrgg gggbbbbb */
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
+ .planes = 1,
+ .buffers = 1,
+ },
+ {
+ .name = "ARGB555 (BE)",
+ .fourcc = V4L2_PIX_FMT_ARGB555X, /* arrrrrgg gggbbbbb */
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
+ .planes = 1,
+ .buffers = 1,
+ .alpha_mask = 0x0080,
},
{
.name = "RGB24 (LE)",
.fourcc = V4L2_PIX_FMT_RGB24, /* rgb */
- .depth = 24,
+ .vdownsampling = { 1 },
+ .bit_depth = { 24 },
.planes = 1,
+ .buffers = 1,
},
{
.name = "RGB24 (BE)",
.fourcc = V4L2_PIX_FMT_BGR24, /* bgr */
- .depth = 24,
+ .vdownsampling = { 1 },
+ .bit_depth = { 24 },
.planes = 1,
+ .buffers = 1,
+ },
+ {
+ .name = "BGR666",
+ .fourcc = V4L2_PIX_FMT_BGR666, /* bbbbbbgg ggggrrrr rrxxxxxx */
+ .vdownsampling = { 1 },
+ .bit_depth = { 32 },
+ .planes = 1,
+ .buffers = 1,
},
{
.name = "RGB32 (LE)",
- .fourcc = V4L2_PIX_FMT_RGB32, /* argb */
- .depth = 32,
+ .fourcc = V4L2_PIX_FMT_RGB32, /* xrgb */
+ .vdownsampling = { 1 },
+ .bit_depth = { 32 },
.planes = 1,
+ .buffers = 1,
},
{
.name = "RGB32 (BE)",
- .fourcc = V4L2_PIX_FMT_BGR32, /* bgra */
- .depth = 32,
+ .fourcc = V4L2_PIX_FMT_BGR32, /* bgrx */
+ .vdownsampling = { 1 },
+ .bit_depth = { 32 },
.planes = 1,
+ .buffers = 1,
},
{
.name = "XRGB32 (LE)",
- .fourcc = V4L2_PIX_FMT_XRGB32, /* argb */
- .depth = 32,
+ .fourcc = V4L2_PIX_FMT_XRGB32, /* xrgb */
+ .vdownsampling = { 1 },
+ .bit_depth = { 32 },
.planes = 1,
+ .buffers = 1,
},
{
.name = "XRGB32 (BE)",
- .fourcc = V4L2_PIX_FMT_XBGR32, /* bgra */
- .depth = 32,
+ .fourcc = V4L2_PIX_FMT_XBGR32, /* bgrx */
+ .vdownsampling = { 1 },
+ .bit_depth = { 32 },
.planes = 1,
+ .buffers = 1,
},
{
.name = "ARGB32 (LE)",
.fourcc = V4L2_PIX_FMT_ARGB32, /* argb */
- .depth = 32,
+ .vdownsampling = { 1 },
+ .bit_depth = { 32 },
.planes = 1,
+ .buffers = 1,
.alpha_mask = 0x000000ff,
},
{
.name = "ARGB32 (BE)",
.fourcc = V4L2_PIX_FMT_ABGR32, /* bgra */
- .depth = 32,
+ .vdownsampling = { 1 },
+ .bit_depth = { 32 },
.planes = 1,
+ .buffers = 1,
.alpha_mask = 0xff000000,
},
{
- .name = "4:2:2, planar, YUV",
+ .name = "Bayer BG/GR",
+ .fourcc = V4L2_PIX_FMT_SBGGR8, /* Bayer BG/GR */
+ .vdownsampling = { 1 },
+ .bit_depth = { 8 },
+ .planes = 1,
+ .buffers = 1,
+ },
+ {
+ .name = "Bayer GB/RG",
+ .fourcc = V4L2_PIX_FMT_SGBRG8, /* Bayer GB/RG */
+ .vdownsampling = { 1 },
+ .bit_depth = { 8 },
+ .planes = 1,
+ .buffers = 1,
+ },
+ {
+ .name = "Bayer GR/BG",
+ .fourcc = V4L2_PIX_FMT_SGRBG8, /* Bayer GR/BG */
+ .vdownsampling = { 1 },
+ .bit_depth = { 8 },
+ .planes = 1,
+ .buffers = 1,
+ },
+ {
+ .name = "Bayer RG/GB",
+ .fourcc = V4L2_PIX_FMT_SRGGB8, /* Bayer RG/GB */
+ .vdownsampling = { 1 },
+ .bit_depth = { 8 },
+ .planes = 1,
+ .buffers = 1,
+ },
+ {
+ .name = "4:2:2, biplanar, YUV",
.fourcc = V4L2_PIX_FMT_NV16M,
- .depth = 8,
+ .vdownsampling = { 1, 1 },
+ .bit_depth = { 8, 8 },
.is_yuv = true,
.planes = 2,
+ .buffers = 2,
.data_offset = { PLANE0_DATA_OFFSET, 0 },
},
{
- .name = "4:2:2, planar, YVU",
+ .name = "4:2:2, biplanar, YVU",
.fourcc = V4L2_PIX_FMT_NV61M,
- .depth = 8,
+ .vdownsampling = { 1, 1 },
+ .bit_depth = { 8, 8 },
.is_yuv = true,
.planes = 2,
+ .buffers = 2,
.data_offset = { 0, PLANE0_DATA_OFFSET },
},
+ {
+ .name = "4:2:0, triplanar, YUV",
+ .fourcc = V4L2_PIX_FMT_YUV420M,
+ .vdownsampling = { 1, 2, 2 },
+ .bit_depth = { 8, 4, 4 },
+ .is_yuv = true,
+ .planes = 3,
+ .buffers = 3,
+ },
+ {
+ .name = "4:2:0, triplanar, YVU",
+ .fourcc = V4L2_PIX_FMT_YVU420M,
+ .vdownsampling = { 1, 2, 2 },
+ .bit_depth = { 8, 4, 4 },
+ .is_yuv = true,
+ .planes = 3,
+ .buffers = 3,
+ },
+ {
+ .name = "4:2:0, biplanar, YUV",
+ .fourcc = V4L2_PIX_FMT_NV12M,
+ .vdownsampling = { 1, 2 },
+ .bit_depth = { 8, 8 },
+ .is_yuv = true,
+ .planes = 2,
+ .buffers = 2,
+ },
+ {
+ .name = "4:2:0, biplanar, YVU",
+ .fourcc = V4L2_PIX_FMT_NV21M,
+ .vdownsampling = { 1, 2 },
+ .bit_depth = { 8, 8 },
+ .is_yuv = true,
+ .planes = 2,
+ .buffers = 2,
+ },
};
-/* There are 2 multiplanar formats in the list */
-#define VIVID_MPLANAR_FORMATS 2
+/* There are 6 multiplanar formats in the list */
+#define VIVID_MPLANAR_FORMATS 6
const struct vivid_fmt *vivid_get_format(struct vivid_dev *dev, u32 pixelformat)
{
@@ -194,7 +485,7 @@ const struct vivid_fmt *vivid_get_format(struct vivid_dev *dev, u32 pixelformat)
for (k = 0; k < ARRAY_SIZE(vivid_formats); k++) {
fmt = &vivid_formats[k];
if (fmt->fourcc == pixelformat)
- if (fmt->planes == 1 || dev->multiplanar)
+ if (fmt->buffers == 1 || dev->multiplanar)
return fmt;
}
@@ -210,6 +501,13 @@ bool vivid_vid_can_loop(struct vivid_dev *dev)
return false;
if (dev->field_cap != dev->field_out)
return false;
+ /*
+ * While this can be supported, it is just too much work
+ * to actually implement.
+ */
+ if (dev->field_cap == V4L2_FIELD_SEQ_TB ||
+ dev->field_cap == V4L2_FIELD_SEQ_BT)
+ return false;
if (vivid_is_svid_cap(dev) && vivid_is_svid_out(dev)) {
if (!(dev->std_cap & V4L2_STD_525_60) !=
!(dev->std_out & V4L2_STD_525_60))
@@ -397,6 +695,9 @@ int vivid_vid_adjust_sel(unsigned flags, struct v4l2_rect *r)
unsigned w = r->width;
unsigned h = r->height;
+ /* sanitize w and h in case someone passes ~0 as the value */
+ w &= 0xffff;
+ h &= 0xffff;
if (!(flags & V4L2_SEL_FLAG_LE)) {
w++;
h++;
@@ -421,8 +722,9 @@ int vivid_vid_adjust_sel(unsigned flags, struct v4l2_rect *r)
r->top = 0;
if (r->left < 0)
r->left = 0;
- r->left &= ~1;
- r->top &= ~1;
+ /* sanitize left and top in case someone passes ~0 as the value */
+ r->left &= 0xfffe;
+ r->top &= 0xfffe;
if (r->left + w > MAX_WIDTH)
r->left = MAX_WIDTH - w;
if (r->top + h > MAX_HEIGHT)
diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c
index 39ff79f6aa67..0af43dc7715c 100644
--- a/drivers/media/platform/vivid/vivid-vid-out.c
+++ b/drivers/media/platform/vivid/vivid-vid-out.c
@@ -36,9 +36,14 @@ static int vid_out_queue_setup(struct vb2_queue *vq, const struct v4l2_format *f
unsigned sizes[], void *alloc_ctxs[])
{
struct vivid_dev *dev = vb2_get_drv_priv(vq);
- unsigned planes = dev->fmt_out->planes;
+ const struct vivid_fmt *vfmt = dev->fmt_out;
+ unsigned planes = vfmt->buffers;
unsigned h = dev->fmt_out_rect.height;
unsigned size = dev->bytesperline_out[0] * h;
+ unsigned p;
+
+ for (p = vfmt->buffers; p < vfmt->planes; p++)
+ size += dev->bytesperline_out[p] * h / vfmt->vdownsampling[p];
if (dev->field_out == V4L2_FIELD_ALTERNATE) {
/*
@@ -74,21 +79,16 @@ static int vid_out_queue_setup(struct vb2_queue *vq, const struct v4l2_format *f
if (mp->num_planes != planes)
return -EINVAL;
sizes[0] = mp->plane_fmt[0].sizeimage;
- if (planes == 2) {
- sizes[1] = mp->plane_fmt[1].sizeimage;
- if (sizes[0] < dev->bytesperline_out[0] * h ||
- sizes[1] < dev->bytesperline_out[1] * h)
- return -EINVAL;
- } else if (sizes[0] < size) {
+ if (sizes[0] < size)
return -EINVAL;
+ for (p = 1; p < planes; p++) {
+ sizes[p] = mp->plane_fmt[p].sizeimage;
+ if (sizes[p] < dev->bytesperline_out[p] * h)
+ return -EINVAL;
}
} else {
- if (planes == 2) {
- sizes[0] = dev->bytesperline_out[0] * h;
- sizes[1] = dev->bytesperline_out[1] * h;
- } else {
- sizes[0] = size;
- }
+ for (p = 0; p < planes; p++)
+ sizes[p] = p ? dev->bytesperline_out[p] * h : size;
}
if (vq->num_buffers + *nbuffers < 2)
@@ -101,12 +101,9 @@ static int vid_out_queue_setup(struct vb2_queue *vq, const struct v4l2_format *f
* alloc_ctxs array.
*/
- if (planes == 2)
- dprintk(dev, 1, "%s, count=%d, sizes=%u, %u\n", __func__,
- *nbuffers, sizes[0], sizes[1]);
- else
- dprintk(dev, 1, "%s, count=%d, size=%u\n", __func__,
- *nbuffers, sizes[0]);
+ dprintk(dev, 1, "%s: count=%d\n", __func__, *nbuffers);
+ for (p = 0; p < planes; p++)
+ dprintk(dev, 1, "%s: size[%u]=%u\n", __func__, p, sizes[p]);
return 0;
}
@@ -114,7 +111,7 @@ static int vid_out_buf_prepare(struct vb2_buffer *vb)
{
struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
unsigned long size;
- unsigned planes = dev->fmt_out->planes;
+ unsigned planes;
unsigned p;
dprintk(dev, 1, "%s\n", __func__);
@@ -122,6 +119,8 @@ static int vid_out_buf_prepare(struct vb2_buffer *vb)
if (WARN_ON(NULL == dev->fmt_out))
return -EINVAL;
+ planes = dev->fmt_out->planes;
+
if (dev->buf_prepare_error) {
/*
* Error injection: test what happens if buf_prepare() returns
@@ -220,7 +219,7 @@ const struct vb2_ops vivid_vid_out_qops = {
void vivid_update_format_out(struct vivid_dev *dev)
{
struct v4l2_bt_timings *bt = &dev->dv_timings_out.bt;
- unsigned size;
+ unsigned size, p;
switch (dev->output_type[dev->output]) {
case SVID:
@@ -249,7 +248,7 @@ void vivid_update_format_out(struct vivid_dev *dev)
dev->field_out = V4L2_FIELD_ALTERNATE;
else
dev->field_out = V4L2_FIELD_NONE;
- if (!dev->dvi_d_out && (bt->standards & V4L2_DV_BT_STD_CEA861)) {
+ if (!dev->dvi_d_out && (bt->flags & V4L2_DV_FL_IS_CE_VIDEO)) {
if (bt->width == 720 && bt->height <= 576)
dev->colorspace_out = V4L2_COLORSPACE_SMPTE170M;
else
@@ -267,9 +266,9 @@ void vivid_update_format_out(struct vivid_dev *dev)
if (V4L2_FIELD_HAS_T_OR_B(dev->field_out))
dev->crop_out.height /= 2;
dev->fmt_out_rect = dev->crop_out;
- dev->bytesperline_out[0] = (dev->sink_rect.width * dev->fmt_out->depth) / 8;
- if (dev->fmt_out->planes == 2)
- dev->bytesperline_out[1] = (dev->sink_rect.width * dev->fmt_out->depth) / 8;
+ for (p = 0; p < dev->fmt_out->planes; p++)
+ dev->bytesperline_out[p] =
+ (dev->sink_rect.width * dev->fmt_out->bit_depth[p]) / 8;
}
/* Map the field to something that is valid for the current output */
@@ -313,21 +312,28 @@ int vivid_g_fmt_vid_out(struct file *file, void *priv,
{
struct vivid_dev *dev = video_drvdata(file);
struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp;
+ const struct vivid_fmt *fmt = dev->fmt_out;
unsigned p;
mp->width = dev->fmt_out_rect.width;
mp->height = dev->fmt_out_rect.height;
mp->field = dev->field_out;
- mp->pixelformat = dev->fmt_out->fourcc;
+ mp->pixelformat = fmt->fourcc;
mp->colorspace = dev->colorspace_out;
mp->ycbcr_enc = dev->ycbcr_enc_out;
mp->quantization = dev->quantization_out;
- mp->num_planes = dev->fmt_out->planes;
+ mp->num_planes = fmt->buffers;
for (p = 0; p < mp->num_planes; p++) {
mp->plane_fmt[p].bytesperline = dev->bytesperline_out[p];
mp->plane_fmt[p].sizeimage =
mp->plane_fmt[p].bytesperline * mp->height;
}
+ for (p = fmt->buffers; p < fmt->planes; p++) {
+ unsigned stride = dev->bytesperline_out[p];
+
+ mp->plane_fmt[0].sizeimage +=
+ (stride * mp->height) / fmt->vdownsampling[p];
+ }
return 0;
}
@@ -386,10 +392,10 @@ int vivid_try_fmt_vid_out(struct file *file, void *priv,
/* This driver supports custom bytesperline values */
/* Calculate the minimum supported bytesperline value */
- bytesperline = (mp->width * fmt->depth) >> 3;
+ bytesperline = (mp->width * fmt->bit_depth[0]) >> 3;
/* Calculate the maximum supported bytesperline value */
- max_bpl = (MAX_ZOOM * MAX_WIDTH * fmt->depth) >> 3;
- mp->num_planes = fmt->planes;
+ max_bpl = (MAX_ZOOM * MAX_WIDTH * fmt->bit_depth[0]) >> 3;
+ mp->num_planes = fmt->buffers;
for (p = 0; p < mp->num_planes; p++) {
if (pfmt[p].bytesperline > max_bpl)
pfmt[p].bytesperline = max_bpl;
@@ -398,11 +404,14 @@ int vivid_try_fmt_vid_out(struct file *file, void *priv,
pfmt[p].sizeimage = pfmt[p].bytesperline * mp->height;
memset(pfmt[p].reserved, 0, sizeof(pfmt[p].reserved));
}
+ for (p = fmt->buffers; p < fmt->planes; p++)
+ pfmt[0].sizeimage += (pfmt[0].bytesperline * fmt->bit_depth[p]) /
+ (fmt->bit_depth[0] * fmt->vdownsampling[p]);
mp->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
mp->quantization = V4L2_QUANTIZATION_DEFAULT;
if (vivid_is_svid_out(dev)) {
mp->colorspace = V4L2_COLORSPACE_SMPTE170M;
- } else if (dev->dvi_d_out || !(bt->standards & V4L2_DV_BT_STD_CEA861)) {
+ } else if (dev->dvi_d_out || !(bt->flags & V4L2_DV_FL_IS_CE_VIDEO)) {
mp->colorspace = V4L2_COLORSPACE_SRGB;
if (dev->dvi_d_out)
mp->quantization = V4L2_QUANTIZATION_LIM_RANGE;
@@ -429,6 +438,7 @@ int vivid_s_fmt_vid_out(struct file *file, void *priv,
struct vb2_queue *q = &dev->vb_vid_out_q;
int ret = vivid_try_fmt_vid_out(file, priv, f);
unsigned factor = 1;
+ unsigned p;
if (ret < 0)
return ret;
@@ -524,9 +534,12 @@ int vivid_s_fmt_vid_out(struct file *file, void *priv,
dev->fmt_out_rect.width = mp->width;
dev->fmt_out_rect.height = mp->height;
- dev->bytesperline_out[0] = mp->plane_fmt[0].bytesperline;
- if (mp->num_planes > 1)
- dev->bytesperline_out[1] = mp->plane_fmt[1].bytesperline;
+ for (p = 0; p < mp->num_planes; p++)
+ dev->bytesperline_out[p] = mp->plane_fmt[p].bytesperline;
+ for (p = dev->fmt_out->buffers; p < dev->fmt_out->planes; p++)
+ dev->bytesperline_out[p] =
+ (dev->bytesperline_out[0] * dev->fmt_out->bit_depth[p]) /
+ dev->fmt_out->bit_depth[0];
dev->field_out = mp->field;
if (vivid_is_svid_out(dev))
dev->tv_field_out = mp->field;
@@ -1114,13 +1127,13 @@ int vivid_vid_out_s_dv_timings(struct file *file, void *_fh,
if (!vivid_is_hdmi_out(dev))
return -ENODATA;
- if (vb2_is_busy(&dev->vb_vid_out_q))
- return -EBUSY;
if (!v4l2_find_dv_timings_cap(timings, &vivid_dv_timings_cap,
0, NULL, NULL))
return -EINVAL;
if (v4l2_match_dv_timings(timings, &dev->dv_timings_out, 0))
return 0;
+ if (vb2_is_busy(&dev->vb_vid_out_q))
+ return -EBUSY;
dev->dv_timings_out = *timings;
vivid_update_format_out(dev);
return 0;