~gma500/+junk/emgd160

« back to all changes in this revision

Viewing changes to emgd-dkms-kernel39/emgd/display/mode/tnc/clocks_tnc.c

  • Committer: Luca Forina
  • Date: 2011-05-10 07:28:19 UTC
  • Revision ID: luca.forina@gmail.com-20110510072819-pgj21l6igboa9dsx
emgd-dkms for kernel .39

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- pse-c -*-
 
2
 *-----------------------------------------------------------------------------
 
3
 * Filename: clocks_tnc.c
 
4
 * $Revision: 1.13 $
 
5
 *-----------------------------------------------------------------------------
 
6
 * Copyright © 2002-2010, Intel Corporation.
 
7
 *
 
8
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 
9
 * of this software and associated documentation files (the "Software"), to deal
 
10
 * in the Software without restriction, including without limitation the rights
 
11
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 
12
 * copies of the Software, and to permit persons to whom the Software is
 
13
 * furnished to do so, subject to the following conditions:
 
14
 *
 
15
 * The above copyright notice and this permission notice shall be included in
 
16
 * all copies or substantial portions of the Software.
 
17
 *
 
18
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
19
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
20
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 
21
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 
22
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 
23
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 
24
 * THE SOFTWARE.
 
25
 *
 
26
 *-----------------------------------------------------------------------------
 
27
 * Description:
 
28
 *  Clock programming for Atom E6xx
 
29
 *  program clocks used for LVDS port based on Lincroft
 
30
 *  program clocks used for SDVO port based on Atom E6xx overlay
 
31
 *-----------------------------------------------------------------------------
 
32
 */
 
33
 
 
34
#define MODULE_NAME hal.mode
 
35
 
 
36
#include <io.h>
 
37
#include <sched.h>
 
38
 
 
39
#include <igd_init.h>
 
40
#include <igd_mode.h>
 
41
 
 
42
#include <context.h>
 
43
#include <dsp.h>
 
44
#include <utils.h>
 
45
#include <mode.h>
 
46
#include <pi.h>
 
47
#include <intelpci.h>
 
48
 
 
49
#include <tnc/regs.h>
 
50
 
 
51
#include <tnc/igd_tnc_wa.h> /* needed for vbios for register defines */
 
52
 
 
53
#ifdef CONFIG_DEBUG
 
54
#define FLAG(a) a
 
55
/* Debug flag to turn off CDVO reset sequence */
 
56
static int flag_enable_cdvo_reset = 1;
 
57
#else
 
58
/* Turn all workaround for release driver */
 
59
#define FLAG(a) 1
 
60
#endif
 
61
 
 
62
 
 
63
static void wait_dpll(void);
 
64
 
 
65
static int program_cdvo(igd_display_context_t *display);
 
