2
*-----------------------------------------------------------------------------
3
* Filename: clocks_tnc.c
5
*-----------------------------------------------------------------------------
6
* Copyright © 2002-2010, Intel Corporation.
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:
15
* The above copyright notice and this permission notice shall be included in
16
* all copies or substantial portions of the Software.
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
26
*-----------------------------------------------------------------------------
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
*-----------------------------------------------------------------------------
34
#define MODULE_NAME hal.mode
51
#include <tnc/igd_tnc_wa.h> /* needed for vbios for register defines */
55
/* Debug flag to turn off CDVO reset sequence */
56
static int flag_enable_cdvo_reset = 1;
58
/* Turn all workaround for release driver */
63
static void wait_dpll(void);
65
static int program_cdvo(igd_display_context_t *display);
67
static cdvo_regs_t cdvo_reset[] = {
68
/*turn off the SDVO port*/
70
/*turn off the stall register*/
74
/*programmable cdvo stall*/
82
/*strobe data tuning default*/
85
{0x61170, 0x20022160},
87
/* -- Begin Sequence of 3 pixel signal --*/
100
{0x700c, 0x0008B400},
102
{0x700c, 0x0008B4FF},
104
{0x700c, 0x00008000},
105
{0x700c, 0x0008B400},
107
{0x700c, 0x0008B4FF},
109
{0x700c, 0x00008000},
110
{0x700c, 0x0008B400},
112
{0x700c, 0x0008B4FF},
114
{0x700c, 0x00008000},
115
{0x700c, 0x0008B400},
117
{0x700c, 0x0008B4FF},
122
{0x7014, 0x00004800},
123
/*strobe data tuning default*/
124
{0x700c, 0x000BB4FF},
126
{0x61170, 0x20022160},
127
{0x7010, 0x06000200},
128
/* -- Begin Sequence of 3 pixel signal --*/
130
{0x700c, 0x00008000},
131
{0x700c, 0x0008B400},
133
{0x700c, 0x0008B4FF},
135
{0x700c, 0x00008000},
136
{0x700c, 0x0008B400},
138
{0x700c, 0x0008B4FF},
140
{0x700c, 0x00008000},
141
{0x700c, 0x0008B400},
143
{0x700c, 0x0008B4FF},
145
{0x700c, 0x00008000},
146
{0x700c, 0x0008B400},
148
{0x700c, 0x0008B4FF},
150
{0x700c, 0x00008000},
151
{0x700c, 0x0008B400},
153
{0x700c, 0x0008B4FF},
155
{0x700c, 0x00008000},
156
{0x700c, 0x0008B400},
158
{0x700c, 0x0008B4FF},
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*/
180
* @addtogroup display_group
184
/* Enable this if calculated values are wrong and required fixed table */
185
#define CONFIG_FIXED_TABLE 0
189
extern int program_clock_sdvo_tnc(igd_display_context_t *display,
190
igd_clock_t *clock, unsigned long dclk);
192
/*===========================================================================
194
;--------------------------------------------------------------------------*/
195
#if CONFIG_FIXED_TABLE
196
typedef struct _fixed_clock {
203
/* set mmio register required values */
204
static fixed_clock_t lvds_fixed_clock_table[] = {
206
{ 65000, 0x01, 0x00, 0x00 },
207
{ 0xffffffff, 0x01, 0x00, 0x00}
210
/* set mmio register required values */
211
static fixed_clock_t sdvo_fixed_clock_table[] = {
213
{ 65000, 0x00, 0x00, 0x00 },
214
{ 0xffffffff, 0x00, 0x00, 0x00}
218
#define LVDS_M_MIN 10
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,
227
const unsigned long LVDS_M_CONVERTS_LEN=26; /* Length of the array above*/
229
#define TARGET_ERROR 46
231
typedef const struct _tnc_limits {
232
unsigned long ref_freq;
239
unsigned long min_p1;
240
unsigned long max_p1;
242
unsigned long min_p2;
243
unsigned long max_p2;
245
unsigned long min_vco;
246
unsigned long max_vco;
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
254
* VCO range for 100L is not given: so put a range big enough to go through
255
* calculations for the for loop.
257
static tnc_limits_t tnc_lvds_limits[] =
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 */
265
static tnc_limits_t tnc_sdvo_limits[] =
267
/* reffreq m n p1 p2 vco */
268
{ 96000, 80,137, 3, 7, 1, 2, 10, 10, 1400000, 2800000}, /* SDVO */
279
* @param target_error
281
* @return 0 on success
282
* @return 1 on failure
284
static int calculate_clock(unsigned long dclk,
285
unsigned long ref_freq,
290
unsigned long target_error,
291
unsigned long *actual_dclk,
292
unsigned long port_type,
293
unsigned long pd_type)
296
unsigned long target_vco, actual_freq;
297
long freq_error, min_error;
298
unsigned long dclk_10000;
300
unsigned long current_m, current_n, current_p1;
310
/* dclk * 10000, so it does not have to be calculated within the
312
dclk_10000 = dclk * 10000;
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++) {
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;
323
if (target_vco > l->max_vco) {
324
/* target_vco continues to increase, so start with
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);
338
if (freq_error < -min_error) {
339
/* freq_error continues to decrease once this
340
* point is reached, so start with next
345
if (freq_error < 0) {
346
freq_error = -freq_error;
348
if (freq_error < min_error) {
352
min_error = freq_error;
353
*actual_dclk = actual_freq;
358
if (min_error == 0) {
363
if (pd_type == PD_DISPLAY_TVOUT) {
368
* No clock found that meets error requirement
370
if (min_error > (long)target_error) {
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);
391
* @param target_error
395
* @return 0 on success
396
* @return 1 on failure
398
static int get_clock(unsigned long dclk,
399
unsigned long ref_freq,
404
unsigned long target_error,
405
unsigned long port_type,
406
unsigned long *actual_dclk,
407
unsigned long pd_type)
410
#if CONFIG_FIXED_TABLE
411
fixed_clock_t *fixed;
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;
417
fixed = sdvo_fixed_clock_table;
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);
436
/* No fixed clock found so calculate one. */
437
EMGD_DEBUG("Calculating dynamic clock for clock %ld", dclk);
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);
447
if (pd_type == PD_DISPLAY_TVOUT) {
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));
458
*n = (1L << (*n -1));
460
*p1 = (1L << (*p1 - 2));
461
*m = lvds_m_converts[*m - LVDS_M_MIN];
464
EMGD_DEBUG("reg m=%lu n=%lu p1=%lu p2=%lu", *m, *n, *p1, l->min_p2);
476
* @return 0 on success
477
* @return 1 on failure
479
int program_clock_lvds_tnc(igd_display_context_t *display,
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;
493
port = PORT_OWNER(display);
495
/* LNC ref_freq is determined by SKU, convert to KHz */
497
ref_freq = display->context->device_context.gfx_freq * 1000L;
499
ref_freq = display->context->device_context.core_freq;
500
ref_freq = ref_freq * 1000;
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];
514
for(count=0; count<3; count++){
515
if (tnc_lvds_limits[count].ref_freq == ref_freq){
516
l = &tnc_lvds_limits[count];
523
/* WRITE_PORT80(0xED); */
525
if(ref_freq == 166000){
535
/* Per UMG, there is no defined target_error for LVDS, it supposed to
536
* work for all expected dclks. */
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);
541
EMGD_ERROR_EXIT("Clock %ld could not be programmed", dclk);
542
/* DEAD_LOOP(0xFF); */
546
/* Hard code the values for now */
547
m = 0x2D; // ITP uses 0x2E, should change
553
/* If clocks are already running at required clocks, just return */
554
if (PIPE(display)->dclk == dclk) {
561
control = BIT28 | (1<<clock->p_shift); //Why are we shifting 1 to P1, GMA carry over???
565
WRITE_MMIO_REG(display, clock->dpll_control, control);
566
EMGD_DEBUG("lvds: EMGD_WRITE32: 0x%lx = 0x%lx",
567
clock->dpll_control, control);
570
WRITE_MMIO_REG(display, clock->mnp, (m<<8));
572
WRITE_MMIO_REG(display, 0xF044, (m<<8)); //BUGBUG
574
EMGD_DEBUG("lvds: EMGD_WRITE32: 0x%lx = 0x%lx",
578
control = (BIT31 | BIT28 | BIT27) | (p1<<clock->p_shift);
583
if (ref_freq == 166000) {
589
WRITE_MMIO_REG(display, clock->dpll_control, control);
590
EMGD_DEBUG("lvds: EMGD_WRITE32: 0x%lx = 0x%lx",
591
clock->dpll_control, control);
593
/* Wait 150us for the DPLL to stabilize */
595
PIPE(display)->dclk = dclk;
607
* @return 0 on success
608
* @return 1 on failure
610
int program_clock_sdvo_tnc(igd_display_context_t *display,
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;
623
EMGD_DEBUG("Enter program_clock");
625
port = PORT_OWNER(display);
627
/* FIXME: No info available in EAS and waiting for info. */
628
if (dclk > 100000) { /* 100-200 MHz */
630
} else if (dclk > 50000) { /* 50-100 Mhz */
632
} else { /* 25-50 Mhz */
638
l = &tnc_sdvo_limits[0];
639
ref_freq = l->ref_freq;
641
vga_mult = READ_MMIO_REG_TNC(IGD_PORT_SDVO, clock->dpll_control) & 0x3;
643
target_error = TARGET_ERROR;
645
/* For external clock sources always use ref_clock == dclk */
646
if(port->pd_flags & PD_FLAG_CLK_SOURCE) {
648
/* When clock source sdvo device, allowed error is 0. */
652
ret = get_clock(dclk, ref_freq, l, &m, &n, &p1, target_error,
653
IGD_PORT_SDVO, &actual_dclk, port->pd_driver->type);
655
clock->actual_dclk = actual_dclk/port_mult;
658
EMGD_ERROR("Clock %ld could not be programmed", dclk);
662
/* Disable DPLL, Write 2 into P for saftey */
663
control = BIT28 | (2<<clock->p_shift) | vga_mult;
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);
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);
674
/* Enable DPLL, Disable VGA mode and sitck in new P values */
675
control = BIT31 | BIT30 | BIT28 | (p1<<clock->p_shift) | vga_mult;
677
/* Set the clock source correctly based on PD settings */
678
if(port->pd_flags & PD_FLAG_CLK_SOURCE) {
679
control |= port->clock_bits;
682
/* sDVO Multiplier bits[7:0] */
683
if (port_mult == 2) {
685
} else if (port_mult == 3) {
687
} else if (port_mult == 4) {
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);
697
/* We must wait for 150 us for the dpll clock to warm up */
701
program_cdvo(display);
706
int program_clock_tnc(igd_display_context_t *display,
712
if (PORT_TYPE(display) == IGD_PORT_LVDS) {
714
return program_clock_lvds_tnc(display, clock, dclk);
717
return program_clock_sdvo_tnc(display, clock, dclk);
723
* Poll for DPLL register lock. This is only valid for DPLLB
727
static void wait_dpll(void)
735
/* Wait for DPLL lock, about 50 msec (20Hz). */
736
timeout = OS_SET_ALARM(50);
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;
742
/* Check for timeout */
743
} while ((!temp) && (!OS_TEST_ALARM(timeout)));
746
EMGD_ERROR_EXIT("Timeout waiting for pipe enable/disable");
751
/* to save space in VBIOS, we use to old method of waiting for the DPLL
760
/* This is the initialization code for B0 stepping */
761
static int program_cdvo(igd_display_context_t *display)
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
773
if((READ_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7000) == 0x50) ||
774
!FLAG(flag_enable_cdvo_reset)){
781
/* pipe_temp = READ_MMIO_REG_TNC(IGD_PORT_SDVO, PIPE(display)->pipe_reg); */
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);
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 */
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;
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);
803
/* the checking is needed for VBIOS but not needed for driver */
805
WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, cdvo_reset[counter].reg,
806
cdvo_reset[counter].value);
808
}while(cdvo_reset[counter].reg != 0);
810
/* Enable sDVOB port */
811
WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x61140,
812
READ_MMIO_REG_TNC(IGD_PORT_SDVO, 0x61140) | 0xC0000018 );
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
*----------------------------------------------------------------------------