2
*-----------------------------------------------------------------------------
3
* Filename: clocks_plb.c
5
*-----------------------------------------------------------------------------
6
* Copyright © 2002-2010, Intel Corporation.
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.
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
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
*-----------------------------------------------------------------------------
23
*-----------------------------------------------------------------------------
26
#define MODULE_NAME hal.mode
45
* @addtogroup display_group
49
/*===========================================================================
51
;--------------------------------------------------------------------------*/
52
typedef struct _fixed_clock {
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}
68
* This function translates from the calculated M value to the M1, M2
75
* @return 0 on success
76
* @return 1 on failure
78
static int calculate_m1_m2(unsigned long m,
82
unsigned long current_m1, current_m2;
84
OS_DEBUG("Enter calculate_m1_m2 %d", 1);
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) {
98
OS_DEBUG("M1, M2 not found for M == %ld", m);
102
#define MAX_M 120 //216
103
#define MIN_M 70 //96
108
#define MAX_P 80 //126
111
#define LVDS_MAX_P 98
114
#define FIX_P2_LO 5 //126
115
#define FIX_P2_HI 10 //2
117
#define MAX_P1 8 //126
120
#define REF_FREQ 96000 //48000
121
#define MAX_VCO 2800000 //1400000
122
#define MAX_FP 200000
124
#define LVDS_FIX_P2_LO 7
125
#define LVDS_FIX_P2_HI 14
136
* @param target_error
138
* @param dual_channel
140
* @return 0 on success
141
* @return 1 on failure
143
static int calculate_clock(unsigned long dclk,
144
unsigned long ref_freq,
149
unsigned long min_vco,
150
unsigned long target_error,
151
unsigned long port_type,
152
unsigned long dual_channel)
158
unsigned long freqmult_p2;
160
/* Intermidiate variables */
162
unsigned long target_vco, actual_freq, actual_vco;
163
long freq_error, min_error;
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;
171
OS_DEBUG("Enter calculate_clock");
176
freqmult_p2 = FIX_P2_LO;
178
freqmult_p2 = FIX_P2_HI;
182
if(port_type==IGD_PORT_LVDS){
183
/* Test if we are dual channel */
185
freqmult_p2=LVDS_FIX_P2_LO;
187
freqmult_p2=LVDS_FIX_P2_HI;
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++) {
196
pdiv = freqmult_p2 * current_p1;
197
target_vco = dclk * pdiv;
199
if ((target_vco <= MAX_VCO) && (target_vco >= min_vco)) {
200
actual_freq = (ref_freq * current_m) /
202
actual_vco = actual_freq * pdiv;
203
freq_error = 10000 - (dclk * 10000 / actual_freq);
205
if (freq_error < 0) {
206
freq_error = -freq_error;
208
if (freq_error < min_error) {
211
best_p1 = current_p1;
212
min_error = freq_error;
214
if (min_error == 0) {
219
if (min_error == 0) {
223
if (min_error == 0) {
228
* No clock found that meets error requirement
230
if (min_error > (long)target_error) {
235
/* Translate M,N,P to m1,m2,n,p register values */
237
if(calculate_m1_m2(best_m, m1, m2)) {
238
/* No M1, M2 match for M */
242
p1 = (1 << (best_p1-1));
243
if((freqmult_p2-5)) {
249
/* Set p2 for LVDS */
250
if(port_type==IGD_PORT_LVDS){
258
*p = ( p1 | (p2<<8) );
263
#define MIN_VCO_PASS1 2000000 //1000000
264
#define MIN_VCO_PASS2 1400000 //930000
274
* @param target_error
276
* @param dual_channel
278
* @return 0 on success
279
* @return 1 on failure
281
static int get_clock(unsigned long dclk,
282
unsigned long ref_freq,
287
unsigned long target_error,
288
unsigned long port_type,
289
unsigned long dual_channel)
291
fixed_clock_t *fixed = fixed_clock_table;
293
OS_DEBUG("Enter get_clock");
296
* First check for a fixed clock from the table. These are ones that
297
* can't be calculated correctly.
299
while(fixed->dclk != 0xffffffff) {
300
if(fixed->dclk == dclk) {
301
OS_DEBUG("Using Fixed Clock From table for clock %ld", dclk);
313
* No fixed clock found so calculate one.
315
OS_DEBUG("Calculating dynamic clock for clock %ld", dclk);
318
* First pass try to find a clock with min_vco at 1000000.
319
* If a clock doesn't come out then try 930000.
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.",
339
#define TARGET_ERROR 46
347
* @return 0 on success
348
* @return 1 on failure
350
int program_clock_plb(igd_display_context_t *display,
354
unsigned long m1, m2, n, p;
355
unsigned long control;
356
unsigned long ref_freq;
358
igd_display_port_t *port;
359
unsigned long port_mult, vga_mult;
360
unsigned long dual_channel = 0;
363
OS_DEBUG("Enter program_clock");
365
port=PORT_OWNER(display);
367
if (dclk > 100000) { /* 100-200 MHz */
371
else if (dclk > 50000) { /* 50-100 Mhz */
375
else { /* 25-50 Mhz */
381
* Clock Multiplier : sDVO ports on all plb chipsets
383
if (port->port_type == IGD_PORT_DIGITAL) {
388
vga_mult = READ_MMIO_REG(display, clock->dpll_control) & 0x3;
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
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*/,
404
/* For external clock sources always use ref_clock == dclk */
405
if(port->pd_flags & PD_FLAG_CLK_SOURCE) {
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.
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);
421
ret = get_clock(dclk, ref_freq, &m1, &m2, &n, &p, TARGET_ERROR
422
,port->port_type,dual_channel);
426
OS_ERROR("Clock %ld could not be programmed", dclk);
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);
434
/* Program N, M1,and M2 */
435
WRITE_MMIO_REG(display, clock->mnp, (n<<16) | (m1<<8) | m2);
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;
443
if(port->attr_list) {
445
for(index = 0; index < port->attr_list->num_attrs; index++) {
447
/* Set spread spectrum and pulse phase */
448
if(port->attr_list->attr[index].id == PD_ATTR_ID_SSC) {
451
* Pulse Phase for Poulsbo only has valid values between
454
if(port->attr_list->attr[index].value >= 3 &&
455
port->attr_list->attr[index].value <= 9) {
457
control |= BIT13 | BIT14;
459
* Set the Pulse Phase to the clock phase specified by
462
control |= (port->attr_list->attr[index].value<<9);
470
control = (BIT31 | BIT28 | BIT26) | (p<<clock->p_shift) | vga_mult;
473
* Poulsbo has high speed clock on always
479
/* Set the clock source correctly based on PD settings */
480
if(port->pd_flags & PD_FLAG_CLK_SOURCE) {
481
control |= port->clock_bits;
483
control |= port->clock_bits & ~0x00006000;
486
/* sDVO Multiplier bits[7:0] */
487
if (port->port_type == IGD_PORT_DIGITAL) {
489
if (port_mult == 2) {
493
} else if (port_mult == 4) {
499
WRITE_MMIO_REG(display, clock->dpll_control, control);
501
/* We must wait for 150 us for the dpll clock to warm up */
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
*----------------------------------------------------------------------------