1 /*
2  * TI OMAP4 ISS V4L2 Driver - ISP IPIPE module
3  *
4  * Copyright (C) 2012 Texas Instruments, Inc.
5  *
6  * Author: Sergio Aguirre <sergio.a.aguirre@gmail.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  */
13 
14 #include <linux/module.h>
15 #include <linux/uaccess.h>
16 #include <linux/delay.h>
17 #include <linux/device.h>
18 #include <linux/dma-mapping.h>
19 #include <linux/mm.h>
20 #include <linux/sched.h>
21 
22 #include "iss.h"
23 #include "iss_regs.h"
24 #include "iss_ipipe.h"
25 
26 static struct v4l2_mbus_framefmt *
27 __ipipe_get_format(struct iss_ipipe_device *ipipe, struct v4l2_subdev_fh *fh,
28 		  unsigned int pad, enum v4l2_subdev_format_whence which);
29 
30 static const unsigned int ipipe_fmts[] = {
31 	MEDIA_BUS_FMT_SGRBG10_1X10,
32 	MEDIA_BUS_FMT_SRGGB10_1X10,
33 	MEDIA_BUS_FMT_SBGGR10_1X10,
34 	MEDIA_BUS_FMT_SGBRG10_1X10,
35 };
36 
37 /*
38  * ipipe_print_status - Print current IPIPE Module register values.
39  * @ipipe: Pointer to ISS ISP IPIPE device.
40  *
41  * Also prints other debug information stored in the IPIPE module.
42  */
43 #define IPIPE_PRINT_REGISTER(iss, name)\
44 	dev_dbg(iss->dev, "###IPIPE " #name "=0x%08x\n", \
45 		iss_reg_read(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_##name))
46 
47 static void ipipe_print_status(struct iss_ipipe_device *ipipe)
48 {
49 	struct iss_device *iss = to_iss_device(ipipe);
50 
51 	dev_dbg(iss->dev, "-------------IPIPE Register dump-------------\n");
52 
53 	IPIPE_PRINT_REGISTER(iss, SRC_EN);
54 	IPIPE_PRINT_REGISTER(iss, SRC_MODE);
55 	IPIPE_PRINT_REGISTER(iss, SRC_FMT);
56 	IPIPE_PRINT_REGISTER(iss, SRC_COL);
57 	IPIPE_PRINT_REGISTER(iss, SRC_VPS);
58 	IPIPE_PRINT_REGISTER(iss, SRC_VSZ);
59 	IPIPE_PRINT_REGISTER(iss, SRC_HPS);
60 	IPIPE_PRINT_REGISTER(iss, SRC_HSZ);
61 	IPIPE_PRINT_REGISTER(iss, GCK_MMR);
62 	IPIPE_PRINT_REGISTER(iss, YUV_PHS);
63 
64 	dev_dbg(iss->dev, "-----------------------------------------------\n");
65 }
66 
67 /*
68  * ipipe_enable - Enable/Disable IPIPE.
69  * @enable: enable flag
70  *
71  */
72 static void ipipe_enable(struct iss_ipipe_device *ipipe, u8 enable)
73 {
74 	struct iss_device *iss = to_iss_device(ipipe);
75 
76 	iss_reg_update(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_EN,
77 		       IPIPE_SRC_EN_EN, enable ? IPIPE_SRC_EN_EN : 0);
78 }
79 
80 /* -----------------------------------------------------------------------------
81  * Format- and pipeline-related configuration helpers
82  */
83 
84 static void ipipe_configure(struct iss_ipipe_device *ipipe)
85 {
86 	struct iss_device *iss = to_iss_device(ipipe);
87 	struct v4l2_mbus_framefmt *format;
88 
89 	/* IPIPE_PAD_SINK */
90 	format = &ipipe->formats[IPIPE_PAD_SINK];
91 
92 	/* NOTE: Currently just supporting pipeline IN: RGB, OUT: YUV422 */
93 	iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_FMT,
94 		      IPIPE_SRC_FMT_RAW2YUV);
95 
96 	/* Enable YUV444 -> YUV422 conversion */
97 	iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_YUV_PHS,
98 		      IPIPE_YUV_PHS_LPF);
99 
100 	iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_VPS, 0);
101 	iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_HPS, 0);
102 	iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_VSZ,
103 		      (format->height - 2) & IPIPE_SRC_VSZ_MASK);
104 	iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_HSZ,
105 		      (format->width - 1) & IPIPE_SRC_HSZ_MASK);
106 
107 	/* Ignore ipipeif_wrt signal, and operate on-the-fly.  */
108 	iss_reg_clr(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_MODE,
109 		    IPIPE_SRC_MODE_WRT | IPIPE_SRC_MODE_OST);
110 
111 	/* HACK: Values tuned for Ducati SW (OV) */
112 	iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_COL,
113 		      IPIPE_SRC_COL_EE_B | IPIPE_SRC_COL_EO_GB |
114 		      IPIPE_SRC_COL_OE_GR | IPIPE_SRC_COL_OO_R);
115 
116 	/* IPIPE_PAD_SOURCE_VP */
117 	format = &ipipe->formats[IPIPE_PAD_SOURCE_VP];
118 	/* Do nothing? */
119 }
120 
121 /* -----------------------------------------------------------------------------
122  * V4L2 subdev operations
123  */
124 
125 /*
126  * ipipe_set_stream - Enable/Disable streaming on the IPIPE module
127  * @sd: ISP IPIPE V4L2 subdevice
128  * @enable: Enable/disable stream
129  */
130 static int ipipe_set_stream(struct v4l2_subdev *sd, int enable)
131 {
132 	struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd);
133 	struct iss_device *iss = to_iss_device(ipipe);
134 	int ret = 0;
135 
136 	if (ipipe->state == ISS_PIPELINE_STREAM_STOPPED) {
137 		if (enable == ISS_PIPELINE_STREAM_STOPPED)
138 			return 0;
139 
140 		omap4iss_isp_subclk_enable(iss, OMAP4_ISS_ISP_SUBCLK_IPIPE);
141 
142 		/* Enable clk_arm_g0 */
143 		iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_GCK_MMR,
144 			      IPIPE_GCK_MMR_REG);
145 
146 		/* Enable clk_pix_g[3:0] */
147 		iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_GCK_PIX,
148 			      IPIPE_GCK_PIX_G3 | IPIPE_GCK_PIX_G2 |
149 			      IPIPE_GCK_PIX_G1 | IPIPE_GCK_PIX_G0);
150 	}
151 
152 	switch (enable) {
153 	case ISS_PIPELINE_STREAM_CONTINUOUS:
154 
155 		ipipe_configure(ipipe);
156 		ipipe_print_status(ipipe);
157 
158 		atomic_set(&ipipe->stopping, 0);
159 		ipipe_enable(ipipe, 1);
160 		break;
161 
162 	case ISS_PIPELINE_STREAM_STOPPED:
163 		if (ipipe->state == ISS_PIPELINE_STREAM_STOPPED)
164 			return 0;
165 		if (omap4iss_module_sync_idle(&sd->entity, &ipipe->wait,
166 					      &ipipe->stopping))
167 			ret = -ETIMEDOUT;
168 
169 		ipipe_enable(ipipe, 0);
170 		omap4iss_isp_subclk_disable(iss, OMAP4_ISS_ISP_SUBCLK_IPIPE);
171 		break;
172 	}
173 
174 	ipipe->state = enable;
175 	return ret;
176 }
177 
178 static struct v4l2_mbus_framefmt *
179 __ipipe_get_format(struct iss_ipipe_device *ipipe, struct v4l2_subdev_fh *fh,
180 		  unsigned int pad, enum v4l2_subdev_format_whence which)
181 {
182 	if (which == V4L2_SUBDEV_FORMAT_TRY)
183 		return v4l2_subdev_get_try_format(fh, pad);
184 
185 	return &ipipe->formats[pad];
186 }
187 
188 /*
189  * ipipe_try_format - Try video format on a pad
190  * @ipipe: ISS IPIPE device
191  * @fh : V4L2 subdev file handle
192  * @pad: Pad number
193  * @fmt: Format
194  */
195 static void
196 ipipe_try_format(struct iss_ipipe_device *ipipe, struct v4l2_subdev_fh *fh,
197 		unsigned int pad, struct v4l2_mbus_framefmt *fmt,
198 		enum v4l2_subdev_format_whence which)
199 {
200 	struct v4l2_mbus_framefmt *format;
201 	unsigned int width = fmt->width;
202 	unsigned int height = fmt->height;
203 	unsigned int i;
204 
205 	switch (pad) {
206 	case IPIPE_PAD_SINK:
207 		for (i = 0; i < ARRAY_SIZE(ipipe_fmts); i++) {
208 			if (fmt->code == ipipe_fmts[i])
209 				break;
210 		}
211 
212 		/* If not found, use SGRBG10 as default */
213 		if (i >= ARRAY_SIZE(ipipe_fmts))
214 			fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
215 
216 		/* Clamp the input size. */
217 		fmt->width = clamp_t(u32, width, 1, 8192);
218 		fmt->height = clamp_t(u32, height, 1, 8192);
219 		fmt->colorspace = V4L2_COLORSPACE_SRGB;
220 		break;
221 
222 	case IPIPE_PAD_SOURCE_VP:
223 		format = __ipipe_get_format(ipipe, fh, IPIPE_PAD_SINK, which);
224 		memcpy(fmt, format, sizeof(*fmt));
225 
226 		fmt->code = MEDIA_BUS_FMT_UYVY8_1X16;
227 		fmt->width = clamp_t(u32, width, 32, fmt->width);
228 		fmt->height = clamp_t(u32, height, 32, fmt->height);
229 		fmt->colorspace = V4L2_COLORSPACE_JPEG;
230 		break;
231 	}
232 
233 	fmt->field = V4L2_FIELD_NONE;
234 }
235 
236 /*
237  * ipipe_enum_mbus_code - Handle pixel format enumeration
238  * @sd     : pointer to v4l2 subdev structure
239  * @fh : V4L2 subdev file handle
240  * @code   : pointer to v4l2_subdev_mbus_code_enum structure
241  * return -EINVAL or zero on success
242  */
243 static int ipipe_enum_mbus_code(struct v4l2_subdev *sd,
244 			       struct v4l2_subdev_fh *fh,
245 			       struct v4l2_subdev_mbus_code_enum *code)
246 {
247 	switch (code->pad) {
248 	case IPIPE_PAD_SINK:
249 		if (code->index >= ARRAY_SIZE(ipipe_fmts))
250 			return -EINVAL;
251 
252 		code->code = ipipe_fmts[code->index];
253 		break;
254 
255 	case IPIPE_PAD_SOURCE_VP:
256 		/* FIXME: Forced format conversion inside IPIPE ? */
257 		if (code->index != 0)
258 			return -EINVAL;
259 
260 		code->code = MEDIA_BUS_FMT_UYVY8_1X16;
261 		break;
262 
263 	default:
264 		return -EINVAL;
265 	}
266 
267 	return 0;
268 }
269 
270 static int ipipe_enum_frame_size(struct v4l2_subdev *sd,
271 				struct v4l2_subdev_fh *fh,
272 				struct v4l2_subdev_frame_size_enum *fse)
273 {
274 	struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd);
275 	struct v4l2_mbus_framefmt format;
276 
277 	if (fse->index != 0)
278 		return -EINVAL;
279 
280 	format.code = fse->code;
281 	format.width = 1;
282 	format.height = 1;
283 	ipipe_try_format(ipipe, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
284 	fse->min_width = format.width;
285 	fse->min_height = format.height;
286 
287 	if (format.code != fse->code)
288 		return -EINVAL;
289 
290 	format.code = fse->code;
291 	format.width = -1;
292 	format.height = -1;
293 	ipipe_try_format(ipipe, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
294 	fse->max_width = format.width;
295 	fse->max_height = format.height;
296 
297 	return 0;
298 }
299 
300 /*
301  * ipipe_get_format - Retrieve the video format on a pad
302  * @sd : ISP IPIPE V4L2 subdevice
303  * @fh : V4L2 subdev file handle
304  * @fmt: Format
305  *
306  * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
307  * to the format type.
308  */
309 static int ipipe_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
310 			   struct v4l2_subdev_format *fmt)
311 {
312 	struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd);
313 	struct v4l2_mbus_framefmt *format;
314 
315 	format = __ipipe_get_format(ipipe, fh, fmt->pad, fmt->which);
316 	if (format == NULL)
317 		return -EINVAL;
318 
319 	fmt->format = *format;
320 	return 0;
321 }
322 
323 /*
324  * ipipe_set_format - Set the video format on a pad
325  * @sd : ISP IPIPE V4L2 subdevice
326  * @fh : V4L2 subdev file handle
327  * @fmt: Format
328  *
329  * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
330  * to the format type.
331  */
332 static int ipipe_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
333 			   struct v4l2_subdev_format *fmt)
334 {
335 	struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd);
336 	struct v4l2_mbus_framefmt *format;
337 
338 	format = __ipipe_get_format(ipipe, fh, fmt->pad, fmt->which);
339 	if (format == NULL)
340 		return -EINVAL;
341 
342 	ipipe_try_format(ipipe, fh, fmt->pad, &fmt->format, fmt->which);
343 	*format = fmt->format;
344 
345 	/* Propagate the format from sink to source */
346 	if (fmt->pad == IPIPE_PAD_SINK) {
347 		format = __ipipe_get_format(ipipe, fh, IPIPE_PAD_SOURCE_VP,
348 					   fmt->which);
349 		*format = fmt->format;
350 		ipipe_try_format(ipipe, fh, IPIPE_PAD_SOURCE_VP, format,
351 				fmt->which);
352 	}
353 
354 	return 0;
355 }
356 
357 static int ipipe_link_validate(struct v4l2_subdev *sd, struct media_link *link,
358 				 struct v4l2_subdev_format *source_fmt,
359 				 struct v4l2_subdev_format *sink_fmt)
360 {
361 	/* Check if the two ends match */
362 	if (source_fmt->format.width != sink_fmt->format.width ||
363 	    source_fmt->format.height != sink_fmt->format.height)
364 		return -EPIPE;
365 
366 	if (source_fmt->format.code != sink_fmt->format.code)
367 		return -EPIPE;
368 
369 	return 0;
370 }
371 
372 /*
373  * ipipe_init_formats - Initialize formats on all pads
374  * @sd: ISP IPIPE V4L2 subdevice
375  * @fh: V4L2 subdev file handle
376  *
377  * Initialize all pad formats with default values. If fh is not NULL, try
378  * formats are initialized on the file handle. Otherwise active formats are
379  * initialized on the device.
380  */
381 static int ipipe_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
382 {
383 	struct v4l2_subdev_format format;
384 
385 	memset(&format, 0, sizeof(format));
386 	format.pad = IPIPE_PAD_SINK;
387 	format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
388 	format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
389 	format.format.width = 4096;
390 	format.format.height = 4096;
391 	ipipe_set_format(sd, fh, &format);
392 
393 	return 0;
394 }
395 
396 /* V4L2 subdev video operations */
397 static const struct v4l2_subdev_video_ops ipipe_v4l2_video_ops = {
398 	.s_stream = ipipe_set_stream,
399 };
400 
401 /* V4L2 subdev pad operations */
402 static const struct v4l2_subdev_pad_ops ipipe_v4l2_pad_ops = {
403 	.enum_mbus_code = ipipe_enum_mbus_code,
404 	.enum_frame_size = ipipe_enum_frame_size,
405 	.get_fmt = ipipe_get_format,
406 	.set_fmt = ipipe_set_format,
407 	.link_validate = ipipe_link_validate,
408 };
409 
410 /* V4L2 subdev operations */
411 static const struct v4l2_subdev_ops ipipe_v4l2_ops = {
412 	.video = &ipipe_v4l2_video_ops,
413 	.pad = &ipipe_v4l2_pad_ops,
414 };
415 
416 /* V4L2 subdev internal operations */
417 static const struct v4l2_subdev_internal_ops ipipe_v4l2_internal_ops = {
418 	.open = ipipe_init_formats,
419 };
420 
421 /* -----------------------------------------------------------------------------
422  * Media entity operations
423  */
424 
425 /*
426  * ipipe_link_setup - Setup IPIPE connections
427  * @entity: IPIPE media entity
428  * @local: Pad at the local end of the link
429  * @remote: Pad at the remote end of the link
430  * @flags: Link flags
431  *
432  * return -EINVAL or zero on success
433  */
434 static int ipipe_link_setup(struct media_entity *entity,
435 			   const struct media_pad *local,
436 			   const struct media_pad *remote, u32 flags)
437 {
438 	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
439 	struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd);
440 	struct iss_device *iss = to_iss_device(ipipe);
441 
442 	switch (local->index | media_entity_type(remote->entity)) {
443 	case IPIPE_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
444 		/* Read from IPIPEIF. */
445 		if (!(flags & MEDIA_LNK_FL_ENABLED)) {
446 			ipipe->input = IPIPE_INPUT_NONE;
447 			break;
448 		}
449 
450 		if (ipipe->input != IPIPE_INPUT_NONE)
451 			return -EBUSY;
452 
453 		if (remote->entity == &iss->ipipeif.subdev.entity)
454 			ipipe->input = IPIPE_INPUT_IPIPEIF;
455 
456 		break;
457 
458 	case IPIPE_PAD_SOURCE_VP | MEDIA_ENT_T_V4L2_SUBDEV:
459 		/* Send to RESIZER */
460 		if (flags & MEDIA_LNK_FL_ENABLED) {
461 			if (ipipe->output & ~IPIPE_OUTPUT_VP)
462 				return -EBUSY;
463 			ipipe->output |= IPIPE_OUTPUT_VP;
464 		} else {
465 			ipipe->output &= ~IPIPE_OUTPUT_VP;
466 		}
467 		break;
468 
469 	default:
470 		return -EINVAL;
471 	}
472 
473 	return 0;
474 }
475 
476 /* media operations */
477 static const struct media_entity_operations ipipe_media_ops = {
478 	.link_setup = ipipe_link_setup,
479 	.link_validate = v4l2_subdev_link_validate,
480 };
481 
482 /*
483  * ipipe_init_entities - Initialize V4L2 subdev and media entity
484  * @ipipe: ISS ISP IPIPE module
485  *
486  * Return 0 on success and a negative error code on failure.
487  */
488 static int ipipe_init_entities(struct iss_ipipe_device *ipipe)
489 {
490 	struct v4l2_subdev *sd = &ipipe->subdev;
491 	struct media_pad *pads = ipipe->pads;
492 	struct media_entity *me = &sd->entity;
493 	int ret;
494 
495 	ipipe->input = IPIPE_INPUT_NONE;
496 
497 	v4l2_subdev_init(sd, &ipipe_v4l2_ops);
498 	sd->internal_ops = &ipipe_v4l2_internal_ops;
499 	strlcpy(sd->name, "OMAP4 ISS ISP IPIPE", sizeof(sd->name));
500 	sd->grp_id = 1 << 16;	/* group ID for iss subdevs */
501 	v4l2_set_subdevdata(sd, ipipe);
502 	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
503 
504 	pads[IPIPE_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
505 	pads[IPIPE_PAD_SOURCE_VP].flags = MEDIA_PAD_FL_SOURCE;
506 
507 	me->ops = &ipipe_media_ops;
508 	ret = media_entity_init(me, IPIPE_PADS_NUM, pads, 0);
509 	if (ret < 0)
510 		return ret;
511 
512 	ipipe_init_formats(sd, NULL);
513 
514 	return 0;
515 }
516 
517 void omap4iss_ipipe_unregister_entities(struct iss_ipipe_device *ipipe)
518 {
519 	media_entity_cleanup(&ipipe->subdev.entity);
520 
521 	v4l2_device_unregister_subdev(&ipipe->subdev);
522 }
523 
524 int omap4iss_ipipe_register_entities(struct iss_ipipe_device *ipipe,
525 	struct v4l2_device *vdev)
526 {
527 	int ret;
528 
529 	/* Register the subdev and video node. */
530 	ret = v4l2_device_register_subdev(vdev, &ipipe->subdev);
531 	if (ret < 0)
532 		goto error;
533 
534 	return 0;
535 
536 error:
537 	omap4iss_ipipe_unregister_entities(ipipe);
538 	return ret;
539 }
540 
541 /* -----------------------------------------------------------------------------
542  * ISP IPIPE initialisation and cleanup
543  */
544 
545 /*
546  * omap4iss_ipipe_init - IPIPE module initialization.
547  * @iss: Device pointer specific to the OMAP4 ISS.
548  *
549  * TODO: Get the initialisation values from platform data.
550  *
551  * Return 0 on success or a negative error code otherwise.
552  */
553 int omap4iss_ipipe_init(struct iss_device *iss)
554 {
555 	struct iss_ipipe_device *ipipe = &iss->ipipe;
556 
557 	ipipe->state = ISS_PIPELINE_STREAM_STOPPED;
558 	init_waitqueue_head(&ipipe->wait);
559 
560 	return ipipe_init_entities(ipipe);
561 }
562 
563 /*
564  * omap4iss_ipipe_cleanup - IPIPE module cleanup.
565  * @iss: Device pointer specific to the OMAP4 ISS.
566  */
567 void omap4iss_ipipe_cleanup(struct iss_device *iss)
568 {
569 	/* FIXME: are you sure there's nothing to do? */
570 }
571