root/drivers/gpu/drm/i915/display/dvo_ch7xxx.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ch7xxx_get_id
  2. ch7xxx_get_did
  3. ch7xxx_readb
  4. ch7xxx_writeb
  5. ch7xxx_init
  6. ch7xxx_detect
  7. ch7xxx_mode_valid
  8. ch7xxx_mode_set
  9. ch7xxx_dpms
  10. ch7xxx_get_hw_state
  11. ch7xxx_dump_regs
  12. ch7xxx_destroy

   1 /**************************************************************************
   2 
   3 Copyright © 2006 Dave Airlie
   4 
   5 All Rights Reserved.
   6 
   7 Permission is hereby granted, free of charge, to any person obtaining a
   8 copy of this software and associated documentation files (the
   9 "Software"), to deal in the Software without restriction, including
  10 without limitation the rights to use, copy, modify, merge, publish,
  11 distribute, sub license, and/or sell copies of the Software, and to
  12 permit persons to whom the Software is furnished to do so, subject to
  13 the following conditions:
  14 
  15 The above copyright notice and this permission notice (including the
  16 next paragraph) shall be included in all copies or substantial portions
  17 of the Software.
  18 
  19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  20 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  21 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
  22 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  23 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  24 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  25 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  26 
  27 **************************************************************************/
  28 
  29 #include "intel_display_types.h"
  30 #include "intel_dvo_dev.h"
  31 
  32 #define CH7xxx_REG_VID          0x4a
  33 #define CH7xxx_REG_DID          0x4b
  34 
  35 #define CH7011_VID              0x83 /* 7010 as well */
  36 #define CH7010B_VID             0x05
  37 #define CH7009A_VID             0x84
  38 #define CH7009B_VID             0x85
  39 #define CH7301_VID              0x95
  40 
  41 #define CH7xxx_VID              0x84
  42 #define CH7xxx_DID              0x17
  43 #define CH7010_DID              0x16
  44 
  45 #define CH7xxx_NUM_REGS         0x4c
  46 
  47 #define CH7xxx_CM               0x1c
  48 #define CH7xxx_CM_XCM           (1<<0)
  49 #define CH7xxx_CM_MCP           (1<<2)
  50 #define CH7xxx_INPUT_CLOCK      0x1d
  51 #define CH7xxx_GPIO             0x1e
  52 #define CH7xxx_GPIO_HPIR        (1<<3)
  53 #define CH7xxx_IDF              0x1f
  54 
  55 #define CH7xxx_IDF_HSP          (1<<3)
  56 #define CH7xxx_IDF_VSP          (1<<4)
  57 
  58 #define CH7xxx_CONNECTION_DETECT 0x20
  59 #define CH7xxx_CDET_DVI         (1<<5)
  60 
  61 #define CH7301_DAC_CNTL         0x21
  62 #define CH7301_HOTPLUG          0x23
  63 #define CH7xxx_TCTL             0x31
  64 #define CH7xxx_TVCO             0x32
  65 #define CH7xxx_TPCP             0x33
  66 #define CH7xxx_TPD              0x34
  67 #define CH7xxx_TPVT             0x35
  68 #define CH7xxx_TLPF             0x36
  69 #define CH7xxx_TCT              0x37
  70 #define CH7301_TEST_PATTERN     0x48
  71 
  72 #define CH7xxx_PM               0x49
  73 #define CH7xxx_PM_FPD           (1<<0)
  74 #define CH7301_PM_DACPD0        (1<<1)
  75 #define CH7301_PM_DACPD1        (1<<2)
  76 #define CH7301_PM_DACPD2        (1<<3)
  77 #define CH7xxx_PM_DVIL          (1<<6)
  78 #define CH7xxx_PM_DVIP          (1<<7)
  79 
  80 #define CH7301_SYNC_POLARITY    0x56
  81 #define CH7301_SYNC_RGB_YUV     (1<<0)
  82 #define CH7301_SYNC_POL_DVI     (1<<5)
  83 
  84 /** @file
  85  * driver for the Chrontel 7xxx DVI chip over DVO.
  86  */
  87 
  88 static struct ch7xxx_id_struct {
  89         u8 vid;
  90         char *name;
  91 } ch7xxx_ids[] = {
  92         { CH7011_VID, "CH7011" },
  93         { CH7010B_VID, "CH7010B" },
  94         { CH7009A_VID, "CH7009A" },
  95         { CH7009B_VID, "CH7009B" },
  96         { CH7301_VID, "CH7301" },
  97 };
  98 
  99 static struct ch7xxx_did_struct {
 100         u8 did;
 101         char *name;
 102 } ch7xxx_dids[] = {
 103         { CH7xxx_DID, "CH7XXX" },
 104         { CH7010_DID, "CH7010B" },
 105 };
 106 
 107 struct ch7xxx_priv {
 108         bool quiet;
 109 };
 110 
 111 static char *ch7xxx_get_id(u8 vid)
 112 {
 113         int i;
 114 
 115         for (i = 0; i < ARRAY_SIZE(ch7xxx_ids); i++) {
 116                 if (ch7xxx_ids[i].vid == vid)
 117                         return ch7xxx_ids[i].name;
 118         }
 119 
 120         return NULL;
 121 }
 122 
 123 static char *ch7xxx_get_did(u8 did)
 124 {
 125         int i;
 126 
 127         for (i = 0; i < ARRAY_SIZE(ch7xxx_dids); i++) {
 128                 if (ch7xxx_dids[i].did == did)
 129                         return ch7xxx_dids[i].name;
 130         }
 131 
 132         return NULL;
 133 }
 134 
 135 /** Reads an 8 bit register */
 136 static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, u8 *ch)
 137 {
 138         struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
 139         struct i2c_adapter *adapter = dvo->i2c_bus;
 140         u8 out_buf[2];
 141         u8 in_buf[2];
 142 
 143         struct i2c_msg msgs[] = {
 144                 {
 145                         .addr = dvo->slave_addr,
 146                         .flags = 0,
 147                         .len = 1,
 148                         .buf = out_buf,
 149                 },
 150                 {
 151                         .addr = dvo->slave_addr,
 152                         .flags = I2C_M_RD,
 153                         .len = 1,
 154                         .buf = in_buf,
 155                 }
 156         };
 157 
 158         out_buf[0] = addr;
 159         out_buf[1] = 0;
 160 
 161         if (i2c_transfer(adapter, msgs, 2) == 2) {
 162                 *ch = in_buf[0];
 163                 return true;
 164         }
 165 
 166         if (!ch7xxx->quiet) {
 167                 DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n",
 168                           addr, adapter->name, dvo->slave_addr);
 169         }
 170         return false;
 171 }
 172 
 173 /** Writes an 8 bit register */
 174 static bool ch7xxx_writeb(struct intel_dvo_device *dvo, int addr, u8 ch)
 175 {
 176         struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
 177         struct i2c_adapter *adapter = dvo->i2c_bus;
 178         u8 out_buf[2];
 179         struct i2c_msg msg = {
 180                 .addr = dvo->slave_addr,
 181                 .flags = 0,
 182                 .len = 2,
 183                 .buf = out_buf,
 184         };
 185 
 186         out_buf[0] = addr;
 187         out_buf[1] = ch;
 188 
 189         if (i2c_transfer(adapter, &msg, 1) == 1)
 190                 return true;
 191 
 192         if (!ch7xxx->quiet) {
 193                 DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
 194                           addr, adapter->name, dvo->slave_addr);
 195         }
 196 
 197         return false;
 198 }
 199 
 200 static bool ch7xxx_init(struct intel_dvo_device *dvo,
 201                         struct i2c_adapter *adapter)
 202 {
 203         /* this will detect the CH7xxx chip on the specified i2c bus */
 204         struct ch7xxx_priv *ch7xxx;
 205         u8 vendor, device;
 206         char *name, *devid;
 207 
 208         ch7xxx = kzalloc(sizeof(struct ch7xxx_priv), GFP_KERNEL);
 209         if (ch7xxx == NULL)
 210                 return false;
 211 
 212         dvo->i2c_bus = adapter;
 213         dvo->dev_priv = ch7xxx;
 214         ch7xxx->quiet = true;
 215 
 216         if (!ch7xxx_readb(dvo, CH7xxx_REG_VID, &vendor))
 217                 goto out;
 218 
 219         name = ch7xxx_get_id(vendor);
 220         if (!name) {
 221                 DRM_DEBUG_KMS("ch7xxx not detected; got VID 0x%02x from %s slave %d.\n",
 222                               vendor, adapter->name, dvo->slave_addr);
 223                 goto out;
 224         }
 225 
 226 
 227         if (!ch7xxx_readb(dvo, CH7xxx_REG_DID, &device))
 228                 goto out;
 229 
 230         devid = ch7xxx_get_did(device);
 231         if (!devid) {
 232                 DRM_DEBUG_KMS("ch7xxx not detected; got DID 0x%02x from %s slave %d.\n",
 233                               device, adapter->name, dvo->slave_addr);
 234                 goto out;
 235         }
 236 
 237         ch7xxx->quiet = false;
 238         DRM_DEBUG_KMS("Detected %s chipset, vendor/device ID 0x%02x/0x%02x\n",
 239                   name, vendor, device);
 240         return true;
 241 out:
 242         kfree(ch7xxx);
 243         return false;
 244 }
 245 
 246 static enum drm_connector_status ch7xxx_detect(struct intel_dvo_device *dvo)
 247 {
 248         u8 cdet, orig_pm, pm;
 249 
 250         ch7xxx_readb(dvo, CH7xxx_PM, &orig_pm);
 251 
 252         pm = orig_pm;
 253         pm &= ~CH7xxx_PM_FPD;
 254         pm |= CH7xxx_PM_DVIL | CH7xxx_PM_DVIP;
 255 
 256         ch7xxx_writeb(dvo, CH7xxx_PM, pm);
 257 
 258         ch7xxx_readb(dvo, CH7xxx_CONNECTION_DETECT, &cdet);
 259 
 260         ch7xxx_writeb(dvo, CH7xxx_PM, orig_pm);
 261 
 262         if (cdet & CH7xxx_CDET_DVI)
 263                 return connector_status_connected;
 264         return connector_status_disconnected;
 265 }
 266 
 267 static enum drm_mode_status ch7xxx_mode_valid(struct intel_dvo_device *dvo,
 268                                               struct drm_display_mode *mode)
 269 {
 270         if (mode->clock > 165000)
 271                 return MODE_CLOCK_HIGH;
 272 
 273         return MODE_OK;
 274 }
 275 
 276 static void ch7xxx_mode_set(struct intel_dvo_device *dvo,
 277                             const struct drm_display_mode *mode,
 278                             const struct drm_display_mode *adjusted_mode)
 279 {
 280         u8 tvco, tpcp, tpd, tlpf, idf;
 281 
 282         if (mode->clock <= 65000) {
 283                 tvco = 0x23;
 284                 tpcp = 0x08;
 285                 tpd = 0x16;
 286                 tlpf = 0x60;
 287         } else {
 288                 tvco = 0x2d;
 289                 tpcp = 0x06;
 290                 tpd = 0x26;
 291                 tlpf = 0xa0;
 292         }
 293 
 294         ch7xxx_writeb(dvo, CH7xxx_TCTL, 0x00);
 295         ch7xxx_writeb(dvo, CH7xxx_TVCO, tvco);
 296         ch7xxx_writeb(dvo, CH7xxx_TPCP, tpcp);
 297         ch7xxx_writeb(dvo, CH7xxx_TPD, tpd);
 298         ch7xxx_writeb(dvo, CH7xxx_TPVT, 0x30);
 299         ch7xxx_writeb(dvo, CH7xxx_TLPF, tlpf);
 300         ch7xxx_writeb(dvo, CH7xxx_TCT, 0x00);
 301 
 302         ch7xxx_readb(dvo, CH7xxx_IDF, &idf);
 303 
 304         idf &= ~(CH7xxx_IDF_HSP | CH7xxx_IDF_VSP);
 305         if (mode->flags & DRM_MODE_FLAG_PHSYNC)
 306                 idf |= CH7xxx_IDF_HSP;
 307 
 308         if (mode->flags & DRM_MODE_FLAG_PVSYNC)
 309                 idf |= CH7xxx_IDF_VSP;
 310 
 311         ch7xxx_writeb(dvo, CH7xxx_IDF, idf);
 312 }
 313 
 314 /* set the CH7xxx power state */
 315 static void ch7xxx_dpms(struct intel_dvo_device *dvo, bool enable)
 316 {
 317         if (enable)
 318                 ch7xxx_writeb(dvo, CH7xxx_PM, CH7xxx_PM_DVIL | CH7xxx_PM_DVIP);
 319         else
 320                 ch7xxx_writeb(dvo, CH7xxx_PM, CH7xxx_PM_FPD);
 321 }
 322 
 323 static bool ch7xxx_get_hw_state(struct intel_dvo_device *dvo)
 324 {
 325         u8 val;
 326 
 327         ch7xxx_readb(dvo, CH7xxx_PM, &val);
 328 
 329         if (val & (CH7xxx_PM_DVIL | CH7xxx_PM_DVIP))
 330                 return true;
 331         else
 332                 return false;
 333 }
 334 
 335 static void ch7xxx_dump_regs(struct intel_dvo_device *dvo)
 336 {
 337         int i;
 338 
 339         for (i = 0; i < CH7xxx_NUM_REGS; i++) {
 340                 u8 val;
 341                 if ((i % 8) == 0)
 342                         DRM_DEBUG_KMS("\n %02X: ", i);
 343                 ch7xxx_readb(dvo, i, &val);
 344                 DRM_DEBUG_KMS("%02X ", val);
 345         }
 346 }
 347 
 348 static void ch7xxx_destroy(struct intel_dvo_device *dvo)
 349 {
 350         struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
 351 
 352         if (ch7xxx) {
 353                 kfree(ch7xxx);
 354                 dvo->dev_priv = NULL;
 355         }
 356 }
 357 
 358 const struct intel_dvo_dev_ops ch7xxx_ops = {
 359         .init = ch7xxx_init,
 360         .detect = ch7xxx_detect,
 361         .mode_valid = ch7xxx_mode_valid,
 362         .mode_set = ch7xxx_mode_set,
 363         .dpms = ch7xxx_dpms,
 364         .get_hw_state = ch7xxx_get_hw_state,
 365         .dump_regs = ch7xxx_dump_regs,
 366         .destroy = ch7xxx_destroy,
 367 };

/* [<][>][^][v][top][bottom][index][help] */