cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

vimc-core.c (9284B)


      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
     19unsigned int vimc_allocator;
     20module_param_named(allocator, vimc_allocator, uint, 0444);
     21MODULE_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 */
     36struct 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 */
     45struct 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
     56static 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
     96static 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
    115static 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
    124static 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
    132static 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
    155err_rm_links:
    156	vimc_rm_links(vimc);
    157	return ret;
    158}
    159
    160static 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
    169static 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
    178static 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
    201static 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
    212static 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
    260err_mdev_unregister:
    261	media_device_unregister(&vimc->mdev);
    262err_rm_subdevs:
    263	vimc_unregister_subdevs(vimc);
    264	vimc_release_subdevs(vimc);
    265err_free_ent_devs:
    266	kfree(vimc->ent_devs);
    267err_v4l2_unregister:
    268	v4l2_device_unregister(&vimc->v4l2_dev);
    269
    270	return ret;
    271}
    272
    273static 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
    324static 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
    338static void vimc_dev_release(struct device *dev)
    339{
    340}
    341
    342static struct platform_device vimc_pdev = {
    343	.name = VIMC_PDEV_NAME,
    344	.dev.release = vimc_dev_release,
    345};
    346
    347static struct platform_driver vimc_pdrv = {
    348	.probe		= vimc_probe,
    349	.remove		= vimc_remove,
    350	.driver		= {
    351		.name	= VIMC_PDEV_NAME,
    352	},
    353};
    354
    355static 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
    377static void __exit vimc_exit(void)
    378{
    379	platform_driver_unregister(&vimc_pdrv);
    380
    381	platform_device_unregister(&vimc_pdev);
    382}
    383
    384module_init(vimc_init);
    385module_exit(vimc_exit);
    386
    387MODULE_DESCRIPTION("Virtual Media Controller Driver (VIMC)");
    388MODULE_AUTHOR("Helen Fornazier <helen.fornazier@gmail.com>");
    389MODULE_LICENSE("GPL");