Merge commit 'u-boot/master' into for-1.3.1
[platform/kernel/u-boot.git] / drivers / video / smiLynxEM.c
1 /*
2  * (C) Copyright 1997-2002 ELTEC Elektronik AG
3  * Frank Gottschling <fgottschling@eltec.de>
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  */
23
24 /*
25  * smiLynxEM.c
26  *
27  * Silicon Motion graphic interface for sm810/sm710/sm712 accelerator
28  *
29  * modification history
30  * --------------------
31  * 04-18-2002 Rewritten for U-Boot <fgottschling@eltec.de>.
32  *
33  * 18-03-2004 - Unify videomodes handling with the ct69000
34  *            - The video output can be set via the variable "videoout"
35  *              in the environment.
36  *              videoout=1 output on LCD
37  *              videoout=2 output on CRT (default value)
38  *                      <p.aubert@staubli.com>
39  */
40
41 #include <common.h>
42
43 #if defined(CONFIG_VIDEO_SMI_LYNXEM)
44
45 #include <pci.h>
46 #include <video_fb.h>
47 #include "videomodes.h"
48 /*
49  * Export Graphic Device
50  */
51 GraphicDevice smi;
52
53 /*
54  * SMI 710/712 have 4MB internal RAM; SMI 810 2MB internal + 2MB external
55  */
56 #define VIDEO_MEM_SIZE  0x400000
57
58
59 /*
60  * ISA mapped regs
61  */
62 #define SMI_INDX_C4             (pGD->isaBase + 0x03c4)    /* index reg */
63 #define SMI_DATA_C5             (pGD->isaBase + 0x03c5)    /* data reg */
64 #define SMI_INDX_D4             (pGD->isaBase + 0x03d4)    /* index reg */
65 #define SMI_DATA_D5             (pGD->isaBase + 0x03d5)    /* data reg */
66 #define SMI_ISR1                (pGD->isaBase + 0x03ca)
67 #define SMI_INDX_CE             (pGD->isaBase + 0x03ce)    /* index reg */
68 #define SMI_DATA_CF             (pGD->isaBase + 0x03cf)    /* data reg */
69 #define SMI_LOCK_REG            (pGD->isaBase + 0x03c3)    /* unlock/lock ext crt reg */
70 #define SMI_MISC_REG            (pGD->isaBase + 0x03c2)    /* misc reg */
71 #define SMI_LUT_MASK            (pGD->isaBase + 0x03c6)    /* lut mask reg */
72 #define SMI_LUT_START           (pGD->isaBase + 0x03c8)    /* lut start index */
73 #define SMI_LUT_RGB             (pGD->isaBase + 0x03c9)    /* lut colors auto incr.*/
74 #define SMI_INDX_ATTR           (pGD->isaBase + 0x03c0)    /* attributes index reg */
75
76 /*
77  * Video processor control
78  */
79 typedef struct {
80         unsigned int   control;
81         unsigned int   colorKey;
82         unsigned int   colorKeyMask;
83         unsigned int   start;
84         unsigned short offset;
85         unsigned short width;
86         unsigned int   fifoPrio;
87         unsigned int   fifoERL;
88         unsigned int   YUVtoRGB;
89 } SmiVideoProc;
90
91 /*
92  * Video window control
93  */
94 typedef struct {
95         unsigned short top;
96         unsigned short left;
97         unsigned short bottom;
98         unsigned short right;
99         unsigned int   srcStart;
100         unsigned short width;
101         unsigned short offset;
102         unsigned char  hStretch;
103         unsigned char  vStretch;
104 } SmiVideoWin;
105
106 /*
107  * Capture port control
108  */
109 typedef struct {
110         unsigned int   control;
111         unsigned short topClip;
112         unsigned short leftClip;
113         unsigned short srcHeight;
114         unsigned short srcWidth;
115         unsigned int   srcBufStart1;
116         unsigned int   srcBufStart2;
117         unsigned short srcOffset;
118         unsigned short fifoControl;
119 } SmiCapturePort;
120
121
122 /*
123  * Register values for common video modes
124  */
125 static char SMI_SCR[] = {
126         /* all modes */
127         0x10, 0xff, 0x11, 0xff, 0x12, 0xff, 0x13, 0xff, 0x15, 0x90,
128         0x17, 0x20, 0x18, 0xb1, 0x19, 0x00,
129 };
130 static char SMI_EXT_CRT[] = {
131         0x31, 0x00, 0x32, 0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00,
132         0x36, 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3f, 0x00,
133 };
134 static char SMI_ATTR [] = {
135         0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05,
136         0x06, 0x06, 0x07, 0x07, 0x08, 0x08, 0x09, 0x09, 0x0a, 0x0a, 0x0b, 0x0b,
137         0x0c, 0x0c, 0x0d, 0x0d, 0x0e, 0x0e, 0x0f, 0x0f, 0x10, 0x41, 0x11, 0x00,
138         0x12, 0x0f, 0x13, 0x00, 0x14, 0x00,
139 };
140 static char SMI_GCR[18] = {
141         0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x40,
142         0x06, 0x05, 0x07, 0x0f, 0x08, 0xff,
143 };
144 static char SMI_SEQR[] = {
145         0x00, 0x00, 0x01, 0x01, 0x02, 0x0f, 0x03, 0x03, 0x04, 0x0e, 0x00, 0x03,
146 };
147 static char SMI_PCR [] = {
148         0x20, 0x04, 0x21, 0x30, 0x22, 0x00, 0x23, 0x00, 0x24, 0x00,
149 };
150 static char SMI_MCR[] = {
151         0x60, 0x01, 0x61, 0x00,
152 #ifdef CONFIG_HMI1001
153         0x62, 0x74, /* Memory type is not configured by pins on HMI1001 */
154 #endif
155 };
156
157 static char SMI_HCR[] = {
158         0x80, 0xff, 0x81, 0x07, 0x82, 0x00, 0x83, 0xff, 0x84, 0xff, 0x88, 0x00,
159         0x89, 0x02, 0x8a, 0x80, 0x8b, 0x01, 0x8c, 0xff, 0x8d, 0x00,
160 };
161
162
163 /*******************************************************************************
164  *
165  * Write SMI ISA register
166  */
167 static void smiWrite (unsigned short index, char reg, char val)
168 {
169         register GraphicDevice *pGD = (GraphicDevice *)&smi;
170
171         out8 ((pGD->isaBase + index), reg);
172         out8 ((pGD->isaBase + index + 1), val);
173 }
174
175 /*******************************************************************************
176  *
177  * Write a table of SMI ISA register
178  */
179 static void smiLoadRegs (
180         unsigned int iReg,
181         unsigned int dReg,
182         char         *regTab,
183         unsigned int tabSize
184         )
185 {
186         register GraphicDevice *pGD  = (GraphicDevice *)&smi;
187         register int i;
188
189         for (i=0; i<tabSize; i+=2) {
190                 if (iReg == SMI_INDX_ATTR) {
191                         /* Reset the Flip Flop */
192                         in8 (SMI_ISR1);
193                         out8 (iReg, regTab[i]);
194                         out8 (iReg, regTab[i+1]);
195                 } else {
196                         out8 (iReg, regTab[i]);
197                         out8 (dReg, regTab[i+1]);
198                 }
199         }
200 }
201
202 /*******************************************************************************
203  *
204  * Init capture port registers
205  */
206 static void smiInitCapturePort (void)
207 {
208         SmiCapturePort smiCP = { 0x01400600, 0x30, 0x40, 480, 640, 0, 0, 2560, 6 };
209         register GraphicDevice *pGD  = (GraphicDevice *)&smi;
210         register SmiCapturePort *pCP = (SmiCapturePort *)&smiCP;
211
212         out32r ((pGD->cprBase + 0x0004), ((pCP->topClip<<16)   | pCP->leftClip));
213         out32r ((pGD->cprBase + 0x0008), ((pCP->srcHeight<<16) | pCP->srcWidth));
214         out32r ((pGD->cprBase + 0x000c), pCP->srcBufStart1/8);
215         out32r ((pGD->cprBase + 0x0010), pCP->srcBufStart2/8);
216         out32r ((pGD->cprBase + 0x0014), pCP->srcOffset/8);
217         out32r ((pGD->cprBase + 0x0018), pCP->fifoControl);
218         out32r ((pGD->cprBase + 0x0000), pCP->control);
219 }
220
221
222 /*******************************************************************************
223  *
224  * Init video processor registers
225  */
226 static void smiInitVideoProcessor (void)
227 {
228         SmiVideoProc smiVP = { 0x100000, 0, 0, 0, 0, 1600, 0x1200543, 4, 0xededed };
229         SmiVideoWin  smiVW = { 0, 0, 599, 799, 0, 1600, 0, 0, 0 };
230         register GraphicDevice *pGD = (GraphicDevice *)&smi;
231         register SmiVideoProc  *pVP = (SmiVideoProc *)&smiVP;
232         register SmiVideoWin *pVWin = (SmiVideoWin *)&smiVW;
233
234         pVP->width    = pGD->plnSizeX * pGD->gdfBytesPP;
235         pVP->control |= pGD->gdfIndex << 16;
236         pVWin->bottom = pGD->winSizeY - 1;
237         pVWin->right  = pGD->winSizeX - 1;
238         pVWin->width  = pVP->width;
239
240         /* color key */
241         out32r ((pGD->vprBase + 0x0004), pVP->colorKey);
242
243         /* color key mask */
244         out32r ((pGD->vprBase + 0x0008), pVP->colorKeyMask);
245
246         /* data src start adrs */
247         out32r ((pGD->vprBase + 0x000c), pVP->start / 8);
248
249         /* data width and offset */
250         out32r ((pGD->vprBase + 0x0010),
251                 ((pVP->offset   / 8 * pGD->gdfBytesPP) << 16) |
252                 (pGD->plnSizeX / 8 * pGD->gdfBytesPP));
253
254         /* video window 1 */
255         out32r ((pGD->vprBase + 0x0014),
256                 ((pVWin->top << 16) | pVWin->left));
257
258         out32r ((pGD->vprBase + 0x0018),
259                 ((pVWin->bottom << 16) | pVWin->right));
260
261         out32r ((pGD->vprBase + 0x001c), pVWin->srcStart / 8);
262
263         out32r ((pGD->vprBase + 0x0020),
264                 (((pVWin->offset / 8) << 16) | (pVWin->width / 8)));
265
266         out32r ((pGD->vprBase + 0x0024),
267                 (((pVWin->hStretch) << 8) | pVWin->vStretch));
268
269         /* video window 2 */
270         out32r ((pGD->vprBase + 0x0028),
271                 ((pVWin->top << 16) | pVWin->left));
272
273         out32r ((pGD->vprBase + 0x002c),
274                 ((pVWin->bottom << 16) | pVWin->right));
275
276         out32r ((pGD->vprBase + 0x0030),
277                 pVWin->srcStart / 8);
278
279         out32r ((pGD->vprBase + 0x0034),
280                 (((pVWin->offset / 8) << 16) | (pVWin->width / 8)));
281
282         out32r ((pGD->vprBase + 0x0038),
283                 (((pVWin->hStretch) << 8) | pVWin->vStretch));
284
285         /* fifo prio control */
286         out32r ((pGD->vprBase + 0x0054), pVP->fifoPrio);
287
288         /* fifo empty request levell */
289         out32r ((pGD->vprBase + 0x0058), pVP->fifoERL);
290
291         /* conversion constant */
292         out32r ((pGD->vprBase + 0x005c), pVP->YUVtoRGB);
293
294         /* vpr control word */
295         out32r ((pGD->vprBase + 0x0000), pVP->control);
296 }
297
298 /******************************************************************************
299  *
300  * Init drawing engine registers
301  */
302 static void smiInitDrawingEngine (void)
303 {
304         GraphicDevice *pGD = (GraphicDevice *)&smi;
305         unsigned int val;
306
307         /* don't start now */
308         out32r ((pGD->dprBase + 0x000c), 0x000f0000);
309
310         /* set rop2 to copypen */
311         val = 0xffff3ff0 & in32r ((pGD->dprBase + 0x000c));
312         out32r ((pGD->dprBase + 0x000c), (val | 0x8000 | 0x0c));
313
314         /* set clip rect */
315         out32r ((pGD->dprBase + 0x002c), 0);
316         out32r ((pGD->dprBase + 0x0030),
317                 ((pGD->winSizeY<<16) | pGD->winSizeX * pGD->gdfBytesPP ));
318
319         /* src row pitch */
320         val = 0xffff0000 & (in32r ((pGD->dprBase + 0x0010)));
321         out32r ((pGD->dprBase + 0x0010),
322                 (val | pGD->plnSizeX * pGD->gdfBytesPP));
323
324         /* dst row pitch */
325         val = 0x0000ffff & (in32r ((pGD->dprBase + 0x0010)));
326         out32r ((pGD->dprBase + 0x0010),
327                 (((pGD->plnSizeX * pGD->gdfBytesPP)<<16) | val));
328
329         /* window width src/dst */
330         out32r ((pGD->dprBase + 0x003c),
331                 (((pGD->plnSizeX * pGD->gdfBytesPP & 0x0fff)<<16) |
332                  (pGD->plnSizeX * pGD->gdfBytesPP & 0x0fff)));
333         out16r ((pGD->dprBase + 0x001e), 0x0000);
334
335         /* src base adrs */
336         out32r ((pGD->dprBase + 0x0040),
337                 (((pGD->frameAdrs/8) & 0x000fffff)));
338
339         /* dst base adrs */
340         out32r ((pGD->dprBase + 0x0044),
341                 (((pGD->frameAdrs/8) & 0x000fffff)));
342
343         /* foreground color */
344         out32r ((pGD->dprBase + 0x0014), pGD->fg);
345
346         /* background color */
347         out32r ((pGD->dprBase + 0x0018), pGD->bg);
348
349         /* xcolor */
350         out32r ((pGD->dprBase + 0x0020), 0x00ffffff);
351
352         /* xcolor mask */
353         out32r ((pGD->dprBase + 0x0024), 0x00ffffff);
354
355         /* bit mask */
356         out32r ((pGD->dprBase + 0x0028), 0x00ffffff);
357
358         /* load mono pattern */
359         out32r ((pGD->dprBase + 0x0034), 0);
360         out32r ((pGD->dprBase + 0x0038), 0);
361 }
362
363 static struct pci_device_id supported[] = {
364         { PCI_VENDOR_ID_SMI, PCI_DEVICE_ID_SMI_710 },
365         { PCI_VENDOR_ID_SMI, PCI_DEVICE_ID_SMI_712 },
366         { PCI_VENDOR_ID_SMI, PCI_DEVICE_ID_SMI_810 },
367         { }
368 };
369
370 /*****************************************************************************/
371 static void smiLoadMsr (struct ctfb_res_modes *mode)
372 {
373         unsigned char h_synch_high, v_synch_high;
374         register GraphicDevice *pGD  = (GraphicDevice *)&smi;
375
376         h_synch_high = (mode->sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : 0x40;  /* horizontal Synch High active */
377         v_synch_high = (mode->sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : 0x80; /* vertical Synch High active */
378         out8 (SMI_MISC_REG, (h_synch_high | v_synch_high | 0x29));
379         /* upper64K==0x20, CLC2select==0x08, RAMenable==0x02!(todo), CGA==0x01
380          * Selects the upper 64KB page.Bit5=1
381          * CLK2 (left reserved in standard VGA) Bit3|2=1|0
382          * Disables CPU access to frame buffer. Bit1=0
383          * Sets the I/O address decode for ST01, FCR, and all CR registers
384          * to the 3Dx I/O address range (CGA emulation). Bit0=1
385          */
386 }
387 /*****************************************************************************/
388 static void smiLoadCrt (struct ctfb_res_modes *var, int bits_per_pixel)
389 {
390         unsigned char cr[0x7a];
391         int i;
392         unsigned int hd, hs, he, ht, hbs, hbe;  /* Horizontal.  */
393         unsigned int vd, vs, ve, vt, vbs, vbe;  /* vertical */
394         unsigned int bpp, wd, dblscan, interlaced;
395
396         const int LineCompare = 0x3ff;
397         unsigned int TextScanLines = 1; /* this is in fact a vertical zoom factor   */
398         register GraphicDevice *pGD  = (GraphicDevice *)&smi;
399
400         /* Horizontal */
401         hd = (var->xres) / 8;   /* HDisp.  */
402         hs = (var->xres + var->right_margin) / 8;       /* HsStrt  */
403         he = (var->xres + var->right_margin + var->hsync_len) / 8;      /* HsEnd   */
404         ht = (var->left_margin + var->xres + var->right_margin + var->hsync_len) / 8;   /* HTotal  */
405         /* Blank */
406         hbs = hd;
407         hbe = 0; /* Blank end at 0 */
408
409         /* Vertical */
410         vd = var->yres;         /* VDisplay   */
411         vs = var->yres + var->lower_margin;     /* VSyncStart */
412         ve = var->yres + var->lower_margin + var->vsync_len;    /* VSyncEnd */
413         vt = var->upper_margin + var->yres + var->lower_margin + var->vsync_len;        /* VTotal  */
414         vbs = vd;
415         vbe = 0;
416
417         bpp = bits_per_pixel;
418         dblscan = (var->vmode & FB_VMODE_DOUBLE) ? 1 : 0;
419         interlaced = var->vmode & FB_VMODE_INTERLACED;
420
421
422         if (bpp == 15)
423                 bpp = 16;
424         wd = var->xres * bpp / 64;      /* double words per line */
425         if (interlaced) {       /* we divide all vertical timings, exept vd */
426                 vs >>= 1;
427                 vbs >>= 1;
428                 ve >>= 1;
429                 vt >>= 1;
430         }
431
432         memset (cr, 0, sizeof (cr));
433         cr[0x00] = ht - 5;
434         cr[0x01] = hd - 1;
435         cr[0x02] = hbs - 1;
436         cr[0x03] = (hbe & 0x1F);
437         cr[0x04] = hs;
438         cr[0x05] = ((hbe & 0x20) << 2) | (he & 0x1f);
439
440         cr[0x06] = (vt - 2) & 0xFF;
441         cr[0x07] = (((vt - 2) & 0x100) >> 8)
442                 | (((vd - 1) & 0x100) >> 7)
443                 | ((vs & 0x100) >> 6)
444                 | (((vbs - 1) & 0x100) >> 5)
445                 | ((LineCompare & 0x100) >> 4)
446                 | (((vt - 2) & 0x200) >> 4)
447                 | (((vd - 1) & 0x200) >> 3)
448                 | ((vs & 0x200) >> 2);
449
450         cr[0x30] = ((vt - 2) & 0x400) >> 7
451                 | (((vd - 1) & 0x400) >> 8)
452                 | (((vbs - 1) & 0x400) >> 9)
453                 | ((vs & 0x400) >> 10)
454                 | (interlaced) ? 0x80 : 0;
455
456
457         cr[0x08] = 0x00;
458         cr[0x09] = (dblscan << 7)
459                 | ((LineCompare & 0x200) >> 3)
460                 | (((vbs - 1) & 0x200) >> 4)
461                 | (TextScanLines - 1);
462
463         cr[0x10] = vs & 0xff;   /* VSyncPulseStart */
464         cr[0x11] = (ve & 0x0f);
465         cr[0x12] = (vd - 1) & 0xff;     /* LineCount  */
466         cr[0x13] = wd & 0xff;
467         cr[0x14] = 0x40;
468         cr[0x15] = (vbs - 1) & 0xff;
469         cr[0x16] = vbe & 0xff;
470         cr[0x17] = 0xe3;        /* but it does not work */
471         cr[0x18] = 0xff & LineCompare;
472         cr[0x22] = 0x00;        /* todo? */
473
474
475         /* now set the registers */
476         for (i = 0; i <= 0x18; i++) {   /*CR00 .. CR18 */
477                 smiWrite (SMI_INDX_D4, i, cr[i]);
478         }
479         i = 0x22;               /*CR22 */
480         smiWrite (SMI_INDX_D4, i, cr[i]);
481         i = 0x30;               /*CR30 */
482         smiWrite (SMI_INDX_D4, i, cr[i]);
483 }
484
485 /*****************************************************************************/
486 #define REF_FREQ        14318180
487 #define PMIN            1
488 #define PMAX            255
489 #define QMIN            1
490 #define QMAX            63
491
492 static unsigned int FindPQ (unsigned int freq, unsigned int *pp, unsigned int *pq)
493 {
494         unsigned int n = QMIN, m = 0;
495         long long int L = 0, P = freq, Q = REF_FREQ, H = P >> 1;
496         long long int D = 0x7ffffffffffffffLL;
497
498         for (n = QMIN; n <= QMAX; n++) {
499                 m = PMIN;       /* p/q ~ freq/ref -> p*ref-freq*q ~ 0 */
500                 L = P * n - m * Q;
501                 while (L > 0 && m < PMAX) {
502                         L -= REF_FREQ;  /* difference is greater as 0 subtract fref */
503                         m++;    /* and increment m */
504                 }
505                 /* difference is less or equal than 0 or m > maximum */
506                 if (m > PMAX)
507                         break;  /* no solution: if we increase n we get the same situation */
508                 /* L is <= 0 now */
509                 if (-L > H && m > PMIN) {       /* if difference > the half fref */
510                         L += REF_FREQ;  /* we take the situation before */
511                         m--;    /* because its closer to 0 */
512                 }
513                 L = (L < 0) ? -L : +L;  /* absolute value */
514                 if (D < L)      /* if last difference was better take next n */
515                         continue;
516                 D = L;
517                 *pp = m;
518                 *pq = n;        /*  keep improved data */
519                 if (D == 0)
520                         break;  /* best result we can get */
521         }
522         return (unsigned int) (0xffffffff & D);
523 }
524
525 /*****************************************************************************/
526 static void smiLoadCcr (struct ctfb_res_modes *var, unsigned short device_id)
527 {
528         unsigned int p = 0;
529         unsigned int q = 0;
530         long long freq;
531         register GraphicDevice *pGD  = (GraphicDevice *)&smi;
532
533         smiWrite (SMI_INDX_C4, 0x65, 0);
534         smiWrite (SMI_INDX_C4, 0x66, 0);
535         smiWrite (SMI_INDX_C4, 0x68, 0x50);
536         if (device_id == PCI_DEVICE_ID_SMI_810) {
537                 smiWrite (SMI_INDX_C4, 0x69, 0x3);
538         } else {
539                 smiWrite (SMI_INDX_C4, 0x69, 0x0);
540         }
541
542         /* Memory clock */
543         switch (device_id) {
544         case PCI_DEVICE_ID_SMI_710 :
545                 smiWrite (SMI_INDX_C4, 0x6a, 0x75);
546                 break;
547         case PCI_DEVICE_ID_SMI_712 :
548                 smiWrite (SMI_INDX_C4, 0x6a, 0x80);
549                 break;
550         default :
551                 smiWrite (SMI_INDX_C4, 0x6a, 0x53);
552                 break;
553         }
554         smiWrite (SMI_INDX_C4, 0x6b, 0x15);
555
556         /* VCLK */
557         freq = 1000000000000LL / var -> pixclock;
558
559         FindPQ ((unsigned int)freq, &p, &q);
560
561         smiWrite (SMI_INDX_C4, 0x6c, p);
562         smiWrite (SMI_INDX_C4, 0x6d, q);
563
564 }
565
566 /*******************************************************************************
567  *
568  * Init video chip with common Linux graphic modes (lilo)
569  */
570 void *video_hw_init (void)
571 {
572         GraphicDevice *pGD = (GraphicDevice *)&smi;
573         unsigned short device_id;
574         pci_dev_t devbusfn;
575         int videomode;
576         unsigned long t1, hsynch, vsynch;
577         unsigned int pci_mem_base, *vm;
578         char *penv;
579         int tmp, i, bits_per_pixel;
580         struct ctfb_res_modes *res_mode;
581         struct ctfb_res_modes var_mode;
582         unsigned char videoout;
583
584         /* Search for video chip */
585         printf("Video: ");
586
587         if ((devbusfn = pci_find_devices(supported, 0)) < 0)
588         {
589                 printf ("Controller not found !\n");
590                 return (NULL);
591         }
592
593         /* PCI setup */
594         pci_write_config_dword (devbusfn, PCI_COMMAND, (PCI_COMMAND_MEMORY | PCI_COMMAND_IO));
595         pci_read_config_word (devbusfn, PCI_DEVICE_ID, &device_id);
596         pci_read_config_dword (devbusfn, PCI_BASE_ADDRESS_0, &pci_mem_base);
597         pci_mem_base = pci_mem_to_phys (devbusfn, pci_mem_base);
598
599         tmp = 0;
600
601         videomode = CFG_DEFAULT_VIDEO_MODE;
602         /* get video mode via environment */
603         if ((penv = getenv ("videomode")) != NULL) {
604                 /* deceide if it is a string */
605                 if (penv[0] <= '9') {
606                         videomode = (int) simple_strtoul (penv, NULL, 16);
607                         tmp = 1;
608                 }
609         } else {
610                 tmp = 1;
611         }
612         if (tmp) {
613                 /* parameter are vesa modes */
614                 /* search params */
615                 for (i = 0; i < VESA_MODES_COUNT; i++) {
616                         if (vesa_modes[i].vesanr == videomode)
617                                 break;
618                 }
619                 if (i == VESA_MODES_COUNT) {
620                         printf ("no VESA Mode found, switching to mode 0x%x ", CFG_DEFAULT_VIDEO_MODE);
621                         i = 0;
622                 }
623                 res_mode =
624                         (struct ctfb_res_modes *) &res_mode_init[vesa_modes[i].
625                                                                  resindex];
626                 bits_per_pixel = vesa_modes[i].bits_per_pixel;
627         } else {
628
629                 res_mode = (struct ctfb_res_modes *) &var_mode;
630                 bits_per_pixel = video_get_params (res_mode, penv);
631         }
632
633         /* calculate hsynch and vsynch freq (info only) */
634         t1 = (res_mode->left_margin + res_mode->xres +
635               res_mode->right_margin + res_mode->hsync_len) / 8;
636         t1 *= 8;
637         t1 *= res_mode->pixclock;
638         t1 /= 1000;
639         hsynch = 1000000000L / t1;
640         t1 *=
641                 (res_mode->upper_margin + res_mode->yres +
642                  res_mode->lower_margin + res_mode->vsync_len);
643         t1 /= 1000;
644         vsynch = 1000000000L / t1;
645
646         /* fill in Graphic device struct */
647         sprintf (pGD->modeIdent, "%dx%dx%d %ldkHz %ldHz", res_mode->xres,
648                  res_mode->yres, bits_per_pixel, (hsynch / 1000),
649                  (vsynch / 1000));
650         printf ("%s\n", pGD->modeIdent);
651         pGD->winSizeX = res_mode->xres;
652         pGD->winSizeY = res_mode->yres;
653         pGD->plnSizeX = res_mode->xres;
654         pGD->plnSizeY = res_mode->yres;
655         switch (bits_per_pixel) {
656         case 8:
657                 pGD->gdfBytesPP = 1;
658                 pGD->gdfIndex = GDF__8BIT_INDEX;
659                 break;
660         case 15:
661                 pGD->gdfBytesPP = 2;
662                 pGD->gdfIndex = GDF_15BIT_555RGB;
663                 break;
664         case 16:
665                 pGD->gdfBytesPP = 2;
666                 pGD->gdfIndex = GDF_16BIT_565RGB;
667                 break;
668         case 24:
669                 pGD->gdfBytesPP = 3;
670                 pGD->gdfIndex = GDF_24BIT_888RGB;
671                 break;
672         }
673
674         pGD->isaBase = CFG_ISA_IO;
675         pGD->pciBase = pci_mem_base;
676         pGD->dprBase = (pci_mem_base + 0x400000 + 0x8000);
677         pGD->vprBase = (pci_mem_base + 0x400000 + 0xc000);
678         pGD->cprBase = (pci_mem_base + 0x400000 + 0xe000);
679         pGD->frameAdrs = pci_mem_base;
680         pGD->memSize = VIDEO_MEM_SIZE;
681
682         /* Set up hardware : select color mode,
683            set Register base to isa 3dx for 3?x regs*/
684         out8 (SMI_MISC_REG, 0x01);
685
686         /* Turn off display */
687         smiWrite (SMI_INDX_C4, 0x01, 0x20);
688
689         /* Unlock ext. crt regs */
690         out8 (SMI_LOCK_REG, 0x40);
691
692         /* Unlock crt regs 0-7 */
693         smiWrite (SMI_INDX_D4, 0x11, 0x0e);
694
695         /* Sytem Control Register */
696         smiLoadRegs (SMI_INDX_C4, SMI_DATA_C5, SMI_SCR, sizeof(SMI_SCR));
697
698         /* extented CRT Register */
699         smiLoadRegs (SMI_INDX_D4, SMI_DATA_D5, SMI_EXT_CRT, sizeof(SMI_EXT_CRT));
700
701         /* Attributes controller registers */
702         smiLoadRegs (SMI_INDX_ATTR, SMI_INDX_ATTR, SMI_ATTR, sizeof(SMI_ATTR));
703
704         /* Graphics Controller Register */
705         smiLoadRegs (SMI_INDX_CE, SMI_DATA_CF, SMI_GCR, sizeof(SMI_GCR));
706
707         /* Sequencer Register */
708         smiLoadRegs (SMI_INDX_C4, SMI_DATA_C5, SMI_SEQR, sizeof(SMI_SEQR));
709
710         /* Power Control Register */
711         smiLoadRegs (SMI_INDX_C4, SMI_DATA_C5, SMI_PCR, sizeof(SMI_PCR));
712
713         /* Memory Control Register */
714         /* Register MSR62 is a power on configurable register. We don't */
715         /* modify it */
716         smiLoadRegs (SMI_INDX_C4, SMI_DATA_C5, SMI_MCR, sizeof(SMI_MCR));
717
718         /* Set misc output register */
719         smiLoadMsr (res_mode);
720
721         /* Set CRT and Clock control registers */
722         smiLoadCrt (res_mode, bits_per_pixel);
723
724         smiLoadCcr (res_mode, device_id);
725
726         /* Hardware Cusor Register */
727         smiLoadRegs (SMI_INDX_C4, SMI_DATA_C5, SMI_HCR, sizeof(SMI_HCR));
728
729         /* Enable  Display  */
730         videoout = 2;       /* Default output is CRT */
731         if ((penv = getenv ("videoout")) != NULL) {
732                 /* deceide if it is a string */
733                 videoout = (int) simple_strtoul (penv, NULL, 16);
734         }
735         smiWrite (SMI_INDX_C4, 0x31, videoout);
736
737         /* Video processor default setup */
738         smiInitVideoProcessor ();
739
740         /* Capture port default setup */
741         smiInitCapturePort ();
742
743         /* Drawing engine default setup */
744         smiInitDrawingEngine ();
745
746         /* Turn on display */
747         smiWrite (0x3c4, 0x01, 0x01);
748
749         /* Clear video memory */
750         i = pGD->memSize/4;
751         vm = (unsigned int *)pGD->pciBase;
752         while(i--)
753                 *vm++ = 0;
754         return ((void*)&smi);
755 }
756
757 /*******************************************************************************
758  *
759  * Drawing engine fill on screen region
760  */
761 void video_hw_rectfill (
762         unsigned int bpp,             /* bytes per pixel */
763         unsigned int dst_x,           /* dest pos x */
764         unsigned int dst_y,           /* dest pos y */
765         unsigned int dim_x,           /* frame width */
766         unsigned int dim_y,           /* frame height */
767         unsigned int color            /* fill color */
768         )
769 {
770         register GraphicDevice *pGD = (GraphicDevice *)&smi;
771         register unsigned int control;
772
773         dim_x *= bpp;
774
775         out32r ((pGD->dprBase + 0x0014), color);
776         out32r ((pGD->dprBase + 0x0004), ((dst_x<<16) | dst_y));
777         out32r ((pGD->dprBase + 0x0008), ((dim_x<<16) | dim_y));
778
779         control = 0x0000ffff &  in32r ((pGD->dprBase + 0x000c));
780
781         control |= 0x80010000;
782
783         out32r ((pGD->dprBase + 0x000c),  control);
784
785         /* Wait for drawing processor */
786         do
787         {
788                 out8 ((pGD->isaBase + 0x3c4), 0x16);
789         } while (in8 (pGD->isaBase + 0x3c5) & 0x08);
790 }
791
792 /*******************************************************************************
793  *
794  * Drawing engine bitblt with screen region
795  */
796 void video_hw_bitblt (
797         unsigned int bpp,             /* bytes per pixel */
798         unsigned int src_x,           /* source pos x */
799         unsigned int src_y,           /* source pos y */
800         unsigned int dst_x,           /* dest pos x */
801         unsigned int dst_y,           /* dest pos y */
802         unsigned int dim_x,           /* frame width */
803         unsigned int dim_y            /* frame height */
804         )
805 {
806         register GraphicDevice *pGD = (GraphicDevice *)&smi;
807         register unsigned int control;
808
809         dim_x *= bpp;
810
811         if ((src_y<dst_y) || ((src_y==dst_y) && (src_x<dst_x)))
812         {
813                 out32r ((pGD->dprBase + 0x0000), (((src_x+dim_x-1)<<16) | (src_y+dim_y-1)));
814                 out32r ((pGD->dprBase + 0x0004), (((dst_x+dim_x-1)<<16) | (dst_y+dim_y-1)));
815                 control = 0x88000000;
816         } else {
817                 out32r ((pGD->dprBase + 0x0000), ((src_x<<16) | src_y));
818                 out32r ((pGD->dprBase + 0x0004), ((dst_x<<16) | dst_y));
819                 control = 0x80000000;
820         }
821
822         out32r ((pGD->dprBase + 0x0008), ((dim_x<<16) | dim_y));
823         control |= (0x0000ffff &  in32r ((pGD->dprBase + 0x000c)));
824         out32r ((pGD->dprBase + 0x000c), control);
825
826         /* Wait for drawing processor */
827         do
828         {
829                 out8 ((pGD->isaBase + 0x3c4), 0x16);
830         } while (in8 (pGD->isaBase + 0x3c5) & 0x08);
831 }
832
833 /*******************************************************************************
834  *
835  * Set a RGB color in the LUT (8 bit index)
836  */
837 void video_set_lut (
838         unsigned int index,           /* color number */
839         unsigned char r,              /* red */
840         unsigned char g,              /* green */
841         unsigned char b               /* blue */
842         )
843 {
844         register GraphicDevice *pGD = (GraphicDevice *)&smi;
845
846         out8 (SMI_LUT_MASK,  0xff);
847
848         out8 (SMI_LUT_START, (char)index);
849
850         out8 (SMI_LUT_RGB, r>>2);    /* red */
851         udelay (10);
852         out8 (SMI_LUT_RGB, g>>2);    /* green */
853         udelay (10);
854         out8 (SMI_LUT_RGB, b>>2);    /* blue */
855         udelay (10);
856 }
857
858 #endif /* CONFIG_VIDEO_SMI_LYNXEM */