1 /* 2 * Exynos DRM Parallel output support. 3 * 4 * Copyright (c) 2014 Samsung Electronics Co., Ltd 5 * 6 * Contacts: Andrzej Hajda <a.hajda@samsung.com> 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 version 2 as 10 * published by the Free Software Foundation. 11 */ 12 13 #include <drm/drmP.h> 14 #include <drm/drm_crtc_helper.h> 15 #include <drm/drm_panel.h> 16 #include <drm/drm_atomic_helper.h> 17 18 #include <linux/regulator/consumer.h> 19 20 #include <video/of_videomode.h> 21 #include <video/videomode.h> 22 23 #include "exynos_drm_drv.h" 24 25 struct exynos_dpi { 26 struct exynos_drm_display display; 27 struct device *dev; 28 struct device_node *panel_node; 29 30 struct drm_panel *panel; 31 struct drm_connector connector; 32 struct drm_encoder *encoder; 33 34 struct videomode *vm; 35 int dpms_mode; 36 }; 37 38 #define connector_to_dpi(c) container_of(c, struct exynos_dpi, connector) 39 40 static inline struct exynos_dpi *display_to_dpi(struct exynos_drm_display *d) 41 { 42 return container_of(d, struct exynos_dpi, display); 43 } 44 45 static enum drm_connector_status 46 exynos_dpi_detect(struct drm_connector *connector, bool force) 47 { 48 struct exynos_dpi *ctx = connector_to_dpi(connector); 49 50 if (ctx->panel && !ctx->panel->connector) 51 drm_panel_attach(ctx->panel, &ctx->connector); 52 53 return connector_status_connected; 54 } 55 56 static void exynos_dpi_connector_destroy(struct drm_connector *connector) 57 { 58 drm_connector_unregister(connector); 59 drm_connector_cleanup(connector); 60 } 61 62 static struct drm_connector_funcs exynos_dpi_connector_funcs = { 63 .dpms = drm_atomic_helper_connector_dpms, 64 .detect = exynos_dpi_detect, 65 .fill_modes = drm_helper_probe_single_connector_modes, 66 .destroy = exynos_dpi_connector_destroy, 67 .reset = drm_atomic_helper_connector_reset, 68 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, 69 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, 70 }; 71 72 static int exynos_dpi_get_modes(struct drm_connector *connector) 73 { 74 struct exynos_dpi *ctx = connector_to_dpi(connector); 75 76 /* fimd timings gets precedence over panel modes */ 77 if (ctx->vm) { 78 struct drm_display_mode *mode; 79 80 mode = drm_mode_create(connector->dev); 81 if (!mode) { 82 DRM_ERROR("failed to create a new display mode\n"); 83 return 0; 84 } 85 drm_display_mode_from_videomode(ctx->vm, mode); 86 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; 87 drm_mode_probed_add(connector, mode); 88 return 1; 89 } 90 91 if (ctx->panel) 92 return ctx->panel->funcs->get_modes(ctx->panel); 93 94 return 0; 95 } 96 97 static struct drm_encoder * 98 exynos_dpi_best_encoder(struct drm_connector *connector) 99 { 100 struct exynos_dpi *ctx = connector_to_dpi(connector); 101 102 return ctx->encoder; 103 } 104 105 static struct drm_connector_helper_funcs exynos_dpi_connector_helper_funcs = { 106 .get_modes = exynos_dpi_get_modes, 107 .best_encoder = exynos_dpi_best_encoder, 108 }; 109 110 static int exynos_dpi_create_connector(struct exynos_drm_display *display, 111 struct drm_encoder *encoder) 112 { 113 struct exynos_dpi *ctx = display_to_dpi(display); 114 struct drm_connector *connector = &ctx->connector; 115 int ret; 116 117 ctx->encoder = encoder; 118 119 connector->polled = DRM_CONNECTOR_POLL_HPD; 120 121 ret = drm_connector_init(encoder->dev, connector, 122 &exynos_dpi_connector_funcs, 123 DRM_MODE_CONNECTOR_VGA); 124 if (ret) { 125 DRM_ERROR("failed to initialize connector with drm\n"); 126 return ret; 127 } 128 129 drm_connector_helper_add(connector, &exynos_dpi_connector_helper_funcs); 130 drm_connector_register(connector); 131 drm_mode_connector_attach_encoder(connector, encoder); 132 133 return 0; 134 } 135 136 static void exynos_dpi_poweron(struct exynos_dpi *ctx) 137 { 138 if (ctx->panel) { 139 drm_panel_prepare(ctx->panel); 140 drm_panel_enable(ctx->panel); 141 } 142 } 143 144 static void exynos_dpi_poweroff(struct exynos_dpi *ctx) 145 { 146 if (ctx->panel) { 147 drm_panel_disable(ctx->panel); 148 drm_panel_unprepare(ctx->panel); 149 } 150 } 151 152 static void exynos_dpi_dpms(struct exynos_drm_display *display, int mode) 153 { 154 struct exynos_dpi *ctx = display_to_dpi(display); 155 156 switch (mode) { 157 case DRM_MODE_DPMS_ON: 158 if (ctx->dpms_mode != DRM_MODE_DPMS_ON) 159 exynos_dpi_poweron(ctx); 160 break; 161 case DRM_MODE_DPMS_STANDBY: 162 case DRM_MODE_DPMS_SUSPEND: 163 case DRM_MODE_DPMS_OFF: 164 if (ctx->dpms_mode == DRM_MODE_DPMS_ON) 165 exynos_dpi_poweroff(ctx); 166 break; 167 default: 168 break; 169 } 170 ctx->dpms_mode = mode; 171 } 172 173 static struct exynos_drm_display_ops exynos_dpi_display_ops = { 174 .create_connector = exynos_dpi_create_connector, 175 .dpms = exynos_dpi_dpms 176 }; 177 178 /* of_* functions will be removed after merge of of_graph patches */ 179 static struct device_node * 180 of_get_child_by_name_reg(struct device_node *parent, const char *name, u32 reg) 181 { 182 struct device_node *np; 183 184 for_each_child_of_node(parent, np) { 185 u32 r; 186 187 if (!np->name || of_node_cmp(np->name, name)) 188 continue; 189 190 if (of_property_read_u32(np, "reg", &r) < 0) 191 r = 0; 192 193 if (reg == r) 194 break; 195 } 196 197 return np; 198 } 199 200 static struct device_node *of_graph_get_port_by_reg(struct device_node *parent, 201 u32 reg) 202 { 203 struct device_node *ports, *port; 204 205 ports = of_get_child_by_name(parent, "ports"); 206 if (ports) 207 parent = ports; 208 209 port = of_get_child_by_name_reg(parent, "port", reg); 210 211 of_node_put(ports); 212 213 return port; 214 } 215 216 static struct device_node * 217 of_graph_get_endpoint_by_reg(struct device_node *port, u32 reg) 218 { 219 return of_get_child_by_name_reg(port, "endpoint", reg); 220 } 221 222 static struct device_node * 223 of_graph_get_remote_port_parent(const struct device_node *node) 224 { 225 struct device_node *np; 226 unsigned int depth; 227 228 np = of_parse_phandle(node, "remote-endpoint", 0); 229 230 /* Walk 3 levels up only if there is 'ports' node. */ 231 for (depth = 3; depth && np; depth--) { 232 np = of_get_next_parent(np); 233 if (depth == 2 && of_node_cmp(np->name, "ports")) 234 break; 235 } 236 return np; 237 } 238 239 enum { 240 FIMD_PORT_IN0, 241 FIMD_PORT_IN1, 242 FIMD_PORT_IN2, 243 FIMD_PORT_RGB, 244 FIMD_PORT_WRB, 245 }; 246 247 static struct device_node *exynos_dpi_of_find_panel_node(struct device *dev) 248 { 249 struct device_node *np, *ep; 250 251 np = of_graph_get_port_by_reg(dev->of_node, FIMD_PORT_RGB); 252 if (!np) 253 return NULL; 254 255 ep = of_graph_get_endpoint_by_reg(np, 0); 256 of_node_put(np); 257 if (!ep) 258 return NULL; 259 260 np = of_graph_get_remote_port_parent(ep); 261 of_node_put(ep); 262 263 return np; 264 } 265 266 static int exynos_dpi_parse_dt(struct exynos_dpi *ctx) 267 { 268 struct device *dev = ctx->dev; 269 struct device_node *dn = dev->of_node; 270 struct device_node *np; 271 272 ctx->panel_node = exynos_dpi_of_find_panel_node(dev); 273 274 np = of_get_child_by_name(dn, "display-timings"); 275 if (np) { 276 struct videomode *vm; 277 int ret; 278 279 of_node_put(np); 280 281 vm = devm_kzalloc(dev, sizeof(*ctx->vm), GFP_KERNEL); 282 if (!vm) 283 return -ENOMEM; 284 285 ret = of_get_videomode(dn, vm, 0); 286 if (ret < 0) { 287 devm_kfree(dev, vm); 288 return ret; 289 } 290 291 ctx->vm = vm; 292 293 return 0; 294 } 295 296 if (!ctx->panel_node) 297 return -EINVAL; 298 299 return 0; 300 } 301 302 struct exynos_drm_display *exynos_dpi_probe(struct device *dev) 303 { 304 struct exynos_dpi *ctx; 305 int ret; 306 307 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); 308 if (!ctx) 309 return ERR_PTR(-ENOMEM); 310 311 ctx->display.type = EXYNOS_DISPLAY_TYPE_LCD; 312 ctx->display.ops = &exynos_dpi_display_ops; 313 ctx->dev = dev; 314 ctx->dpms_mode = DRM_MODE_DPMS_OFF; 315 316 ret = exynos_dpi_parse_dt(ctx); 317 if (ret < 0) { 318 devm_kfree(dev, ctx); 319 return NULL; 320 } 321 322 if (ctx->panel_node) { 323 ctx->panel = of_drm_find_panel(ctx->panel_node); 324 if (!ctx->panel) 325 return ERR_PTR(-EPROBE_DEFER); 326 } 327 328 return &ctx->display; 329 } 330 331 int exynos_dpi_remove(struct exynos_drm_display *display) 332 { 333 struct exynos_dpi *ctx = display_to_dpi(display); 334 335 exynos_dpi_dpms(&ctx->display, DRM_MODE_DPMS_OFF); 336 337 if (ctx->panel) 338 drm_panel_detach(ctx->panel); 339 340 return 0; 341 } 342