66
 
 
67
static cdvo_regs_t cdvo_reset[] = {
 
68
           /*turn off the SDVO port*/
 
69
           {0x61140, 0},
 
70
           /*turn off the stall register*/
 
71
           {0x6102C, 0},
 
72
           /*disable SDVO*/
 
73
           {0x61170, 0},
 
74
           /*programmable cdvo stall*/
 
75
           {0x6102c, 0xf},
 
76
           {0x7000, 0x40},
 
77
           /*reset*/
 
78
           {0x7000, 0x51},
 
79
           {0x7000, 0x50},
 
80
           /*High*/
 
81
           {0x7014, 0x00004800},
 
82
           /*strobe data tuning default*/
 
83
           {0x700c, 0x000BB4FF},
 
84
           /*enable sdvo*/
 
85
           {0x61170, 0x20022160},
 
86
           {0x7010, 0x06000200},
 
87
           /* -- Begin Sequence of 3 pixel signal --*/
 
88
           /*Low*/
 
89
           {0x700c, 0x00008000},
 
90
           {0x700c, 0x0008B400},
 
91
           /*High*/
 
92
           {0x700c, 0x0008B4FF},
 
93
           /*Low*/
 
94
           {0x700c, 0x00008000},
 
95
           {0x700c, 0x0008B400},
 
96
           /*High*/
 
97
           {0x700c, 0x0008B4FF},
 
98
           /*Low*/
 
99
           {0x700c, 0x00008000},
 
100
           {0x700c, 0x0008B400},
 
101
           /*High*/
 
102
           {0x700c, 0x0008B4FF},
 
103
           /*Low*/
 
104
           {0x700c, 0x00008000},
 
105
           {0x700c, 0x0008B400},
 
106
           /*High*/
 
107
           {0x700c, 0x0008B4FF},
 
108
           /*Low*/
 
109
           {0x700c, 0x00008000},
 
110
           {0x700c, 0x0008B400},
 
111
           /*High*/
 
112
           {0x700c, 0x0008B4FF},
 
113
           /*Low*/
 
114
           {0x700c, 0x00008000},
 
115
           {0x700c, 0x0008B400},
 
116
           /*High*/
 
117
           {0x700c, 0x0008B4FF},
 
118
           /*reset*/
 
119
           {0x7000, 0x51},
 
120
           {0x7000, 0x50},
 
121
           /*High*/
 
122
           {0x7014, 0x00004800},
 
123
           /*strobe data tuning default*/
 
124
           {0x700c, 0x000BB4FF},
 
125
           /*enable sdvo*/
 
126
           {0x61170, 0x20022160},
 
127
           {0x7010, 0x06000200},
 
128
           /* -- Begin Sequence of 3 pixel signal --*/
 
129
           /*Low*/
 
130
           {0x700c, 0x00008000},
 
131
           {0x700c, 0x0008B400},
 
132
           /*High*/
 
133
           {0x700c, 0x0008B4FF},
 
134
           /*Low*/
 
135
           {0x700c, 0x00008000},
 
136
           {0x700c, 0x0008B400},
 
137
           /*High*/
 
138
           {0x700c, 0x0008B4FF},
 
139
           /*Low*/
 
140
           {0x700c, 0x00008000},
 
141
           {0x700c, 0x0008B400},
 
142
           /*High*/
 
143
           {0x700c, 0x0008B4FF},
 
144
           /*Low*/
 
145
           {0x700c, 0x00008000},
 
146
           {0x700c, 0x0008B400},
 
147
           /*High*/
 
148
           {0x700c, 0x0008B4FF},
 
149
           /*Low*/
 
150
           {0x700c, 0x00008000},
 
151
           {0x700c, 0x0008B400},
 
152
           /*High*/
 
153
           {0x700c, 0x0008B4FF},
 
154
           /*Low*/
 
155
           {0x700c, 0x00008000},
 
156
           {0x700c, 0x0008B400},
 
157
           /*High*/
 
158
           {0x700c, 0x0008B4FF},
 
159
           /*Reset*/
 
160
           {0x7000, 0x51},
 
161
           {0x7000, 0x50},
 
162
           {0x7010, 0x02000200},    /*gtl gtl*/
 
163
           {0x7014, 0x00004000},    /*ODT*/
 
164
           {0x61170, 0x20022160},    /*enable SDVO*/
 
165
           {0x7010, 0x02000200},    /*gtl gtl*/
 
166
           {0x7014, 0x00000800},
 
167
           {0x7014, 0x00004800},    /*rcomp*/
 
168
           {0x7014, 0x00000000},
 
169
           {0x7000, 0x40},            /*enable cdvo*/
 
170
           {0x7000, 0x50},            /*enable cdvo*/
 
171
           {0x7014, 0x00004000},    /*ODT*/
 
172
           {0x61170, 0x20022160},    /*enable SDVO*/
 
173
           {0,0}
 
174
};
 
175
 
 
176
 
 
177
 
 
178
 
 
179
/*!
 
180
 * @addtogroup display_group
 
181
 * @{
 
182
 */
 
183
 
 
184
/* Enable this if calculated values are wrong and required fixed table */
 
185
#define CONFIG_FIXED_TABLE  0
 
186
 
 
187
#ifdef CONFIG_TNC
 
188
 
 
189
extern int program_clock_sdvo_tnc(igd_display_context_t *display,
 
190
        igd_clock_t *clock, unsigned long dclk);
 
191
 
 
192
/*===========================================================================
 
193
; File Global Data
 
194
;--------------------------------------------------------------------------*/
 
195
#if CONFIG_FIXED_TABLE
 
196
typedef struct _fixed_clock {
 
197
        unsigned long dclk;
 
198
        unsigned long n;
 
199
        unsigned long m;
 
200
        unsigned long p1;
 
201
} fixed_clock_t;
 
202
 
 
203
/* set mmio register required values */
 
204
static fixed_clock_t lvds_fixed_clock_table[] =  {
 
205
        /* Clock       N     M     P1 */
 
206
        { 65000,      0x01, 0x00, 0x00 },
 
207
        { 0xffffffff, 0x01, 0x00, 0x00}
 
208
};
 
