LCOV - code coverage report
Current view: top level - dev/pci/drm/i915 - dvo_ivch.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 143 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 11 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             :  *    Thomas Richter <thor@math.tu-berlin.de>
      26             :  *
      27             :  * Minor modifications (Dithering enable):
      28             :  *    Thomas Richter <thor@math.tu-berlin.de>
      29             :  *
      30             :  */
      31             : 
      32             : #include "dvo.h"
      33             : 
      34             : /*
      35             :  * register definitions for the i82807aa.
      36             :  *
      37             :  * Documentation on this chipset can be found in datasheet #29069001 at
      38             :  * intel.com.
      39             :  */
      40             : 
      41             : /*
      42             :  * VCH Revision & GMBus Base Addr
      43             :  */
      44             : #define VR00            0x00
      45             : # define VR00_BASE_ADDRESS_MASK         0x007f
      46             : 
      47             : /*
      48             :  * Functionality Enable
      49             :  */
      50             : #define VR01            0x01
      51             : 
      52             : /*
      53             :  * Enable the panel fitter
      54             :  */
      55             : # define VR01_PANEL_FIT_ENABLE          (1 << 3)
      56             : /*
      57             :  * Enables the LCD display.
      58             :  *
      59             :  * This must not be set while VR01_DVO_BYPASS_ENABLE is set.
      60             :  */
      61             : # define VR01_LCD_ENABLE                (1 << 2)
      62             : /** Enables the DVO repeater. */
      63             : # define VR01_DVO_BYPASS_ENABLE         (1 << 1)
      64             : /** Enables the DVO clock */
      65             : # define VR01_DVO_ENABLE                (1 << 0)
      66             : /** Enable dithering for 18bpp panels. Not documented. */
      67             : # define VR01_DITHER_ENABLE             (1 << 4)
      68             : 
      69             : /*
      70             :  * LCD Interface Format
      71             :  */
      72             : #define VR10            0x10
      73             : /** Enables LVDS output instead of CMOS */
      74             : # define VR10_LVDS_ENABLE               (1 << 4)
      75             : /** Enables 18-bit LVDS output. */
      76             : # define VR10_INTERFACE_1X18            (0 << 2)
      77             : /** Enables 24-bit LVDS or CMOS output */
      78             : # define VR10_INTERFACE_1X24            (1 << 2)
      79             : /** Enables 2x18-bit LVDS or CMOS output. */
      80             : # define VR10_INTERFACE_2X18            (2 << 2)
      81             : /** Enables 2x24-bit LVDS output */
      82             : # define VR10_INTERFACE_2X24            (3 << 2)
      83             : /** Mask that defines the depth of the pipeline */
      84             : # define VR10_INTERFACE_DEPTH_MASK      (3 << 2)
      85             : 
      86             : /*
      87             :  * VR20 LCD Horizontal Display Size
      88             :  */
      89             : #define VR20    0x20
      90             : 
      91             : /*
      92             :  * LCD Vertical Display Size
      93             :  */
      94             : #define VR21    0x21
      95             : 
      96             : /*
      97             :  * Panel power down status
      98             :  */
      99             : #define VR30            0x30
     100             : /** Read only bit indicating that the panel is not in a safe poweroff state. */
     101             : # define VR30_PANEL_ON                  (1 << 15)
     102             : 
     103             : #define VR40            0x40
     104             : # define VR40_STALL_ENABLE              (1 << 13)
     105             : # define VR40_VERTICAL_INTERP_ENABLE    (1 << 12)
     106             : # define VR40_ENHANCED_PANEL_FITTING    (1 << 11)
     107             : # define VR40_HORIZONTAL_INTERP_ENABLE  (1 << 10)
     108             : # define VR40_AUTO_RATIO_ENABLE         (1 << 9)
     109             : # define VR40_CLOCK_GATING_ENABLE       (1 << 8)
     110             : 
     111             : /*
     112             :  * Panel Fitting Vertical Ratio
     113             :  * (((image_height - 1) << 16) / ((panel_height - 1))) >> 2
     114             :  */
     115             : #define VR41            0x41
     116             : 
     117             : /*
     118             :  * Panel Fitting Horizontal Ratio
     119             :  * (((image_width - 1) << 16) / ((panel_width - 1))) >> 2
     120             :  */
     121             : #define VR42            0x42
     122             : 
     123             : /*
     124             :  * Horizontal Image Size
     125             :  */
     126             : #define VR43            0x43
     127             : 
     128             : /* VR80 GPIO 0
     129             :  */
     130             : #define VR80        0x80
     131             : #define VR81        0x81
     132             : #define VR82        0x82
     133             : #define VR83        0x83
     134             : #define VR84        0x84
     135             : #define VR85        0x85
     136             : #define VR86        0x86
     137             : #define VR87        0x87
     138             : 
     139             : /* VR88 GPIO 8
     140             :  */
     141             : #define VR88        0x88
     142             : 
     143             : /* Graphics BIOS scratch 0
     144             :  */
     145             : #define VR8E        0x8E
     146             : # define VR8E_PANEL_TYPE_MASK           (0xf << 0)
     147             : # define VR8E_PANEL_INTERFACE_CMOS      (0 << 4)
     148             : # define VR8E_PANEL_INTERFACE_LVDS      (1 << 4)
     149             : # define VR8E_FORCE_DEFAULT_PANEL       (1 << 5)
     150             : 
     151             : /* Graphics BIOS scratch 1
     152             :  */
     153             : #define VR8F        0x8F
     154             : # define VR8F_VCH_PRESENT               (1 << 0)
     155             : # define VR8F_DISPLAY_CONN              (1 << 1)
     156             : # define VR8F_POWER_MASK                (0x3c)
     157             : # define VR8F_POWER_POS                 (2)
     158             : 
     159             : /* Some Bios implementations do not restore the DVO state upon
     160             :  * resume from standby. Thus, this driver has to handle it
     161             :  * instead. The following list contains all registers that
     162             :  * require saving.
     163             :  */
     164             : static const uint16_t backup_addresses[] = {
     165             :         0x11, 0x12,
     166             :         0x18, 0x19, 0x1a, 0x1f,
     167             :         0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
     168             :         0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
     169             :         0x8e, 0x8f,
     170             :         0x10            /* this must come last */
     171             : };
     172             : 
     173             : 
     174             : struct ivch_priv {
     175             :         bool quiet;
     176             : 
     177             :         uint16_t width, height;
     178             : 
     179             :         /* Register backup */
     180             : 
     181             :         uint16_t reg_backup[ARRAY_SIZE(backup_addresses)];
     182             : };
     183             : 
     184             : 
     185             : static void ivch_dump_regs(struct intel_dvo_device *dvo);
     186             : /**
     187             :  * Reads a register on the ivch.
     188             :  *
     189             :  * Each of the 256 registers are 16 bits long.
     190             :  */
     191           0 : static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data)
     192             : {
     193           0 :         struct ivch_priv *priv = dvo->dev_priv;
     194           0 :         struct i2c_adapter *adapter = dvo->i2c_bus;
     195           0 :         u8 out_buf[1];
     196           0 :         u8 in_buf[2];
     197             : 
     198           0 :         struct i2c_msg msgs[] = {
     199           0 :                 {
     200           0 :                         .addr = dvo->slave_addr,
     201             :                         .flags = I2C_M_RD,
     202             :                         .len = 0,
     203             :                 },
     204           0 :                 {
     205             :                         .addr = 0,
     206             :                         .flags = I2C_M_NOSTART,
     207             :                         .len = 1,
     208           0 :                         .buf = out_buf,
     209             :                 },
     210           0 :                 {
     211           0 :                         .addr = dvo->slave_addr,
     212             :                         .flags = I2C_M_RD | I2C_M_NOSTART,
     213             :                         .len = 2,
     214           0 :                         .buf = in_buf,
     215             :                 }
     216             :         };
     217             : 
     218           0 :         out_buf[0] = addr;
     219             : 
     220           0 :         if (i2c_transfer(adapter, msgs, 3) == 3) {
     221           0 :                 *data = (in_buf[1] << 8) | in_buf[0];
     222           0 :                 return true;
     223             :         }
     224             : 
     225           0 :         if (!priv->quiet) {
     226             :                 DRM_DEBUG_KMS("Unable to read register 0x%02x from "
     227             :                                 "%s:%02x.\n",
     228             :                           addr, adapter->name, dvo->slave_addr);
     229             :         }
     230           0 :         return false;
     231           0 : }
     232             : 
     233             : /** Writes a 16-bit register on the ivch */
     234           0 : static bool ivch_write(struct intel_dvo_device *dvo, int addr, uint16_t data)
     235             : {
     236           0 :         struct ivch_priv *priv = dvo->dev_priv;
     237           0 :         struct i2c_adapter *adapter = dvo->i2c_bus;
     238           0 :         u8 out_buf[3];
     239           0 :         struct i2c_msg msg = {
     240           0 :                 .addr = dvo->slave_addr,
     241             :                 .flags = 0,
     242             :                 .len = 3,
     243           0 :                 .buf = out_buf,
     244             :         };
     245             : 
     246           0 :         out_buf[0] = addr;
     247           0 :         out_buf[1] = data & 0xff;
     248           0 :         out_buf[2] = data >> 8;
     249             : 
     250           0 :         if (i2c_transfer(adapter, &msg, 1) == 1)
     251           0 :                 return true;
     252             : 
     253           0 :         if (!priv->quiet) {
     254             :                 DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
     255             :                           addr, adapter->name, dvo->slave_addr);
     256             :         }
     257             : 
     258           0 :         return false;
     259           0 : }
     260             : 
     261             : /** Probes the given bus and slave address for an ivch */
     262           0 : static bool ivch_init(struct intel_dvo_device *dvo,
     263             :                       struct i2c_adapter *adapter)
     264             : {
     265             :         struct ivch_priv *priv;
     266           0 :         uint16_t temp;
     267             :         int i;
     268             : 
     269           0 :         priv = kzalloc(sizeof(struct ivch_priv), GFP_KERNEL);
     270           0 :         if (priv == NULL)
     271           0 :                 return false;
     272             : 
     273           0 :         dvo->i2c_bus = adapter;
     274           0 :         dvo->dev_priv = priv;
     275           0 :         priv->quiet = true;
     276             : 
     277           0 :         if (!ivch_read(dvo, VR00, &temp))
     278             :                 goto out;
     279           0 :         priv->quiet = false;
     280             : 
     281             :         /* Since the identification bits are probably zeroes, which doesn't seem
     282             :          * very unique, check that the value in the base address field matches
     283             :          * the address it's responding on.
     284             :          */
     285           0 :         if ((temp & VR00_BASE_ADDRESS_MASK) != dvo->slave_addr) {
     286             :                 DRM_DEBUG_KMS("ivch detect failed due to address mismatch "
     287             :                           "(%d vs %d)\n",
     288             :                           (temp & VR00_BASE_ADDRESS_MASK), dvo->slave_addr);
     289             :                 goto out;
     290             :         }
     291             : 
     292           0 :         ivch_read(dvo, VR20, &priv->width);
     293           0 :         ivch_read(dvo, VR21, &priv->height);
     294             : 
     295             :         /* Make a backup of the registers to be able to restore them
     296             :          * upon suspend.
     297             :          */
     298           0 :         for (i = 0; i < ARRAY_SIZE(backup_addresses); i++)
     299           0 :                 ivch_read(dvo, backup_addresses[i], priv->reg_backup + i);
     300             : 
     301           0 :         ivch_dump_regs(dvo);
     302             : 
     303           0 :         return true;
     304             : 
     305             : out:
     306           0 :         kfree(priv);
     307           0 :         return false;
     308           0 : }
     309             : 
     310           0 : static enum drm_connector_status ivch_detect(struct intel_dvo_device *dvo)
     311             : {
     312           0 :         return connector_status_connected;
     313             : }
     314             : 
     315           0 : static enum drm_mode_status ivch_mode_valid(struct intel_dvo_device *dvo,
     316             :                                             struct drm_display_mode *mode)
     317             : {
     318           0 :         if (mode->clock > 112000)
     319           0 :                 return MODE_CLOCK_HIGH;
     320             : 
     321           0 :         return MODE_OK;
     322           0 : }
     323             : 
     324             : /* Restore the DVO registers after a resume
     325             :  * from RAM. Registers have been saved during
     326             :  * the initialization.
     327             :  */
     328           0 : static void ivch_reset(struct intel_dvo_device *dvo)
     329             : {
     330           0 :         struct ivch_priv *priv = dvo->dev_priv;
     331             :         int i;
     332             : 
     333             :         DRM_DEBUG_KMS("Resetting the IVCH registers\n");
     334             : 
     335           0 :         ivch_write(dvo, VR10, 0x0000);
     336             : 
     337           0 :         for (i = 0; i < ARRAY_SIZE(backup_addresses); i++)
     338           0 :                 ivch_write(dvo, backup_addresses[i], priv->reg_backup[i]);
     339           0 : }
     340             : 
     341             : /** Sets the power state of the panel connected to the ivch */
     342           0 : static void ivch_dpms(struct intel_dvo_device *dvo, bool enable)
     343             : {
     344             :         int i;
     345           0 :         uint16_t vr01, vr30, backlight;
     346             : 
     347           0 :         ivch_reset(dvo);
     348             : 
     349             :         /* Set the new power state of the panel. */
     350           0 :         if (!ivch_read(dvo, VR01, &vr01))
     351           0 :                 return;
     352             : 
     353           0 :         if (enable)
     354           0 :                 backlight = 1;
     355             :         else
     356             :                 backlight = 0;
     357             : 
     358           0 :         ivch_write(dvo, VR80, backlight);
     359             : 
     360           0 :         if (enable)
     361           0 :                 vr01 |= VR01_LCD_ENABLE | VR01_DVO_ENABLE;
     362             :         else
     363           0 :                 vr01 &= ~(VR01_LCD_ENABLE | VR01_DVO_ENABLE);
     364             : 
     365           0 :         ivch_write(dvo, VR01, vr01);
     366             : 
     367             :         /* Wait for the panel to make its state transition */
     368           0 :         for (i = 0; i < 100; i++) {
     369           0 :                 if (!ivch_read(dvo, VR30, &vr30))
     370             :                         break;
     371             : 
     372           0 :                 if (((vr30 & VR30_PANEL_ON) != 0) == enable)
     373             :                         break;
     374           0 :                 udelay(1000);
     375             :         }
     376             :         /* wait some more; vch may fail to resync sometimes without this */
     377           0 :         udelay(16 * 1000);
     378           0 : }
     379             : 
     380           0 : static bool ivch_get_hw_state(struct intel_dvo_device *dvo)
     381             : {
     382           0 :         uint16_t vr01;
     383             : 
     384           0 :         ivch_reset(dvo);
     385             : 
     386             :         /* Set the new power state of the panel. */
     387           0 :         if (!ivch_read(dvo, VR01, &vr01))
     388           0 :                 return false;
     389             : 
     390           0 :         if (vr01 & VR01_LCD_ENABLE)
     391           0 :                 return true;
     392             :         else
     393           0 :                 return false;
     394           0 : }
     395             : 
     396           0 : static void ivch_mode_set(struct intel_dvo_device *dvo,
     397             :                           const struct drm_display_mode *mode,
     398             :                           const struct drm_display_mode *adjusted_mode)
     399             : {
     400           0 :         struct ivch_priv *priv = dvo->dev_priv;
     401             :         uint16_t vr40 = 0;
     402             :         uint16_t vr01 = 0;
     403             :         uint16_t vr10;
     404             : 
     405           0 :         ivch_reset(dvo);
     406             : 
     407           0 :         vr10 = priv->reg_backup[ARRAY_SIZE(backup_addresses) - 1];
     408             : 
     409             :         /* Enable dithering for 18 bpp pipelines */
     410           0 :         vr10 &= VR10_INTERFACE_DEPTH_MASK;
     411           0 :         if (vr10 == VR10_INTERFACE_2X18 || vr10 == VR10_INTERFACE_1X18)
     412           0 :                 vr01 = VR01_DITHER_ENABLE;
     413             : 
     414             :         vr40 = (VR40_STALL_ENABLE | VR40_VERTICAL_INTERP_ENABLE |
     415             :                 VR40_HORIZONTAL_INTERP_ENABLE);
     416             : 
     417           0 :         if (mode->hdisplay != adjusted_mode->crtc_hdisplay ||
     418           0 :             mode->vdisplay != adjusted_mode->crtc_vdisplay) {
     419             :                 uint16_t x_ratio, y_ratio;
     420             : 
     421           0 :                 vr01 |= VR01_PANEL_FIT_ENABLE;
     422             :                 vr40 |= VR40_CLOCK_GATING_ENABLE;
     423           0 :                 x_ratio = (((mode->hdisplay - 1) << 16) /
     424           0 :                            (adjusted_mode->crtc_hdisplay - 1)) >> 2;
     425           0 :                 y_ratio = (((mode->vdisplay - 1) << 16) /
     426           0 :                            (adjusted_mode->crtc_vdisplay - 1)) >> 2;
     427           0 :                 ivch_write(dvo, VR42, x_ratio);
     428           0 :                 ivch_write(dvo, VR41, y_ratio);
     429           0 :         } else {
     430           0 :                 vr01 &= ~VR01_PANEL_FIT_ENABLE;
     431             :                 vr40 &= ~VR40_CLOCK_GATING_ENABLE;
     432             :         }
     433           0 :         vr40 &= ~VR40_AUTO_RATIO_ENABLE;
     434             : 
     435           0 :         ivch_write(dvo, VR01, vr01);
     436           0 :         ivch_write(dvo, VR40, vr40);
     437           0 : }
     438             : 
     439           0 : static void ivch_dump_regs(struct intel_dvo_device *dvo)
     440             : {
     441           0 :         uint16_t val;
     442             : 
     443           0 :         ivch_read(dvo, VR00, &val);
     444             :         DRM_DEBUG_KMS("VR00: 0x%04x\n", val);
     445           0 :         ivch_read(dvo, VR01, &val);
     446             :         DRM_DEBUG_KMS("VR01: 0x%04x\n", val);
     447           0 :         ivch_read(dvo, VR10, &val);
     448             :         DRM_DEBUG_KMS("VR10: 0x%04x\n", val);
     449           0 :         ivch_read(dvo, VR30, &val);
     450             :         DRM_DEBUG_KMS("VR30: 0x%04x\n", val);
     451           0 :         ivch_read(dvo, VR40, &val);
     452             :         DRM_DEBUG_KMS("VR40: 0x%04x\n", val);
     453             : 
     454             :         /* GPIO registers */
     455           0 :         ivch_read(dvo, VR80, &val);
     456             :         DRM_DEBUG_KMS("VR80: 0x%04x\n", val);
     457           0 :         ivch_read(dvo, VR81, &val);
     458             :         DRM_DEBUG_KMS("VR81: 0x%04x\n", val);
     459           0 :         ivch_read(dvo, VR82, &val);
     460             :         DRM_DEBUG_KMS("VR82: 0x%04x\n", val);
     461           0 :         ivch_read(dvo, VR83, &val);
     462             :         DRM_DEBUG_KMS("VR83: 0x%04x\n", val);
     463           0 :         ivch_read(dvo, VR84, &val);
     464             :         DRM_DEBUG_KMS("VR84: 0x%04x\n", val);
     465           0 :         ivch_read(dvo, VR85, &val);
     466             :         DRM_DEBUG_KMS("VR85: 0x%04x\n", val);
     467           0 :         ivch_read(dvo, VR86, &val);
     468             :         DRM_DEBUG_KMS("VR86: 0x%04x\n", val);
     469           0 :         ivch_read(dvo, VR87, &val);
     470             :         DRM_DEBUG_KMS("VR87: 0x%04x\n", val);
     471           0 :         ivch_read(dvo, VR88, &val);
     472             :         DRM_DEBUG_KMS("VR88: 0x%04x\n", val);
     473             : 
     474             :         /* Scratch register 0 - AIM Panel type */
     475           0 :         ivch_read(dvo, VR8E, &val);
     476             :         DRM_DEBUG_KMS("VR8E: 0x%04x\n", val);
     477             : 
     478             :         /* Scratch register 1 - Status register */
     479           0 :         ivch_read(dvo, VR8F, &val);
     480             :         DRM_DEBUG_KMS("VR8F: 0x%04x\n", val);
     481           0 : }
     482             : 
     483           0 : static void ivch_destroy(struct intel_dvo_device *dvo)
     484             : {
     485           0 :         struct ivch_priv *priv = dvo->dev_priv;
     486             : 
     487           0 :         if (priv) {
     488           0 :                 kfree(priv);
     489           0 :                 dvo->dev_priv = NULL;
     490           0 :         }
     491           0 : }
     492             : 
     493             : struct intel_dvo_dev_ops ivch_ops = {
     494             :         .init = ivch_init,
     495             :         .dpms = ivch_dpms,
     496             :         .get_hw_state = ivch_get_hw_state,
     497             :         .mode_valid = ivch_mode_valid,
     498             :         .mode_set = ivch_mode_set,
     499             :         .detect = ivch_detect,
     500             :         .dump_regs = ivch_dump_regs,
     501             :         .destroy = ivch_destroy,
     502             : };

Generated by: LCOV version 1.13