1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * V4L2 Capture IC Preprocess Subdev for Freescale i.MX5/6 SOC 4 * 5 * This subdevice handles capture of video frames from the CSI or VDIC, 6 * which are routed directly to the Image Converter preprocess tasks, 7 * for resizing, colorspace conversion, and rotation. 8 * 9 * Copyright (c) 2012-2017 Mentor Graphics Inc. 10 */ 11 #include <linux/delay.h> 12 #include <linux/interrupt.h> 13 #include <linux/module.h> 14 #include <linux/sched.h> 15 #include <linux/slab.h> 16 #include <linux/spinlock.h> 17 #include <linux/timer.h> 18 #include <media/v4l2-ctrls.h> 19 #include <media/v4l2-device.h> 20 #include <media/v4l2-ioctl.h> 21 #include <media/v4l2-subdev.h> 22 #include <media/imx.h> 23 #include "imx-media.h" 24 #include "imx-ic.h" 25 26 /* 27 * Min/Max supported width and heights. 28 */ 29 #define MIN_W 176 30 #define MIN_H 144 31 #define MAX_W 4096 32 #define MAX_H 4096 33 #define W_ALIGN 4 /* multiple of 16 pixels */ 34 #define H_ALIGN 1 /* multiple of 2 lines */ 35 #define S_ALIGN 1 /* multiple of 2 */ 36 37 struct prp_priv { 38 struct imx_ic_priv *ic_priv; 39 struct media_pad pad[PRP_NUM_PADS]; 40 41 /* lock to protect all members below */ 42 struct mutex lock; 43 44 struct v4l2_subdev *src_sd; 45 struct v4l2_subdev *sink_sd_prpenc; 46 struct v4l2_subdev *sink_sd_prpvf; 47 48 /* the CSI id at link validate */ 49 int csi_id; 50 51 struct v4l2_mbus_framefmt format_mbus; 52 struct v4l2_fract frame_interval; 53 54 int stream_count; 55 }; 56 57 static inline struct prp_priv *sd_to_priv(struct v4l2_subdev *sd) 58 { 59 struct imx_ic_priv *ic_priv = v4l2_get_subdevdata(sd); 60 61 return ic_priv->task_priv; 62 } 63 64 static int prp_start(struct prp_priv *priv) 65 { 66 struct imx_ic_priv *ic_priv = priv->ic_priv; 67 bool src_is_vdic; 68 69 /* set IC to receive from CSI or VDI depending on source */ 70 src_is_vdic = !!(priv->src_sd->grp_id & IMX_MEDIA_GRP_ID_IPU_VDIC); 71 72 ipu_set_ic_src_mux(ic_priv->ipu, priv->csi_id, src_is_vdic); 73 74 return 0; 75 } 76 77 static void prp_stop(struct prp_priv *priv) 78 { 79 } 80 81 static struct v4l2_mbus_framefmt * 82 __prp_get_fmt(struct prp_priv *priv, struct v4l2_subdev_pad_config *cfg, 83 unsigned int pad, enum v4l2_subdev_format_whence which) 84 { 85 struct imx_ic_priv *ic_priv = priv->ic_priv; 86 87 if (which == V4L2_SUBDEV_FORMAT_TRY) 88 return v4l2_subdev_get_try_format(&ic_priv->sd, cfg, pad); 89 else 90 return &priv->format_mbus; 91 } 92 93 /* 94 * V4L2 subdev operations. 95 */ 96 97 static int prp_enum_mbus_code(struct v4l2_subdev *sd, 98 struct v4l2_subdev_pad_config *cfg, 99 struct v4l2_subdev_mbus_code_enum *code) 100 { 101 struct prp_priv *priv = sd_to_priv(sd); 102 struct v4l2_mbus_framefmt *infmt; 103 int ret = 0; 104 105 mutex_lock(&priv->lock); 106 107 switch (code->pad) { 108 case PRP_SINK_PAD: 109 ret = imx_media_enum_ipu_format(&code->code, code->index, 110 CS_SEL_ANY); 111 break; 112 case PRP_SRC_PAD_PRPENC: 113 case PRP_SRC_PAD_PRPVF: 114 if (code->index != 0) { 115 ret = -EINVAL; 116 goto out; 117 } 118 infmt = __prp_get_fmt(priv, cfg, PRP_SINK_PAD, code->which); 119 code->code = infmt->code; 120 break; 121 default: 122 ret = -EINVAL; 123 } 124 out: 125 mutex_unlock(&priv->lock); 126 return ret; 127 } 128 129 static int prp_get_fmt(struct v4l2_subdev *sd, 130 struct v4l2_subdev_pad_config *cfg, 131 struct v4l2_subdev_format *sdformat) 132 { 133 struct prp_priv *priv = sd_to_priv(sd); 134 struct v4l2_mbus_framefmt *fmt; 135 int ret = 0; 136 137 if (sdformat->pad >= PRP_NUM_PADS) 138 return -EINVAL; 139 140 mutex_lock(&priv->lock); 141 142 fmt = __prp_get_fmt(priv, cfg, sdformat->pad, sdformat->which); 143 if (!fmt) { 144 ret = -EINVAL; 145 goto out; 146 } 147 148 sdformat->format = *fmt; 149 out: 150 mutex_unlock(&priv->lock); 151 return ret; 152 } 153 154 static int prp_set_fmt(struct v4l2_subdev *sd, 155 struct v4l2_subdev_pad_config *cfg, 156 struct v4l2_subdev_format *sdformat) 157 { 158 struct prp_priv *priv = sd_to_priv(sd); 159 struct v4l2_mbus_framefmt *fmt, *infmt; 160 const struct imx_media_pixfmt *cc; 161 int ret = 0; 162 u32 code; 163 164 if (sdformat->pad >= PRP_NUM_PADS) 165 return -EINVAL; 166 167 mutex_lock(&priv->lock); 168 169 if (priv->stream_count > 0) { 170 ret = -EBUSY; 171 goto out; 172 } 173 174 infmt = __prp_get_fmt(priv, cfg, PRP_SINK_PAD, sdformat->which); 175 176 switch (sdformat->pad) { 177 case PRP_SINK_PAD: 178 v4l_bound_align_image(&sdformat->format.width, MIN_W, MAX_W, 179 W_ALIGN, &sdformat->format.height, 180 MIN_H, MAX_H, H_ALIGN, S_ALIGN); 181 182 cc = imx_media_find_ipu_format(sdformat->format.code, 183 CS_SEL_ANY); 184 if (!cc) { 185 imx_media_enum_ipu_format(&code, 0, CS_SEL_ANY); 186 cc = imx_media_find_ipu_format(code, CS_SEL_ANY); 187 sdformat->format.code = cc->codes[0]; 188 } 189 190 if (sdformat->format.field == V4L2_FIELD_ANY) 191 sdformat->format.field = V4L2_FIELD_NONE; 192 break; 193 case PRP_SRC_PAD_PRPENC: 194 case PRP_SRC_PAD_PRPVF: 195 /* Output pads mirror input pad */ 196 sdformat->format = *infmt; 197 break; 198 } 199 200 imx_media_try_colorimetry(&sdformat->format, true); 201 202 fmt = __prp_get_fmt(priv, cfg, sdformat->pad, sdformat->which); 203 *fmt = sdformat->format; 204 out: 205 mutex_unlock(&priv->lock); 206 return ret; 207 } 208 209 static int prp_link_setup(struct media_entity *entity, 210 const struct media_pad *local, 211 const struct media_pad *remote, u32 flags) 212 { 213 struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); 214 struct imx_ic_priv *ic_priv = v4l2_get_subdevdata(sd); 215 struct prp_priv *priv = ic_priv->task_priv; 216 struct v4l2_subdev *remote_sd; 217 int ret = 0; 218 219 dev_dbg(ic_priv->ipu_dev, "%s: link setup %s -> %s", 220 ic_priv->sd.name, remote->entity->name, local->entity->name); 221 222 remote_sd = media_entity_to_v4l2_subdev(remote->entity); 223 224 mutex_lock(&priv->lock); 225 226 if (local->flags & MEDIA_PAD_FL_SINK) { 227 if (flags & MEDIA_LNK_FL_ENABLED) { 228 if (priv->src_sd) { 229 ret = -EBUSY; 230 goto out; 231 } 232 if (priv->sink_sd_prpenc && 233 (remote_sd->grp_id & IMX_MEDIA_GRP_ID_IPU_VDIC)) { 234 ret = -EINVAL; 235 goto out; 236 } 237 priv->src_sd = remote_sd; 238 } else { 239 priv->src_sd = NULL; 240 } 241 242 goto out; 243 } 244 245 /* this is a source pad */ 246 if (flags & MEDIA_LNK_FL_ENABLED) { 247 switch (local->index) { 248 case PRP_SRC_PAD_PRPENC: 249 if (priv->sink_sd_prpenc) { 250 ret = -EBUSY; 251 goto out; 252 } 253 if (priv->src_sd && (priv->src_sd->grp_id & 254 IMX_MEDIA_GRP_ID_IPU_VDIC)) { 255 ret = -EINVAL; 256 goto out; 257 } 258 priv->sink_sd_prpenc = remote_sd; 259 break; 260 case PRP_SRC_PAD_PRPVF: 261 if (priv->sink_sd_prpvf) { 262 ret = -EBUSY; 263 goto out; 264 } 265 priv->sink_sd_prpvf = remote_sd; 266 break; 267 default: 268 ret = -EINVAL; 269 } 270 } else { 271 switch (local->index) { 272 case PRP_SRC_PAD_PRPENC: 273 priv->sink_sd_prpenc = NULL; 274 break; 275 case PRP_SRC_PAD_PRPVF: 276 priv->sink_sd_prpvf = NULL; 277 break; 278 default: 279 ret = -EINVAL; 280 } 281 } 282 283 out: 284 mutex_unlock(&priv->lock); 285 return ret; 286 } 287 288 static int prp_link_validate(struct v4l2_subdev *sd, 289 struct media_link *link, 290 struct v4l2_subdev_format *source_fmt, 291 struct v4l2_subdev_format *sink_fmt) 292 { 293 struct imx_ic_priv *ic_priv = v4l2_get_subdevdata(sd); 294 struct prp_priv *priv = ic_priv->task_priv; 295 struct v4l2_subdev *csi; 296 int ret; 297 298 ret = v4l2_subdev_link_validate_default(sd, link, 299 source_fmt, sink_fmt); 300 if (ret) 301 return ret; 302 303 csi = imx_media_pipeline_subdev(&ic_priv->sd.entity, 304 IMX_MEDIA_GRP_ID_IPU_CSI, true); 305 if (IS_ERR(csi)) 306 csi = NULL; 307 308 mutex_lock(&priv->lock); 309 310 if (priv->src_sd->grp_id & IMX_MEDIA_GRP_ID_IPU_VDIC) { 311 /* 312 * the ->PRPENC link cannot be enabled if the source 313 * is the VDIC 314 */ 315 if (priv->sink_sd_prpenc) { 316 ret = -EINVAL; 317 goto out; 318 } 319 } else { 320 /* the source is a CSI */ 321 if (!csi) { 322 ret = -EINVAL; 323 goto out; 324 } 325 } 326 327 if (csi) { 328 switch (csi->grp_id) { 329 case IMX_MEDIA_GRP_ID_IPU_CSI0: 330 priv->csi_id = 0; 331 break; 332 case IMX_MEDIA_GRP_ID_IPU_CSI1: 333 priv->csi_id = 1; 334 break; 335 default: 336 ret = -EINVAL; 337 } 338 } else { 339 priv->csi_id = 0; 340 } 341 342 out: 343 mutex_unlock(&priv->lock); 344 return ret; 345 } 346 347 static int prp_s_stream(struct v4l2_subdev *sd, int enable) 348 { 349 struct imx_ic_priv *ic_priv = v4l2_get_subdevdata(sd); 350 struct prp_priv *priv = ic_priv->task_priv; 351 int ret = 0; 352 353 mutex_lock(&priv->lock); 354 355 if (!priv->src_sd || (!priv->sink_sd_prpenc && !priv->sink_sd_prpvf)) { 356 ret = -EPIPE; 357 goto out; 358 } 359 360 /* 361 * enable/disable streaming only if stream_count is 362 * going from 0 to 1 / 1 to 0. 363 */ 364 if (priv->stream_count != !enable) 365 goto update_count; 366 367 dev_dbg(ic_priv->ipu_dev, "%s: stream %s\n", sd->name, 368 enable ? "ON" : "OFF"); 369 370 if (enable) 371 ret = prp_start(priv); 372 else 373 prp_stop(priv); 374 if (ret) 375 goto out; 376 377 /* start/stop upstream */ 378 ret = v4l2_subdev_call(priv->src_sd, video, s_stream, enable); 379 ret = (ret && ret != -ENOIOCTLCMD) ? ret : 0; 380 if (ret) { 381 if (enable) 382 prp_stop(priv); 383 goto out; 384 } 385 386 update_count: 387 priv->stream_count += enable ? 1 : -1; 388 if (priv->stream_count < 0) 389 priv->stream_count = 0; 390 out: 391 mutex_unlock(&priv->lock); 392 return ret; 393 } 394 395 static int prp_g_frame_interval(struct v4l2_subdev *sd, 396 struct v4l2_subdev_frame_interval *fi) 397 { 398 struct prp_priv *priv = sd_to_priv(sd); 399 400 if (fi->pad >= PRP_NUM_PADS) 401 return -EINVAL; 402 403 mutex_lock(&priv->lock); 404 fi->interval = priv->frame_interval; 405 mutex_unlock(&priv->lock); 406 407 return 0; 408 } 409 410 static int prp_s_frame_interval(struct v4l2_subdev *sd, 411 struct v4l2_subdev_frame_interval *fi) 412 { 413 struct prp_priv *priv = sd_to_priv(sd); 414 415 if (fi->pad >= PRP_NUM_PADS) 416 return -EINVAL; 417 418 mutex_lock(&priv->lock); 419 420 /* No limits on valid frame intervals */ 421 if (fi->interval.numerator == 0 || fi->interval.denominator == 0) 422 fi->interval = priv->frame_interval; 423 else 424 priv->frame_interval = fi->interval; 425 426 mutex_unlock(&priv->lock); 427 428 return 0; 429 } 430 431 static int prp_registered(struct v4l2_subdev *sd) 432 { 433 struct prp_priv *priv = sd_to_priv(sd); 434 u32 code; 435 436 /* init default frame interval */ 437 priv->frame_interval.numerator = 1; 438 priv->frame_interval.denominator = 30; 439 440 /* set a default mbus format */ 441 imx_media_enum_ipu_format(&code, 0, CS_SEL_YUV); 442 return imx_media_init_mbus_fmt(&priv->format_mbus, 640, 480, code, 443 V4L2_FIELD_NONE, NULL); 444 } 445 446 static const struct v4l2_subdev_pad_ops prp_pad_ops = { 447 .init_cfg = imx_media_init_cfg, 448 .enum_mbus_code = prp_enum_mbus_code, 449 .get_fmt = prp_get_fmt, 450 .set_fmt = prp_set_fmt, 451 .link_validate = prp_link_validate, 452 }; 453 454 static const struct v4l2_subdev_video_ops prp_video_ops = { 455 .g_frame_interval = prp_g_frame_interval, 456 .s_frame_interval = prp_s_frame_interval, 457 .s_stream = prp_s_stream, 458 }; 459 460 static const struct media_entity_operations prp_entity_ops = { 461 .link_setup = prp_link_setup, 462 .link_validate = v4l2_subdev_link_validate, 463 }; 464 465 static const struct v4l2_subdev_ops prp_subdev_ops = { 466 .video = &prp_video_ops, 467 .pad = &prp_pad_ops, 468 }; 469 470 static const struct v4l2_subdev_internal_ops prp_internal_ops = { 471 .registered = prp_registered, 472 }; 473 474 static int prp_init(struct imx_ic_priv *ic_priv) 475 { 476 struct prp_priv *priv; 477 int i; 478 479 priv = devm_kzalloc(ic_priv->ipu_dev, sizeof(*priv), GFP_KERNEL); 480 if (!priv) 481 return -ENOMEM; 482 483 mutex_init(&priv->lock); 484 ic_priv->task_priv = priv; 485 priv->ic_priv = ic_priv; 486 487 for (i = 0; i < PRP_NUM_PADS; i++) 488 priv->pad[i].flags = (i == PRP_SINK_PAD) ? 489 MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE; 490 491 return media_entity_pads_init(&ic_priv->sd.entity, PRP_NUM_PADS, 492 priv->pad); 493 } 494 495 static void prp_remove(struct imx_ic_priv *ic_priv) 496 { 497 struct prp_priv *priv = ic_priv->task_priv; 498 499 mutex_destroy(&priv->lock); 500 } 501 502 struct imx_ic_ops imx_ic_prp_ops = { 503 .subdev_ops = &prp_subdev_ops, 504 .internal_ops = &prp_internal_ops, 505 .entity_ops = &prp_entity_ops, 506 .init = prp_init, 507 .remove = prp_remove, 508 }; 509