LCOV - code coverage report
Current view: top level - dev/pci/drm/i915 - dvo_ch7017.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 97 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 10 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13