209
 
 
210
/* set mmio register required values */
 
211
static fixed_clock_t sdvo_fixed_clock_table[] =  {
 
212
        /* Clock       N     M    P1 */
 
213
        { 65000,      0x00, 0x00, 0x00 },
 
214
        { 0xffffffff, 0x00, 0x00, 0x00}
 
215
};
 
216
#endif
 
217
 
 
218
#define LVDS_M_MIN 10
 
219
 
 
220
/* This table is also used by mode_tnc.c */
 
221
const unsigned long lvds_m_converts[] = {
 
222
        0x2B, 0x15, 0x2A, 0x35, 0x1A, 0x0D, 0x26, 0x33, 0x19, 0x2C,
 
223
        0x36, 0x3B, 0x1D, 0x2E, 0x37, 0x1B, 0x2D, 0x16, 0x0B, 0x25,
 
224
        0x12, 0x09, 0x24, 0x32, 0x39, 0x1c,
 
225
};
 
226
 
 
227
const unsigned long LVDS_M_CONVERTS_LEN=26;   /* Length of the array above*/
 
228
 
 
229
#define TARGET_ERROR 46
 
230
 
 
231
typedef const struct _tnc_limits {
 
232
        unsigned long ref_freq;
 
233
        unsigned long min_m;
 
234
        unsigned long max_m;
 
235
 
 
236
        unsigned long min_n;
 
237
        unsigned long max_n;
 
238
 
 
239
        unsigned long min_p1;
 
240
        unsigned long max_p1;
 
241
 
 
242
        unsigned long min_p2;
 
243
        unsigned long max_p2;
 
244
 
 
245
        unsigned long min_vco;
 
246
        unsigned long max_vco;
 
247
} tnc_limits_t;
 
248
 
 
249
/* m, n, p value limits:
 
250
 * source: http://moss.amr.ith.intel.com/sites/LCD/LNC/HAS/Secured
 
251
 * %20Documents/LNC%20HAS%20work%20area/Lincroft%20DPLL_1.2_ww31_08.docx
 
252
 *
 
253
 * Note:
 
254
 * VCO range for 100L is not given: so put a range big enough to go through
 
255
 * calculations for the for loop.
 
256
 */
 
257
static tnc_limits_t tnc_lvds_limits[] =
 
258
{
 
259
        /* reffreq  m      n     p1     p2          vco */
 
260
        { 200000, 10, 17, 1, 1, 2, 8, 14, 14, 2000000, 3400000},  /* SKU 100 */
 
261
        { 100000, 20, 34, 1, 1, 2, 8, 14, 14, 1000000, 3400000},  /* SKU 100L */
 
262
        { 166000, 12, 20, 1, 1, 2, 7, 14, 14, 2000000, 3333333},  /* SKU 83 */
 
263
};
 
264
 
 
265
static tnc_limits_t tnc_sdvo_limits[] =
 
266
{
 
267
        /* reffreq  m      n     p1     p2          vco */
 
268
        {  96000, 80,137, 3, 7, 1, 2, 10, 10, 1400000, 2800000},  /* SDVO */
 
269
};
 
270
 
 
271
/*!
 
272
 *
 
273
 * @param dclk
 
274
 * @param ref_freq
 
275
 * @param limits
 
276
 * @param m
 
277
 * @param n
 
278
 * @param p
 
279
 * @param target_error
 
280
 *
 
281
 * @return 0 on success
 
282
 * @return 1 on failure
 
283
 */
 
284
static int calculate_clock(unsigned long dclk,
 
285
        unsigned long ref_freq,
 
286
        tnc_limits_t *l,
 
287
        unsigned long *m,
 
288
        unsigned long *n,
 
289
        unsigned long *p1,
 
290
        unsigned long target_error,
 
291
        unsigned long *actual_dclk,
 
292
        unsigned long port_type,
 
293
        unsigned long pd_type)
 
