root/drivers/staging/media/imx/imx-media-internal-sd.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. create_internal_link
  2. create_ipu_internal_links
  3. imx_media_register_ipu_internal_subdevs
  4. imx_media_unregister_ipu_internal_subdevs

   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 
  17 struct internal_subdev;
  18 
  19 struct internal_link {
  20         int remote;
  21         int local_pad;
  22         int remote_pad;
  23 };
  24 
  25 struct internal_pad {
  26         int num_links;
  27         struct internal_link link[MAX_INTERNAL_LINKS];
  28 };
  29 
  30 struct 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 
  41 static 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 
 133 static 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         v4l2_info(&imxmd->v4l2_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 
 157 static 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 
 190 int 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 
 268 err_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 
 283 void 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 }

/* [<][>][^][v][top][bottom][index][help] */