]> git.ipfire.org Git - people/ms/u-boot.git/blame - drivers/smiLynxEM.c
Files include/linux/byteorder/{big,little}_endian.h define
[people/ms/u-boot.git] / drivers / smiLynxEM.c
CommitLineData
c609719b
WD
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
eeb1b77b 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
c609719b
WD
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 *
eeb1b77b
WD
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>
c609719b
WD
39 */
40
41#include <common.h>
42
43#if defined(CONFIG_VIDEO_SMI_LYNXEM)
44
45#include <pci.h>
46#include <video_fb.h>
eeb1b77b 47#include "videomodes.h"
c609719b
WD
48/*
49 * Export Graphic Device
50 */
51GraphicDevice smi;
52
53/*
54 * SMI 710/712 have 4MB internal RAM; SMI 810 2MB internal + 2MB external
55 */
eeb1b77b 56#define VIDEO_MEM_SIZE 0x400000
c609719b
WD
57
58
59/*
60 * ISA mapped regs
61 */
eeb1b77b
WD
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 */
c609719b
WD
75
76/*
77 * Video processor control
eeb1b77b 78 */
c609719b 79typedef struct {
eeb1b77b
WD
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;
c609719b
WD
89} SmiVideoProc;
90
91/*
92 * Video window control
93 */
94typedef struct {
eeb1b77b
WD
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;
c609719b
WD
104} SmiVideoWin;
105
106/*
107 * Capture port control
108 */
109typedef struct {
eeb1b77b
WD
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;
c609719b
WD
119} SmiCapturePort;
120
121
c609719b
WD
122/*
123 * Register values for common video modes
124 */
eeb1b77b
WD
125static char SMI_SCR[] = {
126 /* all modes */
127 0x10, 0xff, 0x11, 0xff, 0x12, 0xff, 0x13, 0xff, 0x15, 0x90,
128 0x17, 0x20, 0x18, 0xb1, 0x19, 0x00,
c609719b 129};
eeb1b77b
WD
130static char SMI_EXT_CRT[] = {
131 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00,
ccd9d3d6 132 0x36, 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3f, 0x00,
c609719b 133};
eeb1b77b
WD
134static 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,
c609719b 139};
eeb1b77b
WD
140static char SMI_GCR[18] = {
141 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x40,
ccd9d3d6 142 0x06, 0x05, 0x07, 0x0f, 0x08, 0xff,
c609719b 143};
eeb1b77b 144static char SMI_SEQR[] = {
ccd9d3d6 145 0x00, 0x00, 0x01, 0x01, 0x02, 0x0f, 0x03, 0x03, 0x04, 0x0e, 0x00, 0x03,
c609719b 146};
eeb1b77b 147static char SMI_PCR [] = {
ccd9d3d6 148 0x20, 0x04, 0x21, 0x30, 0x22, 0x00, 0x23, 0x00, 0x24, 0x00,
c609719b 149};
eeb1b77b 150static char SMI_MCR[] = {
b79a11cc 151 0x60, 0x01, 0x61, 0x00,
ccd9d3d6
WD
152#ifdef CONFIG_HMI1001
153 0x62, 0x74, /* Memory type is not configured by pins on HMI1001 */
154#endif
c609719b
WD
155};
156
eeb1b77b
WD
157static char SMI_HCR[] = {
158 0x80, 0xff, 0x81, 0x07, 0x82, 0x00, 0x83, 0xff, 0x84, 0xff, 0x88, 0x00,
ccd9d3d6 159 0x89, 0x02, 0x8a, 0x80, 0x8b, 0x01, 0x8c, 0xff, 0x8d, 0x00,
c609719b
WD
160};
161
c609719b
WD
162
163/*******************************************************************************
eeb1b77b
WD
164 *
165 * Write SMI ISA register
166 */
c609719b
WD
167static void smiWrite (unsigned short index, char reg, char val)
168{
eeb1b77b 169 register GraphicDevice *pGD = (GraphicDevice *)&smi;
c609719b 170
eeb1b77b
WD
171 out8 ((pGD->isaBase + index), reg);
172 out8 ((pGD->isaBase + index + 1), val);
c609719b
WD
173}
174
175/*******************************************************************************
eeb1b77b
WD
176 *
177 * Write a table of SMI ISA register
178 */
c609719b 179static void smiLoadRegs (
eeb1b77b
WD
180 unsigned int iReg,
181 unsigned int dReg,
182 char *regTab,
183 unsigned int tabSize
184 )
c609719b 185{
eeb1b77b
WD
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 }
c609719b
WD
200}
201
202/*******************************************************************************
eeb1b77b
WD
203 *
204 * Init capture port registers
205 */
c609719b
WD
206static void smiInitCapturePort (void)
207{
eeb1b77b
WD
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);
c609719b
WD
219}
220
221
222/*******************************************************************************
eeb1b77b
WD
223 *
224 * Init video processor registers
225 */
c609719b
WD
226static void smiInitVideoProcessor (void)
227{
eeb1b77b
WD
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;
c609719b 233
eeb1b77b
WD
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;
c609719b 239
eeb1b77b
WD
240 /* color key */
241 out32r ((pGD->vprBase + 0x0004), pVP->colorKey);
c609719b 242
eeb1b77b
WD
243 /* color key mask */
244 out32r ((pGD->vprBase + 0x0008), pVP->colorKeyMask);
c609719b 245
eeb1b77b
WD
246 /* data src start adrs */
247 out32r ((pGD->vprBase + 0x000c), pVP->start / 8);
c609719b 248
eeb1b77b
WD
249 /* data width and offset */
250 out32r ((pGD->vprBase + 0x0010),
251 ((pVP->offset / 8 * pGD->gdfBytesPP) << 16) |
252 (pGD->plnSizeX / 8 * pGD->gdfBytesPP));
c609719b 253
eeb1b77b
WD
254 /* video window 1 */
255 out32r ((pGD->vprBase + 0x0014),
256 ((pVWin->top << 16) | pVWin->left));
c609719b 257
eeb1b77b
WD
258 out32r ((pGD->vprBase + 0x0018),
259 ((pVWin->bottom << 16) | pVWin->right));
c609719b 260
eeb1b77b 261 out32r ((pGD->vprBase + 0x001c), pVWin->srcStart / 8);
c609719b 262
eeb1b77b
WD
263 out32r ((pGD->vprBase + 0x0020),
264 (((pVWin->offset / 8) << 16) | (pVWin->width / 8)));
c609719b 265
eeb1b77b
WD
266 out32r ((pGD->vprBase + 0x0024),
267 (((pVWin->hStretch) << 8) | pVWin->vStretch));
c609719b 268
eeb1b77b
WD
269 /* video window 2 */
270 out32r ((pGD->vprBase + 0x0028),
271 ((pVWin->top << 16) | pVWin->left));
c609719b 272
eeb1b77b
WD
273 out32r ((pGD->vprBase + 0x002c),
274 ((pVWin->bottom << 16) | pVWin->right));
c609719b 275
eeb1b77b
WD
276 out32r ((pGD->vprBase + 0x0030),
277 pVWin->srcStart / 8);
c609719b 278
eeb1b77b
WD
279 out32r ((pGD->vprBase + 0x0034),
280 (((pVWin->offset / 8) << 16) | (pVWin->width / 8)));
c609719b 281
eeb1b77b
WD
282 out32r ((pGD->vprBase + 0x0038),
283 (((pVWin->hStretch) << 8) | pVWin->vStretch));
c609719b 284
eeb1b77b
WD
285 /* fifo prio control */
286 out32r ((pGD->vprBase + 0x0054), pVP->fifoPrio);
c609719b 287
eeb1b77b
WD
288 /* fifo empty request levell */
289 out32r ((pGD->vprBase + 0x0058), pVP->fifoERL);
c609719b 290
eeb1b77b
WD
291 /* conversion constant */
292 out32r ((pGD->vprBase + 0x005c), pVP->YUVtoRGB);
c609719b 293
eeb1b77b
WD
294 /* vpr control word */
295 out32r ((pGD->vprBase + 0x0000), pVP->control);
c609719b
WD
296}
297
298/******************************************************************************
299 *
300 * Init drawing engine registers
301 */
302static void smiInitDrawingEngine (void)
303{
eeb1b77b
WD
304 GraphicDevice *pGD = (GraphicDevice *)&smi;
305 unsigned int val;
c609719b 306
eeb1b77b
WD
307 /* don't start now */
308 out32r ((pGD->dprBase + 0x000c), 0x000f0000);
c609719b 309
eeb1b77b
WD
310 /* set rop2 to copypen */
311 val = 0xffff3ff0 & in32r ((pGD->dprBase + 0x000c));
312 out32r ((pGD->dprBase + 0x000c), (val | 0x8000 | 0x0c));
c609719b 313
eeb1b77b
WD
314 /* set clip rect */
315 out32r ((pGD->dprBase + 0x002c), 0);
316 out32r ((pGD->dprBase + 0x0030),
317 ((pGD->winSizeY<<16) | pGD->winSizeX * pGD->gdfBytesPP ));
c609719b 318
eeb1b77b
WD
319 /* src row pitch */
320 val = 0xffff0000 & (in32r ((pGD->dprBase + 0x0010)));
321 out32r ((pGD->dprBase + 0x0010),
322 (val | pGD->plnSizeX * pGD->gdfBytesPP));
c609719b 323
eeb1b77b
WD
324 /* dst row pitch */
325 val = 0x0000ffff & (in32r ((pGD->dprBase + 0x0010)));
326 out32r ((pGD->dprBase + 0x0010),
327 (((pGD->plnSizeX * pGD->gdfBytesPP)<<16) | val));
c609719b 328
eeb1b77b
WD
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);
c609719b 334
eeb1b77b
WD
335 /* src base adrs */
336 out32r ((pGD->dprBase + 0x0040),
337 (((pGD->frameAdrs/8) & 0x000fffff)));
c609719b 338
eeb1b77b
WD
339 /* dst base adrs */
340 out32r ((pGD->dprBase + 0x0044),
341 (((pGD->frameAdrs/8) & 0x000fffff)));
c609719b 342
eeb1b77b
WD
343 /* foreground color */
344 out32r ((pGD->dprBase + 0x0014), pGD->fg);
c609719b 345
eeb1b77b
WD
346 /* background color */
347 out32r ((pGD->dprBase + 0x0018), pGD->bg);
c609719b 348
eeb1b77b
WD
349 /* xcolor */
350 out32r ((pGD->dprBase + 0x0020), 0x00ffffff);
c609719b 351
eeb1b77b
WD
352 /* xcolor mask */
353 out32r ((pGD->dprBase + 0x0024), 0x00ffffff);
c609719b 354
eeb1b77b
WD
355 /* bit mask */
356 out32r ((pGD->dprBase + 0x0028), 0x00ffffff);
c609719b 357
eeb1b77b
WD
358 /* load mono pattern */
359 out32r ((pGD->dprBase + 0x0034), 0);
360 out32r ((pGD->dprBase + 0x0038), 0);
c609719b
WD
361}
362
363static struct pci_device_id supported[] = {
eeb1b77b
WD
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 { }
c609719b
WD
368};
369
eeb1b77b
WD
370/*****************************************************************************/
371static 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/*****************************************************************************/
388static 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 */
b79a11cc 406 hbs = hd;
eeb1b77b
WD
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;
b79a11cc 416
eeb1b77b
WD
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);
b79a11cc 439
eeb1b77b
WD
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;
b79a11cc 455
eeb1b77b
WD
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 */
b79a11cc 464 cr[0x11] = (ve & 0x0f);
eeb1b77b
WD
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
492static 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 */
b79a11cc 500 L = P * n - m * Q;
eeb1b77b
WD
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/*****************************************************************************/
526static void smiLoadCcr (struct ctfb_res_modes *var, unsigned short device_id)
527{
77ddac94
WD
528 unsigned int p = 0;
529 unsigned int q = 0;
eeb1b77b
WD
530 long long freq;
531 register GraphicDevice *pGD = (GraphicDevice *)&smi;
532
533 smiWrite (SMI_INDX_C4, 0x65, 0);
534 smiWrite (SMI_INDX_C4, 0x66, 0);
535 smiWrite (SMI_INDX_C4, 0x68, 0x50);
536 if (device_id == PCI_DEVICE_ID_SMI_810) {
537 smiWrite (SMI_INDX_C4, 0x69, 0x3);
538 } else {
539 smiWrite (SMI_INDX_C4, 0x69, 0x0);
540 }
541
542 /* Memory clock */
543 switch (device_id) {
544 case PCI_DEVICE_ID_SMI_710 :
545 smiWrite (SMI_INDX_C4, 0x6a, 0x75);
546 break;
547 case PCI_DEVICE_ID_SMI_712 :
548 smiWrite (SMI_INDX_C4, 0x6a, 0x80);
549 break;
550 default :
551 smiWrite (SMI_INDX_C4, 0x6a, 0x53);
552 break;
553 }
554 smiWrite (SMI_INDX_C4, 0x6b, 0x15);
b79a11cc 555
eeb1b77b 556 /* VCLK */
eedcd078 557 freq = 1000000000000LL / var -> pixclock;
b79a11cc 558
eeb1b77b 559 FindPQ ((unsigned int)freq, &p, &q);
b79a11cc 560
eeb1b77b
WD
561 smiWrite (SMI_INDX_C4, 0x6c, p);
562 smiWrite (SMI_INDX_C4, 0x6d, q);
563
564}
c609719b
WD
565
566/*******************************************************************************
eeb1b77b
WD
567 *
568 * Init video chip with common Linux graphic modes (lilo)
569 */
c609719b
WD
570void *video_hw_init (void)
571{
eeb1b77b
WD
572 GraphicDevice *pGD = (GraphicDevice *)&smi;
573 unsigned short device_id;
574 pci_dev_t devbusfn;
575 int videomode;
576 unsigned long t1, hsynch, vsynch;
577 unsigned int pci_mem_base, *vm;
578 char *penv;
579 int tmp, i, bits_per_pixel;
580 struct ctfb_res_modes *res_mode;
581 struct ctfb_res_modes var_mode;
582 unsigned char videoout;
b79a11cc 583
eeb1b77b
WD
584 /* Search for video chip */
585 printf("Video: ");
586
587 if ((devbusfn = pci_find_devices(supported, 0)) < 0)
8bde7f77 588 {
eeb1b77b
WD
589 printf ("Controller not found !\n");
590 return (NULL);
591 }
592
593 /* PCI setup */
594 pci_write_config_dword (devbusfn, PCI_COMMAND, (PCI_COMMAND_MEMORY | PCI_COMMAND_IO));
595 pci_read_config_word (devbusfn, PCI_DEVICE_ID, &device_id);
596 pci_read_config_dword (devbusfn, PCI_BASE_ADDRESS_0, &pci_mem_base);
597 pci_mem_base = pci_mem_to_phys (devbusfn, pci_mem_base);
598
599 tmp = 0;
b79a11cc 600
eeb1b77b
WD
601 videomode = CFG_DEFAULT_VIDEO_MODE;
602 /* get video mode via environment */
603 if ((penv = getenv ("videomode")) != NULL) {
604 /* deceide if it is a string */
605 if (penv[0] <= '9') {
606 videomode = (int) simple_strtoul (penv, NULL, 16);
607 tmp = 1;
608 }
609 } else {
610 tmp = 1;
611 }
612 if (tmp) {
613 /* parameter are vesa modes */
614 /* search params */
615 for (i = 0; i < VESA_MODES_COUNT; i++) {
616 if (vesa_modes[i].vesanr == videomode)
617 break;
618 }
619 if (i == VESA_MODES_COUNT) {
620 printf ("no VESA Mode found, switching to mode 0x%x ", CFG_DEFAULT_VIDEO_MODE);
621 i = 0;
622 }
623 res_mode =
624 (struct ctfb_res_modes *) &res_mode_init[vesa_modes[i].
625 resindex];
626 bits_per_pixel = vesa_modes[i].bits_per_pixel;
627 } else {
b79a11cc 628
eeb1b77b
WD
629 res_mode = (struct ctfb_res_modes *) &var_mode;
630 bits_per_pixel = video_get_params (res_mode, penv);
631 }
632
633 /* calculate hsynch and vsynch freq (info only) */
634 t1 = (res_mode->left_margin + res_mode->xres +
635 res_mode->right_margin + res_mode->hsync_len) / 8;
636 t1 *= 8;
637 t1 *= res_mode->pixclock;
638 t1 /= 1000;
639 hsynch = 1000000000L / t1;
640 t1 *=
641 (res_mode->upper_margin + res_mode->yres +
642 res_mode->lower_margin + res_mode->vsync_len);
643 t1 /= 1000;
644 vsynch = 1000000000L / t1;
b79a11cc 645
eeb1b77b
WD
646 /* fill in Graphic device struct */
647 sprintf (pGD->modeIdent, "%dx%dx%d %ldkHz %ldHz", res_mode->xres,
648 res_mode->yres, bits_per_pixel, (hsynch / 1000),
649 (vsynch / 1000));
650 printf ("%s\n", pGD->modeIdent);
651 pGD->winSizeX = res_mode->xres;
652 pGD->winSizeY = res_mode->yres;
653 pGD->plnSizeX = res_mode->xres;
654 pGD->plnSizeY = res_mode->yres;
655 switch (bits_per_pixel) {
656 case 8:
657 pGD->gdfBytesPP = 1;
658 pGD->gdfIndex = GDF__8BIT_INDEX;
659 break;
660 case 15:
661 pGD->gdfBytesPP = 2;
662 pGD->gdfIndex = GDF_15BIT_555RGB;
663 break;
664 case 16:
665 pGD->gdfBytesPP = 2;
666 pGD->gdfIndex = GDF_16BIT_565RGB;
667 break;
668 case 24:
669 pGD->gdfBytesPP = 3;
670 pGD->gdfIndex = GDF_24BIT_888RGB;
671 break;
8bde7f77 672 }
eeb1b77b
WD
673
674 pGD->isaBase = CFG_ISA_IO;
675 pGD->pciBase = pci_mem_base;
676 pGD->dprBase = (pci_mem_base + 0x400000 + 0x8000);
677 pGD->vprBase = (pci_mem_base + 0x400000 + 0xc000);
678 pGD->cprBase = (pci_mem_base + 0x400000 + 0xe000);
679 pGD->frameAdrs = pci_mem_base;
680 pGD->memSize = VIDEO_MEM_SIZE;
681
682 /* Set up hardware : select color mode,
683 set Register base to isa 3dx for 3?x regs*/
684 out8 (SMI_MISC_REG, 0x01);
685
686 /* Turn off display */
687 smiWrite (SMI_INDX_C4, 0x01, 0x20);
688
689 /* Unlock ext. crt regs */
690 out8 (SMI_LOCK_REG, 0x40);
691
692 /* Unlock crt regs 0-7 */
693 smiWrite (SMI_INDX_D4, 0x11, 0x0e);
694
695 /* Sytem Control Register */
696 smiLoadRegs (SMI_INDX_C4, SMI_DATA_C5, SMI_SCR, sizeof(SMI_SCR));
697
698 /* extented CRT Register */
699 smiLoadRegs (SMI_INDX_D4, SMI_DATA_D5, SMI_EXT_CRT, sizeof(SMI_EXT_CRT));
700
701 /* Attributes controller registers */
702 smiLoadRegs (SMI_INDX_ATTR, SMI_INDX_ATTR, SMI_ATTR, sizeof(SMI_ATTR));
b79a11cc 703
eeb1b77b
WD
704 /* Graphics Controller Register */
705 smiLoadRegs (SMI_INDX_CE, SMI_DATA_CF, SMI_GCR, sizeof(SMI_GCR));
706
707 /* Sequencer Register */
708 smiLoadRegs (SMI_INDX_C4, SMI_DATA_C5, SMI_SEQR, sizeof(SMI_SEQR));
709
710 /* Power Control Register */
711 smiLoadRegs (SMI_INDX_C4, SMI_DATA_C5, SMI_PCR, sizeof(SMI_PCR));
712
713 /* Memory Control Register */
714 /* Register MSR62 is a power on configurable register. We don't */
715 /* modify it */
716 smiLoadRegs (SMI_INDX_C4, SMI_DATA_C5, SMI_MCR, sizeof(SMI_MCR));
717
718 /* Set misc output register */
719 smiLoadMsr (res_mode);
b79a11cc 720
eeb1b77b
WD
721 /* Set CRT and Clock control registers */
722 smiLoadCrt (res_mode, bits_per_pixel);
b79a11cc 723
eeb1b77b
WD
724 smiLoadCcr (res_mode, device_id);
725
726 /* Hardware Cusor Register */
727 smiLoadRegs (SMI_INDX_C4, SMI_DATA_C5, SMI_HCR, sizeof(SMI_HCR));
728
729 /* Enable Display */
730 videoout = 2; /* Default output is CRT */
731 if ((penv = getenv ("videoout")) != NULL) {
732 /* deceide if it is a string */
733 videoout = (int) simple_strtoul (penv, NULL, 16);
734 }
735 smiWrite (SMI_INDX_C4, 0x31, videoout);
736
737 /* Video processor default setup */
738 smiInitVideoProcessor ();
739
740 /* Capture port default setup */
741 smiInitCapturePort ();
742
743 /* Drawing engine default setup */
744 smiInitDrawingEngine ();
745
746 /* Turn on display */
747 smiWrite (0x3c4, 0x01, 0x01);
748
749 /* Clear video memory */
750 i = pGD->memSize/4;
751 vm = (unsigned int *)pGD->pciBase;
752 while(i--)
753 *vm++ = 0;
754 return ((void*)&smi);
c609719b
WD
755}
756
757/*******************************************************************************
eeb1b77b
WD
758 *
759 * Drawing engine fill on screen region
760 */
c609719b 761void video_hw_rectfill (
eeb1b77b
WD
762 unsigned int bpp, /* bytes per pixel */
763 unsigned int dst_x, /* dest pos x */
764 unsigned int dst_y, /* dest pos y */
765 unsigned int dim_x, /* frame width */
766 unsigned int dim_y, /* frame height */
767 unsigned int color /* fill color */
768 )
c609719b 769{
eeb1b77b
WD
770 register GraphicDevice *pGD = (GraphicDevice *)&smi;
771 register unsigned int control;
c609719b 772
eeb1b77b 773 dim_x *= bpp;
c609719b 774
eeb1b77b
WD
775 out32r ((pGD->dprBase + 0x0014), color);
776 out32r ((pGD->dprBase + 0x0004), ((dst_x<<16) | dst_y));
777 out32r ((pGD->dprBase + 0x0008), ((dim_x<<16) | dim_y));
c609719b 778
eeb1b77b 779 control = 0x0000ffff & in32r ((pGD->dprBase + 0x000c));
c609719b 780
eeb1b77b 781 control |= 0x80010000;
c609719b 782
eeb1b77b 783 out32r ((pGD->dprBase + 0x000c), control);
c609719b 784
eeb1b77b
WD
785 /* Wait for drawing processor */
786 do
787 {
788 out8 ((pGD->isaBase + 0x3c4), 0x16);
789 } while (in8 (pGD->isaBase + 0x3c5) & 0x08);
c609719b
WD
790}
791
792/*******************************************************************************
eeb1b77b
WD
793 *
794 * Drawing engine bitblt with screen region
795 */
c609719b 796void video_hw_bitblt (
eeb1b77b
WD
797 unsigned int bpp, /* bytes per pixel */
798 unsigned int src_x, /* source pos x */
799 unsigned int src_y, /* source pos y */
800 unsigned int dst_x, /* dest pos x */
801 unsigned int dst_y, /* dest pos y */
802 unsigned int dim_x, /* frame width */
803 unsigned int dim_y /* frame height */
804 )
c609719b 805{
eeb1b77b
WD
806 register GraphicDevice *pGD = (GraphicDevice *)&smi;
807 register unsigned int control;
808
809 dim_x *= bpp;
810
811 if ((src_y<dst_y) || ((src_y==dst_y) && (src_x<dst_x)))
812 {
813 out32r ((pGD->dprBase + 0x0000), (((src_x+dim_x-1)<<16) | (src_y+dim_y-1)));
814 out32r ((pGD->dprBase + 0x0004), (((dst_x+dim_x-1)<<16) | (dst_y+dim_y-1)));
815 control = 0x88000000;
816 } else {
817 out32r ((pGD->dprBase + 0x0000), ((src_x<<16) | src_y));
818 out32r ((pGD->dprBase + 0x0004), ((dst_x<<16) | dst_y));
819 control = 0x80000000;
820 }
821
822 out32r ((pGD->dprBase + 0x0008), ((dim_x<<16) | dim_y));
823 control |= (0x0000ffff & in32r ((pGD->dprBase + 0x000c)));
824 out32r ((pGD->dprBase + 0x000c), control);
825
826 /* Wait for drawing processor */
827 do
828 {
829 out8 ((pGD->isaBase + 0x3c4), 0x16);
830 } while (in8 (pGD->isaBase + 0x3c5) & 0x08);
c609719b
WD
831}
832
833/*******************************************************************************
eeb1b77b
WD
834 *
835 * Set a RGB color in the LUT (8 bit index)
836 */
c609719b 837void video_set_lut (
eeb1b77b
WD
838 unsigned int index, /* color number */
839 unsigned char r, /* red */
840 unsigned char g, /* green */
841 unsigned char b /* blue */
842 )
c609719b 843{
eeb1b77b 844 register GraphicDevice *pGD = (GraphicDevice *)&smi;
c609719b 845
eeb1b77b 846 out8 (SMI_LUT_MASK, 0xff);
c609719b 847
eeb1b77b 848 out8 (SMI_LUT_START, (char)index);
c609719b 849
eeb1b77b
WD
850 out8 (SMI_LUT_RGB, r>>2); /* red */
851 udelay (10);
852 out8 (SMI_LUT_RGB, g>>2); /* green */
853 udelay (10);
854 out8 (SMI_LUT_RGB, b>>2); /* blue */
855 udelay (10);
c609719b
WD
856}
857
858#endif /* CONFIG_VIDEO_SMI_LYNXEM */