Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * vimc-core.c Virtual Media Controller Driver
0004  *
0005  * Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com>
0006  */
0007 
0008 #include <linux/dma-mapping.h>
0009 #include <linux/font.h>
0010 #include <linux/init.h>
0011 #include <linux/module.h>
0012 #include <linux/platform_device.h>
0013 #include <media/media-device.h>
0014 #include <media/tpg/v4l2-tpg.h>
0015 #include <media/v4l2-device.h>
0016 
0017 #include "vimc-common.h"
0018 
0019 unsigned int vimc_allocator;
0020 module_param_named(allocator, vimc_allocator, uint, 0444);
0021 MODULE_PARM_DESC(allocator, " memory allocator selection, default is 0.\n"
0022                  "\t\t    0 == vmalloc\n"
0023                  "\t\t    1 == dma-contig");
0024 
0025 #define VIMC_MDEV_MODEL_NAME "VIMC MDEV"
0026 
0027 #define VIMC_DATA_LINK(src, srcpad, sink, sinkpad, link_flags) {    \
0028     .src_ent = src,                     \
0029     .src_pad = srcpad,                  \
0030     .sink_ent = sink,                   \
0031     .sink_pad = sinkpad,                    \
0032     .flags = link_flags,                    \
0033 }
0034 
0035 #define VIMC_ANCILLARY_LINK(primary, ancillary) {   \
0036     .primary_ent = primary,         \
0037     .ancillary_ent = ancillary      \
0038 }
0039 
0040 /* Structure which describes data links between entities */
0041 struct vimc_data_link {
0042     unsigned int src_ent;
0043     u16 src_pad;
0044     unsigned int sink_ent;
0045     u16 sink_pad;
0046     u32 flags;
0047 };
0048 
0049 /* Enum to improve clarity when defining vimc_data_links */
0050 enum vimc_data_link_ents {
0051     SENSOR_A,
0052     SENSOR_B,
0053     DEBAYER_A,
0054     DEBAYER_B,
0055     RAW_CAPTURE_0,
0056     RAW_CAPTURE_1,
0057     RGB_YUV_INPUT,
0058     SCALER,
0059     RGB_YUV_CAPTURE,
0060     LENS_A,
0061     LENS_B,
0062 };
0063 
0064 /* Structure which describes ancillary links between entities */
0065 struct vimc_ancillary_link {
0066     unsigned int primary_ent;
0067     unsigned int ancillary_ent;
0068 };
0069 
0070 /* Structure which describes the whole topology */
0071 struct vimc_pipeline_config {
0072     const struct vimc_ent_config *ents;
0073     size_t num_ents;
0074     const struct vimc_data_link *data_links;
0075     size_t num_data_links;
0076     const struct vimc_ancillary_link *ancillary_links;
0077     size_t num_ancillary_links;
0078 };
0079 
0080 /* --------------------------------------------------------------------------
0081  * Topology Configuration
0082  */
0083 
0084 static struct vimc_ent_config ent_config[] = {
0085     [SENSOR_A] = {
0086         .name = "Sensor A",
0087         .type = &vimc_sensor_type
0088     },
0089     [SENSOR_B] = {
0090         .name = "Sensor B",
0091         .type = &vimc_sensor_type
0092     },
0093     [DEBAYER_A] = {
0094         .name = "Debayer A",
0095         .type = &vimc_debayer_type
0096     },
0097     [DEBAYER_B] = {
0098         .name = "Debayer B",
0099         .type = &vimc_debayer_type
0100     },
0101     [RAW_CAPTURE_0] = {
0102         .name = "Raw Capture 0",
0103         .type = &vimc_capture_type
0104     },
0105     [RAW_CAPTURE_1] = {
0106         .name = "Raw Capture 1",
0107         .type = &vimc_capture_type
0108     },
0109     [RGB_YUV_INPUT] = {
0110         /* TODO: change this to vimc-input when it is implemented */
0111         .name = "RGB/YUV Input",
0112         .type = &vimc_sensor_type
0113     },
0114     [SCALER] = {
0115         .name = "Scaler",
0116         .type = &vimc_scaler_type
0117     },
0118     [RGB_YUV_CAPTURE] = {
0119         .name = "RGB/YUV Capture",
0120         .type = &vimc_capture_type
0121     },
0122     [LENS_A] = {
0123         .name = "Lens A",
0124         .type = &vimc_lens_type
0125     },
0126     [LENS_B] = {
0127         .name = "Lens B",
0128         .type = &vimc_lens_type
0129     },
0130 };
0131 
0132 static const struct vimc_data_link data_links[] = {
0133     /* Link: Sensor A (Pad 0)->(Pad 0) Debayer A */
0134     VIMC_DATA_LINK(SENSOR_A, 0, DEBAYER_A, 0,
0135                MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
0136     /* Link: Sensor A (Pad 0)->(Pad 0) Raw Capture 0 */
0137     VIMC_DATA_LINK(SENSOR_A, 0, RAW_CAPTURE_0, 0,
0138                MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
0139     /* Link: Sensor B (Pad 0)->(Pad 0) Debayer B */
0140     VIMC_DATA_LINK(SENSOR_B, 0, DEBAYER_B, 0,
0141                MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
0142     /* Link: Sensor B (Pad 0)->(Pad 0) Raw Capture 1 */
0143     VIMC_DATA_LINK(SENSOR_B, 0, RAW_CAPTURE_1, 0,
0144                MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
0145     /* Link: Debayer A (Pad 1)->(Pad 0) Scaler */
0146     VIMC_DATA_LINK(DEBAYER_A, 1, SCALER, 0, MEDIA_LNK_FL_ENABLED),
0147     /* Link: Debayer B (Pad 1)->(Pad 0) Scaler */
0148     VIMC_DATA_LINK(DEBAYER_B, 1, SCALER, 0, 0),
0149     /* Link: RGB/YUV Input (Pad 0)->(Pad 0) Scaler */
0150     VIMC_DATA_LINK(RGB_YUV_INPUT, 0, SCALER, 0, 0),
0151     /* Link: Scaler (Pad 1)->(Pad 0) RGB/YUV Capture */
0152     VIMC_DATA_LINK(SCALER, 1, RGB_YUV_CAPTURE, 0,
0153                MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
0154 };
0155 
0156 static const struct vimc_ancillary_link ancillary_links[] = {
0157     /* Link: Sensor A -> Lens A */
0158     VIMC_ANCILLARY_LINK(0, 9),
0159     /* Link: Sensor B -> Lens B */
0160     VIMC_ANCILLARY_LINK(1, 10),
0161 };
0162 
0163 static struct vimc_pipeline_config pipe_cfg = {
0164     .ents            = ent_config,
0165     .num_ents        = ARRAY_SIZE(ent_config),
0166     .data_links      = data_links,
0167     .num_data_links      = ARRAY_SIZE(data_links),
0168     .ancillary_links     = ancillary_links,
0169     .num_ancillary_links = ARRAY_SIZE(ancillary_links),
0170 };
0171 
0172 /* -------------------------------------------------------------------------- */
0173 
0174 static void vimc_rm_links(struct vimc_device *vimc)
0175 {
0176     unsigned int i;
0177 
0178     for (i = 0; i < vimc->pipe_cfg->num_ents; i++)
0179         media_entity_remove_links(vimc->ent_devs[i]->ent);
0180 }
0181 
0182 static int vimc_create_links(struct vimc_device *vimc)
0183 {
0184     unsigned int i;
0185     int ret;
0186 
0187     /* Initialize the links between entities */
0188     for (i = 0; i < vimc->pipe_cfg->num_data_links; i++) {
0189         const struct vimc_data_link *link = &vimc->pipe_cfg->data_links[i];
0190 
0191         struct vimc_ent_device *ved_src =
0192             vimc->ent_devs[link->src_ent];
0193         struct vimc_ent_device *ved_sink =
0194             vimc->ent_devs[link->sink_ent];
0195 
0196         ret = media_create_pad_link(ved_src->ent, link->src_pad,
0197                         ved_sink->ent, link->sink_pad,
0198                         link->flags);
0199         if (ret)
0200             goto err_rm_links;
0201     }
0202 
0203     for (i = 0; i < vimc->pipe_cfg->num_ancillary_links; i++) {
0204         const struct vimc_ancillary_link *link = &vimc->pipe_cfg->ancillary_links[i];
0205 
0206         struct vimc_ent_device *ved_primary =
0207             vimc->ent_devs[link->primary_ent];
0208         struct vimc_ent_device *ved_ancillary =
0209             vimc->ent_devs[link->ancillary_ent];
0210         struct media_link *ret_link =
0211             media_create_ancillary_link(ved_primary->ent, ved_ancillary->ent);
0212 
0213         if (IS_ERR(ret_link)) {
0214             ret = PTR_ERR(ret_link);
0215             goto err_rm_links;
0216         }
0217     }
0218 
0219     return 0;
0220 
0221 err_rm_links:
0222     vimc_rm_links(vimc);
0223     return ret;
0224 }
0225 
0226 static void vimc_release_subdevs(struct vimc_device *vimc)
0227 {
0228     unsigned int i;
0229 
0230     for (i = 0; i < vimc->pipe_cfg->num_ents; i++)
0231         if (vimc->ent_devs[i])
0232             vimc->pipe_cfg->ents[i].type->release(vimc->ent_devs[i]);
0233 }
0234 
0235 static void vimc_unregister_subdevs(struct vimc_device *vimc)
0236 {
0237     unsigned int i;
0238 
0239     for (i = 0; i < vimc->pipe_cfg->num_ents; i++)
0240         if (vimc->ent_devs[i] && vimc->pipe_cfg->ents[i].type->unregister)
0241             vimc->pipe_cfg->ents[i].type->unregister(vimc->ent_devs[i]);
0242 }
0243 
0244 static int vimc_add_subdevs(struct vimc_device *vimc)
0245 {
0246     unsigned int i;
0247 
0248     for (i = 0; i < vimc->pipe_cfg->num_ents; i++) {
0249         dev_dbg(vimc->mdev.dev, "new entity for %s\n",
0250             vimc->pipe_cfg->ents[i].name);
0251         vimc->ent_devs[i] = vimc->pipe_cfg->ents[i].type->add(vimc,
0252                     vimc->pipe_cfg->ents[i].name);
0253         if (IS_ERR(vimc->ent_devs[i])) {
0254             int err = PTR_ERR(vimc->ent_devs[i]);
0255 
0256             dev_err(vimc->mdev.dev, "adding entity %s failed (%d)\n",
0257                 vimc->pipe_cfg->ents[i].name, err);
0258             vimc->ent_devs[i] = NULL;
0259             vimc_unregister_subdevs(vimc);
0260             vimc_release_subdevs(vimc);
0261             return err;
0262         }
0263     }
0264     return 0;
0265 }
0266 
0267 static void vimc_v4l2_dev_release(struct v4l2_device *v4l2_dev)
0268 {
0269     struct vimc_device *vimc =
0270         container_of(v4l2_dev, struct vimc_device, v4l2_dev);
0271 
0272     vimc_release_subdevs(vimc);
0273     media_device_cleanup(&vimc->mdev);
0274     kfree(vimc->ent_devs);
0275     kfree(vimc);
0276 }
0277 
0278 static int vimc_register_devices(struct vimc_device *vimc)
0279 {
0280     int ret;
0281 
0282     /* Register the v4l2 struct */
0283     ret = v4l2_device_register(vimc->mdev.dev, &vimc->v4l2_dev);
0284     if (ret) {
0285         dev_err(vimc->mdev.dev,
0286             "v4l2 device register failed (err=%d)\n", ret);
0287         return ret;
0288     }
0289     /* allocate ent_devs */
0290     vimc->ent_devs = kcalloc(vimc->pipe_cfg->num_ents,
0291                  sizeof(*vimc->ent_devs), GFP_KERNEL);
0292     if (!vimc->ent_devs) {
0293         ret = -ENOMEM;
0294         goto err_v4l2_unregister;
0295     }
0296 
0297     /* Invoke entity config hooks to initialize and register subdevs */
0298     ret = vimc_add_subdevs(vimc);
0299     if (ret)
0300         goto err_free_ent_devs;
0301 
0302     /* Initialize links */
0303     ret = vimc_create_links(vimc);
0304     if (ret)
0305         goto err_rm_subdevs;
0306 
0307     /* Register the media device */
0308     ret = media_device_register(&vimc->mdev);
0309     if (ret) {
0310         dev_err(vimc->mdev.dev,
0311             "media device register failed (err=%d)\n", ret);
0312         goto err_rm_subdevs;
0313     }
0314 
0315     /* Expose all subdev's nodes*/
0316     ret = v4l2_device_register_subdev_nodes(&vimc->v4l2_dev);
0317     if (ret) {
0318         dev_err(vimc->mdev.dev,
0319             "vimc subdev nodes registration failed (err=%d)\n",
0320             ret);
0321         goto err_mdev_unregister;
0322     }
0323 
0324     return 0;
0325 
0326 err_mdev_unregister:
0327     media_device_unregister(&vimc->mdev);
0328 err_rm_subdevs:
0329     vimc_unregister_subdevs(vimc);
0330     vimc_release_subdevs(vimc);
0331 err_free_ent_devs:
0332     kfree(vimc->ent_devs);
0333 err_v4l2_unregister:
0334     v4l2_device_unregister(&vimc->v4l2_dev);
0335 
0336     return ret;
0337 }
0338 
0339 static int vimc_probe(struct platform_device *pdev)
0340 {
0341     const struct font_desc *font = find_font("VGA8x16");
0342     struct vimc_device *vimc;
0343     int ret;
0344 
0345     dev_dbg(&pdev->dev, "probe");
0346 
0347     if (!font) {
0348         dev_err(&pdev->dev, "could not find font\n");
0349         return -ENODEV;
0350     }
0351 
0352     tpg_set_font(font->data);
0353 
0354     if (vimc_allocator == VIMC_ALLOCATOR_DMA_CONTIG)
0355         dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
0356 
0357     vimc = kzalloc(sizeof(*vimc), GFP_KERNEL);
0358     if (!vimc)
0359         return -ENOMEM;
0360 
0361     vimc->pipe_cfg = &pipe_cfg;
0362 
0363     /* Link the media device within the v4l2_device */
0364     vimc->v4l2_dev.mdev = &vimc->mdev;
0365 
0366     /* Initialize media device */
0367     strscpy(vimc->mdev.model, VIMC_MDEV_MODEL_NAME,
0368         sizeof(vimc->mdev.model));
0369     snprintf(vimc->mdev.bus_info, sizeof(vimc->mdev.bus_info),
0370          "platform:%s", VIMC_PDEV_NAME);
0371     vimc->mdev.dev = &pdev->dev;
0372     media_device_init(&vimc->mdev);
0373 
0374     ret = vimc_register_devices(vimc);
0375     if (ret) {
0376         media_device_cleanup(&vimc->mdev);
0377         kfree(vimc);
0378         return ret;
0379     }
0380     /*
0381      * the release cb is set only after successful registration.
0382      * if the registration fails, we release directly from probe
0383      */
0384 
0385     vimc->v4l2_dev.release = vimc_v4l2_dev_release;
0386     platform_set_drvdata(pdev, vimc);
0387     return 0;
0388 }
0389 
0390 static int vimc_remove(struct platform_device *pdev)
0391 {
0392     struct vimc_device *vimc = platform_get_drvdata(pdev);
0393 
0394     dev_dbg(&pdev->dev, "remove");
0395 
0396     vimc_unregister_subdevs(vimc);
0397     media_device_unregister(&vimc->mdev);
0398     v4l2_device_unregister(&vimc->v4l2_dev);
0399     v4l2_device_put(&vimc->v4l2_dev);
0400 
0401     return 0;
0402 }
0403 
0404 static void vimc_dev_release(struct device *dev)
0405 {
0406 }
0407 
0408 static struct platform_device vimc_pdev = {
0409     .name = VIMC_PDEV_NAME,
0410     .dev.release = vimc_dev_release,
0411 };
0412 
0413 static struct platform_driver vimc_pdrv = {
0414     .probe      = vimc_probe,
0415     .remove     = vimc_remove,
0416     .driver     = {
0417         .name   = VIMC_PDEV_NAME,
0418     },
0419 };
0420 
0421 static int __init vimc_init(void)
0422 {
0423     int ret;
0424 
0425     ret = platform_device_register(&vimc_pdev);
0426     if (ret) {
0427         dev_err(&vimc_pdev.dev,
0428             "platform device registration failed (err=%d)\n", ret);
0429         return ret;
0430     }
0431 
0432     ret = platform_driver_register(&vimc_pdrv);
0433     if (ret) {
0434         dev_err(&vimc_pdev.dev,
0435             "platform driver registration failed (err=%d)\n", ret);
0436         platform_driver_unregister(&vimc_pdrv);
0437         return ret;
0438     }
0439 
0440     return 0;
0441 }
0442 
0443 static void __exit vimc_exit(void)
0444 {
0445     platform_driver_unregister(&vimc_pdrv);
0446 
0447     platform_device_unregister(&vimc_pdev);
0448 }
0449 
0450 module_init(vimc_init);
0451 module_exit(vimc_exit);
0452 
0453 MODULE_DESCRIPTION("Virtual Media Controller Driver (VIMC)");
0454 MODULE_AUTHOR("Helen Fornazier <helen.fornazier@gmail.com>");
0455 MODULE_LICENSE("GPL");