~gma500/emgd/trunk

« back to all changes in this revision

Viewing changes to emgd-dkms-1.5.15.2856/emgd/display/mode/plb/clocks_plb.c

  • Committer: José Bernardo Bandos
  • Date: 2010-08-28 16:04:10 UTC
  • Revision ID: jbs@jbs-laptop-20100828160410-nw5zohdn37oupdv2
First step to add emgd drivers from meego

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- pse-c -*-
 
2
 *-----------------------------------------------------------------------------
 
3
 * Filename: clocks_plb.c
 
4
 * $Revision: 1.3 $
 
5
 *-----------------------------------------------------------------------------
 
6
 * Copyright © 2002-2010, Intel Corporation.
 
7
 *  
 
8
 * This program is free software; you can redistribute it and/or modify it
 
9
 * under the terms and conditions of the GNU General Public License,
 
10
 * version 2, as published by the Free Software Foundation.
 
11
 * 
 
12
 * This program is distributed in the hope it will be useful, but WITHOUT
 
13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
14
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 
15
 * more details.
 
16
 * 
 
17
 * You should have received a copy of the GNU General Public License along with
 
18
 * this program; if not, write to the Free Software Foundation, Inc., 
 
19
 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 
20
 *-----------------------------------------------------------------------------
 
21
 * Description:
 
22
 *  
 
23
 *-----------------------------------------------------------------------------
 
24
 */
 
25
 
 
26
#define MODULE_NAME hal.mode
 
27
 
 
28
#include <io.h>
 
29
#include <list.h>
 
30
 
 
31
#include <igd_mode.h>
 
32
#include <igd_init.h>
 
33
 
 
34
#include <context.h>
 
35
#include <intelpci.h>
 
36
#include <dsp.h>
 
37
#include <utils.h>
 
38
#include <mode.h>
 
39
#include <pi.h>
 
40
#include <sched.h>
 
41
 
 
42
#include <plb/regs.h>
 
43
 
 
44
/*!
 
45
 * @addtogroup display_group
 
46
 * @{
 
47
 */
 
48
 
 
49
/*===========================================================================
 
50
; File Global Data
 
51
;--------------------------------------------------------------------------*/
 
52
typedef struct _fixed_clock {
 
53
        unsigned long dclk;
 
54
        unsigned long n;
 
55
        unsigned long m1;
 
56
        unsigned long m2;
 
57
        unsigned long p;
 
58
}fixed_clock_t;
 
59
 
 
60
static fixed_clock_t fixed_clock_table[] =  {
 
61
        /* Clock    N    M1    M2  Post Div */
 
62
    { 43163, 0x03, 0x12, 0x06, 0x84},  /* 43.163 GTF for 640x480 @ 100Hz */
 
63
    { 81624, 0x03, 0x18, 0x04, 0x82},  /* 81.624MHz */
 
64
        {0xffffffff, 0x00, 0x00, 0x00, 0x00}
 
65
};
 
66
 
 
67
/*!
 
68
 * This function translates from the calculated M value to the M1, M2
 
69
 * register values.
 
70
 *
 
71
 * @param m
 
72
 * @param *m1
 
73
 * @param *m2
 
74
 *
 
75
 * @return 0 on success
 
76
 * @return 1 on failure
 
77
 */
 
78
static int calculate_m1_m2(unsigned long m,
 
79
        unsigned long *m1,
 
80
        unsigned long *m2)
 
81
{
 
82
        unsigned long current_m1, current_m2;
 
83
 
 
84
        OS_DEBUG("Enter calculate_m1_m2 %d", 1);
 
85
 
 
86
        /* ori was in steps of 2*/
 
87
        for(current_m1 = (10+2); current_m1 <= (20+2); current_m1 += 1) {
 
88
                for(current_m2 = (5+2); current_m2 <= (9+2); current_m2++)  {
 
89
                        if((current_m1 * 5 + current_m2) == m) {
 
90
                                *m1 = current_m1 - 2;
 
91
                                *m2 = current_m2 - 2;
 
92
                                return 0;
 
93
                        }
 
94
 
 
95
                }
 
96
        }
 
97
 
 
98
        OS_DEBUG("M1, M2 not found for M == %ld", m);
 
99
        return 1;
 
100
}
 
