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