Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

media: staging/imx: remove static media link arrays

Remove the static list of media links that were formed at probe time.
These links can instead be created after all registered async subdevices
have been bound in imx_media_probe_complete().

The media links between subdevices that exist in the device tree, can
be created post-async completion by using v4l2_fwnode_parse_link() for
each endpoint node of that subdevice. Note this approach assumes
device-tree ports are equivalent to media pads (pad index equals
port id), and that device-tree endpoints are equivalent to media
links between pads.

Because links are no longer parsed by imx_media_of_parse(), its sole
function is now only to add subdevices that it encounters by walking
the OF graph to the async list, so the function has been renamed
imx_media_add_of_subdevs().

Similarly, the media links between the IPU-internal subdevice pads (the
CSI source pads, and all pads between the vdic, ic-prp, ic-prpenc, and
ic-prpvf subdevices), can be created post-async completion by looping
through the subdevice's media pads and using the const internal_subdev
table.

Because links are no longer parsed by imx_media_add_internal_subdevs(),
this function no longer needs an array of CSI subdevs to form links
from.

In summary, the following functions, which were used to form a list
of media links at probe time, are removed:

imx_media_add_pad_link()
add_internal_links()
of_add_pad_link()

replaced by these functions, called at probe time, which only populate
the async subdev list:

imx_media_add_of_subdevs()
imx_media_add_internal_subdevs()

and these functions, called at async completion, which create the
media links:

imx_media_create_of_links()
imx_media_create_csi_of_links()
imx_media_create_internal_links()

Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>

authored by

Steve Longerbeam and committed by
Mauro Carvalho Chehab
621b08ea bf3cfaa7