101
 
 
102
#define MAX_M 120 //216
 
103
#define MIN_M 70 //96
 
104
 
 
105
#define MAX_N 8 //16
 
106
#define MIN_N 3
 
107
 
 
108
#define MAX_P 80 //126
 
109
#define MIN_P 5 //2
 
110
 
 
111
#define LVDS_MAX_P 98
 
112
#define LVDS_MIN_P 7
 
113
 
 
114
#define FIX_P2_LO 5 //126
 
115
#define FIX_P2_HI 10 //2
 
116
 
 
117
#define MAX_P1 8 //126
 
118
#define MIN_P1 1 //2
 
119
 
 
120
#define REF_FREQ 96000 //48000
 
121
#define MAX_VCO 2800000 //1400000
 
122
#define MAX_FP 200000
 
123
/* For LVDS port */
 
124
#define LVDS_FIX_P2_LO 7
 
125
#define LVDS_FIX_P2_HI 14
 
126
 
 
127
/*!
 
128
 *
 
129
 * @param dclk
 
130
 * @param ref_freq
 
131
 * @param m1
 
132
 * @param m2
 
133
 * @param n
 
134
 * @param p
 
135
 * @param min_vco
 
136
 * @param target_error
 
137
 * @param port_type
 
138
 * @param dual_channel
 
139
 *
 
140
 * @return 0 on success
 
141
 * @return 1 on failure
 
142
 */
 
143
static int calculate_clock(unsigned long dclk,
 
144
        unsigned long ref_freq,
 
145
        unsigned long *m1,
 
146
        unsigned long *m2,
 
147
        unsigned long *n,
 
148
        unsigned long *p,
 
149
        unsigned long min_vco,
 
150
        unsigned long target_error,
 
151
        unsigned long port_type,
 
152
        unsigned long dual_channel)
 
153
 
 
154
{
 
155
        unsigned long p1;
 
156
        unsigned long p2;
 
157
        /* Parameters */
 
158
    unsigned long freqmult_p2;
 
159
 
 
160
        /* Intermidiate variables */
 
161
        unsigned long  pdiv;
 
162
        unsigned long  target_vco, actual_freq, actual_vco;
 
163
        long freq_error, min_error;
 
164
 
 
165
        unsigned long current_m, current_n, current_p1;
 
166
        unsigned long best_m = 0;
 
167
        unsigned long best_n = 0;
 
168
        unsigned long best_p1 = 0;
 
169
 
 
170
 
 
171
        OS_DEBUG("Enter calculate_clock");
 
172
 
 
173
        min_error = 100000;
 
174
 
 
175
        if (dclk > MAX_FP) {
 
176
                freqmult_p2 = FIX_P2_LO;
 
177
        } else {
 
178
                freqmult_p2 = FIX_P2_HI;
 
179
        }
 
180
 
 
181
        /* For LVDS port */
 
182
        if(port_type==IGD_PORT_LVDS){
 
183
                /* Test if we are dual channel */
 
184
                if(dual_channel){
 
185
                        freqmult_p2=LVDS_FIX_P2_LO;
 
186
                } else{
 
187
                        freqmult_p2=LVDS_FIX_P2_HI;
 
188
                }
 
189
 
 
190
        }
 
191
 
 
192
        for(current_m = MIN_M; current_m <= MAX_M; current_m++) {
 
193
                for(current_n = MIN_N; current_n < MAX_N; current_n++) {
 
194
                        for(current_p1 = MIN_P1; current_p1 <= MAX_P1; current_p1++) {
 
195
 
 
196
                                pdiv = freqmult_p2 * current_p1;
 
197
                                target_vco = dclk * pdiv;
 
198
 
 
199
                                if ((target_vco <= MAX_VCO) && (target_vco >= min_vco)) {
 
200
                                        actual_freq = (ref_freq * current_m) /
 
201
                                                (current_n * pdiv);
 
202
                                        actual_vco = actual_freq * pdiv;
 
203
                                        freq_error = 10000 - (dclk * 10000 / actual_freq);
 
204
 
 
205
                                        if (freq_error < 0) {
 
206
                                                freq_error = -freq_error;
 
207
                                        }
 
208
                                        if (freq_error < min_error)  {
 
209
                                                best_n = current_n;
 
210
                                                best_m = current_m;
 
211
                                                best_p1 = current_p1;
 
212
                                                min_error = freq_error;
 
213
                                        }
 
214
                                        if (min_error == 0) {
 
215
                                                break;
 
216
                                        }
 
217
                                }
 
218
                        }
 
219
                        if (min_error == 0) {
 
220
                                break;
 
221
                        }
 
222
                }
 
223
                if (min_error == 0) {
 
224
                        break;
 
225
                }
 
226
        }
 
227
        /*
 
228
         * No clock found that meets error requirement
 
229
         */
 
230
        if (min_error > (long)target_error) {
 
231
                return 1;
 
232
        }
 
233
 
 
234
 
 
235
        /* Translate M,N,P to m1,m2,n,p register values */
 
236
        *n = best_n - 2;
 
237
        if(calculate_m1_m2(best_m, m1, m2)) {
 
238
                /* No M1, M2 match for M */
 
239
                return 1;
 
240
        }
 
241
 
 
242
        p1 = (1 << (best_p1-1));
 
243
        if((freqmult_p2-5)) {
 
244
                p2 = 0x0;
 
245
        }
 
246
        else {
 
247
                p2 = 0x1;
 
248
        }
 
249
        /* Set p2 for LVDS */
 
250
        if(port_type==IGD_PORT_LVDS){
 
251
                if(dual_channel){
 
252
                        p2=0x1;
 
253
                }else{
 
254
                        p2=0x0;
 
255
                }
 
256
 
 
257
        }
 
258
        *p = (  p1 | (p2<<8) );
 
259
 
 
260
        return 0;
 
261
}
 
