Subversion Repositories Kolibri OS

Rev

Rev 5060 | Rev 6084 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
3031 serge 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
 
5354 serge 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
 
3031 serge 351
struct ns2501_priv {
352
	bool quiet;
5354 serge 353
	const struct ns2501_reg *regs;
3031 serge 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 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;
5060 serge 405
	}
3031 serge 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
*/
422
static 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
 */
456
static 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");
5354 serge 491
 
3031 serge 492
	return true;
493
 
494
out:
495
	kfree(ns);
496
	return false;
497
}
498
 
499
static 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
 
511
static enum drm_mode_status ns2501_mode_valid(struct intel_dvo_device *dvo,
512
					      struct drm_display_mode *mode)
513
{
514
	DRM_DEBUG_KMS
5060 serge 515
	    ("is mode valid (hdisplay=%d,htotal=%d,vdisplay=%d,vtotal=%d)\n",
516
	     mode->hdisplay, mode->htotal, mode->vdisplay, mode->vtotal);
3031 serge 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
	 */
5354 serge 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)) {
3031 serge 527
		return MODE_OK;
528
	} else {
529
		return MODE_ONE_SIZE;	/* Is this a reasonable error? */
530
	}
531
}
532
 
533
static 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);
5354 serge 538
	int mode_idx, i;
3031 serge 539
 
540
	DRM_DEBUG_KMS
5060 serge 541
	    ("set mode (hdisplay=%d,htotal=%d,vdisplay=%d,vtotal=%d).\n",
542
	     mode->hdisplay, mode->htotal, mode->vdisplay, mode->vtotal);
3031 serge 543
 
5354 serge 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;
3031 serge 552
 
5354 serge 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);
3031 serge 556
 
5354 serge 557
	ns->regs = regs_1024x768[mode_idx];
3031 serge 558
 
5354 serge 559
	for (i = 0; i < 84; i++)
560
		ns2501_writeb(dvo, ns->regs[i].offset, ns->regs[i].value);
3031 serge 561
}
562
 
563
/* set the NS2501 power state */
564
static 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
 
5354 serge 571
	return ch & NS2501_8_PD;
3031 serge 572
}
573
 
574
/* set the NS2501 power state */
575
static void ns2501_dpms(struct intel_dvo_device *dvo, bool enable)
576
{
577
	struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv);
578
 
5060 serge 579
	DRM_DEBUG_KMS("Trying set the dpms of the DVO to %i\n", enable);
3031 serge 580
 
5354 serge 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;
3031 serge 586
 
5354 serge 587
		ns2501_writeb(dvo, 0xc0, ns->regs[85].value | 0x08);
3031 serge 588
 
5354 serge 589
		ns2501_writeb(dvo, 0x41, ns->regs[84].value);
3031 serge 590
 
5354 serge 591
		ns2501_writeb(dvo, 0x34, 0x01);
592
		msleep(15);
3031 serge 593
 
5354 serge 594
		ns2501_writeb(dvo, 0x08, 0x35);
595
		if (!(ns->regs[83].value & NS2501_8_BPAS))
596
			ns2501_writeb(dvo, 0x08, 0x31);
597
		msleep(200);
3031 serge 598
 
5354 serge 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
	}
3031 serge 611
}
612
 
613
static 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
 
623
struct 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
};