~gma500/+junk/emgd160

« back to all changes in this revision

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

  • 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: micro_mode_tnc.c
 
4
 * $Revision: 1.33 $
 
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
 *-----------------------------------------------------------------------------
 
22
 * Description:
 
23
 *  1) Atom E6xx Core implementations for the mode dispatch functions.
 
24
 *  2) 0:2:0 = Device2 = LNC VGA
 
25
 *  0:3:0 = Device3 = Atom E6xx overlay
 
26
 *  3) For MMIO access:
 
27
 *  Dev2 only: Use EMGD_READ32(), EMGD_WRITE32(): less code
 
28
 *  Dev2/3: Use READ_MMIO_REG_TNC(), WRITE_MMIO_REG_TNC(): more code
 
29
 *  For code optimization sake use the right macro.
 
30
 *-----------------------------------------------------------------------------
 
31
 */
 
32
 
 
33
#define MODULE_NAME hal.mode
 
34
 
 
35
#include <io.h>
 
36
 
 
37
#include <igd.h>
 
38
#include <igd_pwr.h>
 
39
 
 
40
#include <context.h>
 
41
#include <mode.h>
 
42
#include <utils.h>
 
43
#include <dsp.h>
 
44
#include <vga.h>
 
45
#include <intelpci.h>
 
46
#include <math_fix.h>
 
47
#include <mode_access.h>
 
48
#include <rb.h>
 
49
#include <pi.h>
 
50
#include <dispatch.h>
 
51
 
 
52
#include <tnc/regs.h>
 
53
#include <tnc/context.h>
 
54
#include <tnc/mi.h>
 
55
#include <tnc/instr.h>
 
56
#include <tnc/igd_tnc_wa.h>
 
57
 
 
58
#include "../cmn/match.h"
 
59
#include "../cmn/mode_dispatch.h"
 
60
 
 
61
/* 
 
62
        Turning on FIB part workaround for all IALs, for vBIOS this will limit
 
63
    the port drivers to one at a time (SDVO or LVDS)due to code size
 
64
 */
 
65
 
 
66
/*!
 
67
 * @addtogroup display_group
 
68
 * @{
 
69
 */
 
70
 
 
71
/*
 
72
 * Exports from the other components of this module.
 
73
 */
 
74
 
 
75
#ifdef CONFIG_TNC
 
76
 
 
77
extern int program_clock_tnc(igd_display_context_t *display,
 
78
        igd_clock_t *clock, unsigned long dclk);
 
79
 
 
80
extern mode_full_dispatch_t mode_full_dispatch_tnc;
 
81
 
 
82
int wait_for_vblank_tnc(unsigned long pipe_reg);
 
83
static void wait_pipe(unsigned long pipe_reg, unsigned long check_on_off);
 
84
 
 
85
#if 0
 
86
static void cdvo_signal(void);
 
87
#endif
 
88
 
 
89
typedef struct _mode_data_tnc {
 
90
        unsigned long plane_a_preserve;
 
91
        unsigned long plane_b_c_preserve;
 
92
        unsigned long pipe_preserve;
 
93
        unsigned long dsp_arb;
 
94
        unsigned long fifo_watermark1;
 
95
        unsigned long fifo_watermark2;
 
96
        unsigned long fifo_watermark3;
 
97
        unsigned long fifo_watermark4;
 
98
        unsigned long fifo_watermark5;
 
99
        unsigned long fifo_watermark6;
 
100
} mode_data_tnc_t;
 
101
 
 
102
static mode_data_tnc_t device_data[1] = {
 
103
        {
 
104
                0x000b0000, /* plane a preservation */
 
105
                0x00000000, /* plane b c preservation */
 
106
                0x60000000, /* pipe preservation */
 
107
                0x00003232, /* DSP FIFO Size A=50 B=50 C=28 May require fine tuning*/
 
108
                0x3f8f0404, /* FIFO watermark control1 */
 
109
                0x04040f04, /* FIFO watermark control2 */
 
110
                0x00000000, /* FIFO watermark control3 */
 
111
                0x04040404, /* FIFO watermark1 control4 */
 
112
                0x04040404, /* FIFO watermark1 control5 */
 
113
                0x00000078, /* FIFO watermark1 control6 */
 
114
        }
 
115
};
 
116
 
 
117
/* Do not change the order */
 
118
static const unsigned long ports_tnc[2] = {IGD_PORT_LVDS, IGD_PORT_SDVO};
 
119
 
 
120
/* Extern defines for Device2, device3 and device31 iobases.
 
121
 * For Atom E6xx all devices are always io_mapped. */
 
122
extern unsigned char io_mapped;
 
123
extern unsigned short io_base;
 
124
extern unsigned char io_mapped_lvds;
 
125
extern unsigned short io_base_lvds;
 
126
extern unsigned char io_mapped_sdvo;
 
127
extern unsigned short io_base_sdvo;
 
128
extern unsigned char io_mapped_lpc;
 
129
extern unsigned short io_base_lpc;
 
130
 
 
131
static tnc_wa_timing_t tune = {0, 0, 0, 0, 0, 0, 0,};
 
132
 
 
133
#ifndef CONFIG_MICRO
 
134
#define CHECK_VGA(a) MODE_IS_VGA(a)
 
135
#ifdef DEBUG_BUILD_TYPE 
 
136
#define FLAG(a) a
 
137
/* Debug configuration flag for B0 workaround. Workaround is turned on by default */
 
138
static int flag_turn_off_port_wa = 1;                   /* Turn off port when sweeping */
 
139
static int flag_enable_tuning_wa = 1;                   /* Disable sweeping flag */
 
140
static int flag_basic_htotal_formula_wa = 1;    /* Enable formula workaround flag */
 
141
#else
 
142
/* Turn all workaround for release driver */
 
143
#define FLAG(a) 1
 
144
#endif
 
145
 
 
146
/* VPhase variable */
 
147
static int vphase = 0;                                                  /* The current value to enable  vphase is 5 */
 
148
 
 
149
/* Temporary frame buffer */
 
150
static igd_framebuffer_info_t fb_info_tmp = {0,0,0,0,0,0,0};
 
151
 
 
152
#else
 
153
#define CHECK_VGA(a) 1
 
154
#endif
 
155
 
 
156
pixel_crc_t compute_pixel_crc( pixel_crc_t  pixel, pixel_crc_t  new_pixel)
 
157
{
 
158
        pixel_crc_t  pixel_crc_new;
 
159
 
 
160
    pixel_crc_new.pixel = 0x0;
 
161
 
 
162
    pixel_crc_new.bit.bit22 = pixel.bit.bit14;
 
163
    pixel_crc_new.bit.bit21 = pixel.bit.bit13;
 
164
    pixel_crc_new.bit.bit20 = pixel.bit.bit12;
 
165
    pixel_crc_new.bit.bit19 = pixel.bit.bit11;
 
166
    pixel_crc_new.bit.bit18 = pixel.bit.bit10;
 
167
    pixel_crc_new.bit.bit17 = pixel.bit.bit9;
 
168
    pixel_crc_new.bit.bit16 = pixel.bit.bit22 ^ pixel.bit.bit8;
 
169
    pixel_crc_new.bit.bit15 = pixel.bit.bit21 ^ pixel.bit.bit7;
 
170
    pixel_crc_new.bit.bit14 = pixel.bit.bit20 ^ pixel.bit.bit6;
 
171
    pixel_crc_new.bit.bit13 = pixel.bit.bit19 ^ pixel.bit.bit5;
 
172
    pixel_crc_new.bit.bit12 = pixel.bit.bit18 ^ pixel.bit.bit4;
 
173
    pixel_crc_new.bit.bit11 = pixel.bit.bit17 ^ pixel.bit.bit3;
 
174
    pixel_crc_new.bit.bit10 = pixel.bit.bit16 ^ pixel.bit.bit2;
 
175
    pixel_crc_new.bit.bit9  = pixel.bit.bit15 ^ pixel.bit.bit1;
 
176
    pixel_crc_new.bit.bit8  = pixel.bit.bit0;
 
177
    pixel_crc_new.bit.bit7  = pixel.bit.bit22 ^ new_pixel.bit.bit0;
 
178
    pixel_crc_new.bit.bit6  = pixel.bit.bit21 ^ new_pixel.bit.bit1;
 
179
    pixel_crc_new.bit.bit5  = pixel.bit.bit20 ^ new_pixel.bit.bit2;
 
180
    pixel_crc_new.bit.bit4  = pixel.bit.bit19 ^ new_pixel.bit.bit3;
 
181
    pixel_crc_new.bit.bit3  = pixel.bit.bit18 ^ new_pixel.bit.bit4;
 
182
    pixel_crc_new.bit.bit2  = pixel.bit.bit17 ^ new_pixel.bit.bit5;
 
183
    pixel_crc_new.bit.bit1  = pixel.bit.bit16 ^ new_pixel.bit.bit6;
 
184
    pixel_crc_new.bit.bit0  = pixel.bit.bit15 ^ new_pixel.bit.bit7;
 
185
 
 
186
        return (pixel_crc_new);
 
187
}
 
188
 
 
189
#ifndef CONFIG_MICRO
 
190
int check_display_tnc(igd_display_context_t *display,
 
191
                                          unsigned short port_number,unsigned long status)
 
192
{
 
193
        pixel_crc_t red_val, green_val, blue_val;
 
194
        pixel_crc_t blue_crc, green_crc, red_crc;
 
195
        int i, j, bps = 4, ret_val = 0;
 
196
        unsigned long *curr_pixel, sync = 0, size = 0, dc;
 
197
        unsigned long tnc_crc_red, tnc_crc_green, tnc_crc_blue, temp;
 
198
        unsigned long temp_plane, temp_pitch, temp_control, plane_control;
 
199
        unsigned long pt = PORT_TYPE(display);
 
200
        igd_framebuffer_info_t *fb_info = PLANE(display)->fb_info;
 
201
        igd_timing_info_t pTimings_tmp, *pTimings_ext,*pTimings = PIPE(display)->timing;
 
202
        /* igd_display_port_t *port = PORT_OWNER(display); */
 
203
        igd_rect_t dst_rect;
 
204
        igd_surface_t front_buffer;
 
205
        tnc_wa_timing_t *wa = WA_TUNE;
 
206
        os_alarm_t timeout;
 
207
 
 
208
        EMGD_TRACE_ENTER;
 
209
 
 
210
        dc = *(display->context->mod_dispatch.dsp_current_dc);
 
211
        pTimings_tmp = *pTimings;
 
212
        pTimings_ext = pTimings;
 
213
 
 
214
        /* Check to see if VGA plane was requested */
 
215
        while (pTimings_ext->extn_ptr) {
 
216
                pTimings_ext = (igd_timing_info_t *)pTimings_ext->extn_ptr;
 
217
        }
 
218
        if((pt != IGD_PORT_SDVO) || (display->context->device_context.rid != TNC_B0_RID)
 
219
                || (pTimings->reserved_dd & TNC_HTOTAL_TUNED) || (!FLAG(flag_enable_tuning_wa))
 
220
                || (mode_context->tuning_wa == 0) /*if 0 don't tune*/
 
221
                || wa->counter > LIMIT_TOTAL_CHECK_DISPLAY
 
222
                || (MODE_IS_VGA(pTimings_ext))
 
223
                || (!IGD_DC_CLONE(dc) && !IGD_DC_EXTENDED(dc))){
 
224
                /* Workaround is specific for SDVO display
 
225
                 * Dont tuned if it isnt B0 silicon
 
226
                 * Dont tuned if it is already tuned
 
227
                 * Dont tuned if bypass is turned on (debug)
 
228
                 * No tuning for VGA modes
 
229
                 * Stop Tuning if above limit LIMIT_TOTAL_CHECK_DISPLAY
 
230
                 */
 
231
                if(pt != IGD_PORT_SDVO ||
 
232
                        (MODE_IS_VGA(pTimings_ext))){
 
233
                        EMGD_DEBUG("Unsupported tuning");
 
234
                }else if((wa->counter > LIMIT_TOTAL_CHECK_DISPLAY) &&
 
235
                        !(pTimings->reserved_dd & TNC_HTOTAL_TUNED)){
 
236
                        pTimings->reserved_dd = 0;
 
237
                        EMGD_ERROR("Unable to get tuned value!");
 
238
                }
 
239
 
 
240
                if(FLAG(flag_turn_off_port_wa)){
 
241
                        /* Turn on SDVO source */
 
242
                        temp = READ_MMIO_REG_TNC(IGD_PORT_SDVO, SDVO_BUFF_CTRL_REG);
 
243
                        temp |= BIT13;
 
244
                        WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, SDVO_BUFF_CTRL_REG, temp);
 
245
                }
 
246
                
 
247
                if(fb_info_tmp.width){
 
248
                        /* Free up the temporary frame buffer */
 
249
                        display->context->dispatch.gmm_free(fb_info_tmp.fb_base_offset);
 
250
                        OS_MEMSET(&fb_info_tmp,0,sizeof (igd_framebuffer_info_t));
 
251
                }
 
252
                OS_MEMSET(wa, 0, sizeof(tnc_wa_timing_t));
 
253
                EMGD_TRACE_EXIT;
 
254
                return TRUE;
 
255
        }
 
256
 
 
257
        /* Increment checking counter */
 
258
        wa->counter++;
 
259
 
 
260
        /* CRC starting value */
 
261
        blue_crc.pixel = 0x007FFFFF;
 
262
        green_crc.pixel = 0x007FFFFF;
 
263
        red_crc.pixel = 0x007FFFFF;
 
264
 
 
265
        if(FLAG(flag_turn_off_port_wa)){
 
266
                /* Turn of port source.
 
267
                 * */
 
268
                temp = READ_MMIO_REG_TNC(IGD_PORT_SDVO, SDVO_BUFF_CTRL_REG);
 
269
                temp &= ~BIT13;
 
270
                WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, SDVO_BUFF_CTRL_REG, temp);
 
271
        }
 
272
 
 
273
        /* Allocate temporary 32 bpp frame buffer for CRC calculation.
 
274
         * SV only provided codes for 32bpp CRC calculation so we would
 
275
         * only calculate CRC for 32bpp. Once CRC is calculated EMGD
 
276
         * would revert back to original plane. A temporary place is also
 
277
         * neede so no corruption is seen on lvds for clone display
 
278
         */
 
