18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright © 2006-2009 Intel Corporation 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Authors: 68c2ecf20Sopenharmony_ci * Eric Anholt <eric@anholt.net> 78c2ecf20Sopenharmony_ci * Dave Airlie <airlied@linux.ie> 88c2ecf20Sopenharmony_ci * Jesse Barnes <jesse.barnes@intel.com> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/i2c.h> 128c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <asm/intel-mid.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <drm/drm_simple_kms_helper.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include "intel_bios.h" 198c2ecf20Sopenharmony_ci#include "power.h" 208c2ecf20Sopenharmony_ci#include "psb_drv.h" 218c2ecf20Sopenharmony_ci#include "psb_intel_drv.h" 228c2ecf20Sopenharmony_ci#include "psb_intel_reg.h" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci/* The max/min PWM frequency in BPCR[31:17] - */ 258c2ecf20Sopenharmony_ci/* The smallest number is 1 (not 0) that can fit in the 268c2ecf20Sopenharmony_ci * 15-bit field of the and then*/ 278c2ecf20Sopenharmony_ci/* shifts to the left by one bit to get the actual 16-bit 288c2ecf20Sopenharmony_ci * value that the 15-bits correspond to.*/ 298c2ecf20Sopenharmony_ci#define MRST_BLC_MAX_PWM_REG_FREQ 0xFFFF 308c2ecf20Sopenharmony_ci#define BRIGHTNESS_MAX_LEVEL 100 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/** 338c2ecf20Sopenharmony_ci * Sets the power state for the panel. 348c2ecf20Sopenharmony_ci */ 358c2ecf20Sopenharmony_cistatic void oaktrail_lvds_set_power(struct drm_device *dev, 368c2ecf20Sopenharmony_ci struct gma_encoder *gma_encoder, 378c2ecf20Sopenharmony_ci bool on) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci u32 pp_status; 408c2ecf20Sopenharmony_ci struct drm_psb_private *dev_priv = dev->dev_private; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci if (!gma_power_begin(dev, true)) 438c2ecf20Sopenharmony_ci return; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci if (on) { 468c2ecf20Sopenharmony_ci REG_WRITE(PP_CONTROL, REG_READ(PP_CONTROL) | 478c2ecf20Sopenharmony_ci POWER_TARGET_ON); 488c2ecf20Sopenharmony_ci do { 498c2ecf20Sopenharmony_ci pp_status = REG_READ(PP_STATUS); 508c2ecf20Sopenharmony_ci } while ((pp_status & (PP_ON | PP_READY)) == PP_READY); 518c2ecf20Sopenharmony_ci dev_priv->is_lvds_on = true; 528c2ecf20Sopenharmony_ci if (dev_priv->ops->lvds_bl_power) 538c2ecf20Sopenharmony_ci dev_priv->ops->lvds_bl_power(dev, true); 548c2ecf20Sopenharmony_ci } else { 558c2ecf20Sopenharmony_ci if (dev_priv->ops->lvds_bl_power) 568c2ecf20Sopenharmony_ci dev_priv->ops->lvds_bl_power(dev, false); 578c2ecf20Sopenharmony_ci REG_WRITE(PP_CONTROL, REG_READ(PP_CONTROL) & 588c2ecf20Sopenharmony_ci ~POWER_TARGET_ON); 598c2ecf20Sopenharmony_ci do { 608c2ecf20Sopenharmony_ci pp_status = REG_READ(PP_STATUS); 618c2ecf20Sopenharmony_ci } while (pp_status & PP_ON); 628c2ecf20Sopenharmony_ci dev_priv->is_lvds_on = false; 638c2ecf20Sopenharmony_ci pm_request_idle(&dev->pdev->dev); 648c2ecf20Sopenharmony_ci } 658c2ecf20Sopenharmony_ci gma_power_end(dev); 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic void oaktrail_lvds_dpms(struct drm_encoder *encoder, int mode) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 718c2ecf20Sopenharmony_ci struct gma_encoder *gma_encoder = to_gma_encoder(encoder); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci if (mode == DRM_MODE_DPMS_ON) 748c2ecf20Sopenharmony_ci oaktrail_lvds_set_power(dev, gma_encoder, true); 758c2ecf20Sopenharmony_ci else 768c2ecf20Sopenharmony_ci oaktrail_lvds_set_power(dev, gma_encoder, false); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci /* XXX: We never power down the LVDS pairs. */ 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic void oaktrail_lvds_mode_set(struct drm_encoder *encoder, 828c2ecf20Sopenharmony_ci struct drm_display_mode *mode, 838c2ecf20Sopenharmony_ci struct drm_display_mode *adjusted_mode) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 868c2ecf20Sopenharmony_ci struct drm_psb_private *dev_priv = dev->dev_private; 878c2ecf20Sopenharmony_ci struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; 888c2ecf20Sopenharmony_ci struct drm_mode_config *mode_config = &dev->mode_config; 898c2ecf20Sopenharmony_ci struct drm_connector *connector = NULL; 908c2ecf20Sopenharmony_ci struct drm_crtc *crtc = encoder->crtc; 918c2ecf20Sopenharmony_ci u32 lvds_port; 928c2ecf20Sopenharmony_ci uint64_t v = DRM_MODE_SCALE_FULLSCREEN; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci if (!gma_power_begin(dev, true)) 958c2ecf20Sopenharmony_ci return; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci /* 988c2ecf20Sopenharmony_ci * The LVDS pin pair will already have been turned on in the 998c2ecf20Sopenharmony_ci * psb_intel_crtc_mode_set since it has a large impact on the DPLL 1008c2ecf20Sopenharmony_ci * settings. 1018c2ecf20Sopenharmony_ci */ 1028c2ecf20Sopenharmony_ci lvds_port = (REG_READ(LVDS) & 1038c2ecf20Sopenharmony_ci (~LVDS_PIPEB_SELECT)) | 1048c2ecf20Sopenharmony_ci LVDS_PORT_EN | 1058c2ecf20Sopenharmony_ci LVDS_BORDER_EN; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci /* If the firmware says dither on Moorestown, or the BIOS does 1088c2ecf20Sopenharmony_ci on Oaktrail then enable dithering */ 1098c2ecf20Sopenharmony_ci if (mode_dev->panel_wants_dither || dev_priv->lvds_dither) 1108c2ecf20Sopenharmony_ci lvds_port |= MRST_PANEL_8TO6_DITHER_ENABLE; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci REG_WRITE(LVDS, lvds_port); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci /* Find the connector we're trying to set up */ 1158c2ecf20Sopenharmony_ci list_for_each_entry(connector, &mode_config->connector_list, head) { 1168c2ecf20Sopenharmony_ci if (!connector->encoder || connector->encoder->crtc != crtc) 1178c2ecf20Sopenharmony_ci continue; 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci if (list_entry_is_head(connector, &mode_config->connector_list, head)) { 1218c2ecf20Sopenharmony_ci DRM_ERROR("Couldn't find connector when setting mode"); 1228c2ecf20Sopenharmony_ci gma_power_end(dev); 1238c2ecf20Sopenharmony_ci return; 1248c2ecf20Sopenharmony_ci } 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci drm_object_property_get_value( 1278c2ecf20Sopenharmony_ci &connector->base, 1288c2ecf20Sopenharmony_ci dev->mode_config.scaling_mode_property, 1298c2ecf20Sopenharmony_ci &v); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci if (v == DRM_MODE_SCALE_NO_SCALE) 1328c2ecf20Sopenharmony_ci REG_WRITE(PFIT_CONTROL, 0); 1338c2ecf20Sopenharmony_ci else if (v == DRM_MODE_SCALE_ASPECT) { 1348c2ecf20Sopenharmony_ci if ((mode->vdisplay != adjusted_mode->crtc_vdisplay) || 1358c2ecf20Sopenharmony_ci (mode->hdisplay != adjusted_mode->crtc_hdisplay)) { 1368c2ecf20Sopenharmony_ci if ((adjusted_mode->crtc_hdisplay * mode->vdisplay) == 1378c2ecf20Sopenharmony_ci (mode->hdisplay * adjusted_mode->crtc_vdisplay)) 1388c2ecf20Sopenharmony_ci REG_WRITE(PFIT_CONTROL, PFIT_ENABLE); 1398c2ecf20Sopenharmony_ci else if ((adjusted_mode->crtc_hdisplay * 1408c2ecf20Sopenharmony_ci mode->vdisplay) > (mode->hdisplay * 1418c2ecf20Sopenharmony_ci adjusted_mode->crtc_vdisplay)) 1428c2ecf20Sopenharmony_ci REG_WRITE(PFIT_CONTROL, PFIT_ENABLE | 1438c2ecf20Sopenharmony_ci PFIT_SCALING_MODE_PILLARBOX); 1448c2ecf20Sopenharmony_ci else 1458c2ecf20Sopenharmony_ci REG_WRITE(PFIT_CONTROL, PFIT_ENABLE | 1468c2ecf20Sopenharmony_ci PFIT_SCALING_MODE_LETTERBOX); 1478c2ecf20Sopenharmony_ci } else 1488c2ecf20Sopenharmony_ci REG_WRITE(PFIT_CONTROL, PFIT_ENABLE); 1498c2ecf20Sopenharmony_ci } else /*(v == DRM_MODE_SCALE_FULLSCREEN)*/ 1508c2ecf20Sopenharmony_ci REG_WRITE(PFIT_CONTROL, PFIT_ENABLE); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci gma_power_end(dev); 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic void oaktrail_lvds_prepare(struct drm_encoder *encoder) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 1588c2ecf20Sopenharmony_ci struct drm_psb_private *dev_priv = dev->dev_private; 1598c2ecf20Sopenharmony_ci struct gma_encoder *gma_encoder = to_gma_encoder(encoder); 1608c2ecf20Sopenharmony_ci struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci if (!gma_power_begin(dev, true)) 1638c2ecf20Sopenharmony_ci return; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci mode_dev->saveBLC_PWM_CTL = REG_READ(BLC_PWM_CTL); 1668c2ecf20Sopenharmony_ci mode_dev->backlight_duty_cycle = (mode_dev->saveBLC_PWM_CTL & 1678c2ecf20Sopenharmony_ci BACKLIGHT_DUTY_CYCLE_MASK); 1688c2ecf20Sopenharmony_ci oaktrail_lvds_set_power(dev, gma_encoder, false); 1698c2ecf20Sopenharmony_ci gma_power_end(dev); 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_cistatic u32 oaktrail_lvds_get_max_backlight(struct drm_device *dev) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci struct drm_psb_private *dev_priv = dev->dev_private; 1758c2ecf20Sopenharmony_ci u32 ret; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci if (gma_power_begin(dev, false)) { 1788c2ecf20Sopenharmony_ci ret = ((REG_READ(BLC_PWM_CTL) & 1798c2ecf20Sopenharmony_ci BACKLIGHT_MODULATION_FREQ_MASK) >> 1808c2ecf20Sopenharmony_ci BACKLIGHT_MODULATION_FREQ_SHIFT) * 2; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci gma_power_end(dev); 1838c2ecf20Sopenharmony_ci } else 1848c2ecf20Sopenharmony_ci ret = ((dev_priv->regs.saveBLC_PWM_CTL & 1858c2ecf20Sopenharmony_ci BACKLIGHT_MODULATION_FREQ_MASK) >> 1868c2ecf20Sopenharmony_ci BACKLIGHT_MODULATION_FREQ_SHIFT) * 2; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci return ret; 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistatic void oaktrail_lvds_commit(struct drm_encoder *encoder) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 1948c2ecf20Sopenharmony_ci struct drm_psb_private *dev_priv = dev->dev_private; 1958c2ecf20Sopenharmony_ci struct gma_encoder *gma_encoder = to_gma_encoder(encoder); 1968c2ecf20Sopenharmony_ci struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci if (mode_dev->backlight_duty_cycle == 0) 1998c2ecf20Sopenharmony_ci mode_dev->backlight_duty_cycle = 2008c2ecf20Sopenharmony_ci oaktrail_lvds_get_max_backlight(dev); 2018c2ecf20Sopenharmony_ci oaktrail_lvds_set_power(dev, gma_encoder, true); 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic const struct drm_encoder_helper_funcs oaktrail_lvds_helper_funcs = { 2058c2ecf20Sopenharmony_ci .dpms = oaktrail_lvds_dpms, 2068c2ecf20Sopenharmony_ci .mode_fixup = psb_intel_lvds_mode_fixup, 2078c2ecf20Sopenharmony_ci .prepare = oaktrail_lvds_prepare, 2088c2ecf20Sopenharmony_ci .mode_set = oaktrail_lvds_mode_set, 2098c2ecf20Sopenharmony_ci .commit = oaktrail_lvds_commit, 2108c2ecf20Sopenharmony_ci}; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci/* Returns the panel fixed mode from configuration. */ 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cistatic void oaktrail_lvds_get_configuration_mode(struct drm_device *dev, 2158c2ecf20Sopenharmony_ci struct psb_intel_mode_device *mode_dev) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci struct drm_display_mode *mode = NULL; 2188c2ecf20Sopenharmony_ci struct drm_psb_private *dev_priv = dev->dev_private; 2198c2ecf20Sopenharmony_ci struct oaktrail_timing_info *ti = &dev_priv->gct_data.DTD; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci mode_dev->panel_fixed_mode = NULL; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci /* Use the firmware provided data on Moorestown */ 2248c2ecf20Sopenharmony_ci if (dev_priv->has_gct) { 2258c2ecf20Sopenharmony_ci mode = kzalloc(sizeof(*mode), GFP_KERNEL); 2268c2ecf20Sopenharmony_ci if (!mode) 2278c2ecf20Sopenharmony_ci return; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci mode->hdisplay = (ti->hactive_hi << 8) | ti->hactive_lo; 2308c2ecf20Sopenharmony_ci mode->vdisplay = (ti->vactive_hi << 8) | ti->vactive_lo; 2318c2ecf20Sopenharmony_ci mode->hsync_start = mode->hdisplay + \ 2328c2ecf20Sopenharmony_ci ((ti->hsync_offset_hi << 8) | \ 2338c2ecf20Sopenharmony_ci ti->hsync_offset_lo); 2348c2ecf20Sopenharmony_ci mode->hsync_end = mode->hsync_start + \ 2358c2ecf20Sopenharmony_ci ((ti->hsync_pulse_width_hi << 8) | \ 2368c2ecf20Sopenharmony_ci ti->hsync_pulse_width_lo); 2378c2ecf20Sopenharmony_ci mode->htotal = mode->hdisplay + ((ti->hblank_hi << 8) | \ 2388c2ecf20Sopenharmony_ci ti->hblank_lo); 2398c2ecf20Sopenharmony_ci mode->vsync_start = \ 2408c2ecf20Sopenharmony_ci mode->vdisplay + ((ti->vsync_offset_hi << 4) | \ 2418c2ecf20Sopenharmony_ci ti->vsync_offset_lo); 2428c2ecf20Sopenharmony_ci mode->vsync_end = \ 2438c2ecf20Sopenharmony_ci mode->vsync_start + ((ti->vsync_pulse_width_hi << 4) | \ 2448c2ecf20Sopenharmony_ci ti->vsync_pulse_width_lo); 2458c2ecf20Sopenharmony_ci mode->vtotal = mode->vdisplay + \ 2468c2ecf20Sopenharmony_ci ((ti->vblank_hi << 8) | ti->vblank_lo); 2478c2ecf20Sopenharmony_ci mode->clock = ti->pixel_clock * 10; 2488c2ecf20Sopenharmony_ci#if 0 2498c2ecf20Sopenharmony_ci pr_info("hdisplay is %d\n", mode->hdisplay); 2508c2ecf20Sopenharmony_ci pr_info("vdisplay is %d\n", mode->vdisplay); 2518c2ecf20Sopenharmony_ci pr_info("HSS is %d\n", mode->hsync_start); 2528c2ecf20Sopenharmony_ci pr_info("HSE is %d\n", mode->hsync_end); 2538c2ecf20Sopenharmony_ci pr_info("htotal is %d\n", mode->htotal); 2548c2ecf20Sopenharmony_ci pr_info("VSS is %d\n", mode->vsync_start); 2558c2ecf20Sopenharmony_ci pr_info("VSE is %d\n", mode->vsync_end); 2568c2ecf20Sopenharmony_ci pr_info("vtotal is %d\n", mode->vtotal); 2578c2ecf20Sopenharmony_ci pr_info("clock is %d\n", mode->clock); 2588c2ecf20Sopenharmony_ci#endif 2598c2ecf20Sopenharmony_ci mode_dev->panel_fixed_mode = mode; 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci /* Use the BIOS VBT mode if available */ 2638c2ecf20Sopenharmony_ci if (mode_dev->panel_fixed_mode == NULL && mode_dev->vbt_mode) 2648c2ecf20Sopenharmony_ci mode_dev->panel_fixed_mode = drm_mode_duplicate(dev, 2658c2ecf20Sopenharmony_ci mode_dev->vbt_mode); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci /* Then try the LVDS VBT mode */ 2688c2ecf20Sopenharmony_ci if (mode_dev->panel_fixed_mode == NULL) 2698c2ecf20Sopenharmony_ci if (dev_priv->lfp_lvds_vbt_mode) 2708c2ecf20Sopenharmony_ci mode_dev->panel_fixed_mode = 2718c2ecf20Sopenharmony_ci drm_mode_duplicate(dev, 2728c2ecf20Sopenharmony_ci dev_priv->lfp_lvds_vbt_mode); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci /* If we still got no mode then bail */ 2758c2ecf20Sopenharmony_ci if (mode_dev->panel_fixed_mode == NULL) 2768c2ecf20Sopenharmony_ci return; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci drm_mode_set_name(mode_dev->panel_fixed_mode); 2798c2ecf20Sopenharmony_ci drm_mode_set_crtcinfo(mode_dev->panel_fixed_mode, 0); 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci/** 2838c2ecf20Sopenharmony_ci * oaktrail_lvds_init - setup LVDS connectors on this device 2848c2ecf20Sopenharmony_ci * @dev: drm device 2858c2ecf20Sopenharmony_ci * 2868c2ecf20Sopenharmony_ci * Create the connector, register the LVDS DDC bus, and try to figure out what 2878c2ecf20Sopenharmony_ci * modes we can display on the LVDS panel (if present). 2888c2ecf20Sopenharmony_ci */ 2898c2ecf20Sopenharmony_civoid oaktrail_lvds_init(struct drm_device *dev, 2908c2ecf20Sopenharmony_ci struct psb_intel_mode_device *mode_dev) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci struct gma_encoder *gma_encoder; 2938c2ecf20Sopenharmony_ci struct gma_connector *gma_connector; 2948c2ecf20Sopenharmony_ci struct drm_connector *connector; 2958c2ecf20Sopenharmony_ci struct drm_encoder *encoder; 2968c2ecf20Sopenharmony_ci struct drm_psb_private *dev_priv = dev->dev_private; 2978c2ecf20Sopenharmony_ci struct edid *edid; 2988c2ecf20Sopenharmony_ci struct i2c_adapter *i2c_adap; 2998c2ecf20Sopenharmony_ci struct drm_display_mode *scan; /* *modes, *bios_mode; */ 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci gma_encoder = kzalloc(sizeof(struct gma_encoder), GFP_KERNEL); 3028c2ecf20Sopenharmony_ci if (!gma_encoder) 3038c2ecf20Sopenharmony_ci return; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci gma_connector = kzalloc(sizeof(struct gma_connector), GFP_KERNEL); 3068c2ecf20Sopenharmony_ci if (!gma_connector) 3078c2ecf20Sopenharmony_ci goto failed_connector; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci connector = &gma_connector->base; 3108c2ecf20Sopenharmony_ci encoder = &gma_encoder->base; 3118c2ecf20Sopenharmony_ci dev_priv->is_lvds_on = true; 3128c2ecf20Sopenharmony_ci drm_connector_init(dev, connector, 3138c2ecf20Sopenharmony_ci &psb_intel_lvds_connector_funcs, 3148c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_LVDS); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_LVDS); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci gma_connector_attach_encoder(gma_connector, gma_encoder); 3198c2ecf20Sopenharmony_ci gma_encoder->type = INTEL_OUTPUT_LVDS; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci drm_encoder_helper_add(encoder, &oaktrail_lvds_helper_funcs); 3228c2ecf20Sopenharmony_ci drm_connector_helper_add(connector, 3238c2ecf20Sopenharmony_ci &psb_intel_lvds_connector_helper_funcs); 3248c2ecf20Sopenharmony_ci connector->display_info.subpixel_order = SubPixelHorizontalRGB; 3258c2ecf20Sopenharmony_ci connector->interlace_allowed = false; 3268c2ecf20Sopenharmony_ci connector->doublescan_allowed = false; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci drm_object_attach_property(&connector->base, 3298c2ecf20Sopenharmony_ci dev->mode_config.scaling_mode_property, 3308c2ecf20Sopenharmony_ci DRM_MODE_SCALE_FULLSCREEN); 3318c2ecf20Sopenharmony_ci drm_object_attach_property(&connector->base, 3328c2ecf20Sopenharmony_ci dev_priv->backlight_property, 3338c2ecf20Sopenharmony_ci BRIGHTNESS_MAX_LEVEL); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci mode_dev->panel_wants_dither = false; 3368c2ecf20Sopenharmony_ci if (dev_priv->has_gct) 3378c2ecf20Sopenharmony_ci mode_dev->panel_wants_dither = (dev_priv->gct_data. 3388c2ecf20Sopenharmony_ci Panel_Port_Control & MRST_PANEL_8TO6_DITHER_ENABLE); 3398c2ecf20Sopenharmony_ci if (dev_priv->lvds_dither) 3408c2ecf20Sopenharmony_ci mode_dev->panel_wants_dither = 1; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci /* 3438c2ecf20Sopenharmony_ci * LVDS discovery: 3448c2ecf20Sopenharmony_ci * 1) check for EDID on DDC 3458c2ecf20Sopenharmony_ci * 2) check for VBT data 3468c2ecf20Sopenharmony_ci * 3) check to see if LVDS is already on 3478c2ecf20Sopenharmony_ci * if none of the above, no panel 3488c2ecf20Sopenharmony_ci * 4) make sure lid is open 3498c2ecf20Sopenharmony_ci * if closed, act like it's not there for now 3508c2ecf20Sopenharmony_ci */ 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci edid = NULL; 3538c2ecf20Sopenharmony_ci mutex_lock(&dev->mode_config.mutex); 3548c2ecf20Sopenharmony_ci i2c_adap = i2c_get_adapter(dev_priv->ops->i2c_bus); 3558c2ecf20Sopenharmony_ci if (i2c_adap) 3568c2ecf20Sopenharmony_ci edid = drm_get_edid(connector, i2c_adap); 3578c2ecf20Sopenharmony_ci if (edid == NULL && dev_priv->lpc_gpio_base) { 3588c2ecf20Sopenharmony_ci oaktrail_lvds_i2c_init(encoder); 3598c2ecf20Sopenharmony_ci if (gma_encoder->ddc_bus != NULL) { 3608c2ecf20Sopenharmony_ci i2c_adap = &gma_encoder->ddc_bus->adapter; 3618c2ecf20Sopenharmony_ci edid = drm_get_edid(connector, i2c_adap); 3628c2ecf20Sopenharmony_ci } 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci /* 3658c2ecf20Sopenharmony_ci * Attempt to get the fixed panel mode from DDC. Assume that the 3668c2ecf20Sopenharmony_ci * preferred mode is the right one. 3678c2ecf20Sopenharmony_ci */ 3688c2ecf20Sopenharmony_ci if (edid) { 3698c2ecf20Sopenharmony_ci drm_connector_update_edid_property(connector, edid); 3708c2ecf20Sopenharmony_ci drm_add_edid_modes(connector, edid); 3718c2ecf20Sopenharmony_ci kfree(edid); 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci list_for_each_entry(scan, &connector->probed_modes, head) { 3748c2ecf20Sopenharmony_ci if (scan->type & DRM_MODE_TYPE_PREFERRED) { 3758c2ecf20Sopenharmony_ci mode_dev->panel_fixed_mode = 3768c2ecf20Sopenharmony_ci drm_mode_duplicate(dev, scan); 3778c2ecf20Sopenharmony_ci goto out; /* FIXME: check for quirks */ 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci } else 3818c2ecf20Sopenharmony_ci dev_err(dev->dev, "No ddc adapter available!\n"); 3828c2ecf20Sopenharmony_ci /* 3838c2ecf20Sopenharmony_ci * If we didn't get EDID, try geting panel timing 3848c2ecf20Sopenharmony_ci * from configuration data 3858c2ecf20Sopenharmony_ci */ 3868c2ecf20Sopenharmony_ci oaktrail_lvds_get_configuration_mode(dev, mode_dev); 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci if (mode_dev->panel_fixed_mode) { 3898c2ecf20Sopenharmony_ci mode_dev->panel_fixed_mode->type |= DRM_MODE_TYPE_PREFERRED; 3908c2ecf20Sopenharmony_ci goto out; /* FIXME: check for quirks */ 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci /* If we still don't have a mode after all that, give up. */ 3948c2ecf20Sopenharmony_ci if (!mode_dev->panel_fixed_mode) { 3958c2ecf20Sopenharmony_ci dev_err(dev->dev, "Found no modes on the lvds, ignoring the LVDS\n"); 3968c2ecf20Sopenharmony_ci goto failed_find; 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ciout: 4008c2ecf20Sopenharmony_ci mutex_unlock(&dev->mode_config.mutex); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci drm_connector_register(connector); 4038c2ecf20Sopenharmony_ci return; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_cifailed_find: 4068c2ecf20Sopenharmony_ci mutex_unlock(&dev->mode_config.mutex); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci dev_dbg(dev->dev, "No LVDS modes found, disabling.\n"); 4098c2ecf20Sopenharmony_ci if (gma_encoder->ddc_bus) { 4108c2ecf20Sopenharmony_ci psb_intel_i2c_destroy(gma_encoder->ddc_bus); 4118c2ecf20Sopenharmony_ci gma_encoder->ddc_bus = NULL; 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci/* failed_ddc: */ 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci drm_encoder_cleanup(encoder); 4178c2ecf20Sopenharmony_ci drm_connector_cleanup(connector); 4188c2ecf20Sopenharmony_ci kfree(gma_connector); 4198c2ecf20Sopenharmony_cifailed_connector: 4208c2ecf20Sopenharmony_ci kfree(gma_encoder); 4218c2ecf20Sopenharmony_ci} 4228c2ecf20Sopenharmony_ci 423