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

imx-media-internal-sd.c (6681B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * Media driver for Freescale i.MX5/6 SOC
      4 *
      5 * Adds the IPU internal subdevices and the media links between them.
      6 *
      7 * Copyright (c) 2016 Mentor Graphics Inc.
      8 */
      9#include <linux/platform_device.h>
     10#include "imx-media.h"
     11
     12/* max pads per internal-sd */
     13#define MAX_INTERNAL_PADS   8
     14/* max links per internal-sd pad */
     15#define MAX_INTERNAL_LINKS  8
     16
     17struct internal_subdev;
     18
     19struct internal_link {
     20	int remote;
     21	int local_pad;
     22	int remote_pad;
     23};
     24
     25struct internal_pad {
     26	int num_links;
     27	struct internal_link link[MAX_INTERNAL_LINKS];
     28};
     29
     30struct internal_subdev {
     31	u32 grp_id;
     32	struct internal_pad pad[MAX_INTERNAL_PADS];
     33
     34	struct v4l2_subdev * (*sync_register)(struct v4l2_device *v4l2_dev,
     35					      struct device *ipu_dev,
     36					      struct ipu_soc *ipu,
     37					      u32 grp_id);
     38	int (*sync_unregister)(struct v4l2_subdev *sd);
     39};
     40
     41static const struct internal_subdev int_subdev[NUM_IPU_SUBDEVS] = {
     42	[IPU_CSI0] = {
     43		.grp_id = IMX_MEDIA_GRP_ID_IPU_CSI0,
     44		.pad[CSI_SRC_PAD_DIRECT] = {
     45			.num_links = 2,
     46			.link = {
     47				{
     48					.local_pad = CSI_SRC_PAD_DIRECT,
     49					.remote = IPU_IC_PRP,
     50					.remote_pad = PRP_SINK_PAD,
     51				}, {
     52					.local_pad = CSI_SRC_PAD_DIRECT,
     53					.remote = IPU_VDIC,
     54					.remote_pad = VDIC_SINK_PAD_DIRECT,
     55				},
     56			},
     57		},
     58	},
     59
     60	[IPU_CSI1] = {
     61		.grp_id = IMX_MEDIA_GRP_ID_IPU_CSI1,
     62		.pad[CSI_SRC_PAD_DIRECT] = {
     63			.num_links = 2,
     64			.link = {
     65				{
     66					.local_pad = CSI_SRC_PAD_DIRECT,
     67					.remote = IPU_IC_PRP,
     68					.remote_pad = PRP_SINK_PAD,
     69				}, {
     70					.local_pad = CSI_SRC_PAD_DIRECT,
     71					.remote = IPU_VDIC,
     72					.remote_pad = VDIC_SINK_PAD_DIRECT,
     73				},
     74			},
     75		},
     76	},
     77
     78	[IPU_VDIC] = {
     79		.grp_id = IMX_MEDIA_GRP_ID_IPU_VDIC,
     80		.sync_register = imx_media_vdic_register,
     81		.sync_unregister = imx_media_vdic_unregister,
     82		.pad[VDIC_SRC_PAD_DIRECT] = {
     83			.num_links = 1,
     84			.link = {
     85				{
     86					.local_pad = VDIC_SRC_PAD_DIRECT,
     87					.remote = IPU_IC_PRP,
     88					.remote_pad = PRP_SINK_PAD,
     89				},
     90			},
     91		},
     92	},
     93
     94	[IPU_IC_PRP] = {
     95		.grp_id = IMX_MEDIA_GRP_ID_IPU_IC_PRP,
     96		.sync_register = imx_media_ic_register,
     97		.sync_unregister = imx_media_ic_unregister,
     98		.pad[PRP_SRC_PAD_PRPENC] = {
     99			.num_links = 1,
    100			.link = {
    101				{
    102					.local_pad = PRP_SRC_PAD_PRPENC,
    103					.remote = IPU_IC_PRPENC,
    104					.remote_pad = PRPENCVF_SINK_PAD,
    105				},
    106			},
    107		},
    108		.pad[PRP_SRC_PAD_PRPVF] = {
    109			.num_links = 1,
    110			.link = {
    111				{
    112					.local_pad = PRP_SRC_PAD_PRPVF,
    113					.remote = IPU_IC_PRPVF,
    114					.remote_pad = PRPENCVF_SINK_PAD,
    115				},
    116			},
    117		},
    118	},
    119
    120	[IPU_IC_PRPENC] = {
    121		.grp_id = IMX_MEDIA_GRP_ID_IPU_IC_PRPENC,
    122		.sync_register = imx_media_ic_register,
    123		.sync_unregister = imx_media_ic_unregister,
    124	},
    125
    126	[IPU_IC_PRPVF] = {
    127		.grp_id = IMX_MEDIA_GRP_ID_IPU_IC_PRPVF,
    128		.sync_register = imx_media_ic_register,
    129		.sync_unregister = imx_media_ic_unregister,
    130	},
    131};
    132
    133static int create_internal_link(struct imx_media_dev *imxmd,
    134				struct v4l2_subdev *src,
    135				struct v4l2_subdev *sink,
    136				const struct internal_link *link)
    137{
    138	int ret;
    139
    140	/* skip if this link already created */
    141	if (media_entity_find_link(&src->entity.pads[link->local_pad],
    142				   &sink->entity.pads[link->remote_pad]))
    143		return 0;
    144
    145	dev_dbg(imxmd->md.dev, "%s:%d -> %s:%d\n",
    146		src->name, link->local_pad,
    147		sink->name, link->remote_pad);
    148
    149	ret = media_create_pad_link(&src->entity, link->local_pad,
    150				    &sink->entity, link->remote_pad, 0);
    151	if (ret)
    152		v4l2_err(&imxmd->v4l2_dev, "%s failed: %d\n", __func__, ret);
    153
    154	return ret;
    155}
    156
    157static int create_ipu_internal_links(struct imx_media_dev *imxmd,
    158				     const struct internal_subdev *intsd,
    159				     struct v4l2_subdev *sd,
    160				     int ipu_id)
    161{
    162	const struct internal_pad *intpad;
    163	const struct internal_link *link;
    164	struct media_pad *pad;
    165	int i, j, ret;
    166
    167	/* create the source->sink links */
    168	for (i = 0; i < sd->entity.num_pads; i++) {
    169		intpad = &intsd->pad[i];
    170		pad = &sd->entity.pads[i];
    171
    172		if (!(pad->flags & MEDIA_PAD_FL_SOURCE))
    173			continue;
    174
    175		for (j = 0; j < intpad->num_links; j++) {
    176			struct v4l2_subdev *sink;
    177
    178			link = &intpad->link[j];
    179			sink = imxmd->sync_sd[ipu_id][link->remote];
    180
    181			ret = create_internal_link(imxmd, sd, sink, link);
    182			if (ret)
    183				return ret;
    184		}
    185	}
    186
    187	return 0;
    188}
    189
    190int imx_media_register_ipu_internal_subdevs(struct imx_media_dev *imxmd,
    191					    struct v4l2_subdev *csi)
    192{
    193	struct device *ipu_dev = csi->dev->parent;
    194	const struct internal_subdev *intsd;
    195	struct v4l2_subdev *sd;
    196	struct ipu_soc *ipu;
    197	int i, ipu_id, ret;
    198
    199	ipu = dev_get_drvdata(ipu_dev);
    200	if (!ipu) {
    201		v4l2_err(&imxmd->v4l2_dev, "invalid IPU device!\n");
    202		return -ENODEV;
    203	}
    204
    205	ipu_id = ipu_get_num(ipu);
    206	if (ipu_id > 1) {
    207		v4l2_err(&imxmd->v4l2_dev, "invalid IPU id %d!\n", ipu_id);
    208		return -ENODEV;
    209	}
    210
    211	mutex_lock(&imxmd->mutex);
    212
    213	/* record this IPU */
    214	if (!imxmd->ipu[ipu_id])
    215		imxmd->ipu[ipu_id] = ipu;
    216
    217	/* register the synchronous subdevs */
    218	for (i = 0; i < NUM_IPU_SUBDEVS; i++) {
    219		intsd = &int_subdev[i];
    220
    221		sd = imxmd->sync_sd[ipu_id][i];
    222
    223		/*
    224		 * skip if this sync subdev already registered or its
    225		 * not a sync subdev (one of the CSIs)
    226		 */
    227		if (sd || !intsd->sync_register)
    228			continue;
    229
    230		mutex_unlock(&imxmd->mutex);
    231		sd = intsd->sync_register(&imxmd->v4l2_dev, ipu_dev, ipu,
    232					  intsd->grp_id);
    233		mutex_lock(&imxmd->mutex);
    234		if (IS_ERR(sd)) {
    235			ret = PTR_ERR(sd);
    236			goto err_unwind;
    237		}
    238
    239		imxmd->sync_sd[ipu_id][i] = sd;
    240	}
    241
    242	/*
    243	 * all the sync subdevs are registered, create the media links
    244	 * between them.
    245	 */
    246	for (i = 0; i < NUM_IPU_SUBDEVS; i++) {
    247		intsd = &int_subdev[i];
    248
    249		if (intsd->grp_id == csi->grp_id) {
    250			sd = csi;
    251		} else {
    252			sd = imxmd->sync_sd[ipu_id][i];
    253			if (!sd)
    254				continue;
    255		}
    256
    257		ret = create_ipu_internal_links(imxmd, intsd, sd, ipu_id);
    258		if (ret) {
    259			mutex_unlock(&imxmd->mutex);
    260			imx_media_unregister_ipu_internal_subdevs(imxmd);
    261			return ret;
    262		}
    263	}
    264
    265	mutex_unlock(&imxmd->mutex);
    266	return 0;
    267
    268err_unwind:
    269	while (--i >= 0) {
    270		intsd = &int_subdev[i];
    271		sd = imxmd->sync_sd[ipu_id][i];
    272		if (!sd || !intsd->sync_unregister)
    273			continue;
    274		mutex_unlock(&imxmd->mutex);
    275		intsd->sync_unregister(sd);
    276		mutex_lock(&imxmd->mutex);
    277	}
    278
    279	mutex_unlock(&imxmd->mutex);
    280	return ret;
    281}
    282
    283void imx_media_unregister_ipu_internal_subdevs(struct imx_media_dev *imxmd)
    284{
    285	const struct internal_subdev *intsd;
    286	struct v4l2_subdev *sd;
    287	int i, j;
    288
    289	mutex_lock(&imxmd->mutex);
    290
    291	for (i = 0; i < 2; i++) {
    292		for (j = 0; j < NUM_IPU_SUBDEVS; j++) {
    293			intsd = &int_subdev[j];
    294			sd = imxmd->sync_sd[i][j];
    295
    296			if (!sd || !intsd->sync_unregister)
    297				continue;
    298
    299			mutex_unlock(&imxmd->mutex);
    300			intsd->sync_unregister(sd);
    301			mutex_lock(&imxmd->mutex);
    302		}
    303	}
    304
    305	mutex_unlock(&imxmd->mutex);
    306}