279
        if(fb_info_tmp.width != (unsigned short)pTimings_tmp.width &&
 
280
                fb_info_tmp.height != (unsigned short)pTimings_tmp.height){
 
281
                if(fb_info_tmp.width){
 
282
                        EMGD_ERROR("Memory leak! Previous framebuffer is not freed!");
 
283
                }
 
284
                fb_info_tmp.width  = pTimings_tmp.width;
 
285
                fb_info_tmp.height = pTimings_tmp.height;
 
286
                fb_info_tmp.screen_pitch  = fb_info->screen_pitch;
 
287
                fb_info_tmp.fb_base_offset = 0;
 
288
                fb_info_tmp.pixel_format = IGD_PF_xRGB32;
 
289
                fb_info_tmp.flags = IGD_SURFACE_DISPLAY | IGD_SURFACE_RENDER;
 
290
 
 
291
                ret_val = display->context->dispatch.gmm_alloc_surface(
 
292
                                &fb_info_tmp.fb_base_offset,
 
293
                                fb_info_tmp.pixel_format,
 
294
                                &fb_info_tmp.width,
 
295
                                &fb_info_tmp.height,
 
296
                                &fb_info_tmp.screen_pitch,
 
297
                                &size,
 
298
                                IGD_GMM_ALLOC_TYPE_NORMAL,
 
299
                                &fb_info_tmp.flags);
 
300
        }
 
301
        /* Temp plane is always 32 bpp */
 
302
        temp_control = EMGD_READ32(MMIO(display)
 
303
                + PLANE(display)->plane_reg);
 
304
        plane_control = temp_control;
 
305
        plane_control &= ~(BIT30 | BIT29 | BIT28 | BIT27);
 
306
        plane_control |= BIT28 | BIT27; 
 
307
        EMGD_WRITE32(plane_control, MMIO(display)
 
308
                + PLANE(display)->plane_reg);
 
309
        temp_pitch = EMGD_READ32(MMIO(display)
 
310
                + PLANE(display)->plane_reg + DSP_STRIDE_OFFSET);
 
311
        EMGD_WRITE32(fb_info_tmp.screen_pitch, MMIO(display)
 
312
                + PLANE(display)->plane_reg + DSP_STRIDE_OFFSET);
 
313
        temp_plane = EMGD_READ32(MMIO(display)
 
314
                + PLANE(display)->plane_reg + DSP_START_OFFSET);
 
315
        EMGD_WRITE32(fb_info_tmp.fb_base_offset,
 
316
                MMIO(display) + PLANE(display)->plane_reg + DSP_START_OFFSET);
 
317
        /* Setup front buffer */
 
318
        OS_MEMSET(&front_buffer,0,sizeof (igd_surface_t));
 
319
        front_buffer.width  = fb_info_tmp.width;
 
320
        front_buffer.height = fb_info_tmp.height;
 
321
        front_buffer.pitch  = fb_info_tmp.screen_pitch;
 
322
        front_buffer.offset = fb_info_tmp.fb_base_offset;
 
323
        front_buffer.pixel_format = fb_info_tmp.pixel_format;
 
324
        front_buffer.flags = fb_info_tmp.flags;
 
325
        /* Draw 2 color bars for CRC calculation. This is simple and sufficient
 
326
         * to detect clipping. Will consider complicated color bar if an issue
 
327
         * is found for now go for quickest methodColor bar. Red and Blue */
 
328
        dst_rect.x1 = dst_rect.y1 = 0;
 
329
        dst_rect.x2 = fb_info_tmp.width/2;
 
330
        dst_rect.y2 = fb_info_tmp.height;
 
331
        
 
332
        /*
 
333
        // NOT supported in koheo, using software for now       
 
334
        display->context->dispatch.color_blt((igd_display_h)display,
 
335
                                IGD_PRIORITY_NORMAL,
 
336
                                &front_buffer,
 
337
                                &dst_rect,
 
338
                                IGD_ALPHA_CHANNEL | IGD_RGB_CHANNEL,
 
339
                                0x00FF0000,
 
340
                                0xF0,
 
341
                                (igd_appcontext_h)0, IGD_RENDER_BLOCK);
 
342
        */
 
343
 
 
344
        {
 
345
                unsigned long row, col;
 
346
                unsigned char *buf = NULL;
 
347
                unsigned long height = fb_info_tmp.height;
 
348
                unsigned long width = fb_info_tmp.width/2;
 
349
                unsigned long pitch = fb_info_tmp.screen_pitch; 
 
350
 
 
351
                buf = display->context->dispatch.gmm_map(fb_info_tmp.fb_base_offset);
 
352
                for (row = 0; row < (height); row++) {
 
353
                        for (col = 0; col < (width); col++) {
 
354
                                EMGD_WRITE32(0x00FF0000, (buf + (col*4)));
 
355
                        }
 
356
                        buf = buf + pitch;
 
357
                }       
 
358
                display->context->dispatch.gmm_unmap(buf);
 
359
        }
 
360
 
 
361
        dst_rect.x1 = fb_info_tmp.width/2;
 
362
        dst_rect.y1 = 0;
 
363
        dst_rect.x2 = fb_info_tmp.width;
 
364
        dst_rect.y2 = fb_info_tmp.height;
 
365
 
 
366
        /*
 
367
        // NOT supported in koheo, using software for now       
 
368
        display->context->dispatch.color_blt((igd_display_h)display,
 
369
                                IGD_PRIORITY_NORMAL,
 
370
                                &front_buffer,
 
371
                                &dst_rect,
 
372
                                IGD_ALPHA_CHANNEL | IGD_RGB_CHANNEL,
 
373
                                0x000000FF,
 
374
                                0xF0,
 
375
                                (igd_appcontext_h)0, IGD_RENDER_BLOCK);
 
376
                wa->flag |= TNC_HTOTAL_TUNED;
 
377
                pTimings->reserved_dd = (wa->htotal | TNC_HTOTAL_TUNED);
 
378
                return FALSE;
 
379
        
 
380
        display->context->dispatch.sync((igd_display_h)display, IGD_PRIORITY_NORMAL,
 
381
                &sync,
 
382
                IGD_SYNC_NONBLOCK);
 
383
        */
 
384
 
 
385
        {
 
386
                unsigned long row, col;
 
387
                unsigned char *buf = NULL;
 
388
                unsigned long height = fb_info_tmp.height;
 
389
                unsigned long width = fb_info_tmp.width;
 
390
                unsigned long pitch = fb_info_tmp.screen_pitch;
 
391
 
 
392
                buf = display->context->dispatch.gmm_map(fb_info_tmp.fb_base_offset);
 
393
                for (row = 0; row < (height); row++) {
 
394
                        for (col = fb_info_tmp.width/2; col < (width); col++) {
 
395
                                EMGD_WRITE32(0x000000FF, (buf + (col*4)));
 
396
                        }
 
397
                        buf = buf + pitch;
 
398
                }       
 
399
                display->context->dispatch.gmm_unmap(buf);
 
400
        }
 
401
 
 
402
 
 
403
        ret_val = -IGD_ERROR_BUSY;
 
404
        timeout = OS_SET_ALARM(500);
 
405
        while (-IGD_ERROR_BUSY == ret_val && (!OS_TEST_ALARM(timeout))){
 
406
                ret_val = display->context->dispatch.sync(
 
407
                        (igd_display_h)display,
 
408
                        IGD_PRIORITY_NORMAL,
 
409
                        &sync,
 
410
                        IGD_SYNC_BLOCK);
 
411
                OS_SCHEDULE();
 
412
                if (0 == ret_val) {
 
413
                        break;
 
414
                }
 
415
        }
 
416
 
 
417
        /* Turn on HW CRC */
 
418
        WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, SDVO_CRC_CTRL_REG, 0x80000000);
 
419
        /* Reset Status Bit */
 
420
        temp = READ_MMIO_REG_TNC(IGD_PORT_LVDS, 0x71024);
 
421
        temp |= 0x00001000;
 
422
        WRITE_MMIO_REG_TNC(IGD_PORT_LVDS, 0x71024, temp);
 
423
        temp = READ_MMIO_REG_TNC(IGD_PORT_SDVO, 0x71024);
 
424
        temp |= 0x00001000;
 
425
        WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x71024, temp);
 
426
 
 
427
        /* Calculate CRC pixel by reading every single pixel.
 
428
         * Pixel that is more than the timing range is ignore which happens
 
429
         * during panning. To save time CRC is only calculated once per timing
 
430
         * change and kept inside a scratch global variable wa.
 
431
         */
 
432
        if(wa->crc_red == 0 || wa->crc_green == 0 ||
 
433
                wa->crc_blue == 0 ){
 
434
                unsigned char *fb_adr;  
 
435
 
 
436
                fb_adr = display->context->dispatch.gmm_map(fb_info_tmp.fb_base_offset);
 
437
                
 
438
                /* Calculate CRC for this timing */
 
439
                for(i=0; i<(int)pTimings_tmp.height; i++){
 
440
                        for(j=0; j<(int)pTimings_tmp.width; j++){
 
441
                                if(i < (int)fb_info_tmp.height && j < (int)fb_info_tmp.width){
 
442
                                        /* virt_fb_adr not available anymore    */
 
443
                                        /*
 
444
                                        curr_pixel = (unsigned long*)(
 
445
                                                mode_context->context->device_context.virt_fb_adr +
 
446
                                                fb_info_tmp.fb_base_offset + j*bps + (i*fb_info_tmp.screen_pitch));
 
447
                                        */
 
448
 
 
449
                                        curr_pixel = (unsigned long*)(fb_adr + (j*bps) + (i*fb_info_tmp.screen_pitch)); 
 
450
                                                                        
 
451
                                        if(curr_pixel == NULL){
 
452
                                                EMGD_DEBUG("FB not valid return true for now util FB is allocated");
 
453
                                                return TRUE;
 
454
                                        }
 
455
 
 
456
                                        
 
457
 
 
458
                                        /*
 
459
                                        blue_val.pixel =  (0x0000ff & *curr_pixel) >> 0;
 
460
                                        green_val.pixel = (0x00ff00 & *curr_pixel) >> 8;
 
461
                                        red_val.pixel = (0xff0000 & *curr_pixel) >> 16;
 
462
                                        */
 
463
 
 
464
                                        blue_val.pixel =  (0x0000ff & EMGD_READ32(curr_pixel)) >> 0;
 
465
                                        green_val.pixel = (0x00ff00 & EMGD_READ32(curr_pixel)) >> 8;
 
466
                                        red_val.pixel = (0xff0000 & EMGD_READ32(curr_pixel)) >> 16;
 
467
 
 
468
                                }else{
 
469
                                        red_val.pixel = green_val.pixel = blue_val.pixel = 0;
 
470
                                }
 
471
 
 
472
                                blue_crc = compute_pixel_crc(blue_crc, blue_val);
 
473
                                green_crc = compute_pixel_crc(green_crc, green_val);
 
474
                                red_crc = compute_pixel_crc(red_crc, red_val);
 
475
                        }
 
476
                }
 
477
                display->context->dispatch.gmm_unmap(fb_adr);
 
478
                                
 
479
                /* Save calculated value */
 
480
                wa->crc_red = red_crc.pixel;
 
481
                wa->crc_green = green_crc.pixel;
 
482
                wa->crc_blue = blue_crc.pixel;
 
483
        }else{
 
484
                /* Reuse CRC value calculated before */
 
485
                red_crc.pixel = wa->crc_red;
 
486
                green_crc.pixel = wa->crc_green;
 
487
                blue_crc.pixel = wa->crc_blue;
 
488
        }
 
489
 
 
490
        timeout = OS_SET_ALARM(70);
 
491
        do {
 
492
                temp = READ_MMIO_REG_TNC(IGD_PORT_SDVO, 0x71024);
 
493
                if(temp & 0x00002000){
 
494
                        break;
 
495
                }
 
496
                OS_SCHEDULE();
 
497
        } while ((!OS_TEST_ALARM(timeout)));
 
498
        /* Give some time for CRC to be stable */
 
499
        OS_SLEEP(500);
 
500
        /* Read CRC on LNC and OVL */
 
501
        tnc_crc_red = READ_MMIO_REG_TNC(IGD_PORT_SDVO,0x61060);
 
502
        tnc_crc_green = READ_MMIO_REG_TNC(IGD_PORT_SDVO,0x61064);
 
503
        tnc_crc_blue = READ_MMIO_REG_TNC(IGD_PORT_SDVO,0x61068);
 
504
        
 
505
        /* Revert back to original plane */
 
506
        EMGD_WRITE32(temp_control, MMIO(display)
 
507
                + PLANE(display)->plane_reg);
 
508
        EMGD_WRITE32(temp_pitch, MMIO(display)
 
509
                + PLANE(display)->plane_reg + DSP_STRIDE_OFFSET);
 
510
        EMGD_WRITE32(temp_plane, MMIO(display)
 
511
                + PLANE(display)->plane_reg + DSP_START_OFFSET);
 
512
 
 
513
        /* Turn off CRC */
 
514
        WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, SDVO_CRC_CTRL_REG, 0x00000000);
 
515
        /* Compare CRC calculation with Atom E6xx CRC, return false if a mismatch and
 
516
         * tuning continues. If it matches indicate the flag as tuned and return
 
517
         * false anyway so pipe programming would program based on the correct
 
518
         * timing spec.
 
519
         */
 
520
        if((red_crc.pixel != (unsigned int)tnc_crc_red) ||
 
521
                (green_crc.pixel != (unsigned int)tnc_crc_green) ||
 
522
                (blue_crc.pixel != (unsigned int)tnc_crc_blue)){
 
523
                
 
524
                        /* Step by step tuning */
 
525
                wa->delta = 1;
 
526
 
 
527
                /* Calculate the delta value */
 
528
                wa->htotal = (wa->htotal + wa->delta);
 
529
 
 
530
                EMGD_DEBUG("Counter %d",wa->counter);
 
531
                EMGD_DEBUG("Red CRC: %d Red TNC: %lu",red_crc.pixel,tnc_crc_red);
 
532
                EMGD_DEBUG("Grn CRC: %d Grn TNC: %lu",green_crc.pixel,tnc_crc_green);
 
533
                EMGD_DEBUG("Blu CRC: %d Blu TNC: %lu",blue_crc.pixel,tnc_crc_blue);
 
534
                EMGD_DEBUG("CRC does not match, tuning....");
 
535
                EMGD_TRACE_EXIT;
 
536
                return FALSE;
 
537
        }
 
