11c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae/* 21c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * Copyright (c) 2011 Samsung Electronics Co., Ltd. 31c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * Authors: 41c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * Inki Dae <inki.dae@samsung.com> 51c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * Joonyoung Shim <jy0922.shim@samsung.com> 61c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * Seung-Woo Kim <sw0312.kim@samsung.com> 71c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * 81c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * Permission is hereby granted, free of charge, to any person obtaining a 91c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * copy of this software and associated documentation files (the "Software"), 101c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * to deal in the Software without restriction, including without limitation 111c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * the rights to use, copy, modify, merge, publish, distribute, sublicense, 121c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * and/or sell copies of the Software, and to permit persons to whom the 131c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * Software is furnished to do so, subject to the following conditions: 141c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * 151c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * The above copyright notice and this permission notice (including the next 161c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * paragraph) shall be included in all copies or substantial portions of the 171c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * Software. 181c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * 191c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 201c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 211c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 221c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 231c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 241c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 251c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * OTHER DEALINGS IN THE SOFTWARE. 261c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae */ 271c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 281c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae#include "drmP.h" 291c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae#include "drm_crtc_helper.h" 301c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 31607c50d429371797f198ffc34afb239eadd1c655Eun-Chul Kim#include <drm/exynos_drm.h> 321c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae#include "exynos_drm_drv.h" 331c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae#include "exynos_drm_encoder.h" 341c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 351c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae#define MAX_EDID 256 361c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae#define to_exynos_connector(x) container_of(x, struct exynos_drm_connector,\ 371c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae drm_connector) 381c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 391c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Daestruct exynos_drm_connector { 401c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae struct drm_connector drm_connector; 41adb6b1596743e93e50fad2ff26d9604cda4361abInki Dae uint32_t encoder_id; 42adb6b1596743e93e50fad2ff26d9604cda4361abInki Dae struct exynos_drm_manager *manager; 431c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae}; 441c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 451c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae/* convert exynos_video_timings to drm_display_mode */ 461c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Daestatic inline void 471c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Daeconvert_to_display_mode(struct drm_display_mode *mode, 48607c50d429371797f198ffc34afb239eadd1c655Eun-Chul Kim struct exynos_drm_panel_info *panel) 491c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae{ 50607c50d429371797f198ffc34afb239eadd1c655Eun-Chul Kim struct fb_videomode *timing = &panel->timing; 511c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae DRM_DEBUG_KMS("%s\n", __FILE__); 521c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 531c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae mode->clock = timing->pixclock / 1000; 548b58dfe0290cb57e3f8601b197f00c23fa39a60dSeung-Woo Kim mode->vrefresh = timing->refresh; 551c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 561c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae mode->hdisplay = timing->xres; 571c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae mode->hsync_start = mode->hdisplay + timing->left_margin; 581c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae mode->hsync_end = mode->hsync_start + timing->hsync_len; 591c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae mode->htotal = mode->hsync_end + timing->right_margin; 601c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 611c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae mode->vdisplay = timing->yres; 621c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae mode->vsync_start = mode->vdisplay + timing->upper_margin; 631c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae mode->vsync_end = mode->vsync_start + timing->vsync_len; 641c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae mode->vtotal = mode->vsync_end + timing->lower_margin; 65607c50d429371797f198ffc34afb239eadd1c655Eun-Chul Kim mode->width_mm = panel->width_mm; 66607c50d429371797f198ffc34afb239eadd1c655Eun-Chul Kim mode->height_mm = panel->height_mm; 678b58dfe0290cb57e3f8601b197f00c23fa39a60dSeung-Woo Kim 688b58dfe0290cb57e3f8601b197f00c23fa39a60dSeung-Woo Kim if (timing->vmode & FB_VMODE_INTERLACED) 698b58dfe0290cb57e3f8601b197f00c23fa39a60dSeung-Woo Kim mode->flags |= DRM_MODE_FLAG_INTERLACE; 708b58dfe0290cb57e3f8601b197f00c23fa39a60dSeung-Woo Kim 718b58dfe0290cb57e3f8601b197f00c23fa39a60dSeung-Woo Kim if (timing->vmode & FB_VMODE_DOUBLE) 728b58dfe0290cb57e3f8601b197f00c23fa39a60dSeung-Woo Kim mode->flags |= DRM_MODE_FLAG_DBLSCAN; 731c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae} 741c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 751c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae/* convert drm_display_mode to exynos_video_timings */ 761c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Daestatic inline void 771c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Daeconvert_to_video_timing(struct fb_videomode *timing, 781c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae struct drm_display_mode *mode) 791c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae{ 801c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae DRM_DEBUG_KMS("%s\n", __FILE__); 811c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 821c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae memset(timing, 0, sizeof(*timing)); 831c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 841c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae timing->pixclock = mode->clock * 1000; 858b58dfe0290cb57e3f8601b197f00c23fa39a60dSeung-Woo Kim timing->refresh = drm_mode_vrefresh(mode); 861c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 871c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae timing->xres = mode->hdisplay; 881c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae timing->left_margin = mode->hsync_start - mode->hdisplay; 891c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae timing->hsync_len = mode->hsync_end - mode->hsync_start; 901c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae timing->right_margin = mode->htotal - mode->hsync_end; 911c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 921c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae timing->yres = mode->vdisplay; 931c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae timing->upper_margin = mode->vsync_start - mode->vdisplay; 941c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae timing->vsync_len = mode->vsync_end - mode->vsync_start; 951c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae timing->lower_margin = mode->vtotal - mode->vsync_end; 961c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 971c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae if (mode->flags & DRM_MODE_FLAG_INTERLACE) 981c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae timing->vmode = FB_VMODE_INTERLACED; 991c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae else 1001c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae timing->vmode = FB_VMODE_NONINTERLACED; 1011c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 1021c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae if (mode->flags & DRM_MODE_FLAG_DBLSCAN) 1031c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae timing->vmode |= FB_VMODE_DOUBLE; 1041c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae} 1051c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 1061c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Daestatic int exynos_drm_connector_get_modes(struct drm_connector *connector) 1071c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae{ 108adb6b1596743e93e50fad2ff26d9604cda4361abInki Dae struct exynos_drm_connector *exynos_connector = 109adb6b1596743e93e50fad2ff26d9604cda4361abInki Dae to_exynos_connector(connector); 110adb6b1596743e93e50fad2ff26d9604cda4361abInki Dae struct exynos_drm_manager *manager = exynos_connector->manager; 11174ccc539bcebdb24afb74194223f92a96a7285edInki Dae struct exynos_drm_display_ops *display_ops = manager->display_ops; 1121c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae unsigned int count; 1131c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 1141c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae DRM_DEBUG_KMS("%s\n", __FILE__); 1151c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 11674ccc539bcebdb24afb74194223f92a96a7285edInki Dae if (!display_ops) { 11774ccc539bcebdb24afb74194223f92a96a7285edInki Dae DRM_DEBUG_KMS("display_ops is null.\n"); 1181c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae return 0; 1191c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae } 1201c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 1211c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae /* 1221c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * if get_edid() exists then get_edid() callback of hdmi side 1231c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * is called to get edid data through i2c interface else 1241c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * get timing from the FIMD driver(display controller). 1251c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * 1261c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * P.S. in case of lcd panel, count is always 1 if success 1271c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae * because lcd panel has only one mode. 1281c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae */ 12974ccc539bcebdb24afb74194223f92a96a7285edInki Dae if (display_ops->get_edid) { 1301c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae int ret; 1311c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae void *edid; 1321c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 1331c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae edid = kzalloc(MAX_EDID, GFP_KERNEL); 1341c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae if (!edid) { 1351c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae DRM_ERROR("failed to allocate edid\n"); 1361c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae return 0; 1371c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae } 1381c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 13974ccc539bcebdb24afb74194223f92a96a7285edInki Dae ret = display_ops->get_edid(manager->dev, connector, 1401c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae edid, MAX_EDID); 1411c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae if (ret < 0) { 1421c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae DRM_ERROR("failed to get edid data.\n"); 1431c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae kfree(edid); 1441c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae edid = NULL; 1451c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae return 0; 1461c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae } 1471c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 1481c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae drm_mode_connector_update_edid_property(connector, edid); 1491c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae count = drm_add_edid_modes(connector, edid); 1501c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 1511c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae kfree(connector->display_info.raw_edid); 1521c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae connector->display_info.raw_edid = edid; 1531c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae } else { 1541c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae struct drm_display_mode *mode = drm_mode_create(connector->dev); 155607c50d429371797f198ffc34afb239eadd1c655Eun-Chul Kim struct exynos_drm_panel_info *panel; 1561c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 157607c50d429371797f198ffc34afb239eadd1c655Eun-Chul Kim if (display_ops->get_panel) 158607c50d429371797f198ffc34afb239eadd1c655Eun-Chul Kim panel = display_ops->get_panel(manager->dev); 1591c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae else { 1601c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae drm_mode_destroy(connector->dev, mode); 1611c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae return 0; 1621c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae } 1631c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 164607c50d429371797f198ffc34afb239eadd1c655Eun-Chul Kim convert_to_display_mode(mode, panel); 165607c50d429371797f198ffc34afb239eadd1c655Eun-Chul Kim connector->display_info.width_mm = mode->width_mm; 166607c50d429371797f198ffc34afb239eadd1c655Eun-Chul Kim connector->display_info.height_mm = mode->height_mm; 1671c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 1681c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; 1691c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae drm_mode_set_name(mode); 1701c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae drm_mode_probed_add(connector, mode); 1711c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 1721c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae count = 1; 1731c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae } 1741c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 1751c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae return count; 1761c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae} 1771c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 1781c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Daestatic int exynos_drm_connector_mode_valid(struct drm_connector *connector, 1791c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae struct drm_display_mode *mode) 1801c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae{ 181adb6b1596743e93e50fad2ff26d9604cda4361abInki Dae struct exynos_drm_connector *exynos_connector = 182adb6b1596743e93e50fad2ff26d9604cda4361abInki Dae to_exynos_connector(connector); 183adb6b1596743e93e50fad2ff26d9604cda4361abInki Dae struct exynos_drm_manager *manager = exynos_connector->manager; 18474ccc539bcebdb24afb74194223f92a96a7285edInki Dae struct exynos_drm_display_ops *display_ops = manager->display_ops; 1851c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae struct fb_videomode timing; 1861c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae int ret = MODE_BAD; 1871c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 1881c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae DRM_DEBUG_KMS("%s\n", __FILE__); 1891c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 1901c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae convert_to_video_timing(&timing, mode); 1911c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 19274ccc539bcebdb24afb74194223f92a96a7285edInki Dae if (display_ops && display_ops->check_timing) 19374ccc539bcebdb24afb74194223f92a96a7285edInki Dae if (!display_ops->check_timing(manager->dev, (void *)&timing)) 1941c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae ret = MODE_OK; 1951c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 1961c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae return ret; 1971c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae} 1981c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 1991c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Daestruct drm_encoder *exynos_drm_best_encoder(struct drm_connector *connector) 2001c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae{ 201adb6b1596743e93e50fad2ff26d9604cda4361abInki Dae struct drm_device *dev = connector->dev; 202adb6b1596743e93e50fad2ff26d9604cda4361abInki Dae struct exynos_drm_connector *exynos_connector = 203adb6b1596743e93e50fad2ff26d9604cda4361abInki Dae to_exynos_connector(connector); 204adb6b1596743e93e50fad2ff26d9604cda4361abInki Dae struct drm_mode_object *obj; 205adb6b1596743e93e50fad2ff26d9604cda4361abInki Dae struct drm_encoder *encoder; 206adb6b1596743e93e50fad2ff26d9604cda4361abInki Dae 2071c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae DRM_DEBUG_KMS("%s\n", __FILE__); 2081c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 209adb6b1596743e93e50fad2ff26d9604cda4361abInki Dae obj = drm_mode_object_find(dev, exynos_connector->encoder_id, 210adb6b1596743e93e50fad2ff26d9604cda4361abInki Dae DRM_MODE_OBJECT_ENCODER); 211adb6b1596743e93e50fad2ff26d9604cda4361abInki Dae if (!obj) { 212adb6b1596743e93e50fad2ff26d9604cda4361abInki Dae DRM_DEBUG_KMS("Unknown ENCODER ID %d\n", 213adb6b1596743e93e50fad2ff26d9604cda4361abInki Dae exynos_connector->encoder_id); 214adb6b1596743e93e50fad2ff26d9604cda4361abInki Dae return NULL; 215adb6b1596743e93e50fad2ff26d9604cda4361abInki Dae } 216adb6b1596743e93e50fad2ff26d9604cda4361abInki Dae 217adb6b1596743e93e50fad2ff26d9604cda4361abInki Dae encoder = obj_to_encoder(obj); 218adb6b1596743e93e50fad2ff26d9604cda4361abInki Dae 219adb6b1596743e93e50fad2ff26d9604cda4361abInki Dae return encoder; 2201c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae} 2211c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 2221c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Daestatic struct drm_connector_helper_funcs exynos_connector_helper_funcs = { 2231c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae .get_modes = exynos_drm_connector_get_modes, 2241c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae .mode_valid = exynos_drm_connector_mode_valid, 2251c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae .best_encoder = exynos_drm_best_encoder, 2261c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae}; 2271c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 2281c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae/* get detection status of display device. */ 2291c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Daestatic enum drm_connector_status 2301c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Daeexynos_drm_connector_detect(struct drm_connector *connector, bool force) 2311c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae{ 232adb6b1596743e93e50fad2ff26d9604cda4361abInki Dae struct exynos_drm_connector *exynos_connector = 233adb6b1596743e93e50fad2ff26d9604cda4361abInki Dae to_exynos_connector(connector); 234adb6b1596743e93e50fad2ff26d9604cda4361abInki Dae struct exynos_drm_manager *manager = exynos_connector->manager; 23574ccc539bcebdb24afb74194223f92a96a7285edInki Dae struct exynos_drm_display_ops *display_ops = 23674ccc539bcebdb24afb74194223f92a96a7285edInki Dae manager->display_ops; 2371c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae enum drm_connector_status status = connector_status_disconnected; 2381c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 2391c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae DRM_DEBUG_KMS("%s\n", __FILE__); 2401c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 24174ccc539bcebdb24afb74194223f92a96a7285edInki Dae if (display_ops && display_ops->is_connected) { 24274ccc539bcebdb24afb74194223f92a96a7285edInki Dae if (display_ops->is_connected(manager->dev)) 2431c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae status = connector_status_connected; 2441c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae else 2451c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae status = connector_status_disconnected; 2461c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae } 2471c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 2481c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae return status; 2491c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae} 2501c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 2511c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Daestatic void exynos_drm_connector_destroy(struct drm_connector *connector) 2521c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae{ 2531c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae struct exynos_drm_connector *exynos_connector = 2541c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae to_exynos_connector(connector); 2551c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 2561c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae DRM_DEBUG_KMS("%s\n", __FILE__); 2571c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 2581c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae drm_sysfs_connector_remove(connector); 2591c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae drm_connector_cleanup(connector); 2601c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae kfree(exynos_connector); 2611c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae} 2621c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 2631c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Daestatic struct drm_connector_funcs exynos_connector_funcs = { 2641c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae .dpms = drm_helper_connector_dpms, 2651c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae .fill_modes = drm_helper_probe_single_connector_modes, 2661c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae .detect = exynos_drm_connector_detect, 2671c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae .destroy = exynos_drm_connector_destroy, 2681c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae}; 2691c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 2701c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Daestruct drm_connector *exynos_drm_connector_create(struct drm_device *dev, 2711c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae struct drm_encoder *encoder) 2721c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae{ 2731c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae struct exynos_drm_connector *exynos_connector; 2741c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder); 2751c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae struct drm_connector *connector; 2761c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae int type; 2771c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae int err; 2781c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 2791c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae DRM_DEBUG_KMS("%s\n", __FILE__); 2801c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 2811c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae exynos_connector = kzalloc(sizeof(*exynos_connector), GFP_KERNEL); 2821c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae if (!exynos_connector) { 2831c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae DRM_ERROR("failed to allocate connector\n"); 2841c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae return NULL; 2851c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae } 2861c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 2871c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae connector = &exynos_connector->drm_connector; 2881c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 28974ccc539bcebdb24afb74194223f92a96a7285edInki Dae switch (manager->display_ops->type) { 2901c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae case EXYNOS_DISPLAY_TYPE_HDMI: 2911c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae type = DRM_MODE_CONNECTOR_HDMIA; 2921b17b206560c433ae9e8f8409f3f3842949a74c8Seung-Woo Kim connector->interlace_allowed = true; 2931b17b206560c433ae9e8f8409f3f3842949a74c8Seung-Woo Kim connector->polled = DRM_CONNECTOR_POLL_HPD; 2941c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae break; 2951c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae default: 2961c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae type = DRM_MODE_CONNECTOR_Unknown; 2971c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae break; 2981c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae } 2991c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 3001c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae drm_connector_init(dev, connector, &exynos_connector_funcs, type); 3011c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae drm_connector_helper_add(connector, &exynos_connector_helper_funcs); 3021c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 3031c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae err = drm_sysfs_connector_add(connector); 3041c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae if (err) 3051c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae goto err_connector; 3061c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 307adb6b1596743e93e50fad2ff26d9604cda4361abInki Dae exynos_connector->encoder_id = encoder->base.id; 308adb6b1596743e93e50fad2ff26d9604cda4361abInki Dae exynos_connector->manager = manager; 3091c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae connector->encoder = encoder; 310adb6b1596743e93e50fad2ff26d9604cda4361abInki Dae 3111c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae err = drm_mode_connector_attach_encoder(connector, encoder); 3121c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae if (err) { 3131c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae DRM_ERROR("failed to attach a connector to a encoder\n"); 3141c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae goto err_sysfs; 3151c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae } 3161c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 3171c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae DRM_DEBUG_KMS("connector has been created\n"); 3181c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 3191c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae return connector; 3201c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 3211c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Daeerr_sysfs: 3221c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae drm_sysfs_connector_remove(connector); 3231c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Daeerr_connector: 3241c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae drm_connector_cleanup(connector); 3251c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae kfree(exynos_connector); 3261c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae return NULL; 3271c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae} 3281c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki Dae 3291c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki DaeMODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>"); 3301c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki DaeMODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>"); 3311c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki DaeMODULE_AUTHOR("Seung-Woo Kim <sw0312.kim@samsung.com>"); 3321c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki DaeMODULE_DESCRIPTION("Samsung SoC DRM Connector Driver"); 3331c248b7d2960faec3e1b8f3f9c5d9d0df28e0a3cInki DaeMODULE_LICENSE("GPL"); 334