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 63 enum { 64 MODE_640x480, 65 MODE_800x600, 66 MODE_1024x768, 67 }; 68 69 struct 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 */ 78 static 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 345 static 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 351 struct 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 */ 377 static bool ns2501_readb(struct intel_dvo_device *dvo, int addr, uint8_t * ch) 378 { 379 struct intel_iic_softc *sc; 380 struct ns2501_priv *ns = dvo->dev_priv; 381 struct i2c_adapter *adapter = dvo->i2c_bus; 382 u8 out_buf[2]; 383 u8 in_buf[2]; 384 385 struct i2c_msg msgs[] = { 386 { 387 .slave = dvo->slave_addr << 1, 388 .flags = 0, 389 .len = 1, 390 .buf = out_buf, 391 }, 392 { 393 .slave = dvo->slave_addr << 1, 394 .flags = I2C_M_RD, 395 .len = 1, 396 .buf = in_buf, 397 } 398 }; 399 400 out_buf[0] = addr; 401 out_buf[1] = 0; 402 403 sc = device_get_softc(adapter); 404 405 if (iicbus_transfer(adapter, msgs, 2) == 0) { 406 *ch = in_buf[0]; 407 return true; 408 } 409 410 if (!ns->quiet) { 411 DRM_DEBUG_KMS 412 ("Unable to read register 0x%02x from %s:0x%02x.\n", addr, 413 sc->name, dvo->slave_addr); 414 } 415 416 return false; 417 } 418 419 /* 420 ** Write a register to the ns2501. 421 ** Returns true if successful, false otherwise. 422 ** If it returns false, it might be wise to enable the 423 ** DVO with the above function. 424 */ 425 static bool ns2501_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch) 426 { 427 struct intel_iic_softc *sc; 428 struct ns2501_priv *ns = dvo->dev_priv; 429 struct i2c_adapter *adapter = dvo->i2c_bus; 430 uint8_t out_buf[2]; 431 432 struct i2c_msg msg = { 433 .slave = dvo->slave_addr << 1, 434 .flags = 0, 435 .len = 2, 436 .buf = out_buf, 437 }; 438 439 out_buf[0] = addr; 440 out_buf[1] = ch; 441 442 sc = device_get_softc(adapter); 443 444 if (iicbus_transfer(adapter, &msg, 1) == 0) { 445 return true; 446 } 447 448 if (!ns->quiet) { 449 DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d\n", 450 addr, sc->name, dvo->slave_addr); 451 } 452 453 return false; 454 } 455 456 /* National Semiconductor 2501 driver for chip on i2c bus 457 * scan for the chip on the bus. 458 * Hope the VBIOS initialized the PLL correctly so we can 459 * talk to it. If not, it will not be seen and not detected. 460 * Bummer! 461 */ 462 static bool ns2501_init(struct intel_dvo_device *dvo, 463 struct i2c_adapter *adapter) 464 { 465 struct intel_iic_softc *sc; 466 /* this will detect the NS2501 chip on the specified i2c bus */ 467 struct ns2501_priv *ns; 468 unsigned char ch; 469 470 sc = device_get_softc(adapter); 471 472 ns = kzalloc(sizeof(struct ns2501_priv), GFP_KERNEL); 473 if (ns == NULL) 474 return false; 475 476 dvo->i2c_bus = adapter; 477 dvo->dev_priv = ns; 478 ns->quiet = true; 479 480 if (!ns2501_readb(dvo, NS2501_VID_LO, &ch)) 481 goto out; 482 483 if (ch != (NS2501_VID & 0xff)) { 484 DRM_DEBUG_KMS("ns2501 not detected got %d: from %s Slave %d.\n", 485 ch, sc->name, dvo->slave_addr); 486 goto out; 487 } 488 489 if (!ns2501_readb(dvo, NS2501_DID_LO, &ch)) 490 goto out; 491 492 if (ch != (NS2501_DID & 0xff)) { 493 DRM_DEBUG_KMS("ns2501 not detected got %d: from %s Slave %d.\n", 494 ch, sc->name, dvo->slave_addr); 495 goto out; 496 } 497 ns->quiet = false; 498 499 DRM_DEBUG_KMS("init ns2501 dvo controller successfully!\n"); 500 501 return true; 502 503 out: 504 kfree(ns); 505 return false; 506 } 507 508 static enum drm_connector_status ns2501_detect(struct intel_dvo_device *dvo) 509 { 510 /* 511 * This is a Laptop display, it doesn't have hotplugging. 512 * Even if not, the detection bit of the 2501 is unreliable as 513 * it only works for some display types. 514 * It is even more unreliable as the PLL must be active for 515 * allowing reading from the chiop. 516 */ 517 return connector_status_connected; 518 } 519 520 static enum drm_mode_status ns2501_mode_valid(struct intel_dvo_device *dvo, 521 struct drm_display_mode *mode) 522 { 523 DRM_DEBUG_KMS 524 ("is mode valid (hdisplay=%d,htotal=%d,vdisplay=%d,vtotal=%d)\n", 525 mode->hdisplay, mode->htotal, mode->vdisplay, mode->vtotal); 526 527 /* 528 * Currently, these are all the modes I have data from. 529 * More might exist. Unclear how to find the native resolution 530 * of the panel in here so we could always accept it 531 * by disabling the scaler. 532 */ 533 if ((mode->hdisplay == 640 && mode->vdisplay == 480 && mode->clock == 25175) || 534 (mode->hdisplay == 800 && mode->vdisplay == 600 && mode->clock == 40000) || 535 (mode->hdisplay == 1024 && mode->vdisplay == 768 && mode->clock == 65000)) { 536 return MODE_OK; 537 } else { 538 return MODE_ONE_SIZE; /* Is this a reasonable error? */ 539 } 540 } 541 542 static void ns2501_mode_set(struct intel_dvo_device *dvo, 543 struct drm_display_mode *mode, 544 struct drm_display_mode *adjusted_mode) 545 { 546 struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv); 547 int mode_idx, i; 548 549 DRM_DEBUG_KMS 550 ("set mode (hdisplay=%d,htotal=%d,vdisplay=%d,vtotal=%d).\n", 551 mode->hdisplay, mode->htotal, mode->vdisplay, mode->vtotal); 552 553 if (mode->hdisplay == 640 && mode->vdisplay == 480) 554 mode_idx = MODE_640x480; 555 else if (mode->hdisplay == 800 && mode->vdisplay == 600) 556 mode_idx = MODE_800x600; 557 else if (mode->hdisplay == 1024 && mode->vdisplay == 768) 558 mode_idx = MODE_1024x768; 559 else 560 return; 561 562 /* Hopefully doing it every time won't hurt... */ 563 for (i = 0; i < ARRAY_SIZE(regs_init); i++) 564 ns2501_writeb(dvo, regs_init[i].offset, regs_init[i].value); 565 566 ns->regs = regs_1024x768[mode_idx]; 567 568 for (i = 0; i < 84; i++) 569 ns2501_writeb(dvo, ns->regs[i].offset, ns->regs[i].value); 570 } 571 572 /* set the NS2501 power state */ 573 static bool ns2501_get_hw_state(struct intel_dvo_device *dvo) 574 { 575 unsigned char ch; 576 577 if (!ns2501_readb(dvo, NS2501_REG8, &ch)) 578 return false; 579 580 return ch & NS2501_8_PD; 581 } 582 583 /* set the NS2501 power state */ 584 static void ns2501_dpms(struct intel_dvo_device *dvo, bool enable) 585 { 586 struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv); 587 588 DRM_DEBUG_KMS("Trying set the dpms of the DVO to %i\n", enable); 589 590 if (enable) { 591 if (WARN_ON(ns->regs[83].offset != 0x08 || 592 ns->regs[84].offset != 0x41 || 593 ns->regs[85].offset != 0xc0)) 594 return; 595 596 ns2501_writeb(dvo, 0xc0, ns->regs[85].value | 0x08); 597 598 ns2501_writeb(dvo, 0x41, ns->regs[84].value); 599 600 ns2501_writeb(dvo, 0x34, 0x01); 601 msleep(15); 602 603 ns2501_writeb(dvo, 0x08, 0x35); 604 if (!(ns->regs[83].value & NS2501_8_BPAS)) 605 ns2501_writeb(dvo, 0x08, 0x31); 606 msleep(200); 607 608 ns2501_writeb(dvo, 0x34, 0x03); 609 610 ns2501_writeb(dvo, 0xc0, ns->regs[85].value); 611 } else { 612 ns2501_writeb(dvo, 0x34, 0x01); 613 msleep(200); 614 615 ns2501_writeb(dvo, 0x08, 0x34); 616 msleep(15); 617 618 ns2501_writeb(dvo, 0x34, 0x00); 619 } 620 } 621 622 static void ns2501_destroy(struct intel_dvo_device *dvo) 623 { 624 struct ns2501_priv *ns = dvo->dev_priv; 625 626 if (ns) { 627 kfree(ns); 628 dvo->dev_priv = NULL; 629 } 630 } 631 632 struct intel_dvo_dev_ops ns2501_ops = { 633 .init = ns2501_init, 634 .detect = ns2501_detect, 635 .mode_valid = ns2501_mode_valid, 636 .mode_set = ns2501_mode_set, 637 .dpms = ns2501_dpms, 638 .get_hw_state = ns2501_get_hw_state, 639 .destroy = ns2501_destroy, 640 }; 641