538
        EMGD_ERROR("Tuned value found.");
 
539
        EMGD_ERROR("Total tuning required %d",wa->counter);
 
540
        EMGD_DEBUG("Red CRC: %d Red TNC: %lu",red_crc.pixel,tnc_crc_red);
 
541
        EMGD_DEBUG("Grn CRC: %d Grn TNC: %lu",green_crc.pixel,tnc_crc_green);
 
542
        EMGD_DEBUG("Blu CRC: %d Blu TNC: %lu",blue_crc.pixel,tnc_crc_blue);
 
543
        wa->flag |= TNC_HTOTAL_TUNED;
 
544
        pTimings->reserved_dd = (wa->htotal | TNC_HTOTAL_TUNED);
 
545
 
 
546
        EMGD_TRACE_EXIT;
 
547
        /* We are tuned but lets do another sequence since we may have changed
 
548
         * the blanks to get a valid CRC. This happens on certain modes that has
 
549
         * weird blanks value like VESA's 640x480@60
 
550
         */
 
551
        return FALSE;
 
552
}
 
553
#endif
 
554
 
 
555
#if 0
 
556
/* Setting the CDVO Signal */
 
557
static void cdvo_signal()
 
558
{
 
559
        // Low
 
560
        WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x700c, 0x00008000);
 
561
        WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x700c, 0x0008B400);
 
562
 
 
563
        OS_SLEEP(25);
 
564
 
 
565
        // High
 
566
        WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x700c, 0x0008B4FF);
 
567
        OS_SLEEP(25);
 
568
}
 
569
#endif
 
570
 
 
571
#if 0
 
572
/* disable this function now */
 
573
/* This is the initialization code for B0 stepping */
 
574
void program_cdvo(igd_display_context_t *display, unsigned long pipe_reg)
 
575
{
 
576
        /* unsigned long pipe_conf; */
 
577
        int i;
 
578
 
 
579
        EMGD_TRACE_ENTER;
 
580
 
 
581
        //if(READ_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7000) != 0x50){
 
582
 
 
583
                //programmable cdvo stall
 
584
                        WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x6102c, 0xf);
 
585
                WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7000, 0x40);
 
586
 
 
587
                //reset
 
588
                WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7000, 0x51);
 
589
                WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7000, 0x50);
 
590
 
 
591
                // High
 
592
                WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7014, 0x00004800);
 
593
                WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x700c, 0x000BB4FF);
 
594
                WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, SDVO_BUFF_CTRL_REG, 0x20022160);
 
595
                WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7010, 0x06000200);
 
596
 
 
597
                /* loop 3 pixels, 6 calls to cdvo_signal() */
 
598
                for(i=0;i<6;i++){
 
599
                        cdvo_signal();
 
600
                }
 
601
 
 
602
                //reset
 
603
                WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7000, 0x51);
 
604
                WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7000, 0x50);
 
605
 
 
606
                // High
 
607
                WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7014, 0x00004800);
 
608
                WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x700c, 0x000BB4FF);
 
609
                WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, SDVO_BUFF_CTRL_REG, 0x20022160);
 
610
                WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7010, 0x06000200);
 
611
 
 
612
                /* loop 3 pixels, 6 calls to cdvo_signal() */
 
613
                for(i=0;i<6;i++){
 
614
                        cdvo_signal();
 
615
                }
 
616
 
 
617
                //reset
 
618
                WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7000, 0x51);
 
619
                WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7000, 0x50);
 
620
 
 
621
                WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7010, 0x02000200);
 
622
                WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7014, 0x00004000);
 
623
                WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, SDVO_BUFF_CTRL_REG, 0x20022160);
 
624
                        WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7010, 0x02000200);
 
625
                        WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7014, 0x00000800);
 
626
                        WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7014, 0x00004800);
 
627
                        WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7014, 0x00000000);
 
628
                WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7000, 0x50);
 
629
 
 
630
                        WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7014, 0x00004000);
 
631
 
 
632
                WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, SDVO_BUFF_CTRL_REG, 0x20022160);//enable sdvo
 
633
 
 
634
                //WRITE_MMIO_REG_TNC(IGD_PORT_LVDS, 0x70400, 0x4088);//enable sdvo
 
635
        //}
 
636
 
 
637
        EMGD_TRACE_EXIT;
 
638
}
 
639
#endif
 
640
 
 
641
/*!
 
642
 *
 
643
 * @param mmio dev2 mmio
 
644
 *
 
645
 * @return void
 
646
 */
 
647
static void disable_vga_tnc (unsigned char *mmio)
 
648
{
 
649
        unsigned long temp;
 
650
        unsigned char sr01;
 
651
 
 
652
        EMGD_TRACE_ENTER;
 
653
 
 
654
        /* Disable VGA plane if it is enabled. */
 
655
        temp = EMGD_READ32(EMGD_MMIO(mmio) + VGACNTRL);
 
656
        if ((temp & BIT31) == 0) {
 
657
                /* Read SR01 */
 
658
                READ_VGA(mmio, SR_PORT, SR01, sr01);
 
659
 
 
660
                /* Turn on SR01 bit 5 */
 
661
                WRITE_VGA(mmio, SR_PORT, SR01, sr01|BIT(5));
 
662
 
 
663
                /* Wait for 30us */
 
664
                OS_SLEEP(30);
 
665
 
 
666
                temp |= BIT31;     /* set bit 31 to disable */
 
667
                temp &= ~BIT30;    /* clear bit 30 to get VGA display in normal size */
 
668
                EMGD_WRITE32(temp, EMGD_MMIO(mmio) + VGACNTRL);
 
669
 
 
670
        }
 
671
 
 
672
        EMGD_TRACE_EXIT;
 
673
}
 
674
 
 
675
/*!
 
676
 *
 
677
 * @param display_handle
 
678
 * @param palette_entry
 
679
 * @param palette_color
 
680
 *
 
681
 * @return 0 on success
 
682
 * @return -IGD_INVAL on failure
 
683
 */
 
684
int igd_set_palette_entry_tnc(
 
685
        igd_display_h display_handle,
 
686
        unsigned long palette_entry,
 
687
        unsigned long palette_color)
 
688
{
 
689
        /* Return if Pipe is not on */
 
690
        if(!((1L<<31) & READ_MMIO_REG_TNC(PORT_TYPE_DH(display_handle),
 
691
                        PIPE(display_handle)->pipe_reg))) {
 
692
                return -IGD_INVAL;
 
693
        }
 
694
        /* Palette can is only on 0:2:0 so use _TNC IGD_PORT_LVDS */
 
695
        WRITE_MMIO_REG_TNC(IGD_PORT_LVDS,
 
696
                PIPE(display_handle)->palette_reg + palette_entry * 4,
 
697
                palette_color);
 
698
 
 
699
        return 0;
 
700
}
 
701
 
 
702
/*!
 
703
 *
 
704
 * @param display_handle
 
705
 * @param palette_entry
 
706
 * @param palette_color
 
707
 *
 
708
 * @return 0 on success
 
709
 * @return -IGD_INVAL on failure
 
710
 */
 
711
int igd_get_palette_entry_tnc(
 
712
        igd_display_h display_handle,
 
713
        unsigned long palette_entry,
 
714
        unsigned long *palette_color)
 
715
{
 
716
        /* Return if Pipe is not on */
 
717
        if(!((1L<<31) & READ_MMIO_REG_TNC(
 
718
                        PORT_TYPE_DH(display_handle),
 
719
                        PIPE(display_handle)->pipe_reg))) {
 
720
                return -IGD_INVAL;
 
721
        }
 
722
        /* Palette can is only on 0:2:0 so use _TNC IGD_PORT_LVDS */
 
723
        *palette_color = 0xffffff & READ_MMIO_REG_TNC(
 
724
                IGD_PORT_LVDS,
 
725
                PIPE(display_handle)->palette_reg + palette_entry * 4);
 
726
        return 0;
 
727
}
 
728
 
 
729
/*!
 
730
 *
 
731
 * @param mmio
 
732
 * @param pipe_reg
 
733
 *
 
734
 * @return 0 on success
 
735
 * @return 1 on failure
 
736
 */
 
737
int wait_for_vblank_tnc(unsigned long pipe_reg)
 
738
{
 
739
        unsigned long pipe_status_reg = pipe_reg + PIPE_STATUS_OFFSET;
 
740
        unsigned long tmp;
 
741
        unsigned long port_type = IGD_PORT_LVDS;
 
742
        os_alarm_t timeout;
 
743
        int ret;
 
744
        unsigned long request_for;
 
745
 
 
746
        EMGD_TRACE_ENTER;
 
747
 
 
748
        EMGD_DEBUG("Parameter: pipe_reg = %lx", pipe_reg);
 
749
 
 
750
        /* If pipe is off then just return */
 
751
        if(!((1L<<31) & READ_MMIO_REG_TNC(port_type, pipe_reg))) {
 
752
                EMGD_DEBUG("Pipe disabled/Off");
 
753
                EMGD_TRACE_EXIT;
 
754
                return 1;
 
755
        }
 
756
 
 
757
        /*
 
758
         * When VGA plane is on the normal wait for vblank won't work
 
759
         * so just skip it. VGA plane is on 0:2:0 so no need to use _TNC macros.
 
760
         */
 
761
        if(!(EMGD_READ32(MMIO_TNC(port_type) + 0x71400) & 0x80000000)) {
 
762
                EMGD_DEBUG("VGA Plane On");
 
763
                EMGD_TRACE_EXIT;
 
764
                return 1;
 
765
        }
 
766
 
 
767
        /* 1. Request the interrupt handler to record the next VBlank: */
 
768
        request_for = VBINT_REQUEST(VBINT_WAIT,
 
769
                (pipe_status_reg == PIPEA_STAT) ? VBINT_PORT2 : VBINT_PORT4);
 
770
        mode_context->dispatch->full->request_vblanks(request_for,
 
771
                MMIO_TNC(port_type));
 
772
 
 
773
        /* 2. Wait (about 50 msec, 20Hz) & poll for the next VBlank: */
 
774
        timeout = OS_SET_ALARM(50);
 
775
        do {
 
776
                OS_SCHEDULE();
 
777
                tmp = mode_context->dispatch->full->vblank_occured(request_for);
 
778
        } while ((tmp == 0x00) && (!OS_TEST_ALARM(timeout)));
 
779
        if (tmp == 0) {
 
780
                EMGD_ERROR_EXIT("Timeout waiting for VBLANK");
 
781
                ret = 0;
 
782
        } else {
 
783
                ret = 1;
 
784
        }
 
785
 
 
786
        /* 3. End our request for the next VBlank: */
 
787
        mode_context->dispatch->full->end_request(request_for,
 
788
                MMIO_TNC(port_type));
 
789
 
 
790
 
 
791
        EMGD_TRACE_EXIT;
 
792
        return ret;
 
793
} /* wait_for_vblank_tnc */
 
794
 
 
795
/*!
 
796
 * This procedure waits for the next vertical blanking (vertical retrace)
 
797
 * period. If the display is already in a vertical blanking period, this
 
798
 * procedure exits.
 
799
 *
 
800
 * Note: A timeout is included to prevent an endless loop.
 
801
 *
 
802
 * @param display_handle
 
803
 *
 
804
 * @return FALSE if timed out
 
805
 */
 
806
int igd_wait_vblank_tnc(igd_display_h display_handle)
 
807
{
 
808
 
 
809
        return wait_for_vblank_tnc(PIPE(display_handle)->pipe_reg);
 
810
 
 
811
}
 
812
 
 
813
/*!
 
814
 * Get the stride and stereo values based on the display.  This is also used
 
815
 * by the MI instructions.
 
816
 *
 
817
 * @param display Pointer to hardware device instance data
 
818
 * @param flags Should the stereo be for the frontbuffer or backbuffer?
 
819
 *
 
820
 * @return stride - Stride of the display
 
821
 * @return stereo - Stereo address of the display
 
822
 */
 
823
int mode_get_stride_stereo_tnc(igd_display_context_t *display,
 
824
        unsigned long *stride,
 
825
        unsigned long *stereo,
 
826
        unsigned long flags)
 
827
{
 
828
        unsigned long pitch = PLANE(display)->fb_info->screen_pitch;
 
829
        igd_timing_info_t *timing = PIPE(display)->timing;
 
830
        unsigned long base_offset;
 
831
 
 
832
        EMGD_TRACE_ENTER;
 
833
 
 
834
        base_offset = PLANE(display)->fb_info->visible_offset;
 
835
        *stride = pitch;
 
836
        *stereo = 0;
 
837
 
 
838
        /* For field replication, valid for interlaced modes only
 
839
         *     set stereo = fb_base
 
840
         *         stride = pitch
 
841
         */
 
842
        if (timing->mode_info_flags & IGD_SCAN_INTERLACE) {
 
843
 
 
844
                if(timing->mode_info_flags & IGD_LINE_DOUBLE) {
 
845
                        /* Interlaced + Line double flags means field replication.
 
846
                         * same lines are sent for both fields. Program the
 
847
                         * second eye to be same as the first
 
848
                         */
 
849
                        *stereo = base_offset;
 
850
                } else {
 
851
                        /* Regular interlaced. Second eye starts on line 2.
 
852
                         * Skip every other line.
 
853
                         */
 
854
                        *stereo = base_offset + pitch;
 
855
                        *stride = pitch * 2;
 
856
                }
 
857
        }
 
858
 
 
859
        EMGD_TRACE_EXIT;
 
860
        return 0;
 
861
}
 