294
{
 
295
        unsigned long  pdiv;
 
296
        unsigned long  target_vco, actual_freq;
 
297
        long freq_error, min_error;
 
298
        unsigned long dclk_10000;
 
299
 
 
300
        unsigned long current_m, current_n, current_p1;
 
301
 
 
302
        EMGD_TRACE_ENTER;
 
303
 
 
304
        min_error = 100000;
 
305
 
 
306
        *m = 0;
 
307
        *n = 0;
 
308
        *p1 = 0;
 
309
 
 
310
        /* dclk * 10000, so it does not have to be calculated within the
 
311
         * loop */
 
312
        dclk_10000 = dclk * 10000;
 
313
 
 
314
        for(current_m = l->min_m; current_m <= l->max_m; current_m++) {
 
315
                for(current_n = l->min_n; current_n <= l->max_n; current_n++) {
 
316
                        for(current_p1 = l->min_p1; current_p1 <= l->max_p1; current_p1++) {
 
317
 
 
318
                                /* For both LVDS/SDVO ports min_p2 and max_p2 are same,
 
319
                                 * so assign use either min/max p2 */
 
320
                                pdiv = current_p1 * l->min_p2;
 
321
                                target_vco = dclk * pdiv;
 
322
 
 
323
                                if (target_vco > l->max_vco) {
 
324
                                        /* target_vco continues to increase, so start with
 
325
                                         * next current_n */
 
326
                                        break;
 
327
                                }
 
328
 
 
329
                                if (target_vco >= l->min_vco) {
 
330
                                        /* Frequency calculations for SDVO and LVDS are different
 
331
                                         * SDVO Dotclock_frequency = (Reference Frequency * (M+2)) / (N*(P1*P2))
 
332
                                         * LVDS DotClk_Frequency = (ReferenceFrequency * M)/ (P1* P2)
 
333
                                         * need to find a way to differentiate SDVO and LVDS
 
334
                                         * Works for now but signal generated will be different */
 
335
                                        actual_freq = (ref_freq * current_m) / (current_n*pdiv);
 
336
                                        freq_error = 10000 - (dclk_10000 / actual_freq);
 
337
 
 
338
                                        if (freq_error < -min_error) {
 
339
                                                /* freq_error continues to decrease once this
 
340
                                                 * point is reached, so start with next
 
341
                                                 * current_n */
 
342
                                                break;
 
343
                                        }
 
344
 
 
345
                                        if (freq_error < 0) {
 
346
                                                freq_error = -freq_error;
 
347
                                        }
 
348
                                        if (freq_error < min_error)  {
 
349
                                                *n = current_n;
 
350
                                                *m = current_m;
 
351
                                                *p1 = current_p1;
 
352
                                                min_error = freq_error;
 
353
                                                *actual_dclk = actual_freq;
 
354
                                        }
 
355
                                }
 
356
                        }
 
357
                }
 
358
                if (min_error == 0) {
 
359
                        break;
 
360
                }
 
361
        }
 
362
 
 
363
        if (pd_type == PD_DISPLAY_TVOUT) {
 
364
                EMGD_TRACE_EXIT;
 
365
                return 0;
 
366
        }
 
367
        /*
 
368
         * No clock found that meets error requirement
 
369
         */
 
370
        if (min_error > (long)target_error) {
 
371
                EMGD_TRACE_EXIT;
 
372
                return 1;
 
373
        }
 
374
 
 
375
        EMGD_DEBUG("dclk = (ref*m)/(n*p1*p2) => %lu = (%lu*%lu)/(%lu*%lu*%lu) = %lu",
 
376
                dclk, ref_freq, *m, *n, *p1, l->min_p2,
 
377
                (ref_freq*(*m))/((*n)*(*p1)*l->min_p2));
 
378
        EMGD_DEBUG("min_error:%ld", min_error);
 
379
        EMGD_TRACE_EXIT;
 
380
        return 0;
 
381
}
 
382
 
 
383
/*!
 
384
 *
 
385
 * @param dclk
 
386
 * @param ref_freq
 
387
 * @param limits
 
388
 * @param m
 
389
 * @param n
 
390
 * @param p
 
391
 * @param target_error
 
392
 * @param port_type
 
393
 * @param pd_type
 
394
 *
 
395
 * @return 0 on success
 
396
 * @return 1 on failure
 
397
 */
 
398
static int get_clock(unsigned long dclk,
 
399
        unsigned long ref_freq,
 
400
        tnc_limits_t *l,
 
401
        unsigned long *m,
 
402
        unsigned long *n,
 
403
        unsigned long *p1,
 
404
        unsigned long target_error,
 
405
        unsigned long port_type,
 
406
        unsigned long *actual_dclk,
 
407
        unsigned long pd_type)
 
