]>
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 | ||
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 | */ | |
51 | GraphicDevice 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 | 79 | typedef 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 | */ | |
94 | typedef 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 | */ | |
109 | typedef 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 |
125 | static char SMI_SCR[] = { |
126 | /* all modes */ | |
127 | 0x10, 0xff, 0x11, 0xff, 0x12, 0xff, 0x13, 0xff, 0x15, 0x90, | |
128 | 0x17, 0x20, 0x18, 0xb1, 0x19, 0x00, | |
c609719b | 129 | }; |
eeb1b77b WD |
130 | static 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 |
134 | static char SMI_ATTR [] = { |
135 | 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05, | |
136 | 0x06, 0x06, 0x07, 0x07, 0x08, 0x08, 0x09, 0x09, 0x0a, 0x0a, 0x0b, 0x0b, | |
137 | 0x0c, 0x0c, 0x0d, 0x0d, 0x0e, 0x0e, 0x0f, 0x0f, 0x10, 0x41, 0x11, 0x00, | |
138 | 0x12, 0x0f, 0x13, 0x00, 0x14, 0x00, | |
c609719b | 139 | }; |
eeb1b77b WD |
140 | static 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 | 144 | static char SMI_SEQR[] = { |
ccd9d3d6 | 145 | 0x00, 0x00, 0x01, 0x01, 0x02, 0x0f, 0x03, 0x03, 0x04, 0x0e, 0x00, 0x03, |
c609719b | 146 | }; |
eeb1b77b | 147 | static char SMI_PCR [] = { |
ccd9d3d6 | 148 | 0x20, 0x04, 0x21, 0x30, 0x22, 0x00, 0x23, 0x00, 0x24, 0x00, |
c609719b | 149 | }; |
eeb1b77b | 150 | static 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 |
157 | static 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 |
167 | static 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 | 179 | static 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 |
206 | static 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 |
226 | static 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 | */ | |
302 | static 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 | ||
363 | static 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 | /*****************************************************************************/ |
371 | static void smiLoadMsr (struct ctfb_res_modes *mode) | |
372 | { | |
373 | unsigned char h_synch_high, v_synch_high; | |
374 | register GraphicDevice *pGD = (GraphicDevice *)&smi; | |
375 | ||
376 | h_synch_high = (mode->sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : 0x40; /* horizontal Synch High active */ | |
377 | v_synch_high = (mode->sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : 0x80; /* vertical Synch High active */ | |
378 | out8 (SMI_MISC_REG, (h_synch_high | v_synch_high | 0x29)); | |
379 | /* upper64K==0x20, CLC2select==0x08, RAMenable==0x02!(todo), CGA==0x01 | |
380 | * Selects the upper 64KB page.Bit5=1 | |
381 | * CLK2 (left reserved in standard VGA) Bit3|2=1|0 | |
382 | * Disables CPU access to frame buffer. Bit1=0 | |
383 | * Sets the I/O address decode for ST01, FCR, and all CR registers | |
384 | * to the 3Dx I/O address range (CGA emulation). Bit0=1 | |
385 | */ | |
386 | } | |
387 | /*****************************************************************************/ | |
388 | static void smiLoadCrt (struct ctfb_res_modes *var, int bits_per_pixel) | |
389 | { | |
390 | unsigned char cr[0x7a]; | |
391 | int i; | |
392 | unsigned int hd, hs, he, ht, hbs, hbe; /* Horizontal. */ | |
393 | unsigned int vd, vs, ve, vt, vbs, vbe; /* vertical */ | |
394 | unsigned int bpp, wd, dblscan, interlaced; | |
395 | ||
396 | const int LineCompare = 0x3ff; | |
397 | unsigned int TextScanLines = 1; /* this is in fact a vertical zoom factor */ | |
398 | register GraphicDevice *pGD = (GraphicDevice *)&smi; | |
399 | ||
400 | /* Horizontal */ | |
401 | hd = (var->xres) / 8; /* HDisp. */ | |
402 | hs = (var->xres + var->right_margin) / 8; /* HsStrt */ | |
403 | he = (var->xres + var->right_margin + var->hsync_len) / 8; /* HsEnd */ | |
404 | ht = (var->left_margin + var->xres + var->right_margin + var->hsync_len) / 8; /* HTotal */ | |
405 | /* Blank */ | |
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 | ||
492 | static unsigned int FindPQ (unsigned int freq, unsigned int *pp, unsigned int *pq) | |
493 | { | |
494 | unsigned int n = QMIN, m = 0; | |
495 | long long int L = 0, P = freq, Q = REF_FREQ, H = P >> 1; | |
496 | long long int D = 0x7ffffffffffffffLL; | |
497 | ||
498 | for (n = QMIN; n <= QMAX; n++) { | |
499 | m = PMIN; /* p/q ~ freq/ref -> p*ref-freq*q ~ 0 */ | |
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 | /*****************************************************************************/ | |
526 | static 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 |
570 | void *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 | 761 | void 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 | 796 | void 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 | 837 | void 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 */ |