862
 
 
863
/*
 
864
 * Atom E6xx LVDS display: Mode switch sequence
 
865
 *
 
866
 * 1. Enable sequence
 
867
 *
 
868
 * Program power on delay, power off delay, power cycle delay registers
 
869
 * Program backlight control register to set appropriate backlight value
 
870
 * Pipe A must be completely off at this point
 
871
 * Write PIPEACONF bits[19:18] = 00
 
872
 * Write DSPACNTR bit[31] = 1
 
873
 * Write DSPASURF = 0x00000000
 
874
 * Write DSPACNTR bit[31] = 0
 
875
 * Write DSPASURF = 0x00000000
 
876
 * Restore PIPEACONF bits[19:18]  to original value
 
877
 * Program DPLL
 
878
 * Enable DPLL
 
879
 * Wait for DPLL warm up 10us and check for DPLL lock bit in Pipe A config reg
 
880
 * (Wait ensures clock is running smoothly before enabling pipe)
 
881
 * Program pipe timings (Can be done before DPLL programming)
 
882
 * Enable panel fitter as needed (Can be done before DPLL and/or
 
883
 *     pipe timing programming)
 
884
 * Enable pipe
 
885
 * Enable planes (VGA or HiRes)
 
886
 * Enable ports
 
887
 * Enable panel power (Can be done before DPLL programming)
 
888
 *
 
889
 * 2. Disable sequence
 
890
 *
 
891
 * Disable panel backlight
 
892
 * Disable panel power (for AOAC standby)
 
893
 * Disable ports
 
894
 * Disable planes (VGA or hires)
 
895
 * Disable pipe
 
896
 * Disable VGA display in 0x71400 bit 31
 
897
 * (Disable VGA display done after disable pipe to allow pipe to turn off
 
898
 *     when no vblank is available in native VGA mode)
 
899
 * Wait for pipe off status
 
900
 * (Wait ensures planes and pipe have completely turned off prior to
 
901
 *     disabling panelfitter then DPLL)
 
902
 * Disable panelfitter
 
903
 * Disable DPLL
 
904
 * Pipe timings change or change between VGA native or VGA center/upperleft
 
905
 *     or HiRes
 
906
 * Use complete disable sequence followed by complete enable sequence with
 
907
 *     new mode programmings.
 
908
 *
 
909
 *
 
910
 * Atom E6xx SDVO display: Display Pipe B Enable/Disable sequence:
 
911
 *
 
912
 * 1. Enable sequence
 
913
 *
 
914
 * Program LNC and LNW DPLL
 
915
 * Write all planes, port, power control registers on both LNC and LNW
 
916
 * 1st Enable LNC pipe
 
917
 * 2nd Enable LNW pipe
 
918
 *
 
919
 * 2. Disable Sequence
 
920
 *
 
921
 * Disable panel power
 
922
 * Disable ports
 
923
 * Disable planes
 
924
 * 1st Disable LNC pipe
 
925
 * 2nd Disable TNC_SDVO pipe
 
926
 * Disable panel fitter
 
927
 * Disable DPLL
 
928
 */
 
929
 
 
930
/*!
 
931
 *
 
932
 * @param display Pointer to hardware device instance data
 
933
 *
 
934
 * @return void
 
935
 */
 
936
void program_pipe_vga_tnc(
 
937
        igd_display_context_t *display)
 
938
{
 
939
        igd_timing_info_t *timing;
 
940
        unsigned long vga_control;
 
941
        unsigned long upscale = 0;
 
942
        int centering = 1;
 
943
 
 
944
        EMGD_TRACE_ENTER;
 
945
 
 
946
        /*
 
947
         * VGA Plane can attach to only one pipe at a time. LVDS can
 
948
         * only attach to pipe B. We need to use the display passed to
 
949
         * determine the pipe number to use. (Napa is same as Alm).
 
950
         */
 
951
 
 
952
        /*
 
953
         * We can come here with following cases:
 
954
         *   1. magic->vga    CRT, DVI type displays
 
955
         *   2. native->vga   int-lvds, and up-scaling lvds displays
 
956
         *   3. pipe->vga     TV and other unscaled-lvds displays
 
957
         */
 
958
        vga_control = EMGD_READ32(MMIO(display) + 0x71400);
 
959
        vga_control &= 0x18e3ff00;
 
960
        vga_control |= 0x8e;
 
961
 
 
962
        timing = PIPE(display)->timing;
 
963
        if(!timing->extn_ptr) {
 
964
                EMGD_ERROR_EXIT("No Extension pointer in program_pipe_vga_tnc");
 
965
                return;
 
966
        }
 
967
 
 
968
        /* Find UPSCALING attr value*/
 
969
        pi_pd_find_attr_and_value(PORT_OWNER(display),
 
970
                        PD_ATTR_ID_PANEL_FIT,
 
971
                        0,/*no PD_FLAG for UPSCALING */
 
972
                        NULL, /* dont need the attr ptr*/
 
973
                        &upscale);
 
974
        /* this PI func will not modify value of upscale if attr does not exist */
 
975
 
 
976
        /* magic->vga || native->vga cases, centering isn't required */
 
977
        if ((timing->width == 720 && timing->height == 400) || upscale) {
 
978
                EMGD_DEBUG("Centering = 0");
 
979
                centering = 0;
 
980
        }
 
981
 
 
982
        /* Enable border */
 
983
        if((timing->width >= 800) && !upscale) {
 
984
                EMGD_DEBUG("Enable VGA Border");
 
985
                vga_control |= (1L<<26);
 
986
        }
 
987
 
 
988
        if(timing->width == 640) {
 
989
                EMGD_DEBUG("Enable Nine Dot Disable");
 
990
                vga_control |= (1L<<18);
 
991
        }
 
992
 
 
993
        if(centering) {
 
994
                EMGD_DEBUG("Enable VGA Center Centering");
 
995
                vga_control |= 1L<<24;
 
996
 
 
997
                if(timing->height >= 960) {
 
998
                        if(timing->width >= 1280) {
 
999
                                EMGD_DEBUG("Enable VGA 2x (Nine Dot Disable)");
 
1000
                                vga_control |= (1L<<30) | (1L<<18);
 
1001
                        }
 
1002
                }
 
1003
        } else {
 
1004
                if(PORT_OWNER(display)->port_type == IGD_PORT_LVDS) {
 
1005
                        EMGD_DEBUG("Enable VGA Upper-Left Centering & Nine Dot Disable");
 
1006
                        vga_control |= (1L<<25 | (1L<<18));
 
1007
                } else if (upscale) {
 
1008
                        EMGD_DEBUG("Enable VGA Center Upper-left for upscale ports");
 
1009
                        vga_control |= 1L<<25;
 
1010
                }
 
1011
        }
 
1012
 
 
1013
        if(PIPE(display)->pipe_num) {
 
1014
                vga_control |= 1L<<29;
 
1015
        }
 
1016
 
 
1017
        program_pipe_vga(display, (igd_timing_info_t *)timing->extn_ptr);
 
1018
        EMGD_WRITE32(vga_control, MMIO(display) + 0x71400);
 
1019
 
 
1020
        EMGD_TRACE_EXIT;
 
1021
        return;
 
1022
}
 
1023
 
 
1024
/*!
 
1025
 * Program Display Plane Values.
 
1026
 *
 
1027
 * @param display Pointer to hardware device instance data
 
1028
 * @param status
 
1029
 *
 
1030
 * @return void
 
1031
 */
 
1032
void program_plane_tnc(igd_display_context_t *display,
 
1033
        unsigned long status)
 
1034
{
 
1035
        unsigned long stride;
 
1036
        unsigned long stereo;
 
1037
        unsigned long plane_control;
 
1038
        unsigned long other_plane_reg;
 
1039
        igd_timing_info_t *timing;
 
1040
        igd_framebuffer_info_t *fb_info = PLANE(display)->fb_info;
 
1041
        unsigned long plane_reg = PLANE(display)->plane_reg;
 
1042
        igd_timing_info_t *pipe_timing;
 
1043
        /* tnc_wa_timing_t *wa = WA_TUNE; */
 
1044
 
 
1045
        EMGD_TRACE_ENTER;
 
1046
 
 
1047
        EMGD_DEBUG("Program Plane: %s", status?"ENABLE":"DISABLE");
 
1048
        EMGD_DEBUG("Device power state: D%ld", GET_DEVICE_POWER_STATE(display));
 
1049
 
 
1050
        igd_wait_vblank_tnc((igd_display_h)display);
 
1051
 
 
1052
        plane_control = EMGD_READ32(MMIO(display) + plane_reg);
 
1053
        if(PLANE(display)->plane_reg == DSPACNTR) {
 
1054
                plane_control &= device_data->plane_a_preserve;
 
1055
        } else { /* if it's plane b or plane c */
 
1056
                plane_control &= device_data->plane_b_c_preserve;
 
1057
        }
 
1058
 
 
1059
        /* TODO: Bspec: For EagleLake this Trickle Feed must always disable */
 
1060
 
 
1061
        if((status == FALSE) ||
 
1062
                (GET_DEVICE_POWER_STATE(display) != IGD_POWERSTATE_D0)) {
 
1063
 
 
1064
                /*
 
1065
                 * Note: The vga programming code does not have an "off". So
 
1066
                 * when programming the plane to off we make sure VGA is off
 
1067
                 * as well.
 
1068
                 */
 
1069
                disable_vga_tnc(MMIO(display));
 
1070
 
 
1071
                /*
 
1072
                 * To turn off plane A or B, the program have to triger the plane A or B
 
1073
                 * start register.  Or else, it will not work.
 
1074
                 */
 
1075
                EMGD_WRITE32(plane_control, MMIO(display) + plane_reg);
 
1076
                EMGD_WRITE32(EMGD_READ32(MMIO(display) + plane_reg + DSP_START_OFFSET),
 
1077
                        MMIO(display) + plane_reg + DSP_START_OFFSET);
 
1078
 
 
1079
                igd_wait_vblank_tnc((igd_display_h)display);
 
1080
                EMGD_TRACE_EXIT;
 
1081
                return;
 
1082
        }
 
1083
        /*
 
1084
         * Note: The very first pass through this function will be with
 
1085
         * status false and timings == NULL. Don't use the timings before
 
1086
         * the check above.
 
1087
         */
 
1088
        timing = PIPE(display)->timing;
 
1089
        pipe_timing = timing;
 
1090
        /* There is a special case code for legacy VGA modes */
 
1091
        while (timing->extn_ptr) {
 
1092
                timing = (igd_timing_info_t *)timing->extn_ptr;
 
1093
        }
 
1094
        if(MODE_IS_VGA(timing) && CHECK_VGA(pipe_timing)) {
 
1095
                program_plane_vga(display, timing);
 
1096
                EMGD_TRACE_EXIT;
 
1097
                return;
 
1098
        }
 
1099
 
 
1100
        disable_vga_tnc(MMIO(display));
 
1101
 
 
1102
        /* enable plane, select pipe, enable gamma correction logic */
 
1103
        plane_control |= 0x80000000 | (PIPE(display)->pipe_num<<24);
 
1104
        PIPE(display)->plane = PLANE(display);
 
1105
#ifndef CONFIG_MICRO
 
1106
        plane_control |= (1<<30);
 
1107
#endif
 
1108
 
 
1109
        /* Here the settings:
 
1110
         *   If line + pixel dbling, set 21,20 to 01b, and set Horz Multiply
 
1111
         *   If line dbling only,    set 21,20 to 11b
 
1112
         *   If pixel dbling only,   set 21,20 to 00b, but set Horz Multiply
 
1113
         *   If no doubling,         set 21,20 to 00b (no Horz Multiply)
 
1114
         * For pixel doubling
 
1115
         *           --> both progressive/interlaced modes
 
1116
         * For Line doubling
 
1117
         *           --> progressive modes only
 
1118
         */
 
1119
 
 
1120
        if (!(timing->mode_info_flags & IGD_SCAN_INTERLACE)) {
 
1121
                /* Line doubling in progressive mode requires special bits */
 
1122
                if (timing->mode_info_flags & IGD_LINE_DOUBLE) {
 
1123
                        /* BIT 20 for line & pixel doubling*/
 
1124
                        plane_control |= BIT20;
 
1125
                        /* check later, if no pixel doubling, set bit 21 too*/
 
1126
                }
 
1127
        }
 
1128
        if (timing->mode_info_flags & IGD_PIXEL_DOUBLE) {
 
1129
                /* For line ONLY doubling, set bit 21 also '1' */
 
1130
                plane_control |= BIT21;
 
1131
        }
 
1132
 
 
1133
        mode_get_stride_stereo_tnc(display, &stride, &stereo, 0);
 
1134
 
 
1135
        /* set color depth */
 
1136
        switch (IGD_PF_DEPTH(fb_info->pixel_format)) {
 
1137
        case PF_DEPTH_8:
 
1138
                plane_control |= BIT27 | BIT30;
 
1139
                break;
 
1140
        case PF_DEPTH_16:
 
1141
                plane_control |= BIT28 | BIT26;
 
1142
                break;
 
1143
        default:
 
1144
        case PF_DEPTH_32:
 
1145
                plane_control |= BIT28 | BIT27;
 
1146
                break;
 
1147
        }
 
1148
 
 
1149
        if(fb_info->flags & IGD_ENABLE_DISPLAY_GAMMA) {
 
1150
                plane_control |= (BIT30);
 
1151
        }
 
1152
 
 
1153
        if(fb_info->flags & IGD_SURFACE_TILED) {
 
1154
                plane_control |= (BIT10);
 
1155
        }
 
1156
 
 
1157
        /* Set watermark for Atom E6xx */
 
1158
#ifndef  CONFIG_MICRO
 
1159
 
 
1160
        if (plane_reg == DSPACNTR) {
 
1161
                other_plane_reg = DSPBCNTR;
 
1162
        } else {
 
1163
                other_plane_reg = DSPACNTR;
 
1164
        }
 
1165
 
 
1166
        if (EMGD_READ32(MMIO(display) + other_plane_reg) & 0x80000000) {
 
1167
                EMGD_WRITE32(device_data->dsp_arb, MMIO(display) + DSP_ARB);
 
1168
        } else if (plane_reg == DSPACNTR) {
 
1169
                EMGD_WRITE32(0x00003fff, MMIO(display) + DSP_ARB);
 
1170
        } else {
 
1171
                EMGD_WRITE32(0x00003f80, MMIO(display) + DSP_ARB);
 
1172
        }
 
1173
 
 
1174
        EMGD_WRITE32(device_data->fifo_watermark1, MMIO(display) + FW_1);
 
1175
        EMGD_WRITE32(device_data->fifo_watermark2, MMIO(display) + FW_2);
 
1176
        EMGD_WRITE32(device_data->fifo_watermark3, MMIO(display) + FW_3);
 
1177
        EMGD_WRITE32(device_data->fifo_watermark4, MMIO(display) + FW_4);
 
1178
        EMGD_WRITE32(device_data->fifo_watermark5, MMIO(display) + FW_5);
 
1179
        EMGD_WRITE32(device_data->fifo_watermark6, MMIO(display) + FW_6);
 
1180
 
 
1181
#else
 
1182
        /* ITP Script is doing this and so go ahead */
 
1183
        /* The DSP_ARB set fixed the issue with 32bit vesa modes */
 
1184
        EMGD_WRITE32(0x00001FBF, MMIO(display) + DSP_ARB);
 
1185
        EMGD_WRITE32(0x3F8F0F18, MMIO(display) + FW_1);
 
1186
#endif
 
1187
        /* FIXME: Not required for TNC.
 
1188
         * The B-Spec states that rendering will be slower if the fences are not
 
1189
         * a power of 2.  So for now, always use a power of 2. */
 
1190
        /* EMGD_WRITE32(0x04000400, MMIO(display) + 0x209c); */
 
1191
 
 
1192
        EMGD_DEBUG(" Plane Control: 0x%lx", plane_control);
 
1193
        EMGD_DEBUG(" Plane Base:    0x%lx", fb_info->visible_offset);
 
1194
        EMGD_DEBUG(" Plane Pitch:   0x%lx", stride);
 
1195
 
 
1196
        EMGD_WRITE32(plane_control, MMIO(display) + plane_reg);
 
1197
        EMGD_WRITE32(stride, MMIO(display) + plane_reg + DSP_STRIDE_OFFSET);
 
1198
        /* Both of these registers are Reserved on Gen4 */
 
1199
        /*EMGD_WRITE32(size, MMIO(display) + plane_reg + DSP_SIZE_OFFSET);*/
 
1200
        /*EMGD_WRITE32(stereo, MMIO(display) + plane_reg + DSP_STEREO_OFFSET);*/
 
1201
        EMGD_WRITE32(0, MMIO(display) + plane_reg + DSP_LINEAR_OFFSET);
 
1202
        EMGD_WRITE32(0, MMIO(display) + plane_reg + 0x24);
 
1203
        EMGD_WRITE32(fb_info->visible_offset,
 
1204
                MMIO(display) + plane_reg + DSP_START_OFFSET);
 
1205
 
 
1206
        igd_wait_vblank_tnc((igd_display_h)display);
 
1207
 
 
1208
        EMGD_TRACE_EXIT;
 
1209
}
 