262
 
 
263
#define MIN_VCO_PASS1 2000000 //1000000
 
264
#define MIN_VCO_PASS2 1400000 //930000
 
265
 
 
266
/*!
 
267
 *
 
268
 * @param dclk
 
269
 * @param ref_freq
 
270
 * @param m1
 
271
 * @param m2
 
272
 * @param n
 
273
 * @param p
 
274
 * @param target_error
 
275
 * @param port_type
 
276
 * @param dual_channel
 
277
 *
 
278
 * @return 0 on success
 
279
 * @return 1 on failure
 
280
 */
 
281
static int get_clock(unsigned long dclk,
 
282
        unsigned long ref_freq,
 
283
        unsigned long *m1,
 
284
        unsigned long *m2,
 
285
        unsigned long *n,
 
286
        unsigned long *p,
 
287
        unsigned long target_error,
 
288
        unsigned long port_type,
 
289
        unsigned long dual_channel)
 
290
{
 
291
        fixed_clock_t *fixed = fixed_clock_table;
 
292
 
 
293
        OS_DEBUG("Enter get_clock");
 
294
 
 
295
        /*
 
296
         * First check for a fixed clock from the table. These are ones that
 
297
         * can't be calculated correctly.
 
298
         */
 
299
        while(fixed->dclk != 0xffffffff) {
 
300
                if(fixed->dclk == dclk) {
 
301
                        OS_DEBUG("Using Fixed Clock From table for clock %ld", dclk);
 
302
                        *m1 = fixed->m1;
 
303
                        *m2 = fixed->m2;
 
304
                        *n = fixed->n;
 
305
                        *p = fixed->p;
 
306
                        return 0;
 
307
                }
 
308
                fixed++;
 
309
        }
 
310
 
 
311
 
 
312
        /*
 
313
         * No fixed clock found so calculate one.
 
314
         */
 
315
        OS_DEBUG("Calculating dynamic clock for clock %ld", dclk);
 
316
 
 
317
        /*
 
318
         * First pass try to find a clock with min_vco at 1000000.
 
319
         * If a clock doesn't come out then try 930000.
 
320
         */
 
321
        if(calculate_clock(dclk, ref_freq, m1, m2, n, p, MIN_VCO_PASS1,
 
322
                   target_error,port_type,dual_channel)) {
 
323
                if(calculate_clock(dclk, ref_freq, m1, m2, n, p, MIN_VCO_PASS2,
 
324
                           target_error,port_type,dual_channel)) {
 
325
                        /* No usable clock */
 
326
                        OS_ERROR("Could not calculate clock %ld, returning default.",
 
327
                                dclk);
 
328
                        *m1 = 0x14;
 
329
                        *m2 = 0xc;
 
330
                        *n = 0x3;
 
331
                        *p = 0x82;
 
332
                        return 1;
 
333
                }
 
334
        }
 
335
 
 
336
        return 0;
 
337
}
 
