GNU Linux-libre 4.14.290-gnu1
[releases.git] / drivers / staging / media / imx / imx-media-of.c
1 /*
2  * Media driver for Freescale i.MX5/6 SOC
3  *
4  * Open Firmware parsing.
5  *
6  * 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.
12  */
13 #include <linux/of_platform.h>
14 #include <media/v4l2-ctrls.h>
15 #include <media/v4l2-device.h>
16 #include <media/v4l2-fwnode.h>
17 #include <media/v4l2-subdev.h>
18 #include <media/videobuf2-dma-contig.h>
19 #include <linux/of_graph.h>
20 #include <video/imx-ipu-v3.h>
21 #include "imx-media.h"
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 static void of_parse_sensor(struct imx_media_dev *imxmd,
38                             struct imx_media_subdev *sensor,
39                             struct device_node *sensor_np)
40 {
41         struct device_node *endpoint;
42
43         endpoint = of_graph_get_next_endpoint(sensor_np, NULL);
44         if (endpoint) {
45                 v4l2_fwnode_endpoint_parse(of_fwnode_handle(endpoint),
46                                            &sensor->sensor_ep);
47                 of_node_put(endpoint);
48         }
49 }
50
51 static int of_get_port_count(const struct device_node *np)
52 {
53         struct device_node *ports, *child;
54         int num = 0;
55
56         /* check if this node has a ports subnode */
57         ports = of_get_child_by_name(np, "ports");
58         if (ports)
59                 np = ports;
60
61         for_each_child_of_node(np, child)
62                 if (of_node_cmp(child->name, "port") == 0)
63                         num++;
64
65         of_node_put(ports);
66         return num;
67 }
68
69 /*
70  * find the remote device node and remote port id (remote pad #)
71  * given local endpoint node
72  */
73 static void of_get_remote_pad(struct device_node *epnode,
74                               struct device_node **remote_node,
75                               int *remote_pad)
76 {
77         struct device_node *rp, *rpp;
78         struct device_node *remote;
79
80         rp = of_graph_get_remote_port(epnode);
81         rpp = of_graph_get_remote_port_parent(epnode);
82
83         if (of_device_is_compatible(rpp, "fsl,imx6q-ipu")) {
84                 /* the remote is one of the CSI ports */
85                 remote = rp;
86                 *remote_pad = 0;
87                 of_node_put(rpp);
88         } else {
89                 remote = rpp;
90                 if (of_property_read_u32(rp, "reg", remote_pad))
91                         *remote_pad = 0;
92                 of_node_put(rp);
93         }
94
95         if (!of_device_is_available(remote)) {
96                 of_node_put(remote);
97                 *remote_node = NULL;
98         } else {
99                 *remote_node = remote;
100         }
101 }
102
103 static int
104 of_parse_subdev(struct imx_media_dev *imxmd, struct device_node *sd_np,
105                 bool is_csi_port, struct imx_media_subdev **subdev)
106 {
107         struct imx_media_subdev *imxsd;
108         int i, num_pads, ret;
109
110         if (!of_device_is_available(sd_np)) {
111                 dev_dbg(imxmd->md.dev, "%s: %s not enabled\n", __func__,
112                         sd_np->name);
113                 *subdev = NULL;
114                 /* unavailable is not an error */
115                 return 0;
116         }
117
118         /* register this subdev with async notifier */
119         imxsd = imx_media_add_async_subdev(imxmd, sd_np, NULL);
120         ret = PTR_ERR_OR_ZERO(imxsd);
121         if (ret) {
122                 if (ret == -EEXIST) {
123                         /* already added, everything is fine */
124                         *subdev = NULL;
125                         return 0;
126                 }
127
128                 /* other error, can't continue */
129                 return ret;
130         }
131         *subdev = imxsd;
132
133         if (is_csi_port) {
134                 /*
135                  * the ipu-csi has one sink port and two source ports.
136                  * The source ports are not represented in the device tree,
137                  * but are described by the internal pads and links later.
138                  */
139                 num_pads = CSI_NUM_PADS;
140                 imxsd->num_sink_pads = CSI_NUM_SINK_PADS;
141         } else if (of_device_is_compatible(sd_np, "fsl,imx6-mipi-csi2")) {
142                 num_pads = of_get_port_count(sd_np);
143                 /* the mipi csi2 receiver has only one sink port */
144                 imxsd->num_sink_pads = 1;
145         } else if (of_device_is_compatible(sd_np, "video-mux")) {
146                 num_pads = of_get_port_count(sd_np);
147                 /* for the video mux, all but the last port are sinks */
148                 imxsd->num_sink_pads = num_pads - 1;
149         } else {
150                 num_pads = of_get_port_count(sd_np);
151                 if (num_pads != 1) {
152                         /* confused, but no reason to give up here */
153                         dev_warn(imxmd->md.dev,
154                                  "%s: unknown device %s with %d ports\n",
155                                  __func__, sd_np->name, num_pads);
156                         return 0;
157                 }
158
159                 /*
160                  * we got to this node from this single source port,
161                  * there are no sink pads.
162                  */
163                 imxsd->num_sink_pads = 0;
164         }
165
166         if (imxsd->num_sink_pads >= num_pads)
167                 return -EINVAL;
168
169         imxsd->num_src_pads = num_pads - imxsd->num_sink_pads;
170
171         dev_dbg(imxmd->md.dev, "%s: %s has %d pads (%d sink, %d src)\n",
172                 __func__, sd_np->name, num_pads,
173                 imxsd->num_sink_pads, imxsd->num_src_pads);
174
175         /*
176          * With no sink, this subdev node is the original source
177          * of video, parse it's media bus for use by the pipeline.
178          */
179         if (imxsd->num_sink_pads == 0)
180                 of_parse_sensor(imxmd, imxsd, sd_np);
181
182         for (i = 0; i < num_pads; i++) {
183                 struct device_node *epnode = NULL, *port, *remote_np;
184                 struct imx_media_subdev *remote_imxsd;
185                 struct imx_media_pad *pad;
186                 int remote_pad;
187
188                 /* init this pad */
189                 pad = &imxsd->pad[i];
190                 pad->pad.flags = (i < imxsd->num_sink_pads) ?
191                         MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
192
193                 if (is_csi_port)
194                         port = (i < imxsd->num_sink_pads) ? sd_np : NULL;
195                 else
196                         port = of_graph_get_port_by_id(sd_np, i);
197                 if (!port)
198                         continue;
199
200                 for_each_child_of_node(port, epnode) {
201                         of_get_remote_pad(epnode, &remote_np, &remote_pad);
202                         if (!remote_np)
203                                 continue;
204
205                         ret = of_add_pad_link(imxmd, pad, sd_np, remote_np,
206                                               i, remote_pad);
207                         if (ret)
208                                 break;
209
210                         if (i < imxsd->num_sink_pads) {
211                                 /* follow sink endpoints upstream */
212                                 ret = of_parse_subdev(imxmd, remote_np,
213                                                       false, &remote_imxsd);
214                                 if (ret)
215                                         break;
216                         }
217
218                         of_node_put(remote_np);
219                 }
220
221                 if (port != sd_np)
222                         of_node_put(port);
223                 if (ret) {
224                         of_node_put(remote_np);
225                         of_node_put(epnode);
226                         break;
227                 }
228         }
229
230         return ret;
231 }
232
233 int imx_media_of_parse(struct imx_media_dev *imxmd,
234                        struct imx_media_subdev *(*csi)[4],
235                        struct device_node *np)
236 {
237         struct imx_media_subdev *lcsi;
238         struct device_node *csi_np;
239         u32 ipu_id, csi_id;
240         int i, ret;
241
242         for (i = 0; ; i++) {
243                 csi_np = of_parse_phandle(np, "ports", i);
244                 if (!csi_np)
245                         break;
246
247                 ret = of_parse_subdev(imxmd, csi_np, true, &lcsi);
248                 if (ret)
249                         goto err_put;
250
251                 ret = of_property_read_u32(csi_np, "reg", &csi_id);
252                 if (ret) {
253                         dev_err(imxmd->md.dev,
254                                 "%s: csi port missing reg property!\n",
255                                 __func__);
256                         goto err_put;
257                 }
258
259                 ipu_id = of_alias_get_id(csi_np->parent, "ipu");
260                 of_node_put(csi_np);
261
262                 if (ipu_id > 1 || csi_id > 1) {
263                         dev_err(imxmd->md.dev,
264                                 "%s: invalid ipu/csi id (%u/%u)\n",
265                                 __func__, ipu_id, csi_id);
266                         return -EINVAL;
267                 }
268
269                 (*csi)[ipu_id * 2 + csi_id] = lcsi;
270         }
271
272         return 0;
273 err_put:
274         of_node_put(csi_np);
275         return ret;
276 }