1210
 
 
1211
/*!
 
1212
 * PGen4 can check when the pipe is enabled or disabled.
 
1213
 * This function waits for the pipe to be enabled or disabled.
 
1214
 * check_on_off = 0 to wait for the pipe to disable.
 
1215
 * check_on_off = 0x40000000 to wait for the pipe to enable.
 
1216
 *
 
1217
 * @param mmio
 
1218
 * @param pipe_reg
 
1219
 * @param check_on_off
 
1220
 *
 
1221
 * @return void
 
1222
 */
 
1223
static void wait_pipe(unsigned long pipe_reg, unsigned long check_on_off)
 
1224
{
 
1225
        unsigned long temp;
 
1226
        os_alarm_t timeout;
 
1227
 
 
1228
        EMGD_TRACE_ENTER;
 
1229
 
 
1230
        /* 0:3:0 doesn't wait pipe, only LNC device does. */
 
1231
        if (pipe_reg == 0x71008) {
 
1232
                return;
 
1233
        }
 
1234
 
 
1235
        /* Wait for Pipe enable/disable, about 50 msec (20Hz). */
 
1236
        timeout = OS_SET_ALARM(50);
 
1237
        do {
 
1238
                OS_SCHEDULE();
 
1239
                temp = EMGD_READ32(MMIO_TNC(IGD_PORT_LVDS) + pipe_reg) & 0x40000000;
 
1240
                /* Check for timeout */
 
1241
        } while ((temp != check_on_off) && (!OS_TEST_ALARM(timeout)));
 
1242
 
 
1243
        if (temp != check_on_off) {
 
1244
                EMGD_ERROR_EXIT("Timeout waiting for pipe enable/disable");
 
1245
        }
 
1246
 
 
1247
        EMGD_TRACE_EXIT;
 
1248
        return;
 
1249
}
 
1250
 
 
1251
/*!
 
1252
 * This function programs the Timing registers and clock registers and
 
1253
 * other control registers for PIPE.
 
1254
 *
 
1255
 * @param display
 
1256
 * @param status
 
1257
 *
 
1258
 * @return void
 
1259
 */
 
1260
void program_pipe_tnc(igd_display_context_t *display,
 
1261
        unsigned long status)
 
1262
{
 
1263
        unsigned long   timing_reg;
 
1264
        unsigned long   pipe_conf;
 
1265
        unsigned long   hactive, vactive;
 
1266
        igd_timing_info_t  *pTimings;
 
1267
        igd_timing_info_t  pTimings_tmp;
 
1268
        igd_display_port_t *port;
 
1269
        unsigned long temp;
 
1270
        unsigned long pt = PORT_TYPE(display);
 
1271
        unsigned long dc;
 
1272
        unsigned long calc;
 
1273
        short hactive_tmp, vactive_tmp;
 
1274
        int i;
 
1275
        tnc_wa_timing_t *wa;
 
1276
        /* igd_framebuffer_info_t *fb_info = PLANE(display)->fb_info; */
 
1277
 
 
1278
        EMGD_TRACE_ENTER;
 
1279
 
 
1280
        EMGD_DEBUG("Program Pipe: %s", status?"ENABLE":"DISABLE");
 
1281
        EMGD_DEBUG("Device power state: D%ld", GET_DEVICE_POWER_STATE(display));
 
1282
 
 
1283
        pipe_conf = device_data->pipe_preserve &
 
1284
                READ_MMIO_REG_TNC(pt, PIPE(display)->pipe_reg);
 
1285
 
 
1286
        if((status == FALSE) ||
 
1287
                (GET_DEVICE_POWER_STATE(display) == IGD_POWERSTATE_D3)) {
 
1288
                /* For SDVO disable both pipe Bs in 0:2:0 and 0:3:0 */
 
1289
                if (pt == IGD_PORT_SDVO) {
 
1290
                        WRITE_MMIO_REG_TNC(IGD_PORT_LVDS, PIPE(display)->pipe_reg,
 
1291
                                pipe_conf & (~0x80000000L));
 
1292
                }
 
1293
                /* Disable pipe */
 
1294
                WRITE_MMIO_REG_TNC(pt, PIPE(display)->pipe_reg,
 
1295
                        pipe_conf & (~0x80000000L));
 
1296
 
 
1297
                /* check when the pipe is disabled. */
 
1298
                wait_pipe(PIPE(display)->pipe_reg, 0);
 
1299
 
 
1300
                /* Disable DPLL */
 
1301
                //WRITE_MMIO_REG_TNC(pt, PIPE(display)->clock_reg->dpll_control,
 
1302
                //      READ_MMIO_REG_TNC(pt,
 
1303
                //              PIPE(display)->clock_reg->dpll_control) & ~0x80000000L);
 
1304
 
 
1305
                EMGD_TRACE_EXIT;
 
1306
                return;
 
1307
        }
 
1308
 
 
1309
 
 
1310
        port = PORT_OWNER(display);
 
1311
        pTimings = PIPE(display)->timing;
 
1312
 
 
1313
        {
 
1314
                /* Debug messages */
 
1315
                pd_timing_t *vga_timing = (pd_timing_t *)pTimings->extn_ptr;
 
1316
                EMGD_DEBUG("pTimings %ux%u mode_number = %u mode_info_flags = 0x%lx, dclk = %lu",
 
1317
                        pTimings->width,
 
1318
                        pTimings->height,
 
1319
                        pTimings->mode_number,
 
1320
                        pTimings->mode_info_flags,
 
1321
                        pTimings->dclk);
 
1322
                if (vga_timing) {
 
1323
                        EMGD_DEBUG("ext_timing %ux%u mode_number = %u mode_info_flags= 0x%lx, dclk = %lu",
 
1324
                                vga_timing->width,
 
1325
                                vga_timing->height,
 
1326
                                vga_timing->mode_number,
 
1327
                                vga_timing->mode_info_flags,
 
1328
                                vga_timing->dclk);
 
1329
                }
 
1330
        }
 
1331
 
 
1332
        /*
 
1333
         * If the mode is VGA and the PD says it handles all VGA modes without
 
1334
         * reprogramming then just set the mode and leave centering off.
 
1335
         */
 
1336
        if(pTimings->mode_info_flags & IGD_MODE_VESA) {
 
1337
                        EMGD_DEBUG("IGD_MODE_VESA");
 
1338
                if (pTimings->mode_number <= VGA_MODE_NUM_MAX) {
 
1339
                        /* Pipe timings and clocks no longer need to be set since
 
1340
                         * the VGA timings will be used.
 
1341
                        WRITE_MMIO_REG_TNC(pt, PIPE(display)->pipe_reg,
 
1342
                                pipe_conf | 0x80000000); */
 
1343
 
 
1344
                        /* Gen4 can check when the pipe is enabled. No longer needed
 
1345
                         * since pipe not enabled and VGA timings are used.
 
1346
                        wait_pipe(PIPE(display)->pipe_reg, 0x40000000);*/
 
1347
 
 
1348
                        EMGD_DEBUG("pTimings->mode_number <= VGA_MODE_NUM_MAX");
 
1349
                        program_pipe_vga_tnc(display);
 
1350
                        EMGD_TRACE_EXIT;
 
1351
                        return;
 
1352
                } else {
 
1353
#ifdef CONFIG_MICRO
 
1354
                        set_256_palette(
 
1355
                                MMIO_TNC(PORT(display, display->port_number)->port_type));
 
1356
#endif
 
1357
                }
 
1358
        }
 
1359
 
 
1360
        /* Program dot clock divisors. */
 
1361
        program_clock_tnc(display, PIPE(display)->clock_reg, pTimings->dclk);
 
1362
 
 
1363
        /* Program timing registers for the pipe */
 
1364
        timing_reg = PIPE(display)->timing_reg;
 
1365
        if (pTimings->mode_info_flags & IGD_PIXEL_DOUBLE) {
 
1366
                hactive = (unsigned long)pTimings->width*2 - 1;
 
1367
        } else {
 
1368
                hactive = (unsigned long)pTimings->width - 1;
 
1369
        }
 
1370
 
 
1371
        if (pTimings->mode_info_flags & IGD_LINE_DOUBLE) {
 
1372
                vactive = (unsigned long)pTimings->height*2 - 1;
 
1373
        } else {
 
1374
                /* For Atom E6xx Hardware will automatically divide by 2 to
 
1375
                   get the number of line in each field */
 
1376
                vactive = (unsigned long)pTimings->height - 1;
 
1377
        }
 
1378
 
 
1379
#ifndef CONFIG_MICRO
 
1380
        /* reset the palette */
 
1381
        for (i = 0; i < 256; i++) {
 
1382
                WRITE_MMIO_REG_TNC(IGD_PORT_LVDS, PIPE(display)->palette_reg,
 
1383
                        ((i<<16) | (i<<8) | i));
 
1384
        }
 
1385
 
 
1386
 
 
1387
        /* apply color correction */
 
1388
        for( i = 0; PD_ATTR_LIST_END != port->attributes[i].id; i++ ) {
 
1389
 
 
1390
                if ((PD_ATTR_ID_FB_GAMMA      == (port->attributes[i].id)) ||
 
1391
                        (PD_ATTR_ID_FB_BRIGHTNESS == (port->attributes[i].id)) ||
 
1392
                        (PD_ATTR_ID_FB_BRIGHTNESS == (port->attributes[i].id)))  {
 
1393
 
 
1394
                        mode_context->dispatch->full->set_color_correct(display);
 
1395
                }
 
1396
        }
 
1397
#endif
 
1398
 
 
1399
        /*
 
1400
         * NOTE: For size reasons the timng table contains unsigned short
 
1401
         * values. Don't shift them past 16. Use a temp instead.
 
1402
         * All register offsets and bit shift are verified for Gen4
 
1403
         *
 
1404
         * For SDVO display:
 
1405
         * Write values into pipe B registers in both 0:2:0 and 0:3:0
 
1406
         */
 
1407
 
 
1408
        dc = *(display->context->mod_dispatch.dsp_current_dc);
 
1409
 
 
1410
        wa = WA_TUNE;
 
1411
 
 
1412
        for (i=0; i<2; i++) {
 
1413
                /* Temp variable */
 
1414
                pTimings_tmp = *pTimings;
 
1415
                hactive_tmp = (short) hactive;
 
1416
                vactive_tmp = (short) vactive;
 
1417
#ifndef CONFIG_MICRO 
 
1418
                /* Clone and Exteded not Supported in VBIOS for TNC                             
 
1419
                 * This work around is only for Atom E6xx B0
 
1420
                 */
 
1421
                if((IGD_DC_CLONE(dc) || IGD_DC_EXTENDED(dc))
 
1422
                        && pt == IGD_PORT_SDVO && (display->context->device_context.rid == TNC_B0_RID)
 
1423
                        && FLAG(flag_basic_htotal_formula_wa)){
 
1424
                        
 
1425
                        if(!(pTimings->reserved_dd & TNC_HTOTAL_TUNED)){
 
1426
                                /* Modify blanks so it always begin after active pixel and ends at the
 
1427
                                 * end. Do not change it if we are already tuned to maintain
 
1428
                                 * original timing specification
 
1429
                                 */
 
1430
                                pTimings_tmp.hblank_start = (short) (pTimings->width - 1);
 
1431
                                pTimings_tmp.vblank_start = (short) (pTimings->height - 1);
 
1432
                                pTimings_tmp.hblank_end = (short) (pTimings->htotal);
 
1433
                                pTimings_tmp.vblank_end = (short) (pTimings->vtotal);
 
1434
                        }
 
1435
 
 
1436
                        if(i==0){
 
1437
                                if(pTimings->reserved_dd == 0 || (wa->counter > LIMIT_TOTAL_CHECK_DISPLAY)){
 
1438
                                        /* First time tuning */
 
1439
                                        if ((mode_context->ref_freq != 0) && 
 
1440
                                                        (mode_context->ref_freq >= 190000) && 
 
1441
                                                        (mode_context->ref_freq <= 210000)){
 
1442
                                                calc = (pTimings->htotal * mode_context->ref_freq);
 
1443
                                        } else {
 
1444
                                                calc = (pTimings->htotal * LNC_CLOCK);
 
1445
                                        }
 
1446
 
 
1447
                                        calc = (calc / (PIPE(display)->clock_reg->actual_dclk));
 
1448
                                        calc *= (pTimings->vtotal -1);
 
1449
                                        calc /= pTimings->vtotal;
 
1450
                                        pTimings_tmp.htotal = (short)calc;
 
1451
                                        pTimings->reserved_dd = wa->htotal = pTimings_tmp.htotal;
 
1452
                                        EMGD_DEBUG("Delta = %d", wa->htotal);
 
1453
                                }else if (pTimings->reserved_dd & TNC_HTOTAL_TUNED){
 
1454
                                        pTimings_tmp.htotal = (short)(pTimings->reserved_dd & (~TNC_HTOTAL_TUNED));
 
1455
                                }else{
 
1456
                                        if(wa->htotal == 0)
 
1457
                                                wa->htotal = (short)pTimings->reserved_dd;
 
1458
                                        pTimings_tmp.htotal = wa->htotal;
 
1459
                                }
 
1460
                                /* Use vphase formula if available */
 
1461
                                if(vphase){
 
1462
                                        pTimings_tmp.vtotal -= (short)vphase;
 
1463
                                        pTimings_tmp.vsync_start -= (short)vphase;
 
1464
                                        pTimings_tmp.vsync_end -= (short)vphase;
 
1465
                                        pTimings_tmp.vblank_end -= (short)vphase;
 
1466
                                }else{
 
1467
                                        //pTimings_tmp.hblank_start += (short) (pTimings_tmp.htotal - pTimings->htotal);
 
1468
                                        pTimings_tmp.hblank_end += (short) (pTimings_tmp.htotal - pTimings->htotal);
 
1469
                                }
 
1470
                        }
 
1471
                }
 
1472
#endif  
 
1473
 
 
1474
                temp = (unsigned long)(pTimings_tmp.htotal) << 16 | hactive_tmp;
 
1475
                WRITE_MMIO_REG_TNC(ports_tnc[i], timing_reg, temp);
 
1476
 
 
1477
                temp = ((unsigned long) pTimings_tmp.hblank_end << 16) |
 
1478
                        (unsigned long)(pTimings_tmp.hblank_start);
 
1479
                WRITE_MMIO_REG_TNC(ports_tnc[i], timing_reg + 0x04, temp);
 
1480
 
 
1481
                temp = ((unsigned long)(pTimings->hsync_end) << 16) |
 
1482
                        (unsigned long)(pTimings->hsync_start);
 
1483
                WRITE_MMIO_REG_TNC(ports_tnc[i], timing_reg + 0x08, temp);
 
1484
 
 
1485
                temp = ((unsigned long)(pTimings_tmp.vtotal) << 16) | vactive_tmp;
 
1486
                WRITE_MMIO_REG_TNC(ports_tnc[i], timing_reg + 0x0C, temp);
 
1487
 
 
1488
                temp = ((unsigned long)(pTimings_tmp.vblank_end) << 16) |
 
1489
                        (unsigned long)(pTimings_tmp.vblank_start);
 
1490
                WRITE_MMIO_REG_TNC(ports_tnc[i], timing_reg + 0x10, temp);
 
1491
 
 
1492
                temp = ((unsigned long)(pTimings_tmp.vsync_end)<< 16) |
 
1493
                        (unsigned long)(pTimings_tmp.vsync_start);
 
1494
                WRITE_MMIO_REG_TNC(ports_tnc[i], timing_reg + 0x14, temp);
 
1495
 
 
1496
                /*
 
1497
                 * If there is a linked mode it is either the VGA or a scaled
 
1498
                 * mode. If it is scaled then we need to use it as the source size.
 
1499
                 */
 
1500
                if(pTimings->extn_ptr) {
 
1501
                        igd_timing_info_t *scaled_timings =
 
1502
                                (igd_timing_info_t *)pTimings->extn_ptr;
 
1503
                        if((scaled_timings->mode_info_flags & IGD_MODE_VESA) &&
 
1504
                                (scaled_timings->mode_number <= VGA_MODE_NUM_MAX)) {
 
1505
                                temp = (hactive << 16) | vactive;
 
1506
                        } else {
 
1507
                                EMGD_DEBUG("scaled_timings->width [%d], scaled_timings->height [%d]\n", scaled_timings->width, scaled_timings->height);
 
1508
                                temp = (unsigned long)scaled_timings->width  - 1;
 
1509
                                temp = (temp << 16) |
 
1510
                                        (unsigned long)(scaled_timings->height - 1);
 
1511
                        }
 
1512
                } else {
 
1513
                        temp = (hactive_tmp << 16) | vactive_tmp;
 
1514
                }
 
1515
                WRITE_MMIO_REG_TNC(ports_tnc[i], timing_reg + 0x1C, temp);
 
1516
 
 
1517
                /* Enable pipe */
 
1518
                pipe_conf |= PIPE_ENABLE;
 
1519
 
 
1520
                /* Put pipe in interlaced mode if requested:
 
1521
                 *     should only happen for LVDS display if at all. */
 
1522
                if (pTimings->mode_info_flags & IGD_SCAN_INTERLACE) {
 
1523
                        pipe_conf |= (INTERLACE_EN);
 
1524
                } else {
 
1525
                        pipe_conf &= ~(INTERLACE_EN);
 
1526
                }
 
1527
 
 
1528
#ifdef CONFIG_MICRO
 
1529
                if (pt == IGD_PORT_SDVO) {
 
1530
                        /* 
 
1531
                           Enable the panel fitter as VGA controller in Lincroft 
 
1532
                           is a Panel Fitted VGA controller.
 
1533
                           LNC only supports panel fitted VGA mode 
 
1534
                           (upper left VGA mode). You need to enable the panel fitter.
 
1535
                           The timing control will be from the pipe timing generator 
 
1536
                           but not from the VGA timing generator CRTC registers 
 
1537
                           as in the centering mode.   
 
1538
                           
 
1539
                        */
 
1540
                        WRITE_MMIO_REG_TNC(IGD_PORT_LVDS, PFIT_CONTROL, 0xA2000000);
 
1541
                }
 
1542
#endif
 
1543
 
 
1544
                WRITE_MMIO_REG_TNC(ports_tnc[i], PIPE(display)->pipe_reg, pipe_conf);
 
1545
                WRITE_MMIO_REG_TNC(ports_tnc[i], PIPE(display)->pipe_reg, pipe_conf);
 
1546
                /* For LVDS port, don't touch dev3 registers stop after 1st iteration */
 
1547
                if (pt == IGD_PORT_LVDS) {
 
1548
                        break;
 
1549
                }
 
1550
        }
 
1551
 
 
1552
 
 
1553
        /* Gen4 can check when the pipe is enabled. */
 
1554
        wait_pipe(PIPE(display)->pipe_reg, 0x40000000);
 
1555
 
 
1556
        /*
 
1557
         * Set the VGA address range to 0xa0000 so that a normal (not VGA)
 
1558
         * mode can be accessed through 0xa0000 in a 16bit world.
 
1559
         */
 
1560
        WRITE_AR(MMIO(display), 0x10, 0xb);
 
1561
        WRITE_VGA(MMIO(display), GR_PORT, 0x06, 0x5);
 
1562
        WRITE_VGA(MMIO(display), GR_PORT, 0x10, 0x1);
 
1563
 
 
1564
        if(pTimings->extn_ptr) {
 
1565
                /* This means either internal scaling (LVDS) or centered VGA */
 
1566
                pTimings = pTimings->extn_ptr;
 
1567
                if(pTimings->extn_ptr) {
 
1568
                        /* This is both the scaled and centered VGA */
 
1569
                        pTimings = pTimings->extn_ptr;
 
1570
                }
 
1571
                if (pTimings->mode_info_flags & IGD_MODE_VESA) {
 
1572
                        if (pTimings->mode_number <= VGA_MODE_NUM_MAX) {
 
1573
                                program_pipe_vga_tnc(display);
 
1574
                        } else {
 
1575
#ifdef CONFIG_MICRO
 
1576
                                /*
 
1577
                                 * FIXME: This is not appropriate. This assumes that
 
1578
                                 * CONFIG_MICRO means "This is vBIOS" and programs
 
1579
                                 * the palette. vBIOS IAL should probably just set the
 
1580
                                 * palette itself??
 
1581
                                 */
 
1582
                                set_256_palette(
 
1583
                                        MMIO_TNC(PORT(display, display->port_number)->port_type));
 
1584
#endif
 
1585
                        }
 
1586
                }
 
1587
        }
 
1588
 
 
1589
        if (pt == IGD_PORT_SDVO) {
 
1590
                /*  Enable Chicken Bit */
 
1591
                /*  Setting BIT6 enable Pipe B Palette Write 
 
1592
         *  to prevent hang during palette write */ 
 
1593
                WRITE_MMIO_REG_TNC(IGD_PORT_LVDS, 0x70400, 0x4088 | BIT6);
 
1594
        }
 
1595
 
 
1596
        EMGD_TRACE_EXIT;
 
1597
        return;
 
1598
}
 