+285 -300
+24 -106
drivers/staging/media/imx/imx-media-dev.c
··· 11 11 #include <linux/delay.h> 12 12 #include <linux/fs.h> 13 13 #include <linux/module.h> 14 + #include <linux/of_graph.h> 14 15 #include <linux/of_platform.h> 15 16 #include <linux/pinctrl/consumer.h> 16 17 #include <linux/platform_device.h> ··· 129 128 } 130 129 131 130 /* 132 - * Adds an imx-media link to a subdev pad's link list. This is called 133 - * during driver load when forming the links between subdevs. 134 - * 135 - * @pad: the local pad 136 - * @remote_node: the device node of the remote subdev 137 - * @remote_devname: the device name of the remote subdev 138 - * @local_pad: local pad index 139 - * @remote_pad: remote pad index 140 - */ 141 - int imx_media_add_pad_link(struct imx_media_dev *imxmd, 142 - struct imx_media_pad *pad, 143 - struct device_node *remote_node, 144 - const char *remote_devname, 145 - int local_pad, int remote_pad) 146 - { 147 - struct imx_media_link *link; 148 - int link_idx, ret = 0; 149 - 150 - mutex_lock(&imxmd->mutex); 151 - 152 - link_idx = pad->num_links; 153 - if (link_idx >= IMX_MEDIA_MAX_LINKS) { 154 - dev_err(imxmd->md.dev, "%s: too many links!\n", __func__); 155 - ret = -ENOSPC; 156 - goto out; 157 - } 158 - 159 - link = &pad->link[link_idx]; 160 - 161 - link->remote_sd_node = remote_node; 162 - if (remote_devname) 163 - strncpy(link->remote_devname, remote_devname, 164 - sizeof(link->remote_devname)); 165 - 166 - link->local_pad = local_pad; 167 - link->remote_pad = remote_pad; 168 - 169 - pad->num_links++; 170 - out: 171 - mutex_unlock(&imxmd->mutex); 172 - return ret; 173 - } 174 - 175 - /* 176 131 * get IPU from this CSI and add it to the list of IPUs 177 132 * the media driver will control. 178 133 */ ··· 197 240 } 198 241 199 242 /* 200 - * Create a single source->sink media link given a subdev and a single 201 - * link from one of its source pads. Called after all subdevs have 202 - * registered. 203 - */ 204 - static int imx_media_create_link(struct imx_media_dev *imxmd, 205 - struct imx_media_subdev *src, 206 - struct imx_media_link *link) 207 - { 208 - struct imx_media_subdev *sink; 209 - u16 source_pad, sink_pad; 210 - int ret; 211 - 212 - sink = imx_media_find_async_subdev(imxmd, link->remote_sd_node, 213 - link->remote_devname); 214 - if (!sink) { 215 - v4l2_warn(&imxmd->v4l2_dev, "%s: no sink for %s:%d\n", 216 - __func__, src->sd->name, link->local_pad); 217 - return 0; 218 - } 219 - 220 - source_pad = link->local_pad; 221 - sink_pad = link->remote_pad; 222 - 223 - v4l2_info(&imxmd->v4l2_dev, "%s: %s:%d -> %s:%d\n", __func__, 224 - src->sd->name, source_pad, sink->sd->name, sink_pad); 225 - 226 - ret = media_create_pad_link(&src->sd->entity, source_pad, 227 - &sink->sd->entity, sink_pad, 0); 228 - if (ret) 229 - v4l2_err(&imxmd->v4l2_dev, 230 - "create_pad_link failed: %d\n", ret); 231 - 232 - return ret; 233 - } 234 - 235 - /* 236 - * create the media links from all imx-media pads and their links. 243 + * create the media links from all pads and their links. 237 244 * Called after all subdevs have registered. 238 245 */ 239 246 static int imx_media_create_links(struct imx_media_dev *imxmd) 240 247 { 241 248 struct imx_media_subdev *imxsd; 242 - struct imx_media_link *link; 243 - struct imx_media_pad *pad; 244 - int num_pads, i, j, k; 245 - int ret = 0; 249 + struct v4l2_subdev *sd; 250 + int i, ret; 246 251 247 252 for (i = 0; i < imxmd->num_subdevs; i++) { 248 253 imxsd = &imxmd->subdev[i]; 249 - num_pads = imxsd->num_sink_pads + imxsd->num_src_pads; 254 + sd = imxsd->sd; 250 255 251 - for (j = 0; j < num_pads; j++) { 252 - pad = &imxsd->pad[j]; 253 - 254 - /* only create the source->sink links */ 255 - if (!(pad->pad.flags & MEDIA_PAD_FL_SOURCE)) 256 - continue; 257 - 258 - for (k = 0; k < pad->num_links; k++) { 259 - link = &pad->link[k]; 260 - 261 - ret = imx_media_create_link(imxmd, imxsd, link); 262 - if (ret) 263 - goto out; 264 - } 256 + if (((sd->grp_id & IMX_MEDIA_GRP_ID_CSI) || imxsd->pdev)) { 257 + /* this is an internal subdev or a CSI */ 258 + ret = imx_media_create_internal_links(imxmd, imxsd); 259 + if (ret) 260 + return ret; 261 + /* 262 + * the CSIs straddle between the external and the IPU 263 + * internal entities, so create the external links 264 + * to the CSI sink pads. 265 + */ 266 + if (sd->grp_id & IMX_MEDIA_GRP_ID_CSI) 267 + imx_media_create_csi_of_links(imxmd, imxsd); 268 + } else { 269 + /* this is an external fwnode subdev */ 270 + imx_media_create_of_links(imxmd, imxsd); 265 271 } 266 272 } 267 273 268 - out: 269 - return ret; 274 + return 0; 270 275 } 271 276 272 277 /* ··· 469 550 { 470 551 struct device *dev = &pdev->dev; 471 552 struct device_node *node = dev->of_node; 472 - struct imx_media_subdev *csi[4] = {0}; 473 553 struct imx_media_dev *imxmd; 474 554 int ret; 475 555 ··· 499 581 500 582 dev_set_drvdata(imxmd->v4l2_dev.dev, imxmd); 501 583 502 - ret = imx_media_of_parse(imxmd, &csi, node); 584 + ret = imx_media_add_of_subdevs(imxmd, node); 503 585 if (ret) { 504 586 v4l2_err(&imxmd->v4l2_dev, 505 - "imx_media_of_parse failed with %d\n", ret); 587 + "add_of_subdevs failed with %d\n", ret); 506 588 goto unreg_dev; 507 589 } 508 590 509 - ret = imx_media_add_internal_subdevs(imxmd, csi); 591 + ret = imx_media_add_internal_subdevs(imxmd); 510 592 if (ret) { 511 593 v4l2_err(&imxmd->v4l2_dev, 512 594 "add_internal_subdevs failed with %d\n", ret);
+126 -93
drivers/staging/media/imx/imx-media-internal-sd.c
··· 60 60 }, 61 61 }; 62 62 63 + struct internal_subdev; 64 + 63 65 struct internal_link { 64 - const struct internal_subdev_id *remote_id; 66 + const struct internal_subdev *remote; 67 + int local_pad; 65 68 int remote_pad; 66 69 }; 67 70 71 + /* max links per internal-sd pad */ 72 + #define MAX_INTERNAL_LINKS 8 73 + 68 74 struct internal_pad { 69 - bool devnode; /* does this pad link to a device node */ 70 - struct internal_link link[IMX_MEDIA_MAX_LINKS]; 75 + struct internal_link link[MAX_INTERNAL_LINKS]; 71 76 }; 72 77 73 78 static const struct internal_subdev { ··· 80 75 struct internal_pad pad[IMX_MEDIA_MAX_PADS]; 81 76 int num_sink_pads; 82 77 int num_src_pads; 83 - } internal_subdev[num_isd] = { 78 + } int_subdev[num_isd] = { 84 79 [isd_csi0] = { 85 80 .id = &isd_id[isd_csi0], 86 81 .num_sink_pads = CSI_NUM_SINK_PADS, ··· 88 83 .pad[CSI_SRC_PAD_DIRECT] = { 89 84 .link = { 90 85 { 91 - .remote_id = &isd_id[isd_ic_prp], 86 + .local_pad = CSI_SRC_PAD_DIRECT, 87 + .remote = &int_subdev[isd_ic_prp], 92 88 .remote_pad = PRP_SINK_PAD, 93 89 }, { 94 - .remote_id = &isd_id[isd_vdic], 90 + .local_pad = CSI_SRC_PAD_DIRECT, 91 + .remote = &int_subdev[isd_vdic], 95 92 .remote_pad = VDIC_SINK_PAD_DIRECT, 96 93 }, 97 94 }, 98 - }, 99 - .pad[CSI_SRC_PAD_IDMAC] = { 100 - .devnode = true, 101 95 }, 102 96 }, 103 97 ··· 107 103 .pad[CSI_SRC_PAD_DIRECT] = { 108 104 .link = { 109 105 { 110 - .remote_id = &isd_id[isd_ic_prp], 106 + .local_pad = CSI_SRC_PAD_DIRECT, 107 + .remote = &int_subdev[isd_ic_prp], 111 108 .remote_pad = PRP_SINK_PAD, 112 109 }, { 113 - .remote_id = &isd_id[isd_vdic], 110 + .local_pad = CSI_SRC_PAD_DIRECT, 111 + .remote = &int_subdev[isd_vdic], 114 112 .remote_pad = VDIC_SINK_PAD_DIRECT, 115 113 }, 116 114 }, 117 - }, 118 - .pad[CSI_SRC_PAD_IDMAC] = { 119 - .devnode = true, 120 115 }, 121 116 }, 122 117 ··· 123 120 .id = &isd_id[isd_vdic], 124 121 .num_sink_pads = VDIC_NUM_SINK_PADS, 125 122 .num_src_pads = VDIC_NUM_SRC_PADS, 126 - .pad[VDIC_SINK_PAD_IDMAC] = { 127 - .devnode = true, 128 - }, 129 123 .pad[VDIC_SRC_PAD_DIRECT] = { 130 124 .link = { 131 125 { 132 - .remote_id = &isd_id[isd_ic_prp], 126 + .local_pad = VDIC_SRC_PAD_DIRECT, 127 + .remote = &int_subdev[isd_ic_prp], 133 128 .remote_pad = PRP_SINK_PAD, 134 129 }, 135 130 }, ··· 141 140 .pad[PRP_SRC_PAD_PRPENC] = { 142 141 .link = { 143 142 { 144 - .remote_id = &isd_id[isd_ic_prpenc], 143 + .local_pad = PRP_SRC_PAD_PRPENC, 144 + .remote = &int_subdev[isd_ic_prpenc], 145 145 .remote_pad = 0, 146 146 }, 147 147 }, ··· 150 148 .pad[PRP_SRC_PAD_PRPVF] = { 151 149 .link = { 152 150 { 153 - .remote_id = &isd_id[isd_ic_prpvf], 151 + .local_pad = PRP_SRC_PAD_PRPVF, 152 + .remote = &int_subdev[isd_ic_prpvf], 154 153 .remote_pad = 0, 155 154 }, 156 155 }, ··· 162 159 .id = &isd_id[isd_ic_prpenc], 163 160 .num_sink_pads = PRPENCVF_NUM_SINK_PADS, 164 161 .num_src_pads = PRPENCVF_NUM_SRC_PADS, 165 - .pad[PRPENCVF_SRC_PAD] = { 166 - .devnode = true, 167 - }, 168 162 }, 169 163 170 164 [isd_ic_prpvf] = { 171 165 .id = &isd_id[isd_ic_prpvf], 172 166 .num_sink_pads = PRPENCVF_NUM_SINK_PADS, 173 167 .num_src_pads = PRPENCVF_NUM_SRC_PADS, 174 - .pad[PRPENCVF_SRC_PAD] = { 175 - .devnode = true, 176 - }, 177 168 }, 178 169 }; 179 170 180 - /* form a device name given a group id and ipu id */ 181 - static inline void isd_id_to_devname(char *devname, int sz, 182 - const struct internal_subdev_id *id, 183 - int ipu_id) 171 + /* form a device name given an internal subdev and ipu id */ 172 + static inline void isd_to_devname(char *devname, int sz, 173 + const struct internal_subdev *isd, 174 + int ipu_id) 184 175 { 185 - int pdev_id = ipu_id * num_isd + id->index; 176 + int pdev_id = ipu_id * num_isd + isd->id->index; 186 177 187 - snprintf(devname, sz, "%s.%d", id->name, pdev_id); 178 + snprintf(devname, sz, "%s.%d", isd->id->name, pdev_id); 188 179 } 189 180 190 - /* adds the links from given internal subdev */ 191 - static int add_internal_links(struct imx_media_dev *imxmd, 192 - const struct internal_subdev *isd, 193 - struct imx_media_subdev *imxsd, 194 - int ipu_id) 181 + static const struct internal_subdev *find_intsd_by_grp_id(u32 grp_id) 195 182 { 196 - int i, num_pads, ret; 183 + enum isd_enum i; 197 184 198 - num_pads = isd->num_sink_pads + isd->num_src_pads; 185 + for (i = 0; i < num_isd; i++) { 186 + const struct internal_subdev *isd = &int_subdev[i]; 199 187 200 - for (i = 0; i < num_pads; i++) { 201 - const struct internal_pad *intpad = &isd->pad[i]; 202 - struct imx_media_pad *pad = &imxsd->pad[i]; 203 - int j; 188 + if (isd->id->grp_id == grp_id) 189 + return isd; 190 + } 204 191 205 - /* init the pad flags for this internal subdev */ 206 - pad->pad.flags = (i < isd->num_sink_pads) ? 207 - MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE; 208 - /* export devnode pad flag to the subdevs */ 209 - pad->devnode = intpad->devnode; 192 + return NULL; 193 + } 194 + 195 + static struct imx_media_subdev *find_sink(struct imx_media_dev *imxmd, 196 + struct imx_media_subdev *src, 197 + const struct internal_link *link) 198 + { 199 + char sink_devname[32]; 200 + int ipu_id; 201 + 202 + /* 203 + * retrieve IPU id from subdev name, note: can't get this from 204 + * struct imx_media_internal_sd_platformdata because if src is 205 + * a CSI, it has different struct ipu_client_platformdata which 206 + * does not contain IPU id. 207 + */ 208 + if (sscanf(src->sd->name, "ipu%d", &ipu_id) != 1) 209 + return NULL; 210 + 211 + isd_to_devname(sink_devname, sizeof(sink_devname), 212 + link->remote, ipu_id - 1); 213 + 214 + return imx_media_find_async_subdev(imxmd, NULL, sink_devname); 215 + } 216 + 217 + static int create_ipu_internal_link(struct imx_media_dev *imxmd, 218 + struct imx_media_subdev *src, 219 + const struct internal_link *link) 220 + { 221 + struct imx_media_subdev *sink; 222 + int ret; 223 + 224 + sink = find_sink(imxmd, src, link); 225 + if (!sink) 226 + return -ENODEV; 227 + 228 + v4l2_info(&imxmd->v4l2_dev, "%s:%d -> %s:%d\n", 229 + src->sd->name, link->local_pad, 230 + sink->sd->name, link->remote_pad); 231 + 232 + ret = media_create_pad_link(&src->sd->entity, link->local_pad, 233 + &sink->sd->entity, link->remote_pad, 0); 234 + if (ret) 235 + v4l2_err(&imxmd->v4l2_dev, 236 + "create_pad_link failed: %d\n", ret); 237 + 238 + return ret; 239 + } 240 + 241 + int imx_media_create_internal_links(struct imx_media_dev *imxmd, 242 + struct imx_media_subdev *imxsd) 243 + { 244 + struct v4l2_subdev *sd = imxsd->sd; 245 + const struct internal_subdev *intsd; 246 + const struct internal_pad *intpad; 247 + const struct internal_link *link; 248 + struct media_pad *pad; 249 + int i, j, ret; 250 + 251 + intsd = find_intsd_by_grp_id(imxsd->sd->grp_id); 252 + if (!intsd) 253 + return -ENODEV; 254 + 255 + /* create the source->sink links */ 256 + for (i = 0; i < sd->entity.num_pads; i++) { 257 + intpad = &intsd->pad[i]; 258 + pad = &sd->entity.pads[i]; 259 + 260 + if (!(pad->flags & MEDIA_PAD_FL_SOURCE)) 261 + continue; 210 262 211 263 for (j = 0; ; j++) { 212 - const struct internal_link *link; 213 - char remote_devname[32]; 214 - 215 264 link = &intpad->link[j]; 216 265 217 - if (!link->remote_id) 266 + if (!link->remote) 218 267 break; 219 268 220 - isd_id_to_devname(remote_devname, 221 - sizeof(remote_devname), 222 - link->remote_id, ipu_id); 223 - 224 - ret = imx_media_add_pad_link(imxmd, pad, 225 - NULL, remote_devname, 226 - i, link->remote_pad); 269 + ret = create_ipu_internal_link(imxmd, imxsd, link); 227 270 if (ret) 228 271 return ret; 229 272 } ··· 279 230 } 280 231 281 232 /* register an internal subdev as a platform device */ 282 - static struct imx_media_subdev * 283 - add_internal_subdev(struct imx_media_dev *imxmd, 284 - const struct internal_subdev *isd, 285 - int ipu_id) 233 + static int add_internal_subdev(struct imx_media_dev *imxmd, 234 + const struct internal_subdev *isd, 235 + int ipu_id) 286 236 { 287 237 struct imx_media_internal_sd_platformdata pdata; 288 238 struct platform_device_info pdevinfo = {0}; ··· 306 258 307 259 pdev = platform_device_register_full(&pdevinfo); 308 260 if (IS_ERR(pdev)) 309 - return ERR_CAST(pdev); 261 + return PTR_ERR(pdev); 310 262 311 263 imxsd = imx_media_add_async_subdev(imxmd, NULL, pdev); 312 264 if (IS_ERR(imxsd)) 313 - return imxsd; 265 + return PTR_ERR(imxsd); 314 266 315 267 imxsd->num_sink_pads = isd->num_sink_pads; 316 268 imxsd->num_src_pads = isd->num_src_pads; 317 269 318 - return imxsd; 270 + return 0; 319 271 } 320 272 321 273 /* adds the internal subdevs in one ipu */ 322 - static int add_ipu_internal_subdevs(struct imx_media_dev *imxmd, 323 - struct imx_media_subdev *csi0, 324 - struct imx_media_subdev *csi1, 325 - int ipu_id) 274 + static int add_ipu_internal_subdevs(struct imx_media_dev *imxmd, int ipu_id) 326 275 { 327 276 enum isd_enum i; 328 - int ret; 329 277 330 278 for (i = 0; i < num_isd; i++) { 331 - const struct internal_subdev *isd = &internal_subdev[i]; 332 - struct imx_media_subdev *imxsd; 279 + const struct internal_subdev *isd = &int_subdev[i]; 280 + int ret; 333 281 334 282 /* 335 283 * the CSIs are represented in the device-tree, so those 336 - * devices are added already, and are added to the async 337 - * subdev list by of_parse_subdev(), so we are given those 338 - * subdevs as csi0 and csi1. 284 + * devices are already added to the async subdev list by 285 + * of_parse_subdev(). 339 286 */ 340 287 switch (isd->id->grp_id) { 341 288 case IMX_MEDIA_GRP_ID_CSI0: 342 - imxsd = csi0; 343 - break; 344 289 case IMX_MEDIA_GRP_ID_CSI1: 345 - imxsd = csi1; 290 + ret = 0; 346 291 break; 347 292 default: 348 - imxsd = add_internal_subdev(imxmd, isd, ipu_id); 293 + ret = add_internal_subdev(imxmd, isd, ipu_id); 349 294 break; 350 295 } 351 296 352 - if (IS_ERR(imxsd)) 353 - return PTR_ERR(imxsd); 354 - 355 - /* add the links from this subdev */ 356 - if (imxsd) { 357 - ret = add_internal_links(imxmd, isd, imxsd, ipu_id); 358 - if (ret) 359 - return ret; 360 - } 297 + if (ret) 298 + return ret; 361 299 } 362 300 363 301 return 0; 364 302 } 365 303 366 - int imx_media_add_internal_subdevs(struct imx_media_dev *imxmd, 367 - struct imx_media_subdev *csi[4]) 304 + int imx_media_add_internal_subdevs(struct imx_media_dev *imxmd) 368 305 { 369 306 int ret; 370 307 371 - ret = add_ipu_internal_subdevs(imxmd, csi[0], csi[1], 0); 308 + ret = add_ipu_internal_subdevs(imxmd, 0); 372 309 if (ret) 373 310 goto remove; 374 311 375 - ret = add_ipu_internal_subdevs(imxmd, csi[2], csi[3], 1); 312 + ret = add_ipu_internal_subdevs(imxmd, 1); 376 313 if (ret) 377 314 goto remove; 378 315
+125 -72
drivers/staging/media/imx/imx-media-of.c
··· 20 20 #include <video/imx-ipu-v3.h> 21 21 #include "imx-media.h" 22 22 23 - static int of_add_pad_link(struct imx_media_dev *imxmd, 24 - struct imx_media_pad *pad, 25 - struct device_node *local_sd_node, 26 - struct device_node *remote_sd_node, 27 - int local_pad, int remote_pad) 28 - { 29 - dev_dbg(imxmd->md.dev, "%s: adding %s:%d -> %s:%d\n", __func__, 30 - local_sd_node->name, local_pad, 31 - remote_sd_node->name, remote_pad); 32 - 33 - return imx_media_add_pad_link(imxmd, pad, remote_sd_node, NULL, 34 - local_pad, remote_pad); 35 - } 36 - 37 23 static int of_get_port_count(const struct device_node *np) 38 24 { 39 25 struct device_node *ports, *child; ··· 39 53 } 40 54 41 55 /* 42 - * find the remote device node and remote port id (remote pad #) 43 - * given local endpoint node 56 + * find the remote device node given local endpoint node 44 57 */ 45 - static void of_get_remote_pad(struct device_node *epnode, 46 - struct device_node **remote_node, 47 - int *remote_pad) 58 + static void of_get_remote(struct device_node *epnode, 59 + struct device_node **remote_node) 48 60 { 49 61 struct device_node *rp, *rpp; 50 62 struct device_node *remote; ··· 53 69 if (of_device_is_compatible(rpp, "fsl,imx6q-ipu")) { 54 70 /* the remote is one of the CSI ports */ 55 71 remote = rp; 56 - *remote_pad = 0; 57 72 of_node_put(rpp); 58 73 } else { 59 74 remote = rpp; 60 - if (of_property_read_u32(rp, "reg", remote_pad)) 61 - *remote_pad = 0; 62 75 of_node_put(rp); 63 76 } 64 77 ··· 69 88 70 89 static int 71 90 of_parse_subdev(struct imx_media_dev *imxmd, struct device_node *sd_np, 72 - bool is_csi_port, struct imx_media_subdev **subdev) 91 + bool is_csi_port) 73 92 { 74 93 struct imx_media_subdev *imxsd; 75 94 int i, num_pads, ret; ··· 77 96 if (!of_device_is_available(sd_np)) { 78 97 dev_dbg(imxmd->md.dev, "%s: %s not enabled\n", __func__, 79 98 sd_np->name); 80 - *subdev = NULL; 81 99 /* unavailable is not an error */ 82 100 return 0; 83 101 } ··· 87 107 if (ret) { 88 108 if (ret == -EEXIST) { 89 109 /* already added, everything is fine */ 90 - *subdev = NULL; 91 110 return 0; 92 111 } 93 112 94 113 /* other error, can't continue */ 95 114 return ret; 96 115 } 97 - *subdev = imxsd; 98 116 99 117 if (is_csi_port) { 100 118 /* ··· 138 160 139 161 for (i = 0; i < num_pads; i++) { 140 162 struct device_node *epnode = NULL, *port, *remote_np; 141 - struct imx_media_subdev *remote_imxsd; 142 - struct imx_media_pad *pad; 143 - int remote_pad; 144 - 145 - /* init this pad */ 146 - pad = &imxsd->pad[i]; 147 - pad->pad.flags = (i < imxsd->num_sink_pads) ? 148 - MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE; 149 163 150 164 if (is_csi_port) 151 165 port = (i < imxsd->num_sink_pads) ? sd_np : NULL; ··· 147 177 continue; 148 178 149 179 for_each_child_of_node(port, epnode) { 150 - of_get_remote_pad(epnode, &remote_np, &remote_pad); 180 + of_get_remote(epnode, &remote_np); 151 181 if (!remote_np) 152 182 continue; 153 183 154 - ret = of_add_pad_link(imxmd, pad, sd_np, remote_np, 155 - i, remote_pad); 156 - if (ret) 157 - break; 158 - 159 184 if (i < imxsd->num_sink_pads) { 160 185 /* follow sink endpoints upstream */ 161 - ret = of_parse_subdev(imxmd, remote_np, 162 - false, &remote_imxsd); 186 + ret = of_parse_subdev(imxmd, remote_np, false); 163 187 if (ret) 164 188 break; 165 189 } ··· 173 209 return ret; 174 210 } 175 211 176 - int imx_media_of_parse(struct imx_media_dev *imxmd, 177 - struct imx_media_subdev *(*csi)[4], 178 - struct device_node *np) 212 + int imx_media_add_of_subdevs(struct imx_media_dev *imxmd, 213 + struct device_node *np) 179 214 { 180 - struct imx_media_subdev *lcsi; 181 215 struct device_node *csi_np; 182 - u32 ipu_id, csi_id; 183 216 int i, ret; 184 217 185 218 for (i = 0; ; i++) { ··· 184 223 if (!csi_np) 185 224 break; 186 225 187 - ret = of_parse_subdev(imxmd, csi_np, true, &lcsi); 188 - if (ret) 189 - goto err_put; 190 - 191 - ret = of_property_read_u32(csi_np, "reg", &csi_id); 192 - if (ret) { 193 - dev_err(imxmd->md.dev, 194 - "%s: csi port missing reg property!\n", 195 - __func__); 196 - goto err_put; 197 - } 198 - 199 - ipu_id = of_alias_get_id(csi_np->parent, "ipu"); 226 + ret = of_parse_subdev(imxmd, csi_np, true); 200 227 of_node_put(csi_np); 201 - 202 - if (ipu_id > 1 || csi_id > 1) { 203 - dev_err(imxmd->md.dev, 204 - "%s: invalid ipu/csi id (%u/%u)\n", 205 - __func__, ipu_id, csi_id); 206 - return -EINVAL; 207 - } 208 - 209 - (*csi)[ipu_id * 2 + csi_id] = lcsi; 228 + if (ret) 229 + return ret; 210 230 } 211 231 212 232 return 0; 213 - err_put: 214 - of_node_put(csi_np); 215 - return ret; 233 + } 234 + 235 + /* 236 + * Create a single media link to/from imxsd using a fwnode link. 237 + * 238 + * NOTE: this function assumes an OF port node is equivalent to 239 + * a media pad (port id equal to media pad index), and that an 240 + * OF endpoint node is equivalent to a media link. 241 + */ 242 + static int create_of_link(struct imx_media_dev *imxmd, 243 + struct imx_media_subdev *imxsd, 244 + struct v4l2_fwnode_link *link) 245 + { 246 + struct v4l2_subdev *sd = imxsd->sd; 247 + struct imx_media_subdev *remote; 248 + struct v4l2_subdev *src, *sink; 249 + int src_pad, sink_pad; 250 + 251 + if (link->local_port >= sd->entity.num_pads) 252 + return -EINVAL; 253 + 254 + remote = imx_media_find_async_subdev(imxmd, 255 + to_of_node(link->remote_node), 256 + NULL); 257 + if (!remote) 258 + return 0; 259 + 260 + if (sd->entity.pads[link->local_port].flags & MEDIA_PAD_FL_SINK) { 261 + src = remote->sd; 262 + src_pad = link->remote_port; 263 + sink = sd; 264 + sink_pad = link->local_port; 265 + } else { 266 + src = sd; 267 + src_pad = link->local_port; 268 + sink = remote->sd; 269 + sink_pad = link->remote_port; 270 + } 271 + 272 + /* make sure link doesn't already exist before creating */ 273 + if (media_entity_find_link(&src->entity.pads[src_pad], 274 + &sink->entity.pads[sink_pad])) 275 + return 0; 276 + 277 + v4l2_info(sd->v4l2_dev, "%s:%d -> %s:%d\n", 278 + src->name, src_pad, sink->name, sink_pad); 279 + 280 + return media_create_pad_link(&src->entity, src_pad, 281 + &sink->entity, sink_pad, 0); 282 + } 283 + 284 + /* 285 + * Create media links to/from imxsd using its device-tree endpoints. 286 + */ 287 + int imx_media_create_of_links(struct imx_media_dev *imxmd, 288 + struct imx_media_subdev *imxsd) 289 + { 290 + struct v4l2_subdev *sd = imxsd->sd; 291 + struct v4l2_fwnode_link link; 292 + struct device_node *ep; 293 + int ret; 294 + 295 + for_each_endpoint_of_node(sd->dev->of_node, ep) { 296 + ret = v4l2_fwnode_parse_link(of_fwnode_handle(ep), &link); 297 + if (ret) 298 + continue; 299 + 300 + ret = create_of_link(imxmd, imxsd, &link); 301 + v4l2_fwnode_put_link(&link); 302 + if (ret) 303 + return ret; 304 + } 305 + 306 + return 0; 307 + } 308 + 309 + /* 310 + * Create media links to the given CSI subdevice's sink pads, 311 + * using its device-tree endpoints. 312 + */ 313 + int imx_media_create_csi_of_links(struct imx_media_dev *imxmd, 314 + struct imx_media_subdev *csi) 315 + { 316 + struct device_node *csi_np = csi->sd->dev->of_node; 317 + struct fwnode_handle *fwnode, *csi_ep; 318 + struct v4l2_fwnode_link link; 319 + struct device_node *ep; 320 + int ret; 321 + 322 + link.local_node = of_fwnode_handle(csi_np); 323 + link.local_port = CSI_SINK_PAD; 324 + 325 + for_each_child_of_node(csi_np, ep) { 326 + csi_ep = of_fwnode_handle(ep); 327 + 328 + fwnode = fwnode_graph_get_remote_endpoint(csi_ep); 329 + if (!fwnode) 330 + continue; 331 + 332 + fwnode = fwnode_get_parent(fwnode); 333 + fwnode_property_read_u32(fwnode, "reg", &link.remote_port); 334 + fwnode = fwnode_get_next_parent(fwnode); 335 + if (is_of_node(fwnode) && 336 + of_node_cmp(to_of_node(fwnode)->name, "ports") == 0) 337 + fwnode = fwnode_get_next_parent(fwnode); 338 + link.remote_node = fwnode; 339 + 340 + ret = create_of_link(imxmd, csi, &link); 341 + fwnode_handle_put(link.remote_node); 342 + if (ret) 343 + return ret; 344 + } 345 + 346 + return 0; 216 347 }
+10 -29
drivers/staging/media/imx/imx-media.h
··· 35 35 #define IMX_MEDIA_MAX_SUBDEVS 32 36 36 /* max pads per subdev */ 37 37 #define IMX_MEDIA_MAX_PADS 16 38 - /* max links per pad */ 39 - #define IMX_MEDIA_MAX_LINKS 8 40 38 41 39 /* 42 40 * Pad definitions for the subdevs with multiple source or ··· 117 119 return container_of(vbuf, struct imx_media_buffer, vbuf); 118 120 } 119 121 120 - struct imx_media_link { 121 - struct device_node *remote_sd_node; 122 - char remote_devname[32]; 123 - int local_pad; 124 - int remote_pad; 125 - }; 126 - 127 122 struct imx_media_pad { 128 - struct media_pad pad; 129 - struct imx_media_link link[IMX_MEDIA_MAX_LINKS]; 130 - bool devnode; /* does this pad link to a device node */ 131 - int num_links; 132 - 133 123 /* 134 124 * list of video devices that can be reached from this pad, 135 125 * list is only valid for source pads. ··· 140 154 int num_sink_pads; 141 155 int num_src_pads; 142 156 143 - /* the platform device if this is an internal subdev */ 157 + /* the platform device if this is an IPU-internal subdev */ 144 158 struct platform_device *pdev; 145 159 /* the devname is needed for async devname match */ 146 160 char devname[32]; ··· 211 225 imx_media_add_async_subdev(struct imx_media_dev *imxmd, 212 226 struct device_node *np, 213 227 struct platform_device *pdev); 214 - int imx_media_add_pad_link(struct imx_media_dev *imxmd, 215 - struct imx_media_pad *pad, 216 - struct device_node *remote_node, 217 - const char *remote_devname, 218 - int local_pad, int remote_pad); 219 228 220 229 void imx_media_grp_id_to_sd_name(char *sd_name, int sz, 221 230 u32 grp_id, int ipu_id); 222 231 223 - int imx_media_add_internal_subdevs(struct imx_media_dev *imxmd, 224 - struct imx_media_subdev *csi[4]); 232 + int imx_media_add_internal_subdevs(struct imx_media_dev *imxmd); 233 + int imx_media_create_internal_links(struct imx_media_dev *imxmd, 234 + struct imx_media_subdev *imxsd); 225 235 void imx_media_remove_internal_subdevs(struct imx_media_dev *imxmd); 226 236 227 237 struct imx_media_subdev * ··· 266 284 void imx_media_fim_free(struct imx_media_fim *fim); 267 285 268 286 /* imx-media-of.c */ 269 - struct imx_media_subdev * 270 - imx_media_of_find_subdev(struct imx_media_dev *imxmd, 271 - struct device_node *np, 272 - const char *name); 273 - int imx_media_of_parse(struct imx_media_dev *dev, 274 - struct imx_media_subdev *(*csi)[4], 275 - struct device_node *np); 287 + int imx_media_add_of_subdevs(struct imx_media_dev *dev, 288 + struct device_node *np); 289 + int imx_media_create_of_links(struct imx_media_dev *imxmd, 290 + struct imx_media_subdev *imxsd); 291 + int imx_media_create_csi_of_links(struct imx_media_dev *imxmd, 292 + struct imx_media_subdev *csi); 276 293 277 294 /* imx-media-capture.c */ 278 295 struct imx_media_video_dev *