From 7b49235e83b2347caf4bc66dd0154cb799bd7405 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 11 Feb 2016 22:29:58 -0200 Subject: [media] v4l: Add Renesas R-Car FCP driver The FCP is a companion module of video processing modules in the Renesas R-Car Gen3 SoCs. It provides data compression and decompression, data caching, and conversion of AXI transactions in order to reduce the memory bandwidth. The driver is not meant to be used standalone but provides an API to the video processing modules to control the FCP. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/Kconfig | 13 +++ drivers/media/platform/Makefile | 1 + drivers/media/platform/rcar-fcp.c | 181 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 195 insertions(+) create mode 100644 drivers/media/platform/rcar-fcp.c (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 382f3937379e..d6fe4fe924e7 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -248,6 +248,19 @@ config VIDEO_RENESAS_JPU To compile this driver as a module, choose M here: the module will be called rcar_jpu. +config VIDEO_RENESAS_FCP + tristate "Renesas Frame Compression Processor" + depends on ARCH_RENESAS || COMPILE_TEST + depends on OF + ---help--- + This is a driver for the Renesas Frame Compression Processor (FCP). + The FCP is a companion module of video processing modules in the + Renesas R-Car Gen3 SoCs. It handles memory access for the codec, + VSP and FDP modules. + + To compile this driver as a module, choose M here: the module + will be called rcar-fcp. + config VIDEO_RENESAS_VSP1 tristate "Renesas VSP1 Video Processing Engine" depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && HAS_DMA diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index 99cf31542f54..c83800a74a2d 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -46,6 +46,7 @@ obj-$(CONFIG_VIDEO_SH_VOU) += sh_vou.o obj-$(CONFIG_SOC_CAMERA) += soc_camera/ +obj-$(CONFIG_VIDEO_RENESAS_FCP) += rcar-fcp.o obj-$(CONFIG_VIDEO_RENESAS_JPU) += rcar_jpu.o obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1/ diff --git a/drivers/media/platform/rcar-fcp.c b/drivers/media/platform/rcar-fcp.c new file mode 100644 index 000000000000..6a7bcc3028b1 --- /dev/null +++ b/drivers/media/platform/rcar-fcp.c @@ -0,0 +1,181 @@ +/* + * rcar-fcp.c -- R-Car Frame Compression Processor Driver + * + * Copyright (C) 2016 Renesas Electronics Corporation + * + * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +struct rcar_fcp_device { + struct list_head list; + struct device *dev; +}; + +static LIST_HEAD(fcp_devices); +static DEFINE_MUTEX(fcp_lock); + +/* ----------------------------------------------------------------------------- + * Public API + */ + +/** + * rcar_fcp_get - Find and acquire a reference to an FCP instance + * @np: Device node of the FCP instance + * + * Search the list of registered FCP instances for the instance corresponding to + * the given device node. + * + * Return a pointer to the FCP instance, or an ERR_PTR if the instance can't be + * found. + */ +struct rcar_fcp_device *rcar_fcp_get(const struct device_node *np) +{ + struct rcar_fcp_device *fcp; + + mutex_lock(&fcp_lock); + + list_for_each_entry(fcp, &fcp_devices, list) { + if (fcp->dev->of_node != np) + continue; + + /* + * Make sure the module won't be unloaded behind our back. This + * is a poor man's safety net, the module should really not be + * unloaded while FCP users can be active. + */ + if (!try_module_get(fcp->dev->driver->owner)) + fcp = NULL; + + goto done; + } + + fcp = ERR_PTR(-EPROBE_DEFER); + +done: + mutex_unlock(&fcp_lock); + return fcp; +} +EXPORT_SYMBOL_GPL(rcar_fcp_get); + +/** + * rcar_fcp_put - Release a reference to an FCP instance + * @fcp: The FCP instance + * + * Release the FCP instance acquired by a call to rcar_fcp_get(). + */ +void rcar_fcp_put(struct rcar_fcp_device *fcp) +{ + if (fcp) + module_put(fcp->dev->driver->owner); +} +EXPORT_SYMBOL_GPL(rcar_fcp_put); + +/** + * rcar_fcp_enable - Enable an FCP + * @fcp: The FCP instance + * + * Before any memory access through an FCP is performed by a module, the FCP + * must be enabled by a call to this function. The enable calls are reference + * counted, each successful call must be followed by one rcar_fcp_disable() + * call when no more memory transfer can occur through the FCP. + * + * Return 0 on success or a negative error code if an error occurs. The enable + * reference count isn't increased when this function returns an error. + */ +int rcar_fcp_enable(struct rcar_fcp_device *fcp) +{ + if (!fcp) + return 0; + + return pm_runtime_get_sync(fcp->dev); +} +EXPORT_SYMBOL_GPL(rcar_fcp_enable); + +/** + * rcar_fcp_disable - Disable an FCP + * @fcp: The FCP instance + * + * This function is the counterpart of rcar_fcp_enable(). As enable calls are + * reference counted a disable call may not disable the FCP synchronously. + */ +void rcar_fcp_disable(struct rcar_fcp_device *fcp) +{ + if (fcp) + pm_runtime_put(fcp->dev); +} +EXPORT_SYMBOL_GPL(rcar_fcp_disable); + +/* ----------------------------------------------------------------------------- + * Platform Driver + */ + +static int rcar_fcp_probe(struct platform_device *pdev) +{ + struct rcar_fcp_device *fcp; + + fcp = devm_kzalloc(&pdev->dev, sizeof(*fcp), GFP_KERNEL); + if (fcp == NULL) + return -ENOMEM; + + fcp->dev = &pdev->dev; + + pm_runtime_enable(&pdev->dev); + + mutex_lock(&fcp_lock); + list_add_tail(&fcp->list, &fcp_devices); + mutex_unlock(&fcp_lock); + + platform_set_drvdata(pdev, fcp); + + return 0; +} + +static int rcar_fcp_remove(struct platform_device *pdev) +{ + struct rcar_fcp_device *fcp = platform_get_drvdata(pdev); + + mutex_lock(&fcp_lock); + list_del(&fcp->list); + mutex_unlock(&fcp_lock); + + pm_runtime_disable(&pdev->dev); + + return 0; +} + +static const struct of_device_id rcar_fcp_of_match[] = { + { .compatible = "renesas,fcpv" }, + { }, +}; + +static struct platform_driver rcar_fcp_platform_driver = { + .probe = rcar_fcp_probe, + .remove = rcar_fcp_remove, + .driver = { + .name = "rcar-fcp", + .of_match_table = rcar_fcp_of_match, + .suppress_bind_attrs = true, + }, +}; + +module_platform_driver(rcar_fcp_platform_driver); + +MODULE_ALIAS("rcar-fcp"); +MODULE_AUTHOR("Laurent Pinchart "); +MODULE_DESCRIPTION("Renesas FCP Driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 1e6af546ee66b2870c5c21f4430910a27c26b5bb Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 16 Feb 2016 11:49:39 -0200 Subject: [media] v4l: vsp1: Implement runtime PM support Replace the manual refcount and clock management code by runtime PM. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1.h | 3 - drivers/media/platform/vsp1/vsp1_drv.c | 101 ++++++++++++++++---------------- drivers/media/platform/vsp1/vsp1_pipe.c | 2 +- 3 files changed, 53 insertions(+), 53 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/vsp1/vsp1.h b/drivers/media/platform/vsp1/vsp1.h index 46738b6c5f72..9e09bce43cf3 100644 --- a/drivers/media/platform/vsp1/vsp1.h +++ b/drivers/media/platform/vsp1/vsp1.h @@ -64,9 +64,6 @@ struct vsp1_device { void __iomem *mmio; struct clk *clock; - struct mutex lock; - int ref_count; - struct vsp1_bru *bru; struct vsp1_hsit *hsi; struct vsp1_hsit *hst; diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c index e2d779fac0eb..d6abc7f1216a 100644 --- a/drivers/media/platform/vsp1/vsp1_drv.c +++ b/drivers/media/platform/vsp1/vsp1_drv.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -462,35 +463,16 @@ static int vsp1_device_init(struct vsp1_device *vsp1) /* * vsp1_device_get - Acquire the VSP1 device * - * Increment the VSP1 reference count and initialize the device if the first - * reference is taken. + * Make sure the device is not suspended and initialize it if needed. * * Return 0 on success or a negative error code otherwise. */ int vsp1_device_get(struct vsp1_device *vsp1) { - int ret = 0; - - mutex_lock(&vsp1->lock); - if (vsp1->ref_count > 0) - goto done; - - ret = clk_prepare_enable(vsp1->clock); - if (ret < 0) - goto done; - - ret = vsp1_device_init(vsp1); - if (ret < 0) { - clk_disable_unprepare(vsp1->clock); - goto done; - } - -done: - if (!ret) - vsp1->ref_count++; + int ret; - mutex_unlock(&vsp1->lock); - return ret; + ret = pm_runtime_get_sync(vsp1->dev); + return ret < 0 ? ret : 0; } /* @@ -501,12 +483,7 @@ done: */ void vsp1_device_put(struct vsp1_device *vsp1) { - mutex_lock(&vsp1->lock); - - if (--vsp1->ref_count == 0) - clk_disable_unprepare(vsp1->clock); - - mutex_unlock(&vsp1->lock); + pm_runtime_put_sync(vsp1->dev); } /* ----------------------------------------------------------------------------- @@ -518,37 +495,55 @@ static int vsp1_pm_suspend(struct device *dev) { struct vsp1_device *vsp1 = dev_get_drvdata(dev); - WARN_ON(mutex_is_locked(&vsp1->lock)); + vsp1_pipelines_suspend(vsp1); + pm_runtime_force_suspend(vsp1->dev); - if (vsp1->ref_count == 0) - return 0; + return 0; +} - vsp1_pipelines_suspend(vsp1); +static int vsp1_pm_resume(struct device *dev) +{ + struct vsp1_device *vsp1 = dev_get_drvdata(dev); - clk_disable_unprepare(vsp1->clock); + pm_runtime_force_resume(vsp1->dev); + vsp1_pipelines_resume(vsp1); return 0; } +#endif -static int vsp1_pm_resume(struct device *dev) +static int vsp1_pm_runtime_suspend(struct device *dev) { struct vsp1_device *vsp1 = dev_get_drvdata(dev); - WARN_ON(mutex_is_locked(&vsp1->lock)); + clk_disable_unprepare(vsp1->clock); - if (vsp1->ref_count == 0) - return 0; + return 0; +} - clk_prepare_enable(vsp1->clock); +static int vsp1_pm_runtime_resume(struct device *dev) +{ + struct vsp1_device *vsp1 = dev_get_drvdata(dev); + int ret; - vsp1_pipelines_resume(vsp1); + ret = clk_prepare_enable(vsp1->clock); + if (ret < 0) + return ret; + + if (vsp1->info) { + ret = vsp1_device_init(vsp1); + if (ret < 0) { + clk_disable_unprepare(vsp1->clock); + return ret; + } + } return 0; } -#endif static const struct dev_pm_ops vsp1_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(vsp1_pm_suspend, vsp1_pm_resume) + SET_RUNTIME_PM_OPS(vsp1_pm_runtime_suspend, vsp1_pm_runtime_resume, NULL) }; /* ----------------------------------------------------------------------------- @@ -640,10 +635,11 @@ static int vsp1_probe(struct platform_device *pdev) return -ENOMEM; vsp1->dev = &pdev->dev; - mutex_init(&vsp1->lock); INIT_LIST_HEAD(&vsp1->entities); INIT_LIST_HEAD(&vsp1->videos); + platform_set_drvdata(pdev, vsp1); + /* I/O, IRQ and clock resources */ io = platform_get_resource(pdev, IORESOURCE_MEM, 0); vsp1->mmio = devm_ioremap_resource(&pdev->dev, io); @@ -670,12 +666,14 @@ static int vsp1_probe(struct platform_device *pdev) } /* Configure device parameters based on the version register. */ - ret = clk_prepare_enable(vsp1->clock); + pm_runtime_enable(&pdev->dev); + + ret = pm_runtime_get_sync(&pdev->dev); if (ret < 0) - return ret; + goto done; version = vsp1_read(vsp1, VI6_IP_VERSION); - clk_disable_unprepare(vsp1->clock); + pm_runtime_put_sync(&pdev->dev); for (i = 0; i < ARRAY_SIZE(vsp1_device_infos); ++i) { if ((version & VI6_IP_VERSION_MODEL_MASK) == @@ -687,7 +685,8 @@ static int vsp1_probe(struct platform_device *pdev) if (!vsp1->info) { dev_err(&pdev->dev, "unsupported IP version 0x%08x\n", version); - return -ENXIO; + ret = -ENXIO; + goto done; } dev_dbg(&pdev->dev, "IP version 0x%08x\n", version); @@ -696,12 +695,14 @@ static int vsp1_probe(struct platform_device *pdev) ret = vsp1_create_entities(vsp1); if (ret < 0) { dev_err(&pdev->dev, "failed to create entities\n"); - return ret; + goto done; } - platform_set_drvdata(pdev, vsp1); +done: + if (ret) + pm_runtime_disable(&pdev->dev); - return 0; + return ret; } static int vsp1_remove(struct platform_device *pdev) @@ -710,6 +711,8 @@ static int vsp1_remove(struct platform_device *pdev) vsp1_destroy_entities(vsp1); + pm_runtime_disable(&pdev->dev); + return 0; } diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c b/drivers/media/platform/vsp1/vsp1_pipe.c index 4f3b4a1d028a..0c1dc80eb304 100644 --- a/drivers/media/platform/vsp1/vsp1_pipe.c +++ b/drivers/media/platform/vsp1/vsp1_pipe.c @@ -383,7 +383,7 @@ void vsp1_pipelines_resume(struct vsp1_device *vsp1) { unsigned int i; - /* Resume pipeline all running pipelines. */ + /* Resume all running pipelines. */ for (i = 0; i < vsp1->info->wpf_count; ++i) { struct vsp1_rwpf *wpf = vsp1->wpf[i]; struct vsp1_pipeline *pipe; -- cgit v1.2.3 From c7b12cfddf7b4065a881b5890521a8a1a375924a Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 16 Feb 2016 11:49:39 -0200 Subject: [media] v4l: vsp1: Don't handle clocks manually The power domain performs functional clock handling when using runtime PM, there's no need to enable and disable the clock manually. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1.h | 1 - drivers/media/platform/vsp1/vsp1_drv.c | 20 ++------------------ 2 files changed, 2 insertions(+), 19 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/vsp1/vsp1.h b/drivers/media/platform/vsp1/vsp1.h index 9e09bce43cf3..37cc05e34de0 100644 --- a/drivers/media/platform/vsp1/vsp1.h +++ b/drivers/media/platform/vsp1/vsp1.h @@ -62,7 +62,6 @@ struct vsp1_device { const struct vsp1_device_info *info; void __iomem *mmio; - struct clk *clock; struct vsp1_bru *bru; struct vsp1_hsit *hsi; diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c index d6abc7f1216a..13907d4f08af 100644 --- a/drivers/media/platform/vsp1/vsp1_drv.c +++ b/drivers/media/platform/vsp1/vsp1_drv.c @@ -514,10 +514,6 @@ static int vsp1_pm_resume(struct device *dev) static int vsp1_pm_runtime_suspend(struct device *dev) { - struct vsp1_device *vsp1 = dev_get_drvdata(dev); - - clk_disable_unprepare(vsp1->clock); - return 0; } @@ -526,16 +522,10 @@ static int vsp1_pm_runtime_resume(struct device *dev) struct vsp1_device *vsp1 = dev_get_drvdata(dev); int ret; - ret = clk_prepare_enable(vsp1->clock); - if (ret < 0) - return ret; - if (vsp1->info) { ret = vsp1_device_init(vsp1); - if (ret < 0) { - clk_disable_unprepare(vsp1->clock); + if (ret < 0) return ret; - } } return 0; @@ -640,18 +630,12 @@ static int vsp1_probe(struct platform_device *pdev) platform_set_drvdata(pdev, vsp1); - /* I/O, IRQ and clock resources */ + /* I/O and IRQ resources (clock managed by the clock PM domain) */ io = platform_get_resource(pdev, IORESOURCE_MEM, 0); vsp1->mmio = devm_ioremap_resource(&pdev->dev, io); if (IS_ERR(vsp1->mmio)) return PTR_ERR(vsp1->mmio); - vsp1->clock = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(vsp1->clock)) { - dev_err(&pdev->dev, "failed to get clock\n"); - return PTR_ERR(vsp1->clock); - } - irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!irq) { dev_err(&pdev->dev, "missing IRQ\n"); -- cgit v1.2.3 From 94fcdf829793b141dc93e20a2bbd9eeaa44ea25f Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 11 Feb 2016 22:49:14 -0200 Subject: [media] v4l: vsp1: Add FCP support On some platforms the VSP performs memory accesses through an FCP. When that's the case get a reference to the FCP from the VSP DT node and enable/disable it at runtime as needed. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/renesas,vsp1.txt | 5 +++++ drivers/media/platform/Kconfig | 1 + drivers/media/platform/vsp1/vsp1.h | 2 ++ drivers/media/platform/vsp1/vsp1_drv.c | 21 ++++++++++++++++++++- 4 files changed, 28 insertions(+), 1 deletion(-) (limited to 'drivers/media/platform') diff --git a/Documentation/devicetree/bindings/media/renesas,vsp1.txt b/Documentation/devicetree/bindings/media/renesas,vsp1.txt index 627405abd144..9b695bcbf219 100644 --- a/Documentation/devicetree/bindings/media/renesas,vsp1.txt +++ b/Documentation/devicetree/bindings/media/renesas,vsp1.txt @@ -14,6 +14,11 @@ Required properties: - interrupts: VSP interrupt specifier. - clocks: A phandle + clock-specifier pair for the VSP functional clock. +Optional properties: + + - renesas,fcp: A phandle referencing the FCP that handles memory accesses + for the VSP. Not needed on Gen2, mandatory on Gen3. + Example: R8A7790 (R-Car H2) VSP1-S node diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index d6fe4fe924e7..9d0a3ffe36d2 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -265,6 +265,7 @@ config VIDEO_RENESAS_VSP1 tristate "Renesas VSP1 Video Processing Engine" depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && HAS_DMA depends on (ARCH_RENESAS && OF) || COMPILE_TEST + depends on !ARM64 || VIDEO_RENESAS_FCP select VIDEOBUF2_DMA_CONTIG ---help--- This is a V4L2 driver for the Renesas VSP1 video processing engine. diff --git a/drivers/media/platform/vsp1/vsp1.h b/drivers/media/platform/vsp1/vsp1.h index 37cc05e34de0..7cb0f5e428df 100644 --- a/drivers/media/platform/vsp1/vsp1.h +++ b/drivers/media/platform/vsp1/vsp1.h @@ -25,6 +25,7 @@ struct clk; struct device; +struct rcar_fcp_device; struct vsp1_drm; struct vsp1_entity; @@ -62,6 +63,7 @@ struct vsp1_device { const struct vsp1_device_info *info; void __iomem *mmio; + struct rcar_fcp_device *fcp; struct vsp1_bru *bru; struct vsp1_hsit *hsi; diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c index 13907d4f08af..e655639af7e2 100644 --- a/drivers/media/platform/vsp1/vsp1_drv.c +++ b/drivers/media/platform/vsp1/vsp1_drv.c @@ -22,6 +22,7 @@ #include #include +#include #include #include "vsp1.h" @@ -514,6 +515,10 @@ static int vsp1_pm_resume(struct device *dev) static int vsp1_pm_runtime_suspend(struct device *dev) { + struct vsp1_device *vsp1 = dev_get_drvdata(dev); + + rcar_fcp_disable(vsp1->fcp); + return 0; } @@ -528,7 +533,7 @@ static int vsp1_pm_runtime_resume(struct device *dev) return ret; } - return 0; + return rcar_fcp_enable(vsp1->fcp); } static const struct dev_pm_ops vsp1_pm_ops = { @@ -614,6 +619,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = { static int vsp1_probe(struct platform_device *pdev) { struct vsp1_device *vsp1; + struct device_node *fcp_node; struct resource *irq; struct resource *io; unsigned int i; @@ -649,6 +655,18 @@ static int vsp1_probe(struct platform_device *pdev) return ret; } + /* FCP (optional) */ + fcp_node = of_parse_phandle(pdev->dev.of_node, "renesas,fcp", 0); + if (fcp_node) { + vsp1->fcp = rcar_fcp_get(fcp_node); + of_node_put(fcp_node); + if (IS_ERR(vsp1->fcp)) { + dev_dbg(&pdev->dev, "FCP not found (%ld)\n", + PTR_ERR(vsp1->fcp)); + return PTR_ERR(vsp1->fcp); + } + } + /* Configure device parameters based on the version register. */ pm_runtime_enable(&pdev->dev); @@ -694,6 +712,7 @@ static int vsp1_remove(struct platform_device *pdev) struct vsp1_device *vsp1 = platform_get_drvdata(pdev); vsp1_destroy_entities(vsp1); + rcar_fcp_put(vsp1->fcp); pm_runtime_disable(&pdev->dev); -- cgit v1.2.3 From 44f4619857766289c99e5d61a87ba1621e8ddef6 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 24 Feb 2016 19:10:04 -0300 Subject: [media] v4l: vsp1: Add output node value to routing table The output node value indicates the value to be used in a sampling point register to use the node as the source of histogram data. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_entity.c | 52 ++++++++++++++++++++----------- drivers/media/platform/vsp1/vsp1_entity.h | 6 +++- 2 files changed, 39 insertions(+), 19 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c index 3d070bcc6053..6a96ea77de69 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.c +++ b/drivers/media/platform/vsp1/vsp1_entity.c @@ -274,28 +274,44 @@ int vsp1_entity_link_setup(struct media_entity *entity, * Initialization */ +#define VSP1_ENTITY_ROUTE(ent) \ + { VSP1_ENTITY_##ent, 0, VI6_DPR_##ent##_ROUTE, \ + { VI6_DPR_NODE_##ent }, VI6_DPR_NODE_##ent } + +#define VSP1_ENTITY_ROUTE_RPF(idx) \ + { VSP1_ENTITY_RPF, idx, VI6_DPR_RPF_ROUTE(idx), \ + { 0, }, VI6_DPR_NODE_RPF(idx) } + +#define VSP1_ENTITY_ROUTE_UDS(idx) \ + { VSP1_ENTITY_UDS, idx, VI6_DPR_UDS_ROUTE(idx), \ + { VI6_DPR_NODE_UDS(idx) }, VI6_DPR_NODE_UDS(idx) } + +#define VSP1_ENTITY_ROUTE_WPF(idx) \ + { VSP1_ENTITY_WPF, idx, 0, \ + { VI6_DPR_NODE_WPF(idx) }, VI6_DPR_NODE_WPF(idx) } + static const struct vsp1_route vsp1_routes[] = { { VSP1_ENTITY_BRU, 0, VI6_DPR_BRU_ROUTE, { VI6_DPR_NODE_BRU_IN(0), VI6_DPR_NODE_BRU_IN(1), VI6_DPR_NODE_BRU_IN(2), VI6_DPR_NODE_BRU_IN(3), - VI6_DPR_NODE_BRU_IN(4) } }, - { VSP1_ENTITY_HSI, 0, VI6_DPR_HSI_ROUTE, { VI6_DPR_NODE_HSI, } }, - { VSP1_ENTITY_HST, 0, VI6_DPR_HST_ROUTE, { VI6_DPR_NODE_HST, } }, - { VSP1_ENTITY_LIF, 0, 0, { VI6_DPR_NODE_LIF, } }, - { VSP1_ENTITY_LUT, 0, VI6_DPR_LUT_ROUTE, { VI6_DPR_NODE_LUT, } }, - { VSP1_ENTITY_RPF, 0, VI6_DPR_RPF_ROUTE(0), { 0, } }, - { VSP1_ENTITY_RPF, 1, VI6_DPR_RPF_ROUTE(1), { 0, } }, - { VSP1_ENTITY_RPF, 2, VI6_DPR_RPF_ROUTE(2), { 0, } }, - { VSP1_ENTITY_RPF, 3, VI6_DPR_RPF_ROUTE(3), { 0, } }, - { VSP1_ENTITY_RPF, 4, VI6_DPR_RPF_ROUTE(4), { 0, } }, - { VSP1_ENTITY_SRU, 0, VI6_DPR_SRU_ROUTE, { VI6_DPR_NODE_SRU, } }, - { VSP1_ENTITY_UDS, 0, VI6_DPR_UDS_ROUTE(0), { VI6_DPR_NODE_UDS(0), } }, - { VSP1_ENTITY_UDS, 1, VI6_DPR_UDS_ROUTE(1), { VI6_DPR_NODE_UDS(1), } }, - { VSP1_ENTITY_UDS, 2, VI6_DPR_UDS_ROUTE(2), { VI6_DPR_NODE_UDS(2), } }, - { VSP1_ENTITY_WPF, 0, 0, { VI6_DPR_NODE_WPF(0), } }, - { VSP1_ENTITY_WPF, 1, 0, { VI6_DPR_NODE_WPF(1), } }, - { VSP1_ENTITY_WPF, 2, 0, { VI6_DPR_NODE_WPF(2), } }, - { VSP1_ENTITY_WPF, 3, 0, { VI6_DPR_NODE_WPF(3), } }, + VI6_DPR_NODE_BRU_IN(4) }, VI6_DPR_NODE_BRU_OUT }, + VSP1_ENTITY_ROUTE(HSI), + VSP1_ENTITY_ROUTE(HST), + { VSP1_ENTITY_LIF, 0, 0, { VI6_DPR_NODE_LIF, }, VI6_DPR_NODE_LIF }, + VSP1_ENTITY_ROUTE(LUT), + VSP1_ENTITY_ROUTE_RPF(0), + VSP1_ENTITY_ROUTE_RPF(1), + VSP1_ENTITY_ROUTE_RPF(2), + VSP1_ENTITY_ROUTE_RPF(3), + VSP1_ENTITY_ROUTE_RPF(4), + VSP1_ENTITY_ROUTE(SRU), + VSP1_ENTITY_ROUTE_UDS(0), + VSP1_ENTITY_ROUTE_UDS(1), + VSP1_ENTITY_ROUTE_UDS(2), + VSP1_ENTITY_ROUTE_WPF(0), + VSP1_ENTITY_ROUTE_WPF(1), + VSP1_ENTITY_ROUTE_WPF(2), + VSP1_ENTITY_ROUTE_WPF(3), }; int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity, diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h index 69eff4e17350..aaab05f4952c 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.h +++ b/drivers/media/platform/vsp1/vsp1_entity.h @@ -42,17 +42,21 @@ enum vsp1_entity_type { * @index: Entity index this routing entry is associated with * @reg: Output routing configuration register * @inputs: Target node value for each input + * @output: Target node value for entity output * * Each $vsp1_route entry describes routing configuration for the entity * specified by the entry's @type and @index. @reg indicates the register that * holds output routing configuration for the entity, and the @inputs array - * store the target node value for each input of the entity. + * store the target node value for each input of the entity. The @output field + * stores the target node value of the entity output when used as a source for + * histogram generation. */ struct vsp1_route { enum vsp1_entity_type type; unsigned int index; unsigned int reg; unsigned int inputs[VSP1_ENTITY_MAX_INPUTS]; + unsigned int output; }; /** -- cgit v1.2.3 From 7cf0f123c7354aa9b11cad5e3fdd9a5435cde4f0 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 3 Mar 2016 20:06:22 -0300 Subject: [media] v4l: vsp1: Replace container_of() with dedicated macro Add a macro to cast from a struct media_entity to a struct vsp1_entity to replace the manual implementations. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_entity.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c index 6a96ea77de69..f60d7926d53f 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.c +++ b/drivers/media/platform/vsp1/vsp1_entity.c @@ -22,6 +22,12 @@ #include "vsp1_dl.h" #include "vsp1_entity.h" +static inline struct vsp1_entity * +media_entity_to_vsp1_entity(struct media_entity *entity) +{ + return container_of(entity, struct vsp1_entity, subdev.entity); +} + void vsp1_entity_route_setup(struct vsp1_entity *source, struct vsp1_dl_list *dl) { @@ -30,7 +36,7 @@ void vsp1_entity_route_setup(struct vsp1_entity *source, if (source->route->reg == 0) return; - sink = container_of(source->sink, struct vsp1_entity, subdev.entity); + sink = media_entity_to_vsp1_entity(source->sink); vsp1_dl_list_write(dl, source->route->reg, sink->route->inputs[source->sink_pad]); } @@ -252,7 +258,7 @@ int vsp1_entity_link_setup(struct media_entity *entity, if (!(local->flags & MEDIA_PAD_FL_SOURCE)) return 0; - source = container_of(local->entity, struct vsp1_entity, subdev.entity); + source = media_entity_to_vsp1_entity(local->entity); if (!source->route) return 0; -- cgit v1.2.3 From ccd3d95a93de25e971b23d2230b5c0a2e15d5cb7 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 3 Mar 2016 20:17:49 -0300 Subject: [media] v4l: vsp1: Make vsp1_entity_get_pad_compose() more generic Turn the helper into a function that can retrieve crop and compose selection rectangles. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_entity.c | 26 ++++++++++++++++++++++---- drivers/media/platform/vsp1/vsp1_entity.h | 6 +++--- drivers/media/platform/vsp1/vsp1_rpf.c | 7 ++++--- 3 files changed, 29 insertions(+), 10 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c index f60d7926d53f..fd20c0d8aeea 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.c +++ b/drivers/media/platform/vsp1/vsp1_entity.c @@ -87,12 +87,30 @@ vsp1_entity_get_pad_format(struct vsp1_entity *entity, return v4l2_subdev_get_try_format(&entity->subdev, cfg, pad); } +/** + * vsp1_entity_get_pad_selection - Get a pad selection from storage for entity + * @entity: the entity + * @cfg: the configuration storage + * @pad: the pad number + * @target: the selection target + * + * Return the selection rectangle stored in the given configuration for an + * entity's pad. The configuration can be an ACTIVE or TRY configuration. The + * selection target can be COMPOSE or CROP. + */ struct v4l2_rect * -vsp1_entity_get_pad_compose(struct vsp1_entity *entity, - struct v4l2_subdev_pad_config *cfg, - unsigned int pad) +vsp1_entity_get_pad_selection(struct vsp1_entity *entity, + struct v4l2_subdev_pad_config *cfg, + unsigned int pad, unsigned int target) { - return v4l2_subdev_get_try_compose(&entity->subdev, cfg, pad); + switch (target) { + case V4L2_SEL_TGT_COMPOSE: + return v4l2_subdev_get_try_compose(&entity->subdev, cfg, pad); + case V4L2_SEL_TGT_CROP: + return v4l2_subdev_get_try_crop(&entity->subdev, cfg, pad); + default: + return NULL; + } } /* diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h index aaab05f4952c..a240fc1c59a6 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.h +++ b/drivers/media/platform/vsp1/vsp1_entity.h @@ -122,9 +122,9 @@ vsp1_entity_get_pad_format(struct vsp1_entity *entity, struct v4l2_subdev_pad_config *cfg, unsigned int pad); struct v4l2_rect * -vsp1_entity_get_pad_compose(struct vsp1_entity *entity, - struct v4l2_subdev_pad_config *cfg, - unsigned int pad); +vsp1_entity_get_pad_selection(struct vsp1_entity *entity, + struct v4l2_subdev_pad_config *cfg, + unsigned int pad, unsigned int target); int vsp1_entity_init_cfg(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg); diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c index 49168db3f529..64dfbddf2aba 100644 --- a/drivers/media/platform/vsp1/vsp1_rpf.c +++ b/drivers/media/platform/vsp1/vsp1_rpf.c @@ -130,9 +130,10 @@ static void rpf_configure(struct vsp1_entity *entity, if (pipe->bru) { const struct v4l2_rect *compose; - compose = vsp1_entity_get_pad_compose(pipe->bru, - pipe->bru->config, - rpf->bru_input); + compose = vsp1_entity_get_pad_selection(pipe->bru, + pipe->bru->config, + rpf->bru_input, + V4L2_SEL_TGT_COMPOSE); left = compose->left; top = compose->top; } -- cgit v1.2.3 From 0c1a41b50805464f397a334a6b2dd95ca6415f32 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 10 Apr 2016 02:59:04 -0300 Subject: [media] v4l: vsp1: Move frame sequence number from video node to pipeline The frame sequence number is global to the pipeline, there's no need to store copies in each video node. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_pipe.c | 2 ++ drivers/media/platform/vsp1/vsp1_pipe.h | 2 ++ drivers/media/platform/vsp1/vsp1_video.c | 4 +--- drivers/media/platform/vsp1/vsp1_video.h | 1 - 4 files changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c b/drivers/media/platform/vsp1/vsp1_pipe.c index 0c1dc80eb304..be47c8a1a812 100644 --- a/drivers/media/platform/vsp1/vsp1_pipe.c +++ b/drivers/media/platform/vsp1/vsp1_pipe.c @@ -286,6 +286,8 @@ void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe) if (pipe->frame_end) pipe->frame_end(pipe); + + pipe->sequence++; } /* diff --git a/drivers/media/platform/vsp1/vsp1_pipe.h b/drivers/media/platform/vsp1/vsp1_pipe.h index 7b56113511dd..febc62f99d6d 100644 --- a/drivers/media/platform/vsp1/vsp1_pipe.h +++ b/drivers/media/platform/vsp1/vsp1_pipe.h @@ -67,6 +67,7 @@ enum vsp1_pipeline_state { * @kref: pipeline reference count * @stream_count: number of streaming video nodes * @buffers_ready: bitmask of RPFs and WPFs with at least one buffer available + * @sequence: frame sequence number * @num_inputs: number of RPFs * @inputs: array of RPFs in the pipeline (indexed by RPF index) * @output: WPF at the output of the pipeline @@ -90,6 +91,7 @@ struct vsp1_pipeline { struct kref kref; unsigned int stream_count; unsigned int buffers_ready; + unsigned int sequence; unsigned int num_inputs; struct vsp1_rwpf *inputs[VSP1_MAX_RPF]; diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c index a9aec5c0bec6..34aa6427662d 100644 --- a/drivers/media/platform/vsp1/vsp1_video.c +++ b/drivers/media/platform/vsp1/vsp1_video.c @@ -219,7 +219,7 @@ vsp1_video_complete_buffer(struct vsp1_video *video) spin_unlock_irqrestore(&video->irqlock, flags); - done->buf.sequence = video->sequence++; + done->buf.sequence = pipe->sequence; done->buf.vb2_buf.timestamp = ktime_get_ns(); for (i = 0; i < done->buf.vb2_buf.num_planes; ++i) vb2_set_plane_payload(&done->buf.vb2_buf, i, @@ -805,8 +805,6 @@ vsp1_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) if (video->queue.owner && video->queue.owner != file->private_data) return -EBUSY; - video->sequence = 0; - /* Get a pipeline for the video node and start streaming on it. No link * touching an entity in the pipeline can be activated or deactivated * once streaming is started. diff --git a/drivers/media/platform/vsp1/vsp1_video.h b/drivers/media/platform/vsp1/vsp1_video.h index 867b00807c46..1595fd587fbc 100644 --- a/drivers/media/platform/vsp1/vsp1_video.h +++ b/drivers/media/platform/vsp1/vsp1_video.h @@ -49,7 +49,6 @@ struct vsp1_video { void *alloc_ctx; spinlock_t irqlock; struct list_head irqqueue; - unsigned int sequence; }; static inline struct vsp1_video *to_vsp1_video(struct video_device *vdev) -- cgit v1.2.3 From c6b013ab517b0ae09036d50f6b1684d9dbedf596 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 23 Apr 2016 19:08:59 -0300 Subject: [media] v4l: vsp1: Group DRM RPF parameters in a structure The vsp1_du_atomic_update_ext() function takes 7 RPF configuration parameters, and more will likely be added later. This makes the code difficult to read and error-prone as multiple parameters have the same type. Make the API safer and easier to extend in the future by grouping all parameters in a structure. Use macro magic to ease the transition to the new function by allowing the old and new functions to be called using the same name. The macros and static inline wrapper will be removed as soon as the caller is updated. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_drm.c | 68 +++++++++++++++------------------- include/media/vsp1.h | 47 ++++++++++++++++------- 2 files changed, 64 insertions(+), 51 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c index fc4bbc401e67..fef53ecefe25 100644 --- a/drivers/media/platform/vsp1/vsp1_drm.c +++ b/drivers/media/platform/vsp1/vsp1_drm.c @@ -230,42 +230,33 @@ EXPORT_SYMBOL_GPL(vsp1_du_atomic_begin); * vsp1_du_atomic_update - Setup one RPF input of the VSP pipeline * @dev: the VSP device * @rpf_index: index of the RPF to setup (0-based) - * @pixelformat: V4L2 pixel format for the RPF memory input - * @pitch: number of bytes per line in the image stored in memory - * @mem: DMA addresses of the memory buffers (one per plane) - * @src: the source crop rectangle for the RPF - * @dst: the destination compose rectangle for the BRU input - * @alpha: global alpha value for the input - * @zpos: the Z-order position of the input + * @cfg: the RPF configuration * - * Configure the VSP to perform composition of the image referenced by @mem - * through RPF @rpf_index, using the @src crop rectangle and the @dst + * Configure the VSP to perform image composition through RPF @rpf_index as + * described by the @cfg configuration. The image to compose is referenced by + * @cfg.mem and composed using the @cfg.src crop rectangle and the @cfg.dst * composition rectangle. The Z-order is configurable with higher @zpos values * displayed on top. * - * Image format as stored in memory is expressed as a V4L2 @pixelformat value. - * As a special case, setting the pixel format to 0 will disable the RPF. The - * @pitch, @mem, @src and @dst parameters are ignored in that case. Calling the + * If the @cfg configuration is NULL, the RPF will be disabled. Calling the * function on a disabled RPF is allowed. * - * The memory pitch is configurable to allow for padding at end of lines, or - * simple for images that extend beyond the crop rectangle boundaries. The - * @pitch value is expressed in bytes and applies to all planes for multiplanar - * formats. + * Image format as stored in memory is expressed as a V4L2 @cfg.pixelformat + * value. The memory pitch is configurable to allow for padding at end of lines, + * or simply for images that extend beyond the crop rectangle boundaries. The + * @cfg.pitch value is expressed in bytes and applies to all planes for + * multiplanar formats. * * The source memory buffer is referenced by the DMA address of its planes in - * the @mem array. Up to two planes are supported. The second plane DMA address - * is ignored for formats using a single plane. + * the @cfg.mem array. Up to two planes are supported. The second plane DMA + * address is ignored for formats using a single plane. * * This function isn't reentrant, the caller needs to serialize calls. * * Return 0 on success or a negative error code on failure. */ -int vsp1_du_atomic_update_ext(struct device *dev, unsigned int rpf_index, - u32 pixelformat, unsigned int pitch, - dma_addr_t mem[2], const struct v4l2_rect *src, - const struct v4l2_rect *dst, unsigned int alpha, - unsigned int zpos) +int __vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index, + const struct vsp1_du_atomic_config *cfg) { struct vsp1_device *vsp1 = dev_get_drvdata(dev); const struct vsp1_format_info *fmtinfo; @@ -276,7 +267,7 @@ int vsp1_du_atomic_update_ext(struct device *dev, unsigned int rpf_index, rpf = vsp1->rpf[rpf_index]; - if (pixelformat == 0) { + if (!cfg) { dev_dbg(vsp1->dev, "%s: RPF%u: disable requested\n", __func__, rpf_index); @@ -287,38 +278,39 @@ int vsp1_du_atomic_update_ext(struct device *dev, unsigned int rpf_index, dev_dbg(vsp1->dev, "%s: RPF%u: (%u,%u)/%ux%u -> (%u,%u)/%ux%u (%08x), pitch %u dma { %pad, %pad } zpos %u\n", __func__, rpf_index, - src->left, src->top, src->width, src->height, - dst->left, dst->top, dst->width, dst->height, - pixelformat, pitch, &mem[0], &mem[1], zpos); + cfg->src.left, cfg->src.top, cfg->src.width, cfg->src.height, + cfg->dst.left, cfg->dst.top, cfg->dst.width, cfg->dst.height, + cfg->pixelformat, cfg->pitch, &cfg->mem[0], &cfg->mem[1], + cfg->zpos); /* Store the format, stride, memory buffer address, crop and compose * rectangles and Z-order position and for the input. */ - fmtinfo = vsp1_get_format_info(pixelformat); + fmtinfo = vsp1_get_format_info(cfg->pixelformat); if (!fmtinfo) { dev_dbg(vsp1->dev, "Unsupport pixel format %08x for RPF\n", - pixelformat); + cfg->pixelformat); return -EINVAL; } rpf->fmtinfo = fmtinfo; rpf->format.num_planes = fmtinfo->planes; - rpf->format.plane_fmt[0].bytesperline = pitch; - rpf->format.plane_fmt[1].bytesperline = pitch; - rpf->alpha = alpha; + rpf->format.plane_fmt[0].bytesperline = cfg->pitch; + rpf->format.plane_fmt[1].bytesperline = cfg->pitch; + rpf->alpha = cfg->alpha; - rpf->mem.addr[0] = mem[0]; - rpf->mem.addr[1] = mem[1]; + rpf->mem.addr[0] = cfg->mem[0]; + rpf->mem.addr[1] = cfg->mem[1]; rpf->mem.addr[2] = 0; - vsp1->drm->inputs[rpf_index].crop = *src; - vsp1->drm->inputs[rpf_index].compose = *dst; - vsp1->drm->inputs[rpf_index].zpos = zpos; + vsp1->drm->inputs[rpf_index].crop = cfg->src; + vsp1->drm->inputs[rpf_index].compose = cfg->dst; + vsp1->drm->inputs[rpf_index].zpos = cfg->zpos; vsp1->drm->inputs[rpf_index].enabled = true; return 0; } -EXPORT_SYMBOL_GPL(vsp1_du_atomic_update_ext); +EXPORT_SYMBOL_GPL(__vsp1_du_atomic_update); static int vsp1_du_setup_rpf_pipe(struct vsp1_device *vsp1, struct vsp1_rwpf *rpf, unsigned int bru_input) diff --git a/include/media/vsp1.h b/include/media/vsp1.h index 3e654a0455bd..ea8ad7537057 100644 --- a/include/media/vsp1.h +++ b/include/media/vsp1.h @@ -14,31 +14,52 @@ #define __MEDIA_VSP1_H__ #include +#include struct device; -struct v4l2_rect; int vsp1_du_init(struct device *dev); int vsp1_du_setup_lif(struct device *dev, unsigned int width, unsigned int height); +struct vsp1_du_atomic_config { + u32 pixelformat; + unsigned int pitch; + dma_addr_t mem[2]; + struct v4l2_rect src; + struct v4l2_rect dst; + unsigned int alpha; + unsigned int zpos; +}; + void vsp1_du_atomic_begin(struct device *dev); -int vsp1_du_atomic_update_ext(struct device *dev, unsigned int rpf, - u32 pixelformat, unsigned int pitch, - dma_addr_t mem[2], const struct v4l2_rect *src, - const struct v4l2_rect *dst, unsigned int alpha, - unsigned int zpos); +int __vsp1_du_atomic_update(struct device *dev, unsigned int rpf, + const struct vsp1_du_atomic_config *cfg); void vsp1_du_atomic_flush(struct device *dev); -static inline int vsp1_du_atomic_update(struct device *dev, - unsigned int rpf_index, u32 pixelformat, - unsigned int pitch, dma_addr_t mem[2], - const struct v4l2_rect *src, - const struct v4l2_rect *dst) +static inline int vsp1_du_atomic_update_old(struct device *dev, + unsigned int rpf, u32 pixelformat, unsigned int pitch, + dma_addr_t mem[2], const struct v4l2_rect *src, + const struct v4l2_rect *dst) { - return vsp1_du_atomic_update_ext(dev, rpf_index, pixelformat, pitch, - mem, src, dst, 255, 0); + struct vsp1_du_atomic_config cfg = { + .pixelformat = pixelformat, + .pitch = pitch, + .mem[0] = mem[0], + .mem[1] = mem[1], + .src = *src, + .dst = *dst, + .alpha = 255, + .zpos = 0, + }; + + return __vsp1_du_atomic_update(dev, rpf, &cfg); } +#define _vsp1_du_atomic_update(_1, _2, _3, _4, _5, _6, _7, f, ...) f +#define vsp1_du_atomic_update(...) \ + _vsp1_du_atomic_update(__VA_ARGS__, vsp1_du_atomic_update_old, 0, 0, \ + 0, __vsp1_du_atomic_update)(__VA_ARGS__) + #endif /* __MEDIA_VSP1_H__ */ -- cgit v1.2.3 From c3f34a4bdd596127000666c17bbf8ba1c3d2d332 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 23 Apr 2016 20:11:59 -0300 Subject: [media] v4l: vsp1: Remove deprecated DRM API The DRM driver has switched to the new API, remove the deprecated macros and inline wrapper. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_drm.c | 6 +++--- include/media/vsp1.h | 28 ++-------------------------- 2 files changed, 5 insertions(+), 29 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c index fef53ecefe25..14730119687f 100644 --- a/drivers/media/platform/vsp1/vsp1_drm.c +++ b/drivers/media/platform/vsp1/vsp1_drm.c @@ -255,8 +255,8 @@ EXPORT_SYMBOL_GPL(vsp1_du_atomic_begin); * * Return 0 on success or a negative error code on failure. */ -int __vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index, - const struct vsp1_du_atomic_config *cfg) +int vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index, + const struct vsp1_du_atomic_config *cfg) { struct vsp1_device *vsp1 = dev_get_drvdata(dev); const struct vsp1_format_info *fmtinfo; @@ -310,7 +310,7 @@ int __vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index, return 0; } -EXPORT_SYMBOL_GPL(__vsp1_du_atomic_update); +EXPORT_SYMBOL_GPL(vsp1_du_atomic_update); static int vsp1_du_setup_rpf_pipe(struct vsp1_device *vsp1, struct vsp1_rwpf *rpf, unsigned int bru_input) diff --git a/include/media/vsp1.h b/include/media/vsp1.h index ea8ad7537057..9322d9775fb7 100644 --- a/include/media/vsp1.h +++ b/include/media/vsp1.h @@ -34,32 +34,8 @@ struct vsp1_du_atomic_config { }; void vsp1_du_atomic_begin(struct device *dev); -int __vsp1_du_atomic_update(struct device *dev, unsigned int rpf, - const struct vsp1_du_atomic_config *cfg); +int vsp1_du_atomic_update(struct device *dev, unsigned int rpf, + const struct vsp1_du_atomic_config *cfg); void vsp1_du_atomic_flush(struct device *dev); -static inline int vsp1_du_atomic_update_old(struct device *dev, - unsigned int rpf, u32 pixelformat, unsigned int pitch, - dma_addr_t mem[2], const struct v4l2_rect *src, - const struct v4l2_rect *dst) -{ - struct vsp1_du_atomic_config cfg = { - .pixelformat = pixelformat, - .pitch = pitch, - .mem[0] = mem[0], - .mem[1] = mem[1], - .src = *src, - .dst = *dst, - .alpha = 255, - .zpos = 0, - }; - - return __vsp1_du_atomic_update(dev, rpf, &cfg); -} - -#define _vsp1_du_atomic_update(_1, _2, _3, _4, _5, _6, _7, f, ...) f -#define vsp1_du_atomic_update(...) \ - _vsp1_du_atomic_update(__VA_ARGS__, vsp1_du_atomic_update_old, 0, 0, \ - 0, __vsp1_du_atomic_update)(__VA_ARGS__) - #endif /* __MEDIA_VSP1_H__ */ -- cgit v1.2.3 From 04d983fc4d675949e04417c39ce91bd862d2714a Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 15 May 2016 18:15:47 -0300 Subject: [media] v4l: vsp1: Fix typo in register field names The VI6_RPF_ALPH_SEL ALPHA0 and ALPHA1 fields are inverted, swap them. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_regs.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/vsp1/vsp1_regs.h b/drivers/media/platform/vsp1/vsp1_regs.h index 927b5fb94c48..7657545a75ed 100644 --- a/drivers/media/platform/vsp1/vsp1_regs.h +++ b/drivers/media/platform/vsp1/vsp1_regs.h @@ -154,10 +154,10 @@ #define VI6_RPF_ALPH_SEL_AEXT_EXT (1 << 18) #define VI6_RPF_ALPH_SEL_AEXT_ONE (2 << 18) #define VI6_RPF_ALPH_SEL_AEXT_MASK (3 << 18) -#define VI6_RPF_ALPH_SEL_ALPHA0_MASK (0xff << 8) -#define VI6_RPF_ALPH_SEL_ALPHA0_SHIFT 8 -#define VI6_RPF_ALPH_SEL_ALPHA1_MASK (0xff << 0) -#define VI6_RPF_ALPH_SEL_ALPHA1_SHIFT 0 +#define VI6_RPF_ALPH_SEL_ALPHA1_MASK (0xff << 8) +#define VI6_RPF_ALPH_SEL_ALPHA1_SHIFT 8 +#define VI6_RPF_ALPH_SEL_ALPHA0_MASK (0xff << 0) +#define VI6_RPF_ALPH_SEL_ALPHA0_SHIFT 0 #define VI6_RPF_VRTCOL_SET 0x0318 #define VI6_RPF_VRTCOL_SET_LAYA_MASK (0xff << 24) -- cgit v1.2.3 From 398e3d4f1e0baecb926315673a6740f2573b07ae Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 17 May 2016 04:23:33 -0300 Subject: [media] v4l: vsp1: Fix descriptions of Gen2 VSP instances The number of UDS and WPF are set to incorrect values, fix them. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_drv.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c index e655639af7e2..70e7a81e8255 100644 --- a/drivers/media/platform/vsp1/vsp1_drv.c +++ b/drivers/media/platform/vsp1/vsp1_drv.c @@ -560,7 +560,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = { .gen = 2, .features = VSP1_HAS_BRU | VSP1_HAS_SRU, .rpf_count = 5, - .uds_count = 1, + .uds_count = 3, .wpf_count = 4, .num_bru_inputs = 4, .uapi = true, @@ -570,7 +570,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = { .features = VSP1_HAS_BRU | VSP1_HAS_LIF | VSP1_HAS_LUT, .rpf_count = 4, .uds_count = 1, - .wpf_count = 4, + .wpf_count = 1, .num_bru_inputs = 4, .uapi = true, }, { @@ -578,7 +578,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = { .gen = 2, .features = VSP1_HAS_BRU | VSP1_HAS_LUT | VSP1_HAS_SRU, .rpf_count = 5, - .uds_count = 3, + .uds_count = 1, .wpf_count = 4, .num_bru_inputs = 4, .uapi = true, -- cgit v1.2.3 From d69e40fade97b6b19837c1772efa516bc28cc870 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 18 May 2016 20:01:21 -0300 Subject: [media] v4l: vsp1: Fix crash when resetting pipeline The vsp1_pipeline_reset() function loops over pipeline inputs and output and resets them. When doing so it assumes both that the pipeline has been correctly configured with an output, and that inputs are are stored in the pipe inputs array at positions 0 to num_inputs-1. Both the assumptions are incorrect. The pipeline might need to be reset after a failed attempts to configure it, without any output specified. Furthermore, inputs are stored in a positiong equal to their RPF index, possibly creating holes in the inputs array if the RPFs are not used in sequence. Fix both issues by looping over the whole inputs array and skipping unused entries, and ignoring the output when not set. Fixes: ff7e97c94d9f ("[media] v4l: vsp1: Store pipeline pointer in rwpf") Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_pipe.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c b/drivers/media/platform/vsp1/vsp1_pipe.c index be47c8a1a812..3c6f623f056c 100644 --- a/drivers/media/platform/vsp1/vsp1_pipe.c +++ b/drivers/media/platform/vsp1/vsp1_pipe.c @@ -172,13 +172,17 @@ void vsp1_pipeline_reset(struct vsp1_pipeline *pipe) bru->inputs[i].rpf = NULL; } - for (i = 0; i < pipe->num_inputs; ++i) { - pipe->inputs[i]->pipe = NULL; - pipe->inputs[i] = NULL; + for (i = 0; i < ARRAY_SIZE(pipe->inputs); ++i) { + if (pipe->inputs[i]) { + pipe->inputs[i]->pipe = NULL; + pipe->inputs[i] = NULL; + } } - pipe->output->pipe = NULL; - pipe->output = NULL; + if (pipe->output) { + pipe->output->pipe = NULL; + pipe->output = NULL; + } INIT_LIST_HEAD(&pipe->entities); pipe->state = VSP1_PIPELINE_STOPPED; -- cgit v1.2.3 From e98c59dd717fddde28193777c4602196b1240e66 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 13 May 2016 19:13:51 -0300 Subject: [media] v4l: vsp1: pipe: Fix typo in comment The vsp1_pipeline wq field is a wait queue, not a work queue. Fix the comment accordingly. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_pipe.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/vsp1/vsp1_pipe.h b/drivers/media/platform/vsp1/vsp1_pipe.h index febc62f99d6d..fc9825d3d64c 100644 --- a/drivers/media/platform/vsp1/vsp1_pipe.h +++ b/drivers/media/platform/vsp1/vsp1_pipe.h @@ -61,7 +61,7 @@ enum vsp1_pipeline_state { * @pipe: the media pipeline * @irqlock: protects the pipeline state * @state: current state - * @wq: work queue to wait for state change completion + * @wq: wait queue to wait for state change completion * @frame_end: frame end interrupt handler * @lock: protects the pipeline use count and stream count * @kref: pipeline reference count -- cgit v1.2.3 From eb9163d3bd2700ea3c6570a07e7548f678211dac Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 17 Jun 2016 21:11:26 -0300 Subject: [media] v4l: vsp1: Constify operation structures The structures are never modified, make them const. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_bru.c | 4 ++-- drivers/media/platform/vsp1/vsp1_hsit.c | 4 ++-- drivers/media/platform/vsp1/vsp1_lif.c | 4 ++-- drivers/media/platform/vsp1/vsp1_lut.c | 6 +++--- drivers/media/platform/vsp1/vsp1_rpf.c | 2 +- drivers/media/platform/vsp1/vsp1_sru.c | 4 ++-- drivers/media/platform/vsp1/vsp1_uds.c | 4 ++-- drivers/media/platform/vsp1/vsp1_video.c | 4 ++-- drivers/media/platform/vsp1/vsp1_wpf.c | 4 ++-- 9 files changed, 18 insertions(+), 18 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c index b1068c018011..ed36d3373943 100644 --- a/drivers/media/platform/vsp1/vsp1_bru.c +++ b/drivers/media/platform/vsp1/vsp1_bru.c @@ -249,7 +249,7 @@ static int bru_set_selection(struct v4l2_subdev *subdev, return 0; } -static struct v4l2_subdev_pad_ops bru_pad_ops = { +static const struct v4l2_subdev_pad_ops bru_pad_ops = { .init_cfg = vsp1_entity_init_cfg, .enum_mbus_code = bru_enum_mbus_code, .enum_frame_size = bru_enum_frame_size, @@ -259,7 +259,7 @@ static struct v4l2_subdev_pad_ops bru_pad_ops = { .set_selection = bru_set_selection, }; -static struct v4l2_subdev_ops bru_ops = { +static const struct v4l2_subdev_ops bru_ops = { .pad = &bru_pad_ops, }; diff --git a/drivers/media/platform/vsp1/vsp1_hsit.c b/drivers/media/platform/vsp1/vsp1_hsit.c index 68b8567b374d..ec90af1bb209 100644 --- a/drivers/media/platform/vsp1/vsp1_hsit.c +++ b/drivers/media/platform/vsp1/vsp1_hsit.c @@ -107,7 +107,7 @@ static int hsit_set_format(struct v4l2_subdev *subdev, return 0; } -static struct v4l2_subdev_pad_ops hsit_pad_ops = { +static const struct v4l2_subdev_pad_ops hsit_pad_ops = { .init_cfg = vsp1_entity_init_cfg, .enum_mbus_code = hsit_enum_mbus_code, .enum_frame_size = hsit_enum_frame_size, @@ -115,7 +115,7 @@ static struct v4l2_subdev_pad_ops hsit_pad_ops = { .set_fmt = hsit_set_format, }; -static struct v4l2_subdev_ops hsit_ops = { +static const struct v4l2_subdev_ops hsit_ops = { .pad = &hsit_pad_ops, }; diff --git a/drivers/media/platform/vsp1/vsp1_lif.c b/drivers/media/platform/vsp1/vsp1_lif.c index 0217393f22df..e554b3150748 100644 --- a/drivers/media/platform/vsp1/vsp1_lif.c +++ b/drivers/media/platform/vsp1/vsp1_lif.c @@ -104,7 +104,7 @@ static int lif_set_format(struct v4l2_subdev *subdev, return 0; } -static struct v4l2_subdev_pad_ops lif_pad_ops = { +static const struct v4l2_subdev_pad_ops lif_pad_ops = { .init_cfg = vsp1_entity_init_cfg, .enum_mbus_code = lif_enum_mbus_code, .enum_frame_size = lif_enum_frame_size, @@ -112,7 +112,7 @@ static struct v4l2_subdev_pad_ops lif_pad_ops = { .set_fmt = lif_set_format, }; -static struct v4l2_subdev_ops lif_ops = { +static const struct v4l2_subdev_ops lif_ops = { .pad = &lif_pad_ops, }; diff --git a/drivers/media/platform/vsp1/vsp1_lut.c b/drivers/media/platform/vsp1/vsp1_lut.c index aa09e59f0ab8..a543debaafb5 100644 --- a/drivers/media/platform/vsp1/vsp1_lut.c +++ b/drivers/media/platform/vsp1/vsp1_lut.c @@ -147,11 +147,11 @@ static int lut_set_format(struct v4l2_subdev *subdev, * V4L2 Subdevice Operations */ -static struct v4l2_subdev_core_ops lut_core_ops = { +static const struct v4l2_subdev_core_ops lut_core_ops = { .ioctl = lut_ioctl, }; -static struct v4l2_subdev_pad_ops lut_pad_ops = { +static const struct v4l2_subdev_pad_ops lut_pad_ops = { .init_cfg = vsp1_entity_init_cfg, .enum_mbus_code = lut_enum_mbus_code, .enum_frame_size = lut_enum_frame_size, @@ -159,7 +159,7 @@ static struct v4l2_subdev_pad_ops lut_pad_ops = { .set_fmt = lut_set_format, }; -static struct v4l2_subdev_ops lut_ops = { +static const struct v4l2_subdev_ops lut_ops = { .core = &lut_core_ops, .pad = &lut_pad_ops, }; diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c index 64dfbddf2aba..4b397baef88f 100644 --- a/drivers/media/platform/vsp1/vsp1_rpf.c +++ b/drivers/media/platform/vsp1/vsp1_rpf.c @@ -38,7 +38,7 @@ static inline void vsp1_rpf_write(struct vsp1_rwpf *rpf, * V4L2 Subdevice Operations */ -static struct v4l2_subdev_ops rpf_ops = { +static const struct v4l2_subdev_ops rpf_ops = { .pad = &vsp1_rwpf_pad_ops, }; diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c index 97ef997ae735..6f8cf98de867 100644 --- a/drivers/media/platform/vsp1/vsp1_sru.c +++ b/drivers/media/platform/vsp1/vsp1_sru.c @@ -239,7 +239,7 @@ static int sru_set_format(struct v4l2_subdev *subdev, return 0; } -static struct v4l2_subdev_pad_ops sru_pad_ops = { +static const struct v4l2_subdev_pad_ops sru_pad_ops = { .init_cfg = vsp1_entity_init_cfg, .enum_mbus_code = sru_enum_mbus_code, .enum_frame_size = sru_enum_frame_size, @@ -247,7 +247,7 @@ static struct v4l2_subdev_pad_ops sru_pad_ops = { .set_fmt = sru_set_format, }; -static struct v4l2_subdev_ops sru_ops = { +static const struct v4l2_subdev_ops sru_ops = { .pad = &sru_pad_ops, }; diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c index 1875e29da184..5d508e70fdda 100644 --- a/drivers/media/platform/vsp1/vsp1_uds.c +++ b/drivers/media/platform/vsp1/vsp1_uds.c @@ -226,7 +226,7 @@ static int uds_set_format(struct v4l2_subdev *subdev, * V4L2 Subdevice Operations */ -static struct v4l2_subdev_pad_ops uds_pad_ops = { +static const struct v4l2_subdev_pad_ops uds_pad_ops = { .init_cfg = vsp1_entity_init_cfg, .enum_mbus_code = uds_enum_mbus_code, .enum_frame_size = uds_enum_frame_size, @@ -234,7 +234,7 @@ static struct v4l2_subdev_pad_ops uds_pad_ops = { .set_fmt = uds_set_format, }; -static struct v4l2_subdev_ops uds_ops = { +static const struct v4l2_subdev_ops uds_ops = { .pad = &uds_pad_ops, }; diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c index 34aa6427662d..a899b15c8d87 100644 --- a/drivers/media/platform/vsp1/vsp1_video.c +++ b/drivers/media/platform/vsp1/vsp1_video.c @@ -696,7 +696,7 @@ static void vsp1_video_stop_streaming(struct vb2_queue *vq) spin_unlock_irqrestore(&video->irqlock, flags); } -static struct vb2_ops vsp1_video_queue_qops = { +static const struct vb2_ops vsp1_video_queue_qops = { .queue_setup = vsp1_video_queue_setup, .buf_prepare = vsp1_video_buffer_prepare, .buf_queue = vsp1_video_buffer_queue, @@ -913,7 +913,7 @@ static int vsp1_video_release(struct file *file) return 0; } -static struct v4l2_file_operations vsp1_video_fops = { +static const struct v4l2_file_operations vsp1_video_fops = { .owner = THIS_MODULE, .unlocked_ioctl = video_ioctl2, .open = vsp1_video_open, diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c index 6c91eaa35e75..59bdb450e6f1 100644 --- a/drivers/media/platform/vsp1/vsp1_wpf.c +++ b/drivers/media/platform/vsp1/vsp1_wpf.c @@ -62,11 +62,11 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable) * V4L2 Subdevice Operations */ -static struct v4l2_subdev_video_ops wpf_video_ops = { +static const struct v4l2_subdev_video_ops wpf_video_ops = { .s_stream = wpf_s_stream, }; -static struct v4l2_subdev_ops wpf_ops = { +static const struct v4l2_subdev_ops wpf_ops = { .video = &wpf_video_ops, .pad = &vsp1_rwpf_pad_ops, }; -- cgit v1.2.3 From b4dfb9b35a192f555d76fc4f670a447657bcc183 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 17 Jun 2016 21:03:29 -0300 Subject: [media] v4l: vsp1: Stop the pipeline upon the first STREAMOFF The device is stopped when STREAMOFF is called on the last video node in the pipeline. This results in possible memory corruption and/or crashes, as userspace could free buffers while the hardware is still writing to them, and the frame completion interrupt handler could try to access buffers that don't exist anymore. Fix this by stopping the pipeline upon the first STREAMOFF call, not the last. Reported-by: Kuninori Morimoto Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_video.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c index a899b15c8d87..f6208b9d8118 100644 --- a/drivers/media/platform/vsp1/vsp1_video.c +++ b/drivers/media/platform/vsp1/vsp1_video.c @@ -674,7 +674,7 @@ static void vsp1_video_stop_streaming(struct vb2_queue *vq) int ret; mutex_lock(&pipe->lock); - if (--pipe->stream_count == 0) { + if (--pipe->stream_count == pipe->num_inputs) { /* Stop the pipeline. */ ret = vsp1_pipeline_stop(pipe); if (ret == -ETIMEDOUT) -- cgit v1.2.3 From 67a706f3ebde90416b45257cf4b23f3d9db97670 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 16 Jun 2016 19:33:43 -0300 Subject: [media] v4l: vsp1: sru: Fix intensity control ID The intensity control reused the V4L2_CID_CONTRAST control ID by mistake. Fix it by using an ID from the device-specific IDs range. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_sru.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c index 6f8cf98de867..035c26934bc7 100644 --- a/drivers/media/platform/vsp1/vsp1_sru.c +++ b/drivers/media/platform/vsp1/vsp1_sru.c @@ -37,7 +37,7 @@ static inline void vsp1_sru_write(struct vsp1_sru *sru, struct vsp1_dl_list *dl, * Controls */ -#define V4L2_CID_VSP1_SRU_INTENSITY (V4L2_CID_USER_BASE + 1) +#define V4L2_CID_VSP1_SRU_INTENSITY (V4L2_CID_USER_BASE | 0x1001) struct vsp1_sru_param { u32 ctrl0; -- cgit v1.2.3 From 078e04993aef1bc7388e99dba99f6793e246c659 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 13 May 2016 13:04:51 -0300 Subject: [media] v4l: vsp1: Base link creation on availability of entities Check the entity pointer instead of the feature flag to see if the entity is available before creating related links. The two methods are currently equivalent, but will differ in the future as we implement support for ignoring some of the entities present in the hardware. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c index 70e7a81e8255..7e3b9da5aa11 100644 --- a/drivers/media/platform/vsp1/vsp1_drv.c +++ b/drivers/media/platform/vsp1/vsp1_drv.c @@ -147,7 +147,7 @@ static int vsp1_uapi_create_links(struct vsp1_device *vsp1) return ret; } - if (vsp1->info->features & VSP1_HAS_LIF) { + if (vsp1->lif) { ret = media_create_pad_link(&vsp1->wpf[0]->entity.subdev.entity, RWPF_PAD_SOURCE, &vsp1->lif->entity.subdev.entity, -- cgit v1.2.3 From aa0bad337ff231882dc8849f2234138281b5c414 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 13 May 2016 13:09:25 -0300 Subject: [media] v4l: vsp1: Don't register media device when userspace API is disabled The media device doesn't need to be exposed to userspace when the VSP is fully controlled by the DU driver. Don't register it in that case. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_drv.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c index 7e3b9da5aa11..71fd614c1412 100644 --- a/drivers/media/platform/vsp1/vsp1_drv.c +++ b/drivers/media/platform/vsp1/vsp1_drv.c @@ -206,7 +206,8 @@ static void vsp1_destroy_entities(struct vsp1_device *vsp1) } v4l2_device_unregister(&vsp1->v4l2_dev); - media_device_unregister(&vsp1->media_dev); + if (vsp1->info->uapi) + media_device_unregister(&vsp1->media_dev); media_device_cleanup(&vsp1->media_dev); if (!vsp1->info->uapi) @@ -381,14 +382,15 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) /* Register subdev nodes if the userspace API is enabled or initialize * the DRM pipeline otherwise. */ - if (vsp1->info->uapi) + if (vsp1->info->uapi) { ret = v4l2_device_register_subdev_nodes(&vsp1->v4l2_dev); - else - ret = vsp1_drm_init(vsp1); - if (ret < 0) - goto done; + if (ret < 0) + goto done; - ret = media_device_register(mdev); + ret = media_device_register(mdev); + } else { + ret = vsp1_drm_init(vsp1); + } done: if (ret < 0) -- cgit v1.2.3 From 8d954abe30fcf1e979473abb0f3cf2f18c0d13e0 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 13 May 2016 13:10:57 -0300 Subject: [media] v4l: vsp1: Don't create LIF entity when the userspace API is enabled The LIF is only used when feeding the VSP output to the DU. The only way to do so is by controlling the VSP directly from the DU driver and disabling the VSP userspace API. There is thus no need to create a LIF entity when the userspace API is enabled, as it can't be used in that case. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_drv.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c index 71fd614c1412..0b0e73685a24 100644 --- a/drivers/media/platform/vsp1/vsp1_drv.c +++ b/drivers/media/platform/vsp1/vsp1_drv.c @@ -170,19 +170,15 @@ static int vsp1_uapi_create_links(struct vsp1_device *vsp1) for (i = 0; i < vsp1->info->wpf_count; ++i) { /* Connect the video device to the WPF. All connections are - * immutable except for the WPF0 source link if a LIF is - * present. + * immutable. */ struct vsp1_rwpf *wpf = vsp1->wpf[i]; - unsigned int flags = MEDIA_LNK_FL_ENABLED; - - if (!(vsp1->info->features & VSP1_HAS_LIF) || i != 0) - flags |= MEDIA_LNK_FL_IMMUTABLE; ret = media_create_pad_link(&wpf->entity.subdev.entity, RWPF_PAD_SOURCE, &wpf->video->video.entity, 0, - flags); + MEDIA_LNK_FL_IMMUTABLE | + MEDIA_LNK_FL_ENABLED); if (ret < 0) return ret; } @@ -271,7 +267,11 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) list_add_tail(&vsp1->hst->entity.list_dev, &vsp1->entities); - if (vsp1->info->features & VSP1_HAS_LIF) { + /* The LIF is only supported when used in conjunction with the DU, in + * which case the userspace API is disabled. If the userspace API is + * enabled skip the LIF, even when present. + */ + if (vsp1->info->features & VSP1_HAS_LIF && !vsp1->info->uapi) { vsp1->lif = vsp1_lif_create(vsp1); if (IS_ERR(vsp1->lif)) { ret = PTR_ERR(vsp1->lif); -- cgit v1.2.3 From 6a8e07b215a91be310dac358fdccd7709dd2458f Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 15 Feb 2016 22:10:26 -0200 Subject: [media] v4l: vsp1: Set entities functions Initialize the function field of all subdev entities instantiated by the driver. This gets rids of multiple warnings printed by the media controller core. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_bru.c | 3 ++- drivers/media/platform/vsp1/vsp1_entity.c | 3 ++- drivers/media/platform/vsp1/vsp1_entity.h | 2 +- drivers/media/platform/vsp1/vsp1_hsit.c | 5 +++-- drivers/media/platform/vsp1/vsp1_lif.c | 7 ++++++- drivers/media/platform/vsp1/vsp1_lut.c | 3 ++- drivers/media/platform/vsp1/vsp1_rpf.c | 3 ++- drivers/media/platform/vsp1/vsp1_sru.c | 3 ++- drivers/media/platform/vsp1/vsp1_uds.c | 3 ++- drivers/media/platform/vsp1/vsp1_wpf.c | 3 ++- 10 files changed, 24 insertions(+), 11 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c index ed36d3373943..cae911726778 100644 --- a/drivers/media/platform/vsp1/vsp1_bru.c +++ b/drivers/media/platform/vsp1/vsp1_bru.c @@ -390,7 +390,8 @@ struct vsp1_bru *vsp1_bru_create(struct vsp1_device *vsp1) bru->entity.type = VSP1_ENTITY_BRU; ret = vsp1_entity_init(vsp1, &bru->entity, "bru", - vsp1->info->num_bru_inputs + 1, &bru_ops); + vsp1->info->num_bru_inputs + 1, &bru_ops, + MEDIA_ENT_F_PROC_VIDEO_COMPOSER); if (ret < 0) return ERR_PTR(ret); diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c index fd20c0d8aeea..d72dbcce4b11 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.c +++ b/drivers/media/platform/vsp1/vsp1_entity.c @@ -340,7 +340,7 @@ static const struct vsp1_route vsp1_routes[] = { int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity, const char *name, unsigned int num_pads, - const struct v4l2_subdev_ops *ops) + const struct v4l2_subdev_ops *ops, u32 function) { struct v4l2_subdev *subdev; unsigned int i; @@ -381,6 +381,7 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity, subdev = &entity->subdev; v4l2_subdev_init(subdev, ops); + subdev->entity.function = function; subdev->entity.ops = &vsp1->media_ops; subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h index a240fc1c59a6..bcdea4ee73c5 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.h +++ b/drivers/media/platform/vsp1/vsp1_entity.h @@ -104,7 +104,7 @@ static inline struct vsp1_entity *to_vsp1_entity(struct v4l2_subdev *subdev) int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity, const char *name, unsigned int num_pads, - const struct v4l2_subdev_ops *ops); + const struct v4l2_subdev_ops *ops, u32 function); void vsp1_entity_destroy(struct vsp1_entity *entity); extern const struct v4l2_subdev_internal_ops vsp1_subdev_internal_ops; diff --git a/drivers/media/platform/vsp1/vsp1_hsit.c b/drivers/media/platform/vsp1/vsp1_hsit.c index ec90af1bb209..ab3cae307ba5 100644 --- a/drivers/media/platform/vsp1/vsp1_hsit.c +++ b/drivers/media/platform/vsp1/vsp1_hsit.c @@ -161,8 +161,9 @@ struct vsp1_hsit *vsp1_hsit_create(struct vsp1_device *vsp1, bool inverse) else hsit->entity.type = VSP1_ENTITY_HST; - ret = vsp1_entity_init(vsp1, &hsit->entity, inverse ? "hsi" : "hst", 2, - &hsit_ops); + ret = vsp1_entity_init(vsp1, &hsit->entity, inverse ? "hsi" : "hst", + 2, &hsit_ops, + MEDIA_ENT_F_PROC_VIDEO_PIXEL_ENC_CONV); if (ret < 0) return ERR_PTR(ret); diff --git a/drivers/media/platform/vsp1/vsp1_lif.c b/drivers/media/platform/vsp1/vsp1_lif.c index e554b3150748..e006f0df3ce9 100644 --- a/drivers/media/platform/vsp1/vsp1_lif.c +++ b/drivers/media/platform/vsp1/vsp1_lif.c @@ -165,7 +165,12 @@ struct vsp1_lif *vsp1_lif_create(struct vsp1_device *vsp1) lif->entity.ops = &lif_entity_ops; lif->entity.type = VSP1_ENTITY_LIF; - ret = vsp1_entity_init(vsp1, &lif->entity, "lif", 2, &lif_ops); + /* The LIF is never exposed to userspace, but media entity registration + * requires a function to be set. Use PROC_VIDEO_PIXEL_FORMATTER just to + * avoid triggering a WARN_ON(), the value won't be seen anywhere. + */ + ret = vsp1_entity_init(vsp1, &lif->entity, "lif", 2, &lif_ops, + MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER); if (ret < 0) return ERR_PTR(ret); diff --git a/drivers/media/platform/vsp1/vsp1_lut.c b/drivers/media/platform/vsp1/vsp1_lut.c index a543debaafb5..855e483acb89 100644 --- a/drivers/media/platform/vsp1/vsp1_lut.c +++ b/drivers/media/platform/vsp1/vsp1_lut.c @@ -204,7 +204,8 @@ struct vsp1_lut *vsp1_lut_create(struct vsp1_device *vsp1) lut->entity.ops = &lut_entity_ops; lut->entity.type = VSP1_ENTITY_LUT; - ret = vsp1_entity_init(vsp1, &lut->entity, "lut", 2, &lut_ops); + ret = vsp1_entity_init(vsp1, &lut->entity, "lut", 2, &lut_ops, + MEDIA_ENT_F_PROC_VIDEO_LUT); if (ret < 0) return ERR_PTR(ret); diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c index 4b397baef88f..47b1714f6163 100644 --- a/drivers/media/platform/vsp1/vsp1_rpf.c +++ b/drivers/media/platform/vsp1/vsp1_rpf.c @@ -237,7 +237,8 @@ struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index) rpf->entity.index = index; sprintf(name, "rpf.%u", index); - ret = vsp1_entity_init(vsp1, &rpf->entity, name, 2, &rpf_ops); + ret = vsp1_entity_init(vsp1, &rpf->entity, name, 2, &rpf_ops, + MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER); if (ret < 0) return ERR_PTR(ret); diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c index 035c26934bc7..e13afd5e4d8b 100644 --- a/drivers/media/platform/vsp1/vsp1_sru.c +++ b/drivers/media/platform/vsp1/vsp1_sru.c @@ -308,7 +308,8 @@ struct vsp1_sru *vsp1_sru_create(struct vsp1_device *vsp1) sru->entity.ops = &sru_entity_ops; sru->entity.type = VSP1_ENTITY_SRU; - ret = vsp1_entity_init(vsp1, &sru->entity, "sru", 2, &sru_ops); + ret = vsp1_entity_init(vsp1, &sru->entity, "sru", 2, &sru_ops, + MEDIA_ENT_F_PROC_VIDEO_SCALER); if (ret < 0) return ERR_PTR(ret); diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c index 5d508e70fdda..f22945101bc8 100644 --- a/drivers/media/platform/vsp1/vsp1_uds.c +++ b/drivers/media/platform/vsp1/vsp1_uds.c @@ -314,7 +314,8 @@ struct vsp1_uds *vsp1_uds_create(struct vsp1_device *vsp1, unsigned int index) uds->entity.index = index; sprintf(name, "uds.%u", index); - ret = vsp1_entity_init(vsp1, &uds->entity, name, 2, &uds_ops); + ret = vsp1_entity_init(vsp1, &uds->entity, name, 2, &uds_ops, + MEDIA_ENT_F_PROC_VIDEO_SCALER); if (ret < 0) return ERR_PTR(ret); diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c index 59bdb450e6f1..70fb979d4f94 100644 --- a/drivers/media/platform/vsp1/vsp1_wpf.c +++ b/drivers/media/platform/vsp1/vsp1_wpf.c @@ -216,7 +216,8 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index) wpf->entity.index = index; sprintf(name, "wpf.%u", index); - ret = vsp1_entity_init(vsp1, &wpf->entity, name, 2, &wpf_ops); + ret = vsp1_entity_init(vsp1, &wpf->entity, name, 2, &wpf_ops, + MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER); if (ret < 0) return ERR_PTR(ret); -- cgit v1.2.3 From 9489a8ff0a13fc0f62e556a31341d3bbaef9da6b Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 13 May 2016 19:17:02 -0300 Subject: [media] v4l: vsp1: dl: Don't free fragments with interrupts disabled Freeing a fragment requires freeing DMA coherent memory, which can be performed with interrupts disabled as per the DMA mapping API contract. The fragments can't thus be freed synchronously when a display list is recycled. Instead, move the fragments to a garbage list and use a work queue to run the garbage collection. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_dl.c | 72 ++++++++++++++++++++++++++++------- 1 file changed, 58 insertions(+), 14 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/vsp1/vsp1_dl.c b/drivers/media/platform/vsp1/vsp1_dl.c index e238d9b9376b..37c3518aa2a8 100644 --- a/drivers/media/platform/vsp1/vsp1_dl.c +++ b/drivers/media/platform/vsp1/vsp1_dl.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "vsp1.h" #include "vsp1_dl.h" @@ -92,11 +93,13 @@ enum vsp1_dl_mode { * @index: index of the related WPF * @mode: display list operation mode (header or headerless) * @vsp1: the VSP1 device - * @lock: protects the active, queued and pending lists + * @lock: protects the free, active, queued, pending and gc_fragments lists * @free: array of all free display lists * @active: list currently being processed (loaded) by hardware * @queued: list queued to the hardware (written to the DL registers) * @pending: list waiting to be queued to the hardware + * @gc_work: fragments garbage collector work struct + * @gc_fragments: array of display list fragments waiting to be freed */ struct vsp1_dl_manager { unsigned int index; @@ -108,6 +111,9 @@ struct vsp1_dl_manager { struct vsp1_dl_list *active; struct vsp1_dl_list *queued; struct vsp1_dl_list *pending; + + struct work_struct gc_work; + struct list_head gc_fragments; }; /* ----------------------------------------------------------------------------- @@ -262,21 +268,10 @@ static struct vsp1_dl_list *vsp1_dl_list_alloc(struct vsp1_dl_manager *dlm) return dl; } -static void vsp1_dl_list_free_fragments(struct vsp1_dl_list *dl) -{ - struct vsp1_dl_body *dlb, *next; - - list_for_each_entry_safe(dlb, next, &dl->fragments, list) { - list_del(&dlb->list); - vsp1_dl_body_cleanup(dlb); - kfree(dlb); - } -} - static void vsp1_dl_list_free(struct vsp1_dl_list *dl) { vsp1_dl_body_cleanup(&dl->body0); - vsp1_dl_list_free_fragments(dl); + list_splice_init(&dl->fragments, &dl->dlm->gc_fragments); kfree(dl); } @@ -311,7 +306,16 @@ static void __vsp1_dl_list_put(struct vsp1_dl_list *dl) if (!dl) return; - vsp1_dl_list_free_fragments(dl); + /* We can't free fragments here as DMA memory can only be freed in + * interruptible context. Move all fragments to the display list + * manager's list of fragments to be freed, they will be + * garbage-collected by the work queue. + */ + if (!list_empty(&dl->fragments)) { + list_splice_init(&dl->fragments, &dl->dlm->gc_fragments); + schedule_work(&dl->dlm->gc_work); + } + dl->body0.num_entries = 0; list_add_tail(&dl->list, &dl->dlm->free); @@ -550,6 +554,40 @@ void vsp1_dlm_reset(struct vsp1_dl_manager *dlm) dlm->pending = NULL; } +/* + * Free all fragments awaiting to be garbage-collected. + * + * This function must be called without the display list manager lock held. + */ +static void vsp1_dlm_fragments_free(struct vsp1_dl_manager *dlm) +{ + unsigned long flags; + + spin_lock_irqsave(&dlm->lock, flags); + + while (!list_empty(&dlm->gc_fragments)) { + struct vsp1_dl_body *dlb; + + dlb = list_first_entry(&dlm->gc_fragments, struct vsp1_dl_body, + list); + list_del(&dlb->list); + + spin_unlock_irqrestore(&dlm->lock, flags); + vsp1_dl_fragment_free(dlb); + spin_lock_irqsave(&dlm->lock, flags); + } + + spin_unlock_irqrestore(&dlm->lock, flags); +} + +static void vsp1_dlm_garbage_collect(struct work_struct *work) +{ + struct vsp1_dl_manager *dlm = + container_of(work, struct vsp1_dl_manager, gc_work); + + vsp1_dlm_fragments_free(dlm); +} + struct vsp1_dl_manager *vsp1_dlm_create(struct vsp1_device *vsp1, unsigned int index, unsigned int prealloc) @@ -568,6 +606,8 @@ struct vsp1_dl_manager *vsp1_dlm_create(struct vsp1_device *vsp1, spin_lock_init(&dlm->lock); INIT_LIST_HEAD(&dlm->free); + INIT_LIST_HEAD(&dlm->gc_fragments); + INIT_WORK(&dlm->gc_work, vsp1_dlm_garbage_collect); for (i = 0; i < prealloc; ++i) { struct vsp1_dl_list *dl; @@ -589,8 +629,12 @@ void vsp1_dlm_destroy(struct vsp1_dl_manager *dlm) if (!dlm) return; + cancel_work_sync(&dlm->gc_work); + list_for_each_entry_safe(dl, next, &dlm->free, list) { list_del(&dl->list); vsp1_dl_list_free(dl); } + + vsp1_dlm_fragments_free(dlm); } -- cgit v1.2.3 From 0220990f63668852c8a2a8f03e3afb422780ef9d Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 13 May 2016 18:15:59 -0300 Subject: [media] v4l: vsp1: lut: Initialize the mutex The LUT mutex isn't initialized when creating the LUT, fix it. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_lut.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/vsp1/vsp1_lut.c b/drivers/media/platform/vsp1/vsp1_lut.c index 855e483acb89..4a4724965de1 100644 --- a/drivers/media/platform/vsp1/vsp1_lut.c +++ b/drivers/media/platform/vsp1/vsp1_lut.c @@ -201,6 +201,8 @@ struct vsp1_lut *vsp1_lut_create(struct vsp1_device *vsp1) if (lut == NULL) return ERR_PTR(-ENOMEM); + mutex_init(&lut->lock); + lut->entity.ops = &lut_entity_ops; lut->entity.type = VSP1_ENTITY_LUT; -- cgit v1.2.3 From 42e89bed23000c0bf985a741422ef943df0ee1e9 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 13 May 2016 13:52:11 -0300 Subject: [media] v4l: vsp1: lut: Expose configuration through a control Replace the custom ioctl with a V4L2 control in order to standardize the API. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_lut.c | 76 +++++++++++++++++++++++----------- drivers/media/platform/vsp1/vsp1_lut.h | 6 +-- include/uapi/linux/vsp1.h | 34 --------------- 3 files changed, 54 insertions(+), 62 deletions(-) delete mode 100644 include/uapi/linux/vsp1.h (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/vsp1/vsp1_lut.c b/drivers/media/platform/vsp1/vsp1_lut.c index 4a4724965de1..db8f01dbab84 100644 --- a/drivers/media/platform/vsp1/vsp1_lut.c +++ b/drivers/media/platform/vsp1/vsp1_lut.c @@ -13,7 +13,6 @@ #include #include -#include #include @@ -35,43 +34,60 @@ static inline void vsp1_lut_write(struct vsp1_lut *lut, struct vsp1_dl_list *dl, } /* ----------------------------------------------------------------------------- - * V4L2 Subdevice Core Operations + * Controls */ -static int lut_set_table(struct vsp1_lut *lut, struct vsp1_lut_config *config) +#define V4L2_CID_VSP1_LUT_TABLE (V4L2_CID_USER_BASE | 0x1001) + +static int lut_set_table(struct vsp1_lut *lut, struct v4l2_ctrl *ctrl) { struct vsp1_dl_body *dlb; unsigned int i; - dlb = vsp1_dl_fragment_alloc(lut->entity.vsp1, ARRAY_SIZE(config->lut)); + dlb = vsp1_dl_fragment_alloc(lut->entity.vsp1, 256); if (!dlb) return -ENOMEM; - for (i = 0; i < ARRAY_SIZE(config->lut); ++i) + for (i = 0; i < 256; ++i) vsp1_dl_fragment_write(dlb, VI6_LUT_TABLE + 4 * i, - config->lut[i]); + ctrl->p_new.p_u32[i]); - mutex_lock(&lut->lock); swap(lut->lut, dlb); - mutex_unlock(&lut->lock); vsp1_dl_fragment_free(dlb); return 0; } -static long lut_ioctl(struct v4l2_subdev *subdev, unsigned int cmd, void *arg) +static int lut_s_ctrl(struct v4l2_ctrl *ctrl) { - struct vsp1_lut *lut = to_lut(subdev); - - switch (cmd) { - case VIDIOC_VSP1_LUT_CONFIG: - return lut_set_table(lut, arg); + struct vsp1_lut *lut = + container_of(ctrl->handler, struct vsp1_lut, ctrls); - default: - return -ENOIOCTLCMD; + switch (ctrl->id) { + case V4L2_CID_VSP1_LUT_TABLE: + lut_set_table(lut, ctrl); + break; } + + return 0; } +static const struct v4l2_ctrl_ops lut_ctrl_ops = { + .s_ctrl = lut_s_ctrl, +}; + +static const struct v4l2_ctrl_config lut_table_control = { + .ops = &lut_ctrl_ops, + .id = V4L2_CID_VSP1_LUT_TABLE, + .name = "Look-Up Table", + .type = V4L2_CTRL_TYPE_U32, + .min = 0x00000000, + .max = 0x00ffffff, + .step = 1, + .def = 0, + .dims = { 256}, +}; + /* ----------------------------------------------------------------------------- * V4L2 Subdevice Pad Operations */ @@ -147,10 +163,6 @@ static int lut_set_format(struct v4l2_subdev *subdev, * V4L2 Subdevice Operations */ -static const struct v4l2_subdev_core_ops lut_core_ops = { - .ioctl = lut_ioctl, -}; - static const struct v4l2_subdev_pad_ops lut_pad_ops = { .init_cfg = vsp1_entity_init_cfg, .enum_mbus_code = lut_enum_mbus_code, @@ -160,7 +172,6 @@ static const struct v4l2_subdev_pad_ops lut_pad_ops = { }; static const struct v4l2_subdev_ops lut_ops = { - .core = &lut_core_ops, .pad = &lut_pad_ops, }; @@ -176,12 +187,14 @@ static void lut_configure(struct vsp1_entity *entity, vsp1_lut_write(lut, dl, VI6_LUT_CTRL, VI6_LUT_CTRL_EN); - mutex_lock(&lut->lock); + mutex_lock(lut->ctrls.lock); + if (lut->lut) { vsp1_dl_list_add_fragment(dl, lut->lut); lut->lut = NULL; } - mutex_unlock(&lut->lock); + + mutex_unlock(lut->ctrls.lock); } static const struct vsp1_entity_operations lut_entity_ops = { @@ -201,8 +214,6 @@ struct vsp1_lut *vsp1_lut_create(struct vsp1_device *vsp1) if (lut == NULL) return ERR_PTR(-ENOMEM); - mutex_init(&lut->lock); - lut->entity.ops = &lut_entity_ops; lut->entity.type = VSP1_ENTITY_LUT; @@ -211,5 +222,20 @@ struct vsp1_lut *vsp1_lut_create(struct vsp1_device *vsp1) if (ret < 0) return ERR_PTR(ret); + /* Initialize the control handler. */ + v4l2_ctrl_handler_init(&lut->ctrls, 1); + v4l2_ctrl_new_custom(&lut->ctrls, &lut_table_control, NULL); + + lut->entity.subdev.ctrl_handler = &lut->ctrls; + + if (lut->ctrls.error) { + dev_err(vsp1->dev, "lut: failed to initialize controls\n"); + ret = lut->ctrls.error; + vsp1_entity_destroy(&lut->entity); + return ERR_PTR(ret); + } + + v4l2_ctrl_handler_setup(&lut->ctrls); + return lut; } diff --git a/drivers/media/platform/vsp1/vsp1_lut.h b/drivers/media/platform/vsp1/vsp1_lut.h index cef874f22b6a..021898fc0ce5 100644 --- a/drivers/media/platform/vsp1/vsp1_lut.h +++ b/drivers/media/platform/vsp1/vsp1_lut.h @@ -13,9 +13,8 @@ #ifndef __VSP1_LUT_H__ #define __VSP1_LUT_H__ -#include - #include +#include #include #include "vsp1_entity.h" @@ -28,7 +27,8 @@ struct vsp1_device; struct vsp1_lut { struct vsp1_entity entity; - struct mutex lock; + struct v4l2_ctrl_handler ctrls; + struct vsp1_dl_body *lut; }; diff --git a/include/uapi/linux/vsp1.h b/include/uapi/linux/vsp1.h deleted file mode 100644 index 9a823696d816..000000000000 --- a/include/uapi/linux/vsp1.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * vsp1.h - * - * Renesas R-Car VSP1 - User-space API - * - * Copyright (C) 2013 Renesas Corporation - * - * Contacts: Laurent Pinchart - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef __VSP1_USER_H__ -#define __VSP1_USER_H__ - -#include -#include - -/* - * Private IOCTLs - * - * VIDIOC_VSP1_LUT_CONFIG - Configure the lookup table - */ - -#define VIDIOC_VSP1_LUT_CONFIG \ - _IOWR('V', BASE_VIDIOC_PRIVATE + 1, struct vsp1_lut_config) - -struct vsp1_lut_config { - __u32 lut[256]; -}; - -#endif /* __VSP1_USER_H__ */ -- cgit v1.2.3 From 1fd87bf2f3a76200fe2b57f5b744b1b341cd7690 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 11 Nov 2015 23:04:44 -0200 Subject: [media] v4l: vsp1: Add Cubic Look Up Table (CLU) support The CLU processing block is a 2D/3D lookup table that converts the input three color component data into desired three color components using a lookup table. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/Makefile | 3 +- drivers/media/platform/vsp1/vsp1.h | 3 + drivers/media/platform/vsp1/vsp1_clu.c | 278 ++++++++++++++++++++++++++++++ drivers/media/platform/vsp1/vsp1_clu.h | 44 +++++ drivers/media/platform/vsp1/vsp1_drv.c | 21 ++- drivers/media/platform/vsp1/vsp1_entity.c | 1 + drivers/media/platform/vsp1/vsp1_entity.h | 1 + drivers/media/platform/vsp1/vsp1_regs.h | 9 + 8 files changed, 355 insertions(+), 5 deletions(-) create mode 100644 drivers/media/platform/vsp1/vsp1_clu.c create mode 100644 drivers/media/platform/vsp1/vsp1_clu.h (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/vsp1/Makefile b/drivers/media/platform/vsp1/Makefile index 95b3ac2ea7ef..1328e1bd2143 100644 --- a/drivers/media/platform/vsp1/Makefile +++ b/drivers/media/platform/vsp1/Makefile @@ -1,7 +1,8 @@ vsp1-y := vsp1_drv.o vsp1_entity.o vsp1_pipe.o vsp1-y += vsp1_dl.o vsp1_drm.o vsp1_video.o vsp1-y += vsp1_rpf.o vsp1_rwpf.o vsp1_wpf.o -vsp1-y += vsp1_hsit.o vsp1_lif.o vsp1_lut.o +vsp1-y += vsp1_clu.o vsp1_hsit.o vsp1_lut.o vsp1-y += vsp1_bru.o vsp1_sru.o vsp1_uds.o +vsp1-y += vsp1_lif.o obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1.o diff --git a/drivers/media/platform/vsp1/vsp1.h b/drivers/media/platform/vsp1/vsp1.h index 7cb0f5e428df..8713a437076d 100644 --- a/drivers/media/platform/vsp1/vsp1.h +++ b/drivers/media/platform/vsp1/vsp1.h @@ -31,6 +31,7 @@ struct vsp1_drm; struct vsp1_entity; struct vsp1_platform_data; struct vsp1_bru; +struct vsp1_clu; struct vsp1_hsit; struct vsp1_lif; struct vsp1_lut; @@ -46,6 +47,7 @@ struct vsp1_uds; #define VSP1_HAS_LUT (1 << 1) #define VSP1_HAS_SRU (1 << 2) #define VSP1_HAS_BRU (1 << 3) +#define VSP1_HAS_CLU (1 << 4) struct vsp1_device_info { u32 version; @@ -66,6 +68,7 @@ struct vsp1_device { struct rcar_fcp_device *fcp; struct vsp1_bru *bru; + struct vsp1_clu *clu; struct vsp1_hsit *hsi; struct vsp1_hsit *hst; struct vsp1_lif *lif; diff --git a/drivers/media/platform/vsp1/vsp1_clu.c b/drivers/media/platform/vsp1/vsp1_clu.c new file mode 100644 index 000000000000..cea86e77f7f1 --- /dev/null +++ b/drivers/media/platform/vsp1/vsp1_clu.c @@ -0,0 +1,278 @@ +/* + * vsp1_clu.c -- R-Car VSP1 Cubic Look-Up Table + * + * Copyright (C) 2015-2016 Renesas Electronics Corporation + * + * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include + +#include + +#include "vsp1.h" +#include "vsp1_clu.h" +#include "vsp1_dl.h" + +#define CLU_MIN_SIZE 4U +#define CLU_MAX_SIZE 8190U + +/* ----------------------------------------------------------------------------- + * Device Access + */ + +static inline void vsp1_clu_write(struct vsp1_clu *clu, struct vsp1_dl_list *dl, + u32 reg, u32 data) +{ + vsp1_dl_list_write(dl, reg, data); +} + +/* ----------------------------------------------------------------------------- + * Controls + */ + +#define V4L2_CID_VSP1_CLU_TABLE (V4L2_CID_USER_BASE | 0x1001) +#define V4L2_CID_VSP1_CLU_MODE (V4L2_CID_USER_BASE | 0x1002) +#define V4L2_CID_VSP1_CLU_MODE_2D 0 +#define V4L2_CID_VSP1_CLU_MODE_3D 1 + +static int clu_set_table(struct vsp1_clu *clu, struct v4l2_ctrl *ctrl) +{ + struct vsp1_dl_body *dlb; + unsigned int i; + + dlb = vsp1_dl_fragment_alloc(clu->entity.vsp1, 1 + 17 * 17 * 17); + if (!dlb) + return -ENOMEM; + + vsp1_dl_fragment_write(dlb, VI6_CLU_ADDR, 0); + for (i = 0; i < 17 * 17 * 17; ++i) + vsp1_dl_fragment_write(dlb, VI6_CLU_DATA, ctrl->p_new.p_u32[i]); + + swap(clu->clu, dlb); + + vsp1_dl_fragment_free(dlb); + return 0; +} + +static int clu_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vsp1_clu *clu = + container_of(ctrl->handler, struct vsp1_clu, ctrls); + + switch (ctrl->id) { + case V4L2_CID_VSP1_CLU_TABLE: + clu_set_table(clu, ctrl); + break; + + case V4L2_CID_VSP1_CLU_MODE: + clu->mode = ctrl->val; + break; + } + + return 0; +} + +static const struct v4l2_ctrl_ops clu_ctrl_ops = { + .s_ctrl = clu_s_ctrl, +}; + +static const struct v4l2_ctrl_config clu_table_control = { + .ops = &clu_ctrl_ops, + .id = V4L2_CID_VSP1_CLU_TABLE, + .name = "Look-Up Table", + .type = V4L2_CTRL_TYPE_U32, + .min = 0x00000000, + .max = 0x00ffffff, + .step = 1, + .def = 0, + .dims = { 17, 17, 17 }, +}; + +static const char * const clu_mode_menu[] = { + "2D", + "3D", + NULL, +}; + +static const struct v4l2_ctrl_config clu_mode_control = { + .ops = &clu_ctrl_ops, + .id = V4L2_CID_VSP1_CLU_MODE, + .name = "Mode", + .type = V4L2_CTRL_TYPE_MENU, + .min = 0, + .max = 1, + .def = 1, + .qmenu = clu_mode_menu, +}; + +/* ----------------------------------------------------------------------------- + * V4L2 Subdevice Pad Operations + */ + +static int clu_enum_mbus_code(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + static const unsigned int codes[] = { + MEDIA_BUS_FMT_ARGB8888_1X32, + MEDIA_BUS_FMT_AHSV8888_1X32, + MEDIA_BUS_FMT_AYUV8_1X32, + }; + + return vsp1_subdev_enum_mbus_code(subdev, cfg, code, codes, + ARRAY_SIZE(codes)); +} + +static int clu_enum_frame_size(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + return vsp1_subdev_enum_frame_size(subdev, cfg, fse, CLU_MIN_SIZE, + CLU_MIN_SIZE, CLU_MAX_SIZE, + CLU_MAX_SIZE); +} + +static int clu_set_format(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct vsp1_clu *clu = to_clu(subdev); + struct v4l2_subdev_pad_config *config; + struct v4l2_mbus_framefmt *format; + + config = vsp1_entity_get_pad_config(&clu->entity, cfg, fmt->which); + if (!config) + return -EINVAL; + + /* Default to YUV if the requested format is not supported. */ + if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 && + fmt->format.code != MEDIA_BUS_FMT_AHSV8888_1X32 && + fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32) + fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32; + + format = vsp1_entity_get_pad_format(&clu->entity, config, fmt->pad); + + if (fmt->pad == CLU_PAD_SOURCE) { + /* The CLU output format can't be modified. */ + fmt->format = *format; + return 0; + } + + format->code = fmt->format.code; + format->width = clamp_t(unsigned int, fmt->format.width, + CLU_MIN_SIZE, CLU_MAX_SIZE); + format->height = clamp_t(unsigned int, fmt->format.height, + CLU_MIN_SIZE, CLU_MAX_SIZE); + format->field = V4L2_FIELD_NONE; + format->colorspace = V4L2_COLORSPACE_SRGB; + + fmt->format = *format; + + /* Propagate the format to the source pad. */ + format = vsp1_entity_get_pad_format(&clu->entity, config, + CLU_PAD_SOURCE); + *format = fmt->format; + + return 0; +} + +/* ----------------------------------------------------------------------------- + * V4L2 Subdevice Operations + */ + +static const struct v4l2_subdev_pad_ops clu_pad_ops = { + .init_cfg = vsp1_entity_init_cfg, + .enum_mbus_code = clu_enum_mbus_code, + .enum_frame_size = clu_enum_frame_size, + .get_fmt = vsp1_subdev_get_pad_format, + .set_fmt = clu_set_format, +}; + +static const struct v4l2_subdev_ops clu_ops = { + .pad = &clu_pad_ops, +}; + +/* ----------------------------------------------------------------------------- + * VSP1 Entity Operations + */ + +static void clu_configure(struct vsp1_entity *entity, + struct vsp1_pipeline *pipe, + struct vsp1_dl_list *dl) +{ + struct vsp1_clu *clu = to_clu(&entity->subdev); + struct v4l2_mbus_framefmt *format; + u32 ctrl = VI6_CLU_CTRL_AAI | VI6_CLU_CTRL_MVS | VI6_CLU_CTRL_EN; + + format = vsp1_entity_get_pad_format(&clu->entity, clu->entity.config, + CLU_PAD_SINK); + + mutex_lock(clu->ctrls.lock); + + /* 2D mode can only be used with the YCbCr pixel encoding. */ + if (clu->mode == V4L2_CID_VSP1_CLU_MODE_2D && + format->code == MEDIA_BUS_FMT_AYUV8_1X32) + ctrl |= VI6_CLU_CTRL_AX1I_2D | VI6_CLU_CTRL_AX2I_2D + | VI6_CLU_CTRL_OS0_2D | VI6_CLU_CTRL_OS1_2D + | VI6_CLU_CTRL_OS2_2D | VI6_CLU_CTRL_M2D; + + if (clu->clu) { + vsp1_dl_list_add_fragment(dl, clu->clu); + clu->clu = NULL; + } + + mutex_unlock(clu->ctrls.lock); + + vsp1_clu_write(clu, dl, VI6_CLU_CTRL, ctrl); +} + +static const struct vsp1_entity_operations clu_entity_ops = { + .configure = clu_configure, +}; + +/* ----------------------------------------------------------------------------- + * Initialization and Cleanup + */ + +struct vsp1_clu *vsp1_clu_create(struct vsp1_device *vsp1) +{ + struct vsp1_clu *clu; + int ret; + + clu = devm_kzalloc(vsp1->dev, sizeof(*clu), GFP_KERNEL); + if (clu == NULL) + return ERR_PTR(-ENOMEM); + + clu->entity.ops = &clu_entity_ops; + clu->entity.type = VSP1_ENTITY_CLU; + + ret = vsp1_entity_init(vsp1, &clu->entity, "clu", 2, &clu_ops, + MEDIA_ENT_F_PROC_VIDEO_LUT); + if (ret < 0) + return ERR_PTR(ret); + + /* Initialize the control handler. */ + v4l2_ctrl_handler_init(&clu->ctrls, 2); + v4l2_ctrl_new_custom(&clu->ctrls, &clu_table_control, NULL); + v4l2_ctrl_new_custom(&clu->ctrls, &clu_mode_control, NULL); + + clu->entity.subdev.ctrl_handler = &clu->ctrls; + + if (clu->ctrls.error) { + dev_err(vsp1->dev, "clu: failed to initialize controls\n"); + ret = clu->ctrls.error; + vsp1_entity_destroy(&clu->entity); + return ERR_PTR(ret); + } + + v4l2_ctrl_handler_setup(&clu->ctrls); + + return clu; +} diff --git a/drivers/media/platform/vsp1/vsp1_clu.h b/drivers/media/platform/vsp1/vsp1_clu.h new file mode 100644 index 000000000000..33a69029c719 --- /dev/null +++ b/drivers/media/platform/vsp1/vsp1_clu.h @@ -0,0 +1,44 @@ +/* + * vsp1_clu.h -- R-Car VSP1 Cubic Look-Up Table + * + * Copyright (C) 2015 Renesas Corporation + * + * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ +#ifndef __VSP1_CLU_H__ +#define __VSP1_CLU_H__ + +#include +#include +#include + +#include "vsp1_entity.h" + +struct vsp1_device; +struct vsp1_dl_body; + +#define CLU_PAD_SINK 0 +#define CLU_PAD_SOURCE 1 + +struct vsp1_clu { + struct vsp1_entity entity; + + struct v4l2_ctrl_handler ctrls; + + unsigned int mode; + struct vsp1_dl_body *clu; +}; + +static inline struct vsp1_clu *to_clu(struct v4l2_subdev *subdev) +{ + return container_of(subdev, struct vsp1_clu, entity.subdev); +} + +struct vsp1_clu *vsp1_clu_create(struct vsp1_device *vsp1); + +#endif /* __VSP1_CLU_H__ */ diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c index 0b0e73685a24..769b19edb146 100644 --- a/drivers/media/platform/vsp1/vsp1_drv.c +++ b/drivers/media/platform/vsp1/vsp1_drv.c @@ -27,6 +27,7 @@ #include "vsp1.h" #include "vsp1_bru.h" +#include "vsp1_clu.h" #include "vsp1_dl.h" #include "vsp1_drm.h" #include "vsp1_hsit.h" @@ -251,6 +252,16 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) list_add_tail(&vsp1->bru->entity.list_dev, &vsp1->entities); } + if (vsp1->info->features & VSP1_HAS_CLU) { + vsp1->clu = vsp1_clu_create(vsp1); + if (IS_ERR(vsp1->clu)) { + ret = PTR_ERR(vsp1->clu); + goto done; + } + + list_add_tail(&vsp1->clu->entity.list_dev, &vsp1->entities); + } + vsp1->hsi = vsp1_hsit_create(vsp1, true); if (IS_ERR(vsp1->hsi)) { ret = PTR_ERR(vsp1->hsi); @@ -551,7 +562,8 @@ static const struct vsp1_device_info vsp1_device_infos[] = { { .version = VI6_IP_VERSION_MODEL_VSPS_H2, .gen = 2, - .features = VSP1_HAS_BRU | VSP1_HAS_LUT | VSP1_HAS_SRU, + .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT + | VSP1_HAS_SRU, .rpf_count = 5, .uds_count = 3, .wpf_count = 4, @@ -578,7 +590,8 @@ static const struct vsp1_device_info vsp1_device_infos[] = { }, { .version = VI6_IP_VERSION_MODEL_VSPS_M2, .gen = 2, - .features = VSP1_HAS_BRU | VSP1_HAS_LUT | VSP1_HAS_SRU, + .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT + | VSP1_HAS_SRU, .rpf_count = 5, .uds_count = 1, .wpf_count = 4, @@ -587,7 +600,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = { }, { .version = VI6_IP_VERSION_MODEL_VSPI_GEN3, .gen = 3, - .features = VSP1_HAS_LUT | VSP1_HAS_SRU, + .features = VSP1_HAS_CLU | VSP1_HAS_LUT | VSP1_HAS_SRU, .rpf_count = 1, .uds_count = 1, .wpf_count = 1, @@ -603,7 +616,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = { }, { .version = VI6_IP_VERSION_MODEL_VSPBC_GEN3, .gen = 3, - .features = VSP1_HAS_BRU | VSP1_HAS_LUT, + .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT, .rpf_count = 5, .wpf_count = 1, .num_bru_inputs = 5, diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c index d72dbcce4b11..4cf6cc719c00 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.c +++ b/drivers/media/platform/vsp1/vsp1_entity.c @@ -319,6 +319,7 @@ static const struct vsp1_route vsp1_routes[] = { { VI6_DPR_NODE_BRU_IN(0), VI6_DPR_NODE_BRU_IN(1), VI6_DPR_NODE_BRU_IN(2), VI6_DPR_NODE_BRU_IN(3), VI6_DPR_NODE_BRU_IN(4) }, VI6_DPR_NODE_BRU_OUT }, + VSP1_ENTITY_ROUTE(CLU), VSP1_ENTITY_ROUTE(HSI), VSP1_ENTITY_ROUTE(HST), { VSP1_ENTITY_LIF, 0, 0, { VI6_DPR_NODE_LIF, }, VI6_DPR_NODE_LIF }, diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h index bcdea4ee73c5..f289ed237c8d 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.h +++ b/drivers/media/platform/vsp1/vsp1_entity.h @@ -24,6 +24,7 @@ struct vsp1_pipeline; enum vsp1_entity_type { VSP1_ENTITY_BRU, + VSP1_ENTITY_CLU, VSP1_ENTITY_HSI, VSP1_ENTITY_HST, VSP1_ENTITY_LIF, diff --git a/drivers/media/platform/vsp1/vsp1_regs.h b/drivers/media/platform/vsp1/vsp1_regs.h index 7657545a75ed..dea0bc471108 100644 --- a/drivers/media/platform/vsp1/vsp1_regs.h +++ b/drivers/media/platform/vsp1/vsp1_regs.h @@ -444,6 +444,15 @@ */ #define VI6_CLU_CTRL 0x2900 +#define VI6_CLU_CTRL_AAI (1 << 28) +#define VI6_CLU_CTRL_MVS (1 << 24) +#define VI6_CLU_CTRL_AX1I_2D (3 << 14) +#define VI6_CLU_CTRL_AX2I_2D (1 << 12) +#define VI6_CLU_CTRL_OS0_2D (3 << 8) +#define VI6_CLU_CTRL_OS1_2D (1 << 6) +#define VI6_CLU_CTRL_OS2_2D (3 << 4) +#define VI6_CLU_CTRL_M2D (1 << 1) +#define VI6_CLU_CTRL_EN (1 << 0) /* ----------------------------------------------------------------------------- * HST Control Registers -- cgit v1.2.3 From fc845e520baf00af12f6c39708c5e9e9a6eec661 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 11 Jun 2016 04:07:56 -0300 Subject: [media] v4l: vsp1: Support runtime modification of controls Controls are applied to the hardware in the configure operation of the VSP entities, which is only called when starting the video stream. To enable runtime modification of controls we need to call the configure operations for every frame. Doing so is currently not safe, as most parameters shouldn't be modified during streaming. Furthermore the configure operation can sleep, preventing it from being called from the frame completion interrupt handler for the next frame. Fix this by adding an argument to the configure operation to tell entities whether to perform a full configuration (as done now) or a partial runtime configuration. In the latter case the operation will only configure the subset of parameters related to runtime-configurable controls, and won't be allowed to sleep when doing so. Because partial reconfiguration can depend on parameters computed when performing a full configuration, the core guarantees that the configure operation will always be called with full and partial modes in that order at stream start. Entities thus don't have to duplicate configuration steps in the full and partial code paths. This change affects the VSP driver core only, all entities return immediately from the configure operation when called for a partial runtime configuration. Entities will be modified one by one in further commits. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_bru.c | 5 ++++- drivers/media/platform/vsp1/vsp1_clu.c | 5 ++++- drivers/media/platform/vsp1/vsp1_drm.c | 6 ++++-- drivers/media/platform/vsp1/vsp1_entity.h | 2 +- drivers/media/platform/vsp1/vsp1_hsit.c | 5 ++++- drivers/media/platform/vsp1/vsp1_lif.c | 5 ++++- drivers/media/platform/vsp1/vsp1_lut.c | 5 ++++- drivers/media/platform/vsp1/vsp1_rpf.c | 5 ++++- drivers/media/platform/vsp1/vsp1_sru.c | 5 ++++- drivers/media/platform/vsp1/vsp1_uds.c | 5 ++++- drivers/media/platform/vsp1/vsp1_video.c | 8 +++++++- drivers/media/platform/vsp1/vsp1_wpf.c | 5 ++++- 12 files changed, 48 insertions(+), 13 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c index cae911726778..8268b87727a7 100644 --- a/drivers/media/platform/vsp1/vsp1_bru.c +++ b/drivers/media/platform/vsp1/vsp1_bru.c @@ -269,13 +269,16 @@ static const struct v4l2_subdev_ops bru_ops = { static void bru_configure(struct vsp1_entity *entity, struct vsp1_pipeline *pipe, - struct vsp1_dl_list *dl) + struct vsp1_dl_list *dl, bool full) { struct vsp1_bru *bru = to_bru(&entity->subdev); struct v4l2_mbus_framefmt *format; unsigned int flags; unsigned int i; + if (!full) + return; + format = vsp1_entity_get_pad_format(&bru->entity, bru->entity.config, bru->entity.source_pad); diff --git a/drivers/media/platform/vsp1/vsp1_clu.c b/drivers/media/platform/vsp1/vsp1_clu.c index cea86e77f7f1..dd0cf20bcdda 100644 --- a/drivers/media/platform/vsp1/vsp1_clu.c +++ b/drivers/media/platform/vsp1/vsp1_clu.c @@ -205,12 +205,15 @@ static const struct v4l2_subdev_ops clu_ops = { static void clu_configure(struct vsp1_entity *entity, struct vsp1_pipeline *pipe, - struct vsp1_dl_list *dl) + struct vsp1_dl_list *dl, bool full) { struct vsp1_clu *clu = to_clu(&entity->subdev); struct v4l2_mbus_framefmt *format; u32 ctrl = VI6_CLU_CTRL_AAI | VI6_CLU_CTRL_MVS | VI6_CLU_CTRL_EN; + if (!full) + return; + format = vsp1_entity_get_pad_format(&clu->entity, clu->entity.config, CLU_PAD_SINK); diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c index 14730119687f..fe9665e57b3b 100644 --- a/drivers/media/platform/vsp1/vsp1_drm.c +++ b/drivers/media/platform/vsp1/vsp1_drm.c @@ -491,8 +491,10 @@ void vsp1_du_atomic_flush(struct device *dev) vsp1_entity_route_setup(entity, pipe->dl); - if (entity->ops->configure) - entity->ops->configure(entity, pipe, pipe->dl); + if (entity->ops->configure) { + entity->ops->configure(entity, pipe, pipe->dl, true); + entity->ops->configure(entity, pipe, pipe->dl, false); + } /* The memory buffer address must be applied after configuring * the RPF to make sure the crop offset are computed. diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h index f289ed237c8d..b43457fd2c43 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.h +++ b/drivers/media/platform/vsp1/vsp1_entity.h @@ -73,7 +73,7 @@ struct vsp1_entity_operations { void (*destroy)(struct vsp1_entity *); void (*set_memory)(struct vsp1_entity *, struct vsp1_dl_list *dl); void (*configure)(struct vsp1_entity *, struct vsp1_pipeline *, - struct vsp1_dl_list *); + struct vsp1_dl_list *, bool); }; struct vsp1_entity { diff --git a/drivers/media/platform/vsp1/vsp1_hsit.c b/drivers/media/platform/vsp1/vsp1_hsit.c index ab3cae307ba5..6e5077beb38c 100644 --- a/drivers/media/platform/vsp1/vsp1_hsit.c +++ b/drivers/media/platform/vsp1/vsp1_hsit.c @@ -125,10 +125,13 @@ static const struct v4l2_subdev_ops hsit_ops = { static void hsit_configure(struct vsp1_entity *entity, struct vsp1_pipeline *pipe, - struct vsp1_dl_list *dl) + struct vsp1_dl_list *dl, bool full) { struct vsp1_hsit *hsit = to_hsit(&entity->subdev); + if (!full) + return; + if (hsit->inverse) vsp1_hsit_write(hsit, dl, VI6_HSI_CTRL, VI6_HSI_CTRL_EN); else diff --git a/drivers/media/platform/vsp1/vsp1_lif.c b/drivers/media/platform/vsp1/vsp1_lif.c index e006f0df3ce9..a720063f38c5 100644 --- a/drivers/media/platform/vsp1/vsp1_lif.c +++ b/drivers/media/platform/vsp1/vsp1_lif.c @@ -122,7 +122,7 @@ static const struct v4l2_subdev_ops lif_ops = { static void lif_configure(struct vsp1_entity *entity, struct vsp1_pipeline *pipe, - struct vsp1_dl_list *dl) + struct vsp1_dl_list *dl, bool full) { const struct v4l2_mbus_framefmt *format; struct vsp1_lif *lif = to_lif(&entity->subdev); @@ -130,6 +130,9 @@ static void lif_configure(struct vsp1_entity *entity, unsigned int obth = 400; unsigned int lbth = 200; + if (!full) + return; + format = vsp1_entity_get_pad_format(&lif->entity, lif->entity.config, LIF_PAD_SOURCE); diff --git a/drivers/media/platform/vsp1/vsp1_lut.c b/drivers/media/platform/vsp1/vsp1_lut.c index db8f01dbab84..9619b9a43be4 100644 --- a/drivers/media/platform/vsp1/vsp1_lut.c +++ b/drivers/media/platform/vsp1/vsp1_lut.c @@ -181,10 +181,13 @@ static const struct v4l2_subdev_ops lut_ops = { static void lut_configure(struct vsp1_entity *entity, struct vsp1_pipeline *pipe, - struct vsp1_dl_list *dl) + struct vsp1_dl_list *dl, bool full) { struct vsp1_lut *lut = to_lut(&entity->subdev); + if (!full) + return; + vsp1_lut_write(lut, dl, VI6_LUT_CTRL, VI6_LUT_CTRL_EN); mutex_lock(lut->ctrls.lock); diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c index 47b1714f6163..390040a22b0c 100644 --- a/drivers/media/platform/vsp1/vsp1_rpf.c +++ b/drivers/media/platform/vsp1/vsp1_rpf.c @@ -60,7 +60,7 @@ static void rpf_set_memory(struct vsp1_entity *entity, struct vsp1_dl_list *dl) static void rpf_configure(struct vsp1_entity *entity, struct vsp1_pipeline *pipe, - struct vsp1_dl_list *dl) + struct vsp1_dl_list *dl, bool full) { struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev); const struct vsp1_format_info *fmtinfo = rpf->fmtinfo; @@ -73,6 +73,9 @@ static void rpf_configure(struct vsp1_entity *entity, u32 pstride; u32 infmt; + if (!full) + return; + /* Source size, stride and crop offsets. * * The crop offsets correspond to the location of the crop rectangle top diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c index e13afd5e4d8b..47f5e0cea2ce 100644 --- a/drivers/media/platform/vsp1/vsp1_sru.c +++ b/drivers/media/platform/vsp1/vsp1_sru.c @@ -257,7 +257,7 @@ static const struct v4l2_subdev_ops sru_ops = { static void sru_configure(struct vsp1_entity *entity, struct vsp1_pipeline *pipe, - struct vsp1_dl_list *dl) + struct vsp1_dl_list *dl, bool full) { const struct vsp1_sru_param *param; struct vsp1_sru *sru = to_sru(&entity->subdev); @@ -265,6 +265,9 @@ static void sru_configure(struct vsp1_entity *entity, struct v4l2_mbus_framefmt *output; u32 ctrl0; + if (!full) + return; + input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config, SRU_PAD_SINK); output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config, diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c index f22945101bc8..5d5720f2e5fe 100644 --- a/drivers/media/platform/vsp1/vsp1_uds.c +++ b/drivers/media/platform/vsp1/vsp1_uds.c @@ -244,7 +244,7 @@ static const struct v4l2_subdev_ops uds_ops = { static void uds_configure(struct vsp1_entity *entity, struct vsp1_pipeline *pipe, - struct vsp1_dl_list *dl) + struct vsp1_dl_list *dl, bool full) { struct vsp1_uds *uds = to_uds(&entity->subdev); const struct v4l2_mbus_framefmt *output; @@ -253,6 +253,9 @@ static void uds_configure(struct vsp1_entity *entity, unsigned int vscale; bool multitap; + if (!full) + return; + input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config, UDS_PAD_SINK); output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config, diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c index f6208b9d8118..01654232b695 100644 --- a/drivers/media/platform/vsp1/vsp1_video.c +++ b/drivers/media/platform/vsp1/vsp1_video.c @@ -251,11 +251,17 @@ static void vsp1_video_frame_end(struct vsp1_pipeline *pipe, static void vsp1_video_pipeline_run(struct vsp1_pipeline *pipe) { struct vsp1_device *vsp1 = pipe->output->entity.vsp1; + struct vsp1_entity *entity; unsigned int i; if (!pipe->dl) pipe->dl = vsp1_dl_list_get(pipe->output->dlm); + list_for_each_entry(entity, &pipe->entities, list_pipe) { + if (entity->ops->configure) + entity->ops->configure(entity, pipe, pipe->dl, false); + } + for (i = 0; i < vsp1->info->rpf_count; ++i) { struct vsp1_rwpf *rwpf = pipe->inputs[i]; @@ -632,7 +638,7 @@ static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe) vsp1_entity_route_setup(entity, pipe->dl); if (entity->ops->configure) - entity->ops->configure(entity, pipe, pipe->dl); + entity->ops->configure(entity, pipe, pipe->dl, true); } return 0; diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c index 70fb979d4f94..474feac67155 100644 --- a/drivers/media/platform/vsp1/vsp1_wpf.c +++ b/drivers/media/platform/vsp1/vsp1_wpf.c @@ -93,7 +93,7 @@ static void wpf_set_memory(struct vsp1_entity *entity, struct vsp1_dl_list *dl) static void wpf_configure(struct vsp1_entity *entity, struct vsp1_pipeline *pipe, - struct vsp1_dl_list *dl) + struct vsp1_dl_list *dl, bool full) { struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev); struct vsp1_device *vsp1 = wpf->entity.vsp1; @@ -104,6 +104,9 @@ static void wpf_configure(struct vsp1_entity *entity, u32 outfmt = 0; u32 srcrpf = 0; + if (!full) + return; + /* Cropping */ crop = vsp1_rwpf_get_crop(wpf, wpf->entity.config); -- cgit v1.2.3 From f4e37fb73f3037a4a4da976c7d5b28c221fe8a1a Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 11 Jun 2016 04:11:27 -0300 Subject: [media] v4l: vsp1: lut: Support runtime modification of controls Allow reconfiguration of the look-up table at runtime. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_lut.c | 25 +++++++++++++++---------- drivers/media/platform/vsp1/vsp1_lut.h | 3 +++ 2 files changed, 18 insertions(+), 10 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/vsp1/vsp1_lut.c b/drivers/media/platform/vsp1/vsp1_lut.c index 9619b9a43be4..dc31de9602ba 100644 --- a/drivers/media/platform/vsp1/vsp1_lut.c +++ b/drivers/media/platform/vsp1/vsp1_lut.c @@ -52,7 +52,9 @@ static int lut_set_table(struct vsp1_lut *lut, struct v4l2_ctrl *ctrl) vsp1_dl_fragment_write(dlb, VI6_LUT_TABLE + 4 * i, ctrl->p_new.p_u32[i]); + spin_lock_irq(&lut->lock); swap(lut->lut, dlb); + spin_unlock_irq(&lut->lock); vsp1_dl_fragment_free(dlb); return 0; @@ -184,20 +186,21 @@ static void lut_configure(struct vsp1_entity *entity, struct vsp1_dl_list *dl, bool full) { struct vsp1_lut *lut = to_lut(&entity->subdev); + struct vsp1_dl_body *dlb; + unsigned long flags; - if (!full) + if (full) { + vsp1_lut_write(lut, dl, VI6_LUT_CTRL, VI6_LUT_CTRL_EN); return; - - vsp1_lut_write(lut, dl, VI6_LUT_CTRL, VI6_LUT_CTRL_EN); - - mutex_lock(lut->ctrls.lock); - - if (lut->lut) { - vsp1_dl_list_add_fragment(dl, lut->lut); - lut->lut = NULL; } - mutex_unlock(lut->ctrls.lock); + spin_lock_irqsave(&lut->lock, flags); + dlb = lut->lut; + lut->lut = NULL; + spin_unlock_irqrestore(&lut->lock, flags); + + if (dlb) + vsp1_dl_list_add_fragment(dl, dlb); } static const struct vsp1_entity_operations lut_entity_ops = { @@ -217,6 +220,8 @@ struct vsp1_lut *vsp1_lut_create(struct vsp1_device *vsp1) if (lut == NULL) return ERR_PTR(-ENOMEM); + spin_lock_init(&lut->lock); + lut->entity.ops = &lut_entity_ops; lut->entity.type = VSP1_ENTITY_LUT; diff --git a/drivers/media/platform/vsp1/vsp1_lut.h b/drivers/media/platform/vsp1/vsp1_lut.h index 021898fc0ce5..f8c4e8f0a79d 100644 --- a/drivers/media/platform/vsp1/vsp1_lut.h +++ b/drivers/media/platform/vsp1/vsp1_lut.h @@ -13,6 +13,8 @@ #ifndef __VSP1_LUT_H__ #define __VSP1_LUT_H__ +#include + #include #include #include @@ -29,6 +31,7 @@ struct vsp1_lut { struct v4l2_ctrl_handler ctrls; + spinlock_t lock; struct vsp1_dl_body *lut; }; -- cgit v1.2.3 From 20fab5e086aa141df5a94fd61706b18dfaadd090 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 11 Jun 2016 04:11:27 -0300 Subject: [media] v4l: vsp1: clu: Support runtime modification of controls Allow reconfiguration of the look-up table and processing mode at runtime. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_clu.c | 41 +++++++++++++++++++++------------- drivers/media/platform/vsp1/vsp1_clu.h | 4 ++++ 2 files changed, 30 insertions(+), 15 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/vsp1/vsp1_clu.c b/drivers/media/platform/vsp1/vsp1_clu.c index dd0cf20bcdda..b63d2dbe5ea3 100644 --- a/drivers/media/platform/vsp1/vsp1_clu.c +++ b/drivers/media/platform/vsp1/vsp1_clu.c @@ -55,7 +55,9 @@ static int clu_set_table(struct vsp1_clu *clu, struct v4l2_ctrl *ctrl) for (i = 0; i < 17 * 17 * 17; ++i) vsp1_dl_fragment_write(dlb, VI6_CLU_DATA, ctrl->p_new.p_u32[i]); + spin_lock_irq(&clu->lock); swap(clu->clu, dlb); + spin_unlock_irq(&clu->lock); vsp1_dl_fragment_free(dlb); return 0; @@ -208,32 +210,39 @@ static void clu_configure(struct vsp1_entity *entity, struct vsp1_dl_list *dl, bool full) { struct vsp1_clu *clu = to_clu(&entity->subdev); - struct v4l2_mbus_framefmt *format; + struct vsp1_dl_body *dlb; + unsigned long flags; u32 ctrl = VI6_CLU_CTRL_AAI | VI6_CLU_CTRL_MVS | VI6_CLU_CTRL_EN; - if (!full) + /* The format can't be changed during streaming, only verify it at + * stream start and store the information internally for future partial + * reconfiguration calls. + */ + if (full) { + struct v4l2_mbus_framefmt *format; + + format = vsp1_entity_get_pad_format(&clu->entity, + clu->entity.config, + CLU_PAD_SINK); + clu->yuv_mode = format->code == MEDIA_BUS_FMT_AYUV8_1X32; return; - - format = vsp1_entity_get_pad_format(&clu->entity, clu->entity.config, - CLU_PAD_SINK); - - mutex_lock(clu->ctrls.lock); + } /* 2D mode can only be used with the YCbCr pixel encoding. */ - if (clu->mode == V4L2_CID_VSP1_CLU_MODE_2D && - format->code == MEDIA_BUS_FMT_AYUV8_1X32) + if (clu->mode == V4L2_CID_VSP1_CLU_MODE_2D && clu->yuv_mode) ctrl |= VI6_CLU_CTRL_AX1I_2D | VI6_CLU_CTRL_AX2I_2D | VI6_CLU_CTRL_OS0_2D | VI6_CLU_CTRL_OS1_2D | VI6_CLU_CTRL_OS2_2D | VI6_CLU_CTRL_M2D; - if (clu->clu) { - vsp1_dl_list_add_fragment(dl, clu->clu); - clu->clu = NULL; - } + vsp1_clu_write(clu, dl, VI6_CLU_CTRL, ctrl); - mutex_unlock(clu->ctrls.lock); + spin_lock_irqsave(&clu->lock, flags); + dlb = clu->clu; + clu->clu = NULL; + spin_unlock_irqrestore(&clu->lock, flags); - vsp1_clu_write(clu, dl, VI6_CLU_CTRL, ctrl); + if (dlb) + vsp1_dl_list_add_fragment(dl, dlb); } static const struct vsp1_entity_operations clu_entity_ops = { @@ -253,6 +262,8 @@ struct vsp1_clu *vsp1_clu_create(struct vsp1_device *vsp1) if (clu == NULL) return ERR_PTR(-ENOMEM); + spin_lock_init(&clu->lock); + clu->entity.ops = &clu_entity_ops; clu->entity.type = VSP1_ENTITY_CLU; diff --git a/drivers/media/platform/vsp1/vsp1_clu.h b/drivers/media/platform/vsp1/vsp1_clu.h index 33a69029c719..036e0a2f1a42 100644 --- a/drivers/media/platform/vsp1/vsp1_clu.h +++ b/drivers/media/platform/vsp1/vsp1_clu.h @@ -13,6 +13,8 @@ #ifndef __VSP1_CLU_H__ #define __VSP1_CLU_H__ +#include + #include #include #include @@ -30,6 +32,8 @@ struct vsp1_clu { struct v4l2_ctrl_handler ctrls; + bool yuv_mode; + spinlock_t lock; unsigned int mode; struct vsp1_dl_body *clu; }; -- cgit v1.2.3 From 07a23c611778ab009b46b7b44b98e96157bb075f Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 19 Jun 2016 23:19:43 -0300 Subject: [media] v4l: vsp1: Simplify alpha propagation We don't need to walk the pipeline when propagating the alpha value as all the information needed for propagation is already available from the pipeline structure. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_pipe.c | 40 ++++++++------------------------- drivers/media/platform/vsp1/vsp1_pipe.h | 4 +--- drivers/media/platform/vsp1/vsp1_rpf.c | 2 +- drivers/media/platform/vsp1/vsp1_uds.c | 4 +++- drivers/media/platform/vsp1/vsp1_uds.h | 2 +- 5 files changed, 15 insertions(+), 37 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c b/drivers/media/platform/vsp1/vsp1_pipe.c index 3c6f623f056c..3e75fb3fcace 100644 --- a/drivers/media/platform/vsp1/vsp1_pipe.c +++ b/drivers/media/platform/vsp1/vsp1_pipe.c @@ -301,42 +301,20 @@ void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe) * to be scaled, we disable alpha scaling when the UDS input has a fixed alpha * value. The UDS then outputs a fixed alpha value which needs to be programmed * from the input RPF alpha. - * - * This function can only be called from a subdev s_stream handler as it - * requires a valid display list context. */ void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe, - struct vsp1_entity *input, - struct vsp1_dl_list *dl, - unsigned int alpha) + struct vsp1_dl_list *dl, unsigned int alpha) { - struct vsp1_entity *entity; - struct media_pad *pad; - - pad = media_entity_remote_pad(&input->pads[RWPF_PAD_SOURCE]); - - while (pad) { - if (!is_media_entity_v4l2_subdev(pad->entity)) - break; - - entity = to_vsp1_entity(media_entity_to_v4l2_subdev(pad->entity)); - - /* The BRU background color has a fixed alpha value set to 255, - * the output alpha value is thus always equal to 255. - */ - if (entity->type == VSP1_ENTITY_BRU) - alpha = 255; - - if (entity->type == VSP1_ENTITY_UDS) { - struct vsp1_uds *uds = to_uds(&entity->subdev); + if (!pipe->uds) + return; - vsp1_uds_set_alpha(uds, dl, alpha); - break; - } + /* The BRU background color has a fixed alpha value set to 255, the + * output alpha value is thus always equal to 255. + */ + if (pipe->uds_input->type == VSP1_ENTITY_BRU) + alpha = 255; - pad = &entity->pads[entity->source_pad]; - pad = media_entity_remote_pad(pad); - } + vsp1_uds_set_alpha(pipe->uds, dl, alpha); } void vsp1_pipelines_suspend(struct vsp1_device *vsp1) diff --git a/drivers/media/platform/vsp1/vsp1_pipe.h b/drivers/media/platform/vsp1/vsp1_pipe.h index fc9825d3d64c..d20d997b1fda 100644 --- a/drivers/media/platform/vsp1/vsp1_pipe.h +++ b/drivers/media/platform/vsp1/vsp1_pipe.h @@ -117,9 +117,7 @@ bool vsp1_pipeline_ready(struct vsp1_pipeline *pipe); void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe); void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe, - struct vsp1_entity *input, - struct vsp1_dl_list *dl, - unsigned int alpha); + struct vsp1_dl_list *dl, unsigned int alpha); void vsp1_pipelines_suspend(struct vsp1_device *vsp1); void vsp1_pipelines_resume(struct vsp1_device *vsp1); diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c index 390040a22b0c..b8e801edf84c 100644 --- a/drivers/media/platform/vsp1/vsp1_rpf.c +++ b/drivers/media/platform/vsp1/vsp1_rpf.c @@ -206,7 +206,7 @@ static void rpf_configure(struct vsp1_entity *entity, vsp1_rpf_write(rpf, dl, VI6_RPF_MULT_ALPHA, mult); } - vsp1_pipeline_propagate_alpha(pipe, &rpf->entity, dl, rpf->alpha); + vsp1_pipeline_propagate_alpha(pipe, dl, rpf->alpha); vsp1_rpf_write(rpf, dl, VI6_RPF_MSK_CTRL, 0); vsp1_rpf_write(rpf, dl, VI6_RPF_CKEY_CTRL, 0); diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c index 5d5720f2e5fe..652dcd895022 100644 --- a/drivers/media/platform/vsp1/vsp1_uds.c +++ b/drivers/media/platform/vsp1/vsp1_uds.c @@ -40,9 +40,11 @@ static inline void vsp1_uds_write(struct vsp1_uds *uds, struct vsp1_dl_list *dl, * Scaling Computation */ -void vsp1_uds_set_alpha(struct vsp1_uds *uds, struct vsp1_dl_list *dl, +void vsp1_uds_set_alpha(struct vsp1_entity *entity, struct vsp1_dl_list *dl, unsigned int alpha) { + struct vsp1_uds *uds = to_uds(&entity->subdev); + vsp1_uds_write(uds, dl, VI6_UDS_ALPVAL, alpha << VI6_UDS_ALPVAL_VAL0_SHIFT); } diff --git a/drivers/media/platform/vsp1/vsp1_uds.h b/drivers/media/platform/vsp1/vsp1_uds.h index 5c8cbfcad4cc..7bf3cdcffc65 100644 --- a/drivers/media/platform/vsp1/vsp1_uds.h +++ b/drivers/media/platform/vsp1/vsp1_uds.h @@ -35,7 +35,7 @@ static inline struct vsp1_uds *to_uds(struct v4l2_subdev *subdev) struct vsp1_uds *vsp1_uds_create(struct vsp1_device *vsp1, unsigned int index); -void vsp1_uds_set_alpha(struct vsp1_uds *uds, struct vsp1_dl_list *dl, +void vsp1_uds_set_alpha(struct vsp1_entity *uds, struct vsp1_dl_list *dl, unsigned int alpha); #endif /* __VSP1_UDS_H__ */ -- cgit v1.2.3 From d05a331029d31836053a934365056616b0142898 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 20 Jun 2016 05:04:38 -0300 Subject: [media] v4l: vsp1: rwpf: Support runtime modification of controls Allow reconfiguration of the alpha value at runtime. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_rpf.c | 21 ++++++++++++--------- drivers/media/platform/vsp1/vsp1_rwpf.c | 2 -- drivers/media/platform/vsp1/vsp1_rwpf.h | 3 +++ drivers/media/platform/vsp1/vsp1_wpf.c | 10 +++++++--- 4 files changed, 22 insertions(+), 14 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c index b8e801edf84c..4258c7208877 100644 --- a/drivers/media/platform/vsp1/vsp1_rpf.c +++ b/drivers/media/platform/vsp1/vsp1_rpf.c @@ -73,8 +73,15 @@ static void rpf_configure(struct vsp1_entity *entity, u32 pstride; u32 infmt; - if (!full) + if (!full) { + vsp1_rpf_write(rpf, dl, VI6_RPF_VRTCOL_SET, + rpf->alpha << VI6_RPF_VRTCOL_SET_LAYA_SHIFT); + vsp1_rpf_write(rpf, dl, VI6_RPF_MULT_ALPHA, rpf->mult_alpha | + (rpf->alpha << VI6_RPF_MULT_ALPHA_RATIO_SHIFT)); + + vsp1_pipeline_propagate_alpha(pipe, dl, rpf->alpha); return; + } /* Source size, stride and crop offsets. * @@ -171,9 +178,6 @@ static void rpf_configure(struct vsp1_entity *entity, (fmtinfo->alpha ? VI6_RPF_ALPH_SEL_ASEL_PACKED : VI6_RPF_ALPH_SEL_ASEL_FIXED)); - vsp1_rpf_write(rpf, dl, VI6_RPF_VRTCOL_SET, - rpf->alpha << VI6_RPF_VRTCOL_SET_LAYA_SHIFT); - if (entity->vsp1->info->gen == 3) { u32 mult; @@ -191,8 +195,7 @@ static void rpf_configure(struct vsp1_entity *entity, mult = VI6_RPF_MULT_ALPHA_A_MMD_RATIO | (premultiplied ? VI6_RPF_MULT_ALPHA_P_MMD_RATIO : - VI6_RPF_MULT_ALPHA_P_MMD_NONE) - | (rpf->alpha << VI6_RPF_MULT_ALPHA_RATIO_SHIFT); + VI6_RPF_MULT_ALPHA_P_MMD_NONE); } else { /* When the input doesn't contain an alpha channel the * global alpha value is applied in the unpacking unit, @@ -203,11 +206,9 @@ static void rpf_configure(struct vsp1_entity *entity, | VI6_RPF_MULT_ALPHA_P_MMD_NONE; } - vsp1_rpf_write(rpf, dl, VI6_RPF_MULT_ALPHA, mult); + rpf->mult_alpha = mult; } - vsp1_pipeline_propagate_alpha(pipe, dl, rpf->alpha); - vsp1_rpf_write(rpf, dl, VI6_RPF_MSK_CTRL, 0); vsp1_rpf_write(rpf, dl, VI6_RPF_CKEY_CTRL, 0); @@ -253,6 +254,8 @@ struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index) goto error; } + v4l2_ctrl_handler_setup(&rpf->ctrls); + return rpf; error: diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.c b/drivers/media/platform/vsp1/vsp1_rwpf.c index 3b6e032e7806..cd3562d1d9cf 100644 --- a/drivers/media/platform/vsp1/vsp1_rwpf.c +++ b/drivers/media/platform/vsp1/vsp1_rwpf.c @@ -243,8 +243,6 @@ static const struct v4l2_ctrl_ops vsp1_rwpf_ctrl_ops = { int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf) { - rwpf->alpha = 255; - v4l2_ctrl_handler_init(&rwpf->ctrls, 1); v4l2_ctrl_new_std(&rwpf->ctrls, &vsp1_rwpf_ctrl_ops, V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 255); diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h index 9ff7c78f239e..801cacc12e07 100644 --- a/drivers/media/platform/vsp1/vsp1_rwpf.h +++ b/drivers/media/platform/vsp1/vsp1_rwpf.h @@ -49,6 +49,9 @@ struct vsp1_rwpf { unsigned int alpha; + u32 mult_alpha; + u32 outfmt; + unsigned int offsets[2]; struct vsp1_rwpf_memory mem; diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c index 474feac67155..9385bc703dcd 100644 --- a/drivers/media/platform/vsp1/vsp1_wpf.c +++ b/drivers/media/platform/vsp1/vsp1_wpf.c @@ -104,8 +104,11 @@ static void wpf_configure(struct vsp1_entity *entity, u32 outfmt = 0; u32 srcrpf = 0; - if (!full) + if (!full) { + vsp1_wpf_write(wpf, dl, VI6_WPF_OUTFMT, wpf->outfmt | + (wpf->alpha << VI6_WPF_OUTFMT_PDV_SHIFT)); return; + } /* Cropping */ crop = vsp1_rwpf_get_crop(wpf, wpf->entity.config); @@ -151,8 +154,7 @@ static void wpf_configure(struct vsp1_entity *entity, if (sink_format->code != source_format->code) outfmt |= VI6_WPF_OUTFMT_CSC; - outfmt |= wpf->alpha << VI6_WPF_OUTFMT_PDV_SHIFT; - vsp1_wpf_write(wpf, dl, VI6_WPF_OUTFMT, outfmt); + wpf->outfmt = outfmt; vsp1_dl_list_write(dl, VI6_DPR_WPF_FPORCH(wpf->entity.index), VI6_DPR_WPF_FPORCH_FP_WPFN); @@ -239,6 +241,8 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index) goto error; } + v4l2_ctrl_handler_setup(&wpf->ctrls); + return wpf; error: -- cgit v1.2.3 From 894dde5c5d1c6d33c4bd3d4384c6cf0aff3f8015 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 26 May 2016 05:14:22 -0300 Subject: [media] v4l: vsp1: wpf: Add flipping support Vertical flipping is available on both Gen2 and Gen3, while horizontal flipping is only available on Gen3. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1.h | 2 + drivers/media/platform/vsp1/vsp1_drv.c | 16 ++-- drivers/media/platform/vsp1/vsp1_regs.h | 7 ++ drivers/media/platform/vsp1/vsp1_rpf.c | 2 +- drivers/media/platform/vsp1/vsp1_rwpf.c | 4 +- drivers/media/platform/vsp1/vsp1_rwpf.h | 11 ++- drivers/media/platform/vsp1/vsp1_wpf.c | 145 ++++++++++++++++++++++++++++++-- 7 files changed, 170 insertions(+), 17 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/vsp1/vsp1.h b/drivers/media/platform/vsp1/vsp1.h index 8713a437076d..06a2ec7e5ad4 100644 --- a/drivers/media/platform/vsp1/vsp1.h +++ b/drivers/media/platform/vsp1/vsp1.h @@ -48,6 +48,8 @@ struct vsp1_uds; #define VSP1_HAS_SRU (1 << 2) #define VSP1_HAS_BRU (1 << 3) #define VSP1_HAS_CLU (1 << 4) +#define VSP1_HAS_WPF_VFLIP (1 << 5) +#define VSP1_HAS_WPF_HFLIP (1 << 6) struct vsp1_device_info { u32 version; diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c index 769b19edb146..e1377ffe3d68 100644 --- a/drivers/media/platform/vsp1/vsp1_drv.c +++ b/drivers/media/platform/vsp1/vsp1_drv.c @@ -563,7 +563,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = { .version = VI6_IP_VERSION_MODEL_VSPS_H2, .gen = 2, .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT - | VSP1_HAS_SRU, + | VSP1_HAS_SRU | VSP1_HAS_WPF_VFLIP, .rpf_count = 5, .uds_count = 3, .wpf_count = 4, @@ -572,7 +572,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = { }, { .version = VI6_IP_VERSION_MODEL_VSPR_H2, .gen = 2, - .features = VSP1_HAS_BRU | VSP1_HAS_SRU, + .features = VSP1_HAS_BRU | VSP1_HAS_SRU | VSP1_HAS_WPF_VFLIP, .rpf_count = 5, .uds_count = 3, .wpf_count = 4, @@ -591,7 +591,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = { .version = VI6_IP_VERSION_MODEL_VSPS_M2, .gen = 2, .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT - | VSP1_HAS_SRU, + | VSP1_HAS_SRU | VSP1_HAS_WPF_VFLIP, .rpf_count = 5, .uds_count = 1, .wpf_count = 4, @@ -600,7 +600,8 @@ static const struct vsp1_device_info vsp1_device_infos[] = { }, { .version = VI6_IP_VERSION_MODEL_VSPI_GEN3, .gen = 3, - .features = VSP1_HAS_CLU | VSP1_HAS_LUT | VSP1_HAS_SRU, + .features = VSP1_HAS_CLU | VSP1_HAS_LUT | VSP1_HAS_SRU + | VSP1_HAS_WPF_HFLIP | VSP1_HAS_WPF_VFLIP, .rpf_count = 1, .uds_count = 1, .wpf_count = 1, @@ -608,7 +609,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = { }, { .version = VI6_IP_VERSION_MODEL_VSPBD_GEN3, .gen = 3, - .features = VSP1_HAS_BRU, + .features = VSP1_HAS_BRU | VSP1_HAS_WPF_VFLIP, .rpf_count = 5, .wpf_count = 1, .num_bru_inputs = 5, @@ -616,7 +617,8 @@ static const struct vsp1_device_info vsp1_device_infos[] = { }, { .version = VI6_IP_VERSION_MODEL_VSPBC_GEN3, .gen = 3, - .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT, + .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT + | VSP1_HAS_WPF_VFLIP, .rpf_count = 5, .wpf_count = 1, .num_bru_inputs = 5, @@ -624,7 +626,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = { }, { .version = VI6_IP_VERSION_MODEL_VSPD_GEN3, .gen = 3, - .features = VSP1_HAS_BRU | VSP1_HAS_LIF, + .features = VSP1_HAS_BRU | VSP1_HAS_LIF | VSP1_HAS_WPF_VFLIP, .rpf_count = 5, .wpf_count = 2, .num_bru_inputs = 5, diff --git a/drivers/media/platform/vsp1/vsp1_regs.h b/drivers/media/platform/vsp1/vsp1_regs.h index dea0bc471108..3b03007ba625 100644 --- a/drivers/media/platform/vsp1/vsp1_regs.h +++ b/drivers/media/platform/vsp1/vsp1_regs.h @@ -255,6 +255,8 @@ #define VI6_WPF_OUTFMT_PDV_MASK (0xff << 24) #define VI6_WPF_OUTFMT_PDV_SHIFT 24 #define VI6_WPF_OUTFMT_PXA (1 << 23) +#define VI6_WPF_OUTFMT_ROT (1 << 18) +#define VI6_WPF_OUTFMT_HFLP (1 << 17) #define VI6_WPF_OUTFMT_FLP (1 << 16) #define VI6_WPF_OUTFMT_SPYCS (1 << 15) #define VI6_WPF_OUTFMT_SPUVS (1 << 14) @@ -289,6 +291,11 @@ #define VI6_WPF_RNDCTRL_CLMD_EXT (2 << 12) #define VI6_WPF_RNDCTRL_CLMD_MASK (3 << 12) +#define VI6_WPF_ROT_CTRL 0x1018 +#define VI6_WPF_ROT_CTRL_LN16 (1 << 17) +#define VI6_WPF_ROT_CTRL_LMEM_WD_MASK (0x1fff << 0) +#define VI6_WPF_ROT_CTRL_LMEM_WD_SHIFT 0 + #define VI6_WPF_DSTM_STRIDE_Y 0x101c #define VI6_WPF_DSTM_STRIDE_C 0x1020 #define VI6_WPF_DSTM_ADDR_Y 0x1024 diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c index 4258c7208877..388838913205 100644 --- a/drivers/media/platform/vsp1/vsp1_rpf.c +++ b/drivers/media/platform/vsp1/vsp1_rpf.c @@ -247,7 +247,7 @@ struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index) return ERR_PTR(ret); /* Initialize the control handler. */ - ret = vsp1_rwpf_init_ctrls(rpf); + ret = vsp1_rwpf_init_ctrls(rpf, 0); if (ret < 0) { dev_err(vsp1->dev, "rpf%u: failed to initialize controls\n", index); diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.c b/drivers/media/platform/vsp1/vsp1_rwpf.c index cd3562d1d9cf..8d461b375e91 100644 --- a/drivers/media/platform/vsp1/vsp1_rwpf.c +++ b/drivers/media/platform/vsp1/vsp1_rwpf.c @@ -241,9 +241,9 @@ static const struct v4l2_ctrl_ops vsp1_rwpf_ctrl_ops = { .s_ctrl = vsp1_rwpf_s_ctrl, }; -int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf) +int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf, unsigned int ncontrols) { - v4l2_ctrl_handler_init(&rwpf->ctrls, 1); + v4l2_ctrl_handler_init(&rwpf->ctrls, ncontrols + 1); v4l2_ctrl_new_std(&rwpf->ctrls, &vsp1_rwpf_ctrl_ops, V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 255); diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h index 801cacc12e07..cb20484e80da 100644 --- a/drivers/media/platform/vsp1/vsp1_rwpf.h +++ b/drivers/media/platform/vsp1/vsp1_rwpf.h @@ -13,6 +13,8 @@ #ifndef __VSP1_RWPF_H__ #define __VSP1_RWPF_H__ +#include + #include #include #include @@ -52,6 +54,13 @@ struct vsp1_rwpf { u32 mult_alpha; u32 outfmt; + struct { + spinlock_t lock; + struct v4l2_ctrl *ctrls[2]; + unsigned int pending; + unsigned int active; + } flip; + unsigned int offsets[2]; struct vsp1_rwpf_memory mem; @@ -71,7 +80,7 @@ static inline struct vsp1_rwpf *entity_to_rwpf(struct vsp1_entity *entity) struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index); struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index); -int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf); +int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf, unsigned int ncontrols); extern const struct v4l2_subdev_pad_ops vsp1_rwpf_pad_ops; diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c index 9385bc703dcd..31983169c24a 100644 --- a/drivers/media/platform/vsp1/vsp1_wpf.c +++ b/drivers/media/platform/vsp1/vsp1_wpf.c @@ -36,6 +36,97 @@ static inline void vsp1_wpf_write(struct vsp1_rwpf *wpf, vsp1_dl_list_write(dl, reg + wpf->entity.index * VI6_WPF_OFFSET, data); } +/* ----------------------------------------------------------------------------- + * Controls + */ + +enum wpf_flip_ctrl { + WPF_CTRL_VFLIP = 0, + WPF_CTRL_HFLIP = 1, + WPF_CTRL_MAX, +}; + +static int vsp1_wpf_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vsp1_rwpf *wpf = + container_of(ctrl->handler, struct vsp1_rwpf, ctrls); + unsigned int i; + u32 flip = 0; + + switch (ctrl->id) { + case V4L2_CID_HFLIP: + case V4L2_CID_VFLIP: + for (i = 0; i < WPF_CTRL_MAX; ++i) { + if (wpf->flip.ctrls[i]) + flip |= wpf->flip.ctrls[i]->val ? BIT(i) : 0; + } + + spin_lock_irq(&wpf->flip.lock); + wpf->flip.pending = flip; + spin_unlock_irq(&wpf->flip.lock); + break; + + default: + return -EINVAL; + } + + return 0; +} + +static const struct v4l2_ctrl_ops vsp1_wpf_ctrl_ops = { + .s_ctrl = vsp1_wpf_s_ctrl, +}; + +static int wpf_init_controls(struct vsp1_rwpf *wpf) +{ + struct vsp1_device *vsp1 = wpf->entity.vsp1; + unsigned int num_flip_ctrls; + + spin_lock_init(&wpf->flip.lock); + + if (wpf->entity.index != 0) { + /* Only WPF0 supports flipping. */ + num_flip_ctrls = 0; + } else if (vsp1->info->features & VSP1_HAS_WPF_HFLIP) { + /* When horizontal flip is supported the WPF implements two + * controls (horizontal flip and vertical flip). + */ + num_flip_ctrls = 2; + } else if (vsp1->info->features & VSP1_HAS_WPF_VFLIP) { + /* When only vertical flip is supported the WPF implements a + * single control (vertical flip). + */ + num_flip_ctrls = 1; + } else { + /* Otherwise flipping is not supported. */ + num_flip_ctrls = 0; + } + + vsp1_rwpf_init_ctrls(wpf, num_flip_ctrls); + + if (num_flip_ctrls >= 1) { + wpf->flip.ctrls[WPF_CTRL_VFLIP] = + v4l2_ctrl_new_std(&wpf->ctrls, &vsp1_wpf_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + } + + if (num_flip_ctrls == 2) { + wpf->flip.ctrls[WPF_CTRL_HFLIP] = + v4l2_ctrl_new_std(&wpf->ctrls, &vsp1_wpf_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + + v4l2_ctrl_cluster(2, wpf->flip.ctrls); + } + + if (wpf->ctrls.error) { + dev_err(vsp1->dev, "wpf%u: failed to initialize controls\n", + wpf->entity.index); + return wpf->ctrls.error; + } + + return 0; +} + /* ----------------------------------------------------------------------------- * V4L2 Subdevice Core Operations */ @@ -85,10 +176,32 @@ static void vsp1_wpf_destroy(struct vsp1_entity *entity) static void wpf_set_memory(struct vsp1_entity *entity, struct vsp1_dl_list *dl) { struct vsp1_rwpf *wpf = entity_to_rwpf(entity); + const struct v4l2_pix_format_mplane *format = &wpf->format; + struct vsp1_rwpf_memory mem = wpf->mem; + unsigned int flip = wpf->flip.active; + unsigned int offset; + + /* Update the memory offsets based on flipping configuration. The + * destination addresses point to the locations where the VSP starts + * writing to memory, which can be different corners of the image + * depending on vertical flipping. Horizontal flipping is handled + * through a line buffer and doesn't modify the start address. + */ + if (flip & BIT(WPF_CTRL_VFLIP)) { + mem.addr[0] += (format->height - 1) + * format->plane_fmt[0].bytesperline; + + if (format->num_planes > 1) { + offset = (format->height / wpf->fmtinfo->vsub - 1) + * format->plane_fmt[1].bytesperline; + mem.addr[1] += offset; + mem.addr[2] += offset; + } + } - vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_Y, wpf->mem.addr[0]); - vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C0, wpf->mem.addr[1]); - vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C1, wpf->mem.addr[2]); + vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_Y, mem.addr[0]); + vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C0, mem.addr[1]); + vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C1, mem.addr[2]); } static void wpf_configure(struct vsp1_entity *entity, @@ -105,8 +218,22 @@ static void wpf_configure(struct vsp1_entity *entity, u32 srcrpf = 0; if (!full) { - vsp1_wpf_write(wpf, dl, VI6_WPF_OUTFMT, wpf->outfmt | - (wpf->alpha << VI6_WPF_OUTFMT_PDV_SHIFT)); + const unsigned int mask = BIT(WPF_CTRL_VFLIP) + | BIT(WPF_CTRL_HFLIP); + + spin_lock(&wpf->flip.lock); + wpf->flip.active = (wpf->flip.active & ~mask) + | (wpf->flip.pending & mask); + spin_unlock(&wpf->flip.lock); + + outfmt = (wpf->alpha << VI6_WPF_OUTFMT_PDV_SHIFT) | wpf->outfmt; + + if (wpf->flip.active & BIT(WPF_CTRL_VFLIP)) + outfmt |= VI6_WPF_OUTFMT_FLP; + if (wpf->flip.active & BIT(WPF_CTRL_HFLIP)) + outfmt |= VI6_WPF_OUTFMT_HFLP; + + vsp1_wpf_write(wpf, dl, VI6_WPF_OUTFMT, outfmt); return; } @@ -149,6 +276,12 @@ static void wpf_configure(struct vsp1_entity *entity, format->plane_fmt[1].bytesperline); vsp1_wpf_write(wpf, dl, VI6_WPF_DSWAP, fmtinfo->swap); + + if (vsp1->info->features & VSP1_HAS_WPF_HFLIP && + wpf->entity.index == 0) + vsp1_wpf_write(wpf, dl, VI6_WPF_ROT_CTRL, + VI6_WPF_ROT_CTRL_LN16 | + (256 << VI6_WPF_ROT_CTRL_LMEM_WD_SHIFT)); } if (sink_format->code != source_format->code) @@ -234,7 +367,7 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index) } /* Initialize the control handler. */ - ret = vsp1_rwpf_init_ctrls(wpf); + ret = wpf_init_controls(wpf); if (ret < 0) { dev_err(vsp1->dev, "wpf%u: failed to initialize controls\n", index); -- cgit v1.2.3