408
{
 
409
 
 
410
#if CONFIG_FIXED_TABLE
 
411
        fixed_clock_t *fixed;
 
412
        EMGD_TRACE_ENTER;
 
413
    /* Enable this if calculated values are wrong and required fixed table */
 
414
        if (port_type == IGD_PORT_LVDS) {
 
415
                fixed = lvds_fixed_clock_table;
 
416
        } else {
 
417
                fixed = sdvo_fixed_clock_table;
 
418
        }
 
419
 
 
420
        /* First check for a fixed clock from the table. These are ones that
 
421
         * can't be calculated correctly. */
 
422
        while (fixed->dclk != 0xffffffff) {
 
423
                if (fixed->dclk == dclk) {
 
424
                        EMGD_DEBUG("Using Fixed Clock From table for clock %ld", dclk);
 
425
                        *m = fixed->m;
 
426
                        *n = fixed->n;
 
427
                        *p1 = fixed->p1;
 
428
                        EMGD_TRACE_EXIT;
 
429
                        return 0;
 
430
                }
 
431
                fixed++;
 
432
        }
 
433
#endif
 
434
 
 
435
        EMGD_TRACE_ENTER;
 
436
        /* No fixed clock found so calculate one. */
 
437
        EMGD_DEBUG("Calculating dynamic clock for clock %ld", dclk);
 
438
 
 
439
        if (calculate_clock(dclk, ref_freq, l, m, n, p1, target_error, actual_dclk, port_type, pd_type)) {
 
440
                /* No usable clock.  Cannot use 640x480@60 as default, because
 
441
                 * there are several vcos and several reference clocks. */
 
442
                EMGD_ERROR("Could not calculate clock %ld, returning default.", dclk);
 
443
                EMGD_TRACE_EXIT;
 
444
                return 1;
 
445
        }
 
446
 
 
447
        if (pd_type == PD_DISPLAY_TVOUT) {
 
448
                *p1 = 2;
 
449
                *m = 100;
 
450
                *n = 5;
 
451
        }
 
452
 
 
453
        /* Translate returned values to m,n,p1 register values */
 
454
        /* No change required for *n value */
 
455
        if (port_type == IGD_PORT_SDVO) {
 
456
                *p1 = (1L << (*p1 - 1));
 
457
                *m -= 2;
 
458
                *n = (1L << (*n -1));
 
459
        } else {
 
460
                *p1 = (1L << (*p1 - 2));
 
461
                *m = lvds_m_converts[*m - LVDS_M_MIN];
 
462
        }
 
463
 
 
464
        EMGD_DEBUG("reg m=%lu n=%lu p1=%lu p2=%lu", *m, *n, *p1, l->min_p2);
 
465
 
 
466
        EMGD_TRACE_EXIT;
 
467
        return 0;
 
468
}
 
469
 
 
470
/*!
 
471
 *
 
472
 * @param display
 
473
 * @param clock
 
474
 * @param dclk
 
475
 *
 
476
 * @return 0 on success
 
477
 * @return 1 on failure
 
478
 */
 
479
int program_clock_lvds_tnc(igd_display_context_t *display,
 
480
        igd_clock_t *clock,
 
481
        unsigned long dclk)
 
