blob: 1880cccac2618b816fb650ae0c744acd3a5943c7 [file] [log] [blame]
wdenkc6097192002-11-03 00:24:07 +00001/*
2 * (C) Copyright 1997-2002 ELTEC Elektronik AG
3 * Frank Gottschling <fgottschling@eltec.de>
4 *
Wolfgang Denk1a459662013-07-08 09:37:19 +02005 * SPDX-License-Identifier: GPL-2.0+
wdenkc6097192002-11-03 00:24:07 +00006 */
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 *
wdenkeeb1b772004-03-23 22:53:55 +000017 * 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>
wdenkc6097192002-11-03 00:24:07 +000023 */
24
25#include <common.h>
26
wdenkc6097192002-11-03 00:24:07 +000027#include <pci.h>
28#include <video_fb.h>
wdenkeeb1b772004-03-23 22:53:55 +000029#include "videomodes.h"
wdenkc6097192002-11-03 00:24:07 +000030/*
31 * Export Graphic Device
32 */
33GraphicDevice smi;
34
35/*
36 * SMI 710/712 have 4MB internal RAM; SMI 810 2MB internal + 2MB external
37 */
wdenkeeb1b772004-03-23 22:53:55 +000038#define VIDEO_MEM_SIZE 0x400000
wdenkc6097192002-11-03 00:24:07 +000039
40
41/*
42 * ISA mapped regs
43 */
wdenkeeb1b772004-03-23 22:53:55 +000044#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 */
wdenkc6097192002-11-03 00:24:07 +000057
58/*
59 * Video processor control
wdenkeeb1b772004-03-23 22:53:55 +000060 */
wdenkc6097192002-11-03 00:24:07 +000061typedef struct {
wdenkeeb1b772004-03-23 22:53:55 +000062 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;
wdenkc6097192002-11-03 00:24:07 +000071} SmiVideoProc;
72
73/*
74 * Video window control
75 */
76typedef struct {
wdenkeeb1b772004-03-23 22:53:55 +000077 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;
wdenkc6097192002-11-03 00:24:07 +000086} SmiVideoWin;
87
88/*
89 * Capture port control
90 */
91typedef struct {
wdenkeeb1b772004-03-23 22:53:55 +000092 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;
wdenkc6097192002-11-03 00:24:07 +0000101} SmiCapturePort;
102
103
wdenkc6097192002-11-03 00:24:07 +0000104/*
105 * Register values for common video modes
106 */
wdenkeeb1b772004-03-23 22:53:55 +0000107static char SMI_SCR[] = {
108 /* all modes */
109 0x10, 0xff, 0x11, 0xff, 0x12, 0xff, 0x13, 0xff, 0x15, 0x90,
110 0x17, 0x20, 0x18, 0xb1, 0x19, 0x00,
wdenkc6097192002-11-03 00:24:07 +0000111};
wdenkeeb1b772004-03-23 22:53:55 +0000112static char SMI_EXT_CRT[] = {
113 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00,
Wolfgang Denkccd9d3d2005-09-03 01:21:50 +0200114 0x36, 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3f, 0x00,
wdenkc6097192002-11-03 00:24:07 +0000115};
wdenkeeb1b772004-03-23 22:53:55 +0000116static 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,
wdenkc6097192002-11-03 00:24:07 +0000121};
wdenkc6097192002-11-03 00:24:07 +0000122static char SMI_GCR[18] = {
wdenkeeb1b772004-03-23 22:53:55 +0000123 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x40,
Wolfgang Denkccd9d3d2005-09-03 01:21:50 +0200124 0x06, 0x05, 0x07, 0x0f, 0x08, 0xff,
wdenkeeb1b772004-03-23 22:53:55 +0000125};
126static char SMI_SEQR[] = {
Wolfgang Denkccd9d3d2005-09-03 01:21:50 +0200127 0x00, 0x00, 0x01, 0x01, 0x02, 0x0f, 0x03, 0x03, 0x04, 0x0e, 0x00, 0x03,
wdenkeeb1b772004-03-23 22:53:55 +0000128};
129static char SMI_PCR [] = {
Wolfgang Denkccd9d3d2005-09-03 01:21:50 +0200130 0x20, 0x04, 0x21, 0x30, 0x22, 0x00, 0x23, 0x00, 0x24, 0x00,
wdenkeeb1b772004-03-23 22:53:55 +0000131};
132static char SMI_MCR[] = {
wdenkb79a11c2004-03-25 15:14:43 +0000133 0x60, 0x01, 0x61, 0x00,
wdenkc6097192002-11-03 00:24:07 +0000134};
135
wdenkeeb1b772004-03-23 22:53:55 +0000136static char SMI_HCR[] = {
137 0x80, 0xff, 0x81, 0x07, 0x82, 0x00, 0x83, 0xff, 0x84, 0xff, 0x88, 0x00,
Wolfgang Denkccd9d3d2005-09-03 01:21:50 +0200138 0x89, 0x02, 0x8a, 0x80, 0x8b, 0x01, 0x8c, 0xff, 0x8d, 0x00,
wdenkeeb1b772004-03-23 22:53:55 +0000139};
wdenkc6097192002-11-03 00:24:07 +0000140
wdenkc6097192002-11-03 00:24:07 +0000141
142/*******************************************************************************
wdenkeeb1b772004-03-23 22:53:55 +0000143 *
144 * Write SMI ISA register
145 */
wdenkc6097192002-11-03 00:24:07 +0000146static void smiWrite (unsigned short index, char reg, char val)
147{
wdenkeeb1b772004-03-23 22:53:55 +0000148 register GraphicDevice *pGD = (GraphicDevice *)&smi;
wdenkc6097192002-11-03 00:24:07 +0000149
wdenkeeb1b772004-03-23 22:53:55 +0000150 out8 ((pGD->isaBase + index), reg);
151 out8 ((pGD->isaBase + index + 1), val);
wdenkc6097192002-11-03 00:24:07 +0000152}
153
154/*******************************************************************************
wdenkeeb1b772004-03-23 22:53:55 +0000155 *
156 * Write a table of SMI ISA register
157 */
wdenkc6097192002-11-03 00:24:07 +0000158static void smiLoadRegs (
wdenkeeb1b772004-03-23 22:53:55 +0000159 unsigned int iReg,
160 unsigned int dReg,
161 char *regTab,
162 unsigned int tabSize
163 )
wdenkc6097192002-11-03 00:24:07 +0000164{
wdenkeeb1b772004-03-23 22:53:55 +0000165 register GraphicDevice *pGD = (GraphicDevice *)&smi;
166 register int i;
wdenkc6097192002-11-03 00:24:07 +0000167
wdenkeeb1b772004-03-23 22:53:55 +0000168 for (i=0; i<tabSize; i+=2) {
169 if (iReg == SMI_INDX_ATTR) {
170 /* Reset the Flip Flop */
171 in8 (SMI_ISR1);
172 out8 (iReg, regTab[i]);
173 out8 (iReg, regTab[i+1]);
174 } else {
175 out8 (iReg, regTab[i]);
176 out8 (dReg, regTab[i+1]);
177 }
178 }
wdenkc6097192002-11-03 00:24:07 +0000179}
180
181/*******************************************************************************
wdenkeeb1b772004-03-23 22:53:55 +0000182 *
183 * Init capture port registers
184 */
wdenkc6097192002-11-03 00:24:07 +0000185static void smiInitCapturePort (void)
186{
wdenkeeb1b772004-03-23 22:53:55 +0000187 SmiCapturePort smiCP = { 0x01400600, 0x30, 0x40, 480, 640, 0, 0, 2560, 6 };
188 register GraphicDevice *pGD = (GraphicDevice *)&smi;
189 register SmiCapturePort *pCP = (SmiCapturePort *)&smiCP;
wdenkc6097192002-11-03 00:24:07 +0000190
wdenkeeb1b772004-03-23 22:53:55 +0000191 out32r ((pGD->cprBase + 0x0004), ((pCP->topClip<<16) | pCP->leftClip));
192 out32r ((pGD->cprBase + 0x0008), ((pCP->srcHeight<<16) | pCP->srcWidth));
193 out32r ((pGD->cprBase + 0x000c), pCP->srcBufStart1/8);
194 out32r ((pGD->cprBase + 0x0010), pCP->srcBufStart2/8);
195 out32r ((pGD->cprBase + 0x0014), pCP->srcOffset/8);
196 out32r ((pGD->cprBase + 0x0018), pCP->fifoControl);
197 out32r ((pGD->cprBase + 0x0000), pCP->control);
wdenkc6097192002-11-03 00:24:07 +0000198}
199
200
201/*******************************************************************************
wdenkeeb1b772004-03-23 22:53:55 +0000202 *
203 * Init video processor registers
204 */
wdenkc6097192002-11-03 00:24:07 +0000205static void smiInitVideoProcessor (void)
206{
wdenkeeb1b772004-03-23 22:53:55 +0000207 SmiVideoProc smiVP = { 0x100000, 0, 0, 0, 0, 1600, 0x1200543, 4, 0xededed };
208 SmiVideoWin smiVW = { 0, 0, 599, 799, 0, 1600, 0, 0, 0 };
209 register GraphicDevice *pGD = (GraphicDevice *)&smi;
210 register SmiVideoProc *pVP = (SmiVideoProc *)&smiVP;
211 register SmiVideoWin *pVWin = (SmiVideoWin *)&smiVW;
wdenkc6097192002-11-03 00:24:07 +0000212
wdenkeeb1b772004-03-23 22:53:55 +0000213 pVP->width = pGD->plnSizeX * pGD->gdfBytesPP;
214 pVP->control |= pGD->gdfIndex << 16;
215 pVWin->bottom = pGD->winSizeY - 1;
216 pVWin->right = pGD->winSizeX - 1;
217 pVWin->width = pVP->width;
wdenkc6097192002-11-03 00:24:07 +0000218
wdenkeeb1b772004-03-23 22:53:55 +0000219 /* color key */
220 out32r ((pGD->vprBase + 0x0004), pVP->colorKey);
wdenkc6097192002-11-03 00:24:07 +0000221
wdenkeeb1b772004-03-23 22:53:55 +0000222 /* color key mask */
223 out32r ((pGD->vprBase + 0x0008), pVP->colorKeyMask);
wdenkc6097192002-11-03 00:24:07 +0000224
wdenkeeb1b772004-03-23 22:53:55 +0000225 /* data src start adrs */
226 out32r ((pGD->vprBase + 0x000c), pVP->start / 8);
wdenkc6097192002-11-03 00:24:07 +0000227
wdenkeeb1b772004-03-23 22:53:55 +0000228 /* data width and offset */
229 out32r ((pGD->vprBase + 0x0010),
230 ((pVP->offset / 8 * pGD->gdfBytesPP) << 16) |
231 (pGD->plnSizeX / 8 * pGD->gdfBytesPP));
wdenkc6097192002-11-03 00:24:07 +0000232
wdenkeeb1b772004-03-23 22:53:55 +0000233 /* video window 1 */
234 out32r ((pGD->vprBase + 0x0014),
235 ((pVWin->top << 16) | pVWin->left));
wdenkc6097192002-11-03 00:24:07 +0000236
wdenkeeb1b772004-03-23 22:53:55 +0000237 out32r ((pGD->vprBase + 0x0018),
238 ((pVWin->bottom << 16) | pVWin->right));
wdenkc6097192002-11-03 00:24:07 +0000239
wdenkeeb1b772004-03-23 22:53:55 +0000240 out32r ((pGD->vprBase + 0x001c), pVWin->srcStart / 8);
wdenkc6097192002-11-03 00:24:07 +0000241
wdenkeeb1b772004-03-23 22:53:55 +0000242 out32r ((pGD->vprBase + 0x0020),
243 (((pVWin->offset / 8) << 16) | (pVWin->width / 8)));
wdenkc6097192002-11-03 00:24:07 +0000244
wdenkeeb1b772004-03-23 22:53:55 +0000245 out32r ((pGD->vprBase + 0x0024),
246 (((pVWin->hStretch) << 8) | pVWin->vStretch));
wdenkc6097192002-11-03 00:24:07 +0000247
wdenkeeb1b772004-03-23 22:53:55 +0000248 /* video window 2 */
249 out32r ((pGD->vprBase + 0x0028),
250 ((pVWin->top << 16) | pVWin->left));
wdenkc6097192002-11-03 00:24:07 +0000251
wdenkeeb1b772004-03-23 22:53:55 +0000252 out32r ((pGD->vprBase + 0x002c),
253 ((pVWin->bottom << 16) | pVWin->right));
wdenkc6097192002-11-03 00:24:07 +0000254
wdenkeeb1b772004-03-23 22:53:55 +0000255 out32r ((pGD->vprBase + 0x0030),
256 pVWin->srcStart / 8);
wdenkc6097192002-11-03 00:24:07 +0000257
wdenkeeb1b772004-03-23 22:53:55 +0000258 out32r ((pGD->vprBase + 0x0034),
259 (((pVWin->offset / 8) << 16) | (pVWin->width / 8)));
wdenkc6097192002-11-03 00:24:07 +0000260
wdenkeeb1b772004-03-23 22:53:55 +0000261 out32r ((pGD->vprBase + 0x0038),
262 (((pVWin->hStretch) << 8) | pVWin->vStretch));
wdenkc6097192002-11-03 00:24:07 +0000263
wdenkeeb1b772004-03-23 22:53:55 +0000264 /* fifo prio control */
265 out32r ((pGD->vprBase + 0x0054), pVP->fifoPrio);
wdenkc6097192002-11-03 00:24:07 +0000266
wdenkeeb1b772004-03-23 22:53:55 +0000267 /* fifo empty request levell */
268 out32r ((pGD->vprBase + 0x0058), pVP->fifoERL);
wdenkc6097192002-11-03 00:24:07 +0000269
wdenkeeb1b772004-03-23 22:53:55 +0000270 /* conversion constant */
271 out32r ((pGD->vprBase + 0x005c), pVP->YUVtoRGB);
wdenkc6097192002-11-03 00:24:07 +0000272
wdenkeeb1b772004-03-23 22:53:55 +0000273 /* vpr control word */
274 out32r ((pGD->vprBase + 0x0000), pVP->control);
wdenkc6097192002-11-03 00:24:07 +0000275}
276
277/******************************************************************************
278 *
279 * Init drawing engine registers
280 */
281static void smiInitDrawingEngine (void)
282{
wdenkeeb1b772004-03-23 22:53:55 +0000283 GraphicDevice *pGD = (GraphicDevice *)&smi;
284 unsigned int val;
wdenkc6097192002-11-03 00:24:07 +0000285
wdenkeeb1b772004-03-23 22:53:55 +0000286 /* don't start now */
287 out32r ((pGD->dprBase + 0x000c), 0x000f0000);
wdenkc6097192002-11-03 00:24:07 +0000288
wdenkeeb1b772004-03-23 22:53:55 +0000289 /* set rop2 to copypen */
290 val = 0xffff3ff0 & in32r ((pGD->dprBase + 0x000c));
291 out32r ((pGD->dprBase + 0x000c), (val | 0x8000 | 0x0c));
wdenkc6097192002-11-03 00:24:07 +0000292
wdenkeeb1b772004-03-23 22:53:55 +0000293 /* set clip rect */
294 out32r ((pGD->dprBase + 0x002c), 0);
295 out32r ((pGD->dprBase + 0x0030),
296 ((pGD->winSizeY<<16) | pGD->winSizeX * pGD->gdfBytesPP ));
wdenkc6097192002-11-03 00:24:07 +0000297
wdenkeeb1b772004-03-23 22:53:55 +0000298 /* src row pitch */
299 val = 0xffff0000 & (in32r ((pGD->dprBase + 0x0010)));
300 out32r ((pGD->dprBase + 0x0010),
301 (val | pGD->plnSizeX * pGD->gdfBytesPP));
wdenkc6097192002-11-03 00:24:07 +0000302
wdenkeeb1b772004-03-23 22:53:55 +0000303 /* dst row pitch */
304 val = 0x0000ffff & (in32r ((pGD->dprBase + 0x0010)));
305 out32r ((pGD->dprBase + 0x0010),
306 (((pGD->plnSizeX * pGD->gdfBytesPP)<<16) | val));
wdenkc6097192002-11-03 00:24:07 +0000307
wdenkeeb1b772004-03-23 22:53:55 +0000308 /* window width src/dst */
309 out32r ((pGD->dprBase + 0x003c),
310 (((pGD->plnSizeX * pGD->gdfBytesPP & 0x0fff)<<16) |
311 (pGD->plnSizeX * pGD->gdfBytesPP & 0x0fff)));
312 out16r ((pGD->dprBase + 0x001e), 0x0000);
wdenkc6097192002-11-03 00:24:07 +0000313
wdenkeeb1b772004-03-23 22:53:55 +0000314 /* src base adrs */
315 out32r ((pGD->dprBase + 0x0040),
316 (((pGD->frameAdrs/8) & 0x000fffff)));
wdenkc6097192002-11-03 00:24:07 +0000317
wdenkeeb1b772004-03-23 22:53:55 +0000318 /* dst base adrs */
319 out32r ((pGD->dprBase + 0x0044),
320 (((pGD->frameAdrs/8) & 0x000fffff)));
wdenkc6097192002-11-03 00:24:07 +0000321
wdenkeeb1b772004-03-23 22:53:55 +0000322 /* foreground color */
323 out32r ((pGD->dprBase + 0x0014), pGD->fg);
wdenkc6097192002-11-03 00:24:07 +0000324
wdenkeeb1b772004-03-23 22:53:55 +0000325 /* background color */
326 out32r ((pGD->dprBase + 0x0018), pGD->bg);
wdenkc6097192002-11-03 00:24:07 +0000327
wdenkeeb1b772004-03-23 22:53:55 +0000328 /* xcolor */
329 out32r ((pGD->dprBase + 0x0020), 0x00ffffff);
wdenkc6097192002-11-03 00:24:07 +0000330
wdenkeeb1b772004-03-23 22:53:55 +0000331 /* xcolor mask */
332 out32r ((pGD->dprBase + 0x0024), 0x00ffffff);
wdenkc6097192002-11-03 00:24:07 +0000333
wdenkeeb1b772004-03-23 22:53:55 +0000334 /* bit mask */
335 out32r ((pGD->dprBase + 0x0028), 0x00ffffff);
wdenkc6097192002-11-03 00:24:07 +0000336
wdenkeeb1b772004-03-23 22:53:55 +0000337 /* load mono pattern */
338 out32r ((pGD->dprBase + 0x0034), 0);
339 out32r ((pGD->dprBase + 0x0038), 0);
wdenkc6097192002-11-03 00:24:07 +0000340}
341
342static struct pci_device_id supported[] = {
wdenkeeb1b772004-03-23 22:53:55 +0000343 { PCI_VENDOR_ID_SMI, PCI_DEVICE_ID_SMI_710 },
344 { PCI_VENDOR_ID_SMI, PCI_DEVICE_ID_SMI_712 },
345 { PCI_VENDOR_ID_SMI, PCI_DEVICE_ID_SMI_810 },
346 { }
wdenkc6097192002-11-03 00:24:07 +0000347};
348
wdenkeeb1b772004-03-23 22:53:55 +0000349/*****************************************************************************/
350static void smiLoadMsr (struct ctfb_res_modes *mode)
351{
352 unsigned char h_synch_high, v_synch_high;
353 register GraphicDevice *pGD = (GraphicDevice *)&smi;
354
355 h_synch_high = (mode->sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : 0x40; /* horizontal Synch High active */
356 v_synch_high = (mode->sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : 0x80; /* vertical Synch High active */
357 out8 (SMI_MISC_REG, (h_synch_high | v_synch_high | 0x29));
358 /* upper64K==0x20, CLC2select==0x08, RAMenable==0x02!(todo), CGA==0x01
359 * Selects the upper 64KB page.Bit5=1
360 * CLK2 (left reserved in standard VGA) Bit3|2=1|0
361 * Disables CPU access to frame buffer. Bit1=0
362 * Sets the I/O address decode for ST01, FCR, and all CR registers
363 * to the 3Dx I/O address range (CGA emulation). Bit0=1
364 */
365}
366/*****************************************************************************/
367static void smiLoadCrt (struct ctfb_res_modes *var, int bits_per_pixel)
368{
369 unsigned char cr[0x7a];
370 int i;
371 unsigned int hd, hs, he, ht, hbs, hbe; /* Horizontal. */
372 unsigned int vd, vs, ve, vt, vbs, vbe; /* vertical */
373 unsigned int bpp, wd, dblscan, interlaced;
374
375 const int LineCompare = 0x3ff;
376 unsigned int TextScanLines = 1; /* this is in fact a vertical zoom factor */
377 register GraphicDevice *pGD = (GraphicDevice *)&smi;
378
379 /* Horizontal */
380 hd = (var->xres) / 8; /* HDisp. */
381 hs = (var->xres + var->right_margin) / 8; /* HsStrt */
382 he = (var->xres + var->right_margin + var->hsync_len) / 8; /* HsEnd */
383 ht = (var->left_margin + var->xres + var->right_margin + var->hsync_len) / 8; /* HTotal */
384 /* Blank */
wdenkb79a11c2004-03-25 15:14:43 +0000385 hbs = hd;
wdenkeeb1b772004-03-23 22:53:55 +0000386 hbe = 0; /* Blank end at 0 */
387
388 /* Vertical */
389 vd = var->yres; /* VDisplay */
390 vs = var->yres + var->lower_margin; /* VSyncStart */
391 ve = var->yres + var->lower_margin + var->vsync_len; /* VSyncEnd */
392 vt = var->upper_margin + var->yres + var->lower_margin + var->vsync_len; /* VTotal */
393 vbs = vd;
394 vbe = 0;
wdenkb79a11c2004-03-25 15:14:43 +0000395
wdenkeeb1b772004-03-23 22:53:55 +0000396 bpp = bits_per_pixel;
397 dblscan = (var->vmode & FB_VMODE_DOUBLE) ? 1 : 0;
398 interlaced = var->vmode & FB_VMODE_INTERLACED;
399
400
401 if (bpp == 15)
402 bpp = 16;
403 wd = var->xres * bpp / 64; /* double words per line */
404 if (interlaced) { /* we divide all vertical timings, exept vd */
405 vs >>= 1;
406 vbs >>= 1;
407 ve >>= 1;
408 vt >>= 1;
409 }
410
411 memset (cr, 0, sizeof (cr));
412 cr[0x00] = ht - 5;
413 cr[0x01] = hd - 1;
414 cr[0x02] = hbs - 1;
415 cr[0x03] = (hbe & 0x1F);
416 cr[0x04] = hs;
417 cr[0x05] = ((hbe & 0x20) << 2) | (he & 0x1f);
wdenkb79a11c2004-03-25 15:14:43 +0000418
wdenkeeb1b772004-03-23 22:53:55 +0000419 cr[0x06] = (vt - 2) & 0xFF;
420 cr[0x07] = (((vt - 2) & 0x100) >> 8)
421 | (((vd - 1) & 0x100) >> 7)
422 | ((vs & 0x100) >> 6)
423 | (((vbs - 1) & 0x100) >> 5)
424 | ((LineCompare & 0x100) >> 4)
425 | (((vt - 2) & 0x200) >> 4)
426 | (((vd - 1) & 0x200) >> 3)
427 | ((vs & 0x200) >> 2);
428
429 cr[0x30] = ((vt - 2) & 0x400) >> 7
430 | (((vd - 1) & 0x400) >> 8)
431 | (((vbs - 1) & 0x400) >> 9)
432 | ((vs & 0x400) >> 10)
433 | (interlaced) ? 0x80 : 0;
wdenkb79a11c2004-03-25 15:14:43 +0000434
wdenkeeb1b772004-03-23 22:53:55 +0000435
436 cr[0x08] = 0x00;
437 cr[0x09] = (dblscan << 7)
438 | ((LineCompare & 0x200) >> 3)
439 | (((vbs - 1) & 0x200) >> 4)
440 | (TextScanLines - 1);
441
442 cr[0x10] = vs & 0xff; /* VSyncPulseStart */
wdenkb79a11c2004-03-25 15:14:43 +0000443 cr[0x11] = (ve & 0x0f);
wdenkeeb1b772004-03-23 22:53:55 +0000444 cr[0x12] = (vd - 1) & 0xff; /* LineCount */
445 cr[0x13] = wd & 0xff;
446 cr[0x14] = 0x40;
447 cr[0x15] = (vbs - 1) & 0xff;
448 cr[0x16] = vbe & 0xff;
449 cr[0x17] = 0xe3; /* but it does not work */
450 cr[0x18] = 0xff & LineCompare;
451 cr[0x22] = 0x00; /* todo? */
452
453
454 /* now set the registers */
455 for (i = 0; i <= 0x18; i++) { /*CR00 .. CR18 */
456 smiWrite (SMI_INDX_D4, i, cr[i]);
457 }
458 i = 0x22; /*CR22 */
459 smiWrite (SMI_INDX_D4, i, cr[i]);
460 i = 0x30; /*CR30 */
461 smiWrite (SMI_INDX_D4, i, cr[i]);
462}
463
464/*****************************************************************************/
465#define REF_FREQ 14318180
466#define PMIN 1
467#define PMAX 255
468#define QMIN 1
469#define QMAX 63
470
471static unsigned int FindPQ (unsigned int freq, unsigned int *pp, unsigned int *pq)
472{
473 unsigned int n = QMIN, m = 0;
474 long long int L = 0, P = freq, Q = REF_FREQ, H = P >> 1;
475 long long int D = 0x7ffffffffffffffLL;
476
477 for (n = QMIN; n <= QMAX; n++) {
478 m = PMIN; /* p/q ~ freq/ref -> p*ref-freq*q ~ 0 */
wdenkb79a11c2004-03-25 15:14:43 +0000479 L = P * n - m * Q;
wdenkeeb1b772004-03-23 22:53:55 +0000480 while (L > 0 && m < PMAX) {
481 L -= REF_FREQ; /* difference is greater as 0 subtract fref */
482 m++; /* and increment m */
483 }
484 /* difference is less or equal than 0 or m > maximum */
485 if (m > PMAX)
486 break; /* no solution: if we increase n we get the same situation */
487 /* L is <= 0 now */
488 if (-L > H && m > PMIN) { /* if difference > the half fref */
489 L += REF_FREQ; /* we take the situation before */
490 m--; /* because its closer to 0 */
491 }
492 L = (L < 0) ? -L : +L; /* absolute value */
493 if (D < L) /* if last difference was better take next n */
494 continue;
495 D = L;
496 *pp = m;
497 *pq = n; /* keep improved data */
498 if (D == 0)
499 break; /* best result we can get */
500 }
501 return (unsigned int) (0xffffffff & D);
502}
503
504/*****************************************************************************/
505static void smiLoadCcr (struct ctfb_res_modes *var, unsigned short device_id)
506{
Wolfgang Denk77ddac92005-10-13 16:45:02 +0200507 unsigned int p = 0;
508 unsigned int q = 0;
wdenkeeb1b772004-03-23 22:53:55 +0000509 long long freq;
510 register GraphicDevice *pGD = (GraphicDevice *)&smi;
511
512 smiWrite (SMI_INDX_C4, 0x65, 0);
513 smiWrite (SMI_INDX_C4, 0x66, 0);
514 smiWrite (SMI_INDX_C4, 0x68, 0x50);
515 if (device_id == PCI_DEVICE_ID_SMI_810) {
516 smiWrite (SMI_INDX_C4, 0x69, 0x3);
517 } else {
518 smiWrite (SMI_INDX_C4, 0x69, 0x0);
519 }
520
521 /* Memory clock */
522 switch (device_id) {
523 case PCI_DEVICE_ID_SMI_710 :
524 smiWrite (SMI_INDX_C4, 0x6a, 0x75);
525 break;
526 case PCI_DEVICE_ID_SMI_712 :
527 smiWrite (SMI_INDX_C4, 0x6a, 0x80);
528 break;
529 default :
530 smiWrite (SMI_INDX_C4, 0x6a, 0x53);
531 break;
532 }
533 smiWrite (SMI_INDX_C4, 0x6b, 0x15);
wdenkb79a11c2004-03-25 15:14:43 +0000534
wdenkeeb1b772004-03-23 22:53:55 +0000535 /* VCLK */
wdenkeedcd072004-09-08 22:03:11 +0000536 freq = 1000000000000LL / var -> pixclock;
wdenkb79a11c2004-03-25 15:14:43 +0000537
wdenkeeb1b772004-03-23 22:53:55 +0000538 FindPQ ((unsigned int)freq, &p, &q);
wdenkb79a11c2004-03-25 15:14:43 +0000539
wdenkeeb1b772004-03-23 22:53:55 +0000540 smiWrite (SMI_INDX_C4, 0x6c, p);
541 smiWrite (SMI_INDX_C4, 0x6d, q);
542
543}
wdenkc6097192002-11-03 00:24:07 +0000544
545/*******************************************************************************
wdenkeeb1b772004-03-23 22:53:55 +0000546 *
547 * Init video chip with common Linux graphic modes (lilo)
548 */
wdenkc6097192002-11-03 00:24:07 +0000549void *video_hw_init (void)
550{
wdenkeeb1b772004-03-23 22:53:55 +0000551 GraphicDevice *pGD = (GraphicDevice *)&smi;
552 unsigned short device_id;
553 pci_dev_t devbusfn;
554 int videomode;
555 unsigned long t1, hsynch, vsynch;
556 unsigned int pci_mem_base, *vm;
557 char *penv;
558 int tmp, i, bits_per_pixel;
559 struct ctfb_res_modes *res_mode;
560 struct ctfb_res_modes var_mode;
561 unsigned char videoout;
wdenkb79a11c2004-03-25 15:14:43 +0000562
wdenkeeb1b772004-03-23 22:53:55 +0000563 /* Search for video chip */
564 printf("Video: ");
wdenkc6097192002-11-03 00:24:07 +0000565
wdenkeeb1b772004-03-23 22:53:55 +0000566 if ((devbusfn = pci_find_devices(supported, 0)) < 0)
wdenk8bde7f72003-06-27 21:31:46 +0000567 {
wdenkeeb1b772004-03-23 22:53:55 +0000568 printf ("Controller not found !\n");
569 return (NULL);
wdenk8bde7f72003-06-27 21:31:46 +0000570 }
wdenkc6097192002-11-03 00:24:07 +0000571
wdenkeeb1b772004-03-23 22:53:55 +0000572 /* PCI setup */
573 pci_write_config_dword (devbusfn, PCI_COMMAND, (PCI_COMMAND_MEMORY | PCI_COMMAND_IO));
574 pci_read_config_word (devbusfn, PCI_DEVICE_ID, &device_id);
575 pci_read_config_dword (devbusfn, PCI_BASE_ADDRESS_0, &pci_mem_base);
576 pci_mem_base = pci_mem_to_phys (devbusfn, pci_mem_base);
wdenkc6097192002-11-03 00:24:07 +0000577
wdenkeeb1b772004-03-23 22:53:55 +0000578 tmp = 0;
wdenkb79a11c2004-03-25 15:14:43 +0000579
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200580 videomode = CONFIG_SYS_DEFAULT_VIDEO_MODE;
wdenkeeb1b772004-03-23 22:53:55 +0000581 /* get video mode via environment */
582 if ((penv = getenv ("videomode")) != NULL) {
583 /* deceide if it is a string */
584 if (penv[0] <= '9') {
585 videomode = (int) simple_strtoul (penv, NULL, 16);
586 tmp = 1;
587 }
588 } else {
589 tmp = 1;
590 }
591 if (tmp) {
592 /* parameter are vesa modes */
593 /* search params */
594 for (i = 0; i < VESA_MODES_COUNT; i++) {
595 if (vesa_modes[i].vesanr == videomode)
596 break;
597 }
598 if (i == VESA_MODES_COUNT) {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200599 printf ("no VESA Mode found, switching to mode 0x%x ", CONFIG_SYS_DEFAULT_VIDEO_MODE);
wdenkeeb1b772004-03-23 22:53:55 +0000600 i = 0;
601 }
602 res_mode =
603 (struct ctfb_res_modes *) &res_mode_init[vesa_modes[i].
604 resindex];
605 bits_per_pixel = vesa_modes[i].bits_per_pixel;
606 } else {
wdenkb79a11c2004-03-25 15:14:43 +0000607
wdenkeeb1b772004-03-23 22:53:55 +0000608 res_mode = (struct ctfb_res_modes *) &var_mode;
609 bits_per_pixel = video_get_params (res_mode, penv);
610 }
wdenkc6097192002-11-03 00:24:07 +0000611
wdenkeeb1b772004-03-23 22:53:55 +0000612 /* calculate hsynch and vsynch freq (info only) */
613 t1 = (res_mode->left_margin + res_mode->xres +
614 res_mode->right_margin + res_mode->hsync_len) / 8;
615 t1 *= 8;
616 t1 *= res_mode->pixclock;
617 t1 /= 1000;
618 hsynch = 1000000000L / t1;
619 t1 *=
620 (res_mode->upper_margin + res_mode->yres +
621 res_mode->lower_margin + res_mode->vsync_len);
622 t1 /= 1000;
623 vsynch = 1000000000L / t1;
wdenkb79a11c2004-03-25 15:14:43 +0000624
wdenkeeb1b772004-03-23 22:53:55 +0000625 /* fill in Graphic device struct */
626 sprintf (pGD->modeIdent, "%dx%dx%d %ldkHz %ldHz", res_mode->xres,
627 res_mode->yres, bits_per_pixel, (hsynch / 1000),
628 (vsynch / 1000));
629 printf ("%s\n", pGD->modeIdent);
630 pGD->winSizeX = res_mode->xres;
631 pGD->winSizeY = res_mode->yres;
632 pGD->plnSizeX = res_mode->xres;
633 pGD->plnSizeY = res_mode->yres;
634 switch (bits_per_pixel) {
635 case 8:
636 pGD->gdfBytesPP = 1;
637 pGD->gdfIndex = GDF__8BIT_INDEX;
638 break;
639 case 15:
640 pGD->gdfBytesPP = 2;
641 pGD->gdfIndex = GDF_15BIT_555RGB;
642 break;
643 case 16:
644 pGD->gdfBytesPP = 2;
645 pGD->gdfIndex = GDF_16BIT_565RGB;
646 break;
647 case 24:
648 pGD->gdfBytesPP = 3;
649 pGD->gdfIndex = GDF_24BIT_888RGB;
650 break;
651 }
wdenkc6097192002-11-03 00:24:07 +0000652
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200653 pGD->isaBase = CONFIG_SYS_ISA_IO;
wdenkeeb1b772004-03-23 22:53:55 +0000654 pGD->pciBase = pci_mem_base;
655 pGD->dprBase = (pci_mem_base + 0x400000 + 0x8000);
656 pGD->vprBase = (pci_mem_base + 0x400000 + 0xc000);
657 pGD->cprBase = (pci_mem_base + 0x400000 + 0xe000);
658 pGD->frameAdrs = pci_mem_base;
659 pGD->memSize = VIDEO_MEM_SIZE;
wdenkc6097192002-11-03 00:24:07 +0000660
wdenkeeb1b772004-03-23 22:53:55 +0000661 /* Set up hardware : select color mode,
662 set Register base to isa 3dx for 3?x regs*/
663 out8 (SMI_MISC_REG, 0x01);
wdenkc6097192002-11-03 00:24:07 +0000664
wdenkeeb1b772004-03-23 22:53:55 +0000665 /* Turn off display */
666 smiWrite (SMI_INDX_C4, 0x01, 0x20);
wdenkc6097192002-11-03 00:24:07 +0000667
wdenkeeb1b772004-03-23 22:53:55 +0000668 /* Unlock ext. crt regs */
669 out8 (SMI_LOCK_REG, 0x40);
wdenkc6097192002-11-03 00:24:07 +0000670
wdenkeeb1b772004-03-23 22:53:55 +0000671 /* Unlock crt regs 0-7 */
672 smiWrite (SMI_INDX_D4, 0x11, 0x0e);
wdenkc6097192002-11-03 00:24:07 +0000673
wdenkeeb1b772004-03-23 22:53:55 +0000674 /* Sytem Control Register */
675 smiLoadRegs (SMI_INDX_C4, SMI_DATA_C5, SMI_SCR, sizeof(SMI_SCR));
wdenkc6097192002-11-03 00:24:07 +0000676
wdenkeeb1b772004-03-23 22:53:55 +0000677 /* extented CRT Register */
678 smiLoadRegs (SMI_INDX_D4, SMI_DATA_D5, SMI_EXT_CRT, sizeof(SMI_EXT_CRT));
wdenkc6097192002-11-03 00:24:07 +0000679
wdenkeeb1b772004-03-23 22:53:55 +0000680 /* Attributes controller registers */
681 smiLoadRegs (SMI_INDX_ATTR, SMI_INDX_ATTR, SMI_ATTR, sizeof(SMI_ATTR));
wdenkb79a11c2004-03-25 15:14:43 +0000682
wdenkeeb1b772004-03-23 22:53:55 +0000683 /* Graphics Controller Register */
684 smiLoadRegs (SMI_INDX_CE, SMI_DATA_CF, SMI_GCR, sizeof(SMI_GCR));
wdenkc6097192002-11-03 00:24:07 +0000685
wdenkeeb1b772004-03-23 22:53:55 +0000686 /* Sequencer Register */
687 smiLoadRegs (SMI_INDX_C4, SMI_DATA_C5, SMI_SEQR, sizeof(SMI_SEQR));
wdenkc6097192002-11-03 00:24:07 +0000688
wdenkeeb1b772004-03-23 22:53:55 +0000689 /* Power Control Register */
690 smiLoadRegs (SMI_INDX_C4, SMI_DATA_C5, SMI_PCR, sizeof(SMI_PCR));
wdenkc6097192002-11-03 00:24:07 +0000691
wdenkeeb1b772004-03-23 22:53:55 +0000692 /* Memory Control Register */
693 /* Register MSR62 is a power on configurable register. We don't */
694 /* modify it */
695 smiLoadRegs (SMI_INDX_C4, SMI_DATA_C5, SMI_MCR, sizeof(SMI_MCR));
wdenkc6097192002-11-03 00:24:07 +0000696
wdenkeeb1b772004-03-23 22:53:55 +0000697 /* Set misc output register */
698 smiLoadMsr (res_mode);
wdenkb79a11c2004-03-25 15:14:43 +0000699
wdenkeeb1b772004-03-23 22:53:55 +0000700 /* Set CRT and Clock control registers */
701 smiLoadCrt (res_mode, bits_per_pixel);
wdenkb79a11c2004-03-25 15:14:43 +0000702
wdenkeeb1b772004-03-23 22:53:55 +0000703 smiLoadCcr (res_mode, device_id);
wdenkc6097192002-11-03 00:24:07 +0000704
wdenkeeb1b772004-03-23 22:53:55 +0000705 /* Hardware Cusor Register */
706 smiLoadRegs (SMI_INDX_C4, SMI_DATA_C5, SMI_HCR, sizeof(SMI_HCR));
wdenkc6097192002-11-03 00:24:07 +0000707
wdenkeeb1b772004-03-23 22:53:55 +0000708 /* Enable Display */
709 videoout = 2; /* Default output is CRT */
710 if ((penv = getenv ("videoout")) != NULL) {
711 /* deceide if it is a string */
712 videoout = (int) simple_strtoul (penv, NULL, 16);
713 }
714 smiWrite (SMI_INDX_C4, 0x31, videoout);
wdenkc6097192002-11-03 00:24:07 +0000715
wdenkeeb1b772004-03-23 22:53:55 +0000716 /* Video processor default setup */
717 smiInitVideoProcessor ();
wdenkc6097192002-11-03 00:24:07 +0000718
wdenkeeb1b772004-03-23 22:53:55 +0000719 /* Capture port default setup */
720 smiInitCapturePort ();
wdenkc6097192002-11-03 00:24:07 +0000721
wdenkeeb1b772004-03-23 22:53:55 +0000722 /* Drawing engine default setup */
723 smiInitDrawingEngine ();
wdenkc6097192002-11-03 00:24:07 +0000724
wdenkeeb1b772004-03-23 22:53:55 +0000725 /* Turn on display */
726 smiWrite (0x3c4, 0x01, 0x01);
wdenkc6097192002-11-03 00:24:07 +0000727
wdenkeeb1b772004-03-23 22:53:55 +0000728 /* Clear video memory */
729 i = pGD->memSize/4;
730 vm = (unsigned int *)pGD->pciBase;
731 while(i--)
732 *vm++ = 0;
733 return ((void*)&smi);
wdenkc6097192002-11-03 00:24:07 +0000734}
735
736/*******************************************************************************
wdenkeeb1b772004-03-23 22:53:55 +0000737 *
738 * Drawing engine fill on screen region
739 */
wdenkc6097192002-11-03 00:24:07 +0000740void video_hw_rectfill (
wdenkeeb1b772004-03-23 22:53:55 +0000741 unsigned int bpp, /* bytes per pixel */
742 unsigned int dst_x, /* dest pos x */
743 unsigned int dst_y, /* dest pos y */
744 unsigned int dim_x, /* frame width */
745 unsigned int dim_y, /* frame height */
746 unsigned int color /* fill color */
747 )
wdenkc6097192002-11-03 00:24:07 +0000748{
wdenkeeb1b772004-03-23 22:53:55 +0000749 register GraphicDevice *pGD = (GraphicDevice *)&smi;
750 register unsigned int control;
wdenkc6097192002-11-03 00:24:07 +0000751
wdenkeeb1b772004-03-23 22:53:55 +0000752 dim_x *= bpp;
wdenkc6097192002-11-03 00:24:07 +0000753
wdenkeeb1b772004-03-23 22:53:55 +0000754 out32r ((pGD->dprBase + 0x0014), color);
755 out32r ((pGD->dprBase + 0x0004), ((dst_x<<16) | dst_y));
756 out32r ((pGD->dprBase + 0x0008), ((dim_x<<16) | dim_y));
wdenkc6097192002-11-03 00:24:07 +0000757
wdenkeeb1b772004-03-23 22:53:55 +0000758 control = 0x0000ffff & in32r ((pGD->dprBase + 0x000c));
wdenkc6097192002-11-03 00:24:07 +0000759
wdenkeeb1b772004-03-23 22:53:55 +0000760 control |= 0x80010000;
wdenkc6097192002-11-03 00:24:07 +0000761
wdenkeeb1b772004-03-23 22:53:55 +0000762 out32r ((pGD->dprBase + 0x000c), control);
wdenkc6097192002-11-03 00:24:07 +0000763
wdenkeeb1b772004-03-23 22:53:55 +0000764 /* Wait for drawing processor */
765 do
766 {
767 out8 ((pGD->isaBase + 0x3c4), 0x16);
768 } while (in8 (pGD->isaBase + 0x3c5) & 0x08);
wdenkc6097192002-11-03 00:24:07 +0000769}
770
771/*******************************************************************************
wdenkeeb1b772004-03-23 22:53:55 +0000772 *
773 * Drawing engine bitblt with screen region
774 */
wdenkc6097192002-11-03 00:24:07 +0000775void video_hw_bitblt (
wdenkeeb1b772004-03-23 22:53:55 +0000776 unsigned int bpp, /* bytes per pixel */
777 unsigned int src_x, /* source pos x */
778 unsigned int src_y, /* source pos y */
779 unsigned int dst_x, /* dest pos x */
780 unsigned int dst_y, /* dest pos y */
781 unsigned int dim_x, /* frame width */
782 unsigned int dim_y /* frame height */
783 )
wdenkc6097192002-11-03 00:24:07 +0000784{
wdenkeeb1b772004-03-23 22:53:55 +0000785 register GraphicDevice *pGD = (GraphicDevice *)&smi;
786 register unsigned int control;
wdenkc6097192002-11-03 00:24:07 +0000787
wdenkeeb1b772004-03-23 22:53:55 +0000788 dim_x *= bpp;
wdenkc6097192002-11-03 00:24:07 +0000789
wdenkeeb1b772004-03-23 22:53:55 +0000790 if ((src_y<dst_y) || ((src_y==dst_y) && (src_x<dst_x)))
791 {
792 out32r ((pGD->dprBase + 0x0000), (((src_x+dim_x-1)<<16) | (src_y+dim_y-1)));
793 out32r ((pGD->dprBase + 0x0004), (((dst_x+dim_x-1)<<16) | (dst_y+dim_y-1)));
794 control = 0x88000000;
795 } else {
796 out32r ((pGD->dprBase + 0x0000), ((src_x<<16) | src_y));
797 out32r ((pGD->dprBase + 0x0004), ((dst_x<<16) | dst_y));
798 control = 0x80000000;
799 }
wdenkc6097192002-11-03 00:24:07 +0000800
wdenkeeb1b772004-03-23 22:53:55 +0000801 out32r ((pGD->dprBase + 0x0008), ((dim_x<<16) | dim_y));
802 control |= (0x0000ffff & in32r ((pGD->dprBase + 0x000c)));
803 out32r ((pGD->dprBase + 0x000c), control);
wdenkc6097192002-11-03 00:24:07 +0000804
wdenkeeb1b772004-03-23 22:53:55 +0000805 /* Wait for drawing processor */
806 do
807 {
808 out8 ((pGD->isaBase + 0x3c4), 0x16);
809 } while (in8 (pGD->isaBase + 0x3c5) & 0x08);
wdenkc6097192002-11-03 00:24:07 +0000810}
811
812/*******************************************************************************
wdenkeeb1b772004-03-23 22:53:55 +0000813 *
814 * Set a RGB color in the LUT (8 bit index)
815 */
wdenkc6097192002-11-03 00:24:07 +0000816void video_set_lut (
wdenkeeb1b772004-03-23 22:53:55 +0000817 unsigned int index, /* color number */
818 unsigned char r, /* red */
819 unsigned char g, /* green */
820 unsigned char b /* blue */
821 )
wdenkc6097192002-11-03 00:24:07 +0000822{
wdenkeeb1b772004-03-23 22:53:55 +0000823 register GraphicDevice *pGD = (GraphicDevice *)&smi;
wdenkc6097192002-11-03 00:24:07 +0000824
wdenkeeb1b772004-03-23 22:53:55 +0000825 out8 (SMI_LUT_MASK, 0xff);
wdenkc6097192002-11-03 00:24:07 +0000826
wdenkeeb1b772004-03-23 22:53:55 +0000827 out8 (SMI_LUT_START, (char)index);
wdenkc6097192002-11-03 00:24:07 +0000828
wdenkeeb1b772004-03-23 22:53:55 +0000829 out8 (SMI_LUT_RGB, r>>2); /* red */
830 udelay (10);
831 out8 (SMI_LUT_RGB, g>>2); /* green */
832 udelay (10);
833 out8 (SMI_LUT_RGB, b>>2); /* blue */
834 udelay (10);
wdenkc6097192002-11-03 00:24:07 +0000835}