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