1599
 
 
1600
/*!
 
1601
 *
 
1602
 * @param context
 
1603
 *
 
1604
 * @return void
 
1605
 */
 
1606
void reset_plane_pipe_ports_tnc(igd_context_t *context)
 
1607
{
 
1608
        igd_plane_t *plane;
 
1609
        igd_display_pipe_t *pipe;
 
1610
        igd_display_port_t *port,*tv_port=NULL;
 
1611
        unsigned long temp;
 
1612
        unsigned long i, j;
 
1613
        unsigned char *mmio;
 
1614
        inter_module_dispatch_t *md;
 
1615
 
 
1616
        EMGD_TRACE_ENTER;
 
1617
 
 
1618
        /*
 
1619
         * Disable all plane, pipe and port registers because the
 
1620
         * bios may have been using a different set. Only unset the
 
1621
         * enable bit.
 
1622
         */
 
1623
        mmio = EMGD_MMIO(context->device_context.virt_mmadr);
 
1624
        md = &context->mod_dispatch;
 
1625
 
 
1626
        /* Turn off LVDS and SDVO ports */
 
1627
        port = NULL;
 
1628
        while((port = md->dsp_get_next_port(context, port, 0)) != NULL) {
 
1629
                /* if the port is TV, then don't set the power to S3 as this causes
 
1630
                 * blank screen on analog port after killx or cosole mode,
 
1631
                 * probably because the external clock needs to be on till the pipes and
 
1632
                 * DPLLs are off
 
1633
                 */
 
1634
                if (port->pd_driver) {
 
1635
                        if(port->pd_type == PD_DISPLAY_TVOUT) {
 
1636
                                tv_port = port;
 
1637
                        }else {
 
1638
                                port->pd_driver->set_power(port->pd_context, IGD_POWERSTATE_D3);
 
1639
                        }
 
1640
                }
 
1641
 
 
1642
                /* Disable WRITE protection on PIPE B for parts with Int-LVDS*/
 
1643
                /* This should never happen as the panel power was set to D3 above */
 
1644
                if (port->port_reg == LVDSCNTR) {
 
1645
                        if(EMGD_READ32(EMGD_MMIO(mmio) + LVDS_PNL_PWR_CTL) & 0x1) {
 
1646
                                EMGD_WRITE32(0xABCD0000, EMGD_MMIO(mmio) + LVDS_PNL_PWR_CTL);
 
1647
                                i=0;
 
1648
                                while(i++ < 0x10) {
 
1649
                                        OS_SLEEP(10);
 
1650
                                        if((EMGD_READ32(EMGD_MMIO(mmio)+LVDS_PNL_PWR_STS)&BIT(31))==0) {
 
1651
                                                break;
 
1652
                                        }
 
1653
                                }
 
1654
                        }
 
1655
                }
 
1656
                if (port->pd_driver) {
 
1657
                        temp = READ_MMIO_REG_TNC(port->port_type, port->port_reg);
 
1658
                        WRITE_MMIO_REG_TNC(port->port_type, port->port_reg, (temp & ~BIT31));
 
1659
                }
 
1660
        }
 
1661
 
 
1662
        /*
 
1663
         * Gen4 appears to require that plane B be shut off prior to
 
1664
         * shutting off plane A.  The normal get_next_plane returns them
 
1665
         * in order.  We need to read the list backwards.
 
1666
         */
 
1667
        plane = NULL;
 
1668
        while ((plane = md->dsp_get_next_plane(context, plane, 1)) != NULL) {
 
1669
                /*  This section only deals with display planes.
 
1670
                 *  Leave cursor, VGA, overlay, sprite planes alone since they will
 
1671
                 *  need a different disable bit/sequence.
 
1672
                 */
 
1673
                temp = EMGD_READ32(EMGD_MMIO(mmio) + plane->plane_reg);
 
1674
                if ((plane->plane_features & IGD_PLANE_DISPLAY)) {
 
1675
                        i = 0x71008;  /* PIPE B */
 
1676
                        if (temp & BIT31) {
 
1677
                                if(plane->plane_reg == DSPACNTR) {
 
1678
                                        temp = temp & device_data->plane_a_preserve;
 
1679
                                        i = 0x70008;  /* use i as pipe_reg */
 
1680
                                }
 
1681
                                EMGD_WRITE32((temp & ~BIT31), EMGD_MMIO(mmio) + plane->plane_reg);
 
1682
 
 
1683
                                /* The B-Spec is ambiguous on which register is the trigger.
 
1684
                                 * Testing has shown the the surface start address is the
 
1685
                                 * correct trigger to disable the plane.
 
1686
                                 */
 
1687
                                EMGD_WRITE32(0, EMGD_MMIO(mmio)+plane->plane_reg+DSP_START_OFFSET);
 
1688
 
 
1689
                                /* Wait for VBLANK to ensure that the plane is really off */
 
1690
                                wait_for_vblank_tnc(i);
 
1691
 
 
1692
                                EMGD_DEBUG("Plane disabled 0x%lx", plane->plane_reg);
 
1693
                        }
 
1694
                } else if ((plane->plane_features & IGD_PLANE_CURSOR)) {
 
1695
                        EMGD_WRITE32((temp & 0xffffffe8),
 
1696
                                EMGD_MMIO(mmio) + plane->plane_reg);
 
1697
                        EMGD_WRITE32(0, EMGD_MMIO(mmio) + plane->plane_reg+4);
 
1698
                }
 
1699
 
 
1700
        }
 
1701
 
 
1702
        /* Turn off pipes */
 
1703
        pipe = NULL;
 
1704
        while ((pipe = md->dsp_get_next_pipe(context, pipe, 0)) != NULL) {
 
1705
                j = 0;
 
1706
 
 
1707
                /* Is this really required? Just waited for vblank above 2 times */
 
1708
                wait_for_vblank_tnc(pipe->pipe_reg);
 
1709
 
 
1710
                for (i = 0; i < 2; i++) {
 
1711
                        temp = READ_MMIO_REG_TNC(ports_tnc[i], pipe->pipe_reg);
 
1712
 
 
1713
                        if (temp & BIT31) {
 
1714
                                /* Do not turn off Pipe B when shutting down */
 
1715
                                if((context->device_context.power_state
 
1716
                                                == IGD_POWERSTATE_UNDEFINED) &&
 
1717
                                        (pipe->pipe_reg == PIPEB_CONF)){
 
1718
                                        continue;
 
1719
                                }
 
1720
                                WRITE_MMIO_REG_TNC(ports_tnc[i], pipe->pipe_reg,
 
1721
                                        (temp & device_data->pipe_preserve));
 
1722
 
 
1723
                                /* Gen4 can check when the pipe is disabled. */
 
1724
                                wait_pipe(pipe->pipe_reg, 0);
 
1725
 
 
1726
                                /* Disable VGA display */
 
1727
                                disable_vga_tnc(EMGD_MMIO(mmio));
 
1728
 
 
1729
                        }
 
1730
 
 
1731
                        /* If current pipe is for sDVO, then iterate for PIPE B in
 
1732
                         * both 0:2:0 LNC and 0:3:0 Atom E6xx devices */
 
1733
                        if (pipe->pipe_reg == 0x70008L) {
 
1734
                                break;
 
1735
                        }
 
1736
                }
 
1737
                /* Disable DPLL:
 
1738
                 *  LVDS: LNC 0xF014
 
1739
                 *  SDVO: Atom E6xx 0x6018 */
 
1740
                temp = READ_MMIO_REG_TNC(ports_tnc[j], pipe->clock_reg->dpll_control);
 
1741
 
 
1742
                if (temp & BIT31) {
 
1743
                        WRITE_MMIO_REG_TNC(ports_tnc[j], pipe->clock_reg->dpll_control,
 
1744
                                temp & ~BIT31);
 
1745
                }
 
1746
                j++;
 
1747
        }
 
1748
        /* pipes and DPLLs are off, now set the power for TV */
 
1749
        if(tv_port && tv_port->pd_driver) {
 
1750
                tv_port->pd_driver->set_power(tv_port->pd_context, IGD_POWERSTATE_D3);
 
1751
        }
 
1752
 
 
1753
        EMGD_TRACE_EXIT;
 
1754
} /* end reset_plane_pipe_ports */
 
