Commit 113ac3e2 authored by Hans Verkuil's avatar Hans Verkuil

Merge tag 'tags/next-media-renesas-20240619' of...

Merge tag 'tags/next-media-renesas-20240619' of git://git.kernel.org/pub/scm/linux/kernel/git/pinchartl/linux.git

- Conversion of max9286 and adv748x to V4L2 subdev active state
- Cleanups and fixes for the Renesas R-Car VSP and VIN drivers
- Miscellaneous cleanups to V4L2 core
Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
parents bf9817d2 1b9fd2f0
...@@ -199,7 +199,6 @@ module_param(debug, int, 0644); ...@@ -199,7 +199,6 @@ module_param(debug, int, 0644);
}) })
static void __vb2_queue_cancel(struct vb2_queue *q); static void __vb2_queue_cancel(struct vb2_queue *q);
static void __enqueue_in_driver(struct vb2_buffer *vb);
static const char *vb2_state_name(enum vb2_buffer_state s) static const char *vb2_state_name(enum vb2_buffer_state s)
{ {
......
...@@ -114,7 +114,7 @@ static void adv748x_afe_fill_format(struct adv748x_afe *afe, ...@@ -114,7 +114,7 @@ static void adv748x_afe_fill_format(struct adv748x_afe *afe,
{ {
memset(fmt, 0, sizeof(*fmt)); memset(fmt, 0, sizeof(*fmt));
fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; fmt->code = MEDIA_BUS_FMT_UYVY8_1X16;
fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
fmt->field = V4L2_FIELD_ALTERNATE; fmt->field = V4L2_FIELD_ALTERNATE;
...@@ -337,7 +337,7 @@ static int adv748x_afe_enum_mbus_code(struct v4l2_subdev *sd, ...@@ -337,7 +337,7 @@ static int adv748x_afe_enum_mbus_code(struct v4l2_subdev *sd,
if (code->index != 0) if (code->index != 0)
return -EINVAL; return -EINVAL;
code->code = MEDIA_BUS_FMT_UYVY8_2X8; code->code = MEDIA_BUS_FMT_UYVY8_1X16;
return 0; return 0;
} }
......
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/mutex.h>
#include <media/v4l2-ctrls.h> #include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h> #include <media/v4l2-device.h>
...@@ -14,6 +13,15 @@ ...@@ -14,6 +13,15 @@
#include "adv748x.h" #include "adv748x.h"
static const unsigned int adv748x_csi2_txa_fmts[] = {
MEDIA_BUS_FMT_UYVY8_1X16,
MEDIA_BUS_FMT_RGB888_1X24,
};
static const unsigned int adv748x_csi2_txb_fmts[] = {
MEDIA_BUS_FMT_UYVY8_1X16,
};
int adv748x_csi2_set_virtual_channel(struct adv748x_csi2 *tx, unsigned int vc) int adv748x_csi2_set_virtual_channel(struct adv748x_csi2 *tx, unsigned int vc)
{ {
return tx_write(tx, ADV748X_CSI_VC_REF, vc << ADV748X_CSI_VC_REF_SHIFT); return tx_write(tx, ADV748X_CSI_VC_REF, vc << ADV748X_CSI_VC_REF_SHIFT);
...@@ -59,7 +67,33 @@ static int adv748x_csi2_register_link(struct adv748x_csi2 *tx, ...@@ -59,7 +67,33 @@ static int adv748x_csi2_register_link(struct adv748x_csi2 *tx,
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
* v4l2_subdev_internal_ops * v4l2_subdev_internal_ops
* */
static int adv748x_csi2_init_state(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state)
{
static const struct v4l2_mbus_framefmt adv748x_csi2_default_fmt = {
.width = 1280,
.height = 720,
.code = MEDIA_BUS_FMT_UYVY8_1X16,
.colorspace = V4L2_COLORSPACE_SRGB,
.field = V4L2_FIELD_NONE,
.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT,
.quantization = V4L2_QUANTIZATION_DEFAULT,
.xfer_func = V4L2_XFER_FUNC_DEFAULT,
};
struct v4l2_mbus_framefmt *fmt;
fmt = v4l2_subdev_state_get_format(state, ADV748X_CSI2_SINK);
*fmt = adv748x_csi2_default_fmt;
fmt = v4l2_subdev_state_get_format(state, ADV748X_CSI2_SOURCE);
*fmt = adv748x_csi2_default_fmt;
return 0;
}
/*
* We use the internal registered operation to be able to ensure that our * We use the internal registered operation to be able to ensure that our
* incremental subdevices (not connected in the forward path) can be registered * incremental subdevices (not connected in the forward path) can be registered
* against the resulting video path and media device. * against the resulting video path and media device.
...@@ -109,6 +143,7 @@ static int adv748x_csi2_registered(struct v4l2_subdev *sd) ...@@ -109,6 +143,7 @@ static int adv748x_csi2_registered(struct v4l2_subdev *sd)
} }
static const struct v4l2_subdev_internal_ops adv748x_csi2_internal_ops = { static const struct v4l2_subdev_internal_ops adv748x_csi2_internal_ops = {
.init_state = adv748x_csi2_init_state,
.registered = adv748x_csi2_registered, .registered = adv748x_csi2_registered,
}; };
...@@ -139,39 +174,55 @@ static const struct v4l2_subdev_video_ops adv748x_csi2_video_ops = { ...@@ -139,39 +174,55 @@ static const struct v4l2_subdev_video_ops adv748x_csi2_video_ops = {
* But we must support setting the pad formats for format propagation. * But we must support setting the pad formats for format propagation.
*/ */
static struct v4l2_mbus_framefmt * static int adv748x_csi2_enum_mbus_code(struct v4l2_subdev *sd,
adv748x_csi2_get_pad_format(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code)
unsigned int pad, u32 which)
{ {
struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd); struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
const unsigned int *codes = is_txa(tx) ?
adv748x_csi2_txa_fmts :
adv748x_csi2_txb_fmts;
size_t num_fmts = is_txa(tx) ? ARRAY_SIZE(adv748x_csi2_txa_fmts)
: ARRAY_SIZE(adv748x_csi2_txb_fmts);
if (which == V4L2_SUBDEV_FORMAT_TRY) /*
return v4l2_subdev_state_get_format(sd_state, pad); * The format available on the source pad is the one applied on the sink
* pad.
*/
if (code->pad == ADV748X_CSI2_SOURCE) {
struct v4l2_mbus_framefmt *fmt;
return &tx->format; if (code->index)
} return -EINVAL;
static int adv748x_csi2_get_format(struct v4l2_subdev *sd, fmt = v4l2_subdev_state_get_format(sd_state, ADV748X_CSI2_SINK);
struct v4l2_subdev_state *sd_state, code->code = fmt->code;
struct v4l2_subdev_format *sdformat)
{
struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
struct adv748x_state *state = tx->state;
struct v4l2_mbus_framefmt *mbusformat;
mbusformat = adv748x_csi2_get_pad_format(sd, sd_state, sdformat->pad, return 0;
sdformat->which); }
if (!mbusformat)
if (code->index >= num_fmts)
return -EINVAL; return -EINVAL;
mutex_lock(&state->mutex); code->code = codes[code->index];
sdformat->format = *mbusformat; return 0;
}
mutex_unlock(&state->mutex); static bool adv748x_csi2_is_fmt_supported(struct adv748x_csi2 *tx, u32 code)
{
const unsigned int *codes = is_txa(tx) ?
adv748x_csi2_txa_fmts :
adv748x_csi2_txb_fmts;
size_t num_fmts = is_txa(tx) ? ARRAY_SIZE(adv748x_csi2_txa_fmts)
: ARRAY_SIZE(adv748x_csi2_txb_fmts);
for (unsigned int i = 0; i < num_fmts; i++) {
if (codes[i] == code)
return true;
}
return 0; return false;
} }
static int adv748x_csi2_set_format(struct v4l2_subdev *sd, static int adv748x_csi2_set_format(struct v4l2_subdev *sd,
...@@ -179,38 +230,26 @@ static int adv748x_csi2_set_format(struct v4l2_subdev *sd, ...@@ -179,38 +230,26 @@ static int adv748x_csi2_set_format(struct v4l2_subdev *sd,
struct v4l2_subdev_format *sdformat) struct v4l2_subdev_format *sdformat)
{ {
struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd); struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
struct adv748x_state *state = tx->state;
struct v4l2_mbus_framefmt *mbusformat; struct v4l2_mbus_framefmt *mbusformat;
int ret = 0;
mbusformat = adv748x_csi2_get_pad_format(sd, sd_state, sdformat->pad,
sdformat->which);
if (!mbusformat)
return -EINVAL;
mutex_lock(&state->mutex);
if (sdformat->pad == ADV748X_CSI2_SOURCE) { if (sdformat->pad == ADV748X_CSI2_SOURCE)
const struct v4l2_mbus_framefmt *sink_fmt; return v4l2_subdev_get_fmt(sd, sd_state, sdformat);
sink_fmt = adv748x_csi2_get_pad_format(sd, sd_state, /*
ADV748X_CSI2_SINK, * Make sure the format is supported, if not default it to
sdformat->which); * UYVY8 as it's supported by both TXes.
*/
if (!sink_fmt) { if (!adv748x_csi2_is_fmt_supported(tx, sdformat->format.code))
ret = -EINVAL; sdformat->format.code = MEDIA_BUS_FMT_UYVY8_1X16;
goto unlock;
}
sdformat->format = *sink_fmt;
}
mbusformat = v4l2_subdev_state_get_format(sd_state, sdformat->pad);
*mbusformat = sdformat->format; *mbusformat = sdformat->format;
unlock: /* Propagate format to the source pad. */
mutex_unlock(&state->mutex); mbusformat = v4l2_subdev_state_get_format(sd_state, ADV748X_CSI2_SOURCE);
*mbusformat = sdformat->format;
return ret; return 0;
} }
static int adv748x_csi2_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad, static int adv748x_csi2_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad,
...@@ -228,7 +267,8 @@ static int adv748x_csi2_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad ...@@ -228,7 +267,8 @@ static int adv748x_csi2_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad
} }
static const struct v4l2_subdev_pad_ops adv748x_csi2_pad_ops = { static const struct v4l2_subdev_pad_ops adv748x_csi2_pad_ops = {
.get_fmt = adv748x_csi2_get_format, .enum_mbus_code = adv748x_csi2_enum_mbus_code,
.get_fmt = v4l2_subdev_get_fmt,
.set_fmt = adv748x_csi2_set_format, .set_fmt = adv748x_csi2_set_format,
.get_mbus_config = adv748x_csi2_get_mbus_config, .get_mbus_config = adv748x_csi2_get_mbus_config,
}; };
...@@ -320,6 +360,11 @@ int adv748x_csi2_init(struct adv748x_state *state, struct adv748x_csi2 *tx) ...@@ -320,6 +360,11 @@ int adv748x_csi2_init(struct adv748x_state *state, struct adv748x_csi2 *tx)
if (ret) if (ret)
goto err_cleanup_subdev; goto err_cleanup_subdev;
tx->sd.state_lock = &state->mutex;
ret = v4l2_subdev_init_finalize(&tx->sd);
if (ret)
goto err_free_ctrl;
ret = v4l2_async_register_subdev(&tx->sd); ret = v4l2_async_register_subdev(&tx->sd);
if (ret) if (ret)
goto err_free_ctrl; goto err_free_ctrl;
......
...@@ -75,7 +75,6 @@ enum adv748x_csi2_pads { ...@@ -75,7 +75,6 @@ enum adv748x_csi2_pads {
struct adv748x_csi2 { struct adv748x_csi2 {
struct adv748x_state *state; struct adv748x_state *state;
struct v4l2_mbus_framefmt format;
unsigned int page; unsigned int page;
unsigned int port; unsigned int port;
unsigned int num_lanes; unsigned int num_lanes;
......
This diff is collapsed.
...@@ -587,7 +587,8 @@ enum rcar_csi2_pads { ...@@ -587,7 +587,8 @@ enum rcar_csi2_pads {
struct rcar_csi2_info { struct rcar_csi2_info {
int (*init_phtw)(struct rcar_csi2 *priv, unsigned int mbps); int (*init_phtw)(struct rcar_csi2 *priv, unsigned int mbps);
int (*phy_post_init)(struct rcar_csi2 *priv); int (*phy_post_init)(struct rcar_csi2 *priv);
int (*start_receiver)(struct rcar_csi2 *priv); int (*start_receiver)(struct rcar_csi2 *priv,
struct v4l2_subdev_state *state);
void (*enter_standby)(struct rcar_csi2 *priv); void (*enter_standby)(struct rcar_csi2 *priv);
const struct rcsi2_mbps_reg *hsfreqrange; const struct rcsi2_mbps_reg *hsfreqrange;
unsigned int csi0clkfreqrange; unsigned int csi0clkfreqrange;
...@@ -613,8 +614,6 @@ struct rcar_csi2 { ...@@ -613,8 +614,6 @@ struct rcar_csi2 {
int channel_vc[4]; int channel_vc[4];
struct mutex lock; /* Protects mf and stream_count. */
struct v4l2_mbus_framefmt mf;
int stream_count; int stream_count;
bool cphy; bool cphy;
...@@ -632,6 +631,16 @@ static inline struct rcar_csi2 *notifier_to_csi2(struct v4l2_async_notifier *n) ...@@ -632,6 +631,16 @@ static inline struct rcar_csi2 *notifier_to_csi2(struct v4l2_async_notifier *n)
return container_of(n, struct rcar_csi2, notifier); return container_of(n, struct rcar_csi2, notifier);
} }
static unsigned int rcsi2_num_pads(const struct rcar_csi2 *priv)
{
/* Used together with R-Car ISP: one sink and one source pad. */
if (priv->info->use_isp)
return 2;
/* Used together with R-Car VIN: one sink and four source pads. */
return 5;
}
static u32 rcsi2_read(struct rcar_csi2 *priv, unsigned int reg) static u32 rcsi2_read(struct rcar_csi2 *priv, unsigned int reg)
{ {
return ioread32(priv->base + reg); return ioread32(priv->base + reg);
...@@ -808,20 +817,25 @@ static int rcsi2_get_active_lanes(struct rcar_csi2 *priv, ...@@ -808,20 +817,25 @@ static int rcsi2_get_active_lanes(struct rcar_csi2 *priv,
return 0; return 0;
} }
static int rcsi2_start_receiver_gen3(struct rcar_csi2 *priv) static int rcsi2_start_receiver_gen3(struct rcar_csi2 *priv,
struct v4l2_subdev_state *state)
{ {
const struct rcar_csi2_format *format; const struct rcar_csi2_format *format;
u32 phycnt, vcdt = 0, vcdt2 = 0, fld = 0; u32 phycnt, vcdt = 0, vcdt2 = 0, fld = 0;
const struct v4l2_mbus_framefmt *fmt;
unsigned int lanes; unsigned int lanes;
unsigned int i; unsigned int i;
int mbps, ret; int mbps, ret;
/* Use the format on the sink pad to compute the receiver config. */
fmt = v4l2_subdev_state_get_format(state, RCAR_CSI2_SINK);
dev_dbg(priv->dev, "Input size (%ux%u%c)\n", dev_dbg(priv->dev, "Input size (%ux%u%c)\n",
priv->mf.width, priv->mf.height, fmt->width, fmt->height,
priv->mf.field == V4L2_FIELD_NONE ? 'p' : 'i'); fmt->field == V4L2_FIELD_NONE ? 'p' : 'i');
/* Code is validated in set_fmt. */ /* Code is validated in set_fmt. */
format = rcsi2_code_to_fmt(priv->mf.code); format = rcsi2_code_to_fmt(fmt->code);
if (!format) if (!format)
return -EINVAL; return -EINVAL;
...@@ -849,11 +863,11 @@ static int rcsi2_start_receiver_gen3(struct rcar_csi2 *priv) ...@@ -849,11 +863,11 @@ static int rcsi2_start_receiver_gen3(struct rcar_csi2 *priv)
vcdt2 |= vcdt_part << ((i % 2) * 16); vcdt2 |= vcdt_part << ((i % 2) * 16);
} }
if (priv->mf.field == V4L2_FIELD_ALTERNATE) { if (fmt->field == V4L2_FIELD_ALTERNATE) {
fld = FLD_DET_SEL(1) | FLD_FLD_EN4 | FLD_FLD_EN3 | FLD_FLD_EN2 fld = FLD_DET_SEL(1) | FLD_FLD_EN4 | FLD_FLD_EN3 | FLD_FLD_EN2
| FLD_FLD_EN; | FLD_FLD_EN;
if (priv->mf.height == 240) if (fmt->height == 240)
fld |= FLD_FLD_NUM(0); fld |= FLD_FLD_NUM(0);
else else
fld |= FLD_FLD_NUM(1); fld |= FLD_FLD_NUM(1);
...@@ -1049,15 +1063,18 @@ static int rcsi2_c_phy_setting_v4h(struct rcar_csi2 *priv, int msps) ...@@ -1049,15 +1063,18 @@ static int rcsi2_c_phy_setting_v4h(struct rcar_csi2 *priv, int msps)
return 0; return 0;
} }
static int rcsi2_start_receiver_v4h(struct rcar_csi2 *priv) static int rcsi2_start_receiver_v4h(struct rcar_csi2 *priv,
struct v4l2_subdev_state *state)
{ {
const struct rcar_csi2_format *format; const struct rcar_csi2_format *format;
const struct v4l2_mbus_framefmt *fmt;
unsigned int lanes; unsigned int lanes;
int msps; int msps;
int ret; int ret;
/* Calculate parameters */ /* Use the format on the sink pad to compute the receiver config. */
format = rcsi2_code_to_fmt(priv->mf.code); fmt = v4l2_subdev_state_get_format(state, RCAR_CSI2_SINK);
format = rcsi2_code_to_fmt(fmt->code);
if (!format) if (!format)
return -EINVAL; return -EINVAL;
...@@ -1114,7 +1131,7 @@ static int rcsi2_start_receiver_v4h(struct rcar_csi2 *priv) ...@@ -1114,7 +1131,7 @@ static int rcsi2_start_receiver_v4h(struct rcar_csi2 *priv)
return 0; return 0;
} }
static int rcsi2_start(struct rcar_csi2 *priv) static int rcsi2_start(struct rcar_csi2 *priv, struct v4l2_subdev_state *state)
{ {
int ret; int ret;
...@@ -1122,7 +1139,7 @@ static int rcsi2_start(struct rcar_csi2 *priv) ...@@ -1122,7 +1139,7 @@ static int rcsi2_start(struct rcar_csi2 *priv)
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = priv->info->start_receiver(priv); ret = priv->info->start_receiver(priv, state);
if (ret) { if (ret) {
rcsi2_enter_standby(priv); rcsi2_enter_standby(priv);
return ret; return ret;
...@@ -1146,17 +1163,16 @@ static void rcsi2_stop(struct rcar_csi2 *priv) ...@@ -1146,17 +1163,16 @@ static void rcsi2_stop(struct rcar_csi2 *priv)
static int rcsi2_s_stream(struct v4l2_subdev *sd, int enable) static int rcsi2_s_stream(struct v4l2_subdev *sd, int enable)
{ {
struct rcar_csi2 *priv = sd_to_csi2(sd); struct rcar_csi2 *priv = sd_to_csi2(sd);
struct v4l2_subdev_state *state;
int ret = 0; int ret = 0;
mutex_lock(&priv->lock); if (!priv->remote)
return -ENODEV;
if (!priv->remote) { state = v4l2_subdev_lock_and_get_active_state(&priv->subdev);
ret = -ENODEV;
goto out;
}
if (enable && priv->stream_count == 0) { if (enable && priv->stream_count == 0) {
ret = rcsi2_start(priv); ret = rcsi2_start(priv, state);
if (ret) if (ret)
goto out; goto out;
} else if (!enable && priv->stream_count == 1) { } else if (!enable && priv->stream_count == 1) {
...@@ -1165,49 +1181,29 @@ static int rcsi2_s_stream(struct v4l2_subdev *sd, int enable) ...@@ -1165,49 +1181,29 @@ static int rcsi2_s_stream(struct v4l2_subdev *sd, int enable)
priv->stream_count += enable ? 1 : -1; priv->stream_count += enable ? 1 : -1;
out: out:
mutex_unlock(&priv->lock); v4l2_subdev_unlock_state(state);
return ret; return ret;
} }
static int rcsi2_set_pad_format(struct v4l2_subdev *sd, static int rcsi2_set_pad_format(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state, struct v4l2_subdev_state *state,
struct v4l2_subdev_format *format) struct v4l2_subdev_format *format)
{ {
struct rcar_csi2 *priv = sd_to_csi2(sd); struct rcar_csi2 *priv = sd_to_csi2(sd);
struct v4l2_mbus_framefmt *framefmt; unsigned int num_pads = rcsi2_num_pads(priv);
mutex_lock(&priv->lock); if (format->pad > RCAR_CSI2_SINK)
return v4l2_subdev_get_fmt(sd, state, format);
if (!rcsi2_code_to_fmt(format->format.code)) if (!rcsi2_code_to_fmt(format->format.code))
format->format.code = rcar_csi2_formats[0].code; format->format.code = rcar_csi2_formats[0].code;
if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) { *v4l2_subdev_state_get_format(state, format->pad) = format->format;
priv->mf = format->format;
} else {
framefmt = v4l2_subdev_state_get_format(sd_state, 0);
*framefmt = format->format;
}
mutex_unlock(&priv->lock); /* Propagate the format to the source pads. */
for (unsigned int i = RCAR_CSI2_SOURCE_VC0; i < num_pads; i++)
return 0; *v4l2_subdev_state_get_format(state, i) = format->format;
}
static int rcsi2_get_pad_format(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct rcar_csi2 *priv = sd_to_csi2(sd);
mutex_lock(&priv->lock);
if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
format->format = priv->mf;
else
format->format = *v4l2_subdev_state_get_format(sd_state, 0);
mutex_unlock(&priv->lock);
return 0; return 0;
} }
...@@ -1218,7 +1214,7 @@ static const struct v4l2_subdev_video_ops rcar_csi2_video_ops = { ...@@ -1218,7 +1214,7 @@ static const struct v4l2_subdev_video_ops rcar_csi2_video_ops = {
static const struct v4l2_subdev_pad_ops rcar_csi2_pad_ops = { static const struct v4l2_subdev_pad_ops rcar_csi2_pad_ops = {
.set_fmt = rcsi2_set_pad_format, .set_fmt = rcsi2_set_pad_format,
.get_fmt = rcsi2_get_pad_format, .get_fmt = v4l2_subdev_get_fmt,
}; };
static const struct v4l2_subdev_ops rcar_csi2_subdev_ops = { static const struct v4l2_subdev_ops rcar_csi2_subdev_ops = {
...@@ -1226,6 +1222,33 @@ static const struct v4l2_subdev_ops rcar_csi2_subdev_ops = { ...@@ -1226,6 +1222,33 @@ static const struct v4l2_subdev_ops rcar_csi2_subdev_ops = {
.pad = &rcar_csi2_pad_ops, .pad = &rcar_csi2_pad_ops,
}; };
static int rcsi2_init_state(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state)
{
struct rcar_csi2 *priv = sd_to_csi2(sd);
unsigned int num_pads = rcsi2_num_pads(priv);
static const struct v4l2_mbus_framefmt rcar_csi2_default_fmt = {
.width = 1920,
.height = 1080,
.code = MEDIA_BUS_FMT_RGB888_1X24,
.colorspace = V4L2_COLORSPACE_SRGB,
.field = V4L2_FIELD_NONE,
.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT,
.quantization = V4L2_QUANTIZATION_DEFAULT,
.xfer_func = V4L2_XFER_FUNC_DEFAULT,
};
for (unsigned int i = RCAR_CSI2_SINK; i < num_pads; i++)
*v4l2_subdev_state_get_format(state, i) = rcar_csi2_default_fmt;
return 0;
}
static const struct v4l2_subdev_internal_ops rcar_csi2_internal_ops = {
.init_state = rcsi2_init_state,
};
static irqreturn_t rcsi2_irq(int irq, void *data) static irqreturn_t rcsi2_irq(int irq, void *data)
{ {
struct rcar_csi2 *priv = data; struct rcar_csi2 *priv = data;
...@@ -1251,14 +1274,17 @@ static irqreturn_t rcsi2_irq(int irq, void *data) ...@@ -1251,14 +1274,17 @@ static irqreturn_t rcsi2_irq(int irq, void *data)
static irqreturn_t rcsi2_irq_thread(int irq, void *data) static irqreturn_t rcsi2_irq_thread(int irq, void *data)
{ {
struct v4l2_subdev_state *state;
struct rcar_csi2 *priv = data; struct rcar_csi2 *priv = data;
mutex_lock(&priv->lock); state = v4l2_subdev_lock_and_get_active_state(&priv->subdev);
rcsi2_stop(priv); rcsi2_stop(priv);
usleep_range(1000, 2000); usleep_range(1000, 2000);
if (rcsi2_start(priv)) if (rcsi2_start(priv, state))
dev_warn(priv->dev, "Failed to restart CSI-2 receiver\n"); dev_warn(priv->dev, "Failed to restart CSI-2 receiver\n");
mutex_unlock(&priv->lock);
v4l2_subdev_unlock_state(state);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -1870,23 +1896,23 @@ static int rcsi2_probe(struct platform_device *pdev) ...@@ -1870,23 +1896,23 @@ static int rcsi2_probe(struct platform_device *pdev)
priv->dev = &pdev->dev; priv->dev = &pdev->dev;
mutex_init(&priv->lock);
priv->stream_count = 0; priv->stream_count = 0;
ret = rcsi2_probe_resources(priv, pdev); ret = rcsi2_probe_resources(priv, pdev);
if (ret) { if (ret) {
dev_err(priv->dev, "Failed to get resources\n"); dev_err(priv->dev, "Failed to get resources\n");
goto error_mutex; return ret;
} }
platform_set_drvdata(pdev, priv); platform_set_drvdata(pdev, priv);
ret = rcsi2_parse_dt(priv); ret = rcsi2_parse_dt(priv);
if (ret) if (ret)
goto error_mutex; return ret;
priv->subdev.owner = THIS_MODULE; priv->subdev.owner = THIS_MODULE;
priv->subdev.dev = &pdev->dev; priv->subdev.dev = &pdev->dev;
priv->subdev.internal_ops = &rcar_csi2_internal_ops;
v4l2_subdev_init(&priv->subdev, &rcar_csi2_subdev_ops); v4l2_subdev_init(&priv->subdev, &rcar_csi2_subdev_ops);
v4l2_set_subdevdata(&priv->subdev, &pdev->dev); v4l2_set_subdevdata(&priv->subdev, &pdev->dev);
snprintf(priv->subdev.name, sizeof(priv->subdev.name), "%s %s", snprintf(priv->subdev.name, sizeof(priv->subdev.name), "%s %s",
...@@ -1896,7 +1922,7 @@ static int rcsi2_probe(struct platform_device *pdev) ...@@ -1896,7 +1922,7 @@ static int rcsi2_probe(struct platform_device *pdev)
priv->subdev.entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER; priv->subdev.entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
priv->subdev.entity.ops = &rcar_csi2_entity_ops; priv->subdev.entity.ops = &rcar_csi2_entity_ops;
num_pads = priv->info->use_isp ? 2 : NR_OF_RCAR_CSI2_PAD; num_pads = rcsi2_num_pads(priv);
priv->pads[RCAR_CSI2_SINK].flags = MEDIA_PAD_FL_SINK; priv->pads[RCAR_CSI2_SINK].flags = MEDIA_PAD_FL_SINK;
for (i = RCAR_CSI2_SOURCE_VC0; i < num_pads; i++) for (i = RCAR_CSI2_SOURCE_VC0; i < num_pads; i++)
...@@ -1912,19 +1938,25 @@ static int rcsi2_probe(struct platform_device *pdev) ...@@ -1912,19 +1938,25 @@ static int rcsi2_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev); pm_runtime_enable(&pdev->dev);
ret = v4l2_subdev_init_finalize(&priv->subdev);
if (ret)
goto error_pm_runtime;
ret = v4l2_async_register_subdev(&priv->subdev); ret = v4l2_async_register_subdev(&priv->subdev);
if (ret < 0) if (ret < 0)
goto error_async; goto error_subdev;
dev_info(priv->dev, "%d lanes found\n", priv->lanes); dev_info(priv->dev, "%d lanes found\n", priv->lanes);
return 0; return 0;
error_subdev:
v4l2_subdev_cleanup(&priv->subdev);
error_pm_runtime:
pm_runtime_disable(&pdev->dev);
error_async: error_async:
v4l2_async_nf_unregister(&priv->notifier); v4l2_async_nf_unregister(&priv->notifier);
v4l2_async_nf_cleanup(&priv->notifier); v4l2_async_nf_cleanup(&priv->notifier);
error_mutex:
mutex_destroy(&priv->lock);
return ret; return ret;
} }
...@@ -1936,10 +1968,9 @@ static void rcsi2_remove(struct platform_device *pdev) ...@@ -1936,10 +1968,9 @@ static void rcsi2_remove(struct platform_device *pdev)
v4l2_async_nf_unregister(&priv->notifier); v4l2_async_nf_unregister(&priv->notifier);
v4l2_async_nf_cleanup(&priv->notifier); v4l2_async_nf_cleanup(&priv->notifier);
v4l2_async_unregister_subdev(&priv->subdev); v4l2_async_unregister_subdev(&priv->subdev);
v4l2_subdev_cleanup(&priv->subdev);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
mutex_destroy(&priv->lock);
} }
static struct platform_driver rcar_csi2_pdrv = { static struct platform_driver rcar_csi2_pdrv = {
......
...@@ -742,12 +742,22 @@ static int rvin_setup(struct rvin_dev *vin) ...@@ -742,12 +742,22 @@ static int rvin_setup(struct rvin_dev *vin)
*/ */
switch (vin->mbus_code) { switch (vin->mbus_code) {
case MEDIA_BUS_FMT_YUYV8_1X16: case MEDIA_BUS_FMT_YUYV8_1X16:
/* BT.601/BT.1358 16bit YCbCr422 */ if (vin->is_csi)
vnmc |= VNMC_INF_YUV16; /* YCbCr422 8-bit */
vnmc |= VNMC_INF_YUV8_BT601;
else
/* BT.601/BT.1358 16bit YCbCr422 */
vnmc |= VNMC_INF_YUV16;
input_is_yuv = true; input_is_yuv = true;
break; break;
case MEDIA_BUS_FMT_UYVY8_1X16: case MEDIA_BUS_FMT_UYVY8_1X16:
vnmc |= VNMC_INF_YUV16 | VNMC_YCAL; if (vin->is_csi)
/* YCbCr422 8-bit */
vnmc |= VNMC_INF_YUV8_BT601;
else
/* BT.601/BT.1358 16bit YCbCr422 */
vnmc |= VNMC_INF_YUV16;
vnmc |= VNMC_YCAL;
input_is_yuv = true; input_is_yuv = true;
break; break;
case MEDIA_BUS_FMT_UYVY8_2X8: case MEDIA_BUS_FMT_UYVY8_2X8:
......
...@@ -96,13 +96,6 @@ static int brx_enum_frame_size(struct v4l2_subdev *subdev, ...@@ -96,13 +96,6 @@ static int brx_enum_frame_size(struct v4l2_subdev *subdev,
return 0; return 0;
} }
static struct v4l2_rect *brx_get_compose(struct vsp1_brx *brx,
struct v4l2_subdev_state *sd_state,
unsigned int pad)
{
return v4l2_subdev_state_get_compose(sd_state, pad);
}
static void brx_try_format(struct vsp1_brx *brx, static void brx_try_format(struct vsp1_brx *brx,
struct v4l2_subdev_state *sd_state, struct v4l2_subdev_state *sd_state,
unsigned int pad, struct v4l2_mbus_framefmt *fmt) unsigned int pad, struct v4l2_mbus_framefmt *fmt)
...@@ -119,8 +112,8 @@ static void brx_try_format(struct vsp1_brx *brx, ...@@ -119,8 +112,8 @@ static void brx_try_format(struct vsp1_brx *brx,
default: default:
/* The BRx can't perform format conversion. */ /* The BRx can't perform format conversion. */
format = vsp1_entity_get_pad_format(&brx->entity, sd_state, format = v4l2_subdev_state_get_format(sd_state,
BRX_PAD_SINK(0)); BRX_PAD_SINK(0));
fmt->code = format->code; fmt->code = format->code;
break; break;
} }
...@@ -150,14 +143,14 @@ static int brx_set_format(struct v4l2_subdev *subdev, ...@@ -150,14 +143,14 @@ static int brx_set_format(struct v4l2_subdev *subdev,
brx_try_format(brx, state, fmt->pad, &fmt->format); brx_try_format(brx, state, fmt->pad, &fmt->format);
format = vsp1_entity_get_pad_format(&brx->entity, state, fmt->pad); format = v4l2_subdev_state_get_format(state, fmt->pad);
*format = fmt->format; *format = fmt->format;
/* Reset the compose rectangle. */ /* Reset the compose rectangle. */
if (fmt->pad != brx->entity.source_pad) { if (fmt->pad != brx->entity.source_pad) {
struct v4l2_rect *compose; struct v4l2_rect *compose;
compose = brx_get_compose(brx, state, fmt->pad); compose = v4l2_subdev_state_get_compose(state, fmt->pad);
compose->left = 0; compose->left = 0;
compose->top = 0; compose->top = 0;
compose->width = format->width; compose->width = format->width;
...@@ -169,8 +162,7 @@ static int brx_set_format(struct v4l2_subdev *subdev, ...@@ -169,8 +162,7 @@ static int brx_set_format(struct v4l2_subdev *subdev,
unsigned int i; unsigned int i;
for (i = 0; i <= brx->entity.source_pad; ++i) { for (i = 0; i <= brx->entity.source_pad; ++i) {
format = vsp1_entity_get_pad_format(&brx->entity, format = v4l2_subdev_state_get_format(state, i);
state, i);
format->code = fmt->format.code; format->code = fmt->format.code;
} }
} }
...@@ -205,7 +197,7 @@ static int brx_get_selection(struct v4l2_subdev *subdev, ...@@ -205,7 +197,7 @@ static int brx_get_selection(struct v4l2_subdev *subdev,
return -EINVAL; return -EINVAL;
mutex_lock(&brx->entity.lock); mutex_lock(&brx->entity.lock);
sel->r = *brx_get_compose(brx, state, sel->pad); sel->r = *v4l2_subdev_state_get_compose(state, sel->pad);
mutex_unlock(&brx->entity.lock); mutex_unlock(&brx->entity.lock);
return 0; return 0;
...@@ -242,8 +234,7 @@ static int brx_set_selection(struct v4l2_subdev *subdev, ...@@ -242,8 +234,7 @@ static int brx_set_selection(struct v4l2_subdev *subdev,
* The compose rectangle top left corner must be inside the output * The compose rectangle top left corner must be inside the output
* frame. * frame.
*/ */
format = vsp1_entity_get_pad_format(&brx->entity, state, format = v4l2_subdev_state_get_format(state, brx->entity.source_pad);
brx->entity.source_pad);
sel->r.left = clamp_t(unsigned int, sel->r.left, 0, format->width - 1); 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); sel->r.top = clamp_t(unsigned int, sel->r.top, 0, format->height - 1);
...@@ -251,11 +242,11 @@ static int brx_set_selection(struct v4l2_subdev *subdev, ...@@ -251,11 +242,11 @@ static int brx_set_selection(struct v4l2_subdev *subdev,
* Scaling isn't supported, the compose rectangle size must be identical * Scaling isn't supported, the compose rectangle size must be identical
* to the sink format size. * to the sink format size.
*/ */
format = vsp1_entity_get_pad_format(&brx->entity, state, sel->pad); format = v4l2_subdev_state_get_format(state, sel->pad);
sel->r.width = format->width; sel->r.width = format->width;
sel->r.height = format->height; sel->r.height = format->height;
compose = brx_get_compose(brx, state, sel->pad); compose = v4l2_subdev_state_get_compose(state, sel->pad);
*compose = sel->r; *compose = sel->r;
done: done:
...@@ -281,6 +272,7 @@ static const struct v4l2_subdev_ops brx_ops = { ...@@ -281,6 +272,7 @@ static const struct v4l2_subdev_ops brx_ops = {
*/ */
static void brx_configure_stream(struct vsp1_entity *entity, static void brx_configure_stream(struct vsp1_entity *entity,
struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe, struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl, struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb) struct vsp1_dl_body *dlb)
...@@ -290,8 +282,7 @@ static void brx_configure_stream(struct vsp1_entity *entity, ...@@ -290,8 +282,7 @@ static void brx_configure_stream(struct vsp1_entity *entity,
unsigned int flags; unsigned int flags;
unsigned int i; unsigned int i;
format = vsp1_entity_get_pad_format(&brx->entity, brx->entity.state, format = v4l2_subdev_state_get_format(state, brx->entity.source_pad);
brx->entity.source_pad);
/* /*
* The hardware is extremely flexible but we have no userspace API to * The hardware is extremely flexible but we have no userspace API to
......
...@@ -170,6 +170,7 @@ static const struct v4l2_subdev_ops clu_ops = { ...@@ -170,6 +170,7 @@ static const struct v4l2_subdev_ops clu_ops = {
*/ */
static void clu_configure_stream(struct vsp1_entity *entity, static void clu_configure_stream(struct vsp1_entity *entity,
struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe, struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl, struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb) struct vsp1_dl_body *dlb)
...@@ -181,8 +182,7 @@ static void clu_configure_stream(struct vsp1_entity *entity, ...@@ -181,8 +182,7 @@ static void clu_configure_stream(struct vsp1_entity *entity,
* The yuv_mode can't be changed during streaming. Cache it internally * The yuv_mode can't be changed during streaming. Cache it internally
* for future runtime configuration calls. * for future runtime configuration calls.
*/ */
format = vsp1_entity_get_pad_format(&clu->entity, clu->entity.state, format = v4l2_subdev_state_get_format(state, CLU_PAD_SINK);
CLU_PAD_SINK);
clu->yuv_mode = format->code == MEDIA_BUS_FMT_AYUV8_1X32; clu->yuv_mode = format->code == MEDIA_BUS_FMT_AYUV8_1X32;
} }
......
...@@ -317,7 +317,10 @@ static int vsp1_du_pipeline_setup_brx(struct vsp1_device *vsp1, ...@@ -317,7 +317,10 @@ static int vsp1_du_pipeline_setup_brx(struct vsp1_device *vsp1,
list_add_tail(&released_brx->list_pipe, list_add_tail(&released_brx->list_pipe,
&pipe->entities); &pipe->entities);
/* Add the BRx to the pipeline. */ /*
* Add the BRx to the pipeline, inserting it just before the
* WPF.
*/
dev_dbg(vsp1->dev, "%s: pipe %u: acquired %s\n", dev_dbg(vsp1->dev, "%s: pipe %u: acquired %s\n",
__func__, pipe->lif->index, BRX_NAME(brx)); __func__, pipe->lif->index, BRX_NAME(brx));
...@@ -326,7 +329,8 @@ static int vsp1_du_pipeline_setup_brx(struct vsp1_device *vsp1, ...@@ -326,7 +329,8 @@ static int vsp1_du_pipeline_setup_brx(struct vsp1_device *vsp1,
pipe->brx->sink = &pipe->output->entity; pipe->brx->sink = &pipe->output->entity;
pipe->brx->sink_pad = 0; pipe->brx->sink_pad = 0;
list_add_tail(&pipe->brx->list_pipe, &pipe->entities); list_add_tail(&pipe->brx->list_pipe,
&pipe->output->entity.list_pipe);
} }
/* /*
...@@ -420,7 +424,7 @@ static int vsp1_du_pipeline_setup_inputs(struct vsp1_device *vsp1, ...@@ -420,7 +424,7 @@ static int vsp1_du_pipeline_setup_inputs(struct vsp1_device *vsp1,
if (!rpf->entity.pipe) { if (!rpf->entity.pipe) {
rpf->entity.pipe = pipe; rpf->entity.pipe = pipe;
list_add_tail(&rpf->entity.list_pipe, &pipe->entities); list_add(&rpf->entity.list_pipe, &pipe->entities);
} }
brx->inputs[i].rpf = rpf; brx->inputs[i].rpf = rpf;
...@@ -546,6 +550,9 @@ static void vsp1_du_pipeline_configure(struct vsp1_pipeline *pipe) ...@@ -546,6 +550,9 @@ static void vsp1_du_pipeline_configure(struct vsp1_pipeline *pipe)
struct vsp1_dl_body *dlb; struct vsp1_dl_body *dlb;
unsigned int dl_flags = 0; unsigned int dl_flags = 0;
vsp1_pipeline_calculate_partition(pipe, &pipe->part_table[0],
drm_pipe->width, 0);
if (drm_pipe->force_brx_release) if (drm_pipe->force_brx_release)
dl_flags |= VSP1_DL_FRAME_END_INTERNAL; dl_flags |= VSP1_DL_FRAME_END_INTERNAL;
if (pipe->output->writeback) if (pipe->output->writeback)
...@@ -567,9 +574,11 @@ static void vsp1_du_pipeline_configure(struct vsp1_pipeline *pipe) ...@@ -567,9 +574,11 @@ static void vsp1_du_pipeline_configure(struct vsp1_pipeline *pipe)
} }
vsp1_entity_route_setup(entity, pipe, dlb); vsp1_entity_route_setup(entity, pipe, dlb);
vsp1_entity_configure_stream(entity, pipe, dl, dlb); vsp1_entity_configure_stream(entity, entity->state, pipe,
dl, dlb);
vsp1_entity_configure_frame(entity, pipe, dl, dlb); vsp1_entity_configure_frame(entity, pipe, dl, dlb);
vsp1_entity_configure_partition(entity, pipe, dl, dlb); vsp1_entity_configure_partition(entity, pipe,
&pipe->part_table[0], dl, dlb);
} }
vsp1_dl_list_commit(dl, dl_flags); vsp1_dl_list_commit(dl, dl_flags);
...@@ -733,6 +742,8 @@ int vsp1_du_setup_lif(struct device *dev, unsigned int pipe_index, ...@@ -733,6 +742,8 @@ int vsp1_du_setup_lif(struct device *dev, unsigned int pipe_index,
if (ret < 0) if (ret < 0)
goto unlock; goto unlock;
vsp1_pipeline_dump(pipe, "LIF setup");
/* Enable the VSP1. */ /* Enable the VSP1. */
ret = vsp1_device_get(vsp1); ret = vsp1_device_get(vsp1);
if (ret < 0) if (ret < 0)
...@@ -906,6 +917,9 @@ void vsp1_du_atomic_flush(struct device *dev, unsigned int pipe_index, ...@@ -906,6 +917,9 @@ void vsp1_du_atomic_flush(struct device *dev, unsigned int pipe_index,
} }
vsp1_du_pipeline_setup_inputs(vsp1, pipe); vsp1_du_pipeline_setup_inputs(vsp1, pipe);
vsp1_pipeline_dump(pipe, "atomic update");
vsp1_du_pipeline_configure(pipe); vsp1_du_pipeline_configure(pipe);
done: done:
...@@ -959,6 +973,9 @@ int vsp1_drm_init(struct vsp1_device *vsp1) ...@@ -959,6 +973,9 @@ int vsp1_drm_init(struct vsp1_device *vsp1)
vsp1_pipeline_init(pipe); vsp1_pipeline_init(pipe);
pipe->partitions = 1;
pipe->part_table = &drm_pipe->partition;
pipe->frame_end = vsp1_du_pipeline_frame_end; pipe->frame_end = vsp1_du_pipeline_frame_end;
/* /*
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
/** /**
* struct vsp1_drm_pipeline - State for the API exposed to the DRM driver * struct vsp1_drm_pipeline - State for the API exposed to the DRM driver
* @pipe: the VSP1 pipeline used for display * @pipe: the VSP1 pipeline used for display
* @partition: the pre-calculated partition used by the pipeline
* @width: output display width * @width: output display width
* @height: output display height * @height: output display height
* @force_brx_release: when set, release the BRx during the next reconfiguration * @force_brx_release: when set, release the BRx during the next reconfiguration
...@@ -31,6 +32,7 @@ ...@@ -31,6 +32,7 @@
*/ */
struct vsp1_drm_pipeline { struct vsp1_drm_pipeline {
struct vsp1_pipeline pipe; struct vsp1_pipeline pipe;
struct vsp1_partition partition;
unsigned int width; unsigned int width;
unsigned int height; unsigned int height;
......
...@@ -70,12 +70,13 @@ void vsp1_entity_route_setup(struct vsp1_entity *entity, ...@@ -70,12 +70,13 @@ void vsp1_entity_route_setup(struct vsp1_entity *entity,
} }
void vsp1_entity_configure_stream(struct vsp1_entity *entity, void vsp1_entity_configure_stream(struct vsp1_entity *entity,
struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe, struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl, struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb) struct vsp1_dl_body *dlb)
{ {
if (entity->ops->configure_stream) if (entity->ops->configure_stream)
entity->ops->configure_stream(entity, pipe, dl, dlb); entity->ops->configure_stream(entity, state, pipe, dl, dlb);
} }
void vsp1_entity_configure_frame(struct vsp1_entity *entity, void vsp1_entity_configure_frame(struct vsp1_entity *entity,
...@@ -89,11 +90,13 @@ void vsp1_entity_configure_frame(struct vsp1_entity *entity, ...@@ -89,11 +90,13 @@ void vsp1_entity_configure_frame(struct vsp1_entity *entity,
void vsp1_entity_configure_partition(struct vsp1_entity *entity, void vsp1_entity_configure_partition(struct vsp1_entity *entity,
struct vsp1_pipeline *pipe, struct vsp1_pipeline *pipe,
const struct vsp1_partition *partition,
struct vsp1_dl_list *dl, struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb) struct vsp1_dl_body *dlb)
{ {
if (entity->ops->configure_partition) if (entity->ops->configure_partition)
entity->ops->configure_partition(entity, pipe, dl, dlb); entity->ops->configure_partition(entity, pipe, partition,
dl, dlb);
} }
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
...@@ -127,49 +130,6 @@ vsp1_entity_get_state(struct vsp1_entity *entity, ...@@ -127,49 +130,6 @@ vsp1_entity_get_state(struct vsp1_entity *entity,
} }
} }
/**
* vsp1_entity_get_pad_format - Get a pad format from storage for an entity
* @entity: the entity
* @sd_state: the state storage
* @pad: the pad number
*
* Return the format stored in the given configuration for an entity's pad. The
* configuration can be an ACTIVE or TRY configuration.
*/
struct v4l2_mbus_framefmt *
vsp1_entity_get_pad_format(struct vsp1_entity *entity,
struct v4l2_subdev_state *sd_state,
unsigned int pad)
{
return v4l2_subdev_state_get_format(sd_state, pad);
}
/**
* vsp1_entity_get_pad_selection - Get a pad selection from storage for entity
* @entity: the entity
* @sd_state: the state 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_selection(struct vsp1_entity *entity,
struct v4l2_subdev_state *sd_state,
unsigned int pad, unsigned int target)
{
switch (target) {
case V4L2_SEL_TGT_COMPOSE:
return v4l2_subdev_state_get_compose(sd_state, pad);
case V4L2_SEL_TGT_CROP:
return v4l2_subdev_state_get_crop(sd_state, pad);
default:
return NULL;
}
}
/* /*
* vsp1_subdev_get_pad_format - Subdev pad get_fmt handler * vsp1_subdev_get_pad_format - Subdev pad get_fmt handler
* @subdev: V4L2 subdevice * @subdev: V4L2 subdevice
...@@ -191,7 +151,7 @@ int vsp1_subdev_get_pad_format(struct v4l2_subdev *subdev, ...@@ -191,7 +151,7 @@ int vsp1_subdev_get_pad_format(struct v4l2_subdev *subdev,
return -EINVAL; return -EINVAL;
mutex_lock(&entity->lock); mutex_lock(&entity->lock);
fmt->format = *vsp1_entity_get_pad_format(entity, state, fmt->pad); fmt->format = *v4l2_subdev_state_get_format(state, fmt->pad);
mutex_unlock(&entity->lock); mutex_unlock(&entity->lock);
return 0; return 0;
...@@ -238,7 +198,7 @@ int vsp1_subdev_enum_mbus_code(struct v4l2_subdev *subdev, ...@@ -238,7 +198,7 @@ int vsp1_subdev_enum_mbus_code(struct v4l2_subdev *subdev,
return -EINVAL; return -EINVAL;
mutex_lock(&entity->lock); mutex_lock(&entity->lock);
format = vsp1_entity_get_pad_format(entity, state, 0); format = v4l2_subdev_state_get_format(state, 0);
code->code = format->code; code->code = format->code;
mutex_unlock(&entity->lock); mutex_unlock(&entity->lock);
} }
...@@ -276,7 +236,7 @@ int vsp1_subdev_enum_frame_size(struct v4l2_subdev *subdev, ...@@ -276,7 +236,7 @@ int vsp1_subdev_enum_frame_size(struct v4l2_subdev *subdev,
if (!state) if (!state)
return -EINVAL; return -EINVAL;
format = vsp1_entity_get_pad_format(entity, state, fse->pad); format = v4l2_subdev_state_get_format(state, fse->pad);
mutex_lock(&entity->lock); mutex_lock(&entity->lock);
...@@ -346,7 +306,7 @@ int vsp1_subdev_set_pad_format(struct v4l2_subdev *subdev, ...@@ -346,7 +306,7 @@ int vsp1_subdev_set_pad_format(struct v4l2_subdev *subdev,
goto done; goto done;
} }
format = vsp1_entity_get_pad_format(entity, state, fmt->pad); format = v4l2_subdev_state_get_format(state, fmt->pad);
if (fmt->pad == entity->source_pad) { if (fmt->pad == entity->source_pad) {
/* The output format can't be modified. */ /* The output format can't be modified. */
...@@ -374,19 +334,17 @@ int vsp1_subdev_set_pad_format(struct v4l2_subdev *subdev, ...@@ -374,19 +334,17 @@ int vsp1_subdev_set_pad_format(struct v4l2_subdev *subdev,
fmt->format = *format; fmt->format = *format;
/* Propagate the format to the source pad. */ /* Propagate the format to the source pad. */
format = vsp1_entity_get_pad_format(entity, state, entity->source_pad); format = v4l2_subdev_state_get_format(state, entity->source_pad);
*format = fmt->format; *format = fmt->format;
/* Reset the crop and compose rectangles. */ /* Reset the crop and compose rectangles. */
selection = vsp1_entity_get_pad_selection(entity, state, fmt->pad, selection = v4l2_subdev_state_get_crop(state, fmt->pad);
V4L2_SEL_TGT_CROP);
selection->left = 0; selection->left = 0;
selection->top = 0; selection->top = 0;
selection->width = format->width; selection->width = format->width;
selection->height = format->height; selection->height = format->height;
selection = vsp1_entity_get_pad_selection(entity, state, fmt->pad, selection = v4l2_subdev_state_get_compose(state, fmt->pad);
V4L2_SEL_TGT_COMPOSE);
selection->left = 0; selection->left = 0;
selection->top = 0; selection->top = 0;
selection->width = format->width; selection->width = format->width;
......
...@@ -19,7 +19,6 @@ struct vsp1_dl_body; ...@@ -19,7 +19,6 @@ struct vsp1_dl_body;
struct vsp1_dl_list; struct vsp1_dl_list;
struct vsp1_pipeline; struct vsp1_pipeline;
struct vsp1_partition; struct vsp1_partition;
struct vsp1_partition_window;
enum vsp1_entity_type { enum vsp1_entity_type {
VSP1_ENTITY_BRS, VSP1_ENTITY_BRS,
...@@ -78,19 +77,30 @@ struct vsp1_route { ...@@ -78,19 +77,30 @@ struct vsp1_route {
* configuration. * configuration.
*/ */
struct vsp1_entity_operations { struct vsp1_entity_operations {
void (*destroy)(struct vsp1_entity *); void (*destroy)(struct vsp1_entity *entity);
void (*configure_stream)(struct vsp1_entity *, struct vsp1_pipeline *, void (*configure_stream)(struct vsp1_entity *entity,
struct vsp1_dl_list *, struct vsp1_dl_body *); struct v4l2_subdev_state *state,
void (*configure_frame)(struct vsp1_entity *, struct vsp1_pipeline *, struct vsp1_pipeline *pipe,
struct vsp1_dl_list *, struct vsp1_dl_body *); struct vsp1_dl_list *dl,
void (*configure_partition)(struct vsp1_entity *, struct vsp1_dl_body *dlb);
struct vsp1_pipeline *, void (*configure_frame)(struct vsp1_entity *entity,
struct vsp1_dl_list *, struct vsp1_pipeline *pipe,
struct vsp1_dl_body *); struct vsp1_dl_list *dl,
unsigned int (*max_width)(struct vsp1_entity *, struct vsp1_pipeline *); struct vsp1_dl_body *dlb);
void (*partition)(struct vsp1_entity *, struct vsp1_pipeline *, void (*configure_partition)(struct vsp1_entity *entity,
struct vsp1_partition *, unsigned int, struct vsp1_pipeline *pipe,
struct vsp1_partition_window *); const struct vsp1_partition *partition,
struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb);
unsigned int (*max_width)(struct vsp1_entity *entity,
struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe);
void (*partition)(struct vsp1_entity *entity,
struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe,
struct vsp1_partition *partition,
unsigned int index,
struct v4l2_rect *window);
}; };
struct vsp1_entity { struct vsp1_entity {
...@@ -138,20 +148,13 @@ struct v4l2_subdev_state * ...@@ -138,20 +148,13 @@ struct v4l2_subdev_state *
vsp1_entity_get_state(struct vsp1_entity *entity, vsp1_entity_get_state(struct vsp1_entity *entity,
struct v4l2_subdev_state *sd_state, struct v4l2_subdev_state *sd_state,
enum v4l2_subdev_format_whence which); enum v4l2_subdev_format_whence which);
struct v4l2_mbus_framefmt *
vsp1_entity_get_pad_format(struct vsp1_entity *entity,
struct v4l2_subdev_state *sd_state,
unsigned int pad);
struct v4l2_rect *
vsp1_entity_get_pad_selection(struct vsp1_entity *entity,
struct v4l2_subdev_state *sd_state,
unsigned int pad, unsigned int target);
void vsp1_entity_route_setup(struct vsp1_entity *entity, void vsp1_entity_route_setup(struct vsp1_entity *entity,
struct vsp1_pipeline *pipe, struct vsp1_pipeline *pipe,
struct vsp1_dl_body *dlb); struct vsp1_dl_body *dlb);
void vsp1_entity_configure_stream(struct vsp1_entity *entity, void vsp1_entity_configure_stream(struct vsp1_entity *entity,
struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe, struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl, struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb); struct vsp1_dl_body *dlb);
...@@ -163,6 +166,7 @@ void vsp1_entity_configure_frame(struct vsp1_entity *entity, ...@@ -163,6 +166,7 @@ void vsp1_entity_configure_frame(struct vsp1_entity *entity,
void vsp1_entity_configure_partition(struct vsp1_entity *entity, void vsp1_entity_configure_partition(struct vsp1_entity *entity,
struct vsp1_pipeline *pipe, struct vsp1_pipeline *pipe,
const struct vsp1_partition *partition,
struct vsp1_dl_list *dl, struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb); struct vsp1_dl_body *dlb);
......
...@@ -130,6 +130,7 @@ static const struct v4l2_ctrl_config hgo_num_bins_control = { ...@@ -130,6 +130,7 @@ static const struct v4l2_ctrl_config hgo_num_bins_control = {
*/ */
static void hgo_configure_stream(struct vsp1_entity *entity, static void hgo_configure_stream(struct vsp1_entity *entity,
struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe, struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl, struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb) struct vsp1_dl_body *dlb)
...@@ -140,11 +141,8 @@ static void hgo_configure_stream(struct vsp1_entity *entity, ...@@ -140,11 +141,8 @@ static void hgo_configure_stream(struct vsp1_entity *entity,
unsigned int hratio; unsigned int hratio;
unsigned int vratio; unsigned int vratio;
crop = vsp1_entity_get_pad_selection(entity, entity->state, crop = v4l2_subdev_state_get_crop(state, HISTO_PAD_SINK);
HISTO_PAD_SINK, V4L2_SEL_TGT_CROP); compose = v4l2_subdev_state_get_compose(state, HISTO_PAD_SINK);
compose = vsp1_entity_get_pad_selection(entity, entity->state,
HISTO_PAD_SINK,
V4L2_SEL_TGT_COMPOSE);
vsp1_hgo_write(hgo, dlb, VI6_HGO_REGRST, VI6_HGO_REGRST_RCLEA); vsp1_hgo_write(hgo, dlb, VI6_HGO_REGRST, VI6_HGO_REGRST_RCLEA);
...@@ -194,6 +192,16 @@ struct vsp1_hgo *vsp1_hgo_create(struct vsp1_device *vsp1) ...@@ -194,6 +192,16 @@ struct vsp1_hgo *vsp1_hgo_create(struct vsp1_device *vsp1)
if (hgo == NULL) if (hgo == NULL)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
/* Initialize the video device and queue for statistics data. */
ret = vsp1_histogram_init(vsp1, &hgo->histo, VSP1_ENTITY_HGO, "hgo",
&hgo_entity_ops, hgo_mbus_formats,
ARRAY_SIZE(hgo_mbus_formats),
HGO_DATA_SIZE, V4L2_META_FMT_VSP1_HGO);
if (ret < 0) {
vsp1_entity_destroy(&hgo->histo.entity);
return ERR_PTR(ret);
}
/* Initialize the control handler. */ /* Initialize the control handler. */
v4l2_ctrl_handler_init(&hgo->ctrls.handler, v4l2_ctrl_handler_init(&hgo->ctrls.handler,
vsp1->info->gen >= 3 ? 2 : 1); vsp1->info->gen >= 3 ? 2 : 1);
...@@ -209,15 +217,5 @@ struct vsp1_hgo *vsp1_hgo_create(struct vsp1_device *vsp1) ...@@ -209,15 +217,5 @@ struct vsp1_hgo *vsp1_hgo_create(struct vsp1_device *vsp1)
hgo->histo.entity.subdev.ctrl_handler = &hgo->ctrls.handler; hgo->histo.entity.subdev.ctrl_handler = &hgo->ctrls.handler;
/* Initialize the video device and queue for statistics data. */
ret = vsp1_histogram_init(vsp1, &hgo->histo, VSP1_ENTITY_HGO, "hgo",
&hgo_entity_ops, hgo_mbus_formats,
ARRAY_SIZE(hgo_mbus_formats),
HGO_DATA_SIZE, V4L2_META_FMT_VSP1_HGO);
if (ret < 0) {
vsp1_entity_destroy(&hgo->histo.entity);
return ERR_PTR(ret);
}
return hgo; return hgo;
} }
...@@ -126,6 +126,7 @@ static const struct v4l2_ctrl_config hgt_hue_areas = { ...@@ -126,6 +126,7 @@ static const struct v4l2_ctrl_config hgt_hue_areas = {
*/ */
static void hgt_configure_stream(struct vsp1_entity *entity, static void hgt_configure_stream(struct vsp1_entity *entity,
struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe, struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl, struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb) struct vsp1_dl_body *dlb)
...@@ -139,11 +140,8 @@ static void hgt_configure_stream(struct vsp1_entity *entity, ...@@ -139,11 +140,8 @@ static void hgt_configure_stream(struct vsp1_entity *entity,
u8 upper; u8 upper;
unsigned int i; unsigned int i;
crop = vsp1_entity_get_pad_selection(entity, entity->state, crop = v4l2_subdev_state_get_crop(state, HISTO_PAD_SINK);
HISTO_PAD_SINK, V4L2_SEL_TGT_CROP); compose = v4l2_subdev_state_get_compose(state, HISTO_PAD_SINK);
compose = vsp1_entity_get_pad_selection(entity, entity->state,
HISTO_PAD_SINK,
V4L2_SEL_TGT_COMPOSE);
vsp1_hgt_write(hgt, dlb, VI6_HGT_REGRST, VI6_HGT_REGRST_RCLEA); vsp1_hgt_write(hgt, dlb, VI6_HGT_REGRST, VI6_HGT_REGRST_RCLEA);
...@@ -193,12 +191,6 @@ struct vsp1_hgt *vsp1_hgt_create(struct vsp1_device *vsp1) ...@@ -193,12 +191,6 @@ struct vsp1_hgt *vsp1_hgt_create(struct vsp1_device *vsp1)
if (hgt == NULL) if (hgt == NULL)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
/* Initialize the control handler. */
v4l2_ctrl_handler_init(&hgt->ctrls, 1);
v4l2_ctrl_new_custom(&hgt->ctrls, &hgt_hue_areas, NULL);
hgt->histo.entity.subdev.ctrl_handler = &hgt->ctrls;
/* Initialize the video device and queue for statistics data. */ /* Initialize the video device and queue for statistics data. */
ret = vsp1_histogram_init(vsp1, &hgt->histo, VSP1_ENTITY_HGT, "hgt", ret = vsp1_histogram_init(vsp1, &hgt->histo, VSP1_ENTITY_HGT, "hgt",
&hgt_entity_ops, hgt_mbus_formats, &hgt_entity_ops, hgt_mbus_formats,
...@@ -209,6 +201,12 @@ struct vsp1_hgt *vsp1_hgt_create(struct vsp1_device *vsp1) ...@@ -209,6 +201,12 @@ struct vsp1_hgt *vsp1_hgt_create(struct vsp1_device *vsp1)
return ERR_PTR(ret); return ERR_PTR(ret);
} }
/* Initialize the control handler. */
v4l2_ctrl_handler_init(&hgt->ctrls, 1);
v4l2_ctrl_new_custom(&hgt->ctrls, &hgt_hue_areas, NULL);
hgt->histo.entity.subdev.ctrl_handler = &hgt->ctrls;
v4l2_ctrl_handler_setup(&hgt->ctrls); v4l2_ctrl_handler_setup(&hgt->ctrls);
return hgt; return hgt;
......
...@@ -36,9 +36,8 @@ struct vsp1_histogram_buffer * ...@@ -36,9 +36,8 @@ struct vsp1_histogram_buffer *
vsp1_histogram_buffer_get(struct vsp1_histogram *histo) vsp1_histogram_buffer_get(struct vsp1_histogram *histo)
{ {
struct vsp1_histogram_buffer *buf = NULL; struct vsp1_histogram_buffer *buf = NULL;
unsigned long flags;
spin_lock_irqsave(&histo->irqlock, flags); spin_lock(&histo->irqlock);
if (list_empty(&histo->irqqueue)) if (list_empty(&histo->irqqueue))
goto done; goto done;
...@@ -49,7 +48,7 @@ vsp1_histogram_buffer_get(struct vsp1_histogram *histo) ...@@ -49,7 +48,7 @@ vsp1_histogram_buffer_get(struct vsp1_histogram *histo)
histo->readout = true; histo->readout = true;
done: done:
spin_unlock_irqrestore(&histo->irqlock, flags); spin_unlock(&histo->irqlock);
return buf; return buf;
} }
...@@ -58,7 +57,6 @@ void vsp1_histogram_buffer_complete(struct vsp1_histogram *histo, ...@@ -58,7 +57,6 @@ void vsp1_histogram_buffer_complete(struct vsp1_histogram *histo,
size_t size) size_t size)
{ {
struct vsp1_pipeline *pipe = histo->entity.pipe; struct vsp1_pipeline *pipe = histo->entity.pipe;
unsigned long flags;
/* /*
* The pipeline pointer is guaranteed to be valid as this function is * The pipeline pointer is guaranteed to be valid as this function is
...@@ -70,10 +68,10 @@ void vsp1_histogram_buffer_complete(struct vsp1_histogram *histo, ...@@ -70,10 +68,10 @@ void vsp1_histogram_buffer_complete(struct vsp1_histogram *histo,
vb2_set_plane_payload(&buf->buf.vb2_buf, 0, size); vb2_set_plane_payload(&buf->buf.vb2_buf, 0, size);
vb2_buffer_done(&buf->buf.vb2_buf, VB2_BUF_STATE_DONE); vb2_buffer_done(&buf->buf.vb2_buf, VB2_BUF_STATE_DONE);
spin_lock_irqsave(&histo->irqlock, flags); spin_lock(&histo->irqlock);
histo->readout = false; histo->readout = false;
wake_up(&histo->wait_queue); wake_up(&histo->wait_queue);
spin_unlock_irqrestore(&histo->irqlock, flags); spin_unlock(&histo->irqlock);
} }
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
...@@ -124,11 +122,10 @@ static void histo_buffer_queue(struct vb2_buffer *vb) ...@@ -124,11 +122,10 @@ static void histo_buffer_queue(struct vb2_buffer *vb)
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
struct vsp1_histogram *histo = vb2_get_drv_priv(vb->vb2_queue); struct vsp1_histogram *histo = vb2_get_drv_priv(vb->vb2_queue);
struct vsp1_histogram_buffer *buf = to_vsp1_histogram_buffer(vbuf); struct vsp1_histogram_buffer *buf = to_vsp1_histogram_buffer(vbuf);
unsigned long flags;
spin_lock_irqsave(&histo->irqlock, flags); spin_lock_irq(&histo->irqlock);
list_add_tail(&buf->queue, &histo->irqqueue); list_add_tail(&buf->queue, &histo->irqqueue);
spin_unlock_irqrestore(&histo->irqlock, flags); spin_unlock_irq(&histo->irqlock);
} }
static int histo_start_streaming(struct vb2_queue *vq, unsigned int count) static int histo_start_streaming(struct vb2_queue *vq, unsigned int count)
...@@ -140,9 +137,8 @@ static void histo_stop_streaming(struct vb2_queue *vq) ...@@ -140,9 +137,8 @@ static void histo_stop_streaming(struct vb2_queue *vq)
{ {
struct vsp1_histogram *histo = vb2_get_drv_priv(vq); struct vsp1_histogram *histo = vb2_get_drv_priv(vq);
struct vsp1_histogram_buffer *buffer; struct vsp1_histogram_buffer *buffer;
unsigned long flags;
spin_lock_irqsave(&histo->irqlock, flags); spin_lock_irq(&histo->irqlock);
/* Remove all buffers from the IRQ queue. */ /* Remove all buffers from the IRQ queue. */
list_for_each_entry(buffer, &histo->irqqueue, queue) list_for_each_entry(buffer, &histo->irqqueue, queue)
...@@ -152,7 +148,7 @@ static void histo_stop_streaming(struct vb2_queue *vq) ...@@ -152,7 +148,7 @@ static void histo_stop_streaming(struct vb2_queue *vq)
/* Wait for the buffer being read out (if any) to complete. */ /* Wait for the buffer being read out (if any) to complete. */
wait_event_lock_irq(histo->wait_queue, !histo->readout, histo->irqlock); wait_event_lock_irq(histo->wait_queue, !histo->readout, histo->irqlock);
spin_unlock_irqrestore(&histo->irqlock, flags); spin_unlock_irq(&histo->irqlock);
} }
static const struct vb2_ops histo_video_queue_qops = { static const struct vb2_ops histo_video_queue_qops = {
...@@ -222,9 +218,7 @@ static int histo_get_selection(struct v4l2_subdev *subdev, ...@@ -222,9 +218,7 @@ static int histo_get_selection(struct v4l2_subdev *subdev,
switch (sel->target) { switch (sel->target) {
case V4L2_SEL_TGT_COMPOSE_BOUNDS: case V4L2_SEL_TGT_COMPOSE_BOUNDS:
case V4L2_SEL_TGT_COMPOSE_DEFAULT: case V4L2_SEL_TGT_COMPOSE_DEFAULT:
crop = vsp1_entity_get_pad_selection(&histo->entity, state, crop = v4l2_subdev_state_get_crop(state, HISTO_PAD_SINK);
HISTO_PAD_SINK,
V4L2_SEL_TGT_CROP);
sel->r.left = 0; sel->r.left = 0;
sel->r.top = 0; sel->r.top = 0;
sel->r.width = crop->width; sel->r.width = crop->width;
...@@ -233,8 +227,7 @@ static int histo_get_selection(struct v4l2_subdev *subdev, ...@@ -233,8 +227,7 @@ static int histo_get_selection(struct v4l2_subdev *subdev,
case V4L2_SEL_TGT_CROP_BOUNDS: case V4L2_SEL_TGT_CROP_BOUNDS:
case V4L2_SEL_TGT_CROP_DEFAULT: case V4L2_SEL_TGT_CROP_DEFAULT:
format = vsp1_entity_get_pad_format(&histo->entity, state, format = v4l2_subdev_state_get_format(state, HISTO_PAD_SINK);
HISTO_PAD_SINK);
sel->r.left = 0; sel->r.left = 0;
sel->r.top = 0; sel->r.top = 0;
sel->r.width = format->width; sel->r.width = format->width;
...@@ -242,9 +235,11 @@ static int histo_get_selection(struct v4l2_subdev *subdev, ...@@ -242,9 +235,11 @@ static int histo_get_selection(struct v4l2_subdev *subdev,
break; break;
case V4L2_SEL_TGT_COMPOSE: case V4L2_SEL_TGT_COMPOSE:
sel->r = *v4l2_subdev_state_get_compose(state, sel->pad);
break;
case V4L2_SEL_TGT_CROP: case V4L2_SEL_TGT_CROP:
sel->r = *vsp1_entity_get_pad_selection(&histo->entity, state, sel->r = *v4l2_subdev_state_get_crop(state, sel->pad);
sel->pad, sel->target);
break; break;
default: default:
...@@ -261,13 +256,10 @@ static int histo_set_crop(struct v4l2_subdev *subdev, ...@@ -261,13 +256,10 @@ static int histo_set_crop(struct v4l2_subdev *subdev,
struct v4l2_subdev_state *sd_state, struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel) struct v4l2_subdev_selection *sel)
{ {
struct vsp1_histogram *histo = subdev_to_histo(subdev);
struct v4l2_mbus_framefmt *format; struct v4l2_mbus_framefmt *format;
struct v4l2_rect *selection;
/* The crop rectangle must be inside the input frame. */ /* The crop rectangle must be inside the input frame. */
format = vsp1_entity_get_pad_format(&histo->entity, sd_state, format = v4l2_subdev_state_get_format(sd_state, HISTO_PAD_SINK);
HISTO_PAD_SINK);
sel->r.left = clamp_t(unsigned int, sel->r.left, 0, format->width - 1); 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); sel->r.top = clamp_t(unsigned int, sel->r.top, 0, format->height - 1);
sel->r.width = clamp_t(unsigned int, sel->r.width, HISTO_MIN_SIZE, sel->r.width = clamp_t(unsigned int, sel->r.width, HISTO_MIN_SIZE,
...@@ -276,14 +268,8 @@ static int histo_set_crop(struct v4l2_subdev *subdev, ...@@ -276,14 +268,8 @@ static int histo_set_crop(struct v4l2_subdev *subdev,
format->height - sel->r.top); format->height - sel->r.top);
/* Set the crop rectangle and reset the compose rectangle. */ /* Set the crop rectangle and reset the compose rectangle. */
selection = vsp1_entity_get_pad_selection(&histo->entity, sd_state, *v4l2_subdev_state_get_crop(sd_state, sel->pad) = sel->r;
sel->pad, V4L2_SEL_TGT_CROP); *v4l2_subdev_state_get_compose(sd_state, sel->pad) = sel->r;
*selection = sel->r;
selection = vsp1_entity_get_pad_selection(&histo->entity, sd_state,
sel->pad,
V4L2_SEL_TGT_COMPOSE);
*selection = sel->r;
return 0; return 0;
} }
...@@ -292,7 +278,6 @@ static int histo_set_compose(struct v4l2_subdev *subdev, ...@@ -292,7 +278,6 @@ static int histo_set_compose(struct v4l2_subdev *subdev,
struct v4l2_subdev_state *sd_state, struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel) struct v4l2_subdev_selection *sel)
{ {
struct vsp1_histogram *histo = subdev_to_histo(subdev);
struct v4l2_rect *compose; struct v4l2_rect *compose;
struct v4l2_rect *crop; struct v4l2_rect *crop;
unsigned int ratio; unsigned int ratio;
...@@ -305,9 +290,7 @@ static int histo_set_compose(struct v4l2_subdev *subdev, ...@@ -305,9 +290,7 @@ static int histo_set_compose(struct v4l2_subdev *subdev,
sel->r.left = 0; sel->r.left = 0;
sel->r.top = 0; sel->r.top = 0;
crop = vsp1_entity_get_pad_selection(&histo->entity, sd_state, crop = v4l2_subdev_state_get_crop(sd_state, sel->pad);
sel->pad,
V4L2_SEL_TGT_CROP);
/* /*
* Clamp the width and height to acceptable values first and then * Clamp the width and height to acceptable values first and then
...@@ -332,9 +315,7 @@ static int histo_set_compose(struct v4l2_subdev *subdev, ...@@ -332,9 +315,7 @@ static int histo_set_compose(struct v4l2_subdev *subdev,
ratio = 1 << (crop->height * 2 / sel->r.height / 3); ratio = 1 << (crop->height * 2 / sel->r.height / 3);
sel->r.height = crop->height / ratio; sel->r.height = crop->height / ratio;
compose = vsp1_entity_get_pad_selection(&histo->entity, sd_state, compose = v4l2_subdev_state_get_compose(sd_state, sel->pad);
sel->pad,
V4L2_SEL_TGT_COMPOSE);
*compose = sel->r; *compose = sel->r;
return 0; return 0;
...@@ -371,31 +352,22 @@ static int histo_set_selection(struct v4l2_subdev *subdev, ...@@ -371,31 +352,22 @@ static int histo_set_selection(struct v4l2_subdev *subdev,
return ret; return ret;
} }
static int histo_get_format(struct v4l2_subdev *subdev, static int histo_set_format(struct v4l2_subdev *subdev,
struct v4l2_subdev_state *sd_state, struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt) struct v4l2_subdev_format *fmt)
{ {
struct vsp1_histogram *histo = subdev_to_histo(subdev);
if (fmt->pad == HISTO_PAD_SOURCE) { if (fmt->pad == HISTO_PAD_SOURCE) {
fmt->format.code = MEDIA_BUS_FMT_FIXED; fmt->format.code = MEDIA_BUS_FMT_FIXED;
fmt->format.width = 0; fmt->format.width = 0;
fmt->format.height = 0; fmt->format.height = 0;
fmt->format.field = V4L2_FIELD_NONE; fmt->format.field = V4L2_FIELD_NONE;
fmt->format.colorspace = V4L2_COLORSPACE_RAW; fmt->format.colorspace = V4L2_COLORSPACE_RAW;
return 0; return 0;
} }
return vsp1_subdev_get_pad_format(subdev, sd_state, fmt);
}
static int histo_set_format(struct v4l2_subdev *subdev,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct vsp1_histogram *histo = subdev_to_histo(subdev);
if (fmt->pad != HISTO_PAD_SINK)
return histo_get_format(subdev, sd_state, fmt);
return vsp1_subdev_set_pad_format(subdev, sd_state, fmt, return vsp1_subdev_set_pad_format(subdev, sd_state, fmt,
histo->formats, histo->num_formats, histo->formats, histo->num_formats,
HISTO_MIN_SIZE, HISTO_MIN_SIZE, HISTO_MIN_SIZE, HISTO_MIN_SIZE,
...@@ -405,7 +377,7 @@ static int histo_set_format(struct v4l2_subdev *subdev, ...@@ -405,7 +377,7 @@ static int histo_set_format(struct v4l2_subdev *subdev,
static const struct v4l2_subdev_pad_ops histo_pad_ops = { static const struct v4l2_subdev_pad_ops histo_pad_ops = {
.enum_mbus_code = histo_enum_mbus_code, .enum_mbus_code = histo_enum_mbus_code,
.enum_frame_size = histo_enum_frame_size, .enum_frame_size = histo_enum_frame_size,
.get_fmt = histo_get_format, .get_fmt = vsp1_subdev_get_pad_format,
.set_fmt = histo_set_format, .set_fmt = histo_set_format,
.get_selection = histo_get_selection, .get_selection = histo_get_selection,
.set_selection = histo_set_selection, .set_selection = histo_set_selection,
......
...@@ -78,7 +78,7 @@ static int hsit_set_format(struct v4l2_subdev *subdev, ...@@ -78,7 +78,7 @@ static int hsit_set_format(struct v4l2_subdev *subdev,
goto done; goto done;
} }
format = vsp1_entity_get_pad_format(&hsit->entity, state, fmt->pad); format = v4l2_subdev_state_get_format(state, fmt->pad);
if (fmt->pad == HSIT_PAD_SOURCE) { if (fmt->pad == HSIT_PAD_SOURCE) {
/* /*
...@@ -101,8 +101,7 @@ static int hsit_set_format(struct v4l2_subdev *subdev, ...@@ -101,8 +101,7 @@ static int hsit_set_format(struct v4l2_subdev *subdev,
fmt->format = *format; fmt->format = *format;
/* Propagate the format to the source pad. */ /* Propagate the format to the source pad. */
format = vsp1_entity_get_pad_format(&hsit->entity, state, format = v4l2_subdev_state_get_format(state, HSIT_PAD_SOURCE);
HSIT_PAD_SOURCE);
*format = fmt->format; *format = fmt->format;
format->code = hsit->inverse ? MEDIA_BUS_FMT_ARGB8888_1X32 format->code = hsit->inverse ? MEDIA_BUS_FMT_ARGB8888_1X32
: MEDIA_BUS_FMT_AHSV8888_1X32; : MEDIA_BUS_FMT_AHSV8888_1X32;
...@@ -128,6 +127,7 @@ static const struct v4l2_subdev_ops hsit_ops = { ...@@ -128,6 +127,7 @@ static const struct v4l2_subdev_ops hsit_ops = {
*/ */
static void hsit_configure_stream(struct vsp1_entity *entity, static void hsit_configure_stream(struct vsp1_entity *entity,
struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe, struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl, struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb) struct vsp1_dl_body *dlb)
......
...@@ -83,6 +83,7 @@ static const struct v4l2_subdev_ops lif_ops = { ...@@ -83,6 +83,7 @@ static const struct v4l2_subdev_ops lif_ops = {
*/ */
static void lif_configure_stream(struct vsp1_entity *entity, static void lif_configure_stream(struct vsp1_entity *entity,
struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe, struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl, struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb) struct vsp1_dl_body *dlb)
...@@ -93,8 +94,7 @@ static void lif_configure_stream(struct vsp1_entity *entity, ...@@ -93,8 +94,7 @@ static void lif_configure_stream(struct vsp1_entity *entity,
unsigned int obth; unsigned int obth;
unsigned int lbth; unsigned int lbth;
format = vsp1_entity_get_pad_format(&lif->entity, lif->entity.state, format = v4l2_subdev_state_get_format(state, LIF_PAD_SOURCE);
LIF_PAD_SOURCE);
switch (entity->vsp1->version & VI6_IP_VERSION_MODEL_MASK) { switch (entity->vsp1->version & VI6_IP_VERSION_MODEL_MASK) {
case VI6_IP_VERSION_MODEL_VSPD_GEN2: case VI6_IP_VERSION_MODEL_VSPD_GEN2:
......
...@@ -146,6 +146,7 @@ static const struct v4l2_subdev_ops lut_ops = { ...@@ -146,6 +146,7 @@ static const struct v4l2_subdev_ops lut_ops = {
*/ */
static void lut_configure_stream(struct vsp1_entity *entity, static void lut_configure_stream(struct vsp1_entity *entity,
struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe, struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl, struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb) struct vsp1_dl_body *dlb)
......
...@@ -301,6 +301,28 @@ void vsp1_pipeline_init(struct vsp1_pipeline *pipe) ...@@ -301,6 +301,28 @@ void vsp1_pipeline_init(struct vsp1_pipeline *pipe)
pipe->state = VSP1_PIPELINE_STOPPED; pipe->state = VSP1_PIPELINE_STOPPED;
} }
void __vsp1_pipeline_dump(struct _ddebug *dbg, struct vsp1_pipeline *pipe,
const char *msg)
{
struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
struct vsp1_entity *entity;
bool first = true;
printk(KERN_DEBUG "%s: %s: pipe: ", dev_name(vsp1->dev), msg);
list_for_each_entry(entity, &pipe->entities, list_pipe) {
const char *name;
name = strchrnul(entity->subdev.name, ' ');
name = name ? name + 1 : entity->subdev.name;
pr_cont("%s%s", first ? "" : ", ", name);
first = false;
}
pr_cont("\n");
}
/* Must be called with the pipe irqlock held. */ /* Must be called with the pipe irqlock held. */
void vsp1_pipeline_run(struct vsp1_pipeline *pipe) void vsp1_pipeline_run(struct vsp1_pipeline *pipe)
{ {
...@@ -444,6 +466,10 @@ void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe, ...@@ -444,6 +466,10 @@ void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe,
vsp1_uds_set_alpha(pipe->uds, dlb, alpha); vsp1_uds_set_alpha(pipe->uds, dlb, alpha);
} }
/* -----------------------------------------------------------------------------
* VSP1 Partition Algorithm support
*/
/* /*
* Propagate the partition calculations through the pipeline * Propagate the partition calculations through the pipeline
* *
...@@ -452,17 +478,82 @@ void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe, ...@@ -452,17 +478,82 @@ void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe,
* source. Each entity must produce the partition required for the previous * source. Each entity must produce the partition required for the previous
* entity in the pipeline. * entity in the pipeline.
*/ */
void vsp1_pipeline_propagate_partition(struct vsp1_pipeline *pipe, static void vsp1_pipeline_propagate_partition(struct vsp1_pipeline *pipe,
struct vsp1_partition *partition, struct vsp1_partition *partition,
unsigned int index, unsigned int index,
struct vsp1_partition_window *window) struct v4l2_rect *window)
{ {
struct vsp1_entity *entity; struct vsp1_entity *entity;
list_for_each_entry_reverse(entity, &pipe->entities, list_pipe) { list_for_each_entry_reverse(entity, &pipe->entities, list_pipe) {
if (entity->ops->partition) if (entity->ops->partition)
entity->ops->partition(entity, pipe, partition, index, entity->ops->partition(entity, entity->state, pipe,
window); partition, index, window);
} }
} }
/*
* vsp1_pipeline_calculate_partition - Calculate pipeline configuration for a
* partition
*
* @pipe: the pipeline
* @partition: partition that will hold the calculated values
* @div_size: pre-determined maximum partition division size
* @index: partition index
*/
void vsp1_pipeline_calculate_partition(struct vsp1_pipeline *pipe,
struct vsp1_partition *partition,
unsigned int div_size,
unsigned int index)
{
const struct v4l2_mbus_framefmt *format;
struct v4l2_rect window;
unsigned int modulus;
/*
* Partitions are computed on the size before rotation, use the format
* at the WPF sink.
*/
format = v4l2_subdev_state_get_format(pipe->output->entity.state,
RWPF_PAD_SINK);
/* Initialise the partition with sane starting conditions. */
window.left = index * div_size;
window.width = div_size;
window.top = 0;
window.height = format->height;
modulus = format->width % div_size;
/*
* We need to prevent the last partition from being smaller than the
* *minimum* width of the hardware capabilities.
*
* If the modulus is less than half of the partition size,
* the penultimate partition is reduced to half, which is added
* to the final partition: |1234|1234|1234|12|341|
* to prevent this: |1234|1234|1234|1234|1|.
*/
if (modulus) {
/*
* pipe->partitions is 1 based, whilst index is a 0 based index.
* Normalise this locally.
*/
unsigned int partitions = pipe->partitions - 1;
if (modulus < div_size / 2) {
if (index == partitions - 1) {
/* Halve the penultimate partition. */
window.width = div_size / 2;
} else if (index == partitions) {
/* Increase the final partition. */
window.width = (div_size / 2) + modulus;
window.left -= div_size / 2;
}
} else if (index == partitions) {
window.width = modulus;
}
}
vsp1_pipeline_propagate_partition(pipe, partition, index, &window);
}
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#ifndef __VSP1_PIPE_H__ #ifndef __VSP1_PIPE_H__
#define __VSP1_PIPE_H__ #define __VSP1_PIPE_H__
#include <linux/dynamic_debug.h>
#include <linux/kref.h> #include <linux/kref.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
...@@ -53,17 +54,6 @@ enum vsp1_pipeline_state { ...@@ -53,17 +54,6 @@ enum vsp1_pipeline_state {
VSP1_PIPELINE_STOPPING, VSP1_PIPELINE_STOPPING,
}; };
/*
* struct vsp1_partition_window - Partition window coordinates
* @left: horizontal coordinate of the partition start in pixels relative to the
* left edge of the image
* @width: partition width in pixels
*/
struct vsp1_partition_window {
unsigned int left;
unsigned int width;
};
/* /*
* struct vsp1_partition - A description of a slice for the partition algorithm * struct vsp1_partition - A description of a slice for the partition algorithm
* @rpf: The RPF partition window configuration * @rpf: The RPF partition window configuration
...@@ -73,11 +63,11 @@ struct vsp1_partition_window { ...@@ -73,11 +63,11 @@ struct vsp1_partition_window {
* @wpf: The WPF partition window configuration * @wpf: The WPF partition window configuration
*/ */
struct vsp1_partition { struct vsp1_partition {
struct vsp1_partition_window rpf; struct v4l2_rect rpf[VSP1_MAX_RPF];
struct vsp1_partition_window uds_sink; struct v4l2_rect uds_sink;
struct vsp1_partition_window uds_source; struct v4l2_rect uds_source;
struct vsp1_partition_window sru; struct v4l2_rect sru;
struct vsp1_partition_window wpf; struct v4l2_rect wpf;
}; };
/* /*
...@@ -106,7 +96,6 @@ struct vsp1_partition { ...@@ -106,7 +96,6 @@ struct vsp1_partition {
* @configured: when false the @stream_config shall be written to the hardware * @configured: when false the @stream_config shall be written to the hardware
* @interlaced: True when the pipeline is configured in interlaced mode * @interlaced: True when the pipeline is configured in interlaced mode
* @partitions: The number of partitions used to process one frame * @partitions: The number of partitions used to process one frame
* @partition: The current partition for configuration to process
* @part_table: The pre-calculated partitions used by the pipeline * @part_table: The pre-calculated partitions used by the pipeline
*/ */
struct vsp1_pipeline { struct vsp1_pipeline {
...@@ -146,7 +135,6 @@ struct vsp1_pipeline { ...@@ -146,7 +135,6 @@ struct vsp1_pipeline {
bool interlaced; bool interlaced;
unsigned int partitions; unsigned int partitions;
struct vsp1_partition *partition;
struct vsp1_partition *part_table; struct vsp1_partition *part_table;
u32 underrun_count; u32 underrun_count;
...@@ -155,6 +143,24 @@ struct vsp1_pipeline { ...@@ -155,6 +143,24 @@ struct vsp1_pipeline {
void vsp1_pipeline_reset(struct vsp1_pipeline *pipe); void vsp1_pipeline_reset(struct vsp1_pipeline *pipe);
void vsp1_pipeline_init(struct vsp1_pipeline *pipe); void vsp1_pipeline_init(struct vsp1_pipeline *pipe);
void __vsp1_pipeline_dump(struct _ddebug *, struct vsp1_pipeline *pipe,
const char *msg);
#if defined(CONFIG_DYNAMIC_DEBUG) || \
(defined(CONFIG_DYNAMIC_DEBUG_CORE) && defined(DYNAMIC_DEBUG_MODULE))
#define vsp1_pipeline_dump(pipe, msg) \
_dynamic_func_call("vsp1_pipeline_dump()", __vsp1_pipeline_dump, pipe, msg)
#elif defined(DEBUG)
#define vsp1_pipeline_dump(pipe, msg) \
__vsp1_pipeline_dump(NULL, pipe, msg)
#else
#define vsp1_pipeline_dump(pipe, msg) \
({ \
if (0) \
__vsp1_pipeline_dump(NULL, pipe, msg); \
})
#endif
void vsp1_pipeline_run(struct vsp1_pipeline *pipe); void vsp1_pipeline_run(struct vsp1_pipeline *pipe);
bool vsp1_pipeline_stopped(struct vsp1_pipeline *pipe); bool vsp1_pipeline_stopped(struct vsp1_pipeline *pipe);
int vsp1_pipeline_stop(struct vsp1_pipeline *pipe); int vsp1_pipeline_stop(struct vsp1_pipeline *pipe);
...@@ -166,10 +172,10 @@ void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe, ...@@ -166,10 +172,10 @@ void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe,
struct vsp1_dl_body *dlb, struct vsp1_dl_body *dlb,
unsigned int alpha); unsigned int alpha);
void vsp1_pipeline_propagate_partition(struct vsp1_pipeline *pipe, void vsp1_pipeline_calculate_partition(struct vsp1_pipeline *pipe,
struct vsp1_partition *partition, struct vsp1_partition *partition,
unsigned int index, unsigned int div_size,
struct vsp1_partition_window *window); unsigned int index);
const struct vsp1_format_info *vsp1_get_format_info(struct vsp1_device *vsp1, const struct vsp1_format_info *vsp1_get_format_info(struct vsp1_device *vsp1,
u32 fourcc); u32 fourcc);
......
...@@ -48,6 +48,7 @@ static inline void vsp1_rpf_write(struct vsp1_rwpf *rpf, ...@@ -48,6 +48,7 @@ static inline void vsp1_rpf_write(struct vsp1_rwpf *rpf,
*/ */
static void rpf_configure_stream(struct vsp1_entity *entity, static void rpf_configure_stream(struct vsp1_entity *entity,
struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe, struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl, struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb) struct vsp1_dl_body *dlb)
...@@ -80,12 +81,8 @@ static void rpf_configure_stream(struct vsp1_entity *entity, ...@@ -80,12 +81,8 @@ static void rpf_configure_stream(struct vsp1_entity *entity,
vsp1_rpf_write(rpf, dlb, VI6_RPF_SRCM_PSTRIDE, pstride); vsp1_rpf_write(rpf, dlb, VI6_RPF_SRCM_PSTRIDE, pstride);
/* Format */ /* Format */
sink_format = vsp1_entity_get_pad_format(&rpf->entity, sink_format = v4l2_subdev_state_get_format(state, RWPF_PAD_SINK);
rpf->entity.state, source_format = v4l2_subdev_state_get_format(state, RWPF_PAD_SOURCE);
RWPF_PAD_SINK);
source_format = vsp1_entity_get_pad_format(&rpf->entity,
rpf->entity.state,
RWPF_PAD_SOURCE);
infmt = VI6_RPF_INFMT_CIPM infmt = VI6_RPF_INFMT_CIPM
| (fmtinfo->hwfmt << VI6_RPF_INFMT_RDFMT_SHIFT); | (fmtinfo->hwfmt << VI6_RPF_INFMT_RDFMT_SHIFT);
...@@ -157,10 +154,8 @@ static void rpf_configure_stream(struct vsp1_entity *entity, ...@@ -157,10 +154,8 @@ static void rpf_configure_stream(struct vsp1_entity *entity,
if (pipe->brx) { if (pipe->brx) {
const struct v4l2_rect *compose; const struct v4l2_rect *compose;
compose = vsp1_entity_get_pad_selection(pipe->brx, compose = v4l2_subdev_state_get_compose(pipe->brx->state,
pipe->brx->state, rpf->brx_input);
rpf->brx_input,
V4L2_SEL_TGT_COMPOSE);
left = compose->left; left = compose->left;
top = compose->top; top = compose->top;
} }
...@@ -284,6 +279,7 @@ static void rpf_configure_frame(struct vsp1_entity *entity, ...@@ -284,6 +279,7 @@ static void rpf_configure_frame(struct vsp1_entity *entity,
static void rpf_configure_partition(struct vsp1_entity *entity, static void rpf_configure_partition(struct vsp1_entity *entity,
struct vsp1_pipeline *pipe, struct vsp1_pipeline *pipe,
const struct vsp1_partition *partition,
struct vsp1_dl_list *dl, struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb) struct vsp1_dl_body *dlb)
{ {
...@@ -292,7 +288,7 @@ static void rpf_configure_partition(struct vsp1_entity *entity, ...@@ -292,7 +288,7 @@ static void rpf_configure_partition(struct vsp1_entity *entity,
struct vsp1_device *vsp1 = rpf->entity.vsp1; struct vsp1_device *vsp1 = rpf->entity.vsp1;
const struct vsp1_format_info *fmtinfo = rpf->fmtinfo; const struct vsp1_format_info *fmtinfo = rpf->fmtinfo;
const struct v4l2_pix_format_mplane *format = &rpf->format; const struct v4l2_pix_format_mplane *format = &rpf->format;
struct v4l2_rect crop; struct v4l2_rect crop = partition->rpf[rpf->entity.index];
/* /*
* Source size and crop offsets. * Source size and crop offsets.
...@@ -302,22 +298,6 @@ static void rpf_configure_partition(struct vsp1_entity *entity, ...@@ -302,22 +298,6 @@ static void rpf_configure_partition(struct vsp1_entity *entity,
* offsets are needed, as planes 2 and 3 always have identical * offsets are needed, as planes 2 and 3 always have identical
* strides. * strides.
*/ */
crop = *vsp1_rwpf_get_crop(rpf, rpf->entity.state);
/*
* Partition Algorithm Control
*
* The partition algorithm can split this frame into multiple
* slices. We must scale our partition window based on the pipe
* configuration to match the destination partition window.
* To achieve this, we adjust our crop to provide a 'sub-crop'
* matching the expected partition window. Only 'left' and
* 'width' need to be adjusted.
*/
if (pipe->partitions > 1) {
crop.width = pipe->partition->rpf.width;
crop.left += pipe->partition->rpf.left;
}
if (pipe->interlaced) { if (pipe->interlaced) {
crop.height = round_down(crop.height / 2, fmtinfo->vsub); crop.height = round_down(crop.height / 2, fmtinfo->vsub);
...@@ -366,12 +346,30 @@ static void rpf_configure_partition(struct vsp1_entity *entity, ...@@ -366,12 +346,30 @@ static void rpf_configure_partition(struct vsp1_entity *entity,
} }
static void rpf_partition(struct vsp1_entity *entity, static void rpf_partition(struct vsp1_entity *entity,
struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe, struct vsp1_pipeline *pipe,
struct vsp1_partition *partition, struct vsp1_partition *partition,
unsigned int partition_idx, unsigned int partition_idx,
struct vsp1_partition_window *window) struct v4l2_rect *window)
{ {
partition->rpf = *window; struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev);
struct v4l2_rect *rpf_rect = &partition->rpf[rpf->entity.index];
/*
* Partition Algorithm Control
*
* The partition algorithm can split this frame into multiple slices. We
* must adjust our partition window based on the pipe configuration to
* match the destination partition window. To achieve this, we adjust
* our crop to provide a 'sub-crop' matching the expected partition
* window.
*/
*rpf_rect = *v4l2_subdev_state_get_crop(state, RWPF_PAD_SINK);
if (pipe->partitions > 1) {
rpf_rect->width = window->width;
rpf_rect->left += window->left;
}
} }
static const struct vsp1_entity_operations rpf_entity_ops = { static const struct vsp1_entity_operations rpf_entity_ops = {
......
...@@ -16,12 +16,6 @@ ...@@ -16,12 +16,6 @@
#define RWPF_MIN_WIDTH 1 #define RWPF_MIN_WIDTH 1
#define RWPF_MIN_HEIGHT 1 #define RWPF_MIN_HEIGHT 1
struct v4l2_rect *vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf,
struct v4l2_subdev_state *sd_state)
{
return v4l2_subdev_state_get_crop(sd_state, RWPF_PAD_SINK);
}
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
* V4L2 Subdevice Operations * V4L2 Subdevice Operations
*/ */
...@@ -79,7 +73,7 @@ static int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, ...@@ -79,7 +73,7 @@ static int vsp1_rwpf_set_format(struct v4l2_subdev *subdev,
fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32) fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32)
fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32; fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32;
format = vsp1_entity_get_pad_format(&rwpf->entity, state, fmt->pad); format = v4l2_subdev_state_get_format(state, fmt->pad);
if (fmt->pad == RWPF_PAD_SOURCE) { if (fmt->pad == RWPF_PAD_SOURCE) {
/* /*
...@@ -105,7 +99,7 @@ static int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, ...@@ -105,7 +99,7 @@ static int vsp1_rwpf_set_format(struct v4l2_subdev *subdev,
struct v4l2_rect *crop; struct v4l2_rect *crop;
/* Update the sink crop rectangle. */ /* Update the sink crop rectangle. */
crop = vsp1_rwpf_get_crop(rwpf, state); crop = v4l2_subdev_state_get_crop(state, RWPF_PAD_SINK);
crop->left = 0; crop->left = 0;
crop->top = 0; crop->top = 0;
crop->width = fmt->format.width; crop->width = fmt->format.width;
...@@ -113,8 +107,7 @@ static int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, ...@@ -113,8 +107,7 @@ static int vsp1_rwpf_set_format(struct v4l2_subdev *subdev,
} }
/* Propagate the format to the source pad. */ /* Propagate the format to the source pad. */
format = vsp1_entity_get_pad_format(&rwpf->entity, state, format = v4l2_subdev_state_get_format(state, RWPF_PAD_SOURCE);
RWPF_PAD_SOURCE);
*format = fmt->format; *format = fmt->format;
if (rwpf->flip.rotate) { if (rwpf->flip.rotate) {
...@@ -153,12 +146,11 @@ static int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev, ...@@ -153,12 +146,11 @@ static int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev,
switch (sel->target) { switch (sel->target) {
case V4L2_SEL_TGT_CROP: case V4L2_SEL_TGT_CROP:
sel->r = *vsp1_rwpf_get_crop(rwpf, state); sel->r = *v4l2_subdev_state_get_crop(state, RWPF_PAD_SINK);
break; break;
case V4L2_SEL_TGT_CROP_BOUNDS: case V4L2_SEL_TGT_CROP_BOUNDS:
format = vsp1_entity_get_pad_format(&rwpf->entity, state, format = v4l2_subdev_state_get_format(state, RWPF_PAD_SINK);
RWPF_PAD_SINK);
sel->r.left = 0; sel->r.left = 0;
sel->r.top = 0; sel->r.top = 0;
sel->r.width = format->width; sel->r.width = format->width;
...@@ -204,8 +196,7 @@ static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, ...@@ -204,8 +196,7 @@ static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
} }
/* Make sure the crop rectangle is entirely contained in the image. */ /* Make sure the crop rectangle is entirely contained in the image. */
format = vsp1_entity_get_pad_format(&rwpf->entity, state, format = v4l2_subdev_state_get_format(state, RWPF_PAD_SINK);
RWPF_PAD_SINK);
/* /*
* Restrict the crop rectangle coordinates to multiples of 2 to avoid * Restrict the crop rectangle coordinates to multiples of 2 to avoid
...@@ -225,12 +216,11 @@ static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, ...@@ -225,12 +216,11 @@ static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
sel->r.height = min_t(unsigned int, sel->r.height, sel->r.height = min_t(unsigned int, sel->r.height,
format->height - sel->r.top); format->height - sel->r.top);
crop = vsp1_rwpf_get_crop(rwpf, state); crop = v4l2_subdev_state_get_crop(state, RWPF_PAD_SINK);
*crop = sel->r; *crop = sel->r;
/* Propagate the format to the source pad. */ /* Propagate the format to the source pad. */
format = vsp1_entity_get_pad_format(&rwpf->entity, state, format = v4l2_subdev_state_get_format(state, RWPF_PAD_SOURCE);
RWPF_PAD_SOURCE);
format->width = crop->width; format->width = crop->width;
format->height = crop->height; format->height = crop->height;
......
...@@ -85,7 +85,4 @@ int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf, unsigned int ncontrols); ...@@ -85,7 +85,4 @@ int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf, unsigned int ncontrols);
extern const struct v4l2_subdev_ops vsp1_rwpf_subdev_ops; extern const struct v4l2_subdev_ops vsp1_rwpf_subdev_ops;
struct v4l2_rect *vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf,
struct v4l2_subdev_state *sd_state);
#endif /* __VSP1_RWPF_H__ */ #endif /* __VSP1_RWPF_H__ */
...@@ -131,7 +131,7 @@ static int sru_enum_frame_size(struct v4l2_subdev *subdev, ...@@ -131,7 +131,7 @@ static int sru_enum_frame_size(struct v4l2_subdev *subdev,
if (!state) if (!state)
return -EINVAL; return -EINVAL;
format = vsp1_entity_get_pad_format(&sru->entity, state, SRU_PAD_SINK); format = v4l2_subdev_state_get_format(state, SRU_PAD_SINK);
mutex_lock(&sru->entity.lock); mutex_lock(&sru->entity.lock);
...@@ -184,8 +184,7 @@ static void sru_try_format(struct vsp1_sru *sru, ...@@ -184,8 +184,7 @@ static void sru_try_format(struct vsp1_sru *sru,
case SRU_PAD_SOURCE: case SRU_PAD_SOURCE:
/* The SRU can't perform format conversion. */ /* The SRU can't perform format conversion. */
format = vsp1_entity_get_pad_format(&sru->entity, sd_state, format = v4l2_subdev_state_get_format(sd_state, SRU_PAD_SINK);
SRU_PAD_SINK);
fmt->code = format->code; fmt->code = format->code;
/* /*
...@@ -234,13 +233,12 @@ static int sru_set_format(struct v4l2_subdev *subdev, ...@@ -234,13 +233,12 @@ static int sru_set_format(struct v4l2_subdev *subdev,
sru_try_format(sru, state, fmt->pad, &fmt->format); sru_try_format(sru, state, fmt->pad, &fmt->format);
format = vsp1_entity_get_pad_format(&sru->entity, state, fmt->pad); format = v4l2_subdev_state_get_format(state, fmt->pad);
*format = fmt->format; *format = fmt->format;
if (fmt->pad == SRU_PAD_SINK) { if (fmt->pad == SRU_PAD_SINK) {
/* Propagate the format to the source pad. */ /* Propagate the format to the source pad. */
format = vsp1_entity_get_pad_format(&sru->entity, state, format = v4l2_subdev_state_get_format(state, SRU_PAD_SOURCE);
SRU_PAD_SOURCE);
*format = fmt->format; *format = fmt->format;
sru_try_format(sru, state, SRU_PAD_SOURCE, format); sru_try_format(sru, state, SRU_PAD_SOURCE, format);
...@@ -267,6 +265,7 @@ static const struct v4l2_subdev_ops sru_ops = { ...@@ -267,6 +265,7 @@ static const struct v4l2_subdev_ops sru_ops = {
*/ */
static void sru_configure_stream(struct vsp1_entity *entity, static void sru_configure_stream(struct vsp1_entity *entity,
struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe, struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl, struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb) struct vsp1_dl_body *dlb)
...@@ -277,10 +276,8 @@ static void sru_configure_stream(struct vsp1_entity *entity, ...@@ -277,10 +276,8 @@ static void sru_configure_stream(struct vsp1_entity *entity,
struct v4l2_mbus_framefmt *output; struct v4l2_mbus_framefmt *output;
u32 ctrl0; u32 ctrl0;
input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.state, input = v4l2_subdev_state_get_format(state, SRU_PAD_SINK);
SRU_PAD_SINK); output = v4l2_subdev_state_get_format(state, SRU_PAD_SOURCE);
output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.state,
SRU_PAD_SOURCE);
if (input->code == MEDIA_BUS_FMT_ARGB8888_1X32) if (input->code == MEDIA_BUS_FMT_ARGB8888_1X32)
ctrl0 = VI6_SRU_CTRL0_PARAM2 | VI6_SRU_CTRL0_PARAM3 ctrl0 = VI6_SRU_CTRL0_PARAM2 | VI6_SRU_CTRL0_PARAM3
...@@ -301,16 +298,14 @@ static void sru_configure_stream(struct vsp1_entity *entity, ...@@ -301,16 +298,14 @@ static void sru_configure_stream(struct vsp1_entity *entity,
} }
static unsigned int sru_max_width(struct vsp1_entity *entity, static unsigned int sru_max_width(struct vsp1_entity *entity,
struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe) struct vsp1_pipeline *pipe)
{ {
struct vsp1_sru *sru = to_sru(&entity->subdev);
struct v4l2_mbus_framefmt *input; struct v4l2_mbus_framefmt *input;
struct v4l2_mbus_framefmt *output; struct v4l2_mbus_framefmt *output;
input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.state, input = v4l2_subdev_state_get_format(state, SRU_PAD_SINK);
SRU_PAD_SINK); output = v4l2_subdev_state_get_format(state, SRU_PAD_SOURCE);
output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.state,
SRU_PAD_SOURCE);
/* /*
* The maximum input width of the SRU is 288 input pixels, but 32 * The maximum input width of the SRU is 288 input pixels, but 32
...@@ -324,24 +319,24 @@ static unsigned int sru_max_width(struct vsp1_entity *entity, ...@@ -324,24 +319,24 @@ static unsigned int sru_max_width(struct vsp1_entity *entity,
} }
static void sru_partition(struct vsp1_entity *entity, static void sru_partition(struct vsp1_entity *entity,
struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe, struct vsp1_pipeline *pipe,
struct vsp1_partition *partition, struct vsp1_partition *partition,
unsigned int partition_idx, unsigned int partition_idx,
struct vsp1_partition_window *window) struct v4l2_rect *window)
{ {
struct vsp1_sru *sru = to_sru(&entity->subdev);
struct v4l2_mbus_framefmt *input; struct v4l2_mbus_framefmt *input;
struct v4l2_mbus_framefmt *output; struct v4l2_mbus_framefmt *output;
input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.state, input = v4l2_subdev_state_get_format(state, SRU_PAD_SINK);
SRU_PAD_SINK); output = v4l2_subdev_state_get_format(state, SRU_PAD_SOURCE);
output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.state,
SRU_PAD_SOURCE);
/* Adapt if SRUx2 is enabled. */ /* Adapt if SRUx2 is enabled. */
if (input->width != output->width) { if (input->width != output->width) {
window->width /= 2; window->width /= 2;
window->left /= 2; window->left /= 2;
window->height /= 2;
window->top /= 2;
} }
partition->sru = *window; partition->sru = *window;
......
...@@ -136,7 +136,7 @@ static int uds_enum_frame_size(struct v4l2_subdev *subdev, ...@@ -136,7 +136,7 @@ static int uds_enum_frame_size(struct v4l2_subdev *subdev,
if (!state) if (!state)
return -EINVAL; return -EINVAL;
format = vsp1_entity_get_pad_format(&uds->entity, state, UDS_PAD_SINK); format = v4l2_subdev_state_get_format(state, UDS_PAD_SINK);
mutex_lock(&uds->entity.lock); mutex_lock(&uds->entity.lock);
...@@ -183,8 +183,7 @@ static void uds_try_format(struct vsp1_uds *uds, ...@@ -183,8 +183,7 @@ static void uds_try_format(struct vsp1_uds *uds,
case UDS_PAD_SOURCE: case UDS_PAD_SOURCE:
/* The UDS scales but can't perform format conversion. */ /* The UDS scales but can't perform format conversion. */
format = vsp1_entity_get_pad_format(&uds->entity, sd_state, format = v4l2_subdev_state_get_format(sd_state, UDS_PAD_SINK);
UDS_PAD_SINK);
fmt->code = format->code; fmt->code = format->code;
uds_output_limits(format->width, &minimum, &maximum); uds_output_limits(format->width, &minimum, &maximum);
...@@ -217,13 +216,12 @@ static int uds_set_format(struct v4l2_subdev *subdev, ...@@ -217,13 +216,12 @@ static int uds_set_format(struct v4l2_subdev *subdev,
uds_try_format(uds, state, fmt->pad, &fmt->format); uds_try_format(uds, state, fmt->pad, &fmt->format);
format = vsp1_entity_get_pad_format(&uds->entity, state, fmt->pad); format = v4l2_subdev_state_get_format(state, fmt->pad);
*format = fmt->format; *format = fmt->format;
if (fmt->pad == UDS_PAD_SINK) { if (fmt->pad == UDS_PAD_SINK) {
/* Propagate the format to the source pad. */ /* Propagate the format to the source pad. */
format = vsp1_entity_get_pad_format(&uds->entity, state, format = v4l2_subdev_state_get_format(state, UDS_PAD_SOURCE);
UDS_PAD_SOURCE);
*format = fmt->format; *format = fmt->format;
uds_try_format(uds, state, UDS_PAD_SOURCE, format); uds_try_format(uds, state, UDS_PAD_SOURCE, format);
...@@ -254,6 +252,7 @@ static const struct v4l2_subdev_ops uds_ops = { ...@@ -254,6 +252,7 @@ static const struct v4l2_subdev_ops uds_ops = {
*/ */
static void uds_configure_stream(struct vsp1_entity *entity, static void uds_configure_stream(struct vsp1_entity *entity,
struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe, struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl, struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb) struct vsp1_dl_body *dlb)
...@@ -265,10 +264,8 @@ static void uds_configure_stream(struct vsp1_entity *entity, ...@@ -265,10 +264,8 @@ static void uds_configure_stream(struct vsp1_entity *entity,
unsigned int vscale; unsigned int vscale;
bool multitap; bool multitap;
input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.state, input = v4l2_subdev_state_get_format(state, UDS_PAD_SINK);
UDS_PAD_SINK); output = v4l2_subdev_state_get_format(state, UDS_PAD_SOURCE);
output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.state,
UDS_PAD_SOURCE);
hscale = uds_compute_ratio(input->width, output->width); hscale = uds_compute_ratio(input->width, output->width);
vscale = uds_compute_ratio(input->height, output->height); vscale = uds_compute_ratio(input->height, output->height);
...@@ -303,15 +300,11 @@ static void uds_configure_stream(struct vsp1_entity *entity, ...@@ -303,15 +300,11 @@ static void uds_configure_stream(struct vsp1_entity *entity,
static void uds_configure_partition(struct vsp1_entity *entity, static void uds_configure_partition(struct vsp1_entity *entity,
struct vsp1_pipeline *pipe, struct vsp1_pipeline *pipe,
const struct vsp1_partition *partition,
struct vsp1_dl_list *dl, struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb) struct vsp1_dl_body *dlb)
{ {
struct vsp1_uds *uds = to_uds(&entity->subdev); struct vsp1_uds *uds = to_uds(&entity->subdev);
struct vsp1_partition *partition = pipe->partition;
const struct v4l2_mbus_framefmt *output;
output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.state,
UDS_PAD_SOURCE);
/* Input size clipping. */ /* Input size clipping. */
vsp1_uds_write(uds, dlb, VI6_UDS_HSZCLIP, VI6_UDS_HSZCLIP_HCEN | vsp1_uds_write(uds, dlb, VI6_UDS_HSZCLIP, VI6_UDS_HSZCLIP_HCEN |
...@@ -323,22 +316,20 @@ static void uds_configure_partition(struct vsp1_entity *entity, ...@@ -323,22 +316,20 @@ static void uds_configure_partition(struct vsp1_entity *entity,
vsp1_uds_write(uds, dlb, VI6_UDS_CLIP_SIZE, vsp1_uds_write(uds, dlb, VI6_UDS_CLIP_SIZE,
(partition->uds_source.width (partition->uds_source.width
<< VI6_UDS_CLIP_SIZE_HSIZE_SHIFT) | << VI6_UDS_CLIP_SIZE_HSIZE_SHIFT) |
(output->height (partition->uds_source.height
<< VI6_UDS_CLIP_SIZE_VSIZE_SHIFT)); << VI6_UDS_CLIP_SIZE_VSIZE_SHIFT));
} }
static unsigned int uds_max_width(struct vsp1_entity *entity, static unsigned int uds_max_width(struct vsp1_entity *entity,
struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe) struct vsp1_pipeline *pipe)
{ {
struct vsp1_uds *uds = to_uds(&entity->subdev);
const struct v4l2_mbus_framefmt *output; const struct v4l2_mbus_framefmt *output;
const struct v4l2_mbus_framefmt *input; const struct v4l2_mbus_framefmt *input;
unsigned int hscale; unsigned int hscale;
input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.state, input = v4l2_subdev_state_get_format(state, UDS_PAD_SINK);
UDS_PAD_SINK); output = v4l2_subdev_state_get_format(state, UDS_PAD_SOURCE);
output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.state,
UDS_PAD_SOURCE);
hscale = output->width / input->width; hscale = output->width / input->width;
/* /*
...@@ -364,28 +355,26 @@ static unsigned int uds_max_width(struct vsp1_entity *entity, ...@@ -364,28 +355,26 @@ static unsigned int uds_max_width(struct vsp1_entity *entity,
*/ */
static void uds_partition(struct vsp1_entity *entity, static void uds_partition(struct vsp1_entity *entity,
struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe, struct vsp1_pipeline *pipe,
struct vsp1_partition *partition, struct vsp1_partition *partition,
unsigned int partition_idx, unsigned int partition_idx,
struct vsp1_partition_window *window) struct v4l2_rect *window)
{ {
struct vsp1_uds *uds = to_uds(&entity->subdev);
const struct v4l2_mbus_framefmt *output; const struct v4l2_mbus_framefmt *output;
const struct v4l2_mbus_framefmt *input; const struct v4l2_mbus_framefmt *input;
/* Initialise the partition state. */ input = v4l2_subdev_state_get_format(state, UDS_PAD_SINK);
partition->uds_sink = *window; output = v4l2_subdev_state_get_format(state, UDS_PAD_SOURCE);
partition->uds_source = *window;
input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.state,
UDS_PAD_SINK);
output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.state,
UDS_PAD_SOURCE);
partition->uds_sink.width = window->width * input->width partition->uds_sink.width = window->width * input->width
/ output->width; / output->width;
partition->uds_sink.left = window->left * input->width partition->uds_sink.left = window->left * input->width
/ output->width; / output->width;
partition->uds_sink.height = input->height;
partition->uds_sink.top = 0;
partition->uds_source = *window;
*window = partition->uds_sink; *window = partition->uds_sink;
} }
......
...@@ -104,8 +104,7 @@ static int uif_get_selection(struct v4l2_subdev *subdev, ...@@ -104,8 +104,7 @@ static int uif_get_selection(struct v4l2_subdev *subdev,
switch (sel->target) { switch (sel->target) {
case V4L2_SEL_TGT_CROP_BOUNDS: case V4L2_SEL_TGT_CROP_BOUNDS:
case V4L2_SEL_TGT_CROP_DEFAULT: case V4L2_SEL_TGT_CROP_DEFAULT:
format = vsp1_entity_get_pad_format(&uif->entity, state, format = v4l2_subdev_state_get_format(state, UIF_PAD_SINK);
UIF_PAD_SINK);
sel->r.left = 0; sel->r.left = 0;
sel->r.top = 0; sel->r.top = 0;
sel->r.width = format->width; sel->r.width = format->width;
...@@ -113,8 +112,7 @@ static int uif_get_selection(struct v4l2_subdev *subdev, ...@@ -113,8 +112,7 @@ static int uif_get_selection(struct v4l2_subdev *subdev,
break; break;
case V4L2_SEL_TGT_CROP: case V4L2_SEL_TGT_CROP:
sel->r = *vsp1_entity_get_pad_selection(&uif->entity, state, sel->r = *v4l2_subdev_state_get_crop(state, sel->pad);
sel->pad, sel->target);
break; break;
default: default:
...@@ -150,7 +148,7 @@ static int uif_set_selection(struct v4l2_subdev *subdev, ...@@ -150,7 +148,7 @@ static int uif_set_selection(struct v4l2_subdev *subdev,
} }
/* The crop rectangle must be inside the input frame. */ /* The crop rectangle must be inside the input frame. */
format = vsp1_entity_get_pad_format(&uif->entity, state, UIF_PAD_SINK); format = v4l2_subdev_state_get_format(state, UIF_PAD_SINK);
sel->r.left = clamp_t(unsigned int, sel->r.left, 0, format->width - 1); 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); sel->r.top = clamp_t(unsigned int, sel->r.top, 0, format->height - 1);
...@@ -160,8 +158,7 @@ static int uif_set_selection(struct v4l2_subdev *subdev, ...@@ -160,8 +158,7 @@ static int uif_set_selection(struct v4l2_subdev *subdev,
format->height - sel->r.top); format->height - sel->r.top);
/* Store the crop rectangle. */ /* Store the crop rectangle. */
selection = vsp1_entity_get_pad_selection(&uif->entity, state, selection = v4l2_subdev_state_get_crop(state, sel->pad);
sel->pad, V4L2_SEL_TGT_CROP);
*selection = sel->r; *selection = sel->r;
done: done:
...@@ -191,6 +188,7 @@ static const struct v4l2_subdev_ops uif_ops = { ...@@ -191,6 +188,7 @@ static const struct v4l2_subdev_ops uif_ops = {
*/ */
static void uif_configure_stream(struct vsp1_entity *entity, static void uif_configure_stream(struct vsp1_entity *entity,
struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe, struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl, struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb) struct vsp1_dl_body *dlb)
...@@ -203,8 +201,7 @@ static void uif_configure_stream(struct vsp1_entity *entity, ...@@ -203,8 +201,7 @@ static void uif_configure_stream(struct vsp1_entity *entity,
vsp1_uif_write(uif, dlb, VI6_UIF_DISCOM_DOCMPMR, vsp1_uif_write(uif, dlb, VI6_UIF_DISCOM_DOCMPMR,
VI6_UIF_DISCOM_DOCMPMR_SEL(9)); VI6_UIF_DISCOM_DOCMPMR_SEL(9));
crop = vsp1_entity_get_pad_selection(entity, entity->state, crop = v4l2_subdev_state_get_crop(state, UIF_PAD_SINK);
UIF_PAD_SINK, V4L2_SEL_TGT_CROP);
left = crop->left; left = crop->left;
width = crop->width; width = crop->width;
......
...@@ -78,8 +78,14 @@ static int vsp1_video_verify_format(struct vsp1_video *video) ...@@ -78,8 +78,14 @@ static int vsp1_video_verify_format(struct vsp1_video *video)
if (video->rwpf->fmtinfo->mbus != fmt.format.code || if (video->rwpf->fmtinfo->mbus != fmt.format.code ||
video->rwpf->format.height != fmt.format.height || video->rwpf->format.height != fmt.format.height ||
video->rwpf->format.width != fmt.format.width) video->rwpf->format.width != fmt.format.width) {
return -EINVAL; dev_dbg(video->vsp1->dev,
"Format mismatch: 0x%04x/%ux%u != 0x%04x/%ux%u\n",
video->rwpf->fmtinfo->mbus, video->rwpf->format.width,
video->rwpf->format.height, fmt.format.code,
fmt.format.width, fmt.format.height);
return -EPIPE;
}
return 0; return 0;
} }
...@@ -172,131 +178,6 @@ static int __vsp1_video_try_format(struct vsp1_video *video, ...@@ -172,131 +178,6 @@ static int __vsp1_video_try_format(struct vsp1_video *video,
return 0; return 0;
} }
/* -----------------------------------------------------------------------------
* VSP1 Partition Algorithm support
*/
/**
* vsp1_video_calculate_partition - Calculate the active partition output window
*
* @pipe: the pipeline
* @partition: partition that will hold the calculated values
* @div_size: pre-determined maximum partition division size
* @index: partition index
*/
static void vsp1_video_calculate_partition(struct vsp1_pipeline *pipe,
struct vsp1_partition *partition,
unsigned int div_size,
unsigned int index)
{
const struct v4l2_mbus_framefmt *format;
struct vsp1_partition_window window;
unsigned int modulus;
/*
* Partitions are computed on the size before rotation, use the format
* at the WPF sink.
*/
format = vsp1_entity_get_pad_format(&pipe->output->entity,
pipe->output->entity.state,
RWPF_PAD_SINK);
/* A single partition simply processes the output size in full. */
if (pipe->partitions <= 1) {
window.left = 0;
window.width = format->width;
vsp1_pipeline_propagate_partition(pipe, partition, index,
&window);
return;
}
/* Initialise the partition with sane starting conditions. */
window.left = index * div_size;
window.width = div_size;
modulus = format->width % div_size;
/*
* We need to prevent the last partition from being smaller than the
* *minimum* width of the hardware capabilities.
*
* If the modulus is less than half of the partition size,
* the penultimate partition is reduced to half, which is added
* to the final partition: |1234|1234|1234|12|341|
* to prevent this: |1234|1234|1234|1234|1|.
*/
if (modulus) {
/*
* pipe->partitions is 1 based, whilst index is a 0 based index.
* Normalise this locally.
*/
unsigned int partitions = pipe->partitions - 1;
if (modulus < div_size / 2) {
if (index == partitions - 1) {
/* Halve the penultimate partition. */
window.width = div_size / 2;
} else if (index == partitions) {
/* Increase the final partition. */
window.width = (div_size / 2) + modulus;
window.left -= div_size / 2;
}
} else if (index == partitions) {
window.width = modulus;
}
}
vsp1_pipeline_propagate_partition(pipe, partition, index, &window);
}
static int vsp1_video_pipeline_setup_partitions(struct vsp1_pipeline *pipe)
{
struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
const struct v4l2_mbus_framefmt *format;
struct vsp1_entity *entity;
unsigned int div_size;
unsigned int i;
/*
* Partitions are computed on the size before rotation, use the format
* at the WPF sink.
*/
format = vsp1_entity_get_pad_format(&pipe->output->entity,
pipe->output->entity.state,
RWPF_PAD_SINK);
div_size = format->width;
/*
* Only Gen3+ hardware requires image partitioning, Gen2 will operate
* with a single partition that covers the whole output.
*/
if (vsp1->info->gen >= 3) {
list_for_each_entry(entity, &pipe->entities, list_pipe) {
unsigned int entity_max;
if (!entity->ops->max_width)
continue;
entity_max = entity->ops->max_width(entity, pipe);
if (entity_max)
div_size = min(div_size, entity_max);
}
}
pipe->partitions = DIV_ROUND_UP(format->width, div_size);
pipe->part_table = kcalloc(pipe->partitions, sizeof(*pipe->part_table),
GFP_KERNEL);
if (!pipe->part_table)
return -ENOMEM;
for (i = 0; i < pipe->partitions; ++i)
vsp1_video_calculate_partition(pipe, &pipe->part_table[i],
div_size, i);
return 0;
}
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
* Pipeline Management * Pipeline Management
*/ */
...@@ -365,13 +246,12 @@ static void vsp1_video_pipeline_run_partition(struct vsp1_pipeline *pipe, ...@@ -365,13 +246,12 @@ static void vsp1_video_pipeline_run_partition(struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl, struct vsp1_dl_list *dl,
unsigned int partition) unsigned int partition)
{ {
struct vsp1_partition *part = &pipe->part_table[partition];
struct vsp1_dl_body *dlb = vsp1_dl_list_get_body0(dl); struct vsp1_dl_body *dlb = vsp1_dl_list_get_body0(dl);
struct vsp1_entity *entity; struct vsp1_entity *entity;
pipe->partition = &pipe->part_table[partition];
list_for_each_entry(entity, &pipe->entities, list_pipe) list_for_each_entry(entity, &pipe->entities, list_pipe)
vsp1_entity_configure_partition(entity, pipe, dl, dlb); vsp1_entity_configure_partition(entity, pipe, part, dl, dlb);
} }
static void vsp1_video_pipeline_run(struct vsp1_pipeline *pipe) static void vsp1_video_pipeline_run(struct vsp1_pipeline *pipe)
...@@ -646,11 +526,19 @@ static int vsp1_video_pipeline_build(struct vsp1_pipeline *pipe, ...@@ -646,11 +526,19 @@ static int vsp1_video_pipeline_build(struct vsp1_pipeline *pipe,
static int vsp1_video_pipeline_init(struct vsp1_pipeline *pipe, static int vsp1_video_pipeline_init(struct vsp1_pipeline *pipe,
struct vsp1_video *video) struct vsp1_video *video)
{ {
int ret;
vsp1_pipeline_init(pipe); vsp1_pipeline_init(pipe);
pipe->frame_end = vsp1_video_pipeline_frame_end; pipe->frame_end = vsp1_video_pipeline_frame_end;
return vsp1_video_pipeline_build(pipe, video); ret = vsp1_video_pipeline_build(pipe, video);
if (ret)
return ret;
vsp1_pipeline_dump(pipe, "video");
return 0;
} }
static struct vsp1_pipeline *vsp1_video_pipeline_get(struct vsp1_video *video) static struct vsp1_pipeline *vsp1_video_pipeline_get(struct vsp1_video *video)
...@@ -784,6 +672,54 @@ static void vsp1_video_buffer_queue(struct vb2_buffer *vb) ...@@ -784,6 +672,54 @@ static void vsp1_video_buffer_queue(struct vb2_buffer *vb)
spin_unlock_irqrestore(&pipe->irqlock, flags); spin_unlock_irqrestore(&pipe->irqlock, flags);
} }
static int vsp1_video_pipeline_setup_partitions(struct vsp1_pipeline *pipe)
{
struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
const struct v4l2_mbus_framefmt *format;
struct vsp1_entity *entity;
unsigned int div_size;
unsigned int i;
/*
* Partitions are computed on the size before rotation, use the format
* at the WPF sink.
*/
format = v4l2_subdev_state_get_format(pipe->output->entity.state,
RWPF_PAD_SINK);
div_size = format->width;
/*
* Only Gen3+ hardware requires image partitioning, Gen2 will operate
* with a single partition that covers the whole output.
*/
if (vsp1->info->gen >= 3) {
list_for_each_entry(entity, &pipe->entities, list_pipe) {
unsigned int entity_max;
if (!entity->ops->max_width)
continue;
entity_max = entity->ops->max_width(entity,
entity->state,
pipe);
if (entity_max)
div_size = min(div_size, entity_max);
}
}
pipe->partitions = DIV_ROUND_UP(format->width, div_size);
pipe->part_table = kcalloc(pipe->partitions, sizeof(*pipe->part_table),
GFP_KERNEL);
if (!pipe->part_table)
return -ENOMEM;
for (i = 0; i < pipe->partitions; ++i)
vsp1_pipeline_calculate_partition(pipe, &pipe->part_table[i],
div_size, i);
return 0;
}
static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe) static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe)
{ {
struct vsp1_entity *entity; struct vsp1_entity *entity;
...@@ -826,7 +762,7 @@ static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe) ...@@ -826,7 +762,7 @@ static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe)
list_for_each_entry(entity, &pipe->entities, list_pipe) { list_for_each_entry(entity, &pipe->entities, list_pipe) {
vsp1_entity_route_setup(entity, pipe, pipe->stream_config); vsp1_entity_route_setup(entity, pipe, pipe->stream_config);
vsp1_entity_configure_stream(entity, pipe, NULL, vsp1_entity_configure_stream(entity, entity->state, pipe, NULL,
pipe->stream_config); pipe->stream_config);
} }
......
...@@ -65,12 +65,10 @@ static int vsp1_wpf_set_rotation(struct vsp1_rwpf *wpf, unsigned int rotation) ...@@ -65,12 +65,10 @@ static int vsp1_wpf_set_rotation(struct vsp1_rwpf *wpf, unsigned int rotation)
goto done; goto done;
} }
sink_format = vsp1_entity_get_pad_format(&wpf->entity, sink_format = v4l2_subdev_state_get_format(wpf->entity.state,
wpf->entity.state, RWPF_PAD_SINK);
RWPF_PAD_SINK); source_format = v4l2_subdev_state_get_format(wpf->entity.state,
source_format = vsp1_entity_get_pad_format(&wpf->entity, RWPF_PAD_SOURCE);
wpf->entity.state,
RWPF_PAD_SOURCE);
mutex_lock(&wpf->entity.lock); mutex_lock(&wpf->entity.lock);
...@@ -231,6 +229,7 @@ static int wpf_configure_writeback_chain(struct vsp1_rwpf *wpf, ...@@ -231,6 +229,7 @@ static int wpf_configure_writeback_chain(struct vsp1_rwpf *wpf,
} }
static void wpf_configure_stream(struct vsp1_entity *entity, static void wpf_configure_stream(struct vsp1_entity *entity,
struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe, struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl, struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb) struct vsp1_dl_body *dlb)
...@@ -245,12 +244,8 @@ static void wpf_configure_stream(struct vsp1_entity *entity, ...@@ -245,12 +244,8 @@ static void wpf_configure_stream(struct vsp1_entity *entity,
u32 srcrpf = 0; u32 srcrpf = 0;
int ret; int ret;
sink_format = vsp1_entity_get_pad_format(&wpf->entity, sink_format = v4l2_subdev_state_get_format(state, RWPF_PAD_SINK);
wpf->entity.state, source_format = v4l2_subdev_state_get_format(state, RWPF_PAD_SOURCE);
RWPF_PAD_SINK);
source_format = vsp1_entity_get_pad_format(&wpf->entity,
wpf->entity.state,
RWPF_PAD_SOURCE);
/* Format */ /* Format */
if (!pipe->lif || wpf->writeback) { if (!pipe->lif || wpf->writeback) {
...@@ -367,13 +362,13 @@ static void wpf_configure_frame(struct vsp1_entity *entity, ...@@ -367,13 +362,13 @@ static void wpf_configure_frame(struct vsp1_entity *entity,
static void wpf_configure_partition(struct vsp1_entity *entity, static void wpf_configure_partition(struct vsp1_entity *entity,
struct vsp1_pipeline *pipe, struct vsp1_pipeline *pipe,
const struct vsp1_partition *partition,
struct vsp1_dl_list *dl, struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb) struct vsp1_dl_body *dlb)
{ {
struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev); struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev);
struct vsp1_device *vsp1 = wpf->entity.vsp1; struct vsp1_device *vsp1 = wpf->entity.vsp1;
struct vsp1_rwpf_memory mem = wpf->mem; struct vsp1_rwpf_memory mem = wpf->mem;
const struct v4l2_mbus_framefmt *sink_format;
const struct v4l2_pix_format_mplane *format = &wpf->format; const struct v4l2_pix_format_mplane *format = &wpf->format;
const struct vsp1_format_info *fmtinfo = wpf->fmtinfo; const struct vsp1_format_info *fmtinfo = wpf->fmtinfo;
unsigned int width; unsigned int width;
...@@ -383,21 +378,13 @@ static void wpf_configure_partition(struct vsp1_entity *entity, ...@@ -383,21 +378,13 @@ static void wpf_configure_partition(struct vsp1_entity *entity,
unsigned int flip; unsigned int flip;
unsigned int i; unsigned int i;
sink_format = vsp1_entity_get_pad_format(&wpf->entity,
wpf->entity.state,
RWPF_PAD_SINK);
width = sink_format->width;
height = sink_format->height;
left = 0;
/* /*
* Cropping. The partition algorithm can split the image into * Cropping. The partition algorithm can split the image into multiple
* multiple slices. * slices.
*/ */
if (pipe->partitions > 1) { width = partition->wpf.width;
width = pipe->partition->wpf.width; left = partition->wpf.left;
left = pipe->partition->wpf.left; height = partition->wpf.height;
}
vsp1_wpf_write(wpf, dlb, VI6_WPF_HSZCLIP, VI6_WPF_SZCLIP_EN | vsp1_wpf_write(wpf, dlb, VI6_WPF_HSZCLIP, VI6_WPF_SZCLIP_EN |
(0 << VI6_WPF_SZCLIP_OFST_SHIFT) | (0 << VI6_WPF_SZCLIP_OFST_SHIFT) |
...@@ -508,6 +495,7 @@ static void wpf_configure_partition(struct vsp1_entity *entity, ...@@ -508,6 +495,7 @@ static void wpf_configure_partition(struct vsp1_entity *entity,
} }
static unsigned int wpf_max_width(struct vsp1_entity *entity, static unsigned int wpf_max_width(struct vsp1_entity *entity,
struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe) struct vsp1_pipeline *pipe)
{ {
struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev); struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev);
...@@ -516,10 +504,11 @@ static unsigned int wpf_max_width(struct vsp1_entity *entity, ...@@ -516,10 +504,11 @@ static unsigned int wpf_max_width(struct vsp1_entity *entity,
} }
static void wpf_partition(struct vsp1_entity *entity, static void wpf_partition(struct vsp1_entity *entity,
struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe, struct vsp1_pipeline *pipe,
struct vsp1_partition *partition, struct vsp1_partition *partition,
unsigned int partition_idx, unsigned int partition_idx,
struct vsp1_partition_window *window) struct v4l2_rect *window)
{ {
partition->wpf = *window; partition->wpf = *window;
} }
......
...@@ -1269,14 +1269,6 @@ v4l2_subdev_link_validate_get_format(struct media_pad *pad, u32 stream, ...@@ -1269,14 +1269,6 @@ v4l2_subdev_link_validate_get_format(struct media_pad *pad, u32 stream,
struct v4l2_subdev *sd; struct v4l2_subdev *sd;
int ret; int ret;
if (!is_media_entity_v4l2_subdev(pad->entity)) {
WARN(pad->entity->function != MEDIA_ENT_F_IO_V4L,
"Driver bug! Wrong media entity type 0x%08x, entity %s\n",
pad->entity->function, pad->entity->name);
return -EINVAL;
}
sd = media_entity_to_v4l2_subdev(pad->entity); sd = media_entity_to_v4l2_subdev(pad->entity);
fmt->which = V4L2_SUBDEV_FORMAT_ACTIVE; fmt->which = V4L2_SUBDEV_FORMAT_ACTIVE;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment