Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright © 2006 Intel Corporation
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice (including the next
0012  * paragraph) shall be included in all copies or substantial portions of the
0013  * Software.
0014  *
0015  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0016  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0017  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0018  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
0019  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
0020  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
0021  * DEALINGS IN THE SOFTWARE.
0022  *
0023  * Authors:
0024  *    Eric Anholt <eric@anholt.net>
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 /** Enables the TV output path. */
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 /** Powers down the TV out block, and DAC0-3 */
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 /**< Low bits of horizontal active pixel input */
0088 
0089 #define CH7017_ACTIVE_INPUT_LINE_OUTPUT 0x60
0090 /** High bits of horizontal active pixel input */
0091 #define CH7017_LVDS_HAP_INPUT_MASK  (0x7 << 0)
0092 /** High bits of vertical active line output */
0093 #define CH7017_LVDS_VAL_HIGH_MASK   (0x7 << 3)
0094 
0095 #define CH7017_VERTICAL_ACTIVE_LINE_OUTPUT  0x61
0096 /**< Low bits of vertical active line output */
0097 
0098 #define CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT   0x62
0099 /**< Low bits of horizontal active pixel output */
0100 
0101 #define CH7017_LVDS_POWER_DOWN      0x63
0102 /** High bits of horizontal active pixel output */
0103 #define CH7017_LVDS_HAP_HIGH_MASK   (0x7 << 0)
0104 /** Enables the LVDS power down state transition */
0105 #define CH7017_LVDS_POWER_DOWN_EN   (1 << 6)
0106 /** Enables the LVDS upscaler */
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 /** Enables the LVDS panel output path */
0120 #define CH7017_LVDS_PANEN       (1 << 0)
0121 /** Enables the LVDS panel backlight */
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 /** Probes for a CH7017 on the given bus and slave address. */
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     /* LVDS PLL settings from page 75 of 7017-7017ds.pdf*/
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) { /* XXX: dual channel panel detection.  Assume yes for now. */
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     /* Turn the LVDS back on with new settings. */
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 /* set the CH7017 power state */
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     /* Turn off TV/VGA, and never turn it on since we don't support it. */
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         /* Turn on the LVDS */
0351         ch7017_write(dvo, CH7017_LVDS_POWER_DOWN,
0352                  val & ~CH7017_LVDS_POWER_DOWN_EN);
0353     } else {
0354         /* Turn off the LVDS */
0355         ch7017_write(dvo, CH7017_LVDS_POWER_DOWN,
0356                  val | CH7017_LVDS_POWER_DOWN_EN);
0357     }
0358 
0359     /* XXX: Should actually wait for update power status somehow */
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 };