1755
 
 
1756
/*!
 
1757
 * Status is currently not used
 
1758
 *
 
1759
 * @param display
 
1760
 * @param port_number
 
1761
 * @param status
 
1762
 *
 
1763
 * @return 0 on success
 
1764
 * @return 1 on failure
 
1765
 */
 
1766
int post_program_port_tnc(igd_display_context_t *display,
 
1767
                unsigned short port_number,
 
1768
                unsigned long status)
 
1769
{
 
1770
        int ret;
 
1771
        igd_display_port_t *port;
 
1772
        igd_timing_info_t  *timings;
 
1773
        unsigned long portreg; /* temp; */
 
1774
        /*unsigned long pt = PORT_TYPE(display); */
 
1775
 
 
1776
        EMGD_TRACE_ENTER;
 
1777
 
 
1778
        port = PORT(display, port_number);
 
1779
        timings = PIPE(display)->timing;
 
1780
 
 
1781
        /*
 
1782
         * The programming found in the common code for all chipsets
 
1783
         * has the device programming sequence as follows:
 
1784
         *  Port
 
1785
         *  Pipe
 
1786
         *  Post Port
 
1787
         *  Plane
 
1788
         * On Gen4, if the port is enabled before the pipe, there is a 10%
 
1789
         * chance that the port will not turn on properly.
 
1790
         * Due to compatability requires with other chipsets, this workaround
 
1791
         * fixes this issue
 
1792
         */
 
1793
        portreg = READ_MMIO_REG_TNC(port->port_type, port->port_reg);
 
1794
        WRITE_MMIO_REG_TNC(port->port_type, port->port_reg, portreg & ~BIT31);
 
1795
        WRITE_MMIO_REG_TNC(port->port_type, port->port_reg, portreg);
 
1796
 
 
1797
        ret = 0;
 
1798
        /* call post_set_mode() if exists */
 
1799
        if (port->pd_driver->post_set_mode) {
 
1800
                ret = port->pd_driver->post_set_mode(port->pd_context, timings,
 
1801
                        1<<PIPE(display)->pipe_num);
 
1802
                if (ret) {
 
1803
                        EMGD_ERROR_EXIT("PD post_set_mode returned: 0x%x", ret);
 
1804
                }
 
1805
        }
 
1806
 
 
1807
        EMGD_TRACE_EXIT;
 
1808
        return ret;
 
1809
}
 
1810
 
 
1811
/*!
 
1812
 *
 
1813
 * @param display
 
1814
 * @param port_number
 
1815
 * @param status
 
1816
 *
 
1817
 * @return 0 on success
 
1818
 * @return -IGD_ERROR_INVAL on failure
 
1819
 */
 
1820
int program_port_sdvo_tnc(igd_display_context_t *display,
 
1821
                unsigned short port_number,
 
1822
                unsigned long status)
 
1823
{
 
1824
        unsigned long port_control;
 
1825
        unsigned long pd_powerstate = PD_POWER_MODE_D3;
 
1826
        unsigned long preserve = 0;
 
1827
        unsigned long upscale = 0;
 
1828
        igd_timing_info_t  local_timing;
 
1829
        igd_timing_info_t  *timing;
 
1830
        unsigned long temp;
 
1831
        int ret;
 
1832
 
 
1833
        EMGD_TRACE_ENTER;
 
1834
 
 
1835
        EMGD_DEBUG("Program Port: (%s)", status?"ENABLE":"DISABLE");
 
1836
        EMGD_DEBUG("pd_flags: 0x%lx", PORT(display, port_number)->pd_flags);
 
1837
 
 
1838
        timing = PIPE(display)->timing;
 
1839
 
 
1840
        port_control = preserve & READ_MMIO_REG_TNC(IGD_PORT_SDVO,
 
1841
                        PORT(display, port_number)->port_reg);
 
1842
 
 
1843
        if (status == TRUE) {
 
1844
                if (!(PORT(display, port_number)->pt_info->flags &
 
1845
                        IGD_DISPLAY_ENABLE)) {
 
1846
                        EMGD_TRACE_EXIT;
 
1847
                        return 0;
 
1848
                }
 
1849
 
 
1850
                /* Enable VGA syncs for native vga modes */
 
1851
                if (PORT(display, port_number)->vga_sync == 1) {
 
1852
                        EMGD_DEBUG("VGA sync true, is width x height 720 x 400?");
 
1853
                        if((timing->width == 720) && (timing->height == 400)) {
 
1854
                                EMGD_DEBUG("Modify port control and multi_port_control");
 
1855
                                port_control |= (1L<<15);
 
1856
                        }
 
1857
                }
 
1858
 
 
1859
                /* Fact that both IGD_ powerstates and PD_ powermodes have
 
1860
                 * same definitions */
 
1861
                pd_powerstate = GET_DISPLAY_POWER_STATE(display, port_number);
 
1862
 
 
1863
                if (pd_powerstate == IGD_POWERSTATE_D0) {
 
1864
                        EMGD_DEBUG("Power State: D0");
 
1865
                        /* Upscale */
 
1866
                        pi_pd_find_attr_and_value(PORT(display, port_number),
 
1867
                                PD_ATTR_ID_PANEL_FIT,
 
1868
                                0, /*no PD_FLAG for UPSCALING */
 
1869
                                NULL, /* dont need the attr ptr*/
 
1870
                                &upscale);
 
1871
 
 
1872
                        /* Reach the end timing if upscaling is enabled */
 
1873
                        if (timing->extn_ptr && upscale) {
 
1874
                                timing = (pd_timing_t *)timing->extn_ptr;
 
1875
                        }
 
1876
 
 
1877
                        local_timing = *timing;
 
1878
                        if (upscale) {
 
1879
                                /* For timings smaller than width 360 and height 200,
 
1880
                                 * double the size. This is because the active area of the mode
 
1881
                                 * is double the size of the resolution for these modes
 
1882
                                 *  - Very tricky huh */
 
1883
                                if (local_timing.width <= 360) {
 
1884
                                        local_timing.width <<= 1;
 
1885
                                }
 
1886
                                if (local_timing.height <= 200) {
 
1887
                                        local_timing.height <<= 1;
 
1888
                                }
 
1889
                        }
 
1890
 
 
1891
                        /* BIT31 - Enable
 
1892
                         * BIT30 - PIPE B
 
1893
                         * BIT29 - Stall
 
1894
                         * BIT7  - Border
 
1895
                         */
 
1896
                        port_control |= BIT31|BIT30|BIT29|BIT7;
 
1897
 
 
1898
                        /* Program cDVO registers:
 
1899
                         * Keep default values for
 
1900
                         *     7000h - cDVO control register
 
1901
                         *     7004h - cDVO slew rate register
 
1902
                         *     7008h - cDVO strength register
 
1903
                         *     700Ch - cDVO RCOMP update register
 
1904
                         *     6102Ch - cDVO stall register = 0xA.
 
1905
                         * Note: Though EAS says 6102Ch default value is 6, it is a typo
 
1906
                         *     in the spec, based on Si DE hw default value is 10 (0xA),
 
1907
                         *     so no need to program explicitly. This saves few bytes for
 
1908
                         *     micro.
 
1909
                         */
 
1910
 
 
1911
                        /* Enable Current Source */
 
1912
                        temp = READ_MMIO_REG_TNC(IGD_PORT_SDVO, SDVO_BUFF_CTRL_REG);
 
1913
                        temp |= 0x2000;
 
1914
                        WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, SDVO_BUFF_CTRL_REG, temp);
 
1915
                }
 
1916
        }
 
1917
 
 
1918
        if (pd_powerstate == PD_POWER_MODE_D0) {
 
1919
                ret = PORT(display, port_number)->pd_driver->set_mode(
 
1920
                        PORT(display, port_number)->pd_context, &local_timing, 0);
 
1921
        } else {
 
1922
                ret = PORT(display, port_number)->pd_driver->set_power(
 
1923
                        PORT(display, port_number)->pd_context, pd_powerstate);
 
1924
        }
 
1925
 
 
1926
        if (ret) {
 
1927
                EMGD_ERROR_EXIT("PD set_%s returned: 0x%x",
 
1928
                        (pd_powerstate == PD_POWER_MODE_D0)?"mode":"power", ret);
 
1929
                return -IGD_ERROR_INVAL;
 
1930
        }
 
1931
 
 
1932
        EMGD_DEBUG("Port_control: 0x%lx", port_control);
 
1933
 
 
1934
        WRITE_MMIO_REG_TNC(IGD_PORT_SDVO,
 
1935
                PORT(display, port_number)->port_reg, port_control);
 
1936
 
 
1937
        EMGD_TRACE_EXIT;
 
1938
        return 0;
 
1939
}
 
1940
 
 
1941
/*!
 
1942
 *
 
1943
 * @param display
 
1944
 * @param port_number
 
1945
 * @param status
 
1946
 *
 
1947
 * @return 0 on success
 
1948
 * @return -IGD_ERROR_INVAL on failure
 
1949
 */
 
1950
int program_port_lvds_tnc(igd_display_context_t *display,
 
1951
                unsigned short port_number,
 
1952
                unsigned long status)
 
1953
{
 
1954
        int ret = 0;
 
1955
        unsigned long powerstate = PD_POWER_MODE_D3;
 
1956
        pd_timing_t *timing;
 
1957
 
 
1958
        EMGD_TRACE_ENTER;
 
1959
 
 
1960
        EMGD_DEBUG("Program LVDS: (%s)", status?"ENABLE":"DISABLE");
 
1961
 
 
1962
        if (status == TRUE) {
 
1963
                if(!(PORT(display, port_number)->pt_info->flags & IGD_DISPLAY_ENABLE)) {
 
1964
                        EMGD_TRACE_EXIT;
 
1965
                        return 0;
 
1966
                }
 
1967
 
 
1968
                powerstate = GET_DISPLAY_POWER_STATE(display,port_number);
 
1969
                if (powerstate == IGD_POWERSTATE_D0) {
 
1970
                        EMGD_DEBUG("Power State: D0");
 
1971
                        timing = (pd_timing_t *)PIPE(display)->timing;
 
1972
                        /* Reach end timing to get user resolution and pass it to pd */
 
1973
                        if(timing->extn_ptr) {
 
1974
                                timing = (pd_timing_t *)timing->extn_ptr;
 
1975
                        }
 
1976
                        /* set mode will take care of port control */
 
1977
                        ret = PORT(display, port_number)->pd_driver->set_mode(
 
1978
                                        PORT(display, port_number)->pd_context,
 
1979
                                        timing,
 
1980
                                        1<<PIPE(display)->pipe_num);
 
1981
                }
 
1982
        }
 
1983
 
 
1984
        /* either status == FALSE, or status == TRUE, but powerstate is D1/D2/D3 */
 
1985
        if (powerstate != IGD_POWERSTATE_D0) {
 
1986
                ret = PORT(display, port_number)->pd_driver->set_power(
 
1987
                        PORT(display, port_number)->pd_context,
 
1988
                        PD_POWER_MODE_D3);
 
1989
        }
 
1990
 
 
1991
        if (ret) {
 
1992
                EMGD_ERROR_EXIT("PD set_%s returned: 0x%x",
 
1993
                        (powerstate == IGD_POWERSTATE_D0)?"mode":"power", ret);
 
1994
                return -IGD_ERROR_INVAL;
 
1995
        }
 
1996
 
 
1997
        EMGD_TRACE_EXIT;
 
1998
        return ret;
 
1999
}
 
