0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/delay.h>
0012 #include <linux/interrupt.h>
0013 #include <linux/module.h>
0014 #include <linux/sched.h>
0015 #include <linux/slab.h>
0016 #include <linux/spinlock.h>
0017 #include <linux/timer.h>
0018 #include <media/v4l2-ctrls.h>
0019 #include <media/v4l2-device.h>
0020 #include <media/v4l2-ioctl.h>
0021 #include <media/v4l2-subdev.h>
0022 #include <media/imx.h>
0023 #include "imx-media.h"
0024 #include "imx-ic.h"
0025
0026
0027
0028
0029 #define MIN_W 32
0030 #define MIN_H 32
0031 #define MAX_W 4096
0032 #define MAX_H 4096
0033 #define W_ALIGN 4
0034 #define H_ALIGN 1
0035 #define S_ALIGN 1
0036
0037 struct prp_priv {
0038 struct imx_ic_priv *ic_priv;
0039 struct media_pad pad[PRP_NUM_PADS];
0040
0041
0042 struct mutex lock;
0043
0044 struct v4l2_subdev *src_sd;
0045 struct v4l2_subdev *sink_sd_prpenc;
0046 struct v4l2_subdev *sink_sd_prpvf;
0047
0048
0049 int csi_id;
0050
0051 struct v4l2_mbus_framefmt format_mbus;
0052 struct v4l2_fract frame_interval;
0053
0054 int stream_count;
0055 };
0056
0057 static inline struct prp_priv *sd_to_priv(struct v4l2_subdev *sd)
0058 {
0059 struct imx_ic_priv *ic_priv = v4l2_get_subdevdata(sd);
0060
0061 return ic_priv->task_priv;
0062 }
0063
0064 static int prp_start(struct prp_priv *priv)
0065 {
0066 struct imx_ic_priv *ic_priv = priv->ic_priv;
0067 bool src_is_vdic;
0068
0069
0070 src_is_vdic = !!(priv->src_sd->grp_id & IMX_MEDIA_GRP_ID_IPU_VDIC);
0071
0072 ipu_set_ic_src_mux(ic_priv->ipu, priv->csi_id, src_is_vdic);
0073
0074 return 0;
0075 }
0076
0077 static void prp_stop(struct prp_priv *priv)
0078 {
0079 }
0080
0081 static struct v4l2_mbus_framefmt *
0082 __prp_get_fmt(struct prp_priv *priv, struct v4l2_subdev_state *sd_state,
0083 unsigned int pad, enum v4l2_subdev_format_whence which)
0084 {
0085 struct imx_ic_priv *ic_priv = priv->ic_priv;
0086
0087 if (which == V4L2_SUBDEV_FORMAT_TRY)
0088 return v4l2_subdev_get_try_format(&ic_priv->sd, sd_state, pad);
0089 else
0090 return &priv->format_mbus;
0091 }
0092
0093
0094
0095
0096
0097 static int prp_enum_mbus_code(struct v4l2_subdev *sd,
0098 struct v4l2_subdev_state *sd_state,
0099 struct v4l2_subdev_mbus_code_enum *code)
0100 {
0101 struct prp_priv *priv = sd_to_priv(sd);
0102 struct v4l2_mbus_framefmt *infmt;
0103 int ret = 0;
0104
0105 mutex_lock(&priv->lock);
0106
0107 switch (code->pad) {
0108 case PRP_SINK_PAD:
0109 ret = imx_media_enum_ipu_formats(&code->code, code->index,
0110 PIXFMT_SEL_YUV_RGB);
0111 break;
0112 case PRP_SRC_PAD_PRPENC:
0113 case PRP_SRC_PAD_PRPVF:
0114 if (code->index != 0) {
0115 ret = -EINVAL;
0116 goto out;
0117 }
0118 infmt = __prp_get_fmt(priv, sd_state, PRP_SINK_PAD,
0119 code->which);
0120 code->code = infmt->code;
0121 break;
0122 default:
0123 ret = -EINVAL;
0124 }
0125 out:
0126 mutex_unlock(&priv->lock);
0127 return ret;
0128 }
0129
0130 static int prp_get_fmt(struct v4l2_subdev *sd,
0131 struct v4l2_subdev_state *sd_state,
0132 struct v4l2_subdev_format *sdformat)
0133 {
0134 struct prp_priv *priv = sd_to_priv(sd);
0135 struct v4l2_mbus_framefmt *fmt;
0136 int ret = 0;
0137
0138 if (sdformat->pad >= PRP_NUM_PADS)
0139 return -EINVAL;
0140
0141 mutex_lock(&priv->lock);
0142
0143 fmt = __prp_get_fmt(priv, sd_state, sdformat->pad, sdformat->which);
0144 if (!fmt) {
0145 ret = -EINVAL;
0146 goto out;
0147 }
0148
0149 sdformat->format = *fmt;
0150 out:
0151 mutex_unlock(&priv->lock);
0152 return ret;
0153 }
0154
0155 static int prp_set_fmt(struct v4l2_subdev *sd,
0156 struct v4l2_subdev_state *sd_state,
0157 struct v4l2_subdev_format *sdformat)
0158 {
0159 struct prp_priv *priv = sd_to_priv(sd);
0160 struct v4l2_mbus_framefmt *fmt, *infmt;
0161 const struct imx_media_pixfmt *cc;
0162 int ret = 0;
0163 u32 code;
0164
0165 if (sdformat->pad >= PRP_NUM_PADS)
0166 return -EINVAL;
0167
0168 mutex_lock(&priv->lock);
0169
0170 if (priv->stream_count > 0) {
0171 ret = -EBUSY;
0172 goto out;
0173 }
0174
0175 infmt = __prp_get_fmt(priv, sd_state, PRP_SINK_PAD, sdformat->which);
0176
0177 switch (sdformat->pad) {
0178 case PRP_SINK_PAD:
0179 v4l_bound_align_image(&sdformat->format.width, MIN_W, MAX_W,
0180 W_ALIGN, &sdformat->format.height,
0181 MIN_H, MAX_H, H_ALIGN, S_ALIGN);
0182
0183 cc = imx_media_find_ipu_format(sdformat->format.code,
0184 PIXFMT_SEL_YUV_RGB);
0185 if (!cc) {
0186 imx_media_enum_ipu_formats(&code, 0,
0187 PIXFMT_SEL_YUV_RGB);
0188 cc = imx_media_find_ipu_format(code,
0189 PIXFMT_SEL_YUV_RGB);
0190 sdformat->format.code = cc->codes[0];
0191 }
0192
0193 if (sdformat->format.field == V4L2_FIELD_ANY)
0194 sdformat->format.field = V4L2_FIELD_NONE;
0195 break;
0196 case PRP_SRC_PAD_PRPENC:
0197 case PRP_SRC_PAD_PRPVF:
0198
0199 sdformat->format = *infmt;
0200 break;
0201 }
0202
0203 imx_media_try_colorimetry(&sdformat->format, true);
0204
0205 fmt = __prp_get_fmt(priv, sd_state, sdformat->pad, sdformat->which);
0206 *fmt = sdformat->format;
0207 out:
0208 mutex_unlock(&priv->lock);
0209 return ret;
0210 }
0211
0212 static int prp_link_setup(struct media_entity *entity,
0213 const struct media_pad *local,
0214 const struct media_pad *remote, u32 flags)
0215 {
0216 struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
0217 struct imx_ic_priv *ic_priv = v4l2_get_subdevdata(sd);
0218 struct prp_priv *priv = ic_priv->task_priv;
0219 struct v4l2_subdev *remote_sd;
0220 int ret = 0;
0221
0222 dev_dbg(ic_priv->ipu_dev, "%s: link setup %s -> %s",
0223 ic_priv->sd.name, remote->entity->name, local->entity->name);
0224
0225 remote_sd = media_entity_to_v4l2_subdev(remote->entity);
0226
0227 mutex_lock(&priv->lock);
0228
0229 if (local->flags & MEDIA_PAD_FL_SINK) {
0230 if (flags & MEDIA_LNK_FL_ENABLED) {
0231 if (priv->src_sd) {
0232 ret = -EBUSY;
0233 goto out;
0234 }
0235 if (priv->sink_sd_prpenc &&
0236 (remote_sd->grp_id & IMX_MEDIA_GRP_ID_IPU_VDIC)) {
0237 ret = -EINVAL;
0238 goto out;
0239 }
0240 priv->src_sd = remote_sd;
0241 } else {
0242 priv->src_sd = NULL;
0243 }
0244
0245 goto out;
0246 }
0247
0248
0249 if (flags & MEDIA_LNK_FL_ENABLED) {
0250 switch (local->index) {
0251 case PRP_SRC_PAD_PRPENC:
0252 if (priv->sink_sd_prpenc) {
0253 ret = -EBUSY;
0254 goto out;
0255 }
0256 if (priv->src_sd && (priv->src_sd->grp_id &
0257 IMX_MEDIA_GRP_ID_IPU_VDIC)) {
0258 ret = -EINVAL;
0259 goto out;
0260 }
0261 priv->sink_sd_prpenc = remote_sd;
0262 break;
0263 case PRP_SRC_PAD_PRPVF:
0264 if (priv->sink_sd_prpvf) {
0265 ret = -EBUSY;
0266 goto out;
0267 }
0268 priv->sink_sd_prpvf = remote_sd;
0269 break;
0270 default:
0271 ret = -EINVAL;
0272 }
0273 } else {
0274 switch (local->index) {
0275 case PRP_SRC_PAD_PRPENC:
0276 priv->sink_sd_prpenc = NULL;
0277 break;
0278 case PRP_SRC_PAD_PRPVF:
0279 priv->sink_sd_prpvf = NULL;
0280 break;
0281 default:
0282 ret = -EINVAL;
0283 }
0284 }
0285
0286 out:
0287 mutex_unlock(&priv->lock);
0288 return ret;
0289 }
0290
0291 static int prp_link_validate(struct v4l2_subdev *sd,
0292 struct media_link *link,
0293 struct v4l2_subdev_format *source_fmt,
0294 struct v4l2_subdev_format *sink_fmt)
0295 {
0296 struct imx_ic_priv *ic_priv = v4l2_get_subdevdata(sd);
0297 struct prp_priv *priv = ic_priv->task_priv;
0298 struct v4l2_subdev *csi;
0299 int ret;
0300
0301 ret = v4l2_subdev_link_validate_default(sd, link,
0302 source_fmt, sink_fmt);
0303 if (ret)
0304 return ret;
0305
0306 csi = imx_media_pipeline_subdev(&ic_priv->sd.entity,
0307 IMX_MEDIA_GRP_ID_IPU_CSI, true);
0308 if (IS_ERR(csi))
0309 csi = NULL;
0310
0311 mutex_lock(&priv->lock);
0312
0313 if (priv->src_sd->grp_id & IMX_MEDIA_GRP_ID_IPU_VDIC) {
0314
0315
0316
0317
0318 if (priv->sink_sd_prpenc) {
0319 ret = -EINVAL;
0320 goto out;
0321 }
0322 } else {
0323
0324 if (!csi) {
0325 ret = -EINVAL;
0326 goto out;
0327 }
0328 }
0329
0330 if (csi) {
0331 switch (csi->grp_id) {
0332 case IMX_MEDIA_GRP_ID_IPU_CSI0:
0333 priv->csi_id = 0;
0334 break;
0335 case IMX_MEDIA_GRP_ID_IPU_CSI1:
0336 priv->csi_id = 1;
0337 break;
0338 default:
0339 ret = -EINVAL;
0340 }
0341 } else {
0342 priv->csi_id = 0;
0343 }
0344
0345 out:
0346 mutex_unlock(&priv->lock);
0347 return ret;
0348 }
0349
0350 static int prp_s_stream(struct v4l2_subdev *sd, int enable)
0351 {
0352 struct imx_ic_priv *ic_priv = v4l2_get_subdevdata(sd);
0353 struct prp_priv *priv = ic_priv->task_priv;
0354 int ret = 0;
0355
0356 mutex_lock(&priv->lock);
0357
0358 if (!priv->src_sd || (!priv->sink_sd_prpenc && !priv->sink_sd_prpvf)) {
0359 ret = -EPIPE;
0360 goto out;
0361 }
0362
0363
0364
0365
0366
0367 if (priv->stream_count != !enable)
0368 goto update_count;
0369
0370 dev_dbg(ic_priv->ipu_dev, "%s: stream %s\n", sd->name,
0371 enable ? "ON" : "OFF");
0372
0373 if (enable)
0374 ret = prp_start(priv);
0375 else
0376 prp_stop(priv);
0377 if (ret)
0378 goto out;
0379
0380
0381 ret = v4l2_subdev_call(priv->src_sd, video, s_stream, enable);
0382 ret = (ret && ret != -ENOIOCTLCMD) ? ret : 0;
0383 if (ret) {
0384 if (enable)
0385 prp_stop(priv);
0386 goto out;
0387 }
0388
0389 update_count:
0390 priv->stream_count += enable ? 1 : -1;
0391 if (priv->stream_count < 0)
0392 priv->stream_count = 0;
0393 out:
0394 mutex_unlock(&priv->lock);
0395 return ret;
0396 }
0397
0398 static int prp_g_frame_interval(struct v4l2_subdev *sd,
0399 struct v4l2_subdev_frame_interval *fi)
0400 {
0401 struct prp_priv *priv = sd_to_priv(sd);
0402
0403 if (fi->pad >= PRP_NUM_PADS)
0404 return -EINVAL;
0405
0406 mutex_lock(&priv->lock);
0407 fi->interval = priv->frame_interval;
0408 mutex_unlock(&priv->lock);
0409
0410 return 0;
0411 }
0412
0413 static int prp_s_frame_interval(struct v4l2_subdev *sd,
0414 struct v4l2_subdev_frame_interval *fi)
0415 {
0416 struct prp_priv *priv = sd_to_priv(sd);
0417
0418 if (fi->pad >= PRP_NUM_PADS)
0419 return -EINVAL;
0420
0421 mutex_lock(&priv->lock);
0422
0423
0424 if (fi->interval.numerator == 0 || fi->interval.denominator == 0)
0425 fi->interval = priv->frame_interval;
0426 else
0427 priv->frame_interval = fi->interval;
0428
0429 mutex_unlock(&priv->lock);
0430
0431 return 0;
0432 }
0433
0434 static int prp_registered(struct v4l2_subdev *sd)
0435 {
0436 struct prp_priv *priv = sd_to_priv(sd);
0437 u32 code;
0438
0439
0440 priv->frame_interval.numerator = 1;
0441 priv->frame_interval.denominator = 30;
0442
0443
0444 imx_media_enum_ipu_formats(&code, 0, PIXFMT_SEL_YUV);
0445
0446 return imx_media_init_mbus_fmt(&priv->format_mbus,
0447 IMX_MEDIA_DEF_PIX_WIDTH,
0448 IMX_MEDIA_DEF_PIX_HEIGHT, code,
0449 V4L2_FIELD_NONE, NULL);
0450 }
0451
0452 static const struct v4l2_subdev_pad_ops prp_pad_ops = {
0453 .init_cfg = imx_media_init_cfg,
0454 .enum_mbus_code = prp_enum_mbus_code,
0455 .get_fmt = prp_get_fmt,
0456 .set_fmt = prp_set_fmt,
0457 .link_validate = prp_link_validate,
0458 };
0459
0460 static const struct v4l2_subdev_video_ops prp_video_ops = {
0461 .g_frame_interval = prp_g_frame_interval,
0462 .s_frame_interval = prp_s_frame_interval,
0463 .s_stream = prp_s_stream,
0464 };
0465
0466 static const struct media_entity_operations prp_entity_ops = {
0467 .link_setup = prp_link_setup,
0468 .link_validate = v4l2_subdev_link_validate,
0469 };
0470
0471 static const struct v4l2_subdev_ops prp_subdev_ops = {
0472 .video = &prp_video_ops,
0473 .pad = &prp_pad_ops,
0474 };
0475
0476 static const struct v4l2_subdev_internal_ops prp_internal_ops = {
0477 .registered = prp_registered,
0478 };
0479
0480 static int prp_init(struct imx_ic_priv *ic_priv)
0481 {
0482 struct prp_priv *priv;
0483 int i;
0484
0485 priv = devm_kzalloc(ic_priv->ipu_dev, sizeof(*priv), GFP_KERNEL);
0486 if (!priv)
0487 return -ENOMEM;
0488
0489 mutex_init(&priv->lock);
0490 ic_priv->task_priv = priv;
0491 priv->ic_priv = ic_priv;
0492
0493 for (i = 0; i < PRP_NUM_PADS; i++)
0494 priv->pad[i].flags = (i == PRP_SINK_PAD) ?
0495 MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
0496
0497 return media_entity_pads_init(&ic_priv->sd.entity, PRP_NUM_PADS,
0498 priv->pad);
0499 }
0500
0501 static void prp_remove(struct imx_ic_priv *ic_priv)
0502 {
0503 struct prp_priv *priv = ic_priv->task_priv;
0504
0505 mutex_destroy(&priv->lock);
0506 }
0507
0508 struct imx_ic_ops imx_ic_prp_ops = {
0509 .subdev_ops = &prp_subdev_ops,
0510 .internal_ops = &prp_internal_ops,
0511 .entity_ops = &prp_entity_ops,
0512 .init = prp_init,
0513 .remove = prp_remove,
0514 };