[go: nahoru, domu]

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
26static 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
30static const unsigned int ipipe_fmts[] = {
31	V4L2_MBUS_FMT_SGRBG10_1X10,
32	V4L2_MBUS_FMT_SRGGB10_1X10,
33	V4L2_MBUS_FMT_SBGGR10_1X10,
34	V4L2_MBUS_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
47static 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 */
72static 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
84static 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 */
130static 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
178static 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 */
195static void
196ipipe_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 = V4L2_MBUS_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 = V4L2_MBUS_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 */
243static 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 = V4L2_MBUS_FMT_UYVY8_1X16;
261		break;
262
263	default:
264		return -EINVAL;
265	}
266
267	return 0;
268}
269
270static 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 */
309static 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 */
332static 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
357static 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 */
381static 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 = V4L2_MBUS_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 */
397static const struct v4l2_subdev_video_ops ipipe_v4l2_video_ops = {
398	.s_stream = ipipe_set_stream,
399};
400
401/* V4L2 subdev pad operations */
402static 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 */
411static 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 */
417static 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 */
434static 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 */
477static 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 */
488static 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
517void 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
524int 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
536error:
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 */
553int 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 */
567void omap4iss_ipipe_cleanup(struct iss_device *iss)
568{
569	/* FIXME: are you sure there's nothing to do? */
570}
571