2000
 
 
2001
 
 
2002
/*!
 
2003
 *
 
2004
 * @param display
 
2005
 * @param port_number
 
2006
 * @param status
 
2007
 *
 
2008
 * @return program_port_lvds_gen4()
 
2009
 * @return program_port_sdvo_gen4()
 
2010
 * @return -IGD_ERROR_INVAL on failure
 
2011
 */
 
2012
int program_port_tnc(igd_display_context_t *display,
 
2013
                unsigned short port_number,
 
2014
                unsigned long status)
 
2015
{
 
2016
        EMGD_TRACE_ENTER;
 
2017
 
 
2018
        if (PORT(display, port_number)->port_type == IGD_PORT_LVDS) {
 
2019
                EMGD_TRACE_EXIT;
 
2020
                return program_port_lvds_tnc(display, port_number, status);
 
2021
        } else {
 
2022
                EMGD_TRACE_EXIT;
 
2023
                return program_port_sdvo_tnc(display, port_number, status);
 
2024
        }
 
2025
}
 
2026
 
 
2027
/*!
 
2028
 *
 
2029
 * @param gpio
 
2030
 *
 
2031
 * @return size
 
2032
 */
 
2033
unsigned long get_gpio_sets_tnc(unsigned long **gpio)
 
2034
{
 
2035
        /* To small to trace */
 
2036
        return 0;
 
2037
}
 
2038
 
 
2039
/*!
 
2040
 *
 
2041
 * @param context
 
2042
 * @param in_list
 
2043
 *
 
2044
 * @return void - To small to trace
 
2045
 */
 
2046
void filter_modes_tnc(igd_context_t *context, igd_display_port_t *port,
 
2047
        pd_timing_t *in_list)
 
2048
{
 
2049
        while (in_list->width != IGD_TIMING_TABLE_END) {
 
2050
                /* TC LVDS:
 
2051
                 *    supports from 19.75MHz to 79.MHz
 
2052
                 * TC SDVO:
 
2053
                 *    supports from 25 MHz to 160 MHz and progressive only.
 
2054
                 */
 
2055
                if (port->port_type == IGD_PORT_SDVO) {
 
2056
                        if (in_list->mode_info_flags & IGD_SCAN_INTERLACE ||
 
2057
                                in_list->dclk < 25000 || in_list->dclk > 160000) {
 
2058
                                in_list->mode_info_flags &= ~IGD_MODE_SUPPORTED;
 
2059
                        }
 
2060
                }
 
2061
                /* No clock check is required for LVDS port as LVDS port driver
 
2062
                 * already taken care of this. 
 
2063
                if (port->port_type == IGD_PORT_LVDS) {
 
2064
                        if (in_list->dclk < 19750 || in_list->dclk > 79500) {
 
2065
                                in_list->mode_info_flags &= ~IGD_MODE_SUPPORTED;
 
2066
                        }
 
2067
                }*/
 
2068
                in_list++;
 
2069
                if (in_list->width == IGD_TIMING_TABLE_END && in_list->extn_ptr) {
 
2070
                        in_list = in_list->extn_ptr;
 
2071
                }
 
2072
        }
 
2073
        return;
 
2074
}
 
2075
#ifndef CONFIG_MICRO
 
2076
int get_timing_tnc(igd_display_context_t *display, pd_timing_t *in_list)
 
2077
{
 
2078
        //int ret = TRUE;
 
2079
        igd_timing_info_t *pTimings_ori;
 
2080
        pd_timing_t *timing = NULL;
 
2081
        timing = in_list;       
 
2082
 
 
2083
        EMGD_TRACE_ENTER;
 
2084
        pTimings_ori = PIPE(display)->timing;
 
2085
 
 
2086
        if(display->port_number != 2){
 
2087
                EMGD_DEBUG("Port does not need tuning");
 
2088
                EMGD_TRACE_EXIT;
 
2089
                return FALSE;
 
2090
        }
 
2091
 
 
2092
        while(timing->width != PD_TIMING_LIST_END) {
 
2093
                
 
2094
                if((timing->width == pTimings_ori->width) &&
 
2095
                   (timing->height == pTimings_ori->height) &&
 
2096
                   (timing->refresh == pTimings_ori->refresh)){
 
2097
                        EMGD_DEBUG("Timing found");
 
2098
                        timing->reserved_dd = pTimings_ori->reserved_dd;
 
2099
                        timing->mode_info_flags = pTimings_ori->mode_info_flags;
 
2100
 
 
2101
           /* also return the hblank_end so that ioctl can calculate
 
2102
            * the xblank_length.
 
2103
            */
 
2104
            timing->hblank_end = pTimings_ori->hblank_end;
 
2105
            timing->vblank_end = pTimings_ori->vblank_end;      
 
2106
 
 
2107
 
 
2108
                }
 
2109
                /* Go through the table list */
 
2110
                timing++;
 
2111
                if ((timing->width == PD_TIMING_LIST_END) && timing->extn_ptr) {
 
2112
                                timing = timing->extn_ptr;
 
2113
                }
 
2114
        }
 
2115
 
 
2116
        EMGD_TRACE_EXIT;
 
2117
        return TRUE;
 
2118
}
 
2119
 
 
2120
int check_port_supported(void *port_tmp)
 
2121
{
 
2122
        //igd_display_port_t *port = (igd_display_port_t *)port_tmp;
 
2123
        /* Determine which port driver is supported by Atom E6xx */
 
2124
#if 0 //Pendng confirmation from LNC architect
 
2125
        if(pd_driver->type & PD_DISPLAY_TVOUT){
 
2126
                return 1;
 
2127
        }
 
2128
#endif
 
2129
        return 0;
 
2130
}
 
2131
#endif
 
2132
 
 
2133
/* Function checks if the incoming user DTD is one of the timings
 
2134
 * in the crt_timing_table that has border. Meaning that the
 
2135
 * h_blank_end is not the same as htotal.
 
2136
 * We only see this issue when reading a user DTD generated for
 
2137
 * harmonic which is derived from crt_timing_table. pi module
 
2138
 * only handles user DTD which does not have borders.
 
2139
 */
 
2140
int get_refresh_in_border(pd_timing_t *in_list)
 
2141
{
 
2142
       /* return 1 if refresh is obtained */
 
2143
      
 
2144
       if(in_list->width == 640 &&
 
2145
               in_list->height == 480 &&
 
2146
               in_list->dclk == 25175 &&
 
2147
               in_list->hsync_start == 655 &&
 
2148
               in_list->hsync_end == 751 &&
 
2149
               in_list->vsync_start == 489 &&
 
2150
               in_list->vsync_end == 491){
 
2151
                       in_list->refresh = 60;
 
2152
                       in_list->htotal = 799;
 
2153
                       in_list->vtotal = 524;
 
2154
                       in_list->hblank_start = 646;
 
2155
                       in_list->vblank_start = 486;
 
2156
                       return 1;
 
2157
       }
 
2158
 
 
2159
       if(in_list->width == 640 &&
 
2160
               in_list->height == 480 &&
 
2161
               in_list->dclk == 31500 &&
 
2162
               in_list->hsync_start == 663 &&
 
2163
               in_list->hsync_end == 703 &&
 
2164
               in_list->vsync_start == 488 &&
 
2165
               in_list->vsync_end == 491){
 
2166
 
 
2167
                       in_list->refresh = 72;
 
2168
                       in_list->htotal = 831;
 
2169
                       in_list->vtotal = 519;
 
2170
                       in_list->hblank_start = 646;
 
2171
                       in_list->vblank_start = 486;
 
2172
                       return 1;
 
2173
       }
 
2174
 
 
2175
 
 
2176
       return 0;
 
2177
}
 
2178
 
 
2179
/*
 
2180
 * Function to check if dc is switching from
 
2181
 * SDVO single to clone/extended mode
 
2182
 * Tunnel Creek B0  needs tuning when there are 2 planes,
 
2183
 * if true, it will force alter to run tuning
 
2184
 */
 
2185
bool dsp_is_force_alter_required_tnc(igd_display_context_t *display, 
 
2186
        unsigned long current_dc, unsigned long dc_to_set){
 
2187
 
 
2188
        if ((IGD_DC_SINGLE(current_dc) &&
 
2189
                        (IGD_DC_PRIMARY(current_dc) == IGD_PORT_TYPE_SDVOB )) &&
 
2190
                        (IGD_DC_CLONE(dc_to_set) || IGD_DC_EXTENDED(dc_to_set)) &&
 
2191
                        (display->context->device_context.rid == TNC_B0_RID)){
 
2192
                
 
2193
                return TRUE;
 
2194
        }
 
2195
        
 
2196
        return FALSE;
 
2197
}
 
2198
 
 
2199
mode_dispatch_t mode_dispatch_tnc = {
 
2200
        igd_set_palette_entry_tnc,
 
2201
        igd_get_palette_entry_tnc,
 
2202
        igd_wait_vblank_tnc,
 
2203
        program_plane_tnc,
 
2204
        program_pipe_tnc,
 
2205
        program_port_tnc,
 
2206
        post_program_port_tnc,
 
2207
        program_clock_tnc,
 
2208
        reset_plane_pipe_ports_tnc,
 
2209
        get_gpio_sets_tnc,
 
2210
        filter_modes_tnc,
 
2211
        OPT_MICRO_VALUE(check_display_tnc, NULL),
 
2212
        OPT_MICRO_VALUE(get_timing_tnc, NULL),
 
2213
        OPT_MICRO_VALUE(check_port_supported, NULL),
 
2214
        OPT_MICRO_VALUE(get_refresh_in_border, NULL),
 
2215
        OPT_MICRO_VALUE(dsp_is_force_alter_required_tnc, NULL),
 
2216
        OPT_MICRO_VALUE(&mode_full_dispatch_tnc, NULL)
 
2217
};
 
2218
 
 
2219
/* VBIOS does not use the virtual mapped address
 
2220
 * This function will return 0 for VBIOS anyway */
 
2221
#ifndef CONFIG_MICRO
 
2222
unsigned char *get_mmio_tnc(unsigned long port_type)
 
2223
{
 
2224
        unsigned char *virt_mmio;
 
2225
        if (port_type == IGD_PORT_LVDS) {
 
2226
                virt_mmio = mode_context->context->device_context.virt_mmadr;
 
2227
        } else if (port_type == IGD_PORT_SDVO) {
 
2228
                virt_mmio = mode_context->context->device_context.virt_mmadr_sdvo;
 
2229
        } else {
 
2230
                /* i2c_bitbash will use the else condition by passing in port_type
 
2231
                 * as '0' */
 
2232
                virt_mmio = mode_context->context->device_context.virt_gpio_bar;
 
2233
        }
 
2234
        return virt_mmio;
 
2235
}
 
2236
#endif
 
2237
 
 
2238
/* Function to read Atom E6xx 0:2:0, 0:3:0 and 0:31:0 mmio registers */
 
2239
unsigned long read_mmio_reg_tnc(unsigned long port_type, unsigned long reg)
 
2240
{
 
2241
        unsigned long value;
 
2242
#ifndef CONFIG_MICRO
 
2243
        unsigned char *mmio;
 
2244
#endif
 
2245
 
 
2246
        /* to avoid updating or having another set of read/write macros for
 
2247
         * vbios, overwrite io_base to properly read from 0:2:0/0:3:0/0:31:0
 
2248
         * io_base and set it back after reading */
 
2249
        if (port_type == IGD_PORT_LVDS) {
 
2250
                io_base = io_base_lvds;
 
2251
        } else if (port_type == IGD_PORT_SDVO) {
 
2252
                io_base = io_base_sdvo;
 
2253
        } else if (port_type == IGD_PORT_LPC) { 
 
2254
                io_base = io_base_lpc;
 
2255
        }
 
2256
        OPT_MICRO_CALL_RET(mmio, get_mmio_tnc(port_type));
 
2257
        if (port_type == IGD_PORT_LPC) {
 
2258
                value = EMGD_READ_PORT32(io_base_lpc + reg);
 
2259
        } else {
 
2260
                value = EMGD_READ32(EMGD_MMIO(mmio) + reg);
 
2261
        }
 
2262
 
 
2263
        io_base = io_base_lvds;
 
2264
        return value;
 
2265
}
 
2266
 
 
2267
/* Function to write Atom E6xx 0:2:0 and 0:3:0 mmio registers */
 
2268
void write_mmio_reg_tnc(unsigned long port_type, unsigned long reg,
 
2269
        unsigned long value)
 
2270
{
 
2271
#ifndef CONFIG_MICRO
 
2272
        unsigned char *mmio;
 
2273
#endif
 
2274
 
 
2275
        /* to avoid updating or having another set of read/write macros for
 
2276
         * vbios, overwrite io_base to properly read from 0:2:0/0:3:0 io_base
 
2277
         * and set it back after writing */
 
2278
        if (port_type == IGD_PORT_LVDS) {
 
2279
                io_base = io_base_lvds;
 
2280
        } else if (port_type == IGD_PORT_SDVO) {
 
2281
                io_base = io_base_sdvo;
 
2282
        } else if (port_type == IGD_PORT_LPC) {
 
2283
                io_base = io_base_lpc;
 
2284
        }
 
2285
 
 
2286
        OPT_MICRO_CALL_RET(mmio, get_mmio_tnc(port_type));
 
2287
        if (port_type == IGD_PORT_LPC) {
 
2288
                EMGD_WRITE_PORT32(io_base_lpc + reg, value);
 
2289
        } else {
 
2290
                EMGD_WRITE32(value, EMGD_MMIO(mmio) + reg);
 
2291
        }
 
2292
        io_base = io_base_lvds;
 
2293
        return;
 
2294
}
 
2295
 
 
2296
#endif