aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/mx2_camera.c
diff options
context:
space:
mode:
authorJavier Martin <javier.martin@vista-silicon.com>2011-12-14 11:30:14 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2012-01-06 08:02:07 -0500
commitf410991dcf1fc3ad1d3311b79b4f1b917224ebed (patch)
tree30228a0d10531612307e0d164b06d84426274e67 /drivers/media/video/mx2_camera.c
parentd8ec0961ce5a9ddbece875c2b6fc028cb750df3a (diff)
[media] i.MX27 camera: add support for YUV420 format
This patch uses channel 2 of the eMMa-PrP to convert format provided by the sensor to YUV420. This format is very useful since it is used by the internal H.264 encoder. Signed-off-by: Javier Martin <javier.martin@vista-silicon.com> Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/mx2_camera.c')
-rw-r--r--drivers/media/video/mx2_camera.c291
1 files changed, 241 insertions, 50 deletions
diff --git a/drivers/media/video/mx2_camera.c b/drivers/media/video/mx2_camera.c
index ffbfbfe0516..e635ab3c71e 100644
--- a/drivers/media/video/mx2_camera.c
+++ b/drivers/media/video/mx2_camera.c
@@ -210,6 +210,22 @@
210 210
211#define MAX_VIDEO_MEM 16 211#define MAX_VIDEO_MEM 16
212 212
213struct mx2_prp_cfg {
214 int channel;
215 u32 in_fmt;
216 u32 out_fmt;
217 u32 src_pixel;
218 u32 ch1_pixel;
219 u32 irq_flags;
220};
221
222/* prp configuration for a client-host fmt pair */
223struct mx2_fmt_cfg {
224 enum v4l2_mbus_pixelcode in_fmt;
225 u32 out_fmt;
226 struct mx2_prp_cfg cfg;
227};
228
213struct mx2_camera_dev { 229struct mx2_camera_dev {
214 struct device *dev; 230 struct device *dev;
215 struct soc_camera_host soc_host; 231 struct soc_camera_host soc_host;
@@ -241,6 +257,7 @@ struct mx2_camera_dev {
241 void *discard_buffer; 257 void *discard_buffer;
242 dma_addr_t discard_buffer_dma; 258 dma_addr_t discard_buffer_dma;
243 size_t discard_size; 259 size_t discard_size;
260 struct mx2_fmt_cfg *emma_prp;
244}; 261};
245 262
246/* buffer for one video frame */ 263/* buffer for one video frame */
@@ -253,6 +270,59 @@ struct mx2_buffer {
253 int bufnum; 270 int bufnum;
254}; 271};
255 272
273static struct mx2_fmt_cfg mx27_emma_prp_table[] = {
274 /*
275 * This is a generic configuration which is valid for most
276 * prp input-output format combinations.
277 * We set the incomming and outgoing pixelformat to a
278 * 16 Bit wide format and adjust the bytesperline
279 * accordingly. With this configuration the inputdata
280 * will not be changed by the emma and could be any type
281 * of 16 Bit Pixelformat.
282 */
283 {
284 .in_fmt = 0,
285 .out_fmt = 0,
286 .cfg = {
287 .channel = 1,
288 .in_fmt = PRP_CNTL_DATA_IN_RGB16,
289 .out_fmt = PRP_CNTL_CH1_OUT_RGB16,
290 .src_pixel = 0x2ca00565, /* RGB565 */
291 .ch1_pixel = 0x2ca00565, /* RGB565 */
292 .irq_flags = PRP_INTR_RDERR | PRP_INTR_CH1WERR |
293 PRP_INTR_CH1FC | PRP_INTR_LBOVF,
294 }
295 },
296 {
297 .in_fmt = V4L2_MBUS_FMT_YUYV8_2X8,
298 .out_fmt = V4L2_PIX_FMT_YUV420,
299 .cfg = {
300 .channel = 2,
301 .in_fmt = PRP_CNTL_DATA_IN_YUV422,
302 .out_fmt = PRP_CNTL_CH2_OUT_YUV420,
303 .src_pixel = 0x22000888, /* YUV422 (YUYV) */
304 .irq_flags = PRP_INTR_RDERR | PRP_INTR_CH2WERR |
305 PRP_INTR_CH2FC | PRP_INTR_LBOVF |
306 PRP_INTR_CH2OVF,
307 }
308 },
309};
310
311static struct mx2_fmt_cfg *mx27_emma_prp_get_format(
312 enum v4l2_mbus_pixelcode in_fmt,
313 u32 out_fmt)
314{
315 int i;
316
317 for (i = 1; i < ARRAY_SIZE(mx27_emma_prp_table); i++)
318 if ((mx27_emma_prp_table[i].in_fmt == in_fmt) &&
319 (mx27_emma_prp_table[i].out_fmt == out_fmt)) {
320 return &mx27_emma_prp_table[i];
321 }
322 /* If no match return the most generic configuration */
323 return &mx27_emma_prp_table[0];
324};
325
256static void mx2_camera_deactivate(struct mx2_camera_dev *pcdev) 326static void mx2_camera_deactivate(struct mx2_camera_dev *pcdev)
257{ 327{
258 unsigned long flags; 328 unsigned long flags;
@@ -719,51 +789,74 @@ static void mx27_camera_emma_buf_init(struct soc_camera_device *icd,
719 struct soc_camera_host *ici = 789 struct soc_camera_host *ici =
720 to_soc_camera_host(icd->parent); 790 to_soc_camera_host(icd->parent);
721 struct mx2_camera_dev *pcdev = ici->priv; 791 struct mx2_camera_dev *pcdev = ici->priv;
792 struct mx2_fmt_cfg *prp = pcdev->emma_prp;
793 u32 imgsize = pcdev->icd->user_height * pcdev->icd->user_width;
794
795 if (prp->cfg.channel == 1) {
796 writel(pcdev->discard_buffer_dma,
797 pcdev->base_emma + PRP_DEST_RGB1_PTR);
798 writel(pcdev->discard_buffer_dma,
799 pcdev->base_emma + PRP_DEST_RGB2_PTR);
800
801 writel(PRP_CNTL_CH1EN |
802 PRP_CNTL_CSIEN |
803 prp->cfg.in_fmt |
804 prp->cfg.out_fmt |
805 PRP_CNTL_CH1_LEN |
806 PRP_CNTL_CH1BYP |
807 PRP_CNTL_CH1_TSKIP(0) |
808 PRP_CNTL_IN_TSKIP(0),
809 pcdev->base_emma + PRP_CNTL);
810
811 writel((icd->user_width << 16) | icd->user_height,
812 pcdev->base_emma + PRP_SRC_FRAME_SIZE);
813 writel((icd->user_width << 16) | icd->user_height,
814 pcdev->base_emma + PRP_CH1_OUT_IMAGE_SIZE);
815 writel(bytesperline,
816 pcdev->base_emma + PRP_DEST_CH1_LINE_STRIDE);
817 writel(prp->cfg.src_pixel,
818 pcdev->base_emma + PRP_SRC_PIXEL_FORMAT_CNTL);
819 writel(prp->cfg.ch1_pixel,
820 pcdev->base_emma + PRP_CH1_PIXEL_FORMAT_CNTL);
821 } else { /* channel 2 */
822 writel(pcdev->discard_buffer_dma,
823 pcdev->base_emma + PRP_DEST_Y_PTR);
824 writel(pcdev->discard_buffer_dma,
825 pcdev->base_emma + PRP_SOURCE_Y_PTR);
826
827 if (prp->cfg.out_fmt == PRP_CNTL_CH2_OUT_YUV420) {
828 writel(pcdev->discard_buffer_dma + imgsize,
829 pcdev->base_emma + PRP_DEST_CB_PTR);
830 writel(pcdev->discard_buffer_dma + ((5 * imgsize) / 4),
831 pcdev->base_emma + PRP_DEST_CR_PTR);
832 writel(pcdev->discard_buffer_dma + imgsize,
833 pcdev->base_emma + PRP_SOURCE_CB_PTR);
834 writel(pcdev->discard_buffer_dma + ((5 * imgsize) / 4),
835 pcdev->base_emma + PRP_SOURCE_CR_PTR);
836 }
722 837
723 writel(pcdev->discard_buffer_dma, 838 writel(PRP_CNTL_CH2EN |
724 pcdev->base_emma + PRP_DEST_RGB1_PTR);
725 writel(pcdev->discard_buffer_dma,
726 pcdev->base_emma + PRP_DEST_RGB2_PTR);
727
728 /*
729 * We only use the EMMA engine to get rid of the broken
730 * DMA Engine. No color space consversion at the moment.
731 * We set the incomming and outgoing pixelformat to an
732 * 16 Bit wide format and adjust the bytesperline
733 * accordingly. With this configuration the inputdata
734 * will not be changed by the emma and could be any type
735 * of 16 Bit Pixelformat.
736 */
737 writel(PRP_CNTL_CH1EN |
738 PRP_CNTL_CSIEN | 839 PRP_CNTL_CSIEN |
739 PRP_CNTL_DATA_IN_RGB16 | 840 prp->cfg.in_fmt |
740 PRP_CNTL_CH1_OUT_RGB16 | 841 prp->cfg.out_fmt |
741 PRP_CNTL_CH1_LEN | 842 PRP_CNTL_CH2_LEN |
742 PRP_CNTL_CH1BYP | 843 PRP_CNTL_CH2_TSKIP(0) |
743 PRP_CNTL_CH1_TSKIP(0) |
744 PRP_CNTL_IN_TSKIP(0), 844 PRP_CNTL_IN_TSKIP(0),
745 pcdev->base_emma + PRP_CNTL); 845 pcdev->base_emma + PRP_CNTL);
746 846
747 writel(((bytesperline >> 1) << 16) | icd->user_height, 847 writel((icd->user_width << 16) | icd->user_height,
748 pcdev->base_emma + PRP_SRC_FRAME_SIZE); 848 pcdev->base_emma + PRP_SRC_FRAME_SIZE);
749 writel(((bytesperline >> 1) << 16) | icd->user_height, 849
750 pcdev->base_emma + PRP_CH1_OUT_IMAGE_SIZE); 850 writel((icd->user_width << 16) | icd->user_height,
751 writel(bytesperline, 851 pcdev->base_emma + PRP_CH2_OUT_IMAGE_SIZE);
752 pcdev->base_emma + PRP_DEST_CH1_LINE_STRIDE); 852
753 writel(0x2ca00565, /* RGB565 */ 853 writel(prp->cfg.src_pixel,
754 pcdev->base_emma + PRP_SRC_PIXEL_FORMAT_CNTL); 854 pcdev->base_emma + PRP_SRC_PIXEL_FORMAT_CNTL);
755 writel(0x2ca00565, /* RGB565 */ 855
756 pcdev->base_emma + PRP_CH1_PIXEL_FORMAT_CNTL); 856 }
757 857
758 /* Enable interrupts */ 858 /* Enable interrupts */
759 writel(PRP_INTR_RDERR | 859 writel(prp->cfg.irq_flags, pcdev->base_emma + PRP_INTR_CNTL);
760 PRP_INTR_CH1WERR |
761 PRP_INTR_CH2WERR |
762 PRP_INTR_CH1FC |
763 PRP_INTR_CH2FC |
764 PRP_INTR_LBOVF |
765 PRP_INTR_CH2OVF,
766 pcdev->base_emma + PRP_INTR_CNTL);
767} 860}
768 861
769static int mx2_camera_set_bus_param(struct soc_camera_device *icd) 862static int mx2_camera_set_bus_param(struct soc_camera_device *icd)
@@ -910,9 +1003,58 @@ static int mx2_camera_set_crop(struct soc_camera_device *icd,
910 return ret; 1003 return ret;
911} 1004}
912 1005
1006static int mx2_camera_get_formats(struct soc_camera_device *icd,
1007 unsigned int idx,
1008 struct soc_camera_format_xlate *xlate)
1009{
1010 struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
1011 const struct soc_mbus_pixelfmt *fmt;
1012 struct device *dev = icd->parent;
1013 enum v4l2_mbus_pixelcode code;
1014 int ret, formats = 0;
1015
1016 ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code);
1017 if (ret < 0)
1018 /* no more formats */
1019 return 0;
1020
1021 fmt = soc_mbus_get_fmtdesc(code);
1022 if (!fmt) {
1023 dev_err(dev, "Invalid format code #%u: %d\n", idx, code);
1024 return 0;
1025 }
1026
1027 if (code == V4L2_MBUS_FMT_YUYV8_2X8) {
1028 formats++;
1029 if (xlate) {
1030 /*
1031 * CH2 can output YUV420 which is a standard format in
1032 * soc_mediabus.c
1033 */
1034 xlate->host_fmt =
1035 soc_mbus_get_fmtdesc(V4L2_MBUS_FMT_YUYV8_1_5X8);
1036 xlate->code = code;
1037 dev_dbg(dev, "Providing host format %s for sensor code %d\n",
1038 xlate->host_fmt->name, code);
1039 xlate++;
1040 }
1041 }
1042
1043 /* Generic pass-trough */
1044 formats++;
1045 if (xlate) {
1046 xlate->host_fmt = fmt;
1047 xlate->code = code;
1048 xlate++;
1049 }
1050 return formats;
1051}
1052
913static int mx2_camera_set_fmt(struct soc_camera_device *icd, 1053static int mx2_camera_set_fmt(struct soc_camera_device *icd,
914 struct v4l2_format *f) 1054 struct v4l2_format *f)
915{ 1055{
1056 struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
1057 struct mx2_camera_dev *pcdev = ici->priv;
916 struct v4l2_subdev *sd = soc_camera_to_subdev(icd); 1058 struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
917 const struct soc_camera_format_xlate *xlate; 1059 const struct soc_camera_format_xlate *xlate;
918 struct v4l2_pix_format *pix = &f->fmt.pix; 1060 struct v4l2_pix_format *pix = &f->fmt.pix;
@@ -945,6 +1087,10 @@ static int mx2_camera_set_fmt(struct soc_camera_device *icd,
945 pix->colorspace = mf.colorspace; 1087 pix->colorspace = mf.colorspace;
946 icd->current_fmt = xlate; 1088 icd->current_fmt = xlate;
947 1089
1090 if (mx27_camera_emma(pcdev))
1091 pcdev->emma_prp = mx27_emma_prp_get_format(xlate->code,
1092 xlate->host_fmt->fourcc);
1093
948 return 0; 1094 return 0;
949} 1095}
950 1096
@@ -1010,7 +1156,12 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd,
1010 1156
1011 if (mf.field == V4L2_FIELD_ANY) 1157 if (mf.field == V4L2_FIELD_ANY)
1012 mf.field = V4L2_FIELD_NONE; 1158 mf.field = V4L2_FIELD_NONE;
1013 if (mf.field != V4L2_FIELD_NONE) { 1159 /*
1160 * Driver supports interlaced images provided they have
1161 * both fields so that they can be processed as if they
1162 * were progressive.
1163 */
1164 if (mf.field != V4L2_FIELD_NONE && !V4L2_FIELD_HAS_BOTH(mf.field)) {
1014 dev_err(icd->parent, "Field type %d unsupported.\n", 1165 dev_err(icd->parent, "Field type %d unsupported.\n",
1015 mf.field); 1166 mf.field);
1016 return -EINVAL; 1167 return -EINVAL;
@@ -1172,6 +1323,7 @@ static struct soc_camera_host_ops mx2_soc_camera_host_ops = {
1172 .remove = mx2_camera_remove_device, 1323 .remove = mx2_camera_remove_device,
1173 .set_fmt = mx2_camera_set_fmt, 1324 .set_fmt = mx2_camera_set_fmt,
1174 .set_crop = mx2_camera_set_crop, 1325 .set_crop = mx2_camera_set_crop,
1326 .get_formats = mx2_camera_get_formats,
1175 .try_fmt = mx2_camera_try_fmt, 1327 .try_fmt = mx2_camera_try_fmt,
1176 .init_videobuf = mx2_camera_init_videobuf, 1328 .init_videobuf = mx2_camera_init_videobuf,
1177 .reqbufs = mx2_camera_reqbufs, 1329 .reqbufs = mx2_camera_reqbufs,
@@ -1183,6 +1335,8 @@ static struct soc_camera_host_ops mx2_soc_camera_host_ops = {
1183static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev, 1335static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev,
1184 int bufnum, int state) 1336 int bufnum, int state)
1185{ 1337{
1338 u32 imgsize = pcdev->icd->user_height * pcdev->icd->user_width;
1339 struct mx2_fmt_cfg *prp = pcdev->emma_prp;
1186 struct mx2_buffer *buf; 1340 struct mx2_buffer *buf;
1187 struct videobuf_buffer *vb; 1341 struct videobuf_buffer *vb;
1188 unsigned long phys; 1342 unsigned long phys;
@@ -1196,12 +1350,22 @@ static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev,
1196 vb = &buf->vb; 1350 vb = &buf->vb;
1197#ifdef DEBUG 1351#ifdef DEBUG
1198 phys = videobuf_to_dma_contig(vb); 1352 phys = videobuf_to_dma_contig(vb);
1199 if (readl(pcdev->base_emma + PRP_DEST_RGB1_PTR + 4 * bufnum) 1353 if (prp->cfg.channel == 1) {
1200 != phys) { 1354 if (readl(pcdev->base_emma + PRP_DEST_RGB1_PTR +
1201 dev_err(pcdev->dev, "%p != %p\n", phys, 1355 4 * bufnum) != phys) {
1202 readl(pcdev->base_emma + 1356 dev_err(pcdev->dev, "%p != %p\n", phys,
1203 PRP_DEST_RGB1_PTR + 1357 readl(pcdev->base_emma +
1204 4 * bufnum)); 1358 PRP_DEST_RGB1_PTR +
1359 4 * bufnum));
1360 }
1361 } else {
1362 if (readl(pcdev->base_emma + PRP_DEST_Y_PTR -
1363 0x14 * bufnum) != phys) {
1364 dev_err(pcdev->dev, "%p != %p\n", phys,
1365 readl(pcdev->base_emma +
1366 PRP_DEST_Y_PTR -
1367 0x14 * bufnum));
1368 }
1205 } 1369 }
1206#endif 1370#endif
1207 dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, vb, 1371 dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, vb,
@@ -1216,8 +1380,22 @@ static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev,
1216 } 1380 }
1217 1381
1218 if (list_empty(&pcdev->capture)) { 1382 if (list_empty(&pcdev->capture)) {
1219 writel(pcdev->discard_buffer_dma, pcdev->base_emma + 1383 if (prp->cfg.channel == 1) {
1220 PRP_DEST_RGB1_PTR + 4 * bufnum); 1384 writel(pcdev->discard_buffer_dma, pcdev->base_emma +
1385 PRP_DEST_RGB1_PTR + 4 * bufnum);
1386 } else {
1387 writel(pcdev->discard_buffer_dma, pcdev->base_emma +
1388 PRP_DEST_Y_PTR -
1389 0x14 * bufnum);
1390 if (prp->out_fmt == V4L2_PIX_FMT_YUV420) {
1391 writel(pcdev->discard_buffer_dma + imgsize,
1392 pcdev->base_emma + PRP_DEST_CB_PTR -
1393 0x14 * bufnum);
1394 writel(pcdev->discard_buffer_dma +
1395 ((5 * imgsize) / 4), pcdev->base_emma +
1396 PRP_DEST_CR_PTR - 0x14 * bufnum);
1397 }
1398 }
1221 return; 1399 return;
1222 } 1400 }
1223 1401
@@ -1232,7 +1410,18 @@ static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev,
1232 vb->state = VIDEOBUF_ACTIVE; 1410 vb->state = VIDEOBUF_ACTIVE;
1233 1411
1234 phys = videobuf_to_dma_contig(vb); 1412 phys = videobuf_to_dma_contig(vb);
1235 writel(phys, pcdev->base_emma + PRP_DEST_RGB1_PTR + 4 * bufnum); 1413 if (prp->cfg.channel == 1) {
1414 writel(phys, pcdev->base_emma + PRP_DEST_RGB1_PTR + 4 * bufnum);
1415 } else {
1416 writel(phys, pcdev->base_emma +
1417 PRP_DEST_Y_PTR - 0x14 * bufnum);
1418 if (prp->cfg.out_fmt == PRP_CNTL_CH2_OUT_YUV420) {
1419 writel(phys + imgsize, pcdev->base_emma +
1420 PRP_DEST_CB_PTR - 0x14 * bufnum);
1421 writel(phys + ((5 * imgsize) / 4), pcdev->base_emma +
1422 PRP_DEST_CR_PTR - 0x14 * bufnum);
1423 }
1424 }
1236} 1425}
1237 1426
1238static irqreturn_t mx27_camera_emma_irq(int irq_emma, void *data) 1427static irqreturn_t mx27_camera_emma_irq(int irq_emma, void *data)
@@ -1252,10 +1441,12 @@ static irqreturn_t mx27_camera_emma_irq(int irq_emma, void *data)
1252 * the next one. 1441 * the next one.
1253 */ 1442 */
1254 cntl = readl(pcdev->base_emma + PRP_CNTL); 1443 cntl = readl(pcdev->base_emma + PRP_CNTL);
1255 writel(cntl & ~PRP_CNTL_CH1EN, pcdev->base_emma + PRP_CNTL); 1444 writel(cntl & ~(PRP_CNTL_CH1EN | PRP_CNTL_CH2EN),
1445 pcdev->base_emma + PRP_CNTL);
1256 writel(cntl, pcdev->base_emma + PRP_CNTL); 1446 writel(cntl, pcdev->base_emma + PRP_CNTL);
1257 } 1447 }
1258 if ((status & (3 << 5)) == (3 << 5) 1448 if ((((status & (3 << 5)) == (3 << 5)) ||
1449 ((status & (3 << 3)) == (3 << 3)))
1259 && !list_empty(&pcdev->active_bufs)) { 1450 && !list_empty(&pcdev->active_bufs)) {
1260 /* 1451 /*
1261 * Both buffers have triggered, process the one we're expecting 1452 * Both buffers have triggered, process the one we're expecting
@@ -1266,9 +1457,9 @@ static irqreturn_t mx27_camera_emma_irq(int irq_emma, void *data)
1266 mx27_camera_frame_done_emma(pcdev, buf->bufnum, VIDEOBUF_DONE); 1457 mx27_camera_frame_done_emma(pcdev, buf->bufnum, VIDEOBUF_DONE);
1267 status &= ~(1 << (6 - buf->bufnum)); /* mark processed */ 1458 status &= ~(1 << (6 - buf->bufnum)); /* mark processed */
1268 } 1459 }
1269 if (status & (1 << 6)) 1460 if ((status & (1 << 6)) || (status & (1 << 4)))
1270 mx27_camera_frame_done_emma(pcdev, 0, VIDEOBUF_DONE); 1461 mx27_camera_frame_done_emma(pcdev, 0, VIDEOBUF_DONE);
1271 if (status & (1 << 5)) 1462 if ((status & (1 << 5)) || (status & (1 << 3)))
1272 mx27_camera_frame_done_emma(pcdev, 1, VIDEOBUF_DONE); 1463 mx27_camera_frame_done_emma(pcdev, 1, VIDEOBUF_DONE);
1273 1464
1274 writel(status, pcdev->base_emma + PRP_INTRSTATUS); 1465 writel(status, pcdev->base_emma + PRP_INTRSTATUS);