Path: blob/master/drivers/gpu/drm/i915/intel_dvo.c
15112 views
/*1* Copyright 2006 Dave Airlie <[email protected]>2* Copyright © 2006-2007 Intel Corporation3*4* Permission is hereby granted, free of charge, to any person obtaining a5* copy of this software and associated documentation files (the "Software"),6* to deal in the Software without restriction, including without limitation7* the rights to use, copy, modify, merge, publish, distribute, sublicense,8* and/or sell copies of the Software, and to permit persons to whom the9* Software is furnished to do so, subject to the following conditions:10*11* The above copyright notice and this permission notice (including the next12* paragraph) shall be included in all copies or substantial portions of the13* Software.14*15* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR16* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,17* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL18* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER19* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING20* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER21* DEALINGS IN THE SOFTWARE.22*23* Authors:24* Eric Anholt <[email protected]>25*/26#include <linux/i2c.h>27#include <linux/slab.h>28#include "drmP.h"29#include "drm.h"30#include "drm_crtc.h"31#include "intel_drv.h"32#include "i915_drm.h"33#include "i915_drv.h"34#include "dvo.h"3536#define SIL164_ADDR 0x3837#define CH7xxx_ADDR 0x7638#define TFP410_ADDR 0x383940static const struct intel_dvo_device intel_dvo_devices[] = {41{42.type = INTEL_DVO_CHIP_TMDS,43.name = "sil164",44.dvo_reg = DVOC,45.slave_addr = SIL164_ADDR,46.dev_ops = &sil164_ops,47},48{49.type = INTEL_DVO_CHIP_TMDS,50.name = "ch7xxx",51.dvo_reg = DVOC,52.slave_addr = CH7xxx_ADDR,53.dev_ops = &ch7xxx_ops,54},55{56.type = INTEL_DVO_CHIP_LVDS,57.name = "ivch",58.dvo_reg = DVOA,59.slave_addr = 0x02, /* Might also be 0x44, 0x84, 0xc4 */60.dev_ops = &ivch_ops,61},62{63.type = INTEL_DVO_CHIP_TMDS,64.name = "tfp410",65.dvo_reg = DVOC,66.slave_addr = TFP410_ADDR,67.dev_ops = &tfp410_ops,68},69{70.type = INTEL_DVO_CHIP_LVDS,71.name = "ch7017",72.dvo_reg = DVOC,73.slave_addr = 0x75,74.gpio = GMBUS_PORT_DPB,75.dev_ops = &ch7017_ops,76}77};7879struct intel_dvo {80struct intel_encoder base;8182struct intel_dvo_device dev;8384struct drm_display_mode *panel_fixed_mode;85bool panel_wants_dither;86};8788static struct intel_dvo *enc_to_intel_dvo(struct drm_encoder *encoder)89{90return container_of(encoder, struct intel_dvo, base.base);91}9293static struct intel_dvo *intel_attached_dvo(struct drm_connector *connector)94{95return container_of(intel_attached_encoder(connector),96struct intel_dvo, base);97}9899static void intel_dvo_dpms(struct drm_encoder *encoder, int mode)100{101struct drm_i915_private *dev_priv = encoder->dev->dev_private;102struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder);103u32 dvo_reg = intel_dvo->dev.dvo_reg;104u32 temp = I915_READ(dvo_reg);105106if (mode == DRM_MODE_DPMS_ON) {107I915_WRITE(dvo_reg, temp | DVO_ENABLE);108I915_READ(dvo_reg);109intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, mode);110} else {111intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, mode);112I915_WRITE(dvo_reg, temp & ~DVO_ENABLE);113I915_READ(dvo_reg);114}115}116117static int intel_dvo_mode_valid(struct drm_connector *connector,118struct drm_display_mode *mode)119{120struct intel_dvo *intel_dvo = intel_attached_dvo(connector);121122if (mode->flags & DRM_MODE_FLAG_DBLSCAN)123return MODE_NO_DBLESCAN;124125/* XXX: Validate clock range */126127if (intel_dvo->panel_fixed_mode) {128if (mode->hdisplay > intel_dvo->panel_fixed_mode->hdisplay)129return MODE_PANEL;130if (mode->vdisplay > intel_dvo->panel_fixed_mode->vdisplay)131return MODE_PANEL;132}133134return intel_dvo->dev.dev_ops->mode_valid(&intel_dvo->dev, mode);135}136137static bool intel_dvo_mode_fixup(struct drm_encoder *encoder,138struct drm_display_mode *mode,139struct drm_display_mode *adjusted_mode)140{141struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder);142143/* If we have timings from the BIOS for the panel, put them in144* to the adjusted mode. The CRTC will be set up for this mode,145* with the panel scaling set up to source from the H/VDisplay146* of the original mode.147*/148if (intel_dvo->panel_fixed_mode != NULL) {149#define C(x) adjusted_mode->x = intel_dvo->panel_fixed_mode->x150C(hdisplay);151C(hsync_start);152C(hsync_end);153C(htotal);154C(vdisplay);155C(vsync_start);156C(vsync_end);157C(vtotal);158C(clock);159drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);160#undef C161}162163if (intel_dvo->dev.dev_ops->mode_fixup)164return intel_dvo->dev.dev_ops->mode_fixup(&intel_dvo->dev, mode, adjusted_mode);165166return true;167}168169static void intel_dvo_mode_set(struct drm_encoder *encoder,170struct drm_display_mode *mode,171struct drm_display_mode *adjusted_mode)172{173struct drm_device *dev = encoder->dev;174struct drm_i915_private *dev_priv = dev->dev_private;175struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);176struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder);177int pipe = intel_crtc->pipe;178u32 dvo_val;179u32 dvo_reg = intel_dvo->dev.dvo_reg, dvo_srcdim_reg;180int dpll_reg = DPLL(pipe);181182switch (dvo_reg) {183case DVOA:184default:185dvo_srcdim_reg = DVOA_SRCDIM;186break;187case DVOB:188dvo_srcdim_reg = DVOB_SRCDIM;189break;190case DVOC:191dvo_srcdim_reg = DVOC_SRCDIM;192break;193}194195intel_dvo->dev.dev_ops->mode_set(&intel_dvo->dev, mode, adjusted_mode);196197/* Save the data order, since I don't know what it should be set to. */198dvo_val = I915_READ(dvo_reg) &199(DVO_PRESERVE_MASK | DVO_DATA_ORDER_GBRG);200dvo_val |= DVO_DATA_ORDER_FP | DVO_BORDER_ENABLE |201DVO_BLANK_ACTIVE_HIGH;202203if (pipe == 1)204dvo_val |= DVO_PIPE_B_SELECT;205dvo_val |= DVO_PIPE_STALL;206if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)207dvo_val |= DVO_HSYNC_ACTIVE_HIGH;208if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)209dvo_val |= DVO_VSYNC_ACTIVE_HIGH;210211I915_WRITE(dpll_reg, I915_READ(dpll_reg) | DPLL_DVO_HIGH_SPEED);212213/*I915_WRITE(DVOB_SRCDIM,214(adjusted_mode->hdisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) |215(adjusted_mode->VDisplay << DVO_SRCDIM_VERTICAL_SHIFT));*/216I915_WRITE(dvo_srcdim_reg,217(adjusted_mode->hdisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) |218(adjusted_mode->vdisplay << DVO_SRCDIM_VERTICAL_SHIFT));219/*I915_WRITE(DVOB, dvo_val);*/220I915_WRITE(dvo_reg, dvo_val);221}222223/**224* Detect the output connection on our DVO device.225*226* Unimplemented.227*/228static enum drm_connector_status229intel_dvo_detect(struct drm_connector *connector, bool force)230{231struct intel_dvo *intel_dvo = intel_attached_dvo(connector);232return intel_dvo->dev.dev_ops->detect(&intel_dvo->dev);233}234235static int intel_dvo_get_modes(struct drm_connector *connector)236{237struct intel_dvo *intel_dvo = intel_attached_dvo(connector);238struct drm_i915_private *dev_priv = connector->dev->dev_private;239240/* We should probably have an i2c driver get_modes function for those241* devices which will have a fixed set of modes determined by the chip242* (TV-out, for example), but for now with just TMDS and LVDS,243* that's not the case.244*/245intel_ddc_get_modes(connector,246&dev_priv->gmbus[GMBUS_PORT_DPC].adapter);247if (!list_empty(&connector->probed_modes))248return 1;249250if (intel_dvo->panel_fixed_mode != NULL) {251struct drm_display_mode *mode;252mode = drm_mode_duplicate(connector->dev, intel_dvo->panel_fixed_mode);253if (mode) {254drm_mode_probed_add(connector, mode);255return 1;256}257}258259return 0;260}261262static void intel_dvo_destroy(struct drm_connector *connector)263{264drm_sysfs_connector_remove(connector);265drm_connector_cleanup(connector);266kfree(connector);267}268269static const struct drm_encoder_helper_funcs intel_dvo_helper_funcs = {270.dpms = intel_dvo_dpms,271.mode_fixup = intel_dvo_mode_fixup,272.prepare = intel_encoder_prepare,273.mode_set = intel_dvo_mode_set,274.commit = intel_encoder_commit,275};276277static const struct drm_connector_funcs intel_dvo_connector_funcs = {278.dpms = drm_helper_connector_dpms,279.detect = intel_dvo_detect,280.destroy = intel_dvo_destroy,281.fill_modes = drm_helper_probe_single_connector_modes,282};283284static const struct drm_connector_helper_funcs intel_dvo_connector_helper_funcs = {285.mode_valid = intel_dvo_mode_valid,286.get_modes = intel_dvo_get_modes,287.best_encoder = intel_best_encoder,288};289290static void intel_dvo_enc_destroy(struct drm_encoder *encoder)291{292struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder);293294if (intel_dvo->dev.dev_ops->destroy)295intel_dvo->dev.dev_ops->destroy(&intel_dvo->dev);296297kfree(intel_dvo->panel_fixed_mode);298299intel_encoder_destroy(encoder);300}301302static const struct drm_encoder_funcs intel_dvo_enc_funcs = {303.destroy = intel_dvo_enc_destroy,304};305306/**307* Attempts to get a fixed panel timing for LVDS (currently only the i830).308*309* Other chips with DVO LVDS will need to extend this to deal with the LVDS310* chip being on DVOB/C and having multiple pipes.311*/312static struct drm_display_mode *313intel_dvo_get_current_mode(struct drm_connector *connector)314{315struct drm_device *dev = connector->dev;316struct drm_i915_private *dev_priv = dev->dev_private;317struct intel_dvo *intel_dvo = intel_attached_dvo(connector);318uint32_t dvo_val = I915_READ(intel_dvo->dev.dvo_reg);319struct drm_display_mode *mode = NULL;320321/* If the DVO port is active, that'll be the LVDS, so we can pull out322* its timings to get how the BIOS set up the panel.323*/324if (dvo_val & DVO_ENABLE) {325struct drm_crtc *crtc;326int pipe = (dvo_val & DVO_PIPE_B_SELECT) ? 1 : 0;327328crtc = intel_get_crtc_for_pipe(dev, pipe);329if (crtc) {330mode = intel_crtc_mode_get(dev, crtc);331if (mode) {332mode->type |= DRM_MODE_TYPE_PREFERRED;333if (dvo_val & DVO_HSYNC_ACTIVE_HIGH)334mode->flags |= DRM_MODE_FLAG_PHSYNC;335if (dvo_val & DVO_VSYNC_ACTIVE_HIGH)336mode->flags |= DRM_MODE_FLAG_PVSYNC;337}338}339}340341return mode;342}343344void intel_dvo_init(struct drm_device *dev)345{346struct drm_i915_private *dev_priv = dev->dev_private;347struct intel_encoder *intel_encoder;348struct intel_dvo *intel_dvo;349struct intel_connector *intel_connector;350int i;351int encoder_type = DRM_MODE_ENCODER_NONE;352353intel_dvo = kzalloc(sizeof(struct intel_dvo), GFP_KERNEL);354if (!intel_dvo)355return;356357intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL);358if (!intel_connector) {359kfree(intel_dvo);360return;361}362363intel_encoder = &intel_dvo->base;364drm_encoder_init(dev, &intel_encoder->base,365&intel_dvo_enc_funcs, encoder_type);366367/* Now, try to find a controller */368for (i = 0; i < ARRAY_SIZE(intel_dvo_devices); i++) {369struct drm_connector *connector = &intel_connector->base;370const struct intel_dvo_device *dvo = &intel_dvo_devices[i];371struct i2c_adapter *i2c;372int gpio;373374/* Allow the I2C driver info to specify the GPIO to be used in375* special cases, but otherwise default to what's defined376* in the spec.377*/378if (dvo->gpio != 0)379gpio = dvo->gpio;380else if (dvo->type == INTEL_DVO_CHIP_LVDS)381gpio = GMBUS_PORT_SSC;382else383gpio = GMBUS_PORT_DPB;384385/* Set up the I2C bus necessary for the chip we're probing.386* It appears that everything is on GPIOE except for panels387* on i830 laptops, which are on GPIOB (DVOA).388*/389i2c = &dev_priv->gmbus[gpio].adapter;390391intel_dvo->dev = *dvo;392if (!dvo->dev_ops->init(&intel_dvo->dev, i2c))393continue;394395intel_encoder->type = INTEL_OUTPUT_DVO;396intel_encoder->crtc_mask = (1 << 0) | (1 << 1);397switch (dvo->type) {398case INTEL_DVO_CHIP_TMDS:399intel_encoder->clone_mask =400(1 << INTEL_DVO_TMDS_CLONE_BIT) |401(1 << INTEL_ANALOG_CLONE_BIT);402drm_connector_init(dev, connector,403&intel_dvo_connector_funcs,404DRM_MODE_CONNECTOR_DVII);405encoder_type = DRM_MODE_ENCODER_TMDS;406break;407case INTEL_DVO_CHIP_LVDS:408intel_encoder->clone_mask =409(1 << INTEL_DVO_LVDS_CLONE_BIT);410drm_connector_init(dev, connector,411&intel_dvo_connector_funcs,412DRM_MODE_CONNECTOR_LVDS);413encoder_type = DRM_MODE_ENCODER_LVDS;414break;415}416417drm_connector_helper_add(connector,418&intel_dvo_connector_helper_funcs);419connector->display_info.subpixel_order = SubPixelHorizontalRGB;420connector->interlace_allowed = false;421connector->doublescan_allowed = false;422423drm_encoder_helper_add(&intel_encoder->base,424&intel_dvo_helper_funcs);425426intel_connector_attach_encoder(intel_connector, intel_encoder);427if (dvo->type == INTEL_DVO_CHIP_LVDS) {428/* For our LVDS chipsets, we should hopefully be able429* to dig the fixed panel mode out of the BIOS data.430* However, it's in a different format from the BIOS431* data on chipsets with integrated LVDS (stored in AIM432* headers, likely), so for now, just get the current433* mode being output through DVO.434*/435intel_dvo->panel_fixed_mode =436intel_dvo_get_current_mode(connector);437intel_dvo->panel_wants_dither = true;438}439440drm_sysfs_connector_add(connector);441return;442}443444drm_encoder_cleanup(&intel_encoder->base);445kfree(intel_dvo);446kfree(intel_connector);447}448449450