]>
Commit | Line | Data |
---|---|---|
c609719b WD |
1 | /* |
2 | * (C) Copyright 1997-2002 ELTEC Elektronik AG | |
3 | * Frank Gottschling <[email protected]> | |
4 | * | |
1a459660 | 5 | * SPDX-License-Identifier: GPL-2.0+ |
c609719b WD |
6 | */ |
7 | ||
8 | /* | |
9 | * smiLynxEM.c | |
10 | * | |
11 | * Silicon Motion graphic interface for sm810/sm710/sm712 accelerator | |
12 | * | |
13 | * modification history | |
14 | * -------------------- | |
15 | * 04-18-2002 Rewritten for U-Boot <[email protected]>. | |
16 | * | |
eeb1b77b WD |
17 | * 18-03-2004 - Unify videomodes handling with the ct69000 |
18 | * - The video output can be set via the variable "videoout" | |
19 | * in the environment. | |
20 | * videoout=1 output on LCD | |
21 | * videoout=2 output on CRT (default value) | |
22 | * <[email protected]> | |
c609719b WD |
23 | */ |
24 | ||
25 | #include <common.h> | |
26 | ||
c609719b WD |
27 | #include <pci.h> |
28 | #include <video_fb.h> | |
eeb1b77b | 29 | #include "videomodes.h" |
c609719b WD |
30 | /* |
31 | * Export Graphic Device | |
32 | */ | |
33 | GraphicDevice smi; | |
34 | ||
35 | /* | |
36 | * SMI 710/712 have 4MB internal RAM; SMI 810 2MB internal + 2MB external | |
37 | */ | |
eeb1b77b | 38 | #define VIDEO_MEM_SIZE 0x400000 |
c609719b WD |
39 | |
40 | ||
41 | /* | |
42 | * ISA mapped regs | |
43 | */ | |
eeb1b77b WD |
44 | #define SMI_INDX_C4 (pGD->isaBase + 0x03c4) /* index reg */ |
45 | #define SMI_DATA_C5 (pGD->isaBase + 0x03c5) /* data reg */ | |
46 | #define SMI_INDX_D4 (pGD->isaBase + 0x03d4) /* index reg */ | |
47 | #define SMI_DATA_D5 (pGD->isaBase + 0x03d5) /* data reg */ | |
48 | #define SMI_ISR1 (pGD->isaBase + 0x03ca) | |
49 | #define SMI_INDX_CE (pGD->isaBase + 0x03ce) /* index reg */ | |
50 | #define SMI_DATA_CF (pGD->isaBase + 0x03cf) /* data reg */ | |
51 | #define SMI_LOCK_REG (pGD->isaBase + 0x03c3) /* unlock/lock ext crt reg */ | |
52 | #define SMI_MISC_REG (pGD->isaBase + 0x03c2) /* misc reg */ | |
53 | #define SMI_LUT_MASK (pGD->isaBase + 0x03c6) /* lut mask reg */ | |
54 | #define SMI_LUT_START (pGD->isaBase + 0x03c8) /* lut start index */ | |
55 | #define SMI_LUT_RGB (pGD->isaBase + 0x03c9) /* lut colors auto incr.*/ | |
56 | #define SMI_INDX_ATTR (pGD->isaBase + 0x03c0) /* attributes index reg */ | |
c609719b WD |
57 | |
58 | /* | |
59 | * Video processor control | |
eeb1b77b | 60 | */ |
c609719b | 61 | typedef struct { |
eeb1b77b WD |
62 | unsigned int control; |
63 | unsigned int colorKey; | |
64 | unsigned int colorKeyMask; | |
65 | unsigned int start; | |
66 | unsigned short offset; | |
67 | unsigned short width; | |
68 | unsigned int fifoPrio; | |
69 | unsigned int fifoERL; | |
70 | unsigned int YUVtoRGB; | |
c609719b WD |
71 | } SmiVideoProc; |
72 | ||
73 | /* | |
74 | * Video window control | |
75 | */ | |
76 | typedef struct { | |
eeb1b77b WD |
77 | unsigned short top; |
78 | unsigned short left; | |
79 | unsigned short bottom; | |
80 | unsigned short right; | |
81 | unsigned int srcStart; | |
82 | unsigned short width; | |
83 | unsigned short offset; | |
84 | unsigned char hStretch; | |
85 | unsigned char vStretch; | |
c609719b WD |
86 | } SmiVideoWin; |
87 | ||
88 | /* | |
89 | * Capture port control | |
90 | */ | |
91 | typedef struct { | |
eeb1b77b WD |
92 | unsigned int control; |
93 | unsigned short topClip; | |
94 | unsigned short leftClip; | |
95 | unsigned short srcHeight; | |
96 | unsigned short srcWidth; | |
97 | unsigned int srcBufStart1; | |
98 | unsigned int srcBufStart2; | |
99 | unsigned short srcOffset; | |
100 | unsigned short fifoControl; | |
c609719b WD |
101 | } SmiCapturePort; |
102 | ||
103 | ||
c609719b WD |
104 | /* |
105 | * Register values for common video modes | |
106 | */ | |
eeb1b77b WD |
107 | static char SMI_SCR[] = { |
108 | /* all modes */ | |
109 | 0x10, 0xff, 0x11, 0xff, 0x12, 0xff, 0x13, 0xff, 0x15, 0x90, | |
110 | 0x17, 0x20, 0x18, 0xb1, 0x19, 0x00, | |
c609719b | 111 | }; |
eeb1b77b WD |
112 | static char SMI_EXT_CRT[] = { |
113 | 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, | |
ccd9d3d6 | 114 | 0x36, 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3f, 0x00, |
c609719b | 115 | }; |
eeb1b77b WD |
116 | static char SMI_ATTR [] = { |
117 | 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05, | |
118 | 0x06, 0x06, 0x07, 0x07, 0x08, 0x08, 0x09, 0x09, 0x0a, 0x0a, 0x0b, 0x0b, | |
119 | 0x0c, 0x0c, 0x0d, 0x0d, 0x0e, 0x0e, 0x0f, 0x0f, 0x10, 0x41, 0x11, 0x00, | |
120 | 0x12, 0x0f, 0x13, 0x00, 0x14, 0x00, | |
c609719b | 121 | }; |
eeb1b77b WD |
122 | static char SMI_GCR[18] = { |
123 | 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x40, | |
ccd9d3d6 | 124 | 0x06, 0x05, 0x07, 0x0f, 0x08, 0xff, |
c609719b | 125 | }; |
eeb1b77b | 126 | static char SMI_SEQR[] = { |
ccd9d3d6 | 127 | 0x00, 0x00, 0x01, 0x01, 0x02, 0x0f, 0x03, 0x03, 0x04, 0x0e, 0x00, 0x03, |
c609719b | 128 | }; |
eeb1b77b | 129 | static char SMI_PCR [] = { |
ccd9d3d6 | 130 | 0x20, 0x04, 0x21, 0x30, 0x22, 0x00, 0x23, 0x00, 0x24, 0x00, |
c609719b | 131 | }; |
eeb1b77b | 132 | static char SMI_MCR[] = { |
b79a11cc | 133 | 0x60, 0x01, 0x61, 0x00, |
c609719b WD |
134 | }; |
135 | ||
eeb1b77b WD |
136 | static char SMI_HCR[] = { |
137 | 0x80, 0xff, 0x81, 0x07, 0x82, 0x00, 0x83, 0xff, 0x84, 0xff, 0x88, 0x00, | |
ccd9d3d6 | 138 | 0x89, 0x02, 0x8a, 0x80, 0x8b, 0x01, 0x8c, 0xff, 0x8d, 0x00, |
c609719b WD |
139 | }; |
140 | ||
c609719b WD |
141 | |
142 | /******************************************************************************* | |
eeb1b77b WD |
143 | * |
144 | * Write SMI ISA register | |
145 | */ | |
c609719b WD |
146 | static void smiWrite (unsigned short index, char reg, char val) |
147 | { | |
eeb1b77b | 148 | register GraphicDevice *pGD = (GraphicDevice *)&smi; |
c609719b | 149 | |
eeb1b77b WD |
150 | out8 ((pGD->isaBase + index), reg); |
151 | out8 ((pGD->isaBase + index + 1), val); | |
c609719b WD |
152 | } |
153 | ||
154 | /******************************************************************************* | |
eeb1b77b WD |
155 | * |
156 | * Write a table of SMI ISA register | |
157 | */ | |
c609719b | 158 | static void smiLoadRegs ( |
eeb1b77b WD |
159 | unsigned int iReg, |
160 | unsigned int dReg, | |
161 | char *regTab, | |
162 | unsigned int tabSize | |
163 | ) | |
c609719b | 164 | { |
eeb1b77b WD |
165 | register GraphicDevice *pGD = (GraphicDevice *)&smi; |
166 | register int i; | |
167 | ||
168 | 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 | } | |
c609719b WD |
179 | } |
180 | ||
181 | /******************************************************************************* | |
eeb1b77b WD |
182 | * |
183 | * Init capture port registers | |
184 | */ | |
c609719b WD |
185 | static void smiInitCapturePort (void) |
186 | { | |
eeb1b77b WD |
187 | SmiCapturePort smiCP = { 0x01400600, 0x30, 0x40, 480, 640, 0, 0, 2560, 6 }; |
188 | register GraphicDevice *pGD = (GraphicDevice *)&smi; | |
189 | register SmiCapturePort *pCP = (SmiCapturePort *)&smiCP; | |
190 | ||
191 | 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); | |
c609719b WD |
198 | } |
199 | ||
200 | ||
201 | /******************************************************************************* | |
eeb1b77b WD |
202 | * |
203 | * Init video processor registers | |
204 | */ | |
c609719b WD |
205 | static void smiInitVideoProcessor (void) |
206 | { | |
eeb1b77b WD |
207 | 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; | |
c609719b | 212 | |
eeb1b77b WD |
213 | 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; | |
c609719b | 218 | |
eeb1b77b WD |
219 | /* color key */ |
220 | out32r ((pGD->vprBase + 0x0004), pVP->colorKey); | |
c609719b | 221 | |
eeb1b77b WD |
222 | /* color key mask */ |
223 | out32r ((pGD->vprBase + 0x0008), pVP->colorKeyMask); | |
c609719b | 224 | |
eeb1b77b WD |
225 | /* data src start adrs */ |
226 | out32r ((pGD->vprBase + 0x000c), pVP->start / 8); | |
c609719b | 227 | |
eeb1b77b WD |
228 | /* data width and offset */ |
229 | out32r ((pGD->vprBase + 0x0010), | |
230 | ((pVP->offset / 8 * pGD->gdfBytesPP) << 16) | | |
231 | (pGD->plnSizeX / 8 * pGD->gdfBytesPP)); | |
c609719b | 232 | |
eeb1b77b WD |
233 | /* video window 1 */ |
234 | out32r ((pGD->vprBase + 0x0014), | |
235 | ((pVWin->top << 16) | pVWin->left)); | |
c609719b | 236 | |
eeb1b77b WD |
237 | out32r ((pGD->vprBase + 0x0018), |
238 | ((pVWin->bottom << 16) | pVWin->right)); | |
c609719b | 239 | |
eeb1b77b | 240 | out32r ((pGD->vprBase + 0x001c), pVWin->srcStart / 8); |
c609719b | 241 | |
eeb1b77b WD |
242 | out32r ((pGD->vprBase + 0x0020), |
243 | (((pVWin->offset / 8) << 16) | (pVWin->width / 8))); | |
c609719b | 244 | |
eeb1b77b WD |
245 | out32r ((pGD->vprBase + 0x0024), |
246 | (((pVWin->hStretch) << 8) | pVWin->vStretch)); | |
c609719b | 247 | |
eeb1b77b WD |
248 | /* video window 2 */ |
249 | out32r ((pGD->vprBase + 0x0028), | |
250 | ((pVWin->top << 16) | pVWin->left)); | |
c609719b | 251 | |
eeb1b77b WD |
252 | out32r ((pGD->vprBase + 0x002c), |
253 | ((pVWin->bottom << 16) | pVWin->right)); | |
c609719b | 254 | |
eeb1b77b WD |
255 | out32r ((pGD->vprBase + 0x0030), |
256 | pVWin->srcStart / 8); | |
c609719b | 257 | |
eeb1b77b WD |
258 | out32r ((pGD->vprBase + 0x0034), |
259 | (((pVWin->offset / 8) << 16) | (pVWin->width / 8))); | |
c609719b | 260 | |
eeb1b77b WD |
261 | out32r ((pGD->vprBase + 0x0038), |
262 | (((pVWin->hStretch) << 8) | pVWin->vStretch)); | |
c609719b | 263 | |
eeb1b77b WD |
264 | /* fifo prio control */ |
265 | out32r ((pGD->vprBase + 0x0054), pVP->fifoPrio); | |
c609719b | 266 | |
eeb1b77b WD |
267 | /* fifo empty request levell */ |
268 | out32r ((pGD->vprBase + 0x0058), pVP->fifoERL); | |
c609719b | 269 | |
eeb1b77b WD |
270 | /* conversion constant */ |
271 | out32r ((pGD->vprBase + 0x005c), pVP->YUVtoRGB); | |
c609719b | 272 | |
eeb1b77b WD |
273 | /* vpr control word */ |
274 | out32r ((pGD->vprBase + 0x0000), pVP->control); | |
c609719b WD |
275 | } |
276 | ||
277 | /****************************************************************************** | |
278 | * | |
279 | * Init drawing engine registers | |
280 | */ | |
281 | static void smiInitDrawingEngine (void) | |
282 | { | |
eeb1b77b WD |
283 | GraphicDevice *pGD = (GraphicDevice *)&smi; |
284 | unsigned int val; | |
c609719b | 285 | |
eeb1b77b WD |
286 | /* don't start now */ |
287 | out32r ((pGD->dprBase + 0x000c), 0x000f0000); | |
c609719b | 288 | |
eeb1b77b WD |
289 | /* set rop2 to copypen */ |
290 | val = 0xffff3ff0 & in32r ((pGD->dprBase + 0x000c)); | |
291 | out32r ((pGD->dprBase + 0x000c), (val | 0x8000 | 0x0c)); | |
c609719b | 292 | |
eeb1b77b WD |
293 | /* set clip rect */ |
294 | out32r ((pGD->dprBase + 0x002c), 0); | |
295 | out32r ((pGD->dprBase + 0x0030), | |
296 | ((pGD->winSizeY<<16) | pGD->winSizeX * pGD->gdfBytesPP )); | |
c609719b | 297 | |
eeb1b77b WD |
298 | /* src row pitch */ |
299 | val = 0xffff0000 & (in32r ((pGD->dprBase + 0x0010))); | |
300 | out32r ((pGD->dprBase + 0x0010), | |
301 | (val | pGD->plnSizeX * pGD->gdfBytesPP)); | |
c609719b | 302 | |
eeb1b77b WD |
303 | /* dst row pitch */ |
304 | val = 0x0000ffff & (in32r ((pGD->dprBase + 0x0010))); | |
305 | out32r ((pGD->dprBase + 0x0010), | |
306 | (((pGD->plnSizeX * pGD->gdfBytesPP)<<16) | val)); | |
c609719b | 307 | |
eeb1b77b WD |
308 | /* 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); | |
c609719b | 313 | |
eeb1b77b WD |
314 | /* src base adrs */ |
315 | out32r ((pGD->dprBase + 0x0040), | |
316 | (((pGD->frameAdrs/8) & 0x000fffff))); | |
c609719b | 317 | |
eeb1b77b WD |
318 | /* dst base adrs */ |
319 | out32r ((pGD->dprBase + 0x0044), | |
320 | (((pGD->frameAdrs/8) & 0x000fffff))); | |
c609719b | 321 | |
eeb1b77b WD |
322 | /* foreground color */ |
323 | out32r ((pGD->dprBase + 0x0014), pGD->fg); | |
c609719b | 324 | |
eeb1b77b WD |
325 | /* background color */ |
326 | out32r ((pGD->dprBase + 0x0018), pGD->bg); | |
c609719b | 327 | |
eeb1b77b WD |
328 | /* xcolor */ |
329 | out32r ((pGD->dprBase + 0x0020), 0x00ffffff); | |
c609719b | 330 | |
eeb1b77b WD |
331 | /* xcolor mask */ |
332 | out32r ((pGD->dprBase + 0x0024), 0x00ffffff); | |
c609719b | 333 | |
eeb1b77b WD |
334 | /* bit mask */ |
335 | out32r ((pGD->dprBase + 0x0028), 0x00ffffff); | |
c609719b | 336 | |
eeb1b77b WD |
337 | /* load mono pattern */ |
338 | out32r ((pGD->dprBase + 0x0034), 0); | |
339 | out32r ((pGD->dprBase + 0x0038), 0); | |
c609719b WD |
340 | } |
341 | ||
342 | static struct pci_device_id supported[] = { | |
eeb1b77b WD |
343 | { 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 | { } | |
c609719b WD |
347 | }; |
348 | ||
eeb1b77b WD |
349 | /*****************************************************************************/ |
350 | static 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 | /*****************************************************************************/ | |
367 | static 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 */ | |
b79a11cc | 385 | hbs = hd; |
eeb1b77b WD |
386 | 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; | |
b79a11cc | 395 | |
eeb1b77b WD |
396 | 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); | |
b79a11cc | 418 | |
eeb1b77b WD |
419 | 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; | |
b79a11cc | 434 | |
eeb1b77b WD |
435 | |
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 */ | |
b79a11cc | 443 | cr[0x11] = (ve & 0x0f); |
eeb1b77b WD |
444 | 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 | ||
471 | static 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 */ | |
b79a11cc | 479 | L = P * n - m * Q; |
eeb1b77b WD |
480 | 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 | /*****************************************************************************/ | |
505 | static void smiLoadCcr (struct ctfb_res_modes *var, unsigned short device_id) | |
506 | { | |
77ddac94 WD |
507 | unsigned int p = 0; |
508 | unsigned int q = 0; | |
eeb1b77b WD |
509 | 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); | |
b79a11cc | 534 | |
eeb1b77b | 535 | /* VCLK */ |
eedcd078 | 536 | freq = 1000000000000LL / var -> pixclock; |
b79a11cc | 537 | |
eeb1b77b | 538 | FindPQ ((unsigned int)freq, &p, &q); |
b79a11cc | 539 | |
eeb1b77b WD |
540 | smiWrite (SMI_INDX_C4, 0x6c, p); |
541 | smiWrite (SMI_INDX_C4, 0x6d, q); | |
542 | ||
543 | } | |
c609719b WD |
544 | |
545 | /******************************************************************************* | |
eeb1b77b WD |
546 | * |
547 | * Init video chip with common Linux graphic modes (lilo) | |
548 | */ | |
c609719b WD |
549 | void *video_hw_init (void) |
550 | { | |
eeb1b77b WD |
551 | 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; | |
b79a11cc | 562 | |
eeb1b77b WD |
563 | /* Search for video chip */ |
564 | printf("Video: "); | |
565 | ||
566 | if ((devbusfn = pci_find_devices(supported, 0)) < 0) | |
8bde7f77 | 567 | { |
eeb1b77b WD |
568 | printf ("Controller not found !\n"); |
569 | return (NULL); | |
570 | } | |
571 | ||
572 | /* 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); | |
577 | ||
578 | tmp = 0; | |
b79a11cc | 579 | |
6d0f6bcf | 580 | videomode = CONFIG_SYS_DEFAULT_VIDEO_MODE; |
eeb1b77b WD |
581 | /* 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) { | |
6d0f6bcf | 599 | printf ("no VESA Mode found, switching to mode 0x%x ", CONFIG_SYS_DEFAULT_VIDEO_MODE); |
eeb1b77b WD |
600 | 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 { | |
b79a11cc | 607 | |
eeb1b77b WD |
608 | res_mode = (struct ctfb_res_modes *) &var_mode; |
609 | bits_per_pixel = video_get_params (res_mode, penv); | |
610 | } | |
611 | ||
612 | /* 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; | |
b79a11cc | 624 | |
eeb1b77b WD |
625 | /* 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; | |
8bde7f77 | 651 | } |
eeb1b77b | 652 | |
6d0f6bcf | 653 | pGD->isaBase = CONFIG_SYS_ISA_IO; |
eeb1b77b WD |
654 | 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; | |
660 | ||
661 | /* Set up hardware : select color mode, | |
662 | set Register base to isa 3dx for 3?x regs*/ | |
663 | out8 (SMI_MISC_REG, 0x01); | |
664 | ||
665 | /* Turn off display */ | |
666 | smiWrite (SMI_INDX_C4, 0x01, 0x20); | |
667 | ||
668 | /* Unlock ext. crt regs */ | |
669 | out8 (SMI_LOCK_REG, 0x40); | |
670 | ||
671 | /* Unlock crt regs 0-7 */ | |
672 | smiWrite (SMI_INDX_D4, 0x11, 0x0e); | |
673 | ||
674 | /* Sytem Control Register */ | |
675 | smiLoadRegs (SMI_INDX_C4, SMI_DATA_C5, SMI_SCR, sizeof(SMI_SCR)); | |
676 | ||
677 | /* extented CRT Register */ | |
678 | smiLoadRegs (SMI_INDX_D4, SMI_DATA_D5, SMI_EXT_CRT, sizeof(SMI_EXT_CRT)); | |
679 | ||
680 | /* Attributes controller registers */ | |
681 | smiLoadRegs (SMI_INDX_ATTR, SMI_INDX_ATTR, SMI_ATTR, sizeof(SMI_ATTR)); | |
b79a11cc | 682 | |
eeb1b77b WD |
683 | /* Graphics Controller Register */ |
684 | smiLoadRegs (SMI_INDX_CE, SMI_DATA_CF, SMI_GCR, sizeof(SMI_GCR)); | |
685 | ||
686 | /* Sequencer Register */ | |
687 | smiLoadRegs (SMI_INDX_C4, SMI_DATA_C5, SMI_SEQR, sizeof(SMI_SEQR)); | |
688 | ||
689 | /* Power Control Register */ | |
690 | smiLoadRegs (SMI_INDX_C4, SMI_DATA_C5, SMI_PCR, sizeof(SMI_PCR)); | |
691 | ||
692 | /* 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)); | |
696 | ||
697 | /* Set misc output register */ | |
698 | smiLoadMsr (res_mode); | |
b79a11cc | 699 | |
eeb1b77b WD |
700 | /* Set CRT and Clock control registers */ |
701 | smiLoadCrt (res_mode, bits_per_pixel); | |
b79a11cc | 702 | |
eeb1b77b WD |
703 | smiLoadCcr (res_mode, device_id); |
704 | ||
705 | /* Hardware Cusor Register */ | |
706 | smiLoadRegs (SMI_INDX_C4, SMI_DATA_C5, SMI_HCR, sizeof(SMI_HCR)); | |
707 | ||
708 | /* 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); | |
715 | ||
716 | /* Video processor default setup */ | |
717 | smiInitVideoProcessor (); | |
718 | ||
719 | /* Capture port default setup */ | |
720 | smiInitCapturePort (); | |
721 | ||
722 | /* Drawing engine default setup */ | |
723 | smiInitDrawingEngine (); | |
724 | ||
725 | /* Turn on display */ | |
726 | smiWrite (0x3c4, 0x01, 0x01); | |
727 | ||
728 | /* Clear video memory */ | |
729 | i = pGD->memSize/4; | |
730 | vm = (unsigned int *)pGD->pciBase; | |
731 | while(i--) | |
732 | *vm++ = 0; | |
733 | return ((void*)&smi); | |
c609719b WD |
734 | } |
735 | ||
736 | /******************************************************************************* | |
eeb1b77b WD |
737 | * |
738 | * Drawing engine fill on screen region | |
739 | */ | |
c609719b | 740 | void video_hw_rectfill ( |
eeb1b77b WD |
741 | 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 | ) | |
c609719b | 748 | { |
eeb1b77b WD |
749 | register GraphicDevice *pGD = (GraphicDevice *)&smi; |
750 | register unsigned int control; | |
c609719b | 751 | |
eeb1b77b | 752 | dim_x *= bpp; |
c609719b | 753 | |
eeb1b77b WD |
754 | 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)); | |
c609719b | 757 | |
eeb1b77b | 758 | control = 0x0000ffff & in32r ((pGD->dprBase + 0x000c)); |
c609719b | 759 | |
eeb1b77b | 760 | control |= 0x80010000; |
c609719b | 761 | |
eeb1b77b | 762 | out32r ((pGD->dprBase + 0x000c), control); |
c609719b | 763 | |
eeb1b77b WD |
764 | /* Wait for drawing processor */ |
765 | do | |
766 | { | |
767 | out8 ((pGD->isaBase + 0x3c4), 0x16); | |
768 | } while (in8 (pGD->isaBase + 0x3c5) & 0x08); | |
c609719b WD |
769 | } |
770 | ||
771 | /******************************************************************************* | |
eeb1b77b WD |
772 | * |
773 | * Drawing engine bitblt with screen region | |
774 | */ | |
c609719b | 775 | void video_hw_bitblt ( |
eeb1b77b WD |
776 | 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 | ) | |
c609719b | 784 | { |
eeb1b77b WD |
785 | register GraphicDevice *pGD = (GraphicDevice *)&smi; |
786 | register unsigned int control; | |
787 | ||
788 | dim_x *= bpp; | |
789 | ||
790 | 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 | } | |
800 | ||
801 | out32r ((pGD->dprBase + 0x0008), ((dim_x<<16) | dim_y)); | |
802 | control |= (0x0000ffff & in32r ((pGD->dprBase + 0x000c))); | |
803 | out32r ((pGD->dprBase + 0x000c), control); | |
804 | ||
805 | /* Wait for drawing processor */ | |
806 | do | |
807 | { | |
808 | out8 ((pGD->isaBase + 0x3c4), 0x16); | |
809 | } while (in8 (pGD->isaBase + 0x3c5) & 0x08); | |
c609719b WD |
810 | } |
811 | ||
812 | /******************************************************************************* | |
eeb1b77b WD |
813 | * |
814 | * Set a RGB color in the LUT (8 bit index) | |
815 | */ | |
c609719b | 816 | void video_set_lut ( |
eeb1b77b WD |
817 | unsigned int index, /* color number */ |
818 | unsigned char r, /* red */ | |
819 | unsigned char g, /* green */ | |
820 | unsigned char b /* blue */ | |
821 | ) | |
c609719b | 822 | { |
eeb1b77b | 823 | register GraphicDevice *pGD = (GraphicDevice *)&smi; |
c609719b | 824 | |
eeb1b77b | 825 | out8 (SMI_LUT_MASK, 0xff); |
c609719b | 826 | |
eeb1b77b | 827 | out8 (SMI_LUT_START, (char)index); |
c609719b | 828 | |
eeb1b77b WD |
829 | 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); | |
c609719b | 835 | } |