0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
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
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
0085
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
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
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
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
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 };