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