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