diff options
Diffstat (limited to 'drivers/media/video/s5p-fimc')
-rw-r--r-- | drivers/media/video/s5p-fimc/Makefile | 2 | ||||
-rw-r--r-- | drivers/media/video/s5p-fimc/fimc-capture.c | 819 | ||||
-rw-r--r-- | drivers/media/video/s5p-fimc/fimc-core.c | 952 | ||||
-rw-r--r-- | drivers/media/video/s5p-fimc/fimc-core.h | 377 | ||||
-rw-r--r-- | drivers/media/video/s5p-fimc/fimc-reg.c | 321 | ||||
-rw-r--r-- | drivers/media/video/s5p-fimc/regs-fimc.h | 64 |
6 files changed, 1981 insertions, 554 deletions
diff --git a/drivers/media/video/s5p-fimc/Makefile b/drivers/media/video/s5p-fimc/Makefile index 0d9d54132ecc..7ea1b1403b1e 100644 --- a/drivers/media/video/s5p-fimc/Makefile +++ b/drivers/media/video/s5p-fimc/Makefile | |||
@@ -1,3 +1,3 @@ | |||
1 | 1 | ||
2 | obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) := s5p-fimc.o | 2 | obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) := s5p-fimc.o |
3 | s5p-fimc-y := fimc-core.o fimc-reg.o | 3 | s5p-fimc-y := fimc-core.o fimc-reg.o fimc-capture.o |
diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c new file mode 100644 index 000000000000..e8f13d3e2df1 --- /dev/null +++ b/drivers/media/video/s5p-fimc/fimc-capture.c | |||
@@ -0,0 +1,819 @@ | |||
1 | /* | ||
2 | * Samsung S5P SoC series camera interface (camera capture) driver | ||
3 | * | ||
4 | * Copyright (c) 2010 Samsung Electronics Co., Ltd | ||
5 | * Author: Sylwester Nawrocki, <s.nawrocki@samsung.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/version.h> | ||
15 | #include <linux/types.h> | ||
16 | #include <linux/errno.h> | ||
17 | #include <linux/bug.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/device.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/list.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/clk.h> | ||
24 | #include <linux/i2c.h> | ||
25 | |||
26 | #include <linux/videodev2.h> | ||
27 | #include <media/v4l2-device.h> | ||
28 | #include <media/v4l2-ioctl.h> | ||
29 | #include <media/v4l2-mem2mem.h> | ||
30 | #include <media/videobuf-core.h> | ||
31 | #include <media/videobuf-dma-contig.h> | ||
32 | |||
33 | #include "fimc-core.h" | ||
34 | |||
35 | static struct v4l2_subdev *fimc_subdev_register(struct fimc_dev *fimc, | ||
36 | struct s3c_fimc_isp_info *isp_info) | ||
37 | { | ||
38 | struct i2c_adapter *i2c_adap; | ||
39 | struct fimc_vid_cap *vid_cap = &fimc->vid_cap; | ||
40 | struct v4l2_subdev *sd = NULL; | ||
41 | |||
42 | i2c_adap = i2c_get_adapter(isp_info->i2c_bus_num); | ||
43 | if (!i2c_adap) | ||
44 | return ERR_PTR(-ENOMEM); | ||
45 | |||
46 | sd = v4l2_i2c_new_subdev_board(&vid_cap->v4l2_dev, i2c_adap, | ||
47 | MODULE_NAME, isp_info->board_info, NULL); | ||
48 | if (!sd) { | ||
49 | v4l2_err(&vid_cap->v4l2_dev, "failed to acquire subdev\n"); | ||
50 | return NULL; | ||
51 | } | ||
52 | |||
53 | v4l2_info(&vid_cap->v4l2_dev, "subdevice %s registered successfuly\n", | ||
54 | isp_info->board_info->type); | ||
55 | |||
56 | return sd; | ||
57 | } | ||
58 | |||
59 | static void fimc_subdev_unregister(struct fimc_dev *fimc) | ||
60 | { | ||
61 | struct fimc_vid_cap *vid_cap = &fimc->vid_cap; | ||
62 | struct i2c_client *client; | ||
63 | |||
64 | if (vid_cap->input_index < 0) | ||
65 | return; /* Subdevice already released or not registered. */ | ||
66 | |||
67 | if (vid_cap->sd) { | ||
68 | v4l2_device_unregister_subdev(vid_cap->sd); | ||
69 | client = v4l2_get_subdevdata(vid_cap->sd); | ||
70 | i2c_unregister_device(client); | ||
71 | i2c_put_adapter(client->adapter); | ||
72 | vid_cap->sd = NULL; | ||
73 | } | ||
74 | |||
75 | vid_cap->input_index = -1; | ||
76 | } | ||
77 | |||
78 | /** | ||
79 | * fimc_subdev_attach - attach v4l2_subdev to camera host interface | ||
80 | * | ||
81 | * @fimc: FIMC device information | ||
82 | * @index: index to the array of available subdevices, | ||
83 | * -1 for full array search or non negative value | ||
84 | * to select specific subdevice | ||
85 | */ | ||
86 | static int fimc_subdev_attach(struct fimc_dev *fimc, int index) | ||
87 | { | ||
88 | struct fimc_vid_cap *vid_cap = &fimc->vid_cap; | ||
89 | struct s3c_platform_fimc *pdata = fimc->pdata; | ||
90 | struct s3c_fimc_isp_info *isp_info; | ||
91 | struct v4l2_subdev *sd; | ||
92 | int i; | ||
93 | |||
94 | for (i = 0; i < FIMC_MAX_CAMIF_CLIENTS; ++i) { | ||
95 | isp_info = pdata->isp_info[i]; | ||
96 | |||
97 | if (!isp_info || (index >= 0 && i != index)) | ||
98 | continue; | ||
99 | |||
100 | sd = fimc_subdev_register(fimc, isp_info); | ||
101 | if (sd) { | ||
102 | vid_cap->sd = sd; | ||
103 | vid_cap->input_index = i; | ||
104 | |||
105 | return 0; | ||
106 | } | ||
107 | } | ||
108 | |||
109 | vid_cap->input_index = -1; | ||
110 | vid_cap->sd = NULL; | ||
111 | v4l2_err(&vid_cap->v4l2_dev, "fimc%d: sensor attach failed\n", | ||
112 | fimc->id); | ||
113 | return -ENODEV; | ||
114 | } | ||
115 | |||
116 | static int fimc_isp_subdev_init(struct fimc_dev *fimc, int index) | ||
117 | { | ||
118 | struct s3c_fimc_isp_info *isp_info; | ||
119 | int ret; | ||
120 | |||
121 | ret = fimc_subdev_attach(fimc, index); | ||
122 | if (ret) | ||
123 | return ret; | ||
124 | |||
125 | isp_info = fimc->pdata->isp_info[fimc->vid_cap.input_index]; | ||
126 | ret = fimc_hw_set_camera_polarity(fimc, isp_info); | ||
127 | if (!ret) { | ||
128 | ret = v4l2_subdev_call(fimc->vid_cap.sd, core, | ||
129 | s_power, 1); | ||
130 | if (!ret) | ||
131 | return ret; | ||
132 | } | ||
133 | |||
134 | fimc_subdev_unregister(fimc); | ||
135 | err("ISP initialization failed: %d", ret); | ||
136 | return ret; | ||
137 | } | ||
138 | |||
139 | /* | ||
140 | * At least one buffer on the pending_buf_q queue is required. | ||
141 | * Locking: The caller holds fimc->slock spinlock. | ||
142 | */ | ||
143 | int fimc_vid_cap_buf_queue(struct fimc_dev *fimc, | ||
144 | struct fimc_vid_buffer *fimc_vb) | ||
145 | { | ||
146 | struct fimc_vid_cap *cap = &fimc->vid_cap; | ||
147 | struct fimc_ctx *ctx = cap->ctx; | ||
148 | int ret = 0; | ||
149 | |||
150 | BUG_ON(!fimc || !fimc_vb); | ||
151 | |||
152 | ret = fimc_prepare_addr(ctx, fimc_vb, &ctx->d_frame, | ||
153 | &fimc_vb->paddr); | ||
154 | if (ret) | ||
155 | return ret; | ||
156 | |||
157 | if (test_bit(ST_CAPT_STREAM, &fimc->state)) { | ||
158 | fimc_pending_queue_add(cap, fimc_vb); | ||
159 | } else { | ||
160 | /* Setup the buffer directly for processing. */ | ||
161 | int buf_id = (cap->reqbufs_count == 1) ? -1 : cap->buf_index; | ||
162 | fimc_hw_set_output_addr(fimc, &fimc_vb->paddr, buf_id); | ||
163 | |||
164 | fimc_vb->index = cap->buf_index; | ||
165 | active_queue_add(cap, fimc_vb); | ||
166 | |||
167 | if (++cap->buf_index >= FIMC_MAX_OUT_BUFS) | ||
168 | cap->buf_index = 0; | ||
169 | } | ||
170 | return ret; | ||
171 | } | ||
172 | |||
173 | static int fimc_stop_capture(struct fimc_dev *fimc) | ||
174 | { | ||
175 | unsigned long flags; | ||
176 | struct fimc_vid_cap *cap; | ||
177 | int ret; | ||
178 | |||
179 | cap = &fimc->vid_cap; | ||
180 | |||
181 | if (!fimc_capture_active(fimc)) | ||
182 | return 0; | ||
183 | |||
184 | spin_lock_irqsave(&fimc->slock, flags); | ||
185 | set_bit(ST_CAPT_SHUT, &fimc->state); | ||
186 | fimc_deactivate_capture(fimc); | ||
187 | spin_unlock_irqrestore(&fimc->slock, flags); | ||
188 | |||
189 | wait_event_timeout(fimc->irq_queue, | ||
190 | test_bit(ST_CAPT_SHUT, &fimc->state), | ||
191 | FIMC_SHUTDOWN_TIMEOUT); | ||
192 | |||
193 | ret = v4l2_subdev_call(cap->sd, video, s_stream, 0); | ||
194 | if (ret) | ||
195 | v4l2_err(&fimc->vid_cap.v4l2_dev, "s_stream(0) failed\n"); | ||
196 | |||
197 | spin_lock_irqsave(&fimc->slock, flags); | ||
198 | fimc->state &= ~(1 << ST_CAPT_RUN | 1 << ST_CAPT_PEND | | ||
199 | 1 << ST_CAPT_STREAM); | ||
200 | |||
201 | fimc->vid_cap.active_buf_cnt = 0; | ||
202 | spin_unlock_irqrestore(&fimc->slock, flags); | ||
203 | |||
204 | dbg("state: 0x%lx", fimc->state); | ||
205 | return 0; | ||
206 | } | ||
207 | |||
208 | static int fimc_capture_open(struct file *file) | ||
209 | { | ||
210 | struct fimc_dev *fimc = video_drvdata(file); | ||
211 | int ret = 0; | ||
212 | |||
213 | dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state); | ||
214 | |||
215 | /* Return if the corresponding video mem2mem node is already opened. */ | ||
216 | if (fimc_m2m_active(fimc)) | ||
217 | return -EBUSY; | ||
218 | |||
219 | if (mutex_lock_interruptible(&fimc->lock)) | ||
220 | return -ERESTARTSYS; | ||
221 | |||
222 | if (++fimc->vid_cap.refcnt == 1) { | ||
223 | ret = fimc_isp_subdev_init(fimc, -1); | ||
224 | if (ret) { | ||
225 | fimc->vid_cap.refcnt--; | ||
226 | ret = -EIO; | ||
227 | } | ||
228 | } | ||
229 | |||
230 | file->private_data = fimc->vid_cap.ctx; | ||
231 | |||
232 | mutex_unlock(&fimc->lock); | ||
233 | return ret; | ||
234 | } | ||
235 | |||
236 | static int fimc_capture_close(struct file *file) | ||
237 | { | ||
238 | struct fimc_dev *fimc = video_drvdata(file); | ||
239 | |||
240 | if (mutex_lock_interruptible(&fimc->lock)) | ||
241 | return -ERESTARTSYS; | ||
242 | |||
243 | dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state); | ||
244 | |||
245 | if (--fimc->vid_cap.refcnt == 0) { | ||
246 | fimc_stop_capture(fimc); | ||
247 | |||
248 | videobuf_stop(&fimc->vid_cap.vbq); | ||
249 | videobuf_mmap_free(&fimc->vid_cap.vbq); | ||
250 | |||
251 | v4l2_err(&fimc->vid_cap.v4l2_dev, "releasing ISP\n"); | ||
252 | v4l2_subdev_call(fimc->vid_cap.sd, core, s_power, 0); | ||
253 | fimc_subdev_unregister(fimc); | ||
254 | } | ||
255 | |||
256 | mutex_unlock(&fimc->lock); | ||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | static unsigned int fimc_capture_poll(struct file *file, | ||
261 | struct poll_table_struct *wait) | ||
262 | { | ||
263 | struct fimc_ctx *ctx = file->private_data; | ||
264 | struct fimc_dev *fimc = ctx->fimc_dev; | ||
265 | struct fimc_vid_cap *cap = &fimc->vid_cap; | ||
266 | int ret; | ||
267 | |||
268 | if (mutex_lock_interruptible(&fimc->lock)) | ||
269 | return POLLERR; | ||
270 | |||
271 | ret = videobuf_poll_stream(file, &cap->vbq, wait); | ||
272 | mutex_unlock(&fimc->lock); | ||
273 | |||
274 | return ret; | ||
275 | } | ||
276 | |||
277 | static int fimc_capture_mmap(struct file *file, struct vm_area_struct *vma) | ||
278 | { | ||
279 | struct fimc_ctx *ctx = file->private_data; | ||
280 | struct fimc_dev *fimc = ctx->fimc_dev; | ||
281 | struct fimc_vid_cap *cap = &fimc->vid_cap; | ||
282 | int ret; | ||
283 | |||
284 | if (mutex_lock_interruptible(&fimc->lock)) | ||
285 | return -ERESTARTSYS; | ||
286 | |||
287 | ret = videobuf_mmap_mapper(&cap->vbq, vma); | ||
288 | mutex_unlock(&fimc->lock); | ||
289 | |||
290 | return ret; | ||
291 | } | ||
292 | |||
293 | /* video device file operations */ | ||
294 | static const struct v4l2_file_operations fimc_capture_fops = { | ||
295 | .owner = THIS_MODULE, | ||
296 | .open = fimc_capture_open, | ||
297 | .release = fimc_capture_close, | ||
298 | .poll = fimc_capture_poll, | ||
299 | .unlocked_ioctl = video_ioctl2, | ||
300 | .mmap = fimc_capture_mmap, | ||
301 | }; | ||
302 | |||
303 | static int fimc_vidioc_querycap_capture(struct file *file, void *priv, | ||
304 | struct v4l2_capability *cap) | ||
305 | { | ||
306 | struct fimc_ctx *ctx = file->private_data; | ||
307 | struct fimc_dev *fimc = ctx->fimc_dev; | ||
308 | |||
309 | strncpy(cap->driver, fimc->pdev->name, sizeof(cap->driver) - 1); | ||
310 | strncpy(cap->card, fimc->pdev->name, sizeof(cap->card) - 1); | ||
311 | cap->bus_info[0] = 0; | ||
312 | cap->version = KERNEL_VERSION(1, 0, 0); | ||
313 | cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE; | ||
314 | |||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | /* Synchronize formats of the camera interface input and attached sensor. */ | ||
319 | static int sync_capture_fmt(struct fimc_ctx *ctx) | ||
320 | { | ||
321 | struct fimc_frame *frame = &ctx->s_frame; | ||
322 | struct fimc_dev *fimc = ctx->fimc_dev; | ||
323 | struct v4l2_mbus_framefmt *fmt = &fimc->vid_cap.fmt; | ||
324 | int ret; | ||
325 | |||
326 | fmt->width = ctx->d_frame.o_width; | ||
327 | fmt->height = ctx->d_frame.o_height; | ||
328 | |||
329 | ret = v4l2_subdev_call(fimc->vid_cap.sd, video, s_mbus_fmt, fmt); | ||
330 | if (ret == -ENOIOCTLCMD) { | ||
331 | err("s_mbus_fmt failed"); | ||
332 | return ret; | ||
333 | } | ||
334 | dbg("w: %d, h: %d, code= %d", fmt->width, fmt->height, fmt->code); | ||
335 | |||
336 | frame->fmt = find_mbus_format(fmt, FMT_FLAGS_CAM); | ||
337 | if (!frame->fmt) { | ||
338 | err("fimc source format not found\n"); | ||
339 | return -EINVAL; | ||
340 | } | ||
341 | |||
342 | frame->f_width = fmt->width; | ||
343 | frame->f_height = fmt->height; | ||
344 | frame->width = fmt->width; | ||
345 | frame->height = fmt->height; | ||
346 | frame->o_width = fmt->width; | ||
347 | frame->o_height = fmt->height; | ||
348 | frame->offs_h = 0; | ||
349 | frame->offs_v = 0; | ||
350 | |||
351 | return 0; | ||
352 | } | ||
353 | |||
354 | static int fimc_cap_s_fmt(struct file *file, void *priv, | ||
355 | struct v4l2_format *f) | ||
356 | { | ||
357 | struct fimc_ctx *ctx = priv; | ||
358 | struct fimc_dev *fimc = ctx->fimc_dev; | ||
359 | struct fimc_frame *frame; | ||
360 | struct v4l2_pix_format *pix; | ||
361 | int ret; | ||
362 | |||
363 | if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
364 | return -EINVAL; | ||
365 | |||
366 | ret = fimc_vidioc_try_fmt(file, priv, f); | ||
367 | if (ret) | ||
368 | return ret; | ||
369 | |||
370 | if (mutex_lock_interruptible(&fimc->lock)) | ||
371 | return -ERESTARTSYS; | ||
372 | |||
373 | if (fimc_capture_active(fimc)) { | ||
374 | ret = -EBUSY; | ||
375 | goto sf_unlock; | ||
376 | } | ||
377 | |||
378 | frame = &ctx->d_frame; | ||
379 | |||
380 | pix = &f->fmt.pix; | ||
381 | frame->fmt = find_format(f, FMT_FLAGS_M2M | FMT_FLAGS_CAM); | ||
382 | if (!frame->fmt) { | ||
383 | err("fimc target format not found\n"); | ||
384 | ret = -EINVAL; | ||
385 | goto sf_unlock; | ||
386 | } | ||
387 | |||
388 | /* Output DMA frame pixel size and offsets. */ | ||
389 | frame->f_width = pix->bytesperline * 8 / frame->fmt->depth; | ||
390 | frame->f_height = pix->height; | ||
391 | frame->width = pix->width; | ||
392 | frame->height = pix->height; | ||
393 | frame->o_width = pix->width; | ||
394 | frame->o_height = pix->height; | ||
395 | frame->size = (pix->width * pix->height * frame->fmt->depth) >> 3; | ||
396 | frame->offs_h = 0; | ||
397 | frame->offs_v = 0; | ||
398 | |||
399 | ret = sync_capture_fmt(ctx); | ||
400 | |||
401 | ctx->state |= (FIMC_PARAMS | FIMC_DST_FMT); | ||
402 | |||
403 | sf_unlock: | ||
404 | mutex_unlock(&fimc->lock); | ||
405 | return ret; | ||
406 | } | ||
407 | |||
408 | static int fimc_cap_enum_input(struct file *file, void *priv, | ||
409 | struct v4l2_input *i) | ||
410 | { | ||
411 | struct fimc_ctx *ctx = priv; | ||
412 | struct s3c_platform_fimc *pldata = ctx->fimc_dev->pdata; | ||
413 | struct s3c_fimc_isp_info *isp_info; | ||
414 | |||
415 | if (i->index >= FIMC_MAX_CAMIF_CLIENTS) | ||
416 | return -EINVAL; | ||
417 | |||
418 | isp_info = pldata->isp_info[i->index]; | ||
419 | if (isp_info == NULL) | ||
420 | return -EINVAL; | ||
421 | |||
422 | i->type = V4L2_INPUT_TYPE_CAMERA; | ||
423 | strncpy(i->name, isp_info->board_info->type, 32); | ||
424 | return 0; | ||
425 | } | ||
426 | |||
427 | static int fimc_cap_s_input(struct file *file, void *priv, | ||
428 | unsigned int i) | ||
429 | { | ||
430 | struct fimc_ctx *ctx = priv; | ||
431 | struct fimc_dev *fimc = ctx->fimc_dev; | ||
432 | struct s3c_platform_fimc *pdata = fimc->pdata; | ||
433 | int ret; | ||
434 | |||
435 | if (fimc_capture_active(ctx->fimc_dev)) | ||
436 | return -EBUSY; | ||
437 | |||
438 | if (mutex_lock_interruptible(&fimc->lock)) | ||
439 | return -ERESTARTSYS; | ||
440 | |||
441 | if (i >= FIMC_MAX_CAMIF_CLIENTS || !pdata->isp_info[i]) { | ||
442 | ret = -EINVAL; | ||
443 | goto si_unlock; | ||
444 | } | ||
445 | |||
446 | if (fimc->vid_cap.sd) { | ||
447 | ret = v4l2_subdev_call(fimc->vid_cap.sd, core, s_power, 0); | ||
448 | if (ret) | ||
449 | err("s_power failed: %d", ret); | ||
450 | } | ||
451 | |||
452 | /* Release the attached sensor subdevice. */ | ||
453 | fimc_subdev_unregister(fimc); | ||
454 | |||
455 | ret = fimc_isp_subdev_init(fimc, i); | ||
456 | |||
457 | si_unlock: | ||
458 | mutex_unlock(&fimc->lock); | ||
459 | return ret; | ||
460 | } | ||
461 | |||
462 | static int fimc_cap_g_input(struct file *file, void *priv, | ||
463 | unsigned int *i) | ||
464 | { | ||
465 | struct fimc_ctx *ctx = priv; | ||
466 | struct fimc_vid_cap *cap = &ctx->fimc_dev->vid_cap; | ||
467 | |||
468 | *i = cap->input_index; | ||
469 | return 0; | ||
470 | } | ||
471 | |||
472 | static int fimc_cap_streamon(struct file *file, void *priv, | ||
473 | enum v4l2_buf_type type) | ||
474 | { | ||
475 | struct s3c_fimc_isp_info *isp_info; | ||
476 | struct fimc_ctx *ctx = priv; | ||
477 | struct fimc_dev *fimc = ctx->fimc_dev; | ||
478 | int ret = -EBUSY; | ||
479 | |||
480 | if (mutex_lock_interruptible(&fimc->lock)) | ||
481 | return -ERESTARTSYS; | ||
482 | |||
483 | if (fimc_capture_active(fimc) || !fimc->vid_cap.sd) | ||
484 | goto s_unlock; | ||
485 | |||
486 | if (!(ctx->state & FIMC_DST_FMT)) { | ||
487 | v4l2_err(&fimc->vid_cap.v4l2_dev, "Format is not set\n"); | ||
488 | ret = -EINVAL; | ||
489 | goto s_unlock; | ||
490 | } | ||
491 | |||
492 | ret = v4l2_subdev_call(fimc->vid_cap.sd, video, s_stream, 1); | ||
493 | if (ret && ret != -ENOIOCTLCMD) | ||
494 | goto s_unlock; | ||
495 | |||
496 | ret = fimc_prepare_config(ctx, ctx->state); | ||
497 | if (ret) | ||
498 | goto s_unlock; | ||
499 | |||
500 | isp_info = fimc->pdata->isp_info[fimc->vid_cap.input_index]; | ||
501 | fimc_hw_set_camera_type(fimc, isp_info); | ||
502 | fimc_hw_set_camera_source(fimc, isp_info); | ||
503 | fimc_hw_set_camera_offset(fimc, &ctx->s_frame); | ||
504 | |||
505 | if (ctx->state & FIMC_PARAMS) { | ||
506 | ret = fimc_set_scaler_info(ctx); | ||
507 | if (ret) { | ||
508 | err("Scaler setup error"); | ||
509 | goto s_unlock; | ||
510 | } | ||
511 | fimc_hw_set_input_path(ctx); | ||
512 | fimc_hw_set_scaler(ctx); | ||
513 | fimc_hw_set_target_format(ctx); | ||
514 | fimc_hw_set_rotation(ctx); | ||
515 | fimc_hw_set_effect(ctx); | ||
516 | } | ||
517 | |||
518 | fimc_hw_set_output_path(ctx); | ||
519 | fimc_hw_set_out_dma(ctx); | ||
520 | |||
521 | INIT_LIST_HEAD(&fimc->vid_cap.pending_buf_q); | ||
522 | INIT_LIST_HEAD(&fimc->vid_cap.active_buf_q); | ||
523 | fimc->vid_cap.active_buf_cnt = 0; | ||
524 | fimc->vid_cap.frame_count = 0; | ||
525 | |||
526 | set_bit(ST_CAPT_PEND, &fimc->state); | ||
527 | ret = videobuf_streamon(&fimc->vid_cap.vbq); | ||
528 | |||
529 | s_unlock: | ||
530 | mutex_unlock(&fimc->lock); | ||
531 | return ret; | ||
532 | } | ||
533 | |||
534 | static int fimc_cap_streamoff(struct file *file, void *priv, | ||
535 | enum v4l2_buf_type type) | ||
536 | { | ||
537 | struct fimc_ctx *ctx = priv; | ||
538 | struct fimc_dev *fimc = ctx->fimc_dev; | ||
539 | struct fimc_vid_cap *cap = &fimc->vid_cap; | ||
540 | unsigned long flags; | ||
541 | int ret; | ||
542 | |||
543 | spin_lock_irqsave(&fimc->slock, flags); | ||
544 | if (!fimc_capture_running(fimc) && !fimc_capture_pending(fimc)) { | ||
545 | spin_unlock_irqrestore(&fimc->slock, flags); | ||
546 | dbg("state: 0x%lx", fimc->state); | ||
547 | return -EINVAL; | ||
548 | } | ||
549 | spin_unlock_irqrestore(&fimc->slock, flags); | ||
550 | |||
551 | if (mutex_lock_interruptible(&fimc->lock)) | ||
552 | return -ERESTARTSYS; | ||
553 | |||
554 | fimc_stop_capture(fimc); | ||
555 | ret = videobuf_streamoff(&cap->vbq); | ||
556 | mutex_unlock(&fimc->lock); | ||
557 | return ret; | ||
558 | } | ||
559 | |||
560 | static int fimc_cap_reqbufs(struct file *file, void *priv, | ||
561 | struct v4l2_requestbuffers *reqbufs) | ||
562 | { | ||
563 | struct fimc_ctx *ctx = priv; | ||
564 | struct fimc_dev *fimc = ctx->fimc_dev; | ||
565 | struct fimc_vid_cap *cap = &fimc->vid_cap; | ||
566 | int ret; | ||
567 | |||
568 | if (fimc_capture_active(ctx->fimc_dev)) | ||
569 | return -EBUSY; | ||
570 | |||
571 | if (mutex_lock_interruptible(&fimc->lock)) | ||
572 | return -ERESTARTSYS; | ||
573 | |||
574 | ret = videobuf_reqbufs(&cap->vbq, reqbufs); | ||
575 | if (!ret) | ||
576 | cap->reqbufs_count = reqbufs->count; | ||
577 | |||
578 | mutex_unlock(&fimc->lock); | ||
579 | return ret; | ||
580 | } | ||
581 | |||
582 | static int fimc_cap_querybuf(struct file *file, void *priv, | ||
583 | struct v4l2_buffer *buf) | ||
584 | { | ||
585 | struct fimc_ctx *ctx = priv; | ||
586 | struct fimc_vid_cap *cap = &ctx->fimc_dev->vid_cap; | ||
587 | |||
588 | if (fimc_capture_active(ctx->fimc_dev)) | ||
589 | return -EBUSY; | ||
590 | |||
591 | return videobuf_querybuf(&cap->vbq, buf); | ||
592 | } | ||
593 | |||
594 | static int fimc_cap_qbuf(struct file *file, void *priv, | ||
595 | struct v4l2_buffer *buf) | ||
596 | { | ||
597 | struct fimc_ctx *ctx = priv; | ||
598 | struct fimc_dev *fimc = ctx->fimc_dev; | ||
599 | struct fimc_vid_cap *cap = &fimc->vid_cap; | ||
600 | int ret; | ||
601 | |||
602 | if (mutex_lock_interruptible(&fimc->lock)) | ||
603 | return -ERESTARTSYS; | ||
604 | |||
605 | ret = videobuf_qbuf(&cap->vbq, buf); | ||
606 | |||
607 | mutex_unlock(&fimc->lock); | ||
608 | return ret; | ||
609 | } | ||
610 | |||
611 | static int fimc_cap_dqbuf(struct file *file, void *priv, | ||
612 | struct v4l2_buffer *buf) | ||
613 | { | ||
614 | struct fimc_ctx *ctx = priv; | ||
615 | int ret; | ||
616 | |||
617 | if (mutex_lock_interruptible(&ctx->fimc_dev->lock)) | ||
618 | return -ERESTARTSYS; | ||
619 | |||
620 | ret = videobuf_dqbuf(&ctx->fimc_dev->vid_cap.vbq, buf, | ||
621 | file->f_flags & O_NONBLOCK); | ||
622 | |||
623 | mutex_unlock(&ctx->fimc_dev->lock); | ||
624 | return ret; | ||
625 | } | ||
626 | |||
627 | static int fimc_cap_s_ctrl(struct file *file, void *priv, | ||
628 | struct v4l2_control *ctrl) | ||
629 | { | ||
630 | struct fimc_ctx *ctx = priv; | ||
631 | int ret = -EINVAL; | ||
632 | |||
633 | if (mutex_lock_interruptible(&ctx->fimc_dev->lock)) | ||
634 | return -ERESTARTSYS; | ||
635 | |||
636 | /* Allow any controls but 90/270 rotation while streaming */ | ||
637 | if (!fimc_capture_active(ctx->fimc_dev) || | ||
638 | ctrl->id != V4L2_CID_ROTATE || | ||
639 | (ctrl->value != 90 && ctrl->value != 270)) { | ||
640 | ret = check_ctrl_val(ctx, ctrl); | ||
641 | if (!ret) { | ||
642 | ret = fimc_s_ctrl(ctx, ctrl); | ||
643 | if (!ret) | ||
644 | ctx->state |= FIMC_PARAMS; | ||
645 | } | ||
646 | } | ||
647 | if (ret == -EINVAL) | ||
648 | ret = v4l2_subdev_call(ctx->fimc_dev->vid_cap.sd, | ||
649 | core, s_ctrl, ctrl); | ||
650 | |||
651 | mutex_unlock(&ctx->fimc_dev->lock); | ||
652 | return ret; | ||
653 | } | ||
654 | |||
655 | static int fimc_cap_s_crop(struct file *file, void *fh, | ||
656 | struct v4l2_crop *cr) | ||
657 | { | ||
658 | struct fimc_frame *f; | ||
659 | struct fimc_ctx *ctx = file->private_data; | ||
660 | struct fimc_dev *fimc = ctx->fimc_dev; | ||
661 | int ret = -EINVAL; | ||
662 | |||
663 | if (fimc_capture_active(fimc)) | ||
664 | return -EBUSY; | ||
665 | |||
666 | ret = fimc_try_crop(ctx, cr); | ||
667 | if (ret) | ||
668 | return ret; | ||
669 | |||
670 | if (mutex_lock_interruptible(&fimc->lock)) | ||
671 | return -ERESTARTSYS; | ||
672 | |||
673 | if (!(ctx->state & FIMC_DST_FMT)) { | ||
674 | v4l2_err(&fimc->vid_cap.v4l2_dev, | ||
675 | "Capture color format not set\n"); | ||
676 | goto sc_unlock; | ||
677 | } | ||
678 | |||
679 | f = &ctx->s_frame; | ||
680 | /* Check for the pixel scaling ratio when cropping input image. */ | ||
681 | ret = fimc_check_scaler_ratio(&cr->c, &ctx->d_frame); | ||
682 | if (ret) { | ||
683 | v4l2_err(&fimc->vid_cap.v4l2_dev, "Out of the scaler range"); | ||
684 | } else { | ||
685 | ret = 0; | ||
686 | f->offs_h = cr->c.left; | ||
687 | f->offs_v = cr->c.top; | ||
688 | f->width = cr->c.width; | ||
689 | f->height = cr->c.height; | ||
690 | } | ||
691 | |||
692 | sc_unlock: | ||
693 | mutex_unlock(&fimc->lock); | ||
694 | return ret; | ||
695 | } | ||
696 | |||
697 | |||
698 | static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = { | ||
699 | .vidioc_querycap = fimc_vidioc_querycap_capture, | ||
700 | |||
701 | .vidioc_enum_fmt_vid_cap = fimc_vidioc_enum_fmt, | ||
702 | .vidioc_try_fmt_vid_cap = fimc_vidioc_try_fmt, | ||
703 | .vidioc_s_fmt_vid_cap = fimc_cap_s_fmt, | ||
704 | .vidioc_g_fmt_vid_cap = fimc_vidioc_g_fmt, | ||
705 | |||
706 | .vidioc_reqbufs = fimc_cap_reqbufs, | ||
707 | .vidioc_querybuf = fimc_cap_querybuf, | ||
708 | |||
709 | .vidioc_qbuf = fimc_cap_qbuf, | ||
710 | .vidioc_dqbuf = fimc_cap_dqbuf, | ||
711 | |||
712 | .vidioc_streamon = fimc_cap_streamon, | ||
713 | .vidioc_streamoff = fimc_cap_streamoff, | ||
714 | |||
715 | .vidioc_queryctrl = fimc_vidioc_queryctrl, | ||
716 | .vidioc_g_ctrl = fimc_vidioc_g_ctrl, | ||
717 | .vidioc_s_ctrl = fimc_cap_s_ctrl, | ||
718 | |||
719 | .vidioc_g_crop = fimc_vidioc_g_crop, | ||
720 | .vidioc_s_crop = fimc_cap_s_crop, | ||
721 | .vidioc_cropcap = fimc_vidioc_cropcap, | ||
722 | |||
723 | .vidioc_enum_input = fimc_cap_enum_input, | ||
724 | .vidioc_s_input = fimc_cap_s_input, | ||
725 | .vidioc_g_input = fimc_cap_g_input, | ||
726 | }; | ||
727 | |||
728 | int fimc_register_capture_device(struct fimc_dev *fimc) | ||
729 | { | ||
730 | struct v4l2_device *v4l2_dev = &fimc->vid_cap.v4l2_dev; | ||
731 | struct video_device *vfd; | ||
732 | struct fimc_vid_cap *vid_cap; | ||
733 | struct fimc_ctx *ctx; | ||
734 | struct v4l2_format f; | ||
735 | int ret; | ||
736 | |||
737 | ctx = kzalloc(sizeof *ctx, GFP_KERNEL); | ||
738 | if (!ctx) | ||
739 | return -ENOMEM; | ||
740 | |||
741 | ctx->fimc_dev = fimc; | ||
742 | ctx->in_path = FIMC_CAMERA; | ||
743 | ctx->out_path = FIMC_DMA; | ||
744 | ctx->state = FIMC_CTX_CAP; | ||
745 | |||
746 | f.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24; | ||
747 | ctx->d_frame.fmt = find_format(&f, FMT_FLAGS_M2M); | ||
748 | |||
749 | if (!v4l2_dev->name[0]) | ||
750 | snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), | ||
751 | "%s.capture", dev_name(&fimc->pdev->dev)); | ||
752 | |||
753 | ret = v4l2_device_register(NULL, v4l2_dev); | ||
754 | if (ret) | ||
755 | goto err_info; | ||
756 | |||
757 | vfd = video_device_alloc(); | ||
758 | if (!vfd) { | ||
759 | v4l2_err(v4l2_dev, "Failed to allocate video device\n"); | ||
760 | goto err_v4l2_reg; | ||
761 | } | ||
762 | |||
763 | snprintf(vfd->name, sizeof(vfd->name), "%s:cap", | ||
764 | dev_name(&fimc->pdev->dev)); | ||
765 | |||
766 | vfd->fops = &fimc_capture_fops; | ||
767 | vfd->ioctl_ops = &fimc_capture_ioctl_ops; | ||
768 | vfd->minor = -1; | ||
769 | vfd->release = video_device_release; | ||
770 | video_set_drvdata(vfd, fimc); | ||
771 | |||
772 | vid_cap = &fimc->vid_cap; | ||
773 | vid_cap->vfd = vfd; | ||
774 | vid_cap->active_buf_cnt = 0; | ||
775 | vid_cap->reqbufs_count = 0; | ||
776 | vid_cap->refcnt = 0; | ||
777 | /* The default color format for image sensor. */ | ||
778 | vid_cap->fmt.code = V4L2_MBUS_FMT_YUYV8_2X8; | ||
779 | |||
780 | INIT_LIST_HEAD(&vid_cap->pending_buf_q); | ||
781 | INIT_LIST_HEAD(&vid_cap->active_buf_q); | ||
782 | spin_lock_init(&ctx->slock); | ||
783 | vid_cap->ctx = ctx; | ||
784 | |||
785 | videobuf_queue_dma_contig_init(&vid_cap->vbq, &fimc_qops, | ||
786 | vid_cap->v4l2_dev.dev, &fimc->irqlock, | ||
787 | V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE, | ||
788 | sizeof(struct fimc_vid_buffer), (void *)ctx); | ||
789 | |||
790 | ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1); | ||
791 | if (ret) { | ||
792 | v4l2_err(v4l2_dev, "Failed to register video device\n"); | ||
793 | goto err_vd_reg; | ||
794 | } | ||
795 | |||
796 | v4l2_info(v4l2_dev, | ||
797 | "FIMC capture driver registered as /dev/video%d\n", | ||
798 | vfd->num); | ||
799 | |||
800 | return 0; | ||
801 | |||
802 | err_vd_reg: | ||
803 | video_device_release(vfd); | ||
804 | err_v4l2_reg: | ||
805 | v4l2_device_unregister(v4l2_dev); | ||
806 | err_info: | ||
807 | dev_err(&fimc->pdev->dev, "failed to install\n"); | ||
808 | return ret; | ||
809 | } | ||
810 | |||
811 | void fimc_unregister_capture_device(struct fimc_dev *fimc) | ||
812 | { | ||
813 | struct fimc_vid_cap *capture = &fimc->vid_cap; | ||
814 | |||
815 | if (capture->vfd) | ||
816 | video_unregister_device(capture->vfd); | ||
817 | |||
818 | kfree(capture->ctx); | ||
819 | } | ||
diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index 6961c55baf9b..2e7c547894b6 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * S5P camera interface (video postprocessor) driver | 2 | * S5P camera interface (video postprocessor) driver |
3 | * | 3 | * |
4 | * Copyright (c) 2010 Samsung Electronics | 4 | * Copyright (c) 2010 Samsung Electronics Co., Ltd |
5 | * | 5 | * |
6 | * Sylwester Nawrocki, <s.nawrocki@samsung.com> | 6 | * Sylwester Nawrocki, <s.nawrocki@samsung.com> |
7 | * | 7 | * |
@@ -38,86 +38,103 @@ static struct fimc_fmt fimc_formats[] = { | |||
38 | .depth = 16, | 38 | .depth = 16, |
39 | .color = S5P_FIMC_RGB565, | 39 | .color = S5P_FIMC_RGB565, |
40 | .buff_cnt = 1, | 40 | .buff_cnt = 1, |
41 | .planes_cnt = 1 | 41 | .planes_cnt = 1, |
42 | .mbus_code = V4L2_MBUS_FMT_RGB565_2X8_BE, | ||
43 | .flags = FMT_FLAGS_M2M, | ||
42 | }, { | 44 | }, { |
43 | .name = "BGR666", | 45 | .name = "BGR666", |
44 | .fourcc = V4L2_PIX_FMT_BGR666, | 46 | .fourcc = V4L2_PIX_FMT_BGR666, |
45 | .depth = 32, | 47 | .depth = 32, |
46 | .color = S5P_FIMC_RGB666, | 48 | .color = S5P_FIMC_RGB666, |
47 | .buff_cnt = 1, | 49 | .buff_cnt = 1, |
48 | .planes_cnt = 1 | 50 | .planes_cnt = 1, |
51 | .flags = FMT_FLAGS_M2M, | ||
49 | }, { | 52 | }, { |
50 | .name = "XRGB-8-8-8-8, 24 bpp", | 53 | .name = "XRGB-8-8-8-8, 24 bpp", |
51 | .fourcc = V4L2_PIX_FMT_RGB24, | 54 | .fourcc = V4L2_PIX_FMT_RGB24, |
52 | .depth = 32, | 55 | .depth = 32, |
53 | .color = S5P_FIMC_RGB888, | 56 | .color = S5P_FIMC_RGB888, |
54 | .buff_cnt = 1, | 57 | .buff_cnt = 1, |
55 | .planes_cnt = 1 | 58 | .planes_cnt = 1, |
59 | .flags = FMT_FLAGS_M2M, | ||
56 | }, { | 60 | }, { |
57 | .name = "YUV 4:2:2 packed, YCbYCr", | 61 | .name = "YUV 4:2:2 packed, YCbYCr", |
58 | .fourcc = V4L2_PIX_FMT_YUYV, | 62 | .fourcc = V4L2_PIX_FMT_YUYV, |
59 | .depth = 16, | 63 | .depth = 16, |
60 | .color = S5P_FIMC_YCBYCR422, | 64 | .color = S5P_FIMC_YCBYCR422, |
61 | .buff_cnt = 1, | 65 | .buff_cnt = 1, |
62 | .planes_cnt = 1 | 66 | .planes_cnt = 1, |
63 | }, { | 67 | .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8, |
68 | .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM, | ||
69 | }, { | ||
64 | .name = "YUV 4:2:2 packed, CbYCrY", | 70 | .name = "YUV 4:2:2 packed, CbYCrY", |
65 | .fourcc = V4L2_PIX_FMT_UYVY, | 71 | .fourcc = V4L2_PIX_FMT_UYVY, |
66 | .depth = 16, | 72 | .depth = 16, |
67 | .color = S5P_FIMC_CBYCRY422, | 73 | .color = S5P_FIMC_CBYCRY422, |
68 | .buff_cnt = 1, | 74 | .buff_cnt = 1, |
69 | .planes_cnt = 1 | 75 | .planes_cnt = 1, |
76 | .mbus_code = V4L2_MBUS_FMT_UYVY8_2X8, | ||
77 | .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM, | ||
70 | }, { | 78 | }, { |
71 | .name = "YUV 4:2:2 packed, CrYCbY", | 79 | .name = "YUV 4:2:2 packed, CrYCbY", |
72 | .fourcc = V4L2_PIX_FMT_VYUY, | 80 | .fourcc = V4L2_PIX_FMT_VYUY, |
73 | .depth = 16, | 81 | .depth = 16, |
74 | .color = S5P_FIMC_CRYCBY422, | 82 | .color = S5P_FIMC_CRYCBY422, |
75 | .buff_cnt = 1, | 83 | .buff_cnt = 1, |
76 | .planes_cnt = 1 | 84 | .planes_cnt = 1, |
85 | .mbus_code = V4L2_MBUS_FMT_VYUY8_2X8, | ||
86 | .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM, | ||
77 | }, { | 87 | }, { |
78 | .name = "YUV 4:2:2 packed, YCrYCb", | 88 | .name = "YUV 4:2:2 packed, YCrYCb", |
79 | .fourcc = V4L2_PIX_FMT_YVYU, | 89 | .fourcc = V4L2_PIX_FMT_YVYU, |
80 | .depth = 16, | 90 | .depth = 16, |
81 | .color = S5P_FIMC_YCRYCB422, | 91 | .color = S5P_FIMC_YCRYCB422, |
82 | .buff_cnt = 1, | 92 | .buff_cnt = 1, |
83 | .planes_cnt = 1 | 93 | .planes_cnt = 1, |
94 | .mbus_code = V4L2_MBUS_FMT_YVYU8_2X8, | ||
95 | .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM, | ||
84 | }, { | 96 | }, { |
85 | .name = "YUV 4:2:2 planar, Y/Cb/Cr", | 97 | .name = "YUV 4:2:2 planar, Y/Cb/Cr", |
86 | .fourcc = V4L2_PIX_FMT_YUV422P, | 98 | .fourcc = V4L2_PIX_FMT_YUV422P, |
87 | .depth = 12, | 99 | .depth = 12, |
88 | .color = S5P_FIMC_YCBCR422, | 100 | .color = S5P_FIMC_YCBCR422, |
89 | .buff_cnt = 1, | 101 | .buff_cnt = 1, |
90 | .planes_cnt = 3 | 102 | .planes_cnt = 3, |
103 | .flags = FMT_FLAGS_M2M, | ||
91 | }, { | 104 | }, { |
92 | .name = "YUV 4:2:2 planar, Y/CbCr", | 105 | .name = "YUV 4:2:2 planar, Y/CbCr", |
93 | .fourcc = V4L2_PIX_FMT_NV16, | 106 | .fourcc = V4L2_PIX_FMT_NV16, |
94 | .depth = 16, | 107 | .depth = 16, |
95 | .color = S5P_FIMC_YCBCR422, | 108 | .color = S5P_FIMC_YCBCR422, |
96 | .buff_cnt = 1, | 109 | .buff_cnt = 1, |
97 | .planes_cnt = 2 | 110 | .planes_cnt = 2, |
111 | .flags = FMT_FLAGS_M2M, | ||
98 | }, { | 112 | }, { |
99 | .name = "YUV 4:2:2 planar, Y/CrCb", | 113 | .name = "YUV 4:2:2 planar, Y/CrCb", |
100 | .fourcc = V4L2_PIX_FMT_NV61, | 114 | .fourcc = V4L2_PIX_FMT_NV61, |
101 | .depth = 16, | 115 | .depth = 16, |
102 | .color = S5P_FIMC_RGB565, | 116 | .color = S5P_FIMC_RGB565, |
103 | .buff_cnt = 1, | 117 | .buff_cnt = 1, |
104 | .planes_cnt = 2 | 118 | .planes_cnt = 2, |
119 | .flags = FMT_FLAGS_M2M, | ||
105 | }, { | 120 | }, { |
106 | .name = "YUV 4:2:0 planar, YCbCr", | 121 | .name = "YUV 4:2:0 planar, YCbCr", |
107 | .fourcc = V4L2_PIX_FMT_YUV420, | 122 | .fourcc = V4L2_PIX_FMT_YUV420, |
108 | .depth = 12, | 123 | .depth = 12, |
109 | .color = S5P_FIMC_YCBCR420, | 124 | .color = S5P_FIMC_YCBCR420, |
110 | .buff_cnt = 1, | 125 | .buff_cnt = 1, |
111 | .planes_cnt = 3 | 126 | .planes_cnt = 3, |
127 | .flags = FMT_FLAGS_M2M, | ||
112 | }, { | 128 | }, { |
113 | .name = "YUV 4:2:0 planar, Y/CbCr", | 129 | .name = "YUV 4:2:0 planar, Y/CbCr", |
114 | .fourcc = V4L2_PIX_FMT_NV12, | 130 | .fourcc = V4L2_PIX_FMT_NV12, |
115 | .depth = 12, | 131 | .depth = 12, |
116 | .color = S5P_FIMC_YCBCR420, | 132 | .color = S5P_FIMC_YCBCR420, |
117 | .buff_cnt = 1, | 133 | .buff_cnt = 1, |
118 | .planes_cnt = 2 | 134 | .planes_cnt = 2, |
119 | } | 135 | .flags = FMT_FLAGS_M2M, |
120 | }; | 136 | }, |
137 | }; | ||
121 | 138 | ||
122 | static struct v4l2_queryctrl fimc_ctrls[] = { | 139 | static struct v4l2_queryctrl fimc_ctrls[] = { |
123 | { | 140 | { |
@@ -127,16 +144,14 @@ static struct v4l2_queryctrl fimc_ctrls[] = { | |||
127 | .minimum = 0, | 144 | .minimum = 0, |
128 | .maximum = 1, | 145 | .maximum = 1, |
129 | .default_value = 0, | 146 | .default_value = 0, |
130 | }, | 147 | }, { |
131 | { | ||
132 | .id = V4L2_CID_VFLIP, | 148 | .id = V4L2_CID_VFLIP, |
133 | .type = V4L2_CTRL_TYPE_BOOLEAN, | 149 | .type = V4L2_CTRL_TYPE_BOOLEAN, |
134 | .name = "Vertical flip", | 150 | .name = "Vertical flip", |
135 | .minimum = 0, | 151 | .minimum = 0, |
136 | .maximum = 1, | 152 | .maximum = 1, |
137 | .default_value = 0, | 153 | .default_value = 0, |
138 | }, | 154 | }, { |
139 | { | ||
140 | .id = V4L2_CID_ROTATE, | 155 | .id = V4L2_CID_ROTATE, |
141 | .type = V4L2_CTRL_TYPE_INTEGER, | 156 | .type = V4L2_CTRL_TYPE_INTEGER, |
142 | .name = "Rotation (CCW)", | 157 | .name = "Rotation (CCW)", |
@@ -158,7 +173,7 @@ static struct v4l2_queryctrl *get_ctrl(int id) | |||
158 | return NULL; | 173 | return NULL; |
159 | } | 174 | } |
160 | 175 | ||
161 | static int fimc_check_scaler_ratio(struct v4l2_rect *r, struct fimc_frame *f) | 176 | int fimc_check_scaler_ratio(struct v4l2_rect *r, struct fimc_frame *f) |
162 | { | 177 | { |
163 | if (r->width > f->width) { | 178 | if (r->width > f->width) { |
164 | if (f->width > (r->width * SCALER_MAX_HRATIO)) | 179 | if (f->width > (r->width * SCALER_MAX_HRATIO)) |
@@ -181,32 +196,27 @@ static int fimc_check_scaler_ratio(struct v4l2_rect *r, struct fimc_frame *f) | |||
181 | 196 | ||
182 | static int fimc_get_scaler_factor(u32 src, u32 tar, u32 *ratio, u32 *shift) | 197 | static int fimc_get_scaler_factor(u32 src, u32 tar, u32 *ratio, u32 *shift) |
183 | { | 198 | { |
184 | if (src >= tar * 64) { | 199 | u32 sh = 6; |
200 | |||
201 | if (src >= 64 * tar) | ||
185 | return -EINVAL; | 202 | return -EINVAL; |
186 | } else if (src >= tar * 32) { | 203 | |
187 | *ratio = 32; | 204 | while (sh--) { |
188 | *shift = 5; | 205 | u32 tmp = 1 << sh; |
189 | } else if (src >= tar * 16) { | 206 | if (src >= tar * tmp) { |
190 | *ratio = 16; | 207 | *shift = sh, *ratio = tmp; |
191 | *shift = 4; | 208 | return 0; |
192 | } else if (src >= tar * 8) { | 209 | } |
193 | *ratio = 8; | ||
194 | *shift = 3; | ||
195 | } else if (src >= tar * 4) { | ||
196 | *ratio = 4; | ||
197 | *shift = 2; | ||
198 | } else if (src >= tar * 2) { | ||
199 | *ratio = 2; | ||
200 | *shift = 1; | ||
201 | } else { | ||
202 | *ratio = 1; | ||
203 | *shift = 0; | ||
204 | } | 210 | } |
205 | 211 | ||
212 | *shift = 0, *ratio = 1; | ||
213 | |||
214 | dbg("s: %d, t: %d, shift: %d, ratio: %d", | ||
215 | src, tar, *shift, *ratio); | ||
206 | return 0; | 216 | return 0; |
207 | } | 217 | } |
208 | 218 | ||
209 | static int fimc_set_scaler_info(struct fimc_ctx *ctx) | 219 | int fimc_set_scaler_info(struct fimc_ctx *ctx) |
210 | { | 220 | { |
211 | struct fimc_scaler *sc = &ctx->scaler; | 221 | struct fimc_scaler *sc = &ctx->scaler; |
212 | struct fimc_frame *s_frame = &ctx->s_frame; | 222 | struct fimc_frame *s_frame = &ctx->s_frame; |
@@ -214,8 +224,13 @@ static int fimc_set_scaler_info(struct fimc_ctx *ctx) | |||
214 | int tx, ty, sx, sy; | 224 | int tx, ty, sx, sy; |
215 | int ret; | 225 | int ret; |
216 | 226 | ||
217 | tx = d_frame->width; | 227 | if (ctx->rotation == 90 || ctx->rotation == 270) { |
218 | ty = d_frame->height; | 228 | ty = d_frame->width; |
229 | tx = d_frame->height; | ||
230 | } else { | ||
231 | tx = d_frame->width; | ||
232 | ty = d_frame->height; | ||
233 | } | ||
219 | if (tx <= 0 || ty <= 0) { | 234 | if (tx <= 0 || ty <= 0) { |
220 | v4l2_err(&ctx->fimc_dev->m2m.v4l2_dev, | 235 | v4l2_err(&ctx->fimc_dev->m2m.v4l2_dev, |
221 | "invalid target size: %d x %d", tx, ty); | 236 | "invalid target size: %d x %d", tx, ty); |
@@ -261,12 +276,57 @@ static int fimc_set_scaler_info(struct fimc_ctx *ctx) | |||
261 | return 0; | 276 | return 0; |
262 | } | 277 | } |
263 | 278 | ||
279 | static void fimc_capture_handler(struct fimc_dev *fimc) | ||
280 | { | ||
281 | struct fimc_vid_cap *cap = &fimc->vid_cap; | ||
282 | struct fimc_vid_buffer *v_buf = NULL; | ||
283 | |||
284 | if (!list_empty(&cap->active_buf_q)) { | ||
285 | v_buf = active_queue_pop(cap); | ||
286 | fimc_buf_finish(fimc, v_buf); | ||
287 | } | ||
288 | |||
289 | if (test_and_clear_bit(ST_CAPT_SHUT, &fimc->state)) { | ||
290 | wake_up(&fimc->irq_queue); | ||
291 | return; | ||
292 | } | ||
293 | |||
294 | if (!list_empty(&cap->pending_buf_q)) { | ||
295 | |||
296 | v_buf = pending_queue_pop(cap); | ||
297 | fimc_hw_set_output_addr(fimc, &v_buf->paddr, cap->buf_index); | ||
298 | v_buf->index = cap->buf_index; | ||
299 | |||
300 | dbg("hw ptr: %d, sw ptr: %d", | ||
301 | fimc_hw_get_frame_index(fimc), cap->buf_index); | ||
302 | |||
303 | spin_lock(&fimc->irqlock); | ||
304 | v_buf->vb.state = VIDEOBUF_ACTIVE; | ||
305 | spin_unlock(&fimc->irqlock); | ||
306 | |||
307 | /* Move the buffer to the capture active queue */ | ||
308 | active_queue_add(cap, v_buf); | ||
309 | |||
310 | dbg("next frame: %d, done frame: %d", | ||
311 | fimc_hw_get_frame_index(fimc), v_buf->index); | ||
312 | |||
313 | if (++cap->buf_index >= FIMC_MAX_OUT_BUFS) | ||
314 | cap->buf_index = 0; | ||
315 | |||
316 | } else if (test_and_clear_bit(ST_CAPT_STREAM, &fimc->state) && | ||
317 | cap->active_buf_cnt <= 1) { | ||
318 | fimc_deactivate_capture(fimc); | ||
319 | } | ||
320 | |||
321 | dbg("frame: %d, active_buf_cnt= %d", | ||
322 | fimc_hw_get_frame_index(fimc), cap->active_buf_cnt); | ||
323 | } | ||
264 | 324 | ||
265 | static irqreturn_t fimc_isr(int irq, void *priv) | 325 | static irqreturn_t fimc_isr(int irq, void *priv) |
266 | { | 326 | { |
267 | struct fimc_vid_buffer *src_buf, *dst_buf; | 327 | struct fimc_vid_buffer *src_buf, *dst_buf; |
268 | struct fimc_dev *fimc = (struct fimc_dev *)priv; | ||
269 | struct fimc_ctx *ctx; | 328 | struct fimc_ctx *ctx; |
329 | struct fimc_dev *fimc = priv; | ||
270 | 330 | ||
271 | BUG_ON(!fimc); | 331 | BUG_ON(!fimc); |
272 | fimc_hw_clear_irq(fimc); | 332 | fimc_hw_clear_irq(fimc); |
@@ -281,12 +341,22 @@ static irqreturn_t fimc_isr(int irq, void *priv) | |||
281 | dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); | 341 | dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); |
282 | if (src_buf && dst_buf) { | 342 | if (src_buf && dst_buf) { |
283 | spin_lock(&fimc->irqlock); | 343 | spin_lock(&fimc->irqlock); |
284 | src_buf->vb.state = dst_buf->vb.state = VIDEOBUF_DONE; | 344 | src_buf->vb.state = dst_buf->vb.state = VIDEOBUF_DONE; |
285 | wake_up(&src_buf->vb.done); | 345 | wake_up(&src_buf->vb.done); |
286 | wake_up(&dst_buf->vb.done); | 346 | wake_up(&dst_buf->vb.done); |
287 | spin_unlock(&fimc->irqlock); | 347 | spin_unlock(&fimc->irqlock); |
288 | v4l2_m2m_job_finish(fimc->m2m.m2m_dev, ctx->m2m_ctx); | 348 | v4l2_m2m_job_finish(fimc->m2m.m2m_dev, ctx->m2m_ctx); |
289 | } | 349 | } |
350 | goto isr_unlock; | ||
351 | |||
352 | } | ||
353 | |||
354 | if (test_bit(ST_CAPT_RUN, &fimc->state)) | ||
355 | fimc_capture_handler(fimc); | ||
356 | |||
357 | if (test_and_clear_bit(ST_CAPT_PEND, &fimc->state)) { | ||
358 | set_bit(ST_CAPT_RUN, &fimc->state); | ||
359 | wake_up(&fimc->irq_queue); | ||
290 | } | 360 | } |
291 | 361 | ||
292 | isr_unlock: | 362 | isr_unlock: |
@@ -295,20 +365,13 @@ isr_unlock: | |||
295 | } | 365 | } |
296 | 366 | ||
297 | /* The color format (planes_cnt, buff_cnt) must be already configured. */ | 367 | /* The color format (planes_cnt, buff_cnt) must be already configured. */ |
298 | static int fimc_prepare_addr(struct fimc_ctx *ctx, | 368 | int fimc_prepare_addr(struct fimc_ctx *ctx, struct fimc_vid_buffer *buf, |
299 | struct fimc_vid_buffer *buf, enum v4l2_buf_type type) | 369 | struct fimc_frame *frame, struct fimc_addr *paddr) |
300 | { | 370 | { |
301 | struct fimc_frame *frame; | ||
302 | struct fimc_addr *paddr; | ||
303 | u32 pix_size; | ||
304 | int ret = 0; | 371 | int ret = 0; |
372 | u32 pix_size; | ||
305 | 373 | ||
306 | frame = ctx_m2m_get_frame(ctx, type); | 374 | if (buf == NULL || frame == NULL) |
307 | if (IS_ERR(frame)) | ||
308 | return PTR_ERR(frame); | ||
309 | paddr = &frame->paddr; | ||
310 | |||
311 | if (!buf) | ||
312 | return -EINVAL; | 375 | return -EINVAL; |
313 | 376 | ||
314 | pix_size = frame->width * frame->height; | 377 | pix_size = frame->width * frame->height; |
@@ -344,8 +407,8 @@ static int fimc_prepare_addr(struct fimc_ctx *ctx, | |||
344 | } | 407 | } |
345 | } | 408 | } |
346 | 409 | ||
347 | dbg("PHYS_ADDR: type= %d, y= 0x%X cb= 0x%X cr= 0x%X ret= %d", | 410 | dbg("PHYS_ADDR: y= 0x%X cb= 0x%X cr= 0x%X ret= %d", |
348 | type, paddr->y, paddr->cb, paddr->cr, ret); | 411 | paddr->y, paddr->cb, paddr->cr, ret); |
349 | 412 | ||
350 | return ret; | 413 | return ret; |
351 | } | 414 | } |
@@ -433,7 +496,7 @@ static void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f) | |||
433 | * | 496 | * |
434 | * Return: 0 if dimensions are valid or non zero otherwise. | 497 | * Return: 0 if dimensions are valid or non zero otherwise. |
435 | */ | 498 | */ |
436 | static int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags) | 499 | int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags) |
437 | { | 500 | { |
438 | struct fimc_frame *s_frame, *d_frame; | 501 | struct fimc_frame *s_frame, *d_frame; |
439 | struct fimc_vid_buffer *buf = NULL; | 502 | struct fimc_vid_buffer *buf = NULL; |
@@ -443,12 +506,6 @@ static int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags) | |||
443 | d_frame = &ctx->d_frame; | 506 | d_frame = &ctx->d_frame; |
444 | 507 | ||
445 | if (flags & FIMC_PARAMS) { | 508 | if (flags & FIMC_PARAMS) { |
446 | if ((ctx->out_path == FIMC_DMA) && | ||
447 | (ctx->rotation == 90 || ctx->rotation == 270)) { | ||
448 | swap(d_frame->f_width, d_frame->f_height); | ||
449 | swap(d_frame->width, d_frame->height); | ||
450 | } | ||
451 | |||
452 | /* Prepare the DMA offset ratios for scaler. */ | 509 | /* Prepare the DMA offset ratios for scaler. */ |
453 | fimc_prepare_dma_offset(ctx, &ctx->s_frame); | 510 | fimc_prepare_dma_offset(ctx, &ctx->s_frame); |
454 | fimc_prepare_dma_offset(ctx, &ctx->d_frame); | 511 | fimc_prepare_dma_offset(ctx, &ctx->d_frame); |
@@ -466,16 +523,14 @@ static int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags) | |||
466 | 523 | ||
467 | if (flags & FIMC_SRC_ADDR) { | 524 | if (flags & FIMC_SRC_ADDR) { |
468 | buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx); | 525 | buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx); |
469 | ret = fimc_prepare_addr(ctx, buf, | 526 | ret = fimc_prepare_addr(ctx, buf, s_frame, &s_frame->paddr); |
470 | V4L2_BUF_TYPE_VIDEO_OUTPUT); | ||
471 | if (ret) | 527 | if (ret) |
472 | return ret; | 528 | return ret; |
473 | } | 529 | } |
474 | 530 | ||
475 | if (flags & FIMC_DST_ADDR) { | 531 | if (flags & FIMC_DST_ADDR) { |
476 | buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); | 532 | buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); |
477 | ret = fimc_prepare_addr(ctx, buf, | 533 | ret = fimc_prepare_addr(ctx, buf, d_frame, &d_frame->paddr); |
478 | V4L2_BUF_TYPE_VIDEO_CAPTURE); | ||
479 | } | 534 | } |
480 | 535 | ||
481 | return ret; | 536 | return ret; |
@@ -499,12 +554,14 @@ static void fimc_dma_run(void *priv) | |||
499 | ctx->state |= (FIMC_SRC_ADDR | FIMC_DST_ADDR); | 554 | ctx->state |= (FIMC_SRC_ADDR | FIMC_DST_ADDR); |
500 | ret = fimc_prepare_config(ctx, ctx->state); | 555 | ret = fimc_prepare_config(ctx, ctx->state); |
501 | if (ret) { | 556 | if (ret) { |
502 | err("general configuration error"); | 557 | err("Wrong parameters"); |
503 | goto dma_unlock; | 558 | goto dma_unlock; |
504 | } | 559 | } |
505 | 560 | /* Reconfigure hardware if the context has changed. */ | |
506 | if (fimc->m2m.ctx != ctx) | 561 | if (fimc->m2m.ctx != ctx) { |
507 | ctx->state |= FIMC_PARAMS; | 562 | ctx->state |= FIMC_PARAMS; |
563 | fimc->m2m.ctx = ctx; | ||
564 | } | ||
508 | 565 | ||
509 | fimc_hw_set_input_addr(fimc, &ctx->s_frame.paddr); | 566 | fimc_hw_set_input_addr(fimc, &ctx->s_frame.paddr); |
510 | 567 | ||
@@ -512,10 +569,9 @@ static void fimc_dma_run(void *priv) | |||
512 | fimc_hw_set_input_path(ctx); | 569 | fimc_hw_set_input_path(ctx); |
513 | fimc_hw_set_in_dma(ctx); | 570 | fimc_hw_set_in_dma(ctx); |
514 | if (fimc_set_scaler_info(ctx)) { | 571 | if (fimc_set_scaler_info(ctx)) { |
515 | err("scaler configuration error"); | 572 | err("Scaler setup error"); |
516 | goto dma_unlock; | 573 | goto dma_unlock; |
517 | } | 574 | } |
518 | fimc_hw_set_prescaler(ctx); | ||
519 | fimc_hw_set_scaler(ctx); | 575 | fimc_hw_set_scaler(ctx); |
520 | fimc_hw_set_target_format(ctx); | 576 | fimc_hw_set_target_format(ctx); |
521 | fimc_hw_set_rotation(ctx); | 577 | fimc_hw_set_rotation(ctx); |
@@ -524,19 +580,15 @@ static void fimc_dma_run(void *priv) | |||
524 | 580 | ||
525 | fimc_hw_set_output_path(ctx); | 581 | fimc_hw_set_output_path(ctx); |
526 | if (ctx->state & (FIMC_DST_ADDR | FIMC_PARAMS)) | 582 | if (ctx->state & (FIMC_DST_ADDR | FIMC_PARAMS)) |
527 | fimc_hw_set_output_addr(fimc, &ctx->d_frame.paddr); | 583 | fimc_hw_set_output_addr(fimc, &ctx->d_frame.paddr, -1); |
528 | 584 | ||
529 | if (ctx->state & FIMC_PARAMS) | 585 | if (ctx->state & FIMC_PARAMS) |
530 | fimc_hw_set_out_dma(ctx); | 586 | fimc_hw_set_out_dma(ctx); |
531 | 587 | ||
532 | if (ctx->scaler.enabled) | 588 | fimc_activate_capture(ctx); |
533 | fimc_hw_start_scaler(fimc); | ||
534 | fimc_hw_en_capture(ctx); | ||
535 | 589 | ||
536 | ctx->state = 0; | 590 | ctx->state &= (FIMC_CTX_M2M | FIMC_CTX_CAP); |
537 | fimc_hw_start_in_dma(fimc); | 591 | fimc_hw_activate_input_dma(fimc, true); |
538 | |||
539 | fimc->m2m.ctx = ctx; | ||
540 | 592 | ||
541 | dma_unlock: | 593 | dma_unlock: |
542 | spin_unlock_irqrestore(&ctx->slock, flags); | 594 | spin_unlock_irqrestore(&ctx->slock, flags); |
@@ -560,7 +612,7 @@ static int fimc_buf_setup(struct videobuf_queue *vq, unsigned int *count, | |||
560 | struct fimc_ctx *ctx = vq->priv_data; | 612 | struct fimc_ctx *ctx = vq->priv_data; |
561 | struct fimc_frame *frame; | 613 | struct fimc_frame *frame; |
562 | 614 | ||
563 | frame = ctx_m2m_get_frame(ctx, vq->type); | 615 | frame = ctx_get_frame(ctx, vq->type); |
564 | if (IS_ERR(frame)) | 616 | if (IS_ERR(frame)) |
565 | return PTR_ERR(frame); | 617 | return PTR_ERR(frame); |
566 | 618 | ||
@@ -578,7 +630,7 @@ static int fimc_buf_prepare(struct videobuf_queue *vq, | |||
578 | struct fimc_frame *frame; | 630 | struct fimc_frame *frame; |
579 | int ret; | 631 | int ret; |
580 | 632 | ||
581 | frame = ctx_m2m_get_frame(ctx, vq->type); | 633 | frame = ctx_get_frame(ctx, vq->type); |
582 | if (IS_ERR(frame)) | 634 | if (IS_ERR(frame)) |
583 | return PTR_ERR(frame); | 635 | return PTR_ERR(frame); |
584 | 636 | ||
@@ -618,10 +670,31 @@ static void fimc_buf_queue(struct videobuf_queue *vq, | |||
618 | struct videobuf_buffer *vb) | 670 | struct videobuf_buffer *vb) |
619 | { | 671 | { |
620 | struct fimc_ctx *ctx = vq->priv_data; | 672 | struct fimc_ctx *ctx = vq->priv_data; |
621 | v4l2_m2m_buf_queue(ctx->m2m_ctx, vq, vb); | 673 | struct fimc_dev *fimc = ctx->fimc_dev; |
674 | struct fimc_vid_cap *cap = &fimc->vid_cap; | ||
675 | unsigned long flags; | ||
676 | |||
677 | dbg("ctx: %p, ctx->state: 0x%x", ctx, ctx->state); | ||
678 | |||
679 | if ((ctx->state & FIMC_CTX_M2M) && ctx->m2m_ctx) { | ||
680 | v4l2_m2m_buf_queue(ctx->m2m_ctx, vq, vb); | ||
681 | } else if (ctx->state & FIMC_CTX_CAP) { | ||
682 | spin_lock_irqsave(&fimc->slock, flags); | ||
683 | fimc_vid_cap_buf_queue(fimc, (struct fimc_vid_buffer *)vb); | ||
684 | |||
685 | dbg("fimc->cap.active_buf_cnt: %d", | ||
686 | fimc->vid_cap.active_buf_cnt); | ||
687 | |||
688 | if (cap->active_buf_cnt >= cap->reqbufs_count || | ||
689 | cap->active_buf_cnt >= FIMC_MAX_OUT_BUFS) { | ||
690 | if (!test_and_set_bit(ST_CAPT_STREAM, &fimc->state)) | ||
691 | fimc_activate_capture(ctx); | ||
692 | } | ||
693 | spin_unlock_irqrestore(&fimc->slock, flags); | ||
694 | } | ||
622 | } | 695 | } |
623 | 696 | ||
624 | static struct videobuf_queue_ops fimc_qops = { | 697 | struct videobuf_queue_ops fimc_qops = { |
625 | .buf_setup = fimc_buf_setup, | 698 | .buf_setup = fimc_buf_setup, |
626 | .buf_prepare = fimc_buf_prepare, | 699 | .buf_prepare = fimc_buf_prepare, |
627 | .buf_queue = fimc_buf_queue, | 700 | .buf_queue = fimc_buf_queue, |
@@ -644,7 +717,7 @@ static int fimc_m2m_querycap(struct file *file, void *priv, | |||
644 | return 0; | 717 | return 0; |
645 | } | 718 | } |
646 | 719 | ||
647 | static int fimc_m2m_enum_fmt(struct file *file, void *priv, | 720 | int fimc_vidioc_enum_fmt(struct file *file, void *priv, |
648 | struct v4l2_fmtdesc *f) | 721 | struct v4l2_fmtdesc *f) |
649 | { | 722 | { |
650 | struct fimc_fmt *fmt; | 723 | struct fimc_fmt *fmt; |
@@ -655,189 +728,210 @@ static int fimc_m2m_enum_fmt(struct file *file, void *priv, | |||
655 | fmt = &fimc_formats[f->index]; | 728 | fmt = &fimc_formats[f->index]; |
656 | strncpy(f->description, fmt->name, sizeof(f->description) - 1); | 729 | strncpy(f->description, fmt->name, sizeof(f->description) - 1); |
657 | f->pixelformat = fmt->fourcc; | 730 | f->pixelformat = fmt->fourcc; |
731 | |||
658 | return 0; | 732 | return 0; |
659 | } | 733 | } |
660 | 734 | ||
661 | static int fimc_m2m_g_fmt(struct file *file, void *priv, struct v4l2_format *f) | 735 | int fimc_vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) |
662 | { | 736 | { |
663 | struct fimc_ctx *ctx = priv; | 737 | struct fimc_ctx *ctx = priv; |
738 | struct fimc_dev *fimc = ctx->fimc_dev; | ||
664 | struct fimc_frame *frame; | 739 | struct fimc_frame *frame; |
665 | 740 | ||
666 | frame = ctx_m2m_get_frame(ctx, f->type); | 741 | frame = ctx_get_frame(ctx, f->type); |
667 | if (IS_ERR(frame)) | 742 | if (IS_ERR(frame)) |
668 | return PTR_ERR(frame); | 743 | return PTR_ERR(frame); |
669 | 744 | ||
745 | if (mutex_lock_interruptible(&fimc->lock)) | ||
746 | return -ERESTARTSYS; | ||
747 | |||
670 | f->fmt.pix.width = frame->width; | 748 | f->fmt.pix.width = frame->width; |
671 | f->fmt.pix.height = frame->height; | 749 | f->fmt.pix.height = frame->height; |
672 | f->fmt.pix.field = V4L2_FIELD_NONE; | 750 | f->fmt.pix.field = V4L2_FIELD_NONE; |
673 | f->fmt.pix.pixelformat = frame->fmt->fourcc; | 751 | f->fmt.pix.pixelformat = frame->fmt->fourcc; |
674 | 752 | ||
753 | mutex_unlock(&fimc->lock); | ||
675 | return 0; | 754 | return 0; |
676 | } | 755 | } |
677 | 756 | ||
678 | static struct fimc_fmt *find_format(struct v4l2_format *f) | 757 | struct fimc_fmt *find_format(struct v4l2_format *f, unsigned int mask) |
679 | { | 758 | { |
680 | struct fimc_fmt *fmt; | 759 | struct fimc_fmt *fmt; |
681 | unsigned int i; | 760 | unsigned int i; |
682 | 761 | ||
683 | for (i = 0; i < ARRAY_SIZE(fimc_formats); ++i) { | 762 | for (i = 0; i < ARRAY_SIZE(fimc_formats); ++i) { |
684 | fmt = &fimc_formats[i]; | 763 | fmt = &fimc_formats[i]; |
685 | if (fmt->fourcc == f->fmt.pix.pixelformat) | 764 | if (fmt->fourcc == f->fmt.pix.pixelformat && |
765 | (fmt->flags & mask)) | ||
686 | break; | 766 | break; |
687 | } | 767 | } |
688 | if (i == ARRAY_SIZE(fimc_formats)) | ||
689 | return NULL; | ||
690 | 768 | ||
691 | return fmt; | 769 | return (i == ARRAY_SIZE(fimc_formats)) ? NULL : fmt; |
692 | } | 770 | } |
693 | 771 | ||
694 | static int fimc_m2m_try_fmt(struct file *file, void *priv, | 772 | struct fimc_fmt *find_mbus_format(struct v4l2_mbus_framefmt *f, |
695 | struct v4l2_format *f) | 773 | unsigned int mask) |
696 | { | 774 | { |
697 | struct fimc_fmt *fmt; | 775 | struct fimc_fmt *fmt; |
698 | u32 max_width, max_height, mod_x, mod_y; | 776 | unsigned int i; |
777 | |||
778 | for (i = 0; i < ARRAY_SIZE(fimc_formats); ++i) { | ||
779 | fmt = &fimc_formats[i]; | ||
780 | if (fmt->mbus_code == f->code && (fmt->flags & mask)) | ||
781 | break; | ||
782 | } | ||
783 | |||
784 | return (i == ARRAY_SIZE(fimc_formats)) ? NULL : fmt; | ||
785 | } | ||
786 | |||
787 | |||
788 | int fimc_vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f) | ||
789 | { | ||
699 | struct fimc_ctx *ctx = priv; | 790 | struct fimc_ctx *ctx = priv; |
700 | struct fimc_dev *fimc = ctx->fimc_dev; | 791 | struct fimc_dev *fimc = ctx->fimc_dev; |
701 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
702 | struct samsung_fimc_variant *variant = fimc->variant; | 792 | struct samsung_fimc_variant *variant = fimc->variant; |
793 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
794 | struct fimc_fmt *fmt; | ||
795 | u32 max_width, mod_x, mod_y, mask; | ||
796 | int ret = -EINVAL, is_output = 0; | ||
703 | 797 | ||
704 | fmt = find_format(f); | 798 | if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { |
705 | if (!fmt) { | 799 | if (ctx->state & FIMC_CTX_CAP) |
706 | v4l2_err(&fimc->m2m.v4l2_dev, | 800 | return -EINVAL; |
707 | "Fourcc format (0x%X) invalid.\n", pix->pixelformat); | 801 | is_output = 1; |
802 | } else if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { | ||
708 | return -EINVAL; | 803 | return -EINVAL; |
709 | } | 804 | } |
710 | 805 | ||
806 | dbg("w: %d, h: %d, bpl: %d", | ||
807 | pix->width, pix->height, pix->bytesperline); | ||
808 | |||
809 | if (mutex_lock_interruptible(&fimc->lock)) | ||
810 | return -ERESTARTSYS; | ||
811 | |||
812 | mask = is_output ? FMT_FLAGS_M2M : FMT_FLAGS_M2M | FMT_FLAGS_CAM; | ||
813 | fmt = find_format(f, mask); | ||
814 | if (!fmt) { | ||
815 | v4l2_err(&fimc->m2m.v4l2_dev, "Fourcc format (0x%X) invalid.\n", | ||
816 | pix->pixelformat); | ||
817 | goto tf_out; | ||
818 | } | ||
819 | |||
711 | if (pix->field == V4L2_FIELD_ANY) | 820 | if (pix->field == V4L2_FIELD_ANY) |
712 | pix->field = V4L2_FIELD_NONE; | 821 | pix->field = V4L2_FIELD_NONE; |
713 | else if (V4L2_FIELD_NONE != pix->field) | 822 | else if (V4L2_FIELD_NONE != pix->field) |
714 | return -EINVAL; | 823 | goto tf_out; |
715 | 824 | ||
716 | if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { | 825 | if (is_output) { |
717 | max_width = variant->scaler_dis_w; | 826 | max_width = variant->pix_limit->scaler_dis_w; |
718 | max_height = variant->scaler_dis_w; | 827 | mod_x = ffs(variant->min_inp_pixsize) - 1; |
719 | mod_x = variant->min_inp_pixsize; | ||
720 | mod_y = variant->min_inp_pixsize; | ||
721 | } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { | ||
722 | max_width = variant->out_rot_dis_w; | ||
723 | max_height = variant->out_rot_dis_w; | ||
724 | mod_x = variant->min_out_pixsize; | ||
725 | mod_y = variant->min_out_pixsize; | ||
726 | } else { | 828 | } else { |
727 | err("Wrong stream type (%d)", f->type); | 829 | max_width = variant->pix_limit->out_rot_dis_w; |
728 | return -EINVAL; | 830 | mod_x = ffs(variant->min_out_pixsize) - 1; |
729 | } | 831 | } |
730 | 832 | ||
731 | dbg("max_w= %d, max_h= %d", max_width, max_height); | ||
732 | |||
733 | if (pix->height > max_height) | ||
734 | pix->height = max_height; | ||
735 | if (pix->width > max_width) | ||
736 | pix->width = max_width; | ||
737 | |||
738 | if (tiled_fmt(fmt)) { | 833 | if (tiled_fmt(fmt)) { |
739 | mod_x = 64; /* 64x32 tile */ | 834 | mod_x = 6; /* 64 x 32 pixels tile */ |
740 | mod_y = 32; | 835 | mod_y = 5; |
836 | } else { | ||
837 | if (fimc->id == 1 && fimc->variant->pix_hoff) | ||
838 | mod_y = fimc_fmt_is_rgb(fmt->color) ? 0 : 1; | ||
839 | else | ||
840 | mod_y = mod_x; | ||
741 | } | 841 | } |
742 | 842 | ||
743 | dbg("mod_x= 0x%X, mod_y= 0x%X", mod_x, mod_y); | 843 | dbg("mod_x: %d, mod_y: %d, max_w: %d", mod_x, mod_y, max_width); |
744 | 844 | ||
745 | pix->width = (pix->width == 0) ? mod_x : ALIGN(pix->width, mod_x); | 845 | v4l_bound_align_image(&pix->width, 16, max_width, mod_x, |
746 | pix->height = (pix->height == 0) ? mod_y : ALIGN(pix->height, mod_y); | 846 | &pix->height, 8, variant->pix_limit->scaler_dis_w, mod_y, 0); |
747 | 847 | ||
748 | if (pix->bytesperline == 0 || | 848 | if (pix->bytesperline == 0 || |
749 | pix->bytesperline * 8 / fmt->depth > pix->width) | 849 | (pix->bytesperline * 8 / fmt->depth) > pix->width) |
750 | pix->bytesperline = (pix->width * fmt->depth) >> 3; | 850 | pix->bytesperline = (pix->width * fmt->depth) >> 3; |
751 | 851 | ||
752 | if (pix->sizeimage == 0) | 852 | if (pix->sizeimage == 0) |
753 | pix->sizeimage = pix->height * pix->bytesperline; | 853 | pix->sizeimage = pix->height * pix->bytesperline; |
754 | 854 | ||
755 | dbg("pix->bytesperline= %d, fmt->depth= %d", | 855 | dbg("w: %d, h: %d, bpl: %d, depth: %d", |
756 | pix->bytesperline, fmt->depth); | 856 | pix->width, pix->height, pix->bytesperline, fmt->depth); |
757 | 857 | ||
758 | return 0; | 858 | ret = 0; |
759 | } | ||
760 | 859 | ||
860 | tf_out: | ||
861 | mutex_unlock(&fimc->lock); | ||
862 | return ret; | ||
863 | } | ||
761 | 864 | ||
762 | static int fimc_m2m_s_fmt(struct file *file, void *priv, struct v4l2_format *f) | 865 | static int fimc_m2m_s_fmt(struct file *file, void *priv, struct v4l2_format *f) |
763 | { | 866 | { |
764 | struct fimc_ctx *ctx = priv; | 867 | struct fimc_ctx *ctx = priv; |
765 | struct v4l2_device *v4l2_dev = &ctx->fimc_dev->m2m.v4l2_dev; | 868 | struct fimc_dev *fimc = ctx->fimc_dev; |
766 | struct videobuf_queue *src_vq, *dst_vq; | 869 | struct v4l2_device *v4l2_dev = &fimc->m2m.v4l2_dev; |
870 | struct videobuf_queue *vq; | ||
767 | struct fimc_frame *frame; | 871 | struct fimc_frame *frame; |
768 | struct v4l2_pix_format *pix; | 872 | struct v4l2_pix_format *pix; |
769 | unsigned long flags; | 873 | unsigned long flags; |
770 | int ret = 0; | 874 | int ret = 0; |
771 | 875 | ||
772 | BUG_ON(!ctx); | 876 | ret = fimc_vidioc_try_fmt(file, priv, f); |
773 | |||
774 | ret = fimc_m2m_try_fmt(file, priv, f); | ||
775 | if (ret) | 877 | if (ret) |
776 | return ret; | 878 | return ret; |
777 | 879 | ||
778 | mutex_lock(&ctx->fimc_dev->lock); | 880 | if (mutex_lock_interruptible(&fimc->lock)) |
881 | return -ERESTARTSYS; | ||
779 | 882 | ||
780 | src_vq = v4l2_m2m_get_src_vq(ctx->m2m_ctx); | 883 | vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); |
781 | dst_vq = v4l2_m2m_get_dst_vq(ctx->m2m_ctx); | 884 | mutex_lock(&vq->vb_lock); |
782 | 885 | ||
783 | mutex_lock(&src_vq->vb_lock); | 886 | if (videobuf_queue_is_busy(vq)) { |
784 | mutex_lock(&dst_vq->vb_lock); | 887 | v4l2_err(v4l2_dev, "%s: queue (%d) busy\n", __func__, f->type); |
888 | ret = -EBUSY; | ||
889 | goto sf_out; | ||
890 | } | ||
785 | 891 | ||
892 | spin_lock_irqsave(&ctx->slock, flags); | ||
786 | if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { | 893 | if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { |
787 | if (videobuf_queue_is_busy(src_vq)) { | ||
788 | v4l2_err(v4l2_dev, "%s queue busy\n", __func__); | ||
789 | ret = -EBUSY; | ||
790 | goto s_fmt_out; | ||
791 | } | ||
792 | frame = &ctx->s_frame; | 894 | frame = &ctx->s_frame; |
793 | spin_lock_irqsave(&ctx->slock, flags); | ||
794 | ctx->state |= FIMC_SRC_FMT; | 895 | ctx->state |= FIMC_SRC_FMT; |
795 | spin_unlock_irqrestore(&ctx->slock, flags); | ||
796 | |||
797 | } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { | 896 | } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { |
798 | if (videobuf_queue_is_busy(dst_vq)) { | ||
799 | v4l2_err(v4l2_dev, "%s queue busy\n", __func__); | ||
800 | ret = -EBUSY; | ||
801 | goto s_fmt_out; | ||
802 | } | ||
803 | frame = &ctx->d_frame; | 897 | frame = &ctx->d_frame; |
804 | spin_lock_irqsave(&ctx->slock, flags); | ||
805 | ctx->state |= FIMC_DST_FMT; | 898 | ctx->state |= FIMC_DST_FMT; |
806 | spin_unlock_irqrestore(&ctx->slock, flags); | ||
807 | } else { | 899 | } else { |
900 | spin_unlock_irqrestore(&ctx->slock, flags); | ||
808 | v4l2_err(&ctx->fimc_dev->m2m.v4l2_dev, | 901 | v4l2_err(&ctx->fimc_dev->m2m.v4l2_dev, |
809 | "Wrong buffer/video queue type (%d)\n", f->type); | 902 | "Wrong buffer/video queue type (%d)\n", f->type); |
810 | ret = -EINVAL; | 903 | ret = -EINVAL; |
811 | goto s_fmt_out; | 904 | goto sf_out; |
812 | } | 905 | } |
906 | spin_unlock_irqrestore(&ctx->slock, flags); | ||
813 | 907 | ||
814 | pix = &f->fmt.pix; | 908 | pix = &f->fmt.pix; |
815 | frame->fmt = find_format(f); | 909 | frame->fmt = find_format(f, FMT_FLAGS_M2M); |
816 | if (!frame->fmt) { | 910 | if (!frame->fmt) { |
817 | ret = -EINVAL; | 911 | ret = -EINVAL; |
818 | goto s_fmt_out; | 912 | goto sf_out; |
819 | } | 913 | } |
820 | 914 | ||
821 | frame->f_width = pix->bytesperline * 8 / frame->fmt->depth; | 915 | frame->f_width = pix->bytesperline * 8 / frame->fmt->depth; |
822 | frame->f_height = pix->sizeimage/pix->bytesperline; | 916 | frame->f_height = pix->height; |
823 | frame->width = pix->width; | 917 | frame->width = pix->width; |
824 | frame->height = pix->height; | 918 | frame->height = pix->height; |
825 | frame->o_width = pix->width; | 919 | frame->o_width = pix->width; |
826 | frame->o_height = pix->height; | 920 | frame->o_height = pix->height; |
827 | frame->offs_h = 0; | 921 | frame->offs_h = 0; |
828 | frame->offs_v = 0; | 922 | frame->offs_v = 0; |
829 | frame->size = (pix->width * pix->height * frame->fmt->depth) >> 3; | 923 | frame->size = (pix->width * pix->height * frame->fmt->depth) >> 3; |
830 | src_vq->field = dst_vq->field = pix->field; | 924 | vq->field = pix->field; |
925 | |||
831 | spin_lock_irqsave(&ctx->slock, flags); | 926 | spin_lock_irqsave(&ctx->slock, flags); |
832 | ctx->state |= FIMC_PARAMS; | 927 | ctx->state |= FIMC_PARAMS; |
833 | spin_unlock_irqrestore(&ctx->slock, flags); | 928 | spin_unlock_irqrestore(&ctx->slock, flags); |
834 | 929 | ||
835 | dbg("f_width= %d, f_height= %d", frame->f_width, frame->f_height); | 930 | dbg("f_w: %d, f_h: %d", frame->f_width, frame->f_height); |
836 | 931 | ||
837 | s_fmt_out: | 932 | sf_out: |
838 | mutex_unlock(&dst_vq->vb_lock); | 933 | mutex_unlock(&vq->vb_lock); |
839 | mutex_unlock(&src_vq->vb_lock); | 934 | mutex_unlock(&fimc->lock); |
840 | mutex_unlock(&ctx->fimc_dev->lock); | ||
841 | return ret; | 935 | return ret; |
842 | } | 936 | } |
843 | 937 | ||
@@ -884,21 +978,33 @@ static int fimc_m2m_streamoff(struct file *file, void *priv, | |||
884 | return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); | 978 | return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); |
885 | } | 979 | } |
886 | 980 | ||
887 | int fimc_m2m_queryctrl(struct file *file, void *priv, | 981 | int fimc_vidioc_queryctrl(struct file *file, void *priv, |
888 | struct v4l2_queryctrl *qc) | 982 | struct v4l2_queryctrl *qc) |
889 | { | 983 | { |
984 | struct fimc_ctx *ctx = priv; | ||
890 | struct v4l2_queryctrl *c; | 985 | struct v4l2_queryctrl *c; |
986 | |||
891 | c = get_ctrl(qc->id); | 987 | c = get_ctrl(qc->id); |
892 | if (!c) | 988 | if (c) { |
893 | return -EINVAL; | 989 | *qc = *c; |
894 | *qc = *c; | 990 | return 0; |
895 | return 0; | 991 | } |
992 | |||
993 | if (ctx->state & FIMC_CTX_CAP) | ||
994 | return v4l2_subdev_call(ctx->fimc_dev->vid_cap.sd, | ||
995 | core, queryctrl, qc); | ||
996 | return -EINVAL; | ||
896 | } | 997 | } |
897 | 998 | ||
898 | int fimc_m2m_g_ctrl(struct file *file, void *priv, | 999 | int fimc_vidioc_g_ctrl(struct file *file, void *priv, |
899 | struct v4l2_control *ctrl) | 1000 | struct v4l2_control *ctrl) |
900 | { | 1001 | { |
901 | struct fimc_ctx *ctx = priv; | 1002 | struct fimc_ctx *ctx = priv; |
1003 | struct fimc_dev *fimc = ctx->fimc_dev; | ||
1004 | int ret = 0; | ||
1005 | |||
1006 | if (mutex_lock_interruptible(&fimc->lock)) | ||
1007 | return -ERESTARTSYS; | ||
902 | 1008 | ||
903 | switch (ctrl->id) { | 1009 | switch (ctrl->id) { |
904 | case V4L2_CID_HFLIP: | 1010 | case V4L2_CID_HFLIP: |
@@ -911,15 +1017,22 @@ int fimc_m2m_g_ctrl(struct file *file, void *priv, | |||
911 | ctrl->value = ctx->rotation; | 1017 | ctrl->value = ctx->rotation; |
912 | break; | 1018 | break; |
913 | default: | 1019 | default: |
914 | v4l2_err(&ctx->fimc_dev->m2m.v4l2_dev, "Invalid control\n"); | 1020 | if (ctx->state & FIMC_CTX_CAP) { |
915 | return -EINVAL; | 1021 | ret = v4l2_subdev_call(fimc->vid_cap.sd, core, |
1022 | g_ctrl, ctrl); | ||
1023 | } else { | ||
1024 | v4l2_err(&fimc->m2m.v4l2_dev, | ||
1025 | "Invalid control\n"); | ||
1026 | ret = -EINVAL; | ||
1027 | } | ||
916 | } | 1028 | } |
917 | dbg("ctrl->value= %d", ctrl->value); | 1029 | dbg("ctrl->value= %d", ctrl->value); |
918 | return 0; | 1030 | |
1031 | mutex_unlock(&fimc->lock); | ||
1032 | return ret; | ||
919 | } | 1033 | } |
920 | 1034 | ||
921 | static int check_ctrl_val(struct fimc_ctx *ctx, | 1035 | int check_ctrl_val(struct fimc_ctx *ctx, struct v4l2_control *ctrl) |
922 | struct v4l2_control *ctrl) | ||
923 | { | 1036 | { |
924 | struct v4l2_queryctrl *c; | 1037 | struct v4l2_queryctrl *c; |
925 | c = get_ctrl(ctrl->id); | 1038 | c = get_ctrl(ctrl->id); |
@@ -936,22 +1049,23 @@ static int check_ctrl_val(struct fimc_ctx *ctx, | |||
936 | return 0; | 1049 | return 0; |
937 | } | 1050 | } |
938 | 1051 | ||
939 | int fimc_m2m_s_ctrl(struct file *file, void *priv, | 1052 | int fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_control *ctrl) |
940 | struct v4l2_control *ctrl) | ||
941 | { | 1053 | { |
942 | struct fimc_ctx *ctx = priv; | ||
943 | struct samsung_fimc_variant *variant = ctx->fimc_dev->variant; | 1054 | struct samsung_fimc_variant *variant = ctx->fimc_dev->variant; |
1055 | struct fimc_dev *fimc = ctx->fimc_dev; | ||
944 | unsigned long flags; | 1056 | unsigned long flags; |
945 | int ret = 0; | ||
946 | 1057 | ||
947 | ret = check_ctrl_val(ctx, ctrl); | 1058 | if (ctx->rotation != 0 && |
948 | if (ret) | 1059 | (ctrl->id == V4L2_CID_HFLIP || ctrl->id == V4L2_CID_VFLIP)) { |
949 | return ret; | 1060 | v4l2_err(&fimc->m2m.v4l2_dev, |
1061 | "Simultaneous flip and rotation is not supported\n"); | ||
1062 | return -EINVAL; | ||
1063 | } | ||
1064 | |||
1065 | spin_lock_irqsave(&ctx->slock, flags); | ||
950 | 1066 | ||
951 | switch (ctrl->id) { | 1067 | switch (ctrl->id) { |
952 | case V4L2_CID_HFLIP: | 1068 | case V4L2_CID_HFLIP: |
953 | if (ctx->rotation != 0) | ||
954 | return 0; | ||
955 | if (ctrl->value) | 1069 | if (ctrl->value) |
956 | ctx->flip |= FLIP_X_AXIS; | 1070 | ctx->flip |= FLIP_X_AXIS; |
957 | else | 1071 | else |
@@ -959,8 +1073,6 @@ int fimc_m2m_s_ctrl(struct file *file, void *priv, | |||
959 | break; | 1073 | break; |
960 | 1074 | ||
961 | case V4L2_CID_VFLIP: | 1075 | case V4L2_CID_VFLIP: |
962 | if (ctx->rotation != 0) | ||
963 | return 0; | ||
964 | if (ctrl->value) | 1076 | if (ctrl->value) |
965 | ctx->flip |= FLIP_Y_AXIS; | 1077 | ctx->flip |= FLIP_Y_AXIS; |
966 | else | 1078 | else |
@@ -968,77 +1080,95 @@ int fimc_m2m_s_ctrl(struct file *file, void *priv, | |||
968 | break; | 1080 | break; |
969 | 1081 | ||
970 | case V4L2_CID_ROTATE: | 1082 | case V4L2_CID_ROTATE: |
971 | if (ctrl->value == 90 || ctrl->value == 270) { | 1083 | /* Check for the output rotator availability */ |
972 | if (ctx->out_path == FIMC_LCDFIFO && | 1084 | if ((ctrl->value == 90 || ctrl->value == 270) && |
973 | !variant->has_inp_rot) { | 1085 | (ctx->in_path == FIMC_DMA && !variant->has_out_rot)) { |
974 | return -EINVAL; | 1086 | spin_unlock_irqrestore(&ctx->slock, flags); |
975 | } else if (ctx->in_path == FIMC_DMA && | 1087 | return -EINVAL; |
976 | !variant->has_out_rot) { | 1088 | } else { |
977 | return -EINVAL; | 1089 | ctx->rotation = ctrl->value; |
978 | } | ||
979 | } | 1090 | } |
980 | ctx->rotation = ctrl->value; | ||
981 | if (ctrl->value == 180) | ||
982 | ctx->flip = FLIP_XY_AXIS; | ||
983 | break; | 1091 | break; |
984 | 1092 | ||
985 | default: | 1093 | default: |
986 | v4l2_err(&ctx->fimc_dev->m2m.v4l2_dev, "Invalid control\n"); | 1094 | spin_unlock_irqrestore(&ctx->slock, flags); |
1095 | v4l2_err(&fimc->m2m.v4l2_dev, "Invalid control\n"); | ||
987 | return -EINVAL; | 1096 | return -EINVAL; |
988 | } | 1097 | } |
989 | spin_lock_irqsave(&ctx->slock, flags); | ||
990 | ctx->state |= FIMC_PARAMS; | 1098 | ctx->state |= FIMC_PARAMS; |
991 | spin_unlock_irqrestore(&ctx->slock, flags); | 1099 | spin_unlock_irqrestore(&ctx->slock, flags); |
1100 | |||
992 | return 0; | 1101 | return 0; |
993 | } | 1102 | } |
994 | 1103 | ||
1104 | static int fimc_m2m_s_ctrl(struct file *file, void *priv, | ||
1105 | struct v4l2_control *ctrl) | ||
1106 | { | ||
1107 | struct fimc_ctx *ctx = priv; | ||
1108 | int ret = 0; | ||
1109 | |||
1110 | ret = check_ctrl_val(ctx, ctrl); | ||
1111 | if (ret) | ||
1112 | return ret; | ||
1113 | |||
1114 | ret = fimc_s_ctrl(ctx, ctrl); | ||
1115 | return 0; | ||
1116 | } | ||
995 | 1117 | ||
996 | static int fimc_m2m_cropcap(struct file *file, void *fh, | 1118 | int fimc_vidioc_cropcap(struct file *file, void *fh, |
997 | struct v4l2_cropcap *cr) | 1119 | struct v4l2_cropcap *cr) |
998 | { | 1120 | { |
999 | struct fimc_frame *frame; | 1121 | struct fimc_frame *frame; |
1000 | struct fimc_ctx *ctx = fh; | 1122 | struct fimc_ctx *ctx = fh; |
1123 | struct fimc_dev *fimc = ctx->fimc_dev; | ||
1001 | 1124 | ||
1002 | frame = ctx_m2m_get_frame(ctx, cr->type); | 1125 | frame = ctx_get_frame(ctx, cr->type); |
1003 | if (IS_ERR(frame)) | 1126 | if (IS_ERR(frame)) |
1004 | return PTR_ERR(frame); | 1127 | return PTR_ERR(frame); |
1005 | 1128 | ||
1006 | cr->bounds.left = 0; | 1129 | if (mutex_lock_interruptible(&fimc->lock)) |
1007 | cr->bounds.top = 0; | 1130 | return -ERESTARTSYS; |
1008 | cr->bounds.width = frame->f_width; | 1131 | |
1009 | cr->bounds.height = frame->f_height; | 1132 | cr->bounds.left = 0; |
1010 | cr->defrect.left = frame->offs_h; | 1133 | cr->bounds.top = 0; |
1011 | cr->defrect.top = frame->offs_v; | 1134 | cr->bounds.width = frame->f_width; |
1012 | cr->defrect.width = frame->o_width; | 1135 | cr->bounds.height = frame->f_height; |
1013 | cr->defrect.height = frame->o_height; | 1136 | cr->defrect = cr->bounds; |
1137 | |||
1138 | mutex_unlock(&fimc->lock); | ||
1014 | return 0; | 1139 | return 0; |
1015 | } | 1140 | } |
1016 | 1141 | ||
1017 | static int fimc_m2m_g_crop(struct file *file, void *fh, struct v4l2_crop *cr) | 1142 | int fimc_vidioc_g_crop(struct file *file, void *fh, struct v4l2_crop *cr) |
1018 | { | 1143 | { |
1019 | struct fimc_frame *frame; | 1144 | struct fimc_frame *frame; |
1020 | struct fimc_ctx *ctx = file->private_data; | 1145 | struct fimc_ctx *ctx = file->private_data; |
1146 | struct fimc_dev *fimc = ctx->fimc_dev; | ||
1021 | 1147 | ||
1022 | frame = ctx_m2m_get_frame(ctx, cr->type); | 1148 | frame = ctx_get_frame(ctx, cr->type); |
1023 | if (IS_ERR(frame)) | 1149 | if (IS_ERR(frame)) |
1024 | return PTR_ERR(frame); | 1150 | return PTR_ERR(frame); |
1025 | 1151 | ||
1152 | if (mutex_lock_interruptible(&fimc->lock)) | ||
1153 | return -ERESTARTSYS; | ||
1154 | |||
1026 | cr->c.left = frame->offs_h; | 1155 | cr->c.left = frame->offs_h; |
1027 | cr->c.top = frame->offs_v; | 1156 | cr->c.top = frame->offs_v; |
1028 | cr->c.width = frame->width; | 1157 | cr->c.width = frame->width; |
1029 | cr->c.height = frame->height; | 1158 | cr->c.height = frame->height; |
1030 | 1159 | ||
1160 | mutex_unlock(&fimc->lock); | ||
1031 | return 0; | 1161 | return 0; |
1032 | } | 1162 | } |
1033 | 1163 | ||
1034 | static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr) | 1164 | int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr) |
1035 | { | 1165 | { |
1036 | struct fimc_ctx *ctx = file->private_data; | ||
1037 | struct fimc_dev *fimc = ctx->fimc_dev; | 1166 | struct fimc_dev *fimc = ctx->fimc_dev; |
1038 | unsigned long flags; | ||
1039 | struct fimc_frame *f; | 1167 | struct fimc_frame *f; |
1040 | u32 min_size; | 1168 | u32 min_size, halign; |
1041 | int ret = 0; | 1169 | |
1170 | f = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) ? | ||
1171 | &ctx->s_frame : &ctx->d_frame; | ||
1042 | 1172 | ||
1043 | if (cr->c.top < 0 || cr->c.left < 0) { | 1173 | if (cr->c.top < 0 || cr->c.left < 0) { |
1044 | v4l2_err(&fimc->m2m.v4l2_dev, | 1174 | v4l2_err(&fimc->m2m.v4l2_dev, |
@@ -1046,66 +1176,98 @@ static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr) | |||
1046 | return -EINVAL; | 1176 | return -EINVAL; |
1047 | } | 1177 | } |
1048 | 1178 | ||
1049 | if (cr->c.width <= 0 || cr->c.height <= 0) { | 1179 | f = ctx_get_frame(ctx, cr->type); |
1050 | v4l2_err(&fimc->m2m.v4l2_dev, | ||
1051 | "crop width and height must be greater than 0\n"); | ||
1052 | return -EINVAL; | ||
1053 | } | ||
1054 | |||
1055 | f = ctx_m2m_get_frame(ctx, cr->type); | ||
1056 | if (IS_ERR(f)) | 1180 | if (IS_ERR(f)) |
1057 | return PTR_ERR(f); | 1181 | return PTR_ERR(f); |
1058 | 1182 | ||
1059 | /* Adjust to required pixel boundary. */ | 1183 | min_size = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) |
1060 | min_size = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) ? | 1184 | ? fimc->variant->min_inp_pixsize |
1061 | fimc->variant->min_inp_pixsize : fimc->variant->min_out_pixsize; | 1185 | : fimc->variant->min_out_pixsize; |
1062 | |||
1063 | cr->c.width = round_down(cr->c.width, min_size); | ||
1064 | cr->c.height = round_down(cr->c.height, min_size); | ||
1065 | cr->c.left = round_down(cr->c.left + 1, min_size); | ||
1066 | cr->c.top = round_down(cr->c.top + 1, min_size); | ||
1067 | 1186 | ||
1068 | if ((cr->c.left + cr->c.width > f->o_width) | 1187 | if (ctx->state & FIMC_CTX_M2M) { |
1069 | || (cr->c.top + cr->c.height > f->o_height)) { | 1188 | if (fimc->id == 1 && fimc->variant->pix_hoff) |
1070 | v4l2_err(&fimc->m2m.v4l2_dev, "Error in S_CROP params\n"); | 1189 | halign = fimc_fmt_is_rgb(f->fmt->color) ? 0 : 1; |
1071 | return -EINVAL; | 1190 | else |
1191 | halign = ffs(min_size) - 1; | ||
1192 | /* there are more strict aligment requirements at camera interface */ | ||
1193 | } else { | ||
1194 | min_size = 16; | ||
1195 | halign = 4; | ||
1072 | } | 1196 | } |
1073 | 1197 | ||
1198 | v4l_bound_align_image(&cr->c.width, min_size, f->o_width, | ||
1199 | ffs(min_size) - 1, | ||
1200 | &cr->c.height, min_size, f->o_height, | ||
1201 | halign, 64/(ALIGN(f->fmt->depth, 8))); | ||
1202 | |||
1203 | /* adjust left/top if cropping rectangle is out of bounds */ | ||
1204 | if (cr->c.left + cr->c.width > f->o_width) | ||
1205 | cr->c.left = f->o_width - cr->c.width; | ||
1206 | if (cr->c.top + cr->c.height > f->o_height) | ||
1207 | cr->c.top = f->o_height - cr->c.height; | ||
1208 | |||
1209 | cr->c.left = round_down(cr->c.left, min_size); | ||
1210 | cr->c.top = round_down(cr->c.top, | ||
1211 | ctx->state & FIMC_CTX_M2M ? 8 : 16); | ||
1212 | |||
1213 | dbg("l:%d, t:%d, w:%d, h:%d, f_w: %d, f_h: %d", | ||
1214 | cr->c.left, cr->c.top, cr->c.width, cr->c.height, | ||
1215 | f->f_width, f->f_height); | ||
1216 | |||
1217 | return 0; | ||
1218 | } | ||
1219 | |||
1220 | |||
1221 | static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr) | ||
1222 | { | ||
1223 | struct fimc_ctx *ctx = file->private_data; | ||
1224 | struct fimc_dev *fimc = ctx->fimc_dev; | ||
1225 | unsigned long flags; | ||
1226 | struct fimc_frame *f; | ||
1227 | int ret; | ||
1228 | |||
1229 | ret = fimc_try_crop(ctx, cr); | ||
1230 | if (ret) | ||
1231 | return ret; | ||
1232 | |||
1233 | f = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) ? | ||
1234 | &ctx->s_frame : &ctx->d_frame; | ||
1235 | |||
1074 | spin_lock_irqsave(&ctx->slock, flags); | 1236 | spin_lock_irqsave(&ctx->slock, flags); |
1075 | if ((ctx->state & FIMC_SRC_FMT) && (ctx->state & FIMC_DST_FMT)) { | 1237 | if (~ctx->state & (FIMC_SRC_FMT | FIMC_DST_FMT)) { |
1076 | /* Check for the pixel scaling ratio when cropping input img. */ | 1238 | /* Check to see if scaling ratio is within supported range */ |
1077 | if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) | 1239 | if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) |
1078 | ret = fimc_check_scaler_ratio(&cr->c, &ctx->d_frame); | 1240 | ret = fimc_check_scaler_ratio(&cr->c, &ctx->d_frame); |
1079 | else if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) | 1241 | else |
1080 | ret = fimc_check_scaler_ratio(&cr->c, &ctx->s_frame); | 1242 | ret = fimc_check_scaler_ratio(&cr->c, &ctx->s_frame); |
1081 | |||
1082 | if (ret) { | 1243 | if (ret) { |
1083 | spin_unlock_irqrestore(&ctx->slock, flags); | 1244 | spin_unlock_irqrestore(&ctx->slock, flags); |
1084 | v4l2_err(&fimc->m2m.v4l2_dev, "Out of scaler range"); | 1245 | v4l2_err(&fimc->m2m.v4l2_dev, "Out of scaler range"); |
1085 | return -EINVAL; | 1246 | return -EINVAL; |
1086 | } | 1247 | } |
1087 | } | 1248 | } |
1088 | ctx->state |= FIMC_PARAMS; | 1249 | ctx->state |= FIMC_PARAMS; |
1089 | spin_unlock_irqrestore(&ctx->slock, flags); | ||
1090 | 1250 | ||
1091 | f->offs_h = cr->c.left; | 1251 | f->offs_h = cr->c.left; |
1092 | f->offs_v = cr->c.top; | 1252 | f->offs_v = cr->c.top; |
1093 | f->width = cr->c.width; | 1253 | f->width = cr->c.width; |
1094 | f->height = cr->c.height; | 1254 | f->height = cr->c.height; |
1255 | |||
1256 | spin_unlock_irqrestore(&ctx->slock, flags); | ||
1095 | return 0; | 1257 | return 0; |
1096 | } | 1258 | } |
1097 | 1259 | ||
1098 | static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = { | 1260 | static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = { |
1099 | .vidioc_querycap = fimc_m2m_querycap, | 1261 | .vidioc_querycap = fimc_m2m_querycap, |
1100 | 1262 | ||
1101 | .vidioc_enum_fmt_vid_cap = fimc_m2m_enum_fmt, | 1263 | .vidioc_enum_fmt_vid_cap = fimc_vidioc_enum_fmt, |
1102 | .vidioc_enum_fmt_vid_out = fimc_m2m_enum_fmt, | 1264 | .vidioc_enum_fmt_vid_out = fimc_vidioc_enum_fmt, |
1103 | 1265 | ||
1104 | .vidioc_g_fmt_vid_cap = fimc_m2m_g_fmt, | 1266 | .vidioc_g_fmt_vid_cap = fimc_vidioc_g_fmt, |
1105 | .vidioc_g_fmt_vid_out = fimc_m2m_g_fmt, | 1267 | .vidioc_g_fmt_vid_out = fimc_vidioc_g_fmt, |
1106 | 1268 | ||
1107 | .vidioc_try_fmt_vid_cap = fimc_m2m_try_fmt, | 1269 | .vidioc_try_fmt_vid_cap = fimc_vidioc_try_fmt, |
1108 | .vidioc_try_fmt_vid_out = fimc_m2m_try_fmt, | 1270 | .vidioc_try_fmt_vid_out = fimc_vidioc_try_fmt, |
1109 | 1271 | ||
1110 | .vidioc_s_fmt_vid_cap = fimc_m2m_s_fmt, | 1272 | .vidioc_s_fmt_vid_cap = fimc_m2m_s_fmt, |
1111 | .vidioc_s_fmt_vid_out = fimc_m2m_s_fmt, | 1273 | .vidioc_s_fmt_vid_out = fimc_m2m_s_fmt, |
@@ -1119,13 +1281,13 @@ static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = { | |||
1119 | .vidioc_streamon = fimc_m2m_streamon, | 1281 | .vidioc_streamon = fimc_m2m_streamon, |
1120 | .vidioc_streamoff = fimc_m2m_streamoff, | 1282 | .vidioc_streamoff = fimc_m2m_streamoff, |
1121 | 1283 | ||
1122 | .vidioc_queryctrl = fimc_m2m_queryctrl, | 1284 | .vidioc_queryctrl = fimc_vidioc_queryctrl, |
1123 | .vidioc_g_ctrl = fimc_m2m_g_ctrl, | 1285 | .vidioc_g_ctrl = fimc_vidioc_g_ctrl, |
1124 | .vidioc_s_ctrl = fimc_m2m_s_ctrl, | 1286 | .vidioc_s_ctrl = fimc_m2m_s_ctrl, |
1125 | 1287 | ||
1126 | .vidioc_g_crop = fimc_m2m_g_crop, | 1288 | .vidioc_g_crop = fimc_vidioc_g_crop, |
1127 | .vidioc_s_crop = fimc_m2m_s_crop, | 1289 | .vidioc_s_crop = fimc_m2m_s_crop, |
1128 | .vidioc_cropcap = fimc_m2m_cropcap | 1290 | .vidioc_cropcap = fimc_vidioc_cropcap |
1129 | 1291 | ||
1130 | }; | 1292 | }; |
1131 | 1293 | ||
@@ -1136,9 +1298,9 @@ static void queue_init(void *priv, struct videobuf_queue *vq, | |||
1136 | struct fimc_dev *fimc = ctx->fimc_dev; | 1298 | struct fimc_dev *fimc = ctx->fimc_dev; |
1137 | 1299 | ||
1138 | videobuf_queue_dma_contig_init(vq, &fimc_qops, | 1300 | videobuf_queue_dma_contig_init(vq, &fimc_qops, |
1139 | fimc->m2m.v4l2_dev.dev, | 1301 | &fimc->pdev->dev, |
1140 | &fimc->irqlock, type, V4L2_FIELD_NONE, | 1302 | &fimc->irqlock, type, V4L2_FIELD_NONE, |
1141 | sizeof(struct fimc_vid_buffer), priv); | 1303 | sizeof(struct fimc_vid_buffer), priv, NULL); |
1142 | } | 1304 | } |
1143 | 1305 | ||
1144 | static int fimc_m2m_open(struct file *file) | 1306 | static int fimc_m2m_open(struct file *file) |
@@ -1147,25 +1309,38 @@ static int fimc_m2m_open(struct file *file) | |||
1147 | struct fimc_ctx *ctx = NULL; | 1309 | struct fimc_ctx *ctx = NULL; |
1148 | int err = 0; | 1310 | int err = 0; |
1149 | 1311 | ||
1150 | mutex_lock(&fimc->lock); | 1312 | if (mutex_lock_interruptible(&fimc->lock)) |
1313 | return -ERESTARTSYS; | ||
1314 | |||
1315 | dbg("pid: %d, state: 0x%lx, refcnt: %d", | ||
1316 | task_pid_nr(current), fimc->state, fimc->vid_cap.refcnt); | ||
1317 | |||
1318 | /* | ||
1319 | * Return if the corresponding video capture node | ||
1320 | * is already opened. | ||
1321 | */ | ||
1322 | if (fimc->vid_cap.refcnt > 0) { | ||
1323 | err = -EBUSY; | ||
1324 | goto err_unlock; | ||
1325 | } | ||
1326 | |||
1151 | fimc->m2m.refcnt++; | 1327 | fimc->m2m.refcnt++; |
1152 | set_bit(ST_OUTDMA_RUN, &fimc->state); | 1328 | set_bit(ST_OUTDMA_RUN, &fimc->state); |
1153 | mutex_unlock(&fimc->lock); | ||
1154 | |||
1155 | 1329 | ||
1156 | ctx = kzalloc(sizeof *ctx, GFP_KERNEL); | 1330 | ctx = kzalloc(sizeof *ctx, GFP_KERNEL); |
1157 | if (!ctx) | 1331 | if (!ctx) { |
1158 | return -ENOMEM; | 1332 | err = -ENOMEM; |
1333 | goto err_unlock; | ||
1334 | } | ||
1159 | 1335 | ||
1160 | file->private_data = ctx; | 1336 | file->private_data = ctx; |
1161 | ctx->fimc_dev = fimc; | 1337 | ctx->fimc_dev = fimc; |
1162 | /* default format */ | 1338 | /* Default color format */ |
1163 | ctx->s_frame.fmt = &fimc_formats[0]; | 1339 | ctx->s_frame.fmt = &fimc_formats[0]; |
1164 | ctx->d_frame.fmt = &fimc_formats[0]; | 1340 | ctx->d_frame.fmt = &fimc_formats[0]; |
1165 | /* per user process device context initialization */ | 1341 | /* Setup the device context for mem2mem mode. */ |
1166 | ctx->state = 0; | 1342 | ctx->state = FIMC_CTX_M2M; |
1167 | ctx->flags = 0; | 1343 | ctx->flags = 0; |
1168 | ctx->effect.type = S5P_FIMC_EFFECT_ORIGINAL; | ||
1169 | ctx->in_path = FIMC_DMA; | 1344 | ctx->in_path = FIMC_DMA; |
1170 | ctx->out_path = FIMC_DMA; | 1345 | ctx->out_path = FIMC_DMA; |
1171 | spin_lock_init(&ctx->slock); | 1346 | spin_lock_init(&ctx->slock); |
@@ -1175,6 +1350,9 @@ static int fimc_m2m_open(struct file *file) | |||
1175 | err = PTR_ERR(ctx->m2m_ctx); | 1350 | err = PTR_ERR(ctx->m2m_ctx); |
1176 | kfree(ctx); | 1351 | kfree(ctx); |
1177 | } | 1352 | } |
1353 | |||
1354 | err_unlock: | ||
1355 | mutex_unlock(&fimc->lock); | ||
1178 | return err; | 1356 | return err; |
1179 | } | 1357 | } |
1180 | 1358 | ||
@@ -1183,11 +1361,16 @@ static int fimc_m2m_release(struct file *file) | |||
1183 | struct fimc_ctx *ctx = file->private_data; | 1361 | struct fimc_ctx *ctx = file->private_data; |
1184 | struct fimc_dev *fimc = ctx->fimc_dev; | 1362 | struct fimc_dev *fimc = ctx->fimc_dev; |
1185 | 1363 | ||
1364 | mutex_lock(&fimc->lock); | ||
1365 | |||
1366 | dbg("pid: %d, state: 0x%lx, refcnt= %d", | ||
1367 | task_pid_nr(current), fimc->state, fimc->m2m.refcnt); | ||
1368 | |||
1186 | v4l2_m2m_ctx_release(ctx->m2m_ctx); | 1369 | v4l2_m2m_ctx_release(ctx->m2m_ctx); |
1187 | kfree(ctx); | 1370 | kfree(ctx); |
1188 | mutex_lock(&fimc->lock); | ||
1189 | if (--fimc->m2m.refcnt <= 0) | 1371 | if (--fimc->m2m.refcnt <= 0) |
1190 | clear_bit(ST_OUTDMA_RUN, &fimc->state); | 1372 | clear_bit(ST_OUTDMA_RUN, &fimc->state); |
1373 | |||
1191 | mutex_unlock(&fimc->lock); | 1374 | mutex_unlock(&fimc->lock); |
1192 | return 0; | 1375 | return 0; |
1193 | } | 1376 | } |
@@ -1196,6 +1379,7 @@ static unsigned int fimc_m2m_poll(struct file *file, | |||
1196 | struct poll_table_struct *wait) | 1379 | struct poll_table_struct *wait) |
1197 | { | 1380 | { |
1198 | struct fimc_ctx *ctx = file->private_data; | 1381 | struct fimc_ctx *ctx = file->private_data; |
1382 | |||
1199 | return v4l2_m2m_poll(file, ctx->m2m_ctx, wait); | 1383 | return v4l2_m2m_poll(file, ctx->m2m_ctx, wait); |
1200 | } | 1384 | } |
1201 | 1385 | ||
@@ -1203,6 +1387,7 @@ static unsigned int fimc_m2m_poll(struct file *file, | |||
1203 | static int fimc_m2m_mmap(struct file *file, struct vm_area_struct *vma) | 1387 | static int fimc_m2m_mmap(struct file *file, struct vm_area_struct *vma) |
1204 | { | 1388 | { |
1205 | struct fimc_ctx *ctx = file->private_data; | 1389 | struct fimc_ctx *ctx = file->private_data; |
1390 | |||
1206 | return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma); | 1391 | return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma); |
1207 | } | 1392 | } |
1208 | 1393 | ||
@@ -1241,7 +1426,7 @@ static int fimc_register_m2m_device(struct fimc_dev *fimc) | |||
1241 | 1426 | ||
1242 | ret = v4l2_device_register(&pdev->dev, v4l2_dev); | 1427 | ret = v4l2_device_register(&pdev->dev, v4l2_dev); |
1243 | if (ret) | 1428 | if (ret) |
1244 | return ret;; | 1429 | goto err_m2m_r1; |
1245 | 1430 | ||
1246 | vfd = video_device_alloc(); | 1431 | vfd = video_device_alloc(); |
1247 | if (!vfd) { | 1432 | if (!vfd) { |
@@ -1293,7 +1478,7 @@ static void fimc_unregister_m2m_device(struct fimc_dev *fimc) | |||
1293 | if (fimc) { | 1478 | if (fimc) { |
1294 | v4l2_m2m_release(fimc->m2m.m2m_dev); | 1479 | v4l2_m2m_release(fimc->m2m.m2m_dev); |
1295 | video_unregister_device(fimc->m2m.vfd); | 1480 | video_unregister_device(fimc->m2m.vfd); |
1296 | video_device_release(fimc->m2m.vfd); | 1481 | |
1297 | v4l2_device_unregister(&fimc->m2m.v4l2_dev); | 1482 | v4l2_device_unregister(&fimc->m2m.v4l2_dev); |
1298 | } | 1483 | } |
1299 | } | 1484 | } |
@@ -1337,7 +1522,7 @@ static int fimc_probe(struct platform_device *pdev) | |||
1337 | drv_data = (struct samsung_fimc_driverdata *) | 1522 | drv_data = (struct samsung_fimc_driverdata *) |
1338 | platform_get_device_id(pdev)->driver_data; | 1523 | platform_get_device_id(pdev)->driver_data; |
1339 | 1524 | ||
1340 | if (pdev->id >= drv_data->devs_cnt) { | 1525 | if (pdev->id >= drv_data->num_entities) { |
1341 | dev_err(&pdev->dev, "Invalid platform device id: %d\n", | 1526 | dev_err(&pdev->dev, "Invalid platform device id: %d\n", |
1342 | pdev->id); | 1527 | pdev->id); |
1343 | return -EINVAL; | 1528 | return -EINVAL; |
@@ -1350,9 +1535,11 @@ static int fimc_probe(struct platform_device *pdev) | |||
1350 | fimc->id = pdev->id; | 1535 | fimc->id = pdev->id; |
1351 | fimc->variant = drv_data->variant[fimc->id]; | 1536 | fimc->variant = drv_data->variant[fimc->id]; |
1352 | fimc->pdev = pdev; | 1537 | fimc->pdev = pdev; |
1538 | fimc->pdata = pdev->dev.platform_data; | ||
1353 | fimc->state = ST_IDLE; | 1539 | fimc->state = ST_IDLE; |
1354 | 1540 | ||
1355 | spin_lock_init(&fimc->irqlock); | 1541 | spin_lock_init(&fimc->irqlock); |
1542 | init_waitqueue_head(&fimc->irq_queue); | ||
1356 | spin_lock_init(&fimc->slock); | 1543 | spin_lock_init(&fimc->slock); |
1357 | 1544 | ||
1358 | mutex_init(&fimc->lock); | 1545 | mutex_init(&fimc->lock); |
@@ -1382,6 +1569,7 @@ static int fimc_probe(struct platform_device *pdev) | |||
1382 | ret = fimc_clk_get(fimc); | 1569 | ret = fimc_clk_get(fimc); |
1383 | if (ret) | 1570 | if (ret) |
1384 | goto err_regs_unmap; | 1571 | goto err_regs_unmap; |
1572 | clk_set_rate(fimc->clock[0], drv_data->lclk_frequency); | ||
1385 | 1573 | ||
1386 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | 1574 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |
1387 | if (!res) { | 1575 | if (!res) { |
@@ -1399,25 +1587,38 @@ static int fimc_probe(struct platform_device *pdev) | |||
1399 | goto err_clk; | 1587 | goto err_clk; |
1400 | } | 1588 | } |
1401 | 1589 | ||
1402 | fimc->work_queue = create_workqueue(dev_name(&fimc->pdev->dev)); | ||
1403 | if (!fimc->work_queue) { | ||
1404 | ret = -ENOMEM; | ||
1405 | goto err_irq; | ||
1406 | } | ||
1407 | |||
1408 | ret = fimc_register_m2m_device(fimc); | 1590 | ret = fimc_register_m2m_device(fimc); |
1409 | if (ret) | 1591 | if (ret) |
1410 | goto err_wq; | 1592 | goto err_irq; |
1593 | |||
1594 | /* At least one camera sensor is required to register capture node */ | ||
1595 | if (fimc->pdata) { | ||
1596 | int i; | ||
1597 | for (i = 0; i < FIMC_MAX_CAMIF_CLIENTS; ++i) | ||
1598 | if (fimc->pdata->isp_info[i]) | ||
1599 | break; | ||
1600 | |||
1601 | if (i < FIMC_MAX_CAMIF_CLIENTS) { | ||
1602 | ret = fimc_register_capture_device(fimc); | ||
1603 | if (ret) | ||
1604 | goto err_m2m; | ||
1605 | } | ||
1606 | } | ||
1411 | 1607 | ||
1412 | fimc_hw_en_lastirq(fimc, true); | 1608 | /* |
1609 | * Exclude the additional output DMA address registers by masking | ||
1610 | * them out on HW revisions that provide extended capabilites. | ||
1611 | */ | ||
1612 | if (fimc->variant->out_buf_count > 4) | ||
1613 | fimc_hw_set_dma_seq(fimc, 0xF); | ||
1413 | 1614 | ||
1414 | dev_dbg(&pdev->dev, "%s(): fimc-%d registered successfully\n", | 1615 | dev_dbg(&pdev->dev, "%s(): fimc-%d registered successfully\n", |
1415 | __func__, fimc->id); | 1616 | __func__, fimc->id); |
1416 | 1617 | ||
1417 | return 0; | 1618 | return 0; |
1418 | 1619 | ||
1419 | err_wq: | 1620 | err_m2m: |
1420 | destroy_workqueue(fimc->work_queue); | 1621 | fimc_unregister_m2m_device(fimc); |
1421 | err_irq: | 1622 | err_irq: |
1422 | free_irq(fimc->irq, fimc); | 1623 | free_irq(fimc->irq, fimc); |
1423 | err_clk: | 1624 | err_clk: |
@@ -1429,7 +1630,7 @@ err_req_region: | |||
1429 | kfree(fimc->regs_res); | 1630 | kfree(fimc->regs_res); |
1430 | err_info: | 1631 | err_info: |
1431 | kfree(fimc); | 1632 | kfree(fimc); |
1432 | dev_err(&pdev->dev, "failed to install\n"); | 1633 | |
1433 | return ret; | 1634 | return ret; |
1434 | } | 1635 | } |
1435 | 1636 | ||
@@ -1438,91 +1639,151 @@ static int __devexit fimc_remove(struct platform_device *pdev) | |||
1438 | struct fimc_dev *fimc = | 1639 | struct fimc_dev *fimc = |
1439 | (struct fimc_dev *)platform_get_drvdata(pdev); | 1640 | (struct fimc_dev *)platform_get_drvdata(pdev); |
1440 | 1641 | ||
1441 | v4l2_info(&fimc->m2m.v4l2_dev, "Removing %s\n", pdev->name); | ||
1442 | |||
1443 | free_irq(fimc->irq, fimc); | 1642 | free_irq(fimc->irq, fimc); |
1444 | |||
1445 | fimc_hw_reset(fimc); | 1643 | fimc_hw_reset(fimc); |
1446 | 1644 | ||
1447 | fimc_unregister_m2m_device(fimc); | 1645 | fimc_unregister_m2m_device(fimc); |
1646 | fimc_unregister_capture_device(fimc); | ||
1647 | |||
1448 | fimc_clk_release(fimc); | 1648 | fimc_clk_release(fimc); |
1449 | iounmap(fimc->regs); | 1649 | iounmap(fimc->regs); |
1450 | release_resource(fimc->regs_res); | 1650 | release_resource(fimc->regs_res); |
1451 | kfree(fimc->regs_res); | 1651 | kfree(fimc->regs_res); |
1452 | kfree(fimc); | 1652 | kfree(fimc); |
1653 | |||
1654 | dev_info(&pdev->dev, "%s driver unloaded\n", pdev->name); | ||
1453 | return 0; | 1655 | return 0; |
1454 | } | 1656 | } |
1455 | 1657 | ||
1456 | static struct samsung_fimc_variant fimc01_variant_s5p = { | 1658 | /* Image pixel limits, similar across several FIMC HW revisions. */ |
1457 | .has_inp_rot = 1, | 1659 | static struct fimc_pix_limit s5p_pix_limit[3] = { |
1458 | .has_out_rot = 1, | 1660 | [0] = { |
1661 | .scaler_en_w = 3264, | ||
1662 | .scaler_dis_w = 8192, | ||
1663 | .in_rot_en_h = 1920, | ||
1664 | .in_rot_dis_w = 8192, | ||
1665 | .out_rot_en_w = 1920, | ||
1666 | .out_rot_dis_w = 4224, | ||
1667 | }, | ||
1668 | [1] = { | ||
1669 | .scaler_en_w = 4224, | ||
1670 | .scaler_dis_w = 8192, | ||
1671 | .in_rot_en_h = 1920, | ||
1672 | .in_rot_dis_w = 8192, | ||
1673 | .out_rot_en_w = 1920, | ||
1674 | .out_rot_dis_w = 4224, | ||
1675 | }, | ||
1676 | [2] = { | ||
1677 | .scaler_en_w = 1920, | ||
1678 | .scaler_dis_w = 8192, | ||
1679 | .in_rot_en_h = 1280, | ||
1680 | .in_rot_dis_w = 8192, | ||
1681 | .out_rot_en_w = 1280, | ||
1682 | .out_rot_dis_w = 1920, | ||
1683 | }, | ||
1684 | }; | ||
1685 | |||
1686 | static struct samsung_fimc_variant fimc0_variant_s5p = { | ||
1687 | .has_inp_rot = 1, | ||
1688 | .has_out_rot = 1, | ||
1459 | .min_inp_pixsize = 16, | 1689 | .min_inp_pixsize = 16, |
1460 | .min_out_pixsize = 16, | 1690 | .min_out_pixsize = 16, |
1461 | 1691 | .hor_offs_align = 8, | |
1462 | .scaler_en_w = 3264, | 1692 | .out_buf_count = 4, |
1463 | .scaler_dis_w = 8192, | 1693 | .pix_limit = &s5p_pix_limit[0], |
1464 | .in_rot_en_h = 1920, | ||
1465 | .in_rot_dis_w = 8192, | ||
1466 | .out_rot_en_w = 1920, | ||
1467 | .out_rot_dis_w = 4224, | ||
1468 | }; | 1694 | }; |
1469 | 1695 | ||
1470 | static struct samsung_fimc_variant fimc2_variant_s5p = { | 1696 | static struct samsung_fimc_variant fimc2_variant_s5p = { |
1471 | .min_inp_pixsize = 16, | 1697 | .min_inp_pixsize = 16, |
1472 | .min_out_pixsize = 16, | 1698 | .min_out_pixsize = 16, |
1699 | .hor_offs_align = 8, | ||
1700 | .out_buf_count = 4, | ||
1701 | .pix_limit = &s5p_pix_limit[1], | ||
1702 | }; | ||
1473 | 1703 | ||
1474 | .scaler_en_w = 4224, | 1704 | static struct samsung_fimc_variant fimc0_variant_s5pv210 = { |
1475 | .scaler_dis_w = 8192, | 1705 | .pix_hoff = 1, |
1476 | .in_rot_en_h = 1920, | 1706 | .has_inp_rot = 1, |
1477 | .in_rot_dis_w = 8192, | 1707 | .has_out_rot = 1, |
1478 | .out_rot_en_w = 1920, | 1708 | .min_inp_pixsize = 16, |
1479 | .out_rot_dis_w = 4224, | 1709 | .min_out_pixsize = 16, |
1710 | .hor_offs_align = 8, | ||
1711 | .out_buf_count = 4, | ||
1712 | .pix_limit = &s5p_pix_limit[1], | ||
1480 | }; | 1713 | }; |
1481 | 1714 | ||
1482 | static struct samsung_fimc_variant fimc01_variant_s5pv210 = { | 1715 | static struct samsung_fimc_variant fimc1_variant_s5pv210 = { |
1483 | .pix_hoff = 1, | 1716 | .pix_hoff = 1, |
1484 | .has_inp_rot = 1, | 1717 | .has_inp_rot = 1, |
1485 | .has_out_rot = 1, | 1718 | .has_out_rot = 1, |
1486 | .min_inp_pixsize = 16, | 1719 | .min_inp_pixsize = 16, |
1487 | .min_out_pixsize = 32, | 1720 | .min_out_pixsize = 16, |
1488 | 1721 | .hor_offs_align = 1, | |
1489 | .scaler_en_w = 4224, | 1722 | .out_buf_count = 4, |
1490 | .scaler_dis_w = 8192, | 1723 | .pix_limit = &s5p_pix_limit[2], |
1491 | .in_rot_en_h = 1920, | ||
1492 | .in_rot_dis_w = 8192, | ||
1493 | .out_rot_en_w = 1920, | ||
1494 | .out_rot_dis_w = 4224, | ||
1495 | }; | 1724 | }; |
1496 | 1725 | ||
1497 | static struct samsung_fimc_variant fimc2_variant_s5pv210 = { | 1726 | static struct samsung_fimc_variant fimc2_variant_s5pv210 = { |
1498 | .pix_hoff = 1, | 1727 | .pix_hoff = 1, |
1499 | .min_inp_pixsize = 16, | 1728 | .min_inp_pixsize = 16, |
1500 | .min_out_pixsize = 32, | 1729 | .min_out_pixsize = 16, |
1501 | 1730 | .hor_offs_align = 8, | |
1502 | .scaler_en_w = 1920, | 1731 | .out_buf_count = 4, |
1503 | .scaler_dis_w = 8192, | 1732 | .pix_limit = &s5p_pix_limit[2], |
1504 | .in_rot_en_h = 1280, | 1733 | }; |
1505 | .in_rot_dis_w = 8192, | 1734 | |
1506 | .out_rot_en_w = 1280, | 1735 | static struct samsung_fimc_variant fimc0_variant_s5pv310 = { |
1507 | .out_rot_dis_w = 1920, | 1736 | .pix_hoff = 1, |
1737 | .has_inp_rot = 1, | ||
1738 | .has_out_rot = 1, | ||
1739 | .min_inp_pixsize = 16, | ||
1740 | .min_out_pixsize = 16, | ||
1741 | .hor_offs_align = 1, | ||
1742 | .out_buf_count = 32, | ||
1743 | .pix_limit = &s5p_pix_limit[1], | ||
1744 | }; | ||
1745 | |||
1746 | static struct samsung_fimc_variant fimc2_variant_s5pv310 = { | ||
1747 | .pix_hoff = 1, | ||
1748 | .min_inp_pixsize = 16, | ||
1749 | .min_out_pixsize = 16, | ||
1750 | .hor_offs_align = 1, | ||
1751 | .out_buf_count = 32, | ||
1752 | .pix_limit = &s5p_pix_limit[2], | ||
1508 | }; | 1753 | }; |
1509 | 1754 | ||
1755 | /* S5PC100 */ | ||
1510 | static struct samsung_fimc_driverdata fimc_drvdata_s5p = { | 1756 | static struct samsung_fimc_driverdata fimc_drvdata_s5p = { |
1511 | .variant = { | 1757 | .variant = { |
1512 | [0] = &fimc01_variant_s5p, | 1758 | [0] = &fimc0_variant_s5p, |
1513 | [1] = &fimc01_variant_s5p, | 1759 | [1] = &fimc0_variant_s5p, |
1514 | [2] = &fimc2_variant_s5p, | 1760 | [2] = &fimc2_variant_s5p, |
1515 | }, | 1761 | }, |
1516 | .devs_cnt = 3 | 1762 | .num_entities = 3, |
1763 | .lclk_frequency = 133000000UL, | ||
1517 | }; | 1764 | }; |
1518 | 1765 | ||
1766 | /* S5PV210, S5PC110 */ | ||
1519 | static struct samsung_fimc_driverdata fimc_drvdata_s5pv210 = { | 1767 | static struct samsung_fimc_driverdata fimc_drvdata_s5pv210 = { |
1520 | .variant = { | 1768 | .variant = { |
1521 | [0] = &fimc01_variant_s5pv210, | 1769 | [0] = &fimc0_variant_s5pv210, |
1522 | [1] = &fimc01_variant_s5pv210, | 1770 | [1] = &fimc1_variant_s5pv210, |
1523 | [2] = &fimc2_variant_s5pv210, | 1771 | [2] = &fimc2_variant_s5pv210, |
1524 | }, | 1772 | }, |
1525 | .devs_cnt = 3 | 1773 | .num_entities = 3, |
1774 | .lclk_frequency = 166000000UL, | ||
1775 | }; | ||
1776 | |||
1777 | /* S5PV310, S5PC210 */ | ||
1778 | static struct samsung_fimc_driverdata fimc_drvdata_s5pv310 = { | ||
1779 | .variant = { | ||
1780 | [0] = &fimc0_variant_s5pv310, | ||
1781 | [1] = &fimc0_variant_s5pv310, | ||
1782 | [2] = &fimc0_variant_s5pv310, | ||
1783 | [3] = &fimc2_variant_s5pv310, | ||
1784 | }, | ||
1785 | .num_entities = 4, | ||
1786 | .lclk_frequency = 166000000UL, | ||
1526 | }; | 1787 | }; |
1527 | 1788 | ||
1528 | static struct platform_device_id fimc_driver_ids[] = { | 1789 | static struct platform_device_id fimc_driver_ids[] = { |
@@ -1532,6 +1793,9 @@ static struct platform_device_id fimc_driver_ids[] = { | |||
1532 | }, { | 1793 | }, { |
1533 | .name = "s5pv210-fimc", | 1794 | .name = "s5pv210-fimc", |
1534 | .driver_data = (unsigned long)&fimc_drvdata_s5pv210, | 1795 | .driver_data = (unsigned long)&fimc_drvdata_s5pv210, |
1796 | }, { | ||
1797 | .name = "s5pv310-fimc", | ||
1798 | .driver_data = (unsigned long)&fimc_drvdata_s5pv310, | ||
1535 | }, | 1799 | }, |
1536 | {}, | 1800 | {}, |
1537 | }; | 1801 | }; |
@@ -1547,20 +1811,12 @@ static struct platform_driver fimc_driver = { | |||
1547 | } | 1811 | } |
1548 | }; | 1812 | }; |
1549 | 1813 | ||
1550 | static char banner[] __initdata = KERN_INFO | ||
1551 | "S5PC Camera Interface V4L2 Driver, (c) 2010 Samsung Electronics\n"; | ||
1552 | |||
1553 | static int __init fimc_init(void) | 1814 | static int __init fimc_init(void) |
1554 | { | 1815 | { |
1555 | u32 ret; | 1816 | int ret = platform_driver_register(&fimc_driver); |
1556 | printk(banner); | 1817 | if (ret) |
1557 | 1818 | err("platform_driver_register failed: %d\n", ret); | |
1558 | ret = platform_driver_register(&fimc_driver); | 1819 | return ret; |
1559 | if (ret) { | ||
1560 | printk(KERN_ERR "FIMC platform driver register failed\n"); | ||
1561 | return -1; | ||
1562 | } | ||
1563 | return 0; | ||
1564 | } | 1820 | } |
1565 | 1821 | ||
1566 | static void __exit fimc_exit(void) | 1822 | static void __exit fimc_exit(void) |
@@ -1571,6 +1827,6 @@ static void __exit fimc_exit(void) | |||
1571 | module_init(fimc_init); | 1827 | module_init(fimc_init); |
1572 | module_exit(fimc_exit); | 1828 | module_exit(fimc_exit); |
1573 | 1829 | ||
1574 | MODULE_AUTHOR("Sylwester Nawrocki, s.nawrocki@samsung.com"); | 1830 | MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>"); |
1575 | MODULE_DESCRIPTION("S3C/S5P FIMC (video postprocessor) driver"); | 1831 | MODULE_DESCRIPTION("S5P FIMC camera host interface/video postprocessor driver"); |
1576 | MODULE_LICENSE("GPL"); | 1832 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h index 6b3e0cd73cdd..3e1078516560 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.h +++ b/drivers/media/video/s5p-fimc/fimc-core.h | |||
@@ -11,10 +11,14 @@ | |||
11 | #ifndef FIMC_CORE_H_ | 11 | #ifndef FIMC_CORE_H_ |
12 | #define FIMC_CORE_H_ | 12 | #define FIMC_CORE_H_ |
13 | 13 | ||
14 | /*#define DEBUG*/ | ||
15 | |||
14 | #include <linux/types.h> | 16 | #include <linux/types.h> |
15 | #include <media/videobuf-core.h> | 17 | #include <media/videobuf-core.h> |
16 | #include <media/v4l2-device.h> | 18 | #include <media/v4l2-device.h> |
17 | #include <media/v4l2-mem2mem.h> | 19 | #include <media/v4l2-mem2mem.h> |
20 | #include <media/v4l2-mediabus.h> | ||
21 | #include <media/s3c_fimc.h> | ||
18 | #include <linux/videodev2.h> | 22 | #include <linux/videodev2.h> |
19 | #include "regs-fimc.h" | 23 | #include "regs-fimc.h" |
20 | 24 | ||
@@ -28,47 +32,72 @@ | |||
28 | #define dbg(fmt, args...) | 32 | #define dbg(fmt, args...) |
29 | #endif | 33 | #endif |
30 | 34 | ||
35 | /* Time to wait for next frame VSYNC interrupt while stopping operation. */ | ||
36 | #define FIMC_SHUTDOWN_TIMEOUT ((100*HZ)/1000) | ||
31 | #define NUM_FIMC_CLOCKS 2 | 37 | #define NUM_FIMC_CLOCKS 2 |
32 | #define MODULE_NAME "s5p-fimc" | 38 | #define MODULE_NAME "s5p-fimc" |
33 | #define FIMC_MAX_DEVS 3 | 39 | #define FIMC_MAX_DEVS 4 |
34 | #define FIMC_MAX_OUT_BUFS 4 | 40 | #define FIMC_MAX_OUT_BUFS 4 |
35 | #define SCALER_MAX_HRATIO 64 | 41 | #define SCALER_MAX_HRATIO 64 |
36 | #define SCALER_MAX_VRATIO 64 | 42 | #define SCALER_MAX_VRATIO 64 |
43 | #define DMA_MIN_SIZE 8 | ||
37 | 44 | ||
38 | enum { | 45 | /* FIMC device state flags */ |
46 | enum fimc_dev_flags { | ||
47 | /* for m2m node */ | ||
39 | ST_IDLE, | 48 | ST_IDLE, |
40 | ST_OUTDMA_RUN, | 49 | ST_OUTDMA_RUN, |
41 | ST_M2M_PEND, | 50 | ST_M2M_PEND, |
51 | /* for capture node */ | ||
52 | ST_CAPT_PEND, | ||
53 | ST_CAPT_RUN, | ||
54 | ST_CAPT_STREAM, | ||
55 | ST_CAPT_SHUT, | ||
42 | }; | 56 | }; |
43 | 57 | ||
44 | #define fimc_m2m_active(dev) test_bit(ST_OUTDMA_RUN, &(dev)->state) | 58 | #define fimc_m2m_active(dev) test_bit(ST_OUTDMA_RUN, &(dev)->state) |
45 | #define fimc_m2m_pending(dev) test_bit(ST_M2M_PEND, &(dev)->state) | 59 | #define fimc_m2m_pending(dev) test_bit(ST_M2M_PEND, &(dev)->state) |
46 | 60 | ||
61 | #define fimc_capture_running(dev) test_bit(ST_CAPT_RUN, &(dev)->state) | ||
62 | #define fimc_capture_pending(dev) test_bit(ST_CAPT_PEND, &(dev)->state) | ||
63 | |||
64 | #define fimc_capture_active(dev) \ | ||
65 | (test_bit(ST_CAPT_RUN, &(dev)->state) || \ | ||
66 | test_bit(ST_CAPT_PEND, &(dev)->state)) | ||
67 | |||
68 | #define fimc_capture_streaming(dev) \ | ||
69 | test_bit(ST_CAPT_STREAM, &(dev)->state) | ||
70 | |||
71 | #define fimc_buf_finish(dev, vid_buf) do { \ | ||
72 | spin_lock(&(dev)->irqlock); \ | ||
73 | (vid_buf)->vb.state = VIDEOBUF_DONE; \ | ||
74 | spin_unlock(&(dev)->irqlock); \ | ||
75 | wake_up(&(vid_buf)->vb.done); \ | ||
76 | } while (0) | ||
77 | |||
47 | enum fimc_datapath { | 78 | enum fimc_datapath { |
48 | FIMC_ITU_CAM_A, | 79 | FIMC_CAMERA, |
49 | FIMC_ITU_CAM_B, | ||
50 | FIMC_MIPI_CAM, | ||
51 | FIMC_DMA, | 80 | FIMC_DMA, |
52 | FIMC_LCDFIFO, | 81 | FIMC_LCDFIFO, |
53 | FIMC_WRITEBACK | 82 | FIMC_WRITEBACK |
54 | }; | 83 | }; |
55 | 84 | ||
56 | enum fimc_color_fmt { | 85 | enum fimc_color_fmt { |
57 | S5P_FIMC_RGB565, | 86 | S5P_FIMC_RGB565 = 0x10, |
58 | S5P_FIMC_RGB666, | 87 | S5P_FIMC_RGB666, |
59 | S5P_FIMC_RGB888, | 88 | S5P_FIMC_RGB888, |
60 | S5P_FIMC_YCBCR420, | 89 | S5P_FIMC_RGB30_LOCAL, |
90 | S5P_FIMC_YCBCR420 = 0x20, | ||
61 | S5P_FIMC_YCBCR422, | 91 | S5P_FIMC_YCBCR422, |
62 | S5P_FIMC_YCBYCR422, | 92 | S5P_FIMC_YCBYCR422, |
63 | S5P_FIMC_YCRYCB422, | 93 | S5P_FIMC_YCRYCB422, |
64 | S5P_FIMC_CBYCRY422, | 94 | S5P_FIMC_CBYCRY422, |
65 | S5P_FIMC_CRYCBY422, | 95 | S5P_FIMC_CRYCBY422, |
66 | S5P_FIMC_RGB30_LOCAL, | ||
67 | S5P_FIMC_YCBCR444_LOCAL, | 96 | S5P_FIMC_YCBCR444_LOCAL, |
68 | S5P_FIMC_MAX_COLOR = S5P_FIMC_YCBCR444_LOCAL, | ||
69 | S5P_FIMC_COLOR_MASK = 0x0F, | ||
70 | }; | 97 | }; |
71 | 98 | ||
99 | #define fimc_fmt_is_rgb(x) ((x) & 0x10) | ||
100 | |||
72 | /* Y/Cb/Cr components order at DMA output for 1 plane YCbCr 4:2:2 formats. */ | 101 | /* Y/Cb/Cr components order at DMA output for 1 plane YCbCr 4:2:2 formats. */ |
73 | #define S5P_FIMC_OUT_CRYCBY S5P_CIOCTRL_ORDER422_CRYCBY | 102 | #define S5P_FIMC_OUT_CRYCBY S5P_CIOCTRL_ORDER422_CRYCBY |
74 | #define S5P_FIMC_OUT_CBYCRY S5P_CIOCTRL_ORDER422_YCRYCB | 103 | #define S5P_FIMC_OUT_CBYCRY S5P_CIOCTRL_ORDER422_YCRYCB |
@@ -93,11 +122,13 @@ enum fimc_color_fmt { | |||
93 | #define S5P_FIMC_EFFECT_SIKHOUETTE S5P_CIIMGEFF_FIN_SILHOUETTE | 122 | #define S5P_FIMC_EFFECT_SIKHOUETTE S5P_CIIMGEFF_FIN_SILHOUETTE |
94 | 123 | ||
95 | /* The hardware context state. */ | 124 | /* The hardware context state. */ |
96 | #define FIMC_PARAMS (1 << 0) | 125 | #define FIMC_PARAMS (1 << 0) |
97 | #define FIMC_SRC_ADDR (1 << 1) | 126 | #define FIMC_SRC_ADDR (1 << 1) |
98 | #define FIMC_DST_ADDR (1 << 2) | 127 | #define FIMC_DST_ADDR (1 << 2) |
99 | #define FIMC_SRC_FMT (1 << 3) | 128 | #define FIMC_SRC_FMT (1 << 3) |
100 | #define FIMC_DST_FMT (1 << 4) | 129 | #define FIMC_DST_FMT (1 << 4) |
130 | #define FIMC_CTX_M2M (1 << 5) | ||
131 | #define FIMC_CTX_CAP (1 << 6) | ||
101 | 132 | ||
102 | /* Image conversion flags */ | 133 | /* Image conversion flags */ |
103 | #define FIMC_IN_DMA_ACCESS_TILED (1 << 0) | 134 | #define FIMC_IN_DMA_ACCESS_TILED (1 << 0) |
@@ -106,7 +137,9 @@ enum fimc_color_fmt { | |||
106 | #define FIMC_OUT_DMA_ACCESS_LINEAR (0 << 1) | 137 | #define FIMC_OUT_DMA_ACCESS_LINEAR (0 << 1) |
107 | #define FIMC_SCAN_MODE_PROGRESSIVE (0 << 2) | 138 | #define FIMC_SCAN_MODE_PROGRESSIVE (0 << 2) |
108 | #define FIMC_SCAN_MODE_INTERLACED (1 << 2) | 139 | #define FIMC_SCAN_MODE_INTERLACED (1 << 2) |
109 | /* YCbCr data dynamic range for RGB-YUV color conversion. Y/Cb/Cr: (0 ~ 255) */ | 140 | /* |
141 | * YCbCr data dynamic range for RGB-YUV color conversion. | ||
142 | * Y/Cb/Cr: (0 ~ 255) */ | ||
110 | #define FIMC_COLOR_RANGE_WIDE (0 << 3) | 143 | #define FIMC_COLOR_RANGE_WIDE (0 << 3) |
111 | /* Y (16 ~ 235), Cb/Cr (16 ~ 240) */ | 144 | /* Y (16 ~ 235), Cb/Cr (16 ~ 240) */ |
112 | #define FIMC_COLOR_RANGE_NARROW (1 << 3) | 145 | #define FIMC_COLOR_RANGE_NARROW (1 << 3) |
@@ -118,20 +151,25 @@ enum fimc_color_fmt { | |||
118 | 151 | ||
119 | /** | 152 | /** |
120 | * struct fimc_fmt - the driver's internal color format data | 153 | * struct fimc_fmt - the driver's internal color format data |
154 | * @mbus_code: Media Bus pixel code, -1 if not applicable | ||
121 | * @name: format description | 155 | * @name: format description |
122 | * @fourcc: the fourcc code for this format | 156 | * @fourcc: the fourcc code for this format, 0 if not applicable |
123 | * @color: the corresponding fimc_color_fmt | 157 | * @color: the corresponding fimc_color_fmt |
124 | * @depth: number of bits per pixel | 158 | * @depth: driver's private 'number of bits per pixel' |
125 | * @buff_cnt: number of physically non-contiguous data planes | 159 | * @buff_cnt: number of physically non-contiguous data planes |
126 | * @planes_cnt: number of physically contiguous data planes | 160 | * @planes_cnt: number of physically contiguous data planes |
127 | */ | 161 | */ |
128 | struct fimc_fmt { | 162 | struct fimc_fmt { |
163 | enum v4l2_mbus_pixelcode mbus_code; | ||
129 | char *name; | 164 | char *name; |
130 | u32 fourcc; | 165 | u32 fourcc; |
131 | u32 color; | 166 | u32 color; |
132 | u32 depth; | ||
133 | u16 buff_cnt; | 167 | u16 buff_cnt; |
134 | u16 planes_cnt; | 168 | u16 planes_cnt; |
169 | u16 depth; | ||
170 | u16 flags; | ||
171 | #define FMT_FLAGS_CAM (1 << 0) | ||
172 | #define FMT_FLAGS_M2M (1 << 1) | ||
135 | }; | 173 | }; |
136 | 174 | ||
137 | /** | 175 | /** |
@@ -167,37 +205,37 @@ struct fimc_effect { | |||
167 | /** | 205 | /** |
168 | * struct fimc_scaler - the configuration data for FIMC inetrnal scaler | 206 | * struct fimc_scaler - the configuration data for FIMC inetrnal scaler |
169 | * | 207 | * |
170 | * @enabled: the flag set when the scaler is used | 208 | * @scaleup_h: flag indicating scaling up horizontally |
209 | * @scaleup_v: flag indicating scaling up vertically | ||
210 | * @copy_mode: flag indicating transparent DMA transfer (no scaling | ||
211 | * and color format conversion) | ||
212 | * @enabled: flag indicating if the scaler is used | ||
171 | * @hfactor: horizontal shift factor | 213 | * @hfactor: horizontal shift factor |
172 | * @vfactor: vertical shift factor | 214 | * @vfactor: vertical shift factor |
173 | * @pre_hratio: horizontal ratio of the prescaler | 215 | * @pre_hratio: horizontal ratio of the prescaler |
174 | * @pre_vratio: vertical ratio of the prescaler | 216 | * @pre_vratio: vertical ratio of the prescaler |
175 | * @pre_dst_width: the prescaler's destination width | 217 | * @pre_dst_width: the prescaler's destination width |
176 | * @pre_dst_height: the prescaler's destination height | 218 | * @pre_dst_height: the prescaler's destination height |
177 | * @scaleup_h: flag indicating scaling up horizontally | ||
178 | * @scaleup_v: flag indicating scaling up vertically | ||
179 | * @main_hratio: the main scaler's horizontal ratio | 219 | * @main_hratio: the main scaler's horizontal ratio |
180 | * @main_vratio: the main scaler's vertical ratio | 220 | * @main_vratio: the main scaler's vertical ratio |
181 | * @real_width: source width - offset | 221 | * @real_width: source pixel (width - offset) |
182 | * @real_height: source height - offset | 222 | * @real_height: source pixel (height - offset) |
183 | * @copy_mode: flag set if one-to-one mode is used, i.e. no scaling | ||
184 | * and color format conversion | ||
185 | */ | 223 | */ |
186 | struct fimc_scaler { | 224 | struct fimc_scaler { |
187 | u32 enabled; | 225 | unsigned int scaleup_h:1; |
226 | unsigned int scaleup_v:1; | ||
227 | unsigned int copy_mode:1; | ||
228 | unsigned int enabled:1; | ||
188 | u32 hfactor; | 229 | u32 hfactor; |
189 | u32 vfactor; | 230 | u32 vfactor; |
190 | u32 pre_hratio; | 231 | u32 pre_hratio; |
191 | u32 pre_vratio; | 232 | u32 pre_vratio; |
192 | u32 pre_dst_width; | 233 | u32 pre_dst_width; |
193 | u32 pre_dst_height; | 234 | u32 pre_dst_height; |
194 | u32 scaleup_h; | ||
195 | u32 scaleup_v; | ||
196 | u32 main_hratio; | 235 | u32 main_hratio; |
197 | u32 main_vratio; | 236 | u32 main_vratio; |
198 | u32 real_width; | 237 | u32 real_width; |
199 | u32 real_height; | 238 | u32 real_height; |
200 | u32 copy_mode; | ||
201 | }; | 239 | }; |
202 | 240 | ||
203 | /** | 241 | /** |
@@ -215,15 +253,18 @@ struct fimc_addr { | |||
215 | 253 | ||
216 | /** | 254 | /** |
217 | * struct fimc_vid_buffer - the driver's video buffer | 255 | * struct fimc_vid_buffer - the driver's video buffer |
218 | * @vb: v4l videobuf buffer | 256 | * @vb: v4l videobuf buffer |
257 | * @paddr: precalculated physical address set | ||
258 | * @index: buffer index for the output DMA engine | ||
219 | */ | 259 | */ |
220 | struct fimc_vid_buffer { | 260 | struct fimc_vid_buffer { |
221 | struct videobuf_buffer vb; | 261 | struct videobuf_buffer vb; |
262 | struct fimc_addr paddr; | ||
263 | int index; | ||
222 | }; | 264 | }; |
223 | 265 | ||
224 | /** | 266 | /** |
225 | * struct fimc_frame - input/output frame format properties | 267 | * struct fimc_frame - source/target frame properties |
226 | * | ||
227 | * @f_width: image full width (virtual screen size) | 268 | * @f_width: image full width (virtual screen size) |
228 | * @f_height: image full height (virtual screen size) | 269 | * @f_height: image full height (virtual screen size) |
229 | * @o_width: original image width as set by S_FMT | 270 | * @o_width: original image width as set by S_FMT |
@@ -270,67 +311,119 @@ struct fimc_m2m_device { | |||
270 | }; | 311 | }; |
271 | 312 | ||
272 | /** | 313 | /** |
314 | * struct fimc_vid_cap - camera capture device information | ||
315 | * @ctx: hardware context data | ||
316 | * @vfd: video device node for camera capture mode | ||
317 | * @v4l2_dev: v4l2_device struct to manage subdevs | ||
318 | * @sd: pointer to camera sensor subdevice currently in use | ||
319 | * @fmt: Media Bus format configured at selected image sensor | ||
320 | * @pending_buf_q: the pending buffer queue head | ||
321 | * @active_buf_q: the queue head of buffers scheduled in hardware | ||
322 | * @vbq: the capture am video buffer queue | ||
323 | * @active_buf_cnt: number of video buffers scheduled in hardware | ||
324 | * @buf_index: index for managing the output DMA buffers | ||
325 | * @frame_count: the frame counter for statistics | ||
326 | * @reqbufs_count: the number of buffers requested in REQBUFS ioctl | ||
327 | * @input_index: input (camera sensor) index | ||
328 | * @refcnt: driver's private reference counter | ||
329 | */ | ||
330 | struct fimc_vid_cap { | ||
331 | struct fimc_ctx *ctx; | ||
332 | struct video_device *vfd; | ||
333 | struct v4l2_device v4l2_dev; | ||
334 | struct v4l2_subdev *sd; | ||
335 | struct v4l2_mbus_framefmt fmt; | ||
336 | struct list_head pending_buf_q; | ||
337 | struct list_head active_buf_q; | ||
338 | struct videobuf_queue vbq; | ||
339 | int active_buf_cnt; | ||
340 | int buf_index; | ||
341 | unsigned int frame_count; | ||
342 | unsigned int reqbufs_count; | ||
343 | int input_index; | ||
344 | int refcnt; | ||
345 | }; | ||
346 | |||
347 | /** | ||
348 | * struct fimc_pix_limit - image pixel size limits in various IP configurations | ||
349 | * | ||
350 | * @scaler_en_w: max input pixel width when the scaler is enabled | ||
351 | * @scaler_dis_w: max input pixel width when the scaler is disabled | ||
352 | * @in_rot_en_h: max input width with the input rotator is on | ||
353 | * @in_rot_dis_w: max input width with the input rotator is off | ||
354 | * @out_rot_en_w: max output width with the output rotator on | ||
355 | * @out_rot_dis_w: max output width with the output rotator off | ||
356 | */ | ||
357 | struct fimc_pix_limit { | ||
358 | u16 scaler_en_w; | ||
359 | u16 scaler_dis_w; | ||
360 | u16 in_rot_en_h; | ||
361 | u16 in_rot_dis_w; | ||
362 | u16 out_rot_en_w; | ||
363 | u16 out_rot_dis_w; | ||
364 | }; | ||
365 | |||
366 | /** | ||
273 | * struct samsung_fimc_variant - camera interface variant information | 367 | * struct samsung_fimc_variant - camera interface variant information |
274 | * | 368 | * |
275 | * @pix_hoff: indicate whether horizontal offset is in pixels or in bytes | 369 | * @pix_hoff: indicate whether horizontal offset is in pixels or in bytes |
276 | * @has_inp_rot: set if has input rotator | 370 | * @has_inp_rot: set if has input rotator |
277 | * @has_out_rot: set if has output rotator | 371 | * @has_out_rot: set if has output rotator |
372 | * @pix_limit: pixel size constraints for the scaler | ||
278 | * @min_inp_pixsize: minimum input pixel size | 373 | * @min_inp_pixsize: minimum input pixel size |
279 | * @min_out_pixsize: minimum output pixel size | 374 | * @min_out_pixsize: minimum output pixel size |
280 | * @scaler_en_w: maximum input pixel width when the scaler is enabled | 375 | * @hor_offs_align: horizontal pixel offset aligment |
281 | * @scaler_dis_w: maximum input pixel width when the scaler is disabled | 376 | * @out_buf_count: the number of buffers in output DMA sequence |
282 | * @in_rot_en_h: maximum input width when the input rotator is used | ||
283 | * @in_rot_dis_w: maximum input width when the input rotator is used | ||
284 | * @out_rot_en_w: maximum output width for the output rotator enabled | ||
285 | * @out_rot_dis_w: maximum output width for the output rotator enabled | ||
286 | */ | 377 | */ |
287 | struct samsung_fimc_variant { | 378 | struct samsung_fimc_variant { |
288 | unsigned int pix_hoff:1; | 379 | unsigned int pix_hoff:1; |
289 | unsigned int has_inp_rot:1; | 380 | unsigned int has_inp_rot:1; |
290 | unsigned int has_out_rot:1; | 381 | unsigned int has_out_rot:1; |
291 | 382 | struct fimc_pix_limit *pix_limit; | |
292 | u16 min_inp_pixsize; | 383 | u16 min_inp_pixsize; |
293 | u16 min_out_pixsize; | 384 | u16 min_out_pixsize; |
294 | u16 scaler_en_w; | 385 | u16 hor_offs_align; |
295 | u16 scaler_dis_w; | 386 | u16 out_buf_count; |
296 | u16 in_rot_en_h; | ||
297 | u16 in_rot_dis_w; | ||
298 | u16 out_rot_en_w; | ||
299 | u16 out_rot_dis_w; | ||
300 | }; | 387 | }; |
301 | 388 | ||
302 | /** | 389 | /** |
303 | * struct samsung_fimc_driverdata - per-device type driver data for init time. | 390 | * struct samsung_fimc_driverdata - per device type driver data for init time. |
304 | * | 391 | * |
305 | * @variant: the variant information for this driver. | 392 | * @variant: the variant information for this driver. |
306 | * @dev_cnt: number of fimc sub-devices available in SoC | 393 | * @dev_cnt: number of fimc sub-devices available in SoC |
394 | * @lclk_frequency: fimc bus clock frequency | ||
307 | */ | 395 | */ |
308 | struct samsung_fimc_driverdata { | 396 | struct samsung_fimc_driverdata { |
309 | struct samsung_fimc_variant *variant[FIMC_MAX_DEVS]; | 397 | struct samsung_fimc_variant *variant[FIMC_MAX_DEVS]; |
310 | int devs_cnt; | 398 | unsigned long lclk_frequency; |
399 | int num_entities; | ||
311 | }; | 400 | }; |
312 | 401 | ||
313 | struct fimc_ctx; | 402 | struct fimc_ctx; |
314 | 403 | ||
315 | /** | 404 | /** |
316 | * struct fimc_subdev - abstraction for a FIMC entity | 405 | * struct fimc_dev - abstraction for FIMC entity |
317 | * | 406 | * |
318 | * @slock: the spinlock protecting this data structure | 407 | * @slock: the spinlock protecting this data structure |
319 | * @lock: the mutex protecting this data structure | 408 | * @lock: the mutex protecting this data structure |
320 | * @pdev: pointer to the FIMC platform device | 409 | * @pdev: pointer to the FIMC platform device |
410 | * @pdata: pointer to the device platform data | ||
321 | * @id: FIMC device index (0..2) | 411 | * @id: FIMC device index (0..2) |
322 | * @clock[]: the clocks required for FIMC operation | 412 | * @clock[]: the clocks required for FIMC operation |
323 | * @regs: the mapped hardware registers | 413 | * @regs: the mapped hardware registers |
324 | * @regs_res: the resource claimed for IO registers | 414 | * @regs_res: the resource claimed for IO registers |
325 | * @irq: interrupt number of the FIMC subdevice | 415 | * @irq: interrupt number of the FIMC subdevice |
326 | * @irqlock: spinlock protecting videbuffer queue | 416 | * @irqlock: spinlock protecting videobuffer queue |
417 | * @irq_queue: | ||
327 | * @m2m: memory-to-memory V4L2 device information | 418 | * @m2m: memory-to-memory V4L2 device information |
328 | * @state: the FIMC device state flags | 419 | * @vid_cap: camera capture device information |
420 | * @state: flags used to synchronize m2m and capture mode operation | ||
329 | */ | 421 | */ |
330 | struct fimc_dev { | 422 | struct fimc_dev { |
331 | spinlock_t slock; | 423 | spinlock_t slock; |
332 | struct mutex lock; | 424 | struct mutex lock; |
333 | struct platform_device *pdev; | 425 | struct platform_device *pdev; |
426 | struct s3c_platform_fimc *pdata; | ||
334 | struct samsung_fimc_variant *variant; | 427 | struct samsung_fimc_variant *variant; |
335 | int id; | 428 | int id; |
336 | struct clk *clock[NUM_FIMC_CLOCKS]; | 429 | struct clk *clock[NUM_FIMC_CLOCKS]; |
@@ -338,8 +431,9 @@ struct fimc_dev { | |||
338 | struct resource *regs_res; | 431 | struct resource *regs_res; |
339 | int irq; | 432 | int irq; |
340 | spinlock_t irqlock; | 433 | spinlock_t irqlock; |
341 | struct workqueue_struct *work_queue; | 434 | wait_queue_head_t irq_queue; |
342 | struct fimc_m2m_device m2m; | 435 | struct fimc_m2m_device m2m; |
436 | struct fimc_vid_cap vid_cap; | ||
343 | unsigned long state; | 437 | unsigned long state; |
344 | }; | 438 | }; |
345 | 439 | ||
@@ -359,7 +453,7 @@ struct fimc_dev { | |||
359 | * @effect: image effect | 453 | * @effect: image effect |
360 | * @rotation: image clockwise rotation in degrees | 454 | * @rotation: image clockwise rotation in degrees |
361 | * @flip: image flip mode | 455 | * @flip: image flip mode |
362 | * @flags: an additional flags for image conversion | 456 | * @flags: additional flags for image conversion |
363 | * @state: flags to keep track of user configuration | 457 | * @state: flags to keep track of user configuration |
364 | * @fimc_dev: the FIMC device this context applies to | 458 | * @fimc_dev: the FIMC device this context applies to |
365 | * @m2m_ctx: memory-to-memory device context | 459 | * @m2m_ctx: memory-to-memory device context |
@@ -384,6 +478,7 @@ struct fimc_ctx { | |||
384 | struct v4l2_m2m_ctx *m2m_ctx; | 478 | struct v4l2_m2m_ctx *m2m_ctx; |
385 | }; | 479 | }; |
386 | 480 | ||
481 | extern struct videobuf_queue_ops fimc_qops; | ||
387 | 482 | ||
388 | static inline int tiled_fmt(struct fimc_fmt *fmt) | 483 | static inline int tiled_fmt(struct fimc_fmt *fmt) |
389 | { | 484 | { |
@@ -397,18 +492,24 @@ static inline void fimc_hw_clear_irq(struct fimc_dev *dev) | |||
397 | writel(cfg, dev->regs + S5P_CIGCTRL); | 492 | writel(cfg, dev->regs + S5P_CIGCTRL); |
398 | } | 493 | } |
399 | 494 | ||
400 | static inline void fimc_hw_start_scaler(struct fimc_dev *dev) | 495 | static inline void fimc_hw_enable_scaler(struct fimc_dev *dev, bool on) |
401 | { | 496 | { |
402 | u32 cfg = readl(dev->regs + S5P_CISCCTRL); | 497 | u32 cfg = readl(dev->regs + S5P_CISCCTRL); |
403 | cfg |= S5P_CISCCTRL_SCALERSTART; | 498 | if (on) |
499 | cfg |= S5P_CISCCTRL_SCALERSTART; | ||
500 | else | ||
501 | cfg &= ~S5P_CISCCTRL_SCALERSTART; | ||
404 | writel(cfg, dev->regs + S5P_CISCCTRL); | 502 | writel(cfg, dev->regs + S5P_CISCCTRL); |
405 | } | 503 | } |
406 | 504 | ||
407 | static inline void fimc_hw_stop_scaler(struct fimc_dev *dev) | 505 | static inline void fimc_hw_activate_input_dma(struct fimc_dev *dev, bool on) |
408 | { | 506 | { |
409 | u32 cfg = readl(dev->regs + S5P_CISCCTRL); | 507 | u32 cfg = readl(dev->regs + S5P_MSCTRL); |
410 | cfg &= ~S5P_CISCCTRL_SCALERSTART; | 508 | if (on) |
411 | writel(cfg, dev->regs + S5P_CISCCTRL); | 509 | cfg |= S5P_MSCTRL_ENVID; |
510 | else | ||
511 | cfg &= ~S5P_MSCTRL_ENVID; | ||
512 | writel(cfg, dev->regs + S5P_MSCTRL); | ||
412 | } | 513 | } |
413 | 514 | ||
414 | static inline void fimc_hw_dis_capture(struct fimc_dev *dev) | 515 | static inline void fimc_hw_dis_capture(struct fimc_dev *dev) |
@@ -418,27 +519,30 @@ static inline void fimc_hw_dis_capture(struct fimc_dev *dev) | |||
418 | writel(cfg, dev->regs + S5P_CIIMGCPT); | 519 | writel(cfg, dev->regs + S5P_CIIMGCPT); |
419 | } | 520 | } |
420 | 521 | ||
421 | static inline void fimc_hw_start_in_dma(struct fimc_dev *dev) | 522 | /** |
422 | { | 523 | * fimc_hw_set_dma_seq - configure output DMA buffer sequence |
423 | u32 cfg = readl(dev->regs + S5P_MSCTRL); | 524 | * @mask: each bit corresponds to one of 32 output buffer registers set |
424 | cfg |= S5P_MSCTRL_ENVID; | 525 | * 1 to include buffer in the sequence, 0 to disable |
425 | writel(cfg, dev->regs + S5P_MSCTRL); | 526 | * |
426 | } | 527 | * This function mask output DMA ring buffers, i.e. it allows to configure |
427 | 528 | * which of the output buffer address registers will be used by the DMA | |
428 | static inline void fimc_hw_stop_in_dma(struct fimc_dev *dev) | 529 | * engine. |
530 | */ | ||
531 | static inline void fimc_hw_set_dma_seq(struct fimc_dev *dev, u32 mask) | ||
429 | { | 532 | { |
430 | u32 cfg = readl(dev->regs + S5P_MSCTRL); | 533 | writel(mask, dev->regs + S5P_CIFCNTSEQ); |
431 | cfg &= ~S5P_MSCTRL_ENVID; | ||
432 | writel(cfg, dev->regs + S5P_MSCTRL); | ||
433 | } | 534 | } |
434 | 535 | ||
435 | static inline struct fimc_frame *ctx_m2m_get_frame(struct fimc_ctx *ctx, | 536 | static inline struct fimc_frame *ctx_get_frame(struct fimc_ctx *ctx, |
436 | enum v4l2_buf_type type) | 537 | enum v4l2_buf_type type) |
437 | { | 538 | { |
438 | struct fimc_frame *frame; | 539 | struct fimc_frame *frame; |
439 | 540 | ||
440 | if (V4L2_BUF_TYPE_VIDEO_OUTPUT == type) { | 541 | if (V4L2_BUF_TYPE_VIDEO_OUTPUT == type) { |
441 | frame = &ctx->s_frame; | 542 | if (ctx->state & FIMC_CTX_M2M) |
543 | frame = &ctx->s_frame; | ||
544 | else | ||
545 | return ERR_PTR(-EINVAL); | ||
442 | } else if (V4L2_BUF_TYPE_VIDEO_CAPTURE == type) { | 546 | } else if (V4L2_BUF_TYPE_VIDEO_CAPTURE == type) { |
443 | frame = &ctx->d_frame; | 547 | frame = &ctx->d_frame; |
444 | } else { | 548 | } else { |
@@ -450,22 +554,137 @@ static inline struct fimc_frame *ctx_m2m_get_frame(struct fimc_ctx *ctx, | |||
450 | return frame; | 554 | return frame; |
451 | } | 555 | } |
452 | 556 | ||
557 | static inline u32 fimc_hw_get_frame_index(struct fimc_dev *dev) | ||
558 | { | ||
559 | u32 reg = readl(dev->regs + S5P_CISTATUS); | ||
560 | return (reg & S5P_CISTATUS_FRAMECNT_MASK) >> | ||
561 | S5P_CISTATUS_FRAMECNT_SHIFT; | ||
562 | } | ||
563 | |||
453 | /* -----------------------------------------------------*/ | 564 | /* -----------------------------------------------------*/ |
454 | /* fimc-reg.c */ | 565 | /* fimc-reg.c */ |
455 | void fimc_hw_reset(struct fimc_dev *dev); | 566 | void fimc_hw_reset(struct fimc_dev *fimc); |
456 | void fimc_hw_set_rotation(struct fimc_ctx *ctx); | 567 | void fimc_hw_set_rotation(struct fimc_ctx *ctx); |
457 | void fimc_hw_set_target_format(struct fimc_ctx *ctx); | 568 | void fimc_hw_set_target_format(struct fimc_ctx *ctx); |
458 | void fimc_hw_set_out_dma(struct fimc_ctx *ctx); | 569 | void fimc_hw_set_out_dma(struct fimc_ctx *ctx); |
459 | void fimc_hw_en_lastirq(struct fimc_dev *dev, int enable); | 570 | void fimc_hw_en_lastirq(struct fimc_dev *fimc, int enable); |
460 | void fimc_hw_en_irq(struct fimc_dev *dev, int enable); | 571 | void fimc_hw_en_irq(struct fimc_dev *fimc, int enable); |
461 | void fimc_hw_set_prescaler(struct fimc_ctx *ctx); | ||
462 | void fimc_hw_set_scaler(struct fimc_ctx *ctx); | 572 | void fimc_hw_set_scaler(struct fimc_ctx *ctx); |
463 | void fimc_hw_en_capture(struct fimc_ctx *ctx); | 573 | void fimc_hw_en_capture(struct fimc_ctx *ctx); |
464 | void fimc_hw_set_effect(struct fimc_ctx *ctx); | 574 | void fimc_hw_set_effect(struct fimc_ctx *ctx); |
465 | void fimc_hw_set_in_dma(struct fimc_ctx *ctx); | 575 | void fimc_hw_set_in_dma(struct fimc_ctx *ctx); |
466 | void fimc_hw_set_input_path(struct fimc_ctx *ctx); | 576 | void fimc_hw_set_input_path(struct fimc_ctx *ctx); |
467 | void fimc_hw_set_output_path(struct fimc_ctx *ctx); | 577 | void fimc_hw_set_output_path(struct fimc_ctx *ctx); |
468 | void fimc_hw_set_input_addr(struct fimc_dev *dev, struct fimc_addr *paddr); | 578 | void fimc_hw_set_input_addr(struct fimc_dev *fimc, struct fimc_addr *paddr); |
469 | void fimc_hw_set_output_addr(struct fimc_dev *dev, struct fimc_addr *paddr); | 579 | void fimc_hw_set_output_addr(struct fimc_dev *fimc, struct fimc_addr *paddr, |
580 | int index); | ||
581 | int fimc_hw_set_camera_source(struct fimc_dev *fimc, | ||
582 | struct s3c_fimc_isp_info *cam); | ||
583 | int fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f); | ||
584 | int fimc_hw_set_camera_polarity(struct fimc_dev *fimc, | ||
585 | struct s3c_fimc_isp_info *cam); | ||
586 | int fimc_hw_set_camera_type(struct fimc_dev *fimc, | ||
587 | struct s3c_fimc_isp_info *cam); | ||
588 | |||
589 | /* -----------------------------------------------------*/ | ||
590 | /* fimc-core.c */ | ||
591 | int fimc_vidioc_enum_fmt(struct file *file, void *priv, | ||
592 | struct v4l2_fmtdesc *f); | ||
593 | int fimc_vidioc_g_fmt(struct file *file, void *priv, | ||
594 | struct v4l2_format *f); | ||
595 | int fimc_vidioc_try_fmt(struct file *file, void *priv, | ||
596 | struct v4l2_format *f); | ||
597 | int fimc_vidioc_g_crop(struct file *file, void *fh, | ||
598 | struct v4l2_crop *cr); | ||
599 | int fimc_vidioc_cropcap(struct file *file, void *fh, | ||
600 | struct v4l2_cropcap *cr); | ||
601 | int fimc_vidioc_queryctrl(struct file *file, void *priv, | ||
602 | struct v4l2_queryctrl *qc); | ||
603 | int fimc_vidioc_g_ctrl(struct file *file, void *priv, | ||
604 | struct v4l2_control *ctrl); | ||
605 | |||
606 | int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr); | ||
607 | int check_ctrl_val(struct fimc_ctx *ctx, struct v4l2_control *ctrl); | ||
608 | int fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_control *ctrl); | ||
609 | |||
610 | struct fimc_fmt *find_format(struct v4l2_format *f, unsigned int mask); | ||
611 | struct fimc_fmt *find_mbus_format(struct v4l2_mbus_framefmt *f, | ||
612 | unsigned int mask); | ||
613 | |||
614 | int fimc_check_scaler_ratio(struct v4l2_rect *r, struct fimc_frame *f); | ||
615 | int fimc_set_scaler_info(struct fimc_ctx *ctx); | ||
616 | int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags); | ||
617 | int fimc_prepare_addr(struct fimc_ctx *ctx, struct fimc_vid_buffer *buf, | ||
618 | struct fimc_frame *frame, struct fimc_addr *paddr); | ||
619 | |||
620 | /* -----------------------------------------------------*/ | ||
621 | /* fimc-capture.c */ | ||
622 | int fimc_register_capture_device(struct fimc_dev *fimc); | ||
623 | void fimc_unregister_capture_device(struct fimc_dev *fimc); | ||
624 | int fimc_sensor_sd_init(struct fimc_dev *fimc, int index); | ||
625 | int fimc_vid_cap_buf_queue(struct fimc_dev *fimc, | ||
626 | struct fimc_vid_buffer *fimc_vb); | ||
627 | |||
628 | /* Locking: the caller holds fimc->slock */ | ||
629 | static inline void fimc_activate_capture(struct fimc_ctx *ctx) | ||
630 | { | ||
631 | fimc_hw_enable_scaler(ctx->fimc_dev, ctx->scaler.enabled); | ||
632 | fimc_hw_en_capture(ctx); | ||
633 | } | ||
634 | |||
635 | static inline void fimc_deactivate_capture(struct fimc_dev *fimc) | ||
636 | { | ||
637 | fimc_hw_en_lastirq(fimc, true); | ||
638 | fimc_hw_dis_capture(fimc); | ||
639 | fimc_hw_enable_scaler(fimc, false); | ||
640 | fimc_hw_en_lastirq(fimc, false); | ||
641 | } | ||
642 | |||
643 | /* | ||
644 | * Add video buffer to the active buffers queue. | ||
645 | * The caller holds irqlock spinlock. | ||
646 | */ | ||
647 | static inline void active_queue_add(struct fimc_vid_cap *vid_cap, | ||
648 | struct fimc_vid_buffer *buf) | ||
649 | { | ||
650 | buf->vb.state = VIDEOBUF_ACTIVE; | ||
651 | list_add_tail(&buf->vb.queue, &vid_cap->active_buf_q); | ||
652 | vid_cap->active_buf_cnt++; | ||
653 | } | ||
654 | |||
655 | /* | ||
656 | * Pop a video buffer from the capture active buffers queue | ||
657 | * Locking: Need to be called with dev->slock held. | ||
658 | */ | ||
659 | static inline struct fimc_vid_buffer * | ||
660 | active_queue_pop(struct fimc_vid_cap *vid_cap) | ||
661 | { | ||
662 | struct fimc_vid_buffer *buf; | ||
663 | buf = list_entry(vid_cap->active_buf_q.next, | ||
664 | struct fimc_vid_buffer, vb.queue); | ||
665 | list_del(&buf->vb.queue); | ||
666 | vid_cap->active_buf_cnt--; | ||
667 | return buf; | ||
668 | } | ||
669 | |||
670 | /* Add video buffer to the capture pending buffers queue */ | ||
671 | static inline void fimc_pending_queue_add(struct fimc_vid_cap *vid_cap, | ||
672 | struct fimc_vid_buffer *buf) | ||
673 | { | ||
674 | buf->vb.state = VIDEOBUF_QUEUED; | ||
675 | list_add_tail(&buf->vb.queue, &vid_cap->pending_buf_q); | ||
676 | } | ||
677 | |||
678 | /* Add video buffer to the capture pending buffers queue */ | ||
679 | static inline struct fimc_vid_buffer * | ||
680 | pending_queue_pop(struct fimc_vid_cap *vid_cap) | ||
681 | { | ||
682 | struct fimc_vid_buffer *buf; | ||
683 | buf = list_entry(vid_cap->pending_buf_q.next, | ||
684 | struct fimc_vid_buffer, vb.queue); | ||
685 | list_del(&buf->vb.queue); | ||
686 | return buf; | ||
687 | } | ||
688 | |||
470 | 689 | ||
471 | #endif /* FIMC_CORE_H_ */ | 690 | #endif /* FIMC_CORE_H_ */ |
diff --git a/drivers/media/video/s5p-fimc/fimc-reg.c b/drivers/media/video/s5p-fimc/fimc-reg.c index 5570f1ce0c9c..511631a2e5c3 100644 --- a/drivers/media/video/s5p-fimc/fimc-reg.c +++ b/drivers/media/video/s5p-fimc/fimc-reg.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/io.h> | 13 | #include <linux/io.h> |
14 | #include <linux/delay.h> | 14 | #include <linux/delay.h> |
15 | #include <mach/map.h> | 15 | #include <mach/map.h> |
16 | #include <media/s3c_fimc.h> | ||
16 | 17 | ||
17 | #include "fimc-core.h" | 18 | #include "fimc-core.h" |
18 | 19 | ||
@@ -29,49 +30,11 @@ void fimc_hw_reset(struct fimc_dev *dev) | |||
29 | cfg = readl(dev->regs + S5P_CIGCTRL); | 30 | cfg = readl(dev->regs + S5P_CIGCTRL); |
30 | cfg |= (S5P_CIGCTRL_SWRST | S5P_CIGCTRL_IRQ_LEVEL); | 31 | cfg |= (S5P_CIGCTRL_SWRST | S5P_CIGCTRL_IRQ_LEVEL); |
31 | writel(cfg, dev->regs + S5P_CIGCTRL); | 32 | writel(cfg, dev->regs + S5P_CIGCTRL); |
32 | msleep(1); | 33 | udelay(1000); |
33 | 34 | ||
34 | cfg = readl(dev->regs + S5P_CIGCTRL); | 35 | cfg = readl(dev->regs + S5P_CIGCTRL); |
35 | cfg &= ~S5P_CIGCTRL_SWRST; | 36 | cfg &= ~S5P_CIGCTRL_SWRST; |
36 | writel(cfg, dev->regs + S5P_CIGCTRL); | 37 | writel(cfg, dev->regs + S5P_CIGCTRL); |
37 | |||
38 | } | ||
39 | |||
40 | void fimc_hw_set_rotation(struct fimc_ctx *ctx) | ||
41 | { | ||
42 | u32 cfg, flip; | ||
43 | struct fimc_dev *dev = ctx->fimc_dev; | ||
44 | |||
45 | cfg = readl(dev->regs + S5P_CITRGFMT); | ||
46 | cfg &= ~(S5P_CITRGFMT_INROT90 | S5P_CITRGFMT_OUTROT90); | ||
47 | |||
48 | flip = readl(dev->regs + S5P_MSCTRL); | ||
49 | flip &= ~S5P_MSCTRL_FLIP_MASK; | ||
50 | |||
51 | /* | ||
52 | * The input and output rotator cannot work simultaneously. | ||
53 | * Use the output rotator in output DMA mode or the input rotator | ||
54 | * in direct fifo output mode. | ||
55 | */ | ||
56 | if (ctx->rotation == 90 || ctx->rotation == 270) { | ||
57 | if (ctx->out_path == FIMC_LCDFIFO) { | ||
58 | cfg |= S5P_CITRGFMT_INROT90; | ||
59 | if (ctx->rotation == 270) | ||
60 | flip |= S5P_MSCTRL_FLIP_180; | ||
61 | } else { | ||
62 | cfg |= S5P_CITRGFMT_OUTROT90; | ||
63 | if (ctx->rotation == 270) | ||
64 | cfg |= S5P_CITRGFMT_FLIP_180; | ||
65 | } | ||
66 | } else if (ctx->rotation == 180) { | ||
67 | if (ctx->out_path == FIMC_LCDFIFO) | ||
68 | flip |= S5P_MSCTRL_FLIP_180; | ||
69 | else | ||
70 | cfg |= S5P_CITRGFMT_FLIP_180; | ||
71 | } | ||
72 | if (ctx->rotation == 180 || ctx->rotation == 270) | ||
73 | writel(flip, dev->regs + S5P_MSCTRL); | ||
74 | writel(cfg, dev->regs + S5P_CITRGFMT); | ||
75 | } | 38 | } |
76 | 39 | ||
77 | static u32 fimc_hw_get_in_flip(u32 ctx_flip) | 40 | static u32 fimc_hw_get_in_flip(u32 ctx_flip) |
@@ -114,6 +77,46 @@ static u32 fimc_hw_get_target_flip(u32 ctx_flip) | |||
114 | return flip; | 77 | return flip; |
115 | } | 78 | } |
116 | 79 | ||
80 | void fimc_hw_set_rotation(struct fimc_ctx *ctx) | ||
81 | { | ||
82 | u32 cfg, flip; | ||
83 | struct fimc_dev *dev = ctx->fimc_dev; | ||
84 | |||
85 | cfg = readl(dev->regs + S5P_CITRGFMT); | ||
86 | cfg &= ~(S5P_CITRGFMT_INROT90 | S5P_CITRGFMT_OUTROT90 | | ||
87 | S5P_CITRGFMT_FLIP_180); | ||
88 | |||
89 | flip = readl(dev->regs + S5P_MSCTRL); | ||
90 | flip &= ~S5P_MSCTRL_FLIP_MASK; | ||
91 | |||
92 | /* | ||
93 | * The input and output rotator cannot work simultaneously. | ||
94 | * Use the output rotator in output DMA mode or the input rotator | ||
95 | * in direct fifo output mode. | ||
96 | */ | ||
97 | if (ctx->rotation == 90 || ctx->rotation == 270) { | ||
98 | if (ctx->out_path == FIMC_LCDFIFO) { | ||
99 | cfg |= S5P_CITRGFMT_INROT90; | ||
100 | if (ctx->rotation == 270) | ||
101 | flip |= S5P_MSCTRL_FLIP_180; | ||
102 | } else { | ||
103 | cfg |= S5P_CITRGFMT_OUTROT90; | ||
104 | if (ctx->rotation == 270) | ||
105 | cfg |= S5P_CITRGFMT_FLIP_180; | ||
106 | } | ||
107 | } else if (ctx->rotation == 180) { | ||
108 | if (ctx->out_path == FIMC_LCDFIFO) | ||
109 | flip |= S5P_MSCTRL_FLIP_180; | ||
110 | else | ||
111 | cfg |= S5P_CITRGFMT_FLIP_180; | ||
112 | } | ||
113 | if (ctx->rotation == 180 || ctx->rotation == 270) | ||
114 | writel(flip, dev->regs + S5P_MSCTRL); | ||
115 | |||
116 | cfg |= fimc_hw_get_target_flip(ctx->flip); | ||
117 | writel(cfg, dev->regs + S5P_CITRGFMT); | ||
118 | } | ||
119 | |||
117 | void fimc_hw_set_target_format(struct fimc_ctx *ctx) | 120 | void fimc_hw_set_target_format(struct fimc_ctx *ctx) |
118 | { | 121 | { |
119 | u32 cfg; | 122 | u32 cfg; |
@@ -149,13 +152,15 @@ void fimc_hw_set_target_format(struct fimc_ctx *ctx) | |||
149 | break; | 152 | break; |
150 | } | 153 | } |
151 | 154 | ||
152 | cfg |= S5P_CITRGFMT_HSIZE(frame->width); | 155 | if (ctx->rotation == 90 || ctx->rotation == 270) { |
153 | cfg |= S5P_CITRGFMT_VSIZE(frame->height); | 156 | cfg |= S5P_CITRGFMT_HSIZE(frame->height); |
157 | cfg |= S5P_CITRGFMT_VSIZE(frame->width); | ||
158 | } else { | ||
154 | 159 | ||
155 | if (ctx->rotation == 0) { | 160 | cfg |= S5P_CITRGFMT_HSIZE(frame->width); |
156 | cfg &= ~S5P_CITRGFMT_FLIP_MASK; | 161 | cfg |= S5P_CITRGFMT_VSIZE(frame->height); |
157 | cfg |= fimc_hw_get_target_flip(ctx->flip); | ||
158 | } | 162 | } |
163 | |||
159 | writel(cfg, dev->regs + S5P_CITRGFMT); | 164 | writel(cfg, dev->regs + S5P_CITRGFMT); |
160 | 165 | ||
161 | cfg = readl(dev->regs + S5P_CITAREA) & ~S5P_CITAREA_MASK; | 166 | cfg = readl(dev->regs + S5P_CITAREA) & ~S5P_CITAREA_MASK; |
@@ -167,16 +172,20 @@ static void fimc_hw_set_out_dma_size(struct fimc_ctx *ctx) | |||
167 | { | 172 | { |
168 | struct fimc_dev *dev = ctx->fimc_dev; | 173 | struct fimc_dev *dev = ctx->fimc_dev; |
169 | struct fimc_frame *frame = &ctx->d_frame; | 174 | struct fimc_frame *frame = &ctx->d_frame; |
170 | u32 cfg = 0; | 175 | u32 cfg; |
171 | 176 | ||
172 | if (ctx->rotation == 90 || ctx->rotation == 270) { | 177 | cfg = S5P_ORIG_SIZE_HOR(frame->f_width); |
173 | cfg |= S5P_ORIG_SIZE_HOR(frame->f_height); | 178 | cfg |= S5P_ORIG_SIZE_VER(frame->f_height); |
174 | cfg |= S5P_ORIG_SIZE_VER(frame->f_width); | ||
175 | } else { | ||
176 | cfg |= S5P_ORIG_SIZE_HOR(frame->f_width); | ||
177 | cfg |= S5P_ORIG_SIZE_VER(frame->f_height); | ||
178 | } | ||
179 | writel(cfg, dev->regs + S5P_ORGOSIZE); | 179 | writel(cfg, dev->regs + S5P_ORGOSIZE); |
180 | |||
181 | /* Select color space conversion equation (HD/SD size).*/ | ||
182 | cfg = readl(dev->regs + S5P_CIGCTRL); | ||
183 | if (frame->f_width >= 1280) /* HD */ | ||
184 | cfg |= S5P_CIGCTRL_CSC_ITU601_709; | ||
185 | else /* SD */ | ||
186 | cfg &= ~S5P_CIGCTRL_CSC_ITU601_709; | ||
187 | writel(cfg, dev->regs + S5P_CIGCTRL); | ||
188 | |||
180 | } | 189 | } |
181 | 190 | ||
182 | void fimc_hw_set_out_dma(struct fimc_ctx *ctx) | 191 | void fimc_hw_set_out_dma(struct fimc_ctx *ctx) |
@@ -232,36 +241,28 @@ static void fimc_hw_en_autoload(struct fimc_dev *dev, int enable) | |||
232 | 241 | ||
233 | void fimc_hw_en_lastirq(struct fimc_dev *dev, int enable) | 242 | void fimc_hw_en_lastirq(struct fimc_dev *dev, int enable) |
234 | { | 243 | { |
235 | unsigned long flags; | 244 | u32 cfg = readl(dev->regs + S5P_CIOCTRL); |
236 | u32 cfg; | ||
237 | |||
238 | spin_lock_irqsave(&dev->slock, flags); | ||
239 | |||
240 | cfg = readl(dev->regs + S5P_CIOCTRL); | ||
241 | if (enable) | 245 | if (enable) |
242 | cfg |= S5P_CIOCTRL_LASTIRQ_ENABLE; | 246 | cfg |= S5P_CIOCTRL_LASTIRQ_ENABLE; |
243 | else | 247 | else |
244 | cfg &= ~S5P_CIOCTRL_LASTIRQ_ENABLE; | 248 | cfg &= ~S5P_CIOCTRL_LASTIRQ_ENABLE; |
245 | writel(cfg, dev->regs + S5P_CIOCTRL); | 249 | writel(cfg, dev->regs + S5P_CIOCTRL); |
246 | |||
247 | spin_unlock_irqrestore(&dev->slock, flags); | ||
248 | } | 250 | } |
249 | 251 | ||
250 | void fimc_hw_set_prescaler(struct fimc_ctx *ctx) | 252 | static void fimc_hw_set_prescaler(struct fimc_ctx *ctx) |
251 | { | 253 | { |
252 | struct fimc_dev *dev = ctx->fimc_dev; | 254 | struct fimc_dev *dev = ctx->fimc_dev; |
253 | struct fimc_scaler *sc = &ctx->scaler; | 255 | struct fimc_scaler *sc = &ctx->scaler; |
254 | u32 cfg = 0, shfactor; | 256 | u32 cfg, shfactor; |
255 | 257 | ||
256 | shfactor = 10 - (sc->hfactor + sc->vfactor); | 258 | shfactor = 10 - (sc->hfactor + sc->vfactor); |
257 | 259 | ||
258 | cfg |= S5P_CISCPRERATIO_SHFACTOR(shfactor); | 260 | cfg = S5P_CISCPRERATIO_SHFACTOR(shfactor); |
259 | cfg |= S5P_CISCPRERATIO_HOR(sc->pre_hratio); | 261 | cfg |= S5P_CISCPRERATIO_HOR(sc->pre_hratio); |
260 | cfg |= S5P_CISCPRERATIO_VER(sc->pre_vratio); | 262 | cfg |= S5P_CISCPRERATIO_VER(sc->pre_vratio); |
261 | writel(cfg, dev->regs + S5P_CISCPRERATIO); | 263 | writel(cfg, dev->regs + S5P_CISCPRERATIO); |
262 | 264 | ||
263 | cfg = 0; | 265 | cfg = S5P_CISCPREDST_WIDTH(sc->pre_dst_width); |
264 | cfg |= S5P_CISCPREDST_WIDTH(sc->pre_dst_width); | ||
265 | cfg |= S5P_CISCPREDST_HEIGHT(sc->pre_dst_height); | 266 | cfg |= S5P_CISCPREDST_HEIGHT(sc->pre_dst_height); |
266 | writel(cfg, dev->regs + S5P_CISCPREDST); | 267 | writel(cfg, dev->regs + S5P_CISCPREDST); |
267 | } | 268 | } |
@@ -274,6 +275,8 @@ void fimc_hw_set_scaler(struct fimc_ctx *ctx) | |||
274 | struct fimc_frame *dst_frame = &ctx->d_frame; | 275 | struct fimc_frame *dst_frame = &ctx->d_frame; |
275 | u32 cfg = 0; | 276 | u32 cfg = 0; |
276 | 277 | ||
278 | fimc_hw_set_prescaler(ctx); | ||
279 | |||
277 | if (!(ctx->flags & FIMC_COLOR_RANGE_NARROW)) | 280 | if (!(ctx->flags & FIMC_COLOR_RANGE_NARROW)) |
278 | cfg |= (S5P_CISCCTRL_CSCR2Y_WIDE | S5P_CISCCTRL_CSCY2R_WIDE); | 281 | cfg |= (S5P_CISCCTRL_CSCR2Y_WIDE | S5P_CISCCTRL_CSCY2R_WIDE); |
279 | 282 | ||
@@ -325,14 +328,18 @@ void fimc_hw_set_scaler(struct fimc_ctx *ctx) | |||
325 | void fimc_hw_en_capture(struct fimc_ctx *ctx) | 328 | void fimc_hw_en_capture(struct fimc_ctx *ctx) |
326 | { | 329 | { |
327 | struct fimc_dev *dev = ctx->fimc_dev; | 330 | struct fimc_dev *dev = ctx->fimc_dev; |
328 | u32 cfg; | ||
329 | 331 | ||
330 | cfg = readl(dev->regs + S5P_CIIMGCPT); | 332 | u32 cfg = readl(dev->regs + S5P_CIIMGCPT); |
331 | /* One shot mode for output DMA or freerun for FIFO. */ | 333 | |
332 | if (ctx->out_path == FIMC_DMA) | 334 | if (ctx->out_path == FIMC_DMA) { |
333 | cfg |= S5P_CIIMGCPT_CPT_FREN_ENABLE; | 335 | /* one shot mode */ |
334 | else | 336 | cfg |= S5P_CIIMGCPT_CPT_FREN_ENABLE | S5P_CIIMGCPT_IMGCPTEN; |
335 | cfg &= ~S5P_CIIMGCPT_CPT_FREN_ENABLE; | 337 | } else { |
338 | /* Continous frame capture mode (freerun). */ | ||
339 | cfg &= ~(S5P_CIIMGCPT_CPT_FREN_ENABLE | | ||
340 | S5P_CIIMGCPT_CPT_FRMOD_CNT); | ||
341 | cfg |= S5P_CIIMGCPT_IMGCPTEN; | ||
342 | } | ||
336 | 343 | ||
337 | if (ctx->scaler.enabled) | 344 | if (ctx->scaler.enabled) |
338 | cfg |= S5P_CIIMGCPT_IMGCPTEN_SC; | 345 | cfg |= S5P_CIIMGCPT_IMGCPTEN_SC; |
@@ -364,7 +371,7 @@ static void fimc_hw_set_in_dma_size(struct fimc_ctx *ctx) | |||
364 | u32 cfg_r = 0; | 371 | u32 cfg_r = 0; |
365 | 372 | ||
366 | if (FIMC_LCDFIFO == ctx->out_path) | 373 | if (FIMC_LCDFIFO == ctx->out_path) |
367 | cfg_r |= S5P_CIREAL_ISIZE_AUTOLOAD_EN; | 374 | cfg_r |= S5P_CIREAL_ISIZE_AUTOLOAD_EN; |
368 | 375 | ||
369 | cfg_o |= S5P_ORIG_SIZE_HOR(frame->f_width); | 376 | cfg_o |= S5P_ORIG_SIZE_HOR(frame->f_width); |
370 | cfg_o |= S5P_ORIG_SIZE_VER(frame->f_height); | 377 | cfg_o |= S5P_ORIG_SIZE_VER(frame->f_height); |
@@ -380,27 +387,25 @@ void fimc_hw_set_in_dma(struct fimc_ctx *ctx) | |||
380 | struct fimc_dev *dev = ctx->fimc_dev; | 387 | struct fimc_dev *dev = ctx->fimc_dev; |
381 | struct fimc_frame *frame = &ctx->s_frame; | 388 | struct fimc_frame *frame = &ctx->s_frame; |
382 | struct fimc_dma_offset *offset = &frame->dma_offset; | 389 | struct fimc_dma_offset *offset = &frame->dma_offset; |
383 | u32 cfg = 0; | 390 | u32 cfg; |
384 | 391 | ||
385 | /* Set the pixel offsets. */ | 392 | /* Set the pixel offsets. */ |
386 | cfg |= S5P_CIO_OFFS_HOR(offset->y_h); | 393 | cfg = S5P_CIO_OFFS_HOR(offset->y_h); |
387 | cfg |= S5P_CIO_OFFS_VER(offset->y_v); | 394 | cfg |= S5P_CIO_OFFS_VER(offset->y_v); |
388 | writel(cfg, dev->regs + S5P_CIIYOFF); | 395 | writel(cfg, dev->regs + S5P_CIIYOFF); |
389 | 396 | ||
390 | cfg = 0; | 397 | cfg = S5P_CIO_OFFS_HOR(offset->cb_h); |
391 | cfg |= S5P_CIO_OFFS_HOR(offset->cb_h); | ||
392 | cfg |= S5P_CIO_OFFS_VER(offset->cb_v); | 398 | cfg |= S5P_CIO_OFFS_VER(offset->cb_v); |
393 | writel(cfg, dev->regs + S5P_CIICBOFF); | 399 | writel(cfg, dev->regs + S5P_CIICBOFF); |
394 | 400 | ||
395 | cfg = 0; | 401 | cfg = S5P_CIO_OFFS_HOR(offset->cr_h); |
396 | cfg |= S5P_CIO_OFFS_HOR(offset->cr_h); | ||
397 | cfg |= S5P_CIO_OFFS_VER(offset->cr_v); | 402 | cfg |= S5P_CIO_OFFS_VER(offset->cr_v); |
398 | writel(cfg, dev->regs + S5P_CIICROFF); | 403 | writel(cfg, dev->regs + S5P_CIICROFF); |
399 | 404 | ||
400 | /* Input original and real size. */ | 405 | /* Input original and real size. */ |
401 | fimc_hw_set_in_dma_size(ctx); | 406 | fimc_hw_set_in_dma_size(ctx); |
402 | 407 | ||
403 | /* Autoload is used currently only in FIFO mode. */ | 408 | /* Use DMA autoload only in FIFO mode. */ |
404 | fimc_hw_en_autoload(dev, ctx->out_path == FIMC_LCDFIFO); | 409 | fimc_hw_en_autoload(dev, ctx->out_path == FIMC_LCDFIFO); |
405 | 410 | ||
406 | /* Set the input DMA to process single frame only. */ | 411 | /* Set the input DMA to process single frame only. */ |
@@ -501,27 +506,163 @@ void fimc_hw_set_output_path(struct fimc_ctx *ctx) | |||
501 | 506 | ||
502 | void fimc_hw_set_input_addr(struct fimc_dev *dev, struct fimc_addr *paddr) | 507 | void fimc_hw_set_input_addr(struct fimc_dev *dev, struct fimc_addr *paddr) |
503 | { | 508 | { |
504 | u32 cfg = 0; | 509 | u32 cfg = readl(dev->regs + S5P_CIREAL_ISIZE); |
505 | |||
506 | cfg = readl(dev->regs + S5P_CIREAL_ISIZE); | ||
507 | cfg |= S5P_CIREAL_ISIZE_ADDR_CH_DIS; | 510 | cfg |= S5P_CIREAL_ISIZE_ADDR_CH_DIS; |
508 | writel(cfg, dev->regs + S5P_CIREAL_ISIZE); | 511 | writel(cfg, dev->regs + S5P_CIREAL_ISIZE); |
509 | 512 | ||
510 | writel(paddr->y, dev->regs + S5P_CIIYSA0); | 513 | writel(paddr->y, dev->regs + S5P_CIIYSA(0)); |
511 | writel(paddr->cb, dev->regs + S5P_CIICBSA0); | 514 | writel(paddr->cb, dev->regs + S5P_CIICBSA(0)); |
512 | writel(paddr->cr, dev->regs + S5P_CIICRSA0); | 515 | writel(paddr->cr, dev->regs + S5P_CIICRSA(0)); |
513 | 516 | ||
514 | cfg &= ~S5P_CIREAL_ISIZE_ADDR_CH_DIS; | 517 | cfg &= ~S5P_CIREAL_ISIZE_ADDR_CH_DIS; |
515 | writel(cfg, dev->regs + S5P_CIREAL_ISIZE); | 518 | writel(cfg, dev->regs + S5P_CIREAL_ISIZE); |
516 | } | 519 | } |
517 | 520 | ||
518 | void fimc_hw_set_output_addr(struct fimc_dev *dev, struct fimc_addr *paddr) | 521 | void fimc_hw_set_output_addr(struct fimc_dev *dev, |
522 | struct fimc_addr *paddr, int index) | ||
519 | { | 523 | { |
520 | int i; | 524 | int i = (index == -1) ? 0 : index; |
521 | /* Set all the output register sets to point to single video buffer. */ | 525 | do { |
522 | for (i = 0; i < FIMC_MAX_OUT_BUFS; i++) { | ||
523 | writel(paddr->y, dev->regs + S5P_CIOYSA(i)); | 526 | writel(paddr->y, dev->regs + S5P_CIOYSA(i)); |
524 | writel(paddr->cb, dev->regs + S5P_CIOCBSA(i)); | 527 | writel(paddr->cb, dev->regs + S5P_CIOCBSA(i)); |
525 | writel(paddr->cr, dev->regs + S5P_CIOCRSA(i)); | 528 | writel(paddr->cr, dev->regs + S5P_CIOCRSA(i)); |
529 | dbg("dst_buf[%d]: 0x%X, cb: 0x%X, cr: 0x%X", | ||
530 | i, paddr->y, paddr->cb, paddr->cr); | ||
531 | } while (index == -1 && ++i < FIMC_MAX_OUT_BUFS); | ||
532 | } | ||
533 | |||
534 | int fimc_hw_set_camera_polarity(struct fimc_dev *fimc, | ||
535 | struct s3c_fimc_isp_info *cam) | ||
536 | { | ||
537 | u32 cfg = readl(fimc->regs + S5P_CIGCTRL); | ||
538 | |||
539 | cfg &= ~(S5P_CIGCTRL_INVPOLPCLK | S5P_CIGCTRL_INVPOLVSYNC | | ||
540 | S5P_CIGCTRL_INVPOLHREF | S5P_CIGCTRL_INVPOLHSYNC); | ||
541 | |||
542 | if (cam->flags & FIMC_CLK_INV_PCLK) | ||
543 | cfg |= S5P_CIGCTRL_INVPOLPCLK; | ||
544 | |||
545 | if (cam->flags & FIMC_CLK_INV_VSYNC) | ||
546 | cfg |= S5P_CIGCTRL_INVPOLVSYNC; | ||
547 | |||
548 | if (cam->flags & FIMC_CLK_INV_HREF) | ||
549 | cfg |= S5P_CIGCTRL_INVPOLHREF; | ||
550 | |||
551 | if (cam->flags & FIMC_CLK_INV_HSYNC) | ||
552 | cfg |= S5P_CIGCTRL_INVPOLHSYNC; | ||
553 | |||
554 | writel(cfg, fimc->regs + S5P_CIGCTRL); | ||
555 | |||
556 | return 0; | ||
557 | } | ||
558 | |||
559 | int fimc_hw_set_camera_source(struct fimc_dev *fimc, | ||
560 | struct s3c_fimc_isp_info *cam) | ||
561 | { | ||
562 | struct fimc_frame *f = &fimc->vid_cap.ctx->s_frame; | ||
563 | u32 cfg = 0; | ||
564 | |||
565 | if (cam->bus_type == FIMC_ITU_601 || cam->bus_type == FIMC_ITU_656) { | ||
566 | |||
567 | switch (fimc->vid_cap.fmt.code) { | ||
568 | case V4L2_MBUS_FMT_YUYV8_2X8: | ||
569 | cfg = S5P_CISRCFMT_ORDER422_YCBYCR; | ||
570 | break; | ||
571 | case V4L2_MBUS_FMT_YVYU8_2X8: | ||
572 | cfg = S5P_CISRCFMT_ORDER422_YCRYCB; | ||
573 | break; | ||
574 | case V4L2_MBUS_FMT_VYUY8_2X8: | ||
575 | cfg = S5P_CISRCFMT_ORDER422_CRYCBY; | ||
576 | break; | ||
577 | case V4L2_MBUS_FMT_UYVY8_2X8: | ||
578 | cfg = S5P_CISRCFMT_ORDER422_CBYCRY; | ||
579 | break; | ||
580 | default: | ||
581 | err("camera image format not supported: %d", | ||
582 | fimc->vid_cap.fmt.code); | ||
583 | return -EINVAL; | ||
584 | } | ||
585 | |||
586 | if (cam->bus_type == FIMC_ITU_601) { | ||
587 | if (cam->bus_width == 8) { | ||
588 | cfg |= S5P_CISRCFMT_ITU601_8BIT; | ||
589 | } else if (cam->bus_width == 16) { | ||
590 | cfg |= S5P_CISRCFMT_ITU601_16BIT; | ||
591 | } else { | ||
592 | err("invalid bus width: %d", cam->bus_width); | ||
593 | return -EINVAL; | ||
594 | } | ||
595 | } /* else defaults to ITU-R BT.656 8-bit */ | ||
526 | } | 596 | } |
597 | |||
598 | cfg |= S5P_CISRCFMT_HSIZE(f->o_width) | S5P_CISRCFMT_VSIZE(f->o_height); | ||
599 | writel(cfg, fimc->regs + S5P_CISRCFMT); | ||
600 | return 0; | ||
601 | } | ||
602 | |||
603 | |||
604 | int fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f) | ||
605 | { | ||
606 | u32 hoff2, voff2; | ||
607 | |||
608 | u32 cfg = readl(fimc->regs + S5P_CIWDOFST); | ||
609 | |||
610 | cfg &= ~(S5P_CIWDOFST_HOROFF_MASK | S5P_CIWDOFST_VEROFF_MASK); | ||
611 | cfg |= S5P_CIWDOFST_OFF_EN | | ||
612 | S5P_CIWDOFST_HOROFF(f->offs_h) | | ||
613 | S5P_CIWDOFST_VEROFF(f->offs_v); | ||
614 | |||
615 | writel(cfg, fimc->regs + S5P_CIWDOFST); | ||
616 | |||
617 | /* See CIWDOFSTn register description in the datasheet for details. */ | ||
618 | hoff2 = f->o_width - f->width - f->offs_h; | ||
619 | voff2 = f->o_height - f->height - f->offs_v; | ||
620 | cfg = S5P_CIWDOFST2_HOROFF(hoff2) | S5P_CIWDOFST2_VEROFF(voff2); | ||
621 | |||
622 | writel(cfg, fimc->regs + S5P_CIWDOFST2); | ||
623 | return 0; | ||
624 | } | ||
625 | |||
626 | int fimc_hw_set_camera_type(struct fimc_dev *fimc, | ||
627 | struct s3c_fimc_isp_info *cam) | ||
628 | { | ||
629 | u32 cfg, tmp; | ||
630 | struct fimc_vid_cap *vid_cap = &fimc->vid_cap; | ||
631 | |||
632 | cfg = readl(fimc->regs + S5P_CIGCTRL); | ||
633 | |||
634 | /* Select ITU B interface, disable Writeback path and test pattern. */ | ||
635 | cfg &= ~(S5P_CIGCTRL_TESTPAT_MASK | S5P_CIGCTRL_SELCAM_ITU_A | | ||
636 | S5P_CIGCTRL_SELCAM_MIPI | S5P_CIGCTRL_CAMIF_SELWB | | ||
637 | S5P_CIGCTRL_SELCAM_MIPI_A); | ||
638 | |||
639 | if (cam->bus_type == FIMC_MIPI_CSI2) { | ||
640 | cfg |= S5P_CIGCTRL_SELCAM_MIPI; | ||
641 | |||
642 | if (cam->mux_id == 0) | ||
643 | cfg |= S5P_CIGCTRL_SELCAM_MIPI_A; | ||
644 | |||
645 | /* TODO: add remaining supported formats. */ | ||
646 | if (vid_cap->fmt.code == V4L2_MBUS_FMT_VYUY8_2X8) { | ||
647 | tmp = S5P_CSIIMGFMT_YCBCR422_8BIT; | ||
648 | } else { | ||
649 | err("camera image format not supported: %d", | ||
650 | vid_cap->fmt.code); | ||
651 | return -EINVAL; | ||
652 | } | ||
653 | writel(tmp | (0x1 << 8), fimc->regs + S5P_CSIIMGFMT); | ||
654 | |||
655 | } else if (cam->bus_type == FIMC_ITU_601 || | ||
656 | cam->bus_type == FIMC_ITU_656) { | ||
657 | if (cam->mux_id == 0) /* ITU-A, ITU-B: 0, 1 */ | ||
658 | cfg |= S5P_CIGCTRL_SELCAM_ITU_A; | ||
659 | } else if (cam->bus_type == FIMC_LCD_WB) { | ||
660 | cfg |= S5P_CIGCTRL_CAMIF_SELWB; | ||
661 | } else { | ||
662 | err("invalid camera bus type selected\n"); | ||
663 | return -EINVAL; | ||
664 | } | ||
665 | writel(cfg, fimc->regs + S5P_CIGCTRL); | ||
666 | |||
667 | return 0; | ||
527 | } | 668 | } |
diff --git a/drivers/media/video/s5p-fimc/regs-fimc.h b/drivers/media/video/s5p-fimc/regs-fimc.h index a3cfe824db00..a57daedb5b5c 100644 --- a/drivers/media/video/s5p-fimc/regs-fimc.h +++ b/drivers/media/video/s5p-fimc/regs-fimc.h | |||
@@ -11,10 +11,6 @@ | |||
11 | #ifndef REGS_FIMC_H_ | 11 | #ifndef REGS_FIMC_H_ |
12 | #define REGS_FIMC_H_ | 12 | #define REGS_FIMC_H_ |
13 | 13 | ||
14 | #define S5P_CIOYSA(__x) (0x18 + (__x) * 4) | ||
15 | #define S5P_CIOCBSA(__x) (0x28 + (__x) * 4) | ||
16 | #define S5P_CIOCRSA(__x) (0x38 + (__x) * 4) | ||
17 | |||
18 | /* Input source format */ | 14 | /* Input source format */ |
19 | #define S5P_CISRCFMT 0x00 | 15 | #define S5P_CISRCFMT 0x00 |
20 | #define S5P_CISRCFMT_ITU601_8BIT (1 << 31) | 16 | #define S5P_CISRCFMT_ITU601_8BIT (1 << 31) |
@@ -28,22 +24,21 @@ | |||
28 | 24 | ||
29 | /* Window offset */ | 25 | /* Window offset */ |
30 | #define S5P_CIWDOFST 0x04 | 26 | #define S5P_CIWDOFST 0x04 |
31 | #define S5P_CIWDOFST_WINOFSEN (1 << 31) | 27 | #define S5P_CIWDOFST_OFF_EN (1 << 31) |
32 | #define S5P_CIWDOFST_CLROVFIY (1 << 30) | 28 | #define S5P_CIWDOFST_CLROVFIY (1 << 30) |
33 | #define S5P_CIWDOFST_CLROVRLB (1 << 29) | 29 | #define S5P_CIWDOFST_CLROVRLB (1 << 29) |
34 | #define S5P_CIWDOFST_WINHOROFST_MASK (0x7ff << 16) | 30 | #define S5P_CIWDOFST_HOROFF_MASK (0x7ff << 16) |
35 | #define S5P_CIWDOFST_CLROVFICB (1 << 15) | 31 | #define S5P_CIWDOFST_CLROVFICB (1 << 15) |
36 | #define S5P_CIWDOFST_CLROVFICR (1 << 14) | 32 | #define S5P_CIWDOFST_CLROVFICR (1 << 14) |
37 | #define S5P_CIWDOFST_WINHOROFST(x) ((x) << 16) | 33 | #define S5P_CIWDOFST_HOROFF(x) ((x) << 16) |
38 | #define S5P_CIWDOFST_WINVEROFST(x) ((x) << 0) | 34 | #define S5P_CIWDOFST_VEROFF(x) ((x) << 0) |
39 | #define S5P_CIWDOFST_WINVEROFST_MASK (0xfff << 0) | 35 | #define S5P_CIWDOFST_VEROFF_MASK (0xfff << 0) |
40 | 36 | ||
41 | /* Global control */ | 37 | /* Global control */ |
42 | #define S5P_CIGCTRL 0x08 | 38 | #define S5P_CIGCTRL 0x08 |
43 | #define S5P_CIGCTRL_SWRST (1 << 31) | 39 | #define S5P_CIGCTRL_SWRST (1 << 31) |
44 | #define S5P_CIGCTRL_CAMRST_A (1 << 30) | 40 | #define S5P_CIGCTRL_CAMRST_A (1 << 30) |
45 | #define S5P_CIGCTRL_SELCAM_ITU_A (1 << 29) | 41 | #define S5P_CIGCTRL_SELCAM_ITU_A (1 << 29) |
46 | #define S5P_CIGCTRL_SELCAM_ITU_MASK (1 << 29) | ||
47 | #define S5P_CIGCTRL_TESTPAT_NORMAL (0 << 27) | 42 | #define S5P_CIGCTRL_TESTPAT_NORMAL (0 << 27) |
48 | #define S5P_CIGCTRL_TESTPAT_COLOR_BAR (1 << 27) | 43 | #define S5P_CIGCTRL_TESTPAT_COLOR_BAR (1 << 27) |
49 | #define S5P_CIGCTRL_TESTPAT_HOR_INC (2 << 27) | 44 | #define S5P_CIGCTRL_TESTPAT_HOR_INC (2 << 27) |
@@ -61,6 +56,8 @@ | |||
61 | #define S5P_CIGCTRL_SHDW_DISABLE (1 << 12) | 56 | #define S5P_CIGCTRL_SHDW_DISABLE (1 << 12) |
62 | #define S5P_CIGCTRL_SELCAM_MIPI_A (1 << 7) | 57 | #define S5P_CIGCTRL_SELCAM_MIPI_A (1 << 7) |
63 | #define S5P_CIGCTRL_CAMIF_SELWB (1 << 6) | 58 | #define S5P_CIGCTRL_CAMIF_SELWB (1 << 6) |
59 | /* 0 - ITU601; 1 - ITU709 */ | ||
60 | #define S5P_CIGCTRL_CSC_ITU601_709 (1 << 5) | ||
64 | #define S5P_CIGCTRL_INVPOLHSYNC (1 << 4) | 61 | #define S5P_CIGCTRL_INVPOLHSYNC (1 << 4) |
65 | #define S5P_CIGCTRL_SELCAM_MIPI (1 << 3) | 62 | #define S5P_CIGCTRL_SELCAM_MIPI (1 << 3) |
66 | #define S5P_CIGCTRL_INTERLACE (1 << 0) | 63 | #define S5P_CIGCTRL_INTERLACE (1 << 0) |
@@ -72,23 +69,10 @@ | |||
72 | #define S5P_CIWDOFST2_HOROFF(x) ((x) << 16) | 69 | #define S5P_CIWDOFST2_HOROFF(x) ((x) << 16) |
73 | #define S5P_CIWDOFST2_VEROFF(x) ((x) << 0) | 70 | #define S5P_CIWDOFST2_VEROFF(x) ((x) << 0) |
74 | 71 | ||
75 | /* Output DMA Y plane start address */ | 72 | /* Output DMA Y/Cb/Cr plane start addresses */ |
76 | #define S5P_CIOYSA1 0x18 | 73 | #define S5P_CIOYSA(n) (0x18 + (n) * 4) |
77 | #define S5P_CIOYSA2 0x1c | 74 | #define S5P_CIOCBSA(n) (0x28 + (n) * 4) |
78 | #define S5P_CIOYSA3 0x20 | 75 | #define S5P_CIOCRSA(n) (0x38 + (n) * 4) |
79 | #define S5P_CIOYSA4 0x24 | ||
80 | |||
81 | /* Output DMA Cb plane start address */ | ||
82 | #define S5P_CIOCBSA1 0x28 | ||
83 | #define S5P_CIOCBSA2 0x2c | ||
84 | #define S5P_CIOCBSA3 0x30 | ||
85 | #define S5P_CIOCBSA4 0x34 | ||
86 | |||
87 | /* Output DMA Cr plane start address */ | ||
88 | #define S5P_CIOCRSA1 0x38 | ||
89 | #define S5P_CIOCRSA2 0x3c | ||
90 | #define S5P_CIOCRSA3 0x40 | ||
91 | #define S5P_CIOCRSA4 0x44 | ||
92 | 76 | ||
93 | /* Target image format */ | 77 | /* Target image format */ |
94 | #define S5P_CITRGFMT 0x48 | 78 | #define S5P_CITRGFMT 0x48 |
@@ -168,6 +152,8 @@ | |||
168 | #define S5P_CISTATUS_OVFICB (1 << 30) | 152 | #define S5P_CISTATUS_OVFICB (1 << 30) |
169 | #define S5P_CISTATUS_OVFICR (1 << 29) | 153 | #define S5P_CISTATUS_OVFICR (1 << 29) |
170 | #define S5P_CISTATUS_VSYNC (1 << 28) | 154 | #define S5P_CISTATUS_VSYNC (1 << 28) |
155 | #define S5P_CISTATUS_FRAMECNT_MASK (3 << 26) | ||
156 | #define S5P_CISTATUS_FRAMECNT_SHIFT 26 | ||
171 | #define S5P_CISTATUS_WINOFF_EN (1 << 25) | 157 | #define S5P_CISTATUS_WINOFF_EN (1 << 25) |
172 | #define S5P_CISTATUS_IMGCPT_EN (1 << 22) | 158 | #define S5P_CISTATUS_IMGCPT_EN (1 << 22) |
173 | #define S5P_CISTATUS_IMGCPT_SCEN (1 << 21) | 159 | #define S5P_CISTATUS_IMGCPT_SCEN (1 << 21) |
@@ -206,10 +192,10 @@ | |||
206 | #define S5P_CIIMGEFF_PAT_CB(x) ((x) << 13) | 192 | #define S5P_CIIMGEFF_PAT_CB(x) ((x) << 13) |
207 | #define S5P_CIIMGEFF_PAT_CR(x) ((x) << 0) | 193 | #define S5P_CIIMGEFF_PAT_CR(x) ((x) << 0) |
208 | 194 | ||
209 | /* Input DMA Y/Cb/Cr plane start address 0 */ | 195 | /* Input DMA Y/Cb/Cr plane start address 0/1 */ |
210 | #define S5P_CIIYSA0 0xd4 | 196 | #define S5P_CIIYSA(n) (0xd4 + (n) * 0x70) |
211 | #define S5P_CIICBSA0 0xd8 | 197 | #define S5P_CIICBSA(n) (0xd8 + (n) * 0x70) |
212 | #define S5P_CIICRSA0 0xdc | 198 | #define S5P_CIICRSA(n) (0xdc + (n) * 0x70) |
213 | 199 | ||
214 | /* Real input DMA image size */ | 200 | /* Real input DMA image size */ |
215 | #define S5P_CIREAL_ISIZE 0xf8 | 201 | #define S5P_CIREAL_ISIZE 0xf8 |
@@ -250,11 +236,6 @@ | |||
250 | #define S5P_MSCTRL_ENVID (1 << 0) | 236 | #define S5P_MSCTRL_ENVID (1 << 0) |
251 | #define S5P_MSCTRL_FRAME_COUNT(x) ((x) << 24) | 237 | #define S5P_MSCTRL_FRAME_COUNT(x) ((x) << 24) |
252 | 238 | ||
253 | /* Input DMA Y/Cb/Cr plane start address 1 */ | ||
254 | #define S5P_CIIYSA1 0x144 | ||
255 | #define S5P_CIICBSA1 0x148 | ||
256 | #define S5P_CIICRSA1 0x14c | ||
257 | |||
258 | /* Output DMA Y/Cb/Cr offset */ | 239 | /* Output DMA Y/Cb/Cr offset */ |
259 | #define S5P_CIOYOFF 0x168 | 240 | #define S5P_CIOYOFF 0x168 |
260 | #define S5P_CIOCBOFF 0x16c | 241 | #define S5P_CIOCBOFF 0x16c |
@@ -289,5 +270,16 @@ | |||
289 | 270 | ||
290 | /* MIPI CSI image format */ | 271 | /* MIPI CSI image format */ |
291 | #define S5P_CSIIMGFMT 0x194 | 272 | #define S5P_CSIIMGFMT 0x194 |
273 | #define S5P_CSIIMGFMT_YCBCR422_8BIT 0x1e | ||
274 | #define S5P_CSIIMGFMT_RAW8 0x2a | ||
275 | #define S5P_CSIIMGFMT_RAW10 0x2b | ||
276 | #define S5P_CSIIMGFMT_RAW12 0x2c | ||
277 | #define S5P_CSIIMGFMT_USER1 0x30 | ||
278 | #define S5P_CSIIMGFMT_USER2 0x31 | ||
279 | #define S5P_CSIIMGFMT_USER3 0x32 | ||
280 | #define S5P_CSIIMGFMT_USER4 0x33 | ||
281 | |||
282 | /* Output frame buffer sequence mask */ | ||
283 | #define S5P_CIFCNTSEQ 0x1FC | ||
292 | 284 | ||
293 | #endif /* REGS_FIMC_H_ */ | 285 | #endif /* REGS_FIMC_H_ */ |