482
{
 
483
        int ret;
 
484
        unsigned long m, n, p1;
 
485
        unsigned long control;
 
486
        unsigned long ref_freq;
 
487
        igd_display_port_t *port;
 
488
        tnc_limits_t *l = NULL;
 
489
        unsigned long count;
 
490
 
 
491
        EMGD_TRACE_ENTER;
 
492
 
 
493
        port = PORT_OWNER(display);
 
494
 
 
495
        /* LNC ref_freq is determined by SKU, convert to KHz */
 
496
#if 0
 
497
        ref_freq = display->context->device_context.gfx_freq * 1000L;
 
498
#else
 
499
        ref_freq = display->context->device_context.core_freq;
 
500
        ref_freq = ref_freq * 1000;
 
501
#endif
 
502
 
 
503
#if 0
 
504
        /* Find m,n,p,vco limits */
 
505
        if (ref_freq == 200000) {
 
506
                l = &tnc_lvds_limits[0];
 
507
        } else if (ref_freq == 100000) {
 
508
                l = &tnc_lvds_limits[1];
 
509
        } else if (ref_freq == 166000) {
 
510
                l = &tnc_lvds_limits[2];
 
511
        }
 
512
#endif
 
513
 
 
514
        for(count=0; count<3; count++){
 
515
                if (tnc_lvds_limits[count].ref_freq == ref_freq){
 
516
                        l = &tnc_lvds_limits[count];
 
517
                        break;
 
518
                }
 
519
        }
 
520
 
 
521
/* PO Debug */
 
522
#if 0
 
523
        /* WRITE_PORT80(0xED); */
 
524
 
 
525
        if(ref_freq == 166000){
 
526
        WRITE_PORT80(0xEF);
 
527
        }
 
528
 
 
529
        if (!l){
 
530
                /* FATAL ERROR */
 
531
                DEAD_LOOP(0xDD);
 
532
        }
 
533
#endif
 
534
 
 
535
        /* Per UMG, there is no defined target_error for LVDS, it supposed to
 
536
         * work for all expected dclks. */
 
537
#if 1
 
538
        ret = get_clock(dclk, ref_freq, l, &m, &n, &p1, dclk /* target_error */,
 
539
                port->port_type, &clock->actual_dclk, port->pd_driver->type);
 
540
        if (ret) {
 
541
                EMGD_ERROR_EXIT("Clock %ld could not be programmed", dclk);
 
542
                /* DEAD_LOOP(0xFF); */
 
543
                return ret;
 
544
        }
 
545
#else
 
546
        /* Hard code the values for now */
 
547
        m = 0x2D;  // ITP uses 0x2E, should change
 
548
        p1 = 2;
 
549
 
 
550
#endif
 
551
 
 
552
#if 0
 
553
        /* If clocks are already running at required clocks, just return */
 
554
        if (PIPE(display)->dclk == dclk) {
 
555
                return 0;
 
556
        }
 
557
#endif
 
558
 
 
559
        /* Disable DPLL */
 
560
#if 0
 
561
        control = BIT28 | (1<<clock->p_shift); //Why are we shifting 1 to P1, GMA carry over???
 
562
#else
 
563
        control = BIT28;
 
564
#endif
 
565
        WRITE_MMIO_REG(display, clock->dpll_control, control);
 
566
        EMGD_DEBUG("lvds: EMGD_WRITE32: 0x%lx = 0x%lx",
 
567
                clock->dpll_control, control);
 
568
 
 
569
        /* Program M */
 
570
        WRITE_MMIO_REG(display, clock->mnp, (m<<8));
 
571
 
 
572
        WRITE_MMIO_REG(display, 0xF044, (m<<8)); //BUGBUG
 
573
 
 
574
        EMGD_DEBUG("lvds: EMGD_WRITE32: 0x%lx = 0x%lx",
 
575
                clock->mnp, (m<<8));
 
576
 
 
577
        /* Enable DPLL */
 
578
        control = (BIT31 | BIT28 | BIT27) | (p1<<clock->p_shift);
 
579
 
 
580
/* PO Debug..*/
 
581
#if 0
 
582
        /* set VCO select */
 
583
        if (ref_freq == 166000) {
 
584
                control |= BIT16;
 
585
        }
 
586
#endif
 
587
 
 
588
 
 
589
        WRITE_MMIO_REG(display, clock->dpll_control, control);
 
590
        EMGD_DEBUG("lvds: EMGD_WRITE32: 0x%lx = 0x%lx",
 
591
                clock->dpll_control, control);
 
592
 
 
593
        /* Wait 150us for the DPLL to stabilize */
 
594
        OS_SLEEP(150);
 
595
        PIPE(display)->dclk = dclk;
 
596
 
 
597
        EMGD_TRACE_EXIT;
 
598
        return 0;
 
599
}
 
600
 
 
601
/*!
 
602
 *
 
603
 * @param display
 
604
 * @param clock
 
605
 * @param dclk
 
606
 *
 
607
 * @return 0 on success
 
608
 * @return 1 on failure
 
609
 */
 
610
int program_clock_sdvo_tnc(igd_display_context_t *display,
 
611
        igd_clock_t *clock,
 
612
        unsigned long dclk)
 
