diff options
Diffstat (limited to 'drivers/media/platform/vsp1')
-rw-r--r-- | drivers/media/platform/vsp1/Makefile | 2 | ||||
-rw-r--r-- | drivers/media/platform/vsp1/vsp1.h | 3 | ||||
-rw-r--r-- | drivers/media/platform/vsp1/vsp1_bru.c | 395 | ||||
-rw-r--r-- | drivers/media/platform/vsp1/vsp1_bru.h | 39 | ||||
-rw-r--r-- | drivers/media/platform/vsp1/vsp1_drv.c | 101 | ||||
-rw-r--r-- | drivers/media/platform/vsp1/vsp1_entity.c | 57 | ||||
-rw-r--r-- | drivers/media/platform/vsp1/vsp1_entity.h | 24 | ||||
-rw-r--r-- | drivers/media/platform/vsp1/vsp1_hsit.c | 7 | ||||
-rw-r--r-- | drivers/media/platform/vsp1/vsp1_lif.c | 1 | ||||
-rw-r--r-- | drivers/media/platform/vsp1/vsp1_lut.c | 1 | ||||
-rw-r--r-- | drivers/media/platform/vsp1/vsp1_regs.h | 98 | ||||
-rw-r--r-- | drivers/media/platform/vsp1/vsp1_rpf.c | 7 | ||||
-rw-r--r-- | drivers/media/platform/vsp1/vsp1_rwpf.h | 4 | ||||
-rw-r--r-- | drivers/media/platform/vsp1/vsp1_sru.c | 1 | ||||
-rw-r--r-- | drivers/media/platform/vsp1/vsp1_uds.c | 4 | ||||
-rw-r--r-- | drivers/media/platform/vsp1/vsp1_video.c | 30 | ||||
-rw-r--r-- | drivers/media/platform/vsp1/vsp1_video.h | 1 | ||||
-rw-r--r-- | drivers/media/platform/vsp1/vsp1_wpf.c | 13 |
18 files changed, 691 insertions, 97 deletions
diff --git a/drivers/media/platform/vsp1/Makefile b/drivers/media/platform/vsp1/Makefile index 151cecd0ea25..6a93f928dfde 100644 --- a/drivers/media/platform/vsp1/Makefile +++ b/drivers/media/platform/vsp1/Makefile @@ -1,6 +1,6 @@ vsp1-y := vsp1_drv.o vsp1_entity.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_sru.o vsp1_uds.o +vsp1-y += vsp1_bru.o vsp1_sru.o vsp1_uds.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 0313210c6e9e..6ca2cf20d545 100644 --- a/drivers/media/platform/vsp1/vsp1.h +++ b/drivers/media/platform/vsp1/vsp1.h @@ -28,6 +28,7 @@ struct clk; struct device; struct vsp1_platform_data; +struct vsp1_bru; struct vsp1_hsit; struct vsp1_lif; struct vsp1_lut; @@ -45,11 +46,11 @@ struct vsp1_device { void __iomem *mmio; struct clk *clock; - struct clk *rt_clock; struct mutex lock; int ref_count; + struct vsp1_bru *bru; struct vsp1_hsit *hsi; struct vsp1_hsit *hst; struct vsp1_lif *lif; diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c new file mode 100644 index 000000000000..f80695480060 --- /dev/null +++ b/drivers/media/platform/vsp1/vsp1_bru.c @@ -0,0 +1,395 @@ +/* + * vsp1_bru.c -- R-Car VSP1 Blend ROP Unit + * + * Copyright (C) 2013 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. + */ + +#include <linux/device.h> +#include <linux/gfp.h> + +#include <media/v4l2-subdev.h> + +#include "vsp1.h" +#include "vsp1_bru.h" + +#define BRU_MIN_SIZE 4U +#define BRU_MAX_SIZE 8190U + +/* ----------------------------------------------------------------------------- + * Device Access + */ + +static inline u32 vsp1_bru_read(struct vsp1_bru *bru, u32 reg) +{ + return vsp1_read(bru->entity.vsp1, reg); +} + +static inline void vsp1_bru_write(struct vsp1_bru *bru, u32 reg, u32 data) +{ + vsp1_write(bru->entity.vsp1, reg, data); +} + +/* ----------------------------------------------------------------------------- + * V4L2 Subdevice Core Operations + */ + +static bool bru_is_input_enabled(struct vsp1_bru *bru, unsigned int input) +{ + return media_entity_remote_pad(&bru->entity.pads[input]) != NULL; +} + +static int bru_s_stream(struct v4l2_subdev *subdev, int enable) +{ + struct vsp1_bru *bru = to_bru(subdev); + struct v4l2_mbus_framefmt *format; + unsigned int i; + + if (!enable) + return 0; + + format = &bru->entity.formats[BRU_PAD_SOURCE]; + + /* The hardware is extremely flexible but we have no userspace API to + * expose all the parameters, nor is it clear whether we would have use + * cases for all the supported modes. Let's just harcode the parameters + * to sane default values for now. + */ + + /* Disable both color data normalization and dithering. */ + vsp1_bru_write(bru, VI6_BRU_INCTRL, 0); + + /* Set the background position to cover the whole output image and + * set its color to opaque black. + */ + vsp1_bru_write(bru, VI6_BRU_VIRRPF_SIZE, + (format->width << VI6_BRU_VIRRPF_SIZE_HSIZE_SHIFT) | + (format->height << VI6_BRU_VIRRPF_SIZE_VSIZE_SHIFT)); + vsp1_bru_write(bru, VI6_BRU_VIRRPF_LOC, 0); + vsp1_bru_write(bru, VI6_BRU_VIRRPF_COL, + 0xff << VI6_BRU_VIRRPF_COL_A_SHIFT); + + /* Route BRU input 1 as SRC input to the ROP unit and configure the ROP + * unit with a NOP operation to make BRU input 1 available as the + * Blend/ROP unit B SRC input. + */ + vsp1_bru_write(bru, VI6_BRU_ROP, VI6_BRU_ROP_DSTSEL_BRUIN(1) | + VI6_BRU_ROP_CROP(VI6_ROP_NOP) | + VI6_BRU_ROP_AROP(VI6_ROP_NOP)); + + for (i = 0; i < 4; ++i) { + u32 ctrl = 0; + + /* Configure all Blend/ROP units corresponding to an enabled BRU + * input for alpha blending. Blend/ROP units corresponding to + * disabled BRU inputs are used in ROP NOP mode to ignore the + * SRC input. + */ + if (bru_is_input_enabled(bru, i)) + ctrl |= VI6_BRU_CTRL_RBC; + else + ctrl |= VI6_BRU_CTRL_CROP(VI6_ROP_NOP) + | VI6_BRU_CTRL_AROP(VI6_ROP_NOP); + + /* Select the virtual RPF as the Blend/ROP unit A DST input to + * serve as a background color. + */ + if (i == 0) + ctrl |= VI6_BRU_CTRL_DSTSEL_VRPF; + + /* Route BRU inputs 0 to 3 as SRC inputs to Blend/ROP units A to + * D in that order. The Blend/ROP unit B SRC is hardwired to the + * ROP unit output, the corresponding register bits must be set + * to 0. + */ + if (i != 1) + ctrl |= VI6_BRU_CTRL_SRCSEL_BRUIN(i); + + vsp1_bru_write(bru, VI6_BRU_CTRL(i), ctrl); + + /* Harcode the blending formula to + * + * DSTc = DSTc * (1 - SRCa) + SRCc * SRCa + * DSTa = DSTa * (1 - SRCa) + SRCa + */ + vsp1_bru_write(bru, VI6_BRU_BLD(i), + VI6_BRU_BLD_CCMDX_255_SRC_A | + VI6_BRU_BLD_CCMDY_SRC_A | + VI6_BRU_BLD_ACMDX_255_SRC_A | + VI6_BRU_BLD_ACMDY_COEFY | + (0xff << VI6_BRU_BLD_COEFY_SHIFT)); + } + + return 0; +} + +/* ----------------------------------------------------------------------------- + * V4L2 Subdevice Pad Operations + */ + +/* + * The BRU can't perform format conversion, all sink and source formats must be + * identical. We pick the format on the first sink pad (pad 0) and propagate it + * to all other pads. + */ + +static int bru_enum_mbus_code(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_mbus_code_enum *code) +{ + static const unsigned int codes[] = { + V4L2_MBUS_FMT_ARGB8888_1X32, + V4L2_MBUS_FMT_AYUV8_1X32, + }; + struct v4l2_mbus_framefmt *format; + + if (code->pad == BRU_PAD_SINK(0)) { + if (code->index >= ARRAY_SIZE(codes)) + return -EINVAL; + + code->code = codes[code->index]; + } else { + if (code->index) + return -EINVAL; + + format = v4l2_subdev_get_try_format(fh, BRU_PAD_SINK(0)); + code->code = format->code; + } + + return 0; +} + +static int bru_enum_frame_size(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_frame_size_enum *fse) +{ + if (fse->index) + return -EINVAL; + + if (fse->code != V4L2_MBUS_FMT_ARGB8888_1X32 && + fse->code != V4L2_MBUS_FMT_AYUV8_1X32) + return -EINVAL; + + fse->min_width = BRU_MIN_SIZE; + fse->max_width = BRU_MAX_SIZE; + fse->min_height = BRU_MIN_SIZE; + fse->max_height = BRU_MAX_SIZE; + + return 0; +} + +static struct v4l2_rect *bru_get_compose(struct vsp1_bru *bru, + struct v4l2_subdev_fh *fh, + unsigned int pad, u32 which) +{ + switch (which) { + case V4L2_SUBDEV_FORMAT_TRY: + return v4l2_subdev_get_try_crop(fh, pad); + case V4L2_SUBDEV_FORMAT_ACTIVE: + return &bru->compose[pad]; + default: + return NULL; + } +} + +static int bru_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct vsp1_bru *bru = to_bru(subdev); + + fmt->format = *vsp1_entity_get_pad_format(&bru->entity, fh, fmt->pad, + fmt->which); + + return 0; +} + +static void bru_try_format(struct vsp1_bru *bru, struct v4l2_subdev_fh *fh, + unsigned int pad, struct v4l2_mbus_framefmt *fmt, + enum v4l2_subdev_format_whence which) +{ + struct v4l2_mbus_framefmt *format; + + switch (pad) { + case BRU_PAD_SINK(0): + /* Default to YUV if the requested format is not supported. */ + if (fmt->code != V4L2_MBUS_FMT_ARGB8888_1X32 && + fmt->code != V4L2_MBUS_FMT_AYUV8_1X32) + fmt->code = V4L2_MBUS_FMT_AYUV8_1X32; + break; + + default: + /* The BRU can't perform format conversion. */ + format = vsp1_entity_get_pad_format(&bru->entity, fh, + BRU_PAD_SINK(0), which); + fmt->code = format->code; + break; + } + + fmt->width = clamp(fmt->width, BRU_MIN_SIZE, BRU_MAX_SIZE); + fmt->height = clamp(fmt->height, BRU_MIN_SIZE, BRU_MAX_SIZE); + fmt->field = V4L2_FIELD_NONE; + fmt->colorspace = V4L2_COLORSPACE_SRGB; +} + +static int bru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct vsp1_bru *bru = to_bru(subdev); + struct v4l2_mbus_framefmt *format; + + bru_try_format(bru, fh, fmt->pad, &fmt->format, fmt->which); + + format = vsp1_entity_get_pad_format(&bru->entity, fh, fmt->pad, + fmt->which); + *format = fmt->format; + + /* Reset the compose rectangle */ + if (fmt->pad != BRU_PAD_SOURCE) { + struct v4l2_rect *compose; + + compose = bru_get_compose(bru, fh, fmt->pad, fmt->which); + compose->left = 0; + compose->top = 0; + compose->width = format->width; + compose->height = format->height; + } + + /* Propagate the format code to all pads */ + if (fmt->pad == BRU_PAD_SINK(0)) { + unsigned int i; + + for (i = 0; i <= BRU_PAD_SOURCE; ++i) { + format = vsp1_entity_get_pad_format(&bru->entity, fh, + i, fmt->which); + format->code = fmt->format.code; + } + } + + return 0; +} + +static int bru_get_selection(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_selection *sel) +{ + struct vsp1_bru *bru = to_bru(subdev); + + if (sel->pad == BRU_PAD_SOURCE) + return -EINVAL; + + switch (sel->target) { + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + sel->r.left = 0; + sel->r.top = 0; + sel->r.width = BRU_MAX_SIZE; + sel->r.height = BRU_MAX_SIZE; + return 0; + + case V4L2_SEL_TGT_COMPOSE: + sel->r = *bru_get_compose(bru, fh, sel->pad, sel->which); + return 0; + + default: + return -EINVAL; + } +} + +static int bru_set_selection(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_selection *sel) +{ + struct vsp1_bru *bru = to_bru(subdev); + struct v4l2_mbus_framefmt *format; + struct v4l2_rect *compose; + + if (sel->pad == BRU_PAD_SOURCE) + return -EINVAL; + + if (sel->target != V4L2_SEL_TGT_COMPOSE) + return -EINVAL; + + /* The compose rectangle top left corner must be inside the output + * frame. + */ + format = vsp1_entity_get_pad_format(&bru->entity, fh, BRU_PAD_SOURCE, + sel->which); + sel->r.left = clamp_t(unsigned int, sel->r.left, 0, format->width - 1); + sel->r.top = clamp_t(unsigned int, sel->r.top, 0, format->height - 1); + + /* Scaling isn't supported, the compose rectangle size must be identical + * to the sink format size. + */ + format = vsp1_entity_get_pad_format(&bru->entity, fh, sel->pad, + sel->which); + sel->r.width = format->width; + sel->r.height = format->height; + + compose = bru_get_compose(bru, fh, sel->pad, sel->which); + *compose = sel->r; + + return 0; +} + +/* ----------------------------------------------------------------------------- + * V4L2 Subdevice Operations + */ + +static struct v4l2_subdev_video_ops bru_video_ops = { + .s_stream = bru_s_stream, +}; + +static struct v4l2_subdev_pad_ops bru_pad_ops = { + .enum_mbus_code = bru_enum_mbus_code, + .enum_frame_size = bru_enum_frame_size, + .get_fmt = bru_get_format, + .set_fmt = bru_set_format, + .get_selection = bru_get_selection, + .set_selection = bru_set_selection, +}; + +static struct v4l2_subdev_ops bru_ops = { + .video = &bru_video_ops, + .pad = &bru_pad_ops, +}; + +/* ----------------------------------------------------------------------------- + * Initialization and Cleanup + */ + +struct vsp1_bru *vsp1_bru_create(struct vsp1_device *vsp1) +{ + struct v4l2_subdev *subdev; + struct vsp1_bru *bru; + int ret; + + bru = devm_kzalloc(vsp1->dev, sizeof(*bru), GFP_KERNEL); + if (bru == NULL) + return ERR_PTR(-ENOMEM); + + bru->entity.type = VSP1_ENTITY_BRU; + + ret = vsp1_entity_init(vsp1, &bru->entity, 5); + if (ret < 0) + return ERR_PTR(ret); + + /* Initialize the V4L2 subdev. */ + subdev = &bru->entity.subdev; + v4l2_subdev_init(subdev, &bru_ops); + + subdev->entity.ops = &vsp1_media_ops; + subdev->internal_ops = &vsp1_subdev_internal_ops; + snprintf(subdev->name, sizeof(subdev->name), "%s bru", + dev_name(vsp1->dev)); + v4l2_set_subdevdata(subdev, bru); + subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + + vsp1_entity_init_formats(subdev, NULL); + + return bru; +} diff --git a/drivers/media/platform/vsp1/vsp1_bru.h b/drivers/media/platform/vsp1/vsp1_bru.h new file mode 100644 index 000000000000..37062704dbf6 --- /dev/null +++ b/drivers/media/platform/vsp1/vsp1_bru.h @@ -0,0 +1,39 @@ +/* + * vsp1_bru.h -- R-Car VSP1 Blend ROP Unit + * + * Copyright (C) 2013 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_BRU_H__ +#define __VSP1_BRU_H__ + +#include <media/media-entity.h> +#include <media/v4l2-subdev.h> + +#include "vsp1_entity.h" + +struct vsp1_device; + +#define BRU_PAD_SINK(n) (n) +#define BRU_PAD_SOURCE 4 + +struct vsp1_bru { + struct vsp1_entity entity; + + struct v4l2_rect compose[4]; +}; + +static inline struct vsp1_bru *to_bru(struct v4l2_subdev *subdev) +{ + return container_of(subdev, struct vsp1_bru, entity.subdev); +} + +struct vsp1_bru *vsp1_bru_create(struct vsp1_device *vsp1); + +#endif /* __VSP1_BRU_H__ */ diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c index 2f74f0e0ddf5..c69ee0657f75 100644 --- a/drivers/media/platform/vsp1/vsp1_drv.c +++ b/drivers/media/platform/vsp1/vsp1_drv.c @@ -16,10 +16,12 @@ #include <linux/device.h> #include <linux/interrupt.h> #include <linux/module.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/videodev2.h> #include "vsp1.h" +#include "vsp1_bru.h" #include "vsp1_hsit.h" #include "vsp1_lif.h" #include "vsp1_lut.h" @@ -155,6 +157,14 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) } /* Instantiate all the entities. */ + vsp1->bru = vsp1_bru_create(vsp1); + if (IS_ERR(vsp1->bru)) { + ret = PTR_ERR(vsp1->bru); + goto done; + } + + list_add_tail(&vsp1->bru->entity.list_dev, &vsp1->entities); + vsp1->hsi = vsp1_hsit_create(vsp1, true); if (IS_ERR(vsp1->hsi)) { ret = PTR_ERR(vsp1->hsi); @@ -329,33 +339,6 @@ static int vsp1_device_init(struct vsp1_device *vsp1) return 0; } -static int vsp1_clocks_enable(struct vsp1_device *vsp1) -{ - int ret; - - ret = clk_prepare_enable(vsp1->clock); - if (ret < 0) - return ret; - - if (IS_ERR(vsp1->rt_clock)) - return 0; - - ret = clk_prepare_enable(vsp1->rt_clock); - if (ret < 0) { - clk_disable_unprepare(vsp1->clock); - return ret; - } - - return 0; -} - -static void vsp1_clocks_disable(struct vsp1_device *vsp1) -{ - if (!IS_ERR(vsp1->rt_clock)) - clk_disable_unprepare(vsp1->rt_clock); - clk_disable_unprepare(vsp1->clock); -} - /* * vsp1_device_get - Acquire the VSP1 device * @@ -373,7 +356,7 @@ struct vsp1_device *vsp1_device_get(struct vsp1_device *vsp1) if (vsp1->ref_count > 0) goto done; - ret = vsp1_clocks_enable(vsp1); + ret = clk_prepare_enable(vsp1->clock); if (ret < 0) { __vsp1 = NULL; goto done; @@ -381,7 +364,7 @@ struct vsp1_device *vsp1_device_get(struct vsp1_device *vsp1) ret = vsp1_device_init(vsp1); if (ret < 0) { - vsp1_clocks_disable(vsp1); + clk_disable_unprepare(vsp1->clock); __vsp1 = NULL; goto done; } @@ -405,7 +388,7 @@ void vsp1_device_put(struct vsp1_device *vsp1) mutex_lock(&vsp1->lock); if (--vsp1->ref_count == 0) - vsp1_clocks_disable(vsp1); + clk_disable_unprepare(vsp1->clock); mutex_unlock(&vsp1->lock); } @@ -424,7 +407,7 @@ static int vsp1_pm_suspend(struct device *dev) if (vsp1->ref_count == 0) return 0; - vsp1_clocks_disable(vsp1); + clk_disable_unprepare(vsp1->clock); return 0; } @@ -437,7 +420,7 @@ static int vsp1_pm_resume(struct device *dev) if (vsp1->ref_count) return 0; - return vsp1_clocks_enable(vsp1); + return clk_prepare_enable(vsp1->clock); } #endif @@ -449,34 +432,59 @@ static const struct dev_pm_ops vsp1_pm_ops = { * Platform Driver */ -static struct vsp1_platform_data * -vsp1_get_platform_data(struct platform_device *pdev) +static int vsp1_validate_platform_data(struct platform_device *pdev, + struct vsp1_platform_data *pdata) { - struct vsp1_platform_data *pdata = pdev->dev.platform_data; - if (pdata == NULL) { dev_err(&pdev->dev, "missing platform data\n"); - return NULL; + return -EINVAL; } if (pdata->rpf_count <= 0 || pdata->rpf_count > VPS1_MAX_RPF) { dev_err(&pdev->dev, "invalid number of RPF (%u)\n", pdata->rpf_count); - return NULL; + return -EINVAL; } if (pdata->uds_count <= 0 || pdata->uds_count > VPS1_MAX_UDS) { dev_err(&pdev->dev, "invalid number of UDS (%u)\n", pdata->uds_count); - return NULL; + return -EINVAL; } if (pdata->wpf_count <= 0 || pdata->wpf_count > VPS1_MAX_WPF) { dev_err(&pdev->dev, "invalid number of WPF (%u)\n", pdata->wpf_count); - return NULL; + return -EINVAL; } + return 0; +} + +static struct vsp1_platform_data * +vsp1_get_platform_data(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct vsp1_platform_data *pdata; + + if (!IS_ENABLED(CONFIG_OF) || np == NULL) + return pdev->dev.platform_data; + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (pdata == NULL) + return NULL; + + if (of_property_read_bool(np, "renesas,has-lif")) + pdata->features |= VSP1_HAS_LIF; + if (of_property_read_bool(np, "renesas,has-lut")) + pdata->features |= VSP1_HAS_LUT; + if (of_property_read_bool(np, "renesas,has-sru")) + pdata->features |= VSP1_HAS_SRU; + + of_property_read_u32(np, "renesas,#rpf", &pdata->rpf_count); + of_property_read_u32(np, "renesas,#uds", &pdata->uds_count); + of_property_read_u32(np, "renesas,#wpf", &pdata->wpf_count); + return pdata; } @@ -499,6 +507,10 @@ static int vsp1_probe(struct platform_device *pdev) if (vsp1->pdata == NULL) return -ENODEV; + ret = vsp1_validate_platform_data(pdev, vsp1->pdata); + if (ret < 0) + return ret; + /* I/O, IRQ and clock resources */ io = platform_get_resource(pdev, IORESOURCE_MEM, 0); vsp1->mmio = devm_ioremap_resource(&pdev->dev, io); @@ -511,9 +523,6 @@ static int vsp1_probe(struct platform_device *pdev) return PTR_ERR(vsp1->clock); } - /* The RT clock is optional */ - vsp1->rt_clock = devm_clk_get(&pdev->dev, "rt"); - irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!irq) { dev_err(&pdev->dev, "missing IRQ\n"); @@ -548,6 +557,11 @@ static int vsp1_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id vsp1_of_match[] = { + { .compatible = "renesas,vsp1" }, + { }, +}; + static struct platform_driver vsp1_platform_driver = { .probe = vsp1_probe, .remove = vsp1_remove, @@ -555,6 +569,7 @@ static struct platform_driver vsp1_platform_driver = { .owner = THIS_MODULE, .name = "vsp1", .pm = &vsp1_pm_ops, + .of_match_table = vsp1_of_match, }, }; diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c index 3fc9e4266caf..44167834285d 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.c +++ b/drivers/media/platform/vsp1/vsp1_entity.c @@ -100,8 +100,10 @@ static int vsp1_entity_link_setup(struct media_entity *entity, if (source->sink) return -EBUSY; source->sink = remote->entity; + source->sink_pad = remote->index; } else { source->sink = NULL; + source->sink_pad = 0; } return 0; @@ -116,42 +118,43 @@ const struct media_entity_operations vsp1_media_ops = { * Initialization */ +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), } }, + { 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), { VI6_DPR_NODE_RPF(0), } }, + { VSP1_ENTITY_RPF, 1, VI6_DPR_RPF_ROUTE(1), { VI6_DPR_NODE_RPF(1), } }, + { VSP1_ENTITY_RPF, 2, VI6_DPR_RPF_ROUTE(2), { VI6_DPR_NODE_RPF(2), } }, + { VSP1_ENTITY_RPF, 3, VI6_DPR_RPF_ROUTE(3), { VI6_DPR_NODE_RPF(3), } }, + { VSP1_ENTITY_RPF, 4, VI6_DPR_RPF_ROUTE(4), { VI6_DPR_NODE_RPF(4), } }, + { 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), } }, +}; + int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity, unsigned int num_pads) { - static const struct { - unsigned int id; - unsigned int reg; - } routes[] = { - { VI6_DPR_NODE_HSI, VI6_DPR_HSI_ROUTE }, - { VI6_DPR_NODE_HST, VI6_DPR_HST_ROUTE }, - { VI6_DPR_NODE_LIF, 0 }, - { VI6_DPR_NODE_LUT, VI6_DPR_LUT_ROUTE }, - { VI6_DPR_NODE_RPF(0), VI6_DPR_RPF_ROUTE(0) }, - { VI6_DPR_NODE_RPF(1), VI6_DPR_RPF_ROUTE(1) }, - { VI6_DPR_NODE_RPF(2), VI6_DPR_RPF_ROUTE(2) }, - { VI6_DPR_NODE_RPF(3), VI6_DPR_RPF_ROUTE(3) }, - { VI6_DPR_NODE_RPF(4), VI6_DPR_RPF_ROUTE(4) }, - { VI6_DPR_NODE_SRU, VI6_DPR_SRU_ROUTE }, - { VI6_DPR_NODE_UDS(0), VI6_DPR_UDS_ROUTE(0) }, - { VI6_DPR_NODE_UDS(1), VI6_DPR_UDS_ROUTE(1) }, - { VI6_DPR_NODE_UDS(2), VI6_DPR_UDS_ROUTE(2) }, - { VI6_DPR_NODE_WPF(0), 0 }, - { VI6_DPR_NODE_WPF(1), 0 }, - { VI6_DPR_NODE_WPF(2), 0 }, - { VI6_DPR_NODE_WPF(3), 0 }, - }; - unsigned int i; - for (i = 0; i < ARRAY_SIZE(routes); ++i) { - if (routes[i].id == entity->id) { - entity->route = routes[i].reg; + for (i = 0; i < ARRAY_SIZE(vsp1_routes); ++i) { + if (vsp1_routes[i].type == entity->type && + vsp1_routes[i].index == entity->index) { + entity->route = &vsp1_routes[i]; break; } } - if (i == ARRAY_SIZE(routes)) + if (i == ARRAY_SIZE(vsp1_routes)) return -EINVAL; entity->vsp1 = vsp1; diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h index f6fd6988aeb0..7afbd8a7ba66 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.h +++ b/drivers/media/platform/vsp1/vsp1_entity.h @@ -20,6 +20,7 @@ struct vsp1_device; enum vsp1_entity_type { + VSP1_ENTITY_BRU, VSP1_ENTITY_HSI, VSP1_ENTITY_HST, VSP1_ENTITY_LIF, @@ -30,13 +31,31 @@ enum vsp1_entity_type { VSP1_ENTITY_WPF, }; +/* + * struct vsp1_route - Entity routing configuration + * @type: Entity type this routing entry is associated with + * @index: Entity index this routing entry is associated with + * @reg: Output routing configuration register + * @inputs: Target node value for each input + * + * 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. + */ +struct vsp1_route { + enum vsp1_entity_type type; + unsigned int index; + unsigned int reg; + unsigned int inputs[4]; +}; + struct vsp1_entity { struct vsp1_device *vsp1; enum vsp1_entity_type type; unsigned int index; - unsigned int id; - unsigned int route; + const struct vsp1_route *route; struct list_head list_dev; struct list_head list_pipe; @@ -45,6 +64,7 @@ struct vsp1_entity { unsigned int source_pad; struct media_entity *sink; + unsigned int sink_pad; struct v4l2_subdev subdev; struct v4l2_mbus_framefmt *formats; diff --git a/drivers/media/platform/vsp1/vsp1_hsit.c b/drivers/media/platform/vsp1/vsp1_hsit.c index 285485350d82..db2950a73c60 100644 --- a/drivers/media/platform/vsp1/vsp1_hsit.c +++ b/drivers/media/platform/vsp1/vsp1_hsit.c @@ -193,13 +193,10 @@ struct vsp1_hsit *vsp1_hsit_create(struct vsp1_device *vsp1, bool inverse) hsit->inverse = inverse; - if (inverse) { + if (inverse) hsit->entity.type = VSP1_ENTITY_HSI; - hsit->entity.id = VI6_DPR_NODE_HSI; - } else { + else hsit->entity.type = VSP1_ENTITY_HST; - hsit->entity.id = VI6_DPR_NODE_HST; - } ret = vsp1_entity_init(vsp1, &hsit->entity, 2); if (ret < 0) diff --git a/drivers/media/platform/vsp1/vsp1_lif.c b/drivers/media/platform/vsp1/vsp1_lif.c index 135a78957014..d4fb23e9c4a8 100644 --- a/drivers/media/platform/vsp1/vsp1_lif.c +++ b/drivers/media/platform/vsp1/vsp1_lif.c @@ -215,7 +215,6 @@ struct vsp1_lif *vsp1_lif_create(struct vsp1_device *vsp1) return ERR_PTR(-ENOMEM); lif->entity.type = VSP1_ENTITY_LIF; - lif->entity.id = VI6_DPR_NODE_LIF; ret = vsp1_entity_init(vsp1, &lif->entity, 2); if (ret < 0) diff --git a/drivers/media/platform/vsp1/vsp1_lut.c b/drivers/media/platform/vsp1/vsp1_lut.c index 4e9dc7c86ef8..fea36ebe2565 100644 --- a/drivers/media/platform/vsp1/vsp1_lut.c +++ b/drivers/media/platform/vsp1/vsp1_lut.c @@ -229,7 +229,6 @@ struct vsp1_lut *vsp1_lut_create(struct vsp1_device *vsp1) return ERR_PTR(-ENOMEM); lut->entity.type = VSP1_ENTITY_LUT; - lut->entity.id = VI6_DPR_NODE_LUT; ret = vsp1_entity_init(vsp1, &lut->entity, 2); if (ret < 0) diff --git a/drivers/media/platform/vsp1/vsp1_regs.h b/drivers/media/platform/vsp1/vsp1_regs.h index 28650806c20f..3e74b44286f6 100644 --- a/drivers/media/platform/vsp1/vsp1_regs.h +++ b/drivers/media/platform/vsp1/vsp1_regs.h @@ -451,13 +451,111 @@ * BRU Control Registers */ +#define VI6_ROP_NOP 0 +#define VI6_ROP_AND 1 +#define VI6_ROP_AND_REV 2 +#define VI6_ROP_COPY 3 +#define VI6_ROP_AND_INV 4 +#define VI6_ROP_CLEAR 5 +#define VI6_ROP_XOR 6 +#define VI6_ROP_OR 7 +#define VI6_ROP_NOR 8 +#define VI6_ROP_EQUIV 9 +#define VI6_ROP_INVERT 10 +#define VI6_ROP_OR_REV 11 +#define VI6_ROP_COPY_INV 12 +#define VI6_ROP_OR_INV 13 +#define VI6_ROP_NAND 14 +#define VI6_ROP_SET 15 + #define VI6_BRU_INCTRL 0x2c00 +#define VI6_BRU_INCTRL_NRM (1 << 28) +#define VI6_BRU_INCTRL_DnON (1 << (16 + (n))) +#define VI6_BRU_INCTRL_DITHn_OFF (0 << ((n) * 4)) +#define VI6_BRU_INCTRL_DITHn_18BPP (1 << ((n) * 4)) +#define VI6_BRU_INCTRL_DITHn_16BPP (2 << ((n) * 4)) +#define VI6_BRU_INCTRL_DITHn_15BPP (3 << ((n) * 4)) +#define VI6_BRU_INCTRL_DITHn_12BPP (4 << ((n) * 4)) +#define VI6_BRU_INCTRL_DITHn_8BPP (5 << ((n) * 4)) +#define VI6_BRU_INCTRL_DITHn_MASK (7 << ((n) * 4)) +#define VI6_BRU_INCTRL_DITHn_SHIFT ((n) * 4) + #define VI6_BRU_VIRRPF_SIZE 0x2c04 +#define VI6_BRU_VIRRPF_SIZE_HSIZE_MASK (0x1fff << 16) +#define VI6_BRU_VIRRPF_SIZE_HSIZE_SHIFT 16 +#define VI6_BRU_VIRRPF_SIZE_VSIZE_MASK (0x1fff << 0) +#define VI6_BRU_VIRRPF_SIZE_VSIZE_SHIFT 0 + #define VI6_BRU_VIRRPF_LOC 0x2c08 +#define VI6_BRU_VIRRPF_LOC_HCOORD_MASK (0x1fff << 16) +#define VI6_BRU_VIRRPF_LOC_HCOORD_SHIFT 16 +#define VI6_BRU_VIRRPF_LOC_VCOORD_MASK (0x1fff << 0) +#define VI6_BRU_VIRRPF_LOC_VCOORD_SHIFT 0 + #define VI6_BRU_VIRRPF_COL 0x2c0c +#define VI6_BRU_VIRRPF_COL_A_MASK (0xff << 24) +#define VI6_BRU_VIRRPF_COL_A_SHIFT 24 +#define VI6_BRU_VIRRPF_COL_RCR_MASK (0xff << 16) +#define VI6_BRU_VIRRPF_COL_RCR_SHIFT 16 +#define VI6_BRU_VIRRPF_COL_GY_MASK (0xff << 8) +#define VI6_BRU_VIRRPF_COL_GY_SHIFT 8 +#define VI6_BRU_VIRRPF_COL_BCB_MASK (0xff << 0) +#define VI6_BRU_VIRRPF_COL_BCB_SHIFT 0 + #define VI6_BRU_CTRL(n) (0x2c10 + (n) * 8) +#define VI6_BRU_CTRL_RBC (1 << 31) +#define VI6_BRU_CTRL_DSTSEL_BRUIN(n) ((n) << 20) +#define VI6_BRU_CTRL_DSTSEL_VRPF (4 << 20) +#define VI6_BRU_CTRL_DSTSEL_MASK (7 << 20) +#define VI6_BRU_CTRL_SRCSEL_BRUIN(n) ((n) << 16) +#define VI6_BRU_CTRL_SRCSEL_VRPF (4 << 16) +#define VI6_BRU_CTRL_SRCSEL_MASK (7 << 16) +#define VI6_BRU_CTRL_CROP(rop) ((rop) << 4) +#define VI6_BRU_CTRL_CROP_MASK (0xf << 4) +#define VI6_BRU_CTRL_AROP(rop) ((rop) << 0) +#define VI6_BRU_CTRL_AROP_MASK (0xf << 0) + #define VI6_BRU_BLD(n) (0x2c14 + (n) * 8) +#define VI6_BRU_BLD_CBES (1 << 31) +#define VI6_BRU_BLD_CCMDX_DST_A (0 << 28) +#define VI6_BRU_BLD_CCMDX_255_DST_A (1 << 28) +#define VI6_BRU_BLD_CCMDX_SRC_A (2 << 28) +#define VI6_BRU_BLD_CCMDX_255_SRC_A (3 << 28) +#define VI6_BRU_BLD_CCMDX_COEFX (4 << 28) +#define VI6_BRU_BLD_CCMDX_MASK (7 << 28) +#define VI6_BRU_BLD_CCMDY_DST_A (0 << 24) +#define VI6_BRU_BLD_CCMDY_255_DST_A (1 << 24) +#define VI6_BRU_BLD_CCMDY_SRC_A (2 << 24) +#define VI6_BRU_BLD_CCMDY_255_SRC_A (3 << 24) +#define VI6_BRU_BLD_CCMDY_COEFY (4 << 24) +#define VI6_BRU_BLD_CCMDY_MASK (7 << 24) +#define VI6_BRU_BLD_CCMDY_SHIFT 24 +#define VI6_BRU_BLD_ABES (1 << 23) +#define VI6_BRU_BLD_ACMDX_DST_A (0 << 20) +#define VI6_BRU_BLD_ACMDX_255_DST_A (1 << 20) +#define VI6_BRU_BLD_ACMDX_SRC_A (2 << 20) +#define VI6_BRU_BLD_ACMDX_255_SRC_A (3 << 20) +#define VI6_BRU_BLD_ACMDX_COEFX (4 << 20) +#define VI6_BRU_BLD_ACMDX_MASK (7 << 20) +#define VI6_BRU_BLD_ACMDY_DST_A (0 << 16) +#define VI6_BRU_BLD_ACMDY_255_DST_A (1 << 16) +#define VI6_BRU_BLD_ACMDY_SRC_A (2 << 16) +#define VI6_BRU_BLD_ACMDY_255_SRC_A (3 << 16) +#define VI6_BRU_BLD_ACMDY_COEFY (4 << 16) +#define VI6_BRU_BLD_ACMDY_MASK (7 << 16) +#define VI6_BRU_BLD_COEFX_MASK (0xff << 8) +#define VI6_BRU_BLD_COEFX_SHIFT 8 +#define VI6_BRU_BLD_COEFY_MASK (0xff << 0) +#define VI6_BRU_BLD_COEFY_SHIFT 0 + #define VI6_BRU_ROP 0x2c30 +#define VI6_BRU_ROP_DSTSEL_BRUIN(n) ((n) << 20) +#define VI6_BRU_ROP_DSTSEL_VRPF (4 << 20) +#define VI6_BRU_ROP_DSTSEL_MASK (7 << 20) +#define VI6_BRU_ROP_CROP(rop) ((rop) << 4) +#define VI6_BRU_ROP_CROP_MASK (0xf << 4) +#define VI6_BRU_ROP_AROP(rop) ((rop) << 0) +#define VI6_BRU_ROP_AROP_MASK (0xf << 0) /* ----------------------------------------------------------------------------- * HGO Control Registers diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c index 2b04d0f95c62..c3d98642a4aa 100644 --- a/drivers/media/platform/vsp1/vsp1_rpf.c +++ b/drivers/media/platform/vsp1/vsp1_rpf.c @@ -96,8 +96,10 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable) vsp1_rpf_write(rpf, VI6_RPF_INFMT, infmt); vsp1_rpf_write(rpf, VI6_RPF_DSWAP, fmtinfo->swap); - /* Output location. Composing isn't supported yet. */ - vsp1_rpf_write(rpf, VI6_RPF_LOC, 0); + /* Output location */ + vsp1_rpf_write(rpf, VI6_RPF_LOC, + (rpf->location.left << VI6_RPF_LOC_HCOORD_SHIFT) | + (rpf->location.top << VI6_RPF_LOC_VCOORD_SHIFT)); /* Disable alpha, mask and color key. Set the alpha channel to a fixed * value of 255. @@ -176,7 +178,6 @@ struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index) rpf->entity.type = VSP1_ENTITY_RPF; rpf->entity.index = index; - rpf->entity.id = VI6_DPR_NODE_RPF(index); ret = vsp1_entity_init(vsp1, &rpf->entity, 2); if (ret < 0) diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h index 5c5ee81bbeae..b4fb65e58770 100644 --- a/drivers/media/platform/vsp1/vsp1_rwpf.h +++ b/drivers/media/platform/vsp1/vsp1_rwpf.h @@ -30,6 +30,10 @@ struct vsp1_rwpf { unsigned int max_width; unsigned int max_height; + struct { + unsigned int left; + unsigned int top; + } location; struct v4l2_rect crop; unsigned int offsets[2]; diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c index 7ab1a0b2d656..aa0e04c56f3f 100644 --- a/drivers/media/platform/vsp1/vsp1_sru.c +++ b/drivers/media/platform/vsp1/vsp1_sru.c @@ -327,7 +327,6 @@ struct vsp1_sru *vsp1_sru_create(struct vsp1_device *vsp1) return ERR_PTR(-ENOMEM); sru->entity.type = VSP1_ENTITY_SRU; - sru->entity.id = VI6_DPR_NODE_SRU; ret = vsp1_entity_init(vsp1, &sru->entity, 2); if (ret < 0) diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c index 622342ac7770..0293bdbb4401 100644 --- a/drivers/media/platform/vsp1/vsp1_uds.c +++ b/drivers/media/platform/vsp1/vsp1_uds.c @@ -131,7 +131,7 @@ static int uds_s_stream(struct v4l2_subdev *subdev, int enable) return 0; /* Enable multi-tap scaling. */ - vsp1_uds_write(uds, VI6_UDS_CTRL, VI6_UDS_CTRL_BC); + vsp1_uds_write(uds, VI6_UDS_CTRL, VI6_UDS_CTRL_AON | VI6_UDS_CTRL_BC); vsp1_uds_write(uds, VI6_UDS_PASS_BWIDTH, (uds_passband_width(uds->hscale) @@ -139,7 +139,6 @@ static int uds_s_stream(struct v4l2_subdev *subdev, int enable) (uds_passband_width(uds->vscale) << VI6_UDS_PASS_BWIDTH_V_SHIFT)); - /* Set the scaling ratios and the output size. */ format = &uds->entity.formats[UDS_PAD_SOURCE]; @@ -323,7 +322,6 @@ struct vsp1_uds *vsp1_uds_create(struct vsp1_device *vsp1, unsigned int index) uds->entity.type = VSP1_ENTITY_UDS; uds->entity.index = index; - uds->entity.id = VI6_DPR_NODE_UDS(index); ret = vsp1_entity_init(vsp1, &uds->entity, 2); if (ret < 0) diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c index b48f135ffc01..8a1253e51f04 100644 --- a/drivers/media/platform/vsp1/vsp1_video.c +++ b/drivers/media/platform/vsp1/vsp1_video.c @@ -28,6 +28,7 @@ #include <media/videobuf2-dma-contig.h> #include "vsp1.h" +#include "vsp1_bru.h" #include "vsp1_entity.h" #include "vsp1_rwpf.h" #include "vsp1_video.h" @@ -280,6 +281,9 @@ static int vsp1_pipeline_validate_branch(struct vsp1_rwpf *input, struct media_pad *pad; bool uds_found = false; + input->location.left = 0; + input->location.top = 0; + pad = media_entity_remote_pad(&input->entity.pads[RWPF_PAD_SOURCE]); while (1) { @@ -292,6 +296,17 @@ static int vsp1_pipeline_validate_branch(struct vsp1_rwpf *input, entity = to_vsp1_entity(media_entity_to_v4l2_subdev(pad->entity)); + /* A BRU is present in the pipeline, store the compose rectangle + * location in the input RPF for use when configuring the RPF. + */ + if (entity->type == VSP1_ENTITY_BRU) { + struct vsp1_bru *bru = to_bru(&entity->subdev); + struct v4l2_rect *rect = &bru->compose[pad->index]; + + input->location.left = rect->left; + input->location.top = rect->top; + } + /* We've reached the WPF, we're done. */ if (entity->type == VSP1_ENTITY_WPF) break; @@ -363,6 +378,8 @@ static int vsp1_pipeline_validate(struct vsp1_pipeline *pipe, rwpf->video.pipe_index = 0; } else if (e->type == VSP1_ENTITY_LIF) { pipe->lif = e; + } else if (e->type == VSP1_ENTITY_BRU) { + pipe->bru = e; } } @@ -392,6 +409,7 @@ error: pipe->num_video = 0; pipe->num_inputs = 0; pipe->output = NULL; + pipe->bru = NULL; pipe->lif = NULL; return ret; } @@ -430,6 +448,7 @@ static void vsp1_pipeline_cleanup(struct vsp1_pipeline *pipe) pipe->num_video = 0; pipe->num_inputs = 0; pipe->output = NULL; + pipe->bru = NULL; pipe->lif = NULL; } @@ -461,7 +480,7 @@ static int vsp1_pipeline_stop(struct vsp1_pipeline *pipe) list_for_each_entry(entity, &pipe->entities, list_pipe) { if (entity->route) - vsp1_write(entity->vsp1, entity->route, + vsp1_write(entity->vsp1, entity->route->reg, VI6_DPR_NODE_UNUSED); v4l2_subdev_call(&entity->subdev, video, s_stream, 0); @@ -680,11 +699,12 @@ static void vsp1_entity_route_setup(struct vsp1_entity *source) { struct vsp1_entity *sink; - if (source->route == 0) + if (source->route->reg == 0) return; sink = container_of(source->sink, struct vsp1_entity, subdev.entity); - vsp1_write(source->vsp1, source->route, sink->id); + vsp1_write(source->vsp1, source->route->reg, + sink->route->inputs[source->sink_pad]); } static int vsp1_video_start_streaming(struct vb2_queue *vq, unsigned int count) @@ -720,7 +740,7 @@ static int vsp1_video_start_streaming(struct vb2_queue *vq, unsigned int count) return 0; } -static int vsp1_video_stop_streaming(struct vb2_queue *vq) +static void vsp1_video_stop_streaming(struct vb2_queue *vq) { struct vsp1_video *video = vb2_get_drv_priv(vq); struct vsp1_pipeline *pipe = to_vsp1_pipeline(&video->video.entity); @@ -743,8 +763,6 @@ static int vsp1_video_stop_streaming(struct vb2_queue *vq) spin_lock_irqsave(&video->irqlock, flags); INIT_LIST_HEAD(&video->irqqueue); spin_unlock_irqrestore(&video->irqlock, flags); - - return 0; } static struct vb2_ops vsp1_video_queue_qops = { diff --git a/drivers/media/platform/vsp1/vsp1_video.h b/drivers/media/platform/vsp1/vsp1_video.h index 53e4b3745940..c04d48fa2999 100644 --- a/drivers/media/platform/vsp1/vsp1_video.h +++ b/drivers/media/platform/vsp1/vsp1_video.h @@ -75,6 +75,7 @@ struct vsp1_pipeline { unsigned int num_inputs; struct vsp1_rwpf *inputs[VPS1_MAX_RPF]; struct vsp1_rwpf *output; + struct vsp1_entity *bru; struct vsp1_entity *lif; struct list_head entities; diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c index 11a61c601da0..1294340dcb36 100644 --- a/drivers/media/platform/vsp1/vsp1_wpf.c +++ b/drivers/media/platform/vsp1/vsp1_wpf.c @@ -58,13 +58,21 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable) return 0; } - /* Sources */ + /* Sources. If the pipeline has a single input configure it as the + * master layer. Otherwise configure all inputs as sub-layers and + * select the virtual RPF as the master layer. + */ for (i = 0; i < pipe->num_inputs; ++i) { struct vsp1_rwpf *input = pipe->inputs[i]; - srcrpf |= VI6_WPF_SRCRPF_RPF_ACT_MST(input->entity.index); + srcrpf |= pipe->num_inputs == 1 + ? VI6_WPF_SRCRPF_RPF_ACT_MST(input->entity.index) + : VI6_WPF_SRCRPF_RPF_ACT_SUB(input->entity.index); } + if (pipe->num_inputs > 1) + srcrpf |= VI6_WPF_SRCRPF_VIRACT_MST; + vsp1_wpf_write(wpf, VI6_WPF_SRCRPF, srcrpf); /* Destination stride. */ @@ -181,7 +189,6 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index) wpf->entity.type = VSP1_ENTITY_WPF; wpf->entity.index = index; - wpf->entity.id = VI6_DPR_NODE_WPF(index); ret = vsp1_entity_init(vsp1, &wpf->entity, 2); if (ret < 0) |