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 32 30 #define MIN_H 32 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_formats(&code->code, code->index, 110 PIXFMT_SEL_YUV_RGB); 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 PIXFMT_SEL_YUV_RGB); 184 if (!cc) { 185 imx_media_enum_ipu_formats(&code, 0, 186 PIXFMT_SEL_YUV_RGB); 187 cc = imx_media_find_ipu_format(code, 188 PIXFMT_SEL_YUV_RGB); 189 sdformat->format.code = cc->codes[0]; 190 } 191 192 if (sdformat->format.field == V4L2_FIELD_ANY) 193 sdformat->format.field = V4L2_FIELD_NONE; 194 break; 195 case PRP_SRC_PAD_PRPENC: 196 case PRP_SRC_PAD_PRPVF: 197 /* Output pads mirror input pad */ 198 sdformat->format = *infmt; 199 break; 200 } 201 202 imx_media_try_colorimetry(&sdformat->format, true); 203 204 fmt = __prp_get_fmt(priv, cfg, sdformat->pad, sdformat->which); 205 *fmt = sdformat->format; 206 out: 207 mutex_unlock(&priv->lock); 208 return ret; 209 } 210 211 static int prp_link_setup(struct media_entity *entity, 212 const struct media_pad *local, 213 const struct media_pad *remote, u32 flags) 214 { 215 struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); 216 struct imx_ic_priv *ic_priv = v4l2_get_subdevdata(sd); 217 struct prp_priv *priv = ic_priv->task_priv; 218 struct v4l2_subdev *remote_sd; 219 int ret = 0; 220 221 dev_dbg(ic_priv->ipu_dev, "%s: link setup %s -> %s", 222 ic_priv->sd.name, remote->entity->name, local->entity->name); 223 224 remote_sd = media_entity_to_v4l2_subdev(remote->entity); 225 226 mutex_lock(&priv->lock); 227 228 if (local->flags & MEDIA_PAD_FL_SINK) { 229 if (flags & MEDIA_LNK_FL_ENABLED) { 230 if (priv->src_sd) { 231 ret = -EBUSY; 232 goto out; 233 } 234 if (priv->sink_sd_prpenc && 235 (remote_sd->grp_id & IMX_MEDIA_GRP_ID_IPU_VDIC)) { 236 ret = -EINVAL; 237 goto out; 238 } 239 priv->src_sd = remote_sd; 240 } else { 241 priv->src_sd = NULL; 242 } 243 244 goto out; 245 } 246 247 /* this is a source pad */ 248 if (flags & MEDIA_LNK_FL_ENABLED) { 249 switch (local->index) { 250 case PRP_SRC_PAD_PRPENC: 251 if (priv->sink_sd_prpenc) { 252 ret = -EBUSY; 253 goto out; 254 } 255 if (priv->src_sd && (priv->src_sd->grp_id & 256 IMX_MEDIA_GRP_ID_IPU_VDIC)) { 257 ret = -EINVAL; 258 goto out; 259 } 260 priv->sink_sd_prpenc = remote_sd; 261 break; 262 case PRP_SRC_PAD_PRPVF: 263 if (priv->sink_sd_prpvf) { 264 ret = -EBUSY; 265 goto out; 266 } 267 priv->sink_sd_prpvf = remote_sd; 268 break; 269 default: 270 ret = -EINVAL; 271 } 272 } else { 273 switch (local->index) { 274 case PRP_SRC_PAD_PRPENC: 275 priv->sink_sd_prpenc = NULL; 276 break; 277 case PRP_SRC_PAD_PRPVF: 278 priv->sink_sd_prpvf = NULL; 279 break; 280 default: 281 ret = -EINVAL; 282 } 283 } 284 285 out: 286 mutex_unlock(&priv->lock); 287 return ret; 288 } 289 290 static int prp_link_validate(struct v4l2_subdev *sd, 291 struct media_link *link, 292 struct v4l2_subdev_format *source_fmt, 293 struct v4l2_subdev_format *sink_fmt) 294 { 295 struct imx_ic_priv *ic_priv = v4l2_get_subdevdata(sd); 296 struct prp_priv *priv = ic_priv->task_priv; 297 struct v4l2_subdev *csi; 298 int ret; 299 300 ret = v4l2_subdev_link_validate_default(sd, link, 301 source_fmt, sink_fmt); 302 if (ret) 303 return ret; 304 305 csi = imx_media_pipeline_subdev(&ic_priv->sd.entity, 306 IMX_MEDIA_GRP_ID_IPU_CSI, true); 307 if (IS_ERR(csi)) 308 csi = NULL; 309 310 mutex_lock(&priv->lock); 311 312 if (priv->src_sd->grp_id & IMX_MEDIA_GRP_ID_IPU_VDIC) { 313 /* 314 * the ->PRPENC link cannot be enabled if the source 315 * is the VDIC 316 */ 317 if (priv->sink_sd_prpenc) { 318 ret = -EINVAL; 319 goto out; 320 } 321 } else { 322 /* the source is a CSI */ 323 if (!csi) { 324 ret = -EINVAL; 325 goto out; 326 } 327 } 328 329 if (csi) { 330 switch (csi->grp_id) { 331 case IMX_MEDIA_GRP_ID_IPU_CSI0: 332 priv->csi_id = 0; 333 break; 334 case IMX_MEDIA_GRP_ID_IPU_CSI1: 335 priv->csi_id = 1; 336 break; 337 default: 338 ret = -EINVAL; 339 } 340 } else { 341 priv->csi_id = 0; 342 } 343 344 out: 345 mutex_unlock(&priv->lock); 346 return ret; 347 } 348 349 static int prp_s_stream(struct v4l2_subdev *sd, int enable) 350 { 351 struct imx_ic_priv *ic_priv = v4l2_get_subdevdata(sd); 352 struct prp_priv *priv = ic_priv->task_priv; 353 int ret = 0; 354 355 mutex_lock(&priv->lock); 356 357 if (!priv->src_sd || (!priv->sink_sd_prpenc && !priv->sink_sd_prpvf)) { 358 ret = -EPIPE; 359 goto out; 360 } 361 362 /* 363 * enable/disable streaming only if stream_count is 364 * going from 0 to 1 / 1 to 0. 365 */ 366 if (priv->stream_count != !enable) 367 goto update_count; 368 369 dev_dbg(ic_priv->ipu_dev, "%s: stream %s\n", sd->name, 370 enable ? "ON" : "OFF"); 371 372 if (enable) 373 ret = prp_start(priv); 374 else 375 prp_stop(priv); 376 if (ret) 377 goto out; 378 379 /* start/stop upstream */ 380 ret = v4l2_subdev_call(priv->src_sd, video, s_stream, enable); 381 ret = (ret && ret != -ENOIOCTLCMD) ? ret : 0; 382 if (ret) { 383 if (enable) 384 prp_stop(priv); 385 goto out; 386 } 387 388 update_count: 389 priv->stream_count += enable ? 1 : -1; 390 if (priv->stream_count < 0) 391 priv->stream_count = 0; 392 out: 393 mutex_unlock(&priv->lock); 394 return ret; 395 } 396 397 static int prp_g_frame_interval(struct v4l2_subdev *sd, 398 struct v4l2_subdev_frame_interval *fi) 399 { 400 struct prp_priv *priv = sd_to_priv(sd); 401 402 if (fi->pad >= PRP_NUM_PADS) 403 return -EINVAL; 404 405 mutex_lock(&priv->lock); 406 fi->interval = priv->frame_interval; 407 mutex_unlock(&priv->lock); 408 409 return 0; 410 } 411 412 static int prp_s_frame_interval(struct v4l2_subdev *sd, 413 struct v4l2_subdev_frame_interval *fi) 414 { 415 struct prp_priv *priv = sd_to_priv(sd); 416 417 if (fi->pad >= PRP_NUM_PADS) 418 return -EINVAL; 419 420 mutex_lock(&priv->lock); 421 422 /* No limits on valid frame intervals */ 423 if (fi->interval.numerator == 0 || fi->interval.denominator == 0) 424 fi->interval = priv->frame_interval; 425 else 426 priv->frame_interval = fi->interval; 427 428 mutex_unlock(&priv->lock); 429 430 return 0; 431 } 432 433 static int prp_registered(struct v4l2_subdev *sd) 434 { 435 struct prp_priv *priv = sd_to_priv(sd); 436 u32 code; 437 438 /* init default frame interval */ 439 priv->frame_interval.numerator = 1; 440 priv->frame_interval.denominator = 30; 441 442 /* set a default mbus format */ 443 imx_media_enum_ipu_formats(&code, 0, PIXFMT_SEL_YUV); 444 445 return imx_media_init_mbus_fmt(&priv->format_mbus, 446 IMX_MEDIA_DEF_PIX_WIDTH, 447 IMX_MEDIA_DEF_PIX_HEIGHT, code, 448 V4L2_FIELD_NONE, NULL); 449 } 450 451 static const struct v4l2_subdev_pad_ops prp_pad_ops = { 452 .init_cfg = imx_media_init_cfg, 453 .enum_mbus_code = prp_enum_mbus_code, 454 .get_fmt = prp_get_fmt, 455 .set_fmt = prp_set_fmt, 456 .link_validate = prp_link_validate, 457 }; 458 459 static const struct v4l2_subdev_video_ops prp_video_ops = { 460 .g_frame_interval = prp_g_frame_interval, 461 .s_frame_interval = prp_s_frame_interval, 462 .s_stream = prp_s_stream, 463 }; 464 465 static const struct media_entity_operations prp_entity_ops = { 466 .link_setup = prp_link_setup, 467 .link_validate = v4l2_subdev_link_validate, 468 }; 469 470 static const struct v4l2_subdev_ops prp_subdev_ops = { 471 .video = &prp_video_ops, 472 .pad = &prp_pad_ops, 473 }; 474 475 static const struct v4l2_subdev_internal_ops prp_internal_ops = { 476 .registered = prp_registered, 477 }; 478 479 static int prp_init(struct imx_ic_priv *ic_priv) 480 { 481 struct prp_priv *priv; 482 int i; 483 484 priv = devm_kzalloc(ic_priv->ipu_dev, sizeof(*priv), GFP_KERNEL); 485 if (!priv) 486 return -ENOMEM; 487 488 mutex_init(&priv->lock); 489 ic_priv->task_priv = priv; 490 priv->ic_priv = ic_priv; 491 492 for (i = 0; i < PRP_NUM_PADS; i++) 493 priv->pad[i].flags = (i == PRP_SINK_PAD) ? 494 MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE; 495 496 return media_entity_pads_init(&ic_priv->sd.entity, PRP_NUM_PADS, 497 priv->pad); 498 } 499 500 static void prp_remove(struct imx_ic_priv *ic_priv) 501 { 502 struct prp_priv *priv = ic_priv->task_priv; 503 504 mutex_destroy(&priv->lock); 505 } 506 507 struct imx_ic_ops imx_ic_prp_ops = { 508 .subdev_ops = &prp_subdev_ops, 509 .internal_ops = &prp_internal_ops, 510 .entity_ops = &prp_entity_ops, 511 .init = prp_init, 512 .remove = prp_remove, 513 }; 514