diff options
| author | Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 2015-04-21 05:12:35 -0400 |
|---|---|---|
| committer | Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 2015-04-21 05:12:35 -0400 |
| commit | 676ee36be04985062522804c2de04f0764212be6 (patch) | |
| tree | 781df135c5a91a04decad1b7d53b5a925dc11522 /drivers/media/platform | |
| parent | b18042a673e88c9457a6d1716219c2367ca447b0 (diff) | |
| parent | e183201b9e917daf2530b637b2f34f1d5afb934d (diff) | |
Merge branch 'patchwork' into v4l_for_linus
* patchwork: (404 commits)
[media] uvcvideo: add support for VIDIOC_QUERY_EXT_CTRL
[media] uvcvideo: fix cropcap v4l2-compliance failure
[media] media: omap3isp: remove unused clkdev
[media] coda: Add tracing support
[media] coda: drop dma_sync_single_for_device in coda_bitstream_queue
[media] coda: fix fill bitstream errors in nonstreaming case
[media] coda: call SEQ_END when the first queue is stopped
[media] coda: fail to start streaming if userspace set invalid formats
[media] coda: remove duplicate error messages for buffer allocations
[media] coda: move parameter buffer in together with context buffer allocation
[media] coda: allocate bitstream buffer from REQBUFS, size depends on the format
[media] coda: allocate per-context buffers from REQBUFS
[media] coda: use strlcpy instead of snprintf
[media] coda: bitstream payload is unsigned
[media] coda: fix double call to debugfs_remove
[media] coda: check kasprintf return value in coda_open
[media] coda: bitrate can only be set in kbps steps
[media] v4l2-mem2mem: no need to initialize b in v4l2_m2m_next_buf and v4l2_m2m_buf_remove
[media] s5p-mfc: set allow_zero_bytesused flag for vb2_queue_init
[media] coda: set allow_zero_bytesused flag for vb2_queue_init
...
Diffstat (limited to 'drivers/media/platform')
84 files changed, 6866 insertions, 1824 deletions
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index d9b872b9285a..421f53188c6c 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig | |||
| @@ -56,7 +56,7 @@ config VIDEO_VIU | |||
| 56 | 56 | ||
| 57 | config VIDEO_TIMBERDALE | 57 | config VIDEO_TIMBERDALE |
| 58 | tristate "Support for timberdale Video In/LogiWIN" | 58 | tristate "Support for timberdale Video In/LogiWIN" |
| 59 | depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API | 59 | depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && HAS_DMA |
| 60 | depends on (MFD_TIMBERDALE && TIMB_DMA) || COMPILE_TEST | 60 | depends on (MFD_TIMBERDALE && TIMB_DMA) || COMPILE_TEST |
| 61 | select VIDEO_ADV7180 | 61 | select VIDEO_ADV7180 |
| 62 | select VIDEOBUF_DMA_CONTIG | 62 | select VIDEOBUF_DMA_CONTIG |
| @@ -90,6 +90,7 @@ config VIDEO_OMAP3 | |||
| 90 | select ARM_DMA_USE_IOMMU | 90 | select ARM_DMA_USE_IOMMU |
| 91 | select OMAP_IOMMU | 91 | select OMAP_IOMMU |
| 92 | select VIDEOBUF2_DMA_CONTIG | 92 | select VIDEOBUF2_DMA_CONTIG |
| 93 | select MFD_SYSCON | ||
| 93 | ---help--- | 94 | ---help--- |
| 94 | Driver for an OMAP 3 camera controller. | 95 | Driver for an OMAP 3 camera controller. |
| 95 | 96 | ||
| @@ -117,6 +118,7 @@ source "drivers/media/platform/soc_camera/Kconfig" | |||
| 117 | source "drivers/media/platform/exynos4-is/Kconfig" | 118 | source "drivers/media/platform/exynos4-is/Kconfig" |
| 118 | source "drivers/media/platform/s5p-tv/Kconfig" | 119 | source "drivers/media/platform/s5p-tv/Kconfig" |
| 119 | source "drivers/media/platform/am437x/Kconfig" | 120 | source "drivers/media/platform/am437x/Kconfig" |
| 121 | source "drivers/media/platform/xilinx/Kconfig" | ||
| 120 | 122 | ||
| 121 | endif # V4L_PLATFORM_DRIVERS | 123 | endif # V4L_PLATFORM_DRIVERS |
| 122 | 124 | ||
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index 3ec154742083..8f855616c237 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile | |||
| @@ -48,4 +48,6 @@ obj-y += omap/ | |||
| 48 | 48 | ||
| 49 | obj-$(CONFIG_VIDEO_AM437X_VPFE) += am437x/ | 49 | obj-$(CONFIG_VIDEO_AM437X_VPFE) += am437x/ |
| 50 | 50 | ||
| 51 | obj-$(CONFIG_VIDEO_XILINX) += xilinx/ | ||
| 52 | |||
| 51 | ccflags-y += -I$(srctree)/drivers/media/i2c | 53 | ccflags-y += -I$(srctree)/drivers/media/i2c |
diff --git a/drivers/media/platform/am437x/Kconfig b/drivers/media/platform/am437x/Kconfig index 7b023a76e32e..42d9c186710a 100644 --- a/drivers/media/platform/am437x/Kconfig +++ b/drivers/media/platform/am437x/Kconfig | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | config VIDEO_AM437X_VPFE | 1 | config VIDEO_AM437X_VPFE |
| 2 | tristate "TI AM437x VPFE video capture driver" | 2 | tristate "TI AM437x VPFE video capture driver" |
| 3 | depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API | 3 | depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && HAS_DMA |
| 4 | depends on SOC_AM43XX || COMPILE_TEST | 4 | depends on SOC_AM43XX || COMPILE_TEST |
| 5 | select VIDEOBUF2_DMA_CONTIG | 5 | select VIDEOBUF2_DMA_CONTIG |
| 6 | help | 6 | help |
diff --git a/drivers/media/platform/am437x/am437x-vpfe.c b/drivers/media/platform/am437x/am437x-vpfe.c index 56a5cb0d2152..4899924ea926 100644 --- a/drivers/media/platform/am437x/am437x-vpfe.c +++ b/drivers/media/platform/am437x/am437x-vpfe.c | |||
| @@ -1645,6 +1645,7 @@ static int vpfe_enum_size(struct file *file, void *priv, | |||
| 1645 | fse.index = fsize->index; | 1645 | fse.index = fsize->index; |
| 1646 | fse.pad = 0; | 1646 | fse.pad = 0; |
| 1647 | fse.code = mbus.code; | 1647 | fse.code = mbus.code; |
| 1648 | fse.which = V4L2_SUBDEV_FORMAT_ACTIVE; | ||
| 1648 | ret = v4l2_subdev_call(sdinfo->sd, pad, enum_frame_size, NULL, &fse); | 1649 | ret = v4l2_subdev_call(sdinfo->sd, pad, enum_frame_size, NULL, &fse); |
| 1649 | if (ret) | 1650 | if (ret) |
| 1650 | return -EINVAL; | 1651 | return -EINVAL; |
| @@ -1700,11 +1701,16 @@ static int vpfe_get_app_input_index(struct vpfe_device *vpfe, | |||
| 1700 | { | 1701 | { |
| 1701 | struct vpfe_config *cfg = vpfe->cfg; | 1702 | struct vpfe_config *cfg = vpfe->cfg; |
| 1702 | struct vpfe_subdev_info *sdinfo; | 1703 | struct vpfe_subdev_info *sdinfo; |
| 1704 | struct i2c_client *client; | ||
| 1705 | struct i2c_client *curr_client; | ||
| 1703 | int i, j = 0; | 1706 | int i, j = 0; |
| 1704 | 1707 | ||
| 1708 | curr_client = v4l2_get_subdevdata(vpfe->current_subdev->sd); | ||
| 1705 | for (i = 0; i < ARRAY_SIZE(vpfe->cfg->asd); i++) { | 1709 | for (i = 0; i < ARRAY_SIZE(vpfe->cfg->asd); i++) { |
| 1706 | sdinfo = &cfg->sub_devs[i]; | 1710 | sdinfo = &cfg->sub_devs[i]; |
| 1707 | if (!strcmp(sdinfo->name, vpfe->current_subdev->name)) { | 1711 | client = v4l2_get_subdevdata(sdinfo->sd); |
| 1712 | if (client->addr == curr_client->addr && | ||
| 1713 | client->adapter->nr == client->adapter->nr) { | ||
| 1708 | if (vpfe->current_input >= 1) | 1714 | if (vpfe->current_input >= 1) |
| 1709 | return -1; | 1715 | return -1; |
| 1710 | *app_input_index = j + vpfe->current_input; | 1716 | *app_input_index = j + vpfe->current_input; |
| @@ -2296,20 +2302,10 @@ vpfe_async_bound(struct v4l2_async_notifier *notifier, | |||
| 2296 | vpfe_dbg(1, vpfe, "vpfe_async_bound\n"); | 2302 | vpfe_dbg(1, vpfe, "vpfe_async_bound\n"); |
| 2297 | 2303 | ||
| 2298 | for (i = 0; i < ARRAY_SIZE(vpfe->cfg->asd); i++) { | 2304 | for (i = 0; i < ARRAY_SIZE(vpfe->cfg->asd); i++) { |
| 2299 | sdinfo = &vpfe->cfg->sub_devs[i]; | 2305 | if (vpfe->cfg->asd[i]->match.of.node == asd[i].match.of.node) { |
| 2300 | 2306 | sdinfo = &vpfe->cfg->sub_devs[i]; | |
| 2301 | if (!strcmp(sdinfo->name, subdev->name)) { | ||
| 2302 | vpfe->sd[i] = subdev; | 2307 | vpfe->sd[i] = subdev; |
| 2303 | vpfe_info(vpfe, | 2308 | vpfe->sd[i]->grp_id = sdinfo->grp_id; |
| 2304 | "v4l2 sub device %s registered\n", | ||
| 2305 | subdev->name); | ||
| 2306 | vpfe->sd[i]->grp_id = | ||
| 2307 | sdinfo->grp_id; | ||
| 2308 | /* update tvnorms from the sub devices */ | ||
| 2309 | for (j = 0; j < 1; j++) | ||
| 2310 | vpfe->video_dev->tvnorms |= | ||
| 2311 | sdinfo->inputs[j].std; | ||
| 2312 | |||
| 2313 | found = true; | 2309 | found = true; |
| 2314 | break; | 2310 | break; |
| 2315 | } | 2311 | } |
| @@ -2320,6 +2316,8 @@ vpfe_async_bound(struct v4l2_async_notifier *notifier, | |||
| 2320 | return -EINVAL; | 2316 | return -EINVAL; |
| 2321 | } | 2317 | } |
| 2322 | 2318 | ||
| 2319 | vpfe->video_dev.tvnorms |= sdinfo->inputs[0].std; | ||
| 2320 | |||
| 2323 | /* setup the supported formats & indexes */ | 2321 | /* setup the supported formats & indexes */ |
| 2324 | for (j = 0, i = 0; ; ++j) { | 2322 | for (j = 0, i = 0; ; ++j) { |
| 2325 | struct vpfe_fmt *fmt; | 2323 | struct vpfe_fmt *fmt; |
| @@ -2327,6 +2325,7 @@ vpfe_async_bound(struct v4l2_async_notifier *notifier, | |||
| 2327 | 2325 | ||
| 2328 | memset(&mbus_code, 0, sizeof(mbus_code)); | 2326 | memset(&mbus_code, 0, sizeof(mbus_code)); |
| 2329 | mbus_code.index = j; | 2327 | mbus_code.index = j; |
| 2328 | mbus_code.which = V4L2_SUBDEV_FORMAT_ACTIVE; | ||
| 2330 | ret = v4l2_subdev_call(subdev, pad, enum_mbus_code, | 2329 | ret = v4l2_subdev_call(subdev, pad, enum_mbus_code, |
| 2331 | NULL, &mbus_code); | 2330 | NULL, &mbus_code); |
| 2332 | if (ret) | 2331 | if (ret) |
| @@ -2390,9 +2389,9 @@ static int vpfe_probe_complete(struct vpfe_device *vpfe) | |||
| 2390 | 2389 | ||
| 2391 | INIT_LIST_HEAD(&vpfe->dma_queue); | 2390 | INIT_LIST_HEAD(&vpfe->dma_queue); |
| 2392 | 2391 | ||
| 2393 | vdev = vpfe->video_dev; | 2392 | vdev = &vpfe->video_dev; |
| 2394 | strlcpy(vdev->name, VPFE_MODULE_NAME, sizeof(vdev->name)); | 2393 | strlcpy(vdev->name, VPFE_MODULE_NAME, sizeof(vdev->name)); |
| 2395 | vdev->release = video_device_release; | 2394 | vdev->release = video_device_release_empty; |
| 2396 | vdev->fops = &vpfe_fops; | 2395 | vdev->fops = &vpfe_fops; |
| 2397 | vdev->ioctl_ops = &vpfe_ioctl_ops; | 2396 | vdev->ioctl_ops = &vpfe_ioctl_ops; |
| 2398 | vdev->v4l2_dev = &vpfe->v4l2_dev; | 2397 | vdev->v4l2_dev = &vpfe->v4l2_dev; |
| @@ -2400,7 +2399,7 @@ static int vpfe_probe_complete(struct vpfe_device *vpfe) | |||
| 2400 | vdev->queue = q; | 2399 | vdev->queue = q; |
| 2401 | vdev->lock = &vpfe->lock; | 2400 | vdev->lock = &vpfe->lock; |
| 2402 | video_set_drvdata(vdev, vpfe); | 2401 | video_set_drvdata(vdev, vpfe); |
| 2403 | err = video_register_device(vpfe->video_dev, VFL_TYPE_GRABBER, -1); | 2402 | err = video_register_device(&vpfe->video_dev, VFL_TYPE_GRABBER, -1); |
| 2404 | if (err) { | 2403 | if (err) { |
| 2405 | vpfe_err(vpfe, | 2404 | vpfe_err(vpfe, |
| 2406 | "Unable to register video device.\n"); | 2405 | "Unable to register video device.\n"); |
| @@ -2425,7 +2424,7 @@ static int vpfe_async_complete(struct v4l2_async_notifier *notifier) | |||
| 2425 | static struct vpfe_config * | 2424 | static struct vpfe_config * |
| 2426 | vpfe_get_pdata(struct platform_device *pdev) | 2425 | vpfe_get_pdata(struct platform_device *pdev) |
| 2427 | { | 2426 | { |
| 2428 | struct device_node *endpoint = NULL, *rem = NULL; | 2427 | struct device_node *endpoint = NULL; |
| 2429 | struct v4l2_of_endpoint bus_cfg; | 2428 | struct v4l2_of_endpoint bus_cfg; |
| 2430 | struct vpfe_subdev_info *sdinfo; | 2429 | struct vpfe_subdev_info *sdinfo; |
| 2431 | struct vpfe_config *pdata; | 2430 | struct vpfe_config *pdata; |
| @@ -2443,6 +2442,8 @@ vpfe_get_pdata(struct platform_device *pdev) | |||
| 2443 | return NULL; | 2442 | return NULL; |
| 2444 | 2443 | ||
| 2445 | for (i = 0; ; i++) { | 2444 | for (i = 0; ; i++) { |
| 2445 | struct device_node *rem; | ||
| 2446 | |||
| 2446 | endpoint = of_graph_get_next_endpoint(pdev->dev.of_node, | 2447 | endpoint = of_graph_get_next_endpoint(pdev->dev.of_node, |
| 2447 | endpoint); | 2448 | endpoint); |
| 2448 | if (!endpoint) | 2449 | if (!endpoint) |
| @@ -2497,11 +2498,15 @@ vpfe_get_pdata(struct platform_device *pdev) | |||
| 2497 | goto done; | 2498 | goto done; |
| 2498 | } | 2499 | } |
| 2499 | 2500 | ||
| 2500 | strncpy(sdinfo->name, rem->name, sizeof(sdinfo->name)); | ||
| 2501 | |||
| 2502 | pdata->asd[i] = devm_kzalloc(&pdev->dev, | 2501 | pdata->asd[i] = devm_kzalloc(&pdev->dev, |
| 2503 | sizeof(struct v4l2_async_subdev), | 2502 | sizeof(struct v4l2_async_subdev), |
| 2504 | GFP_KERNEL); | 2503 | GFP_KERNEL); |
| 2504 | if (!pdata->asd[i]) { | ||
| 2505 | of_node_put(rem); | ||
| 2506 | pdata = NULL; | ||
| 2507 | goto done; | ||
| 2508 | } | ||
| 2509 | |||
| 2505 | pdata->asd[i]->match_type = V4L2_ASYNC_MATCH_OF; | 2510 | pdata->asd[i]->match_type = V4L2_ASYNC_MATCH_OF; |
| 2506 | pdata->asd[i]->match.of.node = rem; | 2511 | pdata->asd[i]->match.of.node = rem; |
| 2507 | of_node_put(endpoint); | 2512 | of_node_put(endpoint); |
| @@ -2513,7 +2518,6 @@ vpfe_get_pdata(struct platform_device *pdev) | |||
| 2513 | 2518 | ||
| 2514 | done: | 2519 | done: |
| 2515 | of_node_put(endpoint); | 2520 | of_node_put(endpoint); |
| 2516 | of_node_put(rem); | ||
| 2517 | return NULL; | 2521 | return NULL; |
| 2518 | } | 2522 | } |
| 2519 | 2523 | ||
| @@ -2561,17 +2565,11 @@ static int vpfe_probe(struct platform_device *pdev) | |||
| 2561 | return -EINVAL; | 2565 | return -EINVAL; |
| 2562 | } | 2566 | } |
| 2563 | 2567 | ||
| 2564 | vpfe->video_dev = video_device_alloc(); | ||
| 2565 | if (!vpfe->video_dev) { | ||
| 2566 | dev_err(&pdev->dev, "Unable to allocate video device\n"); | ||
| 2567 | return -ENOMEM; | ||
| 2568 | } | ||
| 2569 | |||
| 2570 | ret = v4l2_device_register(&pdev->dev, &vpfe->v4l2_dev); | 2568 | ret = v4l2_device_register(&pdev->dev, &vpfe->v4l2_dev); |
| 2571 | if (ret) { | 2569 | if (ret) { |
| 2572 | vpfe_err(vpfe, | 2570 | vpfe_err(vpfe, |
| 2573 | "Unable to register v4l2 device.\n"); | 2571 | "Unable to register v4l2 device.\n"); |
| 2574 | goto probe_out_video_release; | 2572 | return ret; |
| 2575 | } | 2573 | } |
| 2576 | 2574 | ||
| 2577 | /* set the driver data in platform device */ | 2575 | /* set the driver data in platform device */ |
| @@ -2609,9 +2607,6 @@ static int vpfe_probe(struct platform_device *pdev) | |||
| 2609 | 2607 | ||
| 2610 | probe_out_v4l2_unregister: | 2608 | probe_out_v4l2_unregister: |
| 2611 | v4l2_device_unregister(&vpfe->v4l2_dev); | 2609 | v4l2_device_unregister(&vpfe->v4l2_dev); |
| 2612 | probe_out_video_release: | ||
| 2613 | if (!video_is_registered(vpfe->video_dev)) | ||
| 2614 | video_device_release(vpfe->video_dev); | ||
| 2615 | return ret; | 2610 | return ret; |
| 2616 | } | 2611 | } |
| 2617 | 2612 | ||
| @@ -2628,7 +2623,7 @@ static int vpfe_remove(struct platform_device *pdev) | |||
| 2628 | 2623 | ||
| 2629 | v4l2_async_notifier_unregister(&vpfe->notifier); | 2624 | v4l2_async_notifier_unregister(&vpfe->notifier); |
| 2630 | v4l2_device_unregister(&vpfe->v4l2_dev); | 2625 | v4l2_device_unregister(&vpfe->v4l2_dev); |
| 2631 | video_unregister_device(vpfe->video_dev); | 2626 | video_unregister_device(&vpfe->video_dev); |
| 2632 | 2627 | ||
| 2633 | return 0; | 2628 | return 0; |
| 2634 | } | 2629 | } |
diff --git a/drivers/media/platform/am437x/am437x-vpfe.h b/drivers/media/platform/am437x/am437x-vpfe.h index 0f557352313d..5bfb35649a39 100644 --- a/drivers/media/platform/am437x/am437x-vpfe.h +++ b/drivers/media/platform/am437x/am437x-vpfe.h | |||
| @@ -83,7 +83,6 @@ struct vpfe_route { | |||
| 83 | }; | 83 | }; |
| 84 | 84 | ||
| 85 | struct vpfe_subdev_info { | 85 | struct vpfe_subdev_info { |
| 86 | char name[32]; | ||
| 87 | /* Sub device group id */ | 86 | /* Sub device group id */ |
| 88 | int grp_id; | 87 | int grp_id; |
| 89 | /* inputs available at the sub device */ | 88 | /* inputs available at the sub device */ |
| @@ -223,7 +222,7 @@ struct vpfe_ccdc { | |||
| 223 | struct vpfe_device { | 222 | struct vpfe_device { |
| 224 | /* V4l2 specific parameters */ | 223 | /* V4l2 specific parameters */ |
| 225 | /* Identifies video device for this channel */ | 224 | /* Identifies video device for this channel */ |
| 226 | struct video_device *video_dev; | 225 | struct video_device video_dev; |
| 227 | /* sub devices */ | 226 | /* sub devices */ |
| 228 | struct v4l2_subdev **sd; | 227 | struct v4l2_subdev **sd; |
| 229 | /* vpfe cfg */ | 228 | /* vpfe cfg */ |
diff --git a/drivers/media/platform/blackfin/bfin_capture.c b/drivers/media/platform/blackfin/bfin_capture.c index 8f6698668ecf..6a437f86dcdc 100644 --- a/drivers/media/platform/blackfin/bfin_capture.c +++ b/drivers/media/platform/blackfin/bfin_capture.c | |||
| @@ -44,7 +44,6 @@ | |||
| 44 | #include <media/blackfin/ppi.h> | 44 | #include <media/blackfin/ppi.h> |
| 45 | 45 | ||
| 46 | #define CAPTURE_DRV_NAME "bfin_capture" | 46 | #define CAPTURE_DRV_NAME "bfin_capture" |
| 47 | #define BCAP_MIN_NUM_BUF 2 | ||
| 48 | 47 | ||
| 49 | struct bcap_format { | 48 | struct bcap_format { |
| 50 | char *desc; | 49 | char *desc; |
| @@ -65,7 +64,7 @@ struct bcap_device { | |||
| 65 | /* v4l2 control handler */ | 64 | /* v4l2 control handler */ |
| 66 | struct v4l2_ctrl_handler ctrl_handler; | 65 | struct v4l2_ctrl_handler ctrl_handler; |
| 67 | /* device node data */ | 66 | /* device node data */ |
| 68 | struct video_device *video_dev; | 67 | struct video_device video_dev; |
| 69 | /* sub device instance */ | 68 | /* sub device instance */ |
| 70 | struct v4l2_subdev *sd; | 69 | struct v4l2_subdev *sd; |
| 71 | /* capture config */ | 70 | /* capture config */ |
| @@ -104,12 +103,8 @@ struct bcap_device { | |||
| 104 | struct completion comp; | 103 | struct completion comp; |
| 105 | /* prepare to stop */ | 104 | /* prepare to stop */ |
| 106 | bool stop; | 105 | bool stop; |
| 107 | }; | 106 | /* vb2 buffer sequence counter */ |
| 108 | 107 | unsigned sequence; | |
| 109 | struct bcap_fh { | ||
| 110 | struct v4l2_fh fh; | ||
| 111 | /* indicates whether this file handle is doing IO */ | ||
| 112 | bool io_allowed; | ||
| 113 | }; | 108 | }; |
| 114 | 109 | ||
| 115 | static const struct bcap_format bcap_formats[] = { | 110 | static const struct bcap_format bcap_formats[] = { |
| @@ -201,90 +196,6 @@ static void bcap_free_sensor_formats(struct bcap_device *bcap_dev) | |||
| 201 | bcap_dev->sensor_formats = NULL; | 196 | bcap_dev->sensor_formats = NULL; |
| 202 | } | 197 | } |
| 203 | 198 | ||
| 204 | static int bcap_open(struct file *file) | ||
| 205 | { | ||
| 206 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
| 207 | struct video_device *vfd = bcap_dev->video_dev; | ||
| 208 | struct bcap_fh *bcap_fh; | ||
| 209 | |||
| 210 | if (!bcap_dev->sd) { | ||
| 211 | v4l2_err(&bcap_dev->v4l2_dev, "No sub device registered\n"); | ||
| 212 | return -ENODEV; | ||
| 213 | } | ||
| 214 | |||
| 215 | bcap_fh = kzalloc(sizeof(*bcap_fh), GFP_KERNEL); | ||
| 216 | if (!bcap_fh) { | ||
| 217 | v4l2_err(&bcap_dev->v4l2_dev, | ||
| 218 | "unable to allocate memory for file handle object\n"); | ||
| 219 | return -ENOMEM; | ||
| 220 | } | ||
| 221 | |||
| 222 | v4l2_fh_init(&bcap_fh->fh, vfd); | ||
| 223 | |||
| 224 | /* store pointer to v4l2_fh in private_data member of file */ | ||
| 225 | file->private_data = &bcap_fh->fh; | ||
| 226 | v4l2_fh_add(&bcap_fh->fh); | ||
| 227 | bcap_fh->io_allowed = false; | ||
| 228 | return 0; | ||
| 229 | } | ||
| 230 | |||
| 231 | static int bcap_release(struct file *file) | ||
| 232 | { | ||
| 233 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
| 234 | struct v4l2_fh *fh = file->private_data; | ||
| 235 | struct bcap_fh *bcap_fh = container_of(fh, struct bcap_fh, fh); | ||
| 236 | |||
| 237 | /* if this instance is doing IO */ | ||
| 238 | if (bcap_fh->io_allowed) | ||
| 239 | vb2_queue_release(&bcap_dev->buffer_queue); | ||
| 240 | |||
| 241 | file->private_data = NULL; | ||
| 242 | v4l2_fh_del(&bcap_fh->fh); | ||
| 243 | v4l2_fh_exit(&bcap_fh->fh); | ||
| 244 | kfree(bcap_fh); | ||
| 245 | return 0; | ||
| 246 | } | ||
| 247 | |||
| 248 | static int bcap_mmap(struct file *file, struct vm_area_struct *vma) | ||
| 249 | { | ||
| 250 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
| 251 | int ret; | ||
| 252 | |||
| 253 | if (mutex_lock_interruptible(&bcap_dev->mutex)) | ||
| 254 | return -ERESTARTSYS; | ||
| 255 | ret = vb2_mmap(&bcap_dev->buffer_queue, vma); | ||
| 256 | mutex_unlock(&bcap_dev->mutex); | ||
| 257 | return ret; | ||
| 258 | } | ||
| 259 | |||
| 260 | #ifndef CONFIG_MMU | ||
| 261 | static unsigned long bcap_get_unmapped_area(struct file *file, | ||
| 262 | unsigned long addr, | ||
| 263 | unsigned long len, | ||
| 264 | unsigned long pgoff, | ||
| 265 | unsigned long flags) | ||
| 266 | { | ||
| 267 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
| 268 | |||
| 269 | return vb2_get_unmapped_area(&bcap_dev->buffer_queue, | ||
| 270 | addr, | ||
| 271 | len, | ||
| 272 | pgoff, | ||
| 273 | flags); | ||
| 274 | } | ||
| 275 | #endif | ||
| 276 | |||
| 277 | static unsigned int bcap_poll(struct file *file, poll_table *wait) | ||
| 278 | { | ||
| 279 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
| 280 | unsigned int res; | ||
| 281 | |||
| 282 | mutex_lock(&bcap_dev->mutex); | ||
| 283 | res = vb2_poll(&bcap_dev->buffer_queue, file, wait); | ||
| 284 | mutex_unlock(&bcap_dev->mutex); | ||
| 285 | return res; | ||
| 286 | } | ||
| 287 | |||
| 288 | static int bcap_queue_setup(struct vb2_queue *vq, | 199 | static int bcap_queue_setup(struct vb2_queue *vq, |
| 289 | const struct v4l2_format *fmt, | 200 | const struct v4l2_format *fmt, |
| 290 | unsigned int *nbuffers, unsigned int *nplanes, | 201 | unsigned int *nbuffers, unsigned int *nplanes, |
| @@ -292,37 +203,32 @@ static int bcap_queue_setup(struct vb2_queue *vq, | |||
| 292 | { | 203 | { |
| 293 | struct bcap_device *bcap_dev = vb2_get_drv_priv(vq); | 204 | struct bcap_device *bcap_dev = vb2_get_drv_priv(vq); |
| 294 | 205 | ||
| 295 | if (*nbuffers < BCAP_MIN_NUM_BUF) | 206 | if (fmt && fmt->fmt.pix.sizeimage < bcap_dev->fmt.sizeimage) |
| 296 | *nbuffers = BCAP_MIN_NUM_BUF; | 207 | return -EINVAL; |
| 208 | |||
| 209 | if (vq->num_buffers + *nbuffers < 2) | ||
| 210 | *nbuffers = 2; | ||
| 297 | 211 | ||
| 298 | *nplanes = 1; | 212 | *nplanes = 1; |
| 299 | sizes[0] = bcap_dev->fmt.sizeimage; | 213 | sizes[0] = fmt ? fmt->fmt.pix.sizeimage : bcap_dev->fmt.sizeimage; |
| 300 | alloc_ctxs[0] = bcap_dev->alloc_ctx; | 214 | alloc_ctxs[0] = bcap_dev->alloc_ctx; |
| 301 | 215 | ||
| 302 | return 0; | 216 | return 0; |
| 303 | } | 217 | } |
| 304 | 218 | ||
| 305 | static int bcap_buffer_init(struct vb2_buffer *vb) | ||
| 306 | { | ||
| 307 | struct bcap_buffer *buf = to_bcap_vb(vb); | ||
| 308 | |||
| 309 | INIT_LIST_HEAD(&buf->list); | ||
| 310 | return 0; | ||
| 311 | } | ||
| 312 | |||
| 313 | static int bcap_buffer_prepare(struct vb2_buffer *vb) | 219 | static int bcap_buffer_prepare(struct vb2_buffer *vb) |
| 314 | { | 220 | { |
| 315 | struct bcap_device *bcap_dev = vb2_get_drv_priv(vb->vb2_queue); | 221 | struct bcap_device *bcap_dev = vb2_get_drv_priv(vb->vb2_queue); |
| 316 | struct bcap_buffer *buf = to_bcap_vb(vb); | 222 | unsigned long size = bcap_dev->fmt.sizeimage; |
| 317 | unsigned long size; | ||
| 318 | 223 | ||
| 319 | size = bcap_dev->fmt.sizeimage; | ||
| 320 | if (vb2_plane_size(vb, 0) < size) { | 224 | if (vb2_plane_size(vb, 0) < size) { |
| 321 | v4l2_err(&bcap_dev->v4l2_dev, "buffer too small (%lu < %lu)\n", | 225 | v4l2_err(&bcap_dev->v4l2_dev, "buffer too small (%lu < %lu)\n", |
| 322 | vb2_plane_size(vb, 0), size); | 226 | vb2_plane_size(vb, 0), size); |
| 323 | return -EINVAL; | 227 | return -EINVAL; |
| 324 | } | 228 | } |
| 325 | vb2_set_plane_payload(&buf->vb, 0, size); | 229 | vb2_set_plane_payload(vb, 0, size); |
| 230 | |||
| 231 | vb->v4l2_buf.field = bcap_dev->fmt.field; | ||
| 326 | 232 | ||
| 327 | return 0; | 233 | return 0; |
| 328 | } | 234 | } |
| @@ -353,14 +259,16 @@ static int bcap_start_streaming(struct vb2_queue *vq, unsigned int count) | |||
| 353 | { | 259 | { |
| 354 | struct bcap_device *bcap_dev = vb2_get_drv_priv(vq); | 260 | struct bcap_device *bcap_dev = vb2_get_drv_priv(vq); |
| 355 | struct ppi_if *ppi = bcap_dev->ppi; | 261 | struct ppi_if *ppi = bcap_dev->ppi; |
| 262 | struct bcap_buffer *buf, *tmp; | ||
| 356 | struct ppi_params params; | 263 | struct ppi_params params; |
| 264 | dma_addr_t addr; | ||
| 357 | int ret; | 265 | int ret; |
| 358 | 266 | ||
| 359 | /* enable streamon on the sub device */ | 267 | /* enable streamon on the sub device */ |
| 360 | ret = v4l2_subdev_call(bcap_dev->sd, video, s_stream, 1); | 268 | ret = v4l2_subdev_call(bcap_dev->sd, video, s_stream, 1); |
| 361 | if (ret && (ret != -ENOIOCTLCMD)) { | 269 | if (ret && (ret != -ENOIOCTLCMD)) { |
| 362 | v4l2_err(&bcap_dev->v4l2_dev, "stream on failed in subdev\n"); | 270 | v4l2_err(&bcap_dev->v4l2_dev, "stream on failed in subdev\n"); |
| 363 | return ret; | 271 | goto err; |
| 364 | } | 272 | } |
| 365 | 273 | ||
| 366 | /* set ppi params */ | 274 | /* set ppi params */ |
| @@ -399,7 +307,7 @@ static int bcap_start_streaming(struct vb2_queue *vq, unsigned int count) | |||
| 399 | if (ret < 0) { | 307 | if (ret < 0) { |
| 400 | v4l2_err(&bcap_dev->v4l2_dev, | 308 | v4l2_err(&bcap_dev->v4l2_dev, |
| 401 | "Error in setting ppi params\n"); | 309 | "Error in setting ppi params\n"); |
| 402 | return ret; | 310 | goto err; |
| 403 | } | 311 | } |
| 404 | 312 | ||
| 405 | /* attach ppi DMA irq handler */ | 313 | /* attach ppi DMA irq handler */ |
| @@ -407,12 +315,34 @@ static int bcap_start_streaming(struct vb2_queue *vq, unsigned int count) | |||
| 407 | if (ret < 0) { | 315 | if (ret < 0) { |
| 408 | v4l2_err(&bcap_dev->v4l2_dev, | 316 | v4l2_err(&bcap_dev->v4l2_dev, |
| 409 | "Error in attaching interrupt handler\n"); | 317 | "Error in attaching interrupt handler\n"); |
| 410 | return ret; | 318 | goto err; |
| 411 | } | 319 | } |
| 412 | 320 | ||
| 321 | bcap_dev->sequence = 0; | ||
| 322 | |||
| 413 | reinit_completion(&bcap_dev->comp); | 323 | reinit_completion(&bcap_dev->comp); |
| 414 | bcap_dev->stop = false; | 324 | bcap_dev->stop = false; |
| 325 | |||
| 326 | /* get the next frame from the dma queue */ | ||
| 327 | bcap_dev->cur_frm = list_entry(bcap_dev->dma_queue.next, | ||
| 328 | struct bcap_buffer, list); | ||
| 329 | /* remove buffer from the dma queue */ | ||
| 330 | list_del_init(&bcap_dev->cur_frm->list); | ||
| 331 | addr = vb2_dma_contig_plane_dma_addr(&bcap_dev->cur_frm->vb, 0); | ||
| 332 | /* update DMA address */ | ||
| 333 | ppi->ops->update_addr(ppi, (unsigned long)addr); | ||
| 334 | /* enable ppi */ | ||
| 335 | ppi->ops->start(ppi); | ||
| 336 | |||
| 415 | return 0; | 337 | return 0; |
| 338 | |||
| 339 | err: | ||
| 340 | list_for_each_entry_safe(buf, tmp, &bcap_dev->dma_queue, list) { | ||
| 341 | list_del(&buf->list); | ||
| 342 | vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED); | ||
| 343 | } | ||
| 344 | |||
| 345 | return ret; | ||
| 416 | } | 346 | } |
| 417 | 347 | ||
| 418 | static void bcap_stop_streaming(struct vb2_queue *vq) | 348 | static void bcap_stop_streaming(struct vb2_queue *vq) |
| @@ -431,6 +361,9 @@ static void bcap_stop_streaming(struct vb2_queue *vq) | |||
| 431 | "stream off failed in subdev\n"); | 361 | "stream off failed in subdev\n"); |
| 432 | 362 | ||
| 433 | /* release all active buffers */ | 363 | /* release all active buffers */ |
| 364 | if (bcap_dev->cur_frm) | ||
| 365 | vb2_buffer_done(&bcap_dev->cur_frm->vb, VB2_BUF_STATE_ERROR); | ||
| 366 | |||
| 434 | while (!list_empty(&bcap_dev->dma_queue)) { | 367 | while (!list_empty(&bcap_dev->dma_queue)) { |
| 435 | bcap_dev->cur_frm = list_entry(bcap_dev->dma_queue.next, | 368 | bcap_dev->cur_frm = list_entry(bcap_dev->dma_queue.next, |
| 436 | struct bcap_buffer, list); | 369 | struct bcap_buffer, list); |
| @@ -441,7 +374,6 @@ static void bcap_stop_streaming(struct vb2_queue *vq) | |||
| 441 | 374 | ||
| 442 | static struct vb2_ops bcap_video_qops = { | 375 | static struct vb2_ops bcap_video_qops = { |
| 443 | .queue_setup = bcap_queue_setup, | 376 | .queue_setup = bcap_queue_setup, |
| 444 | .buf_init = bcap_buffer_init, | ||
| 445 | .buf_prepare = bcap_buffer_prepare, | 377 | .buf_prepare = bcap_buffer_prepare, |
| 446 | .buf_cleanup = bcap_buffer_cleanup, | 378 | .buf_cleanup = bcap_buffer_cleanup, |
| 447 | .buf_queue = bcap_buffer_queue, | 379 | .buf_queue = bcap_buffer_queue, |
| @@ -451,57 +383,6 @@ static struct vb2_ops bcap_video_qops = { | |||
| 451 | .stop_streaming = bcap_stop_streaming, | 383 | .stop_streaming = bcap_stop_streaming, |
| 452 | }; | 384 | }; |
| 453 | 385 | ||
| 454 | static int bcap_reqbufs(struct file *file, void *priv, | ||
| 455 | struct v4l2_requestbuffers *req_buf) | ||
| 456 | { | ||
| 457 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
| 458 | struct vb2_queue *vq = &bcap_dev->buffer_queue; | ||
| 459 | struct v4l2_fh *fh = file->private_data; | ||
| 460 | struct bcap_fh *bcap_fh = container_of(fh, struct bcap_fh, fh); | ||
| 461 | |||
| 462 | if (vb2_is_busy(vq)) | ||
| 463 | return -EBUSY; | ||
| 464 | |||
| 465 | bcap_fh->io_allowed = true; | ||
| 466 | |||
| 467 | return vb2_reqbufs(vq, req_buf); | ||
| 468 | } | ||
| 469 | |||
| 470 | static int bcap_querybuf(struct file *file, void *priv, | ||
| 471 | struct v4l2_buffer *buf) | ||
| 472 | { | ||
| 473 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
| 474 | |||
| 475 | return vb2_querybuf(&bcap_dev->buffer_queue, buf); | ||
| 476 | } | ||
| 477 | |||
| 478 | static int bcap_qbuf(struct file *file, void *priv, | ||
| 479 | struct v4l2_buffer *buf) | ||
| 480 | { | ||
| 481 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
| 482 | struct v4l2_fh *fh = file->private_data; | ||
| 483 | struct bcap_fh *bcap_fh = container_of(fh, struct bcap_fh, fh); | ||
| 484 | |||
| 485 | if (!bcap_fh->io_allowed) | ||
| 486 | return -EBUSY; | ||
| 487 | |||
| 488 | return vb2_qbuf(&bcap_dev->buffer_queue, buf); | ||
| 489 | } | ||
| 490 | |||
| 491 | static int bcap_dqbuf(struct file *file, void *priv, | ||
| 492 | struct v4l2_buffer *buf) | ||
| 493 | { | ||
| 494 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
| 495 | struct v4l2_fh *fh = file->private_data; | ||
| 496 | struct bcap_fh *bcap_fh = container_of(fh, struct bcap_fh, fh); | ||
| 497 | |||
| 498 | if (!bcap_fh->io_allowed) | ||
| 499 | return -EBUSY; | ||
| 500 | |||
| 501 | return vb2_dqbuf(&bcap_dev->buffer_queue, | ||
| 502 | buf, file->f_flags & O_NONBLOCK); | ||
| 503 | } | ||
| 504 | |||
| 505 | static irqreturn_t bcap_isr(int irq, void *dev_id) | 386 | static irqreturn_t bcap_isr(int irq, void *dev_id) |
| 506 | { | 387 | { |
| 507 | struct ppi_if *ppi = dev_id; | 388 | struct ppi_if *ppi = dev_id; |
| @@ -517,6 +398,7 @@ static irqreturn_t bcap_isr(int irq, void *dev_id) | |||
| 517 | vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); | 398 | vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); |
| 518 | ppi->err = false; | 399 | ppi->err = false; |
| 519 | } else { | 400 | } else { |
| 401 | vb->v4l2_buf.sequence = bcap_dev->sequence++; | ||
| 520 | vb2_buffer_done(vb, VB2_BUF_STATE_DONE); | 402 | vb2_buffer_done(vb, VB2_BUF_STATE_DONE); |
| 521 | } | 403 | } |
| 522 | bcap_dev->cur_frm = list_entry(bcap_dev->dma_queue.next, | 404 | bcap_dev->cur_frm = list_entry(bcap_dev->dma_queue.next, |
| @@ -543,62 +425,14 @@ static irqreturn_t bcap_isr(int irq, void *dev_id) | |||
| 543 | return IRQ_HANDLED; | 425 | return IRQ_HANDLED; |
| 544 | } | 426 | } |
| 545 | 427 | ||
| 546 | static int bcap_streamon(struct file *file, void *priv, | ||
| 547 | enum v4l2_buf_type buf_type) | ||
| 548 | { | ||
| 549 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
| 550 | struct bcap_fh *fh = file->private_data; | ||
| 551 | struct ppi_if *ppi = bcap_dev->ppi; | ||
| 552 | dma_addr_t addr; | ||
| 553 | int ret; | ||
| 554 | |||
| 555 | if (!fh->io_allowed) | ||
| 556 | return -EBUSY; | ||
| 557 | |||
| 558 | /* call streamon to start streaming in videobuf */ | ||
| 559 | ret = vb2_streamon(&bcap_dev->buffer_queue, buf_type); | ||
| 560 | if (ret) | ||
| 561 | return ret; | ||
| 562 | |||
| 563 | /* if dma queue is empty, return error */ | ||
| 564 | if (list_empty(&bcap_dev->dma_queue)) { | ||
| 565 | v4l2_err(&bcap_dev->v4l2_dev, "dma queue is empty\n"); | ||
| 566 | ret = -EINVAL; | ||
| 567 | goto err; | ||
| 568 | } | ||
| 569 | |||
| 570 | /* get the next frame from the dma queue */ | ||
| 571 | bcap_dev->cur_frm = list_entry(bcap_dev->dma_queue.next, | ||
| 572 | struct bcap_buffer, list); | ||
| 573 | /* remove buffer from the dma queue */ | ||
| 574 | list_del_init(&bcap_dev->cur_frm->list); | ||
| 575 | addr = vb2_dma_contig_plane_dma_addr(&bcap_dev->cur_frm->vb, 0); | ||
| 576 | /* update DMA address */ | ||
| 577 | ppi->ops->update_addr(ppi, (unsigned long)addr); | ||
| 578 | /* enable ppi */ | ||
| 579 | ppi->ops->start(ppi); | ||
| 580 | |||
| 581 | return 0; | ||
| 582 | err: | ||
| 583 | vb2_streamoff(&bcap_dev->buffer_queue, buf_type); | ||
| 584 | return ret; | ||
| 585 | } | ||
| 586 | |||
| 587 | static int bcap_streamoff(struct file *file, void *priv, | ||
| 588 | enum v4l2_buf_type buf_type) | ||
| 589 | { | ||
| 590 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
| 591 | struct bcap_fh *fh = file->private_data; | ||
| 592 | |||
| 593 | if (!fh->io_allowed) | ||
| 594 | return -EBUSY; | ||
| 595 | |||
| 596 | return vb2_streamoff(&bcap_dev->buffer_queue, buf_type); | ||
| 597 | } | ||
| 598 | |||
| 599 | static int bcap_querystd(struct file *file, void *priv, v4l2_std_id *std) | 428 | static int bcap_querystd(struct file *file, void *priv, v4l2_std_id *std) |
| 600 | { | 429 | { |
| 601 | struct bcap_device *bcap_dev = video_drvdata(file); | 430 | struct bcap_device *bcap_dev = video_drvdata(file); |
| 431 | struct v4l2_input input; | ||
| 432 | |||
| 433 | input = bcap_dev->cfg->inputs[bcap_dev->cur_input]; | ||
| 434 | if (!(input.capabilities & V4L2_IN_CAP_STD)) | ||
| 435 | return -ENODATA; | ||
| 602 | 436 | ||
| 603 | return v4l2_subdev_call(bcap_dev->sd, video, querystd, std); | 437 | return v4l2_subdev_call(bcap_dev->sd, video, querystd, std); |
| 604 | } | 438 | } |
| @@ -606,6 +440,11 @@ static int bcap_querystd(struct file *file, void *priv, v4l2_std_id *std) | |||
| 606 | static int bcap_g_std(struct file *file, void *priv, v4l2_std_id *std) | 440 | static int bcap_g_std(struct file *file, void *priv, v4l2_std_id *std) |
| 607 | { | 441 | { |
| 608 | struct bcap_device *bcap_dev = video_drvdata(file); | 442 | struct bcap_device *bcap_dev = video_drvdata(file); |
| 443 | struct v4l2_input input; | ||
| 444 | |||
| 445 | input = bcap_dev->cfg->inputs[bcap_dev->cur_input]; | ||
| 446 | if (!(input.capabilities & V4L2_IN_CAP_STD)) | ||
| 447 | return -ENODATA; | ||
| 609 | 448 | ||
| 610 | *std = bcap_dev->std; | 449 | *std = bcap_dev->std; |
| 611 | return 0; | 450 | return 0; |
| @@ -614,8 +453,13 @@ static int bcap_g_std(struct file *file, void *priv, v4l2_std_id *std) | |||
| 614 | static int bcap_s_std(struct file *file, void *priv, v4l2_std_id std) | 453 | static int bcap_s_std(struct file *file, void *priv, v4l2_std_id std) |
| 615 | { | 454 | { |
| 616 | struct bcap_device *bcap_dev = video_drvdata(file); | 455 | struct bcap_device *bcap_dev = video_drvdata(file); |
| 456 | struct v4l2_input input; | ||
| 617 | int ret; | 457 | int ret; |
| 618 | 458 | ||
| 459 | input = bcap_dev->cfg->inputs[bcap_dev->cur_input]; | ||
| 460 | if (!(input.capabilities & V4L2_IN_CAP_STD)) | ||
| 461 | return -ENODATA; | ||
| 462 | |||
| 619 | if (vb2_is_busy(&bcap_dev->buffer_queue)) | 463 | if (vb2_is_busy(&bcap_dev->buffer_queue)) |
| 620 | return -EBUSY; | 464 | return -EBUSY; |
| 621 | 465 | ||
| @@ -631,6 +475,11 @@ static int bcap_enum_dv_timings(struct file *file, void *priv, | |||
| 631 | struct v4l2_enum_dv_timings *timings) | 475 | struct v4l2_enum_dv_timings *timings) |
| 632 | { | 476 | { |
| 633 | struct bcap_device *bcap_dev = video_drvdata(file); | 477 | struct bcap_device *bcap_dev = video_drvdata(file); |
| 478 | struct v4l2_input input; | ||
| 479 | |||
| 480 | input = bcap_dev->cfg->inputs[bcap_dev->cur_input]; | ||
| 481 | if (!(input.capabilities & V4L2_IN_CAP_DV_TIMINGS)) | ||
| 482 | return -ENODATA; | ||
| 634 | 483 | ||
| 635 | timings->pad = 0; | 484 | timings->pad = 0; |
| 636 | 485 | ||
| @@ -642,6 +491,11 @@ static int bcap_query_dv_timings(struct file *file, void *priv, | |||
| 642 | struct v4l2_dv_timings *timings) | 491 | struct v4l2_dv_timings *timings) |
| 643 | { | 492 | { |
| 644 | struct bcap_device *bcap_dev = video_drvdata(file); | 493 | struct bcap_device *bcap_dev = video_drvdata(file); |
| 494 | struct v4l2_input input; | ||
| 495 | |||
| 496 | input = bcap_dev->cfg->inputs[bcap_dev->cur_input]; | ||
| 497 | if (!(input.capabilities & V4L2_IN_CAP_DV_TIMINGS)) | ||
| 498 | return -ENODATA; | ||
| 645 | 499 | ||
| 646 | return v4l2_subdev_call(bcap_dev->sd, video, | 500 | return v4l2_subdev_call(bcap_dev->sd, video, |
| 647 | query_dv_timings, timings); | 501 | query_dv_timings, timings); |
| @@ -651,6 +505,11 @@ static int bcap_g_dv_timings(struct file *file, void *priv, | |||
| 651 | struct v4l2_dv_timings *timings) | 505 | struct v4l2_dv_timings *timings) |
| 652 | { | 506 | { |
| 653 | struct bcap_device *bcap_dev = video_drvdata(file); | 507 | struct bcap_device *bcap_dev = video_drvdata(file); |
| 508 | struct v4l2_input input; | ||
| 509 | |||
| 510 | input = bcap_dev->cfg->inputs[bcap_dev->cur_input]; | ||
| 511 | if (!(input.capabilities & V4L2_IN_CAP_DV_TIMINGS)) | ||
| 512 | return -ENODATA; | ||
| 654 | 513 | ||
| 655 | *timings = bcap_dev->dv_timings; | 514 | *timings = bcap_dev->dv_timings; |
| 656 | return 0; | 515 | return 0; |
| @@ -660,7 +519,13 @@ static int bcap_s_dv_timings(struct file *file, void *priv, | |||
| 660 | struct v4l2_dv_timings *timings) | 519 | struct v4l2_dv_timings *timings) |
| 661 | { | 520 | { |
| 662 | struct bcap_device *bcap_dev = video_drvdata(file); | 521 | struct bcap_device *bcap_dev = video_drvdata(file); |
| 522 | struct v4l2_input input; | ||
| 663 | int ret; | 523 | int ret; |
| 524 | |||
| 525 | input = bcap_dev->cfg->inputs[bcap_dev->cur_input]; | ||
| 526 | if (!(input.capabilities & V4L2_IN_CAP_DV_TIMINGS)) | ||
| 527 | return -ENODATA; | ||
| 528 | |||
| 664 | if (vb2_is_busy(&bcap_dev->buffer_queue)) | 529 | if (vb2_is_busy(&bcap_dev->buffer_queue)) |
| 665 | return -EBUSY; | 530 | return -EBUSY; |
| 666 | 531 | ||
| @@ -881,12 +746,14 @@ static const struct v4l2_ioctl_ops bcap_ioctl_ops = { | |||
| 881 | .vidioc_g_dv_timings = bcap_g_dv_timings, | 746 | .vidioc_g_dv_timings = bcap_g_dv_timings, |
| 882 | .vidioc_query_dv_timings = bcap_query_dv_timings, | 747 | .vidioc_query_dv_timings = bcap_query_dv_timings, |
| 883 | .vidioc_enum_dv_timings = bcap_enum_dv_timings, | 748 | .vidioc_enum_dv_timings = bcap_enum_dv_timings, |
| 884 | .vidioc_reqbufs = bcap_reqbufs, | 749 | .vidioc_reqbufs = vb2_ioctl_reqbufs, |
| 885 | .vidioc_querybuf = bcap_querybuf, | 750 | .vidioc_create_bufs = vb2_ioctl_create_bufs, |
| 886 | .vidioc_qbuf = bcap_qbuf, | 751 | .vidioc_querybuf = vb2_ioctl_querybuf, |
| 887 | .vidioc_dqbuf = bcap_dqbuf, | 752 | .vidioc_qbuf = vb2_ioctl_qbuf, |
| 888 | .vidioc_streamon = bcap_streamon, | 753 | .vidioc_dqbuf = vb2_ioctl_dqbuf, |
| 889 | .vidioc_streamoff = bcap_streamoff, | 754 | .vidioc_expbuf = vb2_ioctl_expbuf, |
| 755 | .vidioc_streamon = vb2_ioctl_streamon, | ||
| 756 | .vidioc_streamoff = vb2_ioctl_streamoff, | ||
| 890 | .vidioc_g_parm = bcap_g_parm, | 757 | .vidioc_g_parm = bcap_g_parm, |
| 891 | .vidioc_s_parm = bcap_s_parm, | 758 | .vidioc_s_parm = bcap_s_parm, |
| 892 | .vidioc_log_status = bcap_log_status, | 759 | .vidioc_log_status = bcap_log_status, |
| @@ -894,14 +761,14 @@ static const struct v4l2_ioctl_ops bcap_ioctl_ops = { | |||
| 894 | 761 | ||
| 895 | static struct v4l2_file_operations bcap_fops = { | 762 | static struct v4l2_file_operations bcap_fops = { |
| 896 | .owner = THIS_MODULE, | 763 | .owner = THIS_MODULE, |
| 897 | .open = bcap_open, | 764 | .open = v4l2_fh_open, |
| 898 | .release = bcap_release, | 765 | .release = vb2_fop_release, |
| 899 | .unlocked_ioctl = video_ioctl2, | 766 | .unlocked_ioctl = video_ioctl2, |
| 900 | .mmap = bcap_mmap, | 767 | .mmap = vb2_fop_mmap, |
| 901 | #ifndef CONFIG_MMU | 768 | #ifndef CONFIG_MMU |
| 902 | .get_unmapped_area = bcap_get_unmapped_area, | 769 | .get_unmapped_area = vb2_fop_get_unmapped_area, |
| 903 | #endif | 770 | #endif |
| 904 | .poll = bcap_poll | 771 | .poll = vb2_fop_poll |
| 905 | }; | 772 | }; |
| 906 | 773 | ||
| 907 | static int bcap_probe(struct platform_device *pdev) | 774 | static int bcap_probe(struct platform_device *pdev) |
| @@ -942,27 +809,20 @@ static int bcap_probe(struct platform_device *pdev) | |||
| 942 | goto err_free_ppi; | 809 | goto err_free_ppi; |
| 943 | } | 810 | } |
| 944 | 811 | ||
| 945 | vfd = video_device_alloc(); | 812 | vfd = &bcap_dev->video_dev; |
| 946 | if (!vfd) { | ||
| 947 | ret = -ENOMEM; | ||
| 948 | v4l2_err(pdev->dev.driver, "Unable to alloc video device\n"); | ||
| 949 | goto err_cleanup_ctx; | ||
| 950 | } | ||
| 951 | |||
| 952 | /* initialize field of video device */ | 813 | /* initialize field of video device */ |
| 953 | vfd->release = video_device_release; | 814 | vfd->release = video_device_release_empty; |
| 954 | vfd->fops = &bcap_fops; | 815 | vfd->fops = &bcap_fops; |
| 955 | vfd->ioctl_ops = &bcap_ioctl_ops; | 816 | vfd->ioctl_ops = &bcap_ioctl_ops; |
| 956 | vfd->tvnorms = 0; | 817 | vfd->tvnorms = 0; |
| 957 | vfd->v4l2_dev = &bcap_dev->v4l2_dev; | 818 | vfd->v4l2_dev = &bcap_dev->v4l2_dev; |
| 958 | strncpy(vfd->name, CAPTURE_DRV_NAME, sizeof(vfd->name)); | 819 | strncpy(vfd->name, CAPTURE_DRV_NAME, sizeof(vfd->name)); |
| 959 | bcap_dev->video_dev = vfd; | ||
| 960 | 820 | ||
| 961 | ret = v4l2_device_register(&pdev->dev, &bcap_dev->v4l2_dev); | 821 | ret = v4l2_device_register(&pdev->dev, &bcap_dev->v4l2_dev); |
| 962 | if (ret) { | 822 | if (ret) { |
| 963 | v4l2_err(pdev->dev.driver, | 823 | v4l2_err(pdev->dev.driver, |
| 964 | "Unable to register v4l2 device\n"); | 824 | "Unable to register v4l2 device\n"); |
| 965 | goto err_release_vdev; | 825 | goto err_cleanup_ctx; |
| 966 | } | 826 | } |
| 967 | v4l2_info(&bcap_dev->v4l2_dev, "v4l2 device registered\n"); | 827 | v4l2_info(&bcap_dev->v4l2_dev, "v4l2 device registered\n"); |
| 968 | 828 | ||
| @@ -978,13 +838,14 @@ static int bcap_probe(struct platform_device *pdev) | |||
| 978 | /* initialize queue */ | 838 | /* initialize queue */ |
| 979 | q = &bcap_dev->buffer_queue; | 839 | q = &bcap_dev->buffer_queue; |
| 980 | q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 840 | q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 981 | q->io_modes = VB2_MMAP; | 841 | q->io_modes = VB2_MMAP | VB2_DMABUF; |
| 982 | q->drv_priv = bcap_dev; | 842 | q->drv_priv = bcap_dev; |
| 983 | q->buf_struct_size = sizeof(struct bcap_buffer); | 843 | q->buf_struct_size = sizeof(struct bcap_buffer); |
| 984 | q->ops = &bcap_video_qops; | 844 | q->ops = &bcap_video_qops; |
| 985 | q->mem_ops = &vb2_dma_contig_memops; | 845 | q->mem_ops = &vb2_dma_contig_memops; |
| 986 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | 846 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 987 | q->lock = &bcap_dev->mutex; | 847 | q->lock = &bcap_dev->mutex; |
| 848 | q->min_buffers_needed = 1; | ||
| 988 | 849 | ||
| 989 | ret = vb2_queue_init(q); | 850 | ret = vb2_queue_init(q); |
| 990 | if (ret) | 851 | if (ret) |
| @@ -997,15 +858,16 @@ static int bcap_probe(struct platform_device *pdev) | |||
| 997 | INIT_LIST_HEAD(&bcap_dev->dma_queue); | 858 | INIT_LIST_HEAD(&bcap_dev->dma_queue); |
| 998 | 859 | ||
| 999 | vfd->lock = &bcap_dev->mutex; | 860 | vfd->lock = &bcap_dev->mutex; |
| 861 | vfd->queue = q; | ||
| 1000 | 862 | ||
| 1001 | /* register video device */ | 863 | /* register video device */ |
| 1002 | ret = video_register_device(bcap_dev->video_dev, VFL_TYPE_GRABBER, -1); | 864 | ret = video_register_device(&bcap_dev->video_dev, VFL_TYPE_GRABBER, -1); |
| 1003 | if (ret) { | 865 | if (ret) { |
| 1004 | v4l2_err(&bcap_dev->v4l2_dev, | 866 | v4l2_err(&bcap_dev->v4l2_dev, |
| 1005 | "Unable to register video device\n"); | 867 | "Unable to register video device\n"); |
| 1006 | goto err_free_handler; | 868 | goto err_free_handler; |
| 1007 | } | 869 | } |
| 1008 | video_set_drvdata(bcap_dev->video_dev, bcap_dev); | 870 | video_set_drvdata(&bcap_dev->video_dev, bcap_dev); |
| 1009 | v4l2_info(&bcap_dev->v4l2_dev, "video device registered as: %s\n", | 871 | v4l2_info(&bcap_dev->v4l2_dev, "video device registered as: %s\n", |
| 1010 | video_device_node_name(vfd)); | 872 | video_device_node_name(vfd)); |
| 1011 | 873 | ||
| @@ -1083,15 +945,11 @@ static int bcap_probe(struct platform_device *pdev) | |||
| 1083 | } | 945 | } |
| 1084 | return 0; | 946 | return 0; |
| 1085 | err_unreg_vdev: | 947 | err_unreg_vdev: |
| 1086 | video_unregister_device(bcap_dev->video_dev); | 948 | video_unregister_device(&bcap_dev->video_dev); |
| 1087 | bcap_dev->video_dev = NULL; | ||
| 1088 | err_free_handler: | 949 | err_free_handler: |
| 1089 | v4l2_ctrl_handler_free(&bcap_dev->ctrl_handler); | 950 | v4l2_ctrl_handler_free(&bcap_dev->ctrl_handler); |
| 1090 | err_unreg_v4l2: | 951 | err_unreg_v4l2: |
| 1091 | v4l2_device_unregister(&bcap_dev->v4l2_dev); | 952 | v4l2_device_unregister(&bcap_dev->v4l2_dev); |
| 1092 | err_release_vdev: | ||
| 1093 | if (bcap_dev->video_dev) | ||
| 1094 | video_device_release(bcap_dev->video_dev); | ||
| 1095 | err_cleanup_ctx: | 953 | err_cleanup_ctx: |
| 1096 | vb2_dma_contig_cleanup_ctx(bcap_dev->alloc_ctx); | 954 | vb2_dma_contig_cleanup_ctx(bcap_dev->alloc_ctx); |
| 1097 | err_free_ppi: | 955 | err_free_ppi: |
| @@ -1108,7 +966,7 @@ static int bcap_remove(struct platform_device *pdev) | |||
| 1108 | struct bcap_device, v4l2_dev); | 966 | struct bcap_device, v4l2_dev); |
| 1109 | 967 | ||
| 1110 | bcap_free_sensor_formats(bcap_dev); | 968 | bcap_free_sensor_formats(bcap_dev); |
| 1111 | video_unregister_device(bcap_dev->video_dev); | 969 | video_unregister_device(&bcap_dev->video_dev); |
| 1112 | v4l2_ctrl_handler_free(&bcap_dev->ctrl_handler); | 970 | v4l2_ctrl_handler_free(&bcap_dev->ctrl_handler); |
| 1113 | v4l2_device_unregister(v4l2_dev); | 971 | v4l2_device_unregister(v4l2_dev); |
| 1114 | vb2_dma_contig_cleanup_ctx(bcap_dev->alloc_ctx); | 972 | vb2_dma_contig_cleanup_ctx(bcap_dev->alloc_ctx); |
diff --git a/drivers/media/platform/coda/Makefile b/drivers/media/platform/coda/Makefile index 25ce15561695..834e504bf085 100644 --- a/drivers/media/platform/coda/Makefile +++ b/drivers/media/platform/coda/Makefile | |||
| @@ -1,3 +1,5 @@ | |||
| 1 | ccflags-y += -I$(src) | ||
| 2 | |||
| 1 | coda-objs := coda-common.o coda-bit.o coda-h264.o coda-jpeg.o | 3 | coda-objs := coda-common.o coda-bit.o coda-h264.o coda-jpeg.o |
| 2 | 4 | ||
| 3 | obj-$(CONFIG_VIDEO_CODA) += coda.o | 5 | obj-$(CONFIG_VIDEO_CODA) += coda.o |
diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 856b542b35b9..d0430071d2ee 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include <linux/clk.h> | 15 | #include <linux/clk.h> |
| 16 | #include <linux/irqreturn.h> | 16 | #include <linux/irqreturn.h> |
| 17 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
| 18 | #include <linux/log2.h> | ||
| 18 | #include <linux/platform_device.h> | 19 | #include <linux/platform_device.h> |
| 19 | #include <linux/reset.h> | 20 | #include <linux/reset.h> |
| 20 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
| @@ -29,13 +30,18 @@ | |||
| 29 | #include <media/videobuf2-vmalloc.h> | 30 | #include <media/videobuf2-vmalloc.h> |
| 30 | 31 | ||
| 31 | #include "coda.h" | 32 | #include "coda.h" |
| 33 | #define CREATE_TRACE_POINTS | ||
| 34 | #include "trace.h" | ||
| 32 | 35 | ||
| 36 | #define CODA_PARA_BUF_SIZE (10 * 1024) | ||
| 33 | #define CODA7_PS_BUF_SIZE 0x28000 | 37 | #define CODA7_PS_BUF_SIZE 0x28000 |
| 34 | #define CODA9_PS_SAVE_SIZE (512 * 1024) | 38 | #define CODA9_PS_SAVE_SIZE (512 * 1024) |
| 35 | 39 | ||
| 36 | #define CODA_DEFAULT_GAMMA 4096 | 40 | #define CODA_DEFAULT_GAMMA 4096 |
| 37 | #define CODA9_DEFAULT_GAMMA 24576 /* 0.75 * 32768 */ | 41 | #define CODA9_DEFAULT_GAMMA 24576 /* 0.75 * 32768 */ |
| 38 | 42 | ||
| 43 | static void coda_free_bitstream_buffer(struct coda_ctx *ctx); | ||
| 44 | |||
| 39 | static inline int coda_is_initialized(struct coda_dev *dev) | 45 | static inline int coda_is_initialized(struct coda_dev *dev) |
| 40 | { | 46 | { |
| 41 | return coda_read(dev, CODA_REG_BIT_CUR_PC) != 0; | 47 | return coda_read(dev, CODA_REG_BIT_CUR_PC) != 0; |
| @@ -84,15 +90,21 @@ static void coda_command_async(struct coda_ctx *ctx, int cmd) | |||
| 84 | coda_write(dev, ctx->params.codec_mode, CODA_REG_BIT_RUN_COD_STD); | 90 | coda_write(dev, ctx->params.codec_mode, CODA_REG_BIT_RUN_COD_STD); |
| 85 | coda_write(dev, ctx->params.codec_mode_aux, CODA7_REG_BIT_RUN_AUX_STD); | 91 | coda_write(dev, ctx->params.codec_mode_aux, CODA7_REG_BIT_RUN_AUX_STD); |
| 86 | 92 | ||
| 93 | trace_coda_bit_run(ctx, cmd); | ||
| 94 | |||
| 87 | coda_write(dev, cmd, CODA_REG_BIT_RUN_COMMAND); | 95 | coda_write(dev, cmd, CODA_REG_BIT_RUN_COMMAND); |
| 88 | } | 96 | } |
| 89 | 97 | ||
| 90 | static int coda_command_sync(struct coda_ctx *ctx, int cmd) | 98 | static int coda_command_sync(struct coda_ctx *ctx, int cmd) |
| 91 | { | 99 | { |
| 92 | struct coda_dev *dev = ctx->dev; | 100 | struct coda_dev *dev = ctx->dev; |
| 101 | int ret; | ||
| 93 | 102 | ||
| 94 | coda_command_async(ctx, cmd); | 103 | coda_command_async(ctx, cmd); |
| 95 | return coda_wait_timeout(dev); | 104 | ret = coda_wait_timeout(dev); |
| 105 | trace_coda_bit_done(ctx); | ||
| 106 | |||
| 107 | return ret; | ||
| 96 | } | 108 | } |
| 97 | 109 | ||
| 98 | int coda_hw_reset(struct coda_ctx *ctx) | 110 | int coda_hw_reset(struct coda_ctx *ctx) |
| @@ -177,10 +189,6 @@ static int coda_bitstream_queue(struct coda_ctx *ctx, | |||
| 177 | if (n < src_size) | 189 | if (n < src_size) |
| 178 | return -ENOSPC; | 190 | return -ENOSPC; |
| 179 | 191 | ||
| 180 | dma_sync_single_for_device(&ctx->dev->plat_dev->dev, | ||
| 181 | ctx->bitstream.paddr, ctx->bitstream.size, | ||
| 182 | DMA_TO_DEVICE); | ||
| 183 | |||
| 184 | src_buf->v4l2_buf.sequence = ctx->qsequence++; | 192 | src_buf->v4l2_buf.sequence = ctx->qsequence++; |
| 185 | 193 | ||
| 186 | return 0; | 194 | return 0; |
| @@ -214,7 +222,7 @@ static bool coda_bitstream_try_queue(struct coda_ctx *ctx, | |||
| 214 | return true; | 222 | return true; |
| 215 | } | 223 | } |
| 216 | 224 | ||
| 217 | void coda_fill_bitstream(struct coda_ctx *ctx) | 225 | void coda_fill_bitstream(struct coda_ctx *ctx, bool streaming) |
| 218 | { | 226 | { |
| 219 | struct vb2_buffer *src_buf; | 227 | struct vb2_buffer *src_buf; |
| 220 | struct coda_buffer_meta *meta; | 228 | struct coda_buffer_meta *meta; |
| @@ -235,9 +243,12 @@ void coda_fill_bitstream(struct coda_ctx *ctx) | |||
| 235 | if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG && | 243 | if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG && |
| 236 | !coda_jpeg_check_buffer(ctx, src_buf)) { | 244 | !coda_jpeg_check_buffer(ctx, src_buf)) { |
| 237 | v4l2_err(&ctx->dev->v4l2_dev, | 245 | v4l2_err(&ctx->dev->v4l2_dev, |
| 238 | "dropping invalid JPEG frame\n"); | 246 | "dropping invalid JPEG frame %d\n", |
| 247 | ctx->qsequence); | ||
| 239 | src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); | 248 | src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); |
| 240 | v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); | 249 | v4l2_m2m_buf_done(src_buf, streaming ? |
| 250 | VB2_BUF_STATE_ERROR : | ||
| 251 | VB2_BUF_STATE_QUEUED); | ||
| 241 | continue; | 252 | continue; |
| 242 | } | 253 | } |
| 243 | 254 | ||
| @@ -262,6 +273,8 @@ void coda_fill_bitstream(struct coda_ctx *ctx) | |||
| 262 | ctx->bitstream_fifo.kfifo.mask; | 273 | ctx->bitstream_fifo.kfifo.mask; |
| 263 | list_add_tail(&meta->list, | 274 | list_add_tail(&meta->list, |
| 264 | &ctx->buffer_meta_list); | 275 | &ctx->buffer_meta_list); |
| 276 | |||
| 277 | trace_coda_bit_queue(ctx, src_buf, meta); | ||
| 265 | } | 278 | } |
| 266 | 279 | ||
| 267 | v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); | 280 | v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); |
| @@ -297,6 +310,14 @@ static void coda_parabuf_write(struct coda_ctx *ctx, int index, u32 value) | |||
| 297 | p[index ^ 1] = value; | 310 | p[index ^ 1] = value; |
| 298 | } | 311 | } |
| 299 | 312 | ||
| 313 | static inline int coda_alloc_context_buf(struct coda_ctx *ctx, | ||
| 314 | struct coda_aux_buf *buf, size_t size, | ||
| 315 | const char *name) | ||
| 316 | { | ||
| 317 | return coda_alloc_aux_buf(ctx->dev, buf, size, name, ctx->debugfs_entry); | ||
| 318 | } | ||
| 319 | |||
| 320 | |||
| 300 | static void coda_free_framebuffers(struct coda_ctx *ctx) | 321 | static void coda_free_framebuffers(struct coda_ctx *ctx) |
| 301 | { | 322 | { |
| 302 | int i; | 323 | int i; |
| @@ -377,6 +398,7 @@ static void coda_free_context_buffers(struct coda_ctx *ctx) | |||
| 377 | coda_free_aux_buf(dev, &ctx->psbuf); | 398 | coda_free_aux_buf(dev, &ctx->psbuf); |
| 378 | if (dev->devtype->product != CODA_DX6) | 399 | if (dev->devtype->product != CODA_DX6) |
| 379 | coda_free_aux_buf(dev, &ctx->workbuf); | 400 | coda_free_aux_buf(dev, &ctx->workbuf); |
| 401 | coda_free_aux_buf(dev, &ctx->parabuf); | ||
| 380 | } | 402 | } |
| 381 | 403 | ||
| 382 | static int coda_alloc_context_buffers(struct coda_ctx *ctx, | 404 | static int coda_alloc_context_buffers(struct coda_ctx *ctx, |
| @@ -386,57 +408,42 @@ static int coda_alloc_context_buffers(struct coda_ctx *ctx, | |||
| 386 | size_t size; | 408 | size_t size; |
| 387 | int ret; | 409 | int ret; |
| 388 | 410 | ||
| 411 | if (!ctx->parabuf.vaddr) { | ||
| 412 | ret = coda_alloc_context_buf(ctx, &ctx->parabuf, | ||
| 413 | CODA_PARA_BUF_SIZE, "parabuf"); | ||
| 414 | if (ret < 0) | ||
| 415 | return ret; | ||
| 416 | } | ||
| 417 | |||
| 389 | if (dev->devtype->product == CODA_DX6) | 418 | if (dev->devtype->product == CODA_DX6) |
| 390 | return 0; | 419 | return 0; |
| 391 | 420 | ||
| 392 | if (ctx->psbuf.vaddr) { | 421 | if (!ctx->slicebuf.vaddr && q_data->fourcc == V4L2_PIX_FMT_H264) { |
| 393 | v4l2_err(&dev->v4l2_dev, "psmembuf still allocated\n"); | ||
| 394 | return -EBUSY; | ||
| 395 | } | ||
| 396 | if (ctx->slicebuf.vaddr) { | ||
| 397 | v4l2_err(&dev->v4l2_dev, "slicebuf still allocated\n"); | ||
| 398 | return -EBUSY; | ||
| 399 | } | ||
| 400 | if (ctx->workbuf.vaddr) { | ||
| 401 | v4l2_err(&dev->v4l2_dev, "context buffer still allocated\n"); | ||
| 402 | ret = -EBUSY; | ||
| 403 | return -ENOMEM; | ||
| 404 | } | ||
| 405 | |||
| 406 | if (q_data->fourcc == V4L2_PIX_FMT_H264) { | ||
| 407 | /* worst case slice size */ | 422 | /* worst case slice size */ |
| 408 | size = (DIV_ROUND_UP(q_data->width, 16) * | 423 | size = (DIV_ROUND_UP(q_data->width, 16) * |
| 409 | DIV_ROUND_UP(q_data->height, 16)) * 3200 / 8 + 512; | 424 | DIV_ROUND_UP(q_data->height, 16)) * 3200 / 8 + 512; |
| 410 | ret = coda_alloc_context_buf(ctx, &ctx->slicebuf, size, | 425 | ret = coda_alloc_context_buf(ctx, &ctx->slicebuf, size, |
| 411 | "slicebuf"); | 426 | "slicebuf"); |
| 412 | if (ret < 0) { | 427 | if (ret < 0) |
| 413 | v4l2_err(&dev->v4l2_dev, | 428 | goto err; |
| 414 | "failed to allocate %d byte slice buffer", | ||
| 415 | ctx->slicebuf.size); | ||
| 416 | return ret; | ||
| 417 | } | ||
| 418 | } | 429 | } |
| 419 | 430 | ||
| 420 | if (dev->devtype->product == CODA_7541) { | 431 | if (!ctx->psbuf.vaddr && dev->devtype->product == CODA_7541) { |
| 421 | ret = coda_alloc_context_buf(ctx, &ctx->psbuf, | 432 | ret = coda_alloc_context_buf(ctx, &ctx->psbuf, |
| 422 | CODA7_PS_BUF_SIZE, "psbuf"); | 433 | CODA7_PS_BUF_SIZE, "psbuf"); |
| 423 | if (ret < 0) { | 434 | if (ret < 0) |
| 424 | v4l2_err(&dev->v4l2_dev, | ||
| 425 | "failed to allocate psmem buffer"); | ||
| 426 | goto err; | 435 | goto err; |
| 427 | } | ||
| 428 | } | 436 | } |
| 429 | 437 | ||
| 430 | size = dev->devtype->workbuf_size; | 438 | if (!ctx->workbuf.vaddr) { |
| 431 | if (dev->devtype->product == CODA_960 && | 439 | size = dev->devtype->workbuf_size; |
| 432 | q_data->fourcc == V4L2_PIX_FMT_H264) | 440 | if (dev->devtype->product == CODA_960 && |
| 433 | size += CODA9_PS_SAVE_SIZE; | 441 | q_data->fourcc == V4L2_PIX_FMT_H264) |
| 434 | ret = coda_alloc_context_buf(ctx, &ctx->workbuf, size, "workbuf"); | 442 | size += CODA9_PS_SAVE_SIZE; |
| 435 | if (ret < 0) { | 443 | ret = coda_alloc_context_buf(ctx, &ctx->workbuf, size, |
| 436 | v4l2_err(&dev->v4l2_dev, | 444 | "workbuf"); |
| 437 | "failed to allocate %d byte context buffer", | 445 | if (ret < 0) |
| 438 | ctx->workbuf.size); | 446 | goto err; |
| 439 | goto err; | ||
| 440 | } | 447 | } |
| 441 | 448 | ||
| 442 | return 0; | 449 | return 0; |
| @@ -709,6 +716,27 @@ err_clk_per: | |||
| 709 | * Encoder context operations | 716 | * Encoder context operations |
| 710 | */ | 717 | */ |
| 711 | 718 | ||
| 719 | static int coda_encoder_reqbufs(struct coda_ctx *ctx, | ||
| 720 | struct v4l2_requestbuffers *rb) | ||
| 721 | { | ||
| 722 | struct coda_q_data *q_data_src; | ||
| 723 | int ret; | ||
| 724 | |||
| 725 | if (rb->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) | ||
| 726 | return 0; | ||
| 727 | |||
| 728 | if (rb->count) { | ||
| 729 | q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); | ||
| 730 | ret = coda_alloc_context_buffers(ctx, q_data_src); | ||
| 731 | if (ret < 0) | ||
| 732 | return ret; | ||
| 733 | } else { | ||
| 734 | coda_free_context_buffers(ctx); | ||
| 735 | } | ||
| 736 | |||
| 737 | return 0; | ||
| 738 | } | ||
| 739 | |||
| 712 | static int coda_start_encoding(struct coda_ctx *ctx) | 740 | static int coda_start_encoding(struct coda_ctx *ctx) |
| 713 | { | 741 | { |
| 714 | struct coda_dev *dev = ctx->dev; | 742 | struct coda_dev *dev = ctx->dev; |
| @@ -725,11 +753,6 @@ static int coda_start_encoding(struct coda_ctx *ctx) | |||
| 725 | q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); | 753 | q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); |
| 726 | dst_fourcc = q_data_dst->fourcc; | 754 | dst_fourcc = q_data_dst->fourcc; |
| 727 | 755 | ||
| 728 | /* Allocate per-instance buffers */ | ||
| 729 | ret = coda_alloc_context_buffers(ctx, q_data_src); | ||
| 730 | if (ret < 0) | ||
| 731 | return ret; | ||
| 732 | |||
| 733 | buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); | 756 | buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); |
| 734 | bitstream_buf = vb2_dma_contig_plane_dma_addr(buf, 0); | 757 | bitstream_buf = vb2_dma_contig_plane_dma_addr(buf, 0); |
| 735 | bitstream_size = q_data_dst->sizeimage; | 758 | bitstream_size = q_data_dst->sizeimage; |
| @@ -1227,6 +1250,8 @@ static int coda_prepare_encode(struct coda_ctx *ctx) | |||
| 1227 | coda_write(dev, ctx->iram_info.axi_sram_use, | 1250 | coda_write(dev, ctx->iram_info.axi_sram_use, |
| 1228 | CODA7_REG_BIT_AXI_SRAM_USE); | 1251 | CODA7_REG_BIT_AXI_SRAM_USE); |
| 1229 | 1252 | ||
| 1253 | trace_coda_enc_pic_run(ctx, src_buf); | ||
| 1254 | |||
| 1230 | coda_command_async(ctx, CODA_COMMAND_PIC_RUN); | 1255 | coda_command_async(ctx, CODA_COMMAND_PIC_RUN); |
| 1231 | 1256 | ||
| 1232 | return 0; | 1257 | return 0; |
| @@ -1241,6 +1266,8 @@ static void coda_finish_encode(struct coda_ctx *ctx) | |||
| 1241 | src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); | 1266 | src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); |
| 1242 | dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); | 1267 | dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); |
| 1243 | 1268 | ||
| 1269 | trace_coda_enc_pic_done(ctx, dst_buf); | ||
| 1270 | |||
| 1244 | /* Get results from the coda */ | 1271 | /* Get results from the coda */ |
| 1245 | start_ptr = coda_read(dev, CODA_CMD_ENC_PIC_BB_START); | 1272 | start_ptr = coda_read(dev, CODA_CMD_ENC_PIC_BB_START); |
| 1246 | wr_ptr = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); | 1273 | wr_ptr = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); |
| @@ -1311,7 +1338,6 @@ static void coda_seq_end_work(struct work_struct *work) | |||
| 1311 | ctx->bitstream.vaddr, ctx->bitstream.size); | 1338 | ctx->bitstream.vaddr, ctx->bitstream.size); |
| 1312 | 1339 | ||
| 1313 | coda_free_framebuffers(ctx); | 1340 | coda_free_framebuffers(ctx); |
| 1314 | coda_free_context_buffers(ctx); | ||
| 1315 | 1341 | ||
| 1316 | mutex_unlock(&dev->coda_mutex); | 1342 | mutex_unlock(&dev->coda_mutex); |
| 1317 | mutex_unlock(&ctx->buffer_mutex); | 1343 | mutex_unlock(&ctx->buffer_mutex); |
| @@ -1322,11 +1348,13 @@ static void coda_bit_release(struct coda_ctx *ctx) | |||
| 1322 | mutex_lock(&ctx->buffer_mutex); | 1348 | mutex_lock(&ctx->buffer_mutex); |
| 1323 | coda_free_framebuffers(ctx); | 1349 | coda_free_framebuffers(ctx); |
| 1324 | coda_free_context_buffers(ctx); | 1350 | coda_free_context_buffers(ctx); |
| 1351 | coda_free_bitstream_buffer(ctx); | ||
| 1325 | mutex_unlock(&ctx->buffer_mutex); | 1352 | mutex_unlock(&ctx->buffer_mutex); |
| 1326 | } | 1353 | } |
| 1327 | 1354 | ||
| 1328 | const struct coda_context_ops coda_bit_encode_ops = { | 1355 | const struct coda_context_ops coda_bit_encode_ops = { |
| 1329 | .queue_init = coda_encoder_queue_init, | 1356 | .queue_init = coda_encoder_queue_init, |
| 1357 | .reqbufs = coda_encoder_reqbufs, | ||
| 1330 | .start_streaming = coda_start_encoding, | 1358 | .start_streaming = coda_start_encoding, |
| 1331 | .prepare_run = coda_prepare_encode, | 1359 | .prepare_run = coda_prepare_encode, |
| 1332 | .finish_run = coda_finish_encode, | 1360 | .finish_run = coda_finish_encode, |
| @@ -1338,6 +1366,65 @@ const struct coda_context_ops coda_bit_encode_ops = { | |||
| 1338 | * Decoder context operations | 1366 | * Decoder context operations |
| 1339 | */ | 1367 | */ |
| 1340 | 1368 | ||
| 1369 | static int coda_alloc_bitstream_buffer(struct coda_ctx *ctx, | ||
| 1370 | struct coda_q_data *q_data) | ||
| 1371 | { | ||
| 1372 | if (ctx->bitstream.vaddr) | ||
| 1373 | return 0; | ||
| 1374 | |||
| 1375 | ctx->bitstream.size = roundup_pow_of_two(q_data->sizeimage * 2); | ||
| 1376 | ctx->bitstream.vaddr = dma_alloc_writecombine( | ||
| 1377 | &ctx->dev->plat_dev->dev, ctx->bitstream.size, | ||
| 1378 | &ctx->bitstream.paddr, GFP_KERNEL); | ||
| 1379 | if (!ctx->bitstream.vaddr) { | ||
| 1380 | v4l2_err(&ctx->dev->v4l2_dev, | ||
| 1381 | "failed to allocate bitstream ringbuffer"); | ||
| 1382 | return -ENOMEM; | ||
| 1383 | } | ||
| 1384 | kfifo_init(&ctx->bitstream_fifo, | ||
| 1385 | ctx->bitstream.vaddr, ctx->bitstream.size); | ||
| 1386 | |||
| 1387 | return 0; | ||
| 1388 | } | ||
| 1389 | |||
| 1390 | static void coda_free_bitstream_buffer(struct coda_ctx *ctx) | ||
| 1391 | { | ||
| 1392 | if (ctx->bitstream.vaddr == NULL) | ||
| 1393 | return; | ||
| 1394 | |||
| 1395 | dma_free_writecombine(&ctx->dev->plat_dev->dev, ctx->bitstream.size, | ||
| 1396 | ctx->bitstream.vaddr, ctx->bitstream.paddr); | ||
| 1397 | ctx->bitstream.vaddr = NULL; | ||
| 1398 | kfifo_init(&ctx->bitstream_fifo, NULL, 0); | ||
| 1399 | } | ||
| 1400 | |||
| 1401 | static int coda_decoder_reqbufs(struct coda_ctx *ctx, | ||
| 1402 | struct v4l2_requestbuffers *rb) | ||
| 1403 | { | ||
| 1404 | struct coda_q_data *q_data_src; | ||
| 1405 | int ret; | ||
| 1406 | |||
| 1407 | if (rb->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) | ||
| 1408 | return 0; | ||
| 1409 | |||
| 1410 | if (rb->count) { | ||
| 1411 | q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); | ||
| 1412 | ret = coda_alloc_context_buffers(ctx, q_data_src); | ||
| 1413 | if (ret < 0) | ||
| 1414 | return ret; | ||
| 1415 | ret = coda_alloc_bitstream_buffer(ctx, q_data_src); | ||
| 1416 | if (ret < 0) { | ||
| 1417 | coda_free_context_buffers(ctx); | ||
| 1418 | return ret; | ||
| 1419 | } | ||
| 1420 | } else { | ||
| 1421 | coda_free_bitstream_buffer(ctx); | ||
| 1422 | coda_free_context_buffers(ctx); | ||
| 1423 | } | ||
| 1424 | |||
| 1425 | return 0; | ||
| 1426 | } | ||
| 1427 | |||
| 1341 | static int __coda_start_decoding(struct coda_ctx *ctx) | 1428 | static int __coda_start_decoding(struct coda_ctx *ctx) |
| 1342 | { | 1429 | { |
| 1343 | struct coda_q_data *q_data_src, *q_data_dst; | 1430 | struct coda_q_data *q_data_src, *q_data_dst; |
| @@ -1356,11 +1443,6 @@ static int __coda_start_decoding(struct coda_ctx *ctx) | |||
| 1356 | src_fourcc = q_data_src->fourcc; | 1443 | src_fourcc = q_data_src->fourcc; |
| 1357 | dst_fourcc = q_data_dst->fourcc; | 1444 | dst_fourcc = q_data_dst->fourcc; |
| 1358 | 1445 | ||
| 1359 | /* Allocate per-instance buffers */ | ||
| 1360 | ret = coda_alloc_context_buffers(ctx, q_data_src); | ||
| 1361 | if (ret < 0) | ||
| 1362 | return ret; | ||
| 1363 | |||
| 1364 | coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR); | 1446 | coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR); |
| 1365 | 1447 | ||
| 1366 | /* Update coda bitstream read and write pointers from kfifo */ | 1448 | /* Update coda bitstream read and write pointers from kfifo */ |
| @@ -1579,7 +1661,7 @@ static int coda_prepare_decode(struct coda_ctx *ctx) | |||
| 1579 | 1661 | ||
| 1580 | /* Try to copy source buffer contents into the bitstream ringbuffer */ | 1662 | /* Try to copy source buffer contents into the bitstream ringbuffer */ |
| 1581 | mutex_lock(&ctx->bitstream_mutex); | 1663 | mutex_lock(&ctx->bitstream_mutex); |
| 1582 | coda_fill_bitstream(ctx); | 1664 | coda_fill_bitstream(ctx, true); |
| 1583 | mutex_unlock(&ctx->bitstream_mutex); | 1665 | mutex_unlock(&ctx->bitstream_mutex); |
| 1584 | 1666 | ||
| 1585 | if (coda_get_bitstream_payload(ctx) < 512 && | 1667 | if (coda_get_bitstream_payload(ctx) < 512 && |
| @@ -1675,6 +1757,8 @@ static int coda_prepare_decode(struct coda_ctx *ctx) | |||
| 1675 | /* Clear decode success flag */ | 1757 | /* Clear decode success flag */ |
| 1676 | coda_write(dev, 0, CODA_RET_DEC_PIC_SUCCESS); | 1758 | coda_write(dev, 0, CODA_RET_DEC_PIC_SUCCESS); |
| 1677 | 1759 | ||
| 1760 | trace_coda_dec_pic_run(ctx, meta); | ||
| 1761 | |||
| 1678 | coda_command_async(ctx, CODA_COMMAND_PIC_RUN); | 1762 | coda_command_async(ctx, CODA_COMMAND_PIC_RUN); |
| 1679 | 1763 | ||
| 1680 | return 0; | 1764 | return 0; |
| @@ -1704,7 +1788,7 @@ static void coda_finish_decode(struct coda_ctx *ctx) | |||
| 1704 | * by up to 512 bytes | 1788 | * by up to 512 bytes |
| 1705 | */ | 1789 | */ |
| 1706 | if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) { | 1790 | if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) { |
| 1707 | if (coda_get_bitstream_payload(ctx) >= CODA_MAX_FRAME_SIZE - 512) | 1791 | if (coda_get_bitstream_payload(ctx) >= ctx->bitstream.size - 512) |
| 1708 | kfifo_init(&ctx->bitstream_fifo, | 1792 | kfifo_init(&ctx->bitstream_fifo, |
| 1709 | ctx->bitstream.vaddr, ctx->bitstream.size); | 1793 | ctx->bitstream.vaddr, ctx->bitstream.size); |
| 1710 | } | 1794 | } |
| @@ -1835,6 +1919,8 @@ static void coda_finish_decode(struct coda_ctx *ctx) | |||
| 1835 | } | 1919 | } |
| 1836 | mutex_unlock(&ctx->bitstream_mutex); | 1920 | mutex_unlock(&ctx->bitstream_mutex); |
| 1837 | 1921 | ||
| 1922 | trace_coda_dec_pic_done(ctx, &ctx->frame_metas[decoded_idx]); | ||
| 1923 | |||
| 1838 | val = coda_read(dev, CODA_RET_DEC_PIC_TYPE) & 0x7; | 1924 | val = coda_read(dev, CODA_RET_DEC_PIC_TYPE) & 0x7; |
| 1839 | if (val == 0) | 1925 | if (val == 0) |
| 1840 | ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_KEYFRAME; | 1926 | ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_KEYFRAME; |
| @@ -1874,6 +1960,8 @@ static void coda_finish_decode(struct coda_ctx *ctx) | |||
| 1874 | dst_buf->v4l2_buf.timecode = meta->timecode; | 1960 | dst_buf->v4l2_buf.timecode = meta->timecode; |
| 1875 | dst_buf->v4l2_buf.timestamp = meta->timestamp; | 1961 | dst_buf->v4l2_buf.timestamp = meta->timestamp; |
| 1876 | 1962 | ||
| 1963 | trace_coda_dec_rot_done(ctx, meta, dst_buf); | ||
| 1964 | |||
| 1877 | switch (q_data_dst->fourcc) { | 1965 | switch (q_data_dst->fourcc) { |
| 1878 | case V4L2_PIX_FMT_YUV420: | 1966 | case V4L2_PIX_FMT_YUV420: |
| 1879 | case V4L2_PIX_FMT_YVU420: | 1967 | case V4L2_PIX_FMT_YVU420: |
| @@ -1906,6 +1994,7 @@ static void coda_finish_decode(struct coda_ctx *ctx) | |||
| 1906 | 1994 | ||
| 1907 | const struct coda_context_ops coda_bit_decode_ops = { | 1995 | const struct coda_context_ops coda_bit_decode_ops = { |
| 1908 | .queue_init = coda_decoder_queue_init, | 1996 | .queue_init = coda_decoder_queue_init, |
| 1997 | .reqbufs = coda_decoder_reqbufs, | ||
| 1909 | .start_streaming = coda_start_decoding, | 1998 | .start_streaming = coda_start_decoding, |
| 1910 | .prepare_run = coda_prepare_decode, | 1999 | .prepare_run = coda_prepare_decode, |
| 1911 | .finish_run = coda_finish_decode, | 2000 | .finish_run = coda_finish_decode, |
| @@ -1931,6 +2020,8 @@ irqreturn_t coda_irq_handler(int irq, void *data) | |||
| 1931 | return IRQ_HANDLED; | 2020 | return IRQ_HANDLED; |
| 1932 | } | 2021 | } |
| 1933 | 2022 | ||
| 2023 | trace_coda_bit_done(ctx); | ||
| 2024 | |||
| 1934 | if (ctx->aborting) { | 2025 | if (ctx->aborting) { |
| 1935 | v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, | 2026 | v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, |
| 1936 | "task has been aborted\n"); | 2027 | "task has been aborted\n"); |
diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 6f32e6d6b156..8e6fe0200117 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c | |||
| @@ -46,7 +46,6 @@ | |||
| 46 | #define CODADX6_MAX_INSTANCES 4 | 46 | #define CODADX6_MAX_INSTANCES 4 |
| 47 | #define CODA_MAX_FORMATS 4 | 47 | #define CODA_MAX_FORMATS 4 |
| 48 | 48 | ||
| 49 | #define CODA_PARA_BUF_SIZE (10 * 1024) | ||
| 50 | #define CODA_ISRAM_SIZE (2048 * 2) | 49 | #define CODA_ISRAM_SIZE (2048 * 2) |
| 51 | 50 | ||
| 52 | #define MIN_W 176 | 51 | #define MIN_W 176 |
| @@ -696,6 +695,26 @@ static int coda_s_fmt_vid_out(struct file *file, void *priv, | |||
| 696 | return coda_s_fmt(ctx, &f_cap); | 695 | return coda_s_fmt(ctx, &f_cap); |
| 697 | } | 696 | } |
| 698 | 697 | ||
| 698 | static int coda_reqbufs(struct file *file, void *priv, | ||
| 699 | struct v4l2_requestbuffers *rb) | ||
| 700 | { | ||
| 701 | struct coda_ctx *ctx = fh_to_ctx(priv); | ||
| 702 | int ret; | ||
| 703 | |||
| 704 | ret = v4l2_m2m_reqbufs(file, ctx->fh.m2m_ctx, rb); | ||
| 705 | if (ret) | ||
| 706 | return ret; | ||
| 707 | |||
| 708 | /* | ||
| 709 | * Allow to allocate instance specific per-context buffers, such as | ||
| 710 | * bitstream ringbuffer, slice buffer, work buffer, etc. if needed. | ||
| 711 | */ | ||
| 712 | if (rb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && ctx->ops->reqbufs) | ||
| 713 | return ctx->ops->reqbufs(ctx, rb); | ||
| 714 | |||
| 715 | return 0; | ||
| 716 | } | ||
| 717 | |||
| 699 | static int coda_qbuf(struct file *file, void *priv, | 718 | static int coda_qbuf(struct file *file, void *priv, |
| 700 | struct v4l2_buffer *buf) | 719 | struct v4l2_buffer *buf) |
| 701 | { | 720 | { |
| @@ -841,7 +860,7 @@ static const struct v4l2_ioctl_ops coda_ioctl_ops = { | |||
| 841 | .vidioc_try_fmt_vid_out = coda_try_fmt_vid_out, | 860 | .vidioc_try_fmt_vid_out = coda_try_fmt_vid_out, |
| 842 | .vidioc_s_fmt_vid_out = coda_s_fmt_vid_out, | 861 | .vidioc_s_fmt_vid_out = coda_s_fmt_vid_out, |
| 843 | 862 | ||
| 844 | .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, | 863 | .vidioc_reqbufs = coda_reqbufs, |
| 845 | .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, | 864 | .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, |
| 846 | 865 | ||
| 847 | .vidioc_qbuf = coda_qbuf, | 866 | .vidioc_qbuf = coda_qbuf, |
| @@ -1173,7 +1192,7 @@ static void coda_buf_queue(struct vb2_buffer *vb) | |||
| 1173 | mutex_lock(&ctx->bitstream_mutex); | 1192 | mutex_lock(&ctx->bitstream_mutex); |
| 1174 | v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb); | 1193 | v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb); |
| 1175 | if (vb2_is_streaming(vb->vb2_queue)) | 1194 | if (vb2_is_streaming(vb->vb2_queue)) |
| 1176 | coda_fill_bitstream(ctx); | 1195 | coda_fill_bitstream(ctx, true); |
| 1177 | mutex_unlock(&ctx->bitstream_mutex); | 1196 | mutex_unlock(&ctx->bitstream_mutex); |
| 1178 | } else { | 1197 | } else { |
| 1179 | v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb); | 1198 | v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb); |
| @@ -1215,8 +1234,9 @@ void coda_free_aux_buf(struct coda_dev *dev, | |||
| 1215 | buf->vaddr, buf->paddr); | 1234 | buf->vaddr, buf->paddr); |
| 1216 | buf->vaddr = NULL; | 1235 | buf->vaddr = NULL; |
| 1217 | buf->size = 0; | 1236 | buf->size = 0; |
| 1237 | debugfs_remove(buf->dentry); | ||
| 1238 | buf->dentry = NULL; | ||
| 1218 | } | 1239 | } |
| 1219 | debugfs_remove(buf->dentry); | ||
| 1220 | } | 1240 | } |
| 1221 | 1241 | ||
| 1222 | static int coda_start_streaming(struct vb2_queue *q, unsigned int count) | 1242 | static int coda_start_streaming(struct vb2_queue *q, unsigned int count) |
| @@ -1232,9 +1252,9 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) | |||
| 1232 | if (q_data_src->fourcc == V4L2_PIX_FMT_H264 || | 1252 | if (q_data_src->fourcc == V4L2_PIX_FMT_H264 || |
| 1233 | (q_data_src->fourcc == V4L2_PIX_FMT_JPEG && | 1253 | (q_data_src->fourcc == V4L2_PIX_FMT_JPEG && |
| 1234 | ctx->dev->devtype->product == CODA_7541)) { | 1254 | ctx->dev->devtype->product == CODA_7541)) { |
| 1235 | /* copy the buffers that where queued before streamon */ | 1255 | /* copy the buffers that were queued before streamon */ |
| 1236 | mutex_lock(&ctx->bitstream_mutex); | 1256 | mutex_lock(&ctx->bitstream_mutex); |
| 1237 | coda_fill_bitstream(ctx); | 1257 | coda_fill_bitstream(ctx, false); |
| 1238 | mutex_unlock(&ctx->bitstream_mutex); | 1258 | mutex_unlock(&ctx->bitstream_mutex); |
| 1239 | 1259 | ||
| 1240 | if (coda_get_bitstream_payload(ctx) < 512) { | 1260 | if (coda_get_bitstream_payload(ctx) < 512) { |
| @@ -1262,12 +1282,23 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) | |||
| 1262 | if (!(ctx->streamon_out & ctx->streamon_cap)) | 1282 | if (!(ctx->streamon_out & ctx->streamon_cap)) |
| 1263 | return 0; | 1283 | return 0; |
| 1264 | 1284 | ||
| 1285 | q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); | ||
| 1286 | if ((q_data_src->width != q_data_dst->width && | ||
| 1287 | round_up(q_data_src->width, 16) != q_data_dst->width) || | ||
| 1288 | (q_data_src->height != q_data_dst->height && | ||
| 1289 | round_up(q_data_src->height, 16) != q_data_dst->height)) { | ||
| 1290 | v4l2_err(v4l2_dev, "can't convert %dx%d to %dx%d\n", | ||
| 1291 | q_data_src->width, q_data_src->height, | ||
| 1292 | q_data_dst->width, q_data_dst->height); | ||
| 1293 | ret = -EINVAL; | ||
| 1294 | goto err; | ||
| 1295 | } | ||
| 1296 | |||
| 1265 | /* Allow BIT decoder device_run with no new buffers queued */ | 1297 | /* Allow BIT decoder device_run with no new buffers queued */ |
| 1266 | if (ctx->inst_type == CODA_INST_DECODER && ctx->use_bit) | 1298 | if (ctx->inst_type == CODA_INST_DECODER && ctx->use_bit) |
| 1267 | v4l2_m2m_set_src_buffered(ctx->fh.m2m_ctx, true); | 1299 | v4l2_m2m_set_src_buffered(ctx->fh.m2m_ctx, true); |
| 1268 | 1300 | ||
| 1269 | ctx->gopcounter = ctx->params.gop_size - 1; | 1301 | ctx->gopcounter = ctx->params.gop_size - 1; |
| 1270 | q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); | ||
| 1271 | 1302 | ||
| 1272 | ctx->codec = coda_find_codec(ctx->dev, q_data_src->fourcc, | 1303 | ctx->codec = coda_find_codec(ctx->dev, q_data_src->fourcc, |
| 1273 | q_data_dst->fourcc); | 1304 | q_data_dst->fourcc); |
| @@ -1308,6 +1339,9 @@ static void coda_stop_streaming(struct vb2_queue *q) | |||
| 1308 | struct coda_ctx *ctx = vb2_get_drv_priv(q); | 1339 | struct coda_ctx *ctx = vb2_get_drv_priv(q); |
| 1309 | struct coda_dev *dev = ctx->dev; | 1340 | struct coda_dev *dev = ctx->dev; |
| 1310 | struct vb2_buffer *buf; | 1341 | struct vb2_buffer *buf; |
| 1342 | bool stop; | ||
| 1343 | |||
| 1344 | stop = ctx->streamon_out && ctx->streamon_cap; | ||
| 1311 | 1345 | ||
| 1312 | if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { | 1346 | if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { |
| 1313 | v4l2_dbg(1, coda_debug, &dev->v4l2_dev, | 1347 | v4l2_dbg(1, coda_debug, &dev->v4l2_dev, |
| @@ -1332,7 +1366,7 @@ static void coda_stop_streaming(struct vb2_queue *q) | |||
| 1332 | v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR); | 1366 | v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR); |
| 1333 | } | 1367 | } |
| 1334 | 1368 | ||
| 1335 | if (!ctx->streamon_out && !ctx->streamon_cap) { | 1369 | if (stop) { |
| 1336 | struct coda_buffer_meta *meta; | 1370 | struct coda_buffer_meta *meta; |
| 1337 | 1371 | ||
| 1338 | if (ctx->ops->seq_end_work) { | 1372 | if (ctx->ops->seq_end_work) { |
| @@ -1457,7 +1491,7 @@ static const struct v4l2_ctrl_ops coda_ctrl_ops = { | |||
| 1457 | static void coda_encode_ctrls(struct coda_ctx *ctx) | 1491 | static void coda_encode_ctrls(struct coda_ctx *ctx) |
| 1458 | { | 1492 | { |
| 1459 | v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, | 1493 | v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, |
| 1460 | V4L2_CID_MPEG_VIDEO_BITRATE, 0, 32767000, 1, 0); | 1494 | V4L2_CID_MPEG_VIDEO_BITRATE, 0, 32767000, 1000, 0); |
| 1461 | v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, | 1495 | v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, |
| 1462 | V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1, 60, 1, 16); | 1496 | V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1, 60, 1, 16); |
| 1463 | v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, | 1497 | v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, |
| @@ -1541,6 +1575,13 @@ static int coda_queue_init(struct coda_ctx *ctx, struct vb2_queue *vq) | |||
| 1541 | vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); | 1575 | vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); |
| 1542 | vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; | 1576 | vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; |
| 1543 | vq->lock = &ctx->dev->dev_mutex; | 1577 | vq->lock = &ctx->dev->dev_mutex; |
| 1578 | /* One way to indicate end-of-stream for coda is to set the | ||
| 1579 | * bytesused == 0. However by default videobuf2 handles bytesused | ||
| 1580 | * equal to 0 as a special case and changes its value to the size | ||
| 1581 | * of the buffer. Set the allow_zero_bytesused flag, so | ||
| 1582 | * that videobuf2 will keep the value of bytesused intact. | ||
| 1583 | */ | ||
| 1584 | vq->allow_zero_bytesused = 1; | ||
| 1544 | 1585 | ||
| 1545 | return vb2_queue_init(vq); | 1586 | return vb2_queue_init(vq); |
| 1546 | } | 1587 | } |
| @@ -1621,6 +1662,11 @@ static int coda_open(struct file *file) | |||
| 1621 | set_bit(idx, &dev->instance_mask); | 1662 | set_bit(idx, &dev->instance_mask); |
| 1622 | 1663 | ||
| 1623 | name = kasprintf(GFP_KERNEL, "context%d", idx); | 1664 | name = kasprintf(GFP_KERNEL, "context%d", idx); |
| 1665 | if (!name) { | ||
| 1666 | ret = -ENOMEM; | ||
| 1667 | goto err_coda_name_init; | ||
| 1668 | } | ||
| 1669 | |||
| 1624 | ctx->debugfs_entry = debugfs_create_dir(name, dev->debugfs_root); | 1670 | ctx->debugfs_entry = debugfs_create_dir(name, dev->debugfs_root); |
| 1625 | kfree(name); | 1671 | kfree(name); |
| 1626 | 1672 | ||
| @@ -1682,28 +1728,6 @@ static int coda_open(struct file *file) | |||
| 1682 | 1728 | ||
| 1683 | ctx->fh.ctrl_handler = &ctx->ctrls; | 1729 | ctx->fh.ctrl_handler = &ctx->ctrls; |
| 1684 | 1730 | ||
| 1685 | if (ctx->use_bit) { | ||
| 1686 | ret = coda_alloc_context_buf(ctx, &ctx->parabuf, | ||
| 1687 | CODA_PARA_BUF_SIZE, "parabuf"); | ||
| 1688 | if (ret < 0) { | ||
| 1689 | v4l2_err(&dev->v4l2_dev, "failed to allocate parabuf"); | ||
| 1690 | goto err_dma_alloc; | ||
| 1691 | } | ||
| 1692 | } | ||
| 1693 | if (ctx->use_bit && ctx->inst_type == CODA_INST_DECODER) { | ||
| 1694 | ctx->bitstream.size = CODA_MAX_FRAME_SIZE; | ||
| 1695 | ctx->bitstream.vaddr = dma_alloc_writecombine( | ||
| 1696 | &dev->plat_dev->dev, ctx->bitstream.size, | ||
| 1697 | &ctx->bitstream.paddr, GFP_KERNEL); | ||
| 1698 | if (!ctx->bitstream.vaddr) { | ||
| 1699 | v4l2_err(&dev->v4l2_dev, | ||
| 1700 | "failed to allocate bitstream ringbuffer"); | ||
| 1701 | ret = -ENOMEM; | ||
| 1702 | goto err_dma_writecombine; | ||
| 1703 | } | ||
| 1704 | } | ||
| 1705 | kfifo_init(&ctx->bitstream_fifo, | ||
| 1706 | ctx->bitstream.vaddr, ctx->bitstream.size); | ||
| 1707 | mutex_init(&ctx->bitstream_mutex); | 1731 | mutex_init(&ctx->bitstream_mutex); |
| 1708 | mutex_init(&ctx->buffer_mutex); | 1732 | mutex_init(&ctx->buffer_mutex); |
| 1709 | INIT_LIST_HEAD(&ctx->buffer_meta_list); | 1733 | INIT_LIST_HEAD(&ctx->buffer_meta_list); |
| @@ -1717,12 +1741,6 @@ static int coda_open(struct file *file) | |||
| 1717 | 1741 | ||
| 1718 | return 0; | 1742 | return 0; |
| 1719 | 1743 | ||
| 1720 | err_dma_writecombine: | ||
| 1721 | if (ctx->dev->devtype->product == CODA_DX6) | ||
| 1722 | coda_free_aux_buf(dev, &ctx->workbuf); | ||
| 1723 | coda_free_aux_buf(dev, &ctx->parabuf); | ||
| 1724 | err_dma_alloc: | ||
| 1725 | v4l2_ctrl_handler_free(&ctx->ctrls); | ||
| 1726 | err_ctrls_setup: | 1744 | err_ctrls_setup: |
| 1727 | v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); | 1745 | v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); |
| 1728 | err_ctx_init: | 1746 | err_ctx_init: |
| @@ -1735,6 +1753,7 @@ err_pm_get: | |||
| 1735 | v4l2_fh_del(&ctx->fh); | 1753 | v4l2_fh_del(&ctx->fh); |
| 1736 | v4l2_fh_exit(&ctx->fh); | 1754 | v4l2_fh_exit(&ctx->fh); |
| 1737 | clear_bit(ctx->idx, &dev->instance_mask); | 1755 | clear_bit(ctx->idx, &dev->instance_mask); |
| 1756 | err_coda_name_init: | ||
| 1738 | err_coda_max: | 1757 | err_coda_max: |
| 1739 | kfree(ctx); | 1758 | kfree(ctx); |
| 1740 | return ret; | 1759 | return ret; |
| @@ -1764,14 +1783,9 @@ static int coda_release(struct file *file) | |||
| 1764 | list_del(&ctx->list); | 1783 | list_del(&ctx->list); |
| 1765 | coda_unlock(ctx); | 1784 | coda_unlock(ctx); |
| 1766 | 1785 | ||
| 1767 | if (ctx->bitstream.vaddr) { | ||
| 1768 | dma_free_writecombine(&dev->plat_dev->dev, ctx->bitstream.size, | ||
| 1769 | ctx->bitstream.vaddr, ctx->bitstream.paddr); | ||
| 1770 | } | ||
| 1771 | if (ctx->dev->devtype->product == CODA_DX6) | 1786 | if (ctx->dev->devtype->product == CODA_DX6) |
| 1772 | coda_free_aux_buf(dev, &ctx->workbuf); | 1787 | coda_free_aux_buf(dev, &ctx->workbuf); |
| 1773 | 1788 | ||
| 1774 | coda_free_aux_buf(dev, &ctx->parabuf); | ||
| 1775 | v4l2_ctrl_handler_free(&ctx->ctrls); | 1789 | v4l2_ctrl_handler_free(&ctx->ctrls); |
| 1776 | clk_disable_unprepare(dev->clk_ahb); | 1790 | clk_disable_unprepare(dev->clk_ahb); |
| 1777 | clk_disable_unprepare(dev->clk_per); | 1791 | clk_disable_unprepare(dev->clk_per); |
| @@ -1901,8 +1915,7 @@ static int coda_register_device(struct coda_dev *dev, int i) | |||
| 1901 | if (i >= dev->devtype->num_vdevs) | 1915 | if (i >= dev->devtype->num_vdevs) |
| 1902 | return -EINVAL; | 1916 | return -EINVAL; |
| 1903 | 1917 | ||
| 1904 | snprintf(vfd->name, sizeof(vfd->name), "%s", | 1918 | strlcpy(vfd->name, dev->devtype->vdevs[i]->name, sizeof(vfd->name)); |
| 1905 | dev->devtype->vdevs[i]->name); | ||
| 1906 | vfd->fops = &coda_fops; | 1919 | vfd->fops = &coda_fops; |
| 1907 | vfd->ioctl_ops = &coda_ioctl_ops; | 1920 | vfd->ioctl_ops = &coda_ioctl_ops; |
| 1908 | vfd->release = video_device_release_empty, | 1921 | vfd->release = video_device_release_empty, |
| @@ -1933,10 +1946,8 @@ static void coda_fw_callback(const struct firmware *fw, void *context) | |||
| 1933 | /* allocate auxiliary per-device code buffer for the BIT processor */ | 1946 | /* allocate auxiliary per-device code buffer for the BIT processor */ |
| 1934 | ret = coda_alloc_aux_buf(dev, &dev->codebuf, fw->size, "codebuf", | 1947 | ret = coda_alloc_aux_buf(dev, &dev->codebuf, fw->size, "codebuf", |
| 1935 | dev->debugfs_root); | 1948 | dev->debugfs_root); |
| 1936 | if (ret < 0) { | 1949 | if (ret < 0) |
| 1937 | dev_err(&pdev->dev, "failed to allocate code buffer\n"); | ||
| 1938 | goto put_pm; | 1950 | goto put_pm; |
| 1939 | } | ||
| 1940 | 1951 | ||
| 1941 | /* Copy the whole firmware image to the code buffer */ | 1952 | /* Copy the whole firmware image to the code buffer */ |
| 1942 | memcpy(dev->codebuf.vaddr, fw->data, fw->size); | 1953 | memcpy(dev->codebuf.vaddr, fw->data, fw->size); |
| @@ -2174,20 +2185,16 @@ static int coda_probe(struct platform_device *pdev) | |||
| 2174 | ret = coda_alloc_aux_buf(dev, &dev->workbuf, | 2185 | ret = coda_alloc_aux_buf(dev, &dev->workbuf, |
| 2175 | dev->devtype->workbuf_size, "workbuf", | 2186 | dev->devtype->workbuf_size, "workbuf", |
| 2176 | dev->debugfs_root); | 2187 | dev->debugfs_root); |
| 2177 | if (ret < 0) { | 2188 | if (ret < 0) |
| 2178 | dev_err(&pdev->dev, "failed to allocate work buffer\n"); | ||
| 2179 | goto err_v4l2_register; | 2189 | goto err_v4l2_register; |
| 2180 | } | ||
| 2181 | } | 2190 | } |
| 2182 | 2191 | ||
| 2183 | if (dev->devtype->tempbuf_size) { | 2192 | if (dev->devtype->tempbuf_size) { |
| 2184 | ret = coda_alloc_aux_buf(dev, &dev->tempbuf, | 2193 | ret = coda_alloc_aux_buf(dev, &dev->tempbuf, |
| 2185 | dev->devtype->tempbuf_size, "tempbuf", | 2194 | dev->devtype->tempbuf_size, "tempbuf", |
| 2186 | dev->debugfs_root); | 2195 | dev->debugfs_root); |
| 2187 | if (ret < 0) { | 2196 | if (ret < 0) |
| 2188 | dev_err(&pdev->dev, "failed to allocate temp buffer\n"); | ||
| 2189 | goto err_v4l2_register; | 2197 | goto err_v4l2_register; |
| 2190 | } | ||
| 2191 | } | 2198 | } |
| 2192 | 2199 | ||
| 2193 | dev->iram.size = dev->devtype->iram_size; | 2200 | dev->iram.size = dev->devtype->iram_size; |
diff --git a/drivers/media/platform/coda/coda-jpeg.c b/drivers/media/platform/coda/coda-jpeg.c index 8fa3e353f9e2..11e734bc2cbd 100644 --- a/drivers/media/platform/coda/coda-jpeg.c +++ b/drivers/media/platform/coda/coda-jpeg.c | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | #include <linux/swab.h> | 13 | #include <linux/swab.h> |
| 14 | 14 | ||
| 15 | #include "coda.h" | 15 | #include "coda.h" |
| 16 | #include "trace.h" | ||
| 16 | 17 | ||
| 17 | #define SOI_MARKER 0xffd8 | 18 | #define SOI_MARKER 0xffd8 |
| 18 | #define EOI_MARKER 0xffd9 | 19 | #define EOI_MARKER 0xffd9 |
diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h index 0c35cd5032ff..6a5c8f6c688e 100644 --- a/drivers/media/platform/coda/coda.h +++ b/drivers/media/platform/coda/coda.h | |||
| @@ -12,6 +12,9 @@ | |||
| 12 | * (at your option) any later version. | 12 | * (at your option) any later version. |
| 13 | */ | 13 | */ |
| 14 | 14 | ||
| 15 | #ifndef __CODA_H__ | ||
| 16 | #define __CODA_H__ | ||
| 17 | |||
| 15 | #include <linux/debugfs.h> | 18 | #include <linux/debugfs.h> |
| 16 | #include <linux/irqreturn.h> | 19 | #include <linux/irqreturn.h> |
| 17 | #include <linux/mutex.h> | 20 | #include <linux/mutex.h> |
| @@ -26,7 +29,6 @@ | |||
| 26 | #include "coda_regs.h" | 29 | #include "coda_regs.h" |
| 27 | 30 | ||
| 28 | #define CODA_MAX_FRAMEBUFFERS 8 | 31 | #define CODA_MAX_FRAMEBUFFERS 8 |
| 29 | #define CODA_MAX_FRAME_SIZE 0x100000 | ||
| 30 | #define FMO_SLICE_SAVE_BUF_SIZE (32) | 32 | #define FMO_SLICE_SAVE_BUF_SIZE (32) |
| 31 | 33 | ||
| 32 | enum { | 34 | enum { |
| @@ -178,6 +180,7 @@ struct coda_ctx; | |||
| 178 | struct coda_context_ops { | 180 | struct coda_context_ops { |
| 179 | int (*queue_init)(void *priv, struct vb2_queue *src_vq, | 181 | int (*queue_init)(void *priv, struct vb2_queue *src_vq, |
| 180 | struct vb2_queue *dst_vq); | 182 | struct vb2_queue *dst_vq); |
| 183 | int (*reqbufs)(struct coda_ctx *ctx, struct v4l2_requestbuffers *rb); | ||
| 181 | int (*start_streaming)(struct coda_ctx *ctx); | 184 | int (*start_streaming)(struct coda_ctx *ctx); |
| 182 | int (*prepare_run)(struct coda_ctx *ctx); | 185 | int (*prepare_run)(struct coda_ctx *ctx); |
| 183 | void (*finish_run)(struct coda_ctx *ctx); | 186 | void (*finish_run)(struct coda_ctx *ctx); |
| @@ -249,13 +252,6 @@ int coda_alloc_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf, | |||
| 249 | size_t size, const char *name, struct dentry *parent); | 252 | size_t size, const char *name, struct dentry *parent); |
| 250 | void coda_free_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf); | 253 | void coda_free_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf); |
| 251 | 254 | ||
| 252 | static inline int coda_alloc_context_buf(struct coda_ctx *ctx, | ||
| 253 | struct coda_aux_buf *buf, size_t size, | ||
| 254 | const char *name) | ||
| 255 | { | ||
| 256 | return coda_alloc_aux_buf(ctx->dev, buf, size, name, ctx->debugfs_entry); | ||
| 257 | } | ||
| 258 | |||
| 259 | int coda_encoder_queue_init(void *priv, struct vb2_queue *src_vq, | 255 | int coda_encoder_queue_init(void *priv, struct vb2_queue *src_vq, |
| 260 | struct vb2_queue *dst_vq); | 256 | struct vb2_queue *dst_vq); |
| 261 | int coda_decoder_queue_init(void *priv, struct vb2_queue *src_vq, | 257 | int coda_decoder_queue_init(void *priv, struct vb2_queue *src_vq, |
| @@ -263,7 +259,7 @@ int coda_decoder_queue_init(void *priv, struct vb2_queue *src_vq, | |||
| 263 | 259 | ||
| 264 | int coda_hw_reset(struct coda_ctx *ctx); | 260 | int coda_hw_reset(struct coda_ctx *ctx); |
| 265 | 261 | ||
| 266 | void coda_fill_bitstream(struct coda_ctx *ctx); | 262 | void coda_fill_bitstream(struct coda_ctx *ctx, bool streaming); |
| 267 | 263 | ||
| 268 | void coda_set_gdi_regs(struct coda_ctx *ctx); | 264 | void coda_set_gdi_regs(struct coda_ctx *ctx); |
| 269 | 265 | ||
| @@ -284,7 +280,7 @@ const char *coda_product_name(int product); | |||
| 284 | 280 | ||
| 285 | int coda_check_firmware(struct coda_dev *dev); | 281 | int coda_check_firmware(struct coda_dev *dev); |
| 286 | 282 | ||
| 287 | static inline int coda_get_bitstream_payload(struct coda_ctx *ctx) | 283 | static inline unsigned int coda_get_bitstream_payload(struct coda_ctx *ctx) |
| 288 | { | 284 | { |
| 289 | return kfifo_len(&ctx->bitstream_fifo); | 285 | return kfifo_len(&ctx->bitstream_fifo); |
| 290 | } | 286 | } |
| @@ -301,3 +297,5 @@ extern const struct coda_context_ops coda_bit_encode_ops; | |||
| 301 | extern const struct coda_context_ops coda_bit_decode_ops; | 297 | extern const struct coda_context_ops coda_bit_decode_ops; |
| 302 | 298 | ||
| 303 | irqreturn_t coda_irq_handler(int irq, void *data); | 299 | irqreturn_t coda_irq_handler(int irq, void *data); |
| 300 | |||
| 301 | #endif /* __CODA_H__ */ | ||
diff --git a/drivers/media/platform/coda/trace.h b/drivers/media/platform/coda/trace.h new file mode 100644 index 000000000000..d1d06cbd1f6a --- /dev/null +++ b/drivers/media/platform/coda/trace.h | |||
| @@ -0,0 +1,203 @@ | |||
| 1 | #undef TRACE_SYSTEM | ||
| 2 | #define TRACE_SYSTEM coda | ||
| 3 | |||
| 4 | #if !defined(__CODA_TRACE_H__) || defined(TRACE_HEADER_MULTI_READ) | ||
| 5 | #define __CODA_TRACE_H__ | ||
| 6 | |||
| 7 | #include <linux/tracepoint.h> | ||
| 8 | #include <media/videobuf2-core.h> | ||
| 9 | |||
| 10 | #include "coda.h" | ||
| 11 | |||
| 12 | #define TRACE_SYSTEM_STRING __stringify(TRACE_SYSTEM) | ||
| 13 | |||
| 14 | TRACE_EVENT(coda_bit_run, | ||
| 15 | TP_PROTO(struct coda_ctx *ctx, int cmd), | ||
| 16 | |||
| 17 | TP_ARGS(ctx, cmd), | ||
| 18 | |||
| 19 | TP_STRUCT__entry( | ||
| 20 | __field(int, minor) | ||
| 21 | __field(int, ctx) | ||
| 22 | __field(int, cmd) | ||
| 23 | ), | ||
| 24 | |||
| 25 | TP_fast_assign( | ||
| 26 | __entry->minor = ctx->fh.vdev->minor; | ||
| 27 | __entry->ctx = ctx->idx; | ||
| 28 | __entry->cmd = cmd; | ||
| 29 | ), | ||
| 30 | |||
| 31 | TP_printk("minor = %d, ctx = %d, cmd = %d", | ||
| 32 | __entry->minor, __entry->ctx, __entry->cmd) | ||
| 33 | ); | ||
| 34 | |||
| 35 | TRACE_EVENT(coda_bit_done, | ||
| 36 | TP_PROTO(struct coda_ctx *ctx), | ||
| 37 | |||
| 38 | TP_ARGS(ctx), | ||
| 39 | |||
| 40 | TP_STRUCT__entry( | ||
| 41 | __field(int, minor) | ||
| 42 | __field(int, ctx) | ||
| 43 | ), | ||
| 44 | |||
| 45 | TP_fast_assign( | ||
| 46 | __entry->minor = ctx->fh.vdev->minor; | ||
| 47 | __entry->ctx = ctx->idx; | ||
| 48 | ), | ||
| 49 | |||
| 50 | TP_printk("minor = %d, ctx = %d", __entry->minor, __entry->ctx) | ||
| 51 | ); | ||
| 52 | |||
| 53 | TRACE_EVENT(coda_enc_pic_run, | ||
| 54 | TP_PROTO(struct coda_ctx *ctx, struct vb2_buffer *buf), | ||
| 55 | |||
| 56 | TP_ARGS(ctx, buf), | ||
| 57 | |||
| 58 | TP_STRUCT__entry( | ||
| 59 | __field(int, minor) | ||
| 60 | __field(int, index) | ||
| 61 | __field(int, ctx) | ||
| 62 | ), | ||
| 63 | |||
| 64 | TP_fast_assign( | ||
| 65 | __entry->minor = ctx->fh.vdev->minor; | ||
| 66 | __entry->index = buf->v4l2_buf.index; | ||
| 67 | __entry->ctx = ctx->idx; | ||
| 68 | ), | ||
| 69 | |||
| 70 | TP_printk("minor = %d, index = %d, ctx = %d", | ||
| 71 | __entry->minor, __entry->index, __entry->ctx) | ||
| 72 | ); | ||
| 73 | |||
| 74 | TRACE_EVENT(coda_enc_pic_done, | ||
| 75 | TP_PROTO(struct coda_ctx *ctx, struct vb2_buffer *buf), | ||
| 76 | |||
| 77 | TP_ARGS(ctx, buf), | ||
| 78 | |||
| 79 | TP_STRUCT__entry( | ||
| 80 | __field(int, minor) | ||
| 81 | __field(int, index) | ||
| 82 | __field(int, ctx) | ||
| 83 | ), | ||
| 84 | |||
| 85 | TP_fast_assign( | ||
| 86 | __entry->minor = ctx->fh.vdev->minor; | ||
| 87 | __entry->index = buf->v4l2_buf.index; | ||
| 88 | __entry->ctx = ctx->idx; | ||
| 89 | ), | ||
| 90 | |||
| 91 | TP_printk("minor = %d, index = %d, ctx = %d", | ||
| 92 | __entry->minor, __entry->index, __entry->ctx) | ||
| 93 | ); | ||
| 94 | |||
| 95 | TRACE_EVENT(coda_bit_queue, | ||
| 96 | TP_PROTO(struct coda_ctx *ctx, struct vb2_buffer *buf, | ||
| 97 | struct coda_buffer_meta *meta), | ||
| 98 | |||
| 99 | TP_ARGS(ctx, buf, meta), | ||
| 100 | |||
| 101 | TP_STRUCT__entry( | ||
| 102 | __field(int, minor) | ||
| 103 | __field(int, index) | ||
| 104 | __field(int, start) | ||
| 105 | __field(int, end) | ||
| 106 | __field(int, ctx) | ||
| 107 | ), | ||
| 108 | |||
| 109 | TP_fast_assign( | ||
| 110 | __entry->minor = ctx->fh.vdev->minor; | ||
| 111 | __entry->index = buf->v4l2_buf.index; | ||
| 112 | __entry->start = meta->start; | ||
| 113 | __entry->end = meta->end; | ||
| 114 | __entry->ctx = ctx->idx; | ||
| 115 | ), | ||
| 116 | |||
| 117 | TP_printk("minor = %d, index = %d, start = 0x%x, end = 0x%x, ctx = %d", | ||
| 118 | __entry->minor, __entry->index, __entry->start, __entry->end, | ||
| 119 | __entry->ctx) | ||
| 120 | ); | ||
| 121 | |||
| 122 | TRACE_EVENT(coda_dec_pic_run, | ||
| 123 | TP_PROTO(struct coda_ctx *ctx, struct coda_buffer_meta *meta), | ||
| 124 | |||
| 125 | TP_ARGS(ctx, meta), | ||
| 126 | |||
| 127 | TP_STRUCT__entry( | ||
| 128 | __field(int, minor) | ||
| 129 | __field(int, start) | ||
| 130 | __field(int, end) | ||
| 131 | __field(int, ctx) | ||
| 132 | ), | ||
| 133 | |||
| 134 | TP_fast_assign( | ||
| 135 | __entry->minor = ctx->fh.vdev->minor; | ||
| 136 | __entry->start = meta ? meta->start : 0; | ||
| 137 | __entry->end = meta ? meta->end : 0; | ||
| 138 | __entry->ctx = ctx->idx; | ||
| 139 | ), | ||
| 140 | |||
| 141 | TP_printk("minor = %d, start = 0x%x, end = 0x%x, ctx = %d", | ||
| 142 | __entry->minor, __entry->start, __entry->end, __entry->ctx) | ||
| 143 | ); | ||
| 144 | |||
| 145 | TRACE_EVENT(coda_dec_pic_done, | ||
| 146 | TP_PROTO(struct coda_ctx *ctx, struct coda_buffer_meta *meta), | ||
| 147 | |||
| 148 | TP_ARGS(ctx, meta), | ||
| 149 | |||
| 150 | TP_STRUCT__entry( | ||
| 151 | __field(int, minor) | ||
| 152 | __field(int, start) | ||
| 153 | __field(int, end) | ||
| 154 | __field(int, ctx) | ||
| 155 | ), | ||
| 156 | |||
| 157 | TP_fast_assign( | ||
| 158 | __entry->minor = ctx->fh.vdev->minor; | ||
| 159 | __entry->start = meta->start; | ||
| 160 | __entry->end = meta->end; | ||
| 161 | __entry->ctx = ctx->idx; | ||
| 162 | ), | ||
| 163 | |||
| 164 | TP_printk("minor = %d, start = 0x%x, end = 0x%x, ctx = %d", | ||
| 165 | __entry->minor, __entry->start, __entry->end, __entry->ctx) | ||
| 166 | ); | ||
| 167 | |||
| 168 | TRACE_EVENT(coda_dec_rot_done, | ||
| 169 | TP_PROTO(struct coda_ctx *ctx, struct coda_buffer_meta *meta, | ||
| 170 | struct vb2_buffer *buf), | ||
| 171 | |||
| 172 | TP_ARGS(ctx, meta, buf), | ||
| 173 | |||
| 174 | TP_STRUCT__entry( | ||
| 175 | __field(int, minor) | ||
| 176 | __field(int, start) | ||
| 177 | __field(int, end) | ||
| 178 | __field(int, index) | ||
| 179 | __field(int, ctx) | ||
| 180 | ), | ||
| 181 | |||
| 182 | TP_fast_assign( | ||
| 183 | __entry->minor = ctx->fh.vdev->minor; | ||
| 184 | __entry->start = meta->start; | ||
| 185 | __entry->end = meta->end; | ||
| 186 | __entry->index = buf->v4l2_buf.index; | ||
| 187 | __entry->ctx = ctx->idx; | ||
| 188 | ), | ||
| 189 | |||
| 190 | TP_printk("minor = %d, start = 0x%x, end = 0x%x, index = %d, ctx = %d", | ||
| 191 | __entry->minor, __entry->start, __entry->end, __entry->index, | ||
| 192 | __entry->ctx) | ||
| 193 | ); | ||
| 194 | |||
| 195 | #endif /* __CODA_TRACE_H__ */ | ||
| 196 | |||
| 197 | #undef TRACE_INCLUDE_PATH | ||
| 198 | #define TRACE_INCLUDE_PATH . | ||
| 199 | #undef TRACE_INCLUDE_FILE | ||
| 200 | #define TRACE_INCLUDE_FILE trace | ||
| 201 | |||
| 202 | /* This part must be outside protection */ | ||
| 203 | #include <trace/define_trace.h> | ||
diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index b41bf7e822c8..ccfcf3f528d3 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c | |||
| @@ -1871,16 +1871,9 @@ static int vpfe_probe(struct platform_device *pdev) | |||
| 1871 | goto probe_free_ccdc_cfg_mem; | 1871 | goto probe_free_ccdc_cfg_mem; |
| 1872 | } | 1872 | } |
| 1873 | 1873 | ||
| 1874 | /* Allocate memory for video device */ | 1874 | vfd = &vpfe_dev->video_dev; |
| 1875 | vfd = video_device_alloc(); | ||
| 1876 | if (NULL == vfd) { | ||
| 1877 | ret = -ENOMEM; | ||
| 1878 | v4l2_err(pdev->dev.driver, "Unable to alloc video device\n"); | ||
| 1879 | goto probe_out_release_irq; | ||
| 1880 | } | ||
| 1881 | |||
| 1882 | /* Initialize field of video device */ | 1875 | /* Initialize field of video device */ |
| 1883 | vfd->release = video_device_release; | 1876 | vfd->release = video_device_release_empty; |
| 1884 | vfd->fops = &vpfe_fops; | 1877 | vfd->fops = &vpfe_fops; |
| 1885 | vfd->ioctl_ops = &vpfe_ioctl_ops; | 1878 | vfd->ioctl_ops = &vpfe_ioctl_ops; |
| 1886 | vfd->tvnorms = 0; | 1879 | vfd->tvnorms = 0; |
| @@ -1891,14 +1884,12 @@ static int vpfe_probe(struct platform_device *pdev) | |||
| 1891 | (VPFE_CAPTURE_VERSION_CODE >> 16) & 0xff, | 1884 | (VPFE_CAPTURE_VERSION_CODE >> 16) & 0xff, |
| 1892 | (VPFE_CAPTURE_VERSION_CODE >> 8) & 0xff, | 1885 | (VPFE_CAPTURE_VERSION_CODE >> 8) & 0xff, |
| 1893 | (VPFE_CAPTURE_VERSION_CODE) & 0xff); | 1886 | (VPFE_CAPTURE_VERSION_CODE) & 0xff); |
| 1894 | /* Set video_dev to the video device */ | ||
| 1895 | vpfe_dev->video_dev = vfd; | ||
| 1896 | 1887 | ||
| 1897 | ret = v4l2_device_register(&pdev->dev, &vpfe_dev->v4l2_dev); | 1888 | ret = v4l2_device_register(&pdev->dev, &vpfe_dev->v4l2_dev); |
| 1898 | if (ret) { | 1889 | if (ret) { |
| 1899 | v4l2_err(pdev->dev.driver, | 1890 | v4l2_err(pdev->dev.driver, |
| 1900 | "Unable to register v4l2 device.\n"); | 1891 | "Unable to register v4l2 device.\n"); |
| 1901 | goto probe_out_video_release; | 1892 | goto probe_out_release_irq; |
| 1902 | } | 1893 | } |
| 1903 | v4l2_info(&vpfe_dev->v4l2_dev, "v4l2 device registered\n"); | 1894 | v4l2_info(&vpfe_dev->v4l2_dev, "v4l2 device registered\n"); |
| 1904 | spin_lock_init(&vpfe_dev->irqlock); | 1895 | spin_lock_init(&vpfe_dev->irqlock); |
| @@ -1914,7 +1905,7 @@ static int vpfe_probe(struct platform_device *pdev) | |||
| 1914 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, | 1905 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, |
| 1915 | "video_dev=%p\n", &vpfe_dev->video_dev); | 1906 | "video_dev=%p\n", &vpfe_dev->video_dev); |
| 1916 | vpfe_dev->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 1907 | vpfe_dev->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 1917 | ret = video_register_device(vpfe_dev->video_dev, | 1908 | ret = video_register_device(&vpfe_dev->video_dev, |
| 1918 | VFL_TYPE_GRABBER, -1); | 1909 | VFL_TYPE_GRABBER, -1); |
| 1919 | 1910 | ||
| 1920 | if (ret) { | 1911 | if (ret) { |
| @@ -1927,7 +1918,7 @@ static int vpfe_probe(struct platform_device *pdev) | |||
| 1927 | /* set the driver data in platform device */ | 1918 | /* set the driver data in platform device */ |
| 1928 | platform_set_drvdata(pdev, vpfe_dev); | 1919 | platform_set_drvdata(pdev, vpfe_dev); |
| 1929 | /* set driver private data */ | 1920 | /* set driver private data */ |
| 1930 | video_set_drvdata(vpfe_dev->video_dev, vpfe_dev); | 1921 | video_set_drvdata(&vpfe_dev->video_dev, vpfe_dev); |
| 1931 | i2c_adap = i2c_get_adapter(vpfe_cfg->i2c_adapter_id); | 1922 | i2c_adap = i2c_get_adapter(vpfe_cfg->i2c_adapter_id); |
| 1932 | num_subdevs = vpfe_cfg->num_subdevs; | 1923 | num_subdevs = vpfe_cfg->num_subdevs; |
| 1933 | vpfe_dev->sd = kmalloc(sizeof(struct v4l2_subdev *) * num_subdevs, | 1924 | vpfe_dev->sd = kmalloc(sizeof(struct v4l2_subdev *) * num_subdevs, |
| @@ -1979,12 +1970,9 @@ static int vpfe_probe(struct platform_device *pdev) | |||
| 1979 | probe_sd_out: | 1970 | probe_sd_out: |
| 1980 | kfree(vpfe_dev->sd); | 1971 | kfree(vpfe_dev->sd); |
| 1981 | probe_out_video_unregister: | 1972 | probe_out_video_unregister: |
| 1982 | video_unregister_device(vpfe_dev->video_dev); | 1973 | video_unregister_device(&vpfe_dev->video_dev); |
| 1983 | probe_out_v4l2_unregister: | 1974 | probe_out_v4l2_unregister: |
| 1984 | v4l2_device_unregister(&vpfe_dev->v4l2_dev); | 1975 | v4l2_device_unregister(&vpfe_dev->v4l2_dev); |
| 1985 | probe_out_video_release: | ||
| 1986 | if (!video_is_registered(vpfe_dev->video_dev)) | ||
| 1987 | video_device_release(vpfe_dev->video_dev); | ||
| 1988 | probe_out_release_irq: | 1976 | probe_out_release_irq: |
| 1989 | free_irq(vpfe_dev->ccdc_irq0, vpfe_dev); | 1977 | free_irq(vpfe_dev->ccdc_irq0, vpfe_dev); |
| 1990 | probe_free_ccdc_cfg_mem: | 1978 | probe_free_ccdc_cfg_mem: |
| @@ -2007,7 +1995,7 @@ static int vpfe_remove(struct platform_device *pdev) | |||
| 2007 | free_irq(vpfe_dev->ccdc_irq0, vpfe_dev); | 1995 | free_irq(vpfe_dev->ccdc_irq0, vpfe_dev); |
| 2008 | kfree(vpfe_dev->sd); | 1996 | kfree(vpfe_dev->sd); |
| 2009 | v4l2_device_unregister(&vpfe_dev->v4l2_dev); | 1997 | v4l2_device_unregister(&vpfe_dev->v4l2_dev); |
| 2010 | video_unregister_device(vpfe_dev->video_dev); | 1998 | video_unregister_device(&vpfe_dev->video_dev); |
| 2011 | kfree(vpfe_dev); | 1999 | kfree(vpfe_dev); |
| 2012 | kfree(ccdc_cfg); | 2000 | kfree(ccdc_cfg); |
| 2013 | return 0; | 2001 | return 0; |
diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index fa0a51521772..a5f548138b91 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c | |||
| @@ -712,7 +712,7 @@ static int vpif_set_input( | |||
| 712 | ch->vpifparams.iface = chan_cfg->vpif_if; | 712 | ch->vpifparams.iface = chan_cfg->vpif_if; |
| 713 | 713 | ||
| 714 | /* update tvnorms from the sub device input info */ | 714 | /* update tvnorms from the sub device input info */ |
| 715 | ch->video_dev->tvnorms = chan_cfg->inputs[index].input.std; | 715 | ch->video_dev.tvnorms = chan_cfg->inputs[index].input.std; |
| 716 | return 0; | 716 | return 0; |
| 717 | } | 717 | } |
| 718 | 718 | ||
| @@ -1337,7 +1337,7 @@ static int vpif_probe_complete(void) | |||
| 1337 | struct video_device *vdev; | 1337 | struct video_device *vdev; |
| 1338 | struct channel_obj *ch; | 1338 | struct channel_obj *ch; |
| 1339 | struct vb2_queue *q; | 1339 | struct vb2_queue *q; |
| 1340 | int i, j, err, k; | 1340 | int j, err, k; |
| 1341 | 1341 | ||
| 1342 | for (j = 0; j < VPIF_CAPTURE_MAX_DEVICES; j++) { | 1342 | for (j = 0; j < VPIF_CAPTURE_MAX_DEVICES; j++) { |
| 1343 | ch = vpif_obj.dev[j]; | 1343 | ch = vpif_obj.dev[j]; |
| @@ -1384,16 +1384,16 @@ static int vpif_probe_complete(void) | |||
| 1384 | INIT_LIST_HEAD(&common->dma_queue); | 1384 | INIT_LIST_HEAD(&common->dma_queue); |
| 1385 | 1385 | ||
| 1386 | /* Initialize the video_device structure */ | 1386 | /* Initialize the video_device structure */ |
| 1387 | vdev = ch->video_dev; | 1387 | vdev = &ch->video_dev; |
| 1388 | strlcpy(vdev->name, VPIF_DRIVER_NAME, sizeof(vdev->name)); | 1388 | strlcpy(vdev->name, VPIF_DRIVER_NAME, sizeof(vdev->name)); |
| 1389 | vdev->release = video_device_release; | 1389 | vdev->release = video_device_release_empty; |
| 1390 | vdev->fops = &vpif_fops; | 1390 | vdev->fops = &vpif_fops; |
| 1391 | vdev->ioctl_ops = &vpif_ioctl_ops; | 1391 | vdev->ioctl_ops = &vpif_ioctl_ops; |
| 1392 | vdev->v4l2_dev = &vpif_obj.v4l2_dev; | 1392 | vdev->v4l2_dev = &vpif_obj.v4l2_dev; |
| 1393 | vdev->vfl_dir = VFL_DIR_RX; | 1393 | vdev->vfl_dir = VFL_DIR_RX; |
| 1394 | vdev->queue = q; | 1394 | vdev->queue = q; |
| 1395 | vdev->lock = &common->lock; | 1395 | vdev->lock = &common->lock; |
| 1396 | video_set_drvdata(ch->video_dev, ch); | 1396 | video_set_drvdata(&ch->video_dev, ch); |
| 1397 | err = video_register_device(vdev, | 1397 | err = video_register_device(vdev, |
| 1398 | VFL_TYPE_GRABBER, (j ? 1 : 0)); | 1398 | VFL_TYPE_GRABBER, (j ? 1 : 0)); |
| 1399 | if (err) | 1399 | if (err) |
| @@ -1410,14 +1410,9 @@ probe_out: | |||
| 1410 | common = &ch->common[k]; | 1410 | common = &ch->common[k]; |
| 1411 | vb2_dma_contig_cleanup_ctx(common->alloc_ctx); | 1411 | vb2_dma_contig_cleanup_ctx(common->alloc_ctx); |
| 1412 | /* Unregister video device */ | 1412 | /* Unregister video device */ |
| 1413 | video_unregister_device(ch->video_dev); | 1413 | video_unregister_device(&ch->video_dev); |
| 1414 | } | 1414 | } |
| 1415 | kfree(vpif_obj.sd); | 1415 | kfree(vpif_obj.sd); |
| 1416 | for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) { | ||
| 1417 | ch = vpif_obj.dev[i]; | ||
| 1418 | /* Note: does nothing if ch->video_dev == NULL */ | ||
| 1419 | video_device_release(ch->video_dev); | ||
| 1420 | } | ||
| 1421 | v4l2_device_unregister(&vpif_obj.v4l2_dev); | 1416 | v4l2_device_unregister(&vpif_obj.v4l2_dev); |
| 1422 | 1417 | ||
| 1423 | return err; | 1418 | return err; |
| @@ -1438,13 +1433,11 @@ static int vpif_async_complete(struct v4l2_async_notifier *notifier) | |||
| 1438 | static __init int vpif_probe(struct platform_device *pdev) | 1433 | static __init int vpif_probe(struct platform_device *pdev) |
| 1439 | { | 1434 | { |
| 1440 | struct vpif_subdev_info *subdevdata; | 1435 | struct vpif_subdev_info *subdevdata; |
| 1441 | int i, j, err; | ||
| 1442 | int res_idx = 0; | ||
| 1443 | struct i2c_adapter *i2c_adap; | 1436 | struct i2c_adapter *i2c_adap; |
| 1444 | struct channel_obj *ch; | ||
| 1445 | struct video_device *vfd; | ||
| 1446 | struct resource *res; | 1437 | struct resource *res; |
| 1447 | int subdev_count; | 1438 | int subdev_count; |
| 1439 | int res_idx = 0; | ||
| 1440 | int i, err; | ||
| 1448 | 1441 | ||
| 1449 | vpif_dev = &pdev->dev; | 1442 | vpif_dev = &pdev->dev; |
| 1450 | 1443 | ||
| @@ -1472,24 +1465,6 @@ static __init int vpif_probe(struct platform_device *pdev) | |||
| 1472 | res_idx++; | 1465 | res_idx++; |
| 1473 | } | 1466 | } |
| 1474 | 1467 | ||
| 1475 | for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) { | ||
| 1476 | /* Get the pointer to the channel object */ | ||
| 1477 | ch = vpif_obj.dev[i]; | ||
| 1478 | /* Allocate memory for video device */ | ||
| 1479 | vfd = video_device_alloc(); | ||
| 1480 | if (NULL == vfd) { | ||
| 1481 | for (j = 0; j < i; j++) { | ||
| 1482 | ch = vpif_obj.dev[j]; | ||
| 1483 | video_device_release(ch->video_dev); | ||
| 1484 | } | ||
| 1485 | err = -ENOMEM; | ||
| 1486 | goto vpif_unregister; | ||
| 1487 | } | ||
| 1488 | |||
| 1489 | /* Set video_dev to the video device */ | ||
| 1490 | ch->video_dev = vfd; | ||
| 1491 | } | ||
| 1492 | |||
| 1493 | vpif_obj.config = pdev->dev.platform_data; | 1468 | vpif_obj.config = pdev->dev.platform_data; |
| 1494 | 1469 | ||
| 1495 | subdev_count = vpif_obj.config->subdev_count; | 1470 | subdev_count = vpif_obj.config->subdev_count; |
| @@ -1498,7 +1473,7 @@ static __init int vpif_probe(struct platform_device *pdev) | |||
| 1498 | if (vpif_obj.sd == NULL) { | 1473 | if (vpif_obj.sd == NULL) { |
| 1499 | vpif_err("unable to allocate memory for subdevice pointers\n"); | 1474 | vpif_err("unable to allocate memory for subdevice pointers\n"); |
| 1500 | err = -ENOMEM; | 1475 | err = -ENOMEM; |
| 1501 | goto vpif_sd_error; | 1476 | goto vpif_unregister; |
| 1502 | } | 1477 | } |
| 1503 | 1478 | ||
| 1504 | if (!vpif_obj.config->asd_sizes) { | 1479 | if (!vpif_obj.config->asd_sizes) { |
| @@ -1541,13 +1516,6 @@ static __init int vpif_probe(struct platform_device *pdev) | |||
| 1541 | probe_subdev_out: | 1516 | probe_subdev_out: |
| 1542 | /* free sub devices memory */ | 1517 | /* free sub devices memory */ |
| 1543 | kfree(vpif_obj.sd); | 1518 | kfree(vpif_obj.sd); |
| 1544 | |||
| 1545 | vpif_sd_error: | ||
| 1546 | for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) { | ||
| 1547 | ch = vpif_obj.dev[i]; | ||
| 1548 | /* Note: does nothing if ch->video_dev == NULL */ | ||
| 1549 | video_device_release(ch->video_dev); | ||
| 1550 | } | ||
| 1551 | vpif_unregister: | 1519 | vpif_unregister: |
| 1552 | v4l2_device_unregister(&vpif_obj.v4l2_dev); | 1520 | v4l2_device_unregister(&vpif_obj.v4l2_dev); |
| 1553 | 1521 | ||
| @@ -1576,7 +1544,7 @@ static int vpif_remove(struct platform_device *device) | |||
| 1576 | common = &ch->common[VPIF_VIDEO_INDEX]; | 1544 | common = &ch->common[VPIF_VIDEO_INDEX]; |
| 1577 | vb2_dma_contig_cleanup_ctx(common->alloc_ctx); | 1545 | vb2_dma_contig_cleanup_ctx(common->alloc_ctx); |
| 1578 | /* Unregister video device */ | 1546 | /* Unregister video device */ |
| 1579 | video_unregister_device(ch->video_dev); | 1547 | video_unregister_device(&ch->video_dev); |
| 1580 | kfree(vpif_obj.dev[i]); | 1548 | kfree(vpif_obj.dev[i]); |
| 1581 | } | 1549 | } |
| 1582 | return 0; | 1550 | return 0; |
diff --git a/drivers/media/platform/davinci/vpif_capture.h b/drivers/media/platform/davinci/vpif_capture.h index f65d28d38e66..8b8a663f6b22 100644 --- a/drivers/media/platform/davinci/vpif_capture.h +++ b/drivers/media/platform/davinci/vpif_capture.h | |||
| @@ -92,7 +92,7 @@ struct common_obj { | |||
| 92 | 92 | ||
| 93 | struct channel_obj { | 93 | struct channel_obj { |
| 94 | /* Identifies video device for this channel */ | 94 | /* Identifies video device for this channel */ |
| 95 | struct video_device *video_dev; | 95 | struct video_device video_dev; |
| 96 | /* Indicates id of the field which is being displayed */ | 96 | /* Indicates id of the field which is being displayed */ |
| 97 | u32 field_id; | 97 | u32 field_id; |
| 98 | /* flag to indicate whether decoder is initialized */ | 98 | /* flag to indicate whether decoder is initialized */ |
diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index 839c24de1fd8..682e5d578bf7 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c | |||
| @@ -829,7 +829,7 @@ static int vpif_set_output(struct vpif_display_config *vpif_cfg, | |||
| 829 | ch->sd = sd; | 829 | ch->sd = sd; |
| 830 | if (chan_cfg->outputs != NULL) | 830 | if (chan_cfg->outputs != NULL) |
| 831 | /* update tvnorms from the sub device output info */ | 831 | /* update tvnorms from the sub device output info */ |
| 832 | ch->video_dev->tvnorms = chan_cfg->outputs[index].output.std; | 832 | ch->video_dev.tvnorms = chan_cfg->outputs[index].output.std; |
| 833 | return 0; | 833 | return 0; |
| 834 | } | 834 | } |
| 835 | 835 | ||
| @@ -1204,16 +1204,16 @@ static int vpif_probe_complete(void) | |||
| 1204 | ch, &ch->video_dev); | 1204 | ch, &ch->video_dev); |
| 1205 | 1205 | ||
| 1206 | /* Initialize the video_device structure */ | 1206 | /* Initialize the video_device structure */ |
| 1207 | vdev = ch->video_dev; | 1207 | vdev = &ch->video_dev; |
| 1208 | strlcpy(vdev->name, VPIF_DRIVER_NAME, sizeof(vdev->name)); | 1208 | strlcpy(vdev->name, VPIF_DRIVER_NAME, sizeof(vdev->name)); |
| 1209 | vdev->release = video_device_release; | 1209 | vdev->release = video_device_release_empty; |
| 1210 | vdev->fops = &vpif_fops; | 1210 | vdev->fops = &vpif_fops; |
| 1211 | vdev->ioctl_ops = &vpif_ioctl_ops; | 1211 | vdev->ioctl_ops = &vpif_ioctl_ops; |
| 1212 | vdev->v4l2_dev = &vpif_obj.v4l2_dev; | 1212 | vdev->v4l2_dev = &vpif_obj.v4l2_dev; |
| 1213 | vdev->vfl_dir = VFL_DIR_TX; | 1213 | vdev->vfl_dir = VFL_DIR_TX; |
| 1214 | vdev->queue = q; | 1214 | vdev->queue = q; |
| 1215 | vdev->lock = &common->lock; | 1215 | vdev->lock = &common->lock; |
| 1216 | video_set_drvdata(ch->video_dev, ch); | 1216 | video_set_drvdata(&ch->video_dev, ch); |
| 1217 | err = video_register_device(vdev, VFL_TYPE_GRABBER, | 1217 | err = video_register_device(vdev, VFL_TYPE_GRABBER, |
| 1218 | (j ? 3 : 2)); | 1218 | (j ? 3 : 2)); |
| 1219 | if (err < 0) | 1219 | if (err < 0) |
| @@ -1227,9 +1227,7 @@ probe_out: | |||
| 1227 | ch = vpif_obj.dev[k]; | 1227 | ch = vpif_obj.dev[k]; |
| 1228 | common = &ch->common[k]; | 1228 | common = &ch->common[k]; |
| 1229 | vb2_dma_contig_cleanup_ctx(common->alloc_ctx); | 1229 | vb2_dma_contig_cleanup_ctx(common->alloc_ctx); |
| 1230 | video_unregister_device(ch->video_dev); | 1230 | video_unregister_device(&ch->video_dev); |
| 1231 | video_device_release(ch->video_dev); | ||
| 1232 | ch->video_dev = NULL; | ||
| 1233 | } | 1231 | } |
| 1234 | return err; | 1232 | return err; |
| 1235 | } | 1233 | } |
| @@ -1246,13 +1244,11 @@ static int vpif_async_complete(struct v4l2_async_notifier *notifier) | |||
| 1246 | static __init int vpif_probe(struct platform_device *pdev) | 1244 | static __init int vpif_probe(struct platform_device *pdev) |
| 1247 | { | 1245 | { |
| 1248 | struct vpif_subdev_info *subdevdata; | 1246 | struct vpif_subdev_info *subdevdata; |
| 1249 | int i, j = 0, err = 0; | ||
| 1250 | int res_idx = 0; | ||
| 1251 | struct i2c_adapter *i2c_adap; | 1247 | struct i2c_adapter *i2c_adap; |
| 1252 | struct channel_obj *ch; | ||
| 1253 | struct video_device *vfd; | ||
| 1254 | struct resource *res; | 1248 | struct resource *res; |
| 1255 | int subdev_count; | 1249 | int subdev_count; |
| 1250 | int res_idx = 0; | ||
| 1251 | int i, err; | ||
| 1256 | 1252 | ||
| 1257 | vpif_dev = &pdev->dev; | 1253 | vpif_dev = &pdev->dev; |
| 1258 | err = initialize_vpif(); | 1254 | err = initialize_vpif(); |
| @@ -1281,25 +1277,6 @@ static __init int vpif_probe(struct platform_device *pdev) | |||
| 1281 | res_idx++; | 1277 | res_idx++; |
| 1282 | } | 1278 | } |
| 1283 | 1279 | ||
| 1284 | for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) { | ||
| 1285 | /* Get the pointer to the channel object */ | ||
| 1286 | ch = vpif_obj.dev[i]; | ||
| 1287 | |||
| 1288 | /* Allocate memory for video device */ | ||
| 1289 | vfd = video_device_alloc(); | ||
| 1290 | if (vfd == NULL) { | ||
| 1291 | for (j = 0; j < i; j++) { | ||
| 1292 | ch = vpif_obj.dev[j]; | ||
| 1293 | video_device_release(ch->video_dev); | ||
| 1294 | } | ||
| 1295 | err = -ENOMEM; | ||
| 1296 | goto vpif_unregister; | ||
| 1297 | } | ||
| 1298 | |||
| 1299 | /* Set video_dev to the video device */ | ||
| 1300 | ch->video_dev = vfd; | ||
| 1301 | } | ||
| 1302 | |||
| 1303 | vpif_obj.config = pdev->dev.platform_data; | 1280 | vpif_obj.config = pdev->dev.platform_data; |
| 1304 | subdev_count = vpif_obj.config->subdev_count; | 1281 | subdev_count = vpif_obj.config->subdev_count; |
| 1305 | subdevdata = vpif_obj.config->subdevinfo; | 1282 | subdevdata = vpif_obj.config->subdevinfo; |
| @@ -1308,7 +1285,7 @@ static __init int vpif_probe(struct platform_device *pdev) | |||
| 1308 | if (vpif_obj.sd == NULL) { | 1285 | if (vpif_obj.sd == NULL) { |
| 1309 | vpif_err("unable to allocate memory for subdevice pointers\n"); | 1286 | vpif_err("unable to allocate memory for subdevice pointers\n"); |
| 1310 | err = -ENOMEM; | 1287 | err = -ENOMEM; |
| 1311 | goto vpif_sd_error; | 1288 | goto vpif_unregister; |
| 1312 | } | 1289 | } |
| 1313 | 1290 | ||
| 1314 | if (!vpif_obj.config->asd_sizes) { | 1291 | if (!vpif_obj.config->asd_sizes) { |
| @@ -1348,12 +1325,6 @@ static __init int vpif_probe(struct platform_device *pdev) | |||
| 1348 | 1325 | ||
| 1349 | probe_subdev_out: | 1326 | probe_subdev_out: |
| 1350 | kfree(vpif_obj.sd); | 1327 | kfree(vpif_obj.sd); |
| 1351 | vpif_sd_error: | ||
| 1352 | for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) { | ||
| 1353 | ch = vpif_obj.dev[i]; | ||
| 1354 | /* Note: does nothing if ch->video_dev == NULL */ | ||
| 1355 | video_device_release(ch->video_dev); | ||
| 1356 | } | ||
| 1357 | vpif_unregister: | 1328 | vpif_unregister: |
| 1358 | v4l2_device_unregister(&vpif_obj.v4l2_dev); | 1329 | v4l2_device_unregister(&vpif_obj.v4l2_dev); |
| 1359 | 1330 | ||
| @@ -1379,9 +1350,7 @@ static int vpif_remove(struct platform_device *device) | |||
| 1379 | common = &ch->common[VPIF_VIDEO_INDEX]; | 1350 | common = &ch->common[VPIF_VIDEO_INDEX]; |
| 1380 | vb2_dma_contig_cleanup_ctx(common->alloc_ctx); | 1351 | vb2_dma_contig_cleanup_ctx(common->alloc_ctx); |
| 1381 | /* Unregister video device */ | 1352 | /* Unregister video device */ |
| 1382 | video_unregister_device(ch->video_dev); | 1353 | video_unregister_device(&ch->video_dev); |
| 1383 | |||
| 1384 | ch->video_dev = NULL; | ||
| 1385 | kfree(vpif_obj.dev[i]); | 1354 | kfree(vpif_obj.dev[i]); |
| 1386 | } | 1355 | } |
| 1387 | 1356 | ||
diff --git a/drivers/media/platform/davinci/vpif_display.h b/drivers/media/platform/davinci/vpif_display.h index 7b21a7607674..849e0e385f18 100644 --- a/drivers/media/platform/davinci/vpif_display.h +++ b/drivers/media/platform/davinci/vpif_display.h | |||
| @@ -100,7 +100,7 @@ struct common_obj { | |||
| 100 | 100 | ||
| 101 | struct channel_obj { | 101 | struct channel_obj { |
| 102 | /* V4l2 specific parameters */ | 102 | /* V4l2 specific parameters */ |
| 103 | struct video_device *video_dev; /* Identifies video device for | 103 | struct video_device video_dev; /* Identifies video device for |
| 104 | * this channel */ | 104 | * this channel */ |
| 105 | u32 field_id; /* Indicates id of the field | 105 | u32 field_id; /* Indicates id of the field |
| 106 | * which is being displayed */ | 106 | * which is being displayed */ |
diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c index 8a2fd8c33d42..cfebf292e15a 100644 --- a/drivers/media/platform/exynos4-is/fimc-capture.c +++ b/drivers/media/platform/exynos4-is/fimc-capture.c | |||
| @@ -1482,7 +1482,7 @@ void fimc_sensor_notify(struct v4l2_subdev *sd, unsigned int notification, | |||
| 1482 | } | 1482 | } |
| 1483 | 1483 | ||
| 1484 | static int fimc_subdev_enum_mbus_code(struct v4l2_subdev *sd, | 1484 | static int fimc_subdev_enum_mbus_code(struct v4l2_subdev *sd, |
| 1485 | struct v4l2_subdev_fh *fh, | 1485 | struct v4l2_subdev_pad_config *cfg, |
| 1486 | struct v4l2_subdev_mbus_code_enum *code) | 1486 | struct v4l2_subdev_mbus_code_enum *code) |
| 1487 | { | 1487 | { |
| 1488 | struct fimc_fmt *fmt; | 1488 | struct fimc_fmt *fmt; |
| @@ -1495,7 +1495,7 @@ static int fimc_subdev_enum_mbus_code(struct v4l2_subdev *sd, | |||
| 1495 | } | 1495 | } |
| 1496 | 1496 | ||
| 1497 | static int fimc_subdev_get_fmt(struct v4l2_subdev *sd, | 1497 | static int fimc_subdev_get_fmt(struct v4l2_subdev *sd, |
| 1498 | struct v4l2_subdev_fh *fh, | 1498 | struct v4l2_subdev_pad_config *cfg, |
| 1499 | struct v4l2_subdev_format *fmt) | 1499 | struct v4l2_subdev_format *fmt) |
| 1500 | { | 1500 | { |
| 1501 | struct fimc_dev *fimc = v4l2_get_subdevdata(sd); | 1501 | struct fimc_dev *fimc = v4l2_get_subdevdata(sd); |
| @@ -1504,7 +1504,7 @@ static int fimc_subdev_get_fmt(struct v4l2_subdev *sd, | |||
| 1504 | struct v4l2_mbus_framefmt *mf; | 1504 | struct v4l2_mbus_framefmt *mf; |
| 1505 | 1505 | ||
| 1506 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { | 1506 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { |
| 1507 | mf = v4l2_subdev_get_try_format(fh, fmt->pad); | 1507 | mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); |
| 1508 | fmt->format = *mf; | 1508 | fmt->format = *mf; |
| 1509 | return 0; | 1509 | return 0; |
| 1510 | } | 1510 | } |
| @@ -1536,7 +1536,7 @@ static int fimc_subdev_get_fmt(struct v4l2_subdev *sd, | |||
| 1536 | } | 1536 | } |
| 1537 | 1537 | ||
| 1538 | static int fimc_subdev_set_fmt(struct v4l2_subdev *sd, | 1538 | static int fimc_subdev_set_fmt(struct v4l2_subdev *sd, |
| 1539 | struct v4l2_subdev_fh *fh, | 1539 | struct v4l2_subdev_pad_config *cfg, |
| 1540 | struct v4l2_subdev_format *fmt) | 1540 | struct v4l2_subdev_format *fmt) |
| 1541 | { | 1541 | { |
| 1542 | struct fimc_dev *fimc = v4l2_get_subdevdata(sd); | 1542 | struct fimc_dev *fimc = v4l2_get_subdevdata(sd); |
| @@ -1559,7 +1559,7 @@ static int fimc_subdev_set_fmt(struct v4l2_subdev *sd, | |||
| 1559 | mf->colorspace = V4L2_COLORSPACE_JPEG; | 1559 | mf->colorspace = V4L2_COLORSPACE_JPEG; |
| 1560 | 1560 | ||
| 1561 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { | 1561 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { |
| 1562 | mf = v4l2_subdev_get_try_format(fh, fmt->pad); | 1562 | mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); |
| 1563 | *mf = fmt->format; | 1563 | *mf = fmt->format; |
| 1564 | return 0; | 1564 | return 0; |
| 1565 | } | 1565 | } |
| @@ -1602,7 +1602,7 @@ static int fimc_subdev_set_fmt(struct v4l2_subdev *sd, | |||
| 1602 | } | 1602 | } |
| 1603 | 1603 | ||
| 1604 | static int fimc_subdev_get_selection(struct v4l2_subdev *sd, | 1604 | static int fimc_subdev_get_selection(struct v4l2_subdev *sd, |
| 1605 | struct v4l2_subdev_fh *fh, | 1605 | struct v4l2_subdev_pad_config *cfg, |
| 1606 | struct v4l2_subdev_selection *sel) | 1606 | struct v4l2_subdev_selection *sel) |
| 1607 | { | 1607 | { |
| 1608 | struct fimc_dev *fimc = v4l2_get_subdevdata(sd); | 1608 | struct fimc_dev *fimc = v4l2_get_subdevdata(sd); |
| @@ -1628,10 +1628,10 @@ static int fimc_subdev_get_selection(struct v4l2_subdev *sd, | |||
| 1628 | return 0; | 1628 | return 0; |
| 1629 | 1629 | ||
| 1630 | case V4L2_SEL_TGT_CROP: | 1630 | case V4L2_SEL_TGT_CROP: |
| 1631 | try_sel = v4l2_subdev_get_try_crop(fh, sel->pad); | 1631 | try_sel = v4l2_subdev_get_try_crop(sd, cfg, sel->pad); |
| 1632 | break; | 1632 | break; |
| 1633 | case V4L2_SEL_TGT_COMPOSE: | 1633 | case V4L2_SEL_TGT_COMPOSE: |
| 1634 | try_sel = v4l2_subdev_get_try_compose(fh, sel->pad); | 1634 | try_sel = v4l2_subdev_get_try_compose(sd, cfg, sel->pad); |
| 1635 | f = &ctx->d_frame; | 1635 | f = &ctx->d_frame; |
| 1636 | break; | 1636 | break; |
| 1637 | default: | 1637 | default: |
| @@ -1657,7 +1657,7 @@ static int fimc_subdev_get_selection(struct v4l2_subdev *sd, | |||
| 1657 | } | 1657 | } |
| 1658 | 1658 | ||
| 1659 | static int fimc_subdev_set_selection(struct v4l2_subdev *sd, | 1659 | static int fimc_subdev_set_selection(struct v4l2_subdev *sd, |
| 1660 | struct v4l2_subdev_fh *fh, | 1660 | struct v4l2_subdev_pad_config *cfg, |
| 1661 | struct v4l2_subdev_selection *sel) | 1661 | struct v4l2_subdev_selection *sel) |
| 1662 | { | 1662 | { |
| 1663 | struct fimc_dev *fimc = v4l2_get_subdevdata(sd); | 1663 | struct fimc_dev *fimc = v4l2_get_subdevdata(sd); |
| @@ -1675,10 +1675,10 @@ static int fimc_subdev_set_selection(struct v4l2_subdev *sd, | |||
| 1675 | 1675 | ||
| 1676 | switch (sel->target) { | 1676 | switch (sel->target) { |
| 1677 | case V4L2_SEL_TGT_CROP: | 1677 | case V4L2_SEL_TGT_CROP: |
| 1678 | try_sel = v4l2_subdev_get_try_crop(fh, sel->pad); | 1678 | try_sel = v4l2_subdev_get_try_crop(sd, cfg, sel->pad); |
| 1679 | break; | 1679 | break; |
| 1680 | case V4L2_SEL_TGT_COMPOSE: | 1680 | case V4L2_SEL_TGT_COMPOSE: |
| 1681 | try_sel = v4l2_subdev_get_try_compose(fh, sel->pad); | 1681 | try_sel = v4l2_subdev_get_try_compose(sd, cfg, sel->pad); |
| 1682 | f = &ctx->d_frame; | 1682 | f = &ctx->d_frame; |
| 1683 | break; | 1683 | break; |
| 1684 | default: | 1684 | default: |
diff --git a/drivers/media/platform/exynos4-is/fimc-isp.c b/drivers/media/platform/exynos4-is/fimc-isp.c index 60c744915549..5d78f5716f3b 100644 --- a/drivers/media/platform/exynos4-is/fimc-isp.c +++ b/drivers/media/platform/exynos4-is/fimc-isp.c | |||
| @@ -112,7 +112,7 @@ static const struct media_entity_operations fimc_is_subdev_media_ops = { | |||
| 112 | }; | 112 | }; |
| 113 | 113 | ||
| 114 | static int fimc_is_subdev_enum_mbus_code(struct v4l2_subdev *sd, | 114 | static int fimc_is_subdev_enum_mbus_code(struct v4l2_subdev *sd, |
| 115 | struct v4l2_subdev_fh *fh, | 115 | struct v4l2_subdev_pad_config *cfg, |
| 116 | struct v4l2_subdev_mbus_code_enum *code) | 116 | struct v4l2_subdev_mbus_code_enum *code) |
| 117 | { | 117 | { |
| 118 | const struct fimc_fmt *fmt; | 118 | const struct fimc_fmt *fmt; |
| @@ -125,14 +125,14 @@ static int fimc_is_subdev_enum_mbus_code(struct v4l2_subdev *sd, | |||
| 125 | } | 125 | } |
| 126 | 126 | ||
| 127 | static int fimc_isp_subdev_get_fmt(struct v4l2_subdev *sd, | 127 | static int fimc_isp_subdev_get_fmt(struct v4l2_subdev *sd, |
| 128 | struct v4l2_subdev_fh *fh, | 128 | struct v4l2_subdev_pad_config *cfg, |
| 129 | struct v4l2_subdev_format *fmt) | 129 | struct v4l2_subdev_format *fmt) |
| 130 | { | 130 | { |
| 131 | struct fimc_isp *isp = v4l2_get_subdevdata(sd); | 131 | struct fimc_isp *isp = v4l2_get_subdevdata(sd); |
| 132 | struct v4l2_mbus_framefmt *mf = &fmt->format; | 132 | struct v4l2_mbus_framefmt *mf = &fmt->format; |
| 133 | 133 | ||
| 134 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { | 134 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { |
| 135 | *mf = *v4l2_subdev_get_try_format(fh, fmt->pad); | 135 | *mf = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad); |
| 136 | return 0; | 136 | return 0; |
| 137 | } | 137 | } |
| 138 | 138 | ||
| @@ -162,7 +162,7 @@ static int fimc_isp_subdev_get_fmt(struct v4l2_subdev *sd, | |||
| 162 | } | 162 | } |
| 163 | 163 | ||
| 164 | static void __isp_subdev_try_format(struct fimc_isp *isp, | 164 | static void __isp_subdev_try_format(struct fimc_isp *isp, |
| 165 | struct v4l2_subdev_fh *fh, | 165 | struct v4l2_subdev_pad_config *cfg, |
| 166 | struct v4l2_subdev_format *fmt) | 166 | struct v4l2_subdev_format *fmt) |
| 167 | { | 167 | { |
| 168 | struct v4l2_mbus_framefmt *mf = &fmt->format; | 168 | struct v4l2_mbus_framefmt *mf = &fmt->format; |
| @@ -178,7 +178,7 @@ static void __isp_subdev_try_format(struct fimc_isp *isp, | |||
| 178 | mf->code = MEDIA_BUS_FMT_SGRBG10_1X10; | 178 | mf->code = MEDIA_BUS_FMT_SGRBG10_1X10; |
| 179 | } else { | 179 | } else { |
| 180 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) | 180 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) |
| 181 | format = v4l2_subdev_get_try_format(fh, | 181 | format = v4l2_subdev_get_try_format(&isp->subdev, cfg, |
| 182 | FIMC_ISP_SD_PAD_SINK); | 182 | FIMC_ISP_SD_PAD_SINK); |
| 183 | else | 183 | else |
| 184 | format = &isp->sink_fmt; | 184 | format = &isp->sink_fmt; |
| @@ -197,7 +197,7 @@ static void __isp_subdev_try_format(struct fimc_isp *isp, | |||
| 197 | } | 197 | } |
| 198 | 198 | ||
| 199 | static int fimc_isp_subdev_set_fmt(struct v4l2_subdev *sd, | 199 | static int fimc_isp_subdev_set_fmt(struct v4l2_subdev *sd, |
| 200 | struct v4l2_subdev_fh *fh, | 200 | struct v4l2_subdev_pad_config *cfg, |
| 201 | struct v4l2_subdev_format *fmt) | 201 | struct v4l2_subdev_format *fmt) |
| 202 | { | 202 | { |
| 203 | struct fimc_isp *isp = v4l2_get_subdevdata(sd); | 203 | struct fimc_isp *isp = v4l2_get_subdevdata(sd); |
| @@ -209,10 +209,10 @@ static int fimc_isp_subdev_set_fmt(struct v4l2_subdev *sd, | |||
| 209 | __func__, fmt->pad, mf->code, mf->width, mf->height); | 209 | __func__, fmt->pad, mf->code, mf->width, mf->height); |
| 210 | 210 | ||
| 211 | mutex_lock(&isp->subdev_lock); | 211 | mutex_lock(&isp->subdev_lock); |
| 212 | __isp_subdev_try_format(isp, fh, fmt); | 212 | __isp_subdev_try_format(isp, cfg, fmt); |
| 213 | 213 | ||
| 214 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { | 214 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { |
| 215 | mf = v4l2_subdev_get_try_format(fh, fmt->pad); | 215 | mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); |
| 216 | *mf = fmt->format; | 216 | *mf = fmt->format; |
| 217 | 217 | ||
| 218 | /* Propagate format to the source pads */ | 218 | /* Propagate format to the source pads */ |
| @@ -223,8 +223,8 @@ static int fimc_isp_subdev_set_fmt(struct v4l2_subdev *sd, | |||
| 223 | for (pad = FIMC_ISP_SD_PAD_SRC_FIFO; | 223 | for (pad = FIMC_ISP_SD_PAD_SRC_FIFO; |
| 224 | pad < FIMC_ISP_SD_PADS_NUM; pad++) { | 224 | pad < FIMC_ISP_SD_PADS_NUM; pad++) { |
| 225 | format.pad = pad; | 225 | format.pad = pad; |
| 226 | __isp_subdev_try_format(isp, fh, &format); | 226 | __isp_subdev_try_format(isp, cfg, &format); |
| 227 | mf = v4l2_subdev_get_try_format(fh, pad); | 227 | mf = v4l2_subdev_get_try_format(sd, cfg, pad); |
| 228 | *mf = format.format; | 228 | *mf = format.format; |
| 229 | } | 229 | } |
| 230 | } | 230 | } |
| @@ -236,7 +236,7 @@ static int fimc_isp_subdev_set_fmt(struct v4l2_subdev *sd, | |||
| 236 | isp->sink_fmt = *mf; | 236 | isp->sink_fmt = *mf; |
| 237 | 237 | ||
| 238 | format.pad = FIMC_ISP_SD_PAD_SRC_DMA; | 238 | format.pad = FIMC_ISP_SD_PAD_SRC_DMA; |
| 239 | __isp_subdev_try_format(isp, fh, &format); | 239 | __isp_subdev_try_format(isp, cfg, &format); |
| 240 | 240 | ||
| 241 | isp->src_fmt = format.format; | 241 | isp->src_fmt = format.format; |
| 242 | __is_set_frame_size(is, &isp->src_fmt); | 242 | __is_set_frame_size(is, &isp->src_fmt); |
| @@ -369,7 +369,7 @@ static int fimc_isp_subdev_open(struct v4l2_subdev *sd, | |||
| 369 | struct v4l2_mbus_framefmt fmt; | 369 | struct v4l2_mbus_framefmt fmt; |
| 370 | struct v4l2_mbus_framefmt *format; | 370 | struct v4l2_mbus_framefmt *format; |
| 371 | 371 | ||
| 372 | format = v4l2_subdev_get_try_format(fh, FIMC_ISP_SD_PAD_SINK); | 372 | format = v4l2_subdev_get_try_format(sd, fh->pad, FIMC_ISP_SD_PAD_SINK); |
| 373 | 373 | ||
| 374 | fmt.colorspace = V4L2_COLORSPACE_SRGB; | 374 | fmt.colorspace = V4L2_COLORSPACE_SRGB; |
| 375 | fmt.code = fimc_isp_formats[0].mbus_code; | 375 | fmt.code = fimc_isp_formats[0].mbus_code; |
| @@ -378,12 +378,12 @@ static int fimc_isp_subdev_open(struct v4l2_subdev *sd, | |||
| 378 | fmt.field = V4L2_FIELD_NONE; | 378 | fmt.field = V4L2_FIELD_NONE; |
| 379 | *format = fmt; | 379 | *format = fmt; |
| 380 | 380 | ||
| 381 | format = v4l2_subdev_get_try_format(fh, FIMC_ISP_SD_PAD_SRC_FIFO); | 381 | format = v4l2_subdev_get_try_format(sd, fh->pad, FIMC_ISP_SD_PAD_SRC_FIFO); |
| 382 | fmt.width = DEFAULT_PREVIEW_STILL_WIDTH; | 382 | fmt.width = DEFAULT_PREVIEW_STILL_WIDTH; |
| 383 | fmt.height = DEFAULT_PREVIEW_STILL_HEIGHT; | 383 | fmt.height = DEFAULT_PREVIEW_STILL_HEIGHT; |
| 384 | *format = fmt; | 384 | *format = fmt; |
| 385 | 385 | ||
| 386 | format = v4l2_subdev_get_try_format(fh, FIMC_ISP_SD_PAD_SRC_DMA); | 386 | format = v4l2_subdev_get_try_format(sd, fh->pad, FIMC_ISP_SD_PAD_SRC_DMA); |
| 387 | *format = fmt; | 387 | *format = fmt; |
| 388 | 388 | ||
| 389 | return 0; | 389 | return 0; |
diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c index 2510f189e242..ca6261a86a5f 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/exynos4-is/fimc-lite.c | |||
| @@ -568,7 +568,7 @@ static const struct v4l2_file_operations fimc_lite_fops = { | |||
| 568 | */ | 568 | */ |
| 569 | 569 | ||
| 570 | static const struct fimc_fmt *fimc_lite_subdev_try_fmt(struct fimc_lite *fimc, | 570 | static const struct fimc_fmt *fimc_lite_subdev_try_fmt(struct fimc_lite *fimc, |
| 571 | struct v4l2_subdev_fh *fh, | 571 | struct v4l2_subdev_pad_config *cfg, |
| 572 | struct v4l2_subdev_format *format) | 572 | struct v4l2_subdev_format *format) |
| 573 | { | 573 | { |
| 574 | struct flite_drvdata *dd = fimc->dd; | 574 | struct flite_drvdata *dd = fimc->dd; |
| @@ -592,13 +592,13 @@ static const struct fimc_fmt *fimc_lite_subdev_try_fmt(struct fimc_lite *fimc, | |||
| 592 | struct v4l2_rect *rect; | 592 | struct v4l2_rect *rect; |
| 593 | 593 | ||
| 594 | if (format->which == V4L2_SUBDEV_FORMAT_TRY) { | 594 | if (format->which == V4L2_SUBDEV_FORMAT_TRY) { |
| 595 | sink_fmt = v4l2_subdev_get_try_format(fh, | 595 | sink_fmt = v4l2_subdev_get_try_format(&fimc->subdev, cfg, |
| 596 | FLITE_SD_PAD_SINK); | 596 | FLITE_SD_PAD_SINK); |
| 597 | 597 | ||
| 598 | mf->code = sink_fmt->code; | 598 | mf->code = sink_fmt->code; |
| 599 | mf->colorspace = sink_fmt->colorspace; | 599 | mf->colorspace = sink_fmt->colorspace; |
| 600 | 600 | ||
| 601 | rect = v4l2_subdev_get_try_crop(fh, | 601 | rect = v4l2_subdev_get_try_crop(&fimc->subdev, cfg, |
| 602 | FLITE_SD_PAD_SINK); | 602 | FLITE_SD_PAD_SINK); |
| 603 | } else { | 603 | } else { |
| 604 | mf->code = sink->fmt->mbus_code; | 604 | mf->code = sink->fmt->mbus_code; |
| @@ -1047,7 +1047,7 @@ static const struct media_entity_operations fimc_lite_subdev_media_ops = { | |||
| 1047 | }; | 1047 | }; |
| 1048 | 1048 | ||
| 1049 | static int fimc_lite_subdev_enum_mbus_code(struct v4l2_subdev *sd, | 1049 | static int fimc_lite_subdev_enum_mbus_code(struct v4l2_subdev *sd, |
| 1050 | struct v4l2_subdev_fh *fh, | 1050 | struct v4l2_subdev_pad_config *cfg, |
| 1051 | struct v4l2_subdev_mbus_code_enum *code) | 1051 | struct v4l2_subdev_mbus_code_enum *code) |
| 1052 | { | 1052 | { |
| 1053 | const struct fimc_fmt *fmt; | 1053 | const struct fimc_fmt *fmt; |
| @@ -1060,16 +1060,17 @@ static int fimc_lite_subdev_enum_mbus_code(struct v4l2_subdev *sd, | |||
| 1060 | } | 1060 | } |
| 1061 | 1061 | ||
| 1062 | static struct v4l2_mbus_framefmt *__fimc_lite_subdev_get_try_fmt( | 1062 | static struct v4l2_mbus_framefmt *__fimc_lite_subdev_get_try_fmt( |
| 1063 | struct v4l2_subdev_fh *fh, unsigned int pad) | 1063 | struct v4l2_subdev *sd, |
| 1064 | struct v4l2_subdev_pad_config *cfg, unsigned int pad) | ||
| 1064 | { | 1065 | { |
| 1065 | if (pad != FLITE_SD_PAD_SINK) | 1066 | if (pad != FLITE_SD_PAD_SINK) |
| 1066 | pad = FLITE_SD_PAD_SOURCE_DMA; | 1067 | pad = FLITE_SD_PAD_SOURCE_DMA; |
| 1067 | 1068 | ||
| 1068 | return v4l2_subdev_get_try_format(fh, pad); | 1069 | return v4l2_subdev_get_try_format(sd, cfg, pad); |
| 1069 | } | 1070 | } |
| 1070 | 1071 | ||
| 1071 | static int fimc_lite_subdev_get_fmt(struct v4l2_subdev *sd, | 1072 | static int fimc_lite_subdev_get_fmt(struct v4l2_subdev *sd, |
| 1072 | struct v4l2_subdev_fh *fh, | 1073 | struct v4l2_subdev_pad_config *cfg, |
| 1073 | struct v4l2_subdev_format *fmt) | 1074 | struct v4l2_subdev_format *fmt) |
| 1074 | { | 1075 | { |
| 1075 | struct fimc_lite *fimc = v4l2_get_subdevdata(sd); | 1076 | struct fimc_lite *fimc = v4l2_get_subdevdata(sd); |
| @@ -1077,7 +1078,7 @@ static int fimc_lite_subdev_get_fmt(struct v4l2_subdev *sd, | |||
| 1077 | struct flite_frame *f = &fimc->inp_frame; | 1078 | struct flite_frame *f = &fimc->inp_frame; |
| 1078 | 1079 | ||
| 1079 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { | 1080 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { |
| 1080 | mf = __fimc_lite_subdev_get_try_fmt(fh, fmt->pad); | 1081 | mf = __fimc_lite_subdev_get_try_fmt(sd, cfg, fmt->pad); |
| 1081 | fmt->format = *mf; | 1082 | fmt->format = *mf; |
| 1082 | return 0; | 1083 | return 0; |
| 1083 | } | 1084 | } |
| @@ -1100,7 +1101,7 @@ static int fimc_lite_subdev_get_fmt(struct v4l2_subdev *sd, | |||
| 1100 | } | 1101 | } |
| 1101 | 1102 | ||
| 1102 | static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd, | 1103 | static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd, |
| 1103 | struct v4l2_subdev_fh *fh, | 1104 | struct v4l2_subdev_pad_config *cfg, |
| 1104 | struct v4l2_subdev_format *fmt) | 1105 | struct v4l2_subdev_format *fmt) |
| 1105 | { | 1106 | { |
| 1106 | struct fimc_lite *fimc = v4l2_get_subdevdata(sd); | 1107 | struct fimc_lite *fimc = v4l2_get_subdevdata(sd); |
| @@ -1122,17 +1123,17 @@ static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd, | |||
| 1122 | return -EBUSY; | 1123 | return -EBUSY; |
| 1123 | } | 1124 | } |
| 1124 | 1125 | ||
| 1125 | ffmt = fimc_lite_subdev_try_fmt(fimc, fh, fmt); | 1126 | ffmt = fimc_lite_subdev_try_fmt(fimc, cfg, fmt); |
| 1126 | 1127 | ||
| 1127 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { | 1128 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { |
| 1128 | struct v4l2_mbus_framefmt *src_fmt; | 1129 | struct v4l2_mbus_framefmt *src_fmt; |
| 1129 | 1130 | ||
| 1130 | mf = __fimc_lite_subdev_get_try_fmt(fh, fmt->pad); | 1131 | mf = __fimc_lite_subdev_get_try_fmt(sd, cfg, fmt->pad); |
| 1131 | *mf = fmt->format; | 1132 | *mf = fmt->format; |
| 1132 | 1133 | ||
| 1133 | if (fmt->pad == FLITE_SD_PAD_SINK) { | 1134 | if (fmt->pad == FLITE_SD_PAD_SINK) { |
| 1134 | unsigned int pad = FLITE_SD_PAD_SOURCE_DMA; | 1135 | unsigned int pad = FLITE_SD_PAD_SOURCE_DMA; |
| 1135 | src_fmt = __fimc_lite_subdev_get_try_fmt(fh, pad); | 1136 | src_fmt = __fimc_lite_subdev_get_try_fmt(sd, cfg, pad); |
| 1136 | *src_fmt = *mf; | 1137 | *src_fmt = *mf; |
| 1137 | } | 1138 | } |
| 1138 | 1139 | ||
| @@ -1160,7 +1161,7 @@ static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd, | |||
| 1160 | } | 1161 | } |
| 1161 | 1162 | ||
| 1162 | static int fimc_lite_subdev_get_selection(struct v4l2_subdev *sd, | 1163 | static int fimc_lite_subdev_get_selection(struct v4l2_subdev *sd, |
| 1163 | struct v4l2_subdev_fh *fh, | 1164 | struct v4l2_subdev_pad_config *cfg, |
| 1164 | struct v4l2_subdev_selection *sel) | 1165 | struct v4l2_subdev_selection *sel) |
| 1165 | { | 1166 | { |
| 1166 | struct fimc_lite *fimc = v4l2_get_subdevdata(sd); | 1167 | struct fimc_lite *fimc = v4l2_get_subdevdata(sd); |
| @@ -1172,7 +1173,7 @@ static int fimc_lite_subdev_get_selection(struct v4l2_subdev *sd, | |||
| 1172 | return -EINVAL; | 1173 | return -EINVAL; |
| 1173 | 1174 | ||
| 1174 | if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { | 1175 | if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { |
| 1175 | sel->r = *v4l2_subdev_get_try_crop(fh, sel->pad); | 1176 | sel->r = *v4l2_subdev_get_try_crop(sd, cfg, sel->pad); |
| 1176 | return 0; | 1177 | return 0; |
| 1177 | } | 1178 | } |
| 1178 | 1179 | ||
| @@ -1195,7 +1196,7 @@ static int fimc_lite_subdev_get_selection(struct v4l2_subdev *sd, | |||
| 1195 | } | 1196 | } |
| 1196 | 1197 | ||
| 1197 | static int fimc_lite_subdev_set_selection(struct v4l2_subdev *sd, | 1198 | static int fimc_lite_subdev_set_selection(struct v4l2_subdev *sd, |
| 1198 | struct v4l2_subdev_fh *fh, | 1199 | struct v4l2_subdev_pad_config *cfg, |
| 1199 | struct v4l2_subdev_selection *sel) | 1200 | struct v4l2_subdev_selection *sel) |
| 1200 | { | 1201 | { |
| 1201 | struct fimc_lite *fimc = v4l2_get_subdevdata(sd); | 1202 | struct fimc_lite *fimc = v4l2_get_subdevdata(sd); |
| @@ -1209,7 +1210,7 @@ static int fimc_lite_subdev_set_selection(struct v4l2_subdev *sd, | |||
| 1209 | fimc_lite_try_crop(fimc, &sel->r); | 1210 | fimc_lite_try_crop(fimc, &sel->r); |
| 1210 | 1211 | ||
| 1211 | if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { | 1212 | if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { |
| 1212 | *v4l2_subdev_get_try_crop(fh, sel->pad) = sel->r; | 1213 | *v4l2_subdev_get_try_crop(sd, cfg, sel->pad) = sel->r; |
| 1213 | } else { | 1214 | } else { |
| 1214 | unsigned long flags; | 1215 | unsigned long flags; |
| 1215 | spin_lock_irqsave(&fimc->slock, flags); | 1216 | spin_lock_irqsave(&fimc->slock, flags); |
diff --git a/drivers/media/platform/exynos4-is/mipi-csis.c b/drivers/media/platform/exynos4-is/mipi-csis.c index 2504aa89a6f4..d74e1bec3d86 100644 --- a/drivers/media/platform/exynos4-is/mipi-csis.c +++ b/drivers/media/platform/exynos4-is/mipi-csis.c | |||
| @@ -540,7 +540,7 @@ unlock: | |||
| 540 | } | 540 | } |
| 541 | 541 | ||
| 542 | static int s5pcsis_enum_mbus_code(struct v4l2_subdev *sd, | 542 | static int s5pcsis_enum_mbus_code(struct v4l2_subdev *sd, |
| 543 | struct v4l2_subdev_fh *fh, | 543 | struct v4l2_subdev_pad_config *cfg, |
| 544 | struct v4l2_subdev_mbus_code_enum *code) | 544 | struct v4l2_subdev_mbus_code_enum *code) |
| 545 | { | 545 | { |
| 546 | if (code->index >= ARRAY_SIZE(s5pcsis_formats)) | 546 | if (code->index >= ARRAY_SIZE(s5pcsis_formats)) |
| @@ -568,23 +568,23 @@ static struct csis_pix_format const *s5pcsis_try_format( | |||
| 568 | } | 568 | } |
| 569 | 569 | ||
| 570 | static struct v4l2_mbus_framefmt *__s5pcsis_get_format( | 570 | static struct v4l2_mbus_framefmt *__s5pcsis_get_format( |
| 571 | struct csis_state *state, struct v4l2_subdev_fh *fh, | 571 | struct csis_state *state, struct v4l2_subdev_pad_config *cfg, |
| 572 | enum v4l2_subdev_format_whence which) | 572 | enum v4l2_subdev_format_whence which) |
| 573 | { | 573 | { |
| 574 | if (which == V4L2_SUBDEV_FORMAT_TRY) | 574 | if (which == V4L2_SUBDEV_FORMAT_TRY) |
| 575 | return fh ? v4l2_subdev_get_try_format(fh, 0) : NULL; | 575 | return cfg ? v4l2_subdev_get_try_format(&state->sd, cfg, 0) : NULL; |
| 576 | 576 | ||
| 577 | return &state->format; | 577 | return &state->format; |
| 578 | } | 578 | } |
| 579 | 579 | ||
| 580 | static int s5pcsis_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | 580 | static int s5pcsis_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, |
| 581 | struct v4l2_subdev_format *fmt) | 581 | struct v4l2_subdev_format *fmt) |
| 582 | { | 582 | { |
| 583 | struct csis_state *state = sd_to_csis_state(sd); | 583 | struct csis_state *state = sd_to_csis_state(sd); |
| 584 | struct csis_pix_format const *csis_fmt; | 584 | struct csis_pix_format const *csis_fmt; |
| 585 | struct v4l2_mbus_framefmt *mf; | 585 | struct v4l2_mbus_framefmt *mf; |
| 586 | 586 | ||
| 587 | mf = __s5pcsis_get_format(state, fh, fmt->which); | 587 | mf = __s5pcsis_get_format(state, cfg, fmt->which); |
| 588 | 588 | ||
| 589 | if (fmt->pad == CSIS_PAD_SOURCE) { | 589 | if (fmt->pad == CSIS_PAD_SOURCE) { |
| 590 | if (mf) { | 590 | if (mf) { |
| @@ -605,13 +605,13 @@ static int s5pcsis_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | |||
| 605 | return 0; | 605 | return 0; |
| 606 | } | 606 | } |
| 607 | 607 | ||
| 608 | static int s5pcsis_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | 608 | static int s5pcsis_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, |
| 609 | struct v4l2_subdev_format *fmt) | 609 | struct v4l2_subdev_format *fmt) |
| 610 | { | 610 | { |
| 611 | struct csis_state *state = sd_to_csis_state(sd); | 611 | struct csis_state *state = sd_to_csis_state(sd); |
| 612 | struct v4l2_mbus_framefmt *mf; | 612 | struct v4l2_mbus_framefmt *mf; |
| 613 | 613 | ||
| 614 | mf = __s5pcsis_get_format(state, fh, fmt->which); | 614 | mf = __s5pcsis_get_format(state, cfg, fmt->which); |
| 615 | if (!mf) | 615 | if (!mf) |
| 616 | return -EINVAL; | 616 | return -EINVAL; |
| 617 | 617 | ||
| @@ -651,7 +651,7 @@ static int s5pcsis_log_status(struct v4l2_subdev *sd) | |||
| 651 | 651 | ||
| 652 | static int s5pcsis_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) | 652 | static int s5pcsis_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) |
| 653 | { | 653 | { |
| 654 | struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0); | 654 | struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(sd, fh->pad, 0); |
| 655 | 655 | ||
| 656 | format->colorspace = V4L2_COLORSPACE_JPEG; | 656 | format->colorspace = V4L2_COLORSPACE_JPEG; |
| 657 | format->code = s5pcsis_formats[0].code; | 657 | format->code = s5pcsis_formats[0].code; |
diff --git a/drivers/media/platform/m2m-deinterlace.c b/drivers/media/platform/m2m-deinterlace.c index b70c1aecca37..92d954973ccf 100644 --- a/drivers/media/platform/m2m-deinterlace.c +++ b/drivers/media/platform/m2m-deinterlace.c | |||
| @@ -127,7 +127,7 @@ static struct deinterlace_fmt *find_format(struct v4l2_format *f) | |||
| 127 | 127 | ||
| 128 | struct deinterlace_dev { | 128 | struct deinterlace_dev { |
| 129 | struct v4l2_device v4l2_dev; | 129 | struct v4l2_device v4l2_dev; |
| 130 | struct video_device *vfd; | 130 | struct video_device vfd; |
| 131 | 131 | ||
| 132 | atomic_t busy; | 132 | atomic_t busy; |
| 133 | struct mutex dev_mutex; | 133 | struct mutex dev_mutex; |
| @@ -983,7 +983,7 @@ static struct video_device deinterlace_videodev = { | |||
| 983 | .fops = &deinterlace_fops, | 983 | .fops = &deinterlace_fops, |
| 984 | .ioctl_ops = &deinterlace_ioctl_ops, | 984 | .ioctl_ops = &deinterlace_ioctl_ops, |
| 985 | .minor = -1, | 985 | .minor = -1, |
| 986 | .release = video_device_release, | 986 | .release = video_device_release_empty, |
| 987 | .vfl_dir = VFL_DIR_M2M, | 987 | .vfl_dir = VFL_DIR_M2M, |
| 988 | }; | 988 | }; |
| 989 | 989 | ||
| @@ -1026,13 +1026,7 @@ static int deinterlace_probe(struct platform_device *pdev) | |||
| 1026 | atomic_set(&pcdev->busy, 0); | 1026 | atomic_set(&pcdev->busy, 0); |
| 1027 | mutex_init(&pcdev->dev_mutex); | 1027 | mutex_init(&pcdev->dev_mutex); |
| 1028 | 1028 | ||
| 1029 | vfd = video_device_alloc(); | 1029 | vfd = &pcdev->vfd; |
| 1030 | if (!vfd) { | ||
| 1031 | v4l2_err(&pcdev->v4l2_dev, "Failed to allocate video device\n"); | ||
| 1032 | ret = -ENOMEM; | ||
| 1033 | goto unreg_dev; | ||
| 1034 | } | ||
| 1035 | |||
| 1036 | *vfd = deinterlace_videodev; | 1030 | *vfd = deinterlace_videodev; |
| 1037 | vfd->lock = &pcdev->dev_mutex; | 1031 | vfd->lock = &pcdev->dev_mutex; |
| 1038 | vfd->v4l2_dev = &pcdev->v4l2_dev; | 1032 | vfd->v4l2_dev = &pcdev->v4l2_dev; |
| @@ -1040,12 +1034,11 @@ static int deinterlace_probe(struct platform_device *pdev) | |||
| 1040 | ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); | 1034 | ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); |
| 1041 | if (ret) { | 1035 | if (ret) { |
| 1042 | v4l2_err(&pcdev->v4l2_dev, "Failed to register video device\n"); | 1036 | v4l2_err(&pcdev->v4l2_dev, "Failed to register video device\n"); |
| 1043 | goto rel_vdev; | 1037 | goto unreg_dev; |
| 1044 | } | 1038 | } |
| 1045 | 1039 | ||
| 1046 | video_set_drvdata(vfd, pcdev); | 1040 | video_set_drvdata(vfd, pcdev); |
| 1047 | snprintf(vfd->name, sizeof(vfd->name), "%s", deinterlace_videodev.name); | 1041 | snprintf(vfd->name, sizeof(vfd->name), "%s", deinterlace_videodev.name); |
| 1048 | pcdev->vfd = vfd; | ||
| 1049 | v4l2_info(&pcdev->v4l2_dev, MEM2MEM_TEST_MODULE_NAME | 1042 | v4l2_info(&pcdev->v4l2_dev, MEM2MEM_TEST_MODULE_NAME |
| 1050 | " Device registered as /dev/video%d\n", vfd->num); | 1043 | " Device registered as /dev/video%d\n", vfd->num); |
| 1051 | 1044 | ||
| @@ -1069,11 +1062,9 @@ static int deinterlace_probe(struct platform_device *pdev) | |||
| 1069 | 1062 | ||
| 1070 | v4l2_m2m_release(pcdev->m2m_dev); | 1063 | v4l2_m2m_release(pcdev->m2m_dev); |
| 1071 | err_m2m: | 1064 | err_m2m: |
| 1072 | video_unregister_device(pcdev->vfd); | 1065 | video_unregister_device(&pcdev->vfd); |
| 1073 | err_ctx: | 1066 | err_ctx: |
| 1074 | vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); | 1067 | vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); |
| 1075 | rel_vdev: | ||
| 1076 | video_device_release(vfd); | ||
| 1077 | unreg_dev: | 1068 | unreg_dev: |
| 1078 | v4l2_device_unregister(&pcdev->v4l2_dev); | 1069 | v4l2_device_unregister(&pcdev->v4l2_dev); |
| 1079 | rel_dma: | 1070 | rel_dma: |
| @@ -1088,7 +1079,7 @@ static int deinterlace_remove(struct platform_device *pdev) | |||
| 1088 | 1079 | ||
| 1089 | v4l2_info(&pcdev->v4l2_dev, "Removing " MEM2MEM_TEST_MODULE_NAME); | 1080 | v4l2_info(&pcdev->v4l2_dev, "Removing " MEM2MEM_TEST_MODULE_NAME); |
| 1090 | v4l2_m2m_release(pcdev->m2m_dev); | 1081 | v4l2_m2m_release(pcdev->m2m_dev); |
| 1091 | video_unregister_device(pcdev->vfd); | 1082 | video_unregister_device(&pcdev->vfd); |
| 1092 | v4l2_device_unregister(&pcdev->v4l2_dev); | 1083 | v4l2_device_unregister(&pcdev->v4l2_dev); |
| 1093 | vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); | 1084 | vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); |
| 1094 | dma_release_channel(pcdev->dma_chan); | 1085 | dma_release_channel(pcdev->dma_chan); |
diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c index dd5b1415f974..9c64b5d01c6a 100644 --- a/drivers/media/platform/marvell-ccic/mcam-core.c +++ b/drivers/media/platform/marvell-ccic/mcam-core.c | |||
| @@ -1568,24 +1568,64 @@ static int mcam_vidioc_enum_framesizes(struct file *filp, void *priv, | |||
| 1568 | struct v4l2_frmsizeenum *sizes) | 1568 | struct v4l2_frmsizeenum *sizes) |
| 1569 | { | 1569 | { |
| 1570 | struct mcam_camera *cam = priv; | 1570 | struct mcam_camera *cam = priv; |
| 1571 | struct mcam_format_struct *f; | ||
| 1572 | struct v4l2_subdev_frame_size_enum fse = { | ||
| 1573 | .index = sizes->index, | ||
| 1574 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
| 1575 | }; | ||
| 1571 | int ret; | 1576 | int ret; |
| 1572 | 1577 | ||
| 1578 | f = mcam_find_format(sizes->pixel_format); | ||
| 1579 | if (f->pixelformat != sizes->pixel_format) | ||
| 1580 | return -EINVAL; | ||
| 1581 | fse.code = f->mbus_code; | ||
| 1573 | mutex_lock(&cam->s_mutex); | 1582 | mutex_lock(&cam->s_mutex); |
| 1574 | ret = sensor_call(cam, video, enum_framesizes, sizes); | 1583 | ret = sensor_call(cam, pad, enum_frame_size, NULL, &fse); |
| 1575 | mutex_unlock(&cam->s_mutex); | 1584 | mutex_unlock(&cam->s_mutex); |
| 1576 | return ret; | 1585 | if (ret) |
| 1586 | return ret; | ||
| 1587 | if (fse.min_width == fse.max_width && | ||
| 1588 | fse.min_height == fse.max_height) { | ||
| 1589 | sizes->type = V4L2_FRMSIZE_TYPE_DISCRETE; | ||
| 1590 | sizes->discrete.width = fse.min_width; | ||
| 1591 | sizes->discrete.height = fse.min_height; | ||
| 1592 | return 0; | ||
| 1593 | } | ||
| 1594 | sizes->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; | ||
| 1595 | sizes->stepwise.min_width = fse.min_width; | ||
| 1596 | sizes->stepwise.max_width = fse.max_width; | ||
| 1597 | sizes->stepwise.min_height = fse.min_height; | ||
| 1598 | sizes->stepwise.max_height = fse.max_height; | ||
| 1599 | sizes->stepwise.step_width = 1; | ||
| 1600 | sizes->stepwise.step_height = 1; | ||
| 1601 | return 0; | ||
| 1577 | } | 1602 | } |
| 1578 | 1603 | ||
| 1579 | static int mcam_vidioc_enum_frameintervals(struct file *filp, void *priv, | 1604 | static int mcam_vidioc_enum_frameintervals(struct file *filp, void *priv, |
| 1580 | struct v4l2_frmivalenum *interval) | 1605 | struct v4l2_frmivalenum *interval) |
| 1581 | { | 1606 | { |
| 1582 | struct mcam_camera *cam = priv; | 1607 | struct mcam_camera *cam = priv; |
| 1608 | struct mcam_format_struct *f; | ||
| 1609 | struct v4l2_subdev_frame_interval_enum fie = { | ||
| 1610 | .index = interval->index, | ||
| 1611 | .width = interval->width, | ||
| 1612 | .height = interval->height, | ||
| 1613 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
| 1614 | }; | ||
| 1583 | int ret; | 1615 | int ret; |
| 1584 | 1616 | ||
| 1617 | f = mcam_find_format(interval->pixel_format); | ||
| 1618 | if (f->pixelformat != interval->pixel_format) | ||
| 1619 | return -EINVAL; | ||
| 1620 | fie.code = f->mbus_code; | ||
| 1585 | mutex_lock(&cam->s_mutex); | 1621 | mutex_lock(&cam->s_mutex); |
| 1586 | ret = sensor_call(cam, video, enum_frameintervals, interval); | 1622 | ret = sensor_call(cam, pad, enum_frame_interval, NULL, &fie); |
| 1587 | mutex_unlock(&cam->s_mutex); | 1623 | mutex_unlock(&cam->s_mutex); |
| 1588 | return ret; | 1624 | if (ret) |
| 1625 | return ret; | ||
| 1626 | interval->type = V4L2_FRMIVAL_TYPE_DISCRETE; | ||
| 1627 | interval->discrete = fie.interval; | ||
| 1628 | return 0; | ||
| 1589 | } | 1629 | } |
| 1590 | 1630 | ||
| 1591 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 1631 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c index ba2d8f973d58..17b189a81ec5 100644 --- a/drivers/media/platform/omap/omap_vout.c +++ b/drivers/media/platform/omap/omap_vout.c | |||
| @@ -1978,7 +1978,7 @@ static int __init omap_vout_setup_video_bufs(struct platform_device *pdev, | |||
| 1978 | vout->cropped_offset = 0; | 1978 | vout->cropped_offset = 0; |
| 1979 | 1979 | ||
| 1980 | if (ovid->rotation_type == VOUT_ROT_VRFB) { | 1980 | if (ovid->rotation_type == VOUT_ROT_VRFB) { |
| 1981 | int static_vrfb_allocation = (vid_num == 0) ? | 1981 | bool static_vrfb_allocation = (vid_num == 0) ? |
| 1982 | vid1_static_vrfb_alloc : vid2_static_vrfb_alloc; | 1982 | vid1_static_vrfb_alloc : vid2_static_vrfb_alloc; |
| 1983 | ret = omap_vout_setup_vrfb_bufs(pdev, vid_num, | 1983 | ret = omap_vout_setup_vrfb_bufs(pdev, vid_num, |
| 1984 | static_vrfb_allocation); | 1984 | static_vrfb_allocation); |
diff --git a/drivers/media/platform/omap/omap_vout_vrfb.c b/drivers/media/platform/omap/omap_vout_vrfb.c index aa39306afc73..c6e252760c62 100644 --- a/drivers/media/platform/omap/omap_vout_vrfb.c +++ b/drivers/media/platform/omap/omap_vout_vrfb.c | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | 21 | ||
| 22 | #include "omap_voutdef.h" | 22 | #include "omap_voutdef.h" |
| 23 | #include "omap_voutlib.h" | 23 | #include "omap_voutlib.h" |
| 24 | #include "omap_vout_vrfb.h" | ||
| 24 | 25 | ||
| 25 | #define OMAP_DMA_NO_DEVICE 0 | 26 | #define OMAP_DMA_NO_DEVICE 0 |
| 26 | 27 | ||
diff --git a/drivers/media/platform/omap/omap_vout_vrfb.h b/drivers/media/platform/omap/omap_vout_vrfb.h index 4c2314839b48..c976975024df 100644 --- a/drivers/media/platform/omap/omap_vout_vrfb.h +++ b/drivers/media/platform/omap/omap_vout_vrfb.h | |||
| @@ -15,7 +15,7 @@ | |||
| 15 | #ifdef CONFIG_VIDEO_OMAP2_VOUT_VRFB | 15 | #ifdef CONFIG_VIDEO_OMAP2_VOUT_VRFB |
| 16 | void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout); | 16 | void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout); |
| 17 | int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num, | 17 | int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num, |
| 18 | u32 static_vrfb_allocation); | 18 | bool static_vrfb_allocation); |
| 19 | void omap_vout_release_vrfb(struct omap_vout_device *vout); | 19 | void omap_vout_release_vrfb(struct omap_vout_device *vout); |
| 20 | int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout, | 20 | int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout, |
| 21 | unsigned int *count, unsigned int startindex); | 21 | unsigned int *count, unsigned int startindex); |
| @@ -25,7 +25,7 @@ void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout); | |||
| 25 | #else | 25 | #else |
| 26 | static inline void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout) { }; | 26 | static inline void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout) { }; |
| 27 | static inline int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num, | 27 | static inline int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num, |
| 28 | u32 static_vrfb_allocation) | 28 | bool static_vrfb_allocation) |
| 29 | { return 0; }; | 29 | { return 0; }; |
| 30 | static inline void omap_vout_release_vrfb(struct omap_vout_device *vout) { }; | 30 | static inline void omap_vout_release_vrfb(struct omap_vout_device *vout) { }; |
| 31 | static inline int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout, | 31 | static inline int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout, |
diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index deca80903c3a..18d0a871747f 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c | |||
| @@ -51,6 +51,7 @@ | |||
| 51 | #include <linux/dma-mapping.h> | 51 | #include <linux/dma-mapping.h> |
| 52 | #include <linux/i2c.h> | 52 | #include <linux/i2c.h> |
| 53 | #include <linux/interrupt.h> | 53 | #include <linux/interrupt.h> |
| 54 | #include <linux/mfd/syscon.h> | ||
| 54 | #include <linux/module.h> | 55 | #include <linux/module.h> |
| 55 | #include <linux/omap-iommu.h> | 56 | #include <linux/omap-iommu.h> |
| 56 | #include <linux/platform_device.h> | 57 | #include <linux/platform_device.h> |
| @@ -63,6 +64,7 @@ | |||
| 63 | 64 | ||
| 64 | #include <media/v4l2-common.h> | 65 | #include <media/v4l2-common.h> |
| 65 | #include <media/v4l2-device.h> | 66 | #include <media/v4l2-device.h> |
| 67 | #include <media/v4l2-of.h> | ||
| 66 | 68 | ||
| 67 | #include "isp.h" | 69 | #include "isp.h" |
| 68 | #include "ispreg.h" | 70 | #include "ispreg.h" |
| @@ -85,35 +87,45 @@ static void isp_restore_ctx(struct isp_device *isp); | |||
| 85 | static const struct isp_res_mapping isp_res_maps[] = { | 87 | static const struct isp_res_mapping isp_res_maps[] = { |
| 86 | { | 88 | { |
| 87 | .isp_rev = ISP_REVISION_2_0, | 89 | .isp_rev = ISP_REVISION_2_0, |
| 88 | .map = 1 << OMAP3_ISP_IOMEM_MAIN | | 90 | .offset = { |
| 89 | 1 << OMAP3_ISP_IOMEM_CCP2 | | 91 | /* first MMIO area */ |
| 90 | 1 << OMAP3_ISP_IOMEM_CCDC | | 92 | 0x0000, /* base, len 0x0070 */ |
| 91 | 1 << OMAP3_ISP_IOMEM_HIST | | 93 | 0x0400, /* ccp2, len 0x01f0 */ |
| 92 | 1 << OMAP3_ISP_IOMEM_H3A | | 94 | 0x0600, /* ccdc, len 0x00a8 */ |
| 93 | 1 << OMAP3_ISP_IOMEM_PREV | | 95 | 0x0a00, /* hist, len 0x0048 */ |
| 94 | 1 << OMAP3_ISP_IOMEM_RESZ | | 96 | 0x0c00, /* h3a, len 0x0060 */ |
| 95 | 1 << OMAP3_ISP_IOMEM_SBL | | 97 | 0x0e00, /* preview, len 0x00a0 */ |
| 96 | 1 << OMAP3_ISP_IOMEM_CSI2A_REGS1 | | 98 | 0x1000, /* resizer, len 0x00ac */ |
| 97 | 1 << OMAP3_ISP_IOMEM_CSIPHY2 | | 99 | 0x1200, /* sbl, len 0x00fc */ |
| 98 | 1 << OMAP3_ISP_IOMEM_343X_CONTROL_CSIRXFE, | 100 | /* second MMIO area */ |
| 101 | 0x0000, /* csi2a, len 0x0170 */ | ||
| 102 | 0x0170, /* csiphy2, len 0x000c */ | ||
| 103 | }, | ||
| 104 | .syscon_offset = 0xdc, | ||
| 105 | .phy_type = ISP_PHY_TYPE_3430, | ||
| 99 | }, | 106 | }, |
| 100 | { | 107 | { |
| 101 | .isp_rev = ISP_REVISION_15_0, | 108 | .isp_rev = ISP_REVISION_15_0, |
| 102 | .map = 1 << OMAP3_ISP_IOMEM_MAIN | | 109 | .offset = { |
| 103 | 1 << OMAP3_ISP_IOMEM_CCP2 | | 110 | /* first MMIO area */ |
| 104 | 1 << OMAP3_ISP_IOMEM_CCDC | | 111 | 0x0000, /* base, len 0x0070 */ |
| 105 | 1 << OMAP3_ISP_IOMEM_HIST | | 112 | 0x0400, /* ccp2, len 0x01f0 */ |
| 106 | 1 << OMAP3_ISP_IOMEM_H3A | | 113 | 0x0600, /* ccdc, len 0x00a8 */ |
| 107 | 1 << OMAP3_ISP_IOMEM_PREV | | 114 | 0x0a00, /* hist, len 0x0048 */ |
| 108 | 1 << OMAP3_ISP_IOMEM_RESZ | | 115 | 0x0c00, /* h3a, len 0x0060 */ |
| 109 | 1 << OMAP3_ISP_IOMEM_SBL | | 116 | 0x0e00, /* preview, len 0x00a0 */ |
| 110 | 1 << OMAP3_ISP_IOMEM_CSI2A_REGS1 | | 117 | 0x1000, /* resizer, len 0x00ac */ |
| 111 | 1 << OMAP3_ISP_IOMEM_CSIPHY2 | | 118 | 0x1200, /* sbl, len 0x00fc */ |
| 112 | 1 << OMAP3_ISP_IOMEM_CSI2A_REGS2 | | 119 | /* second MMIO area */ |
| 113 | 1 << OMAP3_ISP_IOMEM_CSI2C_REGS1 | | 120 | 0x0000, /* csi2a, len 0x0170 (1st area) */ |
| 114 | 1 << OMAP3_ISP_IOMEM_CSIPHY1 | | 121 | 0x0170, /* csiphy2, len 0x000c */ |
| 115 | 1 << OMAP3_ISP_IOMEM_CSI2C_REGS2 | | 122 | 0x01c0, /* csi2a, len 0x0040 (2nd area) */ |
| 116 | 1 << OMAP3_ISP_IOMEM_3630_CONTROL_CAMERA_PHY_CTRL, | 123 | 0x0400, /* csi2c, len 0x0170 (1st area) */ |
| 124 | 0x0570, /* csiphy1, len 0x000c */ | ||
| 125 | 0x05c0, /* csi2c, len 0x0040 (2nd area) */ | ||
| 126 | }, | ||
| 127 | .syscon_offset = 0x2f0, | ||
| 128 | .phy_type = ISP_PHY_TYPE_3630, | ||
| 117 | }, | 129 | }, |
| 118 | }; | 130 | }; |
| 119 | 131 | ||
| @@ -279,9 +291,20 @@ static const struct clk_init_data isp_xclk_init_data = { | |||
| 279 | .num_parents = 1, | 291 | .num_parents = 1, |
| 280 | }; | 292 | }; |
| 281 | 293 | ||
| 294 | static struct clk *isp_xclk_src_get(struct of_phandle_args *clkspec, void *data) | ||
| 295 | { | ||
| 296 | unsigned int idx = clkspec->args[0]; | ||
| 297 | struct isp_device *isp = data; | ||
| 298 | |||
| 299 | if (idx >= ARRAY_SIZE(isp->xclks)) | ||
| 300 | return ERR_PTR(-ENOENT); | ||
| 301 | |||
| 302 | return isp->xclks[idx].clk; | ||
| 303 | } | ||
| 304 | |||
| 282 | static int isp_xclk_init(struct isp_device *isp) | 305 | static int isp_xclk_init(struct isp_device *isp) |
| 283 | { | 306 | { |
| 284 | struct isp_platform_data *pdata = isp->pdata; | 307 | struct device_node *np = isp->dev->of_node; |
| 285 | struct clk_init_data init; | 308 | struct clk_init_data init; |
| 286 | unsigned int i; | 309 | unsigned int i; |
| 287 | 310 | ||
| @@ -311,37 +334,27 @@ static int isp_xclk_init(struct isp_device *isp) | |||
| 311 | xclk->clk = clk_register(NULL, &xclk->hw); | 334 | xclk->clk = clk_register(NULL, &xclk->hw); |
| 312 | if (IS_ERR(xclk->clk)) | 335 | if (IS_ERR(xclk->clk)) |
| 313 | return PTR_ERR(xclk->clk); | 336 | return PTR_ERR(xclk->clk); |
| 314 | |||
| 315 | if (pdata->xclks[i].con_id == NULL && | ||
| 316 | pdata->xclks[i].dev_id == NULL) | ||
| 317 | continue; | ||
| 318 | |||
| 319 | xclk->lookup = kzalloc(sizeof(*xclk->lookup), GFP_KERNEL); | ||
| 320 | if (xclk->lookup == NULL) | ||
| 321 | return -ENOMEM; | ||
| 322 | |||
| 323 | xclk->lookup->con_id = pdata->xclks[i].con_id; | ||
| 324 | xclk->lookup->dev_id = pdata->xclks[i].dev_id; | ||
| 325 | xclk->lookup->clk = xclk->clk; | ||
| 326 | |||
| 327 | clkdev_add(xclk->lookup); | ||
| 328 | } | 337 | } |
| 329 | 338 | ||
| 339 | if (np) | ||
| 340 | of_clk_add_provider(np, isp_xclk_src_get, isp); | ||
| 341 | |||
| 330 | return 0; | 342 | return 0; |
| 331 | } | 343 | } |
| 332 | 344 | ||
| 333 | static void isp_xclk_cleanup(struct isp_device *isp) | 345 | static void isp_xclk_cleanup(struct isp_device *isp) |
| 334 | { | 346 | { |
| 347 | struct device_node *np = isp->dev->of_node; | ||
| 335 | unsigned int i; | 348 | unsigned int i; |
| 336 | 349 | ||
| 350 | if (np) | ||
| 351 | of_clk_del_provider(np); | ||
| 352 | |||
| 337 | for (i = 0; i < ARRAY_SIZE(isp->xclks); ++i) { | 353 | for (i = 0; i < ARRAY_SIZE(isp->xclks); ++i) { |
| 338 | struct isp_xclk *xclk = &isp->xclks[i]; | 354 | struct isp_xclk *xclk = &isp->xclks[i]; |
| 339 | 355 | ||
| 340 | if (!IS_ERR(xclk->clk)) | 356 | if (!IS_ERR(xclk->clk)) |
| 341 | clk_unregister(xclk->clk); | 357 | clk_unregister(xclk->clk); |
| 342 | |||
| 343 | if (xclk->lookup) | ||
| 344 | clkdev_drop(xclk->lookup); | ||
| 345 | } | 358 | } |
| 346 | } | 359 | } |
| 347 | 360 | ||
| @@ -422,7 +435,7 @@ static void isp_core_init(struct isp_device *isp, int idle) | |||
| 422 | */ | 435 | */ |
| 423 | void omap3isp_configure_bridge(struct isp_device *isp, | 436 | void omap3isp_configure_bridge(struct isp_device *isp, |
| 424 | enum ccdc_input_entity input, | 437 | enum ccdc_input_entity input, |
| 425 | const struct isp_parallel_platform_data *pdata, | 438 | const struct isp_parallel_cfg *parcfg, |
| 426 | unsigned int shift, unsigned int bridge) | 439 | unsigned int shift, unsigned int bridge) |
| 427 | { | 440 | { |
| 428 | u32 ispctrl_val; | 441 | u32 ispctrl_val; |
| @@ -437,8 +450,8 @@ void omap3isp_configure_bridge(struct isp_device *isp, | |||
| 437 | switch (input) { | 450 | switch (input) { |
| 438 | case CCDC_INPUT_PARALLEL: | 451 | case CCDC_INPUT_PARALLEL: |
| 439 | ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_PARALLEL; | 452 | ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_PARALLEL; |
| 440 | ispctrl_val |= pdata->clk_pol << ISPCTRL_PAR_CLK_POL_SHIFT; | 453 | ispctrl_val |= parcfg->clk_pol << ISPCTRL_PAR_CLK_POL_SHIFT; |
| 441 | shift += pdata->data_lane_shift * 2; | 454 | shift += parcfg->data_lane_shift * 2; |
| 442 | break; | 455 | break; |
| 443 | 456 | ||
| 444 | case CCDC_INPUT_CSI2A: | 457 | case CCDC_INPUT_CSI2A: |
| @@ -1784,58 +1797,121 @@ static void isp_unregister_entities(struct isp_device *isp) | |||
| 1784 | } | 1797 | } |
| 1785 | 1798 | ||
| 1786 | /* | 1799 | /* |
| 1787 | * isp_register_subdev_group - Register a group of subdevices | 1800 | * isp_register_subdev - Register a sub-device |
| 1788 | * @isp: OMAP3 ISP device | 1801 | * @isp: OMAP3 ISP device |
| 1789 | * @board_info: I2C subdevs board information array | 1802 | * @isp_subdev: platform data related to a sub-device |
| 1790 | * | 1803 | * |
| 1791 | * Register all I2C subdevices in the board_info array. The array must be | 1804 | * Register an I2C sub-device which has not been registered by other |
| 1792 | * terminated by a NULL entry, and the first entry must be the sensor. | 1805 | * means (such as the Device Tree). |
| 1793 | * | 1806 | * |
| 1794 | * Return a pointer to the sensor media entity if it has been successfully | 1807 | * Return a pointer to the sub-device if it has been successfully |
| 1795 | * registered, or NULL otherwise. | 1808 | * registered, or NULL otherwise. |
| 1796 | */ | 1809 | */ |
| 1797 | static struct v4l2_subdev * | 1810 | static struct v4l2_subdev * |
| 1798 | isp_register_subdev_group(struct isp_device *isp, | 1811 | isp_register_subdev(struct isp_device *isp, |
| 1799 | struct isp_subdev_i2c_board_info *board_info) | 1812 | struct isp_platform_subdev *isp_subdev) |
| 1800 | { | 1813 | { |
| 1801 | struct v4l2_subdev *sensor = NULL; | 1814 | struct i2c_adapter *adapter; |
| 1802 | unsigned int first; | 1815 | struct v4l2_subdev *sd; |
| 1803 | 1816 | ||
| 1804 | if (board_info->board_info == NULL) | 1817 | if (isp_subdev->board_info == NULL) |
| 1805 | return NULL; | 1818 | return NULL; |
| 1806 | 1819 | ||
| 1807 | for (first = 1; board_info->board_info; ++board_info, first = 0) { | 1820 | adapter = i2c_get_adapter(isp_subdev->i2c_adapter_id); |
| 1808 | struct v4l2_subdev *subdev; | 1821 | if (adapter == NULL) { |
| 1809 | struct i2c_adapter *adapter; | 1822 | dev_err(isp->dev, |
| 1823 | "%s: Unable to get I2C adapter %d for device %s\n", | ||
| 1824 | __func__, isp_subdev->i2c_adapter_id, | ||
| 1825 | isp_subdev->board_info->type); | ||
| 1826 | return NULL; | ||
| 1827 | } | ||
| 1810 | 1828 | ||
| 1811 | adapter = i2c_get_adapter(board_info->i2c_adapter_id); | 1829 | sd = v4l2_i2c_new_subdev_board(&isp->v4l2_dev, adapter, |
| 1812 | if (adapter == NULL) { | 1830 | isp_subdev->board_info, NULL); |
| 1813 | dev_err(isp->dev, "%s: Unable to get I2C adapter %d for " | 1831 | if (sd == NULL) { |
| 1814 | "device %s\n", __func__, | 1832 | dev_err(isp->dev, "%s: Unable to register subdev %s\n", |
| 1815 | board_info->i2c_adapter_id, | 1833 | __func__, isp_subdev->board_info->type); |
| 1816 | board_info->board_info->type); | 1834 | return NULL; |
| 1817 | continue; | 1835 | } |
| 1818 | } | ||
| 1819 | 1836 | ||
| 1820 | subdev = v4l2_i2c_new_subdev_board(&isp->v4l2_dev, adapter, | 1837 | return sd; |
| 1821 | board_info->board_info, NULL); | 1838 | } |
| 1822 | if (subdev == NULL) { | 1839 | |
| 1823 | dev_err(isp->dev, "%s: Unable to register subdev %s\n", | 1840 | static int isp_link_entity( |
| 1824 | __func__, board_info->board_info->type); | 1841 | struct isp_device *isp, struct media_entity *entity, |
| 1825 | continue; | 1842 | enum isp_interface_type interface) |
| 1826 | } | 1843 | { |
| 1844 | struct media_entity *input; | ||
| 1845 | unsigned int flags; | ||
| 1846 | unsigned int pad; | ||
| 1847 | unsigned int i; | ||
| 1848 | |||
| 1849 | /* Connect the sensor to the correct interface module. | ||
| 1850 | * Parallel sensors are connected directly to the CCDC, while | ||
| 1851 | * serial sensors are connected to the CSI2a, CCP2b or CSI2c | ||
| 1852 | * receiver through CSIPHY1 or CSIPHY2. | ||
| 1853 | */ | ||
| 1854 | switch (interface) { | ||
| 1855 | case ISP_INTERFACE_PARALLEL: | ||
| 1856 | input = &isp->isp_ccdc.subdev.entity; | ||
| 1857 | pad = CCDC_PAD_SINK; | ||
| 1858 | flags = 0; | ||
| 1859 | break; | ||
| 1860 | |||
| 1861 | case ISP_INTERFACE_CSI2A_PHY2: | ||
| 1862 | input = &isp->isp_csi2a.subdev.entity; | ||
| 1863 | pad = CSI2_PAD_SINK; | ||
| 1864 | flags = MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED; | ||
| 1865 | break; | ||
| 1866 | |||
| 1867 | case ISP_INTERFACE_CCP2B_PHY1: | ||
| 1868 | case ISP_INTERFACE_CCP2B_PHY2: | ||
| 1869 | input = &isp->isp_ccp2.subdev.entity; | ||
| 1870 | pad = CCP2_PAD_SINK; | ||
| 1871 | flags = 0; | ||
| 1872 | break; | ||
| 1873 | |||
| 1874 | case ISP_INTERFACE_CSI2C_PHY1: | ||
| 1875 | input = &isp->isp_csi2c.subdev.entity; | ||
| 1876 | pad = CSI2_PAD_SINK; | ||
| 1877 | flags = MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED; | ||
| 1878 | break; | ||
| 1827 | 1879 | ||
| 1828 | if (first) | 1880 | default: |
| 1829 | sensor = subdev; | 1881 | dev_err(isp->dev, "%s: invalid interface type %u\n", __func__, |
| 1882 | interface); | ||
| 1883 | return -EINVAL; | ||
| 1884 | } | ||
| 1885 | |||
| 1886 | /* | ||
| 1887 | * Not all interfaces are available on all revisions of the | ||
| 1888 | * ISP. The sub-devices of those interfaces aren't initialised | ||
| 1889 | * in such a case. Check this by ensuring the num_pads is | ||
| 1890 | * non-zero. | ||
| 1891 | */ | ||
| 1892 | if (!input->num_pads) { | ||
| 1893 | dev_err(isp->dev, "%s: invalid input %u\n", entity->name, | ||
| 1894 | interface); | ||
| 1895 | return -EINVAL; | ||
| 1896 | } | ||
| 1897 | |||
| 1898 | for (i = 0; i < entity->num_pads; i++) { | ||
| 1899 | if (entity->pads[i].flags & MEDIA_PAD_FL_SOURCE) | ||
| 1900 | break; | ||
| 1901 | } | ||
| 1902 | if (i == entity->num_pads) { | ||
| 1903 | dev_err(isp->dev, "%s: no source pad in external entity\n", | ||
| 1904 | __func__); | ||
| 1905 | return -EINVAL; | ||
| 1830 | } | 1906 | } |
| 1831 | 1907 | ||
| 1832 | return sensor; | 1908 | return media_entity_create_link(entity, i, input, pad, flags); |
| 1833 | } | 1909 | } |
| 1834 | 1910 | ||
| 1835 | static int isp_register_entities(struct isp_device *isp) | 1911 | static int isp_register_entities(struct isp_device *isp) |
| 1836 | { | 1912 | { |
| 1837 | struct isp_platform_data *pdata = isp->pdata; | 1913 | struct isp_platform_data *pdata = isp->pdata; |
| 1838 | struct isp_v4l2_subdevs_group *subdevs; | 1914 | struct isp_platform_subdev *isp_subdev; |
| 1839 | int ret; | 1915 | int ret; |
| 1840 | 1916 | ||
| 1841 | isp->media_dev.dev = isp->dev; | 1917 | isp->media_dev.dev = isp->dev; |
| @@ -1892,74 +1968,31 @@ static int isp_register_entities(struct isp_device *isp) | |||
| 1892 | if (ret < 0) | 1968 | if (ret < 0) |
| 1893 | goto done; | 1969 | goto done; |
| 1894 | 1970 | ||
| 1971 | /* | ||
| 1972 | * Device Tree --- the external sub-devices will be registered | ||
| 1973 | * later. The same goes for the sub-device node registration. | ||
| 1974 | */ | ||
| 1975 | if (isp->dev->of_node) | ||
| 1976 | return 0; | ||
| 1977 | |||
| 1895 | /* Register external entities */ | 1978 | /* Register external entities */ |
| 1896 | for (subdevs = pdata->subdevs; subdevs && subdevs->subdevs; ++subdevs) { | 1979 | for (isp_subdev = pdata ? pdata->subdevs : NULL; |
| 1897 | struct v4l2_subdev *sensor; | 1980 | isp_subdev && isp_subdev->board_info; isp_subdev++) { |
| 1898 | struct media_entity *input; | 1981 | struct v4l2_subdev *sd; |
| 1899 | unsigned int flags; | ||
| 1900 | unsigned int pad; | ||
| 1901 | unsigned int i; | ||
| 1902 | |||
| 1903 | sensor = isp_register_subdev_group(isp, subdevs->subdevs); | ||
| 1904 | if (sensor == NULL) | ||
| 1905 | continue; | ||
| 1906 | 1982 | ||
| 1907 | sensor->host_priv = subdevs; | 1983 | sd = isp_register_subdev(isp, isp_subdev); |
| 1908 | 1984 | ||
| 1909 | /* Connect the sensor to the correct interface module. Parallel | 1985 | /* |
| 1910 | * sensors are connected directly to the CCDC, while serial | 1986 | * No bus information --- this is either a flash or a |
| 1911 | * sensors are connected to the CSI2a, CCP2b or CSI2c receiver | 1987 | * lens subdev. |
| 1912 | * through CSIPHY1 or CSIPHY2. | ||
| 1913 | */ | 1988 | */ |
| 1914 | switch (subdevs->interface) { | 1989 | if (!sd || !isp_subdev->bus) |
| 1915 | case ISP_INTERFACE_PARALLEL: | 1990 | continue; |
| 1916 | input = &isp->isp_ccdc.subdev.entity; | ||
| 1917 | pad = CCDC_PAD_SINK; | ||
| 1918 | flags = 0; | ||
| 1919 | break; | ||
| 1920 | |||
| 1921 | case ISP_INTERFACE_CSI2A_PHY2: | ||
| 1922 | input = &isp->isp_csi2a.subdev.entity; | ||
| 1923 | pad = CSI2_PAD_SINK; | ||
| 1924 | flags = MEDIA_LNK_FL_IMMUTABLE | ||
| 1925 | | MEDIA_LNK_FL_ENABLED; | ||
| 1926 | break; | ||
| 1927 | |||
| 1928 | case ISP_INTERFACE_CCP2B_PHY1: | ||
| 1929 | case ISP_INTERFACE_CCP2B_PHY2: | ||
| 1930 | input = &isp->isp_ccp2.subdev.entity; | ||
| 1931 | pad = CCP2_PAD_SINK; | ||
| 1932 | flags = 0; | ||
| 1933 | break; | ||
| 1934 | |||
| 1935 | case ISP_INTERFACE_CSI2C_PHY1: | ||
| 1936 | input = &isp->isp_csi2c.subdev.entity; | ||
| 1937 | pad = CSI2_PAD_SINK; | ||
| 1938 | flags = MEDIA_LNK_FL_IMMUTABLE | ||
| 1939 | | MEDIA_LNK_FL_ENABLED; | ||
| 1940 | break; | ||
| 1941 | |||
| 1942 | default: | ||
| 1943 | dev_err(isp->dev, "%s: invalid interface type %u\n", | ||
| 1944 | __func__, subdevs->interface); | ||
| 1945 | ret = -EINVAL; | ||
| 1946 | goto done; | ||
| 1947 | } | ||
| 1948 | 1991 | ||
| 1949 | for (i = 0; i < sensor->entity.num_pads; i++) { | 1992 | sd->host_priv = isp_subdev->bus; |
| 1950 | if (sensor->entity.pads[i].flags & MEDIA_PAD_FL_SOURCE) | ||
| 1951 | break; | ||
| 1952 | } | ||
| 1953 | if (i == sensor->entity.num_pads) { | ||
| 1954 | dev_err(isp->dev, | ||
| 1955 | "%s: no source pad in external entity\n", | ||
| 1956 | __func__); | ||
| 1957 | ret = -EINVAL; | ||
| 1958 | goto done; | ||
| 1959 | } | ||
| 1960 | 1993 | ||
| 1961 | ret = media_entity_create_link(&sensor->entity, i, input, pad, | 1994 | ret = isp_link_entity(isp, &sd->entity, |
| 1962 | flags); | 1995 | isp_subdev->bus->interface); |
| 1963 | if (ret < 0) | 1996 | if (ret < 0) |
| 1964 | goto done; | 1997 | goto done; |
| 1965 | } | 1998 | } |
| @@ -1967,8 +2000,10 @@ static int isp_register_entities(struct isp_device *isp) | |||
| 1967 | ret = v4l2_device_register_subdev_nodes(&isp->v4l2_dev); | 2000 | ret = v4l2_device_register_subdev_nodes(&isp->v4l2_dev); |
| 1968 | 2001 | ||
| 1969 | done: | 2002 | done: |
| 1970 | if (ret < 0) | 2003 | if (ret < 0) { |
| 1971 | isp_unregister_entities(isp); | 2004 | isp_unregister_entities(isp); |
| 2005 | v4l2_async_notifier_unregister(&isp->notifier); | ||
| 2006 | } | ||
| 1972 | 2007 | ||
| 1973 | return ret; | 2008 | return ret; |
| 1974 | } | 2009 | } |
| @@ -2183,6 +2218,7 @@ static int isp_remove(struct platform_device *pdev) | |||
| 2183 | { | 2218 | { |
| 2184 | struct isp_device *isp = platform_get_drvdata(pdev); | 2219 | struct isp_device *isp = platform_get_drvdata(pdev); |
| 2185 | 2220 | ||
| 2221 | v4l2_async_notifier_unregister(&isp->notifier); | ||
| 2186 | isp_unregister_entities(isp); | 2222 | isp_unregister_entities(isp); |
| 2187 | isp_cleanup_modules(isp); | 2223 | isp_cleanup_modules(isp); |
| 2188 | isp_xclk_cleanup(isp); | 2224 | isp_xclk_cleanup(isp); |
| @@ -2194,26 +2230,156 @@ static int isp_remove(struct platform_device *pdev) | |||
| 2194 | return 0; | 2230 | return 0; |
| 2195 | } | 2231 | } |
| 2196 | 2232 | ||
| 2197 | static int isp_map_mem_resource(struct platform_device *pdev, | 2233 | enum isp_of_phy { |
| 2198 | struct isp_device *isp, | 2234 | ISP_OF_PHY_PARALLEL = 0, |
| 2199 | enum isp_mem_resources res) | 2235 | ISP_OF_PHY_CSIPHY1, |
| 2236 | ISP_OF_PHY_CSIPHY2, | ||
| 2237 | }; | ||
| 2238 | |||
| 2239 | static int isp_of_parse_node(struct device *dev, struct device_node *node, | ||
| 2240 | struct isp_async_subdev *isd) | ||
| 2200 | { | 2241 | { |
| 2201 | struct resource *mem; | 2242 | struct isp_bus_cfg *buscfg = &isd->bus; |
| 2243 | struct v4l2_of_endpoint vep; | ||
| 2244 | unsigned int i; | ||
| 2202 | 2245 | ||
| 2203 | /* request the mem region for the camera registers */ | 2246 | v4l2_of_parse_endpoint(node, &vep); |
| 2247 | |||
| 2248 | dev_dbg(dev, "parsing endpoint %s, interface %u\n", node->full_name, | ||
| 2249 | vep.base.port); | ||
| 2250 | |||
| 2251 | switch (vep.base.port) { | ||
| 2252 | case ISP_OF_PHY_PARALLEL: | ||
| 2253 | buscfg->interface = ISP_INTERFACE_PARALLEL; | ||
| 2254 | buscfg->bus.parallel.data_lane_shift = | ||
| 2255 | vep.bus.parallel.data_shift; | ||
| 2256 | buscfg->bus.parallel.clk_pol = | ||
| 2257 | !!(vep.bus.parallel.flags | ||
| 2258 | & V4L2_MBUS_PCLK_SAMPLE_FALLING); | ||
| 2259 | buscfg->bus.parallel.hs_pol = | ||
| 2260 | !!(vep.bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW); | ||
| 2261 | buscfg->bus.parallel.vs_pol = | ||
| 2262 | !!(vep.bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW); | ||
| 2263 | buscfg->bus.parallel.fld_pol = | ||
| 2264 | !!(vep.bus.parallel.flags & V4L2_MBUS_FIELD_EVEN_LOW); | ||
| 2265 | buscfg->bus.parallel.data_pol = | ||
| 2266 | !!(vep.bus.parallel.flags & V4L2_MBUS_DATA_ACTIVE_LOW); | ||
| 2267 | break; | ||
| 2204 | 2268 | ||
| 2205 | mem = platform_get_resource(pdev, IORESOURCE_MEM, res); | 2269 | case ISP_OF_PHY_CSIPHY1: |
| 2270 | case ISP_OF_PHY_CSIPHY2: | ||
| 2271 | /* FIXME: always assume CSI-2 for now. */ | ||
| 2272 | switch (vep.base.port) { | ||
| 2273 | case ISP_OF_PHY_CSIPHY1: | ||
| 2274 | buscfg->interface = ISP_INTERFACE_CSI2C_PHY1; | ||
| 2275 | break; | ||
| 2276 | case ISP_OF_PHY_CSIPHY2: | ||
| 2277 | buscfg->interface = ISP_INTERFACE_CSI2A_PHY2; | ||
| 2278 | break; | ||
| 2279 | } | ||
| 2280 | buscfg->bus.csi2.lanecfg.clk.pos = vep.bus.mipi_csi2.clock_lane; | ||
| 2281 | buscfg->bus.csi2.lanecfg.clk.pol = | ||
| 2282 | vep.bus.mipi_csi2.lane_polarities[0]; | ||
| 2283 | dev_dbg(dev, "clock lane polarity %u, pos %u\n", | ||
| 2284 | buscfg->bus.csi2.lanecfg.clk.pol, | ||
| 2285 | buscfg->bus.csi2.lanecfg.clk.pos); | ||
| 2286 | |||
| 2287 | for (i = 0; i < ISP_CSIPHY2_NUM_DATA_LANES; i++) { | ||
| 2288 | buscfg->bus.csi2.lanecfg.data[i].pos = | ||
| 2289 | vep.bus.mipi_csi2.data_lanes[i]; | ||
| 2290 | buscfg->bus.csi2.lanecfg.data[i].pol = | ||
| 2291 | vep.bus.mipi_csi2.lane_polarities[i + 1]; | ||
| 2292 | dev_dbg(dev, "data lane %u polarity %u, pos %u\n", i, | ||
| 2293 | buscfg->bus.csi2.lanecfg.data[i].pol, | ||
| 2294 | buscfg->bus.csi2.lanecfg.data[i].pos); | ||
| 2295 | } | ||
| 2206 | 2296 | ||
| 2207 | /* map the region */ | 2297 | /* |
| 2208 | isp->mmio_base[res] = devm_ioremap_resource(isp->dev, mem); | 2298 | * FIXME: now we assume the CRC is always there. |
| 2209 | if (IS_ERR(isp->mmio_base[res])) | 2299 | * Implement a way to obtain this information from the |
| 2210 | return PTR_ERR(isp->mmio_base[res]); | 2300 | * sensor. Frame descriptors, perhaps? |
| 2301 | */ | ||
| 2302 | buscfg->bus.csi2.crc = 1; | ||
| 2303 | break; | ||
| 2211 | 2304 | ||
| 2212 | isp->mmio_base_phys[res] = mem->start; | 2305 | default: |
| 2306 | dev_warn(dev, "%s: invalid interface %u\n", node->full_name, | ||
| 2307 | vep.base.port); | ||
| 2308 | break; | ||
| 2309 | } | ||
| 2213 | 2310 | ||
| 2214 | return 0; | 2311 | return 0; |
| 2215 | } | 2312 | } |
| 2216 | 2313 | ||
| 2314 | static int isp_of_parse_nodes(struct device *dev, | ||
| 2315 | struct v4l2_async_notifier *notifier) | ||
| 2316 | { | ||
| 2317 | struct device_node *node = NULL; | ||
| 2318 | |||
| 2319 | notifier->subdevs = devm_kcalloc( | ||
| 2320 | dev, ISP_MAX_SUBDEVS, sizeof(*notifier->subdevs), GFP_KERNEL); | ||
| 2321 | if (!notifier->subdevs) | ||
| 2322 | return -ENOMEM; | ||
| 2323 | |||
| 2324 | while (notifier->num_subdevs < ISP_MAX_SUBDEVS && | ||
| 2325 | (node = of_graph_get_next_endpoint(dev->of_node, node))) { | ||
| 2326 | struct isp_async_subdev *isd; | ||
| 2327 | |||
| 2328 | isd = devm_kzalloc(dev, sizeof(*isd), GFP_KERNEL); | ||
| 2329 | if (!isd) { | ||
| 2330 | of_node_put(node); | ||
| 2331 | return -ENOMEM; | ||
| 2332 | } | ||
| 2333 | |||
| 2334 | notifier->subdevs[notifier->num_subdevs] = &isd->asd; | ||
| 2335 | |||
| 2336 | if (isp_of_parse_node(dev, node, isd)) { | ||
| 2337 | of_node_put(node); | ||
| 2338 | return -EINVAL; | ||
| 2339 | } | ||
| 2340 | |||
| 2341 | isd->asd.match.of.node = of_graph_get_remote_port_parent(node); | ||
| 2342 | of_node_put(node); | ||
| 2343 | if (!isd->asd.match.of.node) { | ||
| 2344 | dev_warn(dev, "bad remote port parent\n"); | ||
| 2345 | return -EINVAL; | ||
| 2346 | } | ||
| 2347 | |||
| 2348 | isd->asd.match_type = V4L2_ASYNC_MATCH_OF; | ||
| 2349 | notifier->num_subdevs++; | ||
| 2350 | } | ||
| 2351 | |||
| 2352 | return notifier->num_subdevs; | ||
| 2353 | } | ||
| 2354 | |||
| 2355 | static int isp_subdev_notifier_bound(struct v4l2_async_notifier *async, | ||
| 2356 | struct v4l2_subdev *subdev, | ||
| 2357 | struct v4l2_async_subdev *asd) | ||
| 2358 | { | ||
| 2359 | struct isp_device *isp = container_of(async, struct isp_device, | ||
| 2360 | notifier); | ||
| 2361 | struct isp_async_subdev *isd = | ||
| 2362 | container_of(asd, struct isp_async_subdev, asd); | ||
| 2363 | int ret; | ||
| 2364 | |||
| 2365 | ret = isp_link_entity(isp, &subdev->entity, isd->bus.interface); | ||
| 2366 | if (ret < 0) | ||
| 2367 | return ret; | ||
| 2368 | |||
| 2369 | isd->sd = subdev; | ||
| 2370 | isd->sd->host_priv = &isd->bus; | ||
| 2371 | |||
| 2372 | return ret; | ||
| 2373 | } | ||
| 2374 | |||
| 2375 | static int isp_subdev_notifier_complete(struct v4l2_async_notifier *async) | ||
| 2376 | { | ||
| 2377 | struct isp_device *isp = container_of(async, struct isp_device, | ||
| 2378 | notifier); | ||
| 2379 | |||
| 2380 | return v4l2_device_register_subdev_nodes(&isp->v4l2_dev); | ||
| 2381 | } | ||
| 2382 | |||
| 2217 | /* | 2383 | /* |
| 2218 | * isp_probe - Probe ISP platform device | 2384 | * isp_probe - Probe ISP platform device |
| 2219 | * @pdev: Pointer to ISP platform device | 2385 | * @pdev: Pointer to ISP platform device |
| @@ -2227,47 +2393,86 @@ static int isp_map_mem_resource(struct platform_device *pdev, | |||
| 2227 | */ | 2393 | */ |
| 2228 | static int isp_probe(struct platform_device *pdev) | 2394 | static int isp_probe(struct platform_device *pdev) |
| 2229 | { | 2395 | { |
| 2230 | struct isp_platform_data *pdata = pdev->dev.platform_data; | ||
| 2231 | struct isp_device *isp; | 2396 | struct isp_device *isp; |
| 2397 | struct resource *mem; | ||
| 2232 | int ret; | 2398 | int ret; |
| 2233 | int i, m; | 2399 | int i, m; |
| 2234 | 2400 | ||
| 2235 | if (pdata == NULL) | ||
| 2236 | return -EINVAL; | ||
| 2237 | |||
| 2238 | isp = devm_kzalloc(&pdev->dev, sizeof(*isp), GFP_KERNEL); | 2401 | isp = devm_kzalloc(&pdev->dev, sizeof(*isp), GFP_KERNEL); |
| 2239 | if (!isp) { | 2402 | if (!isp) { |
| 2240 | dev_err(&pdev->dev, "could not allocate memory\n"); | 2403 | dev_err(&pdev->dev, "could not allocate memory\n"); |
| 2241 | return -ENOMEM; | 2404 | return -ENOMEM; |
| 2242 | } | 2405 | } |
| 2243 | 2406 | ||
| 2407 | if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) { | ||
| 2408 | ret = of_property_read_u32(pdev->dev.of_node, "ti,phy-type", | ||
| 2409 | &isp->phy_type); | ||
| 2410 | if (ret) | ||
| 2411 | return ret; | ||
| 2412 | |||
| 2413 | isp->syscon = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, | ||
| 2414 | "syscon"); | ||
| 2415 | if (IS_ERR(isp->syscon)) | ||
| 2416 | return PTR_ERR(isp->syscon); | ||
| 2417 | |||
| 2418 | ret = of_property_read_u32_index(pdev->dev.of_node, "syscon", 1, | ||
| 2419 | &isp->syscon_offset); | ||
| 2420 | if (ret) | ||
| 2421 | return ret; | ||
| 2422 | |||
| 2423 | ret = isp_of_parse_nodes(&pdev->dev, &isp->notifier); | ||
| 2424 | if (ret < 0) | ||
| 2425 | return ret; | ||
| 2426 | ret = v4l2_async_notifier_register(&isp->v4l2_dev, | ||
| 2427 | &isp->notifier); | ||
| 2428 | if (ret) | ||
| 2429 | return ret; | ||
| 2430 | } else { | ||
| 2431 | isp->pdata = pdev->dev.platform_data; | ||
| 2432 | isp->syscon = syscon_regmap_lookup_by_pdevname("syscon.0"); | ||
| 2433 | if (IS_ERR(isp->syscon)) | ||
| 2434 | return PTR_ERR(isp->syscon); | ||
| 2435 | dev_warn(&pdev->dev, | ||
| 2436 | "Platform data support is deprecated! Please move to DT now!\n"); | ||
| 2437 | } | ||
| 2438 | |||
| 2244 | isp->autoidle = autoidle; | 2439 | isp->autoidle = autoidle; |
| 2245 | 2440 | ||
| 2246 | mutex_init(&isp->isp_mutex); | 2441 | mutex_init(&isp->isp_mutex); |
| 2247 | spin_lock_init(&isp->stat_lock); | 2442 | spin_lock_init(&isp->stat_lock); |
| 2248 | 2443 | ||
| 2249 | isp->dev = &pdev->dev; | 2444 | isp->dev = &pdev->dev; |
| 2250 | isp->pdata = pdata; | ||
| 2251 | isp->ref_count = 0; | 2445 | isp->ref_count = 0; |
| 2252 | 2446 | ||
| 2253 | ret = dma_coerce_mask_and_coherent(isp->dev, DMA_BIT_MASK(32)); | 2447 | ret = dma_coerce_mask_and_coherent(isp->dev, DMA_BIT_MASK(32)); |
| 2254 | if (ret) | 2448 | if (ret) |
| 2255 | return ret; | 2449 | goto error; |
| 2256 | 2450 | ||
| 2257 | platform_set_drvdata(pdev, isp); | 2451 | platform_set_drvdata(pdev, isp); |
| 2258 | 2452 | ||
| 2259 | /* Regulators */ | 2453 | /* Regulators */ |
| 2260 | isp->isp_csiphy1.vdd = devm_regulator_get(&pdev->dev, "VDD_CSIPHY1"); | 2454 | isp->isp_csiphy1.vdd = devm_regulator_get(&pdev->dev, "vdd-csiphy1"); |
| 2261 | isp->isp_csiphy2.vdd = devm_regulator_get(&pdev->dev, "VDD_CSIPHY2"); | 2455 | isp->isp_csiphy2.vdd = devm_regulator_get(&pdev->dev, "vdd-csiphy2"); |
| 2262 | 2456 | ||
| 2263 | /* Clocks | 2457 | /* Clocks |
| 2264 | * | 2458 | * |
| 2265 | * The ISP clock tree is revision-dependent. We thus need to enable ICLK | 2459 | * The ISP clock tree is revision-dependent. We thus need to enable ICLK |
| 2266 | * manually to read the revision before calling __omap3isp_get(). | 2460 | * manually to read the revision before calling __omap3isp_get(). |
| 2461 | * | ||
| 2462 | * Start by mapping the ISP MMIO area, which is in two pieces. | ||
| 2463 | * The ISP IOMMU is in between. Map both now, and fill in the | ||
| 2464 | * ISP revision specific portions a little later in the | ||
| 2465 | * function. | ||
| 2267 | */ | 2466 | */ |
| 2268 | ret = isp_map_mem_resource(pdev, isp, OMAP3_ISP_IOMEM_MAIN); | 2467 | for (i = 0; i < 2; i++) { |
| 2269 | if (ret < 0) | 2468 | unsigned int map_idx = i ? OMAP3_ISP_IOMEM_CSI2A_REGS1 : 0; |
| 2270 | goto error; | 2469 | |
| 2470 | mem = platform_get_resource(pdev, IORESOURCE_MEM, i); | ||
| 2471 | isp->mmio_base[map_idx] = | ||
| 2472 | devm_ioremap_resource(isp->dev, mem); | ||
| 2473 | if (IS_ERR(isp->mmio_base[map_idx])) | ||
| 2474 | return PTR_ERR(isp->mmio_base[map_idx]); | ||
| 2475 | } | ||
| 2271 | 2476 | ||
| 2272 | ret = isp_get_clocks(isp); | 2477 | ret = isp_get_clocks(isp); |
| 2273 | if (ret < 0) | 2478 | if (ret < 0) |
| @@ -2308,14 +2513,23 @@ static int isp_probe(struct platform_device *pdev) | |||
| 2308 | goto error_isp; | 2513 | goto error_isp; |
| 2309 | } | 2514 | } |
| 2310 | 2515 | ||
| 2311 | for (i = 1; i < OMAP3_ISP_IOMEM_LAST; i++) { | 2516 | if (!IS_ENABLED(CONFIG_OF) || !pdev->dev.of_node) { |
| 2312 | if (isp_res_maps[m].map & 1 << i) { | 2517 | isp->syscon_offset = isp_res_maps[m].syscon_offset; |
| 2313 | ret = isp_map_mem_resource(pdev, isp, i); | 2518 | isp->phy_type = isp_res_maps[m].phy_type; |
| 2314 | if (ret) | ||
| 2315 | goto error_isp; | ||
| 2316 | } | ||
| 2317 | } | 2519 | } |
| 2318 | 2520 | ||
| 2521 | for (i = 1; i < OMAP3_ISP_IOMEM_CSI2A_REGS1; i++) | ||
| 2522 | isp->mmio_base[i] = | ||
| 2523 | isp->mmio_base[0] + isp_res_maps[m].offset[i]; | ||
| 2524 | |||
| 2525 | for (i = OMAP3_ISP_IOMEM_CSIPHY2; i < OMAP3_ISP_IOMEM_LAST; i++) | ||
| 2526 | isp->mmio_base[i] = | ||
| 2527 | isp->mmio_base[OMAP3_ISP_IOMEM_CSI2A_REGS1] | ||
| 2528 | + isp_res_maps[m].offset[i]; | ||
| 2529 | |||
| 2530 | isp->mmio_hist_base_phys = | ||
| 2531 | mem->start + isp_res_maps[m].offset[OMAP3_ISP_IOMEM_HIST]; | ||
| 2532 | |||
| 2319 | /* IOMMU */ | 2533 | /* IOMMU */ |
| 2320 | ret = isp_attach_iommu(isp); | 2534 | ret = isp_attach_iommu(isp); |
| 2321 | if (ret < 0) { | 2535 | if (ret < 0) { |
| @@ -2343,6 +2557,9 @@ static int isp_probe(struct platform_device *pdev) | |||
| 2343 | if (ret < 0) | 2557 | if (ret < 0) |
| 2344 | goto error_iommu; | 2558 | goto error_iommu; |
| 2345 | 2559 | ||
| 2560 | isp->notifier.bound = isp_subdev_notifier_bound; | ||
| 2561 | isp->notifier.complete = isp_subdev_notifier_complete; | ||
| 2562 | |||
| 2346 | ret = isp_register_entities(isp); | 2563 | ret = isp_register_entities(isp); |
| 2347 | if (ret < 0) | 2564 | if (ret < 0) |
| 2348 | goto error_modules; | 2565 | goto error_modules; |
| @@ -2378,6 +2595,11 @@ static struct platform_device_id omap3isp_id_table[] = { | |||
| 2378 | }; | 2595 | }; |
| 2379 | MODULE_DEVICE_TABLE(platform, omap3isp_id_table); | 2596 | MODULE_DEVICE_TABLE(platform, omap3isp_id_table); |
| 2380 | 2597 | ||
| 2598 | static const struct of_device_id omap3isp_of_table[] = { | ||
| 2599 | { .compatible = "ti,omap3-isp" }, | ||
| 2600 | { }, | ||
| 2601 | }; | ||
| 2602 | |||
| 2381 | static struct platform_driver omap3isp_driver = { | 2603 | static struct platform_driver omap3isp_driver = { |
| 2382 | .probe = isp_probe, | 2604 | .probe = isp_probe, |
| 2383 | .remove = isp_remove, | 2605 | .remove = isp_remove, |
| @@ -2385,6 +2607,7 @@ static struct platform_driver omap3isp_driver = { | |||
| 2385 | .driver = { | 2607 | .driver = { |
| 2386 | .name = "omap3isp", | 2608 | .name = "omap3isp", |
| 2387 | .pm = &omap3isp_pm_ops, | 2609 | .pm = &omap3isp_pm_ops, |
| 2610 | .of_match_table = omap3isp_of_table, | ||
| 2388 | }, | 2611 | }, |
| 2389 | }; | 2612 | }; |
| 2390 | 2613 | ||
diff --git a/drivers/media/platform/omap3isp/isp.h b/drivers/media/platform/omap3isp/isp.h index cfdfc8714b6b..e579943175c4 100644 --- a/drivers/media/platform/omap3isp/isp.h +++ b/drivers/media/platform/omap3isp/isp.h | |||
| @@ -18,6 +18,7 @@ | |||
| 18 | #define OMAP3_ISP_CORE_H | 18 | #define OMAP3_ISP_CORE_H |
| 19 | 19 | ||
| 20 | #include <media/omap3isp.h> | 20 | #include <media/omap3isp.h> |
| 21 | #include <media/v4l2-async.h> | ||
| 21 | #include <media/v4l2-device.h> | 22 | #include <media/v4l2-device.h> |
| 22 | #include <linux/clk-provider.h> | 23 | #include <linux/clk-provider.h> |
| 23 | #include <linux/device.h> | 24 | #include <linux/device.h> |
| @@ -59,8 +60,6 @@ enum isp_mem_resources { | |||
| 59 | OMAP3_ISP_IOMEM_CSI2C_REGS1, | 60 | OMAP3_ISP_IOMEM_CSI2C_REGS1, |
| 60 | OMAP3_ISP_IOMEM_CSIPHY1, | 61 | OMAP3_ISP_IOMEM_CSIPHY1, |
| 61 | OMAP3_ISP_IOMEM_CSI2C_REGS2, | 62 | OMAP3_ISP_IOMEM_CSI2C_REGS2, |
| 62 | OMAP3_ISP_IOMEM_343X_CONTROL_CSIRXFE, | ||
| 63 | OMAP3_ISP_IOMEM_3630_CONTROL_CAMERA_PHY_CTRL, | ||
| 64 | OMAP3_ISP_IOMEM_LAST | 63 | OMAP3_ISP_IOMEM_LAST |
| 65 | }; | 64 | }; |
| 66 | 65 | ||
| @@ -93,14 +92,25 @@ enum isp_subclk_resource { | |||
| 93 | /* ISP2P: OMAP 36xx */ | 92 | /* ISP2P: OMAP 36xx */ |
| 94 | #define ISP_REVISION_15_0 0xF0 | 93 | #define ISP_REVISION_15_0 0xF0 |
| 95 | 94 | ||
| 95 | #define ISP_PHY_TYPE_3430 0 | ||
| 96 | #define ISP_PHY_TYPE_3630 1 | ||
| 97 | |||
| 98 | struct regmap; | ||
| 99 | |||
| 96 | /* | 100 | /* |
| 97 | * struct isp_res_mapping - Map ISP io resources to ISP revision. | 101 | * struct isp_res_mapping - Map ISP io resources to ISP revision. |
| 98 | * @isp_rev: ISP_REVISION_x_x | 102 | * @isp_rev: ISP_REVISION_x_x |
| 99 | * @map: bitmap for enum isp_mem_resources | 103 | * @offset: register offsets of various ISP sub-blocks |
| 104 | * @syscon_offset: offset of the syscon register for 343x / 3630 | ||
| 105 | * (CONTROL_CSIRXFE / CONTROL_CAMERA_PHY_CTRL, respectively) | ||
| 106 | * from the syscon base address | ||
| 107 | * @phy_type: ISP_PHY_TYPE_{3430,3630} | ||
| 100 | */ | 108 | */ |
| 101 | struct isp_res_mapping { | 109 | struct isp_res_mapping { |
| 102 | u32 isp_rev; | 110 | u32 isp_rev; |
| 103 | u32 map; | 111 | u32 offset[OMAP3_ISP_IOMEM_LAST]; |
| 112 | u32 syscon_offset; | ||
| 113 | u32 phy_type; | ||
| 104 | }; | 114 | }; |
| 105 | 115 | ||
| 106 | /* | 116 | /* |
| @@ -122,7 +132,6 @@ enum isp_xclk_id { | |||
| 122 | struct isp_xclk { | 132 | struct isp_xclk { |
| 123 | struct isp_device *isp; | 133 | struct isp_device *isp; |
| 124 | struct clk_hw hw; | 134 | struct clk_hw hw; |
| 125 | struct clk_lookup *lookup; | ||
| 126 | struct clk *clk; | 135 | struct clk *clk; |
| 127 | enum isp_xclk_id id; | 136 | enum isp_xclk_id id; |
| 128 | 137 | ||
| @@ -138,8 +147,11 @@ struct isp_xclk { | |||
| 138 | * @irq_num: Currently used IRQ number. | 147 | * @irq_num: Currently used IRQ number. |
| 139 | * @mmio_base: Array with kernel base addresses for ioremapped ISP register | 148 | * @mmio_base: Array with kernel base addresses for ioremapped ISP register |
| 140 | * regions. | 149 | * regions. |
| 141 | * @mmio_base_phys: Array with physical L4 bus addresses for ISP register | 150 | * @mmio_hist_base_phys: Physical L4 bus address for ISP hist block register |
| 142 | * regions. | 151 | * region. |
| 152 | * @syscon: Regmap for the syscon register space | ||
| 153 | * @syscon_offset: Offset of the CSIPHY control register in syscon | ||
| 154 | * @phy_type: ISP_PHY_TYPE_{3430,3630} | ||
| 143 | * @mapping: IOMMU mapping | 155 | * @mapping: IOMMU mapping |
| 144 | * @stat_lock: Spinlock for handling statistics | 156 | * @stat_lock: Spinlock for handling statistics |
| 145 | * @isp_mutex: Mutex for serializing requests to ISP. | 157 | * @isp_mutex: Mutex for serializing requests to ISP. |
| @@ -166,6 +178,7 @@ struct isp_xclk { | |||
| 166 | */ | 178 | */ |
| 167 | struct isp_device { | 179 | struct isp_device { |
| 168 | struct v4l2_device v4l2_dev; | 180 | struct v4l2_device v4l2_dev; |
| 181 | struct v4l2_async_notifier notifier; | ||
| 169 | struct media_device media_dev; | 182 | struct media_device media_dev; |
| 170 | struct device *dev; | 183 | struct device *dev; |
| 171 | u32 revision; | 184 | u32 revision; |
| @@ -175,7 +188,10 @@ struct isp_device { | |||
| 175 | unsigned int irq_num; | 188 | unsigned int irq_num; |
| 176 | 189 | ||
| 177 | void __iomem *mmio_base[OMAP3_ISP_IOMEM_LAST]; | 190 | void __iomem *mmio_base[OMAP3_ISP_IOMEM_LAST]; |
| 178 | unsigned long mmio_base_phys[OMAP3_ISP_IOMEM_LAST]; | 191 | unsigned long mmio_hist_base_phys; |
| 192 | struct regmap *syscon; | ||
| 193 | u32 syscon_offset; | ||
| 194 | u32 phy_type; | ||
| 179 | 195 | ||
| 180 | struct dma_iommu_mapping *mapping; | 196 | struct dma_iommu_mapping *mapping; |
| 181 | 197 | ||
| @@ -209,6 +225,15 @@ struct isp_device { | |||
| 209 | 225 | ||
| 210 | unsigned int sbl_resources; | 226 | unsigned int sbl_resources; |
| 211 | unsigned int subclk_resources; | 227 | unsigned int subclk_resources; |
| 228 | |||
| 229 | #define ISP_MAX_SUBDEVS 8 | ||
| 230 | struct v4l2_subdev *subdevs[ISP_MAX_SUBDEVS]; | ||
| 231 | }; | ||
| 232 | |||
| 233 | struct isp_async_subdev { | ||
| 234 | struct v4l2_subdev *sd; | ||
| 235 | struct isp_bus_cfg bus; | ||
| 236 | struct v4l2_async_subdev asd; | ||
| 212 | }; | 237 | }; |
| 213 | 238 | ||
| 214 | #define v4l2_dev_to_isp_device(dev) \ | 239 | #define v4l2_dev_to_isp_device(dev) \ |
| @@ -229,7 +254,7 @@ int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe, | |||
| 229 | void omap3isp_pipeline_cancel_stream(struct isp_pipeline *pipe); | 254 | void omap3isp_pipeline_cancel_stream(struct isp_pipeline *pipe); |
| 230 | void omap3isp_configure_bridge(struct isp_device *isp, | 255 | void omap3isp_configure_bridge(struct isp_device *isp, |
| 231 | enum ccdc_input_entity input, | 256 | enum ccdc_input_entity input, |
| 232 | const struct isp_parallel_platform_data *pdata, | 257 | const struct isp_parallel_cfg *buscfg, |
| 233 | unsigned int shift, unsigned int bridge); | 258 | unsigned int shift, unsigned int bridge); |
| 234 | 259 | ||
| 235 | struct isp_device *omap3isp_get(struct isp_device *isp); | 260 | struct isp_device *omap3isp_get(struct isp_device *isp); |
diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index 587489a072d5..a6a61cce43dd 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c | |||
| @@ -32,7 +32,7 @@ | |||
| 32 | #define CCDC_MIN_HEIGHT 32 | 32 | #define CCDC_MIN_HEIGHT 32 |
| 33 | 33 | ||
| 34 | static struct v4l2_mbus_framefmt * | 34 | static struct v4l2_mbus_framefmt * |
| 35 | __ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, | 35 | __ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_pad_config *cfg, |
| 36 | unsigned int pad, enum v4l2_subdev_format_whence which); | 36 | unsigned int pad, enum v4l2_subdev_format_whence which); |
| 37 | 37 | ||
| 38 | static const unsigned int ccdc_fmts[] = { | 38 | static const unsigned int ccdc_fmts[] = { |
| @@ -958,11 +958,11 @@ void omap3isp_ccdc_max_rate(struct isp_ccdc_device *ccdc, | |||
| 958 | /* | 958 | /* |
| 959 | * ccdc_config_sync_if - Set CCDC sync interface configuration | 959 | * ccdc_config_sync_if - Set CCDC sync interface configuration |
| 960 | * @ccdc: Pointer to ISP CCDC device. | 960 | * @ccdc: Pointer to ISP CCDC device. |
| 961 | * @pdata: Parallel interface platform data (may be NULL) | 961 | * @parcfg: Parallel interface platform data (may be NULL) |
| 962 | * @data_size: Data size | 962 | * @data_size: Data size |
| 963 | */ | 963 | */ |
| 964 | static void ccdc_config_sync_if(struct isp_ccdc_device *ccdc, | 964 | static void ccdc_config_sync_if(struct isp_ccdc_device *ccdc, |
| 965 | struct isp_parallel_platform_data *pdata, | 965 | struct isp_parallel_cfg *parcfg, |
| 966 | unsigned int data_size) | 966 | unsigned int data_size) |
| 967 | { | 967 | { |
| 968 | struct isp_device *isp = to_isp_device(ccdc); | 968 | struct isp_device *isp = to_isp_device(ccdc); |
| @@ -1000,19 +1000,19 @@ static void ccdc_config_sync_if(struct isp_ccdc_device *ccdc, | |||
| 1000 | break; | 1000 | break; |
| 1001 | } | 1001 | } |
| 1002 | 1002 | ||
| 1003 | if (pdata && pdata->data_pol) | 1003 | if (parcfg && parcfg->data_pol) |
| 1004 | syn_mode |= ISPCCDC_SYN_MODE_DATAPOL; | 1004 | syn_mode |= ISPCCDC_SYN_MODE_DATAPOL; |
| 1005 | 1005 | ||
| 1006 | if (pdata && pdata->hs_pol) | 1006 | if (parcfg && parcfg->hs_pol) |
| 1007 | syn_mode |= ISPCCDC_SYN_MODE_HDPOL; | 1007 | syn_mode |= ISPCCDC_SYN_MODE_HDPOL; |
| 1008 | 1008 | ||
| 1009 | /* The polarity of the vertical sync signal output by the BT.656 | 1009 | /* The polarity of the vertical sync signal output by the BT.656 |
| 1010 | * decoder is not documented and seems to be active low. | 1010 | * decoder is not documented and seems to be active low. |
| 1011 | */ | 1011 | */ |
| 1012 | if ((pdata && pdata->vs_pol) || ccdc->bt656) | 1012 | if ((parcfg && parcfg->vs_pol) || ccdc->bt656) |
| 1013 | syn_mode |= ISPCCDC_SYN_MODE_VDPOL; | 1013 | syn_mode |= ISPCCDC_SYN_MODE_VDPOL; |
| 1014 | 1014 | ||
| 1015 | if (pdata && pdata->fld_pol) | 1015 | if (parcfg && parcfg->fld_pol) |
| 1016 | syn_mode |= ISPCCDC_SYN_MODE_FLDPOL; | 1016 | syn_mode |= ISPCCDC_SYN_MODE_FLDPOL; |
| 1017 | 1017 | ||
| 1018 | isp_reg_writel(isp, syn_mode, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE); | 1018 | isp_reg_writel(isp, syn_mode, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE); |
| @@ -1115,7 +1115,7 @@ static const u32 ccdc_sgbrg_pattern = | |||
| 1115 | static void ccdc_configure(struct isp_ccdc_device *ccdc) | 1115 | static void ccdc_configure(struct isp_ccdc_device *ccdc) |
| 1116 | { | 1116 | { |
| 1117 | struct isp_device *isp = to_isp_device(ccdc); | 1117 | struct isp_device *isp = to_isp_device(ccdc); |
| 1118 | struct isp_parallel_platform_data *pdata = NULL; | 1118 | struct isp_parallel_cfg *parcfg = NULL; |
| 1119 | struct v4l2_subdev *sensor; | 1119 | struct v4l2_subdev *sensor; |
| 1120 | struct v4l2_mbus_framefmt *format; | 1120 | struct v4l2_mbus_framefmt *format; |
| 1121 | const struct v4l2_rect *crop; | 1121 | const struct v4l2_rect *crop; |
| @@ -1145,7 +1145,7 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) | |||
| 1145 | if (!ret) | 1145 | if (!ret) |
| 1146 | ccdc->bt656 = cfg.type == V4L2_MBUS_BT656; | 1146 | ccdc->bt656 = cfg.type == V4L2_MBUS_BT656; |
| 1147 | 1147 | ||
| 1148 | pdata = &((struct isp_v4l2_subdevs_group *)sensor->host_priv) | 1148 | parcfg = &((struct isp_bus_cfg *)sensor->host_priv) |
| 1149 | ->bus.parallel; | 1149 | ->bus.parallel; |
| 1150 | } | 1150 | } |
| 1151 | 1151 | ||
| @@ -1175,10 +1175,10 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) | |||
| 1175 | else | 1175 | else |
| 1176 | bridge = ISPCTRL_PAR_BRIDGE_DISABLE; | 1176 | bridge = ISPCTRL_PAR_BRIDGE_DISABLE; |
| 1177 | 1177 | ||
| 1178 | omap3isp_configure_bridge(isp, ccdc->input, pdata, shift, bridge); | 1178 | omap3isp_configure_bridge(isp, ccdc->input, parcfg, shift, bridge); |
| 1179 | 1179 | ||
| 1180 | /* Configure the sync interface. */ | 1180 | /* Configure the sync interface. */ |
| 1181 | ccdc_config_sync_if(ccdc, pdata, depth_out); | 1181 | ccdc_config_sync_if(ccdc, parcfg, depth_out); |
| 1182 | 1182 | ||
| 1183 | syn_mode = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE); | 1183 | syn_mode = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE); |
| 1184 | 1184 | ||
| @@ -1935,21 +1935,21 @@ static int ccdc_set_stream(struct v4l2_subdev *sd, int enable) | |||
| 1935 | } | 1935 | } |
| 1936 | 1936 | ||
| 1937 | static struct v4l2_mbus_framefmt * | 1937 | static struct v4l2_mbus_framefmt * |
| 1938 | __ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, | 1938 | __ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_pad_config *cfg, |
| 1939 | unsigned int pad, enum v4l2_subdev_format_whence which) | 1939 | unsigned int pad, enum v4l2_subdev_format_whence which) |
| 1940 | { | 1940 | { |
| 1941 | if (which == V4L2_SUBDEV_FORMAT_TRY) | 1941 | if (which == V4L2_SUBDEV_FORMAT_TRY) |
| 1942 | return v4l2_subdev_get_try_format(fh, pad); | 1942 | return v4l2_subdev_get_try_format(&ccdc->subdev, cfg, pad); |
| 1943 | else | 1943 | else |
| 1944 | return &ccdc->formats[pad]; | 1944 | return &ccdc->formats[pad]; |
| 1945 | } | 1945 | } |
| 1946 | 1946 | ||
| 1947 | static struct v4l2_rect * | 1947 | static struct v4l2_rect * |
| 1948 | __ccdc_get_crop(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, | 1948 | __ccdc_get_crop(struct isp_ccdc_device *ccdc, struct v4l2_subdev_pad_config *cfg, |
| 1949 | enum v4l2_subdev_format_whence which) | 1949 | enum v4l2_subdev_format_whence which) |
| 1950 | { | 1950 | { |
| 1951 | if (which == V4L2_SUBDEV_FORMAT_TRY) | 1951 | if (which == V4L2_SUBDEV_FORMAT_TRY) |
| 1952 | return v4l2_subdev_get_try_crop(fh, CCDC_PAD_SOURCE_OF); | 1952 | return v4l2_subdev_get_try_crop(&ccdc->subdev, cfg, CCDC_PAD_SOURCE_OF); |
| 1953 | else | 1953 | else |
| 1954 | return &ccdc->crop; | 1954 | return &ccdc->crop; |
| 1955 | } | 1955 | } |
| @@ -1957,12 +1957,12 @@ __ccdc_get_crop(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, | |||
| 1957 | /* | 1957 | /* |
| 1958 | * ccdc_try_format - Try video format on a pad | 1958 | * ccdc_try_format - Try video format on a pad |
| 1959 | * @ccdc: ISP CCDC device | 1959 | * @ccdc: ISP CCDC device |
| 1960 | * @fh : V4L2 subdev file handle | 1960 | * @cfg : V4L2 subdev pad configuration |
| 1961 | * @pad: Pad number | 1961 | * @pad: Pad number |
| 1962 | * @fmt: Format | 1962 | * @fmt: Format |
| 1963 | */ | 1963 | */ |
| 1964 | static void | 1964 | static void |
| 1965 | ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, | 1965 | ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_pad_config *cfg, |
| 1966 | unsigned int pad, struct v4l2_mbus_framefmt *fmt, | 1966 | unsigned int pad, struct v4l2_mbus_framefmt *fmt, |
| 1967 | enum v4l2_subdev_format_whence which) | 1967 | enum v4l2_subdev_format_whence which) |
| 1968 | { | 1968 | { |
| @@ -1998,7 +1998,7 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, | |||
| 1998 | case CCDC_PAD_SOURCE_OF: | 1998 | case CCDC_PAD_SOURCE_OF: |
| 1999 | pixelcode = fmt->code; | 1999 | pixelcode = fmt->code; |
| 2000 | field = fmt->field; | 2000 | field = fmt->field; |
| 2001 | *fmt = *__ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, which); | 2001 | *fmt = *__ccdc_get_format(ccdc, cfg, CCDC_PAD_SINK, which); |
| 2002 | 2002 | ||
| 2003 | /* In SYNC mode the bridge converts YUV formats from 2X8 to | 2003 | /* In SYNC mode the bridge converts YUV formats from 2X8 to |
| 2004 | * 1X16. In BT.656 no such conversion occurs. As we don't know | 2004 | * 1X16. In BT.656 no such conversion occurs. As we don't know |
| @@ -2023,7 +2023,7 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, | |||
| 2023 | } | 2023 | } |
| 2024 | 2024 | ||
| 2025 | /* Hardcode the output size to the crop rectangle size. */ | 2025 | /* Hardcode the output size to the crop rectangle size. */ |
| 2026 | crop = __ccdc_get_crop(ccdc, fh, which); | 2026 | crop = __ccdc_get_crop(ccdc, cfg, which); |
| 2027 | fmt->width = crop->width; | 2027 | fmt->width = crop->width; |
| 2028 | fmt->height = crop->height; | 2028 | fmt->height = crop->height; |
| 2029 | 2029 | ||
| @@ -2040,7 +2040,7 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, | |||
| 2040 | break; | 2040 | break; |
| 2041 | 2041 | ||
| 2042 | case CCDC_PAD_SOURCE_VP: | 2042 | case CCDC_PAD_SOURCE_VP: |
| 2043 | *fmt = *__ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, which); | 2043 | *fmt = *__ccdc_get_format(ccdc, cfg, CCDC_PAD_SINK, which); |
| 2044 | 2044 | ||
| 2045 | /* The video port interface truncates the data to 10 bits. */ | 2045 | /* The video port interface truncates the data to 10 bits. */ |
| 2046 | info = omap3isp_video_format_info(fmt->code); | 2046 | info = omap3isp_video_format_info(fmt->code); |
| @@ -2112,12 +2112,12 @@ static void ccdc_try_crop(struct isp_ccdc_device *ccdc, | |||
| 2112 | /* | 2112 | /* |
| 2113 | * ccdc_enum_mbus_code - Handle pixel format enumeration | 2113 | * ccdc_enum_mbus_code - Handle pixel format enumeration |
| 2114 | * @sd : pointer to v4l2 subdev structure | 2114 | * @sd : pointer to v4l2 subdev structure |
| 2115 | * @fh : V4L2 subdev file handle | 2115 | * @cfg : V4L2 subdev pad configuration |
| 2116 | * @code : pointer to v4l2_subdev_mbus_code_enum structure | 2116 | * @code : pointer to v4l2_subdev_mbus_code_enum structure |
| 2117 | * return -EINVAL or zero on success | 2117 | * return -EINVAL or zero on success |
| 2118 | */ | 2118 | */ |
| 2119 | static int ccdc_enum_mbus_code(struct v4l2_subdev *sd, | 2119 | static int ccdc_enum_mbus_code(struct v4l2_subdev *sd, |
| 2120 | struct v4l2_subdev_fh *fh, | 2120 | struct v4l2_subdev_pad_config *cfg, |
| 2121 | struct v4l2_subdev_mbus_code_enum *code) | 2121 | struct v4l2_subdev_mbus_code_enum *code) |
| 2122 | { | 2122 | { |
| 2123 | struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); | 2123 | struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); |
| @@ -2132,8 +2132,8 @@ static int ccdc_enum_mbus_code(struct v4l2_subdev *sd, | |||
| 2132 | break; | 2132 | break; |
| 2133 | 2133 | ||
| 2134 | case CCDC_PAD_SOURCE_OF: | 2134 | case CCDC_PAD_SOURCE_OF: |
| 2135 | format = __ccdc_get_format(ccdc, fh, code->pad, | 2135 | format = __ccdc_get_format(ccdc, cfg, code->pad, |
| 2136 | V4L2_SUBDEV_FORMAT_TRY); | 2136 | code->which); |
| 2137 | 2137 | ||
| 2138 | if (format->code == MEDIA_BUS_FMT_YUYV8_2X8 || | 2138 | if (format->code == MEDIA_BUS_FMT_YUYV8_2X8 || |
| 2139 | format->code == MEDIA_BUS_FMT_UYVY8_2X8) { | 2139 | format->code == MEDIA_BUS_FMT_UYVY8_2X8) { |
| @@ -2163,8 +2163,8 @@ static int ccdc_enum_mbus_code(struct v4l2_subdev *sd, | |||
| 2163 | if (code->index != 0) | 2163 | if (code->index != 0) |
| 2164 | return -EINVAL; | 2164 | return -EINVAL; |
| 2165 | 2165 | ||
| 2166 | format = __ccdc_get_format(ccdc, fh, code->pad, | 2166 | format = __ccdc_get_format(ccdc, cfg, code->pad, |
| 2167 | V4L2_SUBDEV_FORMAT_TRY); | 2167 | code->which); |
| 2168 | 2168 | ||
| 2169 | /* A pixel code equal to 0 means that the video port doesn't | 2169 | /* A pixel code equal to 0 means that the video port doesn't |
| 2170 | * support the input format. Don't enumerate any pixel code. | 2170 | * support the input format. Don't enumerate any pixel code. |
| @@ -2183,7 +2183,7 @@ static int ccdc_enum_mbus_code(struct v4l2_subdev *sd, | |||
| 2183 | } | 2183 | } |
| 2184 | 2184 | ||
| 2185 | static int ccdc_enum_frame_size(struct v4l2_subdev *sd, | 2185 | static int ccdc_enum_frame_size(struct v4l2_subdev *sd, |
| 2186 | struct v4l2_subdev_fh *fh, | 2186 | struct v4l2_subdev_pad_config *cfg, |
| 2187 | struct v4l2_subdev_frame_size_enum *fse) | 2187 | struct v4l2_subdev_frame_size_enum *fse) |
| 2188 | { | 2188 | { |
| 2189 | struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); | 2189 | struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); |
| @@ -2195,7 +2195,7 @@ static int ccdc_enum_frame_size(struct v4l2_subdev *sd, | |||
| 2195 | format.code = fse->code; | 2195 | format.code = fse->code; |
| 2196 | format.width = 1; | 2196 | format.width = 1; |
| 2197 | format.height = 1; | 2197 | format.height = 1; |
| 2198 | ccdc_try_format(ccdc, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); | 2198 | ccdc_try_format(ccdc, cfg, fse->pad, &format, fse->which); |
| 2199 | fse->min_width = format.width; | 2199 | fse->min_width = format.width; |
| 2200 | fse->min_height = format.height; | 2200 | fse->min_height = format.height; |
| 2201 | 2201 | ||
| @@ -2205,7 +2205,7 @@ static int ccdc_enum_frame_size(struct v4l2_subdev *sd, | |||
| 2205 | format.code = fse->code; | 2205 | format.code = fse->code; |
| 2206 | format.width = -1; | 2206 | format.width = -1; |
| 2207 | format.height = -1; | 2207 | format.height = -1; |
| 2208 | ccdc_try_format(ccdc, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); | 2208 | ccdc_try_format(ccdc, cfg, fse->pad, &format, fse->which); |
| 2209 | fse->max_width = format.width; | 2209 | fse->max_width = format.width; |
| 2210 | fse->max_height = format.height; | 2210 | fse->max_height = format.height; |
| 2211 | 2211 | ||
| @@ -2215,7 +2215,7 @@ static int ccdc_enum_frame_size(struct v4l2_subdev *sd, | |||
| 2215 | /* | 2215 | /* |
| 2216 | * ccdc_get_selection - Retrieve a selection rectangle on a pad | 2216 | * ccdc_get_selection - Retrieve a selection rectangle on a pad |
| 2217 | * @sd: ISP CCDC V4L2 subdevice | 2217 | * @sd: ISP CCDC V4L2 subdevice |
| 2218 | * @fh: V4L2 subdev file handle | 2218 | * @cfg: V4L2 subdev pad configuration |
| 2219 | * @sel: Selection rectangle | 2219 | * @sel: Selection rectangle |
| 2220 | * | 2220 | * |
| 2221 | * The only supported rectangles are the crop rectangles on the output formatter | 2221 | * The only supported rectangles are the crop rectangles on the output formatter |
| @@ -2223,7 +2223,7 @@ static int ccdc_enum_frame_size(struct v4l2_subdev *sd, | |||
| 2223 | * | 2223 | * |
| 2224 | * Return 0 on success or a negative error code otherwise. | 2224 | * Return 0 on success or a negative error code otherwise. |
| 2225 | */ | 2225 | */ |
| 2226 | static int ccdc_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | 2226 | static int ccdc_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, |
| 2227 | struct v4l2_subdev_selection *sel) | 2227 | struct v4l2_subdev_selection *sel) |
| 2228 | { | 2228 | { |
| 2229 | struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); | 2229 | struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); |
| @@ -2239,12 +2239,12 @@ static int ccdc_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | |||
| 2239 | sel->r.width = INT_MAX; | 2239 | sel->r.width = INT_MAX; |
| 2240 | sel->r.height = INT_MAX; | 2240 | sel->r.height = INT_MAX; |
| 2241 | 2241 | ||
| 2242 | format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, sel->which); | 2242 | format = __ccdc_get_format(ccdc, cfg, CCDC_PAD_SINK, sel->which); |
| 2243 | ccdc_try_crop(ccdc, format, &sel->r); | 2243 | ccdc_try_crop(ccdc, format, &sel->r); |
| 2244 | break; | 2244 | break; |
| 2245 | 2245 | ||
| 2246 | case V4L2_SEL_TGT_CROP: | 2246 | case V4L2_SEL_TGT_CROP: |
| 2247 | sel->r = *__ccdc_get_crop(ccdc, fh, sel->which); | 2247 | sel->r = *__ccdc_get_crop(ccdc, cfg, sel->which); |
| 2248 | break; | 2248 | break; |
| 2249 | 2249 | ||
| 2250 | default: | 2250 | default: |
| @@ -2257,7 +2257,7 @@ static int ccdc_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | |||
| 2257 | /* | 2257 | /* |
| 2258 | * ccdc_set_selection - Set a selection rectangle on a pad | 2258 | * ccdc_set_selection - Set a selection rectangle on a pad |
| 2259 | * @sd: ISP CCDC V4L2 subdevice | 2259 | * @sd: ISP CCDC V4L2 subdevice |
| 2260 | * @fh: V4L2 subdev file handle | 2260 | * @cfg: V4L2 subdev pad configuration |
| 2261 | * @sel: Selection rectangle | 2261 | * @sel: Selection rectangle |
| 2262 | * | 2262 | * |
| 2263 | * The only supported rectangle is the actual crop rectangle on the output | 2263 | * The only supported rectangle is the actual crop rectangle on the output |
| @@ -2265,7 +2265,7 @@ static int ccdc_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | |||
| 2265 | * | 2265 | * |
| 2266 | * Return 0 on success or a negative error code otherwise. | 2266 | * Return 0 on success or a negative error code otherwise. |
| 2267 | */ | 2267 | */ |
| 2268 | static int ccdc_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | 2268 | static int ccdc_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, |
| 2269 | struct v4l2_subdev_selection *sel) | 2269 | struct v4l2_subdev_selection *sel) |
| 2270 | { | 2270 | { |
| 2271 | struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); | 2271 | struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); |
| @@ -2284,17 +2284,17 @@ static int ccdc_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | |||
| 2284 | * rectangle. | 2284 | * rectangle. |
| 2285 | */ | 2285 | */ |
| 2286 | if (sel->flags & V4L2_SEL_FLAG_KEEP_CONFIG) { | 2286 | if (sel->flags & V4L2_SEL_FLAG_KEEP_CONFIG) { |
| 2287 | sel->r = *__ccdc_get_crop(ccdc, fh, sel->which); | 2287 | sel->r = *__ccdc_get_crop(ccdc, cfg, sel->which); |
| 2288 | return 0; | 2288 | return 0; |
| 2289 | } | 2289 | } |
| 2290 | 2290 | ||
| 2291 | format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, sel->which); | 2291 | format = __ccdc_get_format(ccdc, cfg, CCDC_PAD_SINK, sel->which); |
| 2292 | ccdc_try_crop(ccdc, format, &sel->r); | 2292 | ccdc_try_crop(ccdc, format, &sel->r); |
| 2293 | *__ccdc_get_crop(ccdc, fh, sel->which) = sel->r; | 2293 | *__ccdc_get_crop(ccdc, cfg, sel->which) = sel->r; |
| 2294 | 2294 | ||
| 2295 | /* Update the source format. */ | 2295 | /* Update the source format. */ |
| 2296 | format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SOURCE_OF, sel->which); | 2296 | format = __ccdc_get_format(ccdc, cfg, CCDC_PAD_SOURCE_OF, sel->which); |
| 2297 | ccdc_try_format(ccdc, fh, CCDC_PAD_SOURCE_OF, format, sel->which); | 2297 | ccdc_try_format(ccdc, cfg, CCDC_PAD_SOURCE_OF, format, sel->which); |
| 2298 | 2298 | ||
| 2299 | return 0; | 2299 | return 0; |
| 2300 | } | 2300 | } |
| @@ -2302,19 +2302,19 @@ static int ccdc_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | |||
| 2302 | /* | 2302 | /* |
| 2303 | * ccdc_get_format - Retrieve the video format on a pad | 2303 | * ccdc_get_format - Retrieve the video format on a pad |
| 2304 | * @sd : ISP CCDC V4L2 subdevice | 2304 | * @sd : ISP CCDC V4L2 subdevice |
| 2305 | * @fh : V4L2 subdev file handle | 2305 | * @cfg: V4L2 subdev pad configuration |
| 2306 | * @fmt: Format | 2306 | * @fmt: Format |
| 2307 | * | 2307 | * |
| 2308 | * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond | 2308 | * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond |
| 2309 | * to the format type. | 2309 | * to the format type. |
| 2310 | */ | 2310 | */ |
| 2311 | static int ccdc_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | 2311 | static int ccdc_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, |
| 2312 | struct v4l2_subdev_format *fmt) | 2312 | struct v4l2_subdev_format *fmt) |
| 2313 | { | 2313 | { |
| 2314 | struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); | 2314 | struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); |
| 2315 | struct v4l2_mbus_framefmt *format; | 2315 | struct v4l2_mbus_framefmt *format; |
| 2316 | 2316 | ||
| 2317 | format = __ccdc_get_format(ccdc, fh, fmt->pad, fmt->which); | 2317 | format = __ccdc_get_format(ccdc, cfg, fmt->pad, fmt->which); |
| 2318 | if (format == NULL) | 2318 | if (format == NULL) |
| 2319 | return -EINVAL; | 2319 | return -EINVAL; |
| 2320 | 2320 | ||
| @@ -2325,30 +2325,30 @@ static int ccdc_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | |||
| 2325 | /* | 2325 | /* |
| 2326 | * ccdc_set_format - Set the video format on a pad | 2326 | * ccdc_set_format - Set the video format on a pad |
| 2327 | * @sd : ISP CCDC V4L2 subdevice | 2327 | * @sd : ISP CCDC V4L2 subdevice |
| 2328 | * @fh : V4L2 subdev file handle | 2328 | * @cfg: V4L2 subdev pad configuration |
| 2329 | * @fmt: Format | 2329 | * @fmt: Format |
| 2330 | * | 2330 | * |
| 2331 | * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond | 2331 | * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond |
| 2332 | * to the format type. | 2332 | * to the format type. |
| 2333 | */ | 2333 | */ |
| 2334 | static int ccdc_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | 2334 | static int ccdc_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, |
| 2335 | struct v4l2_subdev_format *fmt) | 2335 | struct v4l2_subdev_format *fmt) |
| 2336 | { | 2336 | { |
| 2337 | struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); | 2337 | struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); |
| 2338 | struct v4l2_mbus_framefmt *format; | 2338 | struct v4l2_mbus_framefmt *format; |
| 2339 | struct v4l2_rect *crop; | 2339 | struct v4l2_rect *crop; |
| 2340 | 2340 | ||
| 2341 | format = __ccdc_get_format(ccdc, fh, fmt->pad, fmt->which); | 2341 | format = __ccdc_get_format(ccdc, cfg, fmt->pad, fmt->which); |
| 2342 | if (format == NULL) | 2342 | if (format == NULL) |
| 2343 | return -EINVAL; | 2343 | return -EINVAL; |
| 2344 | 2344 | ||
| 2345 | ccdc_try_format(ccdc, fh, fmt->pad, &fmt->format, fmt->which); | 2345 | ccdc_try_format(ccdc, cfg, fmt->pad, &fmt->format, fmt->which); |
| 2346 | *format = fmt->format; | 2346 | *format = fmt->format; |
| 2347 | 2347 | ||
| 2348 | /* Propagate the format from sink to source */ | 2348 | /* Propagate the format from sink to source */ |
| 2349 | if (fmt->pad == CCDC_PAD_SINK) { | 2349 | if (fmt->pad == CCDC_PAD_SINK) { |
| 2350 | /* Reset the crop rectangle. */ | 2350 | /* Reset the crop rectangle. */ |
| 2351 | crop = __ccdc_get_crop(ccdc, fh, fmt->which); | 2351 | crop = __ccdc_get_crop(ccdc, cfg, fmt->which); |
| 2352 | crop->left = 0; | 2352 | crop->left = 0; |
| 2353 | crop->top = 0; | 2353 | crop->top = 0; |
| 2354 | crop->width = fmt->format.width; | 2354 | crop->width = fmt->format.width; |
| @@ -2357,16 +2357,16 @@ static int ccdc_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | |||
| 2357 | ccdc_try_crop(ccdc, &fmt->format, crop); | 2357 | ccdc_try_crop(ccdc, &fmt->format, crop); |
| 2358 | 2358 | ||
| 2359 | /* Update the source formats. */ | 2359 | /* Update the source formats. */ |
| 2360 | format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SOURCE_OF, | 2360 | format = __ccdc_get_format(ccdc, cfg, CCDC_PAD_SOURCE_OF, |
| 2361 | fmt->which); | 2361 | fmt->which); |
| 2362 | *format = fmt->format; | 2362 | *format = fmt->format; |
| 2363 | ccdc_try_format(ccdc, fh, CCDC_PAD_SOURCE_OF, format, | 2363 | ccdc_try_format(ccdc, cfg, CCDC_PAD_SOURCE_OF, format, |
| 2364 | fmt->which); | 2364 | fmt->which); |
| 2365 | 2365 | ||
| 2366 | format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SOURCE_VP, | 2366 | format = __ccdc_get_format(ccdc, cfg, CCDC_PAD_SOURCE_VP, |
| 2367 | fmt->which); | 2367 | fmt->which); |
| 2368 | *format = fmt->format; | 2368 | *format = fmt->format; |
| 2369 | ccdc_try_format(ccdc, fh, CCDC_PAD_SOURCE_VP, format, | 2369 | ccdc_try_format(ccdc, cfg, CCDC_PAD_SOURCE_VP, format, |
| 2370 | fmt->which); | 2370 | fmt->which); |
| 2371 | } | 2371 | } |
| 2372 | 2372 | ||
| @@ -2417,11 +2417,11 @@ static int ccdc_link_validate(struct v4l2_subdev *sd, | |||
| 2417 | 2417 | ||
| 2418 | /* We've got a parallel sensor here. */ | 2418 | /* We've got a parallel sensor here. */ |
| 2419 | if (ccdc->input == CCDC_INPUT_PARALLEL) { | 2419 | if (ccdc->input == CCDC_INPUT_PARALLEL) { |
| 2420 | struct isp_parallel_platform_data *pdata = | 2420 | struct isp_parallel_cfg *parcfg = |
| 2421 | &((struct isp_v4l2_subdevs_group *) | 2421 | &((struct isp_bus_cfg *) |
| 2422 | media_entity_to_v4l2_subdev(link->source->entity) | 2422 | media_entity_to_v4l2_subdev(link->source->entity) |
| 2423 | ->host_priv)->bus.parallel; | 2423 | ->host_priv)->bus.parallel; |
| 2424 | parallel_shift = pdata->data_lane_shift * 2; | 2424 | parallel_shift = parcfg->data_lane_shift * 2; |
| 2425 | } else { | 2425 | } else { |
| 2426 | parallel_shift = 0; | 2426 | parallel_shift = 0; |
| 2427 | } | 2427 | } |
| @@ -2453,7 +2453,7 @@ static int ccdc_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) | |||
| 2453 | format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10; | 2453 | format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10; |
| 2454 | format.format.width = 4096; | 2454 | format.format.width = 4096; |
| 2455 | format.format.height = 4096; | 2455 | format.format.height = 4096; |
| 2456 | ccdc_set_format(sd, fh, &format); | 2456 | ccdc_set_format(sd, fh ? fh->pad : NULL, &format); |
| 2457 | 2457 | ||
| 2458 | return 0; | 2458 | return 0; |
| 2459 | } | 2459 | } |
diff --git a/drivers/media/platform/omap3isp/ispccp2.c b/drivers/media/platform/omap3isp/ispccp2.c index f4aedb37e41e..38e6a974c5b1 100644 --- a/drivers/media/platform/omap3isp/ispccp2.c +++ b/drivers/media/platform/omap3isp/ispccp2.c | |||
| @@ -201,14 +201,14 @@ static void ccp2_mem_enable(struct isp_ccp2_device *ccp2, u8 enable) | |||
| 201 | /* | 201 | /* |
| 202 | * ccp2_phyif_config - Initialize CCP2 phy interface config | 202 | * ccp2_phyif_config - Initialize CCP2 phy interface config |
| 203 | * @ccp2: Pointer to ISP CCP2 device | 203 | * @ccp2: Pointer to ISP CCP2 device |
| 204 | * @pdata: CCP2 platform data | 204 | * @buscfg: CCP2 platform data |
| 205 | * | 205 | * |
| 206 | * Configure the CCP2 physical interface module from platform data. | 206 | * Configure the CCP2 physical interface module from platform data. |
| 207 | * | 207 | * |
| 208 | * Returns -EIO if strobe is chosen in CSI1 mode, or 0 on success. | 208 | * Returns -EIO if strobe is chosen in CSI1 mode, or 0 on success. |
| 209 | */ | 209 | */ |
| 210 | static int ccp2_phyif_config(struct isp_ccp2_device *ccp2, | 210 | static int ccp2_phyif_config(struct isp_ccp2_device *ccp2, |
| 211 | const struct isp_ccp2_platform_data *pdata) | 211 | const struct isp_ccp2_cfg *buscfg) |
| 212 | { | 212 | { |
| 213 | struct isp_device *isp = to_isp_device(ccp2); | 213 | struct isp_device *isp = to_isp_device(ccp2); |
| 214 | u32 val; | 214 | u32 val; |
| @@ -218,16 +218,16 @@ static int ccp2_phyif_config(struct isp_ccp2_device *ccp2, | |||
| 218 | ISPCCP2_CTRL_IO_OUT_SEL | ISPCCP2_CTRL_MODE; | 218 | ISPCCP2_CTRL_IO_OUT_SEL | ISPCCP2_CTRL_MODE; |
| 219 | /* Data/strobe physical layer */ | 219 | /* Data/strobe physical layer */ |
| 220 | BIT_SET(val, ISPCCP2_CTRL_PHY_SEL_SHIFT, ISPCCP2_CTRL_PHY_SEL_MASK, | 220 | BIT_SET(val, ISPCCP2_CTRL_PHY_SEL_SHIFT, ISPCCP2_CTRL_PHY_SEL_MASK, |
| 221 | pdata->phy_layer); | 221 | buscfg->phy_layer); |
| 222 | BIT_SET(val, ISPCCP2_CTRL_INV_SHIFT, ISPCCP2_CTRL_INV_MASK, | 222 | BIT_SET(val, ISPCCP2_CTRL_INV_SHIFT, ISPCCP2_CTRL_INV_MASK, |
| 223 | pdata->strobe_clk_pol); | 223 | buscfg->strobe_clk_pol); |
| 224 | isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL); | 224 | isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL); |
| 225 | 225 | ||
| 226 | val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL); | 226 | val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL); |
| 227 | if (!(val & ISPCCP2_CTRL_MODE)) { | 227 | if (!(val & ISPCCP2_CTRL_MODE)) { |
| 228 | if (pdata->ccp2_mode == ISP_CCP2_MODE_CCP2) | 228 | if (buscfg->ccp2_mode == ISP_CCP2_MODE_CCP2) |
| 229 | dev_warn(isp->dev, "OMAP3 CCP2 bus not available\n"); | 229 | dev_warn(isp->dev, "OMAP3 CCP2 bus not available\n"); |
| 230 | if (pdata->phy_layer == ISP_CCP2_PHY_DATA_STROBE) | 230 | if (buscfg->phy_layer == ISP_CCP2_PHY_DATA_STROBE) |
| 231 | /* Strobe mode requires CCP2 */ | 231 | /* Strobe mode requires CCP2 */ |
| 232 | return -EIO; | 232 | return -EIO; |
| 233 | } | 233 | } |
| @@ -347,7 +347,7 @@ static void ccp2_lcx_config(struct isp_ccp2_device *ccp2, | |||
| 347 | */ | 347 | */ |
| 348 | static int ccp2_if_configure(struct isp_ccp2_device *ccp2) | 348 | static int ccp2_if_configure(struct isp_ccp2_device *ccp2) |
| 349 | { | 349 | { |
| 350 | const struct isp_v4l2_subdevs_group *pdata; | 350 | const struct isp_bus_cfg *buscfg; |
| 351 | struct v4l2_mbus_framefmt *format; | 351 | struct v4l2_mbus_framefmt *format; |
| 352 | struct media_pad *pad; | 352 | struct media_pad *pad; |
| 353 | struct v4l2_subdev *sensor; | 353 | struct v4l2_subdev *sensor; |
| @@ -358,20 +358,20 @@ static int ccp2_if_configure(struct isp_ccp2_device *ccp2) | |||
| 358 | 358 | ||
| 359 | pad = media_entity_remote_pad(&ccp2->pads[CCP2_PAD_SINK]); | 359 | pad = media_entity_remote_pad(&ccp2->pads[CCP2_PAD_SINK]); |
| 360 | sensor = media_entity_to_v4l2_subdev(pad->entity); | 360 | sensor = media_entity_to_v4l2_subdev(pad->entity); |
| 361 | pdata = sensor->host_priv; | 361 | buscfg = sensor->host_priv; |
| 362 | 362 | ||
| 363 | ret = ccp2_phyif_config(ccp2, &pdata->bus.ccp2); | 363 | ret = ccp2_phyif_config(ccp2, &buscfg->bus.ccp2); |
| 364 | if (ret < 0) | 364 | if (ret < 0) |
| 365 | return ret; | 365 | return ret; |
| 366 | 366 | ||
| 367 | ccp2_vp_config(ccp2, pdata->bus.ccp2.vpclk_div + 1); | 367 | ccp2_vp_config(ccp2, buscfg->bus.ccp2.vpclk_div + 1); |
| 368 | 368 | ||
| 369 | v4l2_subdev_call(sensor, sensor, g_skip_top_lines, &lines); | 369 | v4l2_subdev_call(sensor, sensor, g_skip_top_lines, &lines); |
| 370 | 370 | ||
| 371 | format = &ccp2->formats[CCP2_PAD_SINK]; | 371 | format = &ccp2->formats[CCP2_PAD_SINK]; |
| 372 | 372 | ||
| 373 | ccp2->if_cfg.data_start = lines; | 373 | ccp2->if_cfg.data_start = lines; |
| 374 | ccp2->if_cfg.crc = pdata->bus.ccp2.crc; | 374 | ccp2->if_cfg.crc = buscfg->bus.ccp2.crc; |
| 375 | ccp2->if_cfg.format = format->code; | 375 | ccp2->if_cfg.format = format->code; |
| 376 | ccp2->if_cfg.data_size = format->height; | 376 | ccp2->if_cfg.data_size = format->height; |
| 377 | 377 | ||
| @@ -611,17 +611,17 @@ static const unsigned int ccp2_fmts[] = { | |||
| 611 | /* | 611 | /* |
| 612 | * __ccp2_get_format - helper function for getting ccp2 format | 612 | * __ccp2_get_format - helper function for getting ccp2 format |
| 613 | * @ccp2 : Pointer to ISP CCP2 device | 613 | * @ccp2 : Pointer to ISP CCP2 device |
| 614 | * @fh : V4L2 subdev file handle | 614 | * @cfg: V4L2 subdev pad configuration |
| 615 | * @pad : pad number | 615 | * @pad : pad number |
| 616 | * @which : wanted subdev format | 616 | * @which : wanted subdev format |
| 617 | * return format structure or NULL on error | 617 | * return format structure or NULL on error |
| 618 | */ | 618 | */ |
| 619 | static struct v4l2_mbus_framefmt * | 619 | static struct v4l2_mbus_framefmt * |
| 620 | __ccp2_get_format(struct isp_ccp2_device *ccp2, struct v4l2_subdev_fh *fh, | 620 | __ccp2_get_format(struct isp_ccp2_device *ccp2, struct v4l2_subdev_pad_config *cfg, |
| 621 | unsigned int pad, enum v4l2_subdev_format_whence which) | 621 | unsigned int pad, enum v4l2_subdev_format_whence which) |
| 622 | { | 622 | { |
| 623 | if (which == V4L2_SUBDEV_FORMAT_TRY) | 623 | if (which == V4L2_SUBDEV_FORMAT_TRY) |
| 624 | return v4l2_subdev_get_try_format(fh, pad); | 624 | return v4l2_subdev_get_try_format(&ccp2->subdev, cfg, pad); |
| 625 | else | 625 | else |
| 626 | return &ccp2->formats[pad]; | 626 | return &ccp2->formats[pad]; |
| 627 | } | 627 | } |
| @@ -629,13 +629,13 @@ __ccp2_get_format(struct isp_ccp2_device *ccp2, struct v4l2_subdev_fh *fh, | |||
| 629 | /* | 629 | /* |
| 630 | * ccp2_try_format - Handle try format by pad subdev method | 630 | * ccp2_try_format - Handle try format by pad subdev method |
| 631 | * @ccp2 : Pointer to ISP CCP2 device | 631 | * @ccp2 : Pointer to ISP CCP2 device |
| 632 | * @fh : V4L2 subdev file handle | 632 | * @cfg: V4L2 subdev pad configuration |
| 633 | * @pad : pad num | 633 | * @pad : pad num |
| 634 | * @fmt : pointer to v4l2 mbus format structure | 634 | * @fmt : pointer to v4l2 mbus format structure |
| 635 | * @which : wanted subdev format | 635 | * @which : wanted subdev format |
| 636 | */ | 636 | */ |
| 637 | static void ccp2_try_format(struct isp_ccp2_device *ccp2, | 637 | static void ccp2_try_format(struct isp_ccp2_device *ccp2, |
| 638 | struct v4l2_subdev_fh *fh, unsigned int pad, | 638 | struct v4l2_subdev_pad_config *cfg, unsigned int pad, |
| 639 | struct v4l2_mbus_framefmt *fmt, | 639 | struct v4l2_mbus_framefmt *fmt, |
| 640 | enum v4l2_subdev_format_whence which) | 640 | enum v4l2_subdev_format_whence which) |
| 641 | { | 641 | { |
| @@ -669,7 +669,7 @@ static void ccp2_try_format(struct isp_ccp2_device *ccp2, | |||
| 669 | * When CCP2 write to memory feature will be added this | 669 | * When CCP2 write to memory feature will be added this |
| 670 | * should be changed properly. | 670 | * should be changed properly. |
| 671 | */ | 671 | */ |
| 672 | format = __ccp2_get_format(ccp2, fh, CCP2_PAD_SINK, which); | 672 | format = __ccp2_get_format(ccp2, cfg, CCP2_PAD_SINK, which); |
| 673 | memcpy(fmt, format, sizeof(*fmt)); | 673 | memcpy(fmt, format, sizeof(*fmt)); |
| 674 | fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; | 674 | fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; |
| 675 | break; | 675 | break; |
| @@ -682,12 +682,12 @@ static void ccp2_try_format(struct isp_ccp2_device *ccp2, | |||
| 682 | /* | 682 | /* |
| 683 | * ccp2_enum_mbus_code - Handle pixel format enumeration | 683 | * ccp2_enum_mbus_code - Handle pixel format enumeration |
| 684 | * @sd : pointer to v4l2 subdev structure | 684 | * @sd : pointer to v4l2 subdev structure |
| 685 | * @fh : V4L2 subdev file handle | 685 | * @cfg: V4L2 subdev pad configuration |
| 686 | * @code : pointer to v4l2_subdev_mbus_code_enum structure | 686 | * @code : pointer to v4l2_subdev_mbus_code_enum structure |
| 687 | * return -EINVAL or zero on success | 687 | * return -EINVAL or zero on success |
| 688 | */ | 688 | */ |
| 689 | static int ccp2_enum_mbus_code(struct v4l2_subdev *sd, | 689 | static int ccp2_enum_mbus_code(struct v4l2_subdev *sd, |
| 690 | struct v4l2_subdev_fh *fh, | 690 | struct v4l2_subdev_pad_config *cfg, |
| 691 | struct v4l2_subdev_mbus_code_enum *code) | 691 | struct v4l2_subdev_mbus_code_enum *code) |
| 692 | { | 692 | { |
| 693 | struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd); | 693 | struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd); |
| @@ -702,8 +702,8 @@ static int ccp2_enum_mbus_code(struct v4l2_subdev *sd, | |||
| 702 | if (code->index != 0) | 702 | if (code->index != 0) |
| 703 | return -EINVAL; | 703 | return -EINVAL; |
| 704 | 704 | ||
| 705 | format = __ccp2_get_format(ccp2, fh, CCP2_PAD_SINK, | 705 | format = __ccp2_get_format(ccp2, cfg, CCP2_PAD_SINK, |
| 706 | V4L2_SUBDEV_FORMAT_TRY); | 706 | code->which); |
| 707 | code->code = format->code; | 707 | code->code = format->code; |
| 708 | } | 708 | } |
| 709 | 709 | ||
| @@ -711,7 +711,7 @@ static int ccp2_enum_mbus_code(struct v4l2_subdev *sd, | |||
| 711 | } | 711 | } |
| 712 | 712 | ||
| 713 | static int ccp2_enum_frame_size(struct v4l2_subdev *sd, | 713 | static int ccp2_enum_frame_size(struct v4l2_subdev *sd, |
| 714 | struct v4l2_subdev_fh *fh, | 714 | struct v4l2_subdev_pad_config *cfg, |
| 715 | struct v4l2_subdev_frame_size_enum *fse) | 715 | struct v4l2_subdev_frame_size_enum *fse) |
| 716 | { | 716 | { |
| 717 | struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd); | 717 | struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd); |
| @@ -723,7 +723,7 @@ static int ccp2_enum_frame_size(struct v4l2_subdev *sd, | |||
| 723 | format.code = fse->code; | 723 | format.code = fse->code; |
| 724 | format.width = 1; | 724 | format.width = 1; |
| 725 | format.height = 1; | 725 | format.height = 1; |
| 726 | ccp2_try_format(ccp2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); | 726 | ccp2_try_format(ccp2, cfg, fse->pad, &format, fse->which); |
| 727 | fse->min_width = format.width; | 727 | fse->min_width = format.width; |
| 728 | fse->min_height = format.height; | 728 | fse->min_height = format.height; |
| 729 | 729 | ||
| @@ -733,7 +733,7 @@ static int ccp2_enum_frame_size(struct v4l2_subdev *sd, | |||
| 733 | format.code = fse->code; | 733 | format.code = fse->code; |
| 734 | format.width = -1; | 734 | format.width = -1; |
| 735 | format.height = -1; | 735 | format.height = -1; |
| 736 | ccp2_try_format(ccp2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); | 736 | ccp2_try_format(ccp2, cfg, fse->pad, &format, fse->which); |
| 737 | fse->max_width = format.width; | 737 | fse->max_width = format.width; |
| 738 | fse->max_height = format.height; | 738 | fse->max_height = format.height; |
| 739 | 739 | ||
| @@ -743,17 +743,17 @@ static int ccp2_enum_frame_size(struct v4l2_subdev *sd, | |||
| 743 | /* | 743 | /* |
| 744 | * ccp2_get_format - Handle get format by pads subdev method | 744 | * ccp2_get_format - Handle get format by pads subdev method |
| 745 | * @sd : pointer to v4l2 subdev structure | 745 | * @sd : pointer to v4l2 subdev structure |
| 746 | * @fh : V4L2 subdev file handle | 746 | * @cfg: V4L2 subdev pad configuration |
| 747 | * @fmt : pointer to v4l2 subdev format structure | 747 | * @fmt : pointer to v4l2 subdev format structure |
| 748 | * return -EINVAL or zero on success | 748 | * return -EINVAL or zero on success |
| 749 | */ | 749 | */ |
| 750 | static int ccp2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | 750 | static int ccp2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, |
| 751 | struct v4l2_subdev_format *fmt) | 751 | struct v4l2_subdev_format *fmt) |
| 752 | { | 752 | { |
| 753 | struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd); | 753 | struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd); |
| 754 | struct v4l2_mbus_framefmt *format; | 754 | struct v4l2_mbus_framefmt *format; |
| 755 | 755 | ||
| 756 | format = __ccp2_get_format(ccp2, fh, fmt->pad, fmt->which); | 756 | format = __ccp2_get_format(ccp2, cfg, fmt->pad, fmt->which); |
| 757 | if (format == NULL) | 757 | if (format == NULL) |
| 758 | return -EINVAL; | 758 | return -EINVAL; |
| 759 | 759 | ||
| @@ -764,29 +764,29 @@ static int ccp2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | |||
| 764 | /* | 764 | /* |
| 765 | * ccp2_set_format - Handle set format by pads subdev method | 765 | * ccp2_set_format - Handle set format by pads subdev method |
| 766 | * @sd : pointer to v4l2 subdev structure | 766 | * @sd : pointer to v4l2 subdev structure |
| 767 | * @fh : V4L2 subdev file handle | 767 | * @cfg: V4L2 subdev pad configuration |
| 768 | * @fmt : pointer to v4l2 subdev format structure | 768 | * @fmt : pointer to v4l2 subdev format structure |
| 769 | * returns zero | 769 | * returns zero |
| 770 | */ | 770 | */ |
| 771 | static int ccp2_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | 771 | static int ccp2_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, |
| 772 | struct v4l2_subdev_format *fmt) | 772 | struct v4l2_subdev_format *fmt) |
| 773 | { | 773 | { |
| 774 | struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd); | 774 | struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd); |
| 775 | struct v4l2_mbus_framefmt *format; | 775 | struct v4l2_mbus_framefmt *format; |
| 776 | 776 | ||
| 777 | format = __ccp2_get_format(ccp2, fh, fmt->pad, fmt->which); | 777 | format = __ccp2_get_format(ccp2, cfg, fmt->pad, fmt->which); |
| 778 | if (format == NULL) | 778 | if (format == NULL) |
| 779 | return -EINVAL; | 779 | return -EINVAL; |
| 780 | 780 | ||
| 781 | ccp2_try_format(ccp2, fh, fmt->pad, &fmt->format, fmt->which); | 781 | ccp2_try_format(ccp2, cfg, fmt->pad, &fmt->format, fmt->which); |
| 782 | *format = fmt->format; | 782 | *format = fmt->format; |
| 783 | 783 | ||
| 784 | /* Propagate the format from sink to source */ | 784 | /* Propagate the format from sink to source */ |
| 785 | if (fmt->pad == CCP2_PAD_SINK) { | 785 | if (fmt->pad == CCP2_PAD_SINK) { |
| 786 | format = __ccp2_get_format(ccp2, fh, CCP2_PAD_SOURCE, | 786 | format = __ccp2_get_format(ccp2, cfg, CCP2_PAD_SOURCE, |
| 787 | fmt->which); | 787 | fmt->which); |
| 788 | *format = fmt->format; | 788 | *format = fmt->format; |
| 789 | ccp2_try_format(ccp2, fh, CCP2_PAD_SOURCE, format, fmt->which); | 789 | ccp2_try_format(ccp2, cfg, CCP2_PAD_SOURCE, format, fmt->which); |
| 790 | } | 790 | } |
| 791 | 791 | ||
| 792 | return 0; | 792 | return 0; |
| @@ -811,7 +811,7 @@ static int ccp2_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) | |||
| 811 | format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10; | 811 | format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10; |
| 812 | format.format.width = 4096; | 812 | format.format.width = 4096; |
| 813 | format.format.height = 4096; | 813 | format.format.height = 4096; |
| 814 | ccp2_set_format(sd, fh, &format); | 814 | ccp2_set_format(sd, fh ? fh->pad : NULL, &format); |
| 815 | 815 | ||
| 816 | return 0; | 816 | return 0; |
| 817 | } | 817 | } |
diff --git a/drivers/media/platform/omap3isp/ispcsi2.c b/drivers/media/platform/omap3isp/ispcsi2.c index 09c686d96ae8..a78338d012b4 100644 --- a/drivers/media/platform/omap3isp/ispcsi2.c +++ b/drivers/media/platform/omap3isp/ispcsi2.c | |||
| @@ -548,7 +548,8 @@ int omap3isp_csi2_reset(struct isp_csi2_device *csi2) | |||
| 548 | 548 | ||
| 549 | static int csi2_configure(struct isp_csi2_device *csi2) | 549 | static int csi2_configure(struct isp_csi2_device *csi2) |
| 550 | { | 550 | { |
| 551 | const struct isp_v4l2_subdevs_group *pdata; | 551 | struct isp_pipeline *pipe = to_isp_pipeline(&csi2->subdev.entity); |
| 552 | const struct isp_bus_cfg *buscfg; | ||
| 552 | struct isp_device *isp = csi2->isp; | 553 | struct isp_device *isp = csi2->isp; |
| 553 | struct isp_csi2_timing_cfg *timing = &csi2->timing[0]; | 554 | struct isp_csi2_timing_cfg *timing = &csi2->timing[0]; |
| 554 | struct v4l2_subdev *sensor; | 555 | struct v4l2_subdev *sensor; |
| @@ -565,14 +566,19 @@ static int csi2_configure(struct isp_csi2_device *csi2) | |||
| 565 | 566 | ||
| 566 | pad = media_entity_remote_pad(&csi2->pads[CSI2_PAD_SINK]); | 567 | pad = media_entity_remote_pad(&csi2->pads[CSI2_PAD_SINK]); |
| 567 | sensor = media_entity_to_v4l2_subdev(pad->entity); | 568 | sensor = media_entity_to_v4l2_subdev(pad->entity); |
| 568 | pdata = sensor->host_priv; | 569 | buscfg = sensor->host_priv; |
| 569 | 570 | ||
| 570 | csi2->frame_skip = 0; | 571 | csi2->frame_skip = 0; |
| 571 | v4l2_subdev_call(sensor, sensor, g_skip_frames, &csi2->frame_skip); | 572 | v4l2_subdev_call(sensor, sensor, g_skip_frames, &csi2->frame_skip); |
| 572 | 573 | ||
| 573 | csi2->ctrl.vp_out_ctrl = pdata->bus.csi2.vpclk_div; | 574 | csi2->ctrl.vp_out_ctrl = |
| 575 | clamp_t(unsigned int, pipe->l3_ick / pipe->external_rate - 1, | ||
| 576 | 1, 3); | ||
| 577 | dev_dbg(isp->dev, "%s: l3_ick %lu, external_rate %u, vp_out_ctrl %u\n", | ||
| 578 | __func__, pipe->l3_ick, pipe->external_rate, | ||
| 579 | csi2->ctrl.vp_out_ctrl); | ||
| 574 | csi2->ctrl.frame_mode = ISP_CSI2_FRAME_IMMEDIATE; | 580 | csi2->ctrl.frame_mode = ISP_CSI2_FRAME_IMMEDIATE; |
| 575 | csi2->ctrl.ecc_enable = pdata->bus.csi2.crc; | 581 | csi2->ctrl.ecc_enable = buscfg->bus.csi2.crc; |
| 576 | 582 | ||
| 577 | timing->ionum = 1; | 583 | timing->ionum = 1; |
| 578 | timing->force_rx_mode = 1; | 584 | timing->force_rx_mode = 1; |
| @@ -829,17 +835,17 @@ static const struct isp_video_operations csi2_ispvideo_ops = { | |||
| 829 | */ | 835 | */ |
| 830 | 836 | ||
| 831 | static struct v4l2_mbus_framefmt * | 837 | static struct v4l2_mbus_framefmt * |
| 832 | __csi2_get_format(struct isp_csi2_device *csi2, struct v4l2_subdev_fh *fh, | 838 | __csi2_get_format(struct isp_csi2_device *csi2, struct v4l2_subdev_pad_config *cfg, |
| 833 | unsigned int pad, enum v4l2_subdev_format_whence which) | 839 | unsigned int pad, enum v4l2_subdev_format_whence which) |
| 834 | { | 840 | { |
| 835 | if (which == V4L2_SUBDEV_FORMAT_TRY) | 841 | if (which == V4L2_SUBDEV_FORMAT_TRY) |
| 836 | return v4l2_subdev_get_try_format(fh, pad); | 842 | return v4l2_subdev_get_try_format(&csi2->subdev, cfg, pad); |
| 837 | else | 843 | else |
| 838 | return &csi2->formats[pad]; | 844 | return &csi2->formats[pad]; |
| 839 | } | 845 | } |
| 840 | 846 | ||
| 841 | static void | 847 | static void |
| 842 | csi2_try_format(struct isp_csi2_device *csi2, struct v4l2_subdev_fh *fh, | 848 | csi2_try_format(struct isp_csi2_device *csi2, struct v4l2_subdev_pad_config *cfg, |
| 843 | unsigned int pad, struct v4l2_mbus_framefmt *fmt, | 849 | unsigned int pad, struct v4l2_mbus_framefmt *fmt, |
| 844 | enum v4l2_subdev_format_whence which) | 850 | enum v4l2_subdev_format_whence which) |
| 845 | { | 851 | { |
| @@ -869,7 +875,7 @@ csi2_try_format(struct isp_csi2_device *csi2, struct v4l2_subdev_fh *fh, | |||
| 869 | * compression. | 875 | * compression. |
| 870 | */ | 876 | */ |
| 871 | pixelcode = fmt->code; | 877 | pixelcode = fmt->code; |
| 872 | format = __csi2_get_format(csi2, fh, CSI2_PAD_SINK, which); | 878 | format = __csi2_get_format(csi2, cfg, CSI2_PAD_SINK, which); |
| 873 | memcpy(fmt, format, sizeof(*fmt)); | 879 | memcpy(fmt, format, sizeof(*fmt)); |
| 874 | 880 | ||
| 875 | /* | 881 | /* |
| @@ -890,12 +896,12 @@ csi2_try_format(struct isp_csi2_device *csi2, struct v4l2_subdev_fh *fh, | |||
| 890 | /* | 896 | /* |
| 891 | * csi2_enum_mbus_code - Handle pixel format enumeration | 897 | * csi2_enum_mbus_code - Handle pixel format enumeration |
| 892 | * @sd : pointer to v4l2 subdev structure | 898 | * @sd : pointer to v4l2 subdev structure |
| 893 | * @fh : V4L2 subdev file handle | 899 | * @cfg: V4L2 subdev pad configuration |
| 894 | * @code : pointer to v4l2_subdev_mbus_code_enum structure | 900 | * @code : pointer to v4l2_subdev_mbus_code_enum structure |
| 895 | * return -EINVAL or zero on success | 901 | * return -EINVAL or zero on success |
| 896 | */ | 902 | */ |
| 897 | static int csi2_enum_mbus_code(struct v4l2_subdev *sd, | 903 | static int csi2_enum_mbus_code(struct v4l2_subdev *sd, |
| 898 | struct v4l2_subdev_fh *fh, | 904 | struct v4l2_subdev_pad_config *cfg, |
| 899 | struct v4l2_subdev_mbus_code_enum *code) | 905 | struct v4l2_subdev_mbus_code_enum *code) |
| 900 | { | 906 | { |
| 901 | struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd); | 907 | struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd); |
| @@ -908,8 +914,8 @@ static int csi2_enum_mbus_code(struct v4l2_subdev *sd, | |||
| 908 | 914 | ||
| 909 | code->code = csi2_input_fmts[code->index]; | 915 | code->code = csi2_input_fmts[code->index]; |
| 910 | } else { | 916 | } else { |
| 911 | format = __csi2_get_format(csi2, fh, CSI2_PAD_SINK, | 917 | format = __csi2_get_format(csi2, cfg, CSI2_PAD_SINK, |
| 912 | V4L2_SUBDEV_FORMAT_TRY); | 918 | code->which); |
| 913 | switch (code->index) { | 919 | switch (code->index) { |
| 914 | case 0: | 920 | case 0: |
| 915 | /* Passthrough sink pad code */ | 921 | /* Passthrough sink pad code */ |
| @@ -932,7 +938,7 @@ static int csi2_enum_mbus_code(struct v4l2_subdev *sd, | |||
| 932 | } | 938 | } |
| 933 | 939 | ||
| 934 | static int csi2_enum_frame_size(struct v4l2_subdev *sd, | 940 | static int csi2_enum_frame_size(struct v4l2_subdev *sd, |
| 935 | struct v4l2_subdev_fh *fh, | 941 | struct v4l2_subdev_pad_config *cfg, |
| 936 | struct v4l2_subdev_frame_size_enum *fse) | 942 | struct v4l2_subdev_frame_size_enum *fse) |
| 937 | { | 943 | { |
| 938 | struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd); | 944 | struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd); |
| @@ -944,7 +950,7 @@ static int csi2_enum_frame_size(struct v4l2_subdev *sd, | |||
| 944 | format.code = fse->code; | 950 | format.code = fse->code; |
| 945 | format.width = 1; | 951 | format.width = 1; |
| 946 | format.height = 1; | 952 | format.height = 1; |
| 947 | csi2_try_format(csi2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); | 953 | csi2_try_format(csi2, cfg, fse->pad, &format, fse->which); |
| 948 | fse->min_width = format.width; | 954 | fse->min_width = format.width; |
| 949 | fse->min_height = format.height; | 955 | fse->min_height = format.height; |
| 950 | 956 | ||
| @@ -954,7 +960,7 @@ static int csi2_enum_frame_size(struct v4l2_subdev *sd, | |||
| 954 | format.code = fse->code; | 960 | format.code = fse->code; |
| 955 | format.width = -1; | 961 | format.width = -1; |
| 956 | format.height = -1; | 962 | format.height = -1; |
| 957 | csi2_try_format(csi2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); | 963 | csi2_try_format(csi2, cfg, fse->pad, &format, fse->which); |
| 958 | fse->max_width = format.width; | 964 | fse->max_width = format.width; |
| 959 | fse->max_height = format.height; | 965 | fse->max_height = format.height; |
| 960 | 966 | ||
| @@ -964,17 +970,17 @@ static int csi2_enum_frame_size(struct v4l2_subdev *sd, | |||
| 964 | /* | 970 | /* |
| 965 | * csi2_get_format - Handle get format by pads subdev method | 971 | * csi2_get_format - Handle get format by pads subdev method |
| 966 | * @sd : pointer to v4l2 subdev structure | 972 | * @sd : pointer to v4l2 subdev structure |
| 967 | * @fh : V4L2 subdev file handle | 973 | * @cfg: V4L2 subdev pad configuration |
| 968 | * @fmt: pointer to v4l2 subdev format structure | 974 | * @fmt: pointer to v4l2 subdev format structure |
| 969 | * return -EINVAL or zero on success | 975 | * return -EINVAL or zero on success |
| 970 | */ | 976 | */ |
| 971 | static int csi2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | 977 | static int csi2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, |
| 972 | struct v4l2_subdev_format *fmt) | 978 | struct v4l2_subdev_format *fmt) |
| 973 | { | 979 | { |
| 974 | struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd); | 980 | struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd); |
| 975 | struct v4l2_mbus_framefmt *format; | 981 | struct v4l2_mbus_framefmt *format; |
| 976 | 982 | ||
| 977 | format = __csi2_get_format(csi2, fh, fmt->pad, fmt->which); | 983 | format = __csi2_get_format(csi2, cfg, fmt->pad, fmt->which); |
| 978 | if (format == NULL) | 984 | if (format == NULL) |
| 979 | return -EINVAL; | 985 | return -EINVAL; |
| 980 | 986 | ||
| @@ -985,29 +991,29 @@ static int csi2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | |||
| 985 | /* | 991 | /* |
| 986 | * csi2_set_format - Handle set format by pads subdev method | 992 | * csi2_set_format - Handle set format by pads subdev method |
| 987 | * @sd : pointer to v4l2 subdev structure | 993 | * @sd : pointer to v4l2 subdev structure |
| 988 | * @fh : V4L2 subdev file handle | 994 | * @cfg: V4L2 subdev pad configuration |
| 989 | * @fmt: pointer to v4l2 subdev format structure | 995 | * @fmt: pointer to v4l2 subdev format structure |
| 990 | * return -EINVAL or zero on success | 996 | * return -EINVAL or zero on success |
| 991 | */ | 997 | */ |
| 992 | static int csi2_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | 998 | static int csi2_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, |
| 993 | struct v4l2_subdev_format *fmt) | 999 | struct v4l2_subdev_format *fmt) |
| 994 | { | 1000 | { |
| 995 | struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd); | 1001 | struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd); |
| 996 | struct v4l2_mbus_framefmt *format; | 1002 | struct v4l2_mbus_framefmt *format; |
| 997 | 1003 | ||
| 998 | format = __csi2_get_format(csi2, fh, fmt->pad, fmt->which); | 1004 | format = __csi2_get_format(csi2, cfg, fmt->pad, fmt->which); |
| 999 | if (format == NULL) | 1005 | if (format == NULL) |
| 1000 | return -EINVAL; | 1006 | return -EINVAL; |
| 1001 | 1007 | ||
| 1002 | csi2_try_format(csi2, fh, fmt->pad, &fmt->format, fmt->which); | 1008 | csi2_try_format(csi2, cfg, fmt->pad, &fmt->format, fmt->which); |
| 1003 | *format = fmt->format; | 1009 | *format = fmt->format; |
| 1004 | 1010 | ||
| 1005 | /* Propagate the format from sink to source */ | 1011 | /* Propagate the format from sink to source */ |
| 1006 | if (fmt->pad == CSI2_PAD_SINK) { | 1012 | if (fmt->pad == CSI2_PAD_SINK) { |
| 1007 | format = __csi2_get_format(csi2, fh, CSI2_PAD_SOURCE, | 1013 | format = __csi2_get_format(csi2, cfg, CSI2_PAD_SOURCE, |
| 1008 | fmt->which); | 1014 | fmt->which); |
| 1009 | *format = fmt->format; | 1015 | *format = fmt->format; |
| 1010 | csi2_try_format(csi2, fh, CSI2_PAD_SOURCE, format, fmt->which); | 1016 | csi2_try_format(csi2, cfg, CSI2_PAD_SOURCE, format, fmt->which); |
| 1011 | } | 1017 | } |
| 1012 | 1018 | ||
| 1013 | return 0; | 1019 | return 0; |
| @@ -1032,7 +1038,7 @@ static int csi2_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) | |||
| 1032 | format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10; | 1038 | format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10; |
| 1033 | format.format.width = 4096; | 1039 | format.format.width = 4096; |
| 1034 | format.format.height = 4096; | 1040 | format.format.height = 4096; |
| 1035 | csi2_set_format(sd, fh, &format); | 1041 | csi2_set_format(sd, fh ? fh->pad : NULL, &format); |
| 1036 | 1042 | ||
| 1037 | return 0; | 1043 | return 0; |
| 1038 | } | 1044 | } |
diff --git a/drivers/media/platform/omap3isp/ispcsiphy.c b/drivers/media/platform/omap3isp/ispcsiphy.c index e033f2237a72..495447d66cfd 100644 --- a/drivers/media/platform/omap3isp/ispcsiphy.c +++ b/drivers/media/platform/omap3isp/ispcsiphy.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | 16 | ||
| 17 | #include <linux/delay.h> | 17 | #include <linux/delay.h> |
| 18 | #include <linux/device.h> | 18 | #include <linux/device.h> |
| 19 | #include <linux/regmap.h> | ||
| 19 | #include <linux/regulator/consumer.h> | 20 | #include <linux/regulator/consumer.h> |
| 20 | 21 | ||
| 21 | #include "isp.h" | 22 | #include "isp.h" |
| @@ -26,10 +27,11 @@ static void csiphy_routing_cfg_3630(struct isp_csiphy *phy, | |||
| 26 | enum isp_interface_type iface, | 27 | enum isp_interface_type iface, |
| 27 | bool ccp2_strobe) | 28 | bool ccp2_strobe) |
| 28 | { | 29 | { |
| 29 | u32 reg = isp_reg_readl( | 30 | u32 reg; |
| 30 | phy->isp, OMAP3_ISP_IOMEM_3630_CONTROL_CAMERA_PHY_CTRL, 0); | ||
| 31 | u32 shift, mode; | 31 | u32 shift, mode; |
| 32 | 32 | ||
| 33 | regmap_read(phy->isp->syscon, phy->isp->syscon_offset, ®); | ||
| 34 | |||
| 33 | switch (iface) { | 35 | switch (iface) { |
| 34 | default: | 36 | default: |
| 35 | /* Should not happen in practice, but let's keep the compiler happy. */ | 37 | /* Should not happen in practice, but let's keep the compiler happy. */ |
| @@ -63,8 +65,7 @@ static void csiphy_routing_cfg_3630(struct isp_csiphy *phy, | |||
| 63 | reg &= ~(OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_MASK << shift); | 65 | reg &= ~(OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_MASK << shift); |
| 64 | reg |= mode << shift; | 66 | reg |= mode << shift; |
| 65 | 67 | ||
| 66 | isp_reg_writel(phy->isp, reg, | 68 | regmap_write(phy->isp->syscon, phy->isp->syscon_offset, reg); |
| 67 | OMAP3_ISP_IOMEM_3630_CONTROL_CAMERA_PHY_CTRL, 0); | ||
| 68 | } | 69 | } |
| 69 | 70 | ||
| 70 | static void csiphy_routing_cfg_3430(struct isp_csiphy *phy, u32 iface, bool on, | 71 | static void csiphy_routing_cfg_3430(struct isp_csiphy *phy, u32 iface, bool on, |
| @@ -78,16 +79,14 @@ static void csiphy_routing_cfg_3430(struct isp_csiphy *phy, u32 iface, bool on, | |||
| 78 | return; | 79 | return; |
| 79 | 80 | ||
| 80 | if (!on) { | 81 | if (!on) { |
| 81 | isp_reg_writel(phy->isp, 0, | 82 | regmap_write(phy->isp->syscon, phy->isp->syscon_offset, 0); |
| 82 | OMAP3_ISP_IOMEM_343X_CONTROL_CSIRXFE, 0); | ||
| 83 | return; | 83 | return; |
| 84 | } | 84 | } |
| 85 | 85 | ||
| 86 | if (ccp2_strobe) | 86 | if (ccp2_strobe) |
| 87 | csirxfe |= OMAP343X_CONTROL_CSIRXFE_SELFORM; | 87 | csirxfe |= OMAP343X_CONTROL_CSIRXFE_SELFORM; |
| 88 | 88 | ||
| 89 | isp_reg_writel(phy->isp, csirxfe, | 89 | regmap_write(phy->isp->syscon, phy->isp->syscon_offset, csirxfe); |
| 90 | OMAP3_ISP_IOMEM_343X_CONTROL_CSIRXFE, 0); | ||
| 91 | } | 90 | } |
| 92 | 91 | ||
| 93 | /* | 92 | /* |
| @@ -106,10 +105,9 @@ static void csiphy_routing_cfg(struct isp_csiphy *phy, | |||
| 106 | enum isp_interface_type iface, bool on, | 105 | enum isp_interface_type iface, bool on, |
| 107 | bool ccp2_strobe) | 106 | bool ccp2_strobe) |
| 108 | { | 107 | { |
| 109 | if (phy->isp->mmio_base[OMAP3_ISP_IOMEM_3630_CONTROL_CAMERA_PHY_CTRL] | 108 | if (phy->isp->phy_type == ISP_PHY_TYPE_3630 && on) |
| 110 | && on) | ||
| 111 | return csiphy_routing_cfg_3630(phy, iface, ccp2_strobe); | 109 | return csiphy_routing_cfg_3630(phy, iface, ccp2_strobe); |
| 112 | if (phy->isp->mmio_base[OMAP3_ISP_IOMEM_343X_CONTROL_CSIRXFE]) | 110 | if (phy->isp->phy_type == ISP_PHY_TYPE_3430) |
| 113 | return csiphy_routing_cfg_3430(phy, iface, on, ccp2_strobe); | 111 | return csiphy_routing_cfg_3430(phy, iface, on, ccp2_strobe); |
| 114 | } | 112 | } |
| 115 | 113 | ||
| @@ -168,18 +166,25 @@ static int omap3isp_csiphy_config(struct isp_csiphy *phy) | |||
| 168 | { | 166 | { |
| 169 | struct isp_csi2_device *csi2 = phy->csi2; | 167 | struct isp_csi2_device *csi2 = phy->csi2; |
| 170 | struct isp_pipeline *pipe = to_isp_pipeline(&csi2->subdev.entity); | 168 | struct isp_pipeline *pipe = to_isp_pipeline(&csi2->subdev.entity); |
| 171 | struct isp_v4l2_subdevs_group *subdevs = pipe->external->host_priv; | 169 | struct isp_bus_cfg *buscfg = pipe->external->host_priv; |
| 172 | struct isp_csiphy_lanes_cfg *lanes; | 170 | struct isp_csiphy_lanes_cfg *lanes; |
| 173 | int csi2_ddrclk_khz; | 171 | int csi2_ddrclk_khz; |
| 174 | unsigned int used_lanes = 0; | 172 | unsigned int used_lanes = 0; |
| 175 | unsigned int i; | 173 | unsigned int i; |
| 176 | u32 reg; | 174 | u32 reg; |
| 177 | 175 | ||
| 178 | if (subdevs->interface == ISP_INTERFACE_CCP2B_PHY1 | 176 | if (!buscfg) { |
| 179 | || subdevs->interface == ISP_INTERFACE_CCP2B_PHY2) | 177 | struct isp_async_subdev *isd = |
| 180 | lanes = &subdevs->bus.ccp2.lanecfg; | 178 | container_of(pipe->external->asd, |
| 179 | struct isp_async_subdev, asd); | ||
| 180 | buscfg = &isd->bus; | ||
| 181 | } | ||
| 182 | |||
| 183 | if (buscfg->interface == ISP_INTERFACE_CCP2B_PHY1 | ||
| 184 | || buscfg->interface == ISP_INTERFACE_CCP2B_PHY2) | ||
| 185 | lanes = &buscfg->bus.ccp2.lanecfg; | ||
| 181 | else | 186 | else |
| 182 | lanes = &subdevs->bus.csi2.lanecfg; | 187 | lanes = &buscfg->bus.csi2.lanecfg; |
| 183 | 188 | ||
| 184 | /* Clock and data lanes verification */ | 189 | /* Clock and data lanes verification */ |
| 185 | for (i = 0; i < phy->num_data_lanes; i++) { | 190 | for (i = 0; i < phy->num_data_lanes; i++) { |
| @@ -203,8 +208,8 @@ static int omap3isp_csiphy_config(struct isp_csiphy *phy) | |||
| 203 | * issue since the MPU power domain is forced on whilst the | 208 | * issue since the MPU power domain is forced on whilst the |
| 204 | * ISP is in use. | 209 | * ISP is in use. |
| 205 | */ | 210 | */ |
| 206 | csiphy_routing_cfg(phy, subdevs->interface, true, | 211 | csiphy_routing_cfg(phy, buscfg->interface, true, |
| 207 | subdevs->bus.ccp2.phy_layer); | 212 | buscfg->bus.ccp2.phy_layer); |
| 208 | 213 | ||
| 209 | /* DPHY timing configuration */ | 214 | /* DPHY timing configuration */ |
| 210 | /* CSI-2 is DDR and we only count used lanes. */ | 215 | /* CSI-2 is DDR and we only count used lanes. */ |
| @@ -302,11 +307,10 @@ void omap3isp_csiphy_release(struct isp_csiphy *phy) | |||
| 302 | struct isp_csi2_device *csi2 = phy->csi2; | 307 | struct isp_csi2_device *csi2 = phy->csi2; |
| 303 | struct isp_pipeline *pipe = | 308 | struct isp_pipeline *pipe = |
| 304 | to_isp_pipeline(&csi2->subdev.entity); | 309 | to_isp_pipeline(&csi2->subdev.entity); |
| 305 | struct isp_v4l2_subdevs_group *subdevs = | 310 | struct isp_bus_cfg *buscfg = pipe->external->host_priv; |
| 306 | pipe->external->host_priv; | ||
| 307 | 311 | ||
| 308 | csiphy_routing_cfg(phy, subdevs->interface, false, | 312 | csiphy_routing_cfg(phy, buscfg->interface, false, |
| 309 | subdevs->bus.ccp2.phy_layer); | 313 | buscfg->bus.ccp2.phy_layer); |
| 310 | csiphy_power_autoswitch_enable(phy, false); | 314 | csiphy_power_autoswitch_enable(phy, false); |
| 311 | csiphy_set_power(phy, ISPCSI2_PHY_CFG_PWR_CMD_OFF); | 315 | csiphy_set_power(phy, ISPCSI2_PHY_CFG_PWR_CMD_OFF); |
| 312 | regulator_disable(phy->vdd); | 316 | regulator_disable(phy->vdd); |
diff --git a/drivers/media/platform/omap3isp/isph3a_aewb.c b/drivers/media/platform/omap3isp/isph3a_aewb.c index b208c5417146..ccaf92f39236 100644 --- a/drivers/media/platform/omap3isp/isph3a_aewb.c +++ b/drivers/media/platform/omap3isp/isph3a_aewb.c | |||
| @@ -297,7 +297,6 @@ int omap3isp_h3a_aewb_init(struct isp_device *isp) | |||
| 297 | 297 | ||
| 298 | aewb->ops = &h3a_aewb_ops; | 298 | aewb->ops = &h3a_aewb_ops; |
| 299 | aewb->priv = aewb_cfg; | 299 | aewb->priv = aewb_cfg; |
| 300 | aewb->dma_ch = -1; | ||
| 301 | aewb->event_type = V4L2_EVENT_OMAP3ISP_AEWB; | 300 | aewb->event_type = V4L2_EVENT_OMAP3ISP_AEWB; |
| 302 | aewb->isp = isp; | 301 | aewb->isp = isp; |
| 303 | 302 | ||
diff --git a/drivers/media/platform/omap3isp/isph3a_af.c b/drivers/media/platform/omap3isp/isph3a_af.c index 8a83e195f3e3..92937f7eecef 100644 --- a/drivers/media/platform/omap3isp/isph3a_af.c +++ b/drivers/media/platform/omap3isp/isph3a_af.c | |||
| @@ -360,7 +360,6 @@ int omap3isp_h3a_af_init(struct isp_device *isp) | |||
| 360 | 360 | ||
| 361 | af->ops = &h3a_af_ops; | 361 | af->ops = &h3a_af_ops; |
| 362 | af->priv = af_cfg; | 362 | af->priv = af_cfg; |
| 363 | af->dma_ch = -1; | ||
| 364 | af->event_type = V4L2_EVENT_OMAP3ISP_AF; | 363 | af->event_type = V4L2_EVENT_OMAP3ISP_AF; |
| 365 | af->isp = isp; | 364 | af->isp = isp; |
| 366 | 365 | ||
diff --git a/drivers/media/platform/omap3isp/isphist.c b/drivers/media/platform/omap3isp/isphist.c index ce822c34c843..7138b043a4aa 100644 --- a/drivers/media/platform/omap3isp/isphist.c +++ b/drivers/media/platform/omap3isp/isphist.c | |||
| @@ -16,20 +16,18 @@ | |||
| 16 | */ | 16 | */ |
| 17 | 17 | ||
| 18 | #include <linux/delay.h> | 18 | #include <linux/delay.h> |
| 19 | #include <linux/device.h> | ||
| 20 | #include <linux/dmaengine.h> | ||
| 21 | #include <linux/omap-dmaengine.h> | ||
| 19 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
| 20 | #include <linux/uaccess.h> | 23 | #include <linux/uaccess.h> |
| 21 | #include <linux/device.h> | ||
| 22 | 24 | ||
| 23 | #include "isp.h" | 25 | #include "isp.h" |
| 24 | #include "ispreg.h" | 26 | #include "ispreg.h" |
| 25 | #include "isphist.h" | 27 | #include "isphist.h" |
| 26 | 28 | ||
| 27 | #define OMAP24XX_DMA_NO_DEVICE 0 | ||
| 28 | |||
| 29 | #define HIST_CONFIG_DMA 1 | 29 | #define HIST_CONFIG_DMA 1 |
| 30 | 30 | ||
| 31 | #define HIST_USING_DMA(hist) ((hist)->dma_ch >= 0) | ||
| 32 | |||
| 33 | /* | 31 | /* |
| 34 | * hist_reset_mem - clear Histogram memory before start stats engine. | 32 | * hist_reset_mem - clear Histogram memory before start stats engine. |
| 35 | */ | 33 | */ |
| @@ -62,20 +60,6 @@ static void hist_reset_mem(struct ispstat *hist) | |||
| 62 | hist->wait_acc_frames = conf->num_acc_frames; | 60 | hist->wait_acc_frames = conf->num_acc_frames; |
| 63 | } | 61 | } |
| 64 | 62 | ||
| 65 | static void hist_dma_config(struct ispstat *hist) | ||
| 66 | { | ||
| 67 | struct isp_device *isp = hist->isp; | ||
| 68 | |||
| 69 | hist->dma_config.data_type = OMAP_DMA_DATA_TYPE_S32; | ||
| 70 | hist->dma_config.sync_mode = OMAP_DMA_SYNC_ELEMENT; | ||
| 71 | hist->dma_config.frame_count = 1; | ||
| 72 | hist->dma_config.src_amode = OMAP_DMA_AMODE_CONSTANT; | ||
| 73 | hist->dma_config.src_start = isp->mmio_base_phys[OMAP3_ISP_IOMEM_HIST] | ||
| 74 | + ISPHIST_DATA; | ||
| 75 | hist->dma_config.dst_amode = OMAP_DMA_AMODE_POST_INC; | ||
| 76 | hist->dma_config.src_or_dst_synch = OMAP_DMA_SRC_SYNC; | ||
| 77 | } | ||
| 78 | |||
| 79 | /* | 63 | /* |
| 80 | * hist_setup_regs - Helper function to update Histogram registers. | 64 | * hist_setup_regs - Helper function to update Histogram registers. |
| 81 | */ | 65 | */ |
| @@ -176,17 +160,12 @@ static int hist_busy(struct ispstat *hist) | |||
| 176 | & ISPHIST_PCR_BUSY; | 160 | & ISPHIST_PCR_BUSY; |
| 177 | } | 161 | } |
| 178 | 162 | ||
| 179 | static void hist_dma_cb(int lch, u16 ch_status, void *data) | 163 | static void hist_dma_cb(void *data) |
| 180 | { | 164 | { |
| 181 | struct ispstat *hist = data; | 165 | struct ispstat *hist = data; |
| 182 | 166 | ||
| 183 | if (ch_status & ~OMAP_DMA_BLOCK_IRQ) { | 167 | /* FIXME: The DMA engine API can't report transfer errors :-/ */ |
| 184 | dev_dbg(hist->isp->dev, "hist: DMA error. status = 0x%04x\n", | 168 | |
| 185 | ch_status); | ||
| 186 | omap_stop_dma(lch); | ||
| 187 | hist_reset_mem(hist); | ||
| 188 | atomic_set(&hist->buf_err, 1); | ||
| 189 | } | ||
| 190 | isp_reg_clr(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, | 169 | isp_reg_clr(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, |
| 191 | ISPHIST_CNT_CLEAR); | 170 | ISPHIST_CNT_CLEAR); |
| 192 | 171 | ||
| @@ -198,24 +177,57 @@ static void hist_dma_cb(int lch, u16 ch_status, void *data) | |||
| 198 | static int hist_buf_dma(struct ispstat *hist) | 177 | static int hist_buf_dma(struct ispstat *hist) |
| 199 | { | 178 | { |
| 200 | dma_addr_t dma_addr = hist->active_buf->dma_addr; | 179 | dma_addr_t dma_addr = hist->active_buf->dma_addr; |
| 180 | struct dma_async_tx_descriptor *tx; | ||
| 181 | struct dma_slave_config cfg; | ||
| 182 | dma_cookie_t cookie; | ||
| 183 | int ret; | ||
| 201 | 184 | ||
| 202 | if (unlikely(!dma_addr)) { | 185 | if (unlikely(!dma_addr)) { |
| 203 | dev_dbg(hist->isp->dev, "hist: invalid DMA buffer address\n"); | 186 | dev_dbg(hist->isp->dev, "hist: invalid DMA buffer address\n"); |
| 204 | hist_reset_mem(hist); | 187 | goto error; |
| 205 | return STAT_NO_BUF; | ||
| 206 | } | 188 | } |
| 207 | 189 | ||
| 208 | isp_reg_writel(hist->isp, 0, OMAP3_ISP_IOMEM_HIST, ISPHIST_ADDR); | 190 | isp_reg_writel(hist->isp, 0, OMAP3_ISP_IOMEM_HIST, ISPHIST_ADDR); |
| 209 | isp_reg_set(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, | 191 | isp_reg_set(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, |
| 210 | ISPHIST_CNT_CLEAR); | 192 | ISPHIST_CNT_CLEAR); |
| 211 | omap3isp_flush(hist->isp); | 193 | omap3isp_flush(hist->isp); |
| 212 | hist->dma_config.dst_start = dma_addr; | ||
| 213 | hist->dma_config.elem_count = hist->buf_size / sizeof(u32); | ||
| 214 | omap_set_dma_params(hist->dma_ch, &hist->dma_config); | ||
| 215 | 194 | ||
| 216 | omap_start_dma(hist->dma_ch); | 195 | memset(&cfg, 0, sizeof(cfg)); |
| 196 | cfg.src_addr = hist->isp->mmio_hist_base_phys + ISPHIST_DATA; | ||
| 197 | cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; | ||
| 198 | cfg.src_maxburst = hist->buf_size / 4; | ||
| 199 | |||
| 200 | ret = dmaengine_slave_config(hist->dma_ch, &cfg); | ||
| 201 | if (ret < 0) { | ||
| 202 | dev_dbg(hist->isp->dev, | ||
| 203 | "hist: DMA slave configuration failed\n"); | ||
| 204 | goto error; | ||
| 205 | } | ||
| 206 | |||
| 207 | tx = dmaengine_prep_slave_single(hist->dma_ch, dma_addr, | ||
| 208 | hist->buf_size, DMA_DEV_TO_MEM, | ||
| 209 | DMA_CTRL_ACK); | ||
| 210 | if (tx == NULL) { | ||
| 211 | dev_dbg(hist->isp->dev, | ||
| 212 | "hist: DMA slave preparation failed\n"); | ||
| 213 | goto error; | ||
| 214 | } | ||
| 215 | |||
| 216 | tx->callback = hist_dma_cb; | ||
| 217 | tx->callback_param = hist; | ||
| 218 | cookie = tx->tx_submit(tx); | ||
| 219 | if (dma_submit_error(cookie)) { | ||
| 220 | dev_dbg(hist->isp->dev, "hist: DMA submission failed\n"); | ||
| 221 | goto error; | ||
| 222 | } | ||
| 223 | |||
| 224 | dma_async_issue_pending(hist->dma_ch); | ||
| 217 | 225 | ||
| 218 | return STAT_BUF_WAITING_DMA; | 226 | return STAT_BUF_WAITING_DMA; |
| 227 | |||
| 228 | error: | ||
| 229 | hist_reset_mem(hist); | ||
| 230 | return STAT_NO_BUF; | ||
| 219 | } | 231 | } |
| 220 | 232 | ||
| 221 | static int hist_buf_pio(struct ispstat *hist) | 233 | static int hist_buf_pio(struct ispstat *hist) |
| @@ -272,7 +284,7 @@ static int hist_buf_process(struct ispstat *hist) | |||
| 272 | if (--(hist->wait_acc_frames)) | 284 | if (--(hist->wait_acc_frames)) |
| 273 | return STAT_NO_BUF; | 285 | return STAT_NO_BUF; |
| 274 | 286 | ||
| 275 | if (HIST_USING_DMA(hist)) | 287 | if (hist->dma_ch) |
| 276 | ret = hist_buf_dma(hist); | 288 | ret = hist_buf_dma(hist); |
| 277 | else | 289 | else |
| 278 | ret = hist_buf_pio(hist); | 290 | ret = hist_buf_pio(hist); |
| @@ -473,18 +485,28 @@ int omap3isp_hist_init(struct isp_device *isp) | |||
| 473 | 485 | ||
| 474 | hist->isp = isp; | 486 | hist->isp = isp; |
| 475 | 487 | ||
| 476 | if (HIST_CONFIG_DMA) | 488 | if (HIST_CONFIG_DMA) { |
| 477 | ret = omap_request_dma(OMAP24XX_DMA_NO_DEVICE, "DMA_ISP_HIST", | 489 | struct platform_device *pdev = to_platform_device(isp->dev); |
| 478 | hist_dma_cb, hist, &hist->dma_ch); | 490 | struct resource *res; |
| 479 | if (ret) { | 491 | unsigned int sig = 0; |
| 480 | if (HIST_CONFIG_DMA) | 492 | dma_cap_mask_t mask; |
| 481 | dev_warn(isp->dev, "hist: DMA request channel failed. " | 493 | |
| 482 | "Using PIO only.\n"); | 494 | dma_cap_zero(mask); |
| 483 | hist->dma_ch = -1; | 495 | dma_cap_set(DMA_SLAVE, mask); |
| 484 | } else { | 496 | |
| 485 | dev_dbg(isp->dev, "hist: DMA channel = %d\n", hist->dma_ch); | 497 | res = platform_get_resource_byname(pdev, IORESOURCE_DMA, |
| 486 | hist_dma_config(hist); | 498 | "hist"); |
| 487 | omap_enable_dma_irq(hist->dma_ch, OMAP_DMA_BLOCK_IRQ); | 499 | if (res) |
| 500 | sig = res->start; | ||
| 501 | |||
| 502 | hist->dma_ch = dma_request_slave_channel_compat(mask, | ||
| 503 | omap_dma_filter_fn, &sig, isp->dev, "hist"); | ||
| 504 | if (!hist->dma_ch) | ||
| 505 | dev_warn(isp->dev, | ||
| 506 | "hist: DMA channel request failed, using PIO\n"); | ||
| 507 | else | ||
| 508 | dev_dbg(isp->dev, "hist: using DMA channel %s\n", | ||
| 509 | dma_chan_name(hist->dma_ch)); | ||
| 488 | } | 510 | } |
| 489 | 511 | ||
| 490 | hist->ops = &hist_ops; | 512 | hist->ops = &hist_ops; |
| @@ -493,8 +515,8 @@ int omap3isp_hist_init(struct isp_device *isp) | |||
| 493 | 515 | ||
| 494 | ret = omap3isp_stat_init(hist, "histogram", &hist_subdev_ops); | 516 | ret = omap3isp_stat_init(hist, "histogram", &hist_subdev_ops); |
| 495 | if (ret) { | 517 | if (ret) { |
| 496 | if (HIST_USING_DMA(hist)) | 518 | if (hist->dma_ch) |
| 497 | omap_free_dma(hist->dma_ch); | 519 | dma_release_channel(hist->dma_ch); |
| 498 | } | 520 | } |
| 499 | 521 | ||
| 500 | return ret; | 522 | return ret; |
| @@ -505,7 +527,10 @@ int omap3isp_hist_init(struct isp_device *isp) | |||
| 505 | */ | 527 | */ |
| 506 | void omap3isp_hist_cleanup(struct isp_device *isp) | 528 | void omap3isp_hist_cleanup(struct isp_device *isp) |
| 507 | { | 529 | { |
| 508 | if (HIST_USING_DMA(&isp->isp_hist)) | 530 | struct ispstat *hist = &isp->isp_hist; |
| 509 | omap_free_dma(isp->isp_hist.dma_ch); | 531 | |
| 510 | omap3isp_stat_cleanup(&isp->isp_hist); | 532 | if (hist->dma_ch) |
| 533 | dma_release_channel(hist->dma_ch); | ||
| 534 | |||
| 535 | omap3isp_stat_cleanup(hist); | ||
| 511 | } | 536 | } |
diff --git a/drivers/media/platform/omap3isp/isppreview.c b/drivers/media/platform/omap3isp/isppreview.c index dd9eed45d853..15cb254ccc39 100644 --- a/drivers/media/platform/omap3isp/isppreview.c +++ b/drivers/media/platform/omap3isp/isppreview.c | |||
| @@ -1686,21 +1686,21 @@ static int preview_set_stream(struct v4l2_subdev *sd, int enable) | |||
| 1686 | } | 1686 | } |
| 1687 | 1687 | ||
| 1688 | static struct v4l2_mbus_framefmt * | 1688 | static struct v4l2_mbus_framefmt * |
| 1689 | __preview_get_format(struct isp_prev_device *prev, struct v4l2_subdev_fh *fh, | 1689 | __preview_get_format(struct isp_prev_device *prev, struct v4l2_subdev_pad_config *cfg, |
| 1690 | unsigned int pad, enum v4l2_subdev_format_whence which) | 1690 | unsigned int pad, enum v4l2_subdev_format_whence which) |
| 1691 | { | 1691 | { |
| 1692 | if (which == V4L2_SUBDEV_FORMAT_TRY) | 1692 | if (which == V4L2_SUBDEV_FORMAT_TRY) |
| 1693 | return v4l2_subdev_get_try_format(fh, pad); | 1693 | return v4l2_subdev_get_try_format(&prev->subdev, cfg, pad); |
| 1694 | else | 1694 | else |
| 1695 | return &prev->formats[pad]; | 1695 | return &prev->formats[pad]; |
| 1696 | } | 1696 | } |
| 1697 | 1697 | ||
| 1698 | static struct v4l2_rect * | 1698 | static struct v4l2_rect * |
| 1699 | __preview_get_crop(struct isp_prev_device *prev, struct v4l2_subdev_fh *fh, | 1699 | __preview_get_crop(struct isp_prev_device *prev, struct v4l2_subdev_pad_config *cfg, |
| 1700 | enum v4l2_subdev_format_whence which) | 1700 | enum v4l2_subdev_format_whence which) |
| 1701 | { | 1701 | { |
| 1702 | if (which == V4L2_SUBDEV_FORMAT_TRY) | 1702 | if (which == V4L2_SUBDEV_FORMAT_TRY) |
| 1703 | return v4l2_subdev_get_try_crop(fh, PREV_PAD_SINK); | 1703 | return v4l2_subdev_get_try_crop(&prev->subdev, cfg, PREV_PAD_SINK); |
| 1704 | else | 1704 | else |
| 1705 | return &prev->crop; | 1705 | return &prev->crop; |
| 1706 | } | 1706 | } |
| @@ -1727,7 +1727,7 @@ static const unsigned int preview_output_fmts[] = { | |||
| 1727 | /* | 1727 | /* |
| 1728 | * preview_try_format - Validate a format | 1728 | * preview_try_format - Validate a format |
| 1729 | * @prev: ISP preview engine | 1729 | * @prev: ISP preview engine |
| 1730 | * @fh: V4L2 subdev file handle | 1730 | * @cfg: V4L2 subdev pad configuration |
| 1731 | * @pad: pad number | 1731 | * @pad: pad number |
| 1732 | * @fmt: format to be validated | 1732 | * @fmt: format to be validated |
| 1733 | * @which: try/active format selector | 1733 | * @which: try/active format selector |
| @@ -1736,7 +1736,7 @@ static const unsigned int preview_output_fmts[] = { | |||
| 1736 | * engine limits and the format and crop rectangles on other pads. | 1736 | * engine limits and the format and crop rectangles on other pads. |
| 1737 | */ | 1737 | */ |
| 1738 | static void preview_try_format(struct isp_prev_device *prev, | 1738 | static void preview_try_format(struct isp_prev_device *prev, |
| 1739 | struct v4l2_subdev_fh *fh, unsigned int pad, | 1739 | struct v4l2_subdev_pad_config *cfg, unsigned int pad, |
| 1740 | struct v4l2_mbus_framefmt *fmt, | 1740 | struct v4l2_mbus_framefmt *fmt, |
| 1741 | enum v4l2_subdev_format_whence which) | 1741 | enum v4l2_subdev_format_whence which) |
| 1742 | { | 1742 | { |
| @@ -1777,7 +1777,7 @@ static void preview_try_format(struct isp_prev_device *prev, | |||
| 1777 | 1777 | ||
| 1778 | case PREV_PAD_SOURCE: | 1778 | case PREV_PAD_SOURCE: |
| 1779 | pixelcode = fmt->code; | 1779 | pixelcode = fmt->code; |
| 1780 | *fmt = *__preview_get_format(prev, fh, PREV_PAD_SINK, which); | 1780 | *fmt = *__preview_get_format(prev, cfg, PREV_PAD_SINK, which); |
| 1781 | 1781 | ||
| 1782 | switch (pixelcode) { | 1782 | switch (pixelcode) { |
| 1783 | case MEDIA_BUS_FMT_YUYV8_1X16: | 1783 | case MEDIA_BUS_FMT_YUYV8_1X16: |
| @@ -1795,7 +1795,7 @@ static void preview_try_format(struct isp_prev_device *prev, | |||
| 1795 | * is not supported yet, hardcode the output size to the crop | 1795 | * is not supported yet, hardcode the output size to the crop |
| 1796 | * rectangle size. | 1796 | * rectangle size. |
| 1797 | */ | 1797 | */ |
| 1798 | crop = __preview_get_crop(prev, fh, which); | 1798 | crop = __preview_get_crop(prev, cfg, which); |
| 1799 | fmt->width = crop->width; | 1799 | fmt->width = crop->width; |
| 1800 | fmt->height = crop->height; | 1800 | fmt->height = crop->height; |
| 1801 | 1801 | ||
| @@ -1864,12 +1864,12 @@ static void preview_try_crop(struct isp_prev_device *prev, | |||
| 1864 | /* | 1864 | /* |
| 1865 | * preview_enum_mbus_code - Handle pixel format enumeration | 1865 | * preview_enum_mbus_code - Handle pixel format enumeration |
| 1866 | * @sd : pointer to v4l2 subdev structure | 1866 | * @sd : pointer to v4l2 subdev structure |
| 1867 | * @fh : V4L2 subdev file handle | 1867 | * @cfg: V4L2 subdev pad configuration |
| 1868 | * @code : pointer to v4l2_subdev_mbus_code_enum structure | 1868 | * @code : pointer to v4l2_subdev_mbus_code_enum structure |
| 1869 | * return -EINVAL or zero on success | 1869 | * return -EINVAL or zero on success |
| 1870 | */ | 1870 | */ |
| 1871 | static int preview_enum_mbus_code(struct v4l2_subdev *sd, | 1871 | static int preview_enum_mbus_code(struct v4l2_subdev *sd, |
| 1872 | struct v4l2_subdev_fh *fh, | 1872 | struct v4l2_subdev_pad_config *cfg, |
| 1873 | struct v4l2_subdev_mbus_code_enum *code) | 1873 | struct v4l2_subdev_mbus_code_enum *code) |
| 1874 | { | 1874 | { |
| 1875 | switch (code->pad) { | 1875 | switch (code->pad) { |
| @@ -1893,7 +1893,7 @@ static int preview_enum_mbus_code(struct v4l2_subdev *sd, | |||
| 1893 | } | 1893 | } |
| 1894 | 1894 | ||
| 1895 | static int preview_enum_frame_size(struct v4l2_subdev *sd, | 1895 | static int preview_enum_frame_size(struct v4l2_subdev *sd, |
| 1896 | struct v4l2_subdev_fh *fh, | 1896 | struct v4l2_subdev_pad_config *cfg, |
| 1897 | struct v4l2_subdev_frame_size_enum *fse) | 1897 | struct v4l2_subdev_frame_size_enum *fse) |
| 1898 | { | 1898 | { |
| 1899 | struct isp_prev_device *prev = v4l2_get_subdevdata(sd); | 1899 | struct isp_prev_device *prev = v4l2_get_subdevdata(sd); |
| @@ -1905,7 +1905,7 @@ static int preview_enum_frame_size(struct v4l2_subdev *sd, | |||
| 1905 | format.code = fse->code; | 1905 | format.code = fse->code; |
| 1906 | format.width = 1; | 1906 | format.width = 1; |
| 1907 | format.height = 1; | 1907 | format.height = 1; |
| 1908 | preview_try_format(prev, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); | 1908 | preview_try_format(prev, cfg, fse->pad, &format, fse->which); |
| 1909 | fse->min_width = format.width; | 1909 | fse->min_width = format.width; |
| 1910 | fse->min_height = format.height; | 1910 | fse->min_height = format.height; |
| 1911 | 1911 | ||
| @@ -1915,7 +1915,7 @@ static int preview_enum_frame_size(struct v4l2_subdev *sd, | |||
| 1915 | format.code = fse->code; | 1915 | format.code = fse->code; |
| 1916 | format.width = -1; | 1916 | format.width = -1; |
| 1917 | format.height = -1; | 1917 | format.height = -1; |
| 1918 | preview_try_format(prev, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); | 1918 | preview_try_format(prev, cfg, fse->pad, &format, fse->which); |
| 1919 | fse->max_width = format.width; | 1919 | fse->max_width = format.width; |
| 1920 | fse->max_height = format.height; | 1920 | fse->max_height = format.height; |
| 1921 | 1921 | ||
| @@ -1925,7 +1925,7 @@ static int preview_enum_frame_size(struct v4l2_subdev *sd, | |||
| 1925 | /* | 1925 | /* |
| 1926 | * preview_get_selection - Retrieve a selection rectangle on a pad | 1926 | * preview_get_selection - Retrieve a selection rectangle on a pad |
| 1927 | * @sd: ISP preview V4L2 subdevice | 1927 | * @sd: ISP preview V4L2 subdevice |
| 1928 | * @fh: V4L2 subdev file handle | 1928 | * @cfg: V4L2 subdev pad configuration |
| 1929 | * @sel: Selection rectangle | 1929 | * @sel: Selection rectangle |
| 1930 | * | 1930 | * |
| 1931 | * The only supported rectangles are the crop rectangles on the sink pad. | 1931 | * The only supported rectangles are the crop rectangles on the sink pad. |
| @@ -1933,7 +1933,7 @@ static int preview_enum_frame_size(struct v4l2_subdev *sd, | |||
| 1933 | * Return 0 on success or a negative error code otherwise. | 1933 | * Return 0 on success or a negative error code otherwise. |
| 1934 | */ | 1934 | */ |
| 1935 | static int preview_get_selection(struct v4l2_subdev *sd, | 1935 | static int preview_get_selection(struct v4l2_subdev *sd, |
| 1936 | struct v4l2_subdev_fh *fh, | 1936 | struct v4l2_subdev_pad_config *cfg, |
| 1937 | struct v4l2_subdev_selection *sel) | 1937 | struct v4l2_subdev_selection *sel) |
| 1938 | { | 1938 | { |
| 1939 | struct isp_prev_device *prev = v4l2_get_subdevdata(sd); | 1939 | struct isp_prev_device *prev = v4l2_get_subdevdata(sd); |
| @@ -1949,13 +1949,13 @@ static int preview_get_selection(struct v4l2_subdev *sd, | |||
| 1949 | sel->r.width = INT_MAX; | 1949 | sel->r.width = INT_MAX; |
| 1950 | sel->r.height = INT_MAX; | 1950 | sel->r.height = INT_MAX; |
| 1951 | 1951 | ||
| 1952 | format = __preview_get_format(prev, fh, PREV_PAD_SINK, | 1952 | format = __preview_get_format(prev, cfg, PREV_PAD_SINK, |
| 1953 | sel->which); | 1953 | sel->which); |
| 1954 | preview_try_crop(prev, format, &sel->r); | 1954 | preview_try_crop(prev, format, &sel->r); |
| 1955 | break; | 1955 | break; |
| 1956 | 1956 | ||
| 1957 | case V4L2_SEL_TGT_CROP: | 1957 | case V4L2_SEL_TGT_CROP: |
| 1958 | sel->r = *__preview_get_crop(prev, fh, sel->which); | 1958 | sel->r = *__preview_get_crop(prev, cfg, sel->which); |
| 1959 | break; | 1959 | break; |
| 1960 | 1960 | ||
| 1961 | default: | 1961 | default: |
| @@ -1968,7 +1968,7 @@ static int preview_get_selection(struct v4l2_subdev *sd, | |||
| 1968 | /* | 1968 | /* |
| 1969 | * preview_set_selection - Set a selection rectangle on a pad | 1969 | * preview_set_selection - Set a selection rectangle on a pad |
| 1970 | * @sd: ISP preview V4L2 subdevice | 1970 | * @sd: ISP preview V4L2 subdevice |
| 1971 | * @fh: V4L2 subdev file handle | 1971 | * @cfg: V4L2 subdev pad configuration |
| 1972 | * @sel: Selection rectangle | 1972 | * @sel: Selection rectangle |
| 1973 | * | 1973 | * |
| 1974 | * The only supported rectangle is the actual crop rectangle on the sink pad. | 1974 | * The only supported rectangle is the actual crop rectangle on the sink pad. |
| @@ -1976,7 +1976,7 @@ static int preview_get_selection(struct v4l2_subdev *sd, | |||
| 1976 | * Return 0 on success or a negative error code otherwise. | 1976 | * Return 0 on success or a negative error code otherwise. |
| 1977 | */ | 1977 | */ |
| 1978 | static int preview_set_selection(struct v4l2_subdev *sd, | 1978 | static int preview_set_selection(struct v4l2_subdev *sd, |
| 1979 | struct v4l2_subdev_fh *fh, | 1979 | struct v4l2_subdev_pad_config *cfg, |
| 1980 | struct v4l2_subdev_selection *sel) | 1980 | struct v4l2_subdev_selection *sel) |
| 1981 | { | 1981 | { |
| 1982 | struct isp_prev_device *prev = v4l2_get_subdevdata(sd); | 1982 | struct isp_prev_device *prev = v4l2_get_subdevdata(sd); |
| @@ -1995,17 +1995,17 @@ static int preview_set_selection(struct v4l2_subdev *sd, | |||
| 1995 | * rectangle. | 1995 | * rectangle. |
| 1996 | */ | 1996 | */ |
| 1997 | if (sel->flags & V4L2_SEL_FLAG_KEEP_CONFIG) { | 1997 | if (sel->flags & V4L2_SEL_FLAG_KEEP_CONFIG) { |
| 1998 | sel->r = *__preview_get_crop(prev, fh, sel->which); | 1998 | sel->r = *__preview_get_crop(prev, cfg, sel->which); |
| 1999 | return 0; | 1999 | return 0; |
| 2000 | } | 2000 | } |
| 2001 | 2001 | ||
| 2002 | format = __preview_get_format(prev, fh, PREV_PAD_SINK, sel->which); | 2002 | format = __preview_get_format(prev, cfg, PREV_PAD_SINK, sel->which); |
| 2003 | preview_try_crop(prev, format, &sel->r); | 2003 | preview_try_crop(prev, format, &sel->r); |
| 2004 | *__preview_get_crop(prev, fh, sel->which) = sel->r; | 2004 | *__preview_get_crop(prev, cfg, sel->which) = sel->r; |
| 2005 | 2005 | ||
| 2006 | /* Update the source format. */ | 2006 | /* Update the source format. */ |
| 2007 | format = __preview_get_format(prev, fh, PREV_PAD_SOURCE, sel->which); | 2007 | format = __preview_get_format(prev, cfg, PREV_PAD_SOURCE, sel->which); |
| 2008 | preview_try_format(prev, fh, PREV_PAD_SOURCE, format, sel->which); | 2008 | preview_try_format(prev, cfg, PREV_PAD_SOURCE, format, sel->which); |
| 2009 | 2009 | ||
| 2010 | return 0; | 2010 | return 0; |
| 2011 | } | 2011 | } |
| @@ -2013,17 +2013,17 @@ static int preview_set_selection(struct v4l2_subdev *sd, | |||
| 2013 | /* | 2013 | /* |
| 2014 | * preview_get_format - Handle get format by pads subdev method | 2014 | * preview_get_format - Handle get format by pads subdev method |
| 2015 | * @sd : pointer to v4l2 subdev structure | 2015 | * @sd : pointer to v4l2 subdev structure |
| 2016 | * @fh : V4L2 subdev file handle | 2016 | * @cfg: V4L2 subdev pad configuration |
| 2017 | * @fmt: pointer to v4l2 subdev format structure | 2017 | * @fmt: pointer to v4l2 subdev format structure |
| 2018 | * return -EINVAL or zero on success | 2018 | * return -EINVAL or zero on success |
| 2019 | */ | 2019 | */ |
| 2020 | static int preview_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | 2020 | static int preview_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, |
| 2021 | struct v4l2_subdev_format *fmt) | 2021 | struct v4l2_subdev_format *fmt) |
| 2022 | { | 2022 | { |
| 2023 | struct isp_prev_device *prev = v4l2_get_subdevdata(sd); | 2023 | struct isp_prev_device *prev = v4l2_get_subdevdata(sd); |
| 2024 | struct v4l2_mbus_framefmt *format; | 2024 | struct v4l2_mbus_framefmt *format; |
| 2025 | 2025 | ||
| 2026 | format = __preview_get_format(prev, fh, fmt->pad, fmt->which); | 2026 | format = __preview_get_format(prev, cfg, fmt->pad, fmt->which); |
| 2027 | if (format == NULL) | 2027 | if (format == NULL) |
| 2028 | return -EINVAL; | 2028 | return -EINVAL; |
| 2029 | 2029 | ||
| @@ -2034,28 +2034,28 @@ static int preview_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | |||
| 2034 | /* | 2034 | /* |
| 2035 | * preview_set_format - Handle set format by pads subdev method | 2035 | * preview_set_format - Handle set format by pads subdev method |
| 2036 | * @sd : pointer to v4l2 subdev structure | 2036 | * @sd : pointer to v4l2 subdev structure |
| 2037 | * @fh : V4L2 subdev file handle | 2037 | * @cfg: V4L2 subdev pad configuration |
| 2038 | * @fmt: pointer to v4l2 subdev format structure | 2038 | * @fmt: pointer to v4l2 subdev format structure |
| 2039 | * return -EINVAL or zero on success | 2039 | * return -EINVAL or zero on success |
| 2040 | */ | 2040 | */ |
| 2041 | static int preview_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | 2041 | static int preview_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, |
| 2042 | struct v4l2_subdev_format *fmt) | 2042 | struct v4l2_subdev_format *fmt) |
| 2043 | { | 2043 | { |
| 2044 | struct isp_prev_device *prev = v4l2_get_subdevdata(sd); | 2044 | struct isp_prev_device *prev = v4l2_get_subdevdata(sd); |
| 2045 | struct v4l2_mbus_framefmt *format; | 2045 | struct v4l2_mbus_framefmt *format; |
| 2046 | struct v4l2_rect *crop; | 2046 | struct v4l2_rect *crop; |
| 2047 | 2047 | ||
| 2048 | format = __preview_get_format(prev, fh, fmt->pad, fmt->which); | 2048 | format = __preview_get_format(prev, cfg, fmt->pad, fmt->which); |
| 2049 | if (format == NULL) | 2049 | if (format == NULL) |
| 2050 | return -EINVAL; | 2050 | return -EINVAL; |
| 2051 | 2051 | ||
| 2052 | preview_try_format(prev, fh, fmt->pad, &fmt->format, fmt->which); | 2052 | preview_try_format(prev, cfg, fmt->pad, &fmt->format, fmt->which); |
| 2053 | *format = fmt->format; | 2053 | *format = fmt->format; |
| 2054 | 2054 | ||
| 2055 | /* Propagate the format from sink to source */ | 2055 | /* Propagate the format from sink to source */ |
| 2056 | if (fmt->pad == PREV_PAD_SINK) { | 2056 | if (fmt->pad == PREV_PAD_SINK) { |
| 2057 | /* Reset the crop rectangle. */ | 2057 | /* Reset the crop rectangle. */ |
| 2058 | crop = __preview_get_crop(prev, fh, fmt->which); | 2058 | crop = __preview_get_crop(prev, cfg, fmt->which); |
| 2059 | crop->left = 0; | 2059 | crop->left = 0; |
| 2060 | crop->top = 0; | 2060 | crop->top = 0; |
| 2061 | crop->width = fmt->format.width; | 2061 | crop->width = fmt->format.width; |
| @@ -2064,9 +2064,9 @@ static int preview_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | |||
| 2064 | preview_try_crop(prev, &fmt->format, crop); | 2064 | preview_try_crop(prev, &fmt->format, crop); |
| 2065 | 2065 | ||
| 2066 | /* Update the source format. */ | 2066 | /* Update the source format. */ |
| 2067 | format = __preview_get_format(prev, fh, PREV_PAD_SOURCE, | 2067 | format = __preview_get_format(prev, cfg, PREV_PAD_SOURCE, |
| 2068 | fmt->which); | 2068 | fmt->which); |
| 2069 | preview_try_format(prev, fh, PREV_PAD_SOURCE, format, | 2069 | preview_try_format(prev, cfg, PREV_PAD_SOURCE, format, |
| 2070 | fmt->which); | 2070 | fmt->which); |
| 2071 | } | 2071 | } |
| 2072 | 2072 | ||
| @@ -2093,7 +2093,7 @@ static int preview_init_formats(struct v4l2_subdev *sd, | |||
| 2093 | format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10; | 2093 | format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10; |
| 2094 | format.format.width = 4096; | 2094 | format.format.width = 4096; |
| 2095 | format.format.height = 4096; | 2095 | format.format.height = 4096; |
| 2096 | preview_set_format(sd, fh, &format); | 2096 | preview_set_format(sd, fh ? fh->pad : NULL, &format); |
| 2097 | 2097 | ||
| 2098 | return 0; | 2098 | return 0; |
| 2099 | } | 2099 | } |
diff --git a/drivers/media/platform/omap3isp/ispresizer.c b/drivers/media/platform/omap3isp/ispresizer.c index 2b9bc4839876..7cfb43dc0ffd 100644 --- a/drivers/media/platform/omap3isp/ispresizer.c +++ b/drivers/media/platform/omap3isp/ispresizer.c | |||
| @@ -112,16 +112,16 @@ static const struct isprsz_coef filter_coefs = { | |||
| 112 | * __resizer_get_format - helper function for getting resizer format | 112 | * __resizer_get_format - helper function for getting resizer format |
| 113 | * @res : pointer to resizer private structure | 113 | * @res : pointer to resizer private structure |
| 114 | * @pad : pad number | 114 | * @pad : pad number |
| 115 | * @fh : V4L2 subdev file handle | 115 | * @cfg: V4L2 subdev pad configuration |
| 116 | * @which : wanted subdev format | 116 | * @which : wanted subdev format |
| 117 | * return zero | 117 | * return zero |
| 118 | */ | 118 | */ |
| 119 | static struct v4l2_mbus_framefmt * | 119 | static struct v4l2_mbus_framefmt * |
| 120 | __resizer_get_format(struct isp_res_device *res, struct v4l2_subdev_fh *fh, | 120 | __resizer_get_format(struct isp_res_device *res, struct v4l2_subdev_pad_config *cfg, |
| 121 | unsigned int pad, enum v4l2_subdev_format_whence which) | 121 | unsigned int pad, enum v4l2_subdev_format_whence which) |
| 122 | { | 122 | { |
| 123 | if (which == V4L2_SUBDEV_FORMAT_TRY) | 123 | if (which == V4L2_SUBDEV_FORMAT_TRY) |
| 124 | return v4l2_subdev_get_try_format(fh, pad); | 124 | return v4l2_subdev_get_try_format(&res->subdev, cfg, pad); |
| 125 | else | 125 | else |
| 126 | return &res->formats[pad]; | 126 | return &res->formats[pad]; |
| 127 | } | 127 | } |
| @@ -129,15 +129,15 @@ __resizer_get_format(struct isp_res_device *res, struct v4l2_subdev_fh *fh, | |||
| 129 | /* | 129 | /* |
| 130 | * __resizer_get_crop - helper function for getting resizer crop rectangle | 130 | * __resizer_get_crop - helper function for getting resizer crop rectangle |
| 131 | * @res : pointer to resizer private structure | 131 | * @res : pointer to resizer private structure |
| 132 | * @fh : V4L2 subdev file handle | 132 | * @cfg: V4L2 subdev pad configuration |
| 133 | * @which : wanted subdev crop rectangle | 133 | * @which : wanted subdev crop rectangle |
| 134 | */ | 134 | */ |
| 135 | static struct v4l2_rect * | 135 | static struct v4l2_rect * |
| 136 | __resizer_get_crop(struct isp_res_device *res, struct v4l2_subdev_fh *fh, | 136 | __resizer_get_crop(struct isp_res_device *res, struct v4l2_subdev_pad_config *cfg, |
| 137 | enum v4l2_subdev_format_whence which) | 137 | enum v4l2_subdev_format_whence which) |
| 138 | { | 138 | { |
| 139 | if (which == V4L2_SUBDEV_FORMAT_TRY) | 139 | if (which == V4L2_SUBDEV_FORMAT_TRY) |
| 140 | return v4l2_subdev_get_try_crop(fh, RESZ_PAD_SINK); | 140 | return v4l2_subdev_get_try_crop(&res->subdev, cfg, RESZ_PAD_SINK); |
| 141 | else | 141 | else |
| 142 | return &res->crop.request; | 142 | return &res->crop.request; |
| 143 | } | 143 | } |
| @@ -1215,7 +1215,7 @@ static void resizer_try_crop(const struct v4l2_mbus_framefmt *sink, | |||
| 1215 | /* | 1215 | /* |
| 1216 | * resizer_get_selection - Retrieve a selection rectangle on a pad | 1216 | * resizer_get_selection - Retrieve a selection rectangle on a pad |
| 1217 | * @sd: ISP resizer V4L2 subdevice | 1217 | * @sd: ISP resizer V4L2 subdevice |
| 1218 | * @fh: V4L2 subdev file handle | 1218 | * @cfg: V4L2 subdev pad configuration |
| 1219 | * @sel: Selection rectangle | 1219 | * @sel: Selection rectangle |
| 1220 | * | 1220 | * |
| 1221 | * The only supported rectangles are the crop rectangles on the sink pad. | 1221 | * The only supported rectangles are the crop rectangles on the sink pad. |
| @@ -1223,7 +1223,7 @@ static void resizer_try_crop(const struct v4l2_mbus_framefmt *sink, | |||
| 1223 | * Return 0 on success or a negative error code otherwise. | 1223 | * Return 0 on success or a negative error code otherwise. |
| 1224 | */ | 1224 | */ |
| 1225 | static int resizer_get_selection(struct v4l2_subdev *sd, | 1225 | static int resizer_get_selection(struct v4l2_subdev *sd, |
| 1226 | struct v4l2_subdev_fh *fh, | 1226 | struct v4l2_subdev_pad_config *cfg, |
| 1227 | struct v4l2_subdev_selection *sel) | 1227 | struct v4l2_subdev_selection *sel) |
| 1228 | { | 1228 | { |
| 1229 | struct isp_res_device *res = v4l2_get_subdevdata(sd); | 1229 | struct isp_res_device *res = v4l2_get_subdevdata(sd); |
| @@ -1234,9 +1234,9 @@ static int resizer_get_selection(struct v4l2_subdev *sd, | |||
| 1234 | if (sel->pad != RESZ_PAD_SINK) | 1234 | if (sel->pad != RESZ_PAD_SINK) |
| 1235 | return -EINVAL; | 1235 | return -EINVAL; |
| 1236 | 1236 | ||
| 1237 | format_sink = __resizer_get_format(res, fh, RESZ_PAD_SINK, | 1237 | format_sink = __resizer_get_format(res, cfg, RESZ_PAD_SINK, |
| 1238 | sel->which); | 1238 | sel->which); |
| 1239 | format_source = __resizer_get_format(res, fh, RESZ_PAD_SOURCE, | 1239 | format_source = __resizer_get_format(res, cfg, RESZ_PAD_SOURCE, |
| 1240 | sel->which); | 1240 | sel->which); |
| 1241 | 1241 | ||
| 1242 | switch (sel->target) { | 1242 | switch (sel->target) { |
| @@ -1251,7 +1251,7 @@ static int resizer_get_selection(struct v4l2_subdev *sd, | |||
| 1251 | break; | 1251 | break; |
| 1252 | 1252 | ||
| 1253 | case V4L2_SEL_TGT_CROP: | 1253 | case V4L2_SEL_TGT_CROP: |
| 1254 | sel->r = *__resizer_get_crop(res, fh, sel->which); | 1254 | sel->r = *__resizer_get_crop(res, cfg, sel->which); |
| 1255 | resizer_calc_ratios(res, &sel->r, format_source, &ratio); | 1255 | resizer_calc_ratios(res, &sel->r, format_source, &ratio); |
| 1256 | break; | 1256 | break; |
| 1257 | 1257 | ||
| @@ -1265,7 +1265,7 @@ static int resizer_get_selection(struct v4l2_subdev *sd, | |||
| 1265 | /* | 1265 | /* |
| 1266 | * resizer_set_selection - Set a selection rectangle on a pad | 1266 | * resizer_set_selection - Set a selection rectangle on a pad |
| 1267 | * @sd: ISP resizer V4L2 subdevice | 1267 | * @sd: ISP resizer V4L2 subdevice |
| 1268 | * @fh: V4L2 subdev file handle | 1268 | * @cfg: V4L2 subdev pad configuration |
| 1269 | * @sel: Selection rectangle | 1269 | * @sel: Selection rectangle |
| 1270 | * | 1270 | * |
| 1271 | * The only supported rectangle is the actual crop rectangle on the sink pad. | 1271 | * The only supported rectangle is the actual crop rectangle on the sink pad. |
| @@ -1276,7 +1276,7 @@ static int resizer_get_selection(struct v4l2_subdev *sd, | |||
| 1276 | * Return 0 on success or a negative error code otherwise. | 1276 | * Return 0 on success or a negative error code otherwise. |
| 1277 | */ | 1277 | */ |
| 1278 | static int resizer_set_selection(struct v4l2_subdev *sd, | 1278 | static int resizer_set_selection(struct v4l2_subdev *sd, |
| 1279 | struct v4l2_subdev_fh *fh, | 1279 | struct v4l2_subdev_pad_config *cfg, |
| 1280 | struct v4l2_subdev_selection *sel) | 1280 | struct v4l2_subdev_selection *sel) |
| 1281 | { | 1281 | { |
| 1282 | struct isp_res_device *res = v4l2_get_subdevdata(sd); | 1282 | struct isp_res_device *res = v4l2_get_subdevdata(sd); |
| @@ -1290,9 +1290,9 @@ static int resizer_set_selection(struct v4l2_subdev *sd, | |||
| 1290 | sel->pad != RESZ_PAD_SINK) | 1290 | sel->pad != RESZ_PAD_SINK) |
| 1291 | return -EINVAL; | 1291 | return -EINVAL; |
| 1292 | 1292 | ||
| 1293 | format_sink = __resizer_get_format(res, fh, RESZ_PAD_SINK, | 1293 | format_sink = __resizer_get_format(res, cfg, RESZ_PAD_SINK, |
| 1294 | sel->which); | 1294 | sel->which); |
| 1295 | format_source = *__resizer_get_format(res, fh, RESZ_PAD_SOURCE, | 1295 | format_source = *__resizer_get_format(res, cfg, RESZ_PAD_SOURCE, |
| 1296 | sel->which); | 1296 | sel->which); |
| 1297 | 1297 | ||
| 1298 | dev_dbg(isp->dev, "%s(%s): req %ux%u -> (%d,%d)/%ux%u -> %ux%u\n", | 1298 | dev_dbg(isp->dev, "%s(%s): req %ux%u -> (%d,%d)/%ux%u -> %ux%u\n", |
| @@ -1310,7 +1310,7 @@ static int resizer_set_selection(struct v4l2_subdev *sd, | |||
| 1310 | * stored the mangled rectangle. | 1310 | * stored the mangled rectangle. |
| 1311 | */ | 1311 | */ |
| 1312 | resizer_try_crop(format_sink, &format_source, &sel->r); | 1312 | resizer_try_crop(format_sink, &format_source, &sel->r); |
| 1313 | *__resizer_get_crop(res, fh, sel->which) = sel->r; | 1313 | *__resizer_get_crop(res, cfg, sel->which) = sel->r; |
| 1314 | resizer_calc_ratios(res, &sel->r, &format_source, &ratio); | 1314 | resizer_calc_ratios(res, &sel->r, &format_source, &ratio); |
| 1315 | 1315 | ||
| 1316 | dev_dbg(isp->dev, "%s(%s): got %ux%u -> (%d,%d)/%ux%u -> %ux%u\n", | 1316 | dev_dbg(isp->dev, "%s(%s): got %ux%u -> (%d,%d)/%ux%u -> %ux%u\n", |
| @@ -1320,7 +1320,7 @@ static int resizer_set_selection(struct v4l2_subdev *sd, | |||
| 1320 | format_source.width, format_source.height); | 1320 | format_source.width, format_source.height); |
| 1321 | 1321 | ||
| 1322 | if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { | 1322 | if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { |
| 1323 | *__resizer_get_format(res, fh, RESZ_PAD_SOURCE, sel->which) = | 1323 | *__resizer_get_format(res, cfg, RESZ_PAD_SOURCE, sel->which) = |
| 1324 | format_source; | 1324 | format_source; |
| 1325 | return 0; | 1325 | return 0; |
| 1326 | } | 1326 | } |
| @@ -1331,7 +1331,7 @@ static int resizer_set_selection(struct v4l2_subdev *sd, | |||
| 1331 | */ | 1331 | */ |
| 1332 | spin_lock_irqsave(&res->lock, flags); | 1332 | spin_lock_irqsave(&res->lock, flags); |
| 1333 | 1333 | ||
| 1334 | *__resizer_get_format(res, fh, RESZ_PAD_SOURCE, sel->which) = | 1334 | *__resizer_get_format(res, cfg, RESZ_PAD_SOURCE, sel->which) = |
| 1335 | format_source; | 1335 | format_source; |
| 1336 | 1336 | ||
| 1337 | res->ratio = ratio; | 1337 | res->ratio = ratio; |
| @@ -1368,13 +1368,13 @@ static unsigned int resizer_max_in_width(struct isp_res_device *res) | |||
| 1368 | /* | 1368 | /* |
| 1369 | * resizer_try_format - Handle try format by pad subdev method | 1369 | * resizer_try_format - Handle try format by pad subdev method |
| 1370 | * @res : ISP resizer device | 1370 | * @res : ISP resizer device |
| 1371 | * @fh : V4L2 subdev file handle | 1371 | * @cfg: V4L2 subdev pad configuration |
| 1372 | * @pad : pad num | 1372 | * @pad : pad num |
| 1373 | * @fmt : pointer to v4l2 format structure | 1373 | * @fmt : pointer to v4l2 format structure |
| 1374 | * @which : wanted subdev format | 1374 | * @which : wanted subdev format |
| 1375 | */ | 1375 | */ |
| 1376 | static void resizer_try_format(struct isp_res_device *res, | 1376 | static void resizer_try_format(struct isp_res_device *res, |
| 1377 | struct v4l2_subdev_fh *fh, unsigned int pad, | 1377 | struct v4l2_subdev_pad_config *cfg, unsigned int pad, |
| 1378 | struct v4l2_mbus_framefmt *fmt, | 1378 | struct v4l2_mbus_framefmt *fmt, |
| 1379 | enum v4l2_subdev_format_whence which) | 1379 | enum v4l2_subdev_format_whence which) |
| 1380 | { | 1380 | { |
| @@ -1395,10 +1395,10 @@ static void resizer_try_format(struct isp_res_device *res, | |||
| 1395 | break; | 1395 | break; |
| 1396 | 1396 | ||
| 1397 | case RESZ_PAD_SOURCE: | 1397 | case RESZ_PAD_SOURCE: |
| 1398 | format = __resizer_get_format(res, fh, RESZ_PAD_SINK, which); | 1398 | format = __resizer_get_format(res, cfg, RESZ_PAD_SINK, which); |
| 1399 | fmt->code = format->code; | 1399 | fmt->code = format->code; |
| 1400 | 1400 | ||
| 1401 | crop = *__resizer_get_crop(res, fh, which); | 1401 | crop = *__resizer_get_crop(res, cfg, which); |
| 1402 | resizer_calc_ratios(res, &crop, fmt, &ratio); | 1402 | resizer_calc_ratios(res, &crop, fmt, &ratio); |
| 1403 | break; | 1403 | break; |
| 1404 | } | 1404 | } |
| @@ -1410,12 +1410,12 @@ static void resizer_try_format(struct isp_res_device *res, | |||
| 1410 | /* | 1410 | /* |
| 1411 | * resizer_enum_mbus_code - Handle pixel format enumeration | 1411 | * resizer_enum_mbus_code - Handle pixel format enumeration |
| 1412 | * @sd : pointer to v4l2 subdev structure | 1412 | * @sd : pointer to v4l2 subdev structure |
| 1413 | * @fh : V4L2 subdev file handle | 1413 | * @cfg: V4L2 subdev pad configuration |
| 1414 | * @code : pointer to v4l2_subdev_mbus_code_enum structure | 1414 | * @code : pointer to v4l2_subdev_mbus_code_enum structure |
| 1415 | * return -EINVAL or zero on success | 1415 | * return -EINVAL or zero on success |
| 1416 | */ | 1416 | */ |
| 1417 | static int resizer_enum_mbus_code(struct v4l2_subdev *sd, | 1417 | static int resizer_enum_mbus_code(struct v4l2_subdev *sd, |
| 1418 | struct v4l2_subdev_fh *fh, | 1418 | struct v4l2_subdev_pad_config *cfg, |
| 1419 | struct v4l2_subdev_mbus_code_enum *code) | 1419 | struct v4l2_subdev_mbus_code_enum *code) |
| 1420 | { | 1420 | { |
| 1421 | struct isp_res_device *res = v4l2_get_subdevdata(sd); | 1421 | struct isp_res_device *res = v4l2_get_subdevdata(sd); |
| @@ -1430,8 +1430,8 @@ static int resizer_enum_mbus_code(struct v4l2_subdev *sd, | |||
| 1430 | if (code->index != 0) | 1430 | if (code->index != 0) |
| 1431 | return -EINVAL; | 1431 | return -EINVAL; |
| 1432 | 1432 | ||
| 1433 | format = __resizer_get_format(res, fh, RESZ_PAD_SINK, | 1433 | format = __resizer_get_format(res, cfg, RESZ_PAD_SINK, |
| 1434 | V4L2_SUBDEV_FORMAT_TRY); | 1434 | code->which); |
| 1435 | code->code = format->code; | 1435 | code->code = format->code; |
| 1436 | } | 1436 | } |
| 1437 | 1437 | ||
| @@ -1439,7 +1439,7 @@ static int resizer_enum_mbus_code(struct v4l2_subdev *sd, | |||
| 1439 | } | 1439 | } |
| 1440 | 1440 | ||
| 1441 | static int resizer_enum_frame_size(struct v4l2_subdev *sd, | 1441 | static int resizer_enum_frame_size(struct v4l2_subdev *sd, |
| 1442 | struct v4l2_subdev_fh *fh, | 1442 | struct v4l2_subdev_pad_config *cfg, |
| 1443 | struct v4l2_subdev_frame_size_enum *fse) | 1443 | struct v4l2_subdev_frame_size_enum *fse) |
| 1444 | { | 1444 | { |
| 1445 | struct isp_res_device *res = v4l2_get_subdevdata(sd); | 1445 | struct isp_res_device *res = v4l2_get_subdevdata(sd); |
| @@ -1451,7 +1451,7 @@ static int resizer_enum_frame_size(struct v4l2_subdev *sd, | |||
| 1451 | format.code = fse->code; | 1451 | format.code = fse->code; |
| 1452 | format.width = 1; | 1452 | format.width = 1; |
| 1453 | format.height = 1; | 1453 | format.height = 1; |
| 1454 | resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); | 1454 | resizer_try_format(res, cfg, fse->pad, &format, fse->which); |
| 1455 | fse->min_width = format.width; | 1455 | fse->min_width = format.width; |
| 1456 | fse->min_height = format.height; | 1456 | fse->min_height = format.height; |
| 1457 | 1457 | ||
| @@ -1461,7 +1461,7 @@ static int resizer_enum_frame_size(struct v4l2_subdev *sd, | |||
| 1461 | format.code = fse->code; | 1461 | format.code = fse->code; |
| 1462 | format.width = -1; | 1462 | format.width = -1; |
| 1463 | format.height = -1; | 1463 | format.height = -1; |
| 1464 | resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); | 1464 | resizer_try_format(res, cfg, fse->pad, &format, fse->which); |
| 1465 | fse->max_width = format.width; | 1465 | fse->max_width = format.width; |
| 1466 | fse->max_height = format.height; | 1466 | fse->max_height = format.height; |
| 1467 | 1467 | ||
| @@ -1471,17 +1471,17 @@ static int resizer_enum_frame_size(struct v4l2_subdev *sd, | |||
| 1471 | /* | 1471 | /* |
| 1472 | * resizer_get_format - Handle get format by pads subdev method | 1472 | * resizer_get_format - Handle get format by pads subdev method |
| 1473 | * @sd : pointer to v4l2 subdev structure | 1473 | * @sd : pointer to v4l2 subdev structure |
| 1474 | * @fh : V4L2 subdev file handle | 1474 | * @cfg: V4L2 subdev pad configuration |
| 1475 | * @fmt : pointer to v4l2 subdev format structure | 1475 | * @fmt : pointer to v4l2 subdev format structure |
| 1476 | * return -EINVAL or zero on success | 1476 | * return -EINVAL or zero on success |
| 1477 | */ | 1477 | */ |
| 1478 | static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | 1478 | static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, |
| 1479 | struct v4l2_subdev_format *fmt) | 1479 | struct v4l2_subdev_format *fmt) |
| 1480 | { | 1480 | { |
| 1481 | struct isp_res_device *res = v4l2_get_subdevdata(sd); | 1481 | struct isp_res_device *res = v4l2_get_subdevdata(sd); |
| 1482 | struct v4l2_mbus_framefmt *format; | 1482 | struct v4l2_mbus_framefmt *format; |
| 1483 | 1483 | ||
| 1484 | format = __resizer_get_format(res, fh, fmt->pad, fmt->which); | 1484 | format = __resizer_get_format(res, cfg, fmt->pad, fmt->which); |
| 1485 | if (format == NULL) | 1485 | if (format == NULL) |
| 1486 | return -EINVAL; | 1486 | return -EINVAL; |
| 1487 | 1487 | ||
| @@ -1492,37 +1492,37 @@ static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | |||
| 1492 | /* | 1492 | /* |
| 1493 | * resizer_set_format - Handle set format by pads subdev method | 1493 | * resizer_set_format - Handle set format by pads subdev method |
| 1494 | * @sd : pointer to v4l2 subdev structure | 1494 | * @sd : pointer to v4l2 subdev structure |
| 1495 | * @fh : V4L2 subdev file handle | 1495 | * @cfg: V4L2 subdev pad configuration |
| 1496 | * @fmt : pointer to v4l2 subdev format structure | 1496 | * @fmt : pointer to v4l2 subdev format structure |
| 1497 | * return -EINVAL or zero on success | 1497 | * return -EINVAL or zero on success |
| 1498 | */ | 1498 | */ |
| 1499 | static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | 1499 | static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, |
| 1500 | struct v4l2_subdev_format *fmt) | 1500 | struct v4l2_subdev_format *fmt) |
| 1501 | { | 1501 | { |
| 1502 | struct isp_res_device *res = v4l2_get_subdevdata(sd); | 1502 | struct isp_res_device *res = v4l2_get_subdevdata(sd); |
| 1503 | struct v4l2_mbus_framefmt *format; | 1503 | struct v4l2_mbus_framefmt *format; |
| 1504 | struct v4l2_rect *crop; | 1504 | struct v4l2_rect *crop; |
| 1505 | 1505 | ||
| 1506 | format = __resizer_get_format(res, fh, fmt->pad, fmt->which); | 1506 | format = __resizer_get_format(res, cfg, fmt->pad, fmt->which); |
| 1507 | if (format == NULL) | 1507 | if (format == NULL) |
| 1508 | return -EINVAL; | 1508 | return -EINVAL; |
| 1509 | 1509 | ||
| 1510 | resizer_try_format(res, fh, fmt->pad, &fmt->format, fmt->which); | 1510 | resizer_try_format(res, cfg, fmt->pad, &fmt->format, fmt->which); |
| 1511 | *format = fmt->format; | 1511 | *format = fmt->format; |
| 1512 | 1512 | ||
| 1513 | if (fmt->pad == RESZ_PAD_SINK) { | 1513 | if (fmt->pad == RESZ_PAD_SINK) { |
| 1514 | /* reset crop rectangle */ | 1514 | /* reset crop rectangle */ |
| 1515 | crop = __resizer_get_crop(res, fh, fmt->which); | 1515 | crop = __resizer_get_crop(res, cfg, fmt->which); |
| 1516 | crop->left = 0; | 1516 | crop->left = 0; |
| 1517 | crop->top = 0; | 1517 | crop->top = 0; |
| 1518 | crop->width = fmt->format.width; | 1518 | crop->width = fmt->format.width; |
| 1519 | crop->height = fmt->format.height; | 1519 | crop->height = fmt->format.height; |
| 1520 | 1520 | ||
| 1521 | /* Propagate the format from sink to source */ | 1521 | /* Propagate the format from sink to source */ |
| 1522 | format = __resizer_get_format(res, fh, RESZ_PAD_SOURCE, | 1522 | format = __resizer_get_format(res, cfg, RESZ_PAD_SOURCE, |
| 1523 | fmt->which); | 1523 | fmt->which); |
| 1524 | *format = fmt->format; | 1524 | *format = fmt->format; |
| 1525 | resizer_try_format(res, fh, RESZ_PAD_SOURCE, format, | 1525 | resizer_try_format(res, cfg, RESZ_PAD_SOURCE, format, |
| 1526 | fmt->which); | 1526 | fmt->which); |
| 1527 | } | 1527 | } |
| 1528 | 1528 | ||
| @@ -1573,7 +1573,7 @@ static int resizer_init_formats(struct v4l2_subdev *sd, | |||
| 1573 | format.format.code = MEDIA_BUS_FMT_YUYV8_1X16; | 1573 | format.format.code = MEDIA_BUS_FMT_YUYV8_1X16; |
| 1574 | format.format.width = 4096; | 1574 | format.format.width = 4096; |
| 1575 | format.format.height = 4096; | 1575 | format.format.height = 4096; |
| 1576 | resizer_set_format(sd, fh, &format); | 1576 | resizer_set_format(sd, fh ? fh->pad : NULL, &format); |
| 1577 | 1577 | ||
| 1578 | return 0; | 1578 | return 0; |
| 1579 | } | 1579 | } |
diff --git a/drivers/media/platform/omap3isp/ispstat.c b/drivers/media/platform/omap3isp/ispstat.c index a94e8340508f..20434e83e801 100644 --- a/drivers/media/platform/omap3isp/ispstat.c +++ b/drivers/media/platform/omap3isp/ispstat.c | |||
| @@ -21,7 +21,7 @@ | |||
| 21 | 21 | ||
| 22 | #include "isp.h" | 22 | #include "isp.h" |
| 23 | 23 | ||
| 24 | #define ISP_STAT_USES_DMAENGINE(stat) ((stat)->dma_ch >= 0) | 24 | #define ISP_STAT_USES_DMAENGINE(stat) ((stat)->dma_ch != NULL) |
| 25 | 25 | ||
| 26 | /* | 26 | /* |
| 27 | * MAGIC_SIZE must always be the greatest common divisor of | 27 | * MAGIC_SIZE must always be the greatest common divisor of |
diff --git a/drivers/media/platform/omap3isp/ispstat.h b/drivers/media/platform/omap3isp/ispstat.h index b32b29677e2c..b79380d83fcf 100644 --- a/drivers/media/platform/omap3isp/ispstat.h +++ b/drivers/media/platform/omap3isp/ispstat.h | |||
| @@ -20,7 +20,6 @@ | |||
| 20 | 20 | ||
| 21 | #include <linux/types.h> | 21 | #include <linux/types.h> |
| 22 | #include <linux/omap3isp.h> | 22 | #include <linux/omap3isp.h> |
| 23 | #include <linux/omap-dma.h> | ||
| 24 | #include <media/v4l2-event.h> | 23 | #include <media/v4l2-event.h> |
| 25 | 24 | ||
| 26 | #include "isp.h" | 25 | #include "isp.h" |
| @@ -33,6 +32,7 @@ | |||
| 33 | #define STAT_NO_BUF 1 /* An error has occurred */ | 32 | #define STAT_NO_BUF 1 /* An error has occurred */ |
| 34 | #define STAT_BUF_WAITING_DMA 2 /* Histogram only: DMA is running */ | 33 | #define STAT_BUF_WAITING_DMA 2 /* Histogram only: DMA is running */ |
| 35 | 34 | ||
| 35 | struct dma_chan; | ||
| 36 | struct ispstat; | 36 | struct ispstat; |
| 37 | 37 | ||
| 38 | struct ispstat_buffer { | 38 | struct ispstat_buffer { |
| @@ -96,7 +96,6 @@ struct ispstat { | |||
| 96 | u8 inc_config; | 96 | u8 inc_config; |
| 97 | atomic_t buf_err; | 97 | atomic_t buf_err; |
| 98 | enum ispstat_state_t state; /* enabling/disabling state */ | 98 | enum ispstat_state_t state; /* enabling/disabling state */ |
| 99 | struct omap_dma_channel_params dma_config; | ||
| 100 | struct isp_device *isp; | 99 | struct isp_device *isp; |
| 101 | void *priv; /* pointer to priv config struct */ | 100 | void *priv; /* pointer to priv config struct */ |
| 102 | void *recover_priv; /* pointer to recover priv configuration */ | 101 | void *recover_priv; /* pointer to recover priv configuration */ |
| @@ -110,7 +109,7 @@ struct ispstat { | |||
| 110 | u32 frame_number; | 109 | u32 frame_number; |
| 111 | u32 buf_size; | 110 | u32 buf_size; |
| 112 | u32 buf_alloc_size; | 111 | u32 buf_alloc_size; |
| 113 | int dma_ch; | 112 | struct dma_chan *dma_ch; |
| 114 | unsigned long event_type; | 113 | unsigned long event_type; |
| 115 | struct ispstat_buffer *buf; | 114 | struct ispstat_buffer *buf; |
| 116 | struct ispstat_buffer *active_buf; | 115 | struct ispstat_buffer *active_buf; |
diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c index 3fe9047ef466..d285af18df7f 100644 --- a/drivers/media/platform/omap3isp/ispvideo.c +++ b/drivers/media/platform/omap3isp/ispvideo.c | |||
| @@ -452,7 +452,6 @@ struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video) | |||
| 452 | enum isp_pipeline_state state; | 452 | enum isp_pipeline_state state; |
| 453 | struct isp_buffer *buf; | 453 | struct isp_buffer *buf; |
| 454 | unsigned long flags; | 454 | unsigned long flags; |
| 455 | struct timespec ts; | ||
| 456 | 455 | ||
| 457 | spin_lock_irqsave(&video->irqlock, flags); | 456 | spin_lock_irqsave(&video->irqlock, flags); |
| 458 | if (WARN_ON(list_empty(&video->dmaqueue))) { | 457 | if (WARN_ON(list_empty(&video->dmaqueue))) { |
| @@ -465,9 +464,7 @@ struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video) | |||
| 465 | list_del(&buf->irqlist); | 464 | list_del(&buf->irqlist); |
| 466 | spin_unlock_irqrestore(&video->irqlock, flags); | 465 | spin_unlock_irqrestore(&video->irqlock, flags); |
| 467 | 466 | ||
| 468 | ktime_get_ts(&ts); | 467 | v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp); |
| 469 | buf->vb.v4l2_buf.timestamp.tv_sec = ts.tv_sec; | ||
| 470 | buf->vb.v4l2_buf.timestamp.tv_usec = ts.tv_nsec / NSEC_PER_USEC; | ||
| 471 | 468 | ||
| 472 | /* Do frame number propagation only if this is the output video node. | 469 | /* Do frame number propagation only if this is the output video node. |
| 473 | * Frame number either comes from the CSI receivers or it gets | 470 | * Frame number either comes from the CSI receivers or it gets |
| @@ -524,7 +521,6 @@ struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video) | |||
| 524 | 521 | ||
| 525 | buf = list_first_entry(&video->dmaqueue, struct isp_buffer, | 522 | buf = list_first_entry(&video->dmaqueue, struct isp_buffer, |
| 526 | irqlist); | 523 | irqlist); |
| 527 | buf->vb.state = VB2_BUF_STATE_ACTIVE; | ||
| 528 | 524 | ||
| 529 | spin_unlock_irqrestore(&video->irqlock, flags); | 525 | spin_unlock_irqrestore(&video->irqlock, flags); |
| 530 | 526 | ||
| @@ -1022,7 +1018,7 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) | |||
| 1022 | 1018 | ||
| 1023 | pipe->entities = 0; | 1019 | pipe->entities = 0; |
| 1024 | 1020 | ||
| 1025 | if (video->isp->pdata->set_constraints) | 1021 | if (video->isp->pdata && video->isp->pdata->set_constraints) |
| 1026 | video->isp->pdata->set_constraints(video->isp, true); | 1022 | video->isp->pdata->set_constraints(video->isp, true); |
| 1027 | pipe->l3_ick = clk_get_rate(video->isp->clock[ISP_CLK_L3_ICK]); | 1023 | pipe->l3_ick = clk_get_rate(video->isp->clock[ISP_CLK_L3_ICK]); |
| 1028 | pipe->max_rate = pipe->l3_ick; | 1024 | pipe->max_rate = pipe->l3_ick; |
| @@ -1104,7 +1100,7 @@ err_set_stream: | |||
| 1104 | err_check_format: | 1100 | err_check_format: |
| 1105 | media_entity_pipeline_stop(&video->video.entity); | 1101 | media_entity_pipeline_stop(&video->video.entity); |
| 1106 | err_pipeline_start: | 1102 | err_pipeline_start: |
| 1107 | if (video->isp->pdata->set_constraints) | 1103 | if (video->isp->pdata && video->isp->pdata->set_constraints) |
| 1108 | video->isp->pdata->set_constraints(video->isp, false); | 1104 | video->isp->pdata->set_constraints(video->isp, false); |
| 1109 | /* The DMA queue must be emptied here, otherwise CCDC interrupts that | 1105 | /* The DMA queue must be emptied here, otherwise CCDC interrupts that |
| 1110 | * will get triggered the next time the CCDC is powered up will try to | 1106 | * will get triggered the next time the CCDC is powered up will try to |
| @@ -1165,7 +1161,7 @@ isp_video_streamoff(struct file *file, void *fh, enum v4l2_buf_type type) | |||
| 1165 | video->queue = NULL; | 1161 | video->queue = NULL; |
| 1166 | video->error = false; | 1162 | video->error = false; |
| 1167 | 1163 | ||
| 1168 | if (video->isp->pdata->set_constraints) | 1164 | if (video->isp->pdata && video->isp->pdata->set_constraints) |
| 1169 | video->isp->pdata->set_constraints(video->isp, false); | 1165 | video->isp->pdata->set_constraints(video->isp, false); |
| 1170 | media_entity_pipeline_stop(&video->video.entity); | 1166 | media_entity_pipeline_stop(&video->video.entity); |
| 1171 | 1167 | ||
| @@ -1326,14 +1322,8 @@ static unsigned int isp_video_poll(struct file *file, poll_table *wait) | |||
| 1326 | static int isp_video_mmap(struct file *file, struct vm_area_struct *vma) | 1322 | static int isp_video_mmap(struct file *file, struct vm_area_struct *vma) |
| 1327 | { | 1323 | { |
| 1328 | struct isp_video_fh *vfh = to_isp_video_fh(file->private_data); | 1324 | struct isp_video_fh *vfh = to_isp_video_fh(file->private_data); |
| 1329 | struct isp_video *video = video_drvdata(file); | ||
| 1330 | int ret; | ||
| 1331 | |||
| 1332 | mutex_lock(&video->queue_lock); | ||
| 1333 | ret = vb2_mmap(&vfh->queue, vma); | ||
| 1334 | mutex_unlock(&video->queue_lock); | ||
| 1335 | 1325 | ||
| 1336 | return ret; | 1326 | return vb2_mmap(&vfh->queue, vma); |
| 1337 | } | 1327 | } |
| 1338 | 1328 | ||
| 1339 | static struct v4l2_file_operations isp_video_fops = { | 1329 | static struct v4l2_file_operations isp_video_fops = { |
diff --git a/drivers/media/platform/s3c-camif/camif-capture.c b/drivers/media/platform/s3c-camif/camif-capture.c index 54479d60cc0d..f6a61b9ceff4 100644 --- a/drivers/media/platform/s3c-camif/camif-capture.c +++ b/drivers/media/platform/s3c-camif/camif-capture.c | |||
| @@ -1219,7 +1219,7 @@ static const u32 camif_mbus_formats[] = { | |||
| 1219 | */ | 1219 | */ |
| 1220 | 1220 | ||
| 1221 | static int s3c_camif_subdev_enum_mbus_code(struct v4l2_subdev *sd, | 1221 | static int s3c_camif_subdev_enum_mbus_code(struct v4l2_subdev *sd, |
| 1222 | struct v4l2_subdev_fh *fh, | 1222 | struct v4l2_subdev_pad_config *cfg, |
| 1223 | struct v4l2_subdev_mbus_code_enum *code) | 1223 | struct v4l2_subdev_mbus_code_enum *code) |
| 1224 | { | 1224 | { |
| 1225 | if (code->index >= ARRAY_SIZE(camif_mbus_formats)) | 1225 | if (code->index >= ARRAY_SIZE(camif_mbus_formats)) |
| @@ -1230,14 +1230,14 @@ static int s3c_camif_subdev_enum_mbus_code(struct v4l2_subdev *sd, | |||
| 1230 | } | 1230 | } |
| 1231 | 1231 | ||
| 1232 | static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd, | 1232 | static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd, |
| 1233 | struct v4l2_subdev_fh *fh, | 1233 | struct v4l2_subdev_pad_config *cfg, |
| 1234 | struct v4l2_subdev_format *fmt) | 1234 | struct v4l2_subdev_format *fmt) |
| 1235 | { | 1235 | { |
| 1236 | struct camif_dev *camif = v4l2_get_subdevdata(sd); | 1236 | struct camif_dev *camif = v4l2_get_subdevdata(sd); |
| 1237 | struct v4l2_mbus_framefmt *mf = &fmt->format; | 1237 | struct v4l2_mbus_framefmt *mf = &fmt->format; |
| 1238 | 1238 | ||
| 1239 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { | 1239 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { |
| 1240 | mf = v4l2_subdev_get_try_format(fh, fmt->pad); | 1240 | mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); |
| 1241 | fmt->format = *mf; | 1241 | fmt->format = *mf; |
| 1242 | return 0; | 1242 | return 0; |
| 1243 | } | 1243 | } |
| @@ -1297,7 +1297,7 @@ static void __camif_subdev_try_format(struct camif_dev *camif, | |||
| 1297 | } | 1297 | } |
| 1298 | 1298 | ||
| 1299 | static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd, | 1299 | static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd, |
| 1300 | struct v4l2_subdev_fh *fh, | 1300 | struct v4l2_subdev_pad_config *cfg, |
| 1301 | struct v4l2_subdev_format *fmt) | 1301 | struct v4l2_subdev_format *fmt) |
| 1302 | { | 1302 | { |
| 1303 | struct camif_dev *camif = v4l2_get_subdevdata(sd); | 1303 | struct camif_dev *camif = v4l2_get_subdevdata(sd); |
| @@ -1325,7 +1325,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd, | |||
| 1325 | __camif_subdev_try_format(camif, mf, fmt->pad); | 1325 | __camif_subdev_try_format(camif, mf, fmt->pad); |
| 1326 | 1326 | ||
| 1327 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { | 1327 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { |
| 1328 | mf = v4l2_subdev_get_try_format(fh, fmt->pad); | 1328 | mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); |
| 1329 | *mf = fmt->format; | 1329 | *mf = fmt->format; |
| 1330 | mutex_unlock(&camif->lock); | 1330 | mutex_unlock(&camif->lock); |
| 1331 | return 0; | 1331 | return 0; |
| @@ -1364,7 +1364,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd, | |||
| 1364 | } | 1364 | } |
| 1365 | 1365 | ||
| 1366 | static int s3c_camif_subdev_get_selection(struct v4l2_subdev *sd, | 1366 | static int s3c_camif_subdev_get_selection(struct v4l2_subdev *sd, |
| 1367 | struct v4l2_subdev_fh *fh, | 1367 | struct v4l2_subdev_pad_config *cfg, |
| 1368 | struct v4l2_subdev_selection *sel) | 1368 | struct v4l2_subdev_selection *sel) |
| 1369 | { | 1369 | { |
| 1370 | struct camif_dev *camif = v4l2_get_subdevdata(sd); | 1370 | struct camif_dev *camif = v4l2_get_subdevdata(sd); |
| @@ -1377,7 +1377,7 @@ static int s3c_camif_subdev_get_selection(struct v4l2_subdev *sd, | |||
| 1377 | return -EINVAL; | 1377 | return -EINVAL; |
| 1378 | 1378 | ||
| 1379 | if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { | 1379 | if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { |
| 1380 | sel->r = *v4l2_subdev_get_try_crop(fh, sel->pad); | 1380 | sel->r = *v4l2_subdev_get_try_crop(sd, cfg, sel->pad); |
| 1381 | return 0; | 1381 | return 0; |
| 1382 | } | 1382 | } |
| 1383 | 1383 | ||
| @@ -1451,7 +1451,7 @@ static void __camif_try_crop(struct camif_dev *camif, struct v4l2_rect *r) | |||
| 1451 | } | 1451 | } |
| 1452 | 1452 | ||
| 1453 | static int s3c_camif_subdev_set_selection(struct v4l2_subdev *sd, | 1453 | static int s3c_camif_subdev_set_selection(struct v4l2_subdev *sd, |
| 1454 | struct v4l2_subdev_fh *fh, | 1454 | struct v4l2_subdev_pad_config *cfg, |
| 1455 | struct v4l2_subdev_selection *sel) | 1455 | struct v4l2_subdev_selection *sel) |
| 1456 | { | 1456 | { |
| 1457 | struct camif_dev *camif = v4l2_get_subdevdata(sd); | 1457 | struct camif_dev *camif = v4l2_get_subdevdata(sd); |
| @@ -1465,7 +1465,7 @@ static int s3c_camif_subdev_set_selection(struct v4l2_subdev *sd, | |||
| 1465 | __camif_try_crop(camif, &sel->r); | 1465 | __camif_try_crop(camif, &sel->r); |
| 1466 | 1466 | ||
| 1467 | if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { | 1467 | if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { |
| 1468 | *v4l2_subdev_get_try_crop(fh, sel->pad) = sel->r; | 1468 | *v4l2_subdev_get_try_crop(sd, cfg, sel->pad) = sel->r; |
| 1469 | } else { | 1469 | } else { |
| 1470 | unsigned long flags; | 1470 | unsigned long flags; |
| 1471 | unsigned int i; | 1471 | unsigned int i; |
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c index a92ff4249d10..bfbf1575677c 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c | |||
| @@ -621,6 +621,7 @@ static int s5p_jpeg_to_user_subsampling(struct s5p_jpeg_ctx *ctx) | |||
| 621 | return V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY; | 621 | return V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY; |
| 622 | return ctx->subsampling; | 622 | return ctx->subsampling; |
| 623 | case SJPEG_EXYNOS3250: | 623 | case SJPEG_EXYNOS3250: |
| 624 | case SJPEG_EXYNOS5420: | ||
| 624 | if (ctx->subsampling > 3) | 625 | if (ctx->subsampling > 3) |
| 625 | return V4L2_JPEG_CHROMA_SUBSAMPLING_411; | 626 | return V4L2_JPEG_CHROMA_SUBSAMPLING_411; |
| 626 | return exynos3250_decoded_subsampling[ctx->subsampling]; | 627 | return exynos3250_decoded_subsampling[ctx->subsampling]; |
| @@ -1142,13 +1143,13 @@ static void jpeg_bound_align_image(struct s5p_jpeg_ctx *ctx, | |||
| 1142 | w_step = 1 << walign; | 1143 | w_step = 1 << walign; |
| 1143 | h_step = 1 << halign; | 1144 | h_step = 1 << halign; |
| 1144 | 1145 | ||
| 1145 | if (ctx->jpeg->variant->version == SJPEG_EXYNOS3250) { | 1146 | if (ctx->jpeg->variant->hw3250_compat) { |
| 1146 | /* | 1147 | /* |
| 1147 | * Rightmost and bottommost pixels are cropped by the | 1148 | * Rightmost and bottommost pixels are cropped by the |
| 1148 | * Exynos3250 JPEG IP for RGB formats, for the specific | 1149 | * Exynos3250/compatible JPEG IP for RGB formats, for the |
| 1149 | * width and height values respectively. This assignment | 1150 | * specific width and height values respectively. This |
| 1150 | * will result in v4l_bound_align_image returning dimensions | 1151 | * assignment will result in v4l_bound_align_image returning |
| 1151 | * reduced by 1 for the aforementioned cases. | 1152 | * dimensions reduced by 1 for the aforementioned cases. |
| 1152 | */ | 1153 | */ |
| 1153 | if (w_step == 4 && ((width & 3) == 1)) { | 1154 | if (w_step == 4 && ((width & 3) == 1)) { |
| 1154 | wmax = width; | 1155 | wmax = width; |
| @@ -1384,12 +1385,12 @@ static int s5p_jpeg_s_fmt(struct s5p_jpeg_ctx *ct, struct v4l2_format *f) | |||
| 1384 | 1385 | ||
| 1385 | /* | 1386 | /* |
| 1386 | * Prevent downscaling to YUV420 format by more than 2 | 1387 | * Prevent downscaling to YUV420 format by more than 2 |
| 1387 | * for Exynos3250 SoC as it produces broken raw image | 1388 | * for Exynos3250/compatible SoC as it produces broken raw image |
| 1388 | * in such cases. | 1389 | * in such cases. |
| 1389 | */ | 1390 | */ |
| 1390 | if (ct->mode == S5P_JPEG_DECODE && | 1391 | if (ct->mode == S5P_JPEG_DECODE && |
| 1391 | f_type == FMT_TYPE_CAPTURE && | 1392 | f_type == FMT_TYPE_CAPTURE && |
| 1392 | ct->jpeg->variant->version == SJPEG_EXYNOS3250 && | 1393 | ct->jpeg->variant->hw3250_compat && |
| 1393 | pix->pixelformat == V4L2_PIX_FMT_YUV420 && | 1394 | pix->pixelformat == V4L2_PIX_FMT_YUV420 && |
| 1394 | ct->scale_factor > 2) { | 1395 | ct->scale_factor > 2) { |
| 1395 | scale_rect.width = ct->out_q.w / 2; | 1396 | scale_rect.width = ct->out_q.w / 2; |
| @@ -1569,12 +1570,12 @@ static int s5p_jpeg_s_selection(struct file *file, void *fh, | |||
| 1569 | if (s->target == V4L2_SEL_TGT_COMPOSE) { | 1570 | if (s->target == V4L2_SEL_TGT_COMPOSE) { |
| 1570 | if (ctx->mode != S5P_JPEG_DECODE) | 1571 | if (ctx->mode != S5P_JPEG_DECODE) |
| 1571 | return -EINVAL; | 1572 | return -EINVAL; |
| 1572 | if (ctx->jpeg->variant->version == SJPEG_EXYNOS3250) | 1573 | if (ctx->jpeg->variant->hw3250_compat) |
| 1573 | ret = exynos3250_jpeg_try_downscale(ctx, rect); | 1574 | ret = exynos3250_jpeg_try_downscale(ctx, rect); |
| 1574 | } else if (s->target == V4L2_SEL_TGT_CROP) { | 1575 | } else if (s->target == V4L2_SEL_TGT_CROP) { |
| 1575 | if (ctx->mode != S5P_JPEG_ENCODE) | 1576 | if (ctx->mode != S5P_JPEG_ENCODE) |
| 1576 | return -EINVAL; | 1577 | return -EINVAL; |
| 1577 | if (ctx->jpeg->variant->version == SJPEG_EXYNOS3250) | 1578 | if (ctx->jpeg->variant->hw3250_compat) |
| 1578 | ret = exynos3250_jpeg_try_crop(ctx, rect); | 1579 | ret = exynos3250_jpeg_try_crop(ctx, rect); |
| 1579 | } | 1580 | } |
| 1580 | 1581 | ||
| @@ -1604,8 +1605,9 @@ static int s5p_jpeg_adjust_subs_ctrl(struct s5p_jpeg_ctx *ctx, int *ctrl_val) | |||
| 1604 | case SJPEG_S5P: | 1605 | case SJPEG_S5P: |
| 1605 | return 0; | 1606 | return 0; |
| 1606 | case SJPEG_EXYNOS3250: | 1607 | case SJPEG_EXYNOS3250: |
| 1608 | case SJPEG_EXYNOS5420: | ||
| 1607 | /* | 1609 | /* |
| 1608 | * The exynos3250 device can produce JPEG image only | 1610 | * The exynos3250/compatible device can produce JPEG image only |
| 1609 | * of 4:4:4 subsampling when given RGB32 source image. | 1611 | * of 4:4:4 subsampling when given RGB32 source image. |
| 1610 | */ | 1612 | */ |
| 1611 | if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB32) | 1613 | if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB32) |
| @@ -1624,7 +1626,7 @@ static int s5p_jpeg_adjust_subs_ctrl(struct s5p_jpeg_ctx *ctx, int *ctrl_val) | |||
| 1624 | } | 1626 | } |
| 1625 | 1627 | ||
| 1626 | /* | 1628 | /* |
| 1627 | * The exynos4x12 and exynos3250 devices require resulting | 1629 | * The exynos4x12 and exynos3250/compatible devices require resulting |
| 1628 | * jpeg subsampling not to be lower than the input raw image | 1630 | * jpeg subsampling not to be lower than the input raw image |
| 1629 | * subsampling. | 1631 | * subsampling. |
| 1630 | */ | 1632 | */ |
| @@ -1842,7 +1844,7 @@ static void exynos4_jpeg_set_img_addr(struct s5p_jpeg_ctx *ctx) | |||
| 1842 | struct s5p_jpeg *jpeg = ctx->jpeg; | 1844 | struct s5p_jpeg *jpeg = ctx->jpeg; |
| 1843 | struct s5p_jpeg_fmt *fmt; | 1845 | struct s5p_jpeg_fmt *fmt; |
| 1844 | struct vb2_buffer *vb; | 1846 | struct vb2_buffer *vb; |
| 1845 | struct s5p_jpeg_addr jpeg_addr; | 1847 | struct s5p_jpeg_addr jpeg_addr = {}; |
| 1846 | u32 pix_size, padding_bytes = 0; | 1848 | u32 pix_size, padding_bytes = 0; |
| 1847 | 1849 | ||
| 1848 | jpeg_addr.cb = 0; | 1850 | jpeg_addr.cb = 0; |
| @@ -1946,7 +1948,7 @@ static void exynos3250_jpeg_set_img_addr(struct s5p_jpeg_ctx *ctx) | |||
| 1946 | struct s5p_jpeg *jpeg = ctx->jpeg; | 1948 | struct s5p_jpeg *jpeg = ctx->jpeg; |
| 1947 | struct s5p_jpeg_fmt *fmt; | 1949 | struct s5p_jpeg_fmt *fmt; |
| 1948 | struct vb2_buffer *vb; | 1950 | struct vb2_buffer *vb; |
| 1949 | struct s5p_jpeg_addr jpeg_addr; | 1951 | struct s5p_jpeg_addr jpeg_addr = {}; |
| 1950 | u32 pix_size; | 1952 | u32 pix_size; |
| 1951 | 1953 | ||
| 1952 | pix_size = ctx->cap_q.w * ctx->cap_q.h; | 1954 | pix_size = ctx->cap_q.w * ctx->cap_q.h; |
| @@ -2020,6 +2022,16 @@ static void exynos3250_jpeg_device_run(void *priv) | |||
| 2020 | exynos3250_jpeg_qtbl(jpeg->regs, 2, 1); | 2022 | exynos3250_jpeg_qtbl(jpeg->regs, 2, 1); |
| 2021 | exynos3250_jpeg_qtbl(jpeg->regs, 3, 1); | 2023 | exynos3250_jpeg_qtbl(jpeg->regs, 3, 1); |
| 2022 | 2024 | ||
| 2025 | /* | ||
| 2026 | * Some SoCs require setting Huffman tables before each run | ||
| 2027 | */ | ||
| 2028 | if (jpeg->variant->htbl_reinit) { | ||
| 2029 | s5p_jpeg_set_hdctbl(jpeg->regs); | ||
| 2030 | s5p_jpeg_set_hdctblg(jpeg->regs); | ||
| 2031 | s5p_jpeg_set_hactbl(jpeg->regs); | ||
| 2032 | s5p_jpeg_set_hactblg(jpeg->regs); | ||
| 2033 | } | ||
| 2034 | |||
| 2023 | /* Y, Cb, Cr use Huffman table 0 */ | 2035 | /* Y, Cb, Cr use Huffman table 0 */ |
| 2024 | exynos3250_jpeg_htbl_ac(jpeg->regs, 1); | 2036 | exynos3250_jpeg_htbl_ac(jpeg->regs, 1); |
| 2025 | exynos3250_jpeg_htbl_dc(jpeg->regs, 1); | 2037 | exynos3250_jpeg_htbl_dc(jpeg->regs, 1); |
| @@ -2663,13 +2675,12 @@ static int s5p_jpeg_runtime_resume(struct device *dev) | |||
| 2663 | /* | 2675 | /* |
| 2664 | * JPEG IP allows storing two Huffman tables for each component. | 2676 | * JPEG IP allows storing two Huffman tables for each component. |
| 2665 | * We fill table 0 for each component and do this here only | 2677 | * We fill table 0 for each component and do this here only |
| 2666 | * for S5PC210 and Exynos3250 SoCs. Exynos4x12 SoC requires | 2678 | * for S5PC210 and Exynos3250 SoCs. Exynos4x12 and Exynos542x SoC |
| 2667 | * programming its Huffman tables each time the encoding process | 2679 | * require programming their Huffman tables each time the encoding |
| 2668 | * is initialized, and thus it is accomplished in the device_run | 2680 | * process is initialized, and thus it is accomplished in the |
| 2669 | * callback of m2m_ops. | 2681 | * device_run callback of m2m_ops. |
| 2670 | */ | 2682 | */ |
| 2671 | if (jpeg->variant->version == SJPEG_S5P || | 2683 | if (!jpeg->variant->htbl_reinit) { |
| 2672 | jpeg->variant->version == SJPEG_EXYNOS3250) { | ||
| 2673 | s5p_jpeg_set_hdctbl(jpeg->regs); | 2684 | s5p_jpeg_set_hdctbl(jpeg->regs); |
| 2674 | s5p_jpeg_set_hdctblg(jpeg->regs); | 2685 | s5p_jpeg_set_hdctblg(jpeg->regs); |
| 2675 | s5p_jpeg_set_hactbl(jpeg->regs); | 2686 | s5p_jpeg_set_hactbl(jpeg->regs); |
| @@ -2717,6 +2728,7 @@ static struct s5p_jpeg_variant exynos3250_jpeg_drvdata = { | |||
| 2717 | .jpeg_irq = exynos3250_jpeg_irq, | 2728 | .jpeg_irq = exynos3250_jpeg_irq, |
| 2718 | .m2m_ops = &exynos3250_jpeg_m2m_ops, | 2729 | .m2m_ops = &exynos3250_jpeg_m2m_ops, |
| 2719 | .fmt_ver_flag = SJPEG_FMT_FLAG_EXYNOS3250, | 2730 | .fmt_ver_flag = SJPEG_FMT_FLAG_EXYNOS3250, |
| 2731 | .hw3250_compat = 1, | ||
| 2720 | }; | 2732 | }; |
| 2721 | 2733 | ||
| 2722 | static struct s5p_jpeg_variant exynos4_jpeg_drvdata = { | 2734 | static struct s5p_jpeg_variant exynos4_jpeg_drvdata = { |
| @@ -2724,6 +2736,16 @@ static struct s5p_jpeg_variant exynos4_jpeg_drvdata = { | |||
| 2724 | .jpeg_irq = exynos4_jpeg_irq, | 2736 | .jpeg_irq = exynos4_jpeg_irq, |
| 2725 | .m2m_ops = &exynos4_jpeg_m2m_ops, | 2737 | .m2m_ops = &exynos4_jpeg_m2m_ops, |
| 2726 | .fmt_ver_flag = SJPEG_FMT_FLAG_EXYNOS4, | 2738 | .fmt_ver_flag = SJPEG_FMT_FLAG_EXYNOS4, |
| 2739 | .htbl_reinit = 1, | ||
| 2740 | }; | ||
| 2741 | |||
| 2742 | static struct s5p_jpeg_variant exynos5420_jpeg_drvdata = { | ||
| 2743 | .version = SJPEG_EXYNOS5420, | ||
| 2744 | .jpeg_irq = exynos3250_jpeg_irq, /* intentionally 3250 */ | ||
| 2745 | .m2m_ops = &exynos3250_jpeg_m2m_ops, /* intentionally 3250 */ | ||
| 2746 | .fmt_ver_flag = SJPEG_FMT_FLAG_EXYNOS3250, /* intentionally 3250 */ | ||
| 2747 | .hw3250_compat = 1, | ||
| 2748 | .htbl_reinit = 1, | ||
| 2727 | }; | 2749 | }; |
| 2728 | 2750 | ||
| 2729 | static const struct of_device_id samsung_jpeg_match[] = { | 2751 | static const struct of_device_id samsung_jpeg_match[] = { |
| @@ -2739,6 +2761,9 @@ static const struct of_device_id samsung_jpeg_match[] = { | |||
| 2739 | }, { | 2761 | }, { |
| 2740 | .compatible = "samsung,exynos4212-jpeg", | 2762 | .compatible = "samsung,exynos4212-jpeg", |
| 2741 | .data = &exynos4_jpeg_drvdata, | 2763 | .data = &exynos4_jpeg_drvdata, |
| 2764 | }, { | ||
| 2765 | .compatible = "samsung,exynos5420-jpeg", | ||
| 2766 | .data = &exynos5420_jpeg_drvdata, | ||
| 2742 | }, | 2767 | }, |
| 2743 | {}, | 2768 | {}, |
| 2744 | }; | 2769 | }; |
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.h b/drivers/media/platform/s5p-jpeg/jpeg-core.h index 764b32de326b..7d9a9ed19cea 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.h +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.h | |||
| @@ -67,10 +67,12 @@ | |||
| 67 | #define SJPEG_SUBSAMPLING_420 0x22 | 67 | #define SJPEG_SUBSAMPLING_420 0x22 |
| 68 | 68 | ||
| 69 | /* Version numbers */ | 69 | /* Version numbers */ |
| 70 | 70 | enum sjpeg_version { | |
| 71 | #define SJPEG_S5P 1 | 71 | SJPEG_S5P, |
| 72 | #define SJPEG_EXYNOS3250 2 | 72 | SJPEG_EXYNOS3250, |
| 73 | #define SJPEG_EXYNOS4 3 | 73 | SJPEG_EXYNOS4, |
| 74 | SJPEG_EXYNOS5420, | ||
| 75 | }; | ||
| 74 | 76 | ||
| 75 | enum exynos4_jpeg_result { | 77 | enum exynos4_jpeg_result { |
| 76 | OK_ENC_OR_DEC, | 78 | OK_ENC_OR_DEC, |
| @@ -130,6 +132,8 @@ struct s5p_jpeg { | |||
| 130 | struct s5p_jpeg_variant { | 132 | struct s5p_jpeg_variant { |
| 131 | unsigned int version; | 133 | unsigned int version; |
| 132 | unsigned int fmt_ver_flag; | 134 | unsigned int fmt_ver_flag; |
| 135 | unsigned int hw3250_compat:1; | ||
| 136 | unsigned int htbl_reinit:1; | ||
| 133 | struct v4l2_m2m_ops *m2m_ops; | 137 | struct v4l2_m2m_ops *m2m_ops; |
| 134 | irqreturn_t (*jpeg_irq)(int irq, void *priv); | 138 | irqreturn_t (*jpeg_irq)(int irq, void *priv); |
| 135 | }; | 139 | }; |
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c b/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c index e3b8e67e005f..b5f20e722b63 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c | |||
| @@ -51,18 +51,6 @@ void s5p_jpeg_input_raw_mode(void __iomem *regs, unsigned long mode) | |||
| 51 | writel(reg, regs + S5P_JPGCMOD); | 51 | writel(reg, regs + S5P_JPGCMOD); |
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | void s5p_jpeg_input_raw_y16(void __iomem *regs, bool y16) | ||
| 55 | { | ||
| 56 | unsigned long reg; | ||
| 57 | |||
| 58 | reg = readl(regs + S5P_JPGCMOD); | ||
| 59 | if (y16) | ||
| 60 | reg |= S5P_MODE_Y16; | ||
| 61 | else | ||
| 62 | reg &= ~S5P_MODE_Y16_MASK; | ||
| 63 | writel(reg, regs + S5P_JPGCMOD); | ||
| 64 | } | ||
| 65 | |||
| 66 | void s5p_jpeg_proc_mode(void __iomem *regs, unsigned long mode) | 54 | void s5p_jpeg_proc_mode(void __iomem *regs, unsigned long mode) |
| 67 | { | 55 | { |
| 68 | unsigned long reg, m; | 56 | unsigned long reg, m; |
| @@ -208,26 +196,6 @@ void s5p_jpeg_final_mcu_num_int_enable(void __iomem *regs, bool enbl) | |||
| 208 | writel(reg, regs + S5P_JPGINTSE); | 196 | writel(reg, regs + S5P_JPGINTSE); |
| 209 | } | 197 | } |
| 210 | 198 | ||
| 211 | void s5p_jpeg_timer_enable(void __iomem *regs, unsigned long val) | ||
| 212 | { | ||
| 213 | unsigned long reg; | ||
| 214 | |||
| 215 | reg = readl(regs + S5P_JPG_TIMER_SE); | ||
| 216 | reg |= S5P_TIMER_INT_EN; | ||
| 217 | reg &= ~S5P_TIMER_INIT_MASK; | ||
| 218 | reg |= val & S5P_TIMER_INIT_MASK; | ||
| 219 | writel(reg, regs + S5P_JPG_TIMER_SE); | ||
| 220 | } | ||
| 221 | |||
| 222 | void s5p_jpeg_timer_disable(void __iomem *regs) | ||
| 223 | { | ||
| 224 | unsigned long reg; | ||
| 225 | |||
| 226 | reg = readl(regs + S5P_JPG_TIMER_SE); | ||
| 227 | reg &= ~S5P_TIMER_INT_EN_MASK; | ||
| 228 | writel(reg, regs + S5P_JPG_TIMER_SE); | ||
| 229 | } | ||
| 230 | |||
| 231 | int s5p_jpeg_timer_stat(void __iomem *regs) | 199 | int s5p_jpeg_timer_stat(void __iomem *regs) |
| 232 | { | 200 | { |
| 233 | return (int)((readl(regs + S5P_JPG_TIMER_ST) & S5P_TIMER_INT_STAT_MASK) | 201 | return (int)((readl(regs + S5P_JPG_TIMER_ST) & S5P_TIMER_INT_STAT_MASK) |
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.h b/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.h index c11ebe86b9c9..f208fa3ed738 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.h +++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.h | |||
| @@ -29,7 +29,6 @@ | |||
| 29 | void s5p_jpeg_reset(void __iomem *regs); | 29 | void s5p_jpeg_reset(void __iomem *regs); |
| 30 | void s5p_jpeg_poweron(void __iomem *regs); | 30 | void s5p_jpeg_poweron(void __iomem *regs); |
| 31 | void s5p_jpeg_input_raw_mode(void __iomem *regs, unsigned long mode); | 31 | void s5p_jpeg_input_raw_mode(void __iomem *regs, unsigned long mode); |
| 32 | void s5p_jpeg_input_raw_y16(void __iomem *regs, bool y16); | ||
| 33 | void s5p_jpeg_proc_mode(void __iomem *regs, unsigned long mode); | 32 | void s5p_jpeg_proc_mode(void __iomem *regs, unsigned long mode); |
| 34 | void s5p_jpeg_subsampling_mode(void __iomem *regs, unsigned int mode); | 33 | void s5p_jpeg_subsampling_mode(void __iomem *regs, unsigned int mode); |
| 35 | unsigned int s5p_jpeg_get_subsampling_mode(void __iomem *regs); | 34 | unsigned int s5p_jpeg_get_subsampling_mode(void __iomem *regs); |
| @@ -42,8 +41,6 @@ void s5p_jpeg_x(void __iomem *regs, unsigned int x); | |||
| 42 | void s5p_jpeg_rst_int_enable(void __iomem *regs, bool enable); | 41 | void s5p_jpeg_rst_int_enable(void __iomem *regs, bool enable); |
| 43 | void s5p_jpeg_data_num_int_enable(void __iomem *regs, bool enable); | 42 | void s5p_jpeg_data_num_int_enable(void __iomem *regs, bool enable); |
| 44 | void s5p_jpeg_final_mcu_num_int_enable(void __iomem *regs, bool enbl); | 43 | void s5p_jpeg_final_mcu_num_int_enable(void __iomem *regs, bool enbl); |
| 45 | void s5p_jpeg_timer_enable(void __iomem *regs, unsigned long val); | ||
| 46 | void s5p_jpeg_timer_disable(void __iomem *regs); | ||
| 47 | int s5p_jpeg_timer_stat(void __iomem *regs); | 44 | int s5p_jpeg_timer_stat(void __iomem *regs); |
| 48 | void s5p_jpeg_clear_timer_stat(void __iomem *regs); | 45 | void s5p_jpeg_clear_timer_stat(void __iomem *regs); |
| 49 | void s5p_jpeg_enc_stream_int(void __iomem *regs, unsigned long size); | 46 | void s5p_jpeg_enc_stream_int(void __iomem *regs, unsigned long size); |
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 98374e8bad3e..8333fbc2fe96 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c | |||
| @@ -844,6 +844,13 @@ static int s5p_mfc_open(struct file *file) | |||
| 844 | ret = -ENOENT; | 844 | ret = -ENOENT; |
| 845 | goto err_queue_init; | 845 | goto err_queue_init; |
| 846 | } | 846 | } |
| 847 | /* One way to indicate end-of-stream for MFC is to set the | ||
| 848 | * bytesused == 0. However by default videobuf2 handles bytesused | ||
| 849 | * equal to 0 as a special case and changes its value to the size | ||
| 850 | * of the buffer. Set the allow_zero_bytesused flag so that videobuf2 | ||
| 851 | * will keep the value of bytesused intact. | ||
| 852 | */ | ||
| 853 | q->allow_zero_bytesused = 1; | ||
| 847 | q->mem_ops = &vb2_dma_contig_memops; | 854 | q->mem_ops = &vb2_dma_contig_memops; |
| 848 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; | 855 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; |
| 849 | ret = vb2_queue_init(q); | 856 | ret = vb2_queue_init(q); |
diff --git a/drivers/media/platform/s5p-tv/mixer_video.c b/drivers/media/platform/s5p-tv/mixer_video.c index 72d4f2e1efc0..751f3b618337 100644 --- a/drivers/media/platform/s5p-tv/mixer_video.c +++ b/drivers/media/platform/s5p-tv/mixer_video.c | |||
| @@ -287,7 +287,7 @@ static void mxr_mplane_fill(struct v4l2_plane_pix_format *planes, | |||
| 287 | u32 bl_width = divup(width, blk->width); | 287 | u32 bl_width = divup(width, blk->width); |
| 288 | u32 bl_height = divup(height, blk->height); | 288 | u32 bl_height = divup(height, blk->height); |
| 289 | u32 sizeimage = bl_width * bl_height * blk->size; | 289 | u32 sizeimage = bl_width * bl_height * blk->size; |
| 290 | u16 bytesperline = bl_width * blk->size / blk->height; | 290 | u32 bytesperline = bl_width * blk->size / blk->height; |
| 291 | 291 | ||
| 292 | plane->sizeimage += sizeimage; | 292 | plane->sizeimage += sizeimage; |
| 293 | plane->bytesperline = max(plane->bytesperline, bytesperline); | 293 | plane->bytesperline = max(plane->bytesperline, bytesperline); |
diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c index 261f1195b49f..dde1ccc730be 100644 --- a/drivers/media/platform/sh_vou.c +++ b/drivers/media/platform/sh_vou.c | |||
| @@ -62,7 +62,7 @@ enum sh_vou_status { | |||
| 62 | 62 | ||
| 63 | struct sh_vou_device { | 63 | struct sh_vou_device { |
| 64 | struct v4l2_device v4l2_dev; | 64 | struct v4l2_device v4l2_dev; |
| 65 | struct video_device *vdev; | 65 | struct video_device vdev; |
| 66 | atomic_t use_count; | 66 | atomic_t use_count; |
| 67 | struct sh_vou_pdata *pdata; | 67 | struct sh_vou_pdata *pdata; |
| 68 | spinlock_t lock; | 68 | spinlock_t lock; |
| @@ -890,7 +890,7 @@ static int sh_vou_s_std(struct file *file, void *priv, v4l2_std_id std_id) | |||
| 890 | 890 | ||
| 891 | dev_dbg(vou_dev->v4l2_dev.dev, "%s(): 0x%llx\n", __func__, std_id); | 891 | dev_dbg(vou_dev->v4l2_dev.dev, "%s(): 0x%llx\n", __func__, std_id); |
| 892 | 892 | ||
| 893 | if (std_id & ~vou_dev->vdev->tvnorms) | 893 | if (std_id & ~vou_dev->vdev.tvnorms) |
| 894 | return -EINVAL; | 894 | return -EINVAL; |
| 895 | 895 | ||
| 896 | ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video, | 896 | ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video, |
| @@ -1168,10 +1168,10 @@ static int sh_vou_open(struct file *file) | |||
| 1168 | 1168 | ||
| 1169 | dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); | 1169 | dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); |
| 1170 | 1170 | ||
| 1171 | file->private_data = vou_file; | 1171 | if (mutex_lock_interruptible(&vou_dev->fop_lock)) { |
| 1172 | 1172 | kfree(vou_file); | |
| 1173 | if (mutex_lock_interruptible(&vou_dev->fop_lock)) | ||
| 1174 | return -ERESTARTSYS; | 1173 | return -ERESTARTSYS; |
| 1174 | } | ||
| 1175 | if (atomic_inc_return(&vou_dev->use_count) == 1) { | 1175 | if (atomic_inc_return(&vou_dev->use_count) == 1) { |
| 1176 | int ret; | 1176 | int ret; |
| 1177 | /* First open */ | 1177 | /* First open */ |
| @@ -1183,6 +1183,7 @@ static int sh_vou_open(struct file *file) | |||
| 1183 | pm_runtime_put(vou_dev->v4l2_dev.dev); | 1183 | pm_runtime_put(vou_dev->v4l2_dev.dev); |
| 1184 | vou_dev->status = SH_VOU_IDLE; | 1184 | vou_dev->status = SH_VOU_IDLE; |
| 1185 | mutex_unlock(&vou_dev->fop_lock); | 1185 | mutex_unlock(&vou_dev->fop_lock); |
| 1186 | kfree(vou_file); | ||
| 1186 | return ret; | 1187 | return ret; |
| 1187 | } | 1188 | } |
| 1188 | } | 1189 | } |
| @@ -1192,9 +1193,11 @@ static int sh_vou_open(struct file *file) | |||
| 1192 | V4L2_BUF_TYPE_VIDEO_OUTPUT, | 1193 | V4L2_BUF_TYPE_VIDEO_OUTPUT, |
| 1193 | V4L2_FIELD_NONE, | 1194 | V4L2_FIELD_NONE, |
| 1194 | sizeof(struct videobuf_buffer), | 1195 | sizeof(struct videobuf_buffer), |
| 1195 | vou_dev->vdev, &vou_dev->fop_lock); | 1196 | &vou_dev->vdev, &vou_dev->fop_lock); |
| 1196 | mutex_unlock(&vou_dev->fop_lock); | 1197 | mutex_unlock(&vou_dev->fop_lock); |
| 1197 | 1198 | ||
| 1199 | file->private_data = vou_file; | ||
| 1200 | |||
| 1198 | return 0; | 1201 | return 0; |
| 1199 | } | 1202 | } |
| 1200 | 1203 | ||
| @@ -1358,21 +1361,14 @@ static int sh_vou_probe(struct platform_device *pdev) | |||
| 1358 | goto ev4l2devreg; | 1361 | goto ev4l2devreg; |
| 1359 | } | 1362 | } |
| 1360 | 1363 | ||
| 1361 | /* Allocate memory for video device */ | 1364 | vdev = &vou_dev->vdev; |
| 1362 | vdev = video_device_alloc(); | ||
| 1363 | if (vdev == NULL) { | ||
| 1364 | ret = -ENOMEM; | ||
| 1365 | goto evdevalloc; | ||
| 1366 | } | ||
| 1367 | |||
| 1368 | *vdev = sh_vou_video_template; | 1365 | *vdev = sh_vou_video_template; |
| 1369 | if (vou_pdata->bus_fmt == SH_VOU_BUS_8BIT) | 1366 | if (vou_pdata->bus_fmt == SH_VOU_BUS_8BIT) |
| 1370 | vdev->tvnorms |= V4L2_STD_PAL; | 1367 | vdev->tvnorms |= V4L2_STD_PAL; |
| 1371 | vdev->v4l2_dev = &vou_dev->v4l2_dev; | 1368 | vdev->v4l2_dev = &vou_dev->v4l2_dev; |
| 1372 | vdev->release = video_device_release; | 1369 | vdev->release = video_device_release_empty; |
| 1373 | vdev->lock = &vou_dev->fop_lock; | 1370 | vdev->lock = &vou_dev->fop_lock; |
| 1374 | 1371 | ||
| 1375 | vou_dev->vdev = vdev; | ||
| 1376 | video_set_drvdata(vdev, vou_dev); | 1372 | video_set_drvdata(vdev, vou_dev); |
| 1377 | 1373 | ||
| 1378 | pm_runtime_enable(&pdev->dev); | 1374 | pm_runtime_enable(&pdev->dev); |
| @@ -1406,9 +1402,7 @@ ei2cnd: | |||
| 1406 | ereset: | 1402 | ereset: |
| 1407 | i2c_put_adapter(i2c_adap); | 1403 | i2c_put_adapter(i2c_adap); |
| 1408 | ei2cgadap: | 1404 | ei2cgadap: |
| 1409 | video_device_release(vdev); | ||
| 1410 | pm_runtime_disable(&pdev->dev); | 1405 | pm_runtime_disable(&pdev->dev); |
| 1411 | evdevalloc: | ||
| 1412 | v4l2_device_unregister(&vou_dev->v4l2_dev); | 1406 | v4l2_device_unregister(&vou_dev->v4l2_dev); |
| 1413 | ev4l2devreg: | 1407 | ev4l2devreg: |
| 1414 | free_irq(irq, vou_dev); | 1408 | free_irq(irq, vou_dev); |
| @@ -1435,7 +1429,7 @@ static int sh_vou_remove(struct platform_device *pdev) | |||
| 1435 | if (irq > 0) | 1429 | if (irq > 0) |
| 1436 | free_irq(irq, vou_dev); | 1430 | free_irq(irq, vou_dev); |
| 1437 | pm_runtime_disable(&pdev->dev); | 1431 | pm_runtime_disable(&pdev->dev); |
| 1438 | video_unregister_device(vou_dev->vdev); | 1432 | video_unregister_device(&vou_dev->vdev); |
| 1439 | i2c_put_adapter(client->adapter); | 1433 | i2c_put_adapter(client->adapter); |
| 1440 | v4l2_device_unregister(&vou_dev->v4l2_dev); | 1434 | v4l2_device_unregister(&vou_dev->v4l2_dev); |
| 1441 | iounmap(vou_dev->base); | 1435 | iounmap(vou_dev->base); |
diff --git a/drivers/media/platform/soc_camera/rcar_vin.c b/drivers/media/platform/soc_camera/rcar_vin.c index 279ab9f6ae38..9351f64dee7b 100644 --- a/drivers/media/platform/soc_camera/rcar_vin.c +++ b/drivers/media/platform/soc_camera/rcar_vin.c | |||
| @@ -977,19 +977,6 @@ static void rcar_vin_remove_device(struct soc_camera_device *icd) | |||
| 977 | icd->devnum); | 977 | icd->devnum); |
| 978 | } | 978 | } |
| 979 | 979 | ||
| 980 | /* Called with .host_lock held */ | ||
| 981 | static int rcar_vin_clock_start(struct soc_camera_host *ici) | ||
| 982 | { | ||
| 983 | /* VIN does not have "mclk" */ | ||
| 984 | return 0; | ||
| 985 | } | ||
| 986 | |||
| 987 | /* Called with .host_lock held */ | ||
| 988 | static void rcar_vin_clock_stop(struct soc_camera_host *ici) | ||
| 989 | { | ||
| 990 | /* VIN does not have "mclk" */ | ||
| 991 | } | ||
| 992 | |||
| 993 | static void set_coeff(struct rcar_vin_priv *priv, unsigned short xs) | 980 | static void set_coeff(struct rcar_vin_priv *priv, unsigned short xs) |
| 994 | { | 981 | { |
| 995 | int i; | 982 | int i; |
| @@ -1803,8 +1790,6 @@ static struct soc_camera_host_ops rcar_vin_host_ops = { | |||
| 1803 | .owner = THIS_MODULE, | 1790 | .owner = THIS_MODULE, |
| 1804 | .add = rcar_vin_add_device, | 1791 | .add = rcar_vin_add_device, |
| 1805 | .remove = rcar_vin_remove_device, | 1792 | .remove = rcar_vin_remove_device, |
| 1806 | .clock_start = rcar_vin_clock_start, | ||
| 1807 | .clock_stop = rcar_vin_clock_stop, | ||
| 1808 | .get_formats = rcar_vin_get_formats, | 1793 | .get_formats = rcar_vin_get_formats, |
| 1809 | .put_formats = rcar_vin_put_formats, | 1794 | .put_formats = rcar_vin_put_formats, |
| 1810 | .get_crop = rcar_vin_get_crop, | 1795 | .get_crop = rcar_vin_get_crop, |
diff --git a/drivers/media/platform/soc_camera/sh_mobile_csi2.c b/drivers/media/platform/soc_camera/sh_mobile_csi2.c index c4e7aa0ee7e1..cd93241eb497 100644 --- a/drivers/media/platform/soc_camera/sh_mobile_csi2.c +++ b/drivers/media/platform/soc_camera/sh_mobile_csi2.c | |||
| @@ -380,7 +380,6 @@ static int sh_csi2_remove(struct platform_device *pdev) | |||
| 380 | struct sh_csi2 *priv = container_of(subdev, struct sh_csi2, subdev); | 380 | struct sh_csi2 *priv = container_of(subdev, struct sh_csi2, subdev); |
| 381 | 381 | ||
| 382 | v4l2_async_unregister_subdev(&priv->subdev); | 382 | v4l2_async_unregister_subdev(&priv->subdev); |
| 383 | v4l2_device_unregister_subdev(subdev); | ||
| 384 | pm_runtime_disable(&pdev->dev); | 383 | pm_runtime_disable(&pdev->dev); |
| 385 | 384 | ||
| 386 | return 0; | 385 | return 0; |
diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index 66634b469c98..55370d74ff57 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c | |||
| @@ -177,6 +177,30 @@ static int __soc_camera_power_off(struct soc_camera_device *icd) | |||
| 177 | return 0; | 177 | return 0; |
| 178 | } | 178 | } |
| 179 | 179 | ||
| 180 | static int soc_camera_clock_start(struct soc_camera_host *ici) | ||
| 181 | { | ||
| 182 | int ret; | ||
| 183 | |||
| 184 | if (!ici->ops->clock_start) | ||
| 185 | return 0; | ||
| 186 | |||
| 187 | mutex_lock(&ici->clk_lock); | ||
| 188 | ret = ici->ops->clock_start(ici); | ||
| 189 | mutex_unlock(&ici->clk_lock); | ||
| 190 | |||
| 191 | return ret; | ||
| 192 | } | ||
| 193 | |||
| 194 | static void soc_camera_clock_stop(struct soc_camera_host *ici) | ||
| 195 | { | ||
| 196 | if (!ici->ops->clock_stop) | ||
| 197 | return; | ||
| 198 | |||
| 199 | mutex_lock(&ici->clk_lock); | ||
| 200 | ici->ops->clock_stop(ici); | ||
| 201 | mutex_unlock(&ici->clk_lock); | ||
| 202 | } | ||
| 203 | |||
| 180 | const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc( | 204 | const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc( |
| 181 | struct soc_camera_device *icd, unsigned int fourcc) | 205 | struct soc_camera_device *icd, unsigned int fourcc) |
| 182 | { | 206 | { |
| @@ -584,9 +608,7 @@ static int soc_camera_add_device(struct soc_camera_device *icd) | |||
| 584 | return -EBUSY; | 608 | return -EBUSY; |
| 585 | 609 | ||
| 586 | if (!icd->clk) { | 610 | if (!icd->clk) { |
| 587 | mutex_lock(&ici->clk_lock); | 611 | ret = soc_camera_clock_start(ici); |
| 588 | ret = ici->ops->clock_start(ici); | ||
| 589 | mutex_unlock(&ici->clk_lock); | ||
| 590 | if (ret < 0) | 612 | if (ret < 0) |
| 591 | return ret; | 613 | return ret; |
| 592 | } | 614 | } |
| @@ -602,11 +624,8 @@ static int soc_camera_add_device(struct soc_camera_device *icd) | |||
| 602 | return 0; | 624 | return 0; |
| 603 | 625 | ||
| 604 | eadd: | 626 | eadd: |
| 605 | if (!icd->clk) { | 627 | if (!icd->clk) |
| 606 | mutex_lock(&ici->clk_lock); | 628 | soc_camera_clock_stop(ici); |
| 607 | ici->ops->clock_stop(ici); | ||
| 608 | mutex_unlock(&ici->clk_lock); | ||
| 609 | } | ||
| 610 | return ret; | 629 | return ret; |
| 611 | } | 630 | } |
| 612 | 631 | ||
| @@ -619,11 +638,8 @@ static void soc_camera_remove_device(struct soc_camera_device *icd) | |||
| 619 | 638 | ||
| 620 | if (ici->ops->remove) | 639 | if (ici->ops->remove) |
| 621 | ici->ops->remove(icd); | 640 | ici->ops->remove(icd); |
| 622 | if (!icd->clk) { | 641 | if (!icd->clk) |
| 623 | mutex_lock(&ici->clk_lock); | 642 | soc_camera_clock_stop(ici); |
| 624 | ici->ops->clock_stop(ici); | ||
| 625 | mutex_unlock(&ici->clk_lock); | ||
| 626 | } | ||
| 627 | ici->icd = NULL; | 643 | ici->icd = NULL; |
| 628 | } | 644 | } |
| 629 | 645 | ||
| @@ -688,7 +704,8 @@ static int soc_camera_open(struct file *file) | |||
| 688 | 704 | ||
| 689 | /* The camera could have been already on, try to reset */ | 705 | /* The camera could have been already on, try to reset */ |
| 690 | if (sdesc->subdev_desc.reset) | 706 | if (sdesc->subdev_desc.reset) |
| 691 | sdesc->subdev_desc.reset(icd->pdev); | 707 | if (icd->control) |
| 708 | sdesc->subdev_desc.reset(icd->control); | ||
| 692 | 709 | ||
| 693 | ret = soc_camera_add_device(icd); | 710 | ret = soc_camera_add_device(icd); |
| 694 | if (ret < 0) { | 711 | if (ret < 0) { |
| @@ -1159,7 +1176,8 @@ static void scan_add_host(struct soc_camera_host *ici) | |||
| 1159 | 1176 | ||
| 1160 | /* The camera could have been already on, try to reset */ | 1177 | /* The camera could have been already on, try to reset */ |
| 1161 | if (ssdd->reset) | 1178 | if (ssdd->reset) |
| 1162 | ssdd->reset(icd->pdev); | 1179 | if (icd->control) |
| 1180 | ssdd->reset(icd->control); | ||
| 1163 | 1181 | ||
| 1164 | icd->parent = ici->v4l2_dev.dev; | 1182 | icd->parent = ici->v4l2_dev.dev; |
| 1165 | 1183 | ||
| @@ -1178,7 +1196,6 @@ static int soc_camera_clk_enable(struct v4l2_clk *clk) | |||
| 1178 | { | 1196 | { |
| 1179 | struct soc_camera_device *icd = clk->priv; | 1197 | struct soc_camera_device *icd = clk->priv; |
| 1180 | struct soc_camera_host *ici; | 1198 | struct soc_camera_host *ici; |
| 1181 | int ret; | ||
| 1182 | 1199 | ||
| 1183 | if (!icd || !icd->parent) | 1200 | if (!icd || !icd->parent) |
| 1184 | return -ENODEV; | 1201 | return -ENODEV; |
| @@ -1192,10 +1209,7 @@ static int soc_camera_clk_enable(struct v4l2_clk *clk) | |||
| 1192 | * If a different client is currently being probed, the host will tell | 1209 | * If a different client is currently being probed, the host will tell |
| 1193 | * you to go | 1210 | * you to go |
| 1194 | */ | 1211 | */ |
| 1195 | mutex_lock(&ici->clk_lock); | 1212 | return soc_camera_clock_start(ici); |
| 1196 | ret = ici->ops->clock_start(ici); | ||
| 1197 | mutex_unlock(&ici->clk_lock); | ||
| 1198 | return ret; | ||
| 1199 | } | 1213 | } |
| 1200 | 1214 | ||
| 1201 | static void soc_camera_clk_disable(struct v4l2_clk *clk) | 1215 | static void soc_camera_clk_disable(struct v4l2_clk *clk) |
| @@ -1208,9 +1222,7 @@ static void soc_camera_clk_disable(struct v4l2_clk *clk) | |||
| 1208 | 1222 | ||
| 1209 | ici = to_soc_camera_host(icd->parent); | 1223 | ici = to_soc_camera_host(icd->parent); |
| 1210 | 1224 | ||
| 1211 | mutex_lock(&ici->clk_lock); | 1225 | soc_camera_clock_stop(ici); |
| 1212 | ici->ops->clock_stop(ici); | ||
| 1213 | mutex_unlock(&ici->clk_lock); | ||
| 1214 | 1226 | ||
| 1215 | module_put(ici->ops->owner); | 1227 | module_put(ici->ops->owner); |
| 1216 | } | 1228 | } |
| @@ -1364,7 +1376,7 @@ static int soc_camera_i2c_init(struct soc_camera_device *icd, | |||
| 1364 | snprintf(clk_name, sizeof(clk_name), "%d-%04x", | 1376 | snprintf(clk_name, sizeof(clk_name), "%d-%04x", |
| 1365 | shd->i2c_adapter_id, shd->board_info->addr); | 1377 | shd->i2c_adapter_id, shd->board_info->addr); |
| 1366 | 1378 | ||
| 1367 | icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, "mclk", icd); | 1379 | icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, icd); |
| 1368 | if (IS_ERR(icd->clk)) { | 1380 | if (IS_ERR(icd->clk)) { |
| 1369 | ret = PTR_ERR(icd->clk); | 1381 | ret = PTR_ERR(icd->clk); |
| 1370 | goto eclkreg; | 1382 | goto eclkreg; |
| @@ -1445,7 +1457,7 @@ static int soc_camera_async_bound(struct v4l2_async_notifier *notifier, | |||
| 1445 | memcpy(&sdesc->subdev_desc, ssdd, | 1457 | memcpy(&sdesc->subdev_desc, ssdd, |
| 1446 | sizeof(sdesc->subdev_desc)); | 1458 | sizeof(sdesc->subdev_desc)); |
| 1447 | if (ssdd->reset) | 1459 | if (ssdd->reset) |
| 1448 | ssdd->reset(icd->pdev); | 1460 | ssdd->reset(&client->dev); |
| 1449 | } | 1461 | } |
| 1450 | 1462 | ||
| 1451 | icd->control = &client->dev; | 1463 | icd->control = &client->dev; |
| @@ -1545,7 +1557,7 @@ static int scan_async_group(struct soc_camera_host *ici, | |||
| 1545 | snprintf(clk_name, sizeof(clk_name), "%d-%04x", | 1557 | snprintf(clk_name, sizeof(clk_name), "%d-%04x", |
| 1546 | sasd->asd.match.i2c.adapter_id, sasd->asd.match.i2c.address); | 1558 | sasd->asd.match.i2c.adapter_id, sasd->asd.match.i2c.address); |
| 1547 | 1559 | ||
| 1548 | icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, "mclk", icd); | 1560 | icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, icd); |
| 1549 | if (IS_ERR(icd->clk)) { | 1561 | if (IS_ERR(icd->clk)) { |
| 1550 | ret = PTR_ERR(icd->clk); | 1562 | ret = PTR_ERR(icd->clk); |
| 1551 | goto eclkreg; | 1563 | goto eclkreg; |
| @@ -1650,7 +1662,7 @@ static int soc_of_bind(struct soc_camera_host *ici, | |||
| 1650 | snprintf(clk_name, sizeof(clk_name), "of-%s", | 1662 | snprintf(clk_name, sizeof(clk_name), "of-%s", |
| 1651 | of_node_full_name(remote)); | 1663 | of_node_full_name(remote)); |
| 1652 | 1664 | ||
| 1653 | icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, "mclk", icd); | 1665 | icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, icd); |
| 1654 | if (IS_ERR(icd->clk)) { | 1666 | if (IS_ERR(icd->clk)) { |
| 1655 | ret = PTR_ERR(icd->clk); | 1667 | ret = PTR_ERR(icd->clk); |
| 1656 | goto eclkreg; | 1668 | goto eclkreg; |
| @@ -1659,6 +1671,8 @@ static int soc_of_bind(struct soc_camera_host *ici, | |||
| 1659 | ret = v4l2_async_notifier_register(&ici->v4l2_dev, &sasc->notifier); | 1671 | ret = v4l2_async_notifier_register(&ici->v4l2_dev, &sasc->notifier); |
| 1660 | if (!ret) | 1672 | if (!ret) |
| 1661 | return 0; | 1673 | return 0; |
| 1674 | |||
| 1675 | v4l2_clk_unregister(icd->clk); | ||
| 1662 | eclkreg: | 1676 | eclkreg: |
| 1663 | icd->clk = NULL; | 1677 | icd->clk = NULL; |
| 1664 | platform_device_del(sasc->pdev); | 1678 | platform_device_del(sasc->pdev); |
| @@ -1750,9 +1764,7 @@ static int soc_camera_probe(struct soc_camera_host *ici, | |||
| 1750 | ret = -EINVAL; | 1764 | ret = -EINVAL; |
| 1751 | goto eadd; | 1765 | goto eadd; |
| 1752 | } else { | 1766 | } else { |
| 1753 | mutex_lock(&ici->clk_lock); | 1767 | ret = soc_camera_clock_start(ici); |
| 1754 | ret = ici->ops->clock_start(ici); | ||
| 1755 | mutex_unlock(&ici->clk_lock); | ||
| 1756 | if (ret < 0) | 1768 | if (ret < 0) |
| 1757 | goto eadd; | 1769 | goto eadd; |
| 1758 | 1770 | ||
| @@ -1792,9 +1804,7 @@ efinish: | |||
| 1792 | module_put(control->driver->owner); | 1804 | module_put(control->driver->owner); |
| 1793 | enodrv: | 1805 | enodrv: |
| 1794 | eadddev: | 1806 | eadddev: |
| 1795 | mutex_lock(&ici->clk_lock); | 1807 | soc_camera_clock_stop(ici); |
| 1796 | ici->ops->clock_stop(ici); | ||
| 1797 | mutex_unlock(&ici->clk_lock); | ||
| 1798 | } | 1808 | } |
| 1799 | eadd: | 1809 | eadd: |
| 1800 | if (icd->vdev) { | 1810 | if (icd->vdev) { |
| @@ -1888,22 +1898,34 @@ static int default_enum_framesizes(struct soc_camera_device *icd, | |||
| 1888 | int ret; | 1898 | int ret; |
| 1889 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | 1899 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); |
| 1890 | const struct soc_camera_format_xlate *xlate; | 1900 | const struct soc_camera_format_xlate *xlate; |
| 1891 | __u32 pixfmt = fsize->pixel_format; | 1901 | struct v4l2_subdev_frame_size_enum fse = { |
| 1892 | struct v4l2_frmsizeenum fsize_mbus = *fsize; | 1902 | .index = fsize->index, |
| 1903 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
| 1904 | }; | ||
| 1893 | 1905 | ||
| 1894 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); | 1906 | xlate = soc_camera_xlate_by_fourcc(icd, fsize->pixel_format); |
| 1895 | if (!xlate) | 1907 | if (!xlate) |
| 1896 | return -EINVAL; | 1908 | return -EINVAL; |
| 1897 | /* map xlate-code to pixel_format, sensor only handle xlate-code*/ | 1909 | fse.code = xlate->code; |
| 1898 | fsize_mbus.pixel_format = xlate->code; | ||
| 1899 | 1910 | ||
| 1900 | ret = v4l2_subdev_call(sd, video, enum_framesizes, &fsize_mbus); | 1911 | ret = v4l2_subdev_call(sd, pad, enum_frame_size, NULL, &fse); |
| 1901 | if (ret < 0) | 1912 | if (ret < 0) |
| 1902 | return ret; | 1913 | return ret; |
| 1903 | 1914 | ||
| 1904 | *fsize = fsize_mbus; | 1915 | if (fse.min_width == fse.max_width && |
| 1905 | fsize->pixel_format = pixfmt; | 1916 | fse.min_height == fse.max_height) { |
| 1906 | 1917 | fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; | |
| 1918 | fsize->discrete.width = fse.min_width; | ||
| 1919 | fsize->discrete.height = fse.min_height; | ||
| 1920 | return 0; | ||
| 1921 | } | ||
| 1922 | fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; | ||
| 1923 | fsize->stepwise.min_width = fse.min_width; | ||
| 1924 | fsize->stepwise.max_width = fse.max_width; | ||
| 1925 | fsize->stepwise.min_height = fse.min_height; | ||
| 1926 | fsize->stepwise.max_height = fse.max_height; | ||
| 1927 | fsize->stepwise.step_width = 1; | ||
| 1928 | fsize->stepwise.step_height = 1; | ||
| 1907 | return 0; | 1929 | return 0; |
| 1908 | } | 1930 | } |
| 1909 | 1931 | ||
| @@ -1920,8 +1942,6 @@ int soc_camera_host_register(struct soc_camera_host *ici) | |||
| 1920 | ((!ici->ops->init_videobuf || | 1942 | ((!ici->ops->init_videobuf || |
| 1921 | !ici->ops->reqbufs) && | 1943 | !ici->ops->reqbufs) && |
| 1922 | !ici->ops->init_videobuf2) || | 1944 | !ici->ops->init_videobuf2) || |
| 1923 | !ici->ops->clock_start || | ||
| 1924 | !ici->ops->clock_stop || | ||
| 1925 | !ici->ops->poll || | 1945 | !ici->ops->poll || |
| 1926 | !ici->v4l2_dev.dev) | 1946 | !ici->v4l2_dev.dev) |
| 1927 | return -EINVAL; | 1947 | return -EINVAL; |
diff --git a/drivers/media/platform/via-camera.c b/drivers/media/platform/via-camera.c index 86989d86abfa..678ed9f353cb 100644 --- a/drivers/media/platform/via-camera.c +++ b/drivers/media/platform/via-camera.c | |||
| @@ -1147,12 +1147,23 @@ static int viacam_enum_frameintervals(struct file *filp, void *priv, | |||
| 1147 | struct v4l2_frmivalenum *interval) | 1147 | struct v4l2_frmivalenum *interval) |
| 1148 | { | 1148 | { |
| 1149 | struct via_camera *cam = priv; | 1149 | struct via_camera *cam = priv; |
| 1150 | struct v4l2_subdev_frame_interval_enum fie = { | ||
| 1151 | .index = interval->index, | ||
| 1152 | .code = cam->mbus_code, | ||
| 1153 | .width = cam->sensor_format.width, | ||
| 1154 | .height = cam->sensor_format.height, | ||
| 1155 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
| 1156 | }; | ||
| 1150 | int ret; | 1157 | int ret; |
| 1151 | 1158 | ||
| 1152 | mutex_lock(&cam->lock); | 1159 | mutex_lock(&cam->lock); |
| 1153 | ret = sensor_call(cam, video, enum_frameintervals, interval); | 1160 | ret = sensor_call(cam, pad, enum_frame_interval, NULL, &fie); |
| 1154 | mutex_unlock(&cam->lock); | 1161 | mutex_unlock(&cam->lock); |
| 1155 | return ret; | 1162 | if (ret) |
| 1163 | return ret; | ||
| 1164 | interval->type = V4L2_FRMIVAL_TYPE_DISCRETE; | ||
| 1165 | interval->discrete = fie.interval; | ||
| 1166 | return 0; | ||
| 1156 | } | 1167 | } |
| 1157 | 1168 | ||
| 1158 | 1169 | ||
diff --git a/drivers/media/platform/vim2m.c b/drivers/media/platform/vim2m.c index d9d844aab39b..4d6b4cc57c57 100644 --- a/drivers/media/platform/vim2m.c +++ b/drivers/media/platform/vim2m.c | |||
| @@ -142,7 +142,7 @@ static struct vim2m_fmt *find_format(struct v4l2_format *f) | |||
| 142 | 142 | ||
| 143 | struct vim2m_dev { | 143 | struct vim2m_dev { |
| 144 | struct v4l2_device v4l2_dev; | 144 | struct v4l2_device v4l2_dev; |
| 145 | struct video_device *vfd; | 145 | struct video_device vfd; |
| 146 | 146 | ||
| 147 | atomic_t num_inst; | 147 | atomic_t num_inst; |
| 148 | struct mutex dev_mutex; | 148 | struct mutex dev_mutex; |
| @@ -968,7 +968,7 @@ static struct video_device vim2m_videodev = { | |||
| 968 | .fops = &vim2m_fops, | 968 | .fops = &vim2m_fops, |
| 969 | .ioctl_ops = &vim2m_ioctl_ops, | 969 | .ioctl_ops = &vim2m_ioctl_ops, |
| 970 | .minor = -1, | 970 | .minor = -1, |
| 971 | .release = video_device_release, | 971 | .release = video_device_release_empty, |
| 972 | }; | 972 | }; |
| 973 | 973 | ||
| 974 | static struct v4l2_m2m_ops m2m_ops = { | 974 | static struct v4l2_m2m_ops m2m_ops = { |
| @@ -996,26 +996,19 @@ static int vim2m_probe(struct platform_device *pdev) | |||
| 996 | atomic_set(&dev->num_inst, 0); | 996 | atomic_set(&dev->num_inst, 0); |
| 997 | mutex_init(&dev->dev_mutex); | 997 | mutex_init(&dev->dev_mutex); |
| 998 | 998 | ||
| 999 | vfd = video_device_alloc(); | 999 | dev->vfd = vim2m_videodev; |
| 1000 | if (!vfd) { | 1000 | vfd = &dev->vfd; |
| 1001 | v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n"); | ||
| 1002 | ret = -ENOMEM; | ||
| 1003 | goto unreg_dev; | ||
| 1004 | } | ||
| 1005 | |||
| 1006 | *vfd = vim2m_videodev; | ||
| 1007 | vfd->lock = &dev->dev_mutex; | 1001 | vfd->lock = &dev->dev_mutex; |
| 1008 | vfd->v4l2_dev = &dev->v4l2_dev; | 1002 | vfd->v4l2_dev = &dev->v4l2_dev; |
| 1009 | 1003 | ||
| 1010 | ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); | 1004 | ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); |
| 1011 | if (ret) { | 1005 | if (ret) { |
| 1012 | v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); | 1006 | v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); |
| 1013 | goto rel_vdev; | 1007 | goto unreg_dev; |
| 1014 | } | 1008 | } |
| 1015 | 1009 | ||
| 1016 | video_set_drvdata(vfd, dev); | 1010 | video_set_drvdata(vfd, dev); |
| 1017 | snprintf(vfd->name, sizeof(vfd->name), "%s", vim2m_videodev.name); | 1011 | snprintf(vfd->name, sizeof(vfd->name), "%s", vim2m_videodev.name); |
| 1018 | dev->vfd = vfd; | ||
| 1019 | v4l2_info(&dev->v4l2_dev, | 1012 | v4l2_info(&dev->v4l2_dev, |
| 1020 | "Device registered as /dev/video%d\n", vfd->num); | 1013 | "Device registered as /dev/video%d\n", vfd->num); |
| 1021 | 1014 | ||
| @@ -1033,9 +1026,7 @@ static int vim2m_probe(struct platform_device *pdev) | |||
| 1033 | 1026 | ||
| 1034 | err_m2m: | 1027 | err_m2m: |
| 1035 | v4l2_m2m_release(dev->m2m_dev); | 1028 | v4l2_m2m_release(dev->m2m_dev); |
| 1036 | video_unregister_device(dev->vfd); | 1029 | video_unregister_device(&dev->vfd); |
| 1037 | rel_vdev: | ||
| 1038 | video_device_release(vfd); | ||
| 1039 | unreg_dev: | 1030 | unreg_dev: |
| 1040 | v4l2_device_unregister(&dev->v4l2_dev); | 1031 | v4l2_device_unregister(&dev->v4l2_dev); |
| 1041 | 1032 | ||
| @@ -1049,7 +1040,7 @@ static int vim2m_remove(struct platform_device *pdev) | |||
| 1049 | v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_NAME); | 1040 | v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_NAME); |
| 1050 | v4l2_m2m_release(dev->m2m_dev); | 1041 | v4l2_m2m_release(dev->m2m_dev); |
| 1051 | del_timer_sync(&dev->timer); | 1042 | del_timer_sync(&dev->timer); |
| 1052 | video_unregister_device(dev->vfd); | 1043 | video_unregister_device(&dev->vfd); |
| 1053 | v4l2_device_unregister(&dev->v4l2_dev); | 1044 | v4l2_device_unregister(&dev->v4l2_dev); |
| 1054 | 1045 | ||
| 1055 | return 0; | 1046 | return 0; |
diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c index a7e033a5d291..d33f16495dbc 100644 --- a/drivers/media/platform/vivid/vivid-core.c +++ b/drivers/media/platform/vivid/vivid-core.c | |||
| @@ -26,6 +26,7 @@ | |||
| 26 | #include <linux/vmalloc.h> | 26 | #include <linux/vmalloc.h> |
| 27 | #include <linux/font.h> | 27 | #include <linux/font.h> |
| 28 | #include <linux/mutex.h> | 28 | #include <linux/mutex.h> |
| 29 | #include <linux/platform_device.h> | ||
| 29 | #include <linux/videodev2.h> | 30 | #include <linux/videodev2.h> |
| 30 | #include <linux/v4l2-dv-timings.h> | 31 | #include <linux/v4l2-dv-timings.h> |
| 31 | #include <media/videobuf2-vmalloc.h> | 32 | #include <media/videobuf2-vmalloc.h> |
| @@ -618,7 +619,23 @@ static const struct v4l2_ioctl_ops vivid_ioctl_ops = { | |||
| 618 | Initialization and module stuff | 619 | Initialization and module stuff |
| 619 | ------------------------------------------------------------------*/ | 620 | ------------------------------------------------------------------*/ |
| 620 | 621 | ||
| 621 | static int __init vivid_create_instance(int inst) | 622 | static void vivid_dev_release(struct v4l2_device *v4l2_dev) |
| 623 | { | ||
| 624 | struct vivid_dev *dev = container_of(v4l2_dev, struct vivid_dev, v4l2_dev); | ||
| 625 | |||
| 626 | vivid_free_controls(dev); | ||
| 627 | v4l2_device_unregister(&dev->v4l2_dev); | ||
| 628 | vfree(dev->scaled_line); | ||
| 629 | vfree(dev->blended_line); | ||
| 630 | vfree(dev->edid); | ||
| 631 | vfree(dev->bitmap_cap); | ||
| 632 | vfree(dev->bitmap_out); | ||
| 633 | tpg_free(&dev->tpg); | ||
| 634 | kfree(dev->query_dv_timings_qmenu); | ||
| 635 | kfree(dev); | ||
| 636 | } | ||
| 637 | |||
| 638 | static int vivid_create_instance(struct platform_device *pdev, int inst) | ||
| 622 | { | 639 | { |
| 623 | static const struct v4l2_dv_timings def_dv_timings = | 640 | static const struct v4l2_dv_timings def_dv_timings = |
| 624 | V4L2_DV_BT_CEA_1280X720P60; | 641 | V4L2_DV_BT_CEA_1280X720P60; |
| @@ -646,9 +663,12 @@ static int __init vivid_create_instance(int inst) | |||
| 646 | /* register v4l2_device */ | 663 | /* register v4l2_device */ |
| 647 | snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), | 664 | snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), |
| 648 | "%s-%03d", VIVID_MODULE_NAME, inst); | 665 | "%s-%03d", VIVID_MODULE_NAME, inst); |
| 649 | ret = v4l2_device_register(NULL, &dev->v4l2_dev); | 666 | ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); |
| 650 | if (ret) | 667 | if (ret) { |
| 651 | goto free_dev; | 668 | kfree(dev); |
| 669 | return ret; | ||
| 670 | } | ||
| 671 | dev->v4l2_dev.release = vivid_dev_release; | ||
| 652 | 672 | ||
| 653 | /* start detecting feature set */ | 673 | /* start detecting feature set */ |
| 654 | 674 | ||
| @@ -1256,15 +1276,8 @@ unreg_dev: | |||
| 1256 | video_unregister_device(&dev->vbi_cap_dev); | 1276 | video_unregister_device(&dev->vbi_cap_dev); |
| 1257 | video_unregister_device(&dev->vid_out_dev); | 1277 | video_unregister_device(&dev->vid_out_dev); |
| 1258 | video_unregister_device(&dev->vid_cap_dev); | 1278 | video_unregister_device(&dev->vid_cap_dev); |
| 1259 | vivid_free_controls(dev); | ||
| 1260 | v4l2_device_unregister(&dev->v4l2_dev); | ||
| 1261 | free_dev: | 1279 | free_dev: |
| 1262 | vfree(dev->scaled_line); | 1280 | v4l2_device_put(&dev->v4l2_dev); |
| 1263 | vfree(dev->blended_line); | ||
| 1264 | vfree(dev->edid); | ||
| 1265 | tpg_free(&dev->tpg); | ||
| 1266 | kfree(dev->query_dv_timings_qmenu); | ||
| 1267 | kfree(dev); | ||
| 1268 | return ret; | 1281 | return ret; |
| 1269 | } | 1282 | } |
| 1270 | 1283 | ||
| @@ -1274,7 +1287,7 @@ free_dev: | |||
| 1274 | will succeed. This is limited to the maximum number of devices that | 1287 | will succeed. This is limited to the maximum number of devices that |
| 1275 | videodev supports, which is equal to VIDEO_NUM_DEVICES. | 1288 | videodev supports, which is equal to VIDEO_NUM_DEVICES. |
| 1276 | */ | 1289 | */ |
| 1277 | static int __init vivid_init(void) | 1290 | static int vivid_probe(struct platform_device *pdev) |
| 1278 | { | 1291 | { |
| 1279 | const struct font_desc *font = find_font("VGA8x16"); | 1292 | const struct font_desc *font = find_font("VGA8x16"); |
| 1280 | int ret = 0, i; | 1293 | int ret = 0, i; |
| @@ -1289,7 +1302,7 @@ static int __init vivid_init(void) | |||
| 1289 | n_devs = clamp_t(unsigned, n_devs, 1, VIVID_MAX_DEVS); | 1302 | n_devs = clamp_t(unsigned, n_devs, 1, VIVID_MAX_DEVS); |
| 1290 | 1303 | ||
| 1291 | for (i = 0; i < n_devs; i++) { | 1304 | for (i = 0; i < n_devs; i++) { |
| 1292 | ret = vivid_create_instance(i); | 1305 | ret = vivid_create_instance(pdev, i); |
| 1293 | if (ret) { | 1306 | if (ret) { |
| 1294 | /* If some instantiations succeeded, keep driver */ | 1307 | /* If some instantiations succeeded, keep driver */ |
| 1295 | if (i) | 1308 | if (i) |
| @@ -1309,7 +1322,7 @@ static int __init vivid_init(void) | |||
| 1309 | return ret; | 1322 | return ret; |
| 1310 | } | 1323 | } |
| 1311 | 1324 | ||
| 1312 | static void __exit vivid_exit(void) | 1325 | static int vivid_remove(struct platform_device *pdev) |
| 1313 | { | 1326 | { |
| 1314 | struct vivid_dev *dev; | 1327 | struct vivid_dev *dev; |
| 1315 | unsigned i; | 1328 | unsigned i; |
| @@ -1358,18 +1371,48 @@ static void __exit vivid_exit(void) | |||
| 1358 | unregister_framebuffer(&dev->fb_info); | 1371 | unregister_framebuffer(&dev->fb_info); |
| 1359 | vivid_fb_release_buffers(dev); | 1372 | vivid_fb_release_buffers(dev); |
| 1360 | } | 1373 | } |
| 1361 | v4l2_device_unregister(&dev->v4l2_dev); | 1374 | v4l2_device_put(&dev->v4l2_dev); |
| 1362 | vivid_free_controls(dev); | ||
| 1363 | vfree(dev->scaled_line); | ||
| 1364 | vfree(dev->blended_line); | ||
| 1365 | vfree(dev->edid); | ||
| 1366 | vfree(dev->bitmap_cap); | ||
| 1367 | vfree(dev->bitmap_out); | ||
| 1368 | tpg_free(&dev->tpg); | ||
| 1369 | kfree(dev->query_dv_timings_qmenu); | ||
| 1370 | kfree(dev); | ||
| 1371 | vivid_devs[i] = NULL; | 1375 | vivid_devs[i] = NULL; |
| 1372 | } | 1376 | } |
| 1377 | return 0; | ||
| 1378 | } | ||
| 1379 | |||
| 1380 | static void vivid_pdev_release(struct device *dev) | ||
| 1381 | { | ||
| 1382 | } | ||
| 1383 | |||
| 1384 | static struct platform_device vivid_pdev = { | ||
| 1385 | .name = "vivid", | ||
| 1386 | .dev.release = vivid_pdev_release, | ||
| 1387 | }; | ||
| 1388 | |||
| 1389 | static struct platform_driver vivid_pdrv = { | ||
| 1390 | .probe = vivid_probe, | ||
| 1391 | .remove = vivid_remove, | ||
| 1392 | .driver = { | ||
| 1393 | .name = "vivid", | ||
| 1394 | }, | ||
| 1395 | }; | ||
| 1396 | |||
| 1397 | static int __init vivid_init(void) | ||
| 1398 | { | ||
| 1399 | int ret; | ||
| 1400 | |||
| 1401 | ret = platform_device_register(&vivid_pdev); | ||
| 1402 | if (ret) | ||
| 1403 | return ret; | ||
| 1404 | |||
| 1405 | ret = platform_driver_register(&vivid_pdrv); | ||
| 1406 | if (ret) | ||
| 1407 | platform_device_unregister(&vivid_pdev); | ||
| 1408 | |||
| 1409 | return ret; | ||
| 1410 | } | ||
| 1411 | |||
| 1412 | static void __exit vivid_exit(void) | ||
| 1413 | { | ||
| 1414 | platform_driver_unregister(&vivid_pdrv); | ||
| 1415 | platform_device_unregister(&vivid_pdev); | ||
| 1373 | } | 1416 | } |
| 1374 | 1417 | ||
| 1375 | module_init(vivid_init); | 1418 | module_init(vivid_init); |
diff --git a/drivers/media/platform/vivid/vivid-core.h b/drivers/media/platform/vivid/vivid-core.h index 4b497df4b6a4..9e15aee9a52e 100644 --- a/drivers/media/platform/vivid/vivid-core.h +++ b/drivers/media/platform/vivid/vivid-core.h | |||
| @@ -79,12 +79,14 @@ extern unsigned vivid_debug; | |||
| 79 | struct vivid_fmt { | 79 | struct vivid_fmt { |
| 80 | const char *name; | 80 | const char *name; |
| 81 | u32 fourcc; /* v4l2 format id */ | 81 | u32 fourcc; /* v4l2 format id */ |
| 82 | u8 depth; | ||
| 83 | bool is_yuv; | 82 | bool is_yuv; |
| 84 | bool can_do_overlay; | 83 | bool can_do_overlay; |
| 84 | u8 vdownsampling[TPG_MAX_PLANES]; | ||
| 85 | u32 alpha_mask; | 85 | u32 alpha_mask; |
| 86 | u8 planes; | 86 | u8 planes; |
| 87 | u32 data_offset[2]; | 87 | u8 buffers; |
| 88 | u32 data_offset[TPG_MAX_PLANES]; | ||
| 89 | u32 bit_depth[TPG_MAX_PLANES]; | ||
| 88 | }; | 90 | }; |
| 89 | 91 | ||
| 90 | extern struct vivid_fmt vivid_formats[]; | 92 | extern struct vivid_fmt vivid_formats[]; |
| @@ -332,7 +334,7 @@ struct vivid_dev { | |||
| 332 | u32 ycbcr_enc_out; | 334 | u32 ycbcr_enc_out; |
| 333 | u32 quantization_out; | 335 | u32 quantization_out; |
| 334 | u32 service_set_out; | 336 | u32 service_set_out; |
| 335 | u32 bytesperline_out[2]; | 337 | unsigned bytesperline_out[TPG_MAX_PLANES]; |
| 336 | unsigned tv_field_out; | 338 | unsigned tv_field_out; |
| 337 | unsigned tv_audio_output; | 339 | unsigned tv_audio_output; |
| 338 | bool vbi_out_have_wss; | 340 | bool vbi_out_have_wss; |
diff --git a/drivers/media/platform/vivid/vivid-ctrls.c b/drivers/media/platform/vivid/vivid-ctrls.c index 32a798f2d953..2b9070098b08 100644 --- a/drivers/media/platform/vivid/vivid-ctrls.c +++ b/drivers/media/platform/vivid/vivid-ctrls.c | |||
| @@ -818,7 +818,7 @@ static int vivid_vid_out_s_ctrl(struct v4l2_ctrl *ctrl) | |||
| 818 | dev->dvi_d_out = ctrl->val == V4L2_DV_TX_MODE_DVI_D; | 818 | dev->dvi_d_out = ctrl->val == V4L2_DV_TX_MODE_DVI_D; |
| 819 | if (!vivid_is_hdmi_out(dev)) | 819 | if (!vivid_is_hdmi_out(dev)) |
| 820 | break; | 820 | break; |
| 821 | if (!dev->dvi_d_out && (bt->standards & V4L2_DV_BT_STD_CEA861)) { | 821 | if (!dev->dvi_d_out && (bt->flags & V4L2_DV_FL_IS_CE_VIDEO)) { |
| 822 | if (bt->width == 720 && bt->height <= 576) | 822 | if (bt->width == 720 && bt->height <= 576) |
| 823 | dev->colorspace_out = V4L2_COLORSPACE_SMPTE170M; | 823 | dev->colorspace_out = V4L2_COLORSPACE_SMPTE170M; |
| 824 | else | 824 | else |
diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.c b/drivers/media/platform/vivid/vivid-kthread-cap.c index 39a67cfae120..1727f5453f0b 100644 --- a/drivers/media/platform/vivid/vivid-kthread-cap.c +++ b/drivers/media/platform/vivid/vivid-kthread-cap.c | |||
| @@ -229,14 +229,29 @@ static void vivid_precalc_copy_rects(struct vivid_dev *dev) | |||
| 229 | dev->loop_vid_overlay_cap.left, dev->loop_vid_overlay_cap.top); | 229 | dev->loop_vid_overlay_cap.left, dev->loop_vid_overlay_cap.top); |
| 230 | } | 230 | } |
| 231 | 231 | ||
| 232 | static void *plane_vaddr(struct tpg_data *tpg, struct vivid_buffer *buf, | ||
| 233 | unsigned p, unsigned bpl[TPG_MAX_PLANES], unsigned h) | ||
| 234 | { | ||
| 235 | unsigned i; | ||
| 236 | void *vbuf; | ||
| 237 | |||
| 238 | if (p == 0 || tpg_g_buffers(tpg) > 1) | ||
| 239 | return vb2_plane_vaddr(&buf->vb, p); | ||
| 240 | vbuf = vb2_plane_vaddr(&buf->vb, 0); | ||
| 241 | for (i = 0; i < p; i++) | ||
| 242 | vbuf += bpl[i] * h / tpg->vdownsampling[i]; | ||
| 243 | return vbuf; | ||
| 244 | } | ||
| 245 | |||
| 232 | static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf, | 246 | static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf, |
| 233 | struct vivid_buffer *vid_cap_buf) | 247 | struct vivid_buffer *vid_cap_buf) |
| 234 | { | 248 | { |
| 235 | bool blank = dev->must_blank[vid_cap_buf->vb.v4l2_buf.index]; | 249 | bool blank = dev->must_blank[vid_cap_buf->vb.v4l2_buf.index]; |
| 236 | struct tpg_data *tpg = &dev->tpg; | 250 | struct tpg_data *tpg = &dev->tpg; |
| 237 | struct vivid_buffer *vid_out_buf = NULL; | 251 | struct vivid_buffer *vid_out_buf = NULL; |
| 238 | unsigned pixsize = tpg_g_twopixelsize(tpg, p) / 2; | 252 | unsigned vdiv = dev->fmt_out->vdownsampling[p]; |
| 239 | unsigned img_width = dev->compose_cap.width; | 253 | unsigned twopixsize = tpg_g_twopixelsize(tpg, p); |
| 254 | unsigned img_width = tpg_hdiv(tpg, p, dev->compose_cap.width); | ||
| 240 | unsigned img_height = dev->compose_cap.height; | 255 | unsigned img_height = dev->compose_cap.height; |
| 241 | unsigned stride_cap = tpg->bytesperline[p]; | 256 | unsigned stride_cap = tpg->bytesperline[p]; |
| 242 | unsigned stride_out = dev->bytesperline_out[p]; | 257 | unsigned stride_out = dev->bytesperline_out[p]; |
| @@ -255,6 +270,7 @@ static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf, | |||
| 255 | unsigned vid_overlay_fract_part = 0; | 270 | unsigned vid_overlay_fract_part = 0; |
| 256 | unsigned vid_overlay_y = 0; | 271 | unsigned vid_overlay_y = 0; |
| 257 | unsigned vid_overlay_error = 0; | 272 | unsigned vid_overlay_error = 0; |
| 273 | unsigned vid_cap_left = tpg_hdiv(tpg, p, dev->loop_vid_cap.left); | ||
| 258 | unsigned vid_cap_right; | 274 | unsigned vid_cap_right; |
| 259 | bool quick; | 275 | bool quick; |
| 260 | 276 | ||
| @@ -269,25 +285,29 @@ static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf, | |||
| 269 | 285 | ||
| 270 | vid_cap_buf->vb.v4l2_buf.field = vid_out_buf->vb.v4l2_buf.field; | 286 | vid_cap_buf->vb.v4l2_buf.field = vid_out_buf->vb.v4l2_buf.field; |
| 271 | 287 | ||
| 272 | voutbuf = vb2_plane_vaddr(&vid_out_buf->vb, p) + | 288 | voutbuf = plane_vaddr(tpg, vid_out_buf, p, |
| 273 | vid_out_buf->vb.v4l2_planes[p].data_offset; | 289 | dev->bytesperline_out, dev->fmt_out_rect.height); |
| 274 | voutbuf += dev->loop_vid_out.left * pixsize + dev->loop_vid_out.top * stride_out; | 290 | if (p < dev->fmt_out->buffers) |
| 275 | vcapbuf += dev->compose_cap.left * pixsize + dev->compose_cap.top * stride_cap; | 291 | voutbuf += vid_out_buf->vb.v4l2_planes[p].data_offset; |
| 292 | voutbuf += tpg_hdiv(tpg, p, dev->loop_vid_out.left) + | ||
| 293 | (dev->loop_vid_out.top / vdiv) * stride_out; | ||
| 294 | vcapbuf += tpg_hdiv(tpg, p, dev->compose_cap.left) + | ||
| 295 | (dev->compose_cap.top / vdiv) * stride_cap; | ||
| 276 | 296 | ||
| 277 | if (dev->loop_vid_copy.width == 0 || dev->loop_vid_copy.height == 0) { | 297 | if (dev->loop_vid_copy.width == 0 || dev->loop_vid_copy.height == 0) { |
| 278 | /* | 298 | /* |
| 279 | * If there is nothing to copy, then just fill the capture window | 299 | * If there is nothing to copy, then just fill the capture window |
| 280 | * with black. | 300 | * with black. |
| 281 | */ | 301 | */ |
| 282 | for (y = 0; y < hmax; y++, vcapbuf += stride_cap) | 302 | for (y = 0; y < hmax / vdiv; y++, vcapbuf += stride_cap) |
| 283 | memcpy(vcapbuf, tpg->black_line[p], img_width * pixsize); | 303 | memcpy(vcapbuf, tpg->black_line[p], img_width); |
| 284 | return 0; | 304 | return 0; |
| 285 | } | 305 | } |
| 286 | 306 | ||
| 287 | if (dev->overlay_out_enabled && | 307 | if (dev->overlay_out_enabled && |
| 288 | dev->loop_vid_overlay.width && dev->loop_vid_overlay.height) { | 308 | dev->loop_vid_overlay.width && dev->loop_vid_overlay.height) { |
| 289 | vosdbuf = dev->video_vbase; | 309 | vosdbuf = dev->video_vbase; |
| 290 | vosdbuf += dev->loop_fb_copy.left * pixsize + | 310 | vosdbuf += (dev->loop_fb_copy.left * twopixsize) / 2 + |
| 291 | dev->loop_fb_copy.top * stride_osd; | 311 | dev->loop_fb_copy.top * stride_osd; |
| 292 | vid_overlay_int_part = dev->loop_vid_overlay.height / | 312 | vid_overlay_int_part = dev->loop_vid_overlay.height / |
| 293 | dev->loop_vid_overlay_cap.height; | 313 | dev->loop_vid_overlay_cap.height; |
| @@ -295,12 +315,12 @@ static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf, | |||
| 295 | dev->loop_vid_overlay_cap.height; | 315 | dev->loop_vid_overlay_cap.height; |
| 296 | } | 316 | } |
| 297 | 317 | ||
| 298 | vid_cap_right = dev->loop_vid_cap.left + dev->loop_vid_cap.width; | 318 | vid_cap_right = tpg_hdiv(tpg, p, dev->loop_vid_cap.left + dev->loop_vid_cap.width); |
| 299 | /* quick is true if no video scaling is needed */ | 319 | /* quick is true if no video scaling is needed */ |
| 300 | quick = dev->loop_vid_out.width == dev->loop_vid_cap.width; | 320 | quick = dev->loop_vid_out.width == dev->loop_vid_cap.width; |
| 301 | 321 | ||
| 302 | dev->cur_scaled_line = dev->loop_vid_out.height; | 322 | dev->cur_scaled_line = dev->loop_vid_out.height; |
| 303 | for (y = 0; y < hmax; y++, vcapbuf += stride_cap) { | 323 | for (y = 0; y < hmax; y += vdiv, vcapbuf += stride_cap) { |
| 304 | /* osdline is true if this line requires overlay blending */ | 324 | /* osdline is true if this line requires overlay blending */ |
| 305 | bool osdline = vosdbuf && y >= dev->loop_vid_overlay_cap.top && | 325 | bool osdline = vosdbuf && y >= dev->loop_vid_overlay_cap.top && |
| 306 | y < dev->loop_vid_overlay_cap.top + dev->loop_vid_overlay_cap.height; | 326 | y < dev->loop_vid_overlay_cap.top + dev->loop_vid_overlay_cap.height; |
| @@ -311,34 +331,34 @@ static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf, | |||
| 311 | */ | 331 | */ |
| 312 | if (y < dev->loop_vid_cap.top || | 332 | if (y < dev->loop_vid_cap.top || |
| 313 | y >= dev->loop_vid_cap.top + dev->loop_vid_cap.height) { | 333 | y >= dev->loop_vid_cap.top + dev->loop_vid_cap.height) { |
| 314 | memcpy(vcapbuf, tpg->black_line[p], img_width * pixsize); | 334 | memcpy(vcapbuf, tpg->black_line[p], img_width); |
| 315 | continue; | 335 | continue; |
| 316 | } | 336 | } |
| 317 | 337 | ||
| 318 | /* fill the left border with black */ | 338 | /* fill the left border with black */ |
| 319 | if (dev->loop_vid_cap.left) | 339 | if (dev->loop_vid_cap.left) |
| 320 | memcpy(vcapbuf, tpg->black_line[p], dev->loop_vid_cap.left * pixsize); | 340 | memcpy(vcapbuf, tpg->black_line[p], vid_cap_left); |
| 321 | 341 | ||
| 322 | /* fill the right border with black */ | 342 | /* fill the right border with black */ |
| 323 | if (vid_cap_right < img_width) | 343 | if (vid_cap_right < img_width) |
| 324 | memcpy(vcapbuf + vid_cap_right * pixsize, | 344 | memcpy(vcapbuf + vid_cap_right, tpg->black_line[p], |
| 325 | tpg->black_line[p], (img_width - vid_cap_right) * pixsize); | 345 | img_width - vid_cap_right); |
| 326 | 346 | ||
| 327 | if (quick && !osdline) { | 347 | if (quick && !osdline) { |
| 328 | memcpy(vcapbuf + dev->loop_vid_cap.left * pixsize, | 348 | memcpy(vcapbuf + vid_cap_left, |
| 329 | voutbuf + vid_out_y * stride_out, | 349 | voutbuf + vid_out_y * stride_out, |
| 330 | dev->loop_vid_cap.width * pixsize); | 350 | tpg_hdiv(tpg, p, dev->loop_vid_cap.width)); |
| 331 | goto update_vid_out_y; | 351 | goto update_vid_out_y; |
| 332 | } | 352 | } |
| 333 | if (dev->cur_scaled_line == vid_out_y) { | 353 | if (dev->cur_scaled_line == vid_out_y) { |
| 334 | memcpy(vcapbuf + dev->loop_vid_cap.left * pixsize, | 354 | memcpy(vcapbuf + vid_cap_left, dev->scaled_line, |
| 335 | dev->scaled_line, | 355 | tpg_hdiv(tpg, p, dev->loop_vid_cap.width)); |
| 336 | dev->loop_vid_cap.width * pixsize); | ||
| 337 | goto update_vid_out_y; | 356 | goto update_vid_out_y; |
| 338 | } | 357 | } |
| 339 | if (!osdline) { | 358 | if (!osdline) { |
| 340 | scale_line(voutbuf + vid_out_y * stride_out, dev->scaled_line, | 359 | scale_line(voutbuf + vid_out_y * stride_out, dev->scaled_line, |
| 341 | dev->loop_vid_out.width, dev->loop_vid_cap.width, | 360 | tpg_hdiv(tpg, p, dev->loop_vid_out.width), |
| 361 | tpg_hdiv(tpg, p, dev->loop_vid_cap.width), | ||
| 342 | tpg_g_twopixelsize(tpg, p)); | 362 | tpg_g_twopixelsize(tpg, p)); |
| 343 | } else { | 363 | } else { |
| 344 | /* | 364 | /* |
| @@ -346,7 +366,8 @@ static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf, | |||
| 346 | * loop_vid_overlay rectangle. | 366 | * loop_vid_overlay rectangle. |
| 347 | */ | 367 | */ |
| 348 | unsigned offset = | 368 | unsigned offset = |
| 349 | (dev->loop_vid_overlay.left - dev->loop_vid_copy.left) * pixsize; | 369 | ((dev->loop_vid_overlay.left - dev->loop_vid_copy.left) * |
| 370 | twopixsize) / 2; | ||
| 350 | u8 *osd = vosdbuf + vid_overlay_y * stride_osd; | 371 | u8 *osd = vosdbuf + vid_overlay_y * stride_osd; |
| 351 | 372 | ||
| 352 | scale_line(voutbuf + vid_out_y * stride_out, dev->blended_line, | 373 | scale_line(voutbuf + vid_out_y * stride_out, dev->blended_line, |
| @@ -356,18 +377,17 @@ static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf, | |||
| 356 | blend_line(dev, vid_overlay_y + dev->loop_vid_overlay.top, | 377 | blend_line(dev, vid_overlay_y + dev->loop_vid_overlay.top, |
| 357 | dev->loop_vid_overlay.left, | 378 | dev->loop_vid_overlay.left, |
| 358 | dev->blended_line + offset, osd, | 379 | dev->blended_line + offset, osd, |
| 359 | dev->loop_vid_overlay.width, pixsize); | 380 | dev->loop_vid_overlay.width, twopixsize / 2); |
| 360 | else | 381 | else |
| 361 | memcpy(dev->blended_line + offset, | 382 | memcpy(dev->blended_line + offset, |
| 362 | osd, dev->loop_vid_overlay.width * pixsize); | 383 | osd, (dev->loop_vid_overlay.width * twopixsize) / 2); |
| 363 | scale_line(dev->blended_line, dev->scaled_line, | 384 | scale_line(dev->blended_line, dev->scaled_line, |
| 364 | dev->loop_vid_copy.width, dev->loop_vid_cap.width, | 385 | dev->loop_vid_copy.width, dev->loop_vid_cap.width, |
| 365 | tpg_g_twopixelsize(tpg, p)); | 386 | tpg_g_twopixelsize(tpg, p)); |
| 366 | } | 387 | } |
| 367 | dev->cur_scaled_line = vid_out_y; | 388 | dev->cur_scaled_line = vid_out_y; |
| 368 | memcpy(vcapbuf + dev->loop_vid_cap.left * pixsize, | 389 | memcpy(vcapbuf + vid_cap_left, dev->scaled_line, |
| 369 | dev->scaled_line, | 390 | tpg_hdiv(tpg, p, dev->loop_vid_cap.width)); |
| 370 | dev->loop_vid_cap.width * pixsize); | ||
| 371 | 391 | ||
| 372 | update_vid_out_y: | 392 | update_vid_out_y: |
| 373 | if (osdline) { | 393 | if (osdline) { |
| @@ -380,21 +400,22 @@ update_vid_out_y: | |||
| 380 | } | 400 | } |
| 381 | vid_out_y += vid_out_int_part; | 401 | vid_out_y += vid_out_int_part; |
| 382 | vid_out_error += vid_out_fract_part; | 402 | vid_out_error += vid_out_fract_part; |
| 383 | if (vid_out_error >= dev->loop_vid_cap.height) { | 403 | if (vid_out_error >= dev->loop_vid_cap.height / vdiv) { |
| 384 | vid_out_error -= dev->loop_vid_cap.height; | 404 | vid_out_error -= dev->loop_vid_cap.height / vdiv; |
| 385 | vid_out_y++; | 405 | vid_out_y++; |
| 386 | } | 406 | } |
| 387 | } | 407 | } |
| 388 | 408 | ||
| 389 | if (!blank) | 409 | if (!blank) |
| 390 | return 0; | 410 | return 0; |
| 391 | for (; y < img_height; y++, vcapbuf += stride_cap) | 411 | for (; y < img_height; y += vdiv, vcapbuf += stride_cap) |
| 392 | memcpy(vcapbuf, tpg->contrast_line[p], img_width * pixsize); | 412 | memcpy(vcapbuf, tpg->contrast_line[p], img_width); |
| 393 | return 0; | 413 | return 0; |
| 394 | } | 414 | } |
| 395 | 415 | ||
| 396 | static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf) | 416 | static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf) |
| 397 | { | 417 | { |
| 418 | struct tpg_data *tpg = &dev->tpg; | ||
| 398 | unsigned factor = V4L2_FIELD_HAS_T_OR_B(dev->field_cap) ? 2 : 1; | 419 | unsigned factor = V4L2_FIELD_HAS_T_OR_B(dev->field_cap) ? 2 : 1; |
| 399 | unsigned line_height = 16 / factor; | 420 | unsigned line_height = 16 / factor; |
| 400 | bool is_tv = vivid_is_sdtv_cap(dev); | 421 | bool is_tv = vivid_is_sdtv_cap(dev); |
| @@ -427,7 +448,7 @@ static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf) | |||
| 427 | * standards. | 448 | * standards. |
| 428 | */ | 449 | */ |
| 429 | buf->vb.v4l2_buf.field = ((dev->vid_cap_seq_count & 1) ^ is_60hz) ? | 450 | buf->vb.v4l2_buf.field = ((dev->vid_cap_seq_count & 1) ^ is_60hz) ? |
| 430 | V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM; | 451 | V4L2_FIELD_BOTTOM : V4L2_FIELD_TOP; |
| 431 | /* | 452 | /* |
| 432 | * The sequence counter counts frames, not fields. So divide | 453 | * The sequence counter counts frames, not fields. So divide |
| 433 | * by two. | 454 | * by two. |
| @@ -436,27 +457,29 @@ static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf) | |||
| 436 | } else { | 457 | } else { |
| 437 | buf->vb.v4l2_buf.field = dev->field_cap; | 458 | buf->vb.v4l2_buf.field = dev->field_cap; |
| 438 | } | 459 | } |
| 439 | tpg_s_field(&dev->tpg, buf->vb.v4l2_buf.field); | 460 | tpg_s_field(tpg, buf->vb.v4l2_buf.field, |
| 440 | tpg_s_perc_fill_blank(&dev->tpg, dev->must_blank[buf->vb.v4l2_buf.index]); | 461 | dev->field_cap == V4L2_FIELD_ALTERNATE); |
| 462 | tpg_s_perc_fill_blank(tpg, dev->must_blank[buf->vb.v4l2_buf.index]); | ||
| 441 | 463 | ||
| 442 | vivid_precalc_copy_rects(dev); | 464 | vivid_precalc_copy_rects(dev); |
| 443 | 465 | ||
| 444 | for (p = 0; p < tpg_g_planes(&dev->tpg); p++) { | 466 | for (p = 0; p < tpg_g_planes(tpg); p++) { |
| 445 | void *vbuf = vb2_plane_vaddr(&buf->vb, p); | 467 | void *vbuf = plane_vaddr(tpg, buf, p, |
| 468 | tpg->bytesperline, tpg->buf_height); | ||
| 446 | 469 | ||
| 447 | /* | 470 | /* |
| 448 | * The first plane of a multiplanar format has a non-zero | 471 | * The first plane of a multiplanar format has a non-zero |
| 449 | * data_offset. This helps testing whether the application | 472 | * data_offset. This helps testing whether the application |
| 450 | * correctly supports non-zero data offsets. | 473 | * correctly supports non-zero data offsets. |
| 451 | */ | 474 | */ |
| 452 | if (dev->fmt_cap->data_offset[p]) { | 475 | if (p < tpg_g_buffers(tpg) && dev->fmt_cap->data_offset[p]) { |
| 453 | memset(vbuf, dev->fmt_cap->data_offset[p] & 0xff, | 476 | memset(vbuf, dev->fmt_cap->data_offset[p] & 0xff, |
| 454 | dev->fmt_cap->data_offset[p]); | 477 | dev->fmt_cap->data_offset[p]); |
| 455 | vbuf += dev->fmt_cap->data_offset[p]; | 478 | vbuf += dev->fmt_cap->data_offset[p]; |
| 456 | } | 479 | } |
| 457 | tpg_calc_text_basep(&dev->tpg, basep, p, vbuf); | 480 | tpg_calc_text_basep(tpg, basep, p, vbuf); |
| 458 | if (!is_loop || vivid_copy_buffer(dev, p, vbuf, buf)) | 481 | if (!is_loop || vivid_copy_buffer(dev, p, vbuf, buf)) |
| 459 | tpg_fillbuffer(&dev->tpg, vivid_get_std_cap(dev), p, vbuf); | 482 | tpg_fill_plane_buffer(tpg, vivid_get_std_cap(dev), p, vbuf); |
| 460 | } | 483 | } |
| 461 | dev->must_blank[buf->vb.v4l2_buf.index] = false; | 484 | dev->must_blank[buf->vb.v4l2_buf.index] = false; |
| 462 | 485 | ||
| @@ -475,12 +498,12 @@ static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf) | |||
| 475 | (dev->field_cap == V4L2_FIELD_ALTERNATE) ? | 498 | (dev->field_cap == V4L2_FIELD_ALTERNATE) ? |
| 476 | (buf->vb.v4l2_buf.field == V4L2_FIELD_TOP ? | 499 | (buf->vb.v4l2_buf.field == V4L2_FIELD_TOP ? |
| 477 | " top" : " bottom") : ""); | 500 | " top" : " bottom") : ""); |
| 478 | tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str); | 501 | tpg_gen_text(tpg, basep, line++ * line_height, 16, str); |
| 479 | } | 502 | } |
| 480 | if (dev->osd_mode == 0) { | 503 | if (dev->osd_mode == 0) { |
| 481 | snprintf(str, sizeof(str), " %dx%d, input %d ", | 504 | snprintf(str, sizeof(str), " %dx%d, input %d ", |
| 482 | dev->src_rect.width, dev->src_rect.height, dev->input); | 505 | dev->src_rect.width, dev->src_rect.height, dev->input); |
| 483 | tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str); | 506 | tpg_gen_text(tpg, basep, line++ * line_height, 16, str); |
| 484 | 507 | ||
| 485 | gain = v4l2_ctrl_g_ctrl(dev->gain); | 508 | gain = v4l2_ctrl_g_ctrl(dev->gain); |
| 486 | mutex_lock(dev->ctrl_hdl_user_vid.lock); | 509 | mutex_lock(dev->ctrl_hdl_user_vid.lock); |
| @@ -490,38 +513,38 @@ static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf) | |||
| 490 | dev->contrast->cur.val, | 513 | dev->contrast->cur.val, |
| 491 | dev->saturation->cur.val, | 514 | dev->saturation->cur.val, |
| 492 | dev->hue->cur.val); | 515 | dev->hue->cur.val); |
| 493 | tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str); | 516 | tpg_gen_text(tpg, basep, line++ * line_height, 16, str); |
| 494 | snprintf(str, sizeof(str), | 517 | snprintf(str, sizeof(str), |
| 495 | " autogain %d, gain %3d, alpha 0x%02x ", | 518 | " autogain %d, gain %3d, alpha 0x%02x ", |
| 496 | dev->autogain->cur.val, gain, dev->alpha->cur.val); | 519 | dev->autogain->cur.val, gain, dev->alpha->cur.val); |
| 497 | mutex_unlock(dev->ctrl_hdl_user_vid.lock); | 520 | mutex_unlock(dev->ctrl_hdl_user_vid.lock); |
| 498 | tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str); | 521 | tpg_gen_text(tpg, basep, line++ * line_height, 16, str); |
| 499 | mutex_lock(dev->ctrl_hdl_user_aud.lock); | 522 | mutex_lock(dev->ctrl_hdl_user_aud.lock); |
| 500 | snprintf(str, sizeof(str), | 523 | snprintf(str, sizeof(str), |
| 501 | " volume %3d, mute %d ", | 524 | " volume %3d, mute %d ", |
| 502 | dev->volume->cur.val, dev->mute->cur.val); | 525 | dev->volume->cur.val, dev->mute->cur.val); |
| 503 | mutex_unlock(dev->ctrl_hdl_user_aud.lock); | 526 | mutex_unlock(dev->ctrl_hdl_user_aud.lock); |
| 504 | tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str); | 527 | tpg_gen_text(tpg, basep, line++ * line_height, 16, str); |
| 505 | mutex_lock(dev->ctrl_hdl_user_gen.lock); | 528 | mutex_lock(dev->ctrl_hdl_user_gen.lock); |
| 506 | snprintf(str, sizeof(str), " int32 %d, int64 %lld, bitmask %08x ", | 529 | snprintf(str, sizeof(str), " int32 %d, int64 %lld, bitmask %08x ", |
| 507 | dev->int32->cur.val, | 530 | dev->int32->cur.val, |
| 508 | *dev->int64->p_cur.p_s64, | 531 | *dev->int64->p_cur.p_s64, |
| 509 | dev->bitmask->cur.val); | 532 | dev->bitmask->cur.val); |
| 510 | tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str); | 533 | tpg_gen_text(tpg, basep, line++ * line_height, 16, str); |
| 511 | snprintf(str, sizeof(str), " boolean %d, menu %s, string \"%s\" ", | 534 | snprintf(str, sizeof(str), " boolean %d, menu %s, string \"%s\" ", |
| 512 | dev->boolean->cur.val, | 535 | dev->boolean->cur.val, |
| 513 | dev->menu->qmenu[dev->menu->cur.val], | 536 | dev->menu->qmenu[dev->menu->cur.val], |
| 514 | dev->string->p_cur.p_char); | 537 | dev->string->p_cur.p_char); |
| 515 | tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str); | 538 | tpg_gen_text(tpg, basep, line++ * line_height, 16, str); |
| 516 | snprintf(str, sizeof(str), " integer_menu %lld, value %d ", | 539 | snprintf(str, sizeof(str), " integer_menu %lld, value %d ", |
| 517 | dev->int_menu->qmenu_int[dev->int_menu->cur.val], | 540 | dev->int_menu->qmenu_int[dev->int_menu->cur.val], |
| 518 | dev->int_menu->cur.val); | 541 | dev->int_menu->cur.val); |
| 519 | mutex_unlock(dev->ctrl_hdl_user_gen.lock); | 542 | mutex_unlock(dev->ctrl_hdl_user_gen.lock); |
| 520 | tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str); | 543 | tpg_gen_text(tpg, basep, line++ * line_height, 16, str); |
| 521 | if (dev->button_pressed) { | 544 | if (dev->button_pressed) { |
| 522 | dev->button_pressed--; | 545 | dev->button_pressed--; |
| 523 | snprintf(str, sizeof(str), " button pressed!"); | 546 | snprintf(str, sizeof(str), " button pressed!"); |
| 524 | tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str); | 547 | tpg_gen_text(tpg, basep, line++ * line_height, 16, str); |
| 525 | } | 548 | } |
| 526 | } | 549 | } |
| 527 | 550 | ||
| @@ -585,6 +608,12 @@ static void vivid_overlay(struct vivid_dev *dev, struct vivid_buffer *buf) | |||
| 585 | bool quick = dev->bitmap_cap == NULL && dev->clipcount_cap == 0; | 608 | bool quick = dev->bitmap_cap == NULL && dev->clipcount_cap == 0; |
| 586 | int x, y, w, out_x = 0; | 609 | int x, y, w, out_x = 0; |
| 587 | 610 | ||
| 611 | /* | ||
| 612 | * Overlay support is only supported for formats that have a twopixelsize | ||
| 613 | * that's >= 2. Warn and bail out if that's not the case. | ||
| 614 | */ | ||
| 615 | if (WARN_ON(pixsize == 0)) | ||
| 616 | return; | ||
| 588 | if ((dev->overlay_cap_field == V4L2_FIELD_TOP || | 617 | if ((dev->overlay_cap_field == V4L2_FIELD_TOP || |
| 589 | dev->overlay_cap_field == V4L2_FIELD_BOTTOM) && | 618 | dev->overlay_cap_field == V4L2_FIELD_BOTTOM) && |
| 590 | dev->overlay_cap_field != buf->vb.v4l2_buf.field) | 619 | dev->overlay_cap_field != buf->vb.v4l2_buf.field) |
diff --git a/drivers/media/platform/vivid/vivid-sdr-cap.c b/drivers/media/platform/vivid/vivid-sdr-cap.c index 4af55f18829f..caf131666e37 100644 --- a/drivers/media/platform/vivid/vivid-sdr-cap.c +++ b/drivers/media/platform/vivid/vivid-sdr-cap.c | |||
| @@ -27,6 +27,7 @@ | |||
| 27 | #include <media/v4l2-common.h> | 27 | #include <media/v4l2-common.h> |
| 28 | #include <media/v4l2-event.h> | 28 | #include <media/v4l2-event.h> |
| 29 | #include <media/v4l2-dv-timings.h> | 29 | #include <media/v4l2-dv-timings.h> |
| 30 | #include <linux/fixp-arith.h> | ||
| 30 | 31 | ||
| 31 | #include "vivid-core.h" | 32 | #include "vivid-core.h" |
| 32 | #include "vivid-ctrls.h" | 33 | #include "vivid-ctrls.h" |
| @@ -423,40 +424,19 @@ int vidioc_g_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f) | |||
| 423 | return 0; | 424 | return 0; |
| 424 | } | 425 | } |
| 425 | 426 | ||
| 426 | #define FIXP_FRAC (1 << 15) | 427 | #define FIXP_N (15) |
| 427 | #define FIXP_PI ((int)(FIXP_FRAC * 3.141592653589)) | 428 | #define FIXP_FRAC (1 << FIXP_N) |
| 428 | 429 | #define FIXP_2PI ((int)(2 * 3.141592653589 * FIXP_FRAC)) | |
| 429 | /* cos() from cx88 driver: cx88-dsp.c */ | ||
| 430 | static s32 fixp_cos(unsigned int x) | ||
| 431 | { | ||
| 432 | u32 t2, t4, t6, t8; | ||
| 433 | u16 period = x / FIXP_PI; | ||
| 434 | |||
| 435 | if (period % 2) | ||
| 436 | return -fixp_cos(x - FIXP_PI); | ||
| 437 | x = x % FIXP_PI; | ||
| 438 | if (x > FIXP_PI/2) | ||
| 439 | return -fixp_cos(FIXP_PI/2 - (x % (FIXP_PI/2))); | ||
| 440 | /* Now x is between 0 and FIXP_PI/2. | ||
| 441 | * To calculate cos(x) we use it's Taylor polinom. */ | ||
| 442 | t2 = x*x/FIXP_FRAC/2; | ||
| 443 | t4 = t2*x/FIXP_FRAC*x/FIXP_FRAC/3/4; | ||
| 444 | t6 = t4*x/FIXP_FRAC*x/FIXP_FRAC/5/6; | ||
| 445 | t8 = t6*x/FIXP_FRAC*x/FIXP_FRAC/7/8; | ||
| 446 | return FIXP_FRAC-t2+t4-t6+t8; | ||
| 447 | } | ||
| 448 | |||
| 449 | static inline s32 fixp_sin(unsigned int x) | ||
| 450 | { | ||
| 451 | return -fixp_cos(x + (FIXP_PI / 2)); | ||
| 452 | } | ||
| 453 | 430 | ||
| 454 | void vivid_sdr_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf) | 431 | void vivid_sdr_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf) |
| 455 | { | 432 | { |
| 456 | u8 *vbuf = vb2_plane_vaddr(&buf->vb, 0); | 433 | u8 *vbuf = vb2_plane_vaddr(&buf->vb, 0); |
| 457 | unsigned long i; | 434 | unsigned long i; |
| 458 | unsigned long plane_size = vb2_plane_size(&buf->vb, 0); | 435 | unsigned long plane_size = vb2_plane_size(&buf->vb, 0); |
| 459 | int fixp_src_phase_step, fixp_i, fixp_q; | 436 | s32 src_phase_step; |
| 437 | s32 mod_phase_step; | ||
| 438 | s32 fixp_i; | ||
| 439 | s32 fixp_q; | ||
| 460 | 440 | ||
| 461 | /* | 441 | /* |
| 462 | * TODO: Generated beep tone goes very crackly when sample rate is | 442 | * TODO: Generated beep tone goes very crackly when sample rate is |
| @@ -466,28 +446,36 @@ void vivid_sdr_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf) | |||
| 466 | 446 | ||
| 467 | /* calculate phase step */ | 447 | /* calculate phase step */ |
| 468 | #define BEEP_FREQ 1000 /* 1kHz beep */ | 448 | #define BEEP_FREQ 1000 /* 1kHz beep */ |
| 469 | fixp_src_phase_step = DIV_ROUND_CLOSEST(2 * FIXP_PI * BEEP_FREQ, | 449 | src_phase_step = DIV_ROUND_CLOSEST(FIXP_2PI * BEEP_FREQ, |
| 470 | dev->sdr_adc_freq); | 450 | dev->sdr_adc_freq); |
| 471 | 451 | ||
| 472 | for (i = 0; i < plane_size; i += 2) { | 452 | for (i = 0; i < plane_size; i += 2) { |
| 473 | dev->sdr_fixp_mod_phase += fixp_cos(dev->sdr_fixp_src_phase); | 453 | mod_phase_step = fixp_cos32_rad(dev->sdr_fixp_src_phase, |
| 474 | dev->sdr_fixp_src_phase += fixp_src_phase_step; | 454 | FIXP_2PI) >> (31 - FIXP_N); |
| 455 | |||
| 456 | dev->sdr_fixp_src_phase += src_phase_step; | ||
| 457 | dev->sdr_fixp_mod_phase += mod_phase_step / 4; | ||
| 475 | 458 | ||
| 476 | /* | 459 | /* |
| 477 | * Transfer phases to [0 / 2xPI] in order to avoid variable | 460 | * Transfer phases to [0 / 2xPI] in order to avoid variable |
| 478 | * overflow and make it suitable for cosine implementation | 461 | * overflow and make it suitable for cosine implementation |
| 479 | * used, which does not support negative angles. | 462 | * used, which does not support negative angles. |
| 480 | */ | 463 | */ |
| 481 | while (dev->sdr_fixp_mod_phase < (0 * FIXP_PI)) | 464 | while (dev->sdr_fixp_mod_phase < FIXP_2PI) |
| 482 | dev->sdr_fixp_mod_phase += (2 * FIXP_PI); | 465 | dev->sdr_fixp_mod_phase += FIXP_2PI; |
| 483 | while (dev->sdr_fixp_mod_phase > (2 * FIXP_PI)) | 466 | while (dev->sdr_fixp_mod_phase > FIXP_2PI) |
| 484 | dev->sdr_fixp_mod_phase -= (2 * FIXP_PI); | 467 | dev->sdr_fixp_mod_phase -= FIXP_2PI; |
| 468 | |||
| 469 | while (dev->sdr_fixp_src_phase > FIXP_2PI) | ||
| 470 | dev->sdr_fixp_src_phase -= FIXP_2PI; | ||
| 485 | 471 | ||
| 486 | while (dev->sdr_fixp_src_phase > (2 * FIXP_PI)) | 472 | fixp_i = fixp_cos32_rad(dev->sdr_fixp_mod_phase, FIXP_2PI); |
| 487 | dev->sdr_fixp_src_phase -= (2 * FIXP_PI); | 473 | fixp_q = fixp_sin32_rad(dev->sdr_fixp_mod_phase, FIXP_2PI); |
| 488 | 474 | ||
| 489 | fixp_i = fixp_cos(dev->sdr_fixp_mod_phase); | 475 | /* Normalize fraction values represented with 32 bit precision |
| 490 | fixp_q = fixp_sin(dev->sdr_fixp_mod_phase); | 476 | * to fixed point representation with FIXP_N bits */ |
| 477 | fixp_i >>= (31 - FIXP_N); | ||
| 478 | fixp_q >>= (31 - FIXP_N); | ||
| 491 | 479 | ||
| 492 | /* convert 'fixp float' to u8 */ | 480 | /* convert 'fixp float' to u8 */ |
| 493 | /* u8 = X * 127.5f + 127.5f; where X is float [-1.0 / +1.0] */ | 481 | /* u8 = X * 127.5f + 127.5f; where X is float [-1.0 / +1.0] */ |
diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c index 34493f435d5a..cb766eb154e7 100644 --- a/drivers/media/platform/vivid/vivid-tpg.c +++ b/drivers/media/platform/vivid/vivid-tpg.c | |||
| @@ -35,7 +35,10 @@ const char * const tpg_pattern_strings[] = { | |||
| 35 | "100% Green", | 35 | "100% Green", |
| 36 | "100% Blue", | 36 | "100% Blue", |
| 37 | "16x16 Checkers", | 37 | "16x16 Checkers", |
| 38 | "2x2 Checkers", | ||
| 38 | "1x1 Checkers", | 39 | "1x1 Checkers", |
| 40 | "2x2 Red/Green Checkers", | ||
| 41 | "1x1 Red/Green Checkers", | ||
| 39 | "Alternating Hor Lines", | 42 | "Alternating Hor Lines", |
| 40 | "Alternating Vert Lines", | 43 | "Alternating Vert Lines", |
| 41 | "One Pixel Wide Cross", | 44 | "One Pixel Wide Cross", |
| @@ -120,15 +123,20 @@ int tpg_alloc(struct tpg_data *tpg, unsigned max_w) | |||
| 120 | tpg->max_line_width = max_w; | 123 | tpg->max_line_width = max_w; |
| 121 | for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++) { | 124 | for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++) { |
| 122 | for (plane = 0; plane < TPG_MAX_PLANES; plane++) { | 125 | for (plane = 0; plane < TPG_MAX_PLANES; plane++) { |
| 123 | unsigned pixelsz = plane ? 1 : 4; | 126 | unsigned pixelsz = plane ? 2 : 4; |
| 124 | 127 | ||
| 125 | tpg->lines[pat][plane] = vzalloc(max_w * 2 * pixelsz); | 128 | tpg->lines[pat][plane] = vzalloc(max_w * 2 * pixelsz); |
| 126 | if (!tpg->lines[pat][plane]) | 129 | if (!tpg->lines[pat][plane]) |
| 127 | return -ENOMEM; | 130 | return -ENOMEM; |
| 131 | if (plane == 0) | ||
| 132 | continue; | ||
| 133 | tpg->downsampled_lines[pat][plane] = vzalloc(max_w * 2 * pixelsz); | ||
| 134 | if (!tpg->downsampled_lines[pat][plane]) | ||
| 135 | return -ENOMEM; | ||
| 128 | } | 136 | } |
| 129 | } | 137 | } |
| 130 | for (plane = 0; plane < TPG_MAX_PLANES; plane++) { | 138 | for (plane = 0; plane < TPG_MAX_PLANES; plane++) { |
| 131 | unsigned pixelsz = plane ? 1 : 4; | 139 | unsigned pixelsz = plane ? 2 : 4; |
| 132 | 140 | ||
| 133 | tpg->contrast_line[plane] = vzalloc(max_w * pixelsz); | 141 | tpg->contrast_line[plane] = vzalloc(max_w * pixelsz); |
| 134 | if (!tpg->contrast_line[plane]) | 142 | if (!tpg->contrast_line[plane]) |
| @@ -152,6 +160,10 @@ void tpg_free(struct tpg_data *tpg) | |||
| 152 | for (plane = 0; plane < TPG_MAX_PLANES; plane++) { | 160 | for (plane = 0; plane < TPG_MAX_PLANES; plane++) { |
| 153 | vfree(tpg->lines[pat][plane]); | 161 | vfree(tpg->lines[pat][plane]); |
| 154 | tpg->lines[pat][plane] = NULL; | 162 | tpg->lines[pat][plane] = NULL; |
| 163 | if (plane == 0) | ||
| 164 | continue; | ||
| 165 | vfree(tpg->downsampled_lines[pat][plane]); | ||
| 166 | tpg->downsampled_lines[pat][plane] = NULL; | ||
| 155 | } | 167 | } |
| 156 | for (plane = 0; plane < TPG_MAX_PLANES; plane++) { | 168 | for (plane = 0; plane < TPG_MAX_PLANES; plane++) { |
| 157 | vfree(tpg->contrast_line[plane]); | 169 | vfree(tpg->contrast_line[plane]); |
| @@ -167,14 +179,38 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) | |||
| 167 | { | 179 | { |
| 168 | tpg->fourcc = fourcc; | 180 | tpg->fourcc = fourcc; |
| 169 | tpg->planes = 1; | 181 | tpg->planes = 1; |
| 182 | tpg->buffers = 1; | ||
| 170 | tpg->recalc_colors = true; | 183 | tpg->recalc_colors = true; |
| 184 | tpg->interleaved = false; | ||
| 185 | tpg->vdownsampling[0] = 1; | ||
| 186 | tpg->hdownsampling[0] = 1; | ||
| 187 | tpg->hmask[0] = ~0; | ||
| 188 | tpg->hmask[1] = ~0; | ||
| 189 | tpg->hmask[2] = ~0; | ||
| 190 | |||
| 171 | switch (fourcc) { | 191 | switch (fourcc) { |
| 192 | case V4L2_PIX_FMT_SBGGR8: | ||
| 193 | case V4L2_PIX_FMT_SGBRG8: | ||
| 194 | case V4L2_PIX_FMT_SGRBG8: | ||
| 195 | case V4L2_PIX_FMT_SRGGB8: | ||
| 196 | tpg->interleaved = true; | ||
| 197 | tpg->vdownsampling[1] = 1; | ||
| 198 | tpg->hdownsampling[1] = 1; | ||
| 199 | tpg->planes = 2; | ||
| 200 | /* fall through */ | ||
| 201 | case V4L2_PIX_FMT_RGB332: | ||
| 172 | case V4L2_PIX_FMT_RGB565: | 202 | case V4L2_PIX_FMT_RGB565: |
| 173 | case V4L2_PIX_FMT_RGB565X: | 203 | case V4L2_PIX_FMT_RGB565X: |
| 204 | case V4L2_PIX_FMT_RGB444: | ||
| 205 | case V4L2_PIX_FMT_XRGB444: | ||
| 206 | case V4L2_PIX_FMT_ARGB444: | ||
| 174 | case V4L2_PIX_FMT_RGB555: | 207 | case V4L2_PIX_FMT_RGB555: |
| 175 | case V4L2_PIX_FMT_XRGB555: | 208 | case V4L2_PIX_FMT_XRGB555: |
| 176 | case V4L2_PIX_FMT_ARGB555: | 209 | case V4L2_PIX_FMT_ARGB555: |
| 177 | case V4L2_PIX_FMT_RGB555X: | 210 | case V4L2_PIX_FMT_RGB555X: |
| 211 | case V4L2_PIX_FMT_XRGB555X: | ||
| 212 | case V4L2_PIX_FMT_ARGB555X: | ||
| 213 | case V4L2_PIX_FMT_BGR666: | ||
| 178 | case V4L2_PIX_FMT_RGB24: | 214 | case V4L2_PIX_FMT_RGB24: |
| 179 | case V4L2_PIX_FMT_BGR24: | 215 | case V4L2_PIX_FMT_BGR24: |
| 180 | case V4L2_PIX_FMT_RGB32: | 216 | case V4L2_PIX_FMT_RGB32: |
| @@ -183,16 +219,72 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) | |||
| 183 | case V4L2_PIX_FMT_XBGR32: | 219 | case V4L2_PIX_FMT_XBGR32: |
| 184 | case V4L2_PIX_FMT_ARGB32: | 220 | case V4L2_PIX_FMT_ARGB32: |
| 185 | case V4L2_PIX_FMT_ABGR32: | 221 | case V4L2_PIX_FMT_ABGR32: |
| 222 | case V4L2_PIX_FMT_GREY: | ||
| 186 | tpg->is_yuv = false; | 223 | tpg->is_yuv = false; |
| 187 | break; | 224 | break; |
| 225 | case V4L2_PIX_FMT_YUV444: | ||
| 226 | case V4L2_PIX_FMT_YUV555: | ||
| 227 | case V4L2_PIX_FMT_YUV565: | ||
| 228 | case V4L2_PIX_FMT_YUV32: | ||
| 229 | tpg->is_yuv = true; | ||
| 230 | break; | ||
| 231 | case V4L2_PIX_FMT_YUV420M: | ||
| 232 | case V4L2_PIX_FMT_YVU420M: | ||
| 233 | tpg->buffers = 3; | ||
| 234 | /* fall through */ | ||
| 235 | case V4L2_PIX_FMT_YUV420: | ||
| 236 | case V4L2_PIX_FMT_YVU420: | ||
| 237 | tpg->vdownsampling[1] = 2; | ||
| 238 | tpg->vdownsampling[2] = 2; | ||
| 239 | tpg->hdownsampling[1] = 2; | ||
| 240 | tpg->hdownsampling[2] = 2; | ||
| 241 | tpg->planes = 3; | ||
| 242 | tpg->is_yuv = true; | ||
| 243 | break; | ||
| 244 | case V4L2_PIX_FMT_YUV422P: | ||
| 245 | tpg->vdownsampling[1] = 1; | ||
| 246 | tpg->vdownsampling[2] = 1; | ||
| 247 | tpg->hdownsampling[1] = 2; | ||
| 248 | tpg->hdownsampling[2] = 2; | ||
| 249 | tpg->planes = 3; | ||
| 250 | tpg->is_yuv = true; | ||
| 251 | break; | ||
| 188 | case V4L2_PIX_FMT_NV16M: | 252 | case V4L2_PIX_FMT_NV16M: |
| 189 | case V4L2_PIX_FMT_NV61M: | 253 | case V4L2_PIX_FMT_NV61M: |
| 254 | tpg->buffers = 2; | ||
| 255 | /* fall through */ | ||
| 256 | case V4L2_PIX_FMT_NV16: | ||
| 257 | case V4L2_PIX_FMT_NV61: | ||
| 258 | tpg->vdownsampling[1] = 1; | ||
| 259 | tpg->hdownsampling[1] = 1; | ||
| 260 | tpg->hmask[1] = ~1; | ||
| 190 | tpg->planes = 2; | 261 | tpg->planes = 2; |
| 191 | /* fall-through */ | 262 | tpg->is_yuv = true; |
| 263 | break; | ||
| 264 | case V4L2_PIX_FMT_NV12M: | ||
| 265 | case V4L2_PIX_FMT_NV21M: | ||
| 266 | tpg->buffers = 2; | ||
| 267 | /* fall through */ | ||
| 268 | case V4L2_PIX_FMT_NV12: | ||
| 269 | case V4L2_PIX_FMT_NV21: | ||
| 270 | tpg->vdownsampling[1] = 2; | ||
| 271 | tpg->hdownsampling[1] = 1; | ||
| 272 | tpg->hmask[1] = ~1; | ||
| 273 | tpg->planes = 2; | ||
| 274 | tpg->is_yuv = true; | ||
| 275 | break; | ||
| 276 | case V4L2_PIX_FMT_NV24: | ||
| 277 | case V4L2_PIX_FMT_NV42: | ||
| 278 | tpg->vdownsampling[1] = 1; | ||
| 279 | tpg->hdownsampling[1] = 1; | ||
| 280 | tpg->planes = 2; | ||
| 281 | tpg->is_yuv = true; | ||
| 282 | break; | ||
| 192 | case V4L2_PIX_FMT_YUYV: | 283 | case V4L2_PIX_FMT_YUYV: |
| 193 | case V4L2_PIX_FMT_UYVY: | 284 | case V4L2_PIX_FMT_UYVY: |
| 194 | case V4L2_PIX_FMT_YVYU: | 285 | case V4L2_PIX_FMT_YVYU: |
| 195 | case V4L2_PIX_FMT_VYUY: | 286 | case V4L2_PIX_FMT_VYUY: |
| 287 | tpg->hmask[0] = ~1; | ||
| 196 | tpg->is_yuv = true; | 288 | tpg->is_yuv = true; |
| 197 | break; | 289 | break; |
| 198 | default: | 290 | default: |
| @@ -200,35 +292,75 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) | |||
| 200 | } | 292 | } |
| 201 | 293 | ||
| 202 | switch (fourcc) { | 294 | switch (fourcc) { |
| 295 | case V4L2_PIX_FMT_RGB332: | ||
| 296 | tpg->twopixelsize[0] = 2; | ||
| 297 | break; | ||
| 203 | case V4L2_PIX_FMT_RGB565: | 298 | case V4L2_PIX_FMT_RGB565: |
| 204 | case V4L2_PIX_FMT_RGB565X: | 299 | case V4L2_PIX_FMT_RGB565X: |
| 300 | case V4L2_PIX_FMT_RGB444: | ||
| 301 | case V4L2_PIX_FMT_XRGB444: | ||
| 302 | case V4L2_PIX_FMT_ARGB444: | ||
| 205 | case V4L2_PIX_FMT_RGB555: | 303 | case V4L2_PIX_FMT_RGB555: |
| 206 | case V4L2_PIX_FMT_XRGB555: | 304 | case V4L2_PIX_FMT_XRGB555: |
| 207 | case V4L2_PIX_FMT_ARGB555: | 305 | case V4L2_PIX_FMT_ARGB555: |
| 208 | case V4L2_PIX_FMT_RGB555X: | 306 | case V4L2_PIX_FMT_RGB555X: |
| 307 | case V4L2_PIX_FMT_XRGB555X: | ||
| 308 | case V4L2_PIX_FMT_ARGB555X: | ||
| 209 | case V4L2_PIX_FMT_YUYV: | 309 | case V4L2_PIX_FMT_YUYV: |
| 210 | case V4L2_PIX_FMT_UYVY: | 310 | case V4L2_PIX_FMT_UYVY: |
| 211 | case V4L2_PIX_FMT_YVYU: | 311 | case V4L2_PIX_FMT_YVYU: |
| 212 | case V4L2_PIX_FMT_VYUY: | 312 | case V4L2_PIX_FMT_VYUY: |
| 313 | case V4L2_PIX_FMT_YUV444: | ||
| 314 | case V4L2_PIX_FMT_YUV555: | ||
| 315 | case V4L2_PIX_FMT_YUV565: | ||
| 213 | tpg->twopixelsize[0] = 2 * 2; | 316 | tpg->twopixelsize[0] = 2 * 2; |
| 214 | break; | 317 | break; |
| 215 | case V4L2_PIX_FMT_RGB24: | 318 | case V4L2_PIX_FMT_RGB24: |
| 216 | case V4L2_PIX_FMT_BGR24: | 319 | case V4L2_PIX_FMT_BGR24: |
| 217 | tpg->twopixelsize[0] = 2 * 3; | 320 | tpg->twopixelsize[0] = 2 * 3; |
| 218 | break; | 321 | break; |
| 322 | case V4L2_PIX_FMT_BGR666: | ||
| 219 | case V4L2_PIX_FMT_RGB32: | 323 | case V4L2_PIX_FMT_RGB32: |
| 220 | case V4L2_PIX_FMT_BGR32: | 324 | case V4L2_PIX_FMT_BGR32: |
| 221 | case V4L2_PIX_FMT_XRGB32: | 325 | case V4L2_PIX_FMT_XRGB32: |
| 222 | case V4L2_PIX_FMT_XBGR32: | 326 | case V4L2_PIX_FMT_XBGR32: |
| 223 | case V4L2_PIX_FMT_ARGB32: | 327 | case V4L2_PIX_FMT_ARGB32: |
| 224 | case V4L2_PIX_FMT_ABGR32: | 328 | case V4L2_PIX_FMT_ABGR32: |
| 329 | case V4L2_PIX_FMT_YUV32: | ||
| 225 | tpg->twopixelsize[0] = 2 * 4; | 330 | tpg->twopixelsize[0] = 2 * 4; |
| 226 | break; | 331 | break; |
| 332 | case V4L2_PIX_FMT_GREY: | ||
| 333 | tpg->twopixelsize[0] = 2; | ||
| 334 | break; | ||
| 335 | case V4L2_PIX_FMT_NV12: | ||
| 336 | case V4L2_PIX_FMT_NV21: | ||
| 337 | case V4L2_PIX_FMT_NV12M: | ||
| 338 | case V4L2_PIX_FMT_NV21M: | ||
| 339 | case V4L2_PIX_FMT_NV16: | ||
| 340 | case V4L2_PIX_FMT_NV61: | ||
| 227 | case V4L2_PIX_FMT_NV16M: | 341 | case V4L2_PIX_FMT_NV16M: |
| 228 | case V4L2_PIX_FMT_NV61M: | 342 | case V4L2_PIX_FMT_NV61M: |
| 343 | case V4L2_PIX_FMT_SBGGR8: | ||
| 344 | case V4L2_PIX_FMT_SGBRG8: | ||
| 345 | case V4L2_PIX_FMT_SGRBG8: | ||
| 346 | case V4L2_PIX_FMT_SRGGB8: | ||
| 229 | tpg->twopixelsize[0] = 2; | 347 | tpg->twopixelsize[0] = 2; |
| 230 | tpg->twopixelsize[1] = 2; | 348 | tpg->twopixelsize[1] = 2; |
| 231 | break; | 349 | break; |
| 350 | case V4L2_PIX_FMT_YUV422P: | ||
| 351 | case V4L2_PIX_FMT_YUV420: | ||
| 352 | case V4L2_PIX_FMT_YVU420: | ||
| 353 | case V4L2_PIX_FMT_YUV420M: | ||
| 354 | case V4L2_PIX_FMT_YVU420M: | ||
| 355 | tpg->twopixelsize[0] = 2; | ||
| 356 | tpg->twopixelsize[1] = 2; | ||
| 357 | tpg->twopixelsize[2] = 2; | ||
| 358 | break; | ||
| 359 | case V4L2_PIX_FMT_NV24: | ||
| 360 | case V4L2_PIX_FMT_NV42: | ||
| 361 | tpg->twopixelsize[0] = 2; | ||
| 362 | tpg->twopixelsize[1] = 4; | ||
| 363 | break; | ||
| 232 | } | 364 | } |
| 233 | return true; | 365 | return true; |
| 234 | } | 366 | } |
| @@ -267,7 +399,8 @@ void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height, | |||
| 267 | tpg->compose.width = width; | 399 | tpg->compose.width = width; |
| 268 | tpg->compose.height = tpg->buf_height; | 400 | tpg->compose.height = tpg->buf_height; |
| 269 | for (p = 0; p < tpg->planes; p++) | 401 | for (p = 0; p < tpg->planes; p++) |
| 270 | tpg->bytesperline[p] = width * tpg->twopixelsize[p] / 2; | 402 | tpg->bytesperline[p] = (width * tpg->twopixelsize[p]) / |
| 403 | (2 * tpg->hdownsampling[p]); | ||
| 271 | tpg->recalc_square_border = true; | 404 | tpg->recalc_square_border = true; |
| 272 | } | 405 | } |
| 273 | 406 | ||
| @@ -347,9 +480,9 @@ static void color_to_ycbcr(struct tpg_data *tpg, int r, int g, int b, | |||
| 347 | { COEFF(0.5, 224), COEFF(-0.445, 224), COEFF(-0.055, 224) }, | 480 | { COEFF(0.5, 224), COEFF(-0.445, 224), COEFF(-0.055, 224) }, |
| 348 | }; | 481 | }; |
| 349 | static const int bt2020[3][3] = { | 482 | static const int bt2020[3][3] = { |
| 350 | { COEFF(0.2726, 219), COEFF(0.6780, 219), COEFF(0.0593, 219) }, | 483 | { COEFF(0.2627, 219), COEFF(0.6780, 219), COEFF(0.0593, 219) }, |
| 351 | { COEFF(-0.1396, 224), COEFF(-0.3604, 224), COEFF(0.5, 224) }, | 484 | { COEFF(-0.1396, 224), COEFF(-0.3604, 224), COEFF(0.5, 224) }, |
| 352 | { COEFF(0.5, 224), COEFF(-0.4629, 224), COEFF(-0.0405, 224) }, | 485 | { COEFF(0.5, 224), COEFF(-0.4598, 224), COEFF(-0.0402, 224) }, |
| 353 | }; | 486 | }; |
| 354 | bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE; | 487 | bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE; |
| 355 | unsigned y_offset = full ? 0 : 16; | 488 | unsigned y_offset = full ? 0 : 16; |
| @@ -524,10 +657,10 @@ static void precalculate_color(struct tpg_data *tpg, int k) | |||
| 524 | g <<= 4; | 657 | g <<= 4; |
| 525 | b <<= 4; | 658 | b <<= 4; |
| 526 | } | 659 | } |
| 527 | if (tpg->qual == TPG_QUAL_GRAY) { | 660 | if (tpg->qual == TPG_QUAL_GRAY || tpg->fourcc == V4L2_PIX_FMT_GREY) { |
| 528 | /* Rec. 709 Luma function */ | 661 | /* Rec. 709 Luma function */ |
| 529 | /* (0.2126, 0.7152, 0.0722) * (255 * 256) */ | 662 | /* (0.2126, 0.7152, 0.0722) * (255 * 256) */ |
| 530 | r = g = b = ((13879 * r + 46688 * g + 4713 * b) >> 16) + (16 << 4); | 663 | r = g = b = (13879 * r + 46688 * g + 4713 * b) >> 16; |
| 531 | } | 664 | } |
| 532 | 665 | ||
| 533 | /* | 666 | /* |
| @@ -601,9 +734,29 @@ static void precalculate_color(struct tpg_data *tpg, int k) | |||
| 601 | cb = clamp(cb, 16 << 4, 240 << 4); | 734 | cb = clamp(cb, 16 << 4, 240 << 4); |
| 602 | cr = clamp(cr, 16 << 4, 240 << 4); | 735 | cr = clamp(cr, 16 << 4, 240 << 4); |
| 603 | } | 736 | } |
| 604 | tpg->colors[k][0] = clamp(y >> 4, 1, 254); | 737 | y = clamp(y >> 4, 1, 254); |
| 605 | tpg->colors[k][1] = clamp(cb >> 4, 1, 254); | 738 | cb = clamp(cb >> 4, 1, 254); |
| 606 | tpg->colors[k][2] = clamp(cr >> 4, 1, 254); | 739 | cr = clamp(cr >> 4, 1, 254); |
| 740 | switch (tpg->fourcc) { | ||
| 741 | case V4L2_PIX_FMT_YUV444: | ||
| 742 | y >>= 4; | ||
| 743 | cb >>= 4; | ||
| 744 | cr >>= 4; | ||
| 745 | break; | ||
| 746 | case V4L2_PIX_FMT_YUV555: | ||
| 747 | y >>= 3; | ||
| 748 | cb >>= 3; | ||
| 749 | cr >>= 3; | ||
| 750 | break; | ||
| 751 | case V4L2_PIX_FMT_YUV565: | ||
| 752 | y >>= 3; | ||
| 753 | cb >>= 2; | ||
| 754 | cr >>= 3; | ||
| 755 | break; | ||
| 756 | } | ||
| 757 | tpg->colors[k][0] = y; | ||
| 758 | tpg->colors[k][1] = cb; | ||
| 759 | tpg->colors[k][2] = cr; | ||
| 607 | } else { | 760 | } else { |
| 608 | if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) { | 761 | if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) { |
| 609 | r = (r * 219) / 255 + (16 << 4); | 762 | r = (r * 219) / 255 + (16 << 4); |
| @@ -611,20 +764,39 @@ static void precalculate_color(struct tpg_data *tpg, int k) | |||
| 611 | b = (b * 219) / 255 + (16 << 4); | 764 | b = (b * 219) / 255 + (16 << 4); |
| 612 | } | 765 | } |
| 613 | switch (tpg->fourcc) { | 766 | switch (tpg->fourcc) { |
| 767 | case V4L2_PIX_FMT_RGB332: | ||
| 768 | r >>= 9; | ||
| 769 | g >>= 9; | ||
| 770 | b >>= 10; | ||
| 771 | break; | ||
| 614 | case V4L2_PIX_FMT_RGB565: | 772 | case V4L2_PIX_FMT_RGB565: |
| 615 | case V4L2_PIX_FMT_RGB565X: | 773 | case V4L2_PIX_FMT_RGB565X: |
| 616 | r >>= 7; | 774 | r >>= 7; |
| 617 | g >>= 6; | 775 | g >>= 6; |
| 618 | b >>= 7; | 776 | b >>= 7; |
| 619 | break; | 777 | break; |
| 778 | case V4L2_PIX_FMT_RGB444: | ||
| 779 | case V4L2_PIX_FMT_XRGB444: | ||
| 780 | case V4L2_PIX_FMT_ARGB444: | ||
| 781 | r >>= 8; | ||
| 782 | g >>= 8; | ||
| 783 | b >>= 8; | ||
| 784 | break; | ||
| 620 | case V4L2_PIX_FMT_RGB555: | 785 | case V4L2_PIX_FMT_RGB555: |
| 621 | case V4L2_PIX_FMT_XRGB555: | 786 | case V4L2_PIX_FMT_XRGB555: |
| 622 | case V4L2_PIX_FMT_ARGB555: | 787 | case V4L2_PIX_FMT_ARGB555: |
| 623 | case V4L2_PIX_FMT_RGB555X: | 788 | case V4L2_PIX_FMT_RGB555X: |
| 789 | case V4L2_PIX_FMT_XRGB555X: | ||
| 790 | case V4L2_PIX_FMT_ARGB555X: | ||
| 624 | r >>= 7; | 791 | r >>= 7; |
| 625 | g >>= 7; | 792 | g >>= 7; |
| 626 | b >>= 7; | 793 | b >>= 7; |
| 627 | break; | 794 | break; |
| 795 | case V4L2_PIX_FMT_BGR666: | ||
| 796 | r >>= 6; | ||
| 797 | g >>= 6; | ||
| 798 | b >>= 6; | ||
| 799 | break; | ||
| 628 | default: | 800 | default: |
| 629 | r >>= 4; | 801 | r >>= 4; |
| 630 | g >>= 4; | 802 | g >>= 4; |
| @@ -665,31 +837,120 @@ static void gen_twopix(struct tpg_data *tpg, | |||
| 665 | b_v = tpg->colors[color][2]; /* B or precalculated V */ | 837 | b_v = tpg->colors[color][2]; /* B or precalculated V */ |
| 666 | 838 | ||
| 667 | switch (tpg->fourcc) { | 839 | switch (tpg->fourcc) { |
| 840 | case V4L2_PIX_FMT_GREY: | ||
| 841 | buf[0][offset] = r_y; | ||
| 842 | break; | ||
| 843 | case V4L2_PIX_FMT_YUV422P: | ||
| 844 | case V4L2_PIX_FMT_YUV420: | ||
| 845 | case V4L2_PIX_FMT_YUV420M: | ||
| 846 | buf[0][offset] = r_y; | ||
| 847 | if (odd) { | ||
| 848 | buf[1][0] = (buf[1][0] + g_u) / 2; | ||
| 849 | buf[2][0] = (buf[2][0] + b_v) / 2; | ||
| 850 | buf[1][1] = buf[1][0]; | ||
| 851 | buf[2][1] = buf[2][0]; | ||
| 852 | break; | ||
| 853 | } | ||
| 854 | buf[1][0] = g_u; | ||
| 855 | buf[2][0] = b_v; | ||
| 856 | break; | ||
| 857 | case V4L2_PIX_FMT_YVU420: | ||
| 858 | case V4L2_PIX_FMT_YVU420M: | ||
| 859 | buf[0][offset] = r_y; | ||
| 860 | if (odd) { | ||
| 861 | buf[1][0] = (buf[1][0] + b_v) / 2; | ||
| 862 | buf[2][0] = (buf[2][0] + g_u) / 2; | ||
| 863 | buf[1][1] = buf[1][0]; | ||
| 864 | buf[2][1] = buf[2][0]; | ||
| 865 | break; | ||
| 866 | } | ||
| 867 | buf[1][0] = b_v; | ||
| 868 | buf[2][0] = g_u; | ||
| 869 | break; | ||
| 870 | |||
| 871 | case V4L2_PIX_FMT_NV12: | ||
| 872 | case V4L2_PIX_FMT_NV12M: | ||
| 873 | case V4L2_PIX_FMT_NV16: | ||
| 668 | case V4L2_PIX_FMT_NV16M: | 874 | case V4L2_PIX_FMT_NV16M: |
| 669 | buf[0][offset] = r_y; | 875 | buf[0][offset] = r_y; |
| 670 | buf[1][offset] = odd ? b_v : g_u; | 876 | if (odd) { |
| 877 | buf[1][0] = (buf[1][0] + g_u) / 2; | ||
| 878 | buf[1][1] = (buf[1][1] + b_v) / 2; | ||
| 879 | break; | ||
| 880 | } | ||
| 881 | buf[1][0] = g_u; | ||
| 882 | buf[1][1] = b_v; | ||
| 671 | break; | 883 | break; |
| 884 | case V4L2_PIX_FMT_NV21: | ||
| 885 | case V4L2_PIX_FMT_NV21M: | ||
| 886 | case V4L2_PIX_FMT_NV61: | ||
| 672 | case V4L2_PIX_FMT_NV61M: | 887 | case V4L2_PIX_FMT_NV61M: |
| 673 | buf[0][offset] = r_y; | 888 | buf[0][offset] = r_y; |
| 674 | buf[1][offset] = odd ? g_u : b_v; | 889 | if (odd) { |
| 890 | buf[1][0] = (buf[1][0] + b_v) / 2; | ||
| 891 | buf[1][1] = (buf[1][1] + g_u) / 2; | ||
| 892 | break; | ||
| 893 | } | ||
| 894 | buf[1][0] = b_v; | ||
| 895 | buf[1][1] = g_u; | ||
| 896 | break; | ||
| 897 | |||
| 898 | case V4L2_PIX_FMT_NV24: | ||
| 899 | buf[0][offset] = r_y; | ||
| 900 | buf[1][2 * offset] = g_u; | ||
| 901 | buf[1][2 * offset + 1] = b_v; | ||
| 902 | break; | ||
| 903 | |||
| 904 | case V4L2_PIX_FMT_NV42: | ||
| 905 | buf[0][offset] = r_y; | ||
| 906 | buf[1][2 * offset] = b_v; | ||
| 907 | buf[1][2 * offset + 1] = g_u; | ||
| 675 | break; | 908 | break; |
| 676 | 909 | ||
| 677 | case V4L2_PIX_FMT_YUYV: | 910 | case V4L2_PIX_FMT_YUYV: |
| 678 | buf[0][offset] = r_y; | 911 | buf[0][offset] = r_y; |
| 679 | buf[0][offset + 1] = odd ? b_v : g_u; | 912 | if (odd) { |
| 913 | buf[0][1] = (buf[0][1] + g_u) / 2; | ||
| 914 | buf[0][3] = (buf[0][3] + b_v) / 2; | ||
| 915 | break; | ||
| 916 | } | ||
| 917 | buf[0][1] = g_u; | ||
| 918 | buf[0][3] = b_v; | ||
| 680 | break; | 919 | break; |
| 681 | case V4L2_PIX_FMT_UYVY: | 920 | case V4L2_PIX_FMT_UYVY: |
| 682 | buf[0][offset] = odd ? b_v : g_u; | ||
| 683 | buf[0][offset + 1] = r_y; | 921 | buf[0][offset + 1] = r_y; |
| 922 | if (odd) { | ||
| 923 | buf[0][0] = (buf[0][0] + g_u) / 2; | ||
| 924 | buf[0][2] = (buf[0][2] + b_v) / 2; | ||
| 925 | break; | ||
| 926 | } | ||
| 927 | buf[0][0] = g_u; | ||
| 928 | buf[0][2] = b_v; | ||
| 684 | break; | 929 | break; |
| 685 | case V4L2_PIX_FMT_YVYU: | 930 | case V4L2_PIX_FMT_YVYU: |
| 686 | buf[0][offset] = r_y; | 931 | buf[0][offset] = r_y; |
| 687 | buf[0][offset + 1] = odd ? g_u : b_v; | 932 | if (odd) { |
| 933 | buf[0][1] = (buf[0][1] + b_v) / 2; | ||
| 934 | buf[0][3] = (buf[0][3] + g_u) / 2; | ||
| 935 | break; | ||
| 936 | } | ||
| 937 | buf[0][1] = b_v; | ||
| 938 | buf[0][3] = g_u; | ||
| 688 | break; | 939 | break; |
| 689 | case V4L2_PIX_FMT_VYUY: | 940 | case V4L2_PIX_FMT_VYUY: |
| 690 | buf[0][offset] = odd ? g_u : b_v; | ||
| 691 | buf[0][offset + 1] = r_y; | 941 | buf[0][offset + 1] = r_y; |
| 942 | if (odd) { | ||
| 943 | buf[0][0] = (buf[0][0] + b_v) / 2; | ||
| 944 | buf[0][2] = (buf[0][2] + g_u) / 2; | ||
| 945 | break; | ||
| 946 | } | ||
| 947 | buf[0][0] = b_v; | ||
| 948 | buf[0][2] = g_u; | ||
| 949 | break; | ||
| 950 | case V4L2_PIX_FMT_RGB332: | ||
| 951 | buf[0][offset] = (r_y << 5) | (g_u << 2) | b_v; | ||
| 692 | break; | 952 | break; |
| 953 | case V4L2_PIX_FMT_YUV565: | ||
| 693 | case V4L2_PIX_FMT_RGB565: | 954 | case V4L2_PIX_FMT_RGB565: |
| 694 | buf[0][offset] = (g_u << 5) | b_v; | 955 | buf[0][offset] = (g_u << 5) | b_v; |
| 695 | buf[0][offset + 1] = (r_y << 3) | (g_u >> 3); | 956 | buf[0][offset + 1] = (r_y << 3) | (g_u >> 3); |
| @@ -698,15 +959,29 @@ static void gen_twopix(struct tpg_data *tpg, | |||
| 698 | buf[0][offset] = (r_y << 3) | (g_u >> 3); | 959 | buf[0][offset] = (r_y << 3) | (g_u >> 3); |
| 699 | buf[0][offset + 1] = (g_u << 5) | b_v; | 960 | buf[0][offset + 1] = (g_u << 5) | b_v; |
| 700 | break; | 961 | break; |
| 962 | case V4L2_PIX_FMT_RGB444: | ||
| 963 | case V4L2_PIX_FMT_XRGB444: | ||
| 964 | alpha = 0; | ||
| 965 | /* fall through */ | ||
| 966 | case V4L2_PIX_FMT_YUV444: | ||
| 967 | case V4L2_PIX_FMT_ARGB444: | ||
| 968 | buf[0][offset] = (g_u << 4) | b_v; | ||
| 969 | buf[0][offset + 1] = (alpha & 0xf0) | r_y; | ||
| 970 | break; | ||
| 701 | case V4L2_PIX_FMT_RGB555: | 971 | case V4L2_PIX_FMT_RGB555: |
| 702 | case V4L2_PIX_FMT_XRGB555: | 972 | case V4L2_PIX_FMT_XRGB555: |
| 703 | alpha = 0; | 973 | alpha = 0; |
| 704 | /* fall through */ | 974 | /* fall through */ |
| 975 | case V4L2_PIX_FMT_YUV555: | ||
| 705 | case V4L2_PIX_FMT_ARGB555: | 976 | case V4L2_PIX_FMT_ARGB555: |
| 706 | buf[0][offset] = (g_u << 5) | b_v; | 977 | buf[0][offset] = (g_u << 5) | b_v; |
| 707 | buf[0][offset + 1] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3); | 978 | buf[0][offset + 1] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3); |
| 708 | break; | 979 | break; |
| 709 | case V4L2_PIX_FMT_RGB555X: | 980 | case V4L2_PIX_FMT_RGB555X: |
| 981 | case V4L2_PIX_FMT_XRGB555X: | ||
| 982 | alpha = 0; | ||
| 983 | /* fall through */ | ||
| 984 | case V4L2_PIX_FMT_ARGB555X: | ||
| 710 | buf[0][offset] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3); | 985 | buf[0][offset] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3); |
| 711 | buf[0][offset + 1] = (g_u << 5) | b_v; | 986 | buf[0][offset + 1] = (g_u << 5) | b_v; |
| 712 | break; | 987 | break; |
| @@ -720,10 +995,17 @@ static void gen_twopix(struct tpg_data *tpg, | |||
| 720 | buf[0][offset + 1] = g_u; | 995 | buf[0][offset + 1] = g_u; |
| 721 | buf[0][offset + 2] = r_y; | 996 | buf[0][offset + 2] = r_y; |
| 722 | break; | 997 | break; |
| 998 | case V4L2_PIX_FMT_BGR666: | ||
| 999 | buf[0][offset] = (b_v << 2) | (g_u >> 4); | ||
| 1000 | buf[0][offset + 1] = (g_u << 4) | (r_y >> 2); | ||
| 1001 | buf[0][offset + 2] = r_y << 6; | ||
| 1002 | buf[0][offset + 3] = 0; | ||
| 1003 | break; | ||
| 723 | case V4L2_PIX_FMT_RGB32: | 1004 | case V4L2_PIX_FMT_RGB32: |
| 724 | case V4L2_PIX_FMT_XRGB32: | 1005 | case V4L2_PIX_FMT_XRGB32: |
| 725 | alpha = 0; | 1006 | alpha = 0; |
| 726 | /* fall through */ | 1007 | /* fall through */ |
| 1008 | case V4L2_PIX_FMT_YUV32: | ||
| 727 | case V4L2_PIX_FMT_ARGB32: | 1009 | case V4L2_PIX_FMT_ARGB32: |
| 728 | buf[0][offset] = alpha; | 1010 | buf[0][offset] = alpha; |
| 729 | buf[0][offset + 1] = r_y; | 1011 | buf[0][offset + 1] = r_y; |
| @@ -740,15 +1022,47 @@ static void gen_twopix(struct tpg_data *tpg, | |||
| 740 | buf[0][offset + 2] = r_y; | 1022 | buf[0][offset + 2] = r_y; |
| 741 | buf[0][offset + 3] = alpha; | 1023 | buf[0][offset + 3] = alpha; |
| 742 | break; | 1024 | break; |
| 1025 | case V4L2_PIX_FMT_SBGGR8: | ||
| 1026 | buf[0][offset] = odd ? g_u : b_v; | ||
| 1027 | buf[1][offset] = odd ? r_y : g_u; | ||
| 1028 | break; | ||
| 1029 | case V4L2_PIX_FMT_SGBRG8: | ||
| 1030 | buf[0][offset] = odd ? b_v : g_u; | ||
| 1031 | buf[1][offset] = odd ? g_u : r_y; | ||
| 1032 | break; | ||
| 1033 | case V4L2_PIX_FMT_SGRBG8: | ||
| 1034 | buf[0][offset] = odd ? r_y : g_u; | ||
| 1035 | buf[1][offset] = odd ? g_u : b_v; | ||
| 1036 | break; | ||
| 1037 | case V4L2_PIX_FMT_SRGGB8: | ||
| 1038 | buf[0][offset] = odd ? g_u : r_y; | ||
| 1039 | buf[1][offset] = odd ? b_v : g_u; | ||
| 1040 | break; | ||
| 1041 | } | ||
| 1042 | } | ||
| 1043 | |||
| 1044 | unsigned tpg_g_interleaved_plane(const struct tpg_data *tpg, unsigned buf_line) | ||
| 1045 | { | ||
| 1046 | switch (tpg->fourcc) { | ||
| 1047 | case V4L2_PIX_FMT_SBGGR8: | ||
| 1048 | case V4L2_PIX_FMT_SGBRG8: | ||
| 1049 | case V4L2_PIX_FMT_SGRBG8: | ||
| 1050 | case V4L2_PIX_FMT_SRGGB8: | ||
| 1051 | return buf_line & 1; | ||
| 1052 | default: | ||
| 1053 | return 0; | ||
| 743 | } | 1054 | } |
| 744 | } | 1055 | } |
| 745 | 1056 | ||
| 746 | /* Return how many pattern lines are used by the current pattern. */ | 1057 | /* Return how many pattern lines are used by the current pattern. */ |
| 747 | static unsigned tpg_get_pat_lines(struct tpg_data *tpg) | 1058 | static unsigned tpg_get_pat_lines(const struct tpg_data *tpg) |
| 748 | { | 1059 | { |
| 749 | switch (tpg->pattern) { | 1060 | switch (tpg->pattern) { |
| 750 | case TPG_PAT_CHECKERS_16X16: | 1061 | case TPG_PAT_CHECKERS_16X16: |
| 1062 | case TPG_PAT_CHECKERS_2X2: | ||
| 751 | case TPG_PAT_CHECKERS_1X1: | 1063 | case TPG_PAT_CHECKERS_1X1: |
| 1064 | case TPG_PAT_COLOR_CHECKERS_2X2: | ||
| 1065 | case TPG_PAT_COLOR_CHECKERS_1X1: | ||
| 752 | case TPG_PAT_ALTERNATING_HLINES: | 1066 | case TPG_PAT_ALTERNATING_HLINES: |
| 753 | case TPG_PAT_CROSS_1_PIXEL: | 1067 | case TPG_PAT_CROSS_1_PIXEL: |
| 754 | case TPG_PAT_CROSS_2_PIXELS: | 1068 | case TPG_PAT_CROSS_2_PIXELS: |
| @@ -763,14 +1077,18 @@ static unsigned tpg_get_pat_lines(struct tpg_data *tpg) | |||
| 763 | } | 1077 | } |
| 764 | 1078 | ||
| 765 | /* Which pattern line should be used for the given frame line. */ | 1079 | /* Which pattern line should be used for the given frame line. */ |
| 766 | static unsigned tpg_get_pat_line(struct tpg_data *tpg, unsigned line) | 1080 | static unsigned tpg_get_pat_line(const struct tpg_data *tpg, unsigned line) |
| 767 | { | 1081 | { |
| 768 | switch (tpg->pattern) { | 1082 | switch (tpg->pattern) { |
| 769 | case TPG_PAT_CHECKERS_16X16: | 1083 | case TPG_PAT_CHECKERS_16X16: |
| 770 | return (line >> 4) & 1; | 1084 | return (line >> 4) & 1; |
| 771 | case TPG_PAT_CHECKERS_1X1: | 1085 | case TPG_PAT_CHECKERS_1X1: |
| 1086 | case TPG_PAT_COLOR_CHECKERS_1X1: | ||
| 772 | case TPG_PAT_ALTERNATING_HLINES: | 1087 | case TPG_PAT_ALTERNATING_HLINES: |
| 773 | return line & 1; | 1088 | return line & 1; |
| 1089 | case TPG_PAT_CHECKERS_2X2: | ||
| 1090 | case TPG_PAT_COLOR_CHECKERS_2X2: | ||
| 1091 | return (line & 2) >> 1; | ||
| 774 | case TPG_PAT_100_COLORSQUARES: | 1092 | case TPG_PAT_100_COLORSQUARES: |
| 775 | case TPG_PAT_100_HCOLORBAR: | 1093 | case TPG_PAT_100_HCOLORBAR: |
| 776 | return (line * 8) / tpg->src_height; | 1094 | return (line * 8) / tpg->src_height; |
| @@ -789,7 +1107,8 @@ static unsigned tpg_get_pat_line(struct tpg_data *tpg, unsigned line) | |||
| 789 | * Which color should be used for the given pattern line and X coordinate. | 1107 | * Which color should be used for the given pattern line and X coordinate. |
| 790 | * Note: x is in the range 0 to 2 * tpg->src_width. | 1108 | * Note: x is in the range 0 to 2 * tpg->src_width. |
| 791 | */ | 1109 | */ |
| 792 | static enum tpg_color tpg_get_color(struct tpg_data *tpg, unsigned pat_line, unsigned x) | 1110 | static enum tpg_color tpg_get_color(const struct tpg_data *tpg, |
| 1111 | unsigned pat_line, unsigned x) | ||
| 793 | { | 1112 | { |
| 794 | /* Maximum number of bars are TPG_COLOR_MAX - otherwise, the input print code | 1113 | /* Maximum number of bars are TPG_COLOR_MAX - otherwise, the input print code |
| 795 | should be modified */ | 1114 | should be modified */ |
| @@ -836,6 +1155,15 @@ static enum tpg_color tpg_get_color(struct tpg_data *tpg, unsigned pat_line, uns | |||
| 836 | case TPG_PAT_CHECKERS_1X1: | 1155 | case TPG_PAT_CHECKERS_1X1: |
| 837 | return ((x & 1) ^ (pat_line & 1)) ? | 1156 | return ((x & 1) ^ (pat_line & 1)) ? |
| 838 | TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK; | 1157 | TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK; |
| 1158 | case TPG_PAT_COLOR_CHECKERS_1X1: | ||
| 1159 | return ((x & 1) ^ (pat_line & 1)) ? | ||
| 1160 | TPG_COLOR_100_RED : TPG_COLOR_100_BLUE; | ||
| 1161 | case TPG_PAT_CHECKERS_2X2: | ||
| 1162 | return (((x >> 1) & 1) ^ (pat_line & 1)) ? | ||
| 1163 | TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK; | ||
| 1164 | case TPG_PAT_COLOR_CHECKERS_2X2: | ||
| 1165 | return (((x >> 1) & 1) ^ (pat_line & 1)) ? | ||
| 1166 | TPG_COLOR_100_RED : TPG_COLOR_100_BLUE; | ||
| 839 | case TPG_PAT_ALTERNATING_HLINES: | 1167 | case TPG_PAT_ALTERNATING_HLINES: |
| 840 | return pat_line ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK; | 1168 | return pat_line ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK; |
| 841 | case TPG_PAT_ALTERNATING_VLINES: | 1169 | case TPG_PAT_ALTERNATING_VLINES: |
| @@ -948,6 +1276,7 @@ static void tpg_calculate_square_border(struct tpg_data *tpg) | |||
| 948 | static void tpg_precalculate_line(struct tpg_data *tpg) | 1276 | static void tpg_precalculate_line(struct tpg_data *tpg) |
| 949 | { | 1277 | { |
| 950 | enum tpg_color contrast; | 1278 | enum tpg_color contrast; |
| 1279 | u8 pix[TPG_MAX_PLANES][8]; | ||
| 951 | unsigned pat; | 1280 | unsigned pat; |
| 952 | unsigned p; | 1281 | unsigned p; |
| 953 | unsigned x; | 1282 | unsigned x; |
| @@ -974,7 +1303,6 @@ static void tpg_precalculate_line(struct tpg_data *tpg) | |||
| 974 | for (x = 0; x < tpg->scaled_width * 2; x += 2) { | 1303 | for (x = 0; x < tpg->scaled_width * 2; x += 2) { |
| 975 | unsigned real_x = src_x; | 1304 | unsigned real_x = src_x; |
| 976 | enum tpg_color color1, color2; | 1305 | enum tpg_color color1, color2; |
| 977 | u8 pix[TPG_MAX_PLANES][8]; | ||
| 978 | 1306 | ||
| 979 | real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x; | 1307 | real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x; |
| 980 | color1 = tpg_get_color(tpg, pat, real_x); | 1308 | color1 = tpg_get_color(tpg, pat, real_x); |
| @@ -1001,39 +1329,53 @@ static void tpg_precalculate_line(struct tpg_data *tpg) | |||
| 1001 | gen_twopix(tpg, pix, tpg->hflip ? color1 : color2, 1); | 1329 | gen_twopix(tpg, pix, tpg->hflip ? color1 : color2, 1); |
| 1002 | for (p = 0; p < tpg->planes; p++) { | 1330 | for (p = 0; p < tpg->planes; p++) { |
| 1003 | unsigned twopixsize = tpg->twopixelsize[p]; | 1331 | unsigned twopixsize = tpg->twopixelsize[p]; |
| 1004 | u8 *pos = tpg->lines[pat][p] + x * twopixsize / 2; | 1332 | unsigned hdiv = tpg->hdownsampling[p]; |
| 1333 | u8 *pos = tpg->lines[pat][p] + tpg_hdiv(tpg, p, x); | ||
| 1005 | 1334 | ||
| 1006 | memcpy(pos, pix[p], twopixsize); | 1335 | memcpy(pos, pix[p], twopixsize / hdiv); |
| 1007 | } | 1336 | } |
| 1008 | } | 1337 | } |
| 1009 | } | 1338 | } |
| 1010 | for (x = 0; x < tpg->scaled_width; x += 2) { | ||
| 1011 | u8 pix[TPG_MAX_PLANES][8]; | ||
| 1012 | 1339 | ||
| 1013 | gen_twopix(tpg, pix, contrast, 0); | 1340 | if (tpg->vdownsampling[tpg->planes - 1] > 1) { |
| 1014 | gen_twopix(tpg, pix, contrast, 1); | 1341 | unsigned pat_lines = tpg_get_pat_lines(tpg); |
| 1015 | for (p = 0; p < tpg->planes; p++) { | ||
| 1016 | unsigned twopixsize = tpg->twopixelsize[p]; | ||
| 1017 | u8 *pos = tpg->contrast_line[p] + x * twopixsize / 2; | ||
| 1018 | 1342 | ||
| 1019 | memcpy(pos, pix[p], twopixsize); | 1343 | for (pat = 0; pat < pat_lines; pat++) { |
| 1344 | unsigned next_pat = (pat + 1) % pat_lines; | ||
| 1345 | |||
| 1346 | for (p = 1; p < tpg->planes; p++) { | ||
| 1347 | unsigned w = tpg_hdiv(tpg, p, tpg->scaled_width * 2); | ||
| 1348 | u8 *pos1 = tpg->lines[pat][p]; | ||
| 1349 | u8 *pos2 = tpg->lines[next_pat][p]; | ||
| 1350 | u8 *dest = tpg->downsampled_lines[pat][p]; | ||
| 1351 | |||
| 1352 | for (x = 0; x < w; x++, pos1++, pos2++, dest++) | ||
| 1353 | *dest = ((u16)*pos1 + (u16)*pos2) / 2; | ||
| 1354 | } | ||
| 1020 | } | 1355 | } |
| 1021 | } | 1356 | } |
| 1022 | for (x = 0; x < tpg->scaled_width; x += 2) { | ||
| 1023 | u8 pix[TPG_MAX_PLANES][8]; | ||
| 1024 | 1357 | ||
| 1025 | gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 0); | 1358 | gen_twopix(tpg, pix, contrast, 0); |
| 1026 | gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 1); | 1359 | gen_twopix(tpg, pix, contrast, 1); |
| 1027 | for (p = 0; p < tpg->planes; p++) { | 1360 | for (p = 0; p < tpg->planes; p++) { |
| 1028 | unsigned twopixsize = tpg->twopixelsize[p]; | 1361 | unsigned twopixsize = tpg->twopixelsize[p]; |
| 1029 | u8 *pos = tpg->black_line[p] + x * twopixsize / 2; | 1362 | u8 *pos = tpg->contrast_line[p]; |
| 1030 | 1363 | ||
| 1364 | for (x = 0; x < tpg->scaled_width; x += 2, pos += twopixsize) | ||
| 1365 | memcpy(pos, pix[p], twopixsize); | ||
| 1366 | } | ||
| 1367 | |||
| 1368 | gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 0); | ||
| 1369 | gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 1); | ||
| 1370 | for (p = 0; p < tpg->planes; p++) { | ||
| 1371 | unsigned twopixsize = tpg->twopixelsize[p]; | ||
| 1372 | u8 *pos = tpg->black_line[p]; | ||
| 1373 | |||
| 1374 | for (x = 0; x < tpg->scaled_width; x += 2, pos += twopixsize) | ||
| 1031 | memcpy(pos, pix[p], twopixsize); | 1375 | memcpy(pos, pix[p], twopixsize); |
| 1032 | } | ||
| 1033 | } | 1376 | } |
| 1034 | for (x = 0; x < tpg->scaled_width * 2; x += 2) { | ||
| 1035 | u8 pix[TPG_MAX_PLANES][8]; | ||
| 1036 | 1377 | ||
| 1378 | for (x = 0; x < tpg->scaled_width * 2; x += 2) { | ||
| 1037 | gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 0); | 1379 | gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 0); |
| 1038 | gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 1); | 1380 | gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 1); |
| 1039 | for (p = 0; p < tpg->planes; p++) { | 1381 | for (p = 0; p < tpg->planes; p++) { |
| @@ -1043,6 +1385,7 @@ static void tpg_precalculate_line(struct tpg_data *tpg) | |||
| 1043 | memcpy(pos, pix[p], twopixsize); | 1385 | memcpy(pos, pix[p], twopixsize); |
| 1044 | } | 1386 | } |
| 1045 | } | 1387 | } |
| 1388 | |||
| 1046 | gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 0); | 1389 | gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 0); |
| 1047 | gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 1); | 1390 | gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 1); |
| 1048 | gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 0); | 1391 | gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 0); |
| @@ -1052,8 +1395,8 @@ static void tpg_precalculate_line(struct tpg_data *tpg) | |||
| 1052 | /* need this to do rgb24 rendering */ | 1395 | /* need this to do rgb24 rendering */ |
| 1053 | typedef struct { u16 __; u8 _; } __packed x24; | 1396 | typedef struct { u16 __; u8 _; } __packed x24; |
| 1054 | 1397 | ||
| 1055 | void tpg_gen_text(struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], | 1398 | void tpg_gen_text(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], |
| 1056 | int y, int x, char *text) | 1399 | int y, int x, char *text) |
| 1057 | { | 1400 | { |
| 1058 | int line; | 1401 | int line; |
| 1059 | unsigned step = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1; | 1402 | unsigned step = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1; |
| @@ -1083,24 +1426,37 @@ void tpg_gen_text(struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], | |||
| 1083 | div = 2; | 1426 | div = 2; |
| 1084 | 1427 | ||
| 1085 | for (p = 0; p < tpg->planes; p++) { | 1428 | for (p = 0; p < tpg->planes; p++) { |
| 1086 | /* Print stream time */ | 1429 | unsigned vdiv = tpg->vdownsampling[p]; |
| 1430 | unsigned hdiv = tpg->hdownsampling[p]; | ||
| 1431 | |||
| 1432 | /* Print text */ | ||
| 1087 | #define PRINTSTR(PIXTYPE) do { \ | 1433 | #define PRINTSTR(PIXTYPE) do { \ |
| 1088 | PIXTYPE fg; \ | 1434 | PIXTYPE fg; \ |
| 1089 | PIXTYPE bg; \ | 1435 | PIXTYPE bg; \ |
| 1090 | memcpy(&fg, tpg->textfg[p], sizeof(PIXTYPE)); \ | 1436 | memcpy(&fg, tpg->textfg[p], sizeof(PIXTYPE)); \ |
| 1091 | memcpy(&bg, tpg->textbg[p], sizeof(PIXTYPE)); \ | 1437 | memcpy(&bg, tpg->textbg[p], sizeof(PIXTYPE)); \ |
| 1092 | \ | 1438 | \ |
| 1093 | for (line = first; line < 16; line += step) { \ | 1439 | for (line = first; line < 16; line += vdiv * step) { \ |
| 1094 | int l = tpg->vflip ? 15 - line : line; \ | 1440 | int l = tpg->vflip ? 15 - line : line; \ |
| 1095 | PIXTYPE *pos = (PIXTYPE *)(basep[p][line & 1] + \ | 1441 | PIXTYPE *pos = (PIXTYPE *)(basep[p][(line / vdiv) & 1] + \ |
| 1096 | ((y * step + l) / div) * tpg->bytesperline[p] + \ | 1442 | ((y * step + l) / (vdiv * div)) * tpg->bytesperline[p] + \ |
| 1097 | x * sizeof(PIXTYPE)); \ | 1443 | (x / hdiv) * sizeof(PIXTYPE)); \ |
| 1098 | unsigned s; \ | 1444 | unsigned s; \ |
| 1099 | \ | 1445 | \ |
| 1100 | for (s = 0; s < len; s++) { \ | 1446 | for (s = 0; s < len; s++) { \ |
| 1101 | u8 chr = font8x16[text[s] * 16 + line]; \ | 1447 | u8 chr = font8x16[text[s] * 16 + line]; \ |
| 1102 | \ | 1448 | \ |
| 1103 | if (tpg->hflip) { \ | 1449 | if (hdiv == 2 && tpg->hflip) { \ |
| 1450 | pos[3] = (chr & (0x01 << 6) ? fg : bg); \ | ||
| 1451 | pos[2] = (chr & (0x01 << 4) ? fg : bg); \ | ||
| 1452 | pos[1] = (chr & (0x01 << 2) ? fg : bg); \ | ||
| 1453 | pos[0] = (chr & (0x01 << 0) ? fg : bg); \ | ||
| 1454 | } else if (hdiv == 2) { \ | ||
| 1455 | pos[0] = (chr & (0x01 << 7) ? fg : bg); \ | ||
| 1456 | pos[1] = (chr & (0x01 << 5) ? fg : bg); \ | ||
| 1457 | pos[2] = (chr & (0x01 << 3) ? fg : bg); \ | ||
| 1458 | pos[3] = (chr & (0x01 << 1) ? fg : bg); \ | ||
| 1459 | } else if (tpg->hflip) { \ | ||
| 1104 | pos[7] = (chr & (0x01 << 7) ? fg : bg); \ | 1460 | pos[7] = (chr & (0x01 << 7) ? fg : bg); \ |
| 1105 | pos[6] = (chr & (0x01 << 6) ? fg : bg); \ | 1461 | pos[6] = (chr & (0x01 << 6) ? fg : bg); \ |
| 1106 | pos[5] = (chr & (0x01 << 5) ? fg : bg); \ | 1462 | pos[5] = (chr & (0x01 << 5) ? fg : bg); \ |
| @@ -1120,7 +1476,7 @@ void tpg_gen_text(struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], | |||
| 1120 | pos[7] = (chr & (0x01 << 0) ? fg : bg); \ | 1476 | pos[7] = (chr & (0x01 << 0) ? fg : bg); \ |
| 1121 | } \ | 1477 | } \ |
| 1122 | \ | 1478 | \ |
| 1123 | pos += tpg->hflip ? -8 : 8; \ | 1479 | pos += (tpg->hflip ? -8 : 8) / hdiv; \ |
| 1124 | } \ | 1480 | } \ |
| 1125 | } \ | 1481 | } \ |
| 1126 | } while (0) | 1482 | } while (0) |
| @@ -1187,7 +1543,7 @@ void tpg_update_mv_step(struct tpg_data *tpg) | |||
| 1187 | } | 1543 | } |
| 1188 | 1544 | ||
| 1189 | /* Map the line number relative to the crop rectangle to a frame line number */ | 1545 | /* Map the line number relative to the crop rectangle to a frame line number */ |
| 1190 | static unsigned tpg_calc_frameline(struct tpg_data *tpg, unsigned src_y, | 1546 | static unsigned tpg_calc_frameline(const struct tpg_data *tpg, unsigned src_y, |
| 1191 | unsigned field) | 1547 | unsigned field) |
| 1192 | { | 1548 | { |
| 1193 | switch (field) { | 1549 | switch (field) { |
| @@ -1204,7 +1560,7 @@ static unsigned tpg_calc_frameline(struct tpg_data *tpg, unsigned src_y, | |||
| 1204 | * Map the line number relative to the compose rectangle to a destination | 1560 | * Map the line number relative to the compose rectangle to a destination |
| 1205 | * buffer line number. | 1561 | * buffer line number. |
| 1206 | */ | 1562 | */ |
| 1207 | static unsigned tpg_calc_buffer_line(struct tpg_data *tpg, unsigned y, | 1563 | static unsigned tpg_calc_buffer_line(const struct tpg_data *tpg, unsigned y, |
| 1208 | unsigned field) | 1564 | unsigned field) |
| 1209 | { | 1565 | { |
| 1210 | y += tpg->compose.top; | 1566 | y += tpg->compose.top; |
| @@ -1265,6 +1621,10 @@ static void tpg_recalc(struct tpg_data *tpg) | |||
| 1265 | V4L2_QUANTIZATION_LIM_RANGE; | 1621 | V4L2_QUANTIZATION_LIM_RANGE; |
| 1266 | break; | 1622 | break; |
| 1267 | } | 1623 | } |
| 1624 | } else if (tpg->colorspace == V4L2_COLORSPACE_BT2020) { | ||
| 1625 | /* R'G'B' BT.2020 is limited range */ | ||
| 1626 | tpg->real_quantization = | ||
| 1627 | V4L2_QUANTIZATION_LIM_RANGE; | ||
| 1268 | } | 1628 | } |
| 1269 | } | 1629 | } |
| 1270 | tpg_precalculate_colors(tpg); | 1630 | tpg_precalculate_colors(tpg); |
| @@ -1283,191 +1643,388 @@ void tpg_calc_text_basep(struct tpg_data *tpg, | |||
| 1283 | u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf) | 1643 | u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf) |
| 1284 | { | 1644 | { |
| 1285 | unsigned stride = tpg->bytesperline[p]; | 1645 | unsigned stride = tpg->bytesperline[p]; |
| 1646 | unsigned h = tpg->buf_height; | ||
| 1286 | 1647 | ||
| 1287 | tpg_recalc(tpg); | 1648 | tpg_recalc(tpg); |
| 1288 | 1649 | ||
| 1289 | basep[p][0] = vbuf; | 1650 | basep[p][0] = vbuf; |
| 1290 | basep[p][1] = vbuf; | 1651 | basep[p][1] = vbuf; |
| 1652 | h /= tpg->vdownsampling[p]; | ||
| 1291 | if (tpg->field == V4L2_FIELD_SEQ_TB) | 1653 | if (tpg->field == V4L2_FIELD_SEQ_TB) |
| 1292 | basep[p][1] += tpg->buf_height * stride / 2; | 1654 | basep[p][1] += h * stride / 2; |
| 1293 | else if (tpg->field == V4L2_FIELD_SEQ_BT) | 1655 | else if (tpg->field == V4L2_FIELD_SEQ_BT) |
| 1294 | basep[p][0] += tpg->buf_height * stride / 2; | 1656 | basep[p][0] += h * stride / 2; |
| 1657 | if (p == 0 && tpg->interleaved) | ||
| 1658 | tpg_calc_text_basep(tpg, basep, 1, vbuf); | ||
| 1295 | } | 1659 | } |
| 1296 | 1660 | ||
| 1297 | void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf) | 1661 | static int tpg_pattern_avg(const struct tpg_data *tpg, |
| 1662 | unsigned pat1, unsigned pat2) | ||
| 1298 | { | 1663 | { |
| 1299 | bool is_tv = std; | 1664 | unsigned pat_lines = tpg_get_pat_lines(tpg); |
| 1300 | bool is_60hz = is_tv && (std & V4L2_STD_525_60); | 1665 | |
| 1301 | unsigned mv_hor_old = tpg->mv_hor_count % tpg->src_width; | 1666 | if (pat1 == (pat2 + 1) % pat_lines) |
| 1302 | unsigned mv_hor_new = (tpg->mv_hor_count + tpg->mv_hor_step) % tpg->src_width; | 1667 | return pat2; |
| 1303 | unsigned mv_vert_old = tpg->mv_vert_count % tpg->src_height; | 1668 | if (pat2 == (pat1 + 1) % pat_lines) |
| 1304 | unsigned mv_vert_new = (tpg->mv_vert_count + tpg->mv_vert_step) % tpg->src_height; | 1669 | return pat1; |
| 1670 | return -1; | ||
| 1671 | } | ||
| 1672 | |||
| 1673 | /* | ||
| 1674 | * This struct contains common parameters used by both the drawing of the | ||
| 1675 | * test pattern and the drawing of the extras (borders, square, etc.) | ||
| 1676 | */ | ||
| 1677 | struct tpg_draw_params { | ||
| 1678 | /* common data */ | ||
| 1679 | bool is_tv; | ||
| 1680 | bool is_60hz; | ||
| 1681 | unsigned twopixsize; | ||
| 1682 | unsigned img_width; | ||
| 1683 | unsigned stride; | ||
| 1684 | unsigned hmax; | ||
| 1685 | unsigned frame_line; | ||
| 1686 | unsigned frame_line_next; | ||
| 1687 | |||
| 1688 | /* test pattern */ | ||
| 1689 | unsigned mv_hor_old; | ||
| 1690 | unsigned mv_hor_new; | ||
| 1691 | unsigned mv_vert_old; | ||
| 1692 | unsigned mv_vert_new; | ||
| 1693 | |||
| 1694 | /* extras */ | ||
| 1305 | unsigned wss_width; | 1695 | unsigned wss_width; |
| 1306 | unsigned f; | 1696 | unsigned wss_random_offset; |
| 1307 | int hmax = (tpg->compose.height * tpg->perc_fill) / 100; | 1697 | unsigned sav_eav_f; |
| 1308 | int h; | 1698 | unsigned left_pillar_width; |
| 1309 | unsigned twopixsize = tpg->twopixelsize[p]; | 1699 | unsigned right_pillar_start; |
| 1310 | unsigned img_width = tpg->compose.width * twopixsize / 2; | 1700 | }; |
| 1311 | unsigned line_offset; | ||
| 1312 | unsigned left_pillar_width = 0; | ||
| 1313 | unsigned right_pillar_start = img_width; | ||
| 1314 | unsigned stride = tpg->bytesperline[p]; | ||
| 1315 | unsigned factor = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1; | ||
| 1316 | u8 *orig_vbuf = vbuf; | ||
| 1317 | 1701 | ||
| 1318 | /* Coarse scaling with Bresenham */ | 1702 | static void tpg_fill_params_pattern(const struct tpg_data *tpg, unsigned p, |
| 1319 | unsigned int_part = (tpg->crop.height / factor) / tpg->compose.height; | 1703 | struct tpg_draw_params *params) |
| 1320 | unsigned fract_part = (tpg->crop.height / factor) % tpg->compose.height; | 1704 | { |
| 1321 | unsigned src_y = 0; | 1705 | params->mv_hor_old = |
| 1322 | unsigned error = 0; | 1706 | tpg_hscale_div(tpg, p, tpg->mv_hor_count % tpg->src_width); |
| 1707 | params->mv_hor_new = | ||
| 1708 | tpg_hscale_div(tpg, p, (tpg->mv_hor_count + tpg->mv_hor_step) % | ||
| 1709 | tpg->src_width); | ||
| 1710 | params->mv_vert_old = tpg->mv_vert_count % tpg->src_height; | ||
| 1711 | params->mv_vert_new = | ||
| 1712 | (tpg->mv_vert_count + tpg->mv_vert_step) % tpg->src_height; | ||
| 1713 | } | ||
| 1323 | 1714 | ||
| 1324 | tpg_recalc(tpg); | 1715 | static void tpg_fill_params_extras(const struct tpg_data *tpg, |
| 1716 | unsigned p, | ||
| 1717 | struct tpg_draw_params *params) | ||
| 1718 | { | ||
| 1719 | unsigned left_pillar_width = 0; | ||
| 1720 | unsigned right_pillar_start = params->img_width; | ||
| 1721 | |||
| 1722 | params->wss_width = tpg->crop.left < tpg->src_width / 2 ? | ||
| 1723 | tpg->src_width / 2 - tpg->crop.left : 0; | ||
| 1724 | if (params->wss_width > tpg->crop.width) | ||
| 1725 | params->wss_width = tpg->crop.width; | ||
| 1726 | params->wss_width = tpg_hscale_div(tpg, p, params->wss_width); | ||
| 1727 | params->wss_random_offset = | ||
| 1728 | params->twopixsize * prandom_u32_max(tpg->src_width / 2); | ||
| 1325 | 1729 | ||
| 1326 | mv_hor_old = (mv_hor_old * tpg->scaled_width / tpg->src_width) & ~1; | ||
| 1327 | mv_hor_new = (mv_hor_new * tpg->scaled_width / tpg->src_width) & ~1; | ||
| 1328 | wss_width = tpg->crop.left < tpg->src_width / 2 ? | ||
| 1329 | tpg->src_width / 2 - tpg->crop.left : 0; | ||
| 1330 | if (wss_width > tpg->crop.width) | ||
| 1331 | wss_width = tpg->crop.width; | ||
| 1332 | wss_width = wss_width * tpg->scaled_width / tpg->src_width; | ||
| 1333 | |||
| 1334 | vbuf += tpg->compose.left * twopixsize / 2; | ||
| 1335 | line_offset = tpg->crop.left * tpg->scaled_width / tpg->src_width; | ||
| 1336 | line_offset = (line_offset & ~1) * twopixsize / 2; | ||
| 1337 | if (tpg->crop.left < tpg->border.left) { | 1730 | if (tpg->crop.left < tpg->border.left) { |
| 1338 | left_pillar_width = tpg->border.left - tpg->crop.left; | 1731 | left_pillar_width = tpg->border.left - tpg->crop.left; |
| 1339 | if (left_pillar_width > tpg->crop.width) | 1732 | if (left_pillar_width > tpg->crop.width) |
| 1340 | left_pillar_width = tpg->crop.width; | 1733 | left_pillar_width = tpg->crop.width; |
| 1341 | left_pillar_width = (left_pillar_width * tpg->scaled_width) / tpg->src_width; | 1734 | left_pillar_width = tpg_hscale_div(tpg, p, left_pillar_width); |
| 1342 | left_pillar_width = (left_pillar_width & ~1) * twopixsize / 2; | ||
| 1343 | } | 1735 | } |
| 1344 | if (tpg->crop.left + tpg->crop.width > tpg->border.left + tpg->border.width) { | 1736 | params->left_pillar_width = left_pillar_width; |
| 1345 | right_pillar_start = tpg->border.left + tpg->border.width - tpg->crop.left; | 1737 | |
| 1346 | right_pillar_start = (right_pillar_start * tpg->scaled_width) / tpg->src_width; | 1738 | if (tpg->crop.left + tpg->crop.width > |
| 1347 | right_pillar_start = (right_pillar_start & ~1) * twopixsize / 2; | 1739 | tpg->border.left + tpg->border.width) { |
| 1348 | if (right_pillar_start > img_width) | 1740 | right_pillar_start = |
| 1349 | right_pillar_start = img_width; | 1741 | tpg->border.left + tpg->border.width - tpg->crop.left; |
| 1742 | right_pillar_start = | ||
| 1743 | tpg_hscale_div(tpg, p, right_pillar_start); | ||
| 1744 | if (right_pillar_start > params->img_width) | ||
| 1745 | right_pillar_start = params->img_width; | ||
| 1350 | } | 1746 | } |
| 1747 | params->right_pillar_start = right_pillar_start; | ||
| 1351 | 1748 | ||
| 1352 | f = tpg->field == (is_60hz ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM); | 1749 | params->sav_eav_f = tpg->field == |
| 1750 | (params->is_60hz ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM); | ||
| 1751 | } | ||
| 1353 | 1752 | ||
| 1354 | for (h = 0; h < tpg->compose.height; h++) { | 1753 | static void tpg_fill_plane_extras(const struct tpg_data *tpg, |
| 1355 | bool even; | 1754 | const struct tpg_draw_params *params, |
| 1356 | bool fill_blank = false; | 1755 | unsigned p, unsigned h, u8 *vbuf) |
| 1357 | unsigned frame_line; | 1756 | { |
| 1358 | unsigned buf_line; | 1757 | unsigned twopixsize = params->twopixsize; |
| 1359 | unsigned pat_line_old; | 1758 | unsigned img_width = params->img_width; |
| 1360 | unsigned pat_line_new; | 1759 | unsigned frame_line = params->frame_line; |
| 1361 | u8 *linestart_older; | 1760 | const struct v4l2_rect *sq = &tpg->square; |
| 1362 | u8 *linestart_newer; | 1761 | const struct v4l2_rect *b = &tpg->border; |
| 1363 | u8 *linestart_top; | 1762 | const struct v4l2_rect *c = &tpg->crop; |
| 1364 | u8 *linestart_bottom; | 1763 | |
| 1365 | 1764 | if (params->is_tv && !params->is_60hz && | |
| 1366 | frame_line = tpg_calc_frameline(tpg, src_y, tpg->field); | 1765 | frame_line == 0 && params->wss_width) { |
| 1367 | even = !(frame_line & 1); | 1766 | /* |
| 1368 | buf_line = tpg_calc_buffer_line(tpg, h, tpg->field); | 1767 | * Replace the first half of the top line of a 50 Hz frame |
| 1369 | src_y += int_part; | 1768 | * with random data to simulate a WSS signal. |
| 1370 | error += fract_part; | 1769 | */ |
| 1371 | if (error >= tpg->compose.height) { | 1770 | u8 *wss = tpg->random_line[p] + params->wss_random_offset; |
| 1372 | error -= tpg->compose.height; | ||
| 1373 | src_y++; | ||
| 1374 | } | ||
| 1375 | 1771 | ||
| 1376 | if (h >= hmax) { | 1772 | memcpy(vbuf, wss, params->wss_width); |
| 1377 | if (hmax == tpg->compose.height) | 1773 | } |
| 1378 | continue; | 1774 | |
| 1379 | if (!tpg->perc_fill_blank) | 1775 | if (tpg->show_border && frame_line >= b->top && |
| 1380 | continue; | 1776 | frame_line < b->top + b->height) { |
| 1381 | fill_blank = true; | 1777 | unsigned bottom = b->top + b->height - 1; |
| 1382 | } | 1778 | unsigned left = params->left_pillar_width; |
| 1779 | unsigned right = params->right_pillar_start; | ||
| 1383 | 1780 | ||
| 1384 | if (tpg->vflip) | 1781 | if (frame_line == b->top || frame_line == b->top + 1 || |
| 1385 | frame_line = tpg->src_height - frame_line - 1; | 1782 | frame_line == bottom || frame_line == bottom - 1) { |
| 1386 | 1783 | memcpy(vbuf + left, tpg->contrast_line[p], | |
| 1387 | if (fill_blank) { | 1784 | right - left); |
| 1388 | linestart_older = tpg->contrast_line[p]; | ||
| 1389 | linestart_newer = tpg->contrast_line[p]; | ||
| 1390 | } else if (tpg->qual != TPG_QUAL_NOISE && | ||
| 1391 | (frame_line < tpg->border.top || | ||
| 1392 | frame_line >= tpg->border.top + tpg->border.height)) { | ||
| 1393 | linestart_older = tpg->black_line[p]; | ||
| 1394 | linestart_newer = tpg->black_line[p]; | ||
| 1395 | } else if (tpg->pattern == TPG_PAT_NOISE || tpg->qual == TPG_QUAL_NOISE) { | ||
| 1396 | linestart_older = tpg->random_line[p] + | ||
| 1397 | twopixsize * prandom_u32_max(tpg->src_width / 2); | ||
| 1398 | linestart_newer = tpg->random_line[p] + | ||
| 1399 | twopixsize * prandom_u32_max(tpg->src_width / 2); | ||
| 1400 | } else { | 1785 | } else { |
| 1401 | pat_line_old = tpg_get_pat_line(tpg, | 1786 | if (b->left >= c->left && |
| 1402 | (frame_line + mv_vert_old) % tpg->src_height); | 1787 | b->left < c->left + c->width) |
| 1403 | pat_line_new = tpg_get_pat_line(tpg, | 1788 | memcpy(vbuf + left, |
| 1404 | (frame_line + mv_vert_new) % tpg->src_height); | 1789 | tpg->contrast_line[p], twopixsize); |
| 1405 | linestart_older = tpg->lines[pat_line_old][p] + | 1790 | if (b->left + b->width > c->left && |
| 1406 | mv_hor_old * twopixsize / 2; | 1791 | b->left + b->width <= c->left + c->width) |
| 1407 | linestart_newer = tpg->lines[pat_line_new][p] + | 1792 | memcpy(vbuf + right - twopixsize, |
| 1408 | mv_hor_new * twopixsize / 2; | 1793 | tpg->contrast_line[p], twopixsize); |
| 1409 | linestart_older += line_offset; | ||
| 1410 | linestart_newer += line_offset; | ||
| 1411 | } | 1794 | } |
| 1412 | if (is_60hz) { | 1795 | } |
| 1413 | linestart_top = linestart_newer; | 1796 | if (tpg->qual != TPG_QUAL_NOISE && frame_line >= b->top && |
| 1414 | linestart_bottom = linestart_older; | 1797 | frame_line < b->top + b->height) { |
| 1415 | } else { | 1798 | memcpy(vbuf, tpg->black_line[p], params->left_pillar_width); |
| 1416 | linestart_top = linestart_older; | 1799 | memcpy(vbuf + params->right_pillar_start, tpg->black_line[p], |
| 1417 | linestart_bottom = linestart_newer; | 1800 | img_width - params->right_pillar_start); |
| 1801 | } | ||
| 1802 | if (tpg->show_square && frame_line >= sq->top && | ||
| 1803 | frame_line < sq->top + sq->height && | ||
| 1804 | sq->left < c->left + c->width && | ||
| 1805 | sq->left + sq->width >= c->left) { | ||
| 1806 | unsigned left = sq->left; | ||
| 1807 | unsigned width = sq->width; | ||
| 1808 | |||
| 1809 | if (c->left > left) { | ||
| 1810 | width -= c->left - left; | ||
| 1811 | left = c->left; | ||
| 1418 | } | 1812 | } |
| 1813 | if (c->left + c->width < left + width) | ||
| 1814 | width -= left + width - c->left - c->width; | ||
| 1815 | left -= c->left; | ||
| 1816 | left = tpg_hscale_div(tpg, p, left); | ||
| 1817 | width = tpg_hscale_div(tpg, p, width); | ||
| 1818 | memcpy(vbuf + left, tpg->contrast_line[p], width); | ||
| 1819 | } | ||
| 1820 | if (tpg->insert_sav) { | ||
| 1821 | unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width / 3); | ||
| 1822 | u8 *p = vbuf + offset; | ||
| 1823 | unsigned vact = 0, hact = 0; | ||
| 1824 | |||
| 1825 | p[0] = 0xff; | ||
| 1826 | p[1] = 0; | ||
| 1827 | p[2] = 0; | ||
| 1828 | p[3] = 0x80 | (params->sav_eav_f << 6) | | ||
| 1829 | (vact << 5) | (hact << 4) | | ||
| 1830 | ((hact ^ vact) << 3) | | ||
| 1831 | ((hact ^ params->sav_eav_f) << 2) | | ||
| 1832 | ((params->sav_eav_f ^ vact) << 1) | | ||
| 1833 | (hact ^ vact ^ params->sav_eav_f); | ||
| 1834 | } | ||
| 1835 | if (tpg->insert_eav) { | ||
| 1836 | unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width * 2 / 3); | ||
| 1837 | u8 *p = vbuf + offset; | ||
| 1838 | unsigned vact = 0, hact = 1; | ||
| 1839 | |||
| 1840 | p[0] = 0xff; | ||
| 1841 | p[1] = 0; | ||
| 1842 | p[2] = 0; | ||
| 1843 | p[3] = 0x80 | (params->sav_eav_f << 6) | | ||
| 1844 | (vact << 5) | (hact << 4) | | ||
| 1845 | ((hact ^ vact) << 3) | | ||
| 1846 | ((hact ^ params->sav_eav_f) << 2) | | ||
| 1847 | ((params->sav_eav_f ^ vact) << 1) | | ||
| 1848 | (hact ^ vact ^ params->sav_eav_f); | ||
| 1849 | } | ||
| 1850 | } | ||
| 1419 | 1851 | ||
| 1420 | switch (tpg->field) { | 1852 | static void tpg_fill_plane_pattern(const struct tpg_data *tpg, |
| 1421 | case V4L2_FIELD_INTERLACED: | 1853 | const struct tpg_draw_params *params, |
| 1422 | case V4L2_FIELD_INTERLACED_TB: | 1854 | unsigned p, unsigned h, u8 *vbuf) |
| 1423 | case V4L2_FIELD_SEQ_TB: | 1855 | { |
| 1424 | case V4L2_FIELD_SEQ_BT: | 1856 | unsigned twopixsize = params->twopixsize; |
| 1425 | if (even) | 1857 | unsigned img_width = params->img_width; |
| 1426 | memcpy(vbuf + buf_line * stride, linestart_top, img_width); | 1858 | unsigned mv_hor_old = params->mv_hor_old; |
| 1427 | else | 1859 | unsigned mv_hor_new = params->mv_hor_new; |
| 1428 | memcpy(vbuf + buf_line * stride, linestart_bottom, img_width); | 1860 | unsigned mv_vert_old = params->mv_vert_old; |
| 1429 | break; | 1861 | unsigned mv_vert_new = params->mv_vert_new; |
| 1430 | case V4L2_FIELD_INTERLACED_BT: | 1862 | unsigned frame_line = params->frame_line; |
| 1431 | if (even) | 1863 | unsigned frame_line_next = params->frame_line_next; |
| 1432 | memcpy(vbuf + buf_line * stride, linestart_bottom, img_width); | 1864 | unsigned line_offset = tpg_hscale_div(tpg, p, tpg->crop.left); |
| 1433 | else | 1865 | bool even; |
| 1434 | memcpy(vbuf + buf_line * stride, linestart_top, img_width); | 1866 | bool fill_blank = false; |
| 1435 | break; | 1867 | unsigned pat_line_old; |
| 1436 | case V4L2_FIELD_TOP: | 1868 | unsigned pat_line_new; |
| 1437 | memcpy(vbuf + buf_line * stride, linestart_top, img_width); | 1869 | u8 *linestart_older; |
| 1438 | break; | 1870 | u8 *linestart_newer; |
| 1439 | case V4L2_FIELD_BOTTOM: | 1871 | u8 *linestart_top; |
| 1440 | memcpy(vbuf + buf_line * stride, linestart_bottom, img_width); | 1872 | u8 *linestart_bottom; |
| 1441 | break; | 1873 | |
| 1442 | case V4L2_FIELD_NONE: | 1874 | even = !(frame_line & 1); |
| 1443 | default: | 1875 | |
| 1444 | memcpy(vbuf + buf_line * stride, linestart_older, img_width); | 1876 | if (h >= params->hmax) { |
| 1445 | break; | 1877 | if (params->hmax == tpg->compose.height) |
| 1446 | } | 1878 | return; |
| 1879 | if (!tpg->perc_fill_blank) | ||
| 1880 | return; | ||
| 1881 | fill_blank = true; | ||
| 1882 | } | ||
| 1447 | 1883 | ||
| 1448 | if (is_tv && !is_60hz && frame_line == 0 && wss_width) { | 1884 | if (tpg->vflip) { |
| 1449 | /* | 1885 | frame_line = tpg->src_height - frame_line - 1; |
| 1450 | * Replace the first half of the top line of a 50 Hz frame | 1886 | frame_line_next = tpg->src_height - frame_line_next - 1; |
| 1451 | * with random data to simulate a WSS signal. | 1887 | } |
| 1452 | */ | 1888 | |
| 1453 | u8 *wss = tpg->random_line[p] + | 1889 | if (fill_blank) { |
| 1890 | linestart_older = tpg->contrast_line[p]; | ||
| 1891 | linestart_newer = tpg->contrast_line[p]; | ||
| 1892 | } else if (tpg->qual != TPG_QUAL_NOISE && | ||
| 1893 | (frame_line < tpg->border.top || | ||
| 1894 | frame_line >= tpg->border.top + tpg->border.height)) { | ||
| 1895 | linestart_older = tpg->black_line[p]; | ||
| 1896 | linestart_newer = tpg->black_line[p]; | ||
| 1897 | } else if (tpg->pattern == TPG_PAT_NOISE || tpg->qual == TPG_QUAL_NOISE) { | ||
| 1898 | linestart_older = tpg->random_line[p] + | ||
| 1899 | twopixsize * prandom_u32_max(tpg->src_width / 2); | ||
| 1900 | linestart_newer = tpg->random_line[p] + | ||
| 1454 | twopixsize * prandom_u32_max(tpg->src_width / 2); | 1901 | twopixsize * prandom_u32_max(tpg->src_width / 2); |
| 1902 | } else { | ||
| 1903 | unsigned frame_line_old = | ||
| 1904 | (frame_line + mv_vert_old) % tpg->src_height; | ||
| 1905 | unsigned frame_line_new = | ||
| 1906 | (frame_line + mv_vert_new) % tpg->src_height; | ||
| 1907 | unsigned pat_line_next_old; | ||
| 1908 | unsigned pat_line_next_new; | ||
| 1455 | 1909 | ||
| 1456 | memcpy(vbuf + buf_line * stride, wss, wss_width * twopixsize / 2); | 1910 | pat_line_old = tpg_get_pat_line(tpg, frame_line_old); |
| 1911 | pat_line_new = tpg_get_pat_line(tpg, frame_line_new); | ||
| 1912 | linestart_older = tpg->lines[pat_line_old][p] + mv_hor_old; | ||
| 1913 | linestart_newer = tpg->lines[pat_line_new][p] + mv_hor_new; | ||
| 1914 | |||
| 1915 | if (tpg->vdownsampling[p] > 1 && frame_line != frame_line_next) { | ||
| 1916 | int avg_pat; | ||
| 1917 | |||
| 1918 | /* | ||
| 1919 | * Now decide whether we need to use downsampled_lines[]. | ||
| 1920 | * That's necessary if the two lines use different patterns. | ||
| 1921 | */ | ||
| 1922 | pat_line_next_old = tpg_get_pat_line(tpg, | ||
| 1923 | (frame_line_next + mv_vert_old) % tpg->src_height); | ||
| 1924 | pat_line_next_new = tpg_get_pat_line(tpg, | ||
| 1925 | (frame_line_next + mv_vert_new) % tpg->src_height); | ||
| 1926 | |||
| 1927 | switch (tpg->field) { | ||
| 1928 | case V4L2_FIELD_INTERLACED: | ||
| 1929 | case V4L2_FIELD_INTERLACED_BT: | ||
| 1930 | case V4L2_FIELD_INTERLACED_TB: | ||
| 1931 | avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_new); | ||
| 1932 | if (avg_pat < 0) | ||
| 1933 | break; | ||
| 1934 | linestart_older = tpg->downsampled_lines[avg_pat][p] + mv_hor_old; | ||
| 1935 | linestart_newer = linestart_older; | ||
| 1936 | break; | ||
| 1937 | case V4L2_FIELD_NONE: | ||
| 1938 | case V4L2_FIELD_TOP: | ||
| 1939 | case V4L2_FIELD_BOTTOM: | ||
| 1940 | case V4L2_FIELD_SEQ_BT: | ||
| 1941 | case V4L2_FIELD_SEQ_TB: | ||
| 1942 | avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_next_old); | ||
| 1943 | if (avg_pat >= 0) | ||
| 1944 | linestart_older = tpg->downsampled_lines[avg_pat][p] + | ||
| 1945 | mv_hor_old; | ||
| 1946 | avg_pat = tpg_pattern_avg(tpg, pat_line_new, pat_line_next_new); | ||
| 1947 | if (avg_pat >= 0) | ||
| 1948 | linestart_newer = tpg->downsampled_lines[avg_pat][p] + | ||
| 1949 | mv_hor_new; | ||
| 1950 | break; | ||
| 1951 | } | ||
| 1457 | } | 1952 | } |
| 1953 | linestart_older += line_offset; | ||
| 1954 | linestart_newer += line_offset; | ||
| 1955 | } | ||
| 1956 | if (tpg->field_alternate) { | ||
| 1957 | linestart_top = linestart_bottom = linestart_older; | ||
| 1958 | } else if (params->is_60hz) { | ||
| 1959 | linestart_top = linestart_newer; | ||
| 1960 | linestart_bottom = linestart_older; | ||
| 1961 | } else { | ||
| 1962 | linestart_top = linestart_older; | ||
| 1963 | linestart_bottom = linestart_newer; | ||
| 1964 | } | ||
| 1965 | |||
| 1966 | switch (tpg->field) { | ||
| 1967 | case V4L2_FIELD_INTERLACED: | ||
| 1968 | case V4L2_FIELD_INTERLACED_TB: | ||
| 1969 | case V4L2_FIELD_SEQ_TB: | ||
| 1970 | case V4L2_FIELD_SEQ_BT: | ||
| 1971 | if (even) | ||
| 1972 | memcpy(vbuf, linestart_top, img_width); | ||
| 1973 | else | ||
| 1974 | memcpy(vbuf, linestart_bottom, img_width); | ||
| 1975 | break; | ||
| 1976 | case V4L2_FIELD_INTERLACED_BT: | ||
| 1977 | if (even) | ||
| 1978 | memcpy(vbuf, linestart_bottom, img_width); | ||
| 1979 | else | ||
| 1980 | memcpy(vbuf, linestart_top, img_width); | ||
| 1981 | break; | ||
| 1982 | case V4L2_FIELD_TOP: | ||
| 1983 | memcpy(vbuf, linestart_top, img_width); | ||
| 1984 | break; | ||
| 1985 | case V4L2_FIELD_BOTTOM: | ||
| 1986 | memcpy(vbuf, linestart_bottom, img_width); | ||
| 1987 | break; | ||
| 1988 | case V4L2_FIELD_NONE: | ||
| 1989 | default: | ||
| 1990 | memcpy(vbuf, linestart_older, img_width); | ||
| 1991 | break; | ||
| 1458 | } | 1992 | } |
| 1993 | } | ||
| 1994 | |||
| 1995 | void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, | ||
| 1996 | unsigned p, u8 *vbuf) | ||
| 1997 | { | ||
| 1998 | struct tpg_draw_params params; | ||
| 1999 | unsigned factor = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1; | ||
| 2000 | |||
| 2001 | /* Coarse scaling with Bresenham */ | ||
| 2002 | unsigned int_part = (tpg->crop.height / factor) / tpg->compose.height; | ||
| 2003 | unsigned fract_part = (tpg->crop.height / factor) % tpg->compose.height; | ||
| 2004 | unsigned src_y = 0; | ||
| 2005 | unsigned error = 0; | ||
| 2006 | unsigned h; | ||
| 2007 | |||
| 2008 | tpg_recalc(tpg); | ||
| 2009 | |||
| 2010 | params.is_tv = std; | ||
| 2011 | params.is_60hz = std & V4L2_STD_525_60; | ||
| 2012 | params.twopixsize = tpg->twopixelsize[p]; | ||
| 2013 | params.img_width = tpg_hdiv(tpg, p, tpg->compose.width); | ||
| 2014 | params.stride = tpg->bytesperline[p]; | ||
| 2015 | params.hmax = (tpg->compose.height * tpg->perc_fill) / 100; | ||
| 2016 | |||
| 2017 | tpg_fill_params_pattern(tpg, p, ¶ms); | ||
| 2018 | tpg_fill_params_extras(tpg, p, ¶ms); | ||
| 2019 | |||
| 2020 | vbuf += tpg_hdiv(tpg, p, tpg->compose.left); | ||
| 1459 | 2021 | ||
| 1460 | vbuf = orig_vbuf; | ||
| 1461 | vbuf += tpg->compose.left * twopixsize / 2; | ||
| 1462 | src_y = 0; | ||
| 1463 | error = 0; | ||
| 1464 | for (h = 0; h < tpg->compose.height; h++) { | 2022 | for (h = 0; h < tpg->compose.height; h++) { |
| 1465 | unsigned frame_line = tpg_calc_frameline(tpg, src_y, tpg->field); | 2023 | unsigned buf_line; |
| 1466 | unsigned buf_line = tpg_calc_buffer_line(tpg, h, tpg->field); | ||
| 1467 | const struct v4l2_rect *sq = &tpg->square; | ||
| 1468 | const struct v4l2_rect *b = &tpg->border; | ||
| 1469 | const struct v4l2_rect *c = &tpg->crop; | ||
| 1470 | 2024 | ||
| 2025 | params.frame_line = tpg_calc_frameline(tpg, src_y, tpg->field); | ||
| 2026 | params.frame_line_next = params.frame_line; | ||
| 2027 | buf_line = tpg_calc_buffer_line(tpg, h, tpg->field); | ||
| 1471 | src_y += int_part; | 2028 | src_y += int_part; |
| 1472 | error += fract_part; | 2029 | error += fract_part; |
| 1473 | if (error >= tpg->compose.height) { | 2030 | if (error >= tpg->compose.height) { |
| @@ -1475,80 +2032,61 @@ void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf) | |||
| 1475 | src_y++; | 2032 | src_y++; |
| 1476 | } | 2033 | } |
| 1477 | 2034 | ||
| 1478 | if (tpg->show_border && frame_line >= b->top && | 2035 | /* |
| 1479 | frame_line < b->top + b->height) { | 2036 | * For line-interleaved formats determine the 'plane' |
| 1480 | unsigned bottom = b->top + b->height - 1; | 2037 | * based on the buffer line. |
| 1481 | unsigned left = left_pillar_width; | 2038 | */ |
| 1482 | unsigned right = right_pillar_start; | 2039 | if (tpg_g_interleaved(tpg)) |
| 2040 | p = tpg_g_interleaved_plane(tpg, buf_line); | ||
| 1483 | 2041 | ||
| 1484 | if (frame_line == b->top || frame_line == b->top + 1 || | 2042 | if (tpg->vdownsampling[p] > 1) { |
| 1485 | frame_line == bottom || frame_line == bottom - 1) { | 2043 | /* |
| 1486 | memcpy(vbuf + buf_line * stride + left, tpg->contrast_line[p], | 2044 | * When doing vertical downsampling the field setting |
| 1487 | right - left); | 2045 | * matters: for SEQ_BT/TB we downsample each field |
| 2046 | * separately (i.e. lines 0+2 are combined, as are | ||
| 2047 | * lines 1+3), for the other field settings we combine | ||
| 2048 | * odd and even lines. Doing that for SEQ_BT/TB would | ||
| 2049 | * be really weird. | ||
| 2050 | */ | ||
| 2051 | if (tpg->field == V4L2_FIELD_SEQ_BT || | ||
| 2052 | tpg->field == V4L2_FIELD_SEQ_TB) { | ||
| 2053 | unsigned next_src_y = src_y; | ||
| 2054 | |||
| 2055 | if ((h & 3) >= 2) | ||
| 2056 | continue; | ||
| 2057 | next_src_y += int_part; | ||
| 2058 | if (error + fract_part >= tpg->compose.height) | ||
| 2059 | next_src_y++; | ||
| 2060 | params.frame_line_next = | ||
| 2061 | tpg_calc_frameline(tpg, next_src_y, tpg->field); | ||
| 1488 | } else { | 2062 | } else { |
| 1489 | if (b->left >= c->left && | 2063 | if (h & 1) |
| 1490 | b->left < c->left + c->width) | 2064 | continue; |
| 1491 | memcpy(vbuf + buf_line * stride + left, | 2065 | params.frame_line_next = |
| 1492 | tpg->contrast_line[p], twopixsize); | 2066 | tpg_calc_frameline(tpg, src_y, tpg->field); |
| 1493 | if (b->left + b->width > c->left && | ||
| 1494 | b->left + b->width <= c->left + c->width) | ||
| 1495 | memcpy(vbuf + buf_line * stride + right - twopixsize, | ||
| 1496 | tpg->contrast_line[p], twopixsize); | ||
| 1497 | } | 2067 | } |
| 2068 | |||
| 2069 | buf_line /= tpg->vdownsampling[p]; | ||
| 1498 | } | 2070 | } |
| 1499 | if (tpg->qual != TPG_QUAL_NOISE && frame_line >= b->top && | 2071 | tpg_fill_plane_pattern(tpg, ¶ms, p, h, |
| 1500 | frame_line < b->top + b->height) { | 2072 | vbuf + buf_line * params.stride); |
| 1501 | memcpy(vbuf + buf_line * stride, tpg->black_line[p], left_pillar_width); | 2073 | tpg_fill_plane_extras(tpg, ¶ms, p, h, |
| 1502 | memcpy(vbuf + buf_line * stride + right_pillar_start, tpg->black_line[p], | 2074 | vbuf + buf_line * params.stride); |
| 1503 | img_width - right_pillar_start); | 2075 | } |
| 1504 | } | 2076 | } |
| 1505 | if (tpg->show_square && frame_line >= sq->top && | 2077 | |
| 1506 | frame_line < sq->top + sq->height && | 2078 | void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf) |
| 1507 | sq->left < c->left + c->width && | 2079 | { |
| 1508 | sq->left + sq->width >= c->left) { | 2080 | unsigned offset = 0; |
| 1509 | unsigned left = sq->left; | 2081 | unsigned i; |
| 1510 | unsigned width = sq->width; | 2082 | |
| 1511 | 2083 | if (tpg->buffers > 1) { | |
| 1512 | if (c->left > left) { | 2084 | tpg_fill_plane_buffer(tpg, std, p, vbuf); |
| 1513 | width -= c->left - left; | 2085 | return; |
| 1514 | left = c->left; | 2086 | } |
| 1515 | } | 2087 | |
| 1516 | if (c->left + c->width < left + width) | 2088 | for (i = 0; i < tpg_g_planes(tpg); i++) { |
| 1517 | width -= left + width - c->left - c->width; | 2089 | tpg_fill_plane_buffer(tpg, std, i, vbuf + offset); |
| 1518 | left -= c->left; | 2090 | offset += tpg_calc_plane_size(tpg, i); |
| 1519 | left = (left * tpg->scaled_width) / tpg->src_width; | ||
| 1520 | left = (left & ~1) * twopixsize / 2; | ||
| 1521 | width = (width * tpg->scaled_width) / tpg->src_width; | ||
| 1522 | width = (width & ~1) * twopixsize / 2; | ||
| 1523 | memcpy(vbuf + buf_line * stride + left, tpg->contrast_line[p], width); | ||
| 1524 | } | ||
| 1525 | if (tpg->insert_sav) { | ||
| 1526 | unsigned offset = (tpg->compose.width / 6) * twopixsize; | ||
| 1527 | u8 *p = vbuf + buf_line * stride + offset; | ||
| 1528 | unsigned vact = 0, hact = 0; | ||
| 1529 | |||
| 1530 | p[0] = 0xff; | ||
| 1531 | p[1] = 0; | ||
| 1532 | p[2] = 0; | ||
| 1533 | p[3] = 0x80 | (f << 6) | (vact << 5) | (hact << 4) | | ||
| 1534 | ((hact ^ vact) << 3) | | ||
| 1535 | ((hact ^ f) << 2) | | ||
| 1536 | ((f ^ vact) << 1) | | ||
| 1537 | (hact ^ vact ^ f); | ||
| 1538 | } | ||
| 1539 | if (tpg->insert_eav) { | ||
| 1540 | unsigned offset = (tpg->compose.width / 6) * 2 * twopixsize; | ||
| 1541 | u8 *p = vbuf + buf_line * stride + offset; | ||
| 1542 | unsigned vact = 0, hact = 1; | ||
| 1543 | |||
| 1544 | p[0] = 0xff; | ||
| 1545 | p[1] = 0; | ||
| 1546 | p[2] = 0; | ||
| 1547 | p[3] = 0x80 | (f << 6) | (vact << 5) | (hact << 4) | | ||
| 1548 | ((hact ^ vact) << 3) | | ||
| 1549 | ((hact ^ f) << 2) | | ||
| 1550 | ((f ^ vact) << 1) | | ||
| 1551 | (hact ^ vact ^ f); | ||
| 1552 | } | ||
| 1553 | } | 2091 | } |
| 1554 | } | 2092 | } |
diff --git a/drivers/media/platform/vivid/vivid-tpg.h b/drivers/media/platform/vivid/vivid-tpg.h index bd8b1c760b3f..a50cd2e2535b 100644 --- a/drivers/media/platform/vivid/vivid-tpg.h +++ b/drivers/media/platform/vivid/vivid-tpg.h | |||
| @@ -41,7 +41,10 @@ enum tpg_pattern { | |||
| 41 | TPG_PAT_GREEN, | 41 | TPG_PAT_GREEN, |
| 42 | TPG_PAT_BLUE, | 42 | TPG_PAT_BLUE, |
| 43 | TPG_PAT_CHECKERS_16X16, | 43 | TPG_PAT_CHECKERS_16X16, |
| 44 | TPG_PAT_CHECKERS_2X2, | ||
| 44 | TPG_PAT_CHECKERS_1X1, | 45 | TPG_PAT_CHECKERS_1X1, |
| 46 | TPG_PAT_COLOR_CHECKERS_2X2, | ||
| 47 | TPG_PAT_COLOR_CHECKERS_1X1, | ||
| 45 | TPG_PAT_ALTERNATING_HLINES, | 48 | TPG_PAT_ALTERNATING_HLINES, |
| 46 | TPG_PAT_ALTERNATING_VLINES, | 49 | TPG_PAT_ALTERNATING_VLINES, |
| 47 | TPG_PAT_CROSS_1_PIXEL, | 50 | TPG_PAT_CROSS_1_PIXEL, |
| @@ -87,7 +90,7 @@ enum tpg_move_mode { | |||
| 87 | 90 | ||
| 88 | extern const char * const tpg_aspect_strings[]; | 91 | extern const char * const tpg_aspect_strings[]; |
| 89 | 92 | ||
| 90 | #define TPG_MAX_PLANES 2 | 93 | #define TPG_MAX_PLANES 3 |
| 91 | #define TPG_MAX_PAT_LINES 8 | 94 | #define TPG_MAX_PAT_LINES 8 |
| 92 | 95 | ||
| 93 | struct tpg_data { | 96 | struct tpg_data { |
| @@ -98,6 +101,7 @@ struct tpg_data { | |||
| 98 | /* Scaled output frame size */ | 101 | /* Scaled output frame size */ |
| 99 | unsigned scaled_width; | 102 | unsigned scaled_width; |
| 100 | u32 field; | 103 | u32 field; |
| 104 | bool field_alternate; | ||
| 101 | /* crop coordinates are frame-based */ | 105 | /* crop coordinates are frame-based */ |
| 102 | struct v4l2_rect crop; | 106 | struct v4l2_rect crop; |
| 103 | /* compose coordinates are format-based */ | 107 | /* compose coordinates are format-based */ |
| @@ -134,7 +138,16 @@ struct tpg_data { | |||
| 134 | enum tpg_pixel_aspect pix_aspect; | 138 | enum tpg_pixel_aspect pix_aspect; |
| 135 | unsigned rgb_range; | 139 | unsigned rgb_range; |
| 136 | unsigned real_rgb_range; | 140 | unsigned real_rgb_range; |
| 141 | unsigned buffers; | ||
| 137 | unsigned planes; | 142 | unsigned planes; |
| 143 | bool interleaved; | ||
| 144 | u8 vdownsampling[TPG_MAX_PLANES]; | ||
| 145 | u8 hdownsampling[TPG_MAX_PLANES]; | ||
| 146 | /* | ||
| 147 | * horizontal positions must be ANDed with this value to enforce | ||
| 148 | * correct boundaries for packed YUYV values. | ||
| 149 | */ | ||
| 150 | unsigned hmask[TPG_MAX_PLANES]; | ||
| 138 | /* Used to store the colors in native format, either RGB or YUV */ | 151 | /* Used to store the colors in native format, either RGB or YUV */ |
| 139 | u8 colors[TPG_COLOR_MAX][3]; | 152 | u8 colors[TPG_COLOR_MAX][3]; |
| 140 | u8 textfg[TPG_MAX_PLANES][8], textbg[TPG_MAX_PLANES][8]; | 153 | u8 textfg[TPG_MAX_PLANES][8], textbg[TPG_MAX_PLANES][8]; |
| @@ -168,6 +181,7 @@ struct tpg_data { | |||
| 168 | /* Used to store TPG_MAX_PAT_LINES lines, each with up to two planes */ | 181 | /* Used to store TPG_MAX_PAT_LINES lines, each with up to two planes */ |
| 169 | unsigned max_line_width; | 182 | unsigned max_line_width; |
| 170 | u8 *lines[TPG_MAX_PAT_LINES][TPG_MAX_PLANES]; | 183 | u8 *lines[TPG_MAX_PAT_LINES][TPG_MAX_PLANES]; |
| 184 | u8 *downsampled_lines[TPG_MAX_PAT_LINES][TPG_MAX_PLANES]; | ||
| 171 | u8 *random_line[TPG_MAX_PLANES]; | 185 | u8 *random_line[TPG_MAX_PLANES]; |
| 172 | u8 *contrast_line[TPG_MAX_PLANES]; | 186 | u8 *contrast_line[TPG_MAX_PLANES]; |
| 173 | u8 *black_line[TPG_MAX_PLANES]; | 187 | u8 *black_line[TPG_MAX_PLANES]; |
| @@ -180,11 +194,15 @@ void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height, | |||
| 180 | u32 field); | 194 | u32 field); |
| 181 | 195 | ||
| 182 | void tpg_set_font(const u8 *f); | 196 | void tpg_set_font(const u8 *f); |
| 183 | void tpg_gen_text(struct tpg_data *tpg, | 197 | void tpg_gen_text(const struct tpg_data *tpg, |
| 184 | u8 *basep[TPG_MAX_PLANES][2], int y, int x, char *text); | 198 | u8 *basep[TPG_MAX_PLANES][2], int y, int x, char *text); |
| 185 | void tpg_calc_text_basep(struct tpg_data *tpg, | 199 | void tpg_calc_text_basep(struct tpg_data *tpg, |
| 186 | u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf); | 200 | u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf); |
| 187 | void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf); | 201 | unsigned tpg_g_interleaved_plane(const struct tpg_data *tpg, unsigned buf_line); |
| 202 | void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, | ||
| 203 | unsigned p, u8 *vbuf); | ||
| 204 | void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, | ||
| 205 | unsigned p, u8 *vbuf); | ||
| 188 | bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc); | 206 | bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc); |
| 189 | void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop, | 207 | void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop, |
| 190 | const struct v4l2_rect *compose); | 208 | const struct v4l2_rect *compose); |
| @@ -323,9 +341,19 @@ static inline u32 tpg_g_quantization(const struct tpg_data *tpg) | |||
| 323 | return tpg->quantization; | 341 | return tpg->quantization; |
| 324 | } | 342 | } |
| 325 | 343 | ||
| 344 | static inline unsigned tpg_g_buffers(const struct tpg_data *tpg) | ||
| 345 | { | ||
| 346 | return tpg->buffers; | ||
| 347 | } | ||
| 348 | |||
| 326 | static inline unsigned tpg_g_planes(const struct tpg_data *tpg) | 349 | static inline unsigned tpg_g_planes(const struct tpg_data *tpg) |
| 327 | { | 350 | { |
| 328 | return tpg->planes; | 351 | return tpg->interleaved ? 1 : tpg->planes; |
| 352 | } | ||
| 353 | |||
| 354 | static inline bool tpg_g_interleaved(const struct tpg_data *tpg) | ||
| 355 | { | ||
| 356 | return tpg->interleaved; | ||
| 329 | } | 357 | } |
| 330 | 358 | ||
| 331 | static inline unsigned tpg_g_twopixelsize(const struct tpg_data *tpg, unsigned plane) | 359 | static inline unsigned tpg_g_twopixelsize(const struct tpg_data *tpg, unsigned plane) |
| @@ -333,6 +361,24 @@ static inline unsigned tpg_g_twopixelsize(const struct tpg_data *tpg, unsigned p | |||
| 333 | return tpg->twopixelsize[plane]; | 361 | return tpg->twopixelsize[plane]; |
| 334 | } | 362 | } |
| 335 | 363 | ||
| 364 | static inline unsigned tpg_hdiv(const struct tpg_data *tpg, | ||
| 365 | unsigned plane, unsigned x) | ||
| 366 | { | ||
| 367 | return ((x / tpg->hdownsampling[plane]) & tpg->hmask[plane]) * | ||
| 368 | tpg->twopixelsize[plane] / 2; | ||
| 369 | } | ||
| 370 | |||
| 371 | static inline unsigned tpg_hscale(const struct tpg_data *tpg, unsigned x) | ||
| 372 | { | ||
| 373 | return (x * tpg->scaled_width) / tpg->src_width; | ||
| 374 | } | ||
| 375 | |||
| 376 | static inline unsigned tpg_hscale_div(const struct tpg_data *tpg, | ||
| 377 | unsigned plane, unsigned x) | ||
| 378 | { | ||
| 379 | return tpg_hdiv(tpg, plane, tpg_hscale(tpg, x)); | ||
| 380 | } | ||
| 381 | |||
| 336 | static inline unsigned tpg_g_bytesperline(const struct tpg_data *tpg, unsigned plane) | 382 | static inline unsigned tpg_g_bytesperline(const struct tpg_data *tpg, unsigned plane) |
| 337 | { | 383 | { |
| 338 | return tpg->bytesperline[plane]; | 384 | return tpg->bytesperline[plane]; |
| @@ -340,7 +386,60 @@ static inline unsigned tpg_g_bytesperline(const struct tpg_data *tpg, unsigned p | |||
| 340 | 386 | ||
| 341 | static inline void tpg_s_bytesperline(struct tpg_data *tpg, unsigned plane, unsigned bpl) | 387 | static inline void tpg_s_bytesperline(struct tpg_data *tpg, unsigned plane, unsigned bpl) |
| 342 | { | 388 | { |
| 343 | tpg->bytesperline[plane] = bpl; | 389 | unsigned p; |
| 390 | |||
| 391 | if (tpg->buffers > 1) { | ||
| 392 | tpg->bytesperline[plane] = bpl; | ||
| 393 | return; | ||
| 394 | } | ||
| 395 | |||
| 396 | for (p = 0; p < tpg_g_planes(tpg); p++) { | ||
| 397 | unsigned plane_w = bpl * tpg->twopixelsize[p] / tpg->twopixelsize[0]; | ||
| 398 | |||
| 399 | tpg->bytesperline[p] = plane_w / tpg->hdownsampling[p]; | ||
| 400 | } | ||
| 401 | } | ||
| 402 | |||
| 403 | |||
| 404 | static inline unsigned tpg_g_line_width(const struct tpg_data *tpg, unsigned plane) | ||
| 405 | { | ||
| 406 | unsigned w = 0; | ||
| 407 | unsigned p; | ||
| 408 | |||
| 409 | if (tpg->buffers > 1) | ||
| 410 | return tpg_g_bytesperline(tpg, plane); | ||
| 411 | for (p = 0; p < tpg_g_planes(tpg); p++) { | ||
| 412 | unsigned plane_w = tpg_g_bytesperline(tpg, p); | ||
| 413 | |||
| 414 | w += plane_w / tpg->vdownsampling[p]; | ||
| 415 | } | ||
| 416 | return w; | ||
| 417 | } | ||
| 418 | |||
| 419 | static inline unsigned tpg_calc_line_width(const struct tpg_data *tpg, | ||
| 420 | unsigned plane, unsigned bpl) | ||
| 421 | { | ||
| 422 | unsigned w = 0; | ||
| 423 | unsigned p; | ||
| 424 | |||
| 425 | if (tpg->buffers > 1) | ||
| 426 | return bpl; | ||
| 427 | for (p = 0; p < tpg_g_planes(tpg); p++) { | ||
| 428 | unsigned plane_w = bpl * tpg->twopixelsize[p] / tpg->twopixelsize[0]; | ||
| 429 | |||
| 430 | plane_w /= tpg->hdownsampling[p]; | ||
| 431 | w += plane_w / tpg->vdownsampling[p]; | ||
| 432 | } | ||
| 433 | return w; | ||
| 434 | } | ||
| 435 | |||
| 436 | static inline unsigned tpg_calc_plane_size(const struct tpg_data *tpg, unsigned plane) | ||
| 437 | { | ||
| 438 | if (plane >= tpg_g_planes(tpg)) | ||
| 439 | return 0; | ||
| 440 | |||
| 441 | return tpg_g_bytesperline(tpg, plane) * tpg->buf_height / | ||
| 442 | tpg->vdownsampling[plane]; | ||
| 344 | } | 443 | } |
| 345 | 444 | ||
| 346 | static inline void tpg_s_buf_height(struct tpg_data *tpg, unsigned h) | 445 | static inline void tpg_s_buf_height(struct tpg_data *tpg, unsigned h) |
| @@ -348,9 +447,10 @@ static inline void tpg_s_buf_height(struct tpg_data *tpg, unsigned h) | |||
| 348 | tpg->buf_height = h; | 447 | tpg->buf_height = h; |
| 349 | } | 448 | } |
| 350 | 449 | ||
| 351 | static inline void tpg_s_field(struct tpg_data *tpg, unsigned field) | 450 | static inline void tpg_s_field(struct tpg_data *tpg, unsigned field, bool alternate) |
| 352 | { | 451 | { |
| 353 | tpg->field = field; | 452 | tpg->field = field; |
| 453 | tpg->field_alternate = alternate; | ||
| 354 | } | 454 | } |
| 355 | 455 | ||
| 356 | static inline void tpg_s_perc_fill(struct tpg_data *tpg, | 456 | static inline void tpg_s_perc_fill(struct tpg_data *tpg, |
diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c index 867a29a6d18f..dab5990f45a0 100644 --- a/drivers/media/platform/vivid/vivid-vid-cap.c +++ b/drivers/media/platform/vivid/vivid-vid-cap.c | |||
| @@ -42,20 +42,26 @@ static const struct vivid_fmt formats_ovl[] = { | |||
| 42 | { | 42 | { |
| 43 | .name = "RGB565 (LE)", | 43 | .name = "RGB565 (LE)", |
| 44 | .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */ | 44 | .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */ |
| 45 | .depth = 16, | 45 | .vdownsampling = { 1 }, |
| 46 | .bit_depth = { 16 }, | ||
| 46 | .planes = 1, | 47 | .planes = 1, |
| 48 | .buffers = 1, | ||
| 47 | }, | 49 | }, |
| 48 | { | 50 | { |
| 49 | .name = "XRGB555 (LE)", | 51 | .name = "XRGB555 (LE)", |
| 50 | .fourcc = V4L2_PIX_FMT_XRGB555, /* gggbbbbb arrrrrgg */ | 52 | .fourcc = V4L2_PIX_FMT_XRGB555, /* gggbbbbb arrrrrgg */ |
| 51 | .depth = 16, | 53 | .vdownsampling = { 1 }, |
| 54 | .bit_depth = { 16 }, | ||
| 52 | .planes = 1, | 55 | .planes = 1, |
| 56 | .buffers = 1, | ||
| 53 | }, | 57 | }, |
| 54 | { | 58 | { |
| 55 | .name = "ARGB555 (LE)", | 59 | .name = "ARGB555 (LE)", |
| 56 | .fourcc = V4L2_PIX_FMT_ARGB555, /* gggbbbbb arrrrrgg */ | 60 | .fourcc = V4L2_PIX_FMT_ARGB555, /* gggbbbbb arrrrrgg */ |
| 57 | .depth = 16, | 61 | .vdownsampling = { 1 }, |
| 62 | .bit_depth = { 16 }, | ||
| 58 | .planes = 1, | 63 | .planes = 1, |
| 64 | .buffers = 1, | ||
| 59 | }, | 65 | }, |
| 60 | }; | 66 | }; |
| 61 | 67 | ||
| @@ -94,7 +100,7 @@ static int vid_cap_queue_setup(struct vb2_queue *vq, const struct v4l2_format *f | |||
| 94 | unsigned sizes[], void *alloc_ctxs[]) | 100 | unsigned sizes[], void *alloc_ctxs[]) |
| 95 | { | 101 | { |
| 96 | struct vivid_dev *dev = vb2_get_drv_priv(vq); | 102 | struct vivid_dev *dev = vb2_get_drv_priv(vq); |
| 97 | unsigned planes = tpg_g_planes(&dev->tpg); | 103 | unsigned buffers = tpg_g_buffers(&dev->tpg); |
| 98 | unsigned h = dev->fmt_cap_rect.height; | 104 | unsigned h = dev->fmt_cap_rect.height; |
| 99 | unsigned p; | 105 | unsigned p; |
| 100 | 106 | ||
| @@ -127,39 +133,36 @@ static int vid_cap_queue_setup(struct vb2_queue *vq, const struct v4l2_format *f | |||
| 127 | mp = &fmt->fmt.pix_mp; | 133 | mp = &fmt->fmt.pix_mp; |
| 128 | /* | 134 | /* |
| 129 | * Check if the number of planes in the specified format match | 135 | * Check if the number of planes in the specified format match |
| 130 | * the number of planes in the current format. You can't mix that. | 136 | * the number of buffers in the current format. You can't mix that. |
| 131 | */ | 137 | */ |
| 132 | if (mp->num_planes != planes) | 138 | if (mp->num_planes != buffers) |
| 133 | return -EINVAL; | 139 | return -EINVAL; |
| 134 | vfmt = vivid_get_format(dev, mp->pixelformat); | 140 | vfmt = vivid_get_format(dev, mp->pixelformat); |
| 135 | for (p = 0; p < planes; p++) { | 141 | for (p = 0; p < buffers; p++) { |
| 136 | sizes[p] = mp->plane_fmt[p].sizeimage; | 142 | sizes[p] = mp->plane_fmt[p].sizeimage; |
| 137 | if (sizes[0] < tpg_g_bytesperline(&dev->tpg, 0) * h + | 143 | if (sizes[p] < tpg_g_line_width(&dev->tpg, p) * h + |
| 138 | vfmt->data_offset[p]) | 144 | vfmt->data_offset[p]) |
| 139 | return -EINVAL; | 145 | return -EINVAL; |
| 140 | } | 146 | } |
| 141 | } else { | 147 | } else { |
| 142 | for (p = 0; p < planes; p++) | 148 | for (p = 0; p < buffers; p++) |
| 143 | sizes[p] = tpg_g_bytesperline(&dev->tpg, p) * h + | 149 | sizes[p] = tpg_g_line_width(&dev->tpg, p) * h + |
| 144 | dev->fmt_cap->data_offset[p]; | 150 | dev->fmt_cap->data_offset[p]; |
| 145 | } | 151 | } |
| 146 | 152 | ||
| 147 | if (vq->num_buffers + *nbuffers < 2) | 153 | if (vq->num_buffers + *nbuffers < 2) |
| 148 | *nbuffers = 2 - vq->num_buffers; | 154 | *nbuffers = 2 - vq->num_buffers; |
| 149 | 155 | ||
| 150 | *nplanes = planes; | 156 | *nplanes = buffers; |
| 151 | 157 | ||
| 152 | /* | 158 | /* |
| 153 | * videobuf2-vmalloc allocator is context-less so no need to set | 159 | * videobuf2-vmalloc allocator is context-less so no need to set |
| 154 | * alloc_ctxs array. | 160 | * alloc_ctxs array. |
| 155 | */ | 161 | */ |
| 156 | 162 | ||
| 157 | if (planes == 2) | 163 | dprintk(dev, 1, "%s: count=%d\n", __func__, *nbuffers); |
| 158 | dprintk(dev, 1, "%s, count=%d, sizes=%u, %u\n", __func__, | 164 | for (p = 0; p < buffers; p++) |
| 159 | *nbuffers, sizes[0], sizes[1]); | 165 | dprintk(dev, 1, "%s: size[%u]=%u\n", __func__, p, sizes[p]); |
| 160 | else | ||
| 161 | dprintk(dev, 1, "%s, count=%d, size=%u\n", __func__, | ||
| 162 | *nbuffers, sizes[0]); | ||
| 163 | 166 | ||
| 164 | return 0; | 167 | return 0; |
| 165 | } | 168 | } |
| @@ -168,7 +171,7 @@ static int vid_cap_buf_prepare(struct vb2_buffer *vb) | |||
| 168 | { | 171 | { |
| 169 | struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); | 172 | struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); |
| 170 | unsigned long size; | 173 | unsigned long size; |
| 171 | unsigned planes = tpg_g_planes(&dev->tpg); | 174 | unsigned buffers = tpg_g_buffers(&dev->tpg); |
| 172 | unsigned p; | 175 | unsigned p; |
| 173 | 176 | ||
| 174 | dprintk(dev, 1, "%s\n", __func__); | 177 | dprintk(dev, 1, "%s\n", __func__); |
| @@ -184,13 +187,13 @@ static int vid_cap_buf_prepare(struct vb2_buffer *vb) | |||
| 184 | dev->buf_prepare_error = false; | 187 | dev->buf_prepare_error = false; |
| 185 | return -EINVAL; | 188 | return -EINVAL; |
| 186 | } | 189 | } |
| 187 | for (p = 0; p < planes; p++) { | 190 | for (p = 0; p < buffers; p++) { |
| 188 | size = tpg_g_bytesperline(&dev->tpg, p) * dev->fmt_cap_rect.height + | 191 | size = tpg_g_line_width(&dev->tpg, p) * dev->fmt_cap_rect.height + |
| 189 | dev->fmt_cap->data_offset[p]; | 192 | dev->fmt_cap->data_offset[p]; |
| 190 | 193 | ||
| 191 | if (vb2_plane_size(vb, 0) < size) { | 194 | if (vb2_plane_size(vb, p) < size) { |
| 192 | dprintk(dev, 1, "%s data will not fit into plane %u (%lu < %lu)\n", | 195 | dprintk(dev, 1, "%s data will not fit into plane %u (%lu < %lu)\n", |
| 193 | __func__, p, vb2_plane_size(vb, 0), size); | 196 | __func__, p, vb2_plane_size(vb, p), size); |
| 194 | return -EINVAL; | 197 | return -EINVAL; |
| 195 | } | 198 | } |
| 196 | 199 | ||
| @@ -441,7 +444,7 @@ void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls) | |||
| 441 | */ | 444 | */ |
| 442 | if (keep_controls || !dev->colorspace) | 445 | if (keep_controls || !dev->colorspace) |
| 443 | break; | 446 | break; |
| 444 | if (bt->standards & V4L2_DV_BT_STD_CEA861) { | 447 | if (bt->flags & V4L2_DV_FL_IS_CE_VIDEO) { |
| 445 | if (bt->width == 720 && bt->height <= 576) | 448 | if (bt->width == 720 && bt->height <= 576) |
| 446 | v4l2_ctrl_s_ctrl(dev->colorspace, VIVID_CS_170M); | 449 | v4l2_ctrl_s_ctrl(dev->colorspace, VIVID_CS_170M); |
| 447 | else | 450 | else |
| @@ -526,11 +529,11 @@ int vivid_g_fmt_vid_cap(struct file *file, void *priv, | |||
| 526 | mp->colorspace = vivid_colorspace_cap(dev); | 529 | mp->colorspace = vivid_colorspace_cap(dev); |
| 527 | mp->ycbcr_enc = vivid_ycbcr_enc_cap(dev); | 530 | mp->ycbcr_enc = vivid_ycbcr_enc_cap(dev); |
| 528 | mp->quantization = vivid_quantization_cap(dev); | 531 | mp->quantization = vivid_quantization_cap(dev); |
| 529 | mp->num_planes = dev->fmt_cap->planes; | 532 | mp->num_planes = dev->fmt_cap->buffers; |
| 530 | for (p = 0; p < mp->num_planes; p++) { | 533 | for (p = 0; p < mp->num_planes; p++) { |
| 531 | mp->plane_fmt[p].bytesperline = tpg_g_bytesperline(&dev->tpg, p); | 534 | mp->plane_fmt[p].bytesperline = tpg_g_bytesperline(&dev->tpg, p); |
| 532 | mp->plane_fmt[p].sizeimage = | 535 | mp->plane_fmt[p].sizeimage = |
| 533 | mp->plane_fmt[p].bytesperline * mp->height + | 536 | tpg_g_line_width(&dev->tpg, p) * mp->height + |
| 534 | dev->fmt_cap->data_offset[p]; | 537 | dev->fmt_cap->data_offset[p]; |
| 535 | } | 538 | } |
| 536 | return 0; | 539 | return 0; |
| @@ -596,18 +599,19 @@ int vivid_try_fmt_vid_cap(struct file *file, void *priv, | |||
| 596 | 599 | ||
| 597 | /* This driver supports custom bytesperline values */ | 600 | /* This driver supports custom bytesperline values */ |
| 598 | 601 | ||
| 599 | /* Calculate the minimum supported bytesperline value */ | 602 | mp->num_planes = fmt->buffers; |
| 600 | bytesperline = (mp->width * fmt->depth) >> 3; | ||
| 601 | /* Calculate the maximum supported bytesperline value */ | ||
| 602 | max_bpl = (MAX_ZOOM * MAX_WIDTH * fmt->depth) >> 3; | ||
| 603 | mp->num_planes = fmt->planes; | ||
| 604 | for (p = 0; p < mp->num_planes; p++) { | 603 | for (p = 0; p < mp->num_planes; p++) { |
| 604 | /* Calculate the minimum supported bytesperline value */ | ||
| 605 | bytesperline = (mp->width * fmt->bit_depth[p]) >> 3; | ||
| 606 | /* Calculate the maximum supported bytesperline value */ | ||
| 607 | max_bpl = (MAX_ZOOM * MAX_WIDTH * fmt->bit_depth[p]) >> 3; | ||
| 608 | |||
| 605 | if (pfmt[p].bytesperline > max_bpl) | 609 | if (pfmt[p].bytesperline > max_bpl) |
| 606 | pfmt[p].bytesperline = max_bpl; | 610 | pfmt[p].bytesperline = max_bpl; |
| 607 | if (pfmt[p].bytesperline < bytesperline) | 611 | if (pfmt[p].bytesperline < bytesperline) |
| 608 | pfmt[p].bytesperline = bytesperline; | 612 | pfmt[p].bytesperline = bytesperline; |
| 609 | pfmt[p].sizeimage = pfmt[p].bytesperline * mp->height + | 613 | pfmt[p].sizeimage = tpg_calc_line_width(&dev->tpg, p, pfmt[p].bytesperline) * |
| 610 | fmt->data_offset[p]; | 614 | mp->height + fmt->data_offset[p]; |
| 611 | memset(pfmt[p].reserved, 0, sizeof(pfmt[p].reserved)); | 615 | memset(pfmt[p].reserved, 0, sizeof(pfmt[p].reserved)); |
| 612 | } | 616 | } |
| 613 | mp->colorspace = vivid_colorspace_cap(dev); | 617 | mp->colorspace = vivid_colorspace_cap(dev); |
| @@ -627,6 +631,7 @@ int vivid_s_fmt_vid_cap(struct file *file, void *priv, | |||
| 627 | struct vb2_queue *q = &dev->vb_vid_cap_q; | 631 | struct vb2_queue *q = &dev->vb_vid_cap_q; |
| 628 | int ret = vivid_try_fmt_vid_cap(file, priv, f); | 632 | int ret = vivid_try_fmt_vid_cap(file, priv, f); |
| 629 | unsigned factor = 1; | 633 | unsigned factor = 1; |
| 634 | unsigned p; | ||
| 630 | unsigned i; | 635 | unsigned i; |
| 631 | 636 | ||
| 632 | if (ret < 0) | 637 | if (ret < 0) |
| @@ -729,13 +734,15 @@ int vivid_s_fmt_vid_cap(struct file *file, void *priv, | |||
| 729 | dev->fmt_cap_rect.width = mp->width; | 734 | dev->fmt_cap_rect.width = mp->width; |
| 730 | dev->fmt_cap_rect.height = mp->height; | 735 | dev->fmt_cap_rect.height = mp->height; |
| 731 | tpg_s_buf_height(&dev->tpg, mp->height); | 736 | tpg_s_buf_height(&dev->tpg, mp->height); |
| 732 | tpg_s_bytesperline(&dev->tpg, 0, mp->plane_fmt[0].bytesperline); | 737 | tpg_s_fourcc(&dev->tpg, dev->fmt_cap->fourcc); |
| 733 | if (tpg_g_planes(&dev->tpg) > 1) | 738 | for (p = 0; p < tpg_g_buffers(&dev->tpg); p++) |
| 734 | tpg_s_bytesperline(&dev->tpg, 1, mp->plane_fmt[1].bytesperline); | 739 | tpg_s_bytesperline(&dev->tpg, p, mp->plane_fmt[p].bytesperline); |
| 735 | dev->field_cap = mp->field; | 740 | dev->field_cap = mp->field; |
| 736 | tpg_s_field(&dev->tpg, dev->field_cap); | 741 | if (dev->field_cap == V4L2_FIELD_ALTERNATE) |
| 742 | tpg_s_field(&dev->tpg, V4L2_FIELD_TOP, true); | ||
| 743 | else | ||
| 744 | tpg_s_field(&dev->tpg, dev->field_cap, false); | ||
| 737 | tpg_s_crop_compose(&dev->tpg, &dev->crop_cap, &dev->compose_cap); | 745 | tpg_s_crop_compose(&dev->tpg, &dev->crop_cap, &dev->compose_cap); |
| 738 | tpg_s_fourcc(&dev->tpg, dev->fmt_cap->fourcc); | ||
| 739 | if (vivid_is_sdtv_cap(dev)) | 746 | if (vivid_is_sdtv_cap(dev)) |
| 740 | dev->tv_field_cap = mp->field; | 747 | dev->tv_field_cap = mp->field; |
| 741 | tpg_update_mv_step(&dev->tpg); | 748 | tpg_update_mv_step(&dev->tpg); |
| @@ -1012,8 +1019,12 @@ int vivid_vid_cap_cropcap(struct file *file, void *priv, | |||
| 1012 | int vidioc_enum_fmt_vid_overlay(struct file *file, void *priv, | 1019 | int vidioc_enum_fmt_vid_overlay(struct file *file, void *priv, |
| 1013 | struct v4l2_fmtdesc *f) | 1020 | struct v4l2_fmtdesc *f) |
| 1014 | { | 1021 | { |
| 1022 | struct vivid_dev *dev = video_drvdata(file); | ||
| 1015 | const struct vivid_fmt *fmt; | 1023 | const struct vivid_fmt *fmt; |
| 1016 | 1024 | ||
| 1025 | if (dev->multiplanar) | ||
| 1026 | return -ENOTTY; | ||
| 1027 | |||
| 1017 | if (f->index >= ARRAY_SIZE(formats_ovl)) | 1028 | if (f->index >= ARRAY_SIZE(formats_ovl)) |
| 1018 | return -EINVAL; | 1029 | return -EINVAL; |
| 1019 | 1030 | ||
| @@ -1032,6 +1043,9 @@ int vidioc_g_fmt_vid_overlay(struct file *file, void *priv, | |||
| 1032 | struct v4l2_window *win = &f->fmt.win; | 1043 | struct v4l2_window *win = &f->fmt.win; |
| 1033 | unsigned clipcount = win->clipcount; | 1044 | unsigned clipcount = win->clipcount; |
| 1034 | 1045 | ||
| 1046 | if (dev->multiplanar) | ||
| 1047 | return -ENOTTY; | ||
| 1048 | |||
| 1035 | win->w.top = dev->overlay_cap_top; | 1049 | win->w.top = dev->overlay_cap_top; |
| 1036 | win->w.left = dev->overlay_cap_left; | 1050 | win->w.left = dev->overlay_cap_left; |
| 1037 | win->w.width = compose->width; | 1051 | win->w.width = compose->width; |
| @@ -1063,6 +1077,9 @@ int vidioc_try_fmt_vid_overlay(struct file *file, void *priv, | |||
| 1063 | struct v4l2_window *win = &f->fmt.win; | 1077 | struct v4l2_window *win = &f->fmt.win; |
| 1064 | int i, j; | 1078 | int i, j; |
| 1065 | 1079 | ||
| 1080 | if (dev->multiplanar) | ||
| 1081 | return -ENOTTY; | ||
| 1082 | |||
| 1066 | win->w.left = clamp_t(int, win->w.left, | 1083 | win->w.left = clamp_t(int, win->w.left, |
| 1067 | -dev->fb_cap.fmt.width, dev->fb_cap.fmt.width); | 1084 | -dev->fb_cap.fmt.width, dev->fb_cap.fmt.width); |
| 1068 | win->w.top = clamp_t(int, win->w.top, | 1085 | win->w.top = clamp_t(int, win->w.top, |
| @@ -1150,6 +1167,9 @@ int vivid_vid_cap_overlay(struct file *file, void *fh, unsigned i) | |||
| 1150 | { | 1167 | { |
| 1151 | struct vivid_dev *dev = video_drvdata(file); | 1168 | struct vivid_dev *dev = video_drvdata(file); |
| 1152 | 1169 | ||
| 1170 | if (dev->multiplanar) | ||
| 1171 | return -ENOTTY; | ||
| 1172 | |||
| 1153 | if (i && dev->fb_vbase_cap == NULL) | 1173 | if (i && dev->fb_vbase_cap == NULL) |
| 1154 | return -EINVAL; | 1174 | return -EINVAL; |
| 1155 | 1175 | ||
| @@ -1169,6 +1189,9 @@ int vivid_vid_cap_g_fbuf(struct file *file, void *fh, | |||
| 1169 | { | 1189 | { |
| 1170 | struct vivid_dev *dev = video_drvdata(file); | 1190 | struct vivid_dev *dev = video_drvdata(file); |
| 1171 | 1191 | ||
| 1192 | if (dev->multiplanar) | ||
| 1193 | return -ENOTTY; | ||
| 1194 | |||
| 1172 | *a = dev->fb_cap; | 1195 | *a = dev->fb_cap; |
| 1173 | a->capability = V4L2_FBUF_CAP_BITMAP_CLIPPING | | 1196 | a->capability = V4L2_FBUF_CAP_BITMAP_CLIPPING | |
| 1174 | V4L2_FBUF_CAP_LIST_CLIPPING; | 1197 | V4L2_FBUF_CAP_LIST_CLIPPING; |
| @@ -1185,6 +1208,9 @@ int vivid_vid_cap_s_fbuf(struct file *file, void *fh, | |||
| 1185 | struct vivid_dev *dev = video_drvdata(file); | 1208 | struct vivid_dev *dev = video_drvdata(file); |
| 1186 | const struct vivid_fmt *fmt; | 1209 | const struct vivid_fmt *fmt; |
| 1187 | 1210 | ||
| 1211 | if (dev->multiplanar) | ||
| 1212 | return -ENOTTY; | ||
| 1213 | |||
| 1188 | if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO)) | 1214 | if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO)) |
| 1189 | return -EPERM; | 1215 | return -EPERM; |
| 1190 | 1216 | ||
| @@ -1202,7 +1228,7 @@ int vivid_vid_cap_s_fbuf(struct file *file, void *fh, | |||
| 1202 | fmt = vivid_get_format(dev, a->fmt.pixelformat); | 1228 | fmt = vivid_get_format(dev, a->fmt.pixelformat); |
| 1203 | if (!fmt || !fmt->can_do_overlay) | 1229 | if (!fmt || !fmt->can_do_overlay) |
| 1204 | return -EINVAL; | 1230 | return -EINVAL; |
| 1205 | if (a->fmt.bytesperline < (a->fmt.width * fmt->depth) / 8) | 1231 | if (a->fmt.bytesperline < (a->fmt.width * fmt->bit_depth[0]) / 8) |
| 1206 | return -EINVAL; | 1232 | return -EINVAL; |
| 1207 | if (a->fmt.height * a->fmt.bytesperline < a->fmt.sizeimage) | 1233 | if (a->fmt.height * a->fmt.bytesperline < a->fmt.sizeimage) |
| 1208 | return -EINVAL; | 1234 | return -EINVAL; |
| @@ -1332,7 +1358,7 @@ int vidioc_s_input(struct file *file, void *priv, unsigned i) | |||
| 1332 | v4l2_ctrl_s_ctrl(dev->colorspace, VIVID_CS_170M); | 1358 | v4l2_ctrl_s_ctrl(dev->colorspace, VIVID_CS_170M); |
| 1333 | break; | 1359 | break; |
| 1334 | case HDMI: | 1360 | case HDMI: |
| 1335 | if (bt->standards & V4L2_DV_BT_STD_CEA861) { | 1361 | if (bt->flags & V4L2_DV_FL_IS_CE_VIDEO) { |
| 1336 | if (dev->src_rect.width == 720 && dev->src_rect.height <= 576) | 1362 | if (dev->src_rect.width == 720 && dev->src_rect.height <= 576) |
| 1337 | v4l2_ctrl_s_ctrl(dev->colorspace, VIVID_CS_170M); | 1363 | v4l2_ctrl_s_ctrl(dev->colorspace, VIVID_CS_170M); |
| 1338 | else | 1364 | else |
| @@ -1552,6 +1578,65 @@ int vivid_vid_cap_s_std(struct file *file, void *priv, v4l2_std_id id) | |||
| 1552 | return 0; | 1578 | return 0; |
| 1553 | } | 1579 | } |
| 1554 | 1580 | ||
| 1581 | static void find_aspect_ratio(u32 width, u32 height, | ||
| 1582 | u32 *num, u32 *denom) | ||
| 1583 | { | ||
| 1584 | if (!(height % 3) && ((height * 4 / 3) == width)) { | ||
| 1585 | *num = 4; | ||
| 1586 | *denom = 3; | ||
| 1587 | } else if (!(height % 9) && ((height * 16 / 9) == width)) { | ||
| 1588 | *num = 16; | ||
| 1589 | *denom = 9; | ||
| 1590 | } else if (!(height % 10) && ((height * 16 / 10) == width)) { | ||
| 1591 | *num = 16; | ||
| 1592 | *denom = 10; | ||
| 1593 | } else if (!(height % 4) && ((height * 5 / 4) == width)) { | ||
| 1594 | *num = 5; | ||
| 1595 | *denom = 4; | ||
| 1596 | } else if (!(height % 9) && ((height * 15 / 9) == width)) { | ||
| 1597 | *num = 15; | ||
| 1598 | *denom = 9; | ||
| 1599 | } else { /* default to 16:9 */ | ||
| 1600 | *num = 16; | ||
| 1601 | *denom = 9; | ||
| 1602 | } | ||
| 1603 | } | ||
| 1604 | |||
| 1605 | static bool valid_cvt_gtf_timings(struct v4l2_dv_timings *timings) | ||
| 1606 | { | ||
| 1607 | struct v4l2_bt_timings *bt = &timings->bt; | ||
| 1608 | u32 total_h_pixel; | ||
| 1609 | u32 total_v_lines; | ||
| 1610 | u32 h_freq; | ||
| 1611 | |||
| 1612 | if (!v4l2_valid_dv_timings(timings, &vivid_dv_timings_cap, | ||
| 1613 | NULL, NULL)) | ||
| 1614 | return false; | ||
| 1615 | |||
| 1616 | total_h_pixel = V4L2_DV_BT_FRAME_WIDTH(bt); | ||
| 1617 | total_v_lines = V4L2_DV_BT_FRAME_HEIGHT(bt); | ||
| 1618 | |||
| 1619 | h_freq = (u32)bt->pixelclock / total_h_pixel; | ||
| 1620 | |||
| 1621 | if (bt->standards == 0 || (bt->standards & V4L2_DV_BT_STD_CVT)) { | ||
| 1622 | if (v4l2_detect_cvt(total_v_lines, h_freq, bt->vsync, | ||
| 1623 | bt->polarities, timings)) | ||
| 1624 | return true; | ||
| 1625 | } | ||
| 1626 | |||
| 1627 | if (bt->standards == 0 || (bt->standards & V4L2_DV_BT_STD_GTF)) { | ||
| 1628 | struct v4l2_fract aspect_ratio; | ||
| 1629 | |||
| 1630 | find_aspect_ratio(bt->width, bt->height, | ||
| 1631 | &aspect_ratio.numerator, | ||
| 1632 | &aspect_ratio.denominator); | ||
| 1633 | if (v4l2_detect_gtf(total_v_lines, h_freq, bt->vsync, | ||
| 1634 | bt->polarities, aspect_ratio, timings)) | ||
| 1635 | return true; | ||
| 1636 | } | ||
| 1637 | return false; | ||
| 1638 | } | ||
| 1639 | |||
| 1555 | int vivid_vid_cap_s_dv_timings(struct file *file, void *_fh, | 1640 | int vivid_vid_cap_s_dv_timings(struct file *file, void *_fh, |
| 1556 | struct v4l2_dv_timings *timings) | 1641 | struct v4l2_dv_timings *timings) |
| 1557 | { | 1642 | { |
| @@ -1559,13 +1644,16 @@ int vivid_vid_cap_s_dv_timings(struct file *file, void *_fh, | |||
| 1559 | 1644 | ||
| 1560 | if (!vivid_is_hdmi_cap(dev)) | 1645 | if (!vivid_is_hdmi_cap(dev)) |
| 1561 | return -ENODATA; | 1646 | return -ENODATA; |
| 1562 | if (vb2_is_busy(&dev->vb_vid_cap_q)) | ||
| 1563 | return -EBUSY; | ||
| 1564 | if (!v4l2_find_dv_timings_cap(timings, &vivid_dv_timings_cap, | 1647 | if (!v4l2_find_dv_timings_cap(timings, &vivid_dv_timings_cap, |
| 1565 | 0, NULL, NULL)) | 1648 | 0, NULL, NULL) && |
| 1649 | !valid_cvt_gtf_timings(timings)) | ||
| 1566 | return -EINVAL; | 1650 | return -EINVAL; |
| 1651 | |||
| 1567 | if (v4l2_match_dv_timings(timings, &dev->dv_timings_cap, 0)) | 1652 | if (v4l2_match_dv_timings(timings, &dev->dv_timings_cap, 0)) |
| 1568 | return 0; | 1653 | return 0; |
| 1654 | if (vb2_is_busy(&dev->vb_vid_cap_q)) | ||
| 1655 | return -EBUSY; | ||
| 1656 | |||
| 1569 | dev->dv_timings_cap = *timings; | 1657 | dev->dv_timings_cap = *timings; |
| 1570 | vivid_update_format_cap(dev, false); | 1658 | vivid_update_format_cap(dev, false); |
| 1571 | return 0; | 1659 | return 0; |
| @@ -1663,18 +1751,14 @@ int vidioc_enum_frameintervals(struct file *file, void *priv, | |||
| 1663 | return -EINVAL; | 1751 | return -EINVAL; |
| 1664 | 1752 | ||
| 1665 | if (!vivid_is_webcam(dev)) { | 1753 | if (!vivid_is_webcam(dev)) { |
| 1666 | static const struct v4l2_fract step = { 1, 1 }; | ||
| 1667 | |||
| 1668 | if (fival->index) | 1754 | if (fival->index) |
| 1669 | return -EINVAL; | 1755 | return -EINVAL; |
| 1670 | if (fival->width < MIN_WIDTH || fival->width > MAX_WIDTH * MAX_ZOOM) | 1756 | if (fival->width < MIN_WIDTH || fival->width > MAX_WIDTH * MAX_ZOOM) |
| 1671 | return -EINVAL; | 1757 | return -EINVAL; |
| 1672 | if (fival->height < MIN_HEIGHT || fival->height > MAX_HEIGHT * MAX_ZOOM) | 1758 | if (fival->height < MIN_HEIGHT || fival->height > MAX_HEIGHT * MAX_ZOOM) |
| 1673 | return -EINVAL; | 1759 | return -EINVAL; |
| 1674 | fival->type = V4L2_FRMIVAL_TYPE_CONTINUOUS; | 1760 | fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; |
| 1675 | fival->stepwise.min = tpf_min; | 1761 | fival->discrete = dev->timeperframe_vid_cap; |
| 1676 | fival->stepwise.max = tpf_max; | ||
| 1677 | fival->stepwise.step = step; | ||
| 1678 | return 0; | 1762 | return 0; |
| 1679 | } | 1763 | } |
| 1680 | 1764 | ||
diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c index 6bef1e6d6788..aa446271ad34 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.c +++ b/drivers/media/platform/vivid/vivid-vid-common.c | |||
| @@ -33,8 +33,9 @@ const struct v4l2_dv_timings_cap vivid_dv_timings_cap = { | |||
| 33 | .type = V4L2_DV_BT_656_1120, | 33 | .type = V4L2_DV_BT_656_1120, |
| 34 | /* keep this initialization for compatibility with GCC < 4.4.6 */ | 34 | /* keep this initialization for compatibility with GCC < 4.4.6 */ |
| 35 | .reserved = { 0 }, | 35 | .reserved = { 0 }, |
| 36 | V4L2_INIT_BT_TIMINGS(0, MAX_WIDTH, 0, MAX_HEIGHT, 25000000, 600000000, | 36 | V4L2_INIT_BT_TIMINGS(0, MAX_WIDTH, 0, MAX_HEIGHT, 14000000, 775000000, |
| 37 | V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT, | 37 | V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT | |
| 38 | V4L2_DV_BT_STD_CVT | V4L2_DV_BT_STD_GTF, | ||
| 38 | V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_INTERLACED) | 39 | V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_INTERLACED) |
| 39 | }; | 40 | }; |
| 40 | 41 | ||
| @@ -46,145 +47,435 @@ struct vivid_fmt vivid_formats[] = { | |||
| 46 | { | 47 | { |
| 47 | .name = "4:2:2, packed, YUYV", | 48 | .name = "4:2:2, packed, YUYV", |
| 48 | .fourcc = V4L2_PIX_FMT_YUYV, | 49 | .fourcc = V4L2_PIX_FMT_YUYV, |
| 49 | .depth = 16, | 50 | .vdownsampling = { 1 }, |
| 51 | .bit_depth = { 16 }, | ||
| 50 | .is_yuv = true, | 52 | .is_yuv = true, |
| 51 | .planes = 1, | 53 | .planes = 1, |
| 52 | .data_offset = { PLANE0_DATA_OFFSET, 0 }, | 54 | .buffers = 1, |
| 55 | .data_offset = { PLANE0_DATA_OFFSET }, | ||
| 53 | }, | 56 | }, |
| 54 | { | 57 | { |
| 55 | .name = "4:2:2, packed, UYVY", | 58 | .name = "4:2:2, packed, UYVY", |
| 56 | .fourcc = V4L2_PIX_FMT_UYVY, | 59 | .fourcc = V4L2_PIX_FMT_UYVY, |
| 57 | .depth = 16, | 60 | .vdownsampling = { 1 }, |
| 61 | .bit_depth = { 16 }, | ||
| 58 | .is_yuv = true, | 62 | .is_yuv = true, |
| 59 | .planes = 1, | 63 | .planes = 1, |
| 64 | .buffers = 1, | ||
| 60 | }, | 65 | }, |
| 61 | { | 66 | { |
| 62 | .name = "4:2:2, packed, YVYU", | 67 | .name = "4:2:2, packed, YVYU", |
| 63 | .fourcc = V4L2_PIX_FMT_YVYU, | 68 | .fourcc = V4L2_PIX_FMT_YVYU, |
| 64 | .depth = 16, | 69 | .vdownsampling = { 1 }, |
| 70 | .bit_depth = { 16 }, | ||
| 65 | .is_yuv = true, | 71 | .is_yuv = true, |
| 66 | .planes = 1, | 72 | .planes = 1, |
| 73 | .buffers = 1, | ||
| 67 | }, | 74 | }, |
| 68 | { | 75 | { |
| 69 | .name = "4:2:2, packed, VYUY", | 76 | .name = "4:2:2, packed, VYUY", |
| 70 | .fourcc = V4L2_PIX_FMT_VYUY, | 77 | .fourcc = V4L2_PIX_FMT_VYUY, |
| 71 | .depth = 16, | 78 | .vdownsampling = { 1 }, |
| 79 | .bit_depth = { 16 }, | ||
| 80 | .is_yuv = true, | ||
| 81 | .planes = 1, | ||
| 82 | .buffers = 1, | ||
| 83 | }, | ||
| 84 | { | ||
| 85 | .name = "YUV 4:2:2 triplanar", | ||
| 86 | .fourcc = V4L2_PIX_FMT_YUV422P, | ||
| 87 | .vdownsampling = { 1, 1, 1 }, | ||
| 88 | .bit_depth = { 8, 4, 4 }, | ||
| 89 | .is_yuv = true, | ||
| 90 | .planes = 3, | ||
| 91 | .buffers = 1, | ||
| 92 | }, | ||
| 93 | { | ||
| 94 | .name = "YUV 4:2:0 triplanar", | ||
| 95 | .fourcc = V4L2_PIX_FMT_YUV420, | ||
| 96 | .vdownsampling = { 1, 2, 2 }, | ||
| 97 | .bit_depth = { 8, 4, 4 }, | ||
| 98 | .is_yuv = true, | ||
| 99 | .planes = 3, | ||
| 100 | .buffers = 1, | ||
| 101 | }, | ||
| 102 | { | ||
| 103 | .name = "YVU 4:2:0 triplanar", | ||
| 104 | .fourcc = V4L2_PIX_FMT_YVU420, | ||
| 105 | .vdownsampling = { 1, 2, 2 }, | ||
| 106 | .bit_depth = { 8, 4, 4 }, | ||
| 107 | .is_yuv = true, | ||
| 108 | .planes = 3, | ||
| 109 | .buffers = 1, | ||
| 110 | }, | ||
| 111 | { | ||
| 112 | .name = "YUV 4:2:0 biplanar", | ||
| 113 | .fourcc = V4L2_PIX_FMT_NV12, | ||
| 114 | .vdownsampling = { 1, 2 }, | ||
| 115 | .bit_depth = { 8, 8 }, | ||
| 116 | .is_yuv = true, | ||
| 117 | .planes = 2, | ||
| 118 | .buffers = 1, | ||
| 119 | }, | ||
| 120 | { | ||
| 121 | .name = "YVU 4:2:0 biplanar", | ||
| 122 | .fourcc = V4L2_PIX_FMT_NV21, | ||
| 123 | .vdownsampling = { 1, 2 }, | ||
| 124 | .bit_depth = { 8, 8 }, | ||
| 125 | .is_yuv = true, | ||
| 126 | .planes = 2, | ||
| 127 | .buffers = 1, | ||
| 128 | }, | ||
| 129 | { | ||
| 130 | .name = "YUV 4:2:2 biplanar", | ||
| 131 | .fourcc = V4L2_PIX_FMT_NV16, | ||
| 132 | .vdownsampling = { 1, 1 }, | ||
| 133 | .bit_depth = { 8, 8 }, | ||
| 134 | .is_yuv = true, | ||
| 135 | .planes = 2, | ||
| 136 | .buffers = 1, | ||
| 137 | }, | ||
| 138 | { | ||
| 139 | .name = "YVU 4:2:2 biplanar", | ||
| 140 | .fourcc = V4L2_PIX_FMT_NV61, | ||
| 141 | .vdownsampling = { 1, 1 }, | ||
| 142 | .bit_depth = { 8, 8 }, | ||
| 143 | .is_yuv = true, | ||
| 144 | .planes = 2, | ||
| 145 | .buffers = 1, | ||
| 146 | }, | ||
| 147 | { | ||
| 148 | .name = "YUV 4:4:4 biplanar", | ||
| 149 | .fourcc = V4L2_PIX_FMT_NV24, | ||
| 150 | .vdownsampling = { 1, 1 }, | ||
| 151 | .bit_depth = { 8, 16 }, | ||
| 152 | .is_yuv = true, | ||
| 153 | .planes = 2, | ||
| 154 | .buffers = 1, | ||
| 155 | }, | ||
| 156 | { | ||
| 157 | .name = "YVU 4:4:4 biplanar", | ||
| 158 | .fourcc = V4L2_PIX_FMT_NV42, | ||
| 159 | .vdownsampling = { 1, 1 }, | ||
| 160 | .bit_depth = { 8, 16 }, | ||
| 161 | .is_yuv = true, | ||
| 162 | .planes = 2, | ||
| 163 | .buffers = 1, | ||
| 164 | }, | ||
| 165 | { | ||
| 166 | .name = "YUV555 (LE)", | ||
| 167 | .fourcc = V4L2_PIX_FMT_YUV555, /* uuuvvvvv ayyyyyuu */ | ||
| 168 | .vdownsampling = { 1 }, | ||
| 169 | .bit_depth = { 16 }, | ||
| 170 | .planes = 1, | ||
| 171 | .buffers = 1, | ||
| 172 | .alpha_mask = 0x8000, | ||
| 173 | }, | ||
| 174 | { | ||
| 175 | .name = "YUV565 (LE)", | ||
| 176 | .fourcc = V4L2_PIX_FMT_YUV565, /* uuuvvvvv yyyyyuuu */ | ||
| 177 | .vdownsampling = { 1 }, | ||
| 178 | .bit_depth = { 16 }, | ||
| 179 | .planes = 1, | ||
| 180 | .buffers = 1, | ||
| 181 | }, | ||
| 182 | { | ||
| 183 | .name = "YUV444", | ||
| 184 | .fourcc = V4L2_PIX_FMT_YUV444, /* uuuuvvvv aaaayyyy */ | ||
| 185 | .vdownsampling = { 1 }, | ||
| 186 | .bit_depth = { 16 }, | ||
| 187 | .planes = 1, | ||
| 188 | .buffers = 1, | ||
| 189 | .alpha_mask = 0xf000, | ||
| 190 | }, | ||
| 191 | { | ||
| 192 | .name = "YUV32 (LE)", | ||
| 193 | .fourcc = V4L2_PIX_FMT_YUV32, /* ayuv */ | ||
| 194 | .vdownsampling = { 1 }, | ||
| 195 | .bit_depth = { 32 }, | ||
| 196 | .planes = 1, | ||
| 197 | .buffers = 1, | ||
| 198 | .alpha_mask = 0x000000ff, | ||
| 199 | }, | ||
| 200 | { | ||
| 201 | .name = "Monochrome", | ||
| 202 | .fourcc = V4L2_PIX_FMT_GREY, | ||
| 203 | .vdownsampling = { 1 }, | ||
| 204 | .bit_depth = { 8 }, | ||
| 72 | .is_yuv = true, | 205 | .is_yuv = true, |
| 73 | .planes = 1, | 206 | .planes = 1, |
| 207 | .buffers = 1, | ||
| 208 | }, | ||
| 209 | { | ||
| 210 | .name = "RGB332", | ||
| 211 | .fourcc = V4L2_PIX_FMT_RGB332, /* rrrgggbb */ | ||
| 212 | .vdownsampling = { 1 }, | ||
| 213 | .bit_depth = { 8 }, | ||
| 214 | .planes = 1, | ||
| 215 | .buffers = 1, | ||
| 74 | }, | 216 | }, |
| 75 | { | 217 | { |
| 76 | .name = "RGB565 (LE)", | 218 | .name = "RGB565 (LE)", |
| 77 | .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */ | 219 | .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */ |
| 78 | .depth = 16, | 220 | .vdownsampling = { 1 }, |
| 221 | .bit_depth = { 16 }, | ||
| 79 | .planes = 1, | 222 | .planes = 1, |
| 223 | .buffers = 1, | ||
| 80 | .can_do_overlay = true, | 224 | .can_do_overlay = true, |
| 81 | }, | 225 | }, |
| 82 | { | 226 | { |
| 83 | .name = "RGB565 (BE)", | 227 | .name = "RGB565 (BE)", |
| 84 | .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */ | 228 | .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */ |
| 85 | .depth = 16, | 229 | .vdownsampling = { 1 }, |
| 230 | .bit_depth = { 16 }, | ||
| 86 | .planes = 1, | 231 | .planes = 1, |
| 232 | .buffers = 1, | ||
| 87 | .can_do_overlay = true, | 233 | .can_do_overlay = true, |
| 88 | }, | 234 | }, |
| 89 | { | 235 | { |
| 236 | .name = "RGB444", | ||
| 237 | .fourcc = V4L2_PIX_FMT_RGB444, /* xxxxrrrr ggggbbbb */ | ||
| 238 | .vdownsampling = { 1 }, | ||
| 239 | .bit_depth = { 16 }, | ||
| 240 | .planes = 1, | ||
| 241 | .buffers = 1, | ||
| 242 | }, | ||
| 243 | { | ||
| 244 | .name = "XRGB444", | ||
| 245 | .fourcc = V4L2_PIX_FMT_XRGB444, /* xxxxrrrr ggggbbbb */ | ||
| 246 | .vdownsampling = { 1 }, | ||
| 247 | .bit_depth = { 16 }, | ||
| 248 | .planes = 1, | ||
| 249 | .buffers = 1, | ||
| 250 | }, | ||
| 251 | { | ||
| 252 | .name = "ARGB444", | ||
| 253 | .fourcc = V4L2_PIX_FMT_ARGB444, /* aaaarrrr ggggbbbb */ | ||
| 254 | .vdownsampling = { 1 }, | ||
| 255 | .bit_depth = { 16 }, | ||
| 256 | .planes = 1, | ||
| 257 | .buffers = 1, | ||
| 258 | .alpha_mask = 0x00f0, | ||
| 259 | }, | ||
| 260 | { | ||
| 90 | .name = "RGB555 (LE)", | 261 | .name = "RGB555 (LE)", |
| 91 | .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */ | 262 | .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb xrrrrrgg */ |
| 92 | .depth = 16, | 263 | .vdownsampling = { 1 }, |
| 264 | .bit_depth = { 16 }, | ||
| 93 | .planes = 1, | 265 | .planes = 1, |
| 266 | .buffers = 1, | ||
| 94 | .can_do_overlay = true, | 267 | .can_do_overlay = true, |
| 95 | }, | 268 | }, |
| 96 | { | 269 | { |
| 97 | .name = "XRGB555 (LE)", | 270 | .name = "XRGB555 (LE)", |
| 98 | .fourcc = V4L2_PIX_FMT_XRGB555, /* gggbbbbb arrrrrgg */ | 271 | .fourcc = V4L2_PIX_FMT_XRGB555, /* gggbbbbb xrrrrrgg */ |
| 99 | .depth = 16, | 272 | .vdownsampling = { 1 }, |
| 273 | .bit_depth = { 16 }, | ||
| 100 | .planes = 1, | 274 | .planes = 1, |
| 275 | .buffers = 1, | ||
| 101 | .can_do_overlay = true, | 276 | .can_do_overlay = true, |
| 102 | }, | 277 | }, |
| 103 | { | 278 | { |
| 104 | .name = "ARGB555 (LE)", | 279 | .name = "ARGB555 (LE)", |
| 105 | .fourcc = V4L2_PIX_FMT_ARGB555, /* gggbbbbb arrrrrgg */ | 280 | .fourcc = V4L2_PIX_FMT_ARGB555, /* gggbbbbb arrrrrgg */ |
| 106 | .depth = 16, | 281 | .vdownsampling = { 1 }, |
| 282 | .bit_depth = { 16 }, | ||
| 107 | .planes = 1, | 283 | .planes = 1, |
| 284 | .buffers = 1, | ||
| 108 | .can_do_overlay = true, | 285 | .can_do_overlay = true, |
| 109 | .alpha_mask = 0x8000, | 286 | .alpha_mask = 0x8000, |
| 110 | }, | 287 | }, |
| 111 | { | 288 | { |
| 112 | .name = "RGB555 (BE)", | 289 | .name = "RGB555 (BE)", |
| 113 | .fourcc = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */ | 290 | .fourcc = V4L2_PIX_FMT_RGB555X, /* xrrrrrgg gggbbbbb */ |
| 114 | .depth = 16, | 291 | .vdownsampling = { 1 }, |
| 292 | .bit_depth = { 16 }, | ||
| 115 | .planes = 1, | 293 | .planes = 1, |
| 116 | .can_do_overlay = true, | 294 | .buffers = 1, |
| 295 | }, | ||
| 296 | { | ||
| 297 | .name = "XRGB555 (BE)", | ||
| 298 | .fourcc = V4L2_PIX_FMT_XRGB555X, /* xrrrrrgg gggbbbbb */ | ||
| 299 | .vdownsampling = { 1 }, | ||
| 300 | .bit_depth = { 16 }, | ||
| 301 | .planes = 1, | ||
| 302 | .buffers = 1, | ||
| 303 | }, | ||
| 304 | { | ||
| 305 | .name = "ARGB555 (BE)", | ||
| 306 | .fourcc = V4L2_PIX_FMT_ARGB555X, /* arrrrrgg gggbbbbb */ | ||
| 307 | .vdownsampling = { 1 }, | ||
| 308 | .bit_depth = { 16 }, | ||
| 309 | .planes = 1, | ||
| 310 | .buffers = 1, | ||
| 311 | .alpha_mask = 0x0080, | ||
| 117 | }, | 312 | }, |
| 118 | { | 313 | { |
| 119 | .name = "RGB24 (LE)", | 314 | .name = "RGB24 (LE)", |
| 120 | .fourcc = V4L2_PIX_FMT_RGB24, /* rgb */ | 315 | .fourcc = V4L2_PIX_FMT_RGB24, /* rgb */ |
| 121 | .depth = 24, | 316 | .vdownsampling = { 1 }, |
| 317 | .bit_depth = { 24 }, | ||
| 122 | .planes = 1, | 318 | .planes = 1, |
| 319 | .buffers = 1, | ||
| 123 | }, | 320 | }, |
| 124 | { | 321 | { |
| 125 | .name = "RGB24 (BE)", | 322 | .name = "RGB24 (BE)", |
| 126 | .fourcc = V4L2_PIX_FMT_BGR24, /* bgr */ | 323 | .fourcc = V4L2_PIX_FMT_BGR24, /* bgr */ |
| 127 | .depth = 24, | 324 | .vdownsampling = { 1 }, |
| 325 | .bit_depth = { 24 }, | ||
| 128 | .planes = 1, | 326 | .planes = 1, |
| 327 | .buffers = 1, | ||
| 328 | }, | ||
| 329 | { | ||
| 330 | .name = "BGR666", | ||
| 331 | .fourcc = V4L2_PIX_FMT_BGR666, /* bbbbbbgg ggggrrrr rrxxxxxx */ | ||
| 332 | .vdownsampling = { 1 }, | ||
| 333 | .bit_depth = { 32 }, | ||
| 334 | .planes = 1, | ||
| 335 | .buffers = 1, | ||
| 129 | }, | 336 | }, |
| 130 | { | 337 | { |
| 131 | .name = "RGB32 (LE)", | 338 | .name = "RGB32 (LE)", |
| 132 | .fourcc = V4L2_PIX_FMT_RGB32, /* argb */ | 339 | .fourcc = V4L2_PIX_FMT_RGB32, /* xrgb */ |
| 133 | .depth = 32, | 340 | .vdownsampling = { 1 }, |
| 341 | .bit_depth = { 32 }, | ||
| 134 | .planes = 1, | 342 | .planes = 1, |
| 343 | .buffers = 1, | ||
| 135 | }, | 344 | }, |
| 136 | { | 345 | { |
| 137 | .name = "RGB32 (BE)", | 346 | .name = "RGB32 (BE)", |
| 138 | .fourcc = V4L2_PIX_FMT_BGR32, /* bgra */ | 347 | .fourcc = V4L2_PIX_FMT_BGR32, /* bgrx */ |
| 139 | .depth = 32, | 348 | .vdownsampling = { 1 }, |
| 349 | .bit_depth = { 32 }, | ||
| 140 | .planes = 1, | 350 | .planes = 1, |
| 351 | .buffers = 1, | ||
| 141 | }, | 352 | }, |
| 142 | { | 353 | { |
| 143 | .name = "XRGB32 (LE)", | 354 | .name = "XRGB32 (LE)", |
| 144 | .fourcc = V4L2_PIX_FMT_XRGB32, /* argb */ | 355 | .fourcc = V4L2_PIX_FMT_XRGB32, /* xrgb */ |
| 145 | .depth = 32, | 356 | .vdownsampling = { 1 }, |
| 357 | .bit_depth = { 32 }, | ||
| 146 | .planes = 1, | 358 | .planes = 1, |
| 359 | .buffers = 1, | ||
| 147 | }, | 360 | }, |
| 148 | { | 361 | { |
| 149 | .name = "XRGB32 (BE)", | 362 | .name = "XRGB32 (BE)", |
| 150 | .fourcc = V4L2_PIX_FMT_XBGR32, /* bgra */ | 363 | .fourcc = V4L2_PIX_FMT_XBGR32, /* bgrx */ |
| 151 | .depth = 32, | 364 | .vdownsampling = { 1 }, |
| 365 | .bit_depth = { 32 }, | ||
| 152 | .planes = 1, | 366 | .planes = 1, |
| 367 | .buffers = 1, | ||
| 153 | }, | 368 | }, |
| 154 | { | 369 | { |
| 155 | .name = "ARGB32 (LE)", | 370 | .name = "ARGB32 (LE)", |
| 156 | .fourcc = V4L2_PIX_FMT_ARGB32, /* argb */ | 371 | .fourcc = V4L2_PIX_FMT_ARGB32, /* argb */ |
| 157 | .depth = 32, | 372 | .vdownsampling = { 1 }, |
| 373 | .bit_depth = { 32 }, | ||
| 158 | .planes = 1, | 374 | .planes = 1, |
| 375 | .buffers = 1, | ||
| 159 | .alpha_mask = 0x000000ff, | 376 | .alpha_mask = 0x000000ff, |
| 160 | }, | 377 | }, |
| 161 | { | 378 | { |
| 162 | .name = "ARGB32 (BE)", | 379 | .name = "ARGB32 (BE)", |
| 163 | .fourcc = V4L2_PIX_FMT_ABGR32, /* bgra */ | 380 | .fourcc = V4L2_PIX_FMT_ABGR32, /* bgra */ |
| 164 | .depth = 32, | 381 | .vdownsampling = { 1 }, |
| 382 | .bit_depth = { 32 }, | ||
| 165 | .planes = 1, | 383 | .planes = 1, |
| 384 | .buffers = 1, | ||
| 166 | .alpha_mask = 0xff000000, | 385 | .alpha_mask = 0xff000000, |
| 167 | }, | 386 | }, |
| 168 | { | 387 | { |
| 169 | .name = "4:2:2, planar, YUV", | 388 | .name = "Bayer BG/GR", |
| 389 | .fourcc = V4L2_PIX_FMT_SBGGR8, /* Bayer BG/GR */ | ||
| 390 | .vdownsampling = { 1 }, | ||
| 391 | .bit_depth = { 8 }, | ||
| 392 | .planes = 1, | ||
| 393 | .buffers = 1, | ||
| 394 | }, | ||
| 395 | { | ||
| 396 | .name = "Bayer GB/RG", | ||
| 397 | .fourcc = V4L2_PIX_FMT_SGBRG8, /* Bayer GB/RG */ | ||
| 398 | .vdownsampling = { 1 }, | ||
| 399 | .bit_depth = { 8 }, | ||
| 400 | .planes = 1, | ||
| 401 | .buffers = 1, | ||
| 402 | }, | ||
| 403 | { | ||
| 404 | .name = "Bayer GR/BG", | ||
| 405 | .fourcc = V4L2_PIX_FMT_SGRBG8, /* Bayer GR/BG */ | ||
| 406 | .vdownsampling = { 1 }, | ||
| 407 | .bit_depth = { 8 }, | ||
| 408 | .planes = 1, | ||
| 409 | .buffers = 1, | ||
| 410 | }, | ||
| 411 | { | ||
| 412 | .name = "Bayer RG/GB", | ||
| 413 | .fourcc = V4L2_PIX_FMT_SRGGB8, /* Bayer RG/GB */ | ||
| 414 | .vdownsampling = { 1 }, | ||
| 415 | .bit_depth = { 8 }, | ||
| 416 | .planes = 1, | ||
| 417 | .buffers = 1, | ||
| 418 | }, | ||
| 419 | { | ||
| 420 | .name = "4:2:2, biplanar, YUV", | ||
| 170 | .fourcc = V4L2_PIX_FMT_NV16M, | 421 | .fourcc = V4L2_PIX_FMT_NV16M, |
| 171 | .depth = 8, | 422 | .vdownsampling = { 1, 1 }, |
| 423 | .bit_depth = { 8, 8 }, | ||
| 172 | .is_yuv = true, | 424 | .is_yuv = true, |
| 173 | .planes = 2, | 425 | .planes = 2, |
| 426 | .buffers = 2, | ||
| 174 | .data_offset = { PLANE0_DATA_OFFSET, 0 }, | 427 | .data_offset = { PLANE0_DATA_OFFSET, 0 }, |
| 175 | }, | 428 | }, |
| 176 | { | 429 | { |
| 177 | .name = "4:2:2, planar, YVU", | 430 | .name = "4:2:2, biplanar, YVU", |
| 178 | .fourcc = V4L2_PIX_FMT_NV61M, | 431 | .fourcc = V4L2_PIX_FMT_NV61M, |
| 179 | .depth = 8, | 432 | .vdownsampling = { 1, 1 }, |
| 433 | .bit_depth = { 8, 8 }, | ||
| 180 | .is_yuv = true, | 434 | .is_yuv = true, |
| 181 | .planes = 2, | 435 | .planes = 2, |
| 436 | .buffers = 2, | ||
| 182 | .data_offset = { 0, PLANE0_DATA_OFFSET }, | 437 | .data_offset = { 0, PLANE0_DATA_OFFSET }, |
| 183 | }, | 438 | }, |
| 439 | { | ||
| 440 | .name = "4:2:0, triplanar, YUV", | ||
| 441 | .fourcc = V4L2_PIX_FMT_YUV420M, | ||
| 442 | .vdownsampling = { 1, 2, 2 }, | ||
| 443 | .bit_depth = { 8, 4, 4 }, | ||
| 444 | .is_yuv = true, | ||
| 445 | .planes = 3, | ||
| 446 | .buffers = 3, | ||
| 447 | }, | ||
| 448 | { | ||
| 449 | .name = "4:2:0, triplanar, YVU", | ||
| 450 | .fourcc = V4L2_PIX_FMT_YVU420M, | ||
| 451 | .vdownsampling = { 1, 2, 2 }, | ||
| 452 | .bit_depth = { 8, 4, 4 }, | ||
| 453 | .is_yuv = true, | ||
| 454 | .planes = 3, | ||
| 455 | .buffers = 3, | ||
| 456 | }, | ||
| 457 | { | ||
| 458 | .name = "4:2:0, biplanar, YUV", | ||
| 459 | .fourcc = V4L2_PIX_FMT_NV12M, | ||
| 460 | .vdownsampling = { 1, 2 }, | ||
| 461 | .bit_depth = { 8, 8 }, | ||
| 462 | .is_yuv = true, | ||
| 463 | .planes = 2, | ||
| 464 | .buffers = 2, | ||
| 465 | }, | ||
| 466 | { | ||
| 467 | .name = "4:2:0, biplanar, YVU", | ||
| 468 | .fourcc = V4L2_PIX_FMT_NV21M, | ||
| 469 | .vdownsampling = { 1, 2 }, | ||
| 470 | .bit_depth = { 8, 8 }, | ||
| 471 | .is_yuv = true, | ||
| 472 | .planes = 2, | ||
| 473 | .buffers = 2, | ||
| 474 | }, | ||
| 184 | }; | 475 | }; |
| 185 | 476 | ||
| 186 | /* There are 2 multiplanar formats in the list */ | 477 | /* There are 6 multiplanar formats in the list */ |
| 187 | #define VIVID_MPLANAR_FORMATS 2 | 478 | #define VIVID_MPLANAR_FORMATS 6 |
| 188 | 479 | ||
| 189 | const struct vivid_fmt *vivid_get_format(struct vivid_dev *dev, u32 pixelformat) | 480 | const struct vivid_fmt *vivid_get_format(struct vivid_dev *dev, u32 pixelformat) |
| 190 | { | 481 | { |
| @@ -194,7 +485,7 @@ const struct vivid_fmt *vivid_get_format(struct vivid_dev *dev, u32 pixelformat) | |||
| 194 | for (k = 0; k < ARRAY_SIZE(vivid_formats); k++) { | 485 | for (k = 0; k < ARRAY_SIZE(vivid_formats); k++) { |
| 195 | fmt = &vivid_formats[k]; | 486 | fmt = &vivid_formats[k]; |
| 196 | if (fmt->fourcc == pixelformat) | 487 | if (fmt->fourcc == pixelformat) |
| 197 | if (fmt->planes == 1 || dev->multiplanar) | 488 | if (fmt->buffers == 1 || dev->multiplanar) |
| 198 | return fmt; | 489 | return fmt; |
| 199 | } | 490 | } |
| 200 | 491 | ||
| @@ -210,6 +501,13 @@ bool vivid_vid_can_loop(struct vivid_dev *dev) | |||
| 210 | return false; | 501 | return false; |
| 211 | if (dev->field_cap != dev->field_out) | 502 | if (dev->field_cap != dev->field_out) |
| 212 | return false; | 503 | return false; |
| 504 | /* | ||
| 505 | * While this can be supported, it is just too much work | ||
| 506 | * to actually implement. | ||
| 507 | */ | ||
| 508 | if (dev->field_cap == V4L2_FIELD_SEQ_TB || | ||
| 509 | dev->field_cap == V4L2_FIELD_SEQ_BT) | ||
| 510 | return false; | ||
| 213 | if (vivid_is_svid_cap(dev) && vivid_is_svid_out(dev)) { | 511 | if (vivid_is_svid_cap(dev) && vivid_is_svid_out(dev)) { |
| 214 | if (!(dev->std_cap & V4L2_STD_525_60) != | 512 | if (!(dev->std_cap & V4L2_STD_525_60) != |
| 215 | !(dev->std_out & V4L2_STD_525_60)) | 513 | !(dev->std_out & V4L2_STD_525_60)) |
| @@ -397,6 +695,9 @@ int vivid_vid_adjust_sel(unsigned flags, struct v4l2_rect *r) | |||
| 397 | unsigned w = r->width; | 695 | unsigned w = r->width; |
| 398 | unsigned h = r->height; | 696 | unsigned h = r->height; |
| 399 | 697 | ||
| 698 | /* sanitize w and h in case someone passes ~0 as the value */ | ||
| 699 | w &= 0xffff; | ||
| 700 | h &= 0xffff; | ||
| 400 | if (!(flags & V4L2_SEL_FLAG_LE)) { | 701 | if (!(flags & V4L2_SEL_FLAG_LE)) { |
| 401 | w++; | 702 | w++; |
| 402 | h++; | 703 | h++; |
| @@ -421,8 +722,9 @@ int vivid_vid_adjust_sel(unsigned flags, struct v4l2_rect *r) | |||
| 421 | r->top = 0; | 722 | r->top = 0; |
| 422 | if (r->left < 0) | 723 | if (r->left < 0) |
| 423 | r->left = 0; | 724 | r->left = 0; |
| 424 | r->left &= ~1; | 725 | /* sanitize left and top in case someone passes ~0 as the value */ |
| 425 | r->top &= ~1; | 726 | r->left &= 0xfffe; |
| 727 | r->top &= 0xfffe; | ||
| 426 | if (r->left + w > MAX_WIDTH) | 728 | if (r->left + w > MAX_WIDTH) |
| 427 | r->left = MAX_WIDTH - w; | 729 | r->left = MAX_WIDTH - w; |
| 428 | if (r->top + h > MAX_HEIGHT) | 730 | if (r->top + h > MAX_HEIGHT) |
diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c index 39ff79f6aa67..0af43dc7715c 100644 --- a/drivers/media/platform/vivid/vivid-vid-out.c +++ b/drivers/media/platform/vivid/vivid-vid-out.c | |||
| @@ -36,9 +36,14 @@ static int vid_out_queue_setup(struct vb2_queue *vq, const struct v4l2_format *f | |||
| 36 | unsigned sizes[], void *alloc_ctxs[]) | 36 | unsigned sizes[], void *alloc_ctxs[]) |
| 37 | { | 37 | { |
| 38 | struct vivid_dev *dev = vb2_get_drv_priv(vq); | 38 | struct vivid_dev *dev = vb2_get_drv_priv(vq); |
| 39 | unsigned planes = dev->fmt_out->planes; | 39 | const struct vivid_fmt *vfmt = dev->fmt_out; |
| 40 | unsigned planes = vfmt->buffers; | ||
| 40 | unsigned h = dev->fmt_out_rect.height; | 41 | unsigned h = dev->fmt_out_rect.height; |
| 41 | unsigned size = dev->bytesperline_out[0] * h; | 42 | unsigned size = dev->bytesperline_out[0] * h; |
| 43 | unsigned p; | ||
| 44 | |||
| 45 | for (p = vfmt->buffers; p < vfmt->planes; p++) | ||
| 46 | size += dev->bytesperline_out[p] * h / vfmt->vdownsampling[p]; | ||
| 42 | 47 | ||
| 43 | if (dev->field_out == V4L2_FIELD_ALTERNATE) { | 48 | if (dev->field_out == V4L2_FIELD_ALTERNATE) { |
| 44 | /* | 49 | /* |
| @@ -74,21 +79,16 @@ static int vid_out_queue_setup(struct vb2_queue *vq, const struct v4l2_format *f | |||
| 74 | if (mp->num_planes != planes) | 79 | if (mp->num_planes != planes) |
| 75 | return -EINVAL; | 80 | return -EINVAL; |
| 76 | sizes[0] = mp->plane_fmt[0].sizeimage; | 81 | sizes[0] = mp->plane_fmt[0].sizeimage; |
| 77 | if (planes == 2) { | 82 | if (sizes[0] < size) |
| 78 | sizes[1] = mp->plane_fmt[1].sizeimage; | ||
| 79 | if (sizes[0] < dev->bytesperline_out[0] * h || | ||
| 80 | sizes[1] < dev->bytesperline_out[1] * h) | ||
| 81 | return -EINVAL; | ||
| 82 | } else if (sizes[0] < size) { | ||
| 83 | return -EINVAL; | 83 | return -EINVAL; |
| 84 | for (p = 1; p < planes; p++) { | ||
| 85 | sizes[p] = mp->plane_fmt[p].sizeimage; | ||
| 86 | if (sizes[p] < dev->bytesperline_out[p] * h) | ||
| 87 | return -EINVAL; | ||
| 84 | } | 88 | } |
| 85 | } else { | 89 | } else { |
| 86 | if (planes == 2) { | 90 | for (p = 0; p < planes; p++) |
| 87 | sizes[0] = dev->bytesperline_out[0] * h; | 91 | sizes[p] = p ? dev->bytesperline_out[p] * h : size; |
| 88 | sizes[1] = dev->bytesperline_out[1] * h; | ||
| 89 | } else { | ||
| 90 | sizes[0] = size; | ||
| 91 | } | ||
| 92 | } | 92 | } |
| 93 | 93 | ||
| 94 | if (vq->num_buffers + *nbuffers < 2) | 94 | if (vq->num_buffers + *nbuffers < 2) |
| @@ -101,12 +101,9 @@ static int vid_out_queue_setup(struct vb2_queue *vq, const struct v4l2_format *f | |||
| 101 | * alloc_ctxs array. | 101 | * alloc_ctxs array. |
| 102 | */ | 102 | */ |
| 103 | 103 | ||
| 104 | if (planes == 2) | 104 | dprintk(dev, 1, "%s: count=%d\n", __func__, *nbuffers); |
| 105 | dprintk(dev, 1, "%s, count=%d, sizes=%u, %u\n", __func__, | 105 | for (p = 0; p < planes; p++) |
| 106 | *nbuffers, sizes[0], sizes[1]); | 106 | dprintk(dev, 1, "%s: size[%u]=%u\n", __func__, p, sizes[p]); |
| 107 | else | ||
| 108 | dprintk(dev, 1, "%s, count=%d, size=%u\n", __func__, | ||
| 109 | *nbuffers, sizes[0]); | ||
| 110 | return 0; | 107 | return 0; |
| 111 | } | 108 | } |
| 112 | 109 | ||
| @@ -114,7 +111,7 @@ static int vid_out_buf_prepare(struct vb2_buffer *vb) | |||
| 114 | { | 111 | { |
| 115 | struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); | 112 | struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); |
| 116 | unsigned long size; | 113 | unsigned long size; |
| 117 | unsigned planes = dev->fmt_out->planes; | 114 | unsigned planes; |
| 118 | unsigned p; | 115 | unsigned p; |
| 119 | 116 | ||
| 120 | dprintk(dev, 1, "%s\n", __func__); | 117 | dprintk(dev, 1, "%s\n", __func__); |
| @@ -122,6 +119,8 @@ static int vid_out_buf_prepare(struct vb2_buffer *vb) | |||
| 122 | if (WARN_ON(NULL == dev->fmt_out)) | 119 | if (WARN_ON(NULL == dev->fmt_out)) |
| 123 | return -EINVAL; | 120 | return -EINVAL; |
| 124 | 121 | ||
| 122 | planes = dev->fmt_out->planes; | ||
| 123 | |||
| 125 | if (dev->buf_prepare_error) { | 124 | if (dev->buf_prepare_error) { |
| 126 | /* | 125 | /* |
| 127 | * Error injection: test what happens if buf_prepare() returns | 126 | * Error injection: test what happens if buf_prepare() returns |
| @@ -220,7 +219,7 @@ const struct vb2_ops vivid_vid_out_qops = { | |||
| 220 | void vivid_update_format_out(struct vivid_dev *dev) | 219 | void vivid_update_format_out(struct vivid_dev *dev) |
| 221 | { | 220 | { |
| 222 | struct v4l2_bt_timings *bt = &dev->dv_timings_out.bt; | 221 | struct v4l2_bt_timings *bt = &dev->dv_timings_out.bt; |
| 223 | unsigned size; | 222 | unsigned size, p; |
| 224 | 223 | ||
| 225 | switch (dev->output_type[dev->output]) { | 224 | switch (dev->output_type[dev->output]) { |
| 226 | case SVID: | 225 | case SVID: |
| @@ -249,7 +248,7 @@ void vivid_update_format_out(struct vivid_dev *dev) | |||
| 249 | dev->field_out = V4L2_FIELD_ALTERNATE; | 248 | dev->field_out = V4L2_FIELD_ALTERNATE; |
| 250 | else | 249 | else |
| 251 | dev->field_out = V4L2_FIELD_NONE; | 250 | dev->field_out = V4L2_FIELD_NONE; |
| 252 | if (!dev->dvi_d_out && (bt->standards & V4L2_DV_BT_STD_CEA861)) { | 251 | if (!dev->dvi_d_out && (bt->flags & V4L2_DV_FL_IS_CE_VIDEO)) { |
| 253 | if (bt->width == 720 && bt->height <= 576) | 252 | if (bt->width == 720 && bt->height <= 576) |
| 254 | dev->colorspace_out = V4L2_COLORSPACE_SMPTE170M; | 253 | dev->colorspace_out = V4L2_COLORSPACE_SMPTE170M; |
| 255 | else | 254 | else |
| @@ -267,9 +266,9 @@ void vivid_update_format_out(struct vivid_dev *dev) | |||
| 267 | if (V4L2_FIELD_HAS_T_OR_B(dev->field_out)) | 266 | if (V4L2_FIELD_HAS_T_OR_B(dev->field_out)) |
| 268 | dev->crop_out.height /= 2; | 267 | dev->crop_out.height /= 2; |
| 269 | dev->fmt_out_rect = dev->crop_out; | 268 | dev->fmt_out_rect = dev->crop_out; |
| 270 | dev->bytesperline_out[0] = (dev->sink_rect.width * dev->fmt_out->depth) / 8; | 269 | for (p = 0; p < dev->fmt_out->planes; p++) |
| 271 | if (dev->fmt_out->planes == 2) | 270 | dev->bytesperline_out[p] = |
| 272 | dev->bytesperline_out[1] = (dev->sink_rect.width * dev->fmt_out->depth) / 8; | 271 | (dev->sink_rect.width * dev->fmt_out->bit_depth[p]) / 8; |
| 273 | } | 272 | } |
| 274 | 273 | ||
| 275 | /* Map the field to something that is valid for the current output */ | 274 | /* Map the field to something that is valid for the current output */ |
| @@ -313,21 +312,28 @@ int vivid_g_fmt_vid_out(struct file *file, void *priv, | |||
| 313 | { | 312 | { |
| 314 | struct vivid_dev *dev = video_drvdata(file); | 313 | struct vivid_dev *dev = video_drvdata(file); |
| 315 | struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp; | 314 | struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp; |
| 315 | const struct vivid_fmt *fmt = dev->fmt_out; | ||
| 316 | unsigned p; | 316 | unsigned p; |
| 317 | 317 | ||
| 318 | mp->width = dev->fmt_out_rect.width; | 318 | mp->width = dev->fmt_out_rect.width; |
| 319 | mp->height = dev->fmt_out_rect.height; | 319 | mp->height = dev->fmt_out_rect.height; |
| 320 | mp->field = dev->field_out; | 320 | mp->field = dev->field_out; |
| 321 | mp->pixelformat = dev->fmt_out->fourcc; | 321 | mp->pixelformat = fmt->fourcc; |
| 322 | mp->colorspace = dev->colorspace_out; | 322 | mp->colorspace = dev->colorspace_out; |
| 323 | mp->ycbcr_enc = dev->ycbcr_enc_out; | 323 | mp->ycbcr_enc = dev->ycbcr_enc_out; |
| 324 | mp->quantization = dev->quantization_out; | 324 | mp->quantization = dev->quantization_out; |
| 325 | mp->num_planes = dev->fmt_out->planes; | 325 | mp->num_planes = fmt->buffers; |
| 326 | for (p = 0; p < mp->num_planes; p++) { | 326 | for (p = 0; p < mp->num_planes; p++) { |
| 327 | mp->plane_fmt[p].bytesperline = dev->bytesperline_out[p]; | 327 | mp->plane_fmt[p].bytesperline = dev->bytesperline_out[p]; |
| 328 | mp->plane_fmt[p].sizeimage = | 328 | mp->plane_fmt[p].sizeimage = |
| 329 | mp->plane_fmt[p].bytesperline * mp->height; | 329 | mp->plane_fmt[p].bytesperline * mp->height; |
| 330 | } | 330 | } |
| 331 | for (p = fmt->buffers; p < fmt->planes; p++) { | ||
| 332 | unsigned stride = dev->bytesperline_out[p]; | ||
| 333 | |||
| 334 | mp->plane_fmt[0].sizeimage += | ||
| 335 | (stride * mp->height) / fmt->vdownsampling[p]; | ||
| 336 | } | ||
| 331 | return 0; | 337 | return 0; |
| 332 | } | 338 | } |
| 333 | 339 | ||
| @@ -386,10 +392,10 @@ int vivid_try_fmt_vid_out(struct file *file, void *priv, | |||
| 386 | /* This driver supports custom bytesperline values */ | 392 | /* This driver supports custom bytesperline values */ |
| 387 | 393 | ||
| 388 | /* Calculate the minimum supported bytesperline value */ | 394 | /* Calculate the minimum supported bytesperline value */ |
| 389 | bytesperline = (mp->width * fmt->depth) >> 3; | 395 | bytesperline = (mp->width * fmt->bit_depth[0]) >> 3; |
| 390 | /* Calculate the maximum supported bytesperline value */ | 396 | /* Calculate the maximum supported bytesperline value */ |
| 391 | max_bpl = (MAX_ZOOM * MAX_WIDTH * fmt->depth) >> 3; | 397 | max_bpl = (MAX_ZOOM * MAX_WIDTH * fmt->bit_depth[0]) >> 3; |
| 392 | mp->num_planes = fmt->planes; | 398 | mp->num_planes = fmt->buffers; |
| 393 | for (p = 0; p < mp->num_planes; p++) { | 399 | for (p = 0; p < mp->num_planes; p++) { |
| 394 | if (pfmt[p].bytesperline > max_bpl) | 400 | if (pfmt[p].bytesperline > max_bpl) |
| 395 | pfmt[p].bytesperline = max_bpl; | 401 | pfmt[p].bytesperline = max_bpl; |
| @@ -398,11 +404,14 @@ int vivid_try_fmt_vid_out(struct file *file, void *priv, | |||
| 398 | pfmt[p].sizeimage = pfmt[p].bytesperline * mp->height; | 404 | pfmt[p].sizeimage = pfmt[p].bytesperline * mp->height; |
| 399 | memset(pfmt[p].reserved, 0, sizeof(pfmt[p].reserved)); | 405 | memset(pfmt[p].reserved, 0, sizeof(pfmt[p].reserved)); |
| 400 | } | 406 | } |
| 407 | for (p = fmt->buffers; p < fmt->planes; p++) | ||
| 408 | pfmt[0].sizeimage += (pfmt[0].bytesperline * fmt->bit_depth[p]) / | ||
| 409 | (fmt->bit_depth[0] * fmt->vdownsampling[p]); | ||
| 401 | mp->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; | 410 | mp->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; |
| 402 | mp->quantization = V4L2_QUANTIZATION_DEFAULT; | 411 | mp->quantization = V4L2_QUANTIZATION_DEFAULT; |
| 403 | if (vivid_is_svid_out(dev)) { | 412 | if (vivid_is_svid_out(dev)) { |
| 404 | mp->colorspace = V4L2_COLORSPACE_SMPTE170M; | 413 | mp->colorspace = V4L2_COLORSPACE_SMPTE170M; |
| 405 | } else if (dev->dvi_d_out || !(bt->standards & V4L2_DV_BT_STD_CEA861)) { | 414 | } else if (dev->dvi_d_out || !(bt->flags & V4L2_DV_FL_IS_CE_VIDEO)) { |
| 406 | mp->colorspace = V4L2_COLORSPACE_SRGB; | 415 | mp->colorspace = V4L2_COLORSPACE_SRGB; |
| 407 | if (dev->dvi_d_out) | 416 | if (dev->dvi_d_out) |
| 408 | mp->quantization = V4L2_QUANTIZATION_LIM_RANGE; | 417 | mp->quantization = V4L2_QUANTIZATION_LIM_RANGE; |
| @@ -429,6 +438,7 @@ int vivid_s_fmt_vid_out(struct file *file, void *priv, | |||
| 429 | struct vb2_queue *q = &dev->vb_vid_out_q; | 438 | struct vb2_queue *q = &dev->vb_vid_out_q; |
| 430 | int ret = vivid_try_fmt_vid_out(file, priv, f); | 439 | int ret = vivid_try_fmt_vid_out(file, priv, f); |
| 431 | unsigned factor = 1; | 440 | unsigned factor = 1; |
| 441 | unsigned p; | ||
| 432 | 442 | ||
| 433 | if (ret < 0) | 443 | if (ret < 0) |
| 434 | return ret; | 444 | return ret; |
| @@ -524,9 +534,12 @@ int vivid_s_fmt_vid_out(struct file *file, void *priv, | |||
| 524 | 534 | ||
| 525 | dev->fmt_out_rect.width = mp->width; | 535 | dev->fmt_out_rect.width = mp->width; |
| 526 | dev->fmt_out_rect.height = mp->height; | 536 | dev->fmt_out_rect.height = mp->height; |
| 527 | dev->bytesperline_out[0] = mp->plane_fmt[0].bytesperline; | 537 | for (p = 0; p < mp->num_planes; p++) |
| 528 | if (mp->num_planes > 1) | 538 | dev->bytesperline_out[p] = mp->plane_fmt[p].bytesperline; |
| 529 | dev->bytesperline_out[1] = mp->plane_fmt[1].bytesperline; | 539 | for (p = dev->fmt_out->buffers; p < dev->fmt_out->planes; p++) |
| 540 | dev->bytesperline_out[p] = | ||
| 541 | (dev->bytesperline_out[0] * dev->fmt_out->bit_depth[p]) / | ||
| 542 | dev->fmt_out->bit_depth[0]; | ||
| 530 | dev->field_out = mp->field; | 543 | dev->field_out = mp->field; |
| 531 | if (vivid_is_svid_out(dev)) | 544 | if (vivid_is_svid_out(dev)) |
| 532 | dev->tv_field_out = mp->field; | 545 | dev->tv_field_out = mp->field; |
| @@ -1114,13 +1127,13 @@ int vivid_vid_out_s_dv_timings(struct file *file, void *_fh, | |||
| 1114 | 1127 | ||
| 1115 | if (!vivid_is_hdmi_out(dev)) | 1128 | if (!vivid_is_hdmi_out(dev)) |
| 1116 | return -ENODATA; | 1129 | return -ENODATA; |
| 1117 | if (vb2_is_busy(&dev->vb_vid_out_q)) | ||
| 1118 | return -EBUSY; | ||
| 1119 | if (!v4l2_find_dv_timings_cap(timings, &vivid_dv_timings_cap, | 1130 | if (!v4l2_find_dv_timings_cap(timings, &vivid_dv_timings_cap, |
| 1120 | 0, NULL, NULL)) | 1131 | 0, NULL, NULL)) |
| 1121 | return -EINVAL; | 1132 | return -EINVAL; |
| 1122 | if (v4l2_match_dv_timings(timings, &dev->dv_timings_out, 0)) | 1133 | if (v4l2_match_dv_timings(timings, &dev->dv_timings_out, 0)) |
| 1123 | return 0; | 1134 | return 0; |
| 1135 | if (vb2_is_busy(&dev->vb_vid_out_q)) | ||
| 1136 | return -EBUSY; | ||
| 1124 | dev->dv_timings_out = *timings; | 1137 | dev->dv_timings_out = *timings; |
| 1125 | vivid_update_format_out(dev); | 1138 | vivid_update_format_out(dev); |
| 1126 | return 0; | 1139 | return 0; |
diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c index 401e2b77a0b6..7dd763311c0f 100644 --- a/drivers/media/platform/vsp1/vsp1_bru.c +++ b/drivers/media/platform/vsp1/vsp1_bru.c | |||
| @@ -183,13 +183,14 @@ static int bru_s_stream(struct v4l2_subdev *subdev, int enable) | |||
| 183 | */ | 183 | */ |
| 184 | 184 | ||
| 185 | static int bru_enum_mbus_code(struct v4l2_subdev *subdev, | 185 | static int bru_enum_mbus_code(struct v4l2_subdev *subdev, |
| 186 | struct v4l2_subdev_fh *fh, | 186 | struct v4l2_subdev_pad_config *cfg, |
| 187 | struct v4l2_subdev_mbus_code_enum *code) | 187 | struct v4l2_subdev_mbus_code_enum *code) |
| 188 | { | 188 | { |
| 189 | static const unsigned int codes[] = { | 189 | static const unsigned int codes[] = { |
| 190 | MEDIA_BUS_FMT_ARGB8888_1X32, | 190 | MEDIA_BUS_FMT_ARGB8888_1X32, |
| 191 | MEDIA_BUS_FMT_AYUV8_1X32, | 191 | MEDIA_BUS_FMT_AYUV8_1X32, |
| 192 | }; | 192 | }; |
| 193 | struct vsp1_bru *bru = to_bru(subdev); | ||
| 193 | struct v4l2_mbus_framefmt *format; | 194 | struct v4l2_mbus_framefmt *format; |
| 194 | 195 | ||
| 195 | if (code->pad == BRU_PAD_SINK(0)) { | 196 | if (code->pad == BRU_PAD_SINK(0)) { |
| @@ -201,7 +202,8 @@ static int bru_enum_mbus_code(struct v4l2_subdev *subdev, | |||
| 201 | if (code->index) | 202 | if (code->index) |
| 202 | return -EINVAL; | 203 | return -EINVAL; |
| 203 | 204 | ||
| 204 | format = v4l2_subdev_get_try_format(fh, BRU_PAD_SINK(0)); | 205 | format = vsp1_entity_get_pad_format(&bru->entity, cfg, |
| 206 | BRU_PAD_SINK(0), code->which); | ||
| 205 | code->code = format->code; | 207 | code->code = format->code; |
| 206 | } | 208 | } |
| 207 | 209 | ||
| @@ -209,7 +211,7 @@ static int bru_enum_mbus_code(struct v4l2_subdev *subdev, | |||
| 209 | } | 211 | } |
| 210 | 212 | ||
| 211 | static int bru_enum_frame_size(struct v4l2_subdev *subdev, | 213 | static int bru_enum_frame_size(struct v4l2_subdev *subdev, |
| 212 | struct v4l2_subdev_fh *fh, | 214 | struct v4l2_subdev_pad_config *cfg, |
| 213 | struct v4l2_subdev_frame_size_enum *fse) | 215 | struct v4l2_subdev_frame_size_enum *fse) |
| 214 | { | 216 | { |
| 215 | if (fse->index) | 217 | if (fse->index) |
| @@ -228,12 +230,12 @@ static int bru_enum_frame_size(struct v4l2_subdev *subdev, | |||
| 228 | } | 230 | } |
| 229 | 231 | ||
| 230 | static struct v4l2_rect *bru_get_compose(struct vsp1_bru *bru, | 232 | static struct v4l2_rect *bru_get_compose(struct vsp1_bru *bru, |
| 231 | struct v4l2_subdev_fh *fh, | 233 | struct v4l2_subdev_pad_config *cfg, |
| 232 | unsigned int pad, u32 which) | 234 | unsigned int pad, u32 which) |
| 233 | { | 235 | { |
| 234 | switch (which) { | 236 | switch (which) { |
| 235 | case V4L2_SUBDEV_FORMAT_TRY: | 237 | case V4L2_SUBDEV_FORMAT_TRY: |
| 236 | return v4l2_subdev_get_try_crop(fh, pad); | 238 | return v4l2_subdev_get_try_crop(&bru->entity.subdev, cfg, pad); |
| 237 | case V4L2_SUBDEV_FORMAT_ACTIVE: | 239 | case V4L2_SUBDEV_FORMAT_ACTIVE: |
| 238 | return &bru->inputs[pad].compose; | 240 | return &bru->inputs[pad].compose; |
| 239 | default: | 241 | default: |
| @@ -241,18 +243,18 @@ static struct v4l2_rect *bru_get_compose(struct vsp1_bru *bru, | |||
| 241 | } | 243 | } |
| 242 | } | 244 | } |
| 243 | 245 | ||
| 244 | static int bru_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, | 246 | static int bru_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, |
| 245 | struct v4l2_subdev_format *fmt) | 247 | struct v4l2_subdev_format *fmt) |
| 246 | { | 248 | { |
| 247 | struct vsp1_bru *bru = to_bru(subdev); | 249 | struct vsp1_bru *bru = to_bru(subdev); |
| 248 | 250 | ||
| 249 | fmt->format = *vsp1_entity_get_pad_format(&bru->entity, fh, fmt->pad, | 251 | fmt->format = *vsp1_entity_get_pad_format(&bru->entity, cfg, fmt->pad, |
| 250 | fmt->which); | 252 | fmt->which); |
| 251 | 253 | ||
| 252 | return 0; | 254 | return 0; |
| 253 | } | 255 | } |
| 254 | 256 | ||
| 255 | static void bru_try_format(struct vsp1_bru *bru, struct v4l2_subdev_fh *fh, | 257 | static void bru_try_format(struct vsp1_bru *bru, struct v4l2_subdev_pad_config *cfg, |
| 256 | unsigned int pad, struct v4l2_mbus_framefmt *fmt, | 258 | unsigned int pad, struct v4l2_mbus_framefmt *fmt, |
| 257 | enum v4l2_subdev_format_whence which) | 259 | enum v4l2_subdev_format_whence which) |
| 258 | { | 260 | { |
| @@ -268,7 +270,7 @@ static void bru_try_format(struct vsp1_bru *bru, struct v4l2_subdev_fh *fh, | |||
| 268 | 270 | ||
| 269 | default: | 271 | default: |
| 270 | /* The BRU can't perform format conversion. */ | 272 | /* The BRU can't perform format conversion. */ |
| 271 | format = vsp1_entity_get_pad_format(&bru->entity, fh, | 273 | format = vsp1_entity_get_pad_format(&bru->entity, cfg, |
| 272 | BRU_PAD_SINK(0), which); | 274 | BRU_PAD_SINK(0), which); |
| 273 | fmt->code = format->code; | 275 | fmt->code = format->code; |
| 274 | break; | 276 | break; |
| @@ -280,15 +282,15 @@ static void bru_try_format(struct vsp1_bru *bru, struct v4l2_subdev_fh *fh, | |||
| 280 | fmt->colorspace = V4L2_COLORSPACE_SRGB; | 282 | fmt->colorspace = V4L2_COLORSPACE_SRGB; |
| 281 | } | 283 | } |
| 282 | 284 | ||
| 283 | static int bru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, | 285 | static int bru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, |
| 284 | struct v4l2_subdev_format *fmt) | 286 | struct v4l2_subdev_format *fmt) |
| 285 | { | 287 | { |
| 286 | struct vsp1_bru *bru = to_bru(subdev); | 288 | struct vsp1_bru *bru = to_bru(subdev); |
| 287 | struct v4l2_mbus_framefmt *format; | 289 | struct v4l2_mbus_framefmt *format; |
| 288 | 290 | ||
| 289 | bru_try_format(bru, fh, fmt->pad, &fmt->format, fmt->which); | 291 | bru_try_format(bru, cfg, fmt->pad, &fmt->format, fmt->which); |
| 290 | 292 | ||
| 291 | format = vsp1_entity_get_pad_format(&bru->entity, fh, fmt->pad, | 293 | format = vsp1_entity_get_pad_format(&bru->entity, cfg, fmt->pad, |
| 292 | fmt->which); | 294 | fmt->which); |
| 293 | *format = fmt->format; | 295 | *format = fmt->format; |
| 294 | 296 | ||
| @@ -296,7 +298,7 @@ static int bru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, | |||
| 296 | if (fmt->pad != BRU_PAD_SOURCE) { | 298 | if (fmt->pad != BRU_PAD_SOURCE) { |
| 297 | struct v4l2_rect *compose; | 299 | struct v4l2_rect *compose; |
| 298 | 300 | ||
| 299 | compose = bru_get_compose(bru, fh, fmt->pad, fmt->which); | 301 | compose = bru_get_compose(bru, cfg, fmt->pad, fmt->which); |
| 300 | compose->left = 0; | 302 | compose->left = 0; |
| 301 | compose->top = 0; | 303 | compose->top = 0; |
| 302 | compose->width = format->width; | 304 | compose->width = format->width; |
| @@ -308,7 +310,7 @@ static int bru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, | |||
| 308 | unsigned int i; | 310 | unsigned int i; |
| 309 | 311 | ||
| 310 | for (i = 0; i <= BRU_PAD_SOURCE; ++i) { | 312 | for (i = 0; i <= BRU_PAD_SOURCE; ++i) { |
| 311 | format = vsp1_entity_get_pad_format(&bru->entity, fh, | 313 | format = vsp1_entity_get_pad_format(&bru->entity, cfg, |
| 312 | i, fmt->which); | 314 | i, fmt->which); |
| 313 | format->code = fmt->format.code; | 315 | format->code = fmt->format.code; |
| 314 | } | 316 | } |
| @@ -318,7 +320,7 @@ static int bru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, | |||
| 318 | } | 320 | } |
| 319 | 321 | ||
| 320 | static int bru_get_selection(struct v4l2_subdev *subdev, | 322 | static int bru_get_selection(struct v4l2_subdev *subdev, |
| 321 | struct v4l2_subdev_fh *fh, | 323 | struct v4l2_subdev_pad_config *cfg, |
| 322 | struct v4l2_subdev_selection *sel) | 324 | struct v4l2_subdev_selection *sel) |
| 323 | { | 325 | { |
| 324 | struct vsp1_bru *bru = to_bru(subdev); | 326 | struct vsp1_bru *bru = to_bru(subdev); |
| @@ -335,7 +337,7 @@ static int bru_get_selection(struct v4l2_subdev *subdev, | |||
| 335 | return 0; | 337 | return 0; |
| 336 | 338 | ||
| 337 | case V4L2_SEL_TGT_COMPOSE: | 339 | case V4L2_SEL_TGT_COMPOSE: |
| 338 | sel->r = *bru_get_compose(bru, fh, sel->pad, sel->which); | 340 | sel->r = *bru_get_compose(bru, cfg, sel->pad, sel->which); |
| 339 | return 0; | 341 | return 0; |
| 340 | 342 | ||
| 341 | default: | 343 | default: |
| @@ -344,7 +346,7 @@ static int bru_get_selection(struct v4l2_subdev *subdev, | |||
| 344 | } | 346 | } |
| 345 | 347 | ||
| 346 | static int bru_set_selection(struct v4l2_subdev *subdev, | 348 | static int bru_set_selection(struct v4l2_subdev *subdev, |
| 347 | struct v4l2_subdev_fh *fh, | 349 | struct v4l2_subdev_pad_config *cfg, |
| 348 | struct v4l2_subdev_selection *sel) | 350 | struct v4l2_subdev_selection *sel) |
| 349 | { | 351 | { |
| 350 | struct vsp1_bru *bru = to_bru(subdev); | 352 | struct vsp1_bru *bru = to_bru(subdev); |
| @@ -360,7 +362,7 @@ static int bru_set_selection(struct v4l2_subdev *subdev, | |||
| 360 | /* The compose rectangle top left corner must be inside the output | 362 | /* The compose rectangle top left corner must be inside the output |
| 361 | * frame. | 363 | * frame. |
| 362 | */ | 364 | */ |
| 363 | format = vsp1_entity_get_pad_format(&bru->entity, fh, BRU_PAD_SOURCE, | 365 | format = vsp1_entity_get_pad_format(&bru->entity, cfg, BRU_PAD_SOURCE, |
| 364 | sel->which); | 366 | sel->which); |
| 365 | sel->r.left = clamp_t(unsigned int, sel->r.left, 0, format->width - 1); | 367 | sel->r.left = clamp_t(unsigned int, sel->r.left, 0, format->width - 1); |
| 366 | sel->r.top = clamp_t(unsigned int, sel->r.top, 0, format->height - 1); | 368 | sel->r.top = clamp_t(unsigned int, sel->r.top, 0, format->height - 1); |
| @@ -368,12 +370,12 @@ static int bru_set_selection(struct v4l2_subdev *subdev, | |||
| 368 | /* Scaling isn't supported, the compose rectangle size must be identical | 370 | /* Scaling isn't supported, the compose rectangle size must be identical |
| 369 | * to the sink format size. | 371 | * to the sink format size. |
| 370 | */ | 372 | */ |
| 371 | format = vsp1_entity_get_pad_format(&bru->entity, fh, sel->pad, | 373 | format = vsp1_entity_get_pad_format(&bru->entity, cfg, sel->pad, |
| 372 | sel->which); | 374 | sel->which); |
| 373 | sel->r.width = format->width; | 375 | sel->r.width = format->width; |
| 374 | sel->r.height = format->height; | 376 | sel->r.height = format->height; |
| 375 | 377 | ||
| 376 | compose = bru_get_compose(bru, fh, sel->pad, sel->which); | 378 | compose = bru_get_compose(bru, cfg, sel->pad, sel->which); |
| 377 | *compose = sel->r; | 379 | *compose = sel->r; |
| 378 | 380 | ||
| 379 | return 0; | 381 | return 0; |
diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c index 79af71d5e270..a453bb4ddd37 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.c +++ b/drivers/media/platform/vsp1/vsp1_entity.c | |||
| @@ -63,12 +63,12 @@ int vsp1_entity_set_streaming(struct vsp1_entity *entity, bool streaming) | |||
| 63 | 63 | ||
| 64 | struct v4l2_mbus_framefmt * | 64 | struct v4l2_mbus_framefmt * |
| 65 | vsp1_entity_get_pad_format(struct vsp1_entity *entity, | 65 | vsp1_entity_get_pad_format(struct vsp1_entity *entity, |
| 66 | struct v4l2_subdev_fh *fh, | 66 | struct v4l2_subdev_pad_config *cfg, |
| 67 | unsigned int pad, u32 which) | 67 | unsigned int pad, u32 which) |
| 68 | { | 68 | { |
| 69 | switch (which) { | 69 | switch (which) { |
| 70 | case V4L2_SUBDEV_FORMAT_TRY: | 70 | case V4L2_SUBDEV_FORMAT_TRY: |
| 71 | return v4l2_subdev_get_try_format(fh, pad); | 71 | return v4l2_subdev_get_try_format(&entity->subdev, cfg, pad); |
| 72 | case V4L2_SUBDEV_FORMAT_ACTIVE: | 72 | case V4L2_SUBDEV_FORMAT_ACTIVE: |
| 73 | return &entity->formats[pad]; | 73 | return &entity->formats[pad]; |
| 74 | default: | 74 | default: |
| @@ -79,14 +79,14 @@ vsp1_entity_get_pad_format(struct vsp1_entity *entity, | |||
| 79 | /* | 79 | /* |
| 80 | * vsp1_entity_init_formats - Initialize formats on all pads | 80 | * vsp1_entity_init_formats - Initialize formats on all pads |
| 81 | * @subdev: V4L2 subdevice | 81 | * @subdev: V4L2 subdevice |
| 82 | * @fh: V4L2 subdev file handle | 82 | * @cfg: V4L2 subdev pad configuration |
| 83 | * | 83 | * |
| 84 | * Initialize all pad formats with default values. If fh is not NULL, try | 84 | * Initialize all pad formats with default values. If cfg is not NULL, try |
| 85 | * formats are initialized on the file handle. Otherwise active formats are | 85 | * formats are initialized on the file handle. Otherwise active formats are |
| 86 | * initialized on the device. | 86 | * initialized on the device. |
| 87 | */ | 87 | */ |
| 88 | void vsp1_entity_init_formats(struct v4l2_subdev *subdev, | 88 | void vsp1_entity_init_formats(struct v4l2_subdev *subdev, |
| 89 | struct v4l2_subdev_fh *fh) | 89 | struct v4l2_subdev_pad_config *cfg) |
| 90 | { | 90 | { |
| 91 | struct v4l2_subdev_format format; | 91 | struct v4l2_subdev_format format; |
| 92 | unsigned int pad; | 92 | unsigned int pad; |
| @@ -95,17 +95,17 @@ void vsp1_entity_init_formats(struct v4l2_subdev *subdev, | |||
| 95 | memset(&format, 0, sizeof(format)); | 95 | memset(&format, 0, sizeof(format)); |
| 96 | 96 | ||
| 97 | format.pad = pad; | 97 | format.pad = pad; |
| 98 | format.which = fh ? V4L2_SUBDEV_FORMAT_TRY | 98 | format.which = cfg ? V4L2_SUBDEV_FORMAT_TRY |
| 99 | : V4L2_SUBDEV_FORMAT_ACTIVE; | 99 | : V4L2_SUBDEV_FORMAT_ACTIVE; |
| 100 | 100 | ||
| 101 | v4l2_subdev_call(subdev, pad, set_fmt, fh, &format); | 101 | v4l2_subdev_call(subdev, pad, set_fmt, cfg, &format); |
| 102 | } | 102 | } |
| 103 | } | 103 | } |
| 104 | 104 | ||
| 105 | static int vsp1_entity_open(struct v4l2_subdev *subdev, | 105 | static int vsp1_entity_open(struct v4l2_subdev *subdev, |
| 106 | struct v4l2_subdev_fh *fh) | 106 | struct v4l2_subdev_fh *fh) |
| 107 | { | 107 | { |
| 108 | vsp1_entity_init_formats(subdev, fh); | 108 | vsp1_entity_init_formats(subdev, fh->pad); |
| 109 | 109 | ||
| 110 | return 0; | 110 | return 0; |
| 111 | } | 111 | } |
diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h index aa20aaa58208..62c768d1c6aa 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.h +++ b/drivers/media/platform/vsp1/vsp1_entity.h | |||
| @@ -91,10 +91,10 @@ extern const struct media_entity_operations vsp1_media_ops; | |||
| 91 | 91 | ||
| 92 | struct v4l2_mbus_framefmt * | 92 | struct v4l2_mbus_framefmt * |
| 93 | vsp1_entity_get_pad_format(struct vsp1_entity *entity, | 93 | vsp1_entity_get_pad_format(struct vsp1_entity *entity, |
| 94 | struct v4l2_subdev_fh *fh, | 94 | struct v4l2_subdev_pad_config *cfg, |
| 95 | unsigned int pad, u32 which); | 95 | unsigned int pad, u32 which); |
| 96 | void vsp1_entity_init_formats(struct v4l2_subdev *subdev, | 96 | void vsp1_entity_init_formats(struct v4l2_subdev *subdev, |
| 97 | struct v4l2_subdev_fh *fh); | 97 | struct v4l2_subdev_pad_config *cfg); |
| 98 | 98 | ||
| 99 | bool vsp1_entity_is_streaming(struct vsp1_entity *entity); | 99 | bool vsp1_entity_is_streaming(struct vsp1_entity *entity); |
| 100 | int vsp1_entity_set_streaming(struct vsp1_entity *entity, bool streaming); | 100 | int vsp1_entity_set_streaming(struct vsp1_entity *entity, bool streaming); |
diff --git a/drivers/media/platform/vsp1/vsp1_hsit.c b/drivers/media/platform/vsp1/vsp1_hsit.c index 0bc0471746c9..8ffb817ae525 100644 --- a/drivers/media/platform/vsp1/vsp1_hsit.c +++ b/drivers/media/platform/vsp1/vsp1_hsit.c | |||
| @@ -55,7 +55,7 @@ static int hsit_s_stream(struct v4l2_subdev *subdev, int enable) | |||
| 55 | */ | 55 | */ |
| 56 | 56 | ||
| 57 | static int hsit_enum_mbus_code(struct v4l2_subdev *subdev, | 57 | static int hsit_enum_mbus_code(struct v4l2_subdev *subdev, |
| 58 | struct v4l2_subdev_fh *fh, | 58 | struct v4l2_subdev_pad_config *cfg, |
| 59 | struct v4l2_subdev_mbus_code_enum *code) | 59 | struct v4l2_subdev_mbus_code_enum *code) |
| 60 | { | 60 | { |
| 61 | struct vsp1_hsit *hsit = to_hsit(subdev); | 61 | struct vsp1_hsit *hsit = to_hsit(subdev); |
| @@ -73,12 +73,14 @@ static int hsit_enum_mbus_code(struct v4l2_subdev *subdev, | |||
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | static int hsit_enum_frame_size(struct v4l2_subdev *subdev, | 75 | static int hsit_enum_frame_size(struct v4l2_subdev *subdev, |
| 76 | struct v4l2_subdev_fh *fh, | 76 | struct v4l2_subdev_pad_config *cfg, |
| 77 | struct v4l2_subdev_frame_size_enum *fse) | 77 | struct v4l2_subdev_frame_size_enum *fse) |
| 78 | { | 78 | { |
| 79 | struct vsp1_hsit *hsit = to_hsit(subdev); | ||
| 79 | struct v4l2_mbus_framefmt *format; | 80 | struct v4l2_mbus_framefmt *format; |
| 80 | 81 | ||
| 81 | format = v4l2_subdev_get_try_format(fh, fse->pad); | 82 | format = vsp1_entity_get_pad_format(&hsit->entity, cfg, fse->pad, |
| 83 | fse->which); | ||
| 82 | 84 | ||
| 83 | if (fse->index || fse->code != format->code) | 85 | if (fse->index || fse->code != format->code) |
| 84 | return -EINVAL; | 86 | return -EINVAL; |
| @@ -102,25 +104,25 @@ static int hsit_enum_frame_size(struct v4l2_subdev *subdev, | |||
| 102 | } | 104 | } |
| 103 | 105 | ||
| 104 | static int hsit_get_format(struct v4l2_subdev *subdev, | 106 | static int hsit_get_format(struct v4l2_subdev *subdev, |
| 105 | struct v4l2_subdev_fh *fh, | 107 | struct v4l2_subdev_pad_config *cfg, |
| 106 | struct v4l2_subdev_format *fmt) | 108 | struct v4l2_subdev_format *fmt) |
| 107 | { | 109 | { |
| 108 | struct vsp1_hsit *hsit = to_hsit(subdev); | 110 | struct vsp1_hsit *hsit = to_hsit(subdev); |
| 109 | 111 | ||
| 110 | fmt->format = *vsp1_entity_get_pad_format(&hsit->entity, fh, fmt->pad, | 112 | fmt->format = *vsp1_entity_get_pad_format(&hsit->entity, cfg, fmt->pad, |
| 111 | fmt->which); | 113 | fmt->which); |
| 112 | 114 | ||
| 113 | return 0; | 115 | return 0; |
| 114 | } | 116 | } |
| 115 | 117 | ||
| 116 | static int hsit_set_format(struct v4l2_subdev *subdev, | 118 | static int hsit_set_format(struct v4l2_subdev *subdev, |
| 117 | struct v4l2_subdev_fh *fh, | 119 | struct v4l2_subdev_pad_config *cfg, |
| 118 | struct v4l2_subdev_format *fmt) | 120 | struct v4l2_subdev_format *fmt) |
| 119 | { | 121 | { |
| 120 | struct vsp1_hsit *hsit = to_hsit(subdev); | 122 | struct vsp1_hsit *hsit = to_hsit(subdev); |
| 121 | struct v4l2_mbus_framefmt *format; | 123 | struct v4l2_mbus_framefmt *format; |
| 122 | 124 | ||
| 123 | format = vsp1_entity_get_pad_format(&hsit->entity, fh, fmt->pad, | 125 | format = vsp1_entity_get_pad_format(&hsit->entity, cfg, fmt->pad, |
| 124 | fmt->which); | 126 | fmt->which); |
| 125 | 127 | ||
| 126 | if (fmt->pad == HSIT_PAD_SOURCE) { | 128 | if (fmt->pad == HSIT_PAD_SOURCE) { |
| @@ -143,7 +145,7 @@ static int hsit_set_format(struct v4l2_subdev *subdev, | |||
| 143 | fmt->format = *format; | 145 | fmt->format = *format; |
| 144 | 146 | ||
| 145 | /* Propagate the format to the source pad. */ | 147 | /* Propagate the format to the source pad. */ |
| 146 | format = vsp1_entity_get_pad_format(&hsit->entity, fh, HSIT_PAD_SOURCE, | 148 | format = vsp1_entity_get_pad_format(&hsit->entity, cfg, HSIT_PAD_SOURCE, |
| 147 | fmt->which); | 149 | fmt->which); |
| 148 | *format = fmt->format; | 150 | *format = fmt->format; |
| 149 | format->code = hsit->inverse ? MEDIA_BUS_FMT_ARGB8888_1X32 | 151 | format->code = hsit->inverse ? MEDIA_BUS_FMT_ARGB8888_1X32 |
diff --git a/drivers/media/platform/vsp1/vsp1_lif.c b/drivers/media/platform/vsp1/vsp1_lif.c index 17a6ca7dafe6..39fa5ef20fbb 100644 --- a/drivers/media/platform/vsp1/vsp1_lif.c +++ b/drivers/media/platform/vsp1/vsp1_lif.c | |||
| @@ -74,13 +74,14 @@ static int lif_s_stream(struct v4l2_subdev *subdev, int enable) | |||
| 74 | */ | 74 | */ |
| 75 | 75 | ||
| 76 | static int lif_enum_mbus_code(struct v4l2_subdev *subdev, | 76 | static int lif_enum_mbus_code(struct v4l2_subdev *subdev, |
| 77 | struct v4l2_subdev_fh *fh, | 77 | struct v4l2_subdev_pad_config *cfg, |
| 78 | struct v4l2_subdev_mbus_code_enum *code) | 78 | struct v4l2_subdev_mbus_code_enum *code) |
| 79 | { | 79 | { |
| 80 | static const unsigned int codes[] = { | 80 | static const unsigned int codes[] = { |
| 81 | MEDIA_BUS_FMT_ARGB8888_1X32, | 81 | MEDIA_BUS_FMT_ARGB8888_1X32, |
| 82 | MEDIA_BUS_FMT_AYUV8_1X32, | 82 | MEDIA_BUS_FMT_AYUV8_1X32, |
| 83 | }; | 83 | }; |
| 84 | struct vsp1_lif *lif = to_lif(subdev); | ||
| 84 | 85 | ||
| 85 | if (code->pad == LIF_PAD_SINK) { | 86 | if (code->pad == LIF_PAD_SINK) { |
| 86 | if (code->index >= ARRAY_SIZE(codes)) | 87 | if (code->index >= ARRAY_SIZE(codes)) |
| @@ -96,7 +97,8 @@ static int lif_enum_mbus_code(struct v4l2_subdev *subdev, | |||
| 96 | if (code->index) | 97 | if (code->index) |
| 97 | return -EINVAL; | 98 | return -EINVAL; |
| 98 | 99 | ||
| 99 | format = v4l2_subdev_get_try_format(fh, LIF_PAD_SINK); | 100 | format = vsp1_entity_get_pad_format(&lif->entity, cfg, |
| 101 | LIF_PAD_SINK, code->which); | ||
| 100 | code->code = format->code; | 102 | code->code = format->code; |
| 101 | } | 103 | } |
| 102 | 104 | ||
| @@ -104,12 +106,14 @@ static int lif_enum_mbus_code(struct v4l2_subdev *subdev, | |||
| 104 | } | 106 | } |
| 105 | 107 | ||
| 106 | static int lif_enum_frame_size(struct v4l2_subdev *subdev, | 108 | static int lif_enum_frame_size(struct v4l2_subdev *subdev, |
| 107 | struct v4l2_subdev_fh *fh, | 109 | struct v4l2_subdev_pad_config *cfg, |
| 108 | struct v4l2_subdev_frame_size_enum *fse) | 110 | struct v4l2_subdev_frame_size_enum *fse) |
| 109 | { | 111 | { |
| 112 | struct vsp1_lif *lif = to_lif(subdev); | ||
| 110 | struct v4l2_mbus_framefmt *format; | 113 | struct v4l2_mbus_framefmt *format; |
| 111 | 114 | ||
| 112 | format = v4l2_subdev_get_try_format(fh, LIF_PAD_SINK); | 115 | format = vsp1_entity_get_pad_format(&lif->entity, cfg, LIF_PAD_SINK, |
| 116 | fse->which); | ||
| 113 | 117 | ||
| 114 | if (fse->index || fse->code != format->code) | 118 | if (fse->index || fse->code != format->code) |
| 115 | return -EINVAL; | 119 | return -EINVAL; |
| @@ -129,18 +133,18 @@ static int lif_enum_frame_size(struct v4l2_subdev *subdev, | |||
| 129 | return 0; | 133 | return 0; |
| 130 | } | 134 | } |
| 131 | 135 | ||
| 132 | static int lif_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, | 136 | static int lif_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, |
| 133 | struct v4l2_subdev_format *fmt) | 137 | struct v4l2_subdev_format *fmt) |
| 134 | { | 138 | { |
| 135 | struct vsp1_lif *lif = to_lif(subdev); | 139 | struct vsp1_lif *lif = to_lif(subdev); |
| 136 | 140 | ||
| 137 | fmt->format = *vsp1_entity_get_pad_format(&lif->entity, fh, fmt->pad, | 141 | fmt->format = *vsp1_entity_get_pad_format(&lif->entity, cfg, fmt->pad, |
| 138 | fmt->which); | 142 | fmt->which); |
| 139 | 143 | ||
| 140 | return 0; | 144 | return 0; |
| 141 | } | 145 | } |
| 142 | 146 | ||
| 143 | static int lif_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, | 147 | static int lif_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, |
| 144 | struct v4l2_subdev_format *fmt) | 148 | struct v4l2_subdev_format *fmt) |
| 145 | { | 149 | { |
| 146 | struct vsp1_lif *lif = to_lif(subdev); | 150 | struct vsp1_lif *lif = to_lif(subdev); |
| @@ -151,7 +155,7 @@ static int lif_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, | |||
| 151 | fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32) | 155 | fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32) |
| 152 | fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32; | 156 | fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32; |
| 153 | 157 | ||
| 154 | format = vsp1_entity_get_pad_format(&lif->entity, fh, fmt->pad, | 158 | format = vsp1_entity_get_pad_format(&lif->entity, cfg, fmt->pad, |
| 155 | fmt->which); | 159 | fmt->which); |
| 156 | 160 | ||
| 157 | if (fmt->pad == LIF_PAD_SOURCE) { | 161 | if (fmt->pad == LIF_PAD_SOURCE) { |
| @@ -173,7 +177,7 @@ static int lif_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, | |||
| 173 | fmt->format = *format; | 177 | fmt->format = *format; |
| 174 | 178 | ||
| 175 | /* Propagate the format to the source pad. */ | 179 | /* Propagate the format to the source pad. */ |
| 176 | format = vsp1_entity_get_pad_format(&lif->entity, fh, LIF_PAD_SOURCE, | 180 | format = vsp1_entity_get_pad_format(&lif->entity, cfg, LIF_PAD_SOURCE, |
| 177 | fmt->which); | 181 | fmt->which); |
| 178 | *format = fmt->format; | 182 | *format = fmt->format; |
| 179 | 183 | ||
diff --git a/drivers/media/platform/vsp1/vsp1_lut.c b/drivers/media/platform/vsp1/vsp1_lut.c index 6f185c3621fe..656ec272a414 100644 --- a/drivers/media/platform/vsp1/vsp1_lut.c +++ b/drivers/media/platform/vsp1/vsp1_lut.c | |||
| @@ -82,7 +82,7 @@ static int lut_s_stream(struct v4l2_subdev *subdev, int enable) | |||
| 82 | */ | 82 | */ |
| 83 | 83 | ||
| 84 | static int lut_enum_mbus_code(struct v4l2_subdev *subdev, | 84 | static int lut_enum_mbus_code(struct v4l2_subdev *subdev, |
| 85 | struct v4l2_subdev_fh *fh, | 85 | struct v4l2_subdev_pad_config *cfg, |
| 86 | struct v4l2_subdev_mbus_code_enum *code) | 86 | struct v4l2_subdev_mbus_code_enum *code) |
| 87 | { | 87 | { |
| 88 | static const unsigned int codes[] = { | 88 | static const unsigned int codes[] = { |
| @@ -90,6 +90,7 @@ static int lut_enum_mbus_code(struct v4l2_subdev *subdev, | |||
| 90 | MEDIA_BUS_FMT_AHSV8888_1X32, | 90 | MEDIA_BUS_FMT_AHSV8888_1X32, |
| 91 | MEDIA_BUS_FMT_AYUV8_1X32, | 91 | MEDIA_BUS_FMT_AYUV8_1X32, |
| 92 | }; | 92 | }; |
| 93 | struct vsp1_lut *lut = to_lut(subdev); | ||
| 93 | struct v4l2_mbus_framefmt *format; | 94 | struct v4l2_mbus_framefmt *format; |
| 94 | 95 | ||
| 95 | if (code->pad == LUT_PAD_SINK) { | 96 | if (code->pad == LUT_PAD_SINK) { |
| @@ -104,7 +105,8 @@ static int lut_enum_mbus_code(struct v4l2_subdev *subdev, | |||
| 104 | if (code->index) | 105 | if (code->index) |
| 105 | return -EINVAL; | 106 | return -EINVAL; |
| 106 | 107 | ||
| 107 | format = v4l2_subdev_get_try_format(fh, LUT_PAD_SINK); | 108 | format = vsp1_entity_get_pad_format(&lut->entity, cfg, |
| 109 | LUT_PAD_SINK, code->which); | ||
| 108 | code->code = format->code; | 110 | code->code = format->code; |
| 109 | } | 111 | } |
| 110 | 112 | ||
| @@ -112,12 +114,14 @@ static int lut_enum_mbus_code(struct v4l2_subdev *subdev, | |||
| 112 | } | 114 | } |
| 113 | 115 | ||
| 114 | static int lut_enum_frame_size(struct v4l2_subdev *subdev, | 116 | static int lut_enum_frame_size(struct v4l2_subdev *subdev, |
| 115 | struct v4l2_subdev_fh *fh, | 117 | struct v4l2_subdev_pad_config *cfg, |
| 116 | struct v4l2_subdev_frame_size_enum *fse) | 118 | struct v4l2_subdev_frame_size_enum *fse) |
| 117 | { | 119 | { |
| 120 | struct vsp1_lut *lut = to_lut(subdev); | ||
| 118 | struct v4l2_mbus_framefmt *format; | 121 | struct v4l2_mbus_framefmt *format; |
| 119 | 122 | ||
| 120 | format = v4l2_subdev_get_try_format(fh, fse->pad); | 123 | format = vsp1_entity_get_pad_format(&lut->entity, cfg, |
| 124 | fse->pad, fse->which); | ||
| 121 | 125 | ||
| 122 | if (fse->index || fse->code != format->code) | 126 | if (fse->index || fse->code != format->code) |
| 123 | return -EINVAL; | 127 | return -EINVAL; |
| @@ -140,18 +144,18 @@ static int lut_enum_frame_size(struct v4l2_subdev *subdev, | |||
| 140 | return 0; | 144 | return 0; |
| 141 | } | 145 | } |
| 142 | 146 | ||
| 143 | static int lut_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, | 147 | static int lut_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, |
| 144 | struct v4l2_subdev_format *fmt) | 148 | struct v4l2_subdev_format *fmt) |
| 145 | { | 149 | { |
| 146 | struct vsp1_lut *lut = to_lut(subdev); | 150 | struct vsp1_lut *lut = to_lut(subdev); |
| 147 | 151 | ||
| 148 | fmt->format = *vsp1_entity_get_pad_format(&lut->entity, fh, fmt->pad, | 152 | fmt->format = *vsp1_entity_get_pad_format(&lut->entity, cfg, fmt->pad, |
| 149 | fmt->which); | 153 | fmt->which); |
| 150 | 154 | ||
| 151 | return 0; | 155 | return 0; |
| 152 | } | 156 | } |
| 153 | 157 | ||
| 154 | static int lut_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, | 158 | static int lut_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, |
| 155 | struct v4l2_subdev_format *fmt) | 159 | struct v4l2_subdev_format *fmt) |
| 156 | { | 160 | { |
| 157 | struct vsp1_lut *lut = to_lut(subdev); | 161 | struct vsp1_lut *lut = to_lut(subdev); |
| @@ -163,7 +167,7 @@ static int lut_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, | |||
| 163 | fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32) | 167 | fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32) |
| 164 | fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32; | 168 | fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32; |
| 165 | 169 | ||
| 166 | format = vsp1_entity_get_pad_format(&lut->entity, fh, fmt->pad, | 170 | format = vsp1_entity_get_pad_format(&lut->entity, cfg, fmt->pad, |
| 167 | fmt->which); | 171 | fmt->which); |
| 168 | 172 | ||
| 169 | if (fmt->pad == LUT_PAD_SOURCE) { | 173 | if (fmt->pad == LUT_PAD_SOURCE) { |
| @@ -182,7 +186,7 @@ static int lut_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, | |||
| 182 | fmt->format = *format; | 186 | fmt->format = *format; |
| 183 | 187 | ||
| 184 | /* Propagate the format to the source pad. */ | 188 | /* Propagate the format to the source pad. */ |
| 185 | format = vsp1_entity_get_pad_format(&lut->entity, fh, LUT_PAD_SOURCE, | 189 | format = vsp1_entity_get_pad_format(&lut->entity, cfg, LUT_PAD_SOURCE, |
| 186 | fmt->which); | 190 | fmt->which); |
| 187 | *format = fmt->format; | 191 | *format = fmt->format; |
| 188 | 192 | ||
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.c b/drivers/media/platform/vsp1/vsp1_rwpf.c index 1f1ba26a834a..fa71f4695e16 100644 --- a/drivers/media/platform/vsp1/vsp1_rwpf.c +++ b/drivers/media/platform/vsp1/vsp1_rwpf.c | |||
| @@ -25,7 +25,7 @@ | |||
| 25 | */ | 25 | */ |
| 26 | 26 | ||
| 27 | int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev, | 27 | int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev, |
| 28 | struct v4l2_subdev_fh *fh, | 28 | struct v4l2_subdev_pad_config *cfg, |
| 29 | struct v4l2_subdev_mbus_code_enum *code) | 29 | struct v4l2_subdev_mbus_code_enum *code) |
| 30 | { | 30 | { |
| 31 | static const unsigned int codes[] = { | 31 | static const unsigned int codes[] = { |
| @@ -42,13 +42,14 @@ int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev, | |||
| 42 | } | 42 | } |
| 43 | 43 | ||
| 44 | int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev, | 44 | int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev, |
| 45 | struct v4l2_subdev_fh *fh, | 45 | struct v4l2_subdev_pad_config *cfg, |
| 46 | struct v4l2_subdev_frame_size_enum *fse) | 46 | struct v4l2_subdev_frame_size_enum *fse) |
| 47 | { | 47 | { |
| 48 | struct vsp1_rwpf *rwpf = to_rwpf(subdev); | 48 | struct vsp1_rwpf *rwpf = to_rwpf(subdev); |
| 49 | struct v4l2_mbus_framefmt *format; | 49 | struct v4l2_mbus_framefmt *format; |
| 50 | 50 | ||
| 51 | format = v4l2_subdev_get_try_format(fh, fse->pad); | 51 | format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, fse->pad, |
| 52 | fse->which); | ||
| 52 | 53 | ||
| 53 | if (fse->index || fse->code != format->code) | 54 | if (fse->index || fse->code != format->code) |
| 54 | return -EINVAL; | 55 | return -EINVAL; |
| @@ -72,11 +73,11 @@ int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev, | |||
| 72 | } | 73 | } |
| 73 | 74 | ||
| 74 | static struct v4l2_rect * | 75 | static struct v4l2_rect * |
| 75 | vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf, struct v4l2_subdev_fh *fh, u32 which) | 76 | vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf, struct v4l2_subdev_pad_config *cfg, u32 which) |
| 76 | { | 77 | { |
| 77 | switch (which) { | 78 | switch (which) { |
| 78 | case V4L2_SUBDEV_FORMAT_TRY: | 79 | case V4L2_SUBDEV_FORMAT_TRY: |
| 79 | return v4l2_subdev_get_try_crop(fh, RWPF_PAD_SINK); | 80 | return v4l2_subdev_get_try_crop(&rwpf->entity.subdev, cfg, RWPF_PAD_SINK); |
| 80 | case V4L2_SUBDEV_FORMAT_ACTIVE: | 81 | case V4L2_SUBDEV_FORMAT_ACTIVE: |
| 81 | return &rwpf->crop; | 82 | return &rwpf->crop; |
| 82 | default: | 83 | default: |
| @@ -84,18 +85,18 @@ vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf, struct v4l2_subdev_fh *fh, u32 which) | |||
| 84 | } | 85 | } |
| 85 | } | 86 | } |
| 86 | 87 | ||
| 87 | int vsp1_rwpf_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, | 88 | int vsp1_rwpf_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, |
| 88 | struct v4l2_subdev_format *fmt) | 89 | struct v4l2_subdev_format *fmt) |
| 89 | { | 90 | { |
| 90 | struct vsp1_rwpf *rwpf = to_rwpf(subdev); | 91 | struct vsp1_rwpf *rwpf = to_rwpf(subdev); |
| 91 | 92 | ||
| 92 | fmt->format = *vsp1_entity_get_pad_format(&rwpf->entity, fh, fmt->pad, | 93 | fmt->format = *vsp1_entity_get_pad_format(&rwpf->entity, cfg, fmt->pad, |
| 93 | fmt->which); | 94 | fmt->which); |
| 94 | 95 | ||
| 95 | return 0; | 96 | return 0; |
| 96 | } | 97 | } |
| 97 | 98 | ||
| 98 | int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, | 99 | int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, |
| 99 | struct v4l2_subdev_format *fmt) | 100 | struct v4l2_subdev_format *fmt) |
| 100 | { | 101 | { |
| 101 | struct vsp1_rwpf *rwpf = to_rwpf(subdev); | 102 | struct vsp1_rwpf *rwpf = to_rwpf(subdev); |
| @@ -107,7 +108,7 @@ int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, | |||
| 107 | fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32) | 108 | fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32) |
| 108 | fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32; | 109 | fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32; |
| 109 | 110 | ||
| 110 | format = vsp1_entity_get_pad_format(&rwpf->entity, fh, fmt->pad, | 111 | format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, fmt->pad, |
| 111 | fmt->which); | 112 | fmt->which); |
| 112 | 113 | ||
| 113 | if (fmt->pad == RWPF_PAD_SOURCE) { | 114 | if (fmt->pad == RWPF_PAD_SOURCE) { |
| @@ -130,14 +131,14 @@ int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, | |||
| 130 | fmt->format = *format; | 131 | fmt->format = *format; |
| 131 | 132 | ||
| 132 | /* Update the sink crop rectangle. */ | 133 | /* Update the sink crop rectangle. */ |
| 133 | crop = vsp1_rwpf_get_crop(rwpf, fh, fmt->which); | 134 | crop = vsp1_rwpf_get_crop(rwpf, cfg, fmt->which); |
| 134 | crop->left = 0; | 135 | crop->left = 0; |
| 135 | crop->top = 0; | 136 | crop->top = 0; |
| 136 | crop->width = fmt->format.width; | 137 | crop->width = fmt->format.width; |
| 137 | crop->height = fmt->format.height; | 138 | crop->height = fmt->format.height; |
| 138 | 139 | ||
| 139 | /* Propagate the format to the source pad. */ | 140 | /* Propagate the format to the source pad. */ |
| 140 | format = vsp1_entity_get_pad_format(&rwpf->entity, fh, RWPF_PAD_SOURCE, | 141 | format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, RWPF_PAD_SOURCE, |
| 141 | fmt->which); | 142 | fmt->which); |
| 142 | *format = fmt->format; | 143 | *format = fmt->format; |
| 143 | 144 | ||
| @@ -145,7 +146,7 @@ int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, | |||
| 145 | } | 146 | } |
| 146 | 147 | ||
| 147 | int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev, | 148 | int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev, |
| 148 | struct v4l2_subdev_fh *fh, | 149 | struct v4l2_subdev_pad_config *cfg, |
| 149 | struct v4l2_subdev_selection *sel) | 150 | struct v4l2_subdev_selection *sel) |
| 150 | { | 151 | { |
| 151 | struct vsp1_rwpf *rwpf = to_rwpf(subdev); | 152 | struct vsp1_rwpf *rwpf = to_rwpf(subdev); |
| @@ -157,11 +158,11 @@ int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev, | |||
| 157 | 158 | ||
| 158 | switch (sel->target) { | 159 | switch (sel->target) { |
| 159 | case V4L2_SEL_TGT_CROP: | 160 | case V4L2_SEL_TGT_CROP: |
| 160 | sel->r = *vsp1_rwpf_get_crop(rwpf, fh, sel->which); | 161 | sel->r = *vsp1_rwpf_get_crop(rwpf, cfg, sel->which); |
| 161 | break; | 162 | break; |
| 162 | 163 | ||
| 163 | case V4L2_SEL_TGT_CROP_BOUNDS: | 164 | case V4L2_SEL_TGT_CROP_BOUNDS: |
| 164 | format = vsp1_entity_get_pad_format(&rwpf->entity, fh, | 165 | format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, |
| 165 | RWPF_PAD_SINK, sel->which); | 166 | RWPF_PAD_SINK, sel->which); |
| 166 | sel->r.left = 0; | 167 | sel->r.left = 0; |
| 167 | sel->r.top = 0; | 168 | sel->r.top = 0; |
| @@ -177,7 +178,7 @@ int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev, | |||
| 177 | } | 178 | } |
| 178 | 179 | ||
| 179 | int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, | 180 | int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, |
| 180 | struct v4l2_subdev_fh *fh, | 181 | struct v4l2_subdev_pad_config *cfg, |
| 181 | struct v4l2_subdev_selection *sel) | 182 | struct v4l2_subdev_selection *sel) |
| 182 | { | 183 | { |
| 183 | struct vsp1_rwpf *rwpf = to_rwpf(subdev); | 184 | struct vsp1_rwpf *rwpf = to_rwpf(subdev); |
| @@ -194,7 +195,7 @@ int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, | |||
| 194 | /* Make sure the crop rectangle is entirely contained in the image. The | 195 | /* Make sure the crop rectangle is entirely contained in the image. The |
| 195 | * WPF top and left offsets are limited to 255. | 196 | * WPF top and left offsets are limited to 255. |
| 196 | */ | 197 | */ |
| 197 | format = vsp1_entity_get_pad_format(&rwpf->entity, fh, RWPF_PAD_SINK, | 198 | format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, RWPF_PAD_SINK, |
| 198 | sel->which); | 199 | sel->which); |
| 199 | sel->r.left = min_t(unsigned int, sel->r.left, format->width - 2); | 200 | sel->r.left = min_t(unsigned int, sel->r.left, format->width - 2); |
| 200 | sel->r.top = min_t(unsigned int, sel->r.top, format->height - 2); | 201 | sel->r.top = min_t(unsigned int, sel->r.top, format->height - 2); |
| @@ -207,11 +208,11 @@ int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, | |||
| 207 | sel->r.height = min_t(unsigned int, sel->r.height, | 208 | sel->r.height = min_t(unsigned int, sel->r.height, |
| 208 | format->height - sel->r.top); | 209 | format->height - sel->r.top); |
| 209 | 210 | ||
| 210 | crop = vsp1_rwpf_get_crop(rwpf, fh, sel->which); | 211 | crop = vsp1_rwpf_get_crop(rwpf, cfg, sel->which); |
| 211 | *crop = sel->r; | 212 | *crop = sel->r; |
| 212 | 213 | ||
| 213 | /* Propagate the format to the source pad. */ | 214 | /* Propagate the format to the source pad. */ |
| 214 | format = vsp1_entity_get_pad_format(&rwpf->entity, fh, RWPF_PAD_SOURCE, | 215 | format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, RWPF_PAD_SOURCE, |
| 215 | sel->which); | 216 | sel->which); |
| 216 | format->width = crop->width; | 217 | format->width = crop->width; |
| 217 | format->height = crop->height; | 218 | format->height = crop->height; |
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h index 2cf1f13d3bf9..f452dce1a931 100644 --- a/drivers/media/platform/vsp1/vsp1_rwpf.h +++ b/drivers/media/platform/vsp1/vsp1_rwpf.h | |||
| @@ -51,20 +51,20 @@ struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index); | |||
| 51 | struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index); | 51 | struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index); |
| 52 | 52 | ||
| 53 | int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev, | 53 | int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev, |
| 54 | struct v4l2_subdev_fh *fh, | 54 | struct v4l2_subdev_pad_config *cfg, |
| 55 | struct v4l2_subdev_mbus_code_enum *code); | 55 | struct v4l2_subdev_mbus_code_enum *code); |
| 56 | int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev, | 56 | int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev, |
| 57 | struct v4l2_subdev_fh *fh, | 57 | struct v4l2_subdev_pad_config *cfg, |
| 58 | struct v4l2_subdev_frame_size_enum *fse); | 58 | struct v4l2_subdev_frame_size_enum *fse); |
| 59 | int vsp1_rwpf_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, | 59 | int vsp1_rwpf_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, |
| 60 | struct v4l2_subdev_format *fmt); | 60 | struct v4l2_subdev_format *fmt); |
| 61 | int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, | 61 | int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, |
| 62 | struct v4l2_subdev_format *fmt); | 62 | struct v4l2_subdev_format *fmt); |
| 63 | int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev, | 63 | int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev, |
| 64 | struct v4l2_subdev_fh *fh, | 64 | struct v4l2_subdev_pad_config *cfg, |
| 65 | struct v4l2_subdev_selection *sel); | 65 | struct v4l2_subdev_selection *sel); |
| 66 | int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, | 66 | int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, |
| 67 | struct v4l2_subdev_fh *fh, | 67 | struct v4l2_subdev_pad_config *cfg, |
| 68 | struct v4l2_subdev_selection *sel); | 68 | struct v4l2_subdev_selection *sel); |
| 69 | 69 | ||
| 70 | #endif /* __VSP1_RWPF_H__ */ | 70 | #endif /* __VSP1_RWPF_H__ */ |
diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c index 1129494c7cfc..6310acab60e7 100644 --- a/drivers/media/platform/vsp1/vsp1_sru.c +++ b/drivers/media/platform/vsp1/vsp1_sru.c | |||
| @@ -166,13 +166,14 @@ static int sru_s_stream(struct v4l2_subdev *subdev, int enable) | |||
| 166 | */ | 166 | */ |
| 167 | 167 | ||
| 168 | static int sru_enum_mbus_code(struct v4l2_subdev *subdev, | 168 | static int sru_enum_mbus_code(struct v4l2_subdev *subdev, |
| 169 | struct v4l2_subdev_fh *fh, | 169 | struct v4l2_subdev_pad_config *cfg, |
| 170 | struct v4l2_subdev_mbus_code_enum *code) | 170 | struct v4l2_subdev_mbus_code_enum *code) |
| 171 | { | 171 | { |
| 172 | static const unsigned int codes[] = { | 172 | static const unsigned int codes[] = { |
| 173 | MEDIA_BUS_FMT_ARGB8888_1X32, | 173 | MEDIA_BUS_FMT_ARGB8888_1X32, |
| 174 | MEDIA_BUS_FMT_AYUV8_1X32, | 174 | MEDIA_BUS_FMT_AYUV8_1X32, |
| 175 | }; | 175 | }; |
| 176 | struct vsp1_sru *sru = to_sru(subdev); | ||
| 176 | struct v4l2_mbus_framefmt *format; | 177 | struct v4l2_mbus_framefmt *format; |
| 177 | 178 | ||
| 178 | if (code->pad == SRU_PAD_SINK) { | 179 | if (code->pad == SRU_PAD_SINK) { |
| @@ -187,7 +188,8 @@ static int sru_enum_mbus_code(struct v4l2_subdev *subdev, | |||
| 187 | if (code->index) | 188 | if (code->index) |
| 188 | return -EINVAL; | 189 | return -EINVAL; |
| 189 | 190 | ||
| 190 | format = v4l2_subdev_get_try_format(fh, SRU_PAD_SINK); | 191 | format = vsp1_entity_get_pad_format(&sru->entity, cfg, |
| 192 | SRU_PAD_SINK, code->which); | ||
| 191 | code->code = format->code; | 193 | code->code = format->code; |
| 192 | } | 194 | } |
| 193 | 195 | ||
| @@ -195,12 +197,14 @@ static int sru_enum_mbus_code(struct v4l2_subdev *subdev, | |||
| 195 | } | 197 | } |
| 196 | 198 | ||
| 197 | static int sru_enum_frame_size(struct v4l2_subdev *subdev, | 199 | static int sru_enum_frame_size(struct v4l2_subdev *subdev, |
| 198 | struct v4l2_subdev_fh *fh, | 200 | struct v4l2_subdev_pad_config *cfg, |
| 199 | struct v4l2_subdev_frame_size_enum *fse) | 201 | struct v4l2_subdev_frame_size_enum *fse) |
| 200 | { | 202 | { |
| 203 | struct vsp1_sru *sru = to_sru(subdev); | ||
| 201 | struct v4l2_mbus_framefmt *format; | 204 | struct v4l2_mbus_framefmt *format; |
| 202 | 205 | ||
| 203 | format = v4l2_subdev_get_try_format(fh, SRU_PAD_SINK); | 206 | format = vsp1_entity_get_pad_format(&sru->entity, cfg, |
| 207 | SRU_PAD_SINK, fse->which); | ||
| 204 | 208 | ||
| 205 | if (fse->index || fse->code != format->code) | 209 | if (fse->index || fse->code != format->code) |
| 206 | return -EINVAL; | 210 | return -EINVAL; |
| @@ -226,18 +230,18 @@ static int sru_enum_frame_size(struct v4l2_subdev *subdev, | |||
| 226 | return 0; | 230 | return 0; |
| 227 | } | 231 | } |
| 228 | 232 | ||
| 229 | static int sru_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, | 233 | static int sru_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, |
| 230 | struct v4l2_subdev_format *fmt) | 234 | struct v4l2_subdev_format *fmt) |
| 231 | { | 235 | { |
| 232 | struct vsp1_sru *sru = to_sru(subdev); | 236 | struct vsp1_sru *sru = to_sru(subdev); |
| 233 | 237 | ||
| 234 | fmt->format = *vsp1_entity_get_pad_format(&sru->entity, fh, fmt->pad, | 238 | fmt->format = *vsp1_entity_get_pad_format(&sru->entity, cfg, fmt->pad, |
| 235 | fmt->which); | 239 | fmt->which); |
| 236 | 240 | ||
| 237 | return 0; | 241 | return 0; |
| 238 | } | 242 | } |
| 239 | 243 | ||
| 240 | static void sru_try_format(struct vsp1_sru *sru, struct v4l2_subdev_fh *fh, | 244 | static void sru_try_format(struct vsp1_sru *sru, struct v4l2_subdev_pad_config *cfg, |
| 241 | unsigned int pad, struct v4l2_mbus_framefmt *fmt, | 245 | unsigned int pad, struct v4l2_mbus_framefmt *fmt, |
| 242 | enum v4l2_subdev_format_whence which) | 246 | enum v4l2_subdev_format_whence which) |
| 243 | { | 247 | { |
| @@ -258,7 +262,7 @@ static void sru_try_format(struct vsp1_sru *sru, struct v4l2_subdev_fh *fh, | |||
| 258 | 262 | ||
| 259 | case SRU_PAD_SOURCE: | 263 | case SRU_PAD_SOURCE: |
| 260 | /* The SRU can't perform format conversion. */ | 264 | /* The SRU can't perform format conversion. */ |
| 261 | format = vsp1_entity_get_pad_format(&sru->entity, fh, | 265 | format = vsp1_entity_get_pad_format(&sru->entity, cfg, |
| 262 | SRU_PAD_SINK, which); | 266 | SRU_PAD_SINK, which); |
| 263 | fmt->code = format->code; | 267 | fmt->code = format->code; |
| 264 | 268 | ||
| @@ -288,25 +292,25 @@ static void sru_try_format(struct vsp1_sru *sru, struct v4l2_subdev_fh *fh, | |||
| 288 | fmt->colorspace = V4L2_COLORSPACE_SRGB; | 292 | fmt->colorspace = V4L2_COLORSPACE_SRGB; |
| 289 | } | 293 | } |
| 290 | 294 | ||
| 291 | static int sru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, | 295 | static int sru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, |
| 292 | struct v4l2_subdev_format *fmt) | 296 | struct v4l2_subdev_format *fmt) |
| 293 | { | 297 | { |
| 294 | struct vsp1_sru *sru = to_sru(subdev); | 298 | struct vsp1_sru *sru = to_sru(subdev); |
| 295 | struct v4l2_mbus_framefmt *format; | 299 | struct v4l2_mbus_framefmt *format; |
| 296 | 300 | ||
| 297 | sru_try_format(sru, fh, fmt->pad, &fmt->format, fmt->which); | 301 | sru_try_format(sru, cfg, fmt->pad, &fmt->format, fmt->which); |
| 298 | 302 | ||
| 299 | format = vsp1_entity_get_pad_format(&sru->entity, fh, fmt->pad, | 303 | format = vsp1_entity_get_pad_format(&sru->entity, cfg, fmt->pad, |
| 300 | fmt->which); | 304 | fmt->which); |
| 301 | *format = fmt->format; | 305 | *format = fmt->format; |
| 302 | 306 | ||
| 303 | if (fmt->pad == SRU_PAD_SINK) { | 307 | if (fmt->pad == SRU_PAD_SINK) { |
| 304 | /* Propagate the format to the source pad. */ | 308 | /* Propagate the format to the source pad. */ |
| 305 | format = vsp1_entity_get_pad_format(&sru->entity, fh, | 309 | format = vsp1_entity_get_pad_format(&sru->entity, cfg, |
| 306 | SRU_PAD_SOURCE, fmt->which); | 310 | SRU_PAD_SOURCE, fmt->which); |
| 307 | *format = fmt->format; | 311 | *format = fmt->format; |
| 308 | 312 | ||
| 309 | sru_try_format(sru, fh, SRU_PAD_SOURCE, format, fmt->which); | 313 | sru_try_format(sru, cfg, SRU_PAD_SOURCE, format, fmt->which); |
| 310 | } | 314 | } |
| 311 | 315 | ||
| 312 | return 0; | 316 | return 0; |
diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c index a4afec133800..ccc8243e3493 100644 --- a/drivers/media/platform/vsp1/vsp1_uds.c +++ b/drivers/media/platform/vsp1/vsp1_uds.c | |||
| @@ -169,13 +169,14 @@ static int uds_s_stream(struct v4l2_subdev *subdev, int enable) | |||
| 169 | */ | 169 | */ |
| 170 | 170 | ||
| 171 | static int uds_enum_mbus_code(struct v4l2_subdev *subdev, | 171 | static int uds_enum_mbus_code(struct v4l2_subdev *subdev, |
| 172 | struct v4l2_subdev_fh *fh, | 172 | struct v4l2_subdev_pad_config *cfg, |
| 173 | struct v4l2_subdev_mbus_code_enum *code) | 173 | struct v4l2_subdev_mbus_code_enum *code) |
| 174 | { | 174 | { |
| 175 | static const unsigned int codes[] = { | 175 | static const unsigned int codes[] = { |
| 176 | MEDIA_BUS_FMT_ARGB8888_1X32, | 176 | MEDIA_BUS_FMT_ARGB8888_1X32, |
| 177 | MEDIA_BUS_FMT_AYUV8_1X32, | 177 | MEDIA_BUS_FMT_AYUV8_1X32, |
| 178 | }; | 178 | }; |
| 179 | struct vsp1_uds *uds = to_uds(subdev); | ||
| 179 | 180 | ||
| 180 | if (code->pad == UDS_PAD_SINK) { | 181 | if (code->pad == UDS_PAD_SINK) { |
| 181 | if (code->index >= ARRAY_SIZE(codes)) | 182 | if (code->index >= ARRAY_SIZE(codes)) |
| @@ -191,7 +192,8 @@ static int uds_enum_mbus_code(struct v4l2_subdev *subdev, | |||
| 191 | if (code->index) | 192 | if (code->index) |
| 192 | return -EINVAL; | 193 | return -EINVAL; |
| 193 | 194 | ||
| 194 | format = v4l2_subdev_get_try_format(fh, UDS_PAD_SINK); | 195 | format = vsp1_entity_get_pad_format(&uds->entity, cfg, |
| 196 | UDS_PAD_SINK, code->which); | ||
| 195 | code->code = format->code; | 197 | code->code = format->code; |
| 196 | } | 198 | } |
| 197 | 199 | ||
| @@ -199,12 +201,14 @@ static int uds_enum_mbus_code(struct v4l2_subdev *subdev, | |||
| 199 | } | 201 | } |
| 200 | 202 | ||
| 201 | static int uds_enum_frame_size(struct v4l2_subdev *subdev, | 203 | static int uds_enum_frame_size(struct v4l2_subdev *subdev, |
| 202 | struct v4l2_subdev_fh *fh, | 204 | struct v4l2_subdev_pad_config *cfg, |
| 203 | struct v4l2_subdev_frame_size_enum *fse) | 205 | struct v4l2_subdev_frame_size_enum *fse) |
| 204 | { | 206 | { |
| 207 | struct vsp1_uds *uds = to_uds(subdev); | ||
| 205 | struct v4l2_mbus_framefmt *format; | 208 | struct v4l2_mbus_framefmt *format; |
| 206 | 209 | ||
| 207 | format = v4l2_subdev_get_try_format(fh, UDS_PAD_SINK); | 210 | format = vsp1_entity_get_pad_format(&uds->entity, cfg, |
| 211 | UDS_PAD_SINK, fse->which); | ||
| 208 | 212 | ||
| 209 | if (fse->index || fse->code != format->code) | 213 | if (fse->index || fse->code != format->code) |
| 210 | return -EINVAL; | 214 | return -EINVAL; |
| @@ -224,18 +228,18 @@ static int uds_enum_frame_size(struct v4l2_subdev *subdev, | |||
| 224 | return 0; | 228 | return 0; |
| 225 | } | 229 | } |
| 226 | 230 | ||
| 227 | static int uds_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, | 231 | static int uds_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, |
| 228 | struct v4l2_subdev_format *fmt) | 232 | struct v4l2_subdev_format *fmt) |
| 229 | { | 233 | { |
| 230 | struct vsp1_uds *uds = to_uds(subdev); | 234 | struct vsp1_uds *uds = to_uds(subdev); |
| 231 | 235 | ||
| 232 | fmt->format = *vsp1_entity_get_pad_format(&uds->entity, fh, fmt->pad, | 236 | fmt->format = *vsp1_entity_get_pad_format(&uds->entity, cfg, fmt->pad, |
| 233 | fmt->which); | 237 | fmt->which); |
| 234 | 238 | ||
| 235 | return 0; | 239 | return 0; |
| 236 | } | 240 | } |
| 237 | 241 | ||
| 238 | static void uds_try_format(struct vsp1_uds *uds, struct v4l2_subdev_fh *fh, | 242 | static void uds_try_format(struct vsp1_uds *uds, struct v4l2_subdev_pad_config *cfg, |
| 239 | unsigned int pad, struct v4l2_mbus_framefmt *fmt, | 243 | unsigned int pad, struct v4l2_mbus_framefmt *fmt, |
| 240 | enum v4l2_subdev_format_whence which) | 244 | enum v4l2_subdev_format_whence which) |
| 241 | { | 245 | { |
| @@ -256,7 +260,7 @@ static void uds_try_format(struct vsp1_uds *uds, struct v4l2_subdev_fh *fh, | |||
| 256 | 260 | ||
| 257 | case UDS_PAD_SOURCE: | 261 | case UDS_PAD_SOURCE: |
| 258 | /* The UDS scales but can't perform format conversion. */ | 262 | /* The UDS scales but can't perform format conversion. */ |
| 259 | format = vsp1_entity_get_pad_format(&uds->entity, fh, | 263 | format = vsp1_entity_get_pad_format(&uds->entity, cfg, |
| 260 | UDS_PAD_SINK, which); | 264 | UDS_PAD_SINK, which); |
| 261 | fmt->code = format->code; | 265 | fmt->code = format->code; |
| 262 | 266 | ||
| @@ -271,25 +275,25 @@ static void uds_try_format(struct vsp1_uds *uds, struct v4l2_subdev_fh *fh, | |||
| 271 | fmt->colorspace = V4L2_COLORSPACE_SRGB; | 275 | fmt->colorspace = V4L2_COLORSPACE_SRGB; |
| 272 | } | 276 | } |
| 273 | 277 | ||
| 274 | static int uds_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, | 278 | static int uds_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, |
| 275 | struct v4l2_subdev_format *fmt) | 279 | struct v4l2_subdev_format *fmt) |
| 276 | { | 280 | { |
| 277 | struct vsp1_uds *uds = to_uds(subdev); | 281 | struct vsp1_uds *uds = to_uds(subdev); |
| 278 | struct v4l2_mbus_framefmt *format; | 282 | struct v4l2_mbus_framefmt *format; |
| 279 | 283 | ||
| 280 | uds_try_format(uds, fh, fmt->pad, &fmt->format, fmt->which); | 284 | uds_try_format(uds, cfg, fmt->pad, &fmt->format, fmt->which); |
| 281 | 285 | ||
| 282 | format = vsp1_entity_get_pad_format(&uds->entity, fh, fmt->pad, | 286 | format = vsp1_entity_get_pad_format(&uds->entity, cfg, fmt->pad, |
| 283 | fmt->which); | 287 | fmt->which); |
| 284 | *format = fmt->format; | 288 | *format = fmt->format; |
| 285 | 289 | ||
| 286 | if (fmt->pad == UDS_PAD_SINK) { | 290 | if (fmt->pad == UDS_PAD_SINK) { |
| 287 | /* Propagate the format to the source pad. */ | 291 | /* Propagate the format to the source pad. */ |
| 288 | format = vsp1_entity_get_pad_format(&uds->entity, fh, | 292 | format = vsp1_entity_get_pad_format(&uds->entity, cfg, |
| 289 | UDS_PAD_SOURCE, fmt->which); | 293 | UDS_PAD_SOURCE, fmt->which); |
| 290 | *format = fmt->format; | 294 | *format = fmt->format; |
| 291 | 295 | ||
| 292 | uds_try_format(uds, fh, UDS_PAD_SOURCE, format, fmt->which); | 296 | uds_try_format(uds, cfg, UDS_PAD_SOURCE, format, fmt->which); |
| 293 | } | 297 | } |
| 294 | 298 | ||
| 295 | return 0; | 299 | return 0; |
diff --git a/drivers/media/platform/xilinx/Kconfig b/drivers/media/platform/xilinx/Kconfig new file mode 100644 index 000000000000..d7324c726fc2 --- /dev/null +++ b/drivers/media/platform/xilinx/Kconfig | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | config VIDEO_XILINX | ||
| 2 | tristate "Xilinx Video IP (EXPERIMENTAL)" | ||
| 3 | depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && OF | ||
| 4 | select VIDEOBUF2_DMA_CONTIG | ||
| 5 | ---help--- | ||
| 6 | Driver for Xilinx Video IP Pipelines | ||
| 7 | |||
| 8 | if VIDEO_XILINX | ||
| 9 | |||
| 10 | config VIDEO_XILINX_TPG | ||
| 11 | tristate "Xilinx Video Test Pattern Generator" | ||
| 12 | depends on VIDEO_XILINX | ||
| 13 | select VIDEO_XILINX_VTC | ||
| 14 | ---help--- | ||
| 15 | Driver for the Xilinx Video Test Pattern Generator | ||
| 16 | |||
| 17 | config VIDEO_XILINX_VTC | ||
| 18 | tristate "Xilinx Video Timing Controller" | ||
| 19 | depends on VIDEO_XILINX | ||
| 20 | ---help--- | ||
| 21 | Driver for the Xilinx Video Timing Controller | ||
| 22 | |||
| 23 | endif #VIDEO_XILINX | ||
diff --git a/drivers/media/platform/xilinx/Makefile b/drivers/media/platform/xilinx/Makefile new file mode 100644 index 000000000000..e8a0f2a9f733 --- /dev/null +++ b/drivers/media/platform/xilinx/Makefile | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | xilinx-video-objs += xilinx-dma.o xilinx-vip.o xilinx-vipp.o | ||
| 2 | |||
| 3 | obj-$(CONFIG_VIDEO_XILINX) += xilinx-video.o | ||
| 4 | obj-$(CONFIG_VIDEO_XILINX_TPG) += xilinx-tpg.o | ||
| 5 | obj-$(CONFIG_VIDEO_XILINX_VTC) += xilinx-vtc.o | ||
diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c new file mode 100644 index 000000000000..10209c294168 --- /dev/null +++ b/drivers/media/platform/xilinx/xilinx-dma.c | |||
| @@ -0,0 +1,766 @@ | |||
| 1 | /* | ||
| 2 | * Xilinx Video DMA | ||
| 3 | * | ||
| 4 | * Copyright (C) 2013-2015 Ideas on Board | ||
| 5 | * Copyright (C) 2013-2015 Xilinx, Inc. | ||
| 6 | * | ||
| 7 | * Contacts: Hyun Kwon <hyun.kwon@xilinx.com> | ||
| 8 | * Laurent Pinchart <laurent.pinchart@ideasonboard.com> | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License version 2 as | ||
| 12 | * published by the Free Software Foundation. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include <linux/amba/xilinx_dma.h> | ||
| 16 | #include <linux/lcm.h> | ||
| 17 | #include <linux/list.h> | ||
| 18 | #include <linux/module.h> | ||
| 19 | #include <linux/of.h> | ||
| 20 | #include <linux/slab.h> | ||
| 21 | |||
| 22 | #include <media/v4l2-dev.h> | ||
| 23 | #include <media/v4l2-fh.h> | ||
| 24 | #include <media/v4l2-ioctl.h> | ||
| 25 | #include <media/videobuf2-core.h> | ||
| 26 | #include <media/videobuf2-dma-contig.h> | ||
| 27 | |||
| 28 | #include "xilinx-dma.h" | ||
| 29 | #include "xilinx-vip.h" | ||
| 30 | #include "xilinx-vipp.h" | ||
| 31 | |||
| 32 | #define XVIP_DMA_DEF_FORMAT V4L2_PIX_FMT_YUYV | ||
| 33 | #define XVIP_DMA_DEF_WIDTH 1920 | ||
| 34 | #define XVIP_DMA_DEF_HEIGHT 1080 | ||
| 35 | |||
| 36 | /* Minimum and maximum widths are expressed in bytes */ | ||
| 37 | #define XVIP_DMA_MIN_WIDTH 1U | ||
| 38 | #define XVIP_DMA_MAX_WIDTH 65535U | ||
| 39 | #define XVIP_DMA_MIN_HEIGHT 1U | ||
| 40 | #define XVIP_DMA_MAX_HEIGHT 8191U | ||
| 41 | |||
| 42 | /* ----------------------------------------------------------------------------- | ||
| 43 | * Helper functions | ||
| 44 | */ | ||
| 45 | |||
| 46 | static struct v4l2_subdev * | ||
| 47 | xvip_dma_remote_subdev(struct media_pad *local, u32 *pad) | ||
| 48 | { | ||
| 49 | struct media_pad *remote; | ||
| 50 | |||
| 51 | remote = media_entity_remote_pad(local); | ||
| 52 | if (remote == NULL || | ||
| 53 | media_entity_type(remote->entity) != MEDIA_ENT_T_V4L2_SUBDEV) | ||
| 54 | return NULL; | ||
| 55 | |||
| 56 | if (pad) | ||
| 57 | *pad = remote->index; | ||
| 58 | |||
| 59 | return media_entity_to_v4l2_subdev(remote->entity); | ||
| 60 | } | ||
| 61 | |||
| 62 | static int xvip_dma_verify_format(struct xvip_dma *dma) | ||
| 63 | { | ||
| 64 | struct v4l2_subdev_format fmt; | ||
| 65 | struct v4l2_subdev *subdev; | ||
| 66 | int ret; | ||
| 67 | |||
| 68 | subdev = xvip_dma_remote_subdev(&dma->pad, &fmt.pad); | ||
| 69 | if (subdev == NULL) | ||
| 70 | return -EPIPE; | ||
| 71 | |||
| 72 | fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; | ||
| 73 | ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt); | ||
| 74 | if (ret < 0) | ||
| 75 | return ret == -ENOIOCTLCMD ? -EINVAL : ret; | ||
| 76 | |||
| 77 | if (dma->fmtinfo->code != fmt.format.code || | ||
| 78 | dma->format.height != fmt.format.height || | ||
| 79 | dma->format.width != fmt.format.width || | ||
| 80 | dma->format.colorspace != fmt.format.colorspace) | ||
| 81 | return -EINVAL; | ||
| 82 | |||
| 83 | return 0; | ||
| 84 | } | ||
| 85 | |||
| 86 | /* ----------------------------------------------------------------------------- | ||
| 87 | * Pipeline Stream Management | ||
| 88 | */ | ||
| 89 | |||
| 90 | /** | ||
| 91 | * xvip_pipeline_start_stop - Start ot stop streaming on a pipeline | ||
| 92 | * @pipe: The pipeline | ||
| 93 | * @start: Start (when true) or stop (when false) the pipeline | ||
| 94 | * | ||
| 95 | * Walk the entities chain starting at the pipeline output video node and start | ||
| 96 | * or stop all of them. | ||
| 97 | * | ||
| 98 | * Return: 0 if successful, or the return value of the failed video::s_stream | ||
| 99 | * operation otherwise. | ||
| 100 | */ | ||
| 101 | static int xvip_pipeline_start_stop(struct xvip_pipeline *pipe, bool start) | ||
| 102 | { | ||
| 103 | struct xvip_dma *dma = pipe->output; | ||
| 104 | struct media_entity *entity; | ||
| 105 | struct media_pad *pad; | ||
| 106 | struct v4l2_subdev *subdev; | ||
| 107 | int ret; | ||
| 108 | |||
| 109 | entity = &dma->video.entity; | ||
| 110 | while (1) { | ||
| 111 | pad = &entity->pads[0]; | ||
| 112 | if (!(pad->flags & MEDIA_PAD_FL_SINK)) | ||
| 113 | break; | ||
| 114 | |||
| 115 | pad = media_entity_remote_pad(pad); | ||
| 116 | if (pad == NULL || | ||
| 117 | media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) | ||
| 118 | break; | ||
| 119 | |||
| 120 | entity = pad->entity; | ||
| 121 | subdev = media_entity_to_v4l2_subdev(entity); | ||
| 122 | |||
| 123 | ret = v4l2_subdev_call(subdev, video, s_stream, start); | ||
| 124 | if (start && ret < 0 && ret != -ENOIOCTLCMD) | ||
| 125 | return ret; | ||
| 126 | } | ||
| 127 | |||
| 128 | return 0; | ||
| 129 | } | ||
| 130 | |||
| 131 | /** | ||
| 132 | * xvip_pipeline_set_stream - Enable/disable streaming on a pipeline | ||
| 133 | * @pipe: The pipeline | ||
| 134 | * @on: Turn the stream on when true or off when false | ||
| 135 | * | ||
| 136 | * The pipeline is shared between all DMA engines connect at its input and | ||
| 137 | * output. While the stream state of DMA engines can be controlled | ||
| 138 | * independently, pipelines have a shared stream state that enable or disable | ||
| 139 | * all entities in the pipeline. For this reason the pipeline uses a streaming | ||
| 140 | * counter that tracks the number of DMA engines that have requested the stream | ||
| 141 | * to be enabled. | ||
| 142 | * | ||
| 143 | * When called with the @on argument set to true, this function will increment | ||
| 144 | * the pipeline streaming count. If the streaming count reaches the number of | ||
| 145 | * DMA engines in the pipeline it will enable all entities that belong to the | ||
| 146 | * pipeline. | ||
| 147 | * | ||
| 148 | * Similarly, when called with the @on argument set to false, this function will | ||
| 149 | * decrement the pipeline streaming count and disable all entities in the | ||
| 150 | * pipeline when the streaming count reaches zero. | ||
| 151 | * | ||
| 152 | * Return: 0 if successful, or the return value of the failed video::s_stream | ||
| 153 | * operation otherwise. Stopping the pipeline never fails. The pipeline state is | ||
| 154 | * not updated when the operation fails. | ||
| 155 | */ | ||
| 156 | static int xvip_pipeline_set_stream(struct xvip_pipeline *pipe, bool on) | ||
| 157 | { | ||
| 158 | int ret = 0; | ||
| 159 | |||
| 160 | mutex_lock(&pipe->lock); | ||
| 161 | |||
| 162 | if (on) { | ||
| 163 | if (pipe->stream_count == pipe->num_dmas - 1) { | ||
| 164 | ret = xvip_pipeline_start_stop(pipe, true); | ||
| 165 | if (ret < 0) | ||
| 166 | goto done; | ||
| 167 | } | ||
| 168 | pipe->stream_count++; | ||
| 169 | } else { | ||
| 170 | if (--pipe->stream_count == 0) | ||
| 171 | xvip_pipeline_start_stop(pipe, false); | ||
| 172 | } | ||
| 173 | |||
| 174 | done: | ||
| 175 | mutex_unlock(&pipe->lock); | ||
| 176 | return ret; | ||
| 177 | } | ||
| 178 | |||
| 179 | static int xvip_pipeline_validate(struct xvip_pipeline *pipe, | ||
| 180 | struct xvip_dma *start) | ||
| 181 | { | ||
| 182 | struct media_entity_graph graph; | ||
| 183 | struct media_entity *entity = &start->video.entity; | ||
| 184 | struct media_device *mdev = entity->parent; | ||
| 185 | unsigned int num_inputs = 0; | ||
| 186 | unsigned int num_outputs = 0; | ||
| 187 | |||
| 188 | mutex_lock(&mdev->graph_mutex); | ||
| 189 | |||
| 190 | /* Walk the graph to locate the video nodes. */ | ||
| 191 | media_entity_graph_walk_start(&graph, entity); | ||
| 192 | |||
| 193 | while ((entity = media_entity_graph_walk_next(&graph))) { | ||
| 194 | struct xvip_dma *dma; | ||
| 195 | |||
| 196 | if (entity->type != MEDIA_ENT_T_DEVNODE_V4L) | ||
| 197 | continue; | ||
| 198 | |||
| 199 | dma = to_xvip_dma(media_entity_to_video_device(entity)); | ||
| 200 | |||
| 201 | if (dma->pad.flags & MEDIA_PAD_FL_SINK) { | ||
| 202 | pipe->output = dma; | ||
| 203 | num_outputs++; | ||
| 204 | } else { | ||
| 205 | num_inputs++; | ||
| 206 | } | ||
| 207 | } | ||
| 208 | |||
| 209 | mutex_unlock(&mdev->graph_mutex); | ||
| 210 | |||
| 211 | /* We need exactly one output and zero or one input. */ | ||
| 212 | if (num_outputs != 1 || num_inputs > 1) | ||
| 213 | return -EPIPE; | ||
| 214 | |||
| 215 | pipe->num_dmas = num_inputs + num_outputs; | ||
| 216 | |||
| 217 | return 0; | ||
| 218 | } | ||
| 219 | |||
| 220 | static void __xvip_pipeline_cleanup(struct xvip_pipeline *pipe) | ||
| 221 | { | ||
| 222 | pipe->num_dmas = 0; | ||
| 223 | pipe->output = NULL; | ||
| 224 | } | ||
| 225 | |||
| 226 | /** | ||
| 227 | * xvip_pipeline_cleanup - Cleanup the pipeline after streaming | ||
| 228 | * @pipe: the pipeline | ||
| 229 | * | ||
| 230 | * Decrease the pipeline use count and clean it up if we were the last user. | ||
| 231 | */ | ||
| 232 | static void xvip_pipeline_cleanup(struct xvip_pipeline *pipe) | ||
| 233 | { | ||
| 234 | mutex_lock(&pipe->lock); | ||
| 235 | |||
| 236 | /* If we're the last user clean up the pipeline. */ | ||
| 237 | if (--pipe->use_count == 0) | ||
| 238 | __xvip_pipeline_cleanup(pipe); | ||
| 239 | |||
| 240 | mutex_unlock(&pipe->lock); | ||
| 241 | } | ||
| 242 | |||
| 243 | /** | ||
| 244 | * xvip_pipeline_prepare - Prepare the pipeline for streaming | ||
| 245 | * @pipe: the pipeline | ||
| 246 | * @dma: DMA engine at one end of the pipeline | ||
| 247 | * | ||
| 248 | * Validate the pipeline if no user exists yet, otherwise just increase the use | ||
| 249 | * count. | ||
| 250 | * | ||
| 251 | * Return: 0 if successful or -EPIPE if the pipeline is not valid. | ||
| 252 | */ | ||
| 253 | static int xvip_pipeline_prepare(struct xvip_pipeline *pipe, | ||
| 254 | struct xvip_dma *dma) | ||
| 255 | { | ||
| 256 | int ret; | ||
| 257 | |||
| 258 | mutex_lock(&pipe->lock); | ||
| 259 | |||
| 260 | /* If we're the first user validate and initialize the pipeline. */ | ||
| 261 | if (pipe->use_count == 0) { | ||
| 262 | ret = xvip_pipeline_validate(pipe, dma); | ||
| 263 | if (ret < 0) { | ||
| 264 | __xvip_pipeline_cleanup(pipe); | ||
| 265 | goto done; | ||
| 266 | } | ||
| 267 | } | ||
| 268 | |||
| 269 | pipe->use_count++; | ||
| 270 | ret = 0; | ||
| 271 | |||
| 272 | done: | ||
| 273 | mutex_unlock(&pipe->lock); | ||
| 274 | return ret; | ||
| 275 | } | ||
| 276 | |||
| 277 | /* ----------------------------------------------------------------------------- | ||
| 278 | * videobuf2 queue operations | ||
| 279 | */ | ||
| 280 | |||
| 281 | /** | ||
| 282 | * struct xvip_dma_buffer - Video DMA buffer | ||
| 283 | * @buf: vb2 buffer base object | ||
| 284 | * @queue: buffer list entry in the DMA engine queued buffers list | ||
| 285 | * @dma: DMA channel that uses the buffer | ||
| 286 | */ | ||
| 287 | struct xvip_dma_buffer { | ||
| 288 | struct vb2_buffer buf; | ||
| 289 | struct list_head queue; | ||
| 290 | struct xvip_dma *dma; | ||
| 291 | }; | ||
| 292 | |||
| 293 | #define to_xvip_dma_buffer(vb) container_of(vb, struct xvip_dma_buffer, buf) | ||
| 294 | |||
| 295 | static void xvip_dma_complete(void *param) | ||
| 296 | { | ||
| 297 | struct xvip_dma_buffer *buf = param; | ||
| 298 | struct xvip_dma *dma = buf->dma; | ||
| 299 | |||
| 300 | spin_lock(&dma->queued_lock); | ||
| 301 | list_del(&buf->queue); | ||
| 302 | spin_unlock(&dma->queued_lock); | ||
| 303 | |||
| 304 | buf->buf.v4l2_buf.field = V4L2_FIELD_NONE; | ||
| 305 | buf->buf.v4l2_buf.sequence = dma->sequence++; | ||
| 306 | v4l2_get_timestamp(&buf->buf.v4l2_buf.timestamp); | ||
| 307 | vb2_set_plane_payload(&buf->buf, 0, dma->format.sizeimage); | ||
| 308 | vb2_buffer_done(&buf->buf, VB2_BUF_STATE_DONE); | ||
| 309 | } | ||
| 310 | |||
| 311 | static int | ||
| 312 | xvip_dma_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, | ||
| 313 | unsigned int *nbuffers, unsigned int *nplanes, | ||
| 314 | unsigned int sizes[], void *alloc_ctxs[]) | ||
| 315 | { | ||
| 316 | struct xvip_dma *dma = vb2_get_drv_priv(vq); | ||
| 317 | |||
| 318 | /* Make sure the image size is large enough. */ | ||
| 319 | if (fmt && fmt->fmt.pix.sizeimage < dma->format.sizeimage) | ||
| 320 | return -EINVAL; | ||
| 321 | |||
| 322 | *nplanes = 1; | ||
| 323 | |||
| 324 | sizes[0] = fmt ? fmt->fmt.pix.sizeimage : dma->format.sizeimage; | ||
| 325 | alloc_ctxs[0] = dma->alloc_ctx; | ||
| 326 | |||
| 327 | return 0; | ||
| 328 | } | ||
| 329 | |||
| 330 | static int xvip_dma_buffer_prepare(struct vb2_buffer *vb) | ||
| 331 | { | ||
| 332 | struct xvip_dma *dma = vb2_get_drv_priv(vb->vb2_queue); | ||
| 333 | struct xvip_dma_buffer *buf = to_xvip_dma_buffer(vb); | ||
| 334 | |||
| 335 | buf->dma = dma; | ||
| 336 | |||
| 337 | return 0; | ||
| 338 | } | ||
| 339 | |||
| 340 | static void xvip_dma_buffer_queue(struct vb2_buffer *vb) | ||
| 341 | { | ||
| 342 | struct xvip_dma *dma = vb2_get_drv_priv(vb->vb2_queue); | ||
| 343 | struct xvip_dma_buffer *buf = to_xvip_dma_buffer(vb); | ||
| 344 | struct dma_async_tx_descriptor *desc; | ||
| 345 | dma_addr_t addr = vb2_dma_contig_plane_dma_addr(vb, 0); | ||
| 346 | u32 flags; | ||
| 347 | |||
| 348 | if (dma->queue.type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { | ||
| 349 | flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK; | ||
| 350 | dma->xt.dir = DMA_DEV_TO_MEM; | ||
| 351 | dma->xt.src_sgl = false; | ||
| 352 | dma->xt.dst_sgl = true; | ||
| 353 | dma->xt.dst_start = addr; | ||
| 354 | } else { | ||
| 355 | flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK; | ||
| 356 | dma->xt.dir = DMA_MEM_TO_DEV; | ||
| 357 | dma->xt.src_sgl = true; | ||
| 358 | dma->xt.dst_sgl = false; | ||
| 359 | dma->xt.src_start = addr; | ||
| 360 | } | ||
| 361 | |||
| 362 | dma->xt.frame_size = 1; | ||
| 363 | dma->sgl[0].size = dma->format.width * dma->fmtinfo->bpp; | ||
| 364 | dma->sgl[0].icg = dma->format.bytesperline - dma->sgl[0].size; | ||
| 365 | dma->xt.numf = dma->format.height; | ||
| 366 | |||
| 367 | desc = dmaengine_prep_interleaved_dma(dma->dma, &dma->xt, flags); | ||
| 368 | if (!desc) { | ||
| 369 | dev_err(dma->xdev->dev, "Failed to prepare DMA transfer\n"); | ||
| 370 | vb2_buffer_done(&buf->buf, VB2_BUF_STATE_ERROR); | ||
| 371 | return; | ||
| 372 | } | ||
| 373 | desc->callback = xvip_dma_complete; | ||
| 374 | desc->callback_param = buf; | ||
| 375 | |||
| 376 | spin_lock_irq(&dma->queued_lock); | ||
| 377 | list_add_tail(&buf->queue, &dma->queued_bufs); | ||
| 378 | spin_unlock_irq(&dma->queued_lock); | ||
| 379 | |||
| 380 | dmaengine_submit(desc); | ||
| 381 | |||
| 382 | if (vb2_is_streaming(&dma->queue)) | ||
| 383 | dma_async_issue_pending(dma->dma); | ||
| 384 | } | ||
| 385 | |||
| 386 | static int xvip_dma_start_streaming(struct vb2_queue *vq, unsigned int count) | ||
| 387 | { | ||
| 388 | struct xvip_dma *dma = vb2_get_drv_priv(vq); | ||
| 389 | struct xvip_dma_buffer *buf, *nbuf; | ||
| 390 | struct xvip_pipeline *pipe; | ||
| 391 | int ret; | ||
| 392 | |||
| 393 | dma->sequence = 0; | ||
| 394 | |||
| 395 | /* | ||
| 396 | * Start streaming on the pipeline. No link touching an entity in the | ||
| 397 | * pipeline can be activated or deactivated once streaming is started. | ||
| 398 | * | ||
| 399 | * Use the pipeline object embedded in the first DMA object that starts | ||
| 400 | * streaming. | ||
| 401 | */ | ||
| 402 | pipe = dma->video.entity.pipe | ||
| 403 | ? to_xvip_pipeline(&dma->video.entity) : &dma->pipe; | ||
| 404 | |||
| 405 | ret = media_entity_pipeline_start(&dma->video.entity, &pipe->pipe); | ||
| 406 | if (ret < 0) | ||
| 407 | goto error; | ||
| 408 | |||
| 409 | /* Verify that the configured format matches the output of the | ||
| 410 | * connected subdev. | ||
| 411 | */ | ||
| 412 | ret = xvip_dma_verify_format(dma); | ||
| 413 | if (ret < 0) | ||
| 414 | goto error_stop; | ||
| 415 | |||
| 416 | ret = xvip_pipeline_prepare(pipe, dma); | ||
| 417 | if (ret < 0) | ||
| 418 | goto error_stop; | ||
| 419 | |||
| 420 | /* Start the DMA engine. This must be done before starting the blocks | ||
| 421 | * in the pipeline to avoid DMA synchronization issues. | ||
| 422 | */ | ||
| 423 | dma_async_issue_pending(dma->dma); | ||
| 424 | |||
| 425 | /* Start the pipeline. */ | ||
| 426 | xvip_pipeline_set_stream(pipe, true); | ||
| 427 | |||
| 428 | return 0; | ||
| 429 | |||
| 430 | error_stop: | ||
| 431 | media_entity_pipeline_stop(&dma->video.entity); | ||
| 432 | |||
| 433 | error: | ||
| 434 | /* Give back all queued buffers to videobuf2. */ | ||
| 435 | spin_lock_irq(&dma->queued_lock); | ||
| 436 | list_for_each_entry_safe(buf, nbuf, &dma->queued_bufs, queue) { | ||
| 437 | vb2_buffer_done(&buf->buf, VB2_BUF_STATE_QUEUED); | ||
| 438 | list_del(&buf->queue); | ||
| 439 | } | ||
| 440 | spin_unlock_irq(&dma->queued_lock); | ||
| 441 | |||
| 442 | return ret; | ||
| 443 | } | ||
| 444 | |||
| 445 | static void xvip_dma_stop_streaming(struct vb2_queue *vq) | ||
| 446 | { | ||
| 447 | struct xvip_dma *dma = vb2_get_drv_priv(vq); | ||
| 448 | struct xvip_pipeline *pipe = to_xvip_pipeline(&dma->video.entity); | ||
| 449 | struct xvip_dma_buffer *buf, *nbuf; | ||
| 450 | |||
| 451 | /* Stop the pipeline. */ | ||
| 452 | xvip_pipeline_set_stream(pipe, false); | ||
| 453 | |||
| 454 | /* Stop and reset the DMA engine. */ | ||
| 455 | dmaengine_terminate_all(dma->dma); | ||
| 456 | |||
| 457 | /* Cleanup the pipeline and mark it as being stopped. */ | ||
| 458 | xvip_pipeline_cleanup(pipe); | ||
| 459 | media_entity_pipeline_stop(&dma->video.entity); | ||
| 460 | |||
| 461 | /* Give back all queued buffers to videobuf2. */ | ||
| 462 | spin_lock_irq(&dma->queued_lock); | ||
| 463 | list_for_each_entry_safe(buf, nbuf, &dma->queued_bufs, queue) { | ||
| 464 | vb2_buffer_done(&buf->buf, VB2_BUF_STATE_ERROR); | ||
| 465 | list_del(&buf->queue); | ||
| 466 | } | ||
| 467 | spin_unlock_irq(&dma->queued_lock); | ||
| 468 | } | ||
| 469 | |||
| 470 | static struct vb2_ops xvip_dma_queue_qops = { | ||
| 471 | .queue_setup = xvip_dma_queue_setup, | ||
| 472 | .buf_prepare = xvip_dma_buffer_prepare, | ||
| 473 | .buf_queue = xvip_dma_buffer_queue, | ||
| 474 | .wait_prepare = vb2_ops_wait_prepare, | ||
| 475 | .wait_finish = vb2_ops_wait_finish, | ||
| 476 | .start_streaming = xvip_dma_start_streaming, | ||
| 477 | .stop_streaming = xvip_dma_stop_streaming, | ||
| 478 | }; | ||
| 479 | |||
| 480 | /* ----------------------------------------------------------------------------- | ||
| 481 | * V4L2 ioctls | ||
| 482 | */ | ||
| 483 | |||
| 484 | static int | ||
| 485 | xvip_dma_querycap(struct file *file, void *fh, struct v4l2_capability *cap) | ||
| 486 | { | ||
| 487 | struct v4l2_fh *vfh = file->private_data; | ||
| 488 | struct xvip_dma *dma = to_xvip_dma(vfh->vdev); | ||
| 489 | |||
| 490 | cap->capabilities = V4L2_CAP_DEVICE_CAPS | V4L2_CAP_STREAMING | ||
| 491 | | dma->xdev->v4l2_caps; | ||
| 492 | |||
| 493 | if (dma->queue.type == V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
| 494 | cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; | ||
| 495 | else | ||
| 496 | cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; | ||
| 497 | |||
| 498 | strlcpy(cap->driver, "xilinx-vipp", sizeof(cap->driver)); | ||
| 499 | strlcpy(cap->card, dma->video.name, sizeof(cap->card)); | ||
| 500 | snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s:%u", | ||
| 501 | dma->xdev->dev->of_node->name, dma->port); | ||
| 502 | |||
| 503 | return 0; | ||
| 504 | } | ||
| 505 | |||
| 506 | /* FIXME: without this callback function, some applications are not configured | ||
| 507 | * with correct formats, and it results in frames in wrong format. Whether this | ||
| 508 | * callback needs to be required is not clearly defined, so it should be | ||
| 509 | * clarified through the mailing list. | ||
| 510 | */ | ||
| 511 | static int | ||
| 512 | xvip_dma_enum_format(struct file *file, void *fh, struct v4l2_fmtdesc *f) | ||
| 513 | { | ||
| 514 | struct v4l2_fh *vfh = file->private_data; | ||
| 515 | struct xvip_dma *dma = to_xvip_dma(vfh->vdev); | ||
| 516 | |||
| 517 | if (f->index > 0) | ||
| 518 | return -EINVAL; | ||
| 519 | |||
| 520 | f->pixelformat = dma->format.pixelformat; | ||
| 521 | strlcpy(f->description, dma->fmtinfo->description, | ||
| 522 | sizeof(f->description)); | ||
| 523 | |||
| 524 | return 0; | ||
| 525 | } | ||
| 526 | |||
| 527 | static int | ||
| 528 | xvip_dma_get_format(struct file *file, void *fh, struct v4l2_format *format) | ||
| 529 | { | ||
| 530 | struct v4l2_fh *vfh = file->private_data; | ||
| 531 | struct xvip_dma *dma = to_xvip_dma(vfh->vdev); | ||
| 532 | |||
| 533 | format->fmt.pix = dma->format; | ||
| 534 | |||
| 535 | return 0; | ||
| 536 | } | ||
| 537 | |||
| 538 | static void | ||
| 539 | __xvip_dma_try_format(struct xvip_dma *dma, struct v4l2_pix_format *pix, | ||
| 540 | const struct xvip_video_format **fmtinfo) | ||
| 541 | { | ||
| 542 | const struct xvip_video_format *info; | ||
| 543 | unsigned int min_width; | ||
| 544 | unsigned int max_width; | ||
| 545 | unsigned int min_bpl; | ||
| 546 | unsigned int max_bpl; | ||
| 547 | unsigned int width; | ||
| 548 | unsigned int align; | ||
| 549 | unsigned int bpl; | ||
| 550 | |||
| 551 | /* Retrieve format information and select the default format if the | ||
| 552 | * requested format isn't supported. | ||
| 553 | */ | ||
| 554 | info = xvip_get_format_by_fourcc(pix->pixelformat); | ||
| 555 | if (IS_ERR(info)) | ||
| 556 | info = xvip_get_format_by_fourcc(XVIP_DMA_DEF_FORMAT); | ||
| 557 | |||
| 558 | pix->pixelformat = info->fourcc; | ||
| 559 | pix->field = V4L2_FIELD_NONE; | ||
| 560 | |||
| 561 | /* The transfer alignment requirements are expressed in bytes. Compute | ||
| 562 | * the minimum and maximum values, clamp the requested width and convert | ||
| 563 | * it back to pixels. | ||
| 564 | */ | ||
| 565 | align = lcm(dma->align, info->bpp); | ||
| 566 | min_width = roundup(XVIP_DMA_MIN_WIDTH, align); | ||
| 567 | max_width = rounddown(XVIP_DMA_MAX_WIDTH, align); | ||
| 568 | width = rounddown(pix->width * info->bpp, align); | ||
| 569 | |||
| 570 | pix->width = clamp(width, min_width, max_width) / info->bpp; | ||
| 571 | pix->height = clamp(pix->height, XVIP_DMA_MIN_HEIGHT, | ||
| 572 | XVIP_DMA_MAX_HEIGHT); | ||
| 573 | |||
| 574 | /* Clamp the requested bytes per line value. If the maximum bytes per | ||
| 575 | * line value is zero, the module doesn't support user configurable line | ||
| 576 | * sizes. Override the requested value with the minimum in that case. | ||
| 577 | */ | ||
| 578 | min_bpl = pix->width * info->bpp; | ||
| 579 | max_bpl = rounddown(XVIP_DMA_MAX_WIDTH, dma->align); | ||
| 580 | bpl = rounddown(pix->bytesperline, dma->align); | ||
| 581 | |||
| 582 | pix->bytesperline = clamp(bpl, min_bpl, max_bpl); | ||
| 583 | pix->sizeimage = pix->bytesperline * pix->height; | ||
| 584 | |||
| 585 | if (fmtinfo) | ||
| 586 | *fmtinfo = info; | ||
| 587 | } | ||
| 588 | |||
| 589 | static int | ||
| 590 | xvip_dma_try_format(struct file *file, void *fh, struct v4l2_format *format) | ||
| 591 | { | ||
| 592 | struct v4l2_fh *vfh = file->private_data; | ||
| 593 | struct xvip_dma *dma = to_xvip_dma(vfh->vdev); | ||
| 594 | |||
| 595 | __xvip_dma_try_format(dma, &format->fmt.pix, NULL); | ||
| 596 | return 0; | ||
| 597 | } | ||
| 598 | |||
| 599 | static int | ||
| 600 | xvip_dma_set_format(struct file *file, void *fh, struct v4l2_format *format) | ||
| 601 | { | ||
| 602 | struct v4l2_fh *vfh = file->private_data; | ||
| 603 | struct xvip_dma *dma = to_xvip_dma(vfh->vdev); | ||
| 604 | const struct xvip_video_format *info; | ||
| 605 | |||
| 606 | __xvip_dma_try_format(dma, &format->fmt.pix, &info); | ||
| 607 | |||
| 608 | if (vb2_is_busy(&dma->queue)) | ||
| 609 | return -EBUSY; | ||
| 610 | |||
| 611 | dma->format = format->fmt.pix; | ||
| 612 | dma->fmtinfo = info; | ||
| 613 | |||
| 614 | return 0; | ||
| 615 | } | ||
| 616 | |||
| 617 | static const struct v4l2_ioctl_ops xvip_dma_ioctl_ops = { | ||
| 618 | .vidioc_querycap = xvip_dma_querycap, | ||
| 619 | .vidioc_enum_fmt_vid_cap = xvip_dma_enum_format, | ||
| 620 | .vidioc_g_fmt_vid_cap = xvip_dma_get_format, | ||
| 621 | .vidioc_g_fmt_vid_out = xvip_dma_get_format, | ||
| 622 | .vidioc_s_fmt_vid_cap = xvip_dma_set_format, | ||
| 623 | .vidioc_s_fmt_vid_out = xvip_dma_set_format, | ||
| 624 | .vidioc_try_fmt_vid_cap = xvip_dma_try_format, | ||
| 625 | .vidioc_try_fmt_vid_out = xvip_dma_try_format, | ||
| 626 | .vidioc_reqbufs = vb2_ioctl_reqbufs, | ||
| 627 | .vidioc_querybuf = vb2_ioctl_querybuf, | ||
| 628 | .vidioc_qbuf = vb2_ioctl_qbuf, | ||
| 629 | .vidioc_dqbuf = vb2_ioctl_dqbuf, | ||
| 630 | .vidioc_create_bufs = vb2_ioctl_create_bufs, | ||
| 631 | .vidioc_expbuf = vb2_ioctl_expbuf, | ||
| 632 | .vidioc_streamon = vb2_ioctl_streamon, | ||
| 633 | .vidioc_streamoff = vb2_ioctl_streamoff, | ||
| 634 | }; | ||
| 635 | |||
| 636 | /* ----------------------------------------------------------------------------- | ||
| 637 | * V4L2 file operations | ||
| 638 | */ | ||
| 639 | |||
| 640 | static const struct v4l2_file_operations xvip_dma_fops = { | ||
| 641 | .owner = THIS_MODULE, | ||
| 642 | .unlocked_ioctl = video_ioctl2, | ||
| 643 | .open = v4l2_fh_open, | ||
| 644 | .release = vb2_fop_release, | ||
| 645 | .poll = vb2_fop_poll, | ||
| 646 | .mmap = vb2_fop_mmap, | ||
| 647 | }; | ||
| 648 | |||
| 649 | /* ----------------------------------------------------------------------------- | ||
| 650 | * Xilinx Video DMA Core | ||
| 651 | */ | ||
| 652 | |||
| 653 | int xvip_dma_init(struct xvip_composite_device *xdev, struct xvip_dma *dma, | ||
| 654 | enum v4l2_buf_type type, unsigned int port) | ||
| 655 | { | ||
| 656 | char name[14]; | ||
| 657 | int ret; | ||
| 658 | |||
| 659 | dma->xdev = xdev; | ||
| 660 | dma->port = port; | ||
| 661 | mutex_init(&dma->lock); | ||
| 662 | mutex_init(&dma->pipe.lock); | ||
| 663 | INIT_LIST_HEAD(&dma->queued_bufs); | ||
| 664 | spin_lock_init(&dma->queued_lock); | ||
| 665 | |||
| 666 | dma->fmtinfo = xvip_get_format_by_fourcc(XVIP_DMA_DEF_FORMAT); | ||
| 667 | dma->format.pixelformat = dma->fmtinfo->fourcc; | ||
| 668 | dma->format.colorspace = V4L2_COLORSPACE_SRGB; | ||
| 669 | dma->format.field = V4L2_FIELD_NONE; | ||
| 670 | dma->format.width = XVIP_DMA_DEF_WIDTH; | ||
| 671 | dma->format.height = XVIP_DMA_DEF_HEIGHT; | ||
| 672 | dma->format.bytesperline = dma->format.width * dma->fmtinfo->bpp; | ||
| 673 | dma->format.sizeimage = dma->format.bytesperline * dma->format.height; | ||
| 674 | |||
| 675 | /* Initialize the media entity... */ | ||
| 676 | dma->pad.flags = type == V4L2_BUF_TYPE_VIDEO_CAPTURE | ||
| 677 | ? MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE; | ||
| 678 | |||
| 679 | ret = media_entity_init(&dma->video.entity, 1, &dma->pad, 0); | ||
| 680 | if (ret < 0) | ||
| 681 | goto error; | ||
| 682 | |||
| 683 | /* ... and the video node... */ | ||
| 684 | dma->video.fops = &xvip_dma_fops; | ||
| 685 | dma->video.v4l2_dev = &xdev->v4l2_dev; | ||
| 686 | dma->video.queue = &dma->queue; | ||
| 687 | snprintf(dma->video.name, sizeof(dma->video.name), "%s %s %u", | ||
| 688 | xdev->dev->of_node->name, | ||
| 689 | type == V4L2_BUF_TYPE_VIDEO_CAPTURE ? "output" : "input", | ||
| 690 | port); | ||
| 691 | dma->video.vfl_type = VFL_TYPE_GRABBER; | ||
| 692 | dma->video.vfl_dir = type == V4L2_BUF_TYPE_VIDEO_CAPTURE | ||
| 693 | ? VFL_DIR_RX : VFL_DIR_TX; | ||
| 694 | dma->video.release = video_device_release_empty; | ||
| 695 | dma->video.ioctl_ops = &xvip_dma_ioctl_ops; | ||
| 696 | dma->video.lock = &dma->lock; | ||
| 697 | |||
| 698 | video_set_drvdata(&dma->video, dma); | ||
| 699 | |||
| 700 | /* ... and the buffers queue... */ | ||
| 701 | dma->alloc_ctx = vb2_dma_contig_init_ctx(dma->xdev->dev); | ||
| 702 | if (IS_ERR(dma->alloc_ctx)) | ||
| 703 | goto error; | ||
| 704 | |||
| 705 | /* Don't enable VB2_READ and VB2_WRITE, as using the read() and write() | ||
| 706 | * V4L2 APIs would be inefficient. Testing on the command line with a | ||
| 707 | * 'cat /dev/video?' thus won't be possible, but given that the driver | ||
| 708 | * anyway requires a test tool to setup the pipeline before any video | ||
| 709 | * stream can be started, requiring a specific V4L2 test tool as well | ||
| 710 | * instead of 'cat' isn't really a drawback. | ||
| 711 | */ | ||
| 712 | dma->queue.type = type; | ||
| 713 | dma->queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; | ||
| 714 | dma->queue.lock = &dma->lock; | ||
| 715 | dma->queue.drv_priv = dma; | ||
| 716 | dma->queue.buf_struct_size = sizeof(struct xvip_dma_buffer); | ||
| 717 | dma->queue.ops = &xvip_dma_queue_qops; | ||
| 718 | dma->queue.mem_ops = &vb2_dma_contig_memops; | ||
| 719 | dma->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC | ||
| 720 | | V4L2_BUF_FLAG_TSTAMP_SRC_EOF; | ||
| 721 | ret = vb2_queue_init(&dma->queue); | ||
| 722 | if (ret < 0) { | ||
| 723 | dev_err(dma->xdev->dev, "failed to initialize VB2 queue\n"); | ||
| 724 | goto error; | ||
| 725 | } | ||
| 726 | |||
| 727 | /* ... and the DMA channel. */ | ||
| 728 | sprintf(name, "port%u", port); | ||
| 729 | dma->dma = dma_request_slave_channel(dma->xdev->dev, name); | ||
| 730 | if (dma->dma == NULL) { | ||
| 731 | dev_err(dma->xdev->dev, "no VDMA channel found\n"); | ||
| 732 | ret = -ENODEV; | ||
| 733 | goto error; | ||
| 734 | } | ||
| 735 | |||
| 736 | dma->align = 1 << dma->dma->device->copy_align; | ||
| 737 | |||
| 738 | ret = video_register_device(&dma->video, VFL_TYPE_GRABBER, -1); | ||
| 739 | if (ret < 0) { | ||
| 740 | dev_err(dma->xdev->dev, "failed to register video device\n"); | ||
| 741 | goto error; | ||
| 742 | } | ||
| 743 | |||
| 744 | return 0; | ||
| 745 | |||
| 746 | error: | ||
| 747 | xvip_dma_cleanup(dma); | ||
| 748 | return ret; | ||
| 749 | } | ||
| 750 | |||
| 751 | void xvip_dma_cleanup(struct xvip_dma *dma) | ||
| 752 | { | ||
| 753 | if (video_is_registered(&dma->video)) | ||
| 754 | video_unregister_device(&dma->video); | ||
| 755 | |||
| 756 | if (dma->dma) | ||
| 757 | dma_release_channel(dma->dma); | ||
| 758 | |||
| 759 | if (!IS_ERR_OR_NULL(dma->alloc_ctx)) | ||
| 760 | vb2_dma_contig_cleanup_ctx(dma->alloc_ctx); | ||
| 761 | |||
| 762 | media_entity_cleanup(&dma->video.entity); | ||
| 763 | |||
| 764 | mutex_destroy(&dma->lock); | ||
| 765 | mutex_destroy(&dma->pipe.lock); | ||
| 766 | } | ||
diff --git a/drivers/media/platform/xilinx/xilinx-dma.h b/drivers/media/platform/xilinx/xilinx-dma.h new file mode 100644 index 000000000000..a540111f8d3d --- /dev/null +++ b/drivers/media/platform/xilinx/xilinx-dma.h | |||
| @@ -0,0 +1,109 @@ | |||
| 1 | /* | ||
| 2 | * Xilinx Video DMA | ||
| 3 | * | ||
| 4 | * Copyright (C) 2013-2015 Ideas on Board | ||
| 5 | * Copyright (C) 2013-2015 Xilinx, Inc. | ||
| 6 | * | ||
| 7 | * Contacts: Hyun Kwon <hyun.kwon@xilinx.com> | ||
| 8 | * Laurent Pinchart <laurent.pinchart@ideasonboard.com> | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License version 2 as | ||
| 12 | * published by the Free Software Foundation. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #ifndef __XILINX_VIP_DMA_H__ | ||
| 16 | #define __XILINX_VIP_DMA_H__ | ||
| 17 | |||
| 18 | #include <linux/dmaengine.h> | ||
| 19 | #include <linux/mutex.h> | ||
| 20 | #include <linux/spinlock.h> | ||
| 21 | #include <linux/videodev2.h> | ||
| 22 | |||
| 23 | #include <media/media-entity.h> | ||
| 24 | #include <media/v4l2-dev.h> | ||
| 25 | #include <media/videobuf2-core.h> | ||
| 26 | |||
| 27 | struct dma_chan; | ||
| 28 | struct xvip_composite_device; | ||
| 29 | struct xvip_video_format; | ||
| 30 | |||
| 31 | /** | ||
| 32 | * struct xvip_pipeline - Xilinx Video IP pipeline structure | ||
| 33 | * @pipe: media pipeline | ||
| 34 | * @lock: protects the pipeline @stream_count | ||
| 35 | * @use_count: number of DMA engines using the pipeline | ||
| 36 | * @stream_count: number of DMA engines currently streaming | ||
| 37 | * @num_dmas: number of DMA engines in the pipeline | ||
| 38 | * @output: DMA engine at the output of the pipeline | ||
| 39 | */ | ||
| 40 | struct xvip_pipeline { | ||
| 41 | struct media_pipeline pipe; | ||
| 42 | |||
| 43 | struct mutex lock; | ||
| 44 | unsigned int use_count; | ||
| 45 | unsigned int stream_count; | ||
| 46 | |||
| 47 | unsigned int num_dmas; | ||
| 48 | struct xvip_dma *output; | ||
| 49 | }; | ||
| 50 | |||
| 51 | static inline struct xvip_pipeline *to_xvip_pipeline(struct media_entity *e) | ||
| 52 | { | ||
| 53 | return container_of(e->pipe, struct xvip_pipeline, pipe); | ||
| 54 | } | ||
| 55 | |||
| 56 | /** | ||
| 57 | * struct xvip_dma - Video DMA channel | ||
| 58 | * @list: list entry in a composite device dmas list | ||
| 59 | * @video: V4L2 video device associated with the DMA channel | ||
| 60 | * @pad: media pad for the video device entity | ||
| 61 | * @xdev: composite device the DMA channel belongs to | ||
| 62 | * @pipe: pipeline belonging to the DMA channel | ||
| 63 | * @port: composite device DT node port number for the DMA channel | ||
| 64 | * @lock: protects the @format, @fmtinfo and @queue fields | ||
| 65 | * @format: active V4L2 pixel format | ||
| 66 | * @fmtinfo: format information corresponding to the active @format | ||
| 67 | * @queue: vb2 buffers queue | ||
| 68 | * @alloc_ctx: allocation context for the vb2 @queue | ||
| 69 | * @sequence: V4L2 buffers sequence number | ||
| 70 | * @queued_bufs: list of queued buffers | ||
| 71 | * @queued_lock: protects the buf_queued list | ||
| 72 | * @dma: DMA engine channel | ||
| 73 | * @align: transfer alignment required by the DMA channel (in bytes) | ||
| 74 | * @xt: dma interleaved template for dma configuration | ||
| 75 | * @sgl: data chunk structure for dma_interleaved_template | ||
| 76 | */ | ||
| 77 | struct xvip_dma { | ||
| 78 | struct list_head list; | ||
| 79 | struct video_device video; | ||
| 80 | struct media_pad pad; | ||
| 81 | |||
| 82 | struct xvip_composite_device *xdev; | ||
| 83 | struct xvip_pipeline pipe; | ||
| 84 | unsigned int port; | ||
| 85 | |||
| 86 | struct mutex lock; | ||
| 87 | struct v4l2_pix_format format; | ||
| 88 | const struct xvip_video_format *fmtinfo; | ||
| 89 | |||
| 90 | struct vb2_queue queue; | ||
| 91 | void *alloc_ctx; | ||
| 92 | unsigned int sequence; | ||
| 93 | |||
| 94 | struct list_head queued_bufs; | ||
| 95 | spinlock_t queued_lock; | ||
| 96 | |||
| 97 | struct dma_chan *dma; | ||
| 98 | unsigned int align; | ||
| 99 | struct dma_interleaved_template xt; | ||
| 100 | struct data_chunk sgl[1]; | ||
| 101 | }; | ||
| 102 | |||
| 103 | #define to_xvip_dma(vdev) container_of(vdev, struct xvip_dma, video) | ||
| 104 | |||
| 105 | int xvip_dma_init(struct xvip_composite_device *xdev, struct xvip_dma *dma, | ||
| 106 | enum v4l2_buf_type type, unsigned int port); | ||
| 107 | void xvip_dma_cleanup(struct xvip_dma *dma); | ||
| 108 | |||
| 109 | #endif /* __XILINX_VIP_DMA_H__ */ | ||
diff --git a/drivers/media/platform/xilinx/xilinx-tpg.c b/drivers/media/platform/xilinx/xilinx-tpg.c new file mode 100644 index 000000000000..b5f7d5ecb7f6 --- /dev/null +++ b/drivers/media/platform/xilinx/xilinx-tpg.c | |||
| @@ -0,0 +1,931 @@ | |||
| 1 | /* | ||
| 2 | * Xilinx Test Pattern Generator | ||
| 3 | * | ||
| 4 | * Copyright (C) 2013-2015 Ideas on Board | ||
| 5 | * Copyright (C) 2013-2015 Xilinx, Inc. | ||
| 6 | * | ||
| 7 | * Contacts: Hyun Kwon <hyun.kwon@xilinx.com> | ||
| 8 | * Laurent Pinchart <laurent.pinchart@ideasonboard.com> | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License version 2 as | ||
| 12 | * published by the Free Software Foundation. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include <linux/device.h> | ||
| 16 | #include <linux/gpio/consumer.h> | ||
| 17 | #include <linux/module.h> | ||
| 18 | #include <linux/of.h> | ||
| 19 | #include <linux/platform_device.h> | ||
| 20 | #include <linux/xilinx-v4l2-controls.h> | ||
| 21 | |||
| 22 | #include <media/v4l2-async.h> | ||
| 23 | #include <media/v4l2-ctrls.h> | ||
| 24 | #include <media/v4l2-subdev.h> | ||
| 25 | |||
| 26 | #include "xilinx-vip.h" | ||
| 27 | #include "xilinx-vtc.h" | ||
| 28 | |||
| 29 | #define XTPG_CTRL_STATUS_SLAVE_ERROR (1 << 16) | ||
| 30 | #define XTPG_CTRL_IRQ_SLAVE_ERROR (1 << 16) | ||
| 31 | |||
| 32 | #define XTPG_PATTERN_CONTROL 0x0100 | ||
| 33 | #define XTPG_PATTERN_MASK (0xf << 0) | ||
| 34 | #define XTPG_PATTERN_CONTROL_CROSS_HAIRS (1 << 4) | ||
| 35 | #define XTPG_PATTERN_CONTROL_MOVING_BOX (1 << 5) | ||
| 36 | #define XTPG_PATTERN_CONTROL_COLOR_MASK_SHIFT 6 | ||
| 37 | #define XTPG_PATTERN_CONTROL_COLOR_MASK_MASK (0xf << 6) | ||
| 38 | #define XTPG_PATTERN_CONTROL_STUCK_PIXEL (1 << 9) | ||
| 39 | #define XTPG_PATTERN_CONTROL_NOISE (1 << 10) | ||
| 40 | #define XTPG_PATTERN_CONTROL_MOTION (1 << 12) | ||
| 41 | #define XTPG_MOTION_SPEED 0x0104 | ||
| 42 | #define XTPG_CROSS_HAIRS 0x0108 | ||
| 43 | #define XTPG_CROSS_HAIRS_ROW_SHIFT 0 | ||
| 44 | #define XTPG_CROSS_HAIRS_ROW_MASK (0xfff << 0) | ||
| 45 | #define XTPG_CROSS_HAIRS_COLUMN_SHIFT 16 | ||
| 46 | #define XTPG_CROSS_HAIRS_COLUMN_MASK (0xfff << 16) | ||
| 47 | #define XTPG_ZPLATE_HOR_CONTROL 0x010c | ||
| 48 | #define XTPG_ZPLATE_VER_CONTROL 0x0110 | ||
| 49 | #define XTPG_ZPLATE_START_SHIFT 0 | ||
| 50 | #define XTPG_ZPLATE_START_MASK (0xffff << 0) | ||
| 51 | #define XTPG_ZPLATE_SPEED_SHIFT 16 | ||
| 52 | #define XTPG_ZPLATE_SPEED_MASK (0xffff << 16) | ||
| 53 | #define XTPG_BOX_SIZE 0x0114 | ||
| 54 | #define XTPG_BOX_COLOR 0x0118 | ||
| 55 | #define XTPG_STUCK_PIXEL_THRESH 0x011c | ||
| 56 | #define XTPG_NOISE_GAIN 0x0120 | ||
| 57 | #define XTPG_BAYER_PHASE 0x0124 | ||
| 58 | #define XTPG_BAYER_PHASE_RGGB 0 | ||
| 59 | #define XTPG_BAYER_PHASE_GRBG 1 | ||
| 60 | #define XTPG_BAYER_PHASE_GBRG 2 | ||
| 61 | #define XTPG_BAYER_PHASE_BGGR 3 | ||
| 62 | #define XTPG_BAYER_PHASE_OFF 4 | ||
| 63 | |||
| 64 | /* | ||
| 65 | * The minimum blanking value is one clock cycle for the front porch, one clock | ||
| 66 | * cycle for the sync pulse and one clock cycle for the back porch. | ||
| 67 | */ | ||
| 68 | #define XTPG_MIN_HBLANK 3 | ||
| 69 | #define XTPG_MAX_HBLANK (XVTC_MAX_HSIZE - XVIP_MIN_WIDTH) | ||
| 70 | #define XTPG_MIN_VBLANK 3 | ||
| 71 | #define XTPG_MAX_VBLANK (XVTC_MAX_VSIZE - XVIP_MIN_HEIGHT) | ||
| 72 | |||
| 73 | /** | ||
| 74 | * struct xtpg_device - Xilinx Test Pattern Generator device structure | ||
| 75 | * @xvip: Xilinx Video IP device | ||
| 76 | * @pads: media pads | ||
| 77 | * @npads: number of pads (1 or 2) | ||
| 78 | * @has_input: whether an input is connected to the sink pad | ||
| 79 | * @formats: active V4L2 media bus format for each pad | ||
| 80 | * @default_format: default V4L2 media bus format | ||
| 81 | * @vip_format: format information corresponding to the active format | ||
| 82 | * @bayer: boolean flag if TPG is set to any bayer format | ||
| 83 | * @ctrl_handler: control handler | ||
| 84 | * @hblank: horizontal blanking control | ||
| 85 | * @vblank: vertical blanking control | ||
| 86 | * @pattern: test pattern control | ||
| 87 | * @streaming: is the video stream active | ||
| 88 | * @vtc: video timing controller | ||
| 89 | * @vtmux_gpio: video timing mux GPIO | ||
| 90 | */ | ||
| 91 | struct xtpg_device { | ||
| 92 | struct xvip_device xvip; | ||
| 93 | |||
| 94 | struct media_pad pads[2]; | ||
| 95 | unsigned int npads; | ||
| 96 | bool has_input; | ||
| 97 | |||
| 98 | struct v4l2_mbus_framefmt formats[2]; | ||
| 99 | struct v4l2_mbus_framefmt default_format; | ||
| 100 | const struct xvip_video_format *vip_format; | ||
| 101 | bool bayer; | ||
| 102 | |||
| 103 | struct v4l2_ctrl_handler ctrl_handler; | ||
| 104 | struct v4l2_ctrl *hblank; | ||
| 105 | struct v4l2_ctrl *vblank; | ||
| 106 | struct v4l2_ctrl *pattern; | ||
| 107 | bool streaming; | ||
| 108 | |||
| 109 | struct xvtc_device *vtc; | ||
| 110 | struct gpio_desc *vtmux_gpio; | ||
| 111 | }; | ||
| 112 | |||
| 113 | static inline struct xtpg_device *to_tpg(struct v4l2_subdev *subdev) | ||
| 114 | { | ||
| 115 | return container_of(subdev, struct xtpg_device, xvip.subdev); | ||
| 116 | } | ||
| 117 | |||
| 118 | static u32 xtpg_get_bayer_phase(unsigned int code) | ||
| 119 | { | ||
| 120 | switch (code) { | ||
| 121 | case MEDIA_BUS_FMT_SRGGB8_1X8: | ||
| 122 | return XTPG_BAYER_PHASE_RGGB; | ||
| 123 | case MEDIA_BUS_FMT_SGRBG8_1X8: | ||
| 124 | return XTPG_BAYER_PHASE_GRBG; | ||
| 125 | case MEDIA_BUS_FMT_SGBRG8_1X8: | ||
| 126 | return XTPG_BAYER_PHASE_GBRG; | ||
| 127 | case MEDIA_BUS_FMT_SBGGR8_1X8: | ||
| 128 | return XTPG_BAYER_PHASE_BGGR; | ||
| 129 | default: | ||
| 130 | return XTPG_BAYER_PHASE_OFF; | ||
| 131 | } | ||
| 132 | } | ||
| 133 | |||
| 134 | static void __xtpg_update_pattern_control(struct xtpg_device *xtpg, | ||
| 135 | bool passthrough, bool pattern) | ||
| 136 | { | ||
| 137 | u32 pattern_mask = (1 << (xtpg->pattern->maximum + 1)) - 1; | ||
| 138 | |||
| 139 | /* | ||
| 140 | * If the TPG has no sink pad or no input connected to its sink pad | ||
| 141 | * passthrough mode can't be enabled. | ||
| 142 | */ | ||
| 143 | if (xtpg->npads == 1 || !xtpg->has_input) | ||
| 144 | passthrough = false; | ||
| 145 | |||
| 146 | /* If passthrough mode is allowed unmask bit 0. */ | ||
| 147 | if (passthrough) | ||
| 148 | pattern_mask &= ~1; | ||
| 149 | |||
| 150 | /* If test pattern mode is allowed unmask all other bits. */ | ||
| 151 | if (pattern) | ||
| 152 | pattern_mask &= 1; | ||
| 153 | |||
| 154 | __v4l2_ctrl_modify_range(xtpg->pattern, 0, xtpg->pattern->maximum, | ||
| 155 | pattern_mask, pattern ? 9 : 0); | ||
| 156 | } | ||
| 157 | |||
| 158 | static void xtpg_update_pattern_control(struct xtpg_device *xtpg, | ||
| 159 | bool passthrough, bool pattern) | ||
| 160 | { | ||
| 161 | mutex_lock(xtpg->ctrl_handler.lock); | ||
| 162 | __xtpg_update_pattern_control(xtpg, passthrough, pattern); | ||
| 163 | mutex_unlock(xtpg->ctrl_handler.lock); | ||
| 164 | } | ||
| 165 | |||
| 166 | /* ----------------------------------------------------------------------------- | ||
| 167 | * V4L2 Subdevice Video Operations | ||
| 168 | */ | ||
| 169 | |||
| 170 | static int xtpg_s_stream(struct v4l2_subdev *subdev, int enable) | ||
| 171 | { | ||
| 172 | struct xtpg_device *xtpg = to_tpg(subdev); | ||
| 173 | unsigned int width = xtpg->formats[0].width; | ||
| 174 | unsigned int height = xtpg->formats[0].height; | ||
| 175 | bool passthrough; | ||
| 176 | u32 bayer_phase; | ||
| 177 | |||
| 178 | if (!enable) { | ||
| 179 | xvip_stop(&xtpg->xvip); | ||
| 180 | if (xtpg->vtc) | ||
| 181 | xvtc_generator_stop(xtpg->vtc); | ||
| 182 | |||
| 183 | xtpg_update_pattern_control(xtpg, true, true); | ||
| 184 | xtpg->streaming = false; | ||
| 185 | return 0; | ||
| 186 | } | ||
| 187 | |||
| 188 | xvip_set_frame_size(&xtpg->xvip, &xtpg->formats[0]); | ||
| 189 | |||
| 190 | if (xtpg->vtc) { | ||
| 191 | struct xvtc_config config = { | ||
| 192 | .hblank_start = width, | ||
| 193 | .hsync_start = width + 1, | ||
| 194 | .vblank_start = height, | ||
| 195 | .vsync_start = height + 1, | ||
| 196 | }; | ||
| 197 | unsigned int htotal; | ||
| 198 | unsigned int vtotal; | ||
| 199 | |||
| 200 | htotal = min_t(unsigned int, XVTC_MAX_HSIZE, | ||
| 201 | v4l2_ctrl_g_ctrl(xtpg->hblank) + width); | ||
| 202 | vtotal = min_t(unsigned int, XVTC_MAX_VSIZE, | ||
| 203 | v4l2_ctrl_g_ctrl(xtpg->vblank) + height); | ||
| 204 | |||
| 205 | config.hsync_end = htotal - 1; | ||
| 206 | config.hsize = htotal; | ||
| 207 | config.vsync_end = vtotal - 1; | ||
| 208 | config.vsize = vtotal; | ||
| 209 | |||
| 210 | xvtc_generator_start(xtpg->vtc, &config); | ||
| 211 | } | ||
| 212 | |||
| 213 | /* | ||
| 214 | * Configure the bayer phase and video timing mux based on the | ||
| 215 | * operation mode (passthrough or test pattern generation). The test | ||
| 216 | * pattern can be modified by the control set handler, we thus need to | ||
| 217 | * take the control lock here to avoid races. | ||
| 218 | */ | ||
| 219 | mutex_lock(xtpg->ctrl_handler.lock); | ||
| 220 | |||
| 221 | xvip_clr_and_set(&xtpg->xvip, XTPG_PATTERN_CONTROL, | ||
| 222 | XTPG_PATTERN_MASK, xtpg->pattern->cur.val); | ||
| 223 | |||
| 224 | /* | ||
| 225 | * Switching between passthrough and test pattern generation modes isn't | ||
| 226 | * allowed during streaming, update the control range accordingly. | ||
| 227 | */ | ||
| 228 | passthrough = xtpg->pattern->cur.val == 0; | ||
| 229 | __xtpg_update_pattern_control(xtpg, passthrough, !passthrough); | ||
| 230 | |||
| 231 | xtpg->streaming = true; | ||
| 232 | |||
| 233 | mutex_unlock(xtpg->ctrl_handler.lock); | ||
| 234 | |||
| 235 | /* | ||
| 236 | * For TPG v5.0, the bayer phase needs to be off for the pass through | ||
| 237 | * mode, otherwise the external input would be subsampled. | ||
| 238 | */ | ||
| 239 | bayer_phase = passthrough ? XTPG_BAYER_PHASE_OFF | ||
| 240 | : xtpg_get_bayer_phase(xtpg->formats[0].code); | ||
| 241 | xvip_write(&xtpg->xvip, XTPG_BAYER_PHASE, bayer_phase); | ||
| 242 | |||
| 243 | if (xtpg->vtmux_gpio) | ||
| 244 | gpiod_set_value_cansleep(xtpg->vtmux_gpio, !passthrough); | ||
| 245 | |||
| 246 | xvip_start(&xtpg->xvip); | ||
| 247 | |||
| 248 | return 0; | ||
| 249 | } | ||
| 250 | |||
| 251 | /* ----------------------------------------------------------------------------- | ||
| 252 | * V4L2 Subdevice Pad Operations | ||
| 253 | */ | ||
| 254 | |||
| 255 | static struct v4l2_mbus_framefmt * | ||
| 256 | __xtpg_get_pad_format(struct xtpg_device *xtpg, | ||
| 257 | struct v4l2_subdev_pad_config *cfg, | ||
| 258 | unsigned int pad, u32 which) | ||
| 259 | { | ||
| 260 | switch (which) { | ||
| 261 | case V4L2_SUBDEV_FORMAT_TRY: | ||
| 262 | return v4l2_subdev_get_try_format(&xtpg->xvip.subdev, cfg, pad); | ||
| 263 | case V4L2_SUBDEV_FORMAT_ACTIVE: | ||
| 264 | return &xtpg->formats[pad]; | ||
| 265 | default: | ||
| 266 | return NULL; | ||
| 267 | } | ||
| 268 | } | ||
| 269 | |||
| 270 | static int xtpg_get_format(struct v4l2_subdev *subdev, | ||
| 271 | struct v4l2_subdev_pad_config *cfg, | ||
| 272 | struct v4l2_subdev_format *fmt) | ||
| 273 | { | ||
| 274 | struct xtpg_device *xtpg = to_tpg(subdev); | ||
| 275 | |||
| 276 | fmt->format = *__xtpg_get_pad_format(xtpg, cfg, fmt->pad, fmt->which); | ||
| 277 | |||
| 278 | return 0; | ||
| 279 | } | ||
| 280 | |||
| 281 | static int xtpg_set_format(struct v4l2_subdev *subdev, | ||
| 282 | struct v4l2_subdev_pad_config *cfg, | ||
| 283 | struct v4l2_subdev_format *fmt) | ||
| 284 | { | ||
| 285 | struct xtpg_device *xtpg = to_tpg(subdev); | ||
| 286 | struct v4l2_mbus_framefmt *__format; | ||
| 287 | u32 bayer_phase; | ||
| 288 | |||
| 289 | __format = __xtpg_get_pad_format(xtpg, cfg, fmt->pad, fmt->which); | ||
| 290 | |||
| 291 | /* In two pads mode the source pad format is always identical to the | ||
| 292 | * sink pad format. | ||
| 293 | */ | ||
| 294 | if (xtpg->npads == 2 && fmt->pad == 1) { | ||
| 295 | fmt->format = *__format; | ||
| 296 | return 0; | ||
| 297 | } | ||
| 298 | |||
| 299 | /* Bayer phase is configurable at runtime */ | ||
| 300 | if (xtpg->bayer) { | ||
| 301 | bayer_phase = xtpg_get_bayer_phase(fmt->format.code); | ||
| 302 | if (bayer_phase != XTPG_BAYER_PHASE_OFF) | ||
| 303 | __format->code = fmt->format.code; | ||
| 304 | } | ||
| 305 | |||
| 306 | xvip_set_format_size(__format, fmt); | ||
| 307 | |||
| 308 | fmt->format = *__format; | ||
| 309 | |||
| 310 | /* Propagate the format to the source pad. */ | ||
| 311 | if (xtpg->npads == 2) { | ||
| 312 | __format = __xtpg_get_pad_format(xtpg, cfg, 1, fmt->which); | ||
| 313 | *__format = fmt->format; | ||
| 314 | } | ||
| 315 | |||
| 316 | return 0; | ||
| 317 | } | ||
| 318 | |||
| 319 | /* ----------------------------------------------------------------------------- | ||
| 320 | * V4L2 Subdevice Operations | ||
| 321 | */ | ||
| 322 | |||
| 323 | static int xtpg_enum_frame_size(struct v4l2_subdev *subdev, | ||
| 324 | struct v4l2_subdev_pad_config *cfg, | ||
| 325 | struct v4l2_subdev_frame_size_enum *fse) | ||
| 326 | { | ||
| 327 | struct v4l2_mbus_framefmt *format; | ||
| 328 | |||
| 329 | format = v4l2_subdev_get_try_format(subdev, cfg, fse->pad); | ||
| 330 | |||
| 331 | if (fse->index || fse->code != format->code) | ||
| 332 | return -EINVAL; | ||
| 333 | |||
| 334 | /* Min / max values for pad 0 is always fixed in both one and two pads | ||
| 335 | * modes. In two pads mode, the source pad(= 1) size is identical to | ||
| 336 | * the sink pad size */ | ||
| 337 | if (fse->pad == 0) { | ||
| 338 | fse->min_width = XVIP_MIN_WIDTH; | ||
| 339 | fse->max_width = XVIP_MAX_WIDTH; | ||
| 340 | fse->min_height = XVIP_MIN_HEIGHT; | ||
| 341 | fse->max_height = XVIP_MAX_HEIGHT; | ||
| 342 | } else { | ||
| 343 | fse->min_width = format->width; | ||
| 344 | fse->max_width = format->width; | ||
| 345 | fse->min_height = format->height; | ||
| 346 | fse->max_height = format->height; | ||
| 347 | } | ||
| 348 | |||
| 349 | return 0; | ||
| 350 | } | ||
| 351 | |||
| 352 | static int xtpg_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) | ||
| 353 | { | ||
| 354 | struct xtpg_device *xtpg = to_tpg(subdev); | ||
| 355 | struct v4l2_mbus_framefmt *format; | ||
| 356 | |||
| 357 | format = v4l2_subdev_get_try_format(subdev, fh->pad, 0); | ||
| 358 | *format = xtpg->default_format; | ||
| 359 | |||
| 360 | if (xtpg->npads == 2) { | ||
| 361 | format = v4l2_subdev_get_try_format(subdev, fh->pad, 1); | ||
| 362 | *format = xtpg->default_format; | ||
| 363 | } | ||
| 364 | |||
| 365 | return 0; | ||
| 366 | } | ||
| 367 | |||
| 368 | static int xtpg_close(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) | ||
| 369 | { | ||
| 370 | return 0; | ||
| 371 | } | ||
| 372 | |||
| 373 | static int xtpg_s_ctrl(struct v4l2_ctrl *ctrl) | ||
| 374 | { | ||
| 375 | struct xtpg_device *xtpg = container_of(ctrl->handler, | ||
| 376 | struct xtpg_device, | ||
| 377 | ctrl_handler); | ||
| 378 | switch (ctrl->id) { | ||
| 379 | case V4L2_CID_TEST_PATTERN: | ||
| 380 | xvip_clr_and_set(&xtpg->xvip, XTPG_PATTERN_CONTROL, | ||
| 381 | XTPG_PATTERN_MASK, ctrl->val); | ||
| 382 | return 0; | ||
| 383 | case V4L2_CID_XILINX_TPG_CROSS_HAIRS: | ||
| 384 | xvip_clr_or_set(&xtpg->xvip, XTPG_PATTERN_CONTROL, | ||
| 385 | XTPG_PATTERN_CONTROL_CROSS_HAIRS, ctrl->val); | ||
| 386 | return 0; | ||
| 387 | case V4L2_CID_XILINX_TPG_MOVING_BOX: | ||
| 388 | xvip_clr_or_set(&xtpg->xvip, XTPG_PATTERN_CONTROL, | ||
| 389 | XTPG_PATTERN_CONTROL_MOVING_BOX, ctrl->val); | ||
| 390 | return 0; | ||
| 391 | case V4L2_CID_XILINX_TPG_COLOR_MASK: | ||
| 392 | xvip_clr_and_set(&xtpg->xvip, XTPG_PATTERN_CONTROL, | ||
| 393 | XTPG_PATTERN_CONTROL_COLOR_MASK_MASK, | ||
| 394 | ctrl->val << | ||
| 395 | XTPG_PATTERN_CONTROL_COLOR_MASK_SHIFT); | ||
| 396 | return 0; | ||
| 397 | case V4L2_CID_XILINX_TPG_STUCK_PIXEL: | ||
| 398 | xvip_clr_or_set(&xtpg->xvip, XTPG_PATTERN_CONTROL, | ||
| 399 | XTPG_PATTERN_CONTROL_STUCK_PIXEL, ctrl->val); | ||
| 400 | return 0; | ||
| 401 | case V4L2_CID_XILINX_TPG_NOISE: | ||
| 402 | xvip_clr_or_set(&xtpg->xvip, XTPG_PATTERN_CONTROL, | ||
| 403 | XTPG_PATTERN_CONTROL_NOISE, ctrl->val); | ||
| 404 | return 0; | ||
| 405 | case V4L2_CID_XILINX_TPG_MOTION: | ||
| 406 | xvip_clr_or_set(&xtpg->xvip, XTPG_PATTERN_CONTROL, | ||
| 407 | XTPG_PATTERN_CONTROL_MOTION, ctrl->val); | ||
| 408 | return 0; | ||
| 409 | case V4L2_CID_XILINX_TPG_MOTION_SPEED: | ||
| 410 | xvip_write(&xtpg->xvip, XTPG_MOTION_SPEED, ctrl->val); | ||
| 411 | return 0; | ||
| 412 | case V4L2_CID_XILINX_TPG_CROSS_HAIR_ROW: | ||
| 413 | xvip_clr_and_set(&xtpg->xvip, XTPG_CROSS_HAIRS, | ||
| 414 | XTPG_CROSS_HAIRS_ROW_MASK, | ||
| 415 | ctrl->val << XTPG_CROSS_HAIRS_ROW_SHIFT); | ||
| 416 | return 0; | ||
| 417 | case V4L2_CID_XILINX_TPG_CROSS_HAIR_COLUMN: | ||
| 418 | xvip_clr_and_set(&xtpg->xvip, XTPG_CROSS_HAIRS, | ||
| 419 | XTPG_CROSS_HAIRS_COLUMN_MASK, | ||
| 420 | ctrl->val << XTPG_CROSS_HAIRS_COLUMN_SHIFT); | ||
| 421 | return 0; | ||
| 422 | case V4L2_CID_XILINX_TPG_ZPLATE_HOR_START: | ||
| 423 | xvip_clr_and_set(&xtpg->xvip, XTPG_ZPLATE_HOR_CONTROL, | ||
| 424 | XTPG_ZPLATE_START_MASK, | ||
| 425 | ctrl->val << XTPG_ZPLATE_START_SHIFT); | ||
| 426 | return 0; | ||
| 427 | case V4L2_CID_XILINX_TPG_ZPLATE_HOR_SPEED: | ||
| 428 | xvip_clr_and_set(&xtpg->xvip, XTPG_ZPLATE_HOR_CONTROL, | ||
| 429 | XTPG_ZPLATE_SPEED_MASK, | ||
| 430 | ctrl->val << XTPG_ZPLATE_SPEED_SHIFT); | ||
| 431 | return 0; | ||
| 432 | case V4L2_CID_XILINX_TPG_ZPLATE_VER_START: | ||
| 433 | xvip_clr_and_set(&xtpg->xvip, XTPG_ZPLATE_VER_CONTROL, | ||
| 434 | XTPG_ZPLATE_START_MASK, | ||
| 435 | ctrl->val << XTPG_ZPLATE_START_SHIFT); | ||
| 436 | return 0; | ||
| 437 | case V4L2_CID_XILINX_TPG_ZPLATE_VER_SPEED: | ||
| 438 | xvip_clr_and_set(&xtpg->xvip, XTPG_ZPLATE_VER_CONTROL, | ||
| 439 | XTPG_ZPLATE_SPEED_MASK, | ||
| 440 | ctrl->val << XTPG_ZPLATE_SPEED_SHIFT); | ||
| 441 | return 0; | ||
| 442 | case V4L2_CID_XILINX_TPG_BOX_SIZE: | ||
| 443 | xvip_write(&xtpg->xvip, XTPG_BOX_SIZE, ctrl->val); | ||
| 444 | return 0; | ||
| 445 | case V4L2_CID_XILINX_TPG_BOX_COLOR: | ||
| 446 | xvip_write(&xtpg->xvip, XTPG_BOX_COLOR, ctrl->val); | ||
| 447 | return 0; | ||
| 448 | case V4L2_CID_XILINX_TPG_STUCK_PIXEL_THRESH: | ||
| 449 | xvip_write(&xtpg->xvip, XTPG_STUCK_PIXEL_THRESH, ctrl->val); | ||
| 450 | return 0; | ||
| 451 | case V4L2_CID_XILINX_TPG_NOISE_GAIN: | ||
| 452 | xvip_write(&xtpg->xvip, XTPG_NOISE_GAIN, ctrl->val); | ||
| 453 | return 0; | ||
| 454 | } | ||
| 455 | |||
| 456 | return 0; | ||
| 457 | } | ||
| 458 | |||
| 459 | static const struct v4l2_ctrl_ops xtpg_ctrl_ops = { | ||
| 460 | .s_ctrl = xtpg_s_ctrl, | ||
| 461 | }; | ||
| 462 | |||
| 463 | static struct v4l2_subdev_core_ops xtpg_core_ops = { | ||
| 464 | }; | ||
| 465 | |||
| 466 | static struct v4l2_subdev_video_ops xtpg_video_ops = { | ||
| 467 | .s_stream = xtpg_s_stream, | ||
| 468 | }; | ||
| 469 | |||
| 470 | static struct v4l2_subdev_pad_ops xtpg_pad_ops = { | ||
| 471 | .enum_mbus_code = xvip_enum_mbus_code, | ||
| 472 | .enum_frame_size = xtpg_enum_frame_size, | ||
| 473 | .get_fmt = xtpg_get_format, | ||
| 474 | .set_fmt = xtpg_set_format, | ||
| 475 | }; | ||
| 476 | |||
| 477 | static struct v4l2_subdev_ops xtpg_ops = { | ||
| 478 | .core = &xtpg_core_ops, | ||
| 479 | .video = &xtpg_video_ops, | ||
| 480 | .pad = &xtpg_pad_ops, | ||
| 481 | }; | ||
| 482 | |||
| 483 | static const struct v4l2_subdev_internal_ops xtpg_internal_ops = { | ||
| 484 | .open = xtpg_open, | ||
| 485 | .close = xtpg_close, | ||
| 486 | }; | ||
| 487 | |||
| 488 | /* | ||
| 489 | * Control Config | ||
| 490 | */ | ||
| 491 | |||
| 492 | static const char *const xtpg_pattern_strings[] = { | ||
| 493 | "Passthrough", | ||
| 494 | "Horizontal Ramp", | ||
| 495 | "Vertical Ramp", | ||
| 496 | "Temporal Ramp", | ||
| 497 | "Solid Red", | ||
| 498 | "Solid Green", | ||
| 499 | "Solid Blue", | ||
| 500 | "Solid Black", | ||
| 501 | "Solid White", | ||
| 502 | "Color Bars", | ||
| 503 | "Zone Plate", | ||
| 504 | "Tartan Color Bars", | ||
| 505 | "Cross Hatch", | ||
| 506 | "None", | ||
| 507 | "Vertical/Horizontal Ramps", | ||
| 508 | "Black/White Checker Board", | ||
| 509 | }; | ||
| 510 | |||
| 511 | static struct v4l2_ctrl_config xtpg_ctrls[] = { | ||
| 512 | { | ||
| 513 | .ops = &xtpg_ctrl_ops, | ||
| 514 | .id = V4L2_CID_XILINX_TPG_CROSS_HAIRS, | ||
| 515 | .name = "Test Pattern: Cross Hairs", | ||
| 516 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
| 517 | .min = false, | ||
| 518 | .max = true, | ||
| 519 | .step = 1, | ||
| 520 | .def = 0, | ||
| 521 | }, { | ||
| 522 | .ops = &xtpg_ctrl_ops, | ||
| 523 | .id = V4L2_CID_XILINX_TPG_MOVING_BOX, | ||
| 524 | .name = "Test Pattern: Moving Box", | ||
| 525 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
| 526 | .min = false, | ||
| 527 | .max = true, | ||
| 528 | .step = 1, | ||
| 529 | .def = 0, | ||
| 530 | }, { | ||
| 531 | .ops = &xtpg_ctrl_ops, | ||
| 532 | .id = V4L2_CID_XILINX_TPG_COLOR_MASK, | ||
| 533 | .name = "Test Pattern: Color Mask", | ||
| 534 | .type = V4L2_CTRL_TYPE_BITMASK, | ||
| 535 | .min = 0, | ||
| 536 | .max = 0xf, | ||
| 537 | .def = 0, | ||
| 538 | }, { | ||
| 539 | .ops = &xtpg_ctrl_ops, | ||
| 540 | .id = V4L2_CID_XILINX_TPG_STUCK_PIXEL, | ||
| 541 | .name = "Test Pattern: Stuck Pixel", | ||
| 542 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
| 543 | .min = false, | ||
| 544 | .max = true, | ||
| 545 | .step = 1, | ||
| 546 | .def = 0, | ||
| 547 | }, { | ||
| 548 | .ops = &xtpg_ctrl_ops, | ||
| 549 | .id = V4L2_CID_XILINX_TPG_NOISE, | ||
| 550 | .name = "Test Pattern: Noise", | ||
| 551 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
| 552 | .min = false, | ||
| 553 | .max = true, | ||
| 554 | .step = 1, | ||
| 555 | .def = 0, | ||
| 556 | }, { | ||
| 557 | .ops = &xtpg_ctrl_ops, | ||
| 558 | .id = V4L2_CID_XILINX_TPG_MOTION, | ||
| 559 | .name = "Test Pattern: Motion", | ||
| 560 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
| 561 | .min = false, | ||
| 562 | .max = true, | ||
| 563 | .step = 1, | ||
| 564 | .def = 0, | ||
| 565 | }, { | ||
| 566 | .ops = &xtpg_ctrl_ops, | ||
| 567 | .id = V4L2_CID_XILINX_TPG_MOTION_SPEED, | ||
| 568 | .name = "Test Pattern: Motion Speed", | ||
| 569 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 570 | .min = 0, | ||
| 571 | .max = (1 << 8) - 1, | ||
| 572 | .step = 1, | ||
| 573 | .def = 4, | ||
| 574 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
| 575 | }, { | ||
| 576 | .ops = &xtpg_ctrl_ops, | ||
| 577 | .id = V4L2_CID_XILINX_TPG_CROSS_HAIR_ROW, | ||
| 578 | .name = "Test Pattern: Cross Hairs Row", | ||
| 579 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 580 | .min = 0, | ||
| 581 | .max = (1 << 12) - 1, | ||
| 582 | .step = 1, | ||
| 583 | .def = 0x64, | ||
| 584 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
| 585 | }, { | ||
| 586 | .ops = &xtpg_ctrl_ops, | ||
| 587 | .id = V4L2_CID_XILINX_TPG_CROSS_HAIR_COLUMN, | ||
| 588 | .name = "Test Pattern: Cross Hairs Column", | ||
| 589 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 590 | .min = 0, | ||
| 591 | .max = (1 << 12) - 1, | ||
| 592 | .step = 1, | ||
| 593 | .def = 0x64, | ||
| 594 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
| 595 | }, { | ||
| 596 | .ops = &xtpg_ctrl_ops, | ||
| 597 | .id = V4L2_CID_XILINX_TPG_ZPLATE_HOR_START, | ||
| 598 | .name = "Test Pattern: Zplate Horizontal Start Pos", | ||
| 599 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 600 | .min = 0, | ||
| 601 | .max = (1 << 16) - 1, | ||
| 602 | .step = 1, | ||
| 603 | .def = 0x1e, | ||
| 604 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
| 605 | }, { | ||
| 606 | .ops = &xtpg_ctrl_ops, | ||
| 607 | .id = V4L2_CID_XILINX_TPG_ZPLATE_HOR_SPEED, | ||
| 608 | .name = "Test Pattern: Zplate Horizontal Speed", | ||
| 609 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 610 | .min = 0, | ||
| 611 | .max = (1 << 16) - 1, | ||
| 612 | .step = 1, | ||
| 613 | .def = 0, | ||
| 614 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
| 615 | }, { | ||
| 616 | .ops = &xtpg_ctrl_ops, | ||
| 617 | .id = V4L2_CID_XILINX_TPG_ZPLATE_VER_START, | ||
| 618 | .name = "Test Pattern: Zplate Vertical Start Pos", | ||
| 619 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 620 | .min = 0, | ||
| 621 | .max = (1 << 16) - 1, | ||
| 622 | .step = 1, | ||
| 623 | .def = 1, | ||
| 624 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
| 625 | }, { | ||
| 626 | .ops = &xtpg_ctrl_ops, | ||
| 627 | .id = V4L2_CID_XILINX_TPG_ZPLATE_VER_SPEED, | ||
| 628 | .name = "Test Pattern: Zplate Vertical Speed", | ||
| 629 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 630 | .min = 0, | ||
| 631 | .max = (1 << 16) - 1, | ||
| 632 | .step = 1, | ||
| 633 | .def = 0, | ||
| 634 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
| 635 | }, { | ||
| 636 | .ops = &xtpg_ctrl_ops, | ||
| 637 | .id = V4L2_CID_XILINX_TPG_BOX_SIZE, | ||
| 638 | .name = "Test Pattern: Box Size", | ||
| 639 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 640 | .min = 0, | ||
| 641 | .max = (1 << 12) - 1, | ||
| 642 | .step = 1, | ||
| 643 | .def = 0x32, | ||
| 644 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
| 645 | }, { | ||
| 646 | .ops = &xtpg_ctrl_ops, | ||
| 647 | .id = V4L2_CID_XILINX_TPG_BOX_COLOR, | ||
| 648 | .name = "Test Pattern: Box Color(RGB)", | ||
| 649 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 650 | .min = 0, | ||
| 651 | .max = (1 << 24) - 1, | ||
| 652 | .step = 1, | ||
| 653 | .def = 0, | ||
| 654 | }, { | ||
| 655 | .ops = &xtpg_ctrl_ops, | ||
| 656 | .id = V4L2_CID_XILINX_TPG_STUCK_PIXEL_THRESH, | ||
| 657 | .name = "Test Pattern: Stuck Pixel threshold", | ||
| 658 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 659 | .min = 0, | ||
| 660 | .max = (1 << 16) - 1, | ||
| 661 | .step = 1, | ||
| 662 | .def = 0, | ||
| 663 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
| 664 | }, { | ||
| 665 | .ops = &xtpg_ctrl_ops, | ||
| 666 | .id = V4L2_CID_XILINX_TPG_NOISE_GAIN, | ||
| 667 | .name = "Test Pattern: Noise Gain", | ||
| 668 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 669 | .min = 0, | ||
| 670 | .max = (1 << 8) - 1, | ||
| 671 | .step = 1, | ||
| 672 | .def = 0, | ||
| 673 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
| 674 | }, | ||
| 675 | }; | ||
| 676 | |||
| 677 | /* ----------------------------------------------------------------------------- | ||
| 678 | * Media Operations | ||
| 679 | */ | ||
| 680 | |||
| 681 | static const struct media_entity_operations xtpg_media_ops = { | ||
| 682 | .link_validate = v4l2_subdev_link_validate, | ||
| 683 | }; | ||
| 684 | |||
| 685 | /* ----------------------------------------------------------------------------- | ||
| 686 | * Power Management | ||
| 687 | */ | ||
| 688 | |||
| 689 | static int __maybe_unused xtpg_pm_suspend(struct device *dev) | ||
| 690 | { | ||
| 691 | struct xtpg_device *xtpg = dev_get_drvdata(dev); | ||
| 692 | |||
| 693 | xvip_suspend(&xtpg->xvip); | ||
| 694 | |||
| 695 | return 0; | ||
| 696 | } | ||
| 697 | |||
| 698 | static int __maybe_unused xtpg_pm_resume(struct device *dev) | ||
| 699 | { | ||
| 700 | struct xtpg_device *xtpg = dev_get_drvdata(dev); | ||
| 701 | |||
| 702 | xvip_resume(&xtpg->xvip); | ||
| 703 | |||
| 704 | return 0; | ||
| 705 | } | ||
| 706 | |||
| 707 | /* ----------------------------------------------------------------------------- | ||
| 708 | * Platform Device Driver | ||
| 709 | */ | ||
| 710 | |||
| 711 | static int xtpg_parse_of(struct xtpg_device *xtpg) | ||
| 712 | { | ||
| 713 | struct device *dev = xtpg->xvip.dev; | ||
| 714 | struct device_node *node = xtpg->xvip.dev->of_node; | ||
| 715 | struct device_node *ports; | ||
| 716 | struct device_node *port; | ||
| 717 | unsigned int nports = 0; | ||
| 718 | bool has_endpoint = false; | ||
| 719 | |||
| 720 | ports = of_get_child_by_name(node, "ports"); | ||
| 721 | if (ports == NULL) | ||
| 722 | ports = node; | ||
| 723 | |||
| 724 | for_each_child_of_node(ports, port) { | ||
| 725 | const struct xvip_video_format *format; | ||
| 726 | struct device_node *endpoint; | ||
| 727 | |||
| 728 | if (!port->name || of_node_cmp(port->name, "port")) | ||
| 729 | continue; | ||
| 730 | |||
| 731 | format = xvip_of_get_format(port); | ||
| 732 | if (IS_ERR(format)) { | ||
| 733 | dev_err(dev, "invalid format in DT"); | ||
| 734 | return PTR_ERR(format); | ||
| 735 | } | ||
| 736 | |||
| 737 | /* Get and check the format description */ | ||
| 738 | if (!xtpg->vip_format) { | ||
| 739 | xtpg->vip_format = format; | ||
| 740 | } else if (xtpg->vip_format != format) { | ||
| 741 | dev_err(dev, "in/out format mismatch in DT"); | ||
| 742 | return -EINVAL; | ||
| 743 | } | ||
| 744 | |||
| 745 | if (nports == 0) { | ||
| 746 | endpoint = of_get_next_child(port, NULL); | ||
| 747 | if (endpoint) | ||
| 748 | has_endpoint = true; | ||
| 749 | of_node_put(endpoint); | ||
| 750 | } | ||
| 751 | |||
| 752 | /* Count the number of ports. */ | ||
| 753 | nports++; | ||
| 754 | } | ||
| 755 | |||
| 756 | if (nports != 1 && nports != 2) { | ||
| 757 | dev_err(dev, "invalid number of ports %u\n", nports); | ||
| 758 | return -EINVAL; | ||
| 759 | } | ||
| 760 | |||
| 761 | xtpg->npads = nports; | ||
| 762 | if (nports == 2 && has_endpoint) | ||
| 763 | xtpg->has_input = true; | ||
| 764 | |||
| 765 | return 0; | ||
| 766 | } | ||
| 767 | |||
| 768 | static int xtpg_probe(struct platform_device *pdev) | ||
| 769 | { | ||
| 770 | struct v4l2_subdev *subdev; | ||
| 771 | struct xtpg_device *xtpg; | ||
| 772 | u32 i, bayer_phase; | ||
| 773 | int ret; | ||
| 774 | |||
| 775 | xtpg = devm_kzalloc(&pdev->dev, sizeof(*xtpg), GFP_KERNEL); | ||
| 776 | if (!xtpg) | ||
| 777 | return -ENOMEM; | ||
| 778 | |||
| 779 | xtpg->xvip.dev = &pdev->dev; | ||
| 780 | |||
| 781 | ret = xtpg_parse_of(xtpg); | ||
| 782 | if (ret < 0) | ||
| 783 | return ret; | ||
| 784 | |||
| 785 | ret = xvip_init_resources(&xtpg->xvip); | ||
| 786 | if (ret < 0) | ||
| 787 | return ret; | ||
| 788 | |||
| 789 | xtpg->vtmux_gpio = devm_gpiod_get_optional(&pdev->dev, "timing", | ||
| 790 | GPIOD_OUT_HIGH); | ||
| 791 | if (IS_ERR(xtpg->vtmux_gpio)) { | ||
| 792 | ret = PTR_ERR(xtpg->vtmux_gpio); | ||
| 793 | goto error_resource; | ||
| 794 | } | ||
| 795 | |||
| 796 | xtpg->vtc = xvtc_of_get(pdev->dev.of_node); | ||
| 797 | if (IS_ERR(xtpg->vtc)) { | ||
| 798 | ret = PTR_ERR(xtpg->vtc); | ||
| 799 | goto error_resource; | ||
| 800 | } | ||
| 801 | |||
| 802 | /* Reset and initialize the core */ | ||
| 803 | xvip_reset(&xtpg->xvip); | ||
| 804 | |||
| 805 | /* Initialize V4L2 subdevice and media entity. Pad numbers depend on the | ||
| 806 | * number of pads. | ||
| 807 | */ | ||
| 808 | if (xtpg->npads == 2) { | ||
| 809 | xtpg->pads[0].flags = MEDIA_PAD_FL_SINK; | ||
| 810 | xtpg->pads[1].flags = MEDIA_PAD_FL_SOURCE; | ||
| 811 | } else { | ||
| 812 | xtpg->pads[0].flags = MEDIA_PAD_FL_SOURCE; | ||
| 813 | } | ||
| 814 | |||
| 815 | /* Initialize the default format */ | ||
| 816 | xtpg->default_format.code = xtpg->vip_format->code; | ||
| 817 | xtpg->default_format.field = V4L2_FIELD_NONE; | ||
| 818 | xtpg->default_format.colorspace = V4L2_COLORSPACE_SRGB; | ||
| 819 | xvip_get_frame_size(&xtpg->xvip, &xtpg->default_format); | ||
| 820 | |||
| 821 | bayer_phase = xtpg_get_bayer_phase(xtpg->vip_format->code); | ||
| 822 | if (bayer_phase != XTPG_BAYER_PHASE_OFF) | ||
| 823 | xtpg->bayer = true; | ||
| 824 | |||
| 825 | xtpg->formats[0] = xtpg->default_format; | ||
| 826 | if (xtpg->npads == 2) | ||
| 827 | xtpg->formats[1] = xtpg->default_format; | ||
| 828 | |||
| 829 | /* Initialize V4L2 subdevice and media entity */ | ||
| 830 | subdev = &xtpg->xvip.subdev; | ||
| 831 | v4l2_subdev_init(subdev, &xtpg_ops); | ||
| 832 | subdev->dev = &pdev->dev; | ||
| 833 | subdev->internal_ops = &xtpg_internal_ops; | ||
| 834 | strlcpy(subdev->name, dev_name(&pdev->dev), sizeof(subdev->name)); | ||
| 835 | v4l2_set_subdevdata(subdev, xtpg); | ||
| 836 | subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | ||
| 837 | subdev->entity.ops = &xtpg_media_ops; | ||
| 838 | |||
| 839 | ret = media_entity_init(&subdev->entity, xtpg->npads, xtpg->pads, 0); | ||
| 840 | if (ret < 0) | ||
| 841 | goto error; | ||
| 842 | |||
| 843 | v4l2_ctrl_handler_init(&xtpg->ctrl_handler, 3 + ARRAY_SIZE(xtpg_ctrls)); | ||
| 844 | |||
| 845 | xtpg->vblank = v4l2_ctrl_new_std(&xtpg->ctrl_handler, &xtpg_ctrl_ops, | ||
| 846 | V4L2_CID_VBLANK, XTPG_MIN_VBLANK, | ||
| 847 | XTPG_MAX_VBLANK, 1, 100); | ||
| 848 | xtpg->hblank = v4l2_ctrl_new_std(&xtpg->ctrl_handler, &xtpg_ctrl_ops, | ||
| 849 | V4L2_CID_HBLANK, XTPG_MIN_HBLANK, | ||
| 850 | XTPG_MAX_HBLANK, 1, 100); | ||
| 851 | xtpg->pattern = v4l2_ctrl_new_std_menu_items(&xtpg->ctrl_handler, | ||
| 852 | &xtpg_ctrl_ops, V4L2_CID_TEST_PATTERN, | ||
| 853 | ARRAY_SIZE(xtpg_pattern_strings) - 1, | ||
| 854 | 1, 9, xtpg_pattern_strings); | ||
| 855 | |||
| 856 | for (i = 0; i < ARRAY_SIZE(xtpg_ctrls); i++) | ||
| 857 | v4l2_ctrl_new_custom(&xtpg->ctrl_handler, &xtpg_ctrls[i], NULL); | ||
| 858 | |||
| 859 | if (xtpg->ctrl_handler.error) { | ||
| 860 | dev_err(&pdev->dev, "failed to add controls\n"); | ||
| 861 | ret = xtpg->ctrl_handler.error; | ||
| 862 | goto error; | ||
| 863 | } | ||
| 864 | subdev->ctrl_handler = &xtpg->ctrl_handler; | ||
| 865 | |||
| 866 | xtpg_update_pattern_control(xtpg, true, true); | ||
| 867 | |||
| 868 | ret = v4l2_ctrl_handler_setup(&xtpg->ctrl_handler); | ||
| 869 | if (ret < 0) { | ||
| 870 | dev_err(&pdev->dev, "failed to set controls\n"); | ||
| 871 | goto error; | ||
| 872 | } | ||
| 873 | |||
| 874 | platform_set_drvdata(pdev, xtpg); | ||
| 875 | |||
| 876 | xvip_print_version(&xtpg->xvip); | ||
| 877 | |||
| 878 | ret = v4l2_async_register_subdev(subdev); | ||
| 879 | if (ret < 0) { | ||
| 880 | dev_err(&pdev->dev, "failed to register subdev\n"); | ||
| 881 | goto error; | ||
| 882 | } | ||
| 883 | |||
| 884 | return 0; | ||
| 885 | |||
| 886 | error: | ||
| 887 | v4l2_ctrl_handler_free(&xtpg->ctrl_handler); | ||
| 888 | media_entity_cleanup(&subdev->entity); | ||
| 889 | xvtc_put(xtpg->vtc); | ||
| 890 | error_resource: | ||
| 891 | xvip_cleanup_resources(&xtpg->xvip); | ||
| 892 | return ret; | ||
| 893 | } | ||
| 894 | |||
| 895 | static int xtpg_remove(struct platform_device *pdev) | ||
| 896 | { | ||
| 897 | struct xtpg_device *xtpg = platform_get_drvdata(pdev); | ||
| 898 | struct v4l2_subdev *subdev = &xtpg->xvip.subdev; | ||
| 899 | |||
| 900 | v4l2_async_unregister_subdev(subdev); | ||
| 901 | v4l2_ctrl_handler_free(&xtpg->ctrl_handler); | ||
| 902 | media_entity_cleanup(&subdev->entity); | ||
| 903 | |||
| 904 | xvip_cleanup_resources(&xtpg->xvip); | ||
| 905 | |||
| 906 | return 0; | ||
| 907 | } | ||
| 908 | |||
| 909 | static SIMPLE_DEV_PM_OPS(xtpg_pm_ops, xtpg_pm_suspend, xtpg_pm_resume); | ||
| 910 | |||
| 911 | static const struct of_device_id xtpg_of_id_table[] = { | ||
| 912 | { .compatible = "xlnx,v-tpg-5.0" }, | ||
| 913 | { } | ||
| 914 | }; | ||
| 915 | MODULE_DEVICE_TABLE(of, xtpg_of_id_table); | ||
| 916 | |||
| 917 | static struct platform_driver xtpg_driver = { | ||
| 918 | .driver = { | ||
| 919 | .name = "xilinx-tpg", | ||
| 920 | .pm = &xtpg_pm_ops, | ||
| 921 | .of_match_table = xtpg_of_id_table, | ||
| 922 | }, | ||
| 923 | .probe = xtpg_probe, | ||
| 924 | .remove = xtpg_remove, | ||
| 925 | }; | ||
| 926 | |||
| 927 | module_platform_driver(xtpg_driver); | ||
| 928 | |||
| 929 | MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); | ||
| 930 | MODULE_DESCRIPTION("Xilinx Test Pattern Generator Driver"); | ||
| 931 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/media/platform/xilinx/xilinx-vip.c b/drivers/media/platform/xilinx/xilinx-vip.c new file mode 100644 index 000000000000..311259129504 --- /dev/null +++ b/drivers/media/platform/xilinx/xilinx-vip.c | |||
| @@ -0,0 +1,323 @@ | |||
| 1 | /* | ||
| 2 | * Xilinx Video IP Core | ||
| 3 | * | ||
| 4 | * Copyright (C) 2013-2015 Ideas on Board | ||
| 5 | * Copyright (C) 2013-2015 Xilinx, Inc. | ||
| 6 | * | ||
| 7 | * Contacts: Hyun Kwon <hyun.kwon@xilinx.com> | ||
| 8 | * Laurent Pinchart <laurent.pinchart@ideasonboard.com> | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License version 2 as | ||
| 12 | * published by the Free Software Foundation. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include <linux/clk.h> | ||
| 16 | #include <linux/export.h> | ||
| 17 | #include <linux/kernel.h> | ||
| 18 | #include <linux/of.h> | ||
| 19 | #include <linux/platform_device.h> | ||
| 20 | |||
| 21 | #include <dt-bindings/media/xilinx-vip.h> | ||
| 22 | |||
| 23 | #include "xilinx-vip.h" | ||
| 24 | |||
| 25 | /* ----------------------------------------------------------------------------- | ||
| 26 | * Helper functions | ||
| 27 | */ | ||
| 28 | |||
| 29 | static const struct xvip_video_format xvip_video_formats[] = { | ||
| 30 | { XVIP_VF_YUV_422, 8, NULL, MEDIA_BUS_FMT_UYVY8_1X16, | ||
| 31 | 2, V4L2_PIX_FMT_YUYV, "4:2:2, packed, YUYV" }, | ||
| 32 | { XVIP_VF_YUV_444, 8, NULL, MEDIA_BUS_FMT_VUY8_1X24, | ||
| 33 | 3, V4L2_PIX_FMT_YUV444, "4:4:4, packed, YUYV" }, | ||
| 34 | { XVIP_VF_RBG, 8, NULL, MEDIA_BUS_FMT_RBG888_1X24, | ||
| 35 | 3, 0, NULL }, | ||
| 36 | { XVIP_VF_MONO_SENSOR, 8, "mono", MEDIA_BUS_FMT_Y8_1X8, | ||
| 37 | 1, V4L2_PIX_FMT_GREY, "Greyscale 8-bit" }, | ||
| 38 | { XVIP_VF_MONO_SENSOR, 8, "rggb", MEDIA_BUS_FMT_SRGGB8_1X8, | ||
| 39 | 1, V4L2_PIX_FMT_SGRBG8, "Bayer 8-bit RGGB" }, | ||
| 40 | { XVIP_VF_MONO_SENSOR, 8, "grbg", MEDIA_BUS_FMT_SGRBG8_1X8, | ||
| 41 | 1, V4L2_PIX_FMT_SGRBG8, "Bayer 8-bit GRBG" }, | ||
| 42 | { XVIP_VF_MONO_SENSOR, 8, "gbrg", MEDIA_BUS_FMT_SGBRG8_1X8, | ||
| 43 | 1, V4L2_PIX_FMT_SGBRG8, "Bayer 8-bit GBRG" }, | ||
| 44 | { XVIP_VF_MONO_SENSOR, 8, "bggr", MEDIA_BUS_FMT_SBGGR8_1X8, | ||
| 45 | 1, V4L2_PIX_FMT_SBGGR8, "Bayer 8-bit BGGR" }, | ||
| 46 | }; | ||
| 47 | |||
| 48 | /** | ||
| 49 | * xvip_get_format_by_code - Retrieve format information for a media bus code | ||
| 50 | * @code: the format media bus code | ||
| 51 | * | ||
| 52 | * Return: a pointer to the format information structure corresponding to the | ||
| 53 | * given V4L2 media bus format @code, or ERR_PTR if no corresponding format can | ||
| 54 | * be found. | ||
| 55 | */ | ||
| 56 | const struct xvip_video_format *xvip_get_format_by_code(unsigned int code) | ||
| 57 | { | ||
| 58 | unsigned int i; | ||
| 59 | |||
| 60 | for (i = 0; i < ARRAY_SIZE(xvip_video_formats); ++i) { | ||
| 61 | const struct xvip_video_format *format = &xvip_video_formats[i]; | ||
| 62 | |||
| 63 | if (format->code == code) | ||
| 64 | return format; | ||
| 65 | } | ||
| 66 | |||
| 67 | return ERR_PTR(-EINVAL); | ||
| 68 | } | ||
| 69 | EXPORT_SYMBOL_GPL(xvip_get_format_by_code); | ||
| 70 | |||
| 71 | /** | ||
| 72 | * xvip_get_format_by_fourcc - Retrieve format information for a 4CC | ||
| 73 | * @fourcc: the format 4CC | ||
| 74 | * | ||
| 75 | * Return: a pointer to the format information structure corresponding to the | ||
| 76 | * given V4L2 format @fourcc, or ERR_PTR if no corresponding format can be | ||
| 77 | * found. | ||
| 78 | */ | ||
| 79 | const struct xvip_video_format *xvip_get_format_by_fourcc(u32 fourcc) | ||
| 80 | { | ||
| 81 | unsigned int i; | ||
| 82 | |||
| 83 | for (i = 0; i < ARRAY_SIZE(xvip_video_formats); ++i) { | ||
| 84 | const struct xvip_video_format *format = &xvip_video_formats[i]; | ||
| 85 | |||
| 86 | if (format->fourcc == fourcc) | ||
| 87 | return format; | ||
| 88 | } | ||
| 89 | |||
| 90 | return ERR_PTR(-EINVAL); | ||
| 91 | } | ||
| 92 | EXPORT_SYMBOL_GPL(xvip_get_format_by_fourcc); | ||
| 93 | |||
| 94 | /** | ||
| 95 | * xvip_of_get_format - Parse a device tree node and return format information | ||
| 96 | * @node: the device tree node | ||
| 97 | * | ||
| 98 | * Read the xlnx,video-format, xlnx,video-width and xlnx,cfa-pattern properties | ||
| 99 | * from the device tree @node passed as an argument and return the corresponding | ||
| 100 | * format information. | ||
| 101 | * | ||
| 102 | * Return: a pointer to the format information structure corresponding to the | ||
| 103 | * format name and width, or ERR_PTR if no corresponding format can be found. | ||
| 104 | */ | ||
| 105 | const struct xvip_video_format *xvip_of_get_format(struct device_node *node) | ||
| 106 | { | ||
| 107 | const char *pattern = "mono"; | ||
| 108 | unsigned int vf_code; | ||
| 109 | unsigned int i; | ||
| 110 | u32 width; | ||
| 111 | int ret; | ||
| 112 | |||
| 113 | ret = of_property_read_u32(node, "xlnx,video-format", &vf_code); | ||
| 114 | if (ret < 0) | ||
| 115 | return ERR_PTR(ret); | ||
| 116 | |||
| 117 | ret = of_property_read_u32(node, "xlnx,video-width", &width); | ||
| 118 | if (ret < 0) | ||
| 119 | return ERR_PTR(ret); | ||
| 120 | |||
| 121 | if (vf_code == XVIP_VF_MONO_SENSOR) | ||
| 122 | of_property_read_string(node, "xlnx,cfa-pattern", &pattern); | ||
| 123 | |||
| 124 | for (i = 0; i < ARRAY_SIZE(xvip_video_formats); ++i) { | ||
| 125 | const struct xvip_video_format *format = &xvip_video_formats[i]; | ||
| 126 | |||
| 127 | if (format->vf_code != vf_code || format->width != width) | ||
| 128 | continue; | ||
| 129 | |||
| 130 | if (vf_code == XVIP_VF_MONO_SENSOR && | ||
| 131 | strcmp(pattern, format->pattern)) | ||
| 132 | continue; | ||
| 133 | |||
| 134 | return format; | ||
| 135 | } | ||
| 136 | |||
| 137 | return ERR_PTR(-EINVAL); | ||
| 138 | } | ||
| 139 | EXPORT_SYMBOL_GPL(xvip_of_get_format); | ||
| 140 | |||
| 141 | /** | ||
| 142 | * xvip_set_format_size - Set the media bus frame format size | ||
| 143 | * @format: V4L2 frame format on media bus | ||
| 144 | * @fmt: media bus format | ||
| 145 | * | ||
| 146 | * Set the media bus frame format size. The width / height from the subdevice | ||
| 147 | * format are set to the given media bus format. The new format size is stored | ||
| 148 | * in @format. The width and height are clamped using default min / max values. | ||
| 149 | */ | ||
| 150 | void xvip_set_format_size(struct v4l2_mbus_framefmt *format, | ||
| 151 | const struct v4l2_subdev_format *fmt) | ||
| 152 | { | ||
| 153 | format->width = clamp_t(unsigned int, fmt->format.width, | ||
| 154 | XVIP_MIN_WIDTH, XVIP_MAX_WIDTH); | ||
| 155 | format->height = clamp_t(unsigned int, fmt->format.height, | ||
| 156 | XVIP_MIN_HEIGHT, XVIP_MAX_HEIGHT); | ||
| 157 | } | ||
| 158 | EXPORT_SYMBOL_GPL(xvip_set_format_size); | ||
| 159 | |||
| 160 | /** | ||
| 161 | * xvip_clr_or_set - Clear or set the register with a bitmask | ||
| 162 | * @xvip: Xilinx Video IP device | ||
| 163 | * @addr: address of register | ||
| 164 | * @mask: bitmask to be set or cleared | ||
| 165 | * @set: boolean flag indicating whether to set or clear | ||
| 166 | * | ||
| 167 | * Clear or set the register at address @addr with a bitmask @mask depending on | ||
| 168 | * the boolean flag @set. When the flag @set is true, the bitmask is set in | ||
| 169 | * the register, otherwise the bitmask is cleared from the register | ||
| 170 | * when the flag @set is false. | ||
| 171 | * | ||
| 172 | * Fox eample, this function can be used to set a control with a boolean value | ||
| 173 | * requested by users. If the caller knows whether to set or clear in the first | ||
| 174 | * place, the caller should call xvip_clr() or xvip_set() directly instead of | ||
| 175 | * using this function. | ||
| 176 | */ | ||
| 177 | void xvip_clr_or_set(struct xvip_device *xvip, u32 addr, u32 mask, bool set) | ||
| 178 | { | ||
| 179 | u32 reg; | ||
| 180 | |||
| 181 | reg = xvip_read(xvip, addr); | ||
| 182 | reg = set ? reg | mask : reg & ~mask; | ||
| 183 | xvip_write(xvip, addr, reg); | ||
| 184 | } | ||
| 185 | EXPORT_SYMBOL_GPL(xvip_clr_or_set); | ||
| 186 | |||
| 187 | /** | ||
| 188 | * xvip_clr_and_set - Clear and set the register with a bitmask | ||
| 189 | * @xvip: Xilinx Video IP device | ||
| 190 | * @addr: address of register | ||
| 191 | * @clr: bitmask to be cleared | ||
| 192 | * @set: bitmask to be set | ||
| 193 | * | ||
| 194 | * Clear a bit(s) of mask @clr in the register at address @addr, then set | ||
| 195 | * a bit(s) of mask @set in the register after. | ||
| 196 | */ | ||
| 197 | void xvip_clr_and_set(struct xvip_device *xvip, u32 addr, u32 clr, u32 set) | ||
| 198 | { | ||
| 199 | u32 reg; | ||
| 200 | |||
| 201 | reg = xvip_read(xvip, addr); | ||
| 202 | reg &= ~clr; | ||
| 203 | reg |= set; | ||
| 204 | xvip_write(xvip, addr, reg); | ||
| 205 | } | ||
| 206 | EXPORT_SYMBOL_GPL(xvip_clr_and_set); | ||
| 207 | |||
| 208 | int xvip_init_resources(struct xvip_device *xvip) | ||
| 209 | { | ||
| 210 | struct platform_device *pdev = to_platform_device(xvip->dev); | ||
| 211 | struct resource *res; | ||
| 212 | |||
| 213 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 214 | xvip->iomem = devm_ioremap_resource(xvip->dev, res); | ||
| 215 | if (IS_ERR(xvip->iomem)) | ||
| 216 | return PTR_ERR(xvip->iomem); | ||
| 217 | |||
| 218 | xvip->clk = devm_clk_get(xvip->dev, NULL); | ||
| 219 | if (IS_ERR(xvip->clk)) | ||
| 220 | return PTR_ERR(xvip->clk); | ||
| 221 | |||
| 222 | clk_prepare_enable(xvip->clk); | ||
| 223 | return 0; | ||
| 224 | } | ||
| 225 | EXPORT_SYMBOL_GPL(xvip_init_resources); | ||
| 226 | |||
| 227 | void xvip_cleanup_resources(struct xvip_device *xvip) | ||
| 228 | { | ||
| 229 | clk_disable_unprepare(xvip->clk); | ||
| 230 | } | ||
| 231 | EXPORT_SYMBOL_GPL(xvip_cleanup_resources); | ||
| 232 | |||
| 233 | /* ----------------------------------------------------------------------------- | ||
| 234 | * Subdev operations handlers | ||
| 235 | */ | ||
| 236 | |||
| 237 | /** | ||
| 238 | * xvip_enum_mbus_code - Enumerate the media format code | ||
| 239 | * @subdev: V4L2 subdevice | ||
| 240 | * @cfg: V4L2 subdev pad configuration | ||
| 241 | * @code: returning media bus code | ||
| 242 | * | ||
| 243 | * Enumerate the media bus code of the subdevice. Return the corresponding | ||
| 244 | * pad format code. This function only works for subdevices with fixed format | ||
| 245 | * on all pads. Subdevices with multiple format should have their own | ||
| 246 | * function to enumerate mbus codes. | ||
| 247 | * | ||
| 248 | * Return: 0 if the media bus code is found, or -EINVAL if the format index | ||
| 249 | * is not valid. | ||
| 250 | */ | ||
| 251 | int xvip_enum_mbus_code(struct v4l2_subdev *subdev, | ||
| 252 | struct v4l2_subdev_pad_config *cfg, | ||
| 253 | struct v4l2_subdev_mbus_code_enum *code) | ||
| 254 | { | ||
| 255 | struct v4l2_mbus_framefmt *format; | ||
| 256 | |||
| 257 | /* Enumerating frame sizes based on the active configuration isn't | ||
| 258 | * supported yet. | ||
| 259 | */ | ||
| 260 | if (code->which == V4L2_SUBDEV_FORMAT_ACTIVE) | ||
| 261 | return -EINVAL; | ||
| 262 | |||
| 263 | if (code->index) | ||
| 264 | return -EINVAL; | ||
| 265 | |||
| 266 | format = v4l2_subdev_get_try_format(subdev, cfg, code->pad); | ||
| 267 | |||
| 268 | code->code = format->code; | ||
| 269 | |||
| 270 | return 0; | ||
| 271 | } | ||
| 272 | EXPORT_SYMBOL_GPL(xvip_enum_mbus_code); | ||
| 273 | |||
| 274 | /** | ||
| 275 | * xvip_enum_frame_size - Enumerate the media bus frame size | ||
| 276 | * @subdev: V4L2 subdevice | ||
| 277 | * @cfg: V4L2 subdev pad configuration | ||
| 278 | * @fse: returning media bus frame size | ||
| 279 | * | ||
| 280 | * This function is a drop-in implementation of the subdev enum_frame_size pad | ||
| 281 | * operation. It assumes that the subdevice has one sink pad and one source | ||
| 282 | * pad, and that the format on the source pad is always identical to the | ||
| 283 | * format on the sink pad. Entities with different requirements need to | ||
| 284 | * implement their own enum_frame_size handlers. | ||
| 285 | * | ||
| 286 | * Return: 0 if the media bus frame size is found, or -EINVAL | ||
| 287 | * if the index or the code is not valid. | ||
| 288 | */ | ||
| 289 | int xvip_enum_frame_size(struct v4l2_subdev *subdev, | ||
| 290 | struct v4l2_subdev_pad_config *cfg, | ||
| 291 | struct v4l2_subdev_frame_size_enum *fse) | ||
| 292 | { | ||
| 293 | struct v4l2_mbus_framefmt *format; | ||
| 294 | |||
| 295 | /* Enumerating frame sizes based on the active configuration isn't | ||
| 296 | * supported yet. | ||
| 297 | */ | ||
| 298 | if (fse->which == V4L2_SUBDEV_FORMAT_ACTIVE) | ||
| 299 | return -EINVAL; | ||
| 300 | |||
| 301 | format = v4l2_subdev_get_try_format(subdev, cfg, fse->pad); | ||
| 302 | |||
| 303 | if (fse->index || fse->code != format->code) | ||
| 304 | return -EINVAL; | ||
| 305 | |||
| 306 | if (fse->pad == XVIP_PAD_SINK) { | ||
| 307 | fse->min_width = XVIP_MIN_WIDTH; | ||
| 308 | fse->max_width = XVIP_MAX_WIDTH; | ||
| 309 | fse->min_height = XVIP_MIN_HEIGHT; | ||
| 310 | fse->max_height = XVIP_MAX_HEIGHT; | ||
| 311 | } else { | ||
| 312 | /* The size on the source pad is fixed and always identical to | ||
| 313 | * the size on the sink pad. | ||
| 314 | */ | ||
| 315 | fse->min_width = format->width; | ||
| 316 | fse->max_width = format->width; | ||
| 317 | fse->min_height = format->height; | ||
| 318 | fse->max_height = format->height; | ||
| 319 | } | ||
| 320 | |||
| 321 | return 0; | ||
| 322 | } | ||
| 323 | EXPORT_SYMBOL_GPL(xvip_enum_frame_size); | ||
diff --git a/drivers/media/platform/xilinx/xilinx-vip.h b/drivers/media/platform/xilinx/xilinx-vip.h new file mode 100644 index 000000000000..42fee2026815 --- /dev/null +++ b/drivers/media/platform/xilinx/xilinx-vip.h | |||
| @@ -0,0 +1,238 @@ | |||
| 1 | /* | ||
| 2 | * Xilinx Video IP Core | ||
| 3 | * | ||
| 4 | * Copyright (C) 2013-2015 Ideas on Board | ||
| 5 | * Copyright (C) 2013-2015 Xilinx, Inc. | ||
| 6 | * | ||
| 7 | * Contacts: Hyun Kwon <hyun.kwon@xilinx.com> | ||
| 8 | * Laurent Pinchart <laurent.pinchart@ideasonboard.com> | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License version 2 as | ||
| 12 | * published by the Free Software Foundation. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #ifndef __XILINX_VIP_H__ | ||
| 16 | #define __XILINX_VIP_H__ | ||
| 17 | |||
| 18 | #include <linux/io.h> | ||
| 19 | #include <media/v4l2-subdev.h> | ||
| 20 | |||
| 21 | struct clk; | ||
| 22 | |||
| 23 | /* | ||
| 24 | * Minimum and maximum width and height common to most video IP cores. IP | ||
| 25 | * cores with different requirements must define their own values. | ||
| 26 | */ | ||
| 27 | #define XVIP_MIN_WIDTH 32 | ||
| 28 | #define XVIP_MAX_WIDTH 7680 | ||
| 29 | #define XVIP_MIN_HEIGHT 32 | ||
| 30 | #define XVIP_MAX_HEIGHT 7680 | ||
| 31 | |||
| 32 | /* | ||
| 33 | * Pad IDs. IP cores with with multiple inputs or outputs should define | ||
| 34 | * their own values. | ||
| 35 | */ | ||
| 36 | #define XVIP_PAD_SINK 0 | ||
| 37 | #define XVIP_PAD_SOURCE 1 | ||
| 38 | |||
| 39 | /* Xilinx Video IP Control Registers */ | ||
| 40 | #define XVIP_CTRL_CONTROL 0x0000 | ||
| 41 | #define XVIP_CTRL_CONTROL_SW_ENABLE (1 << 0) | ||
| 42 | #define XVIP_CTRL_CONTROL_REG_UPDATE (1 << 1) | ||
| 43 | #define XVIP_CTRL_CONTROL_BYPASS (1 << 4) | ||
| 44 | #define XVIP_CTRL_CONTROL_TEST_PATTERN (1 << 5) | ||
| 45 | #define XVIP_CTRL_CONTROL_FRAME_SYNC_RESET (1 << 30) | ||
| 46 | #define XVIP_CTRL_CONTROL_SW_RESET (1 << 31) | ||
| 47 | #define XVIP_CTRL_STATUS 0x0004 | ||
| 48 | #define XVIP_CTRL_STATUS_PROC_STARTED (1 << 0) | ||
| 49 | #define XVIP_CTRL_STATUS_EOF (1 << 1) | ||
| 50 | #define XVIP_CTRL_ERROR 0x0008 | ||
| 51 | #define XVIP_CTRL_ERROR_SLAVE_EOL_EARLY (1 << 0) | ||
| 52 | #define XVIP_CTRL_ERROR_SLAVE_EOL_LATE (1 << 1) | ||
| 53 | #define XVIP_CTRL_ERROR_SLAVE_SOF_EARLY (1 << 2) | ||
| 54 | #define XVIP_CTRL_ERROR_SLAVE_SOF_LATE (1 << 3) | ||
| 55 | #define XVIP_CTRL_IRQ_ENABLE 0x000c | ||
| 56 | #define XVIP_CTRL_IRQ_ENABLE_PROC_STARTED (1 << 0) | ||
| 57 | #define XVIP_CTRL_IRQ_EOF (1 << 1) | ||
| 58 | #define XVIP_CTRL_VERSION 0x0010 | ||
| 59 | #define XVIP_CTRL_VERSION_MAJOR_MASK (0xff << 24) | ||
| 60 | #define XVIP_CTRL_VERSION_MAJOR_SHIFT 24 | ||
| 61 | #define XVIP_CTRL_VERSION_MINOR_MASK (0xff << 16) | ||
| 62 | #define XVIP_CTRL_VERSION_MINOR_SHIFT 16 | ||
| 63 | #define XVIP_CTRL_VERSION_REVISION_MASK (0xf << 12) | ||
| 64 | #define XVIP_CTRL_VERSION_REVISION_SHIFT 12 | ||
| 65 | #define XVIP_CTRL_VERSION_PATCH_MASK (0xf << 8) | ||
| 66 | #define XVIP_CTRL_VERSION_PATCH_SHIFT 8 | ||
| 67 | #define XVIP_CTRL_VERSION_INTERNAL_MASK (0xff << 0) | ||
| 68 | #define XVIP_CTRL_VERSION_INTERNAL_SHIFT 0 | ||
| 69 | |||
| 70 | /* Xilinx Video IP Timing Registers */ | ||
| 71 | #define XVIP_ACTIVE_SIZE 0x0020 | ||
| 72 | #define XVIP_ACTIVE_VSIZE_MASK (0x7ff << 16) | ||
| 73 | #define XVIP_ACTIVE_VSIZE_SHIFT 16 | ||
| 74 | #define XVIP_ACTIVE_HSIZE_MASK (0x7ff << 0) | ||
| 75 | #define XVIP_ACTIVE_HSIZE_SHIFT 0 | ||
| 76 | #define XVIP_ENCODING 0x0028 | ||
| 77 | #define XVIP_ENCODING_NBITS_8 (0 << 4) | ||
| 78 | #define XVIP_ENCODING_NBITS_10 (1 << 4) | ||
| 79 | #define XVIP_ENCODING_NBITS_12 (2 << 4) | ||
| 80 | #define XVIP_ENCODING_NBITS_16 (3 << 4) | ||
| 81 | #define XVIP_ENCODING_NBITS_MASK (3 << 4) | ||
| 82 | #define XVIP_ENCODING_NBITS_SHIFT 4 | ||
| 83 | #define XVIP_ENCODING_VIDEO_FORMAT_YUV422 (0 << 0) | ||
| 84 | #define XVIP_ENCODING_VIDEO_FORMAT_YUV444 (1 << 0) | ||
| 85 | #define XVIP_ENCODING_VIDEO_FORMAT_RGB (2 << 0) | ||
| 86 | #define XVIP_ENCODING_VIDEO_FORMAT_YUV420 (3 << 0) | ||
| 87 | #define XVIP_ENCODING_VIDEO_FORMAT_MASK (3 << 0) | ||
| 88 | #define XVIP_ENCODING_VIDEO_FORMAT_SHIFT 0 | ||
| 89 | |||
| 90 | /** | ||
| 91 | * struct xvip_device - Xilinx Video IP device structure | ||
| 92 | * @subdev: V4L2 subdevice | ||
| 93 | * @dev: (OF) device | ||
| 94 | * @iomem: device I/O register space remapped to kernel virtual memory | ||
| 95 | * @clk: video core clock | ||
| 96 | * @saved_ctrl: saved control register for resume / suspend | ||
| 97 | */ | ||
| 98 | struct xvip_device { | ||
| 99 | struct v4l2_subdev subdev; | ||
| 100 | struct device *dev; | ||
| 101 | void __iomem *iomem; | ||
| 102 | struct clk *clk; | ||
| 103 | u32 saved_ctrl; | ||
| 104 | }; | ||
| 105 | |||
| 106 | /** | ||
| 107 | * struct xvip_video_format - Xilinx Video IP video format description | ||
| 108 | * @vf_code: AXI4 video format code | ||
| 109 | * @width: AXI4 format width in bits per component | ||
| 110 | * @pattern: CFA pattern for Mono/Sensor formats | ||
| 111 | * @code: media bus format code | ||
| 112 | * @bpp: bytes per pixel (when stored in memory) | ||
| 113 | * @fourcc: V4L2 pixel format FCC identifier | ||
| 114 | * @description: format description, suitable for userspace | ||
| 115 | */ | ||
| 116 | struct xvip_video_format { | ||
| 117 | unsigned int vf_code; | ||
| 118 | unsigned int width; | ||
| 119 | const char *pattern; | ||
| 120 | unsigned int code; | ||
| 121 | unsigned int bpp; | ||
| 122 | u32 fourcc; | ||
| 123 | const char *description; | ||
| 124 | }; | ||
| 125 | |||
| 126 | const struct xvip_video_format *xvip_get_format_by_code(unsigned int code); | ||
| 127 | const struct xvip_video_format *xvip_get_format_by_fourcc(u32 fourcc); | ||
| 128 | const struct xvip_video_format *xvip_of_get_format(struct device_node *node); | ||
| 129 | void xvip_set_format_size(struct v4l2_mbus_framefmt *format, | ||
| 130 | const struct v4l2_subdev_format *fmt); | ||
| 131 | int xvip_enum_mbus_code(struct v4l2_subdev *subdev, | ||
| 132 | struct v4l2_subdev_pad_config *cfg, | ||
| 133 | struct v4l2_subdev_mbus_code_enum *code); | ||
| 134 | int xvip_enum_frame_size(struct v4l2_subdev *subdev, | ||
| 135 | struct v4l2_subdev_pad_config *cfg, | ||
| 136 | struct v4l2_subdev_frame_size_enum *fse); | ||
| 137 | |||
| 138 | static inline u32 xvip_read(struct xvip_device *xvip, u32 addr) | ||
| 139 | { | ||
| 140 | return ioread32(xvip->iomem + addr); | ||
| 141 | } | ||
| 142 | |||
| 143 | static inline void xvip_write(struct xvip_device *xvip, u32 addr, u32 value) | ||
| 144 | { | ||
| 145 | iowrite32(value, xvip->iomem + addr); | ||
| 146 | } | ||
| 147 | |||
| 148 | static inline void xvip_clr(struct xvip_device *xvip, u32 addr, u32 clr) | ||
| 149 | { | ||
| 150 | xvip_write(xvip, addr, xvip_read(xvip, addr) & ~clr); | ||
| 151 | } | ||
| 152 | |||
| 153 | static inline void xvip_set(struct xvip_device *xvip, u32 addr, u32 set) | ||
| 154 | { | ||
| 155 | xvip_write(xvip, addr, xvip_read(xvip, addr) | set); | ||
| 156 | } | ||
| 157 | |||
| 158 | void xvip_clr_or_set(struct xvip_device *xvip, u32 addr, u32 mask, bool set); | ||
| 159 | void xvip_clr_and_set(struct xvip_device *xvip, u32 addr, u32 clr, u32 set); | ||
| 160 | |||
| 161 | int xvip_init_resources(struct xvip_device *xvip); | ||
| 162 | void xvip_cleanup_resources(struct xvip_device *xvip); | ||
| 163 | |||
| 164 | static inline void xvip_reset(struct xvip_device *xvip) | ||
| 165 | { | ||
| 166 | xvip_write(xvip, XVIP_CTRL_CONTROL, XVIP_CTRL_CONTROL_SW_RESET); | ||
| 167 | } | ||
| 168 | |||
| 169 | static inline void xvip_start(struct xvip_device *xvip) | ||
| 170 | { | ||
| 171 | xvip_set(xvip, XVIP_CTRL_CONTROL, | ||
| 172 | XVIP_CTRL_CONTROL_SW_ENABLE | XVIP_CTRL_CONTROL_REG_UPDATE); | ||
| 173 | } | ||
| 174 | |||
| 175 | static inline void xvip_stop(struct xvip_device *xvip) | ||
| 176 | { | ||
| 177 | xvip_clr(xvip, XVIP_CTRL_CONTROL, XVIP_CTRL_CONTROL_SW_ENABLE); | ||
| 178 | } | ||
| 179 | |||
| 180 | static inline void xvip_resume(struct xvip_device *xvip) | ||
| 181 | { | ||
| 182 | xvip_write(xvip, XVIP_CTRL_CONTROL, | ||
| 183 | xvip->saved_ctrl | XVIP_CTRL_CONTROL_SW_ENABLE); | ||
| 184 | } | ||
| 185 | |||
| 186 | static inline void xvip_suspend(struct xvip_device *xvip) | ||
| 187 | { | ||
| 188 | xvip->saved_ctrl = xvip_read(xvip, XVIP_CTRL_CONTROL); | ||
| 189 | xvip_write(xvip, XVIP_CTRL_CONTROL, | ||
| 190 | xvip->saved_ctrl & ~XVIP_CTRL_CONTROL_SW_ENABLE); | ||
| 191 | } | ||
| 192 | |||
| 193 | static inline void xvip_set_frame_size(struct xvip_device *xvip, | ||
| 194 | const struct v4l2_mbus_framefmt *format) | ||
| 195 | { | ||
| 196 | xvip_write(xvip, XVIP_ACTIVE_SIZE, | ||
| 197 | (format->height << XVIP_ACTIVE_VSIZE_SHIFT) | | ||
| 198 | (format->width << XVIP_ACTIVE_HSIZE_SHIFT)); | ||
| 199 | } | ||
| 200 | |||
| 201 | static inline void xvip_get_frame_size(struct xvip_device *xvip, | ||
| 202 | struct v4l2_mbus_framefmt *format) | ||
| 203 | { | ||
| 204 | u32 reg; | ||
| 205 | |||
| 206 | reg = xvip_read(xvip, XVIP_ACTIVE_SIZE); | ||
| 207 | format->width = (reg & XVIP_ACTIVE_HSIZE_MASK) >> | ||
| 208 | XVIP_ACTIVE_HSIZE_SHIFT; | ||
| 209 | format->height = (reg & XVIP_ACTIVE_VSIZE_MASK) >> | ||
| 210 | XVIP_ACTIVE_VSIZE_SHIFT; | ||
| 211 | } | ||
| 212 | |||
| 213 | static inline void xvip_enable_reg_update(struct xvip_device *xvip) | ||
| 214 | { | ||
| 215 | xvip_set(xvip, XVIP_CTRL_CONTROL, XVIP_CTRL_CONTROL_REG_UPDATE); | ||
| 216 | } | ||
| 217 | |||
| 218 | static inline void xvip_disable_reg_update(struct xvip_device *xvip) | ||
| 219 | { | ||
| 220 | xvip_clr(xvip, XVIP_CTRL_CONTROL, XVIP_CTRL_CONTROL_REG_UPDATE); | ||
| 221 | } | ||
| 222 | |||
| 223 | static inline void xvip_print_version(struct xvip_device *xvip) | ||
| 224 | { | ||
| 225 | u32 version; | ||
| 226 | |||
| 227 | version = xvip_read(xvip, XVIP_CTRL_VERSION); | ||
| 228 | |||
| 229 | dev_info(xvip->dev, "device found, version %u.%02x%x\n", | ||
| 230 | ((version & XVIP_CTRL_VERSION_MAJOR_MASK) >> | ||
| 231 | XVIP_CTRL_VERSION_MAJOR_SHIFT), | ||
| 232 | ((version & XVIP_CTRL_VERSION_MINOR_MASK) >> | ||
| 233 | XVIP_CTRL_VERSION_MINOR_SHIFT), | ||
| 234 | ((version & XVIP_CTRL_VERSION_REVISION_MASK) >> | ||
| 235 | XVIP_CTRL_VERSION_REVISION_SHIFT)); | ||
| 236 | } | ||
| 237 | |||
| 238 | #endif /* __XILINX_VIP_H__ */ | ||
diff --git a/drivers/media/platform/xilinx/xilinx-vipp.c b/drivers/media/platform/xilinx/xilinx-vipp.c new file mode 100644 index 000000000000..7b7cb9c28d2c --- /dev/null +++ b/drivers/media/platform/xilinx/xilinx-vipp.c | |||
| @@ -0,0 +1,669 @@ | |||
| 1 | /* | ||
| 2 | * Xilinx Video IP Composite Device | ||
| 3 | * | ||
| 4 | * Copyright (C) 2013-2015 Ideas on Board | ||
| 5 | * Copyright (C) 2013-2015 Xilinx, Inc. | ||
| 6 | * | ||
| 7 | * Contacts: Hyun Kwon <hyun.kwon@xilinx.com> | ||
| 8 | * Laurent Pinchart <laurent.pinchart@ideasonboard.com> | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License version 2 as | ||
| 12 | * published by the Free Software Foundation. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include <linux/list.h> | ||
| 16 | #include <linux/module.h> | ||
| 17 | #include <linux/of.h> | ||
| 18 | #include <linux/of_graph.h> | ||
| 19 | #include <linux/platform_device.h> | ||
| 20 | #include <linux/slab.h> | ||
| 21 | |||
| 22 | #include <media/v4l2-async.h> | ||
| 23 | #include <media/v4l2-common.h> | ||
| 24 | #include <media/v4l2-device.h> | ||
| 25 | #include <media/v4l2-of.h> | ||
| 26 | |||
| 27 | #include "xilinx-dma.h" | ||
| 28 | #include "xilinx-vipp.h" | ||
| 29 | |||
| 30 | #define XVIPP_DMA_S2MM 0 | ||
| 31 | #define XVIPP_DMA_MM2S 1 | ||
| 32 | |||
| 33 | /** | ||
| 34 | * struct xvip_graph_entity - Entity in the video graph | ||
| 35 | * @list: list entry in a graph entities list | ||
| 36 | * @node: the entity's DT node | ||
| 37 | * @entity: media entity, from the corresponding V4L2 subdev | ||
| 38 | * @asd: subdev asynchronous registration information | ||
| 39 | * @subdev: V4L2 subdev | ||
| 40 | */ | ||
| 41 | struct xvip_graph_entity { | ||
| 42 | struct list_head list; | ||
| 43 | struct device_node *node; | ||
| 44 | struct media_entity *entity; | ||
| 45 | |||
| 46 | struct v4l2_async_subdev asd; | ||
| 47 | struct v4l2_subdev *subdev; | ||
| 48 | }; | ||
| 49 | |||
| 50 | /* ----------------------------------------------------------------------------- | ||
| 51 | * Graph Management | ||
| 52 | */ | ||
| 53 | |||
| 54 | static struct xvip_graph_entity * | ||
| 55 | xvip_graph_find_entity(struct xvip_composite_device *xdev, | ||
| 56 | const struct device_node *node) | ||
| 57 | { | ||
| 58 | struct xvip_graph_entity *entity; | ||
| 59 | |||
| 60 | list_for_each_entry(entity, &xdev->entities, list) { | ||
| 61 | if (entity->node == node) | ||
| 62 | return entity; | ||
| 63 | } | ||
| 64 | |||
| 65 | return NULL; | ||
| 66 | } | ||
| 67 | |||
| 68 | static int xvip_graph_build_one(struct xvip_composite_device *xdev, | ||
| 69 | struct xvip_graph_entity *entity) | ||
| 70 | { | ||
| 71 | u32 link_flags = MEDIA_LNK_FL_ENABLED; | ||
| 72 | struct media_entity *local = entity->entity; | ||
| 73 | struct media_entity *remote; | ||
| 74 | struct media_pad *local_pad; | ||
| 75 | struct media_pad *remote_pad; | ||
| 76 | struct xvip_graph_entity *ent; | ||
| 77 | struct v4l2_of_link link; | ||
| 78 | struct device_node *ep = NULL; | ||
| 79 | struct device_node *next; | ||
| 80 | int ret = 0; | ||
| 81 | |||
| 82 | dev_dbg(xdev->dev, "creating links for entity %s\n", local->name); | ||
| 83 | |||
| 84 | while (1) { | ||
| 85 | /* Get the next endpoint and parse its link. */ | ||
| 86 | next = of_graph_get_next_endpoint(entity->node, ep); | ||
| 87 | if (next == NULL) | ||
| 88 | break; | ||
| 89 | |||
| 90 | of_node_put(ep); | ||
| 91 | ep = next; | ||
| 92 | |||
| 93 | dev_dbg(xdev->dev, "processing endpoint %s\n", ep->full_name); | ||
| 94 | |||
| 95 | ret = v4l2_of_parse_link(ep, &link); | ||
| 96 | if (ret < 0) { | ||
| 97 | dev_err(xdev->dev, "failed to parse link for %s\n", | ||
| 98 | ep->full_name); | ||
| 99 | continue; | ||
| 100 | } | ||
| 101 | |||
| 102 | /* Skip sink ports, they will be processed from the other end of | ||
| 103 | * the link. | ||
| 104 | */ | ||
| 105 | if (link.local_port >= local->num_pads) { | ||
| 106 | dev_err(xdev->dev, "invalid port number %u on %s\n", | ||
| 107 | link.local_port, link.local_node->full_name); | ||
| 108 | v4l2_of_put_link(&link); | ||
| 109 | ret = -EINVAL; | ||
| 110 | break; | ||
| 111 | } | ||
| 112 | |||
| 113 | local_pad = &local->pads[link.local_port]; | ||
| 114 | |||
| 115 | if (local_pad->flags & MEDIA_PAD_FL_SINK) { | ||
| 116 | dev_dbg(xdev->dev, "skipping sink port %s:%u\n", | ||
| 117 | link.local_node->full_name, link.local_port); | ||
| 118 | v4l2_of_put_link(&link); | ||
| 119 | continue; | ||
| 120 | } | ||
| 121 | |||
| 122 | /* Skip DMA engines, they will be processed separately. */ | ||
| 123 | if (link.remote_node == xdev->dev->of_node) { | ||
| 124 | dev_dbg(xdev->dev, "skipping DMA port %s:%u\n", | ||
| 125 | link.local_node->full_name, link.local_port); | ||
| 126 | v4l2_of_put_link(&link); | ||
| 127 | continue; | ||
| 128 | } | ||
| 129 | |||
| 130 | /* Find the remote entity. */ | ||
| 131 | ent = xvip_graph_find_entity(xdev, link.remote_node); | ||
| 132 | if (ent == NULL) { | ||
| 133 | dev_err(xdev->dev, "no entity found for %s\n", | ||
| 134 | link.remote_node->full_name); | ||
| 135 | v4l2_of_put_link(&link); | ||
| 136 | ret = -ENODEV; | ||
| 137 | break; | ||
| 138 | } | ||
| 139 | |||
| 140 | remote = ent->entity; | ||
| 141 | |||
| 142 | if (link.remote_port >= remote->num_pads) { | ||
| 143 | dev_err(xdev->dev, "invalid port number %u on %s\n", | ||
| 144 | link.remote_port, link.remote_node->full_name); | ||
| 145 | v4l2_of_put_link(&link); | ||
| 146 | ret = -EINVAL; | ||
| 147 | break; | ||
| 148 | } | ||
| 149 | |||
| 150 | remote_pad = &remote->pads[link.remote_port]; | ||
| 151 | |||
| 152 | v4l2_of_put_link(&link); | ||
| 153 | |||
| 154 | /* Create the media link. */ | ||
| 155 | dev_dbg(xdev->dev, "creating %s:%u -> %s:%u link\n", | ||
| 156 | local->name, local_pad->index, | ||
| 157 | remote->name, remote_pad->index); | ||
| 158 | |||
| 159 | ret = media_entity_create_link(local, local_pad->index, | ||
| 160 | remote, remote_pad->index, | ||
| 161 | link_flags); | ||
| 162 | if (ret < 0) { | ||
| 163 | dev_err(xdev->dev, | ||
| 164 | "failed to create %s:%u -> %s:%u link\n", | ||
| 165 | local->name, local_pad->index, | ||
| 166 | remote->name, remote_pad->index); | ||
| 167 | break; | ||
| 168 | } | ||
| 169 | } | ||
| 170 | |||
| 171 | of_node_put(ep); | ||
| 172 | return ret; | ||
| 173 | } | ||
| 174 | |||
| 175 | static struct xvip_dma * | ||
| 176 | xvip_graph_find_dma(struct xvip_composite_device *xdev, unsigned int port) | ||
| 177 | { | ||
| 178 | struct xvip_dma *dma; | ||
| 179 | |||
| 180 | list_for_each_entry(dma, &xdev->dmas, list) { | ||
| 181 | if (dma->port == port) | ||
| 182 | return dma; | ||
| 183 | } | ||
| 184 | |||
| 185 | return NULL; | ||
| 186 | } | ||
| 187 | |||
| 188 | static int xvip_graph_build_dma(struct xvip_composite_device *xdev) | ||
| 189 | { | ||
| 190 | u32 link_flags = MEDIA_LNK_FL_ENABLED; | ||
| 191 | struct device_node *node = xdev->dev->of_node; | ||
| 192 | struct media_entity *source; | ||
| 193 | struct media_entity *sink; | ||
| 194 | struct media_pad *source_pad; | ||
| 195 | struct media_pad *sink_pad; | ||
| 196 | struct xvip_graph_entity *ent; | ||
| 197 | struct v4l2_of_link link; | ||
| 198 | struct device_node *ep = NULL; | ||
| 199 | struct device_node *next; | ||
| 200 | struct xvip_dma *dma; | ||
| 201 | int ret = 0; | ||
| 202 | |||
| 203 | dev_dbg(xdev->dev, "creating links for DMA engines\n"); | ||
| 204 | |||
| 205 | while (1) { | ||
| 206 | /* Get the next endpoint and parse its link. */ | ||
| 207 | next = of_graph_get_next_endpoint(node, ep); | ||
| 208 | if (next == NULL) | ||
| 209 | break; | ||
| 210 | |||
| 211 | of_node_put(ep); | ||
| 212 | ep = next; | ||
| 213 | |||
| 214 | dev_dbg(xdev->dev, "processing endpoint %s\n", ep->full_name); | ||
| 215 | |||
| 216 | ret = v4l2_of_parse_link(ep, &link); | ||
| 217 | if (ret < 0) { | ||
| 218 | dev_err(xdev->dev, "failed to parse link for %s\n", | ||
| 219 | ep->full_name); | ||
| 220 | continue; | ||
| 221 | } | ||
| 222 | |||
| 223 | /* Find the DMA engine. */ | ||
| 224 | dma = xvip_graph_find_dma(xdev, link.local_port); | ||
| 225 | if (dma == NULL) { | ||
| 226 | dev_err(xdev->dev, "no DMA engine found for port %u\n", | ||
| 227 | link.local_port); | ||
| 228 | v4l2_of_put_link(&link); | ||
| 229 | ret = -EINVAL; | ||
| 230 | break; | ||
| 231 | } | ||
| 232 | |||
| 233 | dev_dbg(xdev->dev, "creating link for DMA engine %s\n", | ||
| 234 | dma->video.name); | ||
| 235 | |||
| 236 | /* Find the remote entity. */ | ||
| 237 | ent = xvip_graph_find_entity(xdev, link.remote_node); | ||
| 238 | if (ent == NULL) { | ||
| 239 | dev_err(xdev->dev, "no entity found for %s\n", | ||
| 240 | link.remote_node->full_name); | ||
| 241 | v4l2_of_put_link(&link); | ||
| 242 | ret = -ENODEV; | ||
| 243 | break; | ||
| 244 | } | ||
| 245 | |||
| 246 | if (link.remote_port >= ent->entity->num_pads) { | ||
| 247 | dev_err(xdev->dev, "invalid port number %u on %s\n", | ||
| 248 | link.remote_port, link.remote_node->full_name); | ||
| 249 | v4l2_of_put_link(&link); | ||
| 250 | ret = -EINVAL; | ||
| 251 | break; | ||
| 252 | } | ||
| 253 | |||
| 254 | if (dma->pad.flags & MEDIA_PAD_FL_SOURCE) { | ||
| 255 | source = &dma->video.entity; | ||
| 256 | source_pad = &dma->pad; | ||
| 257 | sink = ent->entity; | ||
| 258 | sink_pad = &sink->pads[link.remote_port]; | ||
| 259 | } else { | ||
| 260 | source = ent->entity; | ||
| 261 | source_pad = &source->pads[link.remote_port]; | ||
| 262 | sink = &dma->video.entity; | ||
| 263 | sink_pad = &dma->pad; | ||
| 264 | } | ||
| 265 | |||
| 266 | v4l2_of_put_link(&link); | ||
| 267 | |||
| 268 | /* Create the media link. */ | ||
| 269 | dev_dbg(xdev->dev, "creating %s:%u -> %s:%u link\n", | ||
| 270 | source->name, source_pad->index, | ||
| 271 | sink->name, sink_pad->index); | ||
| 272 | |||
| 273 | ret = media_entity_create_link(source, source_pad->index, | ||
| 274 | sink, sink_pad->index, | ||
| 275 | link_flags); | ||
| 276 | if (ret < 0) { | ||
| 277 | dev_err(xdev->dev, | ||
| 278 | "failed to create %s:%u -> %s:%u link\n", | ||
| 279 | source->name, source_pad->index, | ||
| 280 | sink->name, sink_pad->index); | ||
| 281 | break; | ||
| 282 | } | ||
| 283 | } | ||
| 284 | |||
| 285 | of_node_put(ep); | ||
| 286 | return ret; | ||
| 287 | } | ||
| 288 | |||
| 289 | static int xvip_graph_notify_complete(struct v4l2_async_notifier *notifier) | ||
| 290 | { | ||
| 291 | struct xvip_composite_device *xdev = | ||
| 292 | container_of(notifier, struct xvip_composite_device, notifier); | ||
| 293 | struct xvip_graph_entity *entity; | ||
| 294 | int ret; | ||
| 295 | |||
| 296 | dev_dbg(xdev->dev, "notify complete, all subdevs registered\n"); | ||
| 297 | |||
| 298 | /* Create links for every entity. */ | ||
| 299 | list_for_each_entry(entity, &xdev->entities, list) { | ||
| 300 | ret = xvip_graph_build_one(xdev, entity); | ||
| 301 | if (ret < 0) | ||
| 302 | return ret; | ||
| 303 | } | ||
| 304 | |||
| 305 | /* Create links for DMA channels. */ | ||
| 306 | ret = xvip_graph_build_dma(xdev); | ||
| 307 | if (ret < 0) | ||
| 308 | return ret; | ||
| 309 | |||
| 310 | ret = v4l2_device_register_subdev_nodes(&xdev->v4l2_dev); | ||
| 311 | if (ret < 0) | ||
| 312 | dev_err(xdev->dev, "failed to register subdev nodes\n"); | ||
| 313 | |||
| 314 | return ret; | ||
| 315 | } | ||
| 316 | |||
| 317 | static int xvip_graph_notify_bound(struct v4l2_async_notifier *notifier, | ||
| 318 | struct v4l2_subdev *subdev, | ||
| 319 | struct v4l2_async_subdev *asd) | ||
| 320 | { | ||
| 321 | struct xvip_composite_device *xdev = | ||
| 322 | container_of(notifier, struct xvip_composite_device, notifier); | ||
| 323 | struct xvip_graph_entity *entity; | ||
| 324 | |||
| 325 | /* Locate the entity corresponding to the bound subdev and store the | ||
| 326 | * subdev pointer. | ||
| 327 | */ | ||
| 328 | list_for_each_entry(entity, &xdev->entities, list) { | ||
| 329 | if (entity->node != subdev->dev->of_node) | ||
| 330 | continue; | ||
| 331 | |||
| 332 | if (entity->subdev) { | ||
| 333 | dev_err(xdev->dev, "duplicate subdev for node %s\n", | ||
| 334 | entity->node->full_name); | ||
| 335 | return -EINVAL; | ||
| 336 | } | ||
| 337 | |||
| 338 | dev_dbg(xdev->dev, "subdev %s bound\n", subdev->name); | ||
| 339 | entity->entity = &subdev->entity; | ||
| 340 | entity->subdev = subdev; | ||
| 341 | return 0; | ||
| 342 | } | ||
| 343 | |||
| 344 | dev_err(xdev->dev, "no entity for subdev %s\n", subdev->name); | ||
| 345 | return -EINVAL; | ||
| 346 | } | ||
| 347 | |||
| 348 | static int xvip_graph_parse_one(struct xvip_composite_device *xdev, | ||
| 349 | struct device_node *node) | ||
| 350 | { | ||
| 351 | struct xvip_graph_entity *entity; | ||
| 352 | struct device_node *remote; | ||
| 353 | struct device_node *ep = NULL; | ||
| 354 | struct device_node *next; | ||
| 355 | int ret = 0; | ||
| 356 | |||
| 357 | dev_dbg(xdev->dev, "parsing node %s\n", node->full_name); | ||
| 358 | |||
| 359 | while (1) { | ||
| 360 | next = of_graph_get_next_endpoint(node, ep); | ||
| 361 | if (next == NULL) | ||
| 362 | break; | ||
| 363 | |||
| 364 | of_node_put(ep); | ||
| 365 | ep = next; | ||
| 366 | |||
| 367 | dev_dbg(xdev->dev, "handling endpoint %s\n", ep->full_name); | ||
| 368 | |||
| 369 | remote = of_graph_get_remote_port_parent(ep); | ||
| 370 | if (remote == NULL) { | ||
| 371 | ret = -EINVAL; | ||
| 372 | break; | ||
| 373 | } | ||
| 374 | |||
| 375 | /* Skip entities that we have already processed. */ | ||
| 376 | if (remote == xdev->dev->of_node || | ||
| 377 | xvip_graph_find_entity(xdev, remote)) { | ||
| 378 | of_node_put(remote); | ||
| 379 | continue; | ||
| 380 | } | ||
| 381 | |||
| 382 | entity = devm_kzalloc(xdev->dev, sizeof(*entity), GFP_KERNEL); | ||
| 383 | if (entity == NULL) { | ||
| 384 | of_node_put(remote); | ||
| 385 | ret = -ENOMEM; | ||
| 386 | break; | ||
| 387 | } | ||
| 388 | |||
| 389 | entity->node = remote; | ||
| 390 | entity->asd.match_type = V4L2_ASYNC_MATCH_OF; | ||
| 391 | entity->asd.match.of.node = remote; | ||
| 392 | list_add_tail(&entity->list, &xdev->entities); | ||
| 393 | xdev->num_subdevs++; | ||
| 394 | } | ||
| 395 | |||
| 396 | of_node_put(ep); | ||
| 397 | return ret; | ||
| 398 | } | ||
| 399 | |||
| 400 | static int xvip_graph_parse(struct xvip_composite_device *xdev) | ||
| 401 | { | ||
| 402 | struct xvip_graph_entity *entity; | ||
| 403 | int ret; | ||
| 404 | |||
| 405 | /* | ||
| 406 | * Walk the links to parse the full graph. Start by parsing the | ||
| 407 | * composite node and then parse entities in turn. The list_for_each | ||
| 408 | * loop will handle entities added at the end of the list while walking | ||
| 409 | * the links. | ||
| 410 | */ | ||
| 411 | ret = xvip_graph_parse_one(xdev, xdev->dev->of_node); | ||
| 412 | if (ret < 0) | ||
| 413 | return 0; | ||
| 414 | |||
| 415 | list_for_each_entry(entity, &xdev->entities, list) { | ||
| 416 | ret = xvip_graph_parse_one(xdev, entity->node); | ||
| 417 | if (ret < 0) | ||
| 418 | break; | ||
| 419 | } | ||
| 420 | |||
| 421 | return ret; | ||
| 422 | } | ||
| 423 | |||
| 424 | static int xvip_graph_dma_init_one(struct xvip_composite_device *xdev, | ||
| 425 | struct device_node *node) | ||
| 426 | { | ||
| 427 | struct xvip_dma *dma; | ||
| 428 | enum v4l2_buf_type type; | ||
| 429 | const char *direction; | ||
| 430 | unsigned int index; | ||
| 431 | int ret; | ||
| 432 | |||
| 433 | ret = of_property_read_string(node, "direction", &direction); | ||
| 434 | if (ret < 0) | ||
| 435 | return ret; | ||
| 436 | |||
| 437 | if (strcmp(direction, "input") == 0) | ||
| 438 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
| 439 | else if (strcmp(direction, "output") == 0) | ||
| 440 | type = V4L2_BUF_TYPE_VIDEO_OUTPUT; | ||
| 441 | else | ||
| 442 | return -EINVAL; | ||
| 443 | |||
| 444 | of_property_read_u32(node, "reg", &index); | ||
| 445 | |||
| 446 | dma = devm_kzalloc(xdev->dev, sizeof(*dma), GFP_KERNEL); | ||
| 447 | if (dma == NULL) | ||
| 448 | return -ENOMEM; | ||
| 449 | |||
| 450 | ret = xvip_dma_init(xdev, dma, type, index); | ||
| 451 | if (ret < 0) { | ||
| 452 | dev_err(xdev->dev, "%s initialization failed\n", | ||
| 453 | node->full_name); | ||
| 454 | return ret; | ||
| 455 | } | ||
| 456 | |||
| 457 | list_add_tail(&dma->list, &xdev->dmas); | ||
| 458 | |||
| 459 | xdev->v4l2_caps |= type == V4L2_BUF_TYPE_VIDEO_CAPTURE | ||
| 460 | ? V4L2_CAP_VIDEO_CAPTURE : V4L2_CAP_VIDEO_OUTPUT; | ||
| 461 | |||
| 462 | return 0; | ||
| 463 | } | ||
| 464 | |||
| 465 | static int xvip_graph_dma_init(struct xvip_composite_device *xdev) | ||
| 466 | { | ||
| 467 | struct device_node *ports; | ||
| 468 | struct device_node *port; | ||
| 469 | int ret; | ||
| 470 | |||
| 471 | ports = of_get_child_by_name(xdev->dev->of_node, "ports"); | ||
| 472 | if (ports == NULL) { | ||
| 473 | dev_err(xdev->dev, "ports node not present\n"); | ||
| 474 | return -EINVAL; | ||
| 475 | } | ||
| 476 | |||
| 477 | for_each_child_of_node(ports, port) { | ||
| 478 | ret = xvip_graph_dma_init_one(xdev, port); | ||
| 479 | if (ret < 0) | ||
| 480 | return ret; | ||
| 481 | } | ||
| 482 | |||
| 483 | return 0; | ||
| 484 | } | ||
| 485 | |||
| 486 | static void xvip_graph_cleanup(struct xvip_composite_device *xdev) | ||
| 487 | { | ||
| 488 | struct xvip_graph_entity *entityp; | ||
| 489 | struct xvip_graph_entity *entity; | ||
| 490 | struct xvip_dma *dmap; | ||
| 491 | struct xvip_dma *dma; | ||
| 492 | |||
| 493 | v4l2_async_notifier_unregister(&xdev->notifier); | ||
| 494 | |||
| 495 | list_for_each_entry_safe(entity, entityp, &xdev->entities, list) { | ||
| 496 | of_node_put(entity->node); | ||
| 497 | list_del(&entity->list); | ||
| 498 | } | ||
| 499 | |||
| 500 | list_for_each_entry_safe(dma, dmap, &xdev->dmas, list) { | ||
| 501 | xvip_dma_cleanup(dma); | ||
| 502 | list_del(&dma->list); | ||
| 503 | } | ||
| 504 | } | ||
| 505 | |||
| 506 | static int xvip_graph_init(struct xvip_composite_device *xdev) | ||
| 507 | { | ||
| 508 | struct xvip_graph_entity *entity; | ||
| 509 | struct v4l2_async_subdev **subdevs = NULL; | ||
| 510 | unsigned int num_subdevs; | ||
| 511 | unsigned int i; | ||
| 512 | int ret; | ||
| 513 | |||
| 514 | /* Init the DMA channels. */ | ||
| 515 | ret = xvip_graph_dma_init(xdev); | ||
| 516 | if (ret < 0) { | ||
| 517 | dev_err(xdev->dev, "DMA initialization failed\n"); | ||
| 518 | goto done; | ||
| 519 | } | ||
| 520 | |||
| 521 | /* Parse the graph to extract a list of subdevice DT nodes. */ | ||
| 522 | ret = xvip_graph_parse(xdev); | ||
| 523 | if (ret < 0) { | ||
| 524 | dev_err(xdev->dev, "graph parsing failed\n"); | ||
| 525 | goto done; | ||
| 526 | } | ||
| 527 | |||
| 528 | if (!xdev->num_subdevs) { | ||
| 529 | dev_err(xdev->dev, "no subdev found in graph\n"); | ||
| 530 | goto done; | ||
| 531 | } | ||
| 532 | |||
| 533 | /* Register the subdevices notifier. */ | ||
| 534 | num_subdevs = xdev->num_subdevs; | ||
| 535 | subdevs = devm_kzalloc(xdev->dev, sizeof(*subdevs) * num_subdevs, | ||
| 536 | GFP_KERNEL); | ||
| 537 | if (subdevs == NULL) { | ||
| 538 | ret = -ENOMEM; | ||
| 539 | goto done; | ||
| 540 | } | ||
| 541 | |||
| 542 | i = 0; | ||
| 543 | list_for_each_entry(entity, &xdev->entities, list) | ||
| 544 | subdevs[i++] = &entity->asd; | ||
| 545 | |||
| 546 | xdev->notifier.subdevs = subdevs; | ||
| 547 | xdev->notifier.num_subdevs = num_subdevs; | ||
| 548 | xdev->notifier.bound = xvip_graph_notify_bound; | ||
| 549 | xdev->notifier.complete = xvip_graph_notify_complete; | ||
| 550 | |||
| 551 | ret = v4l2_async_notifier_register(&xdev->v4l2_dev, &xdev->notifier); | ||
| 552 | if (ret < 0) { | ||
| 553 | dev_err(xdev->dev, "notifier registration failed\n"); | ||
| 554 | goto done; | ||
| 555 | } | ||
| 556 | |||
| 557 | ret = 0; | ||
| 558 | |||
| 559 | done: | ||
| 560 | if (ret < 0) | ||
| 561 | xvip_graph_cleanup(xdev); | ||
| 562 | |||
| 563 | return ret; | ||
| 564 | } | ||
| 565 | |||
| 566 | /* ----------------------------------------------------------------------------- | ||
| 567 | * Media Controller and V4L2 | ||
| 568 | */ | ||
| 569 | |||
| 570 | static void xvip_composite_v4l2_cleanup(struct xvip_composite_device *xdev) | ||
| 571 | { | ||
| 572 | v4l2_device_unregister(&xdev->v4l2_dev); | ||
| 573 | media_device_unregister(&xdev->media_dev); | ||
| 574 | } | ||
| 575 | |||
| 576 | static int xvip_composite_v4l2_init(struct xvip_composite_device *xdev) | ||
| 577 | { | ||
| 578 | int ret; | ||
| 579 | |||
| 580 | xdev->media_dev.dev = xdev->dev; | ||
| 581 | strlcpy(xdev->media_dev.model, "Xilinx Video Composite Device", | ||
| 582 | sizeof(xdev->media_dev.model)); | ||
| 583 | xdev->media_dev.hw_revision = 0; | ||
| 584 | |||
| 585 | ret = media_device_register(&xdev->media_dev); | ||
| 586 | if (ret < 0) { | ||
| 587 | dev_err(xdev->dev, "media device registration failed (%d)\n", | ||
| 588 | ret); | ||
| 589 | return ret; | ||
| 590 | } | ||
| 591 | |||
| 592 | xdev->v4l2_dev.mdev = &xdev->media_dev; | ||
| 593 | ret = v4l2_device_register(xdev->dev, &xdev->v4l2_dev); | ||
| 594 | if (ret < 0) { | ||
| 595 | dev_err(xdev->dev, "V4L2 device registration failed (%d)\n", | ||
| 596 | ret); | ||
| 597 | media_device_unregister(&xdev->media_dev); | ||
| 598 | return ret; | ||
| 599 | } | ||
| 600 | |||
| 601 | return 0; | ||
| 602 | } | ||
| 603 | |||
| 604 | /* ----------------------------------------------------------------------------- | ||
| 605 | * Platform Device Driver | ||
| 606 | */ | ||
| 607 | |||
| 608 | static int xvip_composite_probe(struct platform_device *pdev) | ||
| 609 | { | ||
| 610 | struct xvip_composite_device *xdev; | ||
| 611 | int ret; | ||
| 612 | |||
| 613 | xdev = devm_kzalloc(&pdev->dev, sizeof(*xdev), GFP_KERNEL); | ||
| 614 | if (!xdev) | ||
| 615 | return -ENOMEM; | ||
| 616 | |||
| 617 | xdev->dev = &pdev->dev; | ||
| 618 | INIT_LIST_HEAD(&xdev->entities); | ||
| 619 | INIT_LIST_HEAD(&xdev->dmas); | ||
| 620 | |||
| 621 | ret = xvip_composite_v4l2_init(xdev); | ||
| 622 | if (ret < 0) | ||
| 623 | return ret; | ||
| 624 | |||
| 625 | ret = xvip_graph_init(xdev); | ||
| 626 | if (ret < 0) | ||
| 627 | goto error; | ||
| 628 | |||
| 629 | platform_set_drvdata(pdev, xdev); | ||
| 630 | |||
| 631 | dev_info(xdev->dev, "device registered\n"); | ||
| 632 | |||
| 633 | return 0; | ||
| 634 | |||
| 635 | error: | ||
| 636 | xvip_composite_v4l2_cleanup(xdev); | ||
| 637 | return ret; | ||
| 638 | } | ||
| 639 | |||
| 640 | static int xvip_composite_remove(struct platform_device *pdev) | ||
| 641 | { | ||
| 642 | struct xvip_composite_device *xdev = platform_get_drvdata(pdev); | ||
| 643 | |||
| 644 | xvip_graph_cleanup(xdev); | ||
| 645 | xvip_composite_v4l2_cleanup(xdev); | ||
| 646 | |||
| 647 | return 0; | ||
| 648 | } | ||
| 649 | |||
| 650 | static const struct of_device_id xvip_composite_of_id_table[] = { | ||
| 651 | { .compatible = "xlnx,video" }, | ||
| 652 | { } | ||
| 653 | }; | ||
| 654 | MODULE_DEVICE_TABLE(of, xvip_composite_of_id_table); | ||
| 655 | |||
| 656 | static struct platform_driver xvip_composite_driver = { | ||
| 657 | .driver = { | ||
| 658 | .name = "xilinx-video", | ||
| 659 | .of_match_table = xvip_composite_of_id_table, | ||
| 660 | }, | ||
| 661 | .probe = xvip_composite_probe, | ||
| 662 | .remove = xvip_composite_remove, | ||
| 663 | }; | ||
| 664 | |||
| 665 | module_platform_driver(xvip_composite_driver); | ||
| 666 | |||
| 667 | MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); | ||
| 668 | MODULE_DESCRIPTION("Xilinx Video IP Composite Driver"); | ||
| 669 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/media/platform/xilinx/xilinx-vipp.h b/drivers/media/platform/xilinx/xilinx-vipp.h new file mode 100644 index 000000000000..faf6b6e80b3b --- /dev/null +++ b/drivers/media/platform/xilinx/xilinx-vipp.h | |||
| @@ -0,0 +1,49 @@ | |||
| 1 | /* | ||
| 2 | * Xilinx Video IP Composite Device | ||
| 3 | * | ||
| 4 | * Copyright (C) 2013-2015 Ideas on Board | ||
| 5 | * Copyright (C) 2013-2015 Xilinx, Inc. | ||
| 6 | * | ||
| 7 | * Contacts: Hyun Kwon <hyun.kwon@xilinx.com> | ||
| 8 | * Laurent Pinchart <laurent.pinchart@ideasonboard.com> | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License version 2 as | ||
| 12 | * published by the Free Software Foundation. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #ifndef __XILINX_VIPP_H__ | ||
| 16 | #define __XILINX_VIPP_H__ | ||
| 17 | |||
| 18 | #include <linux/list.h> | ||
| 19 | #include <linux/mutex.h> | ||
| 20 | #include <media/media-device.h> | ||
| 21 | #include <media/v4l2-async.h> | ||
| 22 | #include <media/v4l2-ctrls.h> | ||
| 23 | #include <media/v4l2-device.h> | ||
| 24 | |||
| 25 | /** | ||
| 26 | * struct xvip_composite_device - Xilinx Video IP device structure | ||
| 27 | * @v4l2_dev: V4L2 device | ||
| 28 | * @media_dev: media device | ||
| 29 | * @dev: (OF) device | ||
| 30 | * @notifier: V4L2 asynchronous subdevs notifier | ||
| 31 | * @entities: entities in the graph as a list of xvip_graph_entity | ||
| 32 | * @num_subdevs: number of subdevs in the pipeline | ||
| 33 | * @dmas: list of DMA channels at the pipeline output and input | ||
| 34 | * @v4l2_caps: V4L2 capabilities of the whole device (see VIDIOC_QUERYCAP) | ||
| 35 | */ | ||
| 36 | struct xvip_composite_device { | ||
| 37 | struct v4l2_device v4l2_dev; | ||
| 38 | struct media_device media_dev; | ||
| 39 | struct device *dev; | ||
| 40 | |||
| 41 | struct v4l2_async_notifier notifier; | ||
| 42 | struct list_head entities; | ||
| 43 | unsigned int num_subdevs; | ||
| 44 | |||
| 45 | struct list_head dmas; | ||
| 46 | u32 v4l2_caps; | ||
| 47 | }; | ||
| 48 | |||
| 49 | #endif /* __XILINX_VIPP_H__ */ | ||
diff --git a/drivers/media/platform/xilinx/xilinx-vtc.c b/drivers/media/platform/xilinx/xilinx-vtc.c new file mode 100644 index 000000000000..01c750edcac5 --- /dev/null +++ b/drivers/media/platform/xilinx/xilinx-vtc.c | |||
| @@ -0,0 +1,380 @@ | |||
| 1 | /* | ||
| 2 | * Xilinx Video Timing Controller | ||
| 3 | * | ||
| 4 | * Copyright (C) 2013-2015 Ideas on Board | ||
| 5 | * Copyright (C) 2013-2015 Xilinx, Inc. | ||
| 6 | * | ||
| 7 | * Contacts: Hyun Kwon <hyun.kwon@xilinx.com> | ||
| 8 | * Laurent Pinchart <laurent.pinchart@ideasonboard.com> | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License version 2 as | ||
| 12 | * published by the Free Software Foundation. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include <linux/clk.h> | ||
| 16 | #include <linux/module.h> | ||
| 17 | #include <linux/of.h> | ||
| 18 | #include <linux/platform_device.h> | ||
| 19 | #include <linux/slab.h> | ||
| 20 | |||
| 21 | #include "xilinx-vip.h" | ||
| 22 | #include "xilinx-vtc.h" | ||
| 23 | |||
| 24 | #define XVTC_CONTROL_FIELD_ID_POL_SRC (1 << 26) | ||
| 25 | #define XVTC_CONTROL_ACTIVE_CHROMA_POL_SRC (1 << 25) | ||
| 26 | #define XVTC_CONTROL_ACTIVE_VIDEO_POL_SRC (1 << 24) | ||
| 27 | #define XVTC_CONTROL_HSYNC_POL_SRC (1 << 23) | ||
| 28 | #define XVTC_CONTROL_VSYNC_POL_SRC (1 << 22) | ||
| 29 | #define XVTC_CONTROL_HBLANK_POL_SRC (1 << 21) | ||
| 30 | #define XVTC_CONTROL_VBLANK_POL_SRC (1 << 20) | ||
| 31 | #define XVTC_CONTROL_CHROMA_SRC (1 << 18) | ||
| 32 | #define XVTC_CONTROL_VBLANK_HOFF_SRC (1 << 17) | ||
| 33 | #define XVTC_CONTROL_VSYNC_END_SRC (1 << 16) | ||
| 34 | #define XVTC_CONTROL_VSYNC_START_SRC (1 << 15) | ||
| 35 | #define XVTC_CONTROL_ACTIVE_VSIZE_SRC (1 << 14) | ||
| 36 | #define XVTC_CONTROL_FRAME_VSIZE_SRC (1 << 13) | ||
| 37 | #define XVTC_CONTROL_HSYNC_END_SRC (1 << 11) | ||
| 38 | #define XVTC_CONTROL_HSYNC_START_SRC (1 << 10) | ||
| 39 | #define XVTC_CONTROL_ACTIVE_HSIZE_SRC (1 << 9) | ||
| 40 | #define XVTC_CONTROL_FRAME_HSIZE_SRC (1 << 8) | ||
| 41 | #define XVTC_CONTROL_SYNC_ENABLE (1 << 5) | ||
| 42 | #define XVTC_CONTROL_DET_ENABLE (1 << 3) | ||
| 43 | #define XVTC_CONTROL_GEN_ENABLE (1 << 2) | ||
| 44 | |||
| 45 | #define XVTC_STATUS_FSYNC(n) ((n) << 16) | ||
| 46 | #define XVTC_STATUS_GEN_ACTIVE_VIDEO (1 << 13) | ||
| 47 | #define XVTC_STATUS_GEN_VBLANK (1 << 12) | ||
| 48 | #define XVTC_STATUS_DET_ACTIVE_VIDEO (1 << 11) | ||
| 49 | #define XVTC_STATUS_DET_VBLANK (1 << 10) | ||
| 50 | #define XVTC_STATUS_LOCK_LOSS (1 << 9) | ||
| 51 | #define XVTC_STATUS_LOCK (1 << 8) | ||
| 52 | |||
| 53 | #define XVTC_ERROR_ACTIVE_CHROMA_LOCK (1 << 21) | ||
| 54 | #define XVTC_ERROR_ACTIVE_VIDEO_LOCK (1 << 20) | ||
| 55 | #define XVTC_ERROR_HSYNC_LOCK (1 << 19) | ||
| 56 | #define XVTC_ERROR_VSYNC_LOCK (1 << 18) | ||
| 57 | #define XVTC_ERROR_HBLANK_LOCK (1 << 17) | ||
| 58 | #define XVTC_ERROR_VBLANK_LOCK (1 << 16) | ||
| 59 | |||
| 60 | #define XVTC_IRQ_ENABLE_FSYNC(n) ((n) << 16) | ||
| 61 | #define XVTC_IRQ_ENABLE_GEN_ACTIVE_VIDEO (1 << 13) | ||
| 62 | #define XVTC_IRQ_ENABLE_GEN_VBLANK (1 << 12) | ||
| 63 | #define XVTC_IRQ_ENABLE_DET_ACTIVE_VIDEO (1 << 11) | ||
| 64 | #define XVTC_IRQ_ENABLE_DET_VBLANK (1 << 10) | ||
| 65 | #define XVTC_IRQ_ENABLE_LOCK_LOSS (1 << 9) | ||
| 66 | #define XVTC_IRQ_ENABLE_LOCK (1 << 8) | ||
| 67 | |||
| 68 | /* | ||
| 69 | * The following registers exist in two blocks, one at 0x0020 for the detector | ||
| 70 | * and one at 0x0060 for the generator. | ||
| 71 | */ | ||
| 72 | |||
| 73 | #define XVTC_DETECTOR_OFFSET 0x0020 | ||
| 74 | #define XVTC_GENERATOR_OFFSET 0x0060 | ||
| 75 | |||
| 76 | #define XVTC_ACTIVE_SIZE 0x0000 | ||
| 77 | #define XVTC_ACTIVE_VSIZE_SHIFT 16 | ||
| 78 | #define XVTC_ACTIVE_VSIZE_MASK (0x1fff << 16) | ||
| 79 | #define XVTC_ACTIVE_HSIZE_SHIFT 0 | ||
| 80 | #define XVTC_ACTIVE_HSIZE_MASK (0x1fff << 0) | ||
| 81 | |||
| 82 | #define XVTC_TIMING_STATUS 0x0004 | ||
| 83 | #define XVTC_TIMING_STATUS_ACTIVE_VIDEO (1 << 2) | ||
| 84 | #define XVTC_TIMING_STATUS_VBLANK (1 << 1) | ||
| 85 | #define XVTC_TIMING_STATUS_LOCKED (1 << 0) | ||
| 86 | |||
| 87 | #define XVTC_ENCODING 0x0008 | ||
| 88 | #define XVTC_ENCODING_CHROMA_PARITY_SHIFT 8 | ||
| 89 | #define XVTC_ENCODING_CHROMA_PARITY_MASK (3 << 8) | ||
| 90 | #define XVTC_ENCODING_CHROMA_PARITY_EVEN_ALL (0 << 8) | ||
| 91 | #define XVTC_ENCODING_CHROMA_PARITY_ODD_ALL (1 << 8) | ||
| 92 | #define XVTC_ENCODING_CHROMA_PARITY_EVEN_EVEN (2 << 8) | ||
| 93 | #define XVTC_ENCODING_CHROMA_PARITY_ODD_EVEN (3 << 8) | ||
| 94 | #define XVTC_ENCODING_VIDEO_FORMAT_SHIFT 0 | ||
| 95 | #define XVTC_ENCODING_VIDEO_FORMAT_MASK (0xf << 0) | ||
| 96 | #define XVTC_ENCODING_VIDEO_FORMAT_YUV422 (0 << 0) | ||
| 97 | #define XVTC_ENCODING_VIDEO_FORMAT_YUV444 (1 << 0) | ||
| 98 | #define XVTC_ENCODING_VIDEO_FORMAT_RGB (2 << 0) | ||
| 99 | #define XVTC_ENCODING_VIDEO_FORMAT_YUV420 (3 << 0) | ||
| 100 | |||
| 101 | #define XVTC_POLARITY 0x000c | ||
| 102 | #define XVTC_POLARITY_ACTIVE_CHROMA_POL (1 << 5) | ||
| 103 | #define XVTC_POLARITY_ACTIVE_VIDEO_POL (1 << 4) | ||
| 104 | #define XVTC_POLARITY_HSYNC_POL (1 << 3) | ||
| 105 | #define XVTC_POLARITY_VSYNC_POL (1 << 2) | ||
| 106 | #define XVTC_POLARITY_HBLANK_POL (1 << 1) | ||
| 107 | #define XVTC_POLARITY_VBLANK_POL (1 << 0) | ||
| 108 | |||
| 109 | #define XVTC_HSIZE 0x0010 | ||
| 110 | #define XVTC_HSIZE_MASK (0x1fff << 0) | ||
| 111 | |||
| 112 | #define XVTC_VSIZE 0x0014 | ||
| 113 | #define XVTC_VSIZE_MASK (0x1fff << 0) | ||
| 114 | |||
| 115 | #define XVTC_HSYNC 0x0018 | ||
| 116 | #define XVTC_HSYNC_END_SHIFT 16 | ||
| 117 | #define XVTC_HSYNC_END_MASK (0x1fff << 16) | ||
| 118 | #define XVTC_HSYNC_START_SHIFT 0 | ||
| 119 | #define XVTC_HSYNC_START_MASK (0x1fff << 0) | ||
| 120 | |||
| 121 | #define XVTC_F0_VBLANK_H 0x001c | ||
| 122 | #define XVTC_F0_VBLANK_HEND_SHIFT 16 | ||
| 123 | #define XVTC_F0_VBLANK_HEND_MASK (0x1fff << 16) | ||
| 124 | #define XVTC_F0_VBLANK_HSTART_SHIFT 0 | ||
| 125 | #define XVTC_F0_VBLANK_HSTART_MASK (0x1fff << 0) | ||
| 126 | |||
| 127 | #define XVTC_F0_VSYNC_V 0x0020 | ||
| 128 | #define XVTC_F0_VSYNC_VEND_SHIFT 16 | ||
| 129 | #define XVTC_F0_VSYNC_VEND_MASK (0x1fff << 16) | ||
| 130 | #define XVTC_F0_VSYNC_VSTART_SHIFT 0 | ||
| 131 | #define XVTC_F0_VSYNC_VSTART_MASK (0x1fff << 0) | ||
| 132 | |||
| 133 | #define XVTC_F0_VSYNC_H 0x0024 | ||
| 134 | #define XVTC_F0_VSYNC_HEND_SHIFT 16 | ||
| 135 | #define XVTC_F0_VSYNC_HEND_MASK (0x1fff << 16) | ||
| 136 | #define XVTC_F0_VSYNC_HSTART_SHIFT 0 | ||
| 137 | #define XVTC_F0_VSYNC_HSTART_MASK (0x1fff << 0) | ||
| 138 | |||
| 139 | #define XVTC_FRAME_SYNC_CONFIG(n) (0x0100 + 4 * (n)) | ||
| 140 | #define XVTC_FRAME_SYNC_V_START_SHIFT 16 | ||
| 141 | #define XVTC_FRAME_SYNC_V_START_MASK (0x1fff << 16) | ||
| 142 | #define XVTC_FRAME_SYNC_H_START_SHIFT 0 | ||
| 143 | #define XVTC_FRAME_SYNC_H_START_MASK (0x1fff << 0) | ||
| 144 | |||
| 145 | #define XVTC_GENERATOR_GLOBAL_DELAY 0x0104 | ||
| 146 | |||
| 147 | /** | ||
| 148 | * struct xvtc_device - Xilinx Video Timing Controller device structure | ||
| 149 | * @xvip: Xilinx Video IP device | ||
| 150 | * @list: entry in the global VTC list | ||
| 151 | * @has_detector: the VTC has a timing detector | ||
| 152 | * @has_generator: the VTC has a timing generator | ||
| 153 | * @config: generator timings configuration | ||
| 154 | */ | ||
| 155 | struct xvtc_device { | ||
| 156 | struct xvip_device xvip; | ||
| 157 | struct list_head list; | ||
| 158 | |||
| 159 | bool has_detector; | ||
| 160 | bool has_generator; | ||
| 161 | |||
| 162 | struct xvtc_config config; | ||
| 163 | }; | ||
| 164 | |||
| 165 | static LIST_HEAD(xvtc_list); | ||
| 166 | static DEFINE_MUTEX(xvtc_lock); | ||
| 167 | |||
| 168 | static inline void xvtc_gen_write(struct xvtc_device *xvtc, u32 addr, u32 value) | ||
| 169 | { | ||
| 170 | xvip_write(&xvtc->xvip, XVTC_GENERATOR_OFFSET + addr, value); | ||
| 171 | } | ||
| 172 | |||
| 173 | /* ----------------------------------------------------------------------------- | ||
| 174 | * Generator Operations | ||
| 175 | */ | ||
| 176 | |||
| 177 | int xvtc_generator_start(struct xvtc_device *xvtc, | ||
| 178 | const struct xvtc_config *config) | ||
| 179 | { | ||
| 180 | int ret; | ||
| 181 | |||
| 182 | if (!xvtc->has_generator) | ||
| 183 | return -ENXIO; | ||
| 184 | |||
| 185 | ret = clk_prepare_enable(xvtc->xvip.clk); | ||
| 186 | if (ret < 0) | ||
| 187 | return ret; | ||
| 188 | |||
| 189 | /* We don't care about the chroma active signal, encoding parameters are | ||
| 190 | * not important for now. | ||
| 191 | */ | ||
| 192 | xvtc_gen_write(xvtc, XVTC_POLARITY, | ||
| 193 | XVTC_POLARITY_ACTIVE_CHROMA_POL | | ||
| 194 | XVTC_POLARITY_ACTIVE_VIDEO_POL | | ||
| 195 | XVTC_POLARITY_HSYNC_POL | XVTC_POLARITY_VSYNC_POL | | ||
| 196 | XVTC_POLARITY_HBLANK_POL | XVTC_POLARITY_VBLANK_POL); | ||
| 197 | |||
| 198 | /* Hardcode the polarity to active high, as required by the video in to | ||
| 199 | * AXI4-stream core. | ||
| 200 | */ | ||
| 201 | xvtc_gen_write(xvtc, XVTC_ENCODING, 0); | ||
| 202 | |||
| 203 | /* Configure the timings. The VBLANK and VSYNC signals assertion and | ||
| 204 | * deassertion are hardcoded to the first pixel of the line. | ||
| 205 | */ | ||
| 206 | xvtc_gen_write(xvtc, XVTC_ACTIVE_SIZE, | ||
| 207 | (config->vblank_start << XVTC_ACTIVE_VSIZE_SHIFT) | | ||
| 208 | (config->hblank_start << XVTC_ACTIVE_HSIZE_SHIFT)); | ||
| 209 | xvtc_gen_write(xvtc, XVTC_HSIZE, config->hsize); | ||
| 210 | xvtc_gen_write(xvtc, XVTC_VSIZE, config->vsize); | ||
| 211 | xvtc_gen_write(xvtc, XVTC_HSYNC, | ||
| 212 | (config->hsync_end << XVTC_HSYNC_END_SHIFT) | | ||
| 213 | (config->hsync_start << XVTC_HSYNC_START_SHIFT)); | ||
| 214 | xvtc_gen_write(xvtc, XVTC_F0_VBLANK_H, 0); | ||
| 215 | xvtc_gen_write(xvtc, XVTC_F0_VSYNC_V, | ||
| 216 | (config->vsync_end << XVTC_F0_VSYNC_VEND_SHIFT) | | ||
| 217 | (config->vsync_start << XVTC_F0_VSYNC_VSTART_SHIFT)); | ||
| 218 | xvtc_gen_write(xvtc, XVTC_F0_VSYNC_H, 0); | ||
| 219 | |||
| 220 | /* Enable the generator. Set the source of all generator parameters to | ||
| 221 | * generator registers. | ||
| 222 | */ | ||
| 223 | xvip_write(&xvtc->xvip, XVIP_CTRL_CONTROL, | ||
| 224 | XVTC_CONTROL_ACTIVE_CHROMA_POL_SRC | | ||
| 225 | XVTC_CONTROL_ACTIVE_VIDEO_POL_SRC | | ||
| 226 | XVTC_CONTROL_HSYNC_POL_SRC | XVTC_CONTROL_VSYNC_POL_SRC | | ||
| 227 | XVTC_CONTROL_HBLANK_POL_SRC | XVTC_CONTROL_VBLANK_POL_SRC | | ||
| 228 | XVTC_CONTROL_CHROMA_SRC | XVTC_CONTROL_VBLANK_HOFF_SRC | | ||
| 229 | XVTC_CONTROL_VSYNC_END_SRC | XVTC_CONTROL_VSYNC_START_SRC | | ||
| 230 | XVTC_CONTROL_ACTIVE_VSIZE_SRC | | ||
| 231 | XVTC_CONTROL_FRAME_VSIZE_SRC | XVTC_CONTROL_HSYNC_END_SRC | | ||
| 232 | XVTC_CONTROL_HSYNC_START_SRC | | ||
| 233 | XVTC_CONTROL_ACTIVE_HSIZE_SRC | | ||
| 234 | XVTC_CONTROL_FRAME_HSIZE_SRC | XVTC_CONTROL_GEN_ENABLE | | ||
| 235 | XVIP_CTRL_CONTROL_REG_UPDATE); | ||
| 236 | |||
| 237 | return 0; | ||
| 238 | } | ||
| 239 | EXPORT_SYMBOL_GPL(xvtc_generator_start); | ||
| 240 | |||
| 241 | int xvtc_generator_stop(struct xvtc_device *xvtc) | ||
| 242 | { | ||
| 243 | if (!xvtc->has_generator) | ||
| 244 | return -ENXIO; | ||
| 245 | |||
| 246 | xvip_write(&xvtc->xvip, XVIP_CTRL_CONTROL, 0); | ||
| 247 | |||
| 248 | clk_disable_unprepare(xvtc->xvip.clk); | ||
| 249 | |||
| 250 | return 0; | ||
| 251 | } | ||
| 252 | EXPORT_SYMBOL_GPL(xvtc_generator_stop); | ||
| 253 | |||
| 254 | struct xvtc_device *xvtc_of_get(struct device_node *np) | ||
| 255 | { | ||
| 256 | struct device_node *xvtc_node; | ||
| 257 | struct xvtc_device *found = NULL; | ||
| 258 | struct xvtc_device *xvtc; | ||
| 259 | |||
| 260 | if (!of_find_property(np, "xlnx,vtc", NULL)) | ||
| 261 | return NULL; | ||
| 262 | |||
| 263 | xvtc_node = of_parse_phandle(np, "xlnx,vtc", 0); | ||
| 264 | if (xvtc_node == NULL) | ||
| 265 | return ERR_PTR(-EINVAL); | ||
| 266 | |||
| 267 | mutex_lock(&xvtc_lock); | ||
| 268 | list_for_each_entry(xvtc, &xvtc_list, list) { | ||
| 269 | if (xvtc->xvip.dev->of_node == xvtc_node) { | ||
| 270 | found = xvtc; | ||
| 271 | break; | ||
| 272 | } | ||
| 273 | } | ||
| 274 | mutex_unlock(&xvtc_lock); | ||
| 275 | |||
| 276 | of_node_put(xvtc_node); | ||
| 277 | |||
| 278 | if (!found) | ||
| 279 | return ERR_PTR(-EPROBE_DEFER); | ||
| 280 | |||
| 281 | return found; | ||
| 282 | } | ||
| 283 | EXPORT_SYMBOL_GPL(xvtc_of_get); | ||
| 284 | |||
| 285 | void xvtc_put(struct xvtc_device *xvtc) | ||
| 286 | { | ||
| 287 | } | ||
| 288 | EXPORT_SYMBOL_GPL(xvtc_put); | ||
| 289 | |||
| 290 | /* ----------------------------------------------------------------------------- | ||
| 291 | * Registration and Unregistration | ||
| 292 | */ | ||
| 293 | |||
| 294 | static void xvtc_register_device(struct xvtc_device *xvtc) | ||
| 295 | { | ||
| 296 | mutex_lock(&xvtc_lock); | ||
| 297 | list_add_tail(&xvtc->list, &xvtc_list); | ||
| 298 | mutex_unlock(&xvtc_lock); | ||
| 299 | } | ||
| 300 | |||
| 301 | static void xvtc_unregister_device(struct xvtc_device *xvtc) | ||
| 302 | { | ||
| 303 | mutex_lock(&xvtc_lock); | ||
| 304 | list_del(&xvtc->list); | ||
| 305 | mutex_unlock(&xvtc_lock); | ||
| 306 | } | ||
| 307 | |||
| 308 | /* ----------------------------------------------------------------------------- | ||
| 309 | * Platform Device Driver | ||
| 310 | */ | ||
| 311 | |||
| 312 | static int xvtc_parse_of(struct xvtc_device *xvtc) | ||
| 313 | { | ||
| 314 | struct device_node *node = xvtc->xvip.dev->of_node; | ||
| 315 | |||
| 316 | xvtc->has_detector = of_property_read_bool(node, "xlnx,detector"); | ||
| 317 | xvtc->has_generator = of_property_read_bool(node, "xlnx,generator"); | ||
| 318 | |||
| 319 | return 0; | ||
| 320 | } | ||
| 321 | |||
| 322 | static int xvtc_probe(struct platform_device *pdev) | ||
| 323 | { | ||
| 324 | struct xvtc_device *xvtc; | ||
| 325 | int ret; | ||
| 326 | |||
| 327 | xvtc = devm_kzalloc(&pdev->dev, sizeof(*xvtc), GFP_KERNEL); | ||
| 328 | if (!xvtc) | ||
| 329 | return -ENOMEM; | ||
| 330 | |||
| 331 | xvtc->xvip.dev = &pdev->dev; | ||
| 332 | |||
| 333 | ret = xvtc_parse_of(xvtc); | ||
| 334 | if (ret < 0) | ||
| 335 | return ret; | ||
| 336 | |||
| 337 | ret = xvip_init_resources(&xvtc->xvip); | ||
| 338 | if (ret < 0) | ||
| 339 | return ret; | ||
| 340 | |||
| 341 | platform_set_drvdata(pdev, xvtc); | ||
| 342 | |||
| 343 | xvip_print_version(&xvtc->xvip); | ||
| 344 | |||
| 345 | xvtc_register_device(xvtc); | ||
| 346 | |||
| 347 | return 0; | ||
| 348 | } | ||
| 349 | |||
| 350 | static int xvtc_remove(struct platform_device *pdev) | ||
| 351 | { | ||
| 352 | struct xvtc_device *xvtc = platform_get_drvdata(pdev); | ||
| 353 | |||
| 354 | xvtc_unregister_device(xvtc); | ||
| 355 | |||
| 356 | xvip_cleanup_resources(&xvtc->xvip); | ||
| 357 | |||
| 358 | return 0; | ||
| 359 | } | ||
| 360 | |||
| 361 | static const struct of_device_id xvtc_of_id_table[] = { | ||
| 362 | { .compatible = "xlnx,v-tc-6.1" }, | ||
| 363 | { } | ||
| 364 | }; | ||
| 365 | MODULE_DEVICE_TABLE(of, xvtc_of_id_table); | ||
| 366 | |||
| 367 | static struct platform_driver xvtc_driver = { | ||
| 368 | .driver = { | ||
| 369 | .name = "xilinx-vtc", | ||
| 370 | .of_match_table = xvtc_of_id_table, | ||
| 371 | }, | ||
| 372 | .probe = xvtc_probe, | ||
| 373 | .remove = xvtc_remove, | ||
| 374 | }; | ||
| 375 | |||
| 376 | module_platform_driver(xvtc_driver); | ||
| 377 | |||
| 378 | MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); | ||
| 379 | MODULE_DESCRIPTION("Xilinx Video Timing Controller Driver"); | ||
| 380 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/media/platform/xilinx/xilinx-vtc.h b/drivers/media/platform/xilinx/xilinx-vtc.h new file mode 100644 index 000000000000..e1bb2cfcf428 --- /dev/null +++ b/drivers/media/platform/xilinx/xilinx-vtc.h | |||
| @@ -0,0 +1,42 @@ | |||
| 1 | /* | ||
| 2 | * Xilinx Video Timing Controller | ||
| 3 | * | ||
| 4 | * Copyright (C) 2013-2015 Ideas on Board | ||
| 5 | * Copyright (C) 2013-2015 Xilinx, Inc. | ||
| 6 | * | ||
| 7 | * Contacts: Hyun Kwon <hyun.kwon@xilinx.com> | ||
| 8 | * Laurent Pinchart <laurent.pinchart@ideasonboard.com> | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License version 2 as | ||
| 12 | * published by the Free Software Foundation. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #ifndef __XILINX_VTC_H__ | ||
| 16 | #define __XILINX_VTC_H__ | ||
| 17 | |||
| 18 | struct device_node; | ||
| 19 | struct xvtc_device; | ||
| 20 | |||
| 21 | #define XVTC_MAX_HSIZE 8191 | ||
| 22 | #define XVTC_MAX_VSIZE 8191 | ||
| 23 | |||
| 24 | struct xvtc_config { | ||
| 25 | unsigned int hblank_start; | ||
| 26 | unsigned int hsync_start; | ||
| 27 | unsigned int hsync_end; | ||
| 28 | unsigned int hsize; | ||
| 29 | unsigned int vblank_start; | ||
| 30 | unsigned int vsync_start; | ||
| 31 | unsigned int vsync_end; | ||
| 32 | unsigned int vsize; | ||
| 33 | }; | ||
| 34 | |||
| 35 | struct xvtc_device *xvtc_of_get(struct device_node *np); | ||
| 36 | void xvtc_put(struct xvtc_device *xvtc); | ||
| 37 | |||
| 38 | int xvtc_generator_start(struct xvtc_device *xvtc, | ||
| 39 | const struct xvtc_config *config); | ||
| 40 | int xvtc_generator_stop(struct xvtc_device *xvtc); | ||
| 41 | |||
| 42 | #endif /* __XILINX_VTC_H__ */ | ||
