Path: blob/master/drivers/gpu/drm/i915/intel_sdvo.c
15113 views
/*1* Copyright 2006 Dave Airlie <[email protected]>2* Copyright © 2006-2007 Intel Corporation3* Jesse Barnes <[email protected]>4*5* Permission is hereby granted, free of charge, to any person obtaining a6* copy of this software and associated documentation files (the "Software"),7* to deal in the Software without restriction, including without limitation8* the rights to use, copy, modify, merge, publish, distribute, sublicense,9* and/or sell copies of the Software, and to permit persons to whom the10* Software is furnished to do so, subject to the following conditions:11*12* The above copyright notice and this permission notice (including the next13* paragraph) shall be included in all copies or substantial portions of the14* Software.15*16* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR17* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,18* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL19* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER20* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING21* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER22* DEALINGS IN THE SOFTWARE.23*24* Authors:25* Eric Anholt <[email protected]>26*/27#include <linux/i2c.h>28#include <linux/slab.h>29#include <linux/delay.h>30#include "drmP.h"31#include "drm.h"32#include "drm_crtc.h"33#include "drm_edid.h"34#include "intel_drv.h"35#include "i915_drm.h"36#include "i915_drv.h"37#include "intel_sdvo_regs.h"3839#define SDVO_TMDS_MASK (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1)40#define SDVO_RGB_MASK (SDVO_OUTPUT_RGB0 | SDVO_OUTPUT_RGB1)41#define SDVO_LVDS_MASK (SDVO_OUTPUT_LVDS0 | SDVO_OUTPUT_LVDS1)42#define SDVO_TV_MASK (SDVO_OUTPUT_CVBS0 | SDVO_OUTPUT_SVID0)4344#define SDVO_OUTPUT_MASK (SDVO_TMDS_MASK | SDVO_RGB_MASK | SDVO_LVDS_MASK |\45SDVO_TV_MASK)4647#define IS_TV(c) (c->output_flag & SDVO_TV_MASK)48#define IS_TMDS(c) (c->output_flag & SDVO_TMDS_MASK)49#define IS_LVDS(c) (c->output_flag & SDVO_LVDS_MASK)50#define IS_TV_OR_LVDS(c) (c->output_flag & (SDVO_TV_MASK | SDVO_LVDS_MASK))515253static const char *tv_format_names[] = {54"NTSC_M" , "NTSC_J" , "NTSC_443",55"PAL_B" , "PAL_D" , "PAL_G" ,56"PAL_H" , "PAL_I" , "PAL_M" ,57"PAL_N" , "PAL_NC" , "PAL_60" ,58"SECAM_B" , "SECAM_D" , "SECAM_G" ,59"SECAM_K" , "SECAM_K1", "SECAM_L" ,60"SECAM_60"61};6263#define TV_FORMAT_NUM (sizeof(tv_format_names) / sizeof(*tv_format_names))6465struct intel_sdvo {66struct intel_encoder base;6768struct i2c_adapter *i2c;69u8 slave_addr;7071struct i2c_adapter ddc;7273/* Register for the SDVO device: SDVOB or SDVOC */74int sdvo_reg;7576/* Active outputs controlled by this SDVO output */77uint16_t controlled_output;7879/*80* Capabilities of the SDVO device returned by81* i830_sdvo_get_capabilities()82*/83struct intel_sdvo_caps caps;8485/* Pixel clock limitations reported by the SDVO device, in kHz */86int pixel_clock_min, pixel_clock_max;8788/*89* For multiple function SDVO device,90* this is for current attached outputs.91*/92uint16_t attached_output;9394/**95* This is used to select the color range of RBG outputs in HDMI mode.96* It is only valid when using TMDS encoding and 8 bit per color mode.97*/98uint32_t color_range;99100/**101* This is set if we're going to treat the device as TV-out.102*103* While we have these nice friendly flags for output types that ought104* to decide this for us, the S-Video output on our HDMI+S-Video card105* shows up as RGB1 (VGA).106*/107bool is_tv;108109/* This is for current tv format name */110int tv_format_index;111112/**113* This is set if we treat the device as HDMI, instead of DVI.114*/115bool is_hdmi;116bool has_hdmi_monitor;117bool has_hdmi_audio;118119/**120* This is set if we detect output of sdvo device as LVDS and121* have a valid fixed mode to use with the panel.122*/123bool is_lvds;124125/**126* This is sdvo fixed pannel mode pointer127*/128struct drm_display_mode *sdvo_lvds_fixed_mode;129130/* DDC bus used by this SDVO encoder */131uint8_t ddc_bus;132133/* Input timings for adjusted_mode */134struct intel_sdvo_dtd input_dtd;135};136137struct intel_sdvo_connector {138struct intel_connector base;139140/* Mark the type of connector */141uint16_t output_flag;142143int force_audio;144145/* This contains all current supported TV format */146u8 tv_format_supported[TV_FORMAT_NUM];147int format_supported_num;148struct drm_property *tv_format;149150/* add the property for the SDVO-TV */151struct drm_property *left;152struct drm_property *right;153struct drm_property *top;154struct drm_property *bottom;155struct drm_property *hpos;156struct drm_property *vpos;157struct drm_property *contrast;158struct drm_property *saturation;159struct drm_property *hue;160struct drm_property *sharpness;161struct drm_property *flicker_filter;162struct drm_property *flicker_filter_adaptive;163struct drm_property *flicker_filter_2d;164struct drm_property *tv_chroma_filter;165struct drm_property *tv_luma_filter;166struct drm_property *dot_crawl;167168/* add the property for the SDVO-TV/LVDS */169struct drm_property *brightness;170171/* Add variable to record current setting for the above property */172u32 left_margin, right_margin, top_margin, bottom_margin;173174/* this is to get the range of margin.*/175u32 max_hscan, max_vscan;176u32 max_hpos, cur_hpos;177u32 max_vpos, cur_vpos;178u32 cur_brightness, max_brightness;179u32 cur_contrast, max_contrast;180u32 cur_saturation, max_saturation;181u32 cur_hue, max_hue;182u32 cur_sharpness, max_sharpness;183u32 cur_flicker_filter, max_flicker_filter;184u32 cur_flicker_filter_adaptive, max_flicker_filter_adaptive;185u32 cur_flicker_filter_2d, max_flicker_filter_2d;186u32 cur_tv_chroma_filter, max_tv_chroma_filter;187u32 cur_tv_luma_filter, max_tv_luma_filter;188u32 cur_dot_crawl, max_dot_crawl;189};190191static struct intel_sdvo *to_intel_sdvo(struct drm_encoder *encoder)192{193return container_of(encoder, struct intel_sdvo, base.base);194}195196static struct intel_sdvo *intel_attached_sdvo(struct drm_connector *connector)197{198return container_of(intel_attached_encoder(connector),199struct intel_sdvo, base);200}201202static struct intel_sdvo_connector *to_intel_sdvo_connector(struct drm_connector *connector)203{204return container_of(to_intel_connector(connector), struct intel_sdvo_connector, base);205}206207static bool208intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo, uint16_t flags);209static bool210intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo,211struct intel_sdvo_connector *intel_sdvo_connector,212int type);213static bool214intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo,215struct intel_sdvo_connector *intel_sdvo_connector);216217/**218* Writes the SDVOB or SDVOC with the given value, but always writes both219* SDVOB and SDVOC to work around apparent hardware issues (according to220* comments in the BIOS).221*/222static void intel_sdvo_write_sdvox(struct intel_sdvo *intel_sdvo, u32 val)223{224struct drm_device *dev = intel_sdvo->base.base.dev;225struct drm_i915_private *dev_priv = dev->dev_private;226u32 bval = val, cval = val;227int i;228229if (intel_sdvo->sdvo_reg == PCH_SDVOB) {230I915_WRITE(intel_sdvo->sdvo_reg, val);231I915_READ(intel_sdvo->sdvo_reg);232return;233}234235if (intel_sdvo->sdvo_reg == SDVOB) {236cval = I915_READ(SDVOC);237} else {238bval = I915_READ(SDVOB);239}240/*241* Write the registers twice for luck. Sometimes,242* writing them only once doesn't appear to 'stick'.243* The BIOS does this too. Yay, magic244*/245for (i = 0; i < 2; i++)246{247I915_WRITE(SDVOB, bval);248I915_READ(SDVOB);249I915_WRITE(SDVOC, cval);250I915_READ(SDVOC);251}252}253254static bool intel_sdvo_read_byte(struct intel_sdvo *intel_sdvo, u8 addr, u8 *ch)255{256struct i2c_msg msgs[] = {257{258.addr = intel_sdvo->slave_addr,259.flags = 0,260.len = 1,261.buf = &addr,262},263{264.addr = intel_sdvo->slave_addr,265.flags = I2C_M_RD,266.len = 1,267.buf = ch,268}269};270int ret;271272if ((ret = i2c_transfer(intel_sdvo->i2c, msgs, 2)) == 2)273return true;274275DRM_DEBUG_KMS("i2c transfer returned %d\n", ret);276return false;277}278279#define SDVO_CMD_NAME_ENTRY(cmd) {cmd, #cmd}280/** Mapping of command numbers to names, for debug output */281static const struct _sdvo_cmd_name {282u8 cmd;283const char *name;284} sdvo_cmd_names[] = {285SDVO_CMD_NAME_ENTRY(SDVO_CMD_RESET),286SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_DEVICE_CAPS),287SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_FIRMWARE_REV),288SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_TRAINED_INPUTS),289SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ACTIVE_OUTPUTS),290SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_ACTIVE_OUTPUTS),291SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_IN_OUT_MAP),292SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_IN_OUT_MAP),293SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ATTACHED_DISPLAYS),294SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HOT_PLUG_SUPPORT),295SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_ACTIVE_HOT_PLUG),296SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ACTIVE_HOT_PLUG),297SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INTERRUPT_EVENT_SOURCE),298SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TARGET_INPUT),299SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TARGET_OUTPUT),300SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INPUT_TIMINGS_PART1),301SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INPUT_TIMINGS_PART2),302SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_INPUT_TIMINGS_PART1),303SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_INPUT_TIMINGS_PART2),304SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_INPUT_TIMINGS_PART1),305SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_OUTPUT_TIMINGS_PART1),306SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_OUTPUT_TIMINGS_PART2),307SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OUTPUT_TIMINGS_PART1),308SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OUTPUT_TIMINGS_PART2),309SDVO_CMD_NAME_ENTRY(SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING),310SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1),311SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2),312SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE),313SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OUTPUT_PIXEL_CLOCK_RANGE),314SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_CLOCK_RATE_MULTS),315SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_CLOCK_RATE_MULT),316SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_CLOCK_RATE_MULT),317SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_TV_FORMATS),318SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_TV_FORMAT),319SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TV_FORMAT),320SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_POWER_STATES),321SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_POWER_STATE),322SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_ENCODER_POWER_STATE),323SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_DISPLAY_POWER_STATE),324SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_CONTROL_BUS_SWITCH),325SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT),326SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SCALED_HDTV_RESOLUTION_SUPPORT),327SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS),328329/* Add the op code for SDVO enhancements */330SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_HPOS),331SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HPOS),332SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_HPOS),333SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_VPOS),334SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_VPOS),335SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_VPOS),336SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_SATURATION),337SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SATURATION),338SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_SATURATION),339SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_HUE),340SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HUE),341SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_HUE),342SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_CONTRAST),343SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_CONTRAST),344SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_CONTRAST),345SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_BRIGHTNESS),346SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_BRIGHTNESS),347SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_BRIGHTNESS),348SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_OVERSCAN_H),349SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OVERSCAN_H),350SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_OVERSCAN_H),351SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_OVERSCAN_V),352SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OVERSCAN_V),353SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_OVERSCAN_V),354SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_FLICKER_FILTER),355SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_FLICKER_FILTER),356SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_FLICKER_FILTER),357SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_FLICKER_FILTER_ADAPTIVE),358SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_FLICKER_FILTER_ADAPTIVE),359SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_FLICKER_FILTER_ADAPTIVE),360SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_FLICKER_FILTER_2D),361SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_FLICKER_FILTER_2D),362SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_FLICKER_FILTER_2D),363SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_SHARPNESS),364SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SHARPNESS),365SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_SHARPNESS),366SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_DOT_CRAWL),367SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_DOT_CRAWL),368SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_TV_CHROMA_FILTER),369SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_TV_CHROMA_FILTER),370SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TV_CHROMA_FILTER),371SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_TV_LUMA_FILTER),372SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_TV_LUMA_FILTER),373SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TV_LUMA_FILTER),374375/* HDMI op code */376SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPP_ENCODE),377SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ENCODE),378SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_ENCODE),379SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_PIXEL_REPLI),380SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_PIXEL_REPLI),381SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_COLORIMETRY_CAP),382SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_COLORIMETRY),383SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_COLORIMETRY),384SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_AUDIO_ENCRYPT_PREFER),385SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_AUDIO_STAT),386SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_AUDIO_STAT),387SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HBUF_INDEX),388SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_HBUF_INDEX),389SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HBUF_INFO),390SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HBUF_AV_SPLIT),391SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_HBUF_AV_SPLIT),392SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HBUF_TXRATE),393SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_HBUF_TXRATE),394SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_HBUF_DATA),395SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HBUF_DATA),396};397398#define IS_SDVOB(reg) (reg == SDVOB || reg == PCH_SDVOB)399#define SDVO_NAME(svdo) (IS_SDVOB((svdo)->sdvo_reg) ? "SDVOB" : "SDVOC")400401static void intel_sdvo_debug_write(struct intel_sdvo *intel_sdvo, u8 cmd,402const void *args, int args_len)403{404int i;405406DRM_DEBUG_KMS("%s: W: %02X ",407SDVO_NAME(intel_sdvo), cmd);408for (i = 0; i < args_len; i++)409DRM_LOG_KMS("%02X ", ((u8 *)args)[i]);410for (; i < 8; i++)411DRM_LOG_KMS(" ");412for (i = 0; i < ARRAY_SIZE(sdvo_cmd_names); i++) {413if (cmd == sdvo_cmd_names[i].cmd) {414DRM_LOG_KMS("(%s)", sdvo_cmd_names[i].name);415break;416}417}418if (i == ARRAY_SIZE(sdvo_cmd_names))419DRM_LOG_KMS("(%02X)", cmd);420DRM_LOG_KMS("\n");421}422423static const char *cmd_status_names[] = {424"Power on",425"Success",426"Not supported",427"Invalid arg",428"Pending",429"Target not specified",430"Scaling not supported"431};432433static bool intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd,434const void *args, int args_len)435{436u8 buf[args_len*2 + 2], status;437struct i2c_msg msgs[args_len + 3];438int i, ret;439440intel_sdvo_debug_write(intel_sdvo, cmd, args, args_len);441442for (i = 0; i < args_len; i++) {443msgs[i].addr = intel_sdvo->slave_addr;444msgs[i].flags = 0;445msgs[i].len = 2;446msgs[i].buf = buf + 2 *i;447buf[2*i + 0] = SDVO_I2C_ARG_0 - i;448buf[2*i + 1] = ((u8*)args)[i];449}450msgs[i].addr = intel_sdvo->slave_addr;451msgs[i].flags = 0;452msgs[i].len = 2;453msgs[i].buf = buf + 2*i;454buf[2*i + 0] = SDVO_I2C_OPCODE;455buf[2*i + 1] = cmd;456457/* the following two are to read the response */458status = SDVO_I2C_CMD_STATUS;459msgs[i+1].addr = intel_sdvo->slave_addr;460msgs[i+1].flags = 0;461msgs[i+1].len = 1;462msgs[i+1].buf = &status;463464msgs[i+2].addr = intel_sdvo->slave_addr;465msgs[i+2].flags = I2C_M_RD;466msgs[i+2].len = 1;467msgs[i+2].buf = &status;468469ret = i2c_transfer(intel_sdvo->i2c, msgs, i+3);470if (ret < 0) {471DRM_DEBUG_KMS("I2c transfer returned %d\n", ret);472return false;473}474if (ret != i+3) {475/* failure in I2C transfer */476DRM_DEBUG_KMS("I2c transfer returned %d/%d\n", ret, i+3);477return false;478}479480return true;481}482483static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo,484void *response, int response_len)485{486u8 retry = 5;487u8 status;488int i;489490DRM_DEBUG_KMS("%s: R: ", SDVO_NAME(intel_sdvo));491492/*493* The documentation states that all commands will be494* processed within 15µs, and that we need only poll495* the status byte a maximum of 3 times in order for the496* command to be complete.497*498* Check 5 times in case the hardware failed to read the docs.499*/500if (!intel_sdvo_read_byte(intel_sdvo,501SDVO_I2C_CMD_STATUS,502&status))503goto log_fail;504505while (status == SDVO_CMD_STATUS_PENDING && retry--) {506udelay(15);507if (!intel_sdvo_read_byte(intel_sdvo,508SDVO_I2C_CMD_STATUS,509&status))510goto log_fail;511}512513if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP)514DRM_LOG_KMS("(%s)", cmd_status_names[status]);515else516DRM_LOG_KMS("(??? %d)", status);517518if (status != SDVO_CMD_STATUS_SUCCESS)519goto log_fail;520521/* Read the command response */522for (i = 0; i < response_len; i++) {523if (!intel_sdvo_read_byte(intel_sdvo,524SDVO_I2C_RETURN_0 + i,525&((u8 *)response)[i]))526goto log_fail;527DRM_LOG_KMS(" %02X", ((u8 *)response)[i]);528}529DRM_LOG_KMS("\n");530return true;531532log_fail:533DRM_LOG_KMS("... failed\n");534return false;535}536537static int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode)538{539if (mode->clock >= 100000)540return 1;541else if (mode->clock >= 50000)542return 2;543else544return 4;545}546547static bool intel_sdvo_set_control_bus_switch(struct intel_sdvo *intel_sdvo,548u8 ddc_bus)549{550/* This must be the immediately preceding write before the i2c xfer */551return intel_sdvo_write_cmd(intel_sdvo,552SDVO_CMD_SET_CONTROL_BUS_SWITCH,553&ddc_bus, 1);554}555556static bool intel_sdvo_set_value(struct intel_sdvo *intel_sdvo, u8 cmd, const void *data, int len)557{558if (!intel_sdvo_write_cmd(intel_sdvo, cmd, data, len))559return false;560561return intel_sdvo_read_response(intel_sdvo, NULL, 0);562}563564static bool565intel_sdvo_get_value(struct intel_sdvo *intel_sdvo, u8 cmd, void *value, int len)566{567if (!intel_sdvo_write_cmd(intel_sdvo, cmd, NULL, 0))568return false;569570return intel_sdvo_read_response(intel_sdvo, value, len);571}572573static bool intel_sdvo_set_target_input(struct intel_sdvo *intel_sdvo)574{575struct intel_sdvo_set_target_input_args targets = {0};576return intel_sdvo_set_value(intel_sdvo,577SDVO_CMD_SET_TARGET_INPUT,578&targets, sizeof(targets));579}580581/**582* Return whether each input is trained.583*584* This function is making an assumption about the layout of the response,585* which should be checked against the docs.586*/587static bool intel_sdvo_get_trained_inputs(struct intel_sdvo *intel_sdvo, bool *input_1, bool *input_2)588{589struct intel_sdvo_get_trained_inputs_response response;590591BUILD_BUG_ON(sizeof(response) != 1);592if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_TRAINED_INPUTS,593&response, sizeof(response)))594return false;595596*input_1 = response.input0_trained;597*input_2 = response.input1_trained;598return true;599}600601static bool intel_sdvo_set_active_outputs(struct intel_sdvo *intel_sdvo,602u16 outputs)603{604return intel_sdvo_set_value(intel_sdvo,605SDVO_CMD_SET_ACTIVE_OUTPUTS,606&outputs, sizeof(outputs));607}608609static bool intel_sdvo_set_encoder_power_state(struct intel_sdvo *intel_sdvo,610int mode)611{612u8 state = SDVO_ENCODER_STATE_ON;613614switch (mode) {615case DRM_MODE_DPMS_ON:616state = SDVO_ENCODER_STATE_ON;617break;618case DRM_MODE_DPMS_STANDBY:619state = SDVO_ENCODER_STATE_STANDBY;620break;621case DRM_MODE_DPMS_SUSPEND:622state = SDVO_ENCODER_STATE_SUSPEND;623break;624case DRM_MODE_DPMS_OFF:625state = SDVO_ENCODER_STATE_OFF;626break;627}628629return intel_sdvo_set_value(intel_sdvo,630SDVO_CMD_SET_ENCODER_POWER_STATE, &state, sizeof(state));631}632633static bool intel_sdvo_get_input_pixel_clock_range(struct intel_sdvo *intel_sdvo,634int *clock_min,635int *clock_max)636{637struct intel_sdvo_pixel_clock_range clocks;638639BUILD_BUG_ON(sizeof(clocks) != 4);640if (!intel_sdvo_get_value(intel_sdvo,641SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE,642&clocks, sizeof(clocks)))643return false;644645/* Convert the values from units of 10 kHz to kHz. */646*clock_min = clocks.min * 10;647*clock_max = clocks.max * 10;648return true;649}650651static bool intel_sdvo_set_target_output(struct intel_sdvo *intel_sdvo,652u16 outputs)653{654return intel_sdvo_set_value(intel_sdvo,655SDVO_CMD_SET_TARGET_OUTPUT,656&outputs, sizeof(outputs));657}658659static bool intel_sdvo_set_timing(struct intel_sdvo *intel_sdvo, u8 cmd,660struct intel_sdvo_dtd *dtd)661{662return intel_sdvo_set_value(intel_sdvo, cmd, &dtd->part1, sizeof(dtd->part1)) &&663intel_sdvo_set_value(intel_sdvo, cmd + 1, &dtd->part2, sizeof(dtd->part2));664}665666static bool intel_sdvo_set_input_timing(struct intel_sdvo *intel_sdvo,667struct intel_sdvo_dtd *dtd)668{669return intel_sdvo_set_timing(intel_sdvo,670SDVO_CMD_SET_INPUT_TIMINGS_PART1, dtd);671}672673static bool intel_sdvo_set_output_timing(struct intel_sdvo *intel_sdvo,674struct intel_sdvo_dtd *dtd)675{676return intel_sdvo_set_timing(intel_sdvo,677SDVO_CMD_SET_OUTPUT_TIMINGS_PART1, dtd);678}679680static bool681intel_sdvo_create_preferred_input_timing(struct intel_sdvo *intel_sdvo,682uint16_t clock,683uint16_t width,684uint16_t height)685{686struct intel_sdvo_preferred_input_timing_args args;687688memset(&args, 0, sizeof(args));689args.clock = clock;690args.width = width;691args.height = height;692args.interlace = 0;693694if (intel_sdvo->is_lvds &&695(intel_sdvo->sdvo_lvds_fixed_mode->hdisplay != width ||696intel_sdvo->sdvo_lvds_fixed_mode->vdisplay != height))697args.scaled = 1;698699return intel_sdvo_set_value(intel_sdvo,700SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING,701&args, sizeof(args));702}703704static bool intel_sdvo_get_preferred_input_timing(struct intel_sdvo *intel_sdvo,705struct intel_sdvo_dtd *dtd)706{707BUILD_BUG_ON(sizeof(dtd->part1) != 8);708BUILD_BUG_ON(sizeof(dtd->part2) != 8);709return intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1,710&dtd->part1, sizeof(dtd->part1)) &&711intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2,712&dtd->part2, sizeof(dtd->part2));713}714715static bool intel_sdvo_set_clock_rate_mult(struct intel_sdvo *intel_sdvo, u8 val)716{717return intel_sdvo_set_value(intel_sdvo, SDVO_CMD_SET_CLOCK_RATE_MULT, &val, 1);718}719720static void intel_sdvo_get_dtd_from_mode(struct intel_sdvo_dtd *dtd,721const struct drm_display_mode *mode)722{723uint16_t width, height;724uint16_t h_blank_len, h_sync_len, v_blank_len, v_sync_len;725uint16_t h_sync_offset, v_sync_offset;726727width = mode->crtc_hdisplay;728height = mode->crtc_vdisplay;729730/* do some mode translations */731h_blank_len = mode->crtc_hblank_end - mode->crtc_hblank_start;732h_sync_len = mode->crtc_hsync_end - mode->crtc_hsync_start;733734v_blank_len = mode->crtc_vblank_end - mode->crtc_vblank_start;735v_sync_len = mode->crtc_vsync_end - mode->crtc_vsync_start;736737h_sync_offset = mode->crtc_hsync_start - mode->crtc_hblank_start;738v_sync_offset = mode->crtc_vsync_start - mode->crtc_vblank_start;739740dtd->part1.clock = mode->clock / 10;741dtd->part1.h_active = width & 0xff;742dtd->part1.h_blank = h_blank_len & 0xff;743dtd->part1.h_high = (((width >> 8) & 0xf) << 4) |744((h_blank_len >> 8) & 0xf);745dtd->part1.v_active = height & 0xff;746dtd->part1.v_blank = v_blank_len & 0xff;747dtd->part1.v_high = (((height >> 8) & 0xf) << 4) |748((v_blank_len >> 8) & 0xf);749750dtd->part2.h_sync_off = h_sync_offset & 0xff;751dtd->part2.h_sync_width = h_sync_len & 0xff;752dtd->part2.v_sync_off_width = (v_sync_offset & 0xf) << 4 |753(v_sync_len & 0xf);754dtd->part2.sync_off_width_high = ((h_sync_offset & 0x300) >> 2) |755((h_sync_len & 0x300) >> 4) | ((v_sync_offset & 0x30) >> 2) |756((v_sync_len & 0x30) >> 4);757758dtd->part2.dtd_flags = 0x18;759if (mode->flags & DRM_MODE_FLAG_PHSYNC)760dtd->part2.dtd_flags |= 0x2;761if (mode->flags & DRM_MODE_FLAG_PVSYNC)762dtd->part2.dtd_flags |= 0x4;763764dtd->part2.sdvo_flags = 0;765dtd->part2.v_sync_off_high = v_sync_offset & 0xc0;766dtd->part2.reserved = 0;767}768769static void intel_sdvo_get_mode_from_dtd(struct drm_display_mode * mode,770const struct intel_sdvo_dtd *dtd)771{772mode->hdisplay = dtd->part1.h_active;773mode->hdisplay += ((dtd->part1.h_high >> 4) & 0x0f) << 8;774mode->hsync_start = mode->hdisplay + dtd->part2.h_sync_off;775mode->hsync_start += (dtd->part2.sync_off_width_high & 0xc0) << 2;776mode->hsync_end = mode->hsync_start + dtd->part2.h_sync_width;777mode->hsync_end += (dtd->part2.sync_off_width_high & 0x30) << 4;778mode->htotal = mode->hdisplay + dtd->part1.h_blank;779mode->htotal += (dtd->part1.h_high & 0xf) << 8;780781mode->vdisplay = dtd->part1.v_active;782mode->vdisplay += ((dtd->part1.v_high >> 4) & 0x0f) << 8;783mode->vsync_start = mode->vdisplay;784mode->vsync_start += (dtd->part2.v_sync_off_width >> 4) & 0xf;785mode->vsync_start += (dtd->part2.sync_off_width_high & 0x0c) << 2;786mode->vsync_start += dtd->part2.v_sync_off_high & 0xc0;787mode->vsync_end = mode->vsync_start +788(dtd->part2.v_sync_off_width & 0xf);789mode->vsync_end += (dtd->part2.sync_off_width_high & 0x3) << 4;790mode->vtotal = mode->vdisplay + dtd->part1.v_blank;791mode->vtotal += (dtd->part1.v_high & 0xf) << 8;792793mode->clock = dtd->part1.clock * 10;794795mode->flags &= ~(DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC);796if (dtd->part2.dtd_flags & 0x2)797mode->flags |= DRM_MODE_FLAG_PHSYNC;798if (dtd->part2.dtd_flags & 0x4)799mode->flags |= DRM_MODE_FLAG_PVSYNC;800}801802static bool intel_sdvo_check_supp_encode(struct intel_sdvo *intel_sdvo)803{804struct intel_sdvo_encode encode;805806BUILD_BUG_ON(sizeof(encode) != 2);807return intel_sdvo_get_value(intel_sdvo,808SDVO_CMD_GET_SUPP_ENCODE,809&encode, sizeof(encode));810}811812static bool intel_sdvo_set_encode(struct intel_sdvo *intel_sdvo,813uint8_t mode)814{815return intel_sdvo_set_value(intel_sdvo, SDVO_CMD_SET_ENCODE, &mode, 1);816}817818static bool intel_sdvo_set_colorimetry(struct intel_sdvo *intel_sdvo,819uint8_t mode)820{821return intel_sdvo_set_value(intel_sdvo, SDVO_CMD_SET_COLORIMETRY, &mode, 1);822}823824#if 0825static void intel_sdvo_dump_hdmi_buf(struct intel_sdvo *intel_sdvo)826{827int i, j;828uint8_t set_buf_index[2];829uint8_t av_split;830uint8_t buf_size;831uint8_t buf[48];832uint8_t *pos;833834intel_sdvo_get_value(encoder, SDVO_CMD_GET_HBUF_AV_SPLIT, &av_split, 1);835836for (i = 0; i <= av_split; i++) {837set_buf_index[0] = i; set_buf_index[1] = 0;838intel_sdvo_write_cmd(encoder, SDVO_CMD_SET_HBUF_INDEX,839set_buf_index, 2);840intel_sdvo_write_cmd(encoder, SDVO_CMD_GET_HBUF_INFO, NULL, 0);841intel_sdvo_read_response(encoder, &buf_size, 1);842843pos = buf;844for (j = 0; j <= buf_size; j += 8) {845intel_sdvo_write_cmd(encoder, SDVO_CMD_GET_HBUF_DATA,846NULL, 0);847intel_sdvo_read_response(encoder, pos, 8);848pos += 8;849}850}851}852#endif853854static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo)855{856struct dip_infoframe avi_if = {857.type = DIP_TYPE_AVI,858.ver = DIP_VERSION_AVI,859.len = DIP_LEN_AVI,860};861uint8_t tx_rate = SDVO_HBUF_TX_VSYNC;862uint8_t set_buf_index[2] = { 1, 0 };863uint64_t *data = (uint64_t *)&avi_if;864unsigned i;865866intel_dip_infoframe_csum(&avi_if);867868if (!intel_sdvo_set_value(intel_sdvo,869SDVO_CMD_SET_HBUF_INDEX,870set_buf_index, 2))871return false;872873for (i = 0; i < sizeof(avi_if); i += 8) {874if (!intel_sdvo_set_value(intel_sdvo,875SDVO_CMD_SET_HBUF_DATA,876data, 8))877return false;878data++;879}880881return intel_sdvo_set_value(intel_sdvo,882SDVO_CMD_SET_HBUF_TXRATE,883&tx_rate, 1);884}885886static bool intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo)887{888struct intel_sdvo_tv_format format;889uint32_t format_map;890891format_map = 1 << intel_sdvo->tv_format_index;892memset(&format, 0, sizeof(format));893memcpy(&format, &format_map, min(sizeof(format), sizeof(format_map)));894895BUILD_BUG_ON(sizeof(format) != 6);896return intel_sdvo_set_value(intel_sdvo,897SDVO_CMD_SET_TV_FORMAT,898&format, sizeof(format));899}900901static bool902intel_sdvo_set_output_timings_from_mode(struct intel_sdvo *intel_sdvo,903struct drm_display_mode *mode)904{905struct intel_sdvo_dtd output_dtd;906907if (!intel_sdvo_set_target_output(intel_sdvo,908intel_sdvo->attached_output))909return false;910911intel_sdvo_get_dtd_from_mode(&output_dtd, mode);912if (!intel_sdvo_set_output_timing(intel_sdvo, &output_dtd))913return false;914915return true;916}917918static bool919intel_sdvo_set_input_timings_for_mode(struct intel_sdvo *intel_sdvo,920struct drm_display_mode *mode,921struct drm_display_mode *adjusted_mode)922{923/* Reset the input timing to the screen. Assume always input 0. */924if (!intel_sdvo_set_target_input(intel_sdvo))925return false;926927if (!intel_sdvo_create_preferred_input_timing(intel_sdvo,928mode->clock / 10,929mode->hdisplay,930mode->vdisplay))931return false;932933if (!intel_sdvo_get_preferred_input_timing(intel_sdvo,934&intel_sdvo->input_dtd))935return false;936937intel_sdvo_get_mode_from_dtd(adjusted_mode, &intel_sdvo->input_dtd);938939drm_mode_set_crtcinfo(adjusted_mode, 0);940return true;941}942943static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,944struct drm_display_mode *mode,945struct drm_display_mode *adjusted_mode)946{947struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder);948int multiplier;949950/* We need to construct preferred input timings based on our951* output timings. To do that, we have to set the output952* timings, even though this isn't really the right place in953* the sequence to do it. Oh well.954*/955if (intel_sdvo->is_tv) {956if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo, mode))957return false;958959(void) intel_sdvo_set_input_timings_for_mode(intel_sdvo,960mode,961adjusted_mode);962} else if (intel_sdvo->is_lvds) {963if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo,964intel_sdvo->sdvo_lvds_fixed_mode))965return false;966967(void) intel_sdvo_set_input_timings_for_mode(intel_sdvo,968mode,969adjusted_mode);970}971972/* Make the CRTC code factor in the SDVO pixel multiplier. The973* SDVO device will factor out the multiplier during mode_set.974*/975multiplier = intel_sdvo_get_pixel_multiplier(adjusted_mode);976intel_mode_set_pixel_multiplier(adjusted_mode, multiplier);977978return true;979}980981static void intel_sdvo_mode_set(struct drm_encoder *encoder,982struct drm_display_mode *mode,983struct drm_display_mode *adjusted_mode)984{985struct drm_device *dev = encoder->dev;986struct drm_i915_private *dev_priv = dev->dev_private;987struct drm_crtc *crtc = encoder->crtc;988struct intel_crtc *intel_crtc = to_intel_crtc(crtc);989struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder);990u32 sdvox;991struct intel_sdvo_in_out_map in_out;992struct intel_sdvo_dtd input_dtd;993int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);994int rate;995996if (!mode)997return;998999/* First, set the input mapping for the first input to our controlled1000* output. This is only correct if we're a single-input device, in1001* which case the first input is the output from the appropriate SDVO1002* channel on the motherboard. In a two-input device, the first input1003* will be SDVOB and the second SDVOC.1004*/1005in_out.in0 = intel_sdvo->attached_output;1006in_out.in1 = 0;10071008intel_sdvo_set_value(intel_sdvo,1009SDVO_CMD_SET_IN_OUT_MAP,1010&in_out, sizeof(in_out));10111012/* Set the output timings to the screen */1013if (!intel_sdvo_set_target_output(intel_sdvo,1014intel_sdvo->attached_output))1015return;10161017/* We have tried to get input timing in mode_fixup, and filled into1018* adjusted_mode.1019*/1020if (intel_sdvo->is_tv || intel_sdvo->is_lvds) {1021input_dtd = intel_sdvo->input_dtd;1022} else {1023/* Set the output timing to the screen */1024if (!intel_sdvo_set_target_output(intel_sdvo,1025intel_sdvo->attached_output))1026return;10271028intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode);1029(void) intel_sdvo_set_output_timing(intel_sdvo, &input_dtd);1030}10311032/* Set the input timing to the screen. Assume always input 0. */1033if (!intel_sdvo_set_target_input(intel_sdvo))1034return;10351036if (intel_sdvo->has_hdmi_monitor) {1037intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_HDMI);1038intel_sdvo_set_colorimetry(intel_sdvo,1039SDVO_COLORIMETRY_RGB256);1040intel_sdvo_set_avi_infoframe(intel_sdvo);1041} else1042intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_DVI);10431044if (intel_sdvo->is_tv &&1045!intel_sdvo_set_tv_format(intel_sdvo))1046return;10471048(void) intel_sdvo_set_input_timing(intel_sdvo, &input_dtd);10491050switch (pixel_multiplier) {1051default:1052case 1: rate = SDVO_CLOCK_RATE_MULT_1X; break;1053case 2: rate = SDVO_CLOCK_RATE_MULT_2X; break;1054case 4: rate = SDVO_CLOCK_RATE_MULT_4X; break;1055}1056if (!intel_sdvo_set_clock_rate_mult(intel_sdvo, rate))1057return;10581059/* Set the SDVO control regs. */1060if (INTEL_INFO(dev)->gen >= 4) {1061sdvox = 0;1062if (intel_sdvo->is_hdmi)1063sdvox |= intel_sdvo->color_range;1064if (INTEL_INFO(dev)->gen < 5)1065sdvox |= SDVO_BORDER_ENABLE;1066if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)1067sdvox |= SDVO_VSYNC_ACTIVE_HIGH;1068if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)1069sdvox |= SDVO_HSYNC_ACTIVE_HIGH;1070} else {1071sdvox = I915_READ(intel_sdvo->sdvo_reg);1072switch (intel_sdvo->sdvo_reg) {1073case SDVOB:1074sdvox &= SDVOB_PRESERVE_MASK;1075break;1076case SDVOC:1077sdvox &= SDVOC_PRESERVE_MASK;1078break;1079}1080sdvox |= (9 << 19) | SDVO_BORDER_ENABLE;1081}1082if (intel_crtc->pipe == 1)1083sdvox |= SDVO_PIPE_B_SELECT;1084if (intel_sdvo->has_hdmi_audio)1085sdvox |= SDVO_AUDIO_ENABLE;10861087if (INTEL_INFO(dev)->gen >= 4) {1088/* done in crtc_mode_set as the dpll_md reg must be written early */1089} else if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) {1090/* done in crtc_mode_set as it lives inside the dpll register */1091} else {1092sdvox |= (pixel_multiplier - 1) << SDVO_PORT_MULTIPLY_SHIFT;1093}10941095if (input_dtd.part2.sdvo_flags & SDVO_NEED_TO_STALL &&1096INTEL_INFO(dev)->gen < 5)1097sdvox |= SDVO_STALL_SELECT;1098intel_sdvo_write_sdvox(intel_sdvo, sdvox);1099}11001101static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode)1102{1103struct drm_device *dev = encoder->dev;1104struct drm_i915_private *dev_priv = dev->dev_private;1105struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder);1106struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);1107u32 temp;11081109if (mode != DRM_MODE_DPMS_ON) {1110intel_sdvo_set_active_outputs(intel_sdvo, 0);1111if (0)1112intel_sdvo_set_encoder_power_state(intel_sdvo, mode);11131114if (mode == DRM_MODE_DPMS_OFF) {1115temp = I915_READ(intel_sdvo->sdvo_reg);1116if ((temp & SDVO_ENABLE) != 0) {1117intel_sdvo_write_sdvox(intel_sdvo, temp & ~SDVO_ENABLE);1118}1119}1120} else {1121bool input1, input2;1122int i;1123u8 status;11241125temp = I915_READ(intel_sdvo->sdvo_reg);1126if ((temp & SDVO_ENABLE) == 0)1127intel_sdvo_write_sdvox(intel_sdvo, temp | SDVO_ENABLE);1128for (i = 0; i < 2; i++)1129intel_wait_for_vblank(dev, intel_crtc->pipe);11301131status = intel_sdvo_get_trained_inputs(intel_sdvo, &input1, &input2);1132/* Warn if the device reported failure to sync.1133* A lot of SDVO devices fail to notify of sync, but it's1134* a given it the status is a success, we succeeded.1135*/1136if (status == SDVO_CMD_STATUS_SUCCESS && !input1) {1137DRM_DEBUG_KMS("First %s output reported failure to "1138"sync\n", SDVO_NAME(intel_sdvo));1139}11401141if (0)1142intel_sdvo_set_encoder_power_state(intel_sdvo, mode);1143intel_sdvo_set_active_outputs(intel_sdvo, intel_sdvo->attached_output);1144}1145return;1146}11471148static int intel_sdvo_mode_valid(struct drm_connector *connector,1149struct drm_display_mode *mode)1150{1151struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);11521153if (mode->flags & DRM_MODE_FLAG_DBLSCAN)1154return MODE_NO_DBLESCAN;11551156if (intel_sdvo->pixel_clock_min > mode->clock)1157return MODE_CLOCK_LOW;11581159if (intel_sdvo->pixel_clock_max < mode->clock)1160return MODE_CLOCK_HIGH;11611162if (intel_sdvo->is_lvds) {1163if (mode->hdisplay > intel_sdvo->sdvo_lvds_fixed_mode->hdisplay)1164return MODE_PANEL;11651166if (mode->vdisplay > intel_sdvo->sdvo_lvds_fixed_mode->vdisplay)1167return MODE_PANEL;1168}11691170return MODE_OK;1171}11721173static bool intel_sdvo_get_capabilities(struct intel_sdvo *intel_sdvo, struct intel_sdvo_caps *caps)1174{1175BUILD_BUG_ON(sizeof(*caps) != 8);1176if (!intel_sdvo_get_value(intel_sdvo,1177SDVO_CMD_GET_DEVICE_CAPS,1178caps, sizeof(*caps)))1179return false;11801181DRM_DEBUG_KMS("SDVO capabilities:\n"1182" vendor_id: %d\n"1183" device_id: %d\n"1184" device_rev_id: %d\n"1185" sdvo_version_major: %d\n"1186" sdvo_version_minor: %d\n"1187" sdvo_inputs_mask: %d\n"1188" smooth_scaling: %d\n"1189" sharp_scaling: %d\n"1190" up_scaling: %d\n"1191" down_scaling: %d\n"1192" stall_support: %d\n"1193" output_flags: %d\n",1194caps->vendor_id,1195caps->device_id,1196caps->device_rev_id,1197caps->sdvo_version_major,1198caps->sdvo_version_minor,1199caps->sdvo_inputs_mask,1200caps->smooth_scaling,1201caps->sharp_scaling,1202caps->up_scaling,1203caps->down_scaling,1204caps->stall_support,1205caps->output_flags);12061207return true;1208}12091210/* No use! */1211#if 01212struct drm_connector* intel_sdvo_find(struct drm_device *dev, int sdvoB)1213{1214struct drm_connector *connector = NULL;1215struct intel_sdvo *iout = NULL;1216struct intel_sdvo *sdvo;12171218/* find the sdvo connector */1219list_for_each_entry(connector, &dev->mode_config.connector_list, head) {1220iout = to_intel_sdvo(connector);12211222if (iout->type != INTEL_OUTPUT_SDVO)1223continue;12241225sdvo = iout->dev_priv;12261227if (sdvo->sdvo_reg == SDVOB && sdvoB)1228return connector;12291230if (sdvo->sdvo_reg == SDVOC && !sdvoB)1231return connector;12321233}12341235return NULL;1236}12371238int intel_sdvo_supports_hotplug(struct drm_connector *connector)1239{1240u8 response[2];1241u8 status;1242struct intel_sdvo *intel_sdvo;1243DRM_DEBUG_KMS("\n");12441245if (!connector)1246return 0;12471248intel_sdvo = to_intel_sdvo(connector);12491250return intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_HOT_PLUG_SUPPORT,1251&response, 2) && response[0];1252}12531254void intel_sdvo_set_hotplug(struct drm_connector *connector, int on)1255{1256u8 response[2];1257u8 status;1258struct intel_sdvo *intel_sdvo = to_intel_sdvo(connector);12591260intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0);1261intel_sdvo_read_response(intel_sdvo, &response, 2);12621263if (on) {1264intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0);1265status = intel_sdvo_read_response(intel_sdvo, &response, 2);12661267intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2);1268} else {1269response[0] = 0;1270response[1] = 0;1271intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2);1272}12731274intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0);1275intel_sdvo_read_response(intel_sdvo, &response, 2);1276}1277#endif12781279static bool1280intel_sdvo_multifunc_encoder(struct intel_sdvo *intel_sdvo)1281{1282/* Is there more than one type of output? */1283int caps = intel_sdvo->caps.output_flags & 0xf;1284return caps & -caps;1285}12861287static struct edid *1288intel_sdvo_get_edid(struct drm_connector *connector)1289{1290struct intel_sdvo *sdvo = intel_attached_sdvo(connector);1291return drm_get_edid(connector, &sdvo->ddc);1292}12931294/* Mac mini hack -- use the same DDC as the analog connector */1295static struct edid *1296intel_sdvo_get_analog_edid(struct drm_connector *connector)1297{1298struct drm_i915_private *dev_priv = connector->dev->dev_private;12991300return drm_get_edid(connector,1301&dev_priv->gmbus[dev_priv->crt_ddc_pin].adapter);1302}13031304enum drm_connector_status1305intel_sdvo_hdmi_sink_detect(struct drm_connector *connector)1306{1307struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);1308enum drm_connector_status status;1309struct edid *edid;13101311edid = intel_sdvo_get_edid(connector);13121313if (edid == NULL && intel_sdvo_multifunc_encoder(intel_sdvo)) {1314u8 ddc, saved_ddc = intel_sdvo->ddc_bus;13151316/*1317* Don't use the 1 as the argument of DDC bus switch to get1318* the EDID. It is used for SDVO SPD ROM.1319*/1320for (ddc = intel_sdvo->ddc_bus >> 1; ddc > 1; ddc >>= 1) {1321intel_sdvo->ddc_bus = ddc;1322edid = intel_sdvo_get_edid(connector);1323if (edid)1324break;1325}1326/*1327* If we found the EDID on the other bus,1328* assume that is the correct DDC bus.1329*/1330if (edid == NULL)1331intel_sdvo->ddc_bus = saved_ddc;1332}13331334/*1335* When there is no edid and no monitor is connected with VGA1336* port, try to use the CRT ddc to read the EDID for DVI-connector.1337*/1338if (edid == NULL)1339edid = intel_sdvo_get_analog_edid(connector);13401341status = connector_status_unknown;1342if (edid != NULL) {1343/* DDC bus is shared, match EDID to connector type */1344if (edid->input & DRM_EDID_INPUT_DIGITAL) {1345status = connector_status_connected;1346if (intel_sdvo->is_hdmi) {1347intel_sdvo->has_hdmi_monitor = drm_detect_hdmi_monitor(edid);1348intel_sdvo->has_hdmi_audio = drm_detect_monitor_audio(edid);1349}1350} else1351status = connector_status_disconnected;1352connector->display_info.raw_edid = NULL;1353kfree(edid);1354}13551356if (status == connector_status_connected) {1357struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);1358if (intel_sdvo_connector->force_audio)1359intel_sdvo->has_hdmi_audio = intel_sdvo_connector->force_audio > 0;1360}13611362return status;1363}13641365static enum drm_connector_status1366intel_sdvo_detect(struct drm_connector *connector, bool force)1367{1368uint16_t response;1369struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);1370struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);1371enum drm_connector_status ret;13721373if (!intel_sdvo_write_cmd(intel_sdvo,1374SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0))1375return connector_status_unknown;13761377/* add 30ms delay when the output type might be TV */1378if (intel_sdvo->caps.output_flags &1379(SDVO_OUTPUT_SVID0 | SDVO_OUTPUT_CVBS0))1380mdelay(30);13811382if (!intel_sdvo_read_response(intel_sdvo, &response, 2))1383return connector_status_unknown;13841385DRM_DEBUG_KMS("SDVO response %d %d [%x]\n",1386response & 0xff, response >> 8,1387intel_sdvo_connector->output_flag);13881389if (response == 0)1390return connector_status_disconnected;13911392intel_sdvo->attached_output = response;13931394intel_sdvo->has_hdmi_monitor = false;1395intel_sdvo->has_hdmi_audio = false;13961397if ((intel_sdvo_connector->output_flag & response) == 0)1398ret = connector_status_disconnected;1399else if (IS_TMDS(intel_sdvo_connector))1400ret = intel_sdvo_hdmi_sink_detect(connector);1401else {1402struct edid *edid;14031404/* if we have an edid check it matches the connection */1405edid = intel_sdvo_get_edid(connector);1406if (edid == NULL)1407edid = intel_sdvo_get_analog_edid(connector);1408if (edid != NULL) {1409if (edid->input & DRM_EDID_INPUT_DIGITAL)1410ret = connector_status_disconnected;1411else1412ret = connector_status_connected;1413connector->display_info.raw_edid = NULL;1414kfree(edid);1415} else1416ret = connector_status_connected;1417}14181419/* May update encoder flag for like clock for SDVO TV, etc.*/1420if (ret == connector_status_connected) {1421intel_sdvo->is_tv = false;1422intel_sdvo->is_lvds = false;1423intel_sdvo->base.needs_tv_clock = false;14241425if (response & SDVO_TV_MASK) {1426intel_sdvo->is_tv = true;1427intel_sdvo->base.needs_tv_clock = true;1428}1429if (response & SDVO_LVDS_MASK)1430intel_sdvo->is_lvds = intel_sdvo->sdvo_lvds_fixed_mode != NULL;1431}14321433return ret;1434}14351436static void intel_sdvo_get_ddc_modes(struct drm_connector *connector)1437{1438struct edid *edid;14391440/* set the bus switch and get the modes */1441edid = intel_sdvo_get_edid(connector);14421443/*1444* Mac mini hack. On this device, the DVI-I connector shares one DDC1445* link between analog and digital outputs. So, if the regular SDVO1446* DDC fails, check to see if the analog output is disconnected, in1447* which case we'll look there for the digital DDC data.1448*/1449if (edid == NULL)1450edid = intel_sdvo_get_analog_edid(connector);14511452if (edid != NULL) {1453struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);1454bool monitor_is_digital = !!(edid->input & DRM_EDID_INPUT_DIGITAL);1455bool connector_is_digital = !!IS_TMDS(intel_sdvo_connector);14561457if (connector_is_digital == monitor_is_digital) {1458drm_mode_connector_update_edid_property(connector, edid);1459drm_add_edid_modes(connector, edid);1460}14611462connector->display_info.raw_edid = NULL;1463kfree(edid);1464}1465}14661467/*1468* Set of SDVO TV modes.1469* Note! This is in reply order (see loop in get_tv_modes).1470* XXX: all 60Hz refresh?1471*/1472static const struct drm_display_mode sdvo_tv_modes[] = {1473{ DRM_MODE("320x200", DRM_MODE_TYPE_DRIVER, 5815, 320, 321, 384,1474416, 0, 200, 201, 232, 233, 0,1475DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },1476{ DRM_MODE("320x240", DRM_MODE_TYPE_DRIVER, 6814, 320, 321, 384,1477416, 0, 240, 241, 272, 273, 0,1478DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },1479{ DRM_MODE("400x300", DRM_MODE_TYPE_DRIVER, 9910, 400, 401, 464,1480496, 0, 300, 301, 332, 333, 0,1481DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },1482{ DRM_MODE("640x350", DRM_MODE_TYPE_DRIVER, 16913, 640, 641, 704,1483736, 0, 350, 351, 382, 383, 0,1484DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },1485{ DRM_MODE("640x400", DRM_MODE_TYPE_DRIVER, 19121, 640, 641, 704,1486736, 0, 400, 401, 432, 433, 0,1487DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },1488{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 22654, 640, 641, 704,1489736, 0, 480, 481, 512, 513, 0,1490DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },1491{ DRM_MODE("704x480", DRM_MODE_TYPE_DRIVER, 24624, 704, 705, 768,1492800, 0, 480, 481, 512, 513, 0,1493DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },1494{ DRM_MODE("704x576", DRM_MODE_TYPE_DRIVER, 29232, 704, 705, 768,1495800, 0, 576, 577, 608, 609, 0,1496DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },1497{ DRM_MODE("720x350", DRM_MODE_TYPE_DRIVER, 18751, 720, 721, 784,1498816, 0, 350, 351, 382, 383, 0,1499DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },1500{ DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 21199, 720, 721, 784,1501816, 0, 400, 401, 432, 433, 0,1502DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },1503{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 25116, 720, 721, 784,1504816, 0, 480, 481, 512, 513, 0,1505DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },1506{ DRM_MODE("720x540", DRM_MODE_TYPE_DRIVER, 28054, 720, 721, 784,1507816, 0, 540, 541, 572, 573, 0,1508DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },1509{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 29816, 720, 721, 784,1510816, 0, 576, 577, 608, 609, 0,1511DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },1512{ DRM_MODE("768x576", DRM_MODE_TYPE_DRIVER, 31570, 768, 769, 832,1513864, 0, 576, 577, 608, 609, 0,1514DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },1515{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 34030, 800, 801, 864,1516896, 0, 600, 601, 632, 633, 0,1517DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },1518{ DRM_MODE("832x624", DRM_MODE_TYPE_DRIVER, 36581, 832, 833, 896,1519928, 0, 624, 625, 656, 657, 0,1520DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },1521{ DRM_MODE("920x766", DRM_MODE_TYPE_DRIVER, 48707, 920, 921, 984,15221016, 0, 766, 767, 798, 799, 0,1523DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },1524{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 53827, 1024, 1025, 1088,15251120, 0, 768, 769, 800, 801, 0,1526DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },1527{ DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 87265, 1280, 1281, 1344,15281376, 0, 1024, 1025, 1056, 1057, 0,1529DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },1530};15311532static void intel_sdvo_get_tv_modes(struct drm_connector *connector)1533{1534struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);1535struct intel_sdvo_sdtv_resolution_request tv_res;1536uint32_t reply = 0, format_map = 0;1537int i;15381539/* Read the list of supported input resolutions for the selected TV1540* format.1541*/1542format_map = 1 << intel_sdvo->tv_format_index;1543memcpy(&tv_res, &format_map,1544min(sizeof(format_map), sizeof(struct intel_sdvo_sdtv_resolution_request)));15451546if (!intel_sdvo_set_target_output(intel_sdvo, intel_sdvo->attached_output))1547return;15481549BUILD_BUG_ON(sizeof(tv_res) != 3);1550if (!intel_sdvo_write_cmd(intel_sdvo,1551SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT,1552&tv_res, sizeof(tv_res)))1553return;1554if (!intel_sdvo_read_response(intel_sdvo, &reply, 3))1555return;15561557for (i = 0; i < ARRAY_SIZE(sdvo_tv_modes); i++)1558if (reply & (1 << i)) {1559struct drm_display_mode *nmode;1560nmode = drm_mode_duplicate(connector->dev,1561&sdvo_tv_modes[i]);1562if (nmode)1563drm_mode_probed_add(connector, nmode);1564}1565}15661567static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)1568{1569struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);1570struct drm_i915_private *dev_priv = connector->dev->dev_private;1571struct drm_display_mode *newmode;15721573/*1574* Attempt to get the mode list from DDC.1575* Assume that the preferred modes are1576* arranged in priority order.1577*/1578intel_ddc_get_modes(connector, intel_sdvo->i2c);1579if (list_empty(&connector->probed_modes) == false)1580goto end;15811582/* Fetch modes from VBT */1583if (dev_priv->sdvo_lvds_vbt_mode != NULL) {1584newmode = drm_mode_duplicate(connector->dev,1585dev_priv->sdvo_lvds_vbt_mode);1586if (newmode != NULL) {1587/* Guarantee the mode is preferred */1588newmode->type = (DRM_MODE_TYPE_PREFERRED |1589DRM_MODE_TYPE_DRIVER);1590drm_mode_probed_add(connector, newmode);1591}1592}15931594end:1595list_for_each_entry(newmode, &connector->probed_modes, head) {1596if (newmode->type & DRM_MODE_TYPE_PREFERRED) {1597intel_sdvo->sdvo_lvds_fixed_mode =1598drm_mode_duplicate(connector->dev, newmode);15991600drm_mode_set_crtcinfo(intel_sdvo->sdvo_lvds_fixed_mode,16010);16021603intel_sdvo->is_lvds = true;1604break;1605}1606}16071608}16091610static int intel_sdvo_get_modes(struct drm_connector *connector)1611{1612struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);16131614if (IS_TV(intel_sdvo_connector))1615intel_sdvo_get_tv_modes(connector);1616else if (IS_LVDS(intel_sdvo_connector))1617intel_sdvo_get_lvds_modes(connector);1618else1619intel_sdvo_get_ddc_modes(connector);16201621return !list_empty(&connector->probed_modes);1622}16231624static void1625intel_sdvo_destroy_enhance_property(struct drm_connector *connector)1626{1627struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);1628struct drm_device *dev = connector->dev;16291630if (intel_sdvo_connector->left)1631drm_property_destroy(dev, intel_sdvo_connector->left);1632if (intel_sdvo_connector->right)1633drm_property_destroy(dev, intel_sdvo_connector->right);1634if (intel_sdvo_connector->top)1635drm_property_destroy(dev, intel_sdvo_connector->top);1636if (intel_sdvo_connector->bottom)1637drm_property_destroy(dev, intel_sdvo_connector->bottom);1638if (intel_sdvo_connector->hpos)1639drm_property_destroy(dev, intel_sdvo_connector->hpos);1640if (intel_sdvo_connector->vpos)1641drm_property_destroy(dev, intel_sdvo_connector->vpos);1642if (intel_sdvo_connector->saturation)1643drm_property_destroy(dev, intel_sdvo_connector->saturation);1644if (intel_sdvo_connector->contrast)1645drm_property_destroy(dev, intel_sdvo_connector->contrast);1646if (intel_sdvo_connector->hue)1647drm_property_destroy(dev, intel_sdvo_connector->hue);1648if (intel_sdvo_connector->sharpness)1649drm_property_destroy(dev, intel_sdvo_connector->sharpness);1650if (intel_sdvo_connector->flicker_filter)1651drm_property_destroy(dev, intel_sdvo_connector->flicker_filter);1652if (intel_sdvo_connector->flicker_filter_2d)1653drm_property_destroy(dev, intel_sdvo_connector->flicker_filter_2d);1654if (intel_sdvo_connector->flicker_filter_adaptive)1655drm_property_destroy(dev, intel_sdvo_connector->flicker_filter_adaptive);1656if (intel_sdvo_connector->tv_luma_filter)1657drm_property_destroy(dev, intel_sdvo_connector->tv_luma_filter);1658if (intel_sdvo_connector->tv_chroma_filter)1659drm_property_destroy(dev, intel_sdvo_connector->tv_chroma_filter);1660if (intel_sdvo_connector->dot_crawl)1661drm_property_destroy(dev, intel_sdvo_connector->dot_crawl);1662if (intel_sdvo_connector->brightness)1663drm_property_destroy(dev, intel_sdvo_connector->brightness);1664}16651666static void intel_sdvo_destroy(struct drm_connector *connector)1667{1668struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);16691670if (intel_sdvo_connector->tv_format)1671drm_property_destroy(connector->dev,1672intel_sdvo_connector->tv_format);16731674intel_sdvo_destroy_enhance_property(connector);1675drm_sysfs_connector_remove(connector);1676drm_connector_cleanup(connector);1677kfree(connector);1678}16791680static bool intel_sdvo_detect_hdmi_audio(struct drm_connector *connector)1681{1682struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);1683struct edid *edid;1684bool has_audio = false;16851686if (!intel_sdvo->is_hdmi)1687return false;16881689edid = intel_sdvo_get_edid(connector);1690if (edid != NULL && edid->input & DRM_EDID_INPUT_DIGITAL)1691has_audio = drm_detect_monitor_audio(edid);16921693return has_audio;1694}16951696static int1697intel_sdvo_set_property(struct drm_connector *connector,1698struct drm_property *property,1699uint64_t val)1700{1701struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);1702struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);1703struct drm_i915_private *dev_priv = connector->dev->dev_private;1704uint16_t temp_value;1705uint8_t cmd;1706int ret;17071708ret = drm_connector_property_set_value(connector, property, val);1709if (ret)1710return ret;17111712if (property == dev_priv->force_audio_property) {1713int i = val;1714bool has_audio;17151716if (i == intel_sdvo_connector->force_audio)1717return 0;17181719intel_sdvo_connector->force_audio = i;17201721if (i == 0)1722has_audio = intel_sdvo_detect_hdmi_audio(connector);1723else1724has_audio = i > 0;17251726if (has_audio == intel_sdvo->has_hdmi_audio)1727return 0;17281729intel_sdvo->has_hdmi_audio = has_audio;1730goto done;1731}17321733if (property == dev_priv->broadcast_rgb_property) {1734if (val == !!intel_sdvo->color_range)1735return 0;17361737intel_sdvo->color_range = val ? SDVO_COLOR_RANGE_16_235 : 0;1738goto done;1739}17401741#define CHECK_PROPERTY(name, NAME) \1742if (intel_sdvo_connector->name == property) { \1743if (intel_sdvo_connector->cur_##name == temp_value) return 0; \1744if (intel_sdvo_connector->max_##name < temp_value) return -EINVAL; \1745cmd = SDVO_CMD_SET_##NAME; \1746intel_sdvo_connector->cur_##name = temp_value; \1747goto set_value; \1748}17491750if (property == intel_sdvo_connector->tv_format) {1751if (val >= TV_FORMAT_NUM)1752return -EINVAL;17531754if (intel_sdvo->tv_format_index ==1755intel_sdvo_connector->tv_format_supported[val])1756return 0;17571758intel_sdvo->tv_format_index = intel_sdvo_connector->tv_format_supported[val];1759goto done;1760} else if (IS_TV_OR_LVDS(intel_sdvo_connector)) {1761temp_value = val;1762if (intel_sdvo_connector->left == property) {1763drm_connector_property_set_value(connector,1764intel_sdvo_connector->right, val);1765if (intel_sdvo_connector->left_margin == temp_value)1766return 0;17671768intel_sdvo_connector->left_margin = temp_value;1769intel_sdvo_connector->right_margin = temp_value;1770temp_value = intel_sdvo_connector->max_hscan -1771intel_sdvo_connector->left_margin;1772cmd = SDVO_CMD_SET_OVERSCAN_H;1773goto set_value;1774} else if (intel_sdvo_connector->right == property) {1775drm_connector_property_set_value(connector,1776intel_sdvo_connector->left, val);1777if (intel_sdvo_connector->right_margin == temp_value)1778return 0;17791780intel_sdvo_connector->left_margin = temp_value;1781intel_sdvo_connector->right_margin = temp_value;1782temp_value = intel_sdvo_connector->max_hscan -1783intel_sdvo_connector->left_margin;1784cmd = SDVO_CMD_SET_OVERSCAN_H;1785goto set_value;1786} else if (intel_sdvo_connector->top == property) {1787drm_connector_property_set_value(connector,1788intel_sdvo_connector->bottom, val);1789if (intel_sdvo_connector->top_margin == temp_value)1790return 0;17911792intel_sdvo_connector->top_margin = temp_value;1793intel_sdvo_connector->bottom_margin = temp_value;1794temp_value = intel_sdvo_connector->max_vscan -1795intel_sdvo_connector->top_margin;1796cmd = SDVO_CMD_SET_OVERSCAN_V;1797goto set_value;1798} else if (intel_sdvo_connector->bottom == property) {1799drm_connector_property_set_value(connector,1800intel_sdvo_connector->top, val);1801if (intel_sdvo_connector->bottom_margin == temp_value)1802return 0;18031804intel_sdvo_connector->top_margin = temp_value;1805intel_sdvo_connector->bottom_margin = temp_value;1806temp_value = intel_sdvo_connector->max_vscan -1807intel_sdvo_connector->top_margin;1808cmd = SDVO_CMD_SET_OVERSCAN_V;1809goto set_value;1810}1811CHECK_PROPERTY(hpos, HPOS)1812CHECK_PROPERTY(vpos, VPOS)1813CHECK_PROPERTY(saturation, SATURATION)1814CHECK_PROPERTY(contrast, CONTRAST)1815CHECK_PROPERTY(hue, HUE)1816CHECK_PROPERTY(brightness, BRIGHTNESS)1817CHECK_PROPERTY(sharpness, SHARPNESS)1818CHECK_PROPERTY(flicker_filter, FLICKER_FILTER)1819CHECK_PROPERTY(flicker_filter_2d, FLICKER_FILTER_2D)1820CHECK_PROPERTY(flicker_filter_adaptive, FLICKER_FILTER_ADAPTIVE)1821CHECK_PROPERTY(tv_chroma_filter, TV_CHROMA_FILTER)1822CHECK_PROPERTY(tv_luma_filter, TV_LUMA_FILTER)1823CHECK_PROPERTY(dot_crawl, DOT_CRAWL)1824}18251826return -EINVAL; /* unknown property */18271828set_value:1829if (!intel_sdvo_set_value(intel_sdvo, cmd, &temp_value, 2))1830return -EIO;183118321833done:1834if (intel_sdvo->base.base.crtc) {1835struct drm_crtc *crtc = intel_sdvo->base.base.crtc;1836drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x,1837crtc->y, crtc->fb);1838}18391840return 0;1841#undef CHECK_PROPERTY1842}18431844static const struct drm_encoder_helper_funcs intel_sdvo_helper_funcs = {1845.dpms = intel_sdvo_dpms,1846.mode_fixup = intel_sdvo_mode_fixup,1847.prepare = intel_encoder_prepare,1848.mode_set = intel_sdvo_mode_set,1849.commit = intel_encoder_commit,1850};18511852static const struct drm_connector_funcs intel_sdvo_connector_funcs = {1853.dpms = drm_helper_connector_dpms,1854.detect = intel_sdvo_detect,1855.fill_modes = drm_helper_probe_single_connector_modes,1856.set_property = intel_sdvo_set_property,1857.destroy = intel_sdvo_destroy,1858};18591860static const struct drm_connector_helper_funcs intel_sdvo_connector_helper_funcs = {1861.get_modes = intel_sdvo_get_modes,1862.mode_valid = intel_sdvo_mode_valid,1863.best_encoder = intel_best_encoder,1864};18651866static void intel_sdvo_enc_destroy(struct drm_encoder *encoder)1867{1868struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder);18691870if (intel_sdvo->sdvo_lvds_fixed_mode != NULL)1871drm_mode_destroy(encoder->dev,1872intel_sdvo->sdvo_lvds_fixed_mode);18731874i2c_del_adapter(&intel_sdvo->ddc);1875intel_encoder_destroy(encoder);1876}18771878static const struct drm_encoder_funcs intel_sdvo_enc_funcs = {1879.destroy = intel_sdvo_enc_destroy,1880};18811882static void1883intel_sdvo_guess_ddc_bus(struct intel_sdvo *sdvo)1884{1885uint16_t mask = 0;1886unsigned int num_bits;18871888/* Make a mask of outputs less than or equal to our own priority in the1889* list.1890*/1891switch (sdvo->controlled_output) {1892case SDVO_OUTPUT_LVDS1:1893mask |= SDVO_OUTPUT_LVDS1;1894case SDVO_OUTPUT_LVDS0:1895mask |= SDVO_OUTPUT_LVDS0;1896case SDVO_OUTPUT_TMDS1:1897mask |= SDVO_OUTPUT_TMDS1;1898case SDVO_OUTPUT_TMDS0:1899mask |= SDVO_OUTPUT_TMDS0;1900case SDVO_OUTPUT_RGB1:1901mask |= SDVO_OUTPUT_RGB1;1902case SDVO_OUTPUT_RGB0:1903mask |= SDVO_OUTPUT_RGB0;1904break;1905}19061907/* Count bits to find what number we are in the priority list. */1908mask &= sdvo->caps.output_flags;1909num_bits = hweight16(mask);1910/* If more than 3 outputs, default to DDC bus 3 for now. */1911if (num_bits > 3)1912num_bits = 3;19131914/* Corresponds to SDVO_CONTROL_BUS_DDCx */1915sdvo->ddc_bus = 1 << num_bits;1916}19171918/**1919* Choose the appropriate DDC bus for control bus switch command for this1920* SDVO output based on the controlled output.1921*1922* DDC bus number assignment is in a priority order of RGB outputs, then TMDS1923* outputs, then LVDS outputs.1924*/1925static void1926intel_sdvo_select_ddc_bus(struct drm_i915_private *dev_priv,1927struct intel_sdvo *sdvo, u32 reg)1928{1929struct sdvo_device_mapping *mapping;19301931if (IS_SDVOB(reg))1932mapping = &(dev_priv->sdvo_mappings[0]);1933else1934mapping = &(dev_priv->sdvo_mappings[1]);19351936if (mapping->initialized)1937sdvo->ddc_bus = 1 << ((mapping->ddc_pin & 0xf0) >> 4);1938else1939intel_sdvo_guess_ddc_bus(sdvo);1940}19411942static void1943intel_sdvo_select_i2c_bus(struct drm_i915_private *dev_priv,1944struct intel_sdvo *sdvo, u32 reg)1945{1946struct sdvo_device_mapping *mapping;1947u8 pin, speed;19481949if (IS_SDVOB(reg))1950mapping = &dev_priv->sdvo_mappings[0];1951else1952mapping = &dev_priv->sdvo_mappings[1];19531954pin = GMBUS_PORT_DPB;1955speed = GMBUS_RATE_1MHZ >> 8;1956if (mapping->initialized) {1957pin = mapping->i2c_pin;1958speed = mapping->i2c_speed;1959}19601961if (pin < GMBUS_NUM_PORTS) {1962sdvo->i2c = &dev_priv->gmbus[pin].adapter;1963intel_gmbus_set_speed(sdvo->i2c, speed);1964intel_gmbus_force_bit(sdvo->i2c, true);1965} else1966sdvo->i2c = &dev_priv->gmbus[GMBUS_PORT_DPB].adapter;1967}19681969static bool1970intel_sdvo_is_hdmi_connector(struct intel_sdvo *intel_sdvo, int device)1971{1972return intel_sdvo_check_supp_encode(intel_sdvo);1973}19741975static u81976intel_sdvo_get_slave_addr(struct drm_device *dev, int sdvo_reg)1977{1978struct drm_i915_private *dev_priv = dev->dev_private;1979struct sdvo_device_mapping *my_mapping, *other_mapping;19801981if (IS_SDVOB(sdvo_reg)) {1982my_mapping = &dev_priv->sdvo_mappings[0];1983other_mapping = &dev_priv->sdvo_mappings[1];1984} else {1985my_mapping = &dev_priv->sdvo_mappings[1];1986other_mapping = &dev_priv->sdvo_mappings[0];1987}19881989/* If the BIOS described our SDVO device, take advantage of it. */1990if (my_mapping->slave_addr)1991return my_mapping->slave_addr;19921993/* If the BIOS only described a different SDVO device, use the1994* address that it isn't using.1995*/1996if (other_mapping->slave_addr) {1997if (other_mapping->slave_addr == 0x70)1998return 0x72;1999else2000return 0x70;2001}20022003/* No SDVO device info is found for another DVO port,2004* so use mapping assumption we had before BIOS parsing.2005*/2006if (IS_SDVOB(sdvo_reg))2007return 0x70;2008else2009return 0x72;2010}20112012static void2013intel_sdvo_connector_init(struct intel_sdvo_connector *connector,2014struct intel_sdvo *encoder)2015{2016drm_connector_init(encoder->base.base.dev,2017&connector->base.base,2018&intel_sdvo_connector_funcs,2019connector->base.base.connector_type);20202021drm_connector_helper_add(&connector->base.base,2022&intel_sdvo_connector_helper_funcs);20232024connector->base.base.interlace_allowed = 0;2025connector->base.base.doublescan_allowed = 0;2026connector->base.base.display_info.subpixel_order = SubPixelHorizontalRGB;20272028intel_connector_attach_encoder(&connector->base, &encoder->base);2029drm_sysfs_connector_add(&connector->base.base);2030}20312032static void2033intel_sdvo_add_hdmi_properties(struct intel_sdvo_connector *connector)2034{2035struct drm_device *dev = connector->base.base.dev;20362037intel_attach_force_audio_property(&connector->base.base);2038if (INTEL_INFO(dev)->gen >= 4 && IS_MOBILE(dev))2039intel_attach_broadcast_rgb_property(&connector->base.base);2040}20412042static bool2043intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)2044{2045struct drm_encoder *encoder = &intel_sdvo->base.base;2046struct drm_connector *connector;2047struct intel_connector *intel_connector;2048struct intel_sdvo_connector *intel_sdvo_connector;20492050intel_sdvo_connector = kzalloc(sizeof(struct intel_sdvo_connector), GFP_KERNEL);2051if (!intel_sdvo_connector)2052return false;20532054if (device == 0) {2055intel_sdvo->controlled_output |= SDVO_OUTPUT_TMDS0;2056intel_sdvo_connector->output_flag = SDVO_OUTPUT_TMDS0;2057} else if (device == 1) {2058intel_sdvo->controlled_output |= SDVO_OUTPUT_TMDS1;2059intel_sdvo_connector->output_flag = SDVO_OUTPUT_TMDS1;2060}20612062intel_connector = &intel_sdvo_connector->base;2063connector = &intel_connector->base;2064connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT;2065encoder->encoder_type = DRM_MODE_ENCODER_TMDS;2066connector->connector_type = DRM_MODE_CONNECTOR_DVID;20672068if (intel_sdvo_is_hdmi_connector(intel_sdvo, device)) {2069connector->connector_type = DRM_MODE_CONNECTOR_HDMIA;2070intel_sdvo->is_hdmi = true;2071}2072intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) |2073(1 << INTEL_ANALOG_CLONE_BIT));20742075intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo);2076if (intel_sdvo->is_hdmi)2077intel_sdvo_add_hdmi_properties(intel_sdvo_connector);20782079return true;2080}20812082static bool2083intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, int type)2084{2085struct drm_encoder *encoder = &intel_sdvo->base.base;2086struct drm_connector *connector;2087struct intel_connector *intel_connector;2088struct intel_sdvo_connector *intel_sdvo_connector;20892090intel_sdvo_connector = kzalloc(sizeof(struct intel_sdvo_connector), GFP_KERNEL);2091if (!intel_sdvo_connector)2092return false;20932094intel_connector = &intel_sdvo_connector->base;2095connector = &intel_connector->base;2096encoder->encoder_type = DRM_MODE_ENCODER_TVDAC;2097connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO;20982099intel_sdvo->controlled_output |= type;2100intel_sdvo_connector->output_flag = type;21012102intel_sdvo->is_tv = true;2103intel_sdvo->base.needs_tv_clock = true;2104intel_sdvo->base.clone_mask = 1 << INTEL_SDVO_TV_CLONE_BIT;21052106intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo);21072108if (!intel_sdvo_tv_create_property(intel_sdvo, intel_sdvo_connector, type))2109goto err;21102111if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector))2112goto err;21132114return true;21152116err:2117intel_sdvo_destroy(connector);2118return false;2119}21202121static bool2122intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, int device)2123{2124struct drm_encoder *encoder = &intel_sdvo->base.base;2125struct drm_connector *connector;2126struct intel_connector *intel_connector;2127struct intel_sdvo_connector *intel_sdvo_connector;21282129intel_sdvo_connector = kzalloc(sizeof(struct intel_sdvo_connector), GFP_KERNEL);2130if (!intel_sdvo_connector)2131return false;21322133intel_connector = &intel_sdvo_connector->base;2134connector = &intel_connector->base;2135connector->polled = DRM_CONNECTOR_POLL_CONNECT;2136encoder->encoder_type = DRM_MODE_ENCODER_DAC;2137connector->connector_type = DRM_MODE_CONNECTOR_VGA;21382139if (device == 0) {2140intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB0;2141intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB0;2142} else if (device == 1) {2143intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB1;2144intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB1;2145}21462147intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) |2148(1 << INTEL_ANALOG_CLONE_BIT));21492150intel_sdvo_connector_init(intel_sdvo_connector,2151intel_sdvo);2152return true;2153}21542155static bool2156intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device)2157{2158struct drm_encoder *encoder = &intel_sdvo->base.base;2159struct drm_connector *connector;2160struct intel_connector *intel_connector;2161struct intel_sdvo_connector *intel_sdvo_connector;21622163intel_sdvo_connector = kzalloc(sizeof(struct intel_sdvo_connector), GFP_KERNEL);2164if (!intel_sdvo_connector)2165return false;21662167intel_connector = &intel_sdvo_connector->base;2168connector = &intel_connector->base;2169encoder->encoder_type = DRM_MODE_ENCODER_LVDS;2170connector->connector_type = DRM_MODE_CONNECTOR_LVDS;21712172if (device == 0) {2173intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS0;2174intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS0;2175} else if (device == 1) {2176intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS1;2177intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS1;2178}21792180intel_sdvo->base.clone_mask = ((1 << INTEL_ANALOG_CLONE_BIT) |2181(1 << INTEL_SDVO_LVDS_CLONE_BIT));21822183intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo);2184if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector))2185goto err;21862187return true;21882189err:2190intel_sdvo_destroy(connector);2191return false;2192}21932194static bool2195intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo, uint16_t flags)2196{2197intel_sdvo->is_tv = false;2198intel_sdvo->base.needs_tv_clock = false;2199intel_sdvo->is_lvds = false;22002201/* SDVO requires XXX1 function may not exist unless it has XXX0 function.*/22022203if (flags & SDVO_OUTPUT_TMDS0)2204if (!intel_sdvo_dvi_init(intel_sdvo, 0))2205return false;22062207if ((flags & SDVO_TMDS_MASK) == SDVO_TMDS_MASK)2208if (!intel_sdvo_dvi_init(intel_sdvo, 1))2209return false;22102211/* TV has no XXX1 function block */2212if (flags & SDVO_OUTPUT_SVID0)2213if (!intel_sdvo_tv_init(intel_sdvo, SDVO_OUTPUT_SVID0))2214return false;22152216if (flags & SDVO_OUTPUT_CVBS0)2217if (!intel_sdvo_tv_init(intel_sdvo, SDVO_OUTPUT_CVBS0))2218return false;22192220if (flags & SDVO_OUTPUT_RGB0)2221if (!intel_sdvo_analog_init(intel_sdvo, 0))2222return false;22232224if ((flags & SDVO_RGB_MASK) == SDVO_RGB_MASK)2225if (!intel_sdvo_analog_init(intel_sdvo, 1))2226return false;22272228if (flags & SDVO_OUTPUT_LVDS0)2229if (!intel_sdvo_lvds_init(intel_sdvo, 0))2230return false;22312232if ((flags & SDVO_LVDS_MASK) == SDVO_LVDS_MASK)2233if (!intel_sdvo_lvds_init(intel_sdvo, 1))2234return false;22352236if ((flags & SDVO_OUTPUT_MASK) == 0) {2237unsigned char bytes[2];22382239intel_sdvo->controlled_output = 0;2240memcpy(bytes, &intel_sdvo->caps.output_flags, 2);2241DRM_DEBUG_KMS("%s: Unknown SDVO output type (0x%02x%02x)\n",2242SDVO_NAME(intel_sdvo),2243bytes[0], bytes[1]);2244return false;2245}2246intel_sdvo->base.crtc_mask = (1 << 0) | (1 << 1);22472248return true;2249}22502251static bool intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo,2252struct intel_sdvo_connector *intel_sdvo_connector,2253int type)2254{2255struct drm_device *dev = intel_sdvo->base.base.dev;2256struct intel_sdvo_tv_format format;2257uint32_t format_map, i;22582259if (!intel_sdvo_set_target_output(intel_sdvo, type))2260return false;22612262BUILD_BUG_ON(sizeof(format) != 6);2263if (!intel_sdvo_get_value(intel_sdvo,2264SDVO_CMD_GET_SUPPORTED_TV_FORMATS,2265&format, sizeof(format)))2266return false;22672268memcpy(&format_map, &format, min(sizeof(format_map), sizeof(format)));22692270if (format_map == 0)2271return false;22722273intel_sdvo_connector->format_supported_num = 0;2274for (i = 0 ; i < TV_FORMAT_NUM; i++)2275if (format_map & (1 << i))2276intel_sdvo_connector->tv_format_supported[intel_sdvo_connector->format_supported_num++] = i;227722782279intel_sdvo_connector->tv_format =2280drm_property_create(dev, DRM_MODE_PROP_ENUM,2281"mode", intel_sdvo_connector->format_supported_num);2282if (!intel_sdvo_connector->tv_format)2283return false;22842285for (i = 0; i < intel_sdvo_connector->format_supported_num; i++)2286drm_property_add_enum(2287intel_sdvo_connector->tv_format, i,2288i, tv_format_names[intel_sdvo_connector->tv_format_supported[i]]);22892290intel_sdvo->tv_format_index = intel_sdvo_connector->tv_format_supported[0];2291drm_connector_attach_property(&intel_sdvo_connector->base.base,2292intel_sdvo_connector->tv_format, 0);2293return true;22942295}22962297#define ENHANCEMENT(name, NAME) do { \2298if (enhancements.name) { \2299if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_MAX_##NAME, &data_value, 4) || \2300!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_##NAME, &response, 2)) \2301return false; \2302intel_sdvo_connector->max_##name = data_value[0]; \2303intel_sdvo_connector->cur_##name = response; \2304intel_sdvo_connector->name = \2305drm_property_create(dev, DRM_MODE_PROP_RANGE, #name, 2); \2306if (!intel_sdvo_connector->name) return false; \2307intel_sdvo_connector->name->values[0] = 0; \2308intel_sdvo_connector->name->values[1] = data_value[0]; \2309drm_connector_attach_property(connector, \2310intel_sdvo_connector->name, \2311intel_sdvo_connector->cur_##name); \2312DRM_DEBUG_KMS(#name ": max %d, default %d, current %d\n", \2313data_value[0], data_value[1], response); \2314} \2315} while(0)23162317static bool2318intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo,2319struct intel_sdvo_connector *intel_sdvo_connector,2320struct intel_sdvo_enhancements_reply enhancements)2321{2322struct drm_device *dev = intel_sdvo->base.base.dev;2323struct drm_connector *connector = &intel_sdvo_connector->base.base;2324uint16_t response, data_value[2];23252326/* when horizontal overscan is supported, Add the left/right property */2327if (enhancements.overscan_h) {2328if (!intel_sdvo_get_value(intel_sdvo,2329SDVO_CMD_GET_MAX_OVERSCAN_H,2330&data_value, 4))2331return false;23322333if (!intel_sdvo_get_value(intel_sdvo,2334SDVO_CMD_GET_OVERSCAN_H,2335&response, 2))2336return false;23372338intel_sdvo_connector->max_hscan = data_value[0];2339intel_sdvo_connector->left_margin = data_value[0] - response;2340intel_sdvo_connector->right_margin = intel_sdvo_connector->left_margin;2341intel_sdvo_connector->left =2342drm_property_create(dev, DRM_MODE_PROP_RANGE,2343"left_margin", 2);2344if (!intel_sdvo_connector->left)2345return false;23462347intel_sdvo_connector->left->values[0] = 0;2348intel_sdvo_connector->left->values[1] = data_value[0];2349drm_connector_attach_property(connector,2350intel_sdvo_connector->left,2351intel_sdvo_connector->left_margin);23522353intel_sdvo_connector->right =2354drm_property_create(dev, DRM_MODE_PROP_RANGE,2355"right_margin", 2);2356if (!intel_sdvo_connector->right)2357return false;23582359intel_sdvo_connector->right->values[0] = 0;2360intel_sdvo_connector->right->values[1] = data_value[0];2361drm_connector_attach_property(connector,2362intel_sdvo_connector->right,2363intel_sdvo_connector->right_margin);2364DRM_DEBUG_KMS("h_overscan: max %d, "2365"default %d, current %d\n",2366data_value[0], data_value[1], response);2367}23682369if (enhancements.overscan_v) {2370if (!intel_sdvo_get_value(intel_sdvo,2371SDVO_CMD_GET_MAX_OVERSCAN_V,2372&data_value, 4))2373return false;23742375if (!intel_sdvo_get_value(intel_sdvo,2376SDVO_CMD_GET_OVERSCAN_V,2377&response, 2))2378return false;23792380intel_sdvo_connector->max_vscan = data_value[0];2381intel_sdvo_connector->top_margin = data_value[0] - response;2382intel_sdvo_connector->bottom_margin = intel_sdvo_connector->top_margin;2383intel_sdvo_connector->top =2384drm_property_create(dev, DRM_MODE_PROP_RANGE,2385"top_margin", 2);2386if (!intel_sdvo_connector->top)2387return false;23882389intel_sdvo_connector->top->values[0] = 0;2390intel_sdvo_connector->top->values[1] = data_value[0];2391drm_connector_attach_property(connector,2392intel_sdvo_connector->top,2393intel_sdvo_connector->top_margin);23942395intel_sdvo_connector->bottom =2396drm_property_create(dev, DRM_MODE_PROP_RANGE,2397"bottom_margin", 2);2398if (!intel_sdvo_connector->bottom)2399return false;24002401intel_sdvo_connector->bottom->values[0] = 0;2402intel_sdvo_connector->bottom->values[1] = data_value[0];2403drm_connector_attach_property(connector,2404intel_sdvo_connector->bottom,2405intel_sdvo_connector->bottom_margin);2406DRM_DEBUG_KMS("v_overscan: max %d, "2407"default %d, current %d\n",2408data_value[0], data_value[1], response);2409}24102411ENHANCEMENT(hpos, HPOS);2412ENHANCEMENT(vpos, VPOS);2413ENHANCEMENT(saturation, SATURATION);2414ENHANCEMENT(contrast, CONTRAST);2415ENHANCEMENT(hue, HUE);2416ENHANCEMENT(sharpness, SHARPNESS);2417ENHANCEMENT(brightness, BRIGHTNESS);2418ENHANCEMENT(flicker_filter, FLICKER_FILTER);2419ENHANCEMENT(flicker_filter_adaptive, FLICKER_FILTER_ADAPTIVE);2420ENHANCEMENT(flicker_filter_2d, FLICKER_FILTER_2D);2421ENHANCEMENT(tv_chroma_filter, TV_CHROMA_FILTER);2422ENHANCEMENT(tv_luma_filter, TV_LUMA_FILTER);24232424if (enhancements.dot_crawl) {2425if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_DOT_CRAWL, &response, 2))2426return false;24272428intel_sdvo_connector->max_dot_crawl = 1;2429intel_sdvo_connector->cur_dot_crawl = response & 0x1;2430intel_sdvo_connector->dot_crawl =2431drm_property_create(dev, DRM_MODE_PROP_RANGE, "dot_crawl", 2);2432if (!intel_sdvo_connector->dot_crawl)2433return false;24342435intel_sdvo_connector->dot_crawl->values[0] = 0;2436intel_sdvo_connector->dot_crawl->values[1] = 1;2437drm_connector_attach_property(connector,2438intel_sdvo_connector->dot_crawl,2439intel_sdvo_connector->cur_dot_crawl);2440DRM_DEBUG_KMS("dot crawl: current %d\n", response);2441}24422443return true;2444}24452446static bool2447intel_sdvo_create_enhance_property_lvds(struct intel_sdvo *intel_sdvo,2448struct intel_sdvo_connector *intel_sdvo_connector,2449struct intel_sdvo_enhancements_reply enhancements)2450{2451struct drm_device *dev = intel_sdvo->base.base.dev;2452struct drm_connector *connector = &intel_sdvo_connector->base.base;2453uint16_t response, data_value[2];24542455ENHANCEMENT(brightness, BRIGHTNESS);24562457return true;2458}2459#undef ENHANCEMENT24602461static bool intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo,2462struct intel_sdvo_connector *intel_sdvo_connector)2463{2464union {2465struct intel_sdvo_enhancements_reply reply;2466uint16_t response;2467} enhancements;24682469BUILD_BUG_ON(sizeof(enhancements) != 2);24702471enhancements.response = 0;2472intel_sdvo_get_value(intel_sdvo,2473SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS,2474&enhancements, sizeof(enhancements));2475if (enhancements.response == 0) {2476DRM_DEBUG_KMS("No enhancement is supported\n");2477return true;2478}24792480if (IS_TV(intel_sdvo_connector))2481return intel_sdvo_create_enhance_property_tv(intel_sdvo, intel_sdvo_connector, enhancements.reply);2482else if(IS_LVDS(intel_sdvo_connector))2483return intel_sdvo_create_enhance_property_lvds(intel_sdvo, intel_sdvo_connector, enhancements.reply);2484else2485return true;2486}24872488static int intel_sdvo_ddc_proxy_xfer(struct i2c_adapter *adapter,2489struct i2c_msg *msgs,2490int num)2491{2492struct intel_sdvo *sdvo = adapter->algo_data;24932494if (!intel_sdvo_set_control_bus_switch(sdvo, sdvo->ddc_bus))2495return -EIO;24962497return sdvo->i2c->algo->master_xfer(sdvo->i2c, msgs, num);2498}24992500static u32 intel_sdvo_ddc_proxy_func(struct i2c_adapter *adapter)2501{2502struct intel_sdvo *sdvo = adapter->algo_data;2503return sdvo->i2c->algo->functionality(sdvo->i2c);2504}25052506static const struct i2c_algorithm intel_sdvo_ddc_proxy = {2507.master_xfer = intel_sdvo_ddc_proxy_xfer,2508.functionality = intel_sdvo_ddc_proxy_func2509};25102511static bool2512intel_sdvo_init_ddc_proxy(struct intel_sdvo *sdvo,2513struct drm_device *dev)2514{2515sdvo->ddc.owner = THIS_MODULE;2516sdvo->ddc.class = I2C_CLASS_DDC;2517snprintf(sdvo->ddc.name, I2C_NAME_SIZE, "SDVO DDC proxy");2518sdvo->ddc.dev.parent = &dev->pdev->dev;2519sdvo->ddc.algo_data = sdvo;2520sdvo->ddc.algo = &intel_sdvo_ddc_proxy;25212522return i2c_add_adapter(&sdvo->ddc) == 0;2523}25242525bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg)2526{2527struct drm_i915_private *dev_priv = dev->dev_private;2528struct intel_encoder *intel_encoder;2529struct intel_sdvo *intel_sdvo;2530int i;25312532intel_sdvo = kzalloc(sizeof(struct intel_sdvo), GFP_KERNEL);2533if (!intel_sdvo)2534return false;25352536intel_sdvo->sdvo_reg = sdvo_reg;2537intel_sdvo->slave_addr = intel_sdvo_get_slave_addr(dev, sdvo_reg) >> 1;2538intel_sdvo_select_i2c_bus(dev_priv, intel_sdvo, sdvo_reg);2539if (!intel_sdvo_init_ddc_proxy(intel_sdvo, dev)) {2540kfree(intel_sdvo);2541return false;2542}25432544/* encoder type will be decided later */2545intel_encoder = &intel_sdvo->base;2546intel_encoder->type = INTEL_OUTPUT_SDVO;2547drm_encoder_init(dev, &intel_encoder->base, &intel_sdvo_enc_funcs, 0);25482549/* Read the regs to test if we can talk to the device */2550for (i = 0; i < 0x40; i++) {2551u8 byte;25522553if (!intel_sdvo_read_byte(intel_sdvo, i, &byte)) {2554DRM_DEBUG_KMS("No SDVO device found on SDVO%c\n",2555IS_SDVOB(sdvo_reg) ? 'B' : 'C');2556goto err;2557}2558}25592560if (IS_SDVOB(sdvo_reg))2561dev_priv->hotplug_supported_mask |= SDVOB_HOTPLUG_INT_STATUS;2562else2563dev_priv->hotplug_supported_mask |= SDVOC_HOTPLUG_INT_STATUS;25642565drm_encoder_helper_add(&intel_encoder->base, &intel_sdvo_helper_funcs);25662567/* In default case sdvo lvds is false */2568if (!intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps))2569goto err;25702571if (intel_sdvo_output_setup(intel_sdvo,2572intel_sdvo->caps.output_flags) != true) {2573DRM_DEBUG_KMS("SDVO output failed to setup on SDVO%c\n",2574IS_SDVOB(sdvo_reg) ? 'B' : 'C');2575goto err;2576}25772578intel_sdvo_select_ddc_bus(dev_priv, intel_sdvo, sdvo_reg);25792580/* Set the input timing to the screen. Assume always input 0. */2581if (!intel_sdvo_set_target_input(intel_sdvo))2582goto err;25832584if (!intel_sdvo_get_input_pixel_clock_range(intel_sdvo,2585&intel_sdvo->pixel_clock_min,2586&intel_sdvo->pixel_clock_max))2587goto err;25882589DRM_DEBUG_KMS("%s device VID/DID: %02X:%02X.%02X, "2590"clock range %dMHz - %dMHz, "2591"input 1: %c, input 2: %c, "2592"output 1: %c, output 2: %c\n",2593SDVO_NAME(intel_sdvo),2594intel_sdvo->caps.vendor_id, intel_sdvo->caps.device_id,2595intel_sdvo->caps.device_rev_id,2596intel_sdvo->pixel_clock_min / 1000,2597intel_sdvo->pixel_clock_max / 1000,2598(intel_sdvo->caps.sdvo_inputs_mask & 0x1) ? 'Y' : 'N',2599(intel_sdvo->caps.sdvo_inputs_mask & 0x2) ? 'Y' : 'N',2600/* check currently supported outputs */2601intel_sdvo->caps.output_flags &2602(SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_RGB0) ? 'Y' : 'N',2603intel_sdvo->caps.output_flags &2604(SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N');2605return true;26062607err:2608drm_encoder_cleanup(&intel_encoder->base);2609i2c_del_adapter(&intel_sdvo->ddc);2610kfree(intel_sdvo);26112612return false;2613}261426152616