1/* 2 * 3 * Copyright (c) 2012 Gilles Dartiguelongue, Thomas Richter 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 "dvo.h" 30#include "i915_reg.h" 31#include "i915_drv.h" 32 33#define NS2501_VID 0x1305 34#define NS2501_DID 0x6726 35 36#define NS2501_VID_LO 0x00 37#define NS2501_VID_HI 0x01 38#define NS2501_DID_LO 0x02 39#define NS2501_DID_HI 0x03 40#define NS2501_REV 0x04 41#define NS2501_RSVD 0x05 42#define NS2501_FREQ_LO 0x06 43#define NS2501_FREQ_HI 0x07 44 45#define NS2501_REG8 0x08 46#define NS2501_8_VEN (1<<5) 47#define NS2501_8_HEN (1<<4) 48#define NS2501_8_DSEL (1<<3) 49#define NS2501_8_BPAS (1<<2) 50#define NS2501_8_RSVD (1<<1) 51#define NS2501_8_PD (1<<0) 52 53#define NS2501_REG9 0x09 54#define NS2501_9_VLOW (1<<7) 55#define NS2501_9_MSEL_MASK (0x7<<4) 56#define NS2501_9_TSEL (1<<3) 57#define NS2501_9_RSEN (1<<2) 58#define NS2501_9_RSVD (1<<1) 59#define NS2501_9_MDI (1<<0) 60 61#define NS2501_REGC 0x0c 62 63enum { 64 MODE_640x480, 65 MODE_800x600, 66 MODE_1024x768, 67}; 68 69struct ns2501_reg { 70 uint8_t offset; 71 uint8_t value; 72}; 73 74/* 75 * Magic values based on what the BIOS on 76 * Fujitsu-Siemens Lifebook S6010 programs (1024x768 panel). 77 */ 78static const struct ns2501_reg regs_1024x768[][86] = { 79 [MODE_640x480] = { 80 [0] = { .offset = 0x0a, .value = 0x81, }, 81 [1] = { .offset = 0x18, .value = 0x07, }, 82 [2] = { .offset = 0x19, .value = 0x00, }, 83 [3] = { .offset = 0x1a, .value = 0x00, }, 84 [4] = { .offset = 0x1b, .value = 0x11, }, 85 [5] = { .offset = 0x1c, .value = 0x54, }, 86 [6] = { .offset = 0x1d, .value = 0x03, }, 87 [7] = { .offset = 0x1e, .value = 0x02, }, 88 [8] = { .offset = 0xf3, .value = 0x90, }, 89 [9] = { .offset = 0xf9, .value = 0x00, }, 90 [10] = { .offset = 0xc1, .value = 0x90, }, 91 [11] = { .offset = 0xc2, .value = 0x00, }, 92 [12] = { .offset = 0xc3, .value = 0x0f, }, 93 [13] = { .offset = 0xc4, .value = 0x03, }, 94 [14] = { .offset = 0xc5, .value = 0x16, }, 95 [15] = { .offset = 0xc6, .value = 0x00, }, 96 [16] = { .offset = 0xc7, .value = 0x02, }, 97 [17] = { .offset = 0xc8, .value = 0x02, }, 98 [18] = { .offset = 0xf4, .value = 0x00, }, 99 [19] = { .offset = 0x80, .value = 0xff, }, 100 [20] = { .offset = 0x81, .value = 0x07, }, 101 [21] = { .offset = 0x82, .value = 0x3d, }, 102 [22] = { .offset = 0x83, .value = 0x05, }, 103 [23] = { .offset = 0x94, .value = 0x00, }, 104 [24] = { .offset = 0x95, .value = 0x00, }, 105 [25] = { .offset = 0x96, .value = 0x05, }, 106 [26] = { .offset = 0x97, .value = 0x00, }, 107 [27] = { .offset = 0x9a, .value = 0x88, }, 108 [28] = { .offset = 0x9b, .value = 0x00, }, 109 [29] = { .offset = 0x98, .value = 0x00, }, 110 [30] = { .offset = 0x99, .value = 0x00, }, 111 [31] = { .offset = 0xf7, .value = 0x88, }, 112 [32] = { .offset = 0xf8, .value = 0x0a, }, 113 [33] = { .offset = 0x9c, .value = 0x24, }, 114 [34] = { .offset = 0x9d, .value = 0x00, }, 115 [35] = { .offset = 0x9e, .value = 0x25, }, 116 [36] = { .offset = 0x9f, .value = 0x03, }, 117 [37] = { .offset = 0xa0, .value = 0x28, }, 118 [38] = { .offset = 0xa1, .value = 0x01, }, 119 [39] = { .offset = 0xa2, .value = 0x28, }, 120 [40] = { .offset = 0xa3, .value = 0x05, }, 121 [41] = { .offset = 0xb6, .value = 0x09, }, 122 [42] = { .offset = 0xb8, .value = 0x00, }, 123 [43] = { .offset = 0xb9, .value = 0xa0, }, 124 [44] = { .offset = 0xba, .value = 0x00, }, 125 [45] = { .offset = 0xbb, .value = 0x20, }, 126 [46] = { .offset = 0x10, .value = 0x00, }, 127 [47] = { .offset = 0x11, .value = 0xa0, }, 128 [48] = { .offset = 0x12, .value = 0x02, }, 129 [49] = { .offset = 0x20, .value = 0x00, }, 130 [50] = { .offset = 0x22, .value = 0x00, }, 131 [51] = { .offset = 0x23, .value = 0x00, }, 132 [52] = { .offset = 0x24, .value = 0x00, }, 133 [53] = { .offset = 0x25, .value = 0x00, }, 134 [54] = { .offset = 0x8c, .value = 0x10, }, 135 [55] = { .offset = 0x8d, .value = 0x02, }, 136 [56] = { .offset = 0x8e, .value = 0x10, }, 137 [57] = { .offset = 0x8f, .value = 0x00, }, 138 [58] = { .offset = 0x90, .value = 0xff, }, 139 [59] = { .offset = 0x91, .value = 0x07, }, 140 [60] = { .offset = 0x92, .value = 0xa0, }, 141 [61] = { .offset = 0x93, .value = 0x02, }, 142 [62] = { .offset = 0xa5, .value = 0x00, }, 143 [63] = { .offset = 0xa6, .value = 0x00, }, 144 [64] = { .offset = 0xa7, .value = 0x00, }, 145 [65] = { .offset = 0xa8, .value = 0x00, }, 146 [66] = { .offset = 0xa9, .value = 0x04, }, 147 [67] = { .offset = 0xaa, .value = 0x70, }, 148 [68] = { .offset = 0xab, .value = 0x4f, }, 149 [69] = { .offset = 0xac, .value = 0x00, }, 150 [70] = { .offset = 0xa4, .value = 0x84, }, 151 [71] = { .offset = 0x7e, .value = 0x18, }, 152 [72] = { .offset = 0x84, .value = 0x00, }, 153 [73] = { .offset = 0x85, .value = 0x00, }, 154 [74] = { .offset = 0x86, .value = 0x00, }, 155 [75] = { .offset = 0x87, .value = 0x00, }, 156 [76] = { .offset = 0x88, .value = 0x00, }, 157 [77] = { .offset = 0x89, .value = 0x00, }, 158 [78] = { .offset = 0x8a, .value = 0x00, }, 159 [79] = { .offset = 0x8b, .value = 0x00, }, 160 [80] = { .offset = 0x26, .value = 0x00, }, 161 [81] = { .offset = 0x27, .value = 0x00, }, 162 [82] = { .offset = 0xad, .value = 0x00, }, 163 [83] = { .offset = 0x08, .value = 0x30, }, /* 0x31 */ 164 [84] = { .offset = 0x41, .value = 0x00, }, 165 [85] = { .offset = 0xc0, .value = 0x05, }, 166 }, 167 [MODE_800x600] = { 168 [0] = { .offset = 0x0a, .value = 0x81, }, 169 [1] = { .offset = 0x18, .value = 0x07, }, 170 [2] = { .offset = 0x19, .value = 0x00, }, 171 [3] = { .offset = 0x1a, .value = 0x00, }, 172 [4] = { .offset = 0x1b, .value = 0x19, }, 173 [5] = { .offset = 0x1c, .value = 0x64, }, 174 [6] = { .offset = 0x1d, .value = 0x02, }, 175 [7] = { .offset = 0x1e, .value = 0x02, }, 176 [8] = { .offset = 0xf3, .value = 0x90, }, 177 [9] = { .offset = 0xf9, .value = 0x00, }, 178 [10] = { .offset = 0xc1, .value = 0xd7, }, 179 [11] = { .offset = 0xc2, .value = 0x00, }, 180 [12] = { .offset = 0xc3, .value = 0xf8, }, 181 [13] = { .offset = 0xc4, .value = 0x03, }, 182 [14] = { .offset = 0xc5, .value = 0x1a, }, 183 [15] = { .offset = 0xc6, .value = 0x00, }, 184 [16] = { .offset = 0xc7, .value = 0x73, }, 185 [17] = { .offset = 0xc8, .value = 0x02, }, 186 [18] = { .offset = 0xf4, .value = 0x00, }, 187 [19] = { .offset = 0x80, .value = 0x27, }, 188 [20] = { .offset = 0x81, .value = 0x03, }, 189 [21] = { .offset = 0x82, .value = 0x41, }, 190 [22] = { .offset = 0x83, .value = 0x05, }, 191 [23] = { .offset = 0x94, .value = 0x00, }, 192 [24] = { .offset = 0x95, .value = 0x00, }, 193 [25] = { .offset = 0x96, .value = 0x05, }, 194 [26] = { .offset = 0x97, .value = 0x00, }, 195 [27] = { .offset = 0x9a, .value = 0x88, }, 196 [28] = { .offset = 0x9b, .value = 0x00, }, 197 [29] = { .offset = 0x98, .value = 0x00, }, 198 [30] = { .offset = 0x99, .value = 0x00, }, 199 [31] = { .offset = 0xf7, .value = 0x88, }, 200 [32] = { .offset = 0xf8, .value = 0x06, }, 201 [33] = { .offset = 0x9c, .value = 0x23, }, 202 [34] = { .offset = 0x9d, .value = 0x00, }, 203 [35] = { .offset = 0x9e, .value = 0x25, }, 204 [36] = { .offset = 0x9f, .value = 0x03, }, 205 [37] = { .offset = 0xa0, .value = 0x28, }, 206 [38] = { .offset = 0xa1, .value = 0x01, }, 207 [39] = { .offset = 0xa2, .value = 0x28, }, 208 [40] = { .offset = 0xa3, .value = 0x05, }, 209 [41] = { .offset = 0xb6, .value = 0x09, }, 210 [42] = { .offset = 0xb8, .value = 0x30, }, 211 [43] = { .offset = 0xb9, .value = 0xc8, }, 212 [44] = { .offset = 0xba, .value = 0x00, }, 213 [45] = { .offset = 0xbb, .value = 0x20, }, 214 [46] = { .offset = 0x10, .value = 0x20, }, 215 [47] = { .offset = 0x11, .value = 0xc8, }, 216 [48] = { .offset = 0x12, .value = 0x02, }, 217 [49] = { .offset = 0x20, .value = 0x00, }, 218 [50] = { .offset = 0x22, .value = 0x00, }, 219 [51] = { .offset = 0x23, .value = 0x00, }, 220 [52] = { .offset = 0x24, .value = 0x00, }, 221 [53] = { .offset = 0x25, .value = 0x00, }, 222 [54] = { .offset = 0x8c, .value = 0x10, }, 223 [55] = { .offset = 0x8d, .value = 0x02, }, 224 [56] = { .offset = 0x8e, .value = 0x04, }, 225 [57] = { .offset = 0x8f, .value = 0x00, }, 226 [58] = { .offset = 0x90, .value = 0xff, }, 227 [59] = { .offset = 0x91, .value = 0x07, }, 228 [60] = { .offset = 0x92, .value = 0xa0, }, 229 [61] = { .offset = 0x93, .value = 0x02, }, 230 [62] = { .offset = 0xa5, .value = 0x00, }, 231 [63] = { .offset = 0xa6, .value = 0x00, }, 232 [64] = { .offset = 0xa7, .value = 0x00, }, 233 [65] = { .offset = 0xa8, .value = 0x00, }, 234 [66] = { .offset = 0xa9, .value = 0x83, }, 235 [67] = { .offset = 0xaa, .value = 0x40, }, 236 [68] = { .offset = 0xab, .value = 0x32, }, 237 [69] = { .offset = 0xac, .value = 0x00, }, 238 [70] = { .offset = 0xa4, .value = 0x80, }, 239 [71] = { .offset = 0x7e, .value = 0x18, }, 240 [72] = { .offset = 0x84, .value = 0x00, }, 241 [73] = { .offset = 0x85, .value = 0x00, }, 242 [74] = { .offset = 0x86, .value = 0x00, }, 243 [75] = { .offset = 0x87, .value = 0x00, }, 244 [76] = { .offset = 0x88, .value = 0x00, }, 245 [77] = { .offset = 0x89, .value = 0x00, }, 246 [78] = { .offset = 0x8a, .value = 0x00, }, 247 [79] = { .offset = 0x8b, .value = 0x00, }, 248 [80] = { .offset = 0x26, .value = 0x00, }, 249 [81] = { .offset = 0x27, .value = 0x00, }, 250 [82] = { .offset = 0xad, .value = 0x00, }, 251 [83] = { .offset = 0x08, .value = 0x30, }, /* 0x31 */ 252 [84] = { .offset = 0x41, .value = 0x00, }, 253 [85] = { .offset = 0xc0, .value = 0x07, }, 254 }, 255 [MODE_1024x768] = { 256 [0] = { .offset = 0x0a, .value = 0x81, }, 257 [1] = { .offset = 0x18, .value = 0x07, }, 258 [2] = { .offset = 0x19, .value = 0x00, }, 259 [3] = { .offset = 0x1a, .value = 0x00, }, 260 [4] = { .offset = 0x1b, .value = 0x11, }, 261 [5] = { .offset = 0x1c, .value = 0x54, }, 262 [6] = { .offset = 0x1d, .value = 0x03, }, 263 [7] = { .offset = 0x1e, .value = 0x02, }, 264 [8] = { .offset = 0xf3, .value = 0x90, }, 265 [9] = { .offset = 0xf9, .value = 0x00, }, 266 [10] = { .offset = 0xc1, .value = 0x90, }, 267 [11] = { .offset = 0xc2, .value = 0x00, }, 268 [12] = { .offset = 0xc3, .value = 0x0f, }, 269 [13] = { .offset = 0xc4, .value = 0x03, }, 270 [14] = { .offset = 0xc5, .value = 0x16, }, 271 [15] = { .offset = 0xc6, .value = 0x00, }, 272 [16] = { .offset = 0xc7, .value = 0x02, }, 273 [17] = { .offset = 0xc8, .value = 0x02, }, 274 [18] = { .offset = 0xf4, .value = 0x00, }, 275 [19] = { .offset = 0x80, .value = 0xff, }, 276 [20] = { .offset = 0x81, .value = 0x07, }, 277 [21] = { .offset = 0x82, .value = 0x3d, }, 278 [22] = { .offset = 0x83, .value = 0x05, }, 279 [23] = { .offset = 0x94, .value = 0x00, }, 280 [24] = { .offset = 0x95, .value = 0x00, }, 281 [25] = { .offset = 0x96, .value = 0x05, }, 282 [26] = { .offset = 0x97, .value = 0x00, }, 283 [27] = { .offset = 0x9a, .value = 0x88, }, 284 [28] = { .offset = 0x9b, .value = 0x00, }, 285 [29] = { .offset = 0x98, .value = 0x00, }, 286 [30] = { .offset = 0x99, .value = 0x00, }, 287 [31] = { .offset = 0xf7, .value = 0x88, }, 288 [32] = { .offset = 0xf8, .value = 0x0a, }, 289 [33] = { .offset = 0x9c, .value = 0x24, }, 290 [34] = { .offset = 0x9d, .value = 0x00, }, 291 [35] = { .offset = 0x9e, .value = 0x25, }, 292 [36] = { .offset = 0x9f, .value = 0x03, }, 293 [37] = { .offset = 0xa0, .value = 0x28, }, 294 [38] = { .offset = 0xa1, .value = 0x01, }, 295 [39] = { .offset = 0xa2, .value = 0x28, }, 296 [40] = { .offset = 0xa3, .value = 0x05, }, 297 [41] = { .offset = 0xb6, .value = 0x09, }, 298 [42] = { .offset = 0xb8, .value = 0x00, }, 299 [43] = { .offset = 0xb9, .value = 0xa0, }, 300 [44] = { .offset = 0xba, .value = 0x00, }, 301 [45] = { .offset = 0xbb, .value = 0x20, }, 302 [46] = { .offset = 0x10, .value = 0x00, }, 303 [47] = { .offset = 0x11, .value = 0xa0, }, 304 [48] = { .offset = 0x12, .value = 0x02, }, 305 [49] = { .offset = 0x20, .value = 0x00, }, 306 [50] = { .offset = 0x22, .value = 0x00, }, 307 [51] = { .offset = 0x23, .value = 0x00, }, 308 [52] = { .offset = 0x24, .value = 0x00, }, 309 [53] = { .offset = 0x25, .value = 0x00, }, 310 [54] = { .offset = 0x8c, .value = 0x10, }, 311 [55] = { .offset = 0x8d, .value = 0x02, }, 312 [56] = { .offset = 0x8e, .value = 0x10, }, 313 [57] = { .offset = 0x8f, .value = 0x00, }, 314 [58] = { .offset = 0x90, .value = 0xff, }, 315 [59] = { .offset = 0x91, .value = 0x07, }, 316 [60] = { .offset = 0x92, .value = 0xa0, }, 317 [61] = { .offset = 0x93, .value = 0x02, }, 318 [62] = { .offset = 0xa5, .value = 0x00, }, 319 [63] = { .offset = 0xa6, .value = 0x00, }, 320 [64] = { .offset = 0xa7, .value = 0x00, }, 321 [65] = { .offset = 0xa8, .value = 0x00, }, 322 [66] = { .offset = 0xa9, .value = 0x04, }, 323 [67] = { .offset = 0xaa, .value = 0x70, }, 324 [68] = { .offset = 0xab, .value = 0x4f, }, 325 [69] = { .offset = 0xac, .value = 0x00, }, 326 [70] = { .offset = 0xa4, .value = 0x84, }, 327 [71] = { .offset = 0x7e, .value = 0x18, }, 328 [72] = { .offset = 0x84, .value = 0x00, }, 329 [73] = { .offset = 0x85, .value = 0x00, }, 330 [74] = { .offset = 0x86, .value = 0x00, }, 331 [75] = { .offset = 0x87, .value = 0x00, }, 332 [76] = { .offset = 0x88, .value = 0x00, }, 333 [77] = { .offset = 0x89, .value = 0x00, }, 334 [78] = { .offset = 0x8a, .value = 0x00, }, 335 [79] = { .offset = 0x8b, .value = 0x00, }, 336 [80] = { .offset = 0x26, .value = 0x00, }, 337 [81] = { .offset = 0x27, .value = 0x00, }, 338 [82] = { .offset = 0xad, .value = 0x00, }, 339 [83] = { .offset = 0x08, .value = 0x34, }, /* 0x35 */ 340 [84] = { .offset = 0x41, .value = 0x00, }, 341 [85] = { .offset = 0xc0, .value = 0x01, }, 342 }, 343}; 344 345static const struct ns2501_reg regs_init[] = { 346 [0] = { .offset = 0x35, .value = 0xff, }, 347 [1] = { .offset = 0x34, .value = 0x00, }, 348 [2] = { .offset = 0x08, .value = 0x30, }, 349}; 350 351struct ns2501_priv { 352 bool quiet; 353 const struct ns2501_reg *regs; 354}; 355 356#define NSPTR(d) ((NS2501Ptr)(d->DriverPrivate.ptr)) 357 358/* 359 * For reasons unclear to me, the ns2501 at least on the Fujitsu/Siemens 360 * laptops does not react on the i2c bus unless 361 * both the PLL is running and the display is configured in its native 362 * resolution. 363 * This function forces the DVO on, and stores the registers it touches. 364 * Afterwards, registers are restored to regular values. 365 * 366 * This is pretty much a hack, though it works. 367 * Without that, ns2501_readb and ns2501_writeb fail 368 * when switching the resolution. 369 */ 370 371/* 372** Read a register from the ns2501. 373** Returns true if successful, false otherwise. 374** If it returns false, it might be wise to enable the 375** DVO with the above function. 376*/ 377static bool ns2501_readb(struct intel_dvo_device *dvo, int addr, uint8_t * ch) 378{ 379 struct ns2501_priv *ns = dvo->dev_priv; 380 struct i2c_adapter *adapter = dvo->i2c_bus; 381 u8 out_buf[2]; 382 u8 in_buf[2]; 383 384 struct i2c_msg msgs[] = { 385 { 386 .addr = dvo->slave_addr, 387 .flags = 0, 388 .len = 1, 389 .buf = out_buf, 390 }, 391 { 392 .addr = dvo->slave_addr, 393 .flags = I2C_M_RD, 394 .len = 1, 395 .buf = in_buf, 396 } 397 }; 398 399 out_buf[0] = addr; 400 out_buf[1] = 0; 401 402 if (i2c_transfer(adapter, msgs, 2) == 2) { 403 *ch = in_buf[0]; 404 return true; 405 } 406 407 if (!ns->quiet) { 408 DRM_DEBUG_KMS 409 ("Unable to read register 0x%02x from %s:0x%02x.\n", addr, 410 adapter->name, dvo->slave_addr); 411 } 412 413 return false; 414} 415 416/* 417** Write a register to the ns2501. 418** Returns true if successful, false otherwise. 419** If it returns false, it might be wise to enable the 420** DVO with the above function. 421*/ 422static bool ns2501_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch) 423{ 424 struct ns2501_priv *ns = dvo->dev_priv; 425 struct i2c_adapter *adapter = dvo->i2c_bus; 426 uint8_t out_buf[2]; 427 428 struct i2c_msg msg = { 429 .addr = dvo->slave_addr, 430 .flags = 0, 431 .len = 2, 432 .buf = out_buf, 433 }; 434 435 out_buf[0] = addr; 436 out_buf[1] = ch; 437 438 if (i2c_transfer(adapter, &msg, 1) == 1) { 439 return true; 440 } 441 442 if (!ns->quiet) { 443 DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d\n", 444 addr, adapter->name, dvo->slave_addr); 445 } 446 447 return false; 448} 449 450/* National Semiconductor 2501 driver for chip on i2c bus 451 * scan for the chip on the bus. 452 * Hope the VBIOS initialized the PLL correctly so we can 453 * talk to it. If not, it will not be seen and not detected. 454 * Bummer! 455 */ 456static bool ns2501_init(struct intel_dvo_device *dvo, 457 struct i2c_adapter *adapter) 458{ 459 /* this will detect the NS2501 chip on the specified i2c bus */ 460 struct ns2501_priv *ns; 461 unsigned char ch; 462 463 ns = kzalloc(sizeof(struct ns2501_priv), GFP_KERNEL); 464 if (ns == NULL) 465 return false; 466 467 dvo->i2c_bus = adapter; 468 dvo->dev_priv = ns; 469 ns->quiet = true; 470 471 if (!ns2501_readb(dvo, NS2501_VID_LO, &ch)) 472 goto out; 473 474 if (ch != (NS2501_VID & 0xff)) { 475 DRM_DEBUG_KMS("ns2501 not detected got %d: from %s Slave %d.\n", 476 ch, adapter->name, dvo->slave_addr); 477 goto out; 478 } 479 480 if (!ns2501_readb(dvo, NS2501_DID_LO, &ch)) 481 goto out; 482 483 if (ch != (NS2501_DID & 0xff)) { 484 DRM_DEBUG_KMS("ns2501 not detected got %d: from %s Slave %d.\n", 485 ch, adapter->name, dvo->slave_addr); 486 goto out; 487 } 488 ns->quiet = false; 489 490 DRM_DEBUG_KMS("init ns2501 dvo controller successfully!\n"); 491 492 return true; 493 494out: 495 kfree(ns); 496 return false; 497} 498 499static enum drm_connector_status ns2501_detect(struct intel_dvo_device *dvo) 500{ 501 /* 502 * This is a Laptop display, it doesn't have hotplugging. 503 * Even if not, the detection bit of the 2501 is unreliable as 504 * it only works for some display types. 505 * It is even more unreliable as the PLL must be active for 506 * allowing reading from the chiop. 507 */ 508 return connector_status_connected; 509} 510 511static enum drm_mode_status ns2501_mode_valid(struct intel_dvo_device *dvo, 512 struct drm_display_mode *mode) 513{ 514 DRM_DEBUG_KMS 515 ("is mode valid (hdisplay=%d,htotal=%d,vdisplay=%d,vtotal=%d)\n", 516 mode->hdisplay, mode->htotal, mode->vdisplay, mode->vtotal); 517 518 /* 519 * Currently, these are all the modes I have data from. 520 * More might exist. Unclear how to find the native resolution 521 * of the panel in here so we could always accept it 522 * by disabling the scaler. 523 */ 524 if ((mode->hdisplay == 640 && mode->vdisplay == 480 && mode->clock == 25175) || 525 (mode->hdisplay == 800 && mode->vdisplay == 600 && mode->clock == 40000) || 526 (mode->hdisplay == 1024 && mode->vdisplay == 768 && mode->clock == 65000)) { 527 return MODE_OK; 528 } else { 529 return MODE_ONE_SIZE; /* Is this a reasonable error? */ 530 } 531} 532 533static void ns2501_mode_set(struct intel_dvo_device *dvo, 534 struct drm_display_mode *mode, 535 struct drm_display_mode *adjusted_mode) 536{ 537 struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv); 538 int mode_idx, i; 539 540 DRM_DEBUG_KMS 541 ("set mode (hdisplay=%d,htotal=%d,vdisplay=%d,vtotal=%d).\n", 542 mode->hdisplay, mode->htotal, mode->vdisplay, mode->vtotal); 543 544 if (mode->hdisplay == 640 && mode->vdisplay == 480) 545 mode_idx = MODE_640x480; 546 else if (mode->hdisplay == 800 && mode->vdisplay == 600) 547 mode_idx = MODE_800x600; 548 else if (mode->hdisplay == 1024 && mode->vdisplay == 768) 549 mode_idx = MODE_1024x768; 550 else 551 return; 552 553 /* Hopefully doing it every time won't hurt... */ 554 for (i = 0; i < ARRAY_SIZE(regs_init); i++) 555 ns2501_writeb(dvo, regs_init[i].offset, regs_init[i].value); 556 557 ns->regs = regs_1024x768[mode_idx]; 558 559 for (i = 0; i < 84; i++) 560 ns2501_writeb(dvo, ns->regs[i].offset, ns->regs[i].value); 561} 562 563/* set the NS2501 power state */ 564static bool ns2501_get_hw_state(struct intel_dvo_device *dvo) 565{ 566 unsigned char ch; 567 568 if (!ns2501_readb(dvo, NS2501_REG8, &ch)) 569 return false; 570 571 return ch & NS2501_8_PD; 572} 573 574/* set the NS2501 power state */ 575static void ns2501_dpms(struct intel_dvo_device *dvo, bool enable) 576{ 577 struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv); 578 579 DRM_DEBUG_KMS("Trying set the dpms of the DVO to %i\n", enable); 580 581 if (enable) { 582 if (WARN_ON(ns->regs[83].offset != 0x08 || 583 ns->regs[84].offset != 0x41 || 584 ns->regs[85].offset != 0xc0)) 585 return; 586 587 ns2501_writeb(dvo, 0xc0, ns->regs[85].value | 0x08); 588 589 ns2501_writeb(dvo, 0x41, ns->regs[84].value); 590 591 ns2501_writeb(dvo, 0x34, 0x01); 592 msleep(15); 593 594 ns2501_writeb(dvo, 0x08, 0x35); 595 if (!(ns->regs[83].value & NS2501_8_BPAS)) 596 ns2501_writeb(dvo, 0x08, 0x31); 597 msleep(200); 598 599 ns2501_writeb(dvo, 0x34, 0x03); 600 601 ns2501_writeb(dvo, 0xc0, ns->regs[85].value); 602 } else { 603 ns2501_writeb(dvo, 0x34, 0x01); 604 msleep(200); 605 606 ns2501_writeb(dvo, 0x08, 0x34); 607 msleep(15); 608 609 ns2501_writeb(dvo, 0x34, 0x00); 610 } 611} 612 613static void ns2501_destroy(struct intel_dvo_device *dvo) 614{ 615 struct ns2501_priv *ns = dvo->dev_priv; 616 617 if (ns) { 618 kfree(ns); 619 dvo->dev_priv = NULL; 620 } 621} 622 623struct intel_dvo_dev_ops ns2501_ops = { 624 .init = ns2501_init, 625 .detect = ns2501_detect, 626 .mode_valid = ns2501_mode_valid, 627 .mode_set = ns2501_mode_set, 628 .dpms = ns2501_dpms, 629 .get_hw_state = ns2501_get_hw_state, 630 .destroy = ns2501_destroy, 631}; 632