0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028 #include "intel_display_types.h"
0029 #include "intel_dvo_dev.h"
0030
0031 #define CH7017_TV_DISPLAY_MODE 0x00
0032 #define CH7017_FLICKER_FILTER 0x01
0033 #define CH7017_VIDEO_BANDWIDTH 0x02
0034 #define CH7017_TEXT_ENHANCEMENT 0x03
0035 #define CH7017_START_ACTIVE_VIDEO 0x04
0036 #define CH7017_HORIZONTAL_POSITION 0x05
0037 #define CH7017_VERTICAL_POSITION 0x06
0038 #define CH7017_BLACK_LEVEL 0x07
0039 #define CH7017_CONTRAST_ENHANCEMENT 0x08
0040 #define CH7017_TV_PLL 0x09
0041 #define CH7017_TV_PLL_M 0x0a
0042 #define CH7017_TV_PLL_N 0x0b
0043 #define CH7017_SUB_CARRIER_0 0x0c
0044 #define CH7017_CIV_CONTROL 0x10
0045 #define CH7017_CIV_0 0x11
0046 #define CH7017_CHROMA_BOOST 0x14
0047 #define CH7017_CLOCK_MODE 0x1c
0048 #define CH7017_INPUT_CLOCK 0x1d
0049 #define CH7017_GPIO_CONTROL 0x1e
0050 #define CH7017_INPUT_DATA_FORMAT 0x1f
0051 #define CH7017_CONNECTION_DETECT 0x20
0052 #define CH7017_DAC_CONTROL 0x21
0053 #define CH7017_BUFFERED_CLOCK_OUTPUT 0x22
0054 #define CH7017_DEFEAT_VSYNC 0x47
0055 #define CH7017_TEST_PATTERN 0x48
0056
0057 #define CH7017_POWER_MANAGEMENT 0x49
0058
0059 #define CH7017_TV_EN (1 << 0)
0060 #define CH7017_DAC0_POWER_DOWN (1 << 1)
0061 #define CH7017_DAC1_POWER_DOWN (1 << 2)
0062 #define CH7017_DAC2_POWER_DOWN (1 << 3)
0063 #define CH7017_DAC3_POWER_DOWN (1 << 4)
0064
0065 #define CH7017_TV_POWER_DOWN_EN (1 << 5)
0066
0067 #define CH7017_VERSION_ID 0x4a
0068
0069 #define CH7017_DEVICE_ID 0x4b
0070 #define CH7017_DEVICE_ID_VALUE 0x1b
0071 #define CH7018_DEVICE_ID_VALUE 0x1a
0072 #define CH7019_DEVICE_ID_VALUE 0x19
0073
0074 #define CH7017_XCLK_D2_ADJUST 0x53
0075 #define CH7017_UP_SCALER_COEFF_0 0x55
0076 #define CH7017_UP_SCALER_COEFF_1 0x56
0077 #define CH7017_UP_SCALER_COEFF_2 0x57
0078 #define CH7017_UP_SCALER_COEFF_3 0x58
0079 #define CH7017_UP_SCALER_COEFF_4 0x59
0080 #define CH7017_UP_SCALER_VERTICAL_INC_0 0x5a
0081 #define CH7017_UP_SCALER_VERTICAL_INC_1 0x5b
0082 #define CH7017_GPIO_INVERT 0x5c
0083 #define CH7017_UP_SCALER_HORIZONTAL_INC_0 0x5d
0084 #define CH7017_UP_SCALER_HORIZONTAL_INC_1 0x5e
0085
0086 #define CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT 0x5f
0087
0088
0089 #define CH7017_ACTIVE_INPUT_LINE_OUTPUT 0x60
0090
0091 #define CH7017_LVDS_HAP_INPUT_MASK (0x7 << 0)
0092
0093 #define CH7017_LVDS_VAL_HIGH_MASK (0x7 << 3)
0094
0095 #define CH7017_VERTICAL_ACTIVE_LINE_OUTPUT 0x61
0096
0097
0098 #define CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT 0x62
0099
0100
0101 #define CH7017_LVDS_POWER_DOWN 0x63
0102
0103 #define CH7017_LVDS_HAP_HIGH_MASK (0x7 << 0)
0104
0105 #define CH7017_LVDS_POWER_DOWN_EN (1 << 6)
0106
0107 #define CH7017_LVDS_UPSCALER_EN (1 << 7)
0108 #define CH7017_LVDS_POWER_DOWN_DEFAULT_RESERVED 0x08
0109
0110 #define CH7017_LVDS_ENCODING 0x64
0111 #define CH7017_LVDS_DITHER_2D (1 << 2)
0112 #define CH7017_LVDS_DITHER_DIS (1 << 3)
0113 #define CH7017_LVDS_DUAL_CHANNEL_EN (1 << 4)
0114 #define CH7017_LVDS_24_BIT (1 << 5)
0115
0116 #define CH7017_LVDS_ENCODING_2 0x65
0117
0118 #define CH7017_LVDS_PLL_CONTROL 0x66
0119
0120 #define CH7017_LVDS_PANEN (1 << 0)
0121
0122 #define CH7017_LVDS_BKLEN (1 << 3)
0123
0124 #define CH7017_POWER_SEQUENCING_T1 0x67
0125 #define CH7017_POWER_SEQUENCING_T2 0x68
0126 #define CH7017_POWER_SEQUENCING_T3 0x69
0127 #define CH7017_POWER_SEQUENCING_T4 0x6a
0128 #define CH7017_POWER_SEQUENCING_T5 0x6b
0129 #define CH7017_GPIO_DRIVER_TYPE 0x6c
0130 #define CH7017_GPIO_DATA 0x6d
0131 #define CH7017_GPIO_DIRECTION_CONTROL 0x6e
0132
0133 #define CH7017_LVDS_PLL_FEEDBACK_DIV 0x71
0134 # define CH7017_LVDS_PLL_FEED_BACK_DIVIDER_SHIFT 4
0135 # define CH7017_LVDS_PLL_FEED_FORWARD_DIVIDER_SHIFT 0
0136 # define CH7017_LVDS_PLL_FEEDBACK_DEFAULT_RESERVED 0x80
0137
0138 #define CH7017_LVDS_PLL_VCO_CONTROL 0x72
0139 # define CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED 0x80
0140 # define CH7017_LVDS_PLL_VCO_SHIFT 4
0141 # define CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT 0
0142
0143 #define CH7017_OUTPUTS_ENABLE 0x73
0144 # define CH7017_CHARGE_PUMP_LOW 0x0
0145 # define CH7017_CHARGE_PUMP_HIGH 0x3
0146 # define CH7017_LVDS_CHANNEL_A (1 << 3)
0147 # define CH7017_LVDS_CHANNEL_B (1 << 4)
0148 # define CH7017_TV_DAC_A (1 << 5)
0149 # define CH7017_TV_DAC_B (1 << 6)
0150 # define CH7017_DDC_SELECT_DC2 (1 << 7)
0151
0152 #define CH7017_LVDS_OUTPUT_AMPLITUDE 0x74
0153 #define CH7017_LVDS_PLL_EMI_REDUCTION 0x75
0154 #define CH7017_LVDS_POWER_DOWN_FLICKER 0x76
0155
0156 #define CH7017_LVDS_CONTROL_2 0x78
0157 # define CH7017_LOOP_FILTER_SHIFT 5
0158 # define CH7017_PHASE_DETECTOR_SHIFT 0
0159
0160 #define CH7017_BANG_LIMIT_CONTROL 0x7f
0161
0162 struct ch7017_priv {
0163 u8 dummy;
0164 };
0165
0166 static void ch7017_dump_regs(struct intel_dvo_device *dvo);
0167 static void ch7017_dpms(struct intel_dvo_device *dvo, bool enable);
0168
0169 static bool ch7017_read(struct intel_dvo_device *dvo, u8 addr, u8 *val)
0170 {
0171 struct i2c_msg msgs[] = {
0172 {
0173 .addr = dvo->slave_addr,
0174 .flags = 0,
0175 .len = 1,
0176 .buf = &addr,
0177 },
0178 {
0179 .addr = dvo->slave_addr,
0180 .flags = I2C_M_RD,
0181 .len = 1,
0182 .buf = val,
0183 }
0184 };
0185 return i2c_transfer(dvo->i2c_bus, msgs, 2) == 2;
0186 }
0187
0188 static bool ch7017_write(struct intel_dvo_device *dvo, u8 addr, u8 val)
0189 {
0190 u8 buf[2] = { addr, val };
0191 struct i2c_msg msg = {
0192 .addr = dvo->slave_addr,
0193 .flags = 0,
0194 .len = 2,
0195 .buf = buf,
0196 };
0197 return i2c_transfer(dvo->i2c_bus, &msg, 1) == 1;
0198 }
0199
0200
0201 static bool ch7017_init(struct intel_dvo_device *dvo,
0202 struct i2c_adapter *adapter)
0203 {
0204 struct ch7017_priv *priv;
0205 const char *str;
0206 u8 val;
0207
0208 priv = kzalloc(sizeof(struct ch7017_priv), GFP_KERNEL);
0209 if (priv == NULL)
0210 return false;
0211
0212 dvo->i2c_bus = adapter;
0213 dvo->dev_priv = priv;
0214
0215 if (!ch7017_read(dvo, CH7017_DEVICE_ID, &val))
0216 goto fail;
0217
0218 switch (val) {
0219 case CH7017_DEVICE_ID_VALUE:
0220 str = "ch7017";
0221 break;
0222 case CH7018_DEVICE_ID_VALUE:
0223 str = "ch7018";
0224 break;
0225 case CH7019_DEVICE_ID_VALUE:
0226 str = "ch7019";
0227 break;
0228 default:
0229 DRM_DEBUG_KMS("ch701x not detected, got %d: from %s "
0230 "slave %d.\n",
0231 val, adapter->name, dvo->slave_addr);
0232 goto fail;
0233 }
0234
0235 DRM_DEBUG_KMS("%s detected on %s, addr %d\n",
0236 str, adapter->name, dvo->slave_addr);
0237 return true;
0238
0239 fail:
0240 kfree(priv);
0241 return false;
0242 }
0243
0244 static enum drm_connector_status ch7017_detect(struct intel_dvo_device *dvo)
0245 {
0246 return connector_status_connected;
0247 }
0248
0249 static enum drm_mode_status ch7017_mode_valid(struct intel_dvo_device *dvo,
0250 struct drm_display_mode *mode)
0251 {
0252 if (mode->clock > 160000)
0253 return MODE_CLOCK_HIGH;
0254
0255 return MODE_OK;
0256 }
0257
0258 static void ch7017_mode_set(struct intel_dvo_device *dvo,
0259 const struct drm_display_mode *mode,
0260 const struct drm_display_mode *adjusted_mode)
0261 {
0262 u8 lvds_pll_feedback_div, lvds_pll_vco_control;
0263 u8 outputs_enable, lvds_control_2, lvds_power_down;
0264 u8 horizontal_active_pixel_input;
0265 u8 horizontal_active_pixel_output, vertical_active_line_output;
0266 u8 active_input_line_output;
0267
0268 DRM_DEBUG_KMS("Registers before mode setting\n");
0269 ch7017_dump_regs(dvo);
0270
0271
0272 if (mode->clock < 100000) {
0273 outputs_enable = CH7017_LVDS_CHANNEL_A | CH7017_CHARGE_PUMP_LOW;
0274 lvds_pll_feedback_div = CH7017_LVDS_PLL_FEEDBACK_DEFAULT_RESERVED |
0275 (2 << CH7017_LVDS_PLL_FEED_BACK_DIVIDER_SHIFT) |
0276 (13 << CH7017_LVDS_PLL_FEED_FORWARD_DIVIDER_SHIFT);
0277 lvds_pll_vco_control = CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED |
0278 (2 << CH7017_LVDS_PLL_VCO_SHIFT) |
0279 (3 << CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT);
0280 lvds_control_2 = (1 << CH7017_LOOP_FILTER_SHIFT) |
0281 (0 << CH7017_PHASE_DETECTOR_SHIFT);
0282 } else {
0283 outputs_enable = CH7017_LVDS_CHANNEL_A | CH7017_CHARGE_PUMP_HIGH;
0284 lvds_pll_feedback_div =
0285 CH7017_LVDS_PLL_FEEDBACK_DEFAULT_RESERVED |
0286 (2 << CH7017_LVDS_PLL_FEED_BACK_DIVIDER_SHIFT) |
0287 (3 << CH7017_LVDS_PLL_FEED_FORWARD_DIVIDER_SHIFT);
0288 lvds_control_2 = (3 << CH7017_LOOP_FILTER_SHIFT) |
0289 (0 << CH7017_PHASE_DETECTOR_SHIFT);
0290 if (1) {
0291 outputs_enable |= CH7017_LVDS_CHANNEL_B;
0292 lvds_pll_vco_control = CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED |
0293 (2 << CH7017_LVDS_PLL_VCO_SHIFT) |
0294 (13 << CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT);
0295 } else {
0296 lvds_pll_vco_control = CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED |
0297 (1 << CH7017_LVDS_PLL_VCO_SHIFT) |
0298 (13 << CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT);
0299 }
0300 }
0301
0302 horizontal_active_pixel_input = mode->hdisplay & 0x00ff;
0303
0304 vertical_active_line_output = mode->vdisplay & 0x00ff;
0305 horizontal_active_pixel_output = mode->hdisplay & 0x00ff;
0306
0307 active_input_line_output = ((mode->hdisplay & 0x0700) >> 8) |
0308 (((mode->vdisplay & 0x0700) >> 8) << 3);
0309
0310 lvds_power_down = CH7017_LVDS_POWER_DOWN_DEFAULT_RESERVED |
0311 (mode->hdisplay & 0x0700) >> 8;
0312
0313 ch7017_dpms(dvo, false);
0314 ch7017_write(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT,
0315 horizontal_active_pixel_input);
0316 ch7017_write(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT,
0317 horizontal_active_pixel_output);
0318 ch7017_write(dvo, CH7017_VERTICAL_ACTIVE_LINE_OUTPUT,
0319 vertical_active_line_output);
0320 ch7017_write(dvo, CH7017_ACTIVE_INPUT_LINE_OUTPUT,
0321 active_input_line_output);
0322 ch7017_write(dvo, CH7017_LVDS_PLL_VCO_CONTROL, lvds_pll_vco_control);
0323 ch7017_write(dvo, CH7017_LVDS_PLL_FEEDBACK_DIV, lvds_pll_feedback_div);
0324 ch7017_write(dvo, CH7017_LVDS_CONTROL_2, lvds_control_2);
0325 ch7017_write(dvo, CH7017_OUTPUTS_ENABLE, outputs_enable);
0326
0327
0328 ch7017_write(dvo, CH7017_LVDS_POWER_DOWN, lvds_power_down);
0329
0330 DRM_DEBUG_KMS("Registers after mode setting\n");
0331 ch7017_dump_regs(dvo);
0332 }
0333
0334
0335 static void ch7017_dpms(struct intel_dvo_device *dvo, bool enable)
0336 {
0337 u8 val;
0338
0339 ch7017_read(dvo, CH7017_LVDS_POWER_DOWN, &val);
0340
0341
0342 ch7017_write(dvo, CH7017_POWER_MANAGEMENT,
0343 CH7017_DAC0_POWER_DOWN |
0344 CH7017_DAC1_POWER_DOWN |
0345 CH7017_DAC2_POWER_DOWN |
0346 CH7017_DAC3_POWER_DOWN |
0347 CH7017_TV_POWER_DOWN_EN);
0348
0349 if (enable) {
0350
0351 ch7017_write(dvo, CH7017_LVDS_POWER_DOWN,
0352 val & ~CH7017_LVDS_POWER_DOWN_EN);
0353 } else {
0354
0355 ch7017_write(dvo, CH7017_LVDS_POWER_DOWN,
0356 val | CH7017_LVDS_POWER_DOWN_EN);
0357 }
0358
0359
0360 msleep(20);
0361 }
0362
0363 static bool ch7017_get_hw_state(struct intel_dvo_device *dvo)
0364 {
0365 u8 val;
0366
0367 ch7017_read(dvo, CH7017_LVDS_POWER_DOWN, &val);
0368
0369 if (val & CH7017_LVDS_POWER_DOWN_EN)
0370 return false;
0371 else
0372 return true;
0373 }
0374
0375 static void ch7017_dump_regs(struct intel_dvo_device *dvo)
0376 {
0377 u8 val;
0378
0379 #define DUMP(reg) \
0380 do { \
0381 ch7017_read(dvo, reg, &val); \
0382 DRM_DEBUG_KMS(#reg ": %02x\n", val); \
0383 } while (0)
0384
0385 DUMP(CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT);
0386 DUMP(CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT);
0387 DUMP(CH7017_VERTICAL_ACTIVE_LINE_OUTPUT);
0388 DUMP(CH7017_ACTIVE_INPUT_LINE_OUTPUT);
0389 DUMP(CH7017_LVDS_PLL_VCO_CONTROL);
0390 DUMP(CH7017_LVDS_PLL_FEEDBACK_DIV);
0391 DUMP(CH7017_LVDS_CONTROL_2);
0392 DUMP(CH7017_OUTPUTS_ENABLE);
0393 DUMP(CH7017_LVDS_POWER_DOWN);
0394 }
0395
0396 static void ch7017_destroy(struct intel_dvo_device *dvo)
0397 {
0398 struct ch7017_priv *priv = dvo->dev_priv;
0399
0400 if (priv) {
0401 kfree(priv);
0402 dvo->dev_priv = NULL;
0403 }
0404 }
0405
0406 const struct intel_dvo_dev_ops ch7017_ops = {
0407 .init = ch7017_init,
0408 .detect = ch7017_detect,
0409 .mode_valid = ch7017_mode_valid,
0410 .mode_set = ch7017_mode_set,
0411 .dpms = ch7017_dpms,
0412 .get_hw_state = ch7017_get_hw_state,
0413 .dump_regs = ch7017_dump_regs,
0414 .destroy = ch7017_destroy,
0415 };