1296548Sdumbbell/* 2296548Sdumbbell * Copyright �� 2006 Intel Corporation 3296548Sdumbbell * 4296548Sdumbbell * Permission is hereby granted, free of charge, to any person obtaining a 5296548Sdumbbell * copy of this software and associated documentation files (the "Software"), 6296548Sdumbbell * to deal in the Software without restriction, including without limitation 7296548Sdumbbell * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8296548Sdumbbell * and/or sell copies of the Software, and to permit persons to whom the 9296548Sdumbbell * Software is furnished to do so, subject to the following conditions: 10296548Sdumbbell * 11296548Sdumbbell * The above copyright notice and this permission notice (including the next 12296548Sdumbbell * paragraph) shall be included in all copies or substantial portions of the 13296548Sdumbbell * Software. 14296548Sdumbbell * 15296548Sdumbbell * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16296548Sdumbbell * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17296548Sdumbbell * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18296548Sdumbbell * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19296548Sdumbbell * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20296548Sdumbbell * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21296548Sdumbbell * DEALINGS IN THE SOFTWARE. 22296548Sdumbbell * 23296548Sdumbbell * Authors: 24296548Sdumbbell * Eric Anholt <eric@anholt.net> 25296548Sdumbbell * 26296548Sdumbbell */ 27296548Sdumbbell 28296548Sdumbbell#include <sys/cdefs.h> 29296548Sdumbbell__FBSDID("$FreeBSD$"); 30296548Sdumbbell 31296548Sdumbbell#include "dvo.h" 32296548Sdumbbell 33296548Sdumbbell#define CH7017_TV_DISPLAY_MODE 0x00 34296548Sdumbbell#define CH7017_FLICKER_FILTER 0x01 35296548Sdumbbell#define CH7017_VIDEO_BANDWIDTH 0x02 36296548Sdumbbell#define CH7017_TEXT_ENHANCEMENT 0x03 37296548Sdumbbell#define CH7017_START_ACTIVE_VIDEO 0x04 38296548Sdumbbell#define CH7017_HORIZONTAL_POSITION 0x05 39296548Sdumbbell#define CH7017_VERTICAL_POSITION 0x06 40296548Sdumbbell#define CH7017_BLACK_LEVEL 0x07 41296548Sdumbbell#define CH7017_CONTRAST_ENHANCEMENT 0x08 42296548Sdumbbell#define CH7017_TV_PLL 0x09 43296548Sdumbbell#define CH7017_TV_PLL_M 0x0a 44296548Sdumbbell#define CH7017_TV_PLL_N 0x0b 45296548Sdumbbell#define CH7017_SUB_CARRIER_0 0x0c 46296548Sdumbbell#define CH7017_CIV_CONTROL 0x10 47296548Sdumbbell#define CH7017_CIV_0 0x11 48296548Sdumbbell#define CH7017_CHROMA_BOOST 0x14 49296548Sdumbbell#define CH7017_CLOCK_MODE 0x1c 50296548Sdumbbell#define CH7017_INPUT_CLOCK 0x1d 51296548Sdumbbell#define CH7017_GPIO_CONTROL 0x1e 52296548Sdumbbell#define CH7017_INPUT_DATA_FORMAT 0x1f 53296548Sdumbbell#define CH7017_CONNECTION_DETECT 0x20 54296548Sdumbbell#define CH7017_DAC_CONTROL 0x21 55296548Sdumbbell#define CH7017_BUFFERED_CLOCK_OUTPUT 0x22 56296548Sdumbbell#define CH7017_DEFEAT_VSYNC 0x47 57296548Sdumbbell#define CH7017_TEST_PATTERN 0x48 58296548Sdumbbell 59296548Sdumbbell#define CH7017_POWER_MANAGEMENT 0x49 60296548Sdumbbell/** Enables the TV output path. */ 61296548Sdumbbell#define CH7017_TV_EN (1 << 0) 62296548Sdumbbell#define CH7017_DAC0_POWER_DOWN (1 << 1) 63296548Sdumbbell#define CH7017_DAC1_POWER_DOWN (1 << 2) 64296548Sdumbbell#define CH7017_DAC2_POWER_DOWN (1 << 3) 65296548Sdumbbell#define CH7017_DAC3_POWER_DOWN (1 << 4) 66296548Sdumbbell/** Powers down the TV out block, and DAC0-3 */ 67296548Sdumbbell#define CH7017_TV_POWER_DOWN_EN (1 << 5) 68296548Sdumbbell 69296548Sdumbbell#define CH7017_VERSION_ID 0x4a 70296548Sdumbbell 71296548Sdumbbell#define CH7017_DEVICE_ID 0x4b 72296548Sdumbbell#define CH7017_DEVICE_ID_VALUE 0x1b 73296548Sdumbbell#define CH7018_DEVICE_ID_VALUE 0x1a 74296548Sdumbbell#define CH7019_DEVICE_ID_VALUE 0x19 75296548Sdumbbell 76296548Sdumbbell#define CH7017_XCLK_D2_ADJUST 0x53 77296548Sdumbbell#define CH7017_UP_SCALER_COEFF_0 0x55 78296548Sdumbbell#define CH7017_UP_SCALER_COEFF_1 0x56 79296548Sdumbbell#define CH7017_UP_SCALER_COEFF_2 0x57 80296548Sdumbbell#define CH7017_UP_SCALER_COEFF_3 0x58 81296548Sdumbbell#define CH7017_UP_SCALER_COEFF_4 0x59 82296548Sdumbbell#define CH7017_UP_SCALER_VERTICAL_INC_0 0x5a 83296548Sdumbbell#define CH7017_UP_SCALER_VERTICAL_INC_1 0x5b 84296548Sdumbbell#define CH7017_GPIO_INVERT 0x5c 85296548Sdumbbell#define CH7017_UP_SCALER_HORIZONTAL_INC_0 0x5d 86296548Sdumbbell#define CH7017_UP_SCALER_HORIZONTAL_INC_1 0x5e 87296548Sdumbbell 88296548Sdumbbell#define CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT 0x5f 89296548Sdumbbell/**< Low bits of horizontal active pixel input */ 90296548Sdumbbell 91296548Sdumbbell#define CH7017_ACTIVE_INPUT_LINE_OUTPUT 0x60 92296548Sdumbbell/** High bits of horizontal active pixel input */ 93296548Sdumbbell#define CH7017_LVDS_HAP_INPUT_MASK (0x7 << 0) 94296548Sdumbbell/** High bits of vertical active line output */ 95296548Sdumbbell#define CH7017_LVDS_VAL_HIGH_MASK (0x7 << 3) 96296548Sdumbbell 97296548Sdumbbell#define CH7017_VERTICAL_ACTIVE_LINE_OUTPUT 0x61 98296548Sdumbbell/**< Low bits of vertical active line output */ 99296548Sdumbbell 100296548Sdumbbell#define CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT 0x62 101296548Sdumbbell/**< Low bits of horizontal active pixel output */ 102296548Sdumbbell 103296548Sdumbbell#define CH7017_LVDS_POWER_DOWN 0x63 104296548Sdumbbell/** High bits of horizontal active pixel output */ 105296548Sdumbbell#define CH7017_LVDS_HAP_HIGH_MASK (0x7 << 0) 106296548Sdumbbell/** Enables the LVDS power down state transition */ 107296548Sdumbbell#define CH7017_LVDS_POWER_DOWN_EN (1 << 6) 108296548Sdumbbell/** Enables the LVDS upscaler */ 109296548Sdumbbell#define CH7017_LVDS_UPSCALER_EN (1 << 7) 110296548Sdumbbell#define CH7017_LVDS_POWER_DOWN_DEFAULT_RESERVED 0x08 111296548Sdumbbell 112296548Sdumbbell#define CH7017_LVDS_ENCODING 0x64 113296548Sdumbbell#define CH7017_LVDS_DITHER_2D (1 << 2) 114296548Sdumbbell#define CH7017_LVDS_DITHER_DIS (1 << 3) 115296548Sdumbbell#define CH7017_LVDS_DUAL_CHANNEL_EN (1 << 4) 116296548Sdumbbell#define CH7017_LVDS_24_BIT (1 << 5) 117296548Sdumbbell 118296548Sdumbbell#define CH7017_LVDS_ENCODING_2 0x65 119296548Sdumbbell 120296548Sdumbbell#define CH7017_LVDS_PLL_CONTROL 0x66 121296548Sdumbbell/** Enables the LVDS panel output path */ 122296548Sdumbbell#define CH7017_LVDS_PANEN (1 << 0) 123296548Sdumbbell/** Enables the LVDS panel backlight */ 124296548Sdumbbell#define CH7017_LVDS_BKLEN (1 << 3) 125296548Sdumbbell 126296548Sdumbbell#define CH7017_POWER_SEQUENCING_T1 0x67 127296548Sdumbbell#define CH7017_POWER_SEQUENCING_T2 0x68 128296548Sdumbbell#define CH7017_POWER_SEQUENCING_T3 0x69 129296548Sdumbbell#define CH7017_POWER_SEQUENCING_T4 0x6a 130296548Sdumbbell#define CH7017_POWER_SEQUENCING_T5 0x6b 131296548Sdumbbell#define CH7017_GPIO_DRIVER_TYPE 0x6c 132296548Sdumbbell#define CH7017_GPIO_DATA 0x6d 133296548Sdumbbell#define CH7017_GPIO_DIRECTION_CONTROL 0x6e 134296548Sdumbbell 135296548Sdumbbell#define CH7017_LVDS_PLL_FEEDBACK_DIV 0x71 136296548Sdumbbell# define CH7017_LVDS_PLL_FEED_BACK_DIVIDER_SHIFT 4 137296548Sdumbbell# define CH7017_LVDS_PLL_FEED_FORWARD_DIVIDER_SHIFT 0 138296548Sdumbbell# define CH7017_LVDS_PLL_FEEDBACK_DEFAULT_RESERVED 0x80 139296548Sdumbbell 140296548Sdumbbell#define CH7017_LVDS_PLL_VCO_CONTROL 0x72 141296548Sdumbbell# define CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED 0x80 142296548Sdumbbell# define CH7017_LVDS_PLL_VCO_SHIFT 4 143296548Sdumbbell# define CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT 0 144296548Sdumbbell 145296548Sdumbbell#define CH7017_OUTPUTS_ENABLE 0x73 146296548Sdumbbell# define CH7017_CHARGE_PUMP_LOW 0x0 147296548Sdumbbell# define CH7017_CHARGE_PUMP_HIGH 0x3 148296548Sdumbbell# define CH7017_LVDS_CHANNEL_A (1 << 3) 149296548Sdumbbell# define CH7017_LVDS_CHANNEL_B (1 << 4) 150296548Sdumbbell# define CH7017_TV_DAC_A (1 << 5) 151296548Sdumbbell# define CH7017_TV_DAC_B (1 << 6) 152296548Sdumbbell# define CH7017_DDC_SELECT_DC2 (1 << 7) 153296548Sdumbbell 154296548Sdumbbell#define CH7017_LVDS_OUTPUT_AMPLITUDE 0x74 155296548Sdumbbell#define CH7017_LVDS_PLL_EMI_REDUCTION 0x75 156296548Sdumbbell#define CH7017_LVDS_POWER_DOWN_FLICKER 0x76 157296548Sdumbbell 158296548Sdumbbell#define CH7017_LVDS_CONTROL_2 0x78 159296548Sdumbbell# define CH7017_LOOP_FILTER_SHIFT 5 160296548Sdumbbell# define CH7017_PHASE_DETECTOR_SHIFT 0 161296548Sdumbbell 162296548Sdumbbell#define CH7017_BANG_LIMIT_CONTROL 0x7f 163296548Sdumbbell 164296548Sdumbbellstruct ch7017_priv { 165296548Sdumbbell uint8_t dummy; 166296548Sdumbbell}; 167296548Sdumbbell 168296548Sdumbbellstatic void ch7017_dump_regs(struct intel_dvo_device *dvo); 169296548Sdumbbellstatic void ch7017_dpms(struct intel_dvo_device *dvo, bool enable); 170296548Sdumbbell 171296548Sdumbbellstatic bool ch7017_read(struct intel_dvo_device *dvo, u8 addr, u8 *val) 172296548Sdumbbell{ 173296548Sdumbbell struct iic_msg msgs[] = { 174296548Sdumbbell { 175296548Sdumbbell .slave = dvo->slave_addr << 1, 176296548Sdumbbell .flags = 0, 177296548Sdumbbell .len = 1, 178296548Sdumbbell .buf = &addr, 179296548Sdumbbell }, 180296548Sdumbbell { 181296548Sdumbbell .slave = dvo->slave_addr << 1, 182296548Sdumbbell .flags = I2C_M_RD, 183296548Sdumbbell .len = 1, 184296548Sdumbbell .buf = val, 185296548Sdumbbell } 186296548Sdumbbell }; 187296548Sdumbbell return -iicbus_transfer(dvo->i2c_bus, msgs, 2) == 0; 188296548Sdumbbell} 189296548Sdumbbell 190296548Sdumbbellstatic bool ch7017_write(struct intel_dvo_device *dvo, u8 addr, u8 val) 191296548Sdumbbell{ 192296548Sdumbbell uint8_t buf[2] = { addr, val }; 193296548Sdumbbell struct iic_msg msg = { 194296548Sdumbbell .slave = dvo->slave_addr << 1, 195296548Sdumbbell .flags = 0, 196296548Sdumbbell .len = 2, 197296548Sdumbbell .buf = buf, 198296548Sdumbbell }; 199296548Sdumbbell return -iicbus_transfer(dvo->i2c_bus, &msg, 1) == 0; 200296548Sdumbbell} 201296548Sdumbbell 202296548Sdumbbell/** Probes for a CH7017 on the given bus and slave address. */ 203296548Sdumbbellstatic bool ch7017_init(struct intel_dvo_device *dvo, 204296548Sdumbbell device_t adapter) 205296548Sdumbbell{ 206296548Sdumbbell struct ch7017_priv *priv; 207296548Sdumbbell const char *str; 208296548Sdumbbell u8 val; 209296548Sdumbbell 210296548Sdumbbell priv = malloc(sizeof(struct ch7017_priv), DRM_MEM_KMS, M_NOWAIT | M_ZERO); 211296548Sdumbbell if (priv == NULL) 212296548Sdumbbell return false; 213296548Sdumbbell 214296548Sdumbbell dvo->i2c_bus = adapter; 215296548Sdumbbell dvo->dev_priv = priv; 216296548Sdumbbell 217296548Sdumbbell if (!ch7017_read(dvo, CH7017_DEVICE_ID, &val)) 218296548Sdumbbell goto fail; 219296548Sdumbbell 220296548Sdumbbell switch (val) { 221296548Sdumbbell case CH7017_DEVICE_ID_VALUE: 222296548Sdumbbell str = "ch7017"; 223296548Sdumbbell break; 224296548Sdumbbell case CH7018_DEVICE_ID_VALUE: 225296548Sdumbbell str = "ch7018"; 226296548Sdumbbell break; 227296548Sdumbbell case CH7019_DEVICE_ID_VALUE: 228296548Sdumbbell str = "ch7019"; 229296548Sdumbbell break; 230296548Sdumbbell default: 231296548Sdumbbell DRM_DEBUG_KMS("ch701x not detected, got %d: from %s " 232296548Sdumbbell "slave %d.\n", 233296548Sdumbbell val, device_get_nameunit(adapter), 234296548Sdumbbell dvo->slave_addr); 235296548Sdumbbell goto fail; 236296548Sdumbbell } 237296548Sdumbbell 238296548Sdumbbell DRM_DEBUG_KMS("%s detected on %s, addr %d\n", 239296548Sdumbbell str, device_get_nameunit(adapter), dvo->slave_addr); 240296548Sdumbbell return true; 241296548Sdumbbell 242296548Sdumbbellfail: 243296548Sdumbbell free(priv, DRM_MEM_KMS); 244296548Sdumbbell return false; 245296548Sdumbbell} 246296548Sdumbbell 247296548Sdumbbellstatic enum drm_connector_status ch7017_detect(struct intel_dvo_device *dvo) 248296548Sdumbbell{ 249296548Sdumbbell return connector_status_connected; 250296548Sdumbbell} 251296548Sdumbbell 252296548Sdumbbellstatic enum drm_mode_status ch7017_mode_valid(struct intel_dvo_device *dvo, 253296548Sdumbbell struct drm_display_mode *mode) 254296548Sdumbbell{ 255296548Sdumbbell if (mode->clock > 160000) 256296548Sdumbbell return MODE_CLOCK_HIGH; 257296548Sdumbbell 258296548Sdumbbell return MODE_OK; 259296548Sdumbbell} 260296548Sdumbbell 261296548Sdumbbellstatic void ch7017_mode_set(struct intel_dvo_device *dvo, 262296548Sdumbbell struct drm_display_mode *mode, 263296548Sdumbbell struct drm_display_mode *adjusted_mode) 264296548Sdumbbell{ 265296548Sdumbbell uint8_t lvds_pll_feedback_div, lvds_pll_vco_control; 266296548Sdumbbell uint8_t outputs_enable, lvds_control_2, lvds_power_down; 267296548Sdumbbell uint8_t horizontal_active_pixel_input; 268296548Sdumbbell uint8_t horizontal_active_pixel_output, vertical_active_line_output; 269296548Sdumbbell uint8_t active_input_line_output; 270296548Sdumbbell 271296548Sdumbbell DRM_DEBUG_KMS("Registers before mode setting\n"); 272296548Sdumbbell ch7017_dump_regs(dvo); 273296548Sdumbbell 274296548Sdumbbell /* LVDS PLL settings from page 75 of 7017-7017ds.pdf*/ 275296548Sdumbbell if (mode->clock < 100000) { 276296548Sdumbbell outputs_enable = CH7017_LVDS_CHANNEL_A | CH7017_CHARGE_PUMP_LOW; 277296548Sdumbbell lvds_pll_feedback_div = CH7017_LVDS_PLL_FEEDBACK_DEFAULT_RESERVED | 278296548Sdumbbell (2 << CH7017_LVDS_PLL_FEED_BACK_DIVIDER_SHIFT) | 279296548Sdumbbell (13 << CH7017_LVDS_PLL_FEED_FORWARD_DIVIDER_SHIFT); 280296548Sdumbbell lvds_pll_vco_control = CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED | 281296548Sdumbbell (2 << CH7017_LVDS_PLL_VCO_SHIFT) | 282296548Sdumbbell (3 << CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT); 283296548Sdumbbell lvds_control_2 = (1 << CH7017_LOOP_FILTER_SHIFT) | 284296548Sdumbbell (0 << CH7017_PHASE_DETECTOR_SHIFT); 285296548Sdumbbell } else { 286296548Sdumbbell outputs_enable = CH7017_LVDS_CHANNEL_A | CH7017_CHARGE_PUMP_HIGH; 287296548Sdumbbell lvds_pll_feedback_div = CH7017_LVDS_PLL_FEEDBACK_DEFAULT_RESERVED | 288296548Sdumbbell (2 << CH7017_LVDS_PLL_FEED_BACK_DIVIDER_SHIFT) | 289296548Sdumbbell (3 << CH7017_LVDS_PLL_FEED_FORWARD_DIVIDER_SHIFT); 290296548Sdumbbell lvds_pll_feedback_div = 35; 291296548Sdumbbell lvds_control_2 = (3 << CH7017_LOOP_FILTER_SHIFT) | 292296548Sdumbbell (0 << CH7017_PHASE_DETECTOR_SHIFT); 293296548Sdumbbell if (1) { /* XXX: dual channel panel detection. Assume yes for now. */ 294296548Sdumbbell outputs_enable |= CH7017_LVDS_CHANNEL_B; 295296548Sdumbbell lvds_pll_vco_control = CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED | 296296548Sdumbbell (2 << CH7017_LVDS_PLL_VCO_SHIFT) | 297296548Sdumbbell (13 << CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT); 298296548Sdumbbell } else { 299296548Sdumbbell lvds_pll_vco_control = CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED | 300296548Sdumbbell (1 << CH7017_LVDS_PLL_VCO_SHIFT) | 301296548Sdumbbell (13 << CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT); 302296548Sdumbbell } 303296548Sdumbbell } 304296548Sdumbbell 305296548Sdumbbell horizontal_active_pixel_input = mode->hdisplay & 0x00ff; 306296548Sdumbbell 307296548Sdumbbell vertical_active_line_output = mode->vdisplay & 0x00ff; 308296548Sdumbbell horizontal_active_pixel_output = mode->hdisplay & 0x00ff; 309296548Sdumbbell 310296548Sdumbbell active_input_line_output = ((mode->hdisplay & 0x0700) >> 8) | 311296548Sdumbbell (((mode->vdisplay & 0x0700) >> 8) << 3); 312296548Sdumbbell 313296548Sdumbbell lvds_power_down = CH7017_LVDS_POWER_DOWN_DEFAULT_RESERVED | 314296548Sdumbbell (mode->hdisplay & 0x0700) >> 8; 315296548Sdumbbell 316296548Sdumbbell ch7017_dpms(dvo, false); 317296548Sdumbbell ch7017_write(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT, 318296548Sdumbbell horizontal_active_pixel_input); 319296548Sdumbbell ch7017_write(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT, 320296548Sdumbbell horizontal_active_pixel_output); 321296548Sdumbbell ch7017_write(dvo, CH7017_VERTICAL_ACTIVE_LINE_OUTPUT, 322296548Sdumbbell vertical_active_line_output); 323296548Sdumbbell ch7017_write(dvo, CH7017_ACTIVE_INPUT_LINE_OUTPUT, 324296548Sdumbbell active_input_line_output); 325296548Sdumbbell ch7017_write(dvo, CH7017_LVDS_PLL_VCO_CONTROL, lvds_pll_vco_control); 326296548Sdumbbell ch7017_write(dvo, CH7017_LVDS_PLL_FEEDBACK_DIV, lvds_pll_feedback_div); 327296548Sdumbbell ch7017_write(dvo, CH7017_LVDS_CONTROL_2, lvds_control_2); 328296548Sdumbbell ch7017_write(dvo, CH7017_OUTPUTS_ENABLE, outputs_enable); 329296548Sdumbbell 330296548Sdumbbell /* Turn the LVDS back on with new settings. */ 331296548Sdumbbell ch7017_write(dvo, CH7017_LVDS_POWER_DOWN, lvds_power_down); 332296548Sdumbbell 333296548Sdumbbell DRM_DEBUG_KMS("Registers after mode setting\n"); 334296548Sdumbbell ch7017_dump_regs(dvo); 335296548Sdumbbell} 336296548Sdumbbell 337296548Sdumbbell/* set the CH7017 power state */ 338296548Sdumbbellstatic void ch7017_dpms(struct intel_dvo_device *dvo, bool enable) 339296548Sdumbbell{ 340296548Sdumbbell uint8_t val; 341296548Sdumbbell 342296548Sdumbbell ch7017_read(dvo, CH7017_LVDS_POWER_DOWN, &val); 343296548Sdumbbell 344296548Sdumbbell /* Turn off TV/VGA, and never turn it on since we don't support it. */ 345296548Sdumbbell ch7017_write(dvo, CH7017_POWER_MANAGEMENT, 346296548Sdumbbell CH7017_DAC0_POWER_DOWN | 347296548Sdumbbell CH7017_DAC1_POWER_DOWN | 348296548Sdumbbell CH7017_DAC2_POWER_DOWN | 349296548Sdumbbell CH7017_DAC3_POWER_DOWN | 350296548Sdumbbell CH7017_TV_POWER_DOWN_EN); 351296548Sdumbbell 352296548Sdumbbell if (enable) { 353296548Sdumbbell /* Turn on the LVDS */ 354296548Sdumbbell ch7017_write(dvo, CH7017_LVDS_POWER_DOWN, 355296548Sdumbbell val & ~CH7017_LVDS_POWER_DOWN_EN); 356296548Sdumbbell } else { 357296548Sdumbbell /* Turn off the LVDS */ 358296548Sdumbbell ch7017_write(dvo, CH7017_LVDS_POWER_DOWN, 359296548Sdumbbell val | CH7017_LVDS_POWER_DOWN_EN); 360296548Sdumbbell } 361296548Sdumbbell 362296548Sdumbbell /* XXX: Should actually wait for update power status somehow */ 363296548Sdumbbell drm_msleep(20, "ch7017"); 364296548Sdumbbell} 365296548Sdumbbell 366296548Sdumbbellstatic bool ch7017_get_hw_state(struct intel_dvo_device *dvo) 367296548Sdumbbell{ 368296548Sdumbbell uint8_t val; 369296548Sdumbbell 370296548Sdumbbell ch7017_read(dvo, CH7017_LVDS_POWER_DOWN, &val); 371296548Sdumbbell 372296548Sdumbbell if (val & CH7017_LVDS_POWER_DOWN_EN) 373296548Sdumbbell return false; 374296548Sdumbbell else 375296548Sdumbbell return true; 376296548Sdumbbell} 377296548Sdumbbell 378296548Sdumbbellstatic void ch7017_dump_regs(struct intel_dvo_device *dvo) 379296548Sdumbbell{ 380296548Sdumbbell uint8_t val; 381296548Sdumbbell 382296548Sdumbbell#define DUMP(reg) \ 383296548Sdumbbelldo { \ 384296548Sdumbbell ch7017_read(dvo, reg, &val); \ 385296548Sdumbbell DRM_DEBUG_KMS(#reg ": %02x\n", val); \ 386296548Sdumbbell} while (0) 387296548Sdumbbell 388296548Sdumbbell DUMP(CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT); 389296548Sdumbbell DUMP(CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT); 390296548Sdumbbell DUMP(CH7017_VERTICAL_ACTIVE_LINE_OUTPUT); 391296548Sdumbbell DUMP(CH7017_ACTIVE_INPUT_LINE_OUTPUT); 392296548Sdumbbell DUMP(CH7017_LVDS_PLL_VCO_CONTROL); 393296548Sdumbbell DUMP(CH7017_LVDS_PLL_FEEDBACK_DIV); 394296548Sdumbbell DUMP(CH7017_LVDS_CONTROL_2); 395296548Sdumbbell DUMP(CH7017_OUTPUTS_ENABLE); 396296548Sdumbbell DUMP(CH7017_LVDS_POWER_DOWN); 397296548Sdumbbell} 398296548Sdumbbell 399296548Sdumbbellstatic void ch7017_destroy(struct intel_dvo_device *dvo) 400296548Sdumbbell{ 401296548Sdumbbell struct ch7017_priv *priv = dvo->dev_priv; 402296548Sdumbbell 403296548Sdumbbell if (priv) { 404296548Sdumbbell free(priv, DRM_MEM_KMS); 405296548Sdumbbell dvo->dev_priv = NULL; 406296548Sdumbbell } 407296548Sdumbbell} 408296548Sdumbbell 409296548Sdumbbellstruct intel_dvo_dev_ops ch7017_ops = { 410296548Sdumbbell .init = ch7017_init, 411296548Sdumbbell .detect = ch7017_detect, 412296548Sdumbbell .mode_valid = ch7017_mode_valid, 413296548Sdumbbell .mode_set = ch7017_mode_set, 414296548Sdumbbell .dpms = ch7017_dpms, 415296548Sdumbbell .get_hw_state = ch7017_get_hw_state, 416296548Sdumbbell .dump_regs = ch7017_dump_regs, 417296548Sdumbbell .destroy = ch7017_destroy, 418296548Sdumbbell}; 419