613
{
 
614
        int ret;
 
615
        unsigned long m, n, p1;
 
616
        unsigned long control;
 
617
        unsigned long ref_freq;
 
618
        unsigned long port_mult, vga_mult;
 
619
        unsigned long target_error, actual_dclk;
 
620
        igd_display_port_t *port;
 
621
        tnc_limits_t *l;
 
622
 
 
623
        EMGD_DEBUG("Enter program_clock");
 
624
 
 
625
        port = PORT_OWNER(display);
 
626
 
 
627
        /* FIXME: No info available in EAS and waiting for info. */
 
628
        if (dclk > 100000) {          /* 100-200 MHz */
 
629
                port_mult = 1;
 
630
        } else if (dclk > 50000) {    /* 50-100 Mhz */
 
631
                port_mult = 2;
 
632
        } else {                      /* 25-50 Mhz */
 
633
                port_mult = 4;
 
634
        }
 
635
 
 
636
        dclk *= port_mult;
 
637
 
 
638
        l = &tnc_sdvo_limits[0];
 
639
        ref_freq = l->ref_freq;
 
640
 
 
641
        vga_mult = READ_MMIO_REG_TNC(IGD_PORT_SDVO, clock->dpll_control) & 0x3;
 
642
 
 
643
        target_error = TARGET_ERROR;
 
644
 
 
645
        /* For external clock sources always use ref_clock == dclk */
 
646
        if(port->pd_flags & PD_FLAG_CLK_SOURCE) {
 
647
                ref_freq = dclk;
 
648
                /* When clock source sdvo device, allowed error is 0. */
 
649
                target_error = 0;
 
650
        }
 
651
 
 
652
        ret = get_clock(dclk, ref_freq, l, &m, &n, &p1, target_error,
 
653
                IGD_PORT_SDVO, &actual_dclk, port->pd_driver->type);
 
654
 
 
655
        clock->actual_dclk = actual_dclk/port_mult;
 
656
 
 
657
        if (ret) {
 
658
                EMGD_ERROR("Clock %ld could not be programmed", dclk);
 
659
                return ret;
 
660
        }
 
661
 
 
662
        /* Disable DPLL, Write 2 into P for saftey */
 
663
        control = BIT28 | (2<<clock->p_shift) | vga_mult;
 
664
 
 
665
        WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, clock->dpll_control, control);
 
666
        EMGD_DEBUG("sdvo: EMGD_WRITE32: 0x%lx = 0x%lx",
 
667
                clock->dpll_control, control);
 
668
 
 
669
        /* Program N, M */
 
670
        WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, clock->mnp, (n<<16) | m);
 
671
        EMGD_DEBUG("sdvo: EMGD_WRITE32: 0x%lx = 0x%lx",
 
672
                clock->mnp, (n<<16)|m);
 
673
 
 
674
        /* Enable DPLL, Disable VGA mode and sitck in new P values */
 
675
        control = BIT31 | BIT30 | BIT28 | (p1<<clock->p_shift) | vga_mult;
 
676
 
 
677
        /* Set the clock source correctly based on PD settings */
 
678
        if(port->pd_flags & PD_FLAG_CLK_SOURCE) {
 
679
                control |= port->clock_bits;
 
680
        }
 
681
 
 
682
        /* sDVO Multiplier bits[7:0] */
 
683
        if (port_mult == 2) {
 
684
                control |= (1 << 4);
 
685
        } else if (port_mult == 3) {
 
686
                control |= (2 << 4);
 
687
        } else if (port_mult == 4) {
 
688
                control |= (3 << 4);
 
689
        }
 
690
 
 
691
        /* Double buffered */
 
692
        WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, clock->dpll_control, control);
 
693
        WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, clock->dpll_control, control);
 
694
        EMGD_DEBUG("sdvo: EMGD_WRITE32: 0x%lx = 0x%lx",
 
695
                clock->dpll_control, control);
 
696
 
 
697
        /* We must wait for 150 us for the dpll clock to warm up */
 
698
        //OS_SLEEP(150);
 
699
        wait_dpll();
 
700
 
 
701
        program_cdvo(display);
 
702
 
 
703
        return 0;
 
704
}
 
705
 
 
706
int program_clock_tnc(igd_display_context_t *display,
 
707
        igd_clock_t *clock,
 
708
        unsigned long dclk)
 
709
{
 
710
        EMGD_TRACE_ENTER;
 
711
 
 
712
        if (PORT_TYPE(display) == IGD_PORT_LVDS) {
 
713
                EMGD_TRACE_EXIT;
 
714
                return program_clock_lvds_tnc(display, clock, dclk);
 
715
        } else {
 
716
                EMGD_TRACE_EXIT;
 
717
                return program_clock_sdvo_tnc(display, clock, dclk);
 
718
        }
 
719
}
 
720
 
 
721
 
 
722
/*!
 
723
 * Poll for DPLL register lock. This is only valid for DPLLB
 
724
 *
 
725
 * @return void
 
726
 */
 
727
static void wait_dpll(void)
 
