Back to home page

OSCL-LXR

 
 

    


0001 /**************************************************************************
0002 
0003 Copyright © 2006 Dave Airlie
0004 
0005 All Rights Reserved.
0006 
0007 Permission is hereby granted, free of charge, to any person obtaining a
0008 copy of this software and associated documentation files (the
0009 "Software"), to deal in the Software without restriction, including
0010 without limitation the rights to use, copy, modify, merge, publish,
0011 distribute, sub license, and/or sell copies of the Software, and to
0012 permit persons to whom the Software is furnished to do so, subject to
0013 the following conditions:
0014 
0015 The above copyright notice and this permission notice (including the
0016 next paragraph) shall be included in all copies or substantial portions
0017 of the Software.
0018 
0019 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
0020 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
0021 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
0022 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
0023 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
0024 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
0025 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
0026 
0027 **************************************************************************/
0028 
0029 #include "intel_display_types.h"
0030 #include "intel_dvo_dev.h"
0031 
0032 #define CH7xxx_REG_VID      0x4a
0033 #define CH7xxx_REG_DID      0x4b
0034 
0035 #define CH7011_VID      0x83 /* 7010 as well */
0036 #define CH7010B_VID     0x05
0037 #define CH7009A_VID     0x84
0038 #define CH7009B_VID     0x85
0039 #define CH7301_VID      0x95
0040 
0041 #define CH7xxx_VID      0x84
0042 #define CH7xxx_DID      0x17
0043 #define CH7010_DID      0x16
0044 
0045 #define CH7xxx_NUM_REGS     0x4c
0046 
0047 #define CH7xxx_CM       0x1c
0048 #define CH7xxx_CM_XCM       (1<<0)
0049 #define CH7xxx_CM_MCP       (1<<2)
0050 #define CH7xxx_INPUT_CLOCK  0x1d
0051 #define CH7xxx_GPIO     0x1e
0052 #define CH7xxx_GPIO_HPIR    (1<<3)
0053 #define CH7xxx_IDF      0x1f
0054 
0055 #define CH7xxx_IDF_HSP      (1<<3)
0056 #define CH7xxx_IDF_VSP      (1<<4)
0057 
0058 #define CH7xxx_CONNECTION_DETECT 0x20
0059 #define CH7xxx_CDET_DVI     (1<<5)
0060 
0061 #define CH7301_DAC_CNTL     0x21
0062 #define CH7301_HOTPLUG      0x23
0063 #define CH7xxx_TCTL     0x31
0064 #define CH7xxx_TVCO     0x32
0065 #define CH7xxx_TPCP     0x33
0066 #define CH7xxx_TPD      0x34
0067 #define CH7xxx_TPVT     0x35
0068 #define CH7xxx_TLPF     0x36
0069 #define CH7xxx_TCT      0x37
0070 #define CH7301_TEST_PATTERN 0x48
0071 
0072 #define CH7xxx_PM       0x49
0073 #define CH7xxx_PM_FPD       (1<<0)
0074 #define CH7301_PM_DACPD0    (1<<1)
0075 #define CH7301_PM_DACPD1    (1<<2)
0076 #define CH7301_PM_DACPD2    (1<<3)
0077 #define CH7xxx_PM_DVIL      (1<<6)
0078 #define CH7xxx_PM_DVIP      (1<<7)
0079 
0080 #define CH7301_SYNC_POLARITY    0x56
0081 #define CH7301_SYNC_RGB_YUV (1<<0)
0082 #define CH7301_SYNC_POL_DVI (1<<5)
0083 
0084 /** @file
0085  * driver for the Chrontel 7xxx DVI chip over DVO.
0086  */
0087 
0088 static struct ch7xxx_id_struct {
0089     u8 vid;
0090     char *name;
0091 } ch7xxx_ids[] = {
0092     { CH7011_VID, "CH7011" },
0093     { CH7010B_VID, "CH7010B" },
0094     { CH7009A_VID, "CH7009A" },
0095     { CH7009B_VID, "CH7009B" },
0096     { CH7301_VID, "CH7301" },
0097 };
0098 
0099 static struct ch7xxx_did_struct {
0100     u8 did;
0101     char *name;
0102 } ch7xxx_dids[] = {
0103     { CH7xxx_DID, "CH7XXX" },
0104     { CH7010_DID, "CH7010B" },
0105 };
0106 
0107 struct ch7xxx_priv {
0108     bool quiet;
0109 };
0110 
0111 static char *ch7xxx_get_id(u8 vid)
0112 {
0113     int i;
0114 
0115     for (i = 0; i < ARRAY_SIZE(ch7xxx_ids); i++) {
0116         if (ch7xxx_ids[i].vid == vid)
0117             return ch7xxx_ids[i].name;
0118     }
0119 
0120     return NULL;
0121 }
0122 
0123 static char *ch7xxx_get_did(u8 did)
0124 {
0125     int i;
0126 
0127     for (i = 0; i < ARRAY_SIZE(ch7xxx_dids); i++) {
0128         if (ch7xxx_dids[i].did == did)
0129             return ch7xxx_dids[i].name;
0130     }
0131 
0132     return NULL;
0133 }
0134 
0135 /** Reads an 8 bit register */
0136 static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, u8 *ch)
0137 {
0138     struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
0139     struct i2c_adapter *adapter = dvo->i2c_bus;
0140     u8 out_buf[2];
0141     u8 in_buf[2];
0142 
0143     struct i2c_msg msgs[] = {
0144         {
0145             .addr = dvo->slave_addr,
0146             .flags = 0,
0147             .len = 1,
0148             .buf = out_buf,
0149         },
0150         {
0151             .addr = dvo->slave_addr,
0152             .flags = I2C_M_RD,
0153             .len = 1,
0154             .buf = in_buf,
0155         }
0156     };
0157 
0158     out_buf[0] = addr;
0159     out_buf[1] = 0;
0160 
0161     if (i2c_transfer(adapter, msgs, 2) == 2) {
0162         *ch = in_buf[0];
0163         return true;
0164     }
0165 
0166     if (!ch7xxx->quiet) {
0167         DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n",
0168               addr, adapter->name, dvo->slave_addr);
0169     }
0170     return false;
0171 }
0172 
0173 /** Writes an 8 bit register */
0174 static bool ch7xxx_writeb(struct intel_dvo_device *dvo, int addr, u8 ch)
0175 {
0176     struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
0177     struct i2c_adapter *adapter = dvo->i2c_bus;
0178     u8 out_buf[2];
0179     struct i2c_msg msg = {
0180         .addr = dvo->slave_addr,
0181         .flags = 0,
0182         .len = 2,
0183         .buf = out_buf,
0184     };
0185 
0186     out_buf[0] = addr;
0187     out_buf[1] = ch;
0188 
0189     if (i2c_transfer(adapter, &msg, 1) == 1)
0190         return true;
0191 
0192     if (!ch7xxx->quiet) {
0193         DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
0194               addr, adapter->name, dvo->slave_addr);
0195     }
0196 
0197     return false;
0198 }
0199 
0200 static bool ch7xxx_init(struct intel_dvo_device *dvo,
0201             struct i2c_adapter *adapter)
0202 {
0203     /* this will detect the CH7xxx chip on the specified i2c bus */
0204     struct ch7xxx_priv *ch7xxx;
0205     u8 vendor, device;
0206     char *name, *devid;
0207 
0208     ch7xxx = kzalloc(sizeof(struct ch7xxx_priv), GFP_KERNEL);
0209     if (ch7xxx == NULL)
0210         return false;
0211 
0212     dvo->i2c_bus = adapter;
0213     dvo->dev_priv = ch7xxx;
0214     ch7xxx->quiet = true;
0215 
0216     if (!ch7xxx_readb(dvo, CH7xxx_REG_VID, &vendor))
0217         goto out;
0218 
0219     name = ch7xxx_get_id(vendor);
0220     if (!name) {
0221         DRM_DEBUG_KMS("ch7xxx not detected; got VID 0x%02x from %s slave %d.\n",
0222                   vendor, adapter->name, dvo->slave_addr);
0223         goto out;
0224     }
0225 
0226 
0227     if (!ch7xxx_readb(dvo, CH7xxx_REG_DID, &device))
0228         goto out;
0229 
0230     devid = ch7xxx_get_did(device);
0231     if (!devid) {
0232         DRM_DEBUG_KMS("ch7xxx not detected; got DID 0x%02x from %s slave %d.\n",
0233                   device, adapter->name, dvo->slave_addr);
0234         goto out;
0235     }
0236 
0237     ch7xxx->quiet = false;
0238     DRM_DEBUG_KMS("Detected %s chipset, vendor/device ID 0x%02x/0x%02x\n",
0239           name, vendor, device);
0240     return true;
0241 out:
0242     kfree(ch7xxx);
0243     return false;
0244 }
0245 
0246 static enum drm_connector_status ch7xxx_detect(struct intel_dvo_device *dvo)
0247 {
0248     u8 cdet, orig_pm, pm;
0249 
0250     ch7xxx_readb(dvo, CH7xxx_PM, &orig_pm);
0251 
0252     pm = orig_pm;
0253     pm &= ~CH7xxx_PM_FPD;
0254     pm |= CH7xxx_PM_DVIL | CH7xxx_PM_DVIP;
0255 
0256     ch7xxx_writeb(dvo, CH7xxx_PM, pm);
0257 
0258     ch7xxx_readb(dvo, CH7xxx_CONNECTION_DETECT, &cdet);
0259 
0260     ch7xxx_writeb(dvo, CH7xxx_PM, orig_pm);
0261 
0262     if (cdet & CH7xxx_CDET_DVI)
0263         return connector_status_connected;
0264     return connector_status_disconnected;
0265 }
0266 
0267 static enum drm_mode_status ch7xxx_mode_valid(struct intel_dvo_device *dvo,
0268                           struct drm_display_mode *mode)
0269 {
0270     if (mode->clock > 165000)
0271         return MODE_CLOCK_HIGH;
0272 
0273     return MODE_OK;
0274 }
0275 
0276 static void ch7xxx_mode_set(struct intel_dvo_device *dvo,
0277                 const struct drm_display_mode *mode,
0278                 const struct drm_display_mode *adjusted_mode)
0279 {
0280     u8 tvco, tpcp, tpd, tlpf, idf;
0281 
0282     if (mode->clock <= 65000) {
0283         tvco = 0x23;
0284         tpcp = 0x08;
0285         tpd = 0x16;
0286         tlpf = 0x60;
0287     } else {
0288         tvco = 0x2d;
0289         tpcp = 0x06;
0290         tpd = 0x26;
0291         tlpf = 0xa0;
0292     }
0293 
0294     ch7xxx_writeb(dvo, CH7xxx_TCTL, 0x00);
0295     ch7xxx_writeb(dvo, CH7xxx_TVCO, tvco);
0296     ch7xxx_writeb(dvo, CH7xxx_TPCP, tpcp);
0297     ch7xxx_writeb(dvo, CH7xxx_TPD, tpd);
0298     ch7xxx_writeb(dvo, CH7xxx_TPVT, 0x30);
0299     ch7xxx_writeb(dvo, CH7xxx_TLPF, tlpf);
0300     ch7xxx_writeb(dvo, CH7xxx_TCT, 0x00);
0301 
0302     ch7xxx_readb(dvo, CH7xxx_IDF, &idf);
0303 
0304     idf &= ~(CH7xxx_IDF_HSP | CH7xxx_IDF_VSP);
0305     if (mode->flags & DRM_MODE_FLAG_PHSYNC)
0306         idf |= CH7xxx_IDF_HSP;
0307 
0308     if (mode->flags & DRM_MODE_FLAG_PVSYNC)
0309         idf |= CH7xxx_IDF_VSP;
0310 
0311     ch7xxx_writeb(dvo, CH7xxx_IDF, idf);
0312 }
0313 
0314 /* set the CH7xxx power state */
0315 static void ch7xxx_dpms(struct intel_dvo_device *dvo, bool enable)
0316 {
0317     if (enable)
0318         ch7xxx_writeb(dvo, CH7xxx_PM, CH7xxx_PM_DVIL | CH7xxx_PM_DVIP);
0319     else
0320         ch7xxx_writeb(dvo, CH7xxx_PM, CH7xxx_PM_FPD);
0321 }
0322 
0323 static bool ch7xxx_get_hw_state(struct intel_dvo_device *dvo)
0324 {
0325     u8 val;
0326 
0327     ch7xxx_readb(dvo, CH7xxx_PM, &val);
0328 
0329     if (val & (CH7xxx_PM_DVIL | CH7xxx_PM_DVIP))
0330         return true;
0331     else
0332         return false;
0333 }
0334 
0335 static void ch7xxx_dump_regs(struct intel_dvo_device *dvo)
0336 {
0337     int i;
0338 
0339     for (i = 0; i < CH7xxx_NUM_REGS; i++) {
0340         u8 val;
0341         if ((i % 8) == 0)
0342             DRM_DEBUG_KMS("\n %02X: ", i);
0343         ch7xxx_readb(dvo, i, &val);
0344         DRM_DEBUG_KMS("%02X ", val);
0345     }
0346 }
0347 
0348 static void ch7xxx_destroy(struct intel_dvo_device *dvo)
0349 {
0350     struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
0351 
0352     if (ch7xxx) {
0353         kfree(ch7xxx);
0354         dvo->dev_priv = NULL;
0355     }
0356 }
0357 
0358 const struct intel_dvo_dev_ops ch7xxx_ops = {
0359     .init = ch7xxx_init,
0360     .detect = ch7xxx_detect,
0361     .mode_valid = ch7xxx_mode_valid,
0362     .mode_set = ch7xxx_mode_set,
0363     .dpms = ch7xxx_dpms,
0364     .get_hw_state = ch7xxx_get_hw_state,
0365     .dump_regs = ch7xxx_dump_regs,
0366     .destroy = ch7xxx_destroy,
0367 };