1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Rockchip Connector Helper Function 4 * 5 * Copyright (C) 2021 Rockchip Electronics Co., Ltd 6 */ 7 8 #include <dm/device.h> 9 #include <dm/read.h> 10 #include <linux/compat.h> 11 #include <linux/list.h> 12 13 #include "rockchip_display.h" 14 #include "rockchip_crtc.h" 15 #include "rockchip_connector.h" 16 #include "rockchip_phy.h" 17 18 #ifdef CONFIG_SPL_BUILD 19 int rockchip_connector_bind(struct rockchip_connector *conn, struct udevice *dev, int id, 20 const struct rockchip_connector_funcs *funcs, void *data, int type) 21 { 22 conn->id = id; 23 conn->funcs = funcs; 24 conn->data = data; 25 conn->type = type; 26 27 return 0; 28 } 29 30 #else 31 static LIST_HEAD(rockchip_connector_list); 32 33 int rockchip_connector_bind(struct rockchip_connector *conn, struct udevice *dev, int id, 34 const struct rockchip_connector_funcs *funcs, void *data, int type) 35 { 36 conn->id = id; 37 conn->dev = dev; 38 conn->funcs = funcs; 39 conn->data = data; 40 conn->type = type; 41 list_add_tail(&conn->head, &rockchip_connector_list); 42 43 return 0; 44 } 45 46 struct rockchip_connector *get_rockchip_connector_by_device(struct udevice *dev) 47 { 48 struct rockchip_connector *conn; 49 50 list_for_each_entry(conn, &rockchip_connector_list, head) { 51 if (conn->dev == dev) 52 return conn; 53 } 54 55 return NULL; 56 } 57 58 int rockchip_connector_pre_init(struct display_state *state) 59 { 60 int ret = 0; 61 struct rockchip_connector *conn; 62 63 conn = state->conn_state.connector; 64 if (conn->funcs->pre_init) { 65 ret = conn->funcs->pre_init(conn, state); 66 if (ret) 67 return ret; 68 if (state->conn_state.secondary) { 69 conn = state->conn_state.connector; 70 ret = conn->funcs->pre_init(conn, state); 71 if (ret) 72 return ret; 73 } 74 } 75 76 return ret; 77 } 78 79 static int rockchip_connector_path_init(struct rockchip_connector *conn, 80 struct display_state *state) 81 { 82 int ret = 0; 83 84 if (conn->panel) 85 rockchip_panel_init(conn->panel, conn, state); 86 87 if (conn->bridge) 88 rockchip_bridge_init(conn->bridge, conn, state); 89 90 if (conn->funcs->init) { 91 ret = conn->funcs->init(conn, state); 92 if (ret) 93 return ret; 94 } 95 96 if (conn->phy) 97 rockchip_phy_init(conn->phy); 98 99 return ret; 100 } 101 102 int rockchip_connector_init(struct display_state *state) 103 { 104 int ret = 0; 105 struct rockchip_connector *conn; 106 107 conn = state->conn_state.connector; 108 ret = rockchip_connector_path_init(conn, state); 109 if (ret) 110 return ret; 111 if (state->conn_state.secondary) { 112 conn = state->conn_state.secondary; 113 ret = rockchip_connector_path_init(conn, state); 114 if (ret) 115 return ret; 116 } 117 118 return ret; 119 } 120 121 122 static bool rockchip_connector_path_detect(struct rockchip_connector *conn, 123 struct display_state *state) 124 { 125 int ret; 126 127 if (conn->funcs->detect) { 128 ret = conn->funcs->detect(conn, state); 129 if (!ret) { 130 printf("%s disconnected\n", conn->dev->name); 131 return false; 132 } 133 } 134 135 if (conn->bridge) { 136 ret = rockchip_bridge_detect(conn->bridge); 137 if (!ret) { 138 printf("%s disconnected\n", 139 dev_np(conn->bridge->dev)->full_name); 140 return false; 141 } 142 } 143 144 return true; 145 } 146 147 bool rockchip_connector_detect(struct display_state *state) 148 { 149 bool ret; 150 struct rockchip_connector *conn; 151 152 conn = state->conn_state.connector; 153 ret = rockchip_connector_path_detect(conn, state); 154 if (!ret) 155 return false; 156 if (state->conn_state.secondary) { 157 conn = state->conn_state.secondary; 158 ret = rockchip_connector_path_detect(conn, state); 159 if (!ret) 160 return false; 161 } 162 163 return true; 164 } 165 166 int rockchip_connector_get_timing(struct display_state *state) 167 { 168 int ret = 0; 169 struct rockchip_connector *conn; 170 171 conn = state->conn_state.connector; 172 if (conn->funcs->get_timing) { 173 ret = conn->funcs->get_timing(conn, state); 174 if (ret) 175 return ret; 176 if (state->conn_state.secondary) { 177 conn = state->conn_state.secondary; 178 ret = conn->funcs->get_timing(conn, state); 179 if (ret) 180 return ret; 181 } 182 } 183 184 return ret; 185 } 186 187 int rockchip_connector_get_edid(struct display_state *state) 188 { 189 int ret = 0; 190 struct rockchip_connector *conn; 191 192 conn = state->conn_state.connector; 193 if (conn->funcs->get_edid) { 194 ret = conn->funcs->get_edid(conn, state); 195 if (ret) 196 return ret; 197 if (state->conn_state.secondary) { 198 conn = state->conn_state.secondary; 199 ret = conn->funcs->get_edid(conn, state); 200 if (ret) 201 return ret; 202 } 203 } 204 205 return ret; 206 } 207 208 static int rockchip_connector_path_pre_enable(struct rockchip_connector *conn, 209 struct display_state *state) 210 { 211 if (conn->funcs->prepare) 212 conn->funcs->prepare(conn, state); 213 214 if (conn->bridge) 215 rockchip_bridge_pre_enable(conn->bridge); 216 217 if (conn->panel) 218 rockchip_panel_prepare(conn->panel); 219 220 return 0; 221 } 222 223 int rockchip_connector_pre_enable(struct display_state *state) 224 { 225 struct rockchip_connector *conn; 226 227 conn = state->conn_state.connector; 228 rockchip_connector_path_pre_enable(conn, state); 229 if (state->conn_state.secondary) { 230 conn = state->conn_state.secondary; 231 rockchip_connector_path_pre_enable(conn, state); 232 } 233 234 return 0; 235 } 236 237 static int rockchip_connector_path_enable(struct rockchip_connector *conn, 238 struct display_state *state) 239 { 240 if (conn->funcs->enable) 241 conn->funcs->enable(conn, state); 242 243 if (conn->bridge) 244 rockchip_bridge_enable(conn->bridge); 245 246 if (conn->panel) 247 rockchip_panel_enable(conn->panel); 248 249 return 0; 250 } 251 252 int rockchip_connector_enable(struct display_state *state) 253 { 254 struct rockchip_connector *conn; 255 256 conn = state->conn_state.connector; 257 rockchip_connector_path_enable(conn, state); 258 if (state->conn_state.secondary) { 259 conn = state->conn_state.secondary; 260 rockchip_connector_path_enable(conn, state); 261 } 262 263 return 0; 264 } 265 266 static int rockchip_connector_path_disable(struct rockchip_connector *conn, 267 struct display_state *state) 268 { 269 if (conn->panel) 270 rockchip_panel_disable(conn->panel); 271 272 if (conn->bridge) 273 rockchip_bridge_disable(conn->bridge); 274 275 if (conn->funcs->disable) 276 conn->funcs->disable(conn, state); 277 278 return 0; 279 } 280 281 int rockchip_connector_disable(struct display_state *state) 282 { 283 struct rockchip_connector *conn; 284 285 conn = state->conn_state.connector; 286 rockchip_connector_path_disable(conn, state); 287 if (state->conn_state.secondary) { 288 conn = state->conn_state.secondary; 289 rockchip_connector_path_disable(conn, state); 290 } 291 292 return 0; 293 } 294 295 static int rockchip_connector_path_post_disable(struct rockchip_connector *conn, 296 struct display_state *state) 297 { 298 if (conn->panel) 299 rockchip_panel_unprepare(conn->panel); 300 301 if (conn->bridge) 302 rockchip_bridge_post_disable(conn->bridge); 303 304 if (conn->funcs->unprepare) 305 conn->funcs->unprepare(conn, state); 306 307 return 0; 308 } 309 310 int rockchip_connector_post_disable(struct display_state *state) 311 { 312 struct rockchip_connector *conn; 313 314 conn = state->conn_state.connector; 315 rockchip_connector_path_post_disable(conn, state); 316 if (state->conn_state.secondary) { 317 conn = state->conn_state.secondary; 318 rockchip_connector_path_post_disable(conn, state); 319 } 320 321 return 0; 322 } 323 #endif 324 325 int rockchip_connector_deinit(struct display_state *state) 326 { 327 struct rockchip_connector *conn; 328 329 conn = state->conn_state.connector; 330 if (conn->funcs->deinit) { 331 conn->funcs->deinit(conn, state); 332 if (state->conn_state.secondary) { 333 conn = state->conn_state.secondary; 334 conn->funcs->deinit(conn, state); 335 } 336 } 337 338 return 0; 339 } 340