1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * video stream multiplexer controlled via mux control 4 * 5 * Copyright (C) 2013 Pengutronix, Sascha Hauer <kernel@pengutronix.de> 6 * Copyright (C) 2016-2017 Pengutronix, Philipp Zabel <kernel@pengutronix.de> 7 */ 8 9 #include <linux/err.h> 10 #include <linux/module.h> 11 #include <linux/mutex.h> 12 #include <linux/mux/consumer.h> 13 #include <linux/of.h> 14 #include <linux/of_graph.h> 15 #include <linux/platform_device.h> 16 #include <linux/slab.h> 17 #include <media/v4l2-async.h> 18 #include <media/v4l2-device.h> 19 #include <media/v4l2-fwnode.h> 20 #include <media/v4l2-mc.h> 21 #include <media/v4l2-subdev.h> 22 23 struct video_mux { 24 struct v4l2_subdev subdev; 25 struct v4l2_async_notifier notifier; 26 struct media_pad *pads; 27 struct v4l2_mbus_framefmt *format_mbus; 28 struct mux_control *mux; 29 struct mutex lock; 30 int active; 31 }; 32 33 static const struct v4l2_mbus_framefmt video_mux_format_mbus_default = { 34 .width = 1, 35 .height = 1, 36 .code = MEDIA_BUS_FMT_Y8_1X8, 37 .field = V4L2_FIELD_NONE, 38 }; 39 40 static inline struct video_mux * 41 notifier_to_video_mux(struct v4l2_async_notifier *n) 42 { 43 return container_of(n, struct video_mux, notifier); 44 } 45 46 static inline struct video_mux *v4l2_subdev_to_video_mux(struct v4l2_subdev *sd) 47 { 48 return container_of(sd, struct video_mux, subdev); 49 } 50 51 static int video_mux_link_setup(struct media_entity *entity, 52 const struct media_pad *local, 53 const struct media_pad *remote, u32 flags) 54 { 55 struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); 56 struct video_mux *vmux = v4l2_subdev_to_video_mux(sd); 57 u16 source_pad = entity->num_pads - 1; 58 int ret = 0; 59 60 /* 61 * The mux state is determined by the enabled sink pad link. 62 * Enabling or disabling the source pad link has no effect. 63 */ 64 if (local->flags & MEDIA_PAD_FL_SOURCE) 65 return 0; 66 67 dev_dbg(sd->dev, "link setup '%s':%d->'%s':%d[%d]", 68 remote->entity->name, remote->index, local->entity->name, 69 local->index, flags & MEDIA_LNK_FL_ENABLED); 70 71 mutex_lock(&vmux->lock); 72 73 if (flags & MEDIA_LNK_FL_ENABLED) { 74 if (vmux->active == local->index) 75 goto out; 76 77 if (vmux->active >= 0) { 78 ret = -EBUSY; 79 goto out; 80 } 81 82 dev_dbg(sd->dev, "setting %d active\n", local->index); 83 ret = mux_control_try_select(vmux->mux, local->index); 84 if (ret < 0) 85 goto out; 86 vmux->active = local->index; 87 88 /* Propagate the active format to the source */ 89 vmux->format_mbus[source_pad] = vmux->format_mbus[vmux->active]; 90 } else { 91 if (vmux->active != local->index) 92 goto out; 93 94 dev_dbg(sd->dev, "going inactive\n"); 95 mux_control_deselect(vmux->mux); 96 vmux->active = -1; 97 } 98 99 out: 100 mutex_unlock(&vmux->lock); 101 return ret; 102 } 103 104 static const struct media_entity_operations video_mux_ops = { 105 .link_setup = video_mux_link_setup, 106 .link_validate = v4l2_subdev_link_validate, 107 .get_fwnode_pad = v4l2_subdev_get_fwnode_pad_1_to_1, 108 }; 109 110 static int video_mux_s_stream(struct v4l2_subdev *sd, int enable) 111 { 112 struct video_mux *vmux = v4l2_subdev_to_video_mux(sd); 113 struct v4l2_subdev *upstream_sd; 114 struct media_pad *pad; 115 116 if (vmux->active == -1) { 117 dev_err(sd->dev, "Can not start streaming on inactive mux\n"); 118 return -EINVAL; 119 } 120 121 pad = media_entity_remote_pad(&sd->entity.pads[vmux->active]); 122 if (!pad) { 123 dev_err(sd->dev, "Failed to find remote source pad\n"); 124 return -ENOLINK; 125 } 126 127 if (!is_media_entity_v4l2_subdev(pad->entity)) { 128 dev_err(sd->dev, "Upstream entity is not a v4l2 subdev\n"); 129 return -ENODEV; 130 } 131 132 upstream_sd = media_entity_to_v4l2_subdev(pad->entity); 133 134 return v4l2_subdev_call(upstream_sd, video, s_stream, enable); 135 } 136 137 static const struct v4l2_subdev_video_ops video_mux_subdev_video_ops = { 138 .s_stream = video_mux_s_stream, 139 }; 140 141 static struct v4l2_mbus_framefmt * 142 __video_mux_get_pad_format(struct v4l2_subdev *sd, 143 struct v4l2_subdev_pad_config *cfg, 144 unsigned int pad, u32 which) 145 { 146 struct video_mux *vmux = v4l2_subdev_to_video_mux(sd); 147 148 switch (which) { 149 case V4L2_SUBDEV_FORMAT_TRY: 150 return v4l2_subdev_get_try_format(sd, cfg, pad); 151 case V4L2_SUBDEV_FORMAT_ACTIVE: 152 return &vmux->format_mbus[pad]; 153 default: 154 return NULL; 155 } 156 } 157 158 static int video_mux_get_format(struct v4l2_subdev *sd, 159 struct v4l2_subdev_pad_config *cfg, 160 struct v4l2_subdev_format *sdformat) 161 { 162 struct video_mux *vmux = v4l2_subdev_to_video_mux(sd); 163 164 mutex_lock(&vmux->lock); 165 166 sdformat->format = *__video_mux_get_pad_format(sd, cfg, sdformat->pad, 167 sdformat->which); 168 169 mutex_unlock(&vmux->lock); 170 171 return 0; 172 } 173 174 static int video_mux_set_format(struct v4l2_subdev *sd, 175 struct v4l2_subdev_pad_config *cfg, 176 struct v4l2_subdev_format *sdformat) 177 { 178 struct video_mux *vmux = v4l2_subdev_to_video_mux(sd); 179 struct v4l2_mbus_framefmt *mbusformat, *source_mbusformat; 180 struct media_pad *pad = &vmux->pads[sdformat->pad]; 181 u16 source_pad = sd->entity.num_pads - 1; 182 183 mbusformat = __video_mux_get_pad_format(sd, cfg, sdformat->pad, 184 sdformat->which); 185 if (!mbusformat) 186 return -EINVAL; 187 188 source_mbusformat = __video_mux_get_pad_format(sd, cfg, source_pad, 189 sdformat->which); 190 if (!source_mbusformat) 191 return -EINVAL; 192 193 /* No size limitations except V4L2 compliance requirements */ 194 v4l_bound_align_image(&sdformat->format.width, 1, 65536, 0, 195 &sdformat->format.height, 1, 65536, 0, 0); 196 197 /* All formats except LVDS and vendor specific formats are acceptable */ 198 switch (sdformat->format.code) { 199 case MEDIA_BUS_FMT_RGB444_1X12: 200 case MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE: 201 case MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE: 202 case MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE: 203 case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE: 204 case MEDIA_BUS_FMT_RGB565_1X16: 205 case MEDIA_BUS_FMT_BGR565_2X8_BE: 206 case MEDIA_BUS_FMT_BGR565_2X8_LE: 207 case MEDIA_BUS_FMT_RGB565_2X8_BE: 208 case MEDIA_BUS_FMT_RGB565_2X8_LE: 209 case MEDIA_BUS_FMT_RGB666_1X18: 210 case MEDIA_BUS_FMT_RBG888_1X24: 211 case MEDIA_BUS_FMT_RGB666_1X24_CPADHI: 212 case MEDIA_BUS_FMT_BGR888_1X24: 213 case MEDIA_BUS_FMT_GBR888_1X24: 214 case MEDIA_BUS_FMT_RGB888_1X24: 215 case MEDIA_BUS_FMT_RGB888_2X12_BE: 216 case MEDIA_BUS_FMT_RGB888_2X12_LE: 217 case MEDIA_BUS_FMT_ARGB8888_1X32: 218 case MEDIA_BUS_FMT_RGB888_1X32_PADHI: 219 case MEDIA_BUS_FMT_RGB101010_1X30: 220 case MEDIA_BUS_FMT_RGB121212_1X36: 221 case MEDIA_BUS_FMT_RGB161616_1X48: 222 case MEDIA_BUS_FMT_Y8_1X8: 223 case MEDIA_BUS_FMT_UV8_1X8: 224 case MEDIA_BUS_FMT_UYVY8_1_5X8: 225 case MEDIA_BUS_FMT_VYUY8_1_5X8: 226 case MEDIA_BUS_FMT_YUYV8_1_5X8: 227 case MEDIA_BUS_FMT_YVYU8_1_5X8: 228 case MEDIA_BUS_FMT_UYVY8_2X8: 229 case MEDIA_BUS_FMT_VYUY8_2X8: 230 case MEDIA_BUS_FMT_YUYV8_2X8: 231 case MEDIA_BUS_FMT_YVYU8_2X8: 232 case MEDIA_BUS_FMT_Y10_1X10: 233 case MEDIA_BUS_FMT_UYVY10_2X10: 234 case MEDIA_BUS_FMT_VYUY10_2X10: 235 case MEDIA_BUS_FMT_YUYV10_2X10: 236 case MEDIA_BUS_FMT_YVYU10_2X10: 237 case MEDIA_BUS_FMT_Y12_1X12: 238 case MEDIA_BUS_FMT_UYVY12_2X12: 239 case MEDIA_BUS_FMT_VYUY12_2X12: 240 case MEDIA_BUS_FMT_YUYV12_2X12: 241 case MEDIA_BUS_FMT_YVYU12_2X12: 242 case MEDIA_BUS_FMT_UYVY8_1X16: 243 case MEDIA_BUS_FMT_VYUY8_1X16: 244 case MEDIA_BUS_FMT_YUYV8_1X16: 245 case MEDIA_BUS_FMT_YVYU8_1X16: 246 case MEDIA_BUS_FMT_YDYUYDYV8_1X16: 247 case MEDIA_BUS_FMT_UYVY10_1X20: 248 case MEDIA_BUS_FMT_VYUY10_1X20: 249 case MEDIA_BUS_FMT_YUYV10_1X20: 250 case MEDIA_BUS_FMT_YVYU10_1X20: 251 case MEDIA_BUS_FMT_VUY8_1X24: 252 case MEDIA_BUS_FMT_YUV8_1X24: 253 case MEDIA_BUS_FMT_UYYVYY8_0_5X24: 254 case MEDIA_BUS_FMT_UYVY12_1X24: 255 case MEDIA_BUS_FMT_VYUY12_1X24: 256 case MEDIA_BUS_FMT_YUYV12_1X24: 257 case MEDIA_BUS_FMT_YVYU12_1X24: 258 case MEDIA_BUS_FMT_YUV10_1X30: 259 case MEDIA_BUS_FMT_UYYVYY10_0_5X30: 260 case MEDIA_BUS_FMT_AYUV8_1X32: 261 case MEDIA_BUS_FMT_UYYVYY12_0_5X36: 262 case MEDIA_BUS_FMT_YUV12_1X36: 263 case MEDIA_BUS_FMT_YUV16_1X48: 264 case MEDIA_BUS_FMT_UYYVYY16_0_5X48: 265 case MEDIA_BUS_FMT_JPEG_1X8: 266 case MEDIA_BUS_FMT_AHSV8888_1X32: 267 case MEDIA_BUS_FMT_SBGGR8_1X8: 268 case MEDIA_BUS_FMT_SGBRG8_1X8: 269 case MEDIA_BUS_FMT_SGRBG8_1X8: 270 case MEDIA_BUS_FMT_SRGGB8_1X8: 271 case MEDIA_BUS_FMT_SBGGR10_1X10: 272 case MEDIA_BUS_FMT_SGBRG10_1X10: 273 case MEDIA_BUS_FMT_SGRBG10_1X10: 274 case MEDIA_BUS_FMT_SRGGB10_1X10: 275 case MEDIA_BUS_FMT_SBGGR12_1X12: 276 case MEDIA_BUS_FMT_SGBRG12_1X12: 277 case MEDIA_BUS_FMT_SGRBG12_1X12: 278 case MEDIA_BUS_FMT_SRGGB12_1X12: 279 case MEDIA_BUS_FMT_SBGGR14_1X14: 280 case MEDIA_BUS_FMT_SGBRG14_1X14: 281 case MEDIA_BUS_FMT_SGRBG14_1X14: 282 case MEDIA_BUS_FMT_SRGGB14_1X14: 283 case MEDIA_BUS_FMT_SBGGR16_1X16: 284 case MEDIA_BUS_FMT_SGBRG16_1X16: 285 case MEDIA_BUS_FMT_SGRBG16_1X16: 286 case MEDIA_BUS_FMT_SRGGB16_1X16: 287 break; 288 default: 289 sdformat->format.code = MEDIA_BUS_FMT_Y8_1X8; 290 break; 291 } 292 if (sdformat->format.field == V4L2_FIELD_ANY) 293 sdformat->format.field = V4L2_FIELD_NONE; 294 295 mutex_lock(&vmux->lock); 296 297 /* Source pad mirrors active sink pad, no limitations on sink pads */ 298 if ((pad->flags & MEDIA_PAD_FL_SOURCE) && vmux->active >= 0) 299 sdformat->format = vmux->format_mbus[vmux->active]; 300 301 *mbusformat = sdformat->format; 302 303 /* Propagate the format from an active sink to source */ 304 if ((pad->flags & MEDIA_PAD_FL_SINK) && (pad->index == vmux->active)) 305 *source_mbusformat = sdformat->format; 306 307 mutex_unlock(&vmux->lock); 308 309 return 0; 310 } 311 312 static int video_mux_init_cfg(struct v4l2_subdev *sd, 313 struct v4l2_subdev_pad_config *cfg) 314 { 315 struct video_mux *vmux = v4l2_subdev_to_video_mux(sd); 316 struct v4l2_mbus_framefmt *mbusformat; 317 unsigned int i; 318 319 mutex_lock(&vmux->lock); 320 321 for (i = 0; i < sd->entity.num_pads; i++) { 322 mbusformat = v4l2_subdev_get_try_format(sd, cfg, i); 323 *mbusformat = video_mux_format_mbus_default; 324 } 325 326 mutex_unlock(&vmux->lock); 327 328 return 0; 329 } 330 331 static const struct v4l2_subdev_pad_ops video_mux_pad_ops = { 332 .init_cfg = video_mux_init_cfg, 333 .get_fmt = video_mux_get_format, 334 .set_fmt = video_mux_set_format, 335 }; 336 337 static const struct v4l2_subdev_ops video_mux_subdev_ops = { 338 .pad = &video_mux_pad_ops, 339 .video = &video_mux_subdev_video_ops, 340 }; 341 342 static int video_mux_notify_bound(struct v4l2_async_notifier *notifier, 343 struct v4l2_subdev *sd, 344 struct v4l2_async_subdev *asd) 345 { 346 struct video_mux *vmux = notifier_to_video_mux(notifier); 347 348 return v4l2_create_fwnode_links(sd, &vmux->subdev); 349 } 350 351 static const struct v4l2_async_notifier_operations video_mux_notify_ops = { 352 .bound = video_mux_notify_bound, 353 }; 354 355 static int video_mux_async_register(struct video_mux *vmux, 356 unsigned int num_input_pads) 357 { 358 unsigned int i; 359 int ret; 360 361 v4l2_async_notifier_init(&vmux->notifier); 362 363 for (i = 0; i < num_input_pads; i++) { 364 struct v4l2_async_subdev *asd; 365 struct fwnode_handle *ep; 366 367 ep = fwnode_graph_get_endpoint_by_id( 368 dev_fwnode(vmux->subdev.dev), i, 0, 369 FWNODE_GRAPH_ENDPOINT_NEXT); 370 if (!ep) 371 continue; 372 373 asd = v4l2_async_notifier_add_fwnode_remote_subdev( 374 &vmux->notifier, ep, struct v4l2_async_subdev); 375 376 fwnode_handle_put(ep); 377 378 if (IS_ERR(asd)) { 379 ret = PTR_ERR(asd); 380 /* OK if asd already exists */ 381 if (ret != -EEXIST) 382 return ret; 383 } 384 } 385 386 vmux->notifier.ops = &video_mux_notify_ops; 387 388 ret = v4l2_async_subdev_notifier_register(&vmux->subdev, 389 &vmux->notifier); 390 if (ret) 391 return ret; 392 393 return v4l2_async_register_subdev(&vmux->subdev); 394 } 395 396 static int video_mux_probe(struct platform_device *pdev) 397 { 398 struct device_node *np = pdev->dev.of_node; 399 struct device *dev = &pdev->dev; 400 struct device_node *ep; 401 struct video_mux *vmux; 402 unsigned int num_pads = 0; 403 unsigned int i; 404 int ret; 405 406 vmux = devm_kzalloc(dev, sizeof(*vmux), GFP_KERNEL); 407 if (!vmux) 408 return -ENOMEM; 409 410 platform_set_drvdata(pdev, vmux); 411 412 v4l2_subdev_init(&vmux->subdev, &video_mux_subdev_ops); 413 snprintf(vmux->subdev.name, sizeof(vmux->subdev.name), "%pOFn", np); 414 vmux->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 415 vmux->subdev.dev = dev; 416 417 /* 418 * The largest numbered port is the output port. It determines 419 * total number of pads. 420 */ 421 for_each_endpoint_of_node(np, ep) { 422 struct of_endpoint endpoint; 423 424 of_graph_parse_endpoint(ep, &endpoint); 425 num_pads = max(num_pads, endpoint.port + 1); 426 } 427 428 if (num_pads < 2) { 429 dev_err(dev, "Not enough ports %d\n", num_pads); 430 return -EINVAL; 431 } 432 433 vmux->mux = devm_mux_control_get(dev, NULL); 434 if (IS_ERR(vmux->mux)) { 435 ret = PTR_ERR(vmux->mux); 436 if (ret != -EPROBE_DEFER) 437 dev_err(dev, "Failed to get mux: %d\n", ret); 438 return ret; 439 } 440 441 mutex_init(&vmux->lock); 442 vmux->active = -1; 443 vmux->pads = devm_kcalloc(dev, num_pads, sizeof(*vmux->pads), 444 GFP_KERNEL); 445 if (!vmux->pads) 446 return -ENOMEM; 447 448 vmux->format_mbus = devm_kcalloc(dev, num_pads, 449 sizeof(*vmux->format_mbus), 450 GFP_KERNEL); 451 if (!vmux->format_mbus) 452 return -ENOMEM; 453 454 for (i = 0; i < num_pads; i++) { 455 vmux->pads[i].flags = (i < num_pads - 1) ? MEDIA_PAD_FL_SINK 456 : MEDIA_PAD_FL_SOURCE; 457 vmux->format_mbus[i] = video_mux_format_mbus_default; 458 } 459 460 vmux->subdev.entity.function = MEDIA_ENT_F_VID_MUX; 461 ret = media_entity_pads_init(&vmux->subdev.entity, num_pads, 462 vmux->pads); 463 if (ret < 0) 464 return ret; 465 466 vmux->subdev.entity.ops = &video_mux_ops; 467 468 ret = video_mux_async_register(vmux, num_pads - 1); 469 if (ret) { 470 v4l2_async_notifier_unregister(&vmux->notifier); 471 v4l2_async_notifier_cleanup(&vmux->notifier); 472 } 473 474 return ret; 475 } 476 477 static int video_mux_remove(struct platform_device *pdev) 478 { 479 struct video_mux *vmux = platform_get_drvdata(pdev); 480 struct v4l2_subdev *sd = &vmux->subdev; 481 482 v4l2_async_notifier_unregister(&vmux->notifier); 483 v4l2_async_notifier_cleanup(&vmux->notifier); 484 v4l2_async_unregister_subdev(sd); 485 media_entity_cleanup(&sd->entity); 486 487 return 0; 488 } 489 490 static const struct of_device_id video_mux_dt_ids[] = { 491 { .compatible = "video-mux", }, 492 { /* sentinel */ } 493 }; 494 MODULE_DEVICE_TABLE(of, video_mux_dt_ids); 495 496 static struct platform_driver video_mux_driver = { 497 .probe = video_mux_probe, 498 .remove = video_mux_remove, 499 .driver = { 500 .of_match_table = video_mux_dt_ids, 501 .name = "video-mux", 502 }, 503 }; 504 505 module_platform_driver(video_mux_driver); 506 507 MODULE_DESCRIPTION("video stream multiplexer"); 508 MODULE_AUTHOR("Sascha Hauer, Pengutronix"); 509 MODULE_AUTHOR("Philipp Zabel, Pengutronix"); 510 MODULE_LICENSE("GPL"); 511