1 /* 2 * video stream multiplexer controlled via mux control 3 * 4 * Copyright (C) 2013 Pengutronix, Sascha Hauer <kernel@pengutronix.de> 5 * Copyright (C) 2016-2017 Pengutronix, Philipp Zabel <kernel@pengutronix.de> 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 */ 16 17 #include <linux/err.h> 18 #include <linux/module.h> 19 #include <linux/mutex.h> 20 #include <linux/mux/consumer.h> 21 #include <linux/of.h> 22 #include <linux/of_graph.h> 23 #include <linux/platform_device.h> 24 #include <linux/slab.h> 25 #include <media/v4l2-async.h> 26 #include <media/v4l2-device.h> 27 #include <media/v4l2-fwnode.h> 28 #include <media/v4l2-subdev.h> 29 30 struct video_mux { 31 struct v4l2_subdev subdev; 32 struct media_pad *pads; 33 struct v4l2_mbus_framefmt *format_mbus; 34 struct mux_control *mux; 35 struct mutex lock; 36 int active; 37 }; 38 39 static const struct v4l2_mbus_framefmt video_mux_format_mbus_default = { 40 .width = 1, 41 .height = 1, 42 .code = MEDIA_BUS_FMT_Y8_1X8, 43 .field = V4L2_FIELD_NONE, 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 }; 108 109 static int video_mux_s_stream(struct v4l2_subdev *sd, int enable) 110 { 111 struct video_mux *vmux = v4l2_subdev_to_video_mux(sd); 112 struct v4l2_subdev *upstream_sd; 113 struct media_pad *pad; 114 115 if (vmux->active == -1) { 116 dev_err(sd->dev, "Can not start streaming on inactive mux\n"); 117 return -EINVAL; 118 } 119 120 pad = media_entity_remote_pad(&sd->entity.pads[vmux->active]); 121 if (!pad) { 122 dev_err(sd->dev, "Failed to find remote source pad\n"); 123 return -ENOLINK; 124 } 125 126 if (!is_media_entity_v4l2_subdev(pad->entity)) { 127 dev_err(sd->dev, "Upstream entity is not a v4l2 subdev\n"); 128 return -ENODEV; 129 } 130 131 upstream_sd = media_entity_to_v4l2_subdev(pad->entity); 132 133 return v4l2_subdev_call(upstream_sd, video, s_stream, enable); 134 } 135 136 static const struct v4l2_subdev_video_ops video_mux_subdev_video_ops = { 137 .s_stream = video_mux_s_stream, 138 }; 139 140 static struct v4l2_mbus_framefmt * 141 __video_mux_get_pad_format(struct v4l2_subdev *sd, 142 struct v4l2_subdev_pad_config *cfg, 143 unsigned int pad, u32 which) 144 { 145 struct video_mux *vmux = v4l2_subdev_to_video_mux(sd); 146 147 switch (which) { 148 case V4L2_SUBDEV_FORMAT_TRY: 149 return v4l2_subdev_get_try_format(sd, cfg, pad); 150 case V4L2_SUBDEV_FORMAT_ACTIVE: 151 return &vmux->format_mbus[pad]; 152 default: 153 return NULL; 154 } 155 } 156 157 static int video_mux_get_format(struct v4l2_subdev *sd, 158 struct v4l2_subdev_pad_config *cfg, 159 struct v4l2_subdev_format *sdformat) 160 { 161 struct video_mux *vmux = v4l2_subdev_to_video_mux(sd); 162 163 mutex_lock(&vmux->lock); 164 165 sdformat->format = *__video_mux_get_pad_format(sd, cfg, sdformat->pad, 166 sdformat->which); 167 168 mutex_unlock(&vmux->lock); 169 170 return 0; 171 } 172 173 static int video_mux_set_format(struct v4l2_subdev *sd, 174 struct v4l2_subdev_pad_config *cfg, 175 struct v4l2_subdev_format *sdformat) 176 { 177 struct video_mux *vmux = v4l2_subdev_to_video_mux(sd); 178 struct v4l2_mbus_framefmt *mbusformat, *source_mbusformat; 179 struct media_pad *pad = &vmux->pads[sdformat->pad]; 180 u16 source_pad = sd->entity.num_pads - 1; 181 182 mbusformat = __video_mux_get_pad_format(sd, cfg, sdformat->pad, 183 sdformat->which); 184 if (!mbusformat) 185 return -EINVAL; 186 187 source_mbusformat = __video_mux_get_pad_format(sd, cfg, source_pad, 188 sdformat->which); 189 if (!source_mbusformat) 190 return -EINVAL; 191 192 /* No size limitations except V4L2 compliance requirements */ 193 v4l_bound_align_image(&sdformat->format.width, 1, 65536, 0, 194 &sdformat->format.height, 1, 65536, 0, 0); 195 196 /* All formats except LVDS and vendor specific formats are acceptable */ 197 switch (sdformat->format.code) { 198 case MEDIA_BUS_FMT_RGB444_1X12: 199 case MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE: 200 case MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE: 201 case MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE: 202 case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE: 203 case MEDIA_BUS_FMT_RGB565_1X16: 204 case MEDIA_BUS_FMT_BGR565_2X8_BE: 205 case MEDIA_BUS_FMT_BGR565_2X8_LE: 206 case MEDIA_BUS_FMT_RGB565_2X8_BE: 207 case MEDIA_BUS_FMT_RGB565_2X8_LE: 208 case MEDIA_BUS_FMT_RGB666_1X18: 209 case MEDIA_BUS_FMT_RBG888_1X24: 210 case MEDIA_BUS_FMT_RGB666_1X24_CPADHI: 211 case MEDIA_BUS_FMT_BGR888_1X24: 212 case MEDIA_BUS_FMT_GBR888_1X24: 213 case MEDIA_BUS_FMT_RGB888_1X24: 214 case MEDIA_BUS_FMT_RGB888_2X12_BE: 215 case MEDIA_BUS_FMT_RGB888_2X12_LE: 216 case MEDIA_BUS_FMT_ARGB8888_1X32: 217 case MEDIA_BUS_FMT_RGB888_1X32_PADHI: 218 case MEDIA_BUS_FMT_RGB101010_1X30: 219 case MEDIA_BUS_FMT_RGB121212_1X36: 220 case MEDIA_BUS_FMT_RGB161616_1X48: 221 case MEDIA_BUS_FMT_Y8_1X8: 222 case MEDIA_BUS_FMT_UV8_1X8: 223 case MEDIA_BUS_FMT_UYVY8_1_5X8: 224 case MEDIA_BUS_FMT_VYUY8_1_5X8: 225 case MEDIA_BUS_FMT_YUYV8_1_5X8: 226 case MEDIA_BUS_FMT_YVYU8_1_5X8: 227 case MEDIA_BUS_FMT_UYVY8_2X8: 228 case MEDIA_BUS_FMT_VYUY8_2X8: 229 case MEDIA_BUS_FMT_YUYV8_2X8: 230 case MEDIA_BUS_FMT_YVYU8_2X8: 231 case MEDIA_BUS_FMT_Y10_1X10: 232 case MEDIA_BUS_FMT_UYVY10_2X10: 233 case MEDIA_BUS_FMT_VYUY10_2X10: 234 case MEDIA_BUS_FMT_YUYV10_2X10: 235 case MEDIA_BUS_FMT_YVYU10_2X10: 236 case MEDIA_BUS_FMT_Y12_1X12: 237 case MEDIA_BUS_FMT_UYVY12_2X12: 238 case MEDIA_BUS_FMT_VYUY12_2X12: 239 case MEDIA_BUS_FMT_YUYV12_2X12: 240 case MEDIA_BUS_FMT_YVYU12_2X12: 241 case MEDIA_BUS_FMT_UYVY8_1X16: 242 case MEDIA_BUS_FMT_VYUY8_1X16: 243 case MEDIA_BUS_FMT_YUYV8_1X16: 244 case MEDIA_BUS_FMT_YVYU8_1X16: 245 case MEDIA_BUS_FMT_YDYUYDYV8_1X16: 246 case MEDIA_BUS_FMT_UYVY10_1X20: 247 case MEDIA_BUS_FMT_VYUY10_1X20: 248 case MEDIA_BUS_FMT_YUYV10_1X20: 249 case MEDIA_BUS_FMT_YVYU10_1X20: 250 case MEDIA_BUS_FMT_VUY8_1X24: 251 case MEDIA_BUS_FMT_YUV8_1X24: 252 case MEDIA_BUS_FMT_UYYVYY8_0_5X24: 253 case MEDIA_BUS_FMT_UYVY12_1X24: 254 case MEDIA_BUS_FMT_VYUY12_1X24: 255 case MEDIA_BUS_FMT_YUYV12_1X24: 256 case MEDIA_BUS_FMT_YVYU12_1X24: 257 case MEDIA_BUS_FMT_YUV10_1X30: 258 case MEDIA_BUS_FMT_UYYVYY10_0_5X30: 259 case MEDIA_BUS_FMT_AYUV8_1X32: 260 case MEDIA_BUS_FMT_UYYVYY12_0_5X36: 261 case MEDIA_BUS_FMT_YUV12_1X36: 262 case MEDIA_BUS_FMT_YUV16_1X48: 263 case MEDIA_BUS_FMT_UYYVYY16_0_5X48: 264 case MEDIA_BUS_FMT_JPEG_1X8: 265 case MEDIA_BUS_FMT_AHSV8888_1X32: 266 case MEDIA_BUS_FMT_SBGGR8_1X8: 267 case MEDIA_BUS_FMT_SGBRG8_1X8: 268 case MEDIA_BUS_FMT_SGRBG8_1X8: 269 case MEDIA_BUS_FMT_SRGGB8_1X8: 270 case MEDIA_BUS_FMT_SBGGR10_1X10: 271 case MEDIA_BUS_FMT_SGBRG10_1X10: 272 case MEDIA_BUS_FMT_SGRBG10_1X10: 273 case MEDIA_BUS_FMT_SRGGB10_1X10: 274 case MEDIA_BUS_FMT_SBGGR12_1X12: 275 case MEDIA_BUS_FMT_SGBRG12_1X12: 276 case MEDIA_BUS_FMT_SGRBG12_1X12: 277 case MEDIA_BUS_FMT_SRGGB12_1X12: 278 case MEDIA_BUS_FMT_SBGGR14_1X14: 279 case MEDIA_BUS_FMT_SGBRG14_1X14: 280 case MEDIA_BUS_FMT_SGRBG14_1X14: 281 case MEDIA_BUS_FMT_SRGGB14_1X14: 282 case MEDIA_BUS_FMT_SBGGR16_1X16: 283 case MEDIA_BUS_FMT_SGBRG16_1X16: 284 case MEDIA_BUS_FMT_SGRBG16_1X16: 285 case MEDIA_BUS_FMT_SRGGB16_1X16: 286 break; 287 default: 288 sdformat->format.code = MEDIA_BUS_FMT_Y8_1X8; 289 break; 290 } 291 if (sdformat->format.field == V4L2_FIELD_ANY) 292 sdformat->format.field = V4L2_FIELD_NONE; 293 294 mutex_lock(&vmux->lock); 295 296 /* Source pad mirrors active sink pad, no limitations on sink pads */ 297 if ((pad->flags & MEDIA_PAD_FL_SOURCE) && vmux->active >= 0) 298 sdformat->format = vmux->format_mbus[vmux->active]; 299 300 *mbusformat = sdformat->format; 301 302 /* Propagate the format from an active sink to source */ 303 if ((pad->flags & MEDIA_PAD_FL_SINK) && (pad->index == vmux->active)) 304 *source_mbusformat = sdformat->format; 305 306 mutex_unlock(&vmux->lock); 307 308 return 0; 309 } 310 311 static int video_mux_init_cfg(struct v4l2_subdev *sd, 312 struct v4l2_subdev_pad_config *cfg) 313 { 314 struct video_mux *vmux = v4l2_subdev_to_video_mux(sd); 315 struct v4l2_mbus_framefmt *mbusformat; 316 unsigned int i; 317 318 mutex_lock(&vmux->lock); 319 320 for (i = 0; i < sd->entity.num_pads; i++) { 321 mbusformat = v4l2_subdev_get_try_format(sd, cfg, i); 322 *mbusformat = video_mux_format_mbus_default; 323 } 324 325 mutex_unlock(&vmux->lock); 326 327 return 0; 328 } 329 330 static const struct v4l2_subdev_pad_ops video_mux_pad_ops = { 331 .init_cfg = video_mux_init_cfg, 332 .get_fmt = video_mux_get_format, 333 .set_fmt = video_mux_set_format, 334 }; 335 336 static const struct v4l2_subdev_ops video_mux_subdev_ops = { 337 .pad = &video_mux_pad_ops, 338 .video = &video_mux_subdev_video_ops, 339 }; 340 341 static int video_mux_parse_endpoint(struct device *dev, 342 struct v4l2_fwnode_endpoint *vep, 343 struct v4l2_async_subdev *asd) 344 { 345 /* 346 * it's not an error if remote is missing on a video-mux 347 * input port, return -ENOTCONN to skip this endpoint with 348 * no error. 349 */ 350 return fwnode_device_is_available(asd->match.fwnode) ? 0 : -ENOTCONN; 351 } 352 353 static int video_mux_async_register(struct video_mux *vmux, 354 unsigned int num_input_pads) 355 { 356 unsigned int i, *ports; 357 int ret; 358 359 ports = kcalloc(num_input_pads, sizeof(*ports), GFP_KERNEL); 360 if (!ports) 361 return -ENOMEM; 362 for (i = 0; i < num_input_pads; i++) 363 ports[i] = i; 364 365 ret = v4l2_async_register_fwnode_subdev( 366 &vmux->subdev, sizeof(struct v4l2_async_subdev), 367 ports, num_input_pads, video_mux_parse_endpoint); 368 369 kfree(ports); 370 return ret; 371 } 372 373 static int video_mux_probe(struct platform_device *pdev) 374 { 375 struct device_node *np = pdev->dev.of_node; 376 struct device *dev = &pdev->dev; 377 struct device_node *ep; 378 struct video_mux *vmux; 379 unsigned int num_pads = 0; 380 unsigned int i; 381 int ret; 382 383 vmux = devm_kzalloc(dev, sizeof(*vmux), GFP_KERNEL); 384 if (!vmux) 385 return -ENOMEM; 386 387 platform_set_drvdata(pdev, vmux); 388 389 v4l2_subdev_init(&vmux->subdev, &video_mux_subdev_ops); 390 snprintf(vmux->subdev.name, sizeof(vmux->subdev.name), "%pOFn", np); 391 vmux->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 392 vmux->subdev.dev = dev; 393 394 /* 395 * The largest numbered port is the output port. It determines 396 * total number of pads. 397 */ 398 for_each_endpoint_of_node(np, ep) { 399 struct of_endpoint endpoint; 400 401 of_graph_parse_endpoint(ep, &endpoint); 402 num_pads = max(num_pads, endpoint.port + 1); 403 } 404 405 if (num_pads < 2) { 406 dev_err(dev, "Not enough ports %d\n", num_pads); 407 return -EINVAL; 408 } 409 410 vmux->mux = devm_mux_control_get(dev, NULL); 411 if (IS_ERR(vmux->mux)) { 412 ret = PTR_ERR(vmux->mux); 413 if (ret != -EPROBE_DEFER) 414 dev_err(dev, "Failed to get mux: %d\n", ret); 415 return ret; 416 } 417 418 mutex_init(&vmux->lock); 419 vmux->active = -1; 420 vmux->pads = devm_kcalloc(dev, num_pads, sizeof(*vmux->pads), 421 GFP_KERNEL); 422 vmux->format_mbus = devm_kcalloc(dev, num_pads, 423 sizeof(*vmux->format_mbus), 424 GFP_KERNEL); 425 426 for (i = 0; i < num_pads; i++) { 427 vmux->pads[i].flags = (i < num_pads - 1) ? MEDIA_PAD_FL_SINK 428 : MEDIA_PAD_FL_SOURCE; 429 vmux->format_mbus[i] = video_mux_format_mbus_default; 430 } 431 432 vmux->subdev.entity.function = MEDIA_ENT_F_VID_MUX; 433 ret = media_entity_pads_init(&vmux->subdev.entity, num_pads, 434 vmux->pads); 435 if (ret < 0) 436 return ret; 437 438 vmux->subdev.entity.ops = &video_mux_ops; 439 440 return video_mux_async_register(vmux, num_pads - 1); 441 } 442 443 static int video_mux_remove(struct platform_device *pdev) 444 { 445 struct video_mux *vmux = platform_get_drvdata(pdev); 446 struct v4l2_subdev *sd = &vmux->subdev; 447 448 v4l2_async_unregister_subdev(sd); 449 media_entity_cleanup(&sd->entity); 450 451 return 0; 452 } 453 454 static const struct of_device_id video_mux_dt_ids[] = { 455 { .compatible = "video-mux", }, 456 { /* sentinel */ } 457 }; 458 MODULE_DEVICE_TABLE(of, video_mux_dt_ids); 459 460 static struct platform_driver video_mux_driver = { 461 .probe = video_mux_probe, 462 .remove = video_mux_remove, 463 .driver = { 464 .of_match_table = video_mux_dt_ids, 465 .name = "video-mux", 466 }, 467 }; 468 469 module_platform_driver(video_mux_driver); 470 471 MODULE_DESCRIPTION("video stream multiplexer"); 472 MODULE_AUTHOR("Sascha Hauer, Pengutronix"); 473 MODULE_AUTHOR("Philipp Zabel, Pengutronix"); 474 MODULE_LICENSE("GPL"); 475