18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright © 2006-2011 Intel Corporation 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 58c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 68c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation 78c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 88c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 98c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice (including the next 128c2ecf20Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 138c2ecf20Sopenharmony_ci * Software. 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 168c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 178c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 188c2ecf20Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 198c2ecf20Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 208c2ecf20Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 218c2ecf20Sopenharmony_ci * DEALINGS IN THE SOFTWARE. 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * Authors: 248c2ecf20Sopenharmony_ci * jim liu <jim.liu@intel.com> 258c2ecf20Sopenharmony_ci * 268c2ecf20Sopenharmony_ci * FIXME: 278c2ecf20Sopenharmony_ci * We should probably make this generic and share it with Medfield 288c2ecf20Sopenharmony_ci */ 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#include <drm/drm.h> 338c2ecf20Sopenharmony_ci#include <drm/drm_crtc.h> 348c2ecf20Sopenharmony_ci#include <drm/drm_edid.h> 358c2ecf20Sopenharmony_ci#include <drm/drm_simple_kms_helper.h> 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#include "cdv_device.h" 388c2ecf20Sopenharmony_ci#include "psb_drv.h" 398c2ecf20Sopenharmony_ci#include "psb_intel_drv.h" 408c2ecf20Sopenharmony_ci#include "psb_intel_reg.h" 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* hdmi control bits */ 438c2ecf20Sopenharmony_ci#define HDMI_NULL_PACKETS_DURING_VSYNC (1 << 9) 448c2ecf20Sopenharmony_ci#define HDMI_BORDER_ENABLE (1 << 7) 458c2ecf20Sopenharmony_ci#define HDMI_AUDIO_ENABLE (1 << 6) 468c2ecf20Sopenharmony_ci#define HDMI_VSYNC_ACTIVE_HIGH (1 << 4) 478c2ecf20Sopenharmony_ci#define HDMI_HSYNC_ACTIVE_HIGH (1 << 3) 488c2ecf20Sopenharmony_ci/* hdmi-b control bits */ 498c2ecf20Sopenharmony_ci#define HDMIB_PIPE_B_SELECT (1 << 30) 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistruct mid_intel_hdmi_priv { 538c2ecf20Sopenharmony_ci u32 hdmi_reg; 548c2ecf20Sopenharmony_ci u32 save_HDMIB; 558c2ecf20Sopenharmony_ci bool has_hdmi_sink; 568c2ecf20Sopenharmony_ci bool has_hdmi_audio; 578c2ecf20Sopenharmony_ci /* Should set this when detect hotplug */ 588c2ecf20Sopenharmony_ci bool hdmi_device_connected; 598c2ecf20Sopenharmony_ci struct mdfld_hdmi_i2c *i2c_bus; 608c2ecf20Sopenharmony_ci struct i2c_adapter *hdmi_i2c_adapter; /* for control functions */ 618c2ecf20Sopenharmony_ci struct drm_device *dev; 628c2ecf20Sopenharmony_ci}; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic void cdv_hdmi_mode_set(struct drm_encoder *encoder, 658c2ecf20Sopenharmony_ci struct drm_display_mode *mode, 668c2ecf20Sopenharmony_ci struct drm_display_mode *adjusted_mode) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 698c2ecf20Sopenharmony_ci struct gma_encoder *gma_encoder = to_gma_encoder(encoder); 708c2ecf20Sopenharmony_ci struct mid_intel_hdmi_priv *hdmi_priv = gma_encoder->dev_priv; 718c2ecf20Sopenharmony_ci u32 hdmib; 728c2ecf20Sopenharmony_ci struct drm_crtc *crtc = encoder->crtc; 738c2ecf20Sopenharmony_ci struct gma_crtc *gma_crtc = to_gma_crtc(crtc); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci hdmib = (2 << 10); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) 788c2ecf20Sopenharmony_ci hdmib |= HDMI_VSYNC_ACTIVE_HIGH; 798c2ecf20Sopenharmony_ci if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) 808c2ecf20Sopenharmony_ci hdmib |= HDMI_HSYNC_ACTIVE_HIGH; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci if (gma_crtc->pipe == 1) 838c2ecf20Sopenharmony_ci hdmib |= HDMIB_PIPE_B_SELECT; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci if (hdmi_priv->has_hdmi_audio) { 868c2ecf20Sopenharmony_ci hdmib |= HDMI_AUDIO_ENABLE; 878c2ecf20Sopenharmony_ci hdmib |= HDMI_NULL_PACKETS_DURING_VSYNC; 888c2ecf20Sopenharmony_ci } 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci REG_WRITE(hdmi_priv->hdmi_reg, hdmib); 918c2ecf20Sopenharmony_ci REG_READ(hdmi_priv->hdmi_reg); 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic void cdv_hdmi_dpms(struct drm_encoder *encoder, int mode) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 978c2ecf20Sopenharmony_ci struct gma_encoder *gma_encoder = to_gma_encoder(encoder); 988c2ecf20Sopenharmony_ci struct mid_intel_hdmi_priv *hdmi_priv = gma_encoder->dev_priv; 998c2ecf20Sopenharmony_ci u32 hdmib; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci hdmib = REG_READ(hdmi_priv->hdmi_reg); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci if (mode != DRM_MODE_DPMS_ON) 1048c2ecf20Sopenharmony_ci REG_WRITE(hdmi_priv->hdmi_reg, hdmib & ~HDMIB_PORT_EN); 1058c2ecf20Sopenharmony_ci else 1068c2ecf20Sopenharmony_ci REG_WRITE(hdmi_priv->hdmi_reg, hdmib | HDMIB_PORT_EN); 1078c2ecf20Sopenharmony_ci REG_READ(hdmi_priv->hdmi_reg); 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistatic void cdv_hdmi_save(struct drm_connector *connector) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci struct drm_device *dev = connector->dev; 1138c2ecf20Sopenharmony_ci struct gma_encoder *gma_encoder = gma_attached_encoder(connector); 1148c2ecf20Sopenharmony_ci struct mid_intel_hdmi_priv *hdmi_priv = gma_encoder->dev_priv; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci hdmi_priv->save_HDMIB = REG_READ(hdmi_priv->hdmi_reg); 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cistatic void cdv_hdmi_restore(struct drm_connector *connector) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci struct drm_device *dev = connector->dev; 1228c2ecf20Sopenharmony_ci struct gma_encoder *gma_encoder = gma_attached_encoder(connector); 1238c2ecf20Sopenharmony_ci struct mid_intel_hdmi_priv *hdmi_priv = gma_encoder->dev_priv; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci REG_WRITE(hdmi_priv->hdmi_reg, hdmi_priv->save_HDMIB); 1268c2ecf20Sopenharmony_ci REG_READ(hdmi_priv->hdmi_reg); 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic enum drm_connector_status cdv_hdmi_detect( 1308c2ecf20Sopenharmony_ci struct drm_connector *connector, bool force) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci struct gma_encoder *gma_encoder = gma_attached_encoder(connector); 1338c2ecf20Sopenharmony_ci struct mid_intel_hdmi_priv *hdmi_priv = gma_encoder->dev_priv; 1348c2ecf20Sopenharmony_ci struct edid *edid = NULL; 1358c2ecf20Sopenharmony_ci enum drm_connector_status status = connector_status_disconnected; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci edid = drm_get_edid(connector, &gma_encoder->i2c_bus->adapter); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci hdmi_priv->has_hdmi_sink = false; 1408c2ecf20Sopenharmony_ci hdmi_priv->has_hdmi_audio = false; 1418c2ecf20Sopenharmony_ci if (edid) { 1428c2ecf20Sopenharmony_ci if (edid->input & DRM_EDID_INPUT_DIGITAL) { 1438c2ecf20Sopenharmony_ci status = connector_status_connected; 1448c2ecf20Sopenharmony_ci hdmi_priv->has_hdmi_sink = 1458c2ecf20Sopenharmony_ci drm_detect_hdmi_monitor(edid); 1468c2ecf20Sopenharmony_ci hdmi_priv->has_hdmi_audio = 1478c2ecf20Sopenharmony_ci drm_detect_monitor_audio(edid); 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci kfree(edid); 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci return status; 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_cistatic int cdv_hdmi_set_property(struct drm_connector *connector, 1558c2ecf20Sopenharmony_ci struct drm_property *property, 1568c2ecf20Sopenharmony_ci uint64_t value) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci struct drm_encoder *encoder = connector->encoder; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci if (!strcmp(property->name, "scaling mode") && encoder) { 1618c2ecf20Sopenharmony_ci struct gma_crtc *crtc = to_gma_crtc(encoder->crtc); 1628c2ecf20Sopenharmony_ci bool centre; 1638c2ecf20Sopenharmony_ci uint64_t curValue; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci if (!crtc) 1668c2ecf20Sopenharmony_ci return -1; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci switch (value) { 1698c2ecf20Sopenharmony_ci case DRM_MODE_SCALE_FULLSCREEN: 1708c2ecf20Sopenharmony_ci break; 1718c2ecf20Sopenharmony_ci case DRM_MODE_SCALE_NO_SCALE: 1728c2ecf20Sopenharmony_ci break; 1738c2ecf20Sopenharmony_ci case DRM_MODE_SCALE_ASPECT: 1748c2ecf20Sopenharmony_ci break; 1758c2ecf20Sopenharmony_ci default: 1768c2ecf20Sopenharmony_ci return -1; 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci if (drm_object_property_get_value(&connector->base, 1808c2ecf20Sopenharmony_ci property, &curValue)) 1818c2ecf20Sopenharmony_ci return -1; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci if (curValue == value) 1848c2ecf20Sopenharmony_ci return 0; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci if (drm_object_property_set_value(&connector->base, 1878c2ecf20Sopenharmony_ci property, value)) 1888c2ecf20Sopenharmony_ci return -1; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci centre = (curValue == DRM_MODE_SCALE_NO_SCALE) || 1918c2ecf20Sopenharmony_ci (value == DRM_MODE_SCALE_NO_SCALE); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci if (crtc->saved_mode.hdisplay != 0 && 1948c2ecf20Sopenharmony_ci crtc->saved_mode.vdisplay != 0) { 1958c2ecf20Sopenharmony_ci if (centre) { 1968c2ecf20Sopenharmony_ci if (!drm_crtc_helper_set_mode(encoder->crtc, &crtc->saved_mode, 1978c2ecf20Sopenharmony_ci encoder->crtc->x, encoder->crtc->y, encoder->crtc->primary->fb)) 1988c2ecf20Sopenharmony_ci return -1; 1998c2ecf20Sopenharmony_ci } else { 2008c2ecf20Sopenharmony_ci const struct drm_encoder_helper_funcs *helpers 2018c2ecf20Sopenharmony_ci = encoder->helper_private; 2028c2ecf20Sopenharmony_ci helpers->mode_set(encoder, &crtc->saved_mode, 2038c2ecf20Sopenharmony_ci &crtc->saved_adjusted_mode); 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci return 0; 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci/* 2118c2ecf20Sopenharmony_ci * Return the list of HDMI DDC modes if available. 2128c2ecf20Sopenharmony_ci */ 2138c2ecf20Sopenharmony_cistatic int cdv_hdmi_get_modes(struct drm_connector *connector) 2148c2ecf20Sopenharmony_ci{ 2158c2ecf20Sopenharmony_ci struct gma_encoder *gma_encoder = gma_attached_encoder(connector); 2168c2ecf20Sopenharmony_ci struct edid *edid = NULL; 2178c2ecf20Sopenharmony_ci int ret = 0; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci edid = drm_get_edid(connector, &gma_encoder->i2c_bus->adapter); 2208c2ecf20Sopenharmony_ci if (edid) { 2218c2ecf20Sopenharmony_ci drm_connector_update_edid_property(connector, edid); 2228c2ecf20Sopenharmony_ci ret = drm_add_edid_modes(connector, edid); 2238c2ecf20Sopenharmony_ci kfree(edid); 2248c2ecf20Sopenharmony_ci } 2258c2ecf20Sopenharmony_ci return ret; 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_cistatic enum drm_mode_status cdv_hdmi_mode_valid(struct drm_connector *connector, 2298c2ecf20Sopenharmony_ci struct drm_display_mode *mode) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci if (mode->clock > 165000) 2328c2ecf20Sopenharmony_ci return MODE_CLOCK_HIGH; 2338c2ecf20Sopenharmony_ci if (mode->clock < 20000) 2348c2ecf20Sopenharmony_ci return MODE_CLOCK_HIGH; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci /* just in case */ 2378c2ecf20Sopenharmony_ci if (mode->flags & DRM_MODE_FLAG_DBLSCAN) 2388c2ecf20Sopenharmony_ci return MODE_NO_DBLESCAN; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci /* just in case */ 2418c2ecf20Sopenharmony_ci if (mode->flags & DRM_MODE_FLAG_INTERLACE) 2428c2ecf20Sopenharmony_ci return MODE_NO_INTERLACE; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci return MODE_OK; 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistatic void cdv_hdmi_destroy(struct drm_connector *connector) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci struct gma_encoder *gma_encoder = gma_attached_encoder(connector); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci psb_intel_i2c_destroy(gma_encoder->i2c_bus); 2528c2ecf20Sopenharmony_ci drm_connector_unregister(connector); 2538c2ecf20Sopenharmony_ci drm_connector_cleanup(connector); 2548c2ecf20Sopenharmony_ci kfree(connector); 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_cistatic const struct drm_encoder_helper_funcs cdv_hdmi_helper_funcs = { 2588c2ecf20Sopenharmony_ci .dpms = cdv_hdmi_dpms, 2598c2ecf20Sopenharmony_ci .prepare = gma_encoder_prepare, 2608c2ecf20Sopenharmony_ci .mode_set = cdv_hdmi_mode_set, 2618c2ecf20Sopenharmony_ci .commit = gma_encoder_commit, 2628c2ecf20Sopenharmony_ci}; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_cistatic const struct drm_connector_helper_funcs 2658c2ecf20Sopenharmony_ci cdv_hdmi_connector_helper_funcs = { 2668c2ecf20Sopenharmony_ci .get_modes = cdv_hdmi_get_modes, 2678c2ecf20Sopenharmony_ci .mode_valid = cdv_hdmi_mode_valid, 2688c2ecf20Sopenharmony_ci .best_encoder = gma_best_encoder, 2698c2ecf20Sopenharmony_ci}; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistatic const struct drm_connector_funcs cdv_hdmi_connector_funcs = { 2728c2ecf20Sopenharmony_ci .dpms = drm_helper_connector_dpms, 2738c2ecf20Sopenharmony_ci .detect = cdv_hdmi_detect, 2748c2ecf20Sopenharmony_ci .fill_modes = drm_helper_probe_single_connector_modes, 2758c2ecf20Sopenharmony_ci .set_property = cdv_hdmi_set_property, 2768c2ecf20Sopenharmony_ci .destroy = cdv_hdmi_destroy, 2778c2ecf20Sopenharmony_ci}; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_civoid cdv_hdmi_init(struct drm_device *dev, 2808c2ecf20Sopenharmony_ci struct psb_intel_mode_device *mode_dev, int reg) 2818c2ecf20Sopenharmony_ci{ 2828c2ecf20Sopenharmony_ci struct gma_encoder *gma_encoder; 2838c2ecf20Sopenharmony_ci struct gma_connector *gma_connector; 2848c2ecf20Sopenharmony_ci struct drm_connector *connector; 2858c2ecf20Sopenharmony_ci struct drm_encoder *encoder; 2868c2ecf20Sopenharmony_ci struct mid_intel_hdmi_priv *hdmi_priv; 2878c2ecf20Sopenharmony_ci int ddc_bus; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci gma_encoder = kzalloc(sizeof(struct gma_encoder), GFP_KERNEL); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci if (!gma_encoder) 2928c2ecf20Sopenharmony_ci return; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci gma_connector = kzalloc(sizeof(struct gma_connector), 2958c2ecf20Sopenharmony_ci GFP_KERNEL); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci if (!gma_connector) 2988c2ecf20Sopenharmony_ci goto err_connector; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci hdmi_priv = kzalloc(sizeof(struct mid_intel_hdmi_priv), GFP_KERNEL); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci if (!hdmi_priv) 3038c2ecf20Sopenharmony_ci goto err_priv; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci connector = &gma_connector->base; 3068c2ecf20Sopenharmony_ci connector->polled = DRM_CONNECTOR_POLL_HPD; 3078c2ecf20Sopenharmony_ci gma_connector->save = cdv_hdmi_save; 3088c2ecf20Sopenharmony_ci gma_connector->restore = cdv_hdmi_restore; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci encoder = &gma_encoder->base; 3118c2ecf20Sopenharmony_ci drm_connector_init(dev, connector, 3128c2ecf20Sopenharmony_ci &cdv_hdmi_connector_funcs, 3138c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_DVID); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_TMDS); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci gma_connector_attach_encoder(gma_connector, gma_encoder); 3188c2ecf20Sopenharmony_ci gma_encoder->type = INTEL_OUTPUT_HDMI; 3198c2ecf20Sopenharmony_ci hdmi_priv->hdmi_reg = reg; 3208c2ecf20Sopenharmony_ci hdmi_priv->has_hdmi_sink = false; 3218c2ecf20Sopenharmony_ci gma_encoder->dev_priv = hdmi_priv; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci drm_encoder_helper_add(encoder, &cdv_hdmi_helper_funcs); 3248c2ecf20Sopenharmony_ci drm_connector_helper_add(connector, 3258c2ecf20Sopenharmony_ci &cdv_hdmi_connector_helper_funcs); 3268c2ecf20Sopenharmony_ci connector->display_info.subpixel_order = SubPixelHorizontalRGB; 3278c2ecf20Sopenharmony_ci connector->interlace_allowed = false; 3288c2ecf20Sopenharmony_ci connector->doublescan_allowed = false; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci drm_object_attach_property(&connector->base, 3318c2ecf20Sopenharmony_ci dev->mode_config.scaling_mode_property, 3328c2ecf20Sopenharmony_ci DRM_MODE_SCALE_FULLSCREEN); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci switch (reg) { 3358c2ecf20Sopenharmony_ci case SDVOB: 3368c2ecf20Sopenharmony_ci ddc_bus = GPIOE; 3378c2ecf20Sopenharmony_ci gma_encoder->ddi_select = DDI0_SELECT; 3388c2ecf20Sopenharmony_ci break; 3398c2ecf20Sopenharmony_ci case SDVOC: 3408c2ecf20Sopenharmony_ci ddc_bus = GPIOD; 3418c2ecf20Sopenharmony_ci gma_encoder->ddi_select = DDI1_SELECT; 3428c2ecf20Sopenharmony_ci break; 3438c2ecf20Sopenharmony_ci default: 3448c2ecf20Sopenharmony_ci DRM_ERROR("unknown reg 0x%x for HDMI\n", reg); 3458c2ecf20Sopenharmony_ci goto failed_ddc; 3468c2ecf20Sopenharmony_ci break; 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci gma_encoder->i2c_bus = psb_intel_i2c_create(dev, 3508c2ecf20Sopenharmony_ci ddc_bus, (reg == SDVOB) ? "HDMIB" : "HDMIC"); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci if (!gma_encoder->i2c_bus) { 3538c2ecf20Sopenharmony_ci dev_err(dev->dev, "No ddc adapter available!\n"); 3548c2ecf20Sopenharmony_ci goto failed_ddc; 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci hdmi_priv->hdmi_i2c_adapter = &(gma_encoder->i2c_bus->adapter); 3588c2ecf20Sopenharmony_ci hdmi_priv->dev = dev; 3598c2ecf20Sopenharmony_ci drm_connector_register(connector); 3608c2ecf20Sopenharmony_ci return; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_cifailed_ddc: 3638c2ecf20Sopenharmony_ci drm_encoder_cleanup(encoder); 3648c2ecf20Sopenharmony_ci drm_connector_cleanup(connector); 3658c2ecf20Sopenharmony_cierr_priv: 3668c2ecf20Sopenharmony_ci kfree(gma_connector); 3678c2ecf20Sopenharmony_cierr_connector: 3688c2ecf20Sopenharmony_ci kfree(gma_encoder); 3698c2ecf20Sopenharmony_ci} 370