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