728
{
 
729
#ifndef CONFIG_MICRO
 
730
        unsigned long temp;
 
731
        os_alarm_t timeout;
 
732
 
 
733
        EMGD_TRACE_ENTER;
 
734
 
 
735
        /* Wait for DPLL lock, about 50 msec (20Hz). */
 
736
        timeout = OS_SET_ALARM(50);
 
737
        do {
 
738
                OS_SCHEDULE();
 
739
                /* Check for Bit16, 1 means DPLL is locked (TNC EAS Ver 2.0) */
 
740
                temp = (READ_MMIO_REG_TNC(IGD_PORT_SDVO, 0x606C) & 0x10000) >> 16;
 
741
 
 
742
                /* Check for timeout */
 
743
        } while ((!temp) && (!OS_TEST_ALARM(timeout)));
 
744
 
 
745
        if (!temp) {
 
746
                EMGD_ERROR_EXIT("Timeout waiting for pipe enable/disable");
 
747
        }
 
748
 
 
749
        EMGD_TRACE_EXIT;
 
750
#else
 
751
        /* to save space in VBIOS, we use to old method of waiting for the DPLL
 
752
        * to warm up */
 
753
        OS_SLEEP(150);
 
754
#endif
 
755
        return;
 
756
}
 
757
 
 
758
 
 
759
 
 
760
/* This is the initialization code for B0 stepping */
 
761
static int program_cdvo(igd_display_context_t *display)
 
762
{
 
763
        int counter = 0;
 
764
 
 
765
        EMGD_TRACE_ENTER;
 
766
 
 
767
    #ifndef CONFIG_MICRO
 
768
        /*
 
769
         * CDVO reset has been done. Check that offset 0x7000 has the value 0x50
 
770
         * and this would mean that reset has been done. We only need to do cdvo
 
771
         * reset once per warm reset
 
772
         */
 
773
        if((READ_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7000) == 0x50) ||
 
774
                !FLAG(flag_enable_cdvo_reset)){
 
775
                EMGD_TRACE_EXIT;
 
776
                return TRUE;
 
777
        }
 
778
 
 
779
    #endif
 
780
 
 
781
        /* pipe_temp = READ_MMIO_REG_TNC(IGD_PORT_SDVO, PIPE(display)->pipe_reg); */
 
782
 
 
783
        /* Disable pipe */
 
784
        WRITE_MMIO_REG_TNC(IGD_PORT_LVDS, PIPE(display)->pipe_reg, 0);
 
785
        WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, PIPE(display)->pipe_reg, 0);
 
786
 
 
787
        /* Sleep for a while to wait for the pipe to disable. There are no
 
788
        * status bits to check if pipe B has been enable */
 
789
        OS_SLEEP(25);
 
790
 
 
791
    #if 0
 
792
       /* Disable DPLL */
 
793
       vga_mult = READ_MMIO_REG_TNC(IGD_PORT_SDVO,
 
794
           PIPE(display)->clock_reg->dpll_control) & 0x3;
 
795
       control = BIT28 | (2<<PIPE(display)->clock_reg->p_shift) | vga_mult;
 
796
 
 
797
       WRITE_MMIO_REG_TNC(IGD_PORT_SDVO,
 
798
           PIPE(display)->clock_reg->dpll_control, control);
 
799
       WRITE_MMIO_REG_TNC(IGD_PORT_SDVO,
 
800
           PIPE(display)->clock_reg->dpll_control, control);
 
801
    #endif
 
802
 
 
803
        /* the checking is needed for VBIOS but not needed for driver */
 
804
        do{
 
805
                WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, cdvo_reset[counter].reg,
 
806
                        cdvo_reset[counter].value);
 
807
                        counter++;
 
808
        }while(cdvo_reset[counter].reg != 0);
 
809
 
 
810
        /* Enable sDVOB port */
 
811
        WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x61140,
 
812
        READ_MMIO_REG_TNC(IGD_PORT_SDVO, 0x61140) | 0xC0000018 );
 
813
 
 
814
 
 
815
        EMGD_TRACE_EXIT;
 
816
 
 
817
        return TRUE;
 
818
}
 
819
#endif
 
820
 
 
821
 
 
822
 
 
823
/*----------------------------------------------------------------------------
 
824
 * File Revision History
 
825
 * $Id: clocks_tnc.c,v 1.13 2011/02/16 17:04:48 astead Exp $
 
826
 * $Source: /nfs/fm/proj/eia/cvsroot/koheo/linux/egd_drm/emgd/display/mode/tnc/clocks_tnc.c,v $
 
827
 *----------------------------------------------------------------------------
 
828
 */