summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/ipu-v3
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-03-09 23:45:54 +0100
committerLinus Torvalds <torvalds@linux-foundation.org>2019-03-09 23:45:54 +0100
commit96a6de1a541c86e9e67b9c310c14db4099bd1cbc (patch)
treee77eb0e998e996f53dd0709611bd8cdd8776ee70 /drivers/gpu/ipu-v3
parentMerge tag 'gfs2-5.1.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/g... (diff)
parentmedia: dvb/earth-pt1: fix wrong initialization for demod blocks (diff)
downloadlinux-96a6de1a541c86e9e67b9c310c14db4099bd1cbc.tar.xz
linux-96a6de1a541c86e9e67b9c310c14db4099bd1cbc.zip
Merge tag 'media/v5.1-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab: - remove sensor drivers that got converted from soc_camera - remaining soc_camera drivers got moved to staging - some documentation cleanups and improvements - the imx staging driver now supports imx7 - the ov9640, mt9m001 and mt9m111 got converted from soc_camera - the vim2m driver now does what a m2m convert driver expects to do - epoll() fixes on media subsystems - several drivers fixes, typos, cleanups and improvements * tag 'media/v5.1-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (346 commits) media: dvb/earth-pt1: fix wrong initialization for demod blocks media: vim2m: Address some coding style issues media: vim2m: don't use BUG() media: vim2m: speedup passthrough copy media: vim2m: add an horizontal scaler media: vim2m: don't accept YUYV anymore as output format media: vim2m: add vertical linear scaler media: vim2m: better handle cap/out buffers with different sizes media: vim2m: use different framesizes for bayer formats media: vim2m: add support for VIDIOC_ENUM_FRAMESIZES media: vim2m: ensure that width is multiple of two media: vim2m: improve debug messages media: vim2m: add bayer capture formats media: a few more typos at staging, pci, platform, radio and usb media: Documentation: fix several typos media: staging: fix several typos media: include: fix several typos media: common: fix several typos media: v4l2-core: fix several typos media: usb: fix several typos ...
Diffstat (limited to 'drivers/gpu/ipu-v3')
-rw-r--r--drivers/gpu/ipu-v3/ipu-cpmem.c26
-rw-r--r--drivers/gpu/ipu-v3/ipu-csi.c126
2 files changed, 109 insertions, 43 deletions
diff --git a/drivers/gpu/ipu-v3/ipu-cpmem.c b/drivers/gpu/ipu-v3/ipu-cpmem.c
index 163fadb8a33a..d047a6867c59 100644
--- a/drivers/gpu/ipu-v3/ipu-cpmem.c
+++ b/drivers/gpu/ipu-v3/ipu-cpmem.c
@@ -277,9 +277,10 @@ void ipu_cpmem_set_uv_offset(struct ipuv3_channel *ch, u32 u_off, u32 v_off)
}
EXPORT_SYMBOL_GPL(ipu_cpmem_set_uv_offset);
-void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride)
+void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride,
+ u32 pixelformat)
{
- u32 ilo, sly;
+ u32 ilo, sly, sluv;
if (stride < 0) {
stride = -stride;
@@ -290,9 +291,30 @@ void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride)
sly = (stride * 2) - 1;
+ switch (pixelformat) {
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_YVU420:
+ sluv = stride / 2 - 1;
+ break;
+ case V4L2_PIX_FMT_NV12:
+ sluv = stride - 1;
+ break;
+ case V4L2_PIX_FMT_YUV422P:
+ sluv = stride - 1;
+ break;
+ case V4L2_PIX_FMT_NV16:
+ sluv = stride * 2 - 1;
+ break;
+ default:
+ sluv = 0;
+ break;
+ }
+
ipu_ch_param_write_field(ch, IPU_FIELD_SO, 1);
ipu_ch_param_write_field(ch, IPU_FIELD_ILO, ilo);
ipu_ch_param_write_field(ch, IPU_FIELD_SLY, sly);
+ if (sluv)
+ ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, sluv);
};
EXPORT_SYMBOL_GPL(ipu_cpmem_interlaced_scan);
diff --git a/drivers/gpu/ipu-v3/ipu-csi.c b/drivers/gpu/ipu-v3/ipu-csi.c
index aa0e30a2ba18..d1e575571a8d 100644
--- a/drivers/gpu/ipu-v3/ipu-csi.c
+++ b/drivers/gpu/ipu-v3/ipu-csi.c
@@ -325,12 +325,21 @@ static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config *cfg, u32 mbus_code,
return 0;
}
+/* translate alternate field mode based on given standard */
+static inline enum v4l2_field
+ipu_csi_translate_field(enum v4l2_field field, v4l2_std_id std)
+{
+ return (field != V4L2_FIELD_ALTERNATE) ? field :
+ ((std & V4L2_STD_525_60) ?
+ V4L2_FIELD_SEQ_BT : V4L2_FIELD_SEQ_TB);
+}
+
/*
* Fill a CSI bus config struct from mbus_config and mbus_framefmt.
*/
static int fill_csi_bus_cfg(struct ipu_csi_bus_config *csicfg,
- struct v4l2_mbus_config *mbus_cfg,
- struct v4l2_mbus_framefmt *mbus_fmt)
+ const struct v4l2_mbus_config *mbus_cfg,
+ const struct v4l2_mbus_framefmt *mbus_fmt)
{
int ret;
@@ -374,22 +383,76 @@ static int fill_csi_bus_cfg(struct ipu_csi_bus_config *csicfg,
return 0;
}
+static int
+ipu_csi_set_bt_interlaced_codes(struct ipu_csi *csi,
+ const struct v4l2_mbus_framefmt *infmt,
+ const struct v4l2_mbus_framefmt *outfmt,
+ v4l2_std_id std)
+{
+ enum v4l2_field infield, outfield;
+ bool swap_fields;
+
+ /* get translated field type of input and output */
+ infield = ipu_csi_translate_field(infmt->field, std);
+ outfield = ipu_csi_translate_field(outfmt->field, std);
+
+ /*
+ * Write the H-V-F codes the CSI will match against the
+ * incoming data for start/end of active and blanking
+ * field intervals. If input and output field types are
+ * sequential but not the same (one is SEQ_BT and the other
+ * is SEQ_TB), swap the F-bit so that the CSI will capture
+ * field 1 lines before field 0 lines.
+ */
+ swap_fields = (V4L2_FIELD_IS_SEQUENTIAL(infield) &&
+ V4L2_FIELD_IS_SEQUENTIAL(outfield) &&
+ infield != outfield);
+
+ if (!swap_fields) {
+ /*
+ * Field0BlankEnd = 110, Field0BlankStart = 010
+ * Field0ActiveEnd = 100, Field0ActiveStart = 000
+ * Field1BlankEnd = 111, Field1BlankStart = 011
+ * Field1ActiveEnd = 101, Field1ActiveStart = 001
+ */
+ ipu_csi_write(csi, 0x40596 | CSI_CCIR_ERR_DET_EN,
+ CSI_CCIR_CODE_1);
+ ipu_csi_write(csi, 0xD07DF, CSI_CCIR_CODE_2);
+ } else {
+ dev_dbg(csi->ipu->dev, "capture field swap\n");
+
+ /* same as above but with F-bit inverted */
+ ipu_csi_write(csi, 0xD07DF | CSI_CCIR_ERR_DET_EN,
+ CSI_CCIR_CODE_1);
+ ipu_csi_write(csi, 0x40596, CSI_CCIR_CODE_2);
+ }
+
+ ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
+
+ return 0;
+}
+
+
int ipu_csi_init_interface(struct ipu_csi *csi,
- struct v4l2_mbus_config *mbus_cfg,
- struct v4l2_mbus_framefmt *mbus_fmt)
+ const struct v4l2_mbus_config *mbus_cfg,
+ const struct v4l2_mbus_framefmt *infmt,
+ const struct v4l2_mbus_framefmt *outfmt)
{
struct ipu_csi_bus_config cfg;
unsigned long flags;
u32 width, height, data = 0;
+ v4l2_std_id std;
int ret;
- ret = fill_csi_bus_cfg(&cfg, mbus_cfg, mbus_fmt);
+ ret = fill_csi_bus_cfg(&cfg, mbus_cfg, infmt);
if (ret < 0)
return ret;
/* set default sensor frame width and height */
- width = mbus_fmt->width;
- height = mbus_fmt->height;
+ width = infmt->width;
+ height = infmt->height;
+ if (infmt->field == V4L2_FIELD_ALTERNATE)
+ height *= 2;
/* Set the CSI_SENS_CONF register remaining fields */
data |= cfg.data_width << CSI_SENS_CONF_DATA_WIDTH_SHIFT |
@@ -416,42 +479,22 @@ int ipu_csi_init_interface(struct ipu_csi *csi,
ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
break;
case IPU_CSI_CLK_MODE_CCIR656_INTERLACED:
- if (mbus_fmt->width == 720 && mbus_fmt->height == 576) {
- /*
- * PAL case
- *
- * Field0BlankEnd = 0x6, Field0BlankStart = 0x2,
- * Field0ActiveEnd = 0x4, Field0ActiveStart = 0
- * Field1BlankEnd = 0x7, Field1BlankStart = 0x3,
- * Field1ActiveEnd = 0x5, Field1ActiveStart = 0x1
- */
- height = 625; /* framelines for PAL */
-
- ipu_csi_write(csi, 0x40596 | CSI_CCIR_ERR_DET_EN,
- CSI_CCIR_CODE_1);
- ipu_csi_write(csi, 0xD07DF, CSI_CCIR_CODE_2);
- ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
- } else if (mbus_fmt->width == 720 && mbus_fmt->height == 480) {
- /*
- * NTSC case
- *
- * Field0BlankEnd = 0x7, Field0BlankStart = 0x3,
- * Field0ActiveEnd = 0x5, Field0ActiveStart = 0x1
- * Field1BlankEnd = 0x6, Field1BlankStart = 0x2,
- * Field1ActiveEnd = 0x4, Field1ActiveStart = 0
- */
- height = 525; /* framelines for NTSC */
-
- ipu_csi_write(csi, 0xD07DF | CSI_CCIR_ERR_DET_EN,
- CSI_CCIR_CODE_1);
- ipu_csi_write(csi, 0x40596, CSI_CCIR_CODE_2);
- ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
+ if (width == 720 && height == 480) {
+ std = V4L2_STD_NTSC;
+ height = 525;
+ } else if (width == 720 && height == 576) {
+ std = V4L2_STD_PAL;
+ height = 625;
} else {
dev_err(csi->ipu->dev,
- "Unsupported CCIR656 interlaced video mode\n");
- spin_unlock_irqrestore(&csi->lock, flags);
- return -EINVAL;
+ "Unsupported interlaced video mode\n");
+ ret = -EINVAL;
+ goto out_unlock;
}
+
+ ret = ipu_csi_set_bt_interlaced_codes(csi, infmt, outfmt, std);
+ if (ret)
+ goto out_unlock;
break;
case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR:
case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR:
@@ -476,9 +519,10 @@ int ipu_csi_init_interface(struct ipu_csi *csi,
dev_dbg(csi->ipu->dev, "CSI_ACT_FRM_SIZE = 0x%08X\n",
ipu_csi_read(csi, CSI_ACT_FRM_SIZE));
+out_unlock:
spin_unlock_irqrestore(&csi->lock, flags);
- return 0;
+ return ret;
}
EXPORT_SYMBOL_GPL(ipu_csi_init_interface);