Add documentation for Open Firmware Flat Tree and usage.
[oweals/u-boot.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 #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, q;
529         long long freq;
530         register GraphicDevice *pGD  = (GraphicDevice *)&smi;
531
532         smiWrite (SMI_INDX_C4, 0x65, 0);
533         smiWrite (SMI_INDX_C4, 0x66, 0);
534         smiWrite (SMI_INDX_C4, 0x68, 0x50);
535         if (device_id == PCI_DEVICE_ID_SMI_810) {
536                 smiWrite (SMI_INDX_C4, 0x69, 0x3);
537         } else {
538                 smiWrite (SMI_INDX_C4, 0x69, 0x0);
539         }
540
541         /* Memory clock */
542         switch (device_id) {
543         case PCI_DEVICE_ID_SMI_710 :
544                 smiWrite (SMI_INDX_C4, 0x6a, 0x75);
545                 break;
546         case PCI_DEVICE_ID_SMI_712 :
547                 smiWrite (SMI_INDX_C4, 0x6a, 0x80);
548                 break;
549         default :
550                 smiWrite (SMI_INDX_C4, 0x6a, 0x53);
551                 break;
552         }
553         smiWrite (SMI_INDX_C4, 0x6b, 0x15);
554
555         /* VCLK */
556         freq = 1000000000000LL / var -> pixclock;
557
558         FindPQ ((unsigned int)freq, &p, &q);
559
560         smiWrite (SMI_INDX_C4, 0x6c, p);
561         smiWrite (SMI_INDX_C4, 0x6d, q);
562
563 }
564
565 /*******************************************************************************
566  *
567  * Init video chip with common Linux graphic modes (lilo)
568  */
569 void *video_hw_init (void)
570 {
571         GraphicDevice *pGD = (GraphicDevice *)&smi;
572         unsigned short device_id;
573         pci_dev_t devbusfn;
574         int videomode;
575         unsigned long t1, hsynch, vsynch;
576         unsigned int pci_mem_base, *vm;
577         char *penv;
578         int tmp, i, bits_per_pixel;
579         struct ctfb_res_modes *res_mode;
580         struct ctfb_res_modes var_mode;
581         unsigned char videoout;
582
583         /* Search for video chip */
584         printf("Video: ");
585
586         if ((devbusfn = pci_find_devices(supported, 0)) < 0)
587         {
588                 printf ("Controller not found !\n");
589                 return (NULL);
590         }
591
592         /* PCI setup */
593         pci_write_config_dword (devbusfn, PCI_COMMAND, (PCI_COMMAND_MEMORY | PCI_COMMAND_IO));
594         pci_read_config_word (devbusfn, PCI_DEVICE_ID, &device_id);
595         pci_read_config_dword (devbusfn, PCI_BASE_ADDRESS_0, &pci_mem_base);
596         pci_mem_base = pci_mem_to_phys (devbusfn, pci_mem_base);
597
598         tmp = 0;
599
600         videomode = CFG_DEFAULT_VIDEO_MODE;
601         /* get video mode via environment */
602         if ((penv = getenv ("videomode")) != NULL) {
603                 /* deceide if it is a string */
604                 if (penv[0] <= '9') {
605                         videomode = (int) simple_strtoul (penv, NULL, 16);
606                         tmp = 1;
607                 }
608         } else {
609                 tmp = 1;
610         }
611         if (tmp) {
612                 /* parameter are vesa modes */
613                 /* search params */
614                 for (i = 0; i < VESA_MODES_COUNT; i++) {
615                         if (vesa_modes[i].vesanr == videomode)
616                                 break;
617                 }
618                 if (i == VESA_MODES_COUNT) {
619                         printf ("no VESA Mode found, switching to mode 0x%x ", CFG_DEFAULT_VIDEO_MODE);
620                         i = 0;
621                 }
622                 res_mode =
623                         (struct ctfb_res_modes *) &res_mode_init[vesa_modes[i].
624                                                                  resindex];
625                 bits_per_pixel = vesa_modes[i].bits_per_pixel;
626         } else {
627
628                 res_mode = (struct ctfb_res_modes *) &var_mode;
629                 bits_per_pixel = video_get_params (res_mode, penv);
630         }
631
632         /* calculate hsynch and vsynch freq (info only) */
633         t1 = (res_mode->left_margin + res_mode->xres +
634               res_mode->right_margin + res_mode->hsync_len) / 8;
635         t1 *= 8;
636         t1 *= res_mode->pixclock;
637         t1 /= 1000;
638         hsynch = 1000000000L / t1;
639         t1 *=
640                 (res_mode->upper_margin + res_mode->yres +
641                  res_mode->lower_margin + res_mode->vsync_len);
642         t1 /= 1000;
643         vsynch = 1000000000L / t1;
644
645         /* fill in Graphic device struct */
646         sprintf (pGD->modeIdent, "%dx%dx%d %ldkHz %ldHz", res_mode->xres,
647                  res_mode->yres, bits_per_pixel, (hsynch / 1000),
648                  (vsynch / 1000));
649         printf ("%s\n", pGD->modeIdent);
650         pGD->winSizeX = res_mode->xres;
651         pGD->winSizeY = res_mode->yres;
652         pGD->plnSizeX = res_mode->xres;
653         pGD->plnSizeY = res_mode->yres;
654         switch (bits_per_pixel) {
655         case 8:
656                 pGD->gdfBytesPP = 1;
657                 pGD->gdfIndex = GDF__8BIT_INDEX;
658                 break;
659         case 15:
660                 pGD->gdfBytesPP = 2;
661                 pGD->gdfIndex = GDF_15BIT_555RGB;
662                 break;
663         case 16:
664                 pGD->gdfBytesPP = 2;
665                 pGD->gdfIndex = GDF_16BIT_565RGB;
666                 break;
667         case 24:
668                 pGD->gdfBytesPP = 3;
669                 pGD->gdfIndex = GDF_24BIT_888RGB;
670                 break;
671         }
672
673         pGD->isaBase = CFG_ISA_IO;
674         pGD->pciBase = pci_mem_base;
675         pGD->dprBase = (pci_mem_base + 0x400000 + 0x8000);
676         pGD->vprBase = (pci_mem_base + 0x400000 + 0xc000);
677         pGD->cprBase = (pci_mem_base + 0x400000 + 0xe000);
678         pGD->frameAdrs = pci_mem_base;
679         pGD->memSize = VIDEO_MEM_SIZE;
680
681         /* Set up hardware : select color mode,
682            set Register base to isa 3dx for 3?x regs*/
683         out8 (SMI_MISC_REG, 0x01);
684
685         /* Turn off display */
686         smiWrite (SMI_INDX_C4, 0x01, 0x20);
687
688         /* Unlock ext. crt regs */
689         out8 (SMI_LOCK_REG, 0x40);
690
691         /* Unlock crt regs 0-7 */
692         smiWrite (SMI_INDX_D4, 0x11, 0x0e);
693
694         /* Sytem Control Register */
695         smiLoadRegs (SMI_INDX_C4, SMI_DATA_C5, SMI_SCR, sizeof(SMI_SCR));
696
697         /* extented CRT Register */
698         smiLoadRegs (SMI_INDX_D4, SMI_DATA_D5, SMI_EXT_CRT, sizeof(SMI_EXT_CRT));
699
700         /* Attributes controller registers */
701         smiLoadRegs (SMI_INDX_ATTR, SMI_INDX_ATTR, SMI_ATTR, sizeof(SMI_ATTR));
702
703         /* Graphics Controller Register */
704         smiLoadRegs (SMI_INDX_CE, SMI_DATA_CF, SMI_GCR, sizeof(SMI_GCR));
705
706         /* Sequencer Register */
707         smiLoadRegs (SMI_INDX_C4, SMI_DATA_C5, SMI_SEQR, sizeof(SMI_SEQR));
708
709         /* Power Control Register */
710         smiLoadRegs (SMI_INDX_C4, SMI_DATA_C5, SMI_PCR, sizeof(SMI_PCR));
711
712         /* Memory Control Register */
713         /* Register MSR62 is a power on configurable register. We don't */
714         /* modify it */
715         smiLoadRegs (SMI_INDX_C4, SMI_DATA_C5, SMI_MCR, sizeof(SMI_MCR));
716
717         /* Set misc output register */
718         smiLoadMsr (res_mode);
719
720         /* Set CRT and Clock control registers */
721         smiLoadCrt (res_mode, bits_per_pixel);
722
723         smiLoadCcr (res_mode, device_id);
724
725         /* Hardware Cusor Register */
726         smiLoadRegs (SMI_INDX_C4, SMI_DATA_C5, SMI_HCR, sizeof(SMI_HCR));
727
728         /* Enable  Display  */
729         videoout = 2;       /* Default output is CRT */
730         if ((penv = getenv ("videoout")) != NULL) {
731                 /* deceide if it is a string */
732                 videoout = (int) simple_strtoul (penv, NULL, 16);
733         }
734         smiWrite (SMI_INDX_C4, 0x31, videoout);
735
736         /* Video processor default setup */
737         smiInitVideoProcessor ();
738
739         /* Capture port default setup */
740         smiInitCapturePort ();
741
742         /* Drawing engine default setup */
743         smiInitDrawingEngine ();
744
745         /* Turn on display */
746         smiWrite (0x3c4, 0x01, 0x01);
747
748         /* Clear video memory */
749         i = pGD->memSize/4;
750         vm = (unsigned int *)pGD->pciBase;
751         while(i--)
752                 *vm++ = 0;
753         return ((void*)&smi);
754 }
755
756 /*******************************************************************************
757  *
758  * Drawing engine fill on screen region
759  */
760 void video_hw_rectfill (
761         unsigned int bpp,             /* bytes per pixel */
762         unsigned int dst_x,           /* dest pos x */
763         unsigned int dst_y,           /* dest pos y */
764         unsigned int dim_x,           /* frame width */
765         unsigned int dim_y,           /* frame height */
766         unsigned int color            /* fill color */
767         )
768 {
769         register GraphicDevice *pGD = (GraphicDevice *)&smi;
770         register unsigned int control;
771
772         dim_x *= bpp;
773
774         out32r ((pGD->dprBase + 0x0014), color);
775         out32r ((pGD->dprBase + 0x0004), ((dst_x<<16) | dst_y));
776         out32r ((pGD->dprBase + 0x0008), ((dim_x<<16) | dim_y));
777
778         control = 0x0000ffff &  in32r ((pGD->dprBase + 0x000c));
779
780         control |= 0x80010000;
781
782         out32r ((pGD->dprBase + 0x000c),  control);
783
784         /* Wait for drawing processor */
785         do
786         {
787                 out8 ((pGD->isaBase + 0x3c4), 0x16);
788         } while (in8 (pGD->isaBase + 0x3c5) & 0x08);
789 }
790
791 /*******************************************************************************
792  *
793  * Drawing engine bitblt with screen region
794  */
795 void video_hw_bitblt (
796         unsigned int bpp,             /* bytes per pixel */
797         unsigned int src_x,           /* source pos x */
798         unsigned int src_y,           /* source pos y */
799         unsigned int dst_x,           /* dest pos x */
800         unsigned int dst_y,           /* dest pos y */
801         unsigned int dim_x,           /* frame width */
802         unsigned int dim_y            /* frame height */
803         )
804 {
805         register GraphicDevice *pGD = (GraphicDevice *)&smi;
806         register unsigned int control;
807
808         dim_x *= bpp;
809
810         if ((src_y<dst_y) || ((src_y==dst_y) && (src_x<dst_x)))
811         {
812                 out32r ((pGD->dprBase + 0x0000), (((src_x+dim_x-1)<<16) | (src_y+dim_y-1)));
813                 out32r ((pGD->dprBase + 0x0004), (((dst_x+dim_x-1)<<16) | (dst_y+dim_y-1)));
814                 control = 0x88000000;
815         } else {
816                 out32r ((pGD->dprBase + 0x0000), ((src_x<<16) | src_y));
817                 out32r ((pGD->dprBase + 0x0004), ((dst_x<<16) | dst_y));
818                 control = 0x80000000;
819         }
820
821         out32r ((pGD->dprBase + 0x0008), ((dim_x<<16) | dim_y));
822         control |= (0x0000ffff &  in32r ((pGD->dprBase + 0x000c)));
823         out32r ((pGD->dprBase + 0x000c), control);
824
825         /* Wait for drawing processor */
826         do
827         {
828                 out8 ((pGD->isaBase + 0x3c4), 0x16);
829         } while (in8 (pGD->isaBase + 0x3c5) & 0x08);
830 }
831
832 /*******************************************************************************
833  *
834  * Set a RGB color in the LUT (8 bit index)
835  */
836 void video_set_lut (
837         unsigned int index,           /* color number */
838         unsigned char r,              /* red */
839         unsigned char g,              /* green */
840         unsigned char b               /* blue */
841         )
842 {
843         register GraphicDevice *pGD = (GraphicDevice *)&smi;
844
845         out8 (SMI_LUT_MASK,  0xff);
846
847         out8 (SMI_LUT_START, (char)index);
848
849         out8 (SMI_LUT_RGB, r>>2);    /* red */
850         udelay (10);
851         out8 (SMI_LUT_RGB, g>>2);    /* green */
852         udelay (10);
853         out8 (SMI_LUT_RGB, b>>2);    /* blue */
854         udelay (10);
855 }
856
857 #endif /* CONFIG_VIDEO_SMI_LYNXEM */