| 1 | /* | 
|---|
| 2 | * Copyright © 2006 Intel Corporation | 
|---|
| 3 | * | 
|---|
| 4 | * Permission is hereby granted, free of charge, to any person obtaining a | 
|---|
| 5 | * copy of this software and associated documentation files (the "Software"), | 
|---|
| 6 | * to deal in the Software without restriction, including without limitation | 
|---|
| 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | 
|---|
| 8 | * and/or sell copies of the Software, and to permit persons to whom the | 
|---|
| 9 | * Software is furnished to do so, subject to the following conditions: | 
|---|
| 10 | * | 
|---|
| 11 | * The above copyright notice and this permission notice (including the next | 
|---|
| 12 | * paragraph) shall be included in all copies or substantial portions of the | 
|---|
| 13 | * Software. | 
|---|
| 14 | * | 
|---|
| 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | 
|---|
| 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | 
|---|
| 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL | 
|---|
| 18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | 
|---|
| 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | 
|---|
| 20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | 
|---|
| 21 | * DEALINGS IN THE SOFTWARE. | 
|---|
| 22 | * | 
|---|
| 23 | * Authors: | 
|---|
| 24 | *    Eric Anholt <eric@anholt.net> | 
|---|
| 25 | * | 
|---|
| 26 | */ | 
|---|
| 27 |  | 
|---|
| 28 | #include <drm/drm_print.h> | 
|---|
| 29 |  | 
|---|
| 30 | #include "intel_display_types.h" | 
|---|
| 31 | #include "intel_dvo_dev.h" | 
|---|
| 32 |  | 
|---|
| 33 | #define CH7017_TV_DISPLAY_MODE		0x00 | 
|---|
| 34 | #define CH7017_FLICKER_FILTER		0x01 | 
|---|
| 35 | #define CH7017_VIDEO_BANDWIDTH		0x02 | 
|---|
| 36 | #define CH7017_TEXT_ENHANCEMENT		0x03 | 
|---|
| 37 | #define CH7017_START_ACTIVE_VIDEO	0x04 | 
|---|
| 38 | #define CH7017_HORIZONTAL_POSITION	0x05 | 
|---|
| 39 | #define CH7017_VERTICAL_POSITION	0x06 | 
|---|
| 40 | #define CH7017_BLACK_LEVEL		0x07 | 
|---|
| 41 | #define CH7017_CONTRAST_ENHANCEMENT	0x08 | 
|---|
| 42 | #define CH7017_TV_PLL			0x09 | 
|---|
| 43 | #define CH7017_TV_PLL_M			0x0a | 
|---|
| 44 | #define CH7017_TV_PLL_N			0x0b | 
|---|
| 45 | #define CH7017_SUB_CARRIER_0		0x0c | 
|---|
| 46 | #define CH7017_CIV_CONTROL		0x10 | 
|---|
| 47 | #define CH7017_CIV_0			0x11 | 
|---|
| 48 | #define CH7017_CHROMA_BOOST		0x14 | 
|---|
| 49 | #define CH7017_CLOCK_MODE		0x1c | 
|---|
| 50 | #define CH7017_INPUT_CLOCK		0x1d | 
|---|
| 51 | #define CH7017_GPIO_CONTROL		0x1e | 
|---|
| 52 | #define CH7017_INPUT_DATA_FORMAT	0x1f | 
|---|
| 53 | #define CH7017_CONNECTION_DETECT	0x20 | 
|---|
| 54 | #define CH7017_DAC_CONTROL		0x21 | 
|---|
| 55 | #define CH7017_BUFFERED_CLOCK_OUTPUT	0x22 | 
|---|
| 56 | #define CH7017_DEFEAT_VSYNC		0x47 | 
|---|
| 57 | #define CH7017_TEST_PATTERN		0x48 | 
|---|
| 58 |  | 
|---|
| 59 | #define CH7017_POWER_MANAGEMENT		0x49 | 
|---|
| 60 | /** Enables the TV output path. */ | 
|---|
| 61 | #define CH7017_TV_EN			(1 << 0) | 
|---|
| 62 | #define CH7017_DAC0_POWER_DOWN		(1 << 1) | 
|---|
| 63 | #define CH7017_DAC1_POWER_DOWN		(1 << 2) | 
|---|
| 64 | #define CH7017_DAC2_POWER_DOWN		(1 << 3) | 
|---|
| 65 | #define CH7017_DAC3_POWER_DOWN		(1 << 4) | 
|---|
| 66 | /** Powers down the TV out block, and DAC0-3 */ | 
|---|
| 67 | #define CH7017_TV_POWER_DOWN_EN		(1 << 5) | 
|---|
| 68 |  | 
|---|
| 69 | #define CH7017_VERSION_ID		0x4a | 
|---|
| 70 |  | 
|---|
| 71 | #define CH7017_DEVICE_ID		0x4b | 
|---|
| 72 | #define CH7017_DEVICE_ID_VALUE		0x1b | 
|---|
| 73 | #define CH7018_DEVICE_ID_VALUE		0x1a | 
|---|
| 74 | #define CH7019_DEVICE_ID_VALUE		0x19 | 
|---|
| 75 |  | 
|---|
| 76 | #define CH7017_XCLK_D2_ADJUST		0x53 | 
|---|
| 77 | #define CH7017_UP_SCALER_COEFF_0	0x55 | 
|---|
| 78 | #define CH7017_UP_SCALER_COEFF_1	0x56 | 
|---|
| 79 | #define CH7017_UP_SCALER_COEFF_2	0x57 | 
|---|
| 80 | #define CH7017_UP_SCALER_COEFF_3	0x58 | 
|---|
| 81 | #define CH7017_UP_SCALER_COEFF_4	0x59 | 
|---|
| 82 | #define CH7017_UP_SCALER_VERTICAL_INC_0	0x5a | 
|---|
| 83 | #define CH7017_UP_SCALER_VERTICAL_INC_1	0x5b | 
|---|
| 84 | #define CH7017_GPIO_INVERT		0x5c | 
|---|
| 85 | #define CH7017_UP_SCALER_HORIZONTAL_INC_0	0x5d | 
|---|
| 86 | #define CH7017_UP_SCALER_HORIZONTAL_INC_1	0x5e | 
|---|
| 87 |  | 
|---|
| 88 | #define CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT	0x5f | 
|---|
| 89 | /**< Low bits of horizontal active pixel input */ | 
|---|
| 90 |  | 
|---|
| 91 | #define CH7017_ACTIVE_INPUT_LINE_OUTPUT	0x60 | 
|---|
| 92 | /** High bits of horizontal active pixel input */ | 
|---|
| 93 | #define CH7017_LVDS_HAP_INPUT_MASK	(0x7 << 0) | 
|---|
| 94 | /** High bits of vertical active line output */ | 
|---|
| 95 | #define CH7017_LVDS_VAL_HIGH_MASK	(0x7 << 3) | 
|---|
| 96 |  | 
|---|
| 97 | #define CH7017_VERTICAL_ACTIVE_LINE_OUTPUT	0x61 | 
|---|
| 98 | /**< Low bits of vertical active line output */ | 
|---|
| 99 |  | 
|---|
| 100 | #define CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT	0x62 | 
|---|
| 101 | /**< Low bits of horizontal active pixel output */ | 
|---|
| 102 |  | 
|---|
| 103 | #define CH7017_LVDS_POWER_DOWN		0x63 | 
|---|
| 104 | /** High bits of horizontal active pixel output */ | 
|---|
| 105 | #define CH7017_LVDS_HAP_HIGH_MASK	(0x7 << 0) | 
|---|
| 106 | /** Enables the LVDS power down state transition */ | 
|---|
| 107 | #define CH7017_LVDS_POWER_DOWN_EN	(1 << 6) | 
|---|
| 108 | /** Enables the LVDS upscaler */ | 
|---|
| 109 | #define CH7017_LVDS_UPSCALER_EN		(1 << 7) | 
|---|
| 110 | #define CH7017_LVDS_POWER_DOWN_DEFAULT_RESERVED 0x08 | 
|---|
| 111 |  | 
|---|
| 112 | #define CH7017_LVDS_ENCODING		0x64 | 
|---|
| 113 | #define CH7017_LVDS_DITHER_2D		(1 << 2) | 
|---|
| 114 | #define CH7017_LVDS_DITHER_DIS		(1 << 3) | 
|---|
| 115 | #define CH7017_LVDS_DUAL_CHANNEL_EN	(1 << 4) | 
|---|
| 116 | #define CH7017_LVDS_24_BIT		(1 << 5) | 
|---|
| 117 |  | 
|---|
| 118 | #define CH7017_LVDS_ENCODING_2		0x65 | 
|---|
| 119 |  | 
|---|
| 120 | #define CH7017_LVDS_PLL_CONTROL		0x66 | 
|---|
| 121 | /** Enables the LVDS panel output path */ | 
|---|
| 122 | #define CH7017_LVDS_PANEN		(1 << 0) | 
|---|
| 123 | /** Enables the LVDS panel backlight */ | 
|---|
| 124 | #define CH7017_LVDS_BKLEN		(1 << 3) | 
|---|
| 125 |  | 
|---|
| 126 | #define CH7017_POWER_SEQUENCING_T1	0x67 | 
|---|
| 127 | #define CH7017_POWER_SEQUENCING_T2	0x68 | 
|---|
| 128 | #define CH7017_POWER_SEQUENCING_T3	0x69 | 
|---|
| 129 | #define CH7017_POWER_SEQUENCING_T4	0x6a | 
|---|
| 130 | #define CH7017_POWER_SEQUENCING_T5	0x6b | 
|---|
| 131 | #define CH7017_GPIO_DRIVER_TYPE		0x6c | 
|---|
| 132 | #define CH7017_GPIO_DATA		0x6d | 
|---|
| 133 | #define CH7017_GPIO_DIRECTION_CONTROL	0x6e | 
|---|
| 134 |  | 
|---|
| 135 | #define CH7017_LVDS_PLL_FEEDBACK_DIV	0x71 | 
|---|
| 136 | # define CH7017_LVDS_PLL_FEED_BACK_DIVIDER_SHIFT 4 | 
|---|
| 137 | # define CH7017_LVDS_PLL_FEED_FORWARD_DIVIDER_SHIFT 0 | 
|---|
| 138 | # define CH7017_LVDS_PLL_FEEDBACK_DEFAULT_RESERVED 0x80 | 
|---|
| 139 |  | 
|---|
| 140 | #define CH7017_LVDS_PLL_VCO_CONTROL	0x72 | 
|---|
| 141 | # define CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED 0x80 | 
|---|
| 142 | # define CH7017_LVDS_PLL_VCO_SHIFT	4 | 
|---|
| 143 | # define CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT 0 | 
|---|
| 144 |  | 
|---|
| 145 | #define CH7017_OUTPUTS_ENABLE		0x73 | 
|---|
| 146 | # define CH7017_CHARGE_PUMP_LOW		0x0 | 
|---|
| 147 | # define CH7017_CHARGE_PUMP_HIGH	0x3 | 
|---|
| 148 | # define CH7017_LVDS_CHANNEL_A		(1 << 3) | 
|---|
| 149 | # define CH7017_LVDS_CHANNEL_B		(1 << 4) | 
|---|
| 150 | # define CH7017_TV_DAC_A		(1 << 5) | 
|---|
| 151 | # define CH7017_TV_DAC_B		(1 << 6) | 
|---|
| 152 | # define CH7017_DDC_SELECT_DC2		(1 << 7) | 
|---|
| 153 |  | 
|---|
| 154 | #define CH7017_LVDS_OUTPUT_AMPLITUDE	0x74 | 
|---|
| 155 | #define CH7017_LVDS_PLL_EMI_REDUCTION	0x75 | 
|---|
| 156 | #define CH7017_LVDS_POWER_DOWN_FLICKER	0x76 | 
|---|
| 157 |  | 
|---|
| 158 | #define CH7017_LVDS_CONTROL_2		0x78 | 
|---|
| 159 | # define CH7017_LOOP_FILTER_SHIFT	5 | 
|---|
| 160 | # define CH7017_PHASE_DETECTOR_SHIFT	0 | 
|---|
| 161 |  | 
|---|
| 162 | #define CH7017_BANG_LIMIT_CONTROL	0x7f | 
|---|
| 163 |  | 
|---|
| 164 | struct ch7017_priv { | 
|---|
| 165 | u8 dummy; | 
|---|
| 166 | }; | 
|---|
| 167 |  | 
|---|
| 168 | static void ch7017_dump_regs(struct intel_dvo_device *dvo); | 
|---|
| 169 | static void ch7017_dpms(struct intel_dvo_device *dvo, bool enable); | 
|---|
| 170 |  | 
|---|
| 171 | static bool ch7017_read(struct intel_dvo_device *dvo, u8 addr, u8 *val) | 
|---|
| 172 | { | 
|---|
| 173 | struct i2c_msg msgs[] = { | 
|---|
| 174 | { | 
|---|
| 175 | .addr = dvo->target_addr, | 
|---|
| 176 | .flags = 0, | 
|---|
| 177 | .len = 1, | 
|---|
| 178 | .buf = &addr, | 
|---|
| 179 | }, | 
|---|
| 180 | { | 
|---|
| 181 | .addr = dvo->target_addr, | 
|---|
| 182 | .flags = I2C_M_RD, | 
|---|
| 183 | .len = 1, | 
|---|
| 184 | .buf = val, | 
|---|
| 185 | } | 
|---|
| 186 | }; | 
|---|
| 187 | return i2c_transfer(adap: dvo->i2c_bus, msgs, num: 2) == 2; | 
|---|
| 188 | } | 
|---|
| 189 |  | 
|---|
| 190 | static bool ch7017_write(struct intel_dvo_device *dvo, u8 addr, u8 val) | 
|---|
| 191 | { | 
|---|
| 192 | u8 buf[2] = { addr, val }; | 
|---|
| 193 | struct i2c_msg msg = { | 
|---|
| 194 | .addr = dvo->target_addr, | 
|---|
| 195 | .flags = 0, | 
|---|
| 196 | .len = 2, | 
|---|
| 197 | .buf = buf, | 
|---|
| 198 | }; | 
|---|
| 199 | return i2c_transfer(adap: dvo->i2c_bus, msgs: &msg, num: 1) == 1; | 
|---|
| 200 | } | 
|---|
| 201 |  | 
|---|
| 202 | /** Probes for a CH7017 on the given bus and target address. */ | 
|---|
| 203 | static bool ch7017_init(struct intel_dvo_device *dvo, | 
|---|
| 204 | struct i2c_adapter *adapter) | 
|---|
| 205 | { | 
|---|
| 206 | struct ch7017_priv *priv; | 
|---|
| 207 | const char *str; | 
|---|
| 208 | u8 val; | 
|---|
| 209 |  | 
|---|
| 210 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | 
|---|
| 211 | if (priv == NULL) | 
|---|
| 212 | return false; | 
|---|
| 213 |  | 
|---|
| 214 | dvo->i2c_bus = adapter; | 
|---|
| 215 | dvo->dev_priv = priv; | 
|---|
| 216 |  | 
|---|
| 217 | if (!ch7017_read(dvo, CH7017_DEVICE_ID, val: &val)) | 
|---|
| 218 | goto fail; | 
|---|
| 219 |  | 
|---|
| 220 | switch (val) { | 
|---|
| 221 | case CH7017_DEVICE_ID_VALUE: | 
|---|
| 222 | str = "ch7017"; | 
|---|
| 223 | break; | 
|---|
| 224 | case CH7018_DEVICE_ID_VALUE: | 
|---|
| 225 | str = "ch7018"; | 
|---|
| 226 | break; | 
|---|
| 227 | case CH7019_DEVICE_ID_VALUE: | 
|---|
| 228 | str = "ch7019"; | 
|---|
| 229 | break; | 
|---|
| 230 | default: | 
|---|
| 231 | DRM_DEBUG_KMS( "ch701x not detected, got %d: from %s " | 
|---|
| 232 | "target %d.\n", | 
|---|
| 233 | val, adapter->name, dvo->target_addr); | 
|---|
| 234 | goto fail; | 
|---|
| 235 | } | 
|---|
| 236 |  | 
|---|
| 237 | DRM_DEBUG_KMS( "%s detected on %s, addr %d\n", | 
|---|
| 238 | str, adapter->name, dvo->target_addr); | 
|---|
| 239 | return true; | 
|---|
| 240 |  | 
|---|
| 241 | fail: | 
|---|
| 242 | kfree(objp: priv); | 
|---|
| 243 | return false; | 
|---|
| 244 | } | 
|---|
| 245 |  | 
|---|
| 246 | static enum drm_connector_status ch7017_detect(struct intel_dvo_device *dvo) | 
|---|
| 247 | { | 
|---|
| 248 | return connector_status_connected; | 
|---|
| 249 | } | 
|---|
| 250 |  | 
|---|
| 251 | static enum drm_mode_status ch7017_mode_valid(struct intel_dvo_device *dvo, | 
|---|
| 252 | const struct drm_display_mode *mode) | 
|---|
| 253 | { | 
|---|
| 254 | if (mode->clock > 160000) | 
|---|
| 255 | return MODE_CLOCK_HIGH; | 
|---|
| 256 |  | 
|---|
| 257 | return MODE_OK; | 
|---|
| 258 | } | 
|---|
| 259 |  | 
|---|
| 260 | static void ch7017_mode_set(struct intel_dvo_device *dvo, | 
|---|
| 261 | const struct drm_display_mode *mode, | 
|---|
| 262 | const struct drm_display_mode *adjusted_mode) | 
|---|
| 263 | { | 
|---|
| 264 | u8 lvds_pll_feedback_div, lvds_pll_vco_control; | 
|---|
| 265 | u8 outputs_enable, lvds_control_2, lvds_power_down; | 
|---|
| 266 | u8 horizontal_active_pixel_input; | 
|---|
| 267 | u8 horizontal_active_pixel_output, vertical_active_line_output; | 
|---|
| 268 | u8 active_input_line_output; | 
|---|
| 269 |  | 
|---|
| 270 | DRM_DEBUG_KMS( "Registers before mode setting\n"); | 
|---|
| 271 | ch7017_dump_regs(dvo); | 
|---|
| 272 |  | 
|---|
| 273 | /* LVDS PLL settings from page 75 of 7017-7017ds.pdf*/ | 
|---|
| 274 | if (mode->clock < 100000) { | 
|---|
| 275 | outputs_enable = CH7017_LVDS_CHANNEL_A | CH7017_CHARGE_PUMP_LOW; | 
|---|
| 276 | lvds_pll_feedback_div = CH7017_LVDS_PLL_FEEDBACK_DEFAULT_RESERVED | | 
|---|
| 277 | (2 << CH7017_LVDS_PLL_FEED_BACK_DIVIDER_SHIFT) | | 
|---|
| 278 | (13 << CH7017_LVDS_PLL_FEED_FORWARD_DIVIDER_SHIFT); | 
|---|
| 279 | lvds_pll_vco_control = CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED | | 
|---|
| 280 | (2 << CH7017_LVDS_PLL_VCO_SHIFT) | | 
|---|
| 281 | (3 << CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT); | 
|---|
| 282 | lvds_control_2 = (1 << CH7017_LOOP_FILTER_SHIFT) | | 
|---|
| 283 | (0 << CH7017_PHASE_DETECTOR_SHIFT); | 
|---|
| 284 | } else { | 
|---|
| 285 | outputs_enable = CH7017_LVDS_CHANNEL_A | CH7017_CHARGE_PUMP_HIGH; | 
|---|
| 286 | lvds_pll_feedback_div = | 
|---|
| 287 | CH7017_LVDS_PLL_FEEDBACK_DEFAULT_RESERVED | | 
|---|
| 288 | (2 << CH7017_LVDS_PLL_FEED_BACK_DIVIDER_SHIFT) | | 
|---|
| 289 | (3 << CH7017_LVDS_PLL_FEED_FORWARD_DIVIDER_SHIFT); | 
|---|
| 290 | lvds_control_2 = (3 << CH7017_LOOP_FILTER_SHIFT) | | 
|---|
| 291 | (0 << CH7017_PHASE_DETECTOR_SHIFT); | 
|---|
| 292 | if (1) { /* XXX: dual channel panel detection.  Assume yes for now. */ | 
|---|
| 293 | outputs_enable |= CH7017_LVDS_CHANNEL_B; | 
|---|
| 294 | lvds_pll_vco_control = CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED | | 
|---|
| 295 | (2 << CH7017_LVDS_PLL_VCO_SHIFT) | | 
|---|
| 296 | (13 << CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT); | 
|---|
| 297 | } else { | 
|---|
| 298 | lvds_pll_vco_control = CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED | | 
|---|
| 299 | (1 << CH7017_LVDS_PLL_VCO_SHIFT) | | 
|---|
| 300 | (13 << CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT); | 
|---|
| 301 | } | 
|---|
| 302 | } | 
|---|
| 303 |  | 
|---|
| 304 | horizontal_active_pixel_input = mode->hdisplay & 0x00ff; | 
|---|
| 305 |  | 
|---|
| 306 | vertical_active_line_output = mode->vdisplay & 0x00ff; | 
|---|
| 307 | horizontal_active_pixel_output = mode->hdisplay & 0x00ff; | 
|---|
| 308 |  | 
|---|
| 309 | active_input_line_output = ((mode->hdisplay & 0x0700) >> 8) | | 
|---|
| 310 | (((mode->vdisplay & 0x0700) >> 8) << 3); | 
|---|
| 311 |  | 
|---|
| 312 | lvds_power_down = CH7017_LVDS_POWER_DOWN_DEFAULT_RESERVED | | 
|---|
| 313 | (mode->hdisplay & 0x0700) >> 8; | 
|---|
| 314 |  | 
|---|
| 315 | ch7017_dpms(dvo, enable: false); | 
|---|
| 316 | ch7017_write(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT, | 
|---|
| 317 | val: horizontal_active_pixel_input); | 
|---|
| 318 | ch7017_write(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT, | 
|---|
| 319 | val: horizontal_active_pixel_output); | 
|---|
| 320 | ch7017_write(dvo, CH7017_VERTICAL_ACTIVE_LINE_OUTPUT, | 
|---|
| 321 | val: vertical_active_line_output); | 
|---|
| 322 | ch7017_write(dvo, CH7017_ACTIVE_INPUT_LINE_OUTPUT, | 
|---|
| 323 | val: active_input_line_output); | 
|---|
| 324 | ch7017_write(dvo, CH7017_LVDS_PLL_VCO_CONTROL, val: lvds_pll_vco_control); | 
|---|
| 325 | ch7017_write(dvo, CH7017_LVDS_PLL_FEEDBACK_DIV, val: lvds_pll_feedback_div); | 
|---|
| 326 | ch7017_write(dvo, CH7017_LVDS_CONTROL_2, val: lvds_control_2); | 
|---|
| 327 | ch7017_write(dvo, CH7017_OUTPUTS_ENABLE, val: outputs_enable); | 
|---|
| 328 |  | 
|---|
| 329 | /* Turn the LVDS back on with new settings. */ | 
|---|
| 330 | ch7017_write(dvo, CH7017_LVDS_POWER_DOWN, val: lvds_power_down); | 
|---|
| 331 |  | 
|---|
| 332 | DRM_DEBUG_KMS( "Registers after mode setting\n"); | 
|---|
| 333 | ch7017_dump_regs(dvo); | 
|---|
| 334 | } | 
|---|
| 335 |  | 
|---|
| 336 | /* set the CH7017 power state */ | 
|---|
| 337 | static void ch7017_dpms(struct intel_dvo_device *dvo, bool enable) | 
|---|
| 338 | { | 
|---|
| 339 | u8 val; | 
|---|
| 340 |  | 
|---|
| 341 | ch7017_read(dvo, CH7017_LVDS_POWER_DOWN, val: &val); | 
|---|
| 342 |  | 
|---|
| 343 | /* Turn off TV/VGA, and never turn it on since we don't support it. */ | 
|---|
| 344 | ch7017_write(dvo, CH7017_POWER_MANAGEMENT, | 
|---|
| 345 | CH7017_DAC0_POWER_DOWN | | 
|---|
| 346 | CH7017_DAC1_POWER_DOWN | | 
|---|
| 347 | CH7017_DAC2_POWER_DOWN | | 
|---|
| 348 | CH7017_DAC3_POWER_DOWN | | 
|---|
| 349 | CH7017_TV_POWER_DOWN_EN); | 
|---|
| 350 |  | 
|---|
| 351 | if (enable) { | 
|---|
| 352 | /* Turn on the LVDS */ | 
|---|
| 353 | ch7017_write(dvo, CH7017_LVDS_POWER_DOWN, | 
|---|
| 354 | val: val & ~CH7017_LVDS_POWER_DOWN_EN); | 
|---|
| 355 | } else { | 
|---|
| 356 | /* Turn off the LVDS */ | 
|---|
| 357 | ch7017_write(dvo, CH7017_LVDS_POWER_DOWN, | 
|---|
| 358 | val: val | CH7017_LVDS_POWER_DOWN_EN); | 
|---|
| 359 | } | 
|---|
| 360 |  | 
|---|
| 361 | /* XXX: Should actually wait for update power status somehow */ | 
|---|
| 362 | msleep(msecs: 20); | 
|---|
| 363 | } | 
|---|
| 364 |  | 
|---|
| 365 | static bool ch7017_get_hw_state(struct intel_dvo_device *dvo) | 
|---|
| 366 | { | 
|---|
| 367 | u8 val; | 
|---|
| 368 |  | 
|---|
| 369 | ch7017_read(dvo, CH7017_LVDS_POWER_DOWN, val: &val); | 
|---|
| 370 |  | 
|---|
| 371 | if (val & CH7017_LVDS_POWER_DOWN_EN) | 
|---|
| 372 | return false; | 
|---|
| 373 | else | 
|---|
| 374 | return true; | 
|---|
| 375 | } | 
|---|
| 376 |  | 
|---|
| 377 | static void ch7017_dump_regs(struct intel_dvo_device *dvo) | 
|---|
| 378 | { | 
|---|
| 379 | u8 val; | 
|---|
| 380 |  | 
|---|
| 381 | #define DUMP(reg)					\ | 
|---|
| 382 | do {							\ | 
|---|
| 383 | ch7017_read(dvo, reg, &val);			\ | 
|---|
| 384 | DRM_DEBUG_KMS(#reg ": %02x\n", val);		\ | 
|---|
| 385 | } while (0) | 
|---|
| 386 |  | 
|---|
| 387 | DUMP(CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT); | 
|---|
| 388 | DUMP(CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT); | 
|---|
| 389 | DUMP(CH7017_VERTICAL_ACTIVE_LINE_OUTPUT); | 
|---|
| 390 | DUMP(CH7017_ACTIVE_INPUT_LINE_OUTPUT); | 
|---|
| 391 | DUMP(CH7017_LVDS_PLL_VCO_CONTROL); | 
|---|
| 392 | DUMP(CH7017_LVDS_PLL_FEEDBACK_DIV); | 
|---|
| 393 | DUMP(CH7017_LVDS_CONTROL_2); | 
|---|
| 394 | DUMP(CH7017_OUTPUTS_ENABLE); | 
|---|
| 395 | DUMP(CH7017_LVDS_POWER_DOWN); | 
|---|
| 396 | } | 
|---|
| 397 |  | 
|---|
| 398 | static void ch7017_destroy(struct intel_dvo_device *dvo) | 
|---|
| 399 | { | 
|---|
| 400 | struct ch7017_priv *priv = dvo->dev_priv; | 
|---|
| 401 |  | 
|---|
| 402 | if (priv) { | 
|---|
| 403 | kfree(objp: priv); | 
|---|
| 404 | dvo->dev_priv = NULL; | 
|---|
| 405 | } | 
|---|
| 406 | } | 
|---|
| 407 |  | 
|---|
| 408 | const struct intel_dvo_dev_ops ch7017_ops = { | 
|---|
| 409 | .init = ch7017_init, | 
|---|
| 410 | .detect = ch7017_detect, | 
|---|
| 411 | .mode_valid = ch7017_mode_valid, | 
|---|
| 412 | .mode_set = ch7017_mode_set, | 
|---|
| 413 | .dpms = ch7017_dpms, | 
|---|
| 414 | .get_hw_state = ch7017_get_hw_state, | 
|---|
| 415 | .dump_regs = ch7017_dump_regs, | 
|---|
| 416 | .destroy = ch7017_destroy, | 
|---|
| 417 | }; | 
|---|
| 418 |  | 
|---|