Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1#include <linux/component.h>
  2#include <linux/export.h>
  3#include <linux/list.h>
  4#include <linux/of_graph.h>
  5#include <drm/drmP.h>
  6#include <drm/drm_bridge.h>
  7#include <drm/drm_crtc.h>
  8#include <drm/drm_encoder.h>
  9#include <drm/drm_panel.h>
 10#include <drm/drm_of.h>
 11
 12static void drm_release_of(struct device *dev, void *data)
 13{
 14	of_node_put(data);
 15}
 16
 17/**
 18 * drm_crtc_port_mask - find the mask of a registered CRTC by port OF node
 19 * @dev: DRM device
 20 * @port: port OF node
 21 *
 22 * Given a port OF node, return the possible mask of the corresponding
 23 * CRTC within a device's list of CRTCs.  Returns zero if not found.
 24 */
 25static uint32_t drm_crtc_port_mask(struct drm_device *dev,
 26				   struct device_node *port)
 27{
 28	unsigned int index = 0;
 29	struct drm_crtc *tmp;
 30
 31	drm_for_each_crtc(tmp, dev) {
 32		if (tmp->port == port)
 33			return 1 << index;
 34
 35		index++;
 36	}
 37
 38	return 0;
 39}
 40
 41/**
 42 * drm_of_find_possible_crtcs - find the possible CRTCs for an encoder port
 43 * @dev: DRM device
 44 * @port: encoder port to scan for endpoints
 45 *
 46 * Scan all endpoints attached to a port, locate their attached CRTCs,
 47 * and generate the DRM mask of CRTCs which may be attached to this
 48 * encoder.
 49 *
 50 * See Documentation/devicetree/bindings/graph.txt for the bindings.
 51 */
 52uint32_t drm_of_find_possible_crtcs(struct drm_device *dev,
 53				    struct device_node *port)
 54{
 55	struct device_node *remote_port, *ep;
 56	uint32_t possible_crtcs = 0;
 57
 58	for_each_endpoint_of_node(port, ep) {
 59		remote_port = of_graph_get_remote_port(ep);
 60		if (!remote_port) {
 61			of_node_put(ep);
 62			return 0;
 63		}
 64
 65		possible_crtcs |= drm_crtc_port_mask(dev, remote_port);
 66
 67		of_node_put(remote_port);
 68	}
 69
 70	return possible_crtcs;
 71}
 72EXPORT_SYMBOL(drm_of_find_possible_crtcs);
 73
 74/**
 75 * drm_of_component_match_add - Add a component helper OF node match rule
 76 * @master: master device
 77 * @matchptr: component match pointer
 78 * @compare: compare function used for matching component
 79 * @node: of_node
 80 */
 81void drm_of_component_match_add(struct device *master,
 82				struct component_match **matchptr,
 83				int (*compare)(struct device *, void *),
 84				struct device_node *node)
 85{
 86	of_node_get(node);
 87	component_match_add_release(master, matchptr, drm_release_of,
 88				    compare, node);
 89}
 90EXPORT_SYMBOL_GPL(drm_of_component_match_add);
 91
 92/**
 93 * drm_of_component_probe - Generic probe function for a component based master
 94 * @dev: master device containing the OF node
 95 * @compare_of: compare function used for matching components
 96 * @master_ops: component master ops to be used
 97 *
 98 * Parse the platform device OF node and bind all the components associated
 99 * with the master. Interface ports are added before the encoders in order to
100 * satisfy their .bind requirements
101 * See Documentation/devicetree/bindings/graph.txt for the bindings.
102 *
103 * Returns zero if successful, or one of the standard error codes if it fails.
104 */
105int drm_of_component_probe(struct device *dev,
106			   int (*compare_of)(struct device *, void *),
107			   const struct component_master_ops *m_ops)
108{
109	struct device_node *ep, *port, *remote;
110	struct component_match *match = NULL;
111	int i;
112
113	if (!dev->of_node)
114		return -EINVAL;
115
116	/*
117	 * Bind the crtc's ports first, so that drm_of_find_possible_crtcs()
118	 * called from encoder's .bind callbacks works as expected
119	 */
120	for (i = 0; ; i++) {
121		port = of_parse_phandle(dev->of_node, "ports", i);
122		if (!port)
123			break;
124
125		if (of_device_is_available(port->parent))
126			drm_of_component_match_add(dev, &match, compare_of,
127						   port);
128
129		of_node_put(port);
130	}
131
132	if (i == 0) {
133		dev_err(dev, "missing 'ports' property\n");
134		return -ENODEV;
135	}
136
137	if (!match) {
138		dev_err(dev, "no available port\n");
139		return -ENODEV;
140	}
141
142	/*
143	 * For bound crtcs, bind the encoders attached to their remote endpoint
144	 */
145	for (i = 0; ; i++) {
146		port = of_parse_phandle(dev->of_node, "ports", i);
147		if (!port)
148			break;
149
150		if (!of_device_is_available(port->parent)) {
151			of_node_put(port);
152			continue;
153		}
154
155		for_each_child_of_node(port, ep) {
156			remote = of_graph_get_remote_port_parent(ep);
157			if (!remote || !of_device_is_available(remote)) {
158				of_node_put(remote);
159				continue;
160			} else if (!of_device_is_available(remote->parent)) {
161				dev_warn(dev, "parent device of %pOF is not available\n",
162					 remote);
163				of_node_put(remote);
164				continue;
165			}
166
167			drm_of_component_match_add(dev, &match, compare_of,
168						   remote);
169			of_node_put(remote);
170		}
171		of_node_put(port);
172	}
173
174	return component_master_add_with_match(dev, m_ops, match);
175}
176EXPORT_SYMBOL(drm_of_component_probe);
177
178/*
179 * drm_of_encoder_active_endpoint - return the active encoder endpoint
180 * @node: device tree node containing encoder input ports
181 * @encoder: drm_encoder
182 *
183 * Given an encoder device node and a drm_encoder with a connected crtc,
184 * parse the encoder endpoint connecting to the crtc port.
185 */
186int drm_of_encoder_active_endpoint(struct device_node *node,
187				   struct drm_encoder *encoder,
188				   struct of_endpoint *endpoint)
189{
190	struct device_node *ep;
191	struct drm_crtc *crtc = encoder->crtc;
192	struct device_node *port;
193	int ret;
194
195	if (!node || !crtc)
196		return -EINVAL;
197
198	for_each_endpoint_of_node(node, ep) {
199		port = of_graph_get_remote_port(ep);
200		of_node_put(port);
201		if (port == crtc->port) {
202			ret = of_graph_parse_endpoint(ep, endpoint);
203			of_node_put(ep);
204			return ret;
205		}
206	}
207
208	return -EINVAL;
209}
210EXPORT_SYMBOL_GPL(drm_of_encoder_active_endpoint);
211
212/*
213 * drm_of_find_panel_or_bridge - return connected panel or bridge device
214 * @np: device tree node containing encoder output ports
215 * @panel: pointer to hold returned drm_panel
216 * @bridge: pointer to hold returned drm_bridge
217 *
218 * Given a DT node's port and endpoint number, find the connected node and
219 * return either the associated struct drm_panel or drm_bridge device. Either
220 * @panel or @bridge must not be NULL.
221 *
222 * Returns zero if successful, or one of the standard error codes if it fails.
223 */
224int drm_of_find_panel_or_bridge(const struct device_node *np,
225				int port, int endpoint,
226				struct drm_panel **panel,
227				struct drm_bridge **bridge)
228{
229	int ret = -EPROBE_DEFER;
230	struct device_node *remote;
231
232	if (!panel && !bridge)
233		return -EINVAL;
234	if (panel)
235		*panel = NULL;
236
237	remote = of_graph_get_remote_node(np, port, endpoint);
238	if (!remote)
239		return -ENODEV;
240
241	if (panel) {
242		*panel = of_drm_find_panel(remote);
243		if (*panel)
244			ret = 0;
245	}
246
247	/* No panel found yet, check for a bridge next. */
248	if (bridge) {
249		if (ret) {
250			*bridge = of_drm_find_bridge(remote);
251			if (*bridge)
252				ret = 0;
253		} else {
254			*bridge = NULL;
255		}
256
257	}
258
259	of_node_put(remote);
260	return ret;
261}
262EXPORT_SYMBOL_GPL(drm_of_find_panel_or_bridge);