hc
2023-12-11 d2ccde1c8e90d38cee87a1b0309ad2827f3fd30d
kernel/drivers/staging/media/imx/imx-media-internal-sd.c
....@@ -1,246 +1,168 @@
1
+// SPDX-License-Identifier: GPL-2.0+
12 /*
23 * Media driver for Freescale i.MX5/6 SOC
34 *
4
- * Adds the internal subdevices and the media links between them.
5
+ * Adds the IPU internal subdevices and the media links between them.
56 *
67 * Copyright (c) 2016 Mentor Graphics Inc.
7
- *
8
- * This program is free software; you can redistribute it and/or modify
9
- * it under the terms of the GNU General Public License as published by
10
- * the Free Software Foundation; either version 2 of the License, or
11
- * (at your option) any later version.
128 */
139 #include <linux/platform_device.h>
1410 #include "imx-media.h"
15
-
16
-enum isd_enum {
17
- isd_csi0 = 0,
18
- isd_csi1,
19
- isd_vdic,
20
- isd_ic_prp,
21
- isd_ic_prpenc,
22
- isd_ic_prpvf,
23
- num_isd,
24
-};
25
-
26
-static const struct internal_subdev_id {
27
- enum isd_enum index;
28
- const char *name;
29
- u32 grp_id;
30
-} isd_id[num_isd] = {
31
- [isd_csi0] = {
32
- .index = isd_csi0,
33
- .grp_id = IMX_MEDIA_GRP_ID_CSI0,
34
- .name = "imx-ipuv3-csi",
35
- },
36
- [isd_csi1] = {
37
- .index = isd_csi1,
38
- .grp_id = IMX_MEDIA_GRP_ID_CSI1,
39
- .name = "imx-ipuv3-csi",
40
- },
41
- [isd_vdic] = {
42
- .index = isd_vdic,
43
- .grp_id = IMX_MEDIA_GRP_ID_VDIC,
44
- .name = "imx-ipuv3-vdic",
45
- },
46
- [isd_ic_prp] = {
47
- .index = isd_ic_prp,
48
- .grp_id = IMX_MEDIA_GRP_ID_IC_PRP,
49
- .name = "imx-ipuv3-ic",
50
- },
51
- [isd_ic_prpenc] = {
52
- .index = isd_ic_prpenc,
53
- .grp_id = IMX_MEDIA_GRP_ID_IC_PRPENC,
54
- .name = "imx-ipuv3-ic",
55
- },
56
- [isd_ic_prpvf] = {
57
- .index = isd_ic_prpvf,
58
- .grp_id = IMX_MEDIA_GRP_ID_IC_PRPVF,
59
- .name = "imx-ipuv3-ic",
60
- },
61
-};
62
-
63
-struct internal_subdev;
64
-
65
-struct internal_link {
66
- const struct internal_subdev *remote;
67
- int local_pad;
68
- int remote_pad;
69
-};
7011
7112 /* max pads per internal-sd */
7213 #define MAX_INTERNAL_PADS 8
7314 /* max links per internal-sd pad */
7415 #define MAX_INTERNAL_LINKS 8
7516
17
+struct internal_subdev;
18
+
19
+struct internal_link {
20
+ int remote;
21
+ int local_pad;
22
+ int remote_pad;
23
+};
24
+
7625 struct internal_pad {
26
+ int num_links;
7727 struct internal_link link[MAX_INTERNAL_LINKS];
7828 };
7929
80
-static const struct internal_subdev {
81
- const struct internal_subdev_id *id;
30
+struct internal_subdev {
31
+ u32 grp_id;
8232 struct internal_pad pad[MAX_INTERNAL_PADS];
83
-} int_subdev[num_isd] = {
84
- [isd_csi0] = {
85
- .id = &isd_id[isd_csi0],
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,
8644 .pad[CSI_SRC_PAD_DIRECT] = {
45
+ .num_links = 2,
8746 .link = {
8847 {
8948 .local_pad = CSI_SRC_PAD_DIRECT,
90
- .remote = &int_subdev[isd_ic_prp],
49
+ .remote = IPU_IC_PRP,
9150 .remote_pad = PRP_SINK_PAD,
9251 }, {
9352 .local_pad = CSI_SRC_PAD_DIRECT,
94
- .remote = &int_subdev[isd_vdic],
53
+ .remote = IPU_VDIC,
9554 .remote_pad = VDIC_SINK_PAD_DIRECT,
9655 },
9756 },
9857 },
9958 },
10059
101
- [isd_csi1] = {
102
- .id = &isd_id[isd_csi1],
60
+ [IPU_CSI1] = {
61
+ .grp_id = IMX_MEDIA_GRP_ID_IPU_CSI1,
10362 .pad[CSI_SRC_PAD_DIRECT] = {
63
+ .num_links = 2,
10464 .link = {
10565 {
10666 .local_pad = CSI_SRC_PAD_DIRECT,
107
- .remote = &int_subdev[isd_ic_prp],
67
+ .remote = IPU_IC_PRP,
10868 .remote_pad = PRP_SINK_PAD,
10969 }, {
11070 .local_pad = CSI_SRC_PAD_DIRECT,
111
- .remote = &int_subdev[isd_vdic],
71
+ .remote = IPU_VDIC,
11272 .remote_pad = VDIC_SINK_PAD_DIRECT,
11373 },
11474 },
11575 },
11676 },
11777
118
- [isd_vdic] = {
119
- .id = &isd_id[isd_vdic],
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,
12082 .pad[VDIC_SRC_PAD_DIRECT] = {
83
+ .num_links = 1,
12184 .link = {
12285 {
12386 .local_pad = VDIC_SRC_PAD_DIRECT,
124
- .remote = &int_subdev[isd_ic_prp],
87
+ .remote = IPU_IC_PRP,
12588 .remote_pad = PRP_SINK_PAD,
12689 },
12790 },
12891 },
12992 },
13093
131
- [isd_ic_prp] = {
132
- .id = &isd_id[isd_ic_prp],
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,
13398 .pad[PRP_SRC_PAD_PRPENC] = {
99
+ .num_links = 1,
134100 .link = {
135101 {
136102 .local_pad = PRP_SRC_PAD_PRPENC,
137
- .remote = &int_subdev[isd_ic_prpenc],
138
- .remote_pad = 0,
103
+ .remote = IPU_IC_PRPENC,
104
+ .remote_pad = PRPENCVF_SINK_PAD,
139105 },
140106 },
141107 },
142108 .pad[PRP_SRC_PAD_PRPVF] = {
109
+ .num_links = 1,
143110 .link = {
144111 {
145112 .local_pad = PRP_SRC_PAD_PRPVF,
146
- .remote = &int_subdev[isd_ic_prpvf],
147
- .remote_pad = 0,
113
+ .remote = IPU_IC_PRPVF,
114
+ .remote_pad = PRPENCVF_SINK_PAD,
148115 },
149116 },
150117 },
151118 },
152119
153
- [isd_ic_prpenc] = {
154
- .id = &isd_id[isd_ic_prpenc],
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,
155124 },
156125
157
- [isd_ic_prpvf] = {
158
- .id = &isd_id[isd_ic_prpvf],
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,
159130 },
160131 };
161132
162
-/* form a device name given an internal subdev and ipu id */
163
-static inline void isd_to_devname(char *devname, int sz,
164
- const struct internal_subdev *isd,
165
- int ipu_id)
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)
166137 {
167
- int pdev_id = ipu_id * num_isd + isd->id->index;
168
-
169
- snprintf(devname, sz, "%s.%d", isd->id->name, pdev_id);
170
-}
171
-
172
-static const struct internal_subdev *find_intsd_by_grp_id(u32 grp_id)
173
-{
174
- enum isd_enum i;
175
-
176
- for (i = 0; i < num_isd; i++) {
177
- const struct internal_subdev *isd = &int_subdev[i];
178
-
179
- if (isd->id->grp_id == grp_id)
180
- return isd;
181
- }
182
-
183
- return NULL;
184
-}
185
-
186
-static struct v4l2_subdev *find_sink(struct imx_media_dev *imxmd,
187
- struct v4l2_subdev *src,
188
- const struct internal_link *link)
189
-{
190
- char sink_devname[32];
191
- int ipu_id;
192
-
193
- /*
194
- * retrieve IPU id from subdev name, note: can't get this from
195
- * struct imx_media_internal_sd_platformdata because if src is
196
- * a CSI, it has different struct ipu_client_platformdata which
197
- * does not contain IPU id.
198
- */
199
- if (sscanf(src->name, "ipu%d", &ipu_id) != 1)
200
- return NULL;
201
-
202
- isd_to_devname(sink_devname, sizeof(sink_devname),
203
- link->remote, ipu_id - 1);
204
-
205
- return imx_media_find_subdev_by_devname(imxmd, sink_devname);
206
-}
207
-
208
-static int create_ipu_internal_link(struct imx_media_dev *imxmd,
209
- struct v4l2_subdev *src,
210
- const struct internal_link *link)
211
-{
212
- struct v4l2_subdev *sink;
213138 int ret;
214139
215
- sink = find_sink(imxmd, src, link);
216
- if (!sink)
217
- return -ENODEV;
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;
218144
219
- v4l2_info(&imxmd->v4l2_dev, "%s:%d -> %s:%d\n",
220
- src->name, link->local_pad,
221
- sink->name, link->remote_pad);
145
+ dev_dbg(imxmd->md.dev, "%s:%d -> %s:%d\n",
146
+ src->name, link->local_pad,
147
+ sink->name, link->remote_pad);
222148
223149 ret = media_create_pad_link(&src->entity, link->local_pad,
224150 &sink->entity, link->remote_pad, 0);
225151 if (ret)
226
- v4l2_err(&imxmd->v4l2_dev,
227
- "create_pad_link failed: %d\n", ret);
152
+ v4l2_err(&imxmd->v4l2_dev, "%s failed: %d\n", __func__, ret);
228153
229154 return ret;
230155 }
231156
232
-int imx_media_create_internal_links(struct imx_media_dev *imxmd,
233
- struct v4l2_subdev *sd)
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)
234161 {
235
- const struct internal_subdev *intsd;
236162 const struct internal_pad *intpad;
237163 const struct internal_link *link;
238164 struct media_pad *pad;
239165 int i, j, ret;
240
-
241
- intsd = find_intsd_by_grp_id(sd->grp_id);
242
- if (!intsd)
243
- return -ENODEV;
244166
245167 /* create the source->sink links */
246168 for (i = 0; i < sd->entity.num_pads; i++) {
....@@ -250,13 +172,13 @@
250172 if (!(pad->flags & MEDIA_PAD_FL_SOURCE))
251173 continue;
252174
253
- for (j = 0; ; j++) {
175
+ for (j = 0; j < intpad->num_links; j++) {
176
+ struct v4l2_subdev *sink;
177
+
254178 link = &intpad->link[j];
179
+ sink = imxmd->sync_sd[ipu_id][link->remote];
255180
256
- if (!link->remote)
257
- break;
258
-
259
- ret = create_ipu_internal_link(imxmd, sd, link);
181
+ ret = create_internal_link(imxmd, sd, sink, link);
260182 if (ret)
261183 return ret;
262184 }
....@@ -265,96 +187,120 @@
265187 return 0;
266188 }
267189
268
-/* register an internal subdev as a platform device */
269
-static int add_internal_subdev(struct imx_media_dev *imxmd,
270
- const struct internal_subdev *isd,
271
- int ipu_id)
190
+int imx_media_register_ipu_internal_subdevs(struct imx_media_dev *imxmd,
191
+ struct v4l2_subdev *csi)
272192 {
273
- struct imx_media_internal_sd_platformdata pdata;
274
- struct platform_device_info pdevinfo = {};
275
- struct platform_device *pdev;
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;
276198
277
- pdata.grp_id = isd->id->grp_id;
278
-
279
- /* the id of IPU this subdev will control */
280
- pdata.ipu_id = ipu_id;
281
-
282
- /* create subdev name */
283
- imx_media_grp_id_to_sd_name(pdata.sd_name, sizeof(pdata.sd_name),
284
- pdata.grp_id, ipu_id);
285
-
286
- pdevinfo.name = isd->id->name;
287
- pdevinfo.id = ipu_id * num_isd + isd->id->index;
288
- pdevinfo.parent = imxmd->md.dev;
289
- pdevinfo.data = &pdata;
290
- pdevinfo.size_data = sizeof(pdata);
291
- pdevinfo.dma_mask = DMA_BIT_MASK(32);
292
-
293
- pdev = platform_device_register_full(&pdevinfo);
294
- if (IS_ERR(pdev))
295
- return PTR_ERR(pdev);
296
-
297
- return imx_media_add_async_subdev(imxmd, NULL, pdev);
298
-}
299
-
300
-/* adds the internal subdevs in one ipu */
301
-static int add_ipu_internal_subdevs(struct imx_media_dev *imxmd, int ipu_id)
302
-{
303
- enum isd_enum i;
304
-
305
- for (i = 0; i < num_isd; i++) {
306
- const struct internal_subdev *isd = &int_subdev[i];
307
- int ret;
308
-
309
- /*
310
- * the CSIs are represented in the device-tree, so those
311
- * devices are already added to the async subdev list by
312
- * of_parse_subdev().
313
- */
314
- switch (isd->id->grp_id) {
315
- case IMX_MEDIA_GRP_ID_CSI0:
316
- case IMX_MEDIA_GRP_ID_CSI1:
317
- ret = 0;
318
- break;
319
- default:
320
- ret = add_internal_subdev(imxmd, isd, ipu_id);
321
- break;
322
- }
323
-
324
- if (ret)
325
- return ret;
199
+ ipu = dev_get_drvdata(ipu_dev);
200
+ if (!ipu) {
201
+ v4l2_err(&imxmd->v4l2_dev, "invalid IPU device!\n");
202
+ return -ENODEV;
326203 }
327204
328
- return 0;
329
-}
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
+ }
330210
331
-int imx_media_add_internal_subdevs(struct imx_media_dev *imxmd)
332
-{
333
- int ret;
211
+ mutex_lock(&imxmd->mutex);
334212
335
- ret = add_ipu_internal_subdevs(imxmd, 0);
336
- if (ret)
337
- goto remove;
213
+ /* record this IPU */
214
+ if (!imxmd->ipu[ipu_id])
215
+ imxmd->ipu[ipu_id] = ipu;
338216
339
- ret = add_ipu_internal_subdevs(imxmd, 1);
340
- if (ret)
341
- goto remove;
217
+ /* register the synchronous subdevs */
218
+ for (i = 0; i < NUM_IPU_SUBDEVS; i++) {
219
+ intsd = &int_subdev[i];
342220
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);
343266 return 0;
344267
345
-remove:
346
- imx_media_remove_internal_subdevs(imxmd);
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);
347280 return ret;
348281 }
349282
350
-void imx_media_remove_internal_subdevs(struct imx_media_dev *imxmd)
283
+void imx_media_unregister_ipu_internal_subdevs(struct imx_media_dev *imxmd)
351284 {
352
- struct imx_media_async_subdev *imxasd;
285
+ const struct internal_subdev *intsd;
286
+ struct v4l2_subdev *sd;
287
+ int i, j;
353288
354
- list_for_each_entry(imxasd, &imxmd->asd_list, list) {
355
- if (!imxasd->pdev)
356
- continue;
289
+ mutex_lock(&imxmd->mutex);
357290
358
- platform_device_unregister(imxasd->pdev);
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
+ }
359303 }
304
+
305
+ mutex_unlock(&imxmd->mutex);
360306 }