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