1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * vimc-core.c Virtual Media Controller Driver 4 * 5 * Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com> 6 */ 7 8 #include <linux/dma-mapping.h> 9 #include <linux/font.h> 10 #include <linux/init.h> 11 #include <linux/module.h> 12 #include <linux/platform_device.h> 13 #include <media/media-device.h> 14 #include <media/tpg/v4l2-tpg.h> 15 #include <media/v4l2-device.h> 16 17 #include "vimc-common.h" 18 19 unsigned int vimc_allocator; 20 module_param_named(allocator, vimc_allocator, uint, 0444); 21 MODULE_PARM_DESC(allocator, " memory allocator selection, default is 0.\n" 22 "\t\t 0 == vmalloc\n" 23 "\t\t 1 == dma-contig"); 24 25 #define VIMC_MDEV_MODEL_NAME "VIMC MDEV" 26 27 #define VIMC_ENT_LINK(src, srcpad, sink, sinkpad, link_flags) { \ 28 .src_ent = src, \ 29 .src_pad = srcpad, \ 30 .sink_ent = sink, \ 31 .sink_pad = sinkpad, \ 32 .flags = link_flags, \ 33 } 34 35 /* Structure which describes links between entities */ 36 struct vimc_ent_link { 37 unsigned int src_ent; 38 u16 src_pad; 39 unsigned int sink_ent; 40 u16 sink_pad; 41 u32 flags; 42 }; 43 44 /* Structure which describes the whole topology */ 45 struct vimc_pipeline_config { 46 const struct vimc_ent_config *ents; 47 size_t num_ents; 48 const struct vimc_ent_link *links; 49 size_t num_links; 50 }; 51 52 /* -------------------------------------------------------------------------- 53 * Topology Configuration 54 */ 55 56 static struct vimc_ent_config ent_config[] = { 57 { 58 .name = "Sensor A", 59 .type = &vimc_sen_type 60 }, 61 { 62 .name = "Sensor B", 63 .type = &vimc_sen_type 64 }, 65 { 66 .name = "Debayer A", 67 .type = &vimc_deb_type 68 }, 69 { 70 .name = "Debayer B", 71 .type = &vimc_deb_type 72 }, 73 { 74 .name = "Raw Capture 0", 75 .type = &vimc_cap_type 76 }, 77 { 78 .name = "Raw Capture 1", 79 .type = &vimc_cap_type 80 }, 81 { 82 /* TODO: change this to vimc-input when it is implemented */ 83 .name = "RGB/YUV Input", 84 .type = &vimc_sen_type 85 }, 86 { 87 .name = "Scaler", 88 .type = &vimc_sca_type 89 }, 90 { 91 .name = "RGB/YUV Capture", 92 .type = &vimc_cap_type 93 }, 94 }; 95 96 static const struct vimc_ent_link ent_links[] = { 97 /* Link: Sensor A (Pad 0)->(Pad 0) Debayer A */ 98 VIMC_ENT_LINK(0, 0, 2, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), 99 /* Link: Sensor A (Pad 0)->(Pad 0) Raw Capture 0 */ 100 VIMC_ENT_LINK(0, 0, 4, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), 101 /* Link: Sensor B (Pad 0)->(Pad 0) Debayer B */ 102 VIMC_ENT_LINK(1, 0, 3, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), 103 /* Link: Sensor B (Pad 0)->(Pad 0) Raw Capture 1 */ 104 VIMC_ENT_LINK(1, 0, 5, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), 105 /* Link: Debayer A (Pad 1)->(Pad 0) Scaler */ 106 VIMC_ENT_LINK(2, 1, 7, 0, MEDIA_LNK_FL_ENABLED), 107 /* Link: Debayer B (Pad 1)->(Pad 0) Scaler */ 108 VIMC_ENT_LINK(3, 1, 7, 0, 0), 109 /* Link: RGB/YUV Input (Pad 0)->(Pad 0) Scaler */ 110 VIMC_ENT_LINK(6, 0, 7, 0, 0), 111 /* Link: Scaler (Pad 1)->(Pad 0) RGB/YUV Capture */ 112 VIMC_ENT_LINK(7, 1, 8, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), 113 }; 114 115 static struct vimc_pipeline_config pipe_cfg = { 116 .ents = ent_config, 117 .num_ents = ARRAY_SIZE(ent_config), 118 .links = ent_links, 119 .num_links = ARRAY_SIZE(ent_links) 120 }; 121 122 /* -------------------------------------------------------------------------- */ 123 124 static void vimc_rm_links(struct vimc_device *vimc) 125 { 126 unsigned int i; 127 128 for (i = 0; i < vimc->pipe_cfg->num_ents; i++) 129 media_entity_remove_links(vimc->ent_devs[i]->ent); 130 } 131 132 static int vimc_create_links(struct vimc_device *vimc) 133 { 134 unsigned int i; 135 int ret; 136 137 /* Initialize the links between entities */ 138 for (i = 0; i < vimc->pipe_cfg->num_links; i++) { 139 const struct vimc_ent_link *link = &vimc->pipe_cfg->links[i]; 140 141 struct vimc_ent_device *ved_src = 142 vimc->ent_devs[link->src_ent]; 143 struct vimc_ent_device *ved_sink = 144 vimc->ent_devs[link->sink_ent]; 145 146 ret = media_create_pad_link(ved_src->ent, link->src_pad, 147 ved_sink->ent, link->sink_pad, 148 link->flags); 149 if (ret) 150 goto err_rm_links; 151 } 152 153 return 0; 154 155 err_rm_links: 156 vimc_rm_links(vimc); 157 return ret; 158 } 159 160 static void vimc_release_subdevs(struct vimc_device *vimc) 161 { 162 unsigned int i; 163 164 for (i = 0; i < vimc->pipe_cfg->num_ents; i++) 165 if (vimc->ent_devs[i]) 166 vimc->pipe_cfg->ents[i].type->release(vimc->ent_devs[i]); 167 } 168 169 static void vimc_unregister_subdevs(struct vimc_device *vimc) 170 { 171 unsigned int i; 172 173 for (i = 0; i < vimc->pipe_cfg->num_ents; i++) 174 if (vimc->ent_devs[i] && vimc->pipe_cfg->ents[i].type->unregister) 175 vimc->pipe_cfg->ents[i].type->unregister(vimc->ent_devs[i]); 176 } 177 178 static int vimc_add_subdevs(struct vimc_device *vimc) 179 { 180 unsigned int i; 181 182 for (i = 0; i < vimc->pipe_cfg->num_ents; i++) { 183 dev_dbg(vimc->mdev.dev, "new entity for %s\n", 184 vimc->pipe_cfg->ents[i].name); 185 vimc->ent_devs[i] = vimc->pipe_cfg->ents[i].type->add(vimc, 186 vimc->pipe_cfg->ents[i].name); 187 if (IS_ERR(vimc->ent_devs[i])) { 188 int err = PTR_ERR(vimc->ent_devs[i]); 189 190 dev_err(vimc->mdev.dev, "adding entity %s failed (%d)\n", 191 vimc->pipe_cfg->ents[i].name, err); 192 vimc->ent_devs[i] = NULL; 193 vimc_unregister_subdevs(vimc); 194 vimc_release_subdevs(vimc); 195 return err; 196 } 197 } 198 return 0; 199 } 200 201 static void vimc_v4l2_dev_release(struct v4l2_device *v4l2_dev) 202 { 203 struct vimc_device *vimc = 204 container_of(v4l2_dev, struct vimc_device, v4l2_dev); 205 206 vimc_release_subdevs(vimc); 207 media_device_cleanup(&vimc->mdev); 208 kfree(vimc->ent_devs); 209 kfree(vimc); 210 } 211 212 static int vimc_register_devices(struct vimc_device *vimc) 213 { 214 int ret; 215 216 /* Register the v4l2 struct */ 217 ret = v4l2_device_register(vimc->mdev.dev, &vimc->v4l2_dev); 218 if (ret) { 219 dev_err(vimc->mdev.dev, 220 "v4l2 device register failed (err=%d)\n", ret); 221 return ret; 222 } 223 /* allocate ent_devs */ 224 vimc->ent_devs = kcalloc(vimc->pipe_cfg->num_ents, 225 sizeof(*vimc->ent_devs), GFP_KERNEL); 226 if (!vimc->ent_devs) { 227 ret = -ENOMEM; 228 goto err_v4l2_unregister; 229 } 230 231 /* Invoke entity config hooks to initialize and register subdevs */ 232 ret = vimc_add_subdevs(vimc); 233 if (ret) 234 goto err_free_ent_devs; 235 236 /* Initialize links */ 237 ret = vimc_create_links(vimc); 238 if (ret) 239 goto err_rm_subdevs; 240 241 /* Register the media device */ 242 ret = media_device_register(&vimc->mdev); 243 if (ret) { 244 dev_err(vimc->mdev.dev, 245 "media device register failed (err=%d)\n", ret); 246 goto err_rm_subdevs; 247 } 248 249 /* Expose all subdev's nodes*/ 250 ret = v4l2_device_register_subdev_nodes(&vimc->v4l2_dev); 251 if (ret) { 252 dev_err(vimc->mdev.dev, 253 "vimc subdev nodes registration failed (err=%d)\n", 254 ret); 255 goto err_mdev_unregister; 256 } 257 258 return 0; 259 260 err_mdev_unregister: 261 media_device_unregister(&vimc->mdev); 262 err_rm_subdevs: 263 vimc_unregister_subdevs(vimc); 264 vimc_release_subdevs(vimc); 265 err_free_ent_devs: 266 kfree(vimc->ent_devs); 267 err_v4l2_unregister: 268 v4l2_device_unregister(&vimc->v4l2_dev); 269 270 return ret; 271 } 272 273 static int vimc_probe(struct platform_device *pdev) 274 { 275 const struct font_desc *font = find_font("VGA8x16"); 276 struct vimc_device *vimc; 277 int ret; 278 279 dev_dbg(&pdev->dev, "probe"); 280 281 if (!font) { 282 dev_err(&pdev->dev, "could not find font\n"); 283 return -ENODEV; 284 } 285 286 tpg_set_font(font->data); 287 288 if (vimc_allocator == VIMC_ALLOCATOR_DMA_CONTIG) 289 dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); 290 291 vimc = kzalloc(sizeof(*vimc), GFP_KERNEL); 292 if (!vimc) 293 return -ENOMEM; 294 295 vimc->pipe_cfg = &pipe_cfg; 296 297 /* Link the media device within the v4l2_device */ 298 vimc->v4l2_dev.mdev = &vimc->mdev; 299 300 /* Initialize media device */ 301 strscpy(vimc->mdev.model, VIMC_MDEV_MODEL_NAME, 302 sizeof(vimc->mdev.model)); 303 snprintf(vimc->mdev.bus_info, sizeof(vimc->mdev.bus_info), 304 "platform:%s", VIMC_PDEV_NAME); 305 vimc->mdev.dev = &pdev->dev; 306 media_device_init(&vimc->mdev); 307 308 ret = vimc_register_devices(vimc); 309 if (ret) { 310 media_device_cleanup(&vimc->mdev); 311 kfree(vimc); 312 return ret; 313 } 314 /* 315 * the release cb is set only after successful registration. 316 * if the registration fails, we release directly from probe 317 */ 318 319 vimc->v4l2_dev.release = vimc_v4l2_dev_release; 320 platform_set_drvdata(pdev, vimc); 321 return 0; 322 } 323 324 static int vimc_remove(struct platform_device *pdev) 325 { 326 struct vimc_device *vimc = platform_get_drvdata(pdev); 327 328 dev_dbg(&pdev->dev, "remove"); 329 330 vimc_unregister_subdevs(vimc); 331 media_device_unregister(&vimc->mdev); 332 v4l2_device_unregister(&vimc->v4l2_dev); 333 v4l2_device_put(&vimc->v4l2_dev); 334 335 return 0; 336 } 337 338 static void vimc_dev_release(struct device *dev) 339 { 340 } 341 342 static struct platform_device vimc_pdev = { 343 .name = VIMC_PDEV_NAME, 344 .dev.release = vimc_dev_release, 345 }; 346 347 static struct platform_driver vimc_pdrv = { 348 .probe = vimc_probe, 349 .remove = vimc_remove, 350 .driver = { 351 .name = VIMC_PDEV_NAME, 352 }, 353 }; 354 355 static int __init vimc_init(void) 356 { 357 int ret; 358 359 ret = platform_device_register(&vimc_pdev); 360 if (ret) { 361 dev_err(&vimc_pdev.dev, 362 "platform device registration failed (err=%d)\n", ret); 363 return ret; 364 } 365 366 ret = platform_driver_register(&vimc_pdrv); 367 if (ret) { 368 dev_err(&vimc_pdev.dev, 369 "platform driver registration failed (err=%d)\n", ret); 370 platform_driver_unregister(&vimc_pdrv); 371 return ret; 372 } 373 374 return 0; 375 } 376 377 static void __exit vimc_exit(void) 378 { 379 platform_driver_unregister(&vimc_pdrv); 380 381 platform_device_unregister(&vimc_pdev); 382 } 383 384 module_init(vimc_init); 385 module_exit(vimc_exit); 386 387 MODULE_DESCRIPTION("Virtual Media Controller Driver (VIMC)"); 388 MODULE_AUTHOR("Helen Fornazier <helen.fornazier@gmail.com>"); 389 MODULE_LICENSE("GPL"); 390