338
 
 
339
#define TARGET_ERROR 46
 
340
 
 
341
/*!
 
342
 *
 
343
 * @param display
 
344
 * @param clock
 
345
 * @param dclk
 
346
 *
 
347
 * @return 0 on success
 
348
 * @return 1 on failure
 
349
 */
 
350
int program_clock_plb(igd_display_context_t *display,
 
351
        igd_clock_t *clock,
 
352
        unsigned long dclk)
 
353
{
 
354
        unsigned long m1, m2, n, p;
 
355
        unsigned long control;
 
356
        unsigned long ref_freq;
 
357
        int ret;
 
358
        igd_display_port_t *port;
 
359
        unsigned long port_mult, vga_mult;
 
360
        unsigned long dual_channel = 0;
 
361
        unsigned long index;
 
362
 
 
363
        OS_DEBUG("Enter program_clock");
 
364
 
 
365
        port=PORT_OWNER(display);
 
366
 
 
367
        if (dclk > 100000) {        /*  100-200 MHz     */
 
368
 
 
369
                port_mult = 1;
 
370
        }
 
371
        else if (dclk > 50000) {    /*  50-100 Mhz      */
 
372
 
 
373
                port_mult = 2;
 
374
        }
 
375
        else {                      /*  25-50 Mhz       */
 
376
 
 
377
                port_mult = 4;
 
378
        }
 
379
 
 
380
        /*
 
381
         * Clock Multiplier : sDVO ports on all plb chipsets
 
382
         */
 
383
        if (port->port_type == IGD_PORT_DIGITAL) {
 
384
 
 
385
                dclk *= port_mult;
 
386
        }
 
387
 
 
388
        vga_mult = READ_MMIO_REG(display, clock->dpll_control) & 0x3;
 
389
 
 
390
        /* For Int-LVDS need to find out if its dual channel and pass
 
391
         * that info into caluculating for p2. Apperently halving
 
392
         * of dot-clock is also required by Ch7017 when operating in
 
393
         * dual channel
 
394
         */
 
395
        if (port->port_type == IGD_PORT_LVDS) {
 
396
                /* Find PD_ATTR_ID_2_CHANNEL_PANEL attr value*/
 
397
                pi_pd_find_attr_and_value(PORT_OWNER(display),
 
398
                                PD_ATTR_ID_2_CHANNEL_PANEL,
 
399
                                0/*no PD_FLAG for 2_channel*/,
 
400
                                NULL,
 
401
                                &dual_channel);
 
402
        }
 
403
 
 
404
        /* For external clock sources always use ref_clock == dclk */
 
405
        if(port->pd_flags & PD_FLAG_CLK_SOURCE) {
 
406
                ref_freq = dclk;
 
407
        } else {
 
408
                ref_freq = 96000;
 
409
        }
 
410
        /* LVDS reference clock can be 96 or 100 MHz. However there
 
411
         * are no mention in the specification to specify which register
 
412
         * to select/set this.
 
413
         */
 
414
 
 
415
        /* When the clock source is provided externally by the port driver,
 
416
         * the allowed error range is 0. */
 
417
        if(port->pd_flags & PD_FLAG_CLK_SOURCE) {
 
418
                ret = get_clock(dclk, ref_freq, &m1, &m2, &n, &p, 0
 
419
                                ,port->port_type,dual_channel);
 
420
        } else {
 
421
                ret = get_clock(dclk, ref_freq, &m1, &m2, &n, &p, TARGET_ERROR
 
422
                                ,port->port_type,dual_channel);
 
423
        }
 
424
 
 
425
        if(ret) {
 
426
                OS_ERROR("Clock %ld could not be programmed", dclk);
 
427
                return ret;
 
428
        }
 
429
 
 
430
        /* Disable DPLL, Write an 0x80 into P for saftey */
 
431
        control = 0x10000000 | (0x80<<clock->p_shift) | BIT26 | vga_mult;
 
432
        WRITE_MMIO_REG(display, clock->dpll_control, control);
 
433
 
 
434
        /* Program N, M1,and M2 */
 
435
        WRITE_MMIO_REG(display, clock->mnp, (n<<16) | (m1<<8) | m2);
 
436
 
 
437
        /* Enable DPLL, Disable VGAm Mode and sitck in new P values */
 
438
        if(port->port_type==IGD_PORT_LVDS){
 
439
                /* If LVDS set the appropriate bits for mode select */
 
440
                control = (BIT31 | BIT28 | BIT27 )
 
441
                        | (p<<clock->p_shift) | vga_mult;
 
442
 
 
443
                if(port->attr_list) {
 
444
 
 
445
                        for(index = 0; index < port->attr_list->num_attrs; index++) {
 
446
 
 
447
                                /* Set spread spectrum and pulse phase */
 
448
                                if(port->attr_list->attr[index].id == PD_ATTR_ID_SSC) {
 
449
 
 
450
                                        /*
 
451
                                         * Pulse Phase for Poulsbo only has valid values between
 
452
                                         * 3 and 9
 
453
                                         */
 
454
                                        if(port->attr_list->attr[index].value >= 3 &&
 
455
                                                port->attr_list->attr[index].value <= 9) {
 
456
 
 
457
                                                control |= BIT13 | BIT14;
 
458
                                                /*
 
459
                                                 * Set the Pulse Phase to the clock phase specified by
 
460
                                                 * the user
 
461
                                                 */
 
462
                                                control |= (port->attr_list->attr[index].value<<9);
 
463
                                        }
 
464
                                        break;
 
465
                                }
 
466
                        }
 
467
                }
 
468
        } else{
 
469
        /* else DAC/SDVO */
 
470
                control = (BIT31 | BIT28 | BIT26) | (p<<clock->p_shift) | vga_mult;
 
471
        }
 
472
        /*
 
473
         * Poulsbo has high speed clock on always
 
474
         */
 
475
        control |= BIT30;
 
476
 
 
477
 
 
478
 
 
479
        /* Set the clock source correctly based on PD settings */
 
480
        if(port->pd_flags & PD_FLAG_CLK_SOURCE) {
 
481
                control |= port->clock_bits;
 
482
        } else {
 
483
                control |= port->clock_bits & ~0x00006000;
 
484
        }
 
485
 
 
486
        /* sDVO Multiplier bits[7:0] */
 
487
        if (port->port_type == IGD_PORT_DIGITAL) {
 
488
 
 
489
                if (port_mult == 2) {
 
490
 
 
491
                        control |= (1 << 4);
 
492
 
 
493
                } else if (port_mult == 4) {
 
494
 
 
495
                        control |= (3 << 4);
 
496
                }
 
497
        }
 
498
 
 
499
        WRITE_MMIO_REG(display, clock->dpll_control, control);
 
500
 
 
501
        /* We must wait for 150 us for the dpll clock to warm up */
 
502
        OS_SLEEP(150);
 
503
 
 
504
        return 0;
 
505
}
 
506
 
 
507
/*----------------------------------------------------------------------------
 
508
 * File Revision History
 
509
 * $Id: clocks_plb.c,v 1.3 2010/04/27 20:33:49 bpaauwe Exp $
 
510
 * $Source: /nfs/fm/proj/eia/cvsroot/koheo/linux/egd_drm/emgd/display/mode/plb/clocks_plb.c,v $
 
511
 *----------------------------------------------------------------------------
 
512
 */