xref: /rk3399_rockchip-uboot/drivers/video/drm/drm_of.c (revision cb86b722916d79452908bfcc35cf59afe17398d2)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2023 Rockchip Electronics Co., Ltd
4  *
5  */
6 #include <dm/device.h>
7 #include <dm/read.h>
8 
9 #include "drm_of.h"
10 
11 enum drm_of_lvds_pixels {
12 	DRM_OF_LVDS_EVEN = BIT(0),
13 	DRM_OF_LVDS_ODD = BIT(1),
14 	DRM_OF_LVDS_LEFT = BIT(2),
15 	DRM_OF_LVDS_RIGHT = BIT(3),
16 };
17 
18 static int
19 drm_of_lvds_get_port_pixels_type(const struct device_node *port_node)
20 {
21 	ofnode node = np_to_ofnode(port_node);
22 
23 	bool even_pixels =
24 		ofnode_read_bool(node, "dual-lvds-even-pixels");
25 	bool odd_pixels =
26 		ofnode_read_bool(node, "dual-lvds-odd-pixels");
27 	bool left_pixels =
28 		ofnode_read_bool(node, "dual-lvds-left-pixels");
29 	bool right_pixels =
30 		ofnode_read_bool(node, "dual-lvds-right-pixels");
31 
32 	return (even_pixels ? DRM_OF_LVDS_EVEN : 0) |
33 		   (odd_pixels ? DRM_OF_LVDS_ODD : 0) |
34 		   (left_pixels ? DRM_OF_LVDS_LEFT : 0) |
35 		   (right_pixels ? DRM_OF_LVDS_RIGHT : 0);
36 }
37 
38 static int
39 drm_of_lvds_get_remote_pixels_type(const struct device_node *port_node)
40 {
41 	ofnode node = np_to_ofnode(port_node);
42 	ofnode endpoint;
43 	uint phandle;
44 	int pixels_type = -EPIPE;
45 
46 	ofnode_for_each_subnode(endpoint, node) {
47 		int current_pt;
48 		const char *name;
49 
50 		if (!ofnode_is_available(endpoint))
51 			continue;
52 
53 		name = ofnode_get_name(endpoint);
54 		if (strncmp(name, "endpoint", 8) != 0)
55 			continue;
56 
57 		if (ofnode_read_u32(endpoint, "remote-endpoint", &phandle))
58 			continue;
59 
60 		endpoint = ofnode_get_by_phandle(phandle);
61 		if (!ofnode_valid(endpoint) || !ofnode_is_available(endpoint))
62 			continue;
63 
64 		endpoint = ofnode_get_parent(endpoint);
65 		if (!ofnode_valid(endpoint))
66 			continue;
67 
68 		current_pt =
69 			drm_of_lvds_get_port_pixels_type(ofnode_to_np(endpoint
70 				));
71 		if (pixels_type < 0)
72 			pixels_type = current_pt;
73 
74 		/*
75 		 * Sanity check, ensure that all remote endpoints have the same
76 		 * pixel type. We may lift this restriction later if we need to
77 		 * support multiple sinks with different dual-link
78 		 * configurations by passing the endpoints explicitly to
79 		 * drm_of_lvds_get_dual_link_pixel_order().
80 		 */
81 		if (!current_pt || pixels_type != current_pt)
82 			return -EINVAL;
83 	}
84 
85 	return pixels_type;
86 }
87 
88 /**
89  * drm_of_lvds_get_dual_link_pixel_order - Get LVDS dual-link pixel order
90  * @port1: First DT port node of the Dual-link LVDS source
91  * @port2: Second DT port node of the Dual-link LVDS source
92  *
93  * An LVDS dual-link connection is made of two links, the two link can transmit
94  * odd pixels and even pixels independently, or the two link can also transmit
95  * left pixels and right pixels independently. This function returns for two
96  * ports of an LVDS dual-link source, based on the requirements of the connected
97  * sink.
98  *
99  * The pixel order is determined from the dual-lvds-even-pixels +
100  * dual-lvds-odd-pixels or dual-lvds-left-pixels + dual-lvds-right-pixels
101  * properties in the sink's DT port nodes. If those
102  * properties are not present, or if their usage is not valid, this function
103  * returns -EINVAL.
104  *
105  * If either port is not connected, this function returns -EPIPE.
106  *
107  * @port1 and @port2 are typically DT sibling nodes, but may have different
108  * parents when, for instance, two separate LVDS encoders carry the even and
109  * odd pixels.
110  *
111  * Return:
112  * * DRM_LVDS_DUAL_LINK_EVEN_ODD_PIXELS - @port1 carries even pixels and @port2
113  *   carries odd pixels
114  * * DRM_LVDS_DUAL_LINK_ODD_EVEN_PIXELS - @port1 carries odd pixels and @port2
115  *   carries even pixels
116  * * DRM_LVDS_DUAL_LINK_LEFT_RIGHT_PIXELS - @port1 carries left pixels and
117  *   @port2 carries right pixels
118  * * DRM_LVDS_DUAL_LINK_RIGHT_LEFT_PIXELS - @port1 carries right pixels and
119  *   @port2 carries left pixels
120 
121  * * -EINVAL - @port1 and @port2 are not connected to a dual-link LVDS sink, or
122  *   the sink configuration is invalid
123  * * -EPIPE - when @port1 or @port2 are not connected
124  */
125 int drm_of_lvds_get_dual_link_pixel_order(const struct device_node *port1,
126 					  const struct device_node *port2)
127 {
128 	int remote_p1_pt, remote_p2_pt;
129 
130 	if (!port1 || !port2)
131 		return -EINVAL;
132 
133 	remote_p1_pt = drm_of_lvds_get_remote_pixels_type(port1);
134 	if (remote_p1_pt < 0)
135 		return remote_p1_pt;
136 
137 	remote_p2_pt = drm_of_lvds_get_remote_pixels_type(port2);
138 	if (remote_p2_pt < 0)
139 		return remote_p2_pt;
140 
141 	/*
142 	 * A valid dual-lVDS bus is found when one remote port is marked with
143 	 * "dual-lvds-even-pixels" or "dual-lvds-left-pixels", and the other
144 	 * remote port is marked with "dual-lvds-odd-pixels"or
145 	 * "dual-lvds-right-pixels", bail out if the markers are not right.
146 	 */
147 	if ((remote_p1_pt + remote_p2_pt !=
148 		DRM_OF_LVDS_EVEN + DRM_OF_LVDS_ODD) &&
149 		(remote_p1_pt + remote_p2_pt !=
150 		DRM_OF_LVDS_LEFT + DRM_OF_LVDS_RIGHT))
151 		return -EINVAL;
152 
153 	if (remote_p1_pt == DRM_OF_LVDS_EVEN)
154 		return DRM_LVDS_DUAL_LINK_EVEN_ODD_PIXELS;
155 	else if (remote_p1_pt == DRM_OF_LVDS_ODD)
156 		return DRM_LVDS_DUAL_LINK_ODD_EVEN_PIXELS;
157 	else if (remote_p1_pt == DRM_OF_LVDS_LEFT)
158 		return DRM_LVDS_DUAL_LINK_LEFT_RIGHT_PIXELS;
159 	else
160 		return DRM_LVDS_DUAL_LINK_RIGHT_LEFT_PIXELS;
161 }
162