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 break; 267 default: 268 sdformat->format.code = MEDIA_BUS_FMT_Y8_1X8; 269 break; 270 } 271 if (sdformat->format.field == V4L2_FIELD_ANY) 272 sdformat->format.field = V4L2_FIELD_NONE; 273 274 mutex_lock(&vmux->lock); 275 276 /* Source pad mirrors active sink pad, no limitations on sink pads */ 277 if ((pad->flags & MEDIA_PAD_FL_SOURCE) && vmux->active >= 0) 278 sdformat->format = vmux->format_mbus[vmux->active]; 279 280 *mbusformat = sdformat->format; 281 282 /* Propagate the format from an active sink to source */ 283 if ((pad->flags & MEDIA_PAD_FL_SINK) && (pad->index == vmux->active)) 284 *source_mbusformat = sdformat->format; 285 286 mutex_unlock(&vmux->lock); 287 288 return 0; 289 } 290 291 static int video_mux_init_cfg(struct v4l2_subdev *sd, 292 struct v4l2_subdev_pad_config *cfg) 293 { 294 struct video_mux *vmux = v4l2_subdev_to_video_mux(sd); 295 struct v4l2_mbus_framefmt *mbusformat; 296 unsigned int i; 297 298 mutex_lock(&vmux->lock); 299 300 for (i = 0; i < sd->entity.num_pads; i++) { 301 mbusformat = v4l2_subdev_get_try_format(sd, cfg, i); 302 *mbusformat = video_mux_format_mbus_default; 303 } 304 305 mutex_unlock(&vmux->lock); 306 307 return 0; 308 } 309 310 static const struct v4l2_subdev_pad_ops video_mux_pad_ops = { 311 .init_cfg = video_mux_init_cfg, 312 .get_fmt = video_mux_get_format, 313 .set_fmt = video_mux_set_format, 314 }; 315 316 static const struct v4l2_subdev_ops video_mux_subdev_ops = { 317 .pad = &video_mux_pad_ops, 318 .video = &video_mux_subdev_video_ops, 319 }; 320 321 static int video_mux_parse_endpoint(struct device *dev, 322 struct v4l2_fwnode_endpoint *vep, 323 struct v4l2_async_subdev *asd) 324 { 325 /* 326 * it's not an error if remote is missing on a video-mux 327 * input port, return -ENOTCONN to skip this endpoint with 328 * no error. 329 */ 330 return fwnode_device_is_available(asd->match.fwnode) ? 0 : -ENOTCONN; 331 } 332 333 static int video_mux_async_register(struct video_mux *vmux, 334 unsigned int num_input_pads) 335 { 336 unsigned int i, *ports; 337 int ret; 338 339 ports = kcalloc(num_input_pads, sizeof(*ports), GFP_KERNEL); 340 if (!ports) 341 return -ENOMEM; 342 for (i = 0; i < num_input_pads; i++) 343 ports[i] = i; 344 345 ret = v4l2_async_register_fwnode_subdev( 346 &vmux->subdev, sizeof(struct v4l2_async_subdev), 347 ports, num_input_pads, video_mux_parse_endpoint); 348 349 kfree(ports); 350 return ret; 351 } 352 353 static int video_mux_probe(struct platform_device *pdev) 354 { 355 struct device_node *np = pdev->dev.of_node; 356 struct device *dev = &pdev->dev; 357 struct device_node *ep; 358 struct video_mux *vmux; 359 unsigned int num_pads = 0; 360 unsigned int i; 361 int ret; 362 363 vmux = devm_kzalloc(dev, sizeof(*vmux), GFP_KERNEL); 364 if (!vmux) 365 return -ENOMEM; 366 367 platform_set_drvdata(pdev, vmux); 368 369 v4l2_subdev_init(&vmux->subdev, &video_mux_subdev_ops); 370 snprintf(vmux->subdev.name, sizeof(vmux->subdev.name), "%pOFn", np); 371 vmux->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 372 vmux->subdev.dev = dev; 373 374 /* 375 * The largest numbered port is the output port. It determines 376 * total number of pads. 377 */ 378 for_each_endpoint_of_node(np, ep) { 379 struct of_endpoint endpoint; 380 381 of_graph_parse_endpoint(ep, &endpoint); 382 num_pads = max(num_pads, endpoint.port + 1); 383 } 384 385 if (num_pads < 2) { 386 dev_err(dev, "Not enough ports %d\n", num_pads); 387 return -EINVAL; 388 } 389 390 vmux->mux = devm_mux_control_get(dev, NULL); 391 if (IS_ERR(vmux->mux)) { 392 ret = PTR_ERR(vmux->mux); 393 if (ret != -EPROBE_DEFER) 394 dev_err(dev, "Failed to get mux: %d\n", ret); 395 return ret; 396 } 397 398 mutex_init(&vmux->lock); 399 vmux->active = -1; 400 vmux->pads = devm_kcalloc(dev, num_pads, sizeof(*vmux->pads), 401 GFP_KERNEL); 402 vmux->format_mbus = devm_kcalloc(dev, num_pads, 403 sizeof(*vmux->format_mbus), 404 GFP_KERNEL); 405 406 for (i = 0; i < num_pads; i++) { 407 vmux->pads[i].flags = (i < num_pads - 1) ? MEDIA_PAD_FL_SINK 408 : MEDIA_PAD_FL_SOURCE; 409 vmux->format_mbus[i] = video_mux_format_mbus_default; 410 } 411 412 vmux->subdev.entity.function = MEDIA_ENT_F_VID_MUX; 413 ret = media_entity_pads_init(&vmux->subdev.entity, num_pads, 414 vmux->pads); 415 if (ret < 0) 416 return ret; 417 418 vmux->subdev.entity.ops = &video_mux_ops; 419 420 return video_mux_async_register(vmux, num_pads - 1); 421 } 422 423 static int video_mux_remove(struct platform_device *pdev) 424 { 425 struct video_mux *vmux = platform_get_drvdata(pdev); 426 struct v4l2_subdev *sd = &vmux->subdev; 427 428 v4l2_async_unregister_subdev(sd); 429 media_entity_cleanup(&sd->entity); 430 431 return 0; 432 } 433 434 static const struct of_device_id video_mux_dt_ids[] = { 435 { .compatible = "video-mux", }, 436 { /* sentinel */ } 437 }; 438 MODULE_DEVICE_TABLE(of, video_mux_dt_ids); 439 440 static struct platform_driver video_mux_driver = { 441 .probe = video_mux_probe, 442 .remove = video_mux_remove, 443 .driver = { 444 .of_match_table = video_mux_dt_ids, 445 .name = "video-mux", 446 }, 447 }; 448 449 module_platform_driver(video_mux_driver); 450 451 MODULE_DESCRIPTION("video stream multiplexer"); 452 MODULE_AUTHOR("Sascha Hauer, Pengutronix"); 453 MODULE_AUTHOR("Philipp Zabel, Pengutronix"); 454 MODULE_LICENSE("GPL"); 455