forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-05-10 37f49e37ab4cb5d0bc4c60eb5c6d4dd57db767bb
kernel/drivers/staging/media/imx/imx-media-of.c
....@@ -1,14 +1,10 @@
1
+// SPDX-License-Identifier: GPL-2.0+
12 /*
23 * Media driver for Freescale i.MX5/6 SOC
34 *
45 * Open Firmware parsing.
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/of_platform.h>
1410 #include <media/v4l2-ctrls.h>
....@@ -20,121 +16,32 @@
2016 #include <video/imx-ipu-v3.h>
2117 #include "imx-media.h"
2218
23
-static int of_get_port_count(const struct device_node *np)
19
+int imx_media_of_add_csi(struct imx_media_dev *imxmd,
20
+ struct device_node *csi_np)
2421 {
25
- struct device_node *ports, *child;
26
- int num = 0;
22
+ struct v4l2_async_subdev *asd;
23
+ int ret = 0;
2724
28
- /* check if this node has a ports subnode */
29
- ports = of_get_child_by_name(np, "ports");
30
- if (ports)
31
- np = ports;
32
-
33
- for_each_child_of_node(np, child)
34
- if (of_node_cmp(child->name, "port") == 0)
35
- num++;
36
-
37
- of_node_put(ports);
38
- return num;
39
-}
40
-
41
-/*
42
- * find the remote device node given local endpoint node
43
- */
44
-static bool of_get_remote(struct device_node *epnode,
45
- struct device_node **remote_node)
46
-{
47
- struct device_node *rp, *rpp;
48
- struct device_node *remote;
49
- bool is_csi_port;
50
-
51
- rp = of_graph_get_remote_port(epnode);
52
- rpp = of_graph_get_remote_port_parent(epnode);
53
-
54
- if (of_device_is_compatible(rpp, "fsl,imx6q-ipu")) {
55
- /* the remote is one of the CSI ports */
56
- remote = rp;
57
- of_node_put(rpp);
58
- is_csi_port = true;
59
- } else {
60
- remote = rpp;
61
- of_node_put(rp);
62
- is_csi_port = false;
25
+ if (!of_device_is_available(csi_np)) {
26
+ dev_dbg(imxmd->md.dev, "%s: %pOFn not enabled\n", __func__,
27
+ csi_np);
28
+ return -ENODEV;
6329 }
6430
65
- if (!of_device_is_available(remote)) {
66
- of_node_put(remote);
67
- *remote_node = NULL;
68
- } else {
69
- *remote_node = remote;
70
- }
71
-
72
- return is_csi_port;
73
-}
74
-
75
-static int
76
-of_parse_subdev(struct imx_media_dev *imxmd, struct device_node *sd_np,
77
- bool is_csi_port)
78
-{
79
- int i, num_ports, ret;
80
-
81
- if (!of_device_is_available(sd_np)) {
82
- dev_dbg(imxmd->md.dev, "%s: %s not enabled\n", __func__,
83
- sd_np->name);
84
- /* unavailable is not an error */
85
- return 0;
86
- }
87
-
88
- /* register this subdev with async notifier */
89
- ret = imx_media_add_async_subdev(imxmd, of_fwnode_handle(sd_np),
90
- NULL);
91
- if (ret) {
92
- if (ret == -EEXIST) {
93
- /* already added, everything is fine */
94
- return 0;
95
- }
96
-
97
- /* other error, can't continue */
98
- return ret;
99
- }
100
-
101
- /*
102
- * the ipu-csi has one sink port. The source pads are not
103
- * represented in the device tree by port nodes, but are
104
- * described by the internal pads and links later.
105
- */
106
- num_ports = is_csi_port ? 1 : of_get_port_count(sd_np);
107
-
108
- for (i = 0; i < num_ports; i++) {
109
- struct device_node *epnode = NULL, *port, *remote_np;
110
-
111
- port = is_csi_port ? sd_np : of_graph_get_port_by_id(sd_np, i);
112
- if (!port)
113
- continue;
114
-
115
- for_each_child_of_node(port, epnode) {
116
- bool remote_is_csi;
117
-
118
- remote_is_csi = of_get_remote(epnode, &remote_np);
119
- if (!remote_np)
120
- continue;
121
-
122
- ret = of_parse_subdev(imxmd, remote_np, remote_is_csi);
123
- of_node_put(remote_np);
124
- if (ret)
125
- break;
126
- }
127
-
128
- if (port != sd_np)
129
- of_node_put(port);
130
- if (ret) {
131
- of_node_put(epnode);
132
- break;
133
- }
31
+ /* add CSI fwnode to async notifier */
32
+ asd = v4l2_async_notifier_add_fwnode_subdev(&imxmd->notifier,
33
+ of_fwnode_handle(csi_np),
34
+ sizeof(*asd));
35
+ if (IS_ERR(asd)) {
36
+ ret = PTR_ERR(asd);
37
+ if (ret == -EEXIST)
38
+ dev_dbg(imxmd->md.dev, "%s: already added %pOFn\n",
39
+ __func__, csi_np);
13440 }
13541
13642 return ret;
13743 }
44
+EXPORT_SYMBOL_GPL(imx_media_of_add_csi);
13845
13946 int imx_media_add_of_subdevs(struct imx_media_dev *imxmd,
14047 struct device_node *np)
....@@ -147,123 +54,23 @@
14754 if (!csi_np)
14855 break;
14956
150
- ret = of_parse_subdev(imxmd, csi_np, true);
151
- of_node_put(csi_np);
152
- if (ret)
153
- return ret;
57
+ ret = imx_media_of_add_csi(imxmd, csi_np);
58
+ if (ret) {
59
+ /* unavailable or already added is not an error */
60
+ if (ret == -ENODEV || ret == -EEXIST) {
61
+ of_node_put(csi_np);
62
+ continue;
63
+ }
64
+
65
+ /* other error, can't continue */
66
+ goto err_out;
67
+ }
15468 }
15569
15670 return 0;
71
+
72
+err_out:
73
+ of_node_put(csi_np);
74
+ return ret;
15775 }
158
-
159
-/*
160
- * Create a single media link to/from sd using a fwnode link.
161
- *
162
- * NOTE: this function assumes an OF port node is equivalent to
163
- * a media pad (port id equal to media pad index), and that an
164
- * OF endpoint node is equivalent to a media link.
165
- */
166
-static int create_of_link(struct imx_media_dev *imxmd,
167
- struct v4l2_subdev *sd,
168
- struct v4l2_fwnode_link *link)
169
-{
170
- struct v4l2_subdev *remote, *src, *sink;
171
- int src_pad, sink_pad;
172
-
173
- if (link->local_port >= sd->entity.num_pads)
174
- return -EINVAL;
175
-
176
- remote = imx_media_find_subdev_by_fwnode(imxmd, link->remote_node);
177
- if (!remote)
178
- return 0;
179
-
180
- if (sd->entity.pads[link->local_port].flags & MEDIA_PAD_FL_SINK) {
181
- src = remote;
182
- src_pad = link->remote_port;
183
- sink = sd;
184
- sink_pad = link->local_port;
185
- } else {
186
- src = sd;
187
- src_pad = link->local_port;
188
- sink = remote;
189
- sink_pad = link->remote_port;
190
- }
191
-
192
- /* make sure link doesn't already exist before creating */
193
- if (media_entity_find_link(&src->entity.pads[src_pad],
194
- &sink->entity.pads[sink_pad]))
195
- return 0;
196
-
197
- v4l2_info(sd->v4l2_dev, "%s:%d -> %s:%d\n",
198
- src->name, src_pad, sink->name, sink_pad);
199
-
200
- return media_create_pad_link(&src->entity, src_pad,
201
- &sink->entity, sink_pad, 0);
202
-}
203
-
204
-/*
205
- * Create media links to/from sd using its device-tree endpoints.
206
- */
207
-int imx_media_create_of_links(struct imx_media_dev *imxmd,
208
- struct v4l2_subdev *sd)
209
-{
210
- struct v4l2_fwnode_link link;
211
- struct device_node *ep;
212
- int ret;
213
-
214
- for_each_endpoint_of_node(sd->dev->of_node, ep) {
215
- ret = v4l2_fwnode_parse_link(of_fwnode_handle(ep), &link);
216
- if (ret)
217
- continue;
218
-
219
- ret = create_of_link(imxmd, sd, &link);
220
- v4l2_fwnode_put_link(&link);
221
- if (ret)
222
- return ret;
223
- }
224
-
225
- return 0;
226
-}
227
-
228
-/*
229
- * Create media links to the given CSI subdevice's sink pads,
230
- * using its device-tree endpoints.
231
- */
232
-int imx_media_create_csi_of_links(struct imx_media_dev *imxmd,
233
- struct v4l2_subdev *csi)
234
-{
235
- struct device_node *csi_np = csi->dev->of_node;
236
- struct device_node *ep;
237
-
238
- for_each_child_of_node(csi_np, ep) {
239
- struct fwnode_handle *fwnode, *csi_ep;
240
- struct v4l2_fwnode_link link;
241
- int ret;
242
-
243
- memset(&link, 0, sizeof(link));
244
-
245
- link.local_node = of_fwnode_handle(csi_np);
246
- link.local_port = CSI_SINK_PAD;
247
-
248
- csi_ep = of_fwnode_handle(ep);
249
-
250
- fwnode = fwnode_graph_get_remote_endpoint(csi_ep);
251
- if (!fwnode)
252
- continue;
253
-
254
- fwnode = fwnode_get_parent(fwnode);
255
- fwnode_property_read_u32(fwnode, "reg", &link.remote_port);
256
- fwnode = fwnode_get_next_parent(fwnode);
257
- if (is_of_node(fwnode) &&
258
- of_node_cmp(to_of_node(fwnode)->name, "ports") == 0)
259
- fwnode = fwnode_get_next_parent(fwnode);
260
- link.remote_node = fwnode;
261
-
262
- ret = create_of_link(imxmd, csi, &link);
263
- fwnode_handle_put(link.remote_node);
264
- if (ret)
265
- return ret;
266
- }
267
-
268
- return 0;
269
-}
76
+EXPORT_SYMBOL_GPL(imx_media_add_of_subdevs);