blob: 563556285bb8f0087acf39b5d2481ad665c33711 [file] [log] [blame]
wdenkc6097192002-11-03 00:24:07 +00001/*
2 * (C) Copyright 2002
3 * Denis Peter, MPL AG Switzerland
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
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
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 * ported from ctfb.c (linux kernel) for the U-Boot
26 *
27 */
28
29/************************************************************************
30 Get Parameters for the video mode:
31 Parameters can be set via the variable "videomode" in the environment.
32 2 diferent ways are possible:
33 "videomode=301" - 301 is a hexadecimal number describing the VESA
34 mode. Following modes are implemented:
35
36 Colors 640x480 800x600 1024x768 1152x864
37 --------+-----------------------------------
38 8 bits | 0x301 0x303 0x305 0x161
39 15 bits | 0x310 0x313 0x316 0x162
40 16 bits | 0x311 0x314 0x317 0x163
41 24 bits | 0x312 0x315 0x318 ?
42 --------+-----------------------------------
43 "videomode=bootargs"
44 - the parameters are parsed from the bootargs.
45 The format is "NAME:VALUE,NAME:VALUE" etc.
46 Ex.:
47 "bootargs=video=ctfb:x:800,y:600,depth:16,pclk:25000"
48 Parameters not included in the list will be taken from
49 the default mode, which is one of the following:
50 mode:0 640x480x24
51 mode:1 800x600x16
52 mode:2 1024x768x8
53 mode:3 960x720x24
54 mode:4 1152x864x16
55 if "mode" is not provided within the parameter list,
56 mode:0 is assumed.
57 Following parameters are supported:
58 x xres = visible resolution horizontal
59 y yres = visible resolution vertical
60 pclk pixelclocks in pico sec
61 le left_marging time from sync to picture in pixelclocks
62 ri right_marging time from picture to sync in pixelclocks
63 up upper_margin time from sync to picture
64 lo lower_margin
65 hs hsync_len length of horizontal sync
66 vs vsync_len length of vertical sync
67 sync see FB_SYNC_*
68 vmode see FB_VMODE_*
69 depth Color depth in bits per pixel
70 All other parameters in the variable bootargs are ignored.
71 It is also possible to set the parameters direct in the
72 variable "videomode", or in another variable i.e.
73 "myvideo" and setting the variable "videomode=myvideo"..
74****************************************************************************/
75
76#include <common.h>
77
78#ifdef CONFIG_VIDEO
79
80#include <pci.h>
81#include <video_fb.h>
82
83#ifdef CONFIG_VIDEO_CT69000
84
85/* debug */
86#undef VGA_DEBUG
87#undef VGA_DUMP_REG
88#ifdef VGA_DEBUG
89#define PRINTF(fmt,args...) printf (fmt ,##args)
90#else
91#define PRINTF(fmt,args...)
92#endif
93
94/* Macros */
95#ifndef min
96#define min( a, b ) ( ( a ) < ( b ) ) ? ( a ) : ( b )
97#endif
98#ifndef max
99#define max( a, b ) ( ( a ) > ( b ) ) ? ( a ) : ( b )
100#endif
101#ifdef minmax
102#error "term minmax already used."
103#endif
104#define minmax( a, x, b ) max( ( a ), min( ( x ), ( b ) ) )
105#define N_ELTS( x ) ( sizeof( x ) / sizeof( x[ 0 ] ) )
106
107/* CT Register Offsets */
108#define CT_AR_O 0x3c0 /* Index and Data write port of the attribute Registers */
109#define CT_GR_O 0x3ce /* Index port of the Graphic Controller Registers */
110#define CT_SR_O 0x3c4 /* Index port of the Sequencer Controller */
111#define CT_CR_O 0x3d4 /* Index port of the CRT Controller */
112#define CT_XR_O 0x3d6 /* Extended Register index */
113#define CT_MSR_W_O 0x3c2 /* Misc. Output Register (write only) */
114#define CT_LUT_MASK_O 0x3c6 /* Color Palette Mask */
115#define CT_LUT_START_O 0x3c8 /* Color Palette Write Mode Index */
116#define CT_LUT_RGB_O 0x3c9 /* Color Palette Data Port */
117#define CT_STATUS_REG0_O 0x3c2 /* Status Register 0 (read only) */
118#define CT_STATUS_REG1_O 0x3da /* Input Status Register 1 (read only) */
119
120#define CT_FP_O 0x3d0 /* Index port of the Flat panel Registers */
121#define CT_MR_O 0x3d2 /* Index Port of the Multimedia Extension */
122
123/* defines for the memory mapped registers */
124#define BR00_o 0x400000 /* Source and Destination Span Register */
125#define BR01_o 0x400004 /* Pattern/Source Expansion Background Color & Transparency Key Register */
126#define BR02_o 0x400008 /* Pattern/Source Expansion Foreground Color Register */
127#define BR03_o 0x40000C /* Monochrome Source Control Register */
128#define BR04_o 0x400010 /* BitBLT Control Register */
129#define BR05_o 0x400014 /* Pattern Address Registe */
130#define BR06_o 0x400018 /* Source Address Register */
131#define BR07_o 0x40001C /* Destination Address Register */
132#define BR08_o 0x400020 /* Destination Width & Height Register */
133#define BR09_o 0x400024 /* Source Expansion Background Color & Transparency Key Register */
134#define BR0A_o 0x400028 /* Source Expansion Foreground Color Register */
135
136#define CURSOR_SIZE 0x1000 /* in KByte for HW Cursor */
137#define PATTERN_ADR (pGD->dprBase + CURSOR_SIZE) /* pattern Memory after Cursor Memory */
138#define PATTERN_SIZE 8*8*4 /* 4 Bytes per Pixel 8 x 8 Pixel */
139#define ACCELMEMORY (CURSOR_SIZE + PATTERN_SIZE) /* reserved Memory for BITBlt and hw cursor */
140
141/* Some Mode definitions */
142#define FB_SYNC_HOR_HIGH_ACT 1 /* horizontal sync high active */
143#define FB_SYNC_VERT_HIGH_ACT 2 /* vertical sync high active */
144#define FB_SYNC_EXT 4 /* external sync */
145#define FB_SYNC_COMP_HIGH_ACT 8 /* composite sync high active */
146#define FB_SYNC_BROADCAST 16 /* broadcast video timings */
147 /* vtotal = 144d/288n/576i => PAL */
148 /* vtotal = 121d/242n/484i => NTSC */
149#define FB_SYNC_ON_GREEN 32 /* sync on green */
150
151#define FB_VMODE_NONINTERLACED 0 /* non interlaced */
152#define FB_VMODE_INTERLACED 1 /* interlaced */
153#define FB_VMODE_DOUBLE 2 /* double scan */
154#define FB_VMODE_MASK 255
155
156#define FB_VMODE_YWRAP 256 /* ywrap instead of panning */
157#define FB_VMODE_SMOOTH_XPAN 512 /* smooth xpan possible (internally used) */
158#define FB_VMODE_CONUPDATE 512 /* don't update x/yoffset */
159
160#define text 0
161#define fntwidth 8
162
163/* table for VGA Initialization */
164typedef struct {
165 const unsigned char reg;
166 const unsigned char val;
167} CT_CFG_TABLE;
168
169/* this table provides some basic initialisations such as Memory Clock etc */
170static CT_CFG_TABLE xreg[] = {
171 {0x09, 0x01}, /* CRT Controller Extensions Enable */
172 {0x0A, 0x02}, /* Frame Buffer Mapping */
173 {0x0B, 0x01}, /* PCI Write Burst support */
174 {0x20, 0x00}, /* BitBLT Configuration */
175 {0x40, 0x03}, /* Memory Access Control */
176 {0x60, 0x00}, /* Video Pin Control */
177 {0x61, 0x00}, /* DPMS Synch control */
178 {0x62, 0x00}, /* GPIO Pin Control */
179 {0x63, 0xBD}, /* GPIO Pin Data */
180 {0x67, 0x00}, /* Pin Tri-State */
181 {0x80, 0x80}, /* Pixel Pipeline Config 0 register */
182 {0xA0, 0x00}, /* Cursor 1 Control Reg */
183 {0xA1, 0x00}, /* Cursor 1 Vertical Extension Reg */
184 {0xA2, 0x00}, /* Cursor 1 Base Address Low */
185 {0xA3, 0x00}, /* Cursor 1 Base Address High */
186 {0xA4, 0x00}, /* Cursor 1 X-Position Low */
187 {0xA5, 0x00}, /* Cursor 1 X-Position High */
188 {0xA6, 0x00}, /* Cursor 1 Y-Position Low */
189 {0xA7, 0x00}, /* Cursor 1 Y-Position High */
190 {0xA8, 0x00}, /* Cursor 2 Control Reg */
191 {0xA9, 0x00}, /* Cursor 2 Vertical Extension Reg */
192 {0xAA, 0x00}, /* Cursor 2 Base Address Low */
193 {0xAB, 0x00}, /* Cursor 2 Base Address High */
194 {0xAC, 0x00}, /* Cursor 2 X-Position Low */
195 {0xAD, 0x00}, /* Cursor 2 X-Position High */
196 {0xAE, 0x00}, /* Cursor 2 Y-Position Low */
197 {0xAF, 0x00}, /* Cursor 2 Y-Position High */
198 {0xC0, 0x7D}, /* Dot Clock 0 VCO M-Divisor */
199 {0xC1, 0x07}, /* Dot Clock 0 VCO N-Divisor */
200 {0xC3, 0x34}, /* Dot Clock 0 Divisor select */
201 {0xC4, 0x55}, /* Dot Clock 1 VCO M-Divisor */
202 {0xC5, 0x09}, /* Dot Clock 1 VCO N-Divisor */
203 {0xC7, 0x24}, /* Dot Clock 1 Divisor select */
204 {0xC8, 0x7D}, /* Dot Clock 2 VCO M-Divisor */
205 {0xC9, 0x07}, /* Dot Clock 2 VCO N-Divisor */
206 {0xCB, 0x34}, /* Dot Clock 2 Divisor select */
207 {0xCC, 0x38}, /* Memory Clock 0 VCO M-Divisor */
208 {0xCD, 0x03}, /* Memory Clock 0 VCO N-Divisor */
209 {0xCE, 0x90}, /* Memory Clock 0 Divisor select */
210 {0xCF, 0x06}, /* Clock Config */
211 {0xD0, 0x0F}, /* Power Down */
212 {0xD1, 0x01}, /* Power Down BitBLT */
213 {0xFF, 0xFF} /* end of table */
214};
215/* Clock Config:
216 * =============
217 *
218 * PD Registers:
219 * -------------
220 * Bit2 and Bit4..6 are used for the Loop Divisor and Post Divisor.
221 * They are encoded as follows:
222 *
223 * +---+--------------+
224 * | 2 | Loop Divisor |
225 * +---+--------------+
226 * | 1 | 1 |
227 * +---+--------------+
228 * | 0 | 4 |
229 * +---+--------------+
230 * Note: The Memory Clock does not have a Loop Divisor.
231 * +---+---+---+--------------+
232 * | 6 | 5 | 4 | Post Divisor |
233 * +---+---+---+--------------+
234 * | 0 | 0 | 0 | 1 |
235 * +---+---+---+--------------+
236 * | 0 | 0 | 1 | 2 |
237 * +---+---+---+--------------+
238 * | 0 | 1 | 0 | 4 |
239 * +---+---+---+--------------+
240 * | 0 | 1 | 1 | 8 |
241 * +---+---+---+--------------+
242 * | 1 | 0 | 0 | 16 |
243 * +---+---+---+--------------+
244 * | 1 | 0 | 1 | 32 |
245 * +---+---+---+--------------+
246 * | 1 | 1 | X | reserved |
247 * +---+---+---+--------------+
248 *
249 * All other bits are reserved in these registers.
250 *
251 * Clock VCO M Registers:
252 * ----------------------
253 * These Registers contain the M Value -2.
254 *
255 * Clock VCO N Registers:
256 * ----------------------
257 * These Registers contain the N Value -2.
258 *
259 * Formulas:
260 * ---------
261 * Fvco = (Fref * Loop Divisor * M/N), whereas 100MHz < Fvco < 220MHz
262 * Fout = Fvco / Post Divisor
263 *
264 * Dot Clk0 (default 25MHz):
265 * -------------------------
266 * Fvco = 14.318 * 127 / 9 = 202.045MHz
267 * Fout = 202.045MHz / 8 = 25.25MHz
268 * Post Divisor = 8
269 * Loop Divisor = 1
270 * XRC0 = (M - 2) = 125 = 0x7D
271 * XRC1 = (N - 2) = 7 = 0x07
272 * XRC3 = 0x34
273 *
274 * Dot Clk1 (default 28MHz):
275 * -------------------------
276 * Fvco = 14.318 * 87 / 11 = 113.24MHz
277 * Fout = 113.24MHz / 4 = 28.31MHz
278 * Post Divisor = 4
279 * Loop Divisor = 1
280 * XRC4 = (M - 2) = 85 = 0x55
281 * XRC5 = (N - 2) = 9 = 0x09
282 * XRC7 = 0x24
283 *
284 * Dot Clk2 (variable for extended modes set to 25MHz):
285 * ----------------------------------------------------
286 * Fvco = 14.318 * 127 / 9 = 202.045MHz
287 * Fout = 202.045MHz / 8 = 25.25MHz
288 * Post Divisor = 8
289 * Loop Divisor = 1
290 * XRC8 = (M - 2) = 125 = 0x7D
291 * XRC9 = (N - 2) = 7 = 0x07
292 * XRCB = 0x34
293 *
294 * Memory Clk for most modes >50MHz:
295 * ----------------------------------
296 * Fvco = 14.318 * 58 / 5 = 166MHz
297 * Fout = 166MHz / 2 = 83MHz
298 * Post Divisor = 2
299 * XRCC = (M - 2) = 57 = 0x38
300 * XRCD = (N - 2) = 3 = 0x03
301 * XRCE = 0x90
302 *
303 * Note Bit7 enables the clock source from the VCO
304 *
305 */
306
307/******************************************************************
308 * Resolution Struct
309 ******************************************************************/
310struct ctfb_res_modes {
311 int xres; /* visible resolution */
312 int yres;
313 /* Timing: All values in pixclocks, except pixclock (of course) */
314 int pixclock; /* pixel clock in ps (pico seconds) */
315 int left_margin; /* time from sync to picture */
316 int right_margin; /* time from picture to sync */
317 int upper_margin; /* time from sync to picture */
318 int lower_margin;
319 int hsync_len; /* length of horizontal sync */
320 int vsync_len; /* length of vertical sync */
321 int sync; /* see FB_SYNC_* */
322 int vmode; /* see FB_VMODE_* */
323};
324
325/******************************************************************
326 * Vesa Mode Struct
327 ******************************************************************/
328struct ctfb_vesa_modes {
329 int vesanr; /* Vesa number as in LILO (VESA Nr + 0x200} */
330 int resindex; /* index to resolution struct */
331 int bits_per_pixel; /* bpp */
332};
333/*******************************************************************
334 * Chips struct
335 *******************************************************************/
336struct ctfb_chips_properties {
337 int device_id; /* PCI Device ID */
338 unsigned long max_mem; /* memory for frame buffer */
339 int vld_set; /* value of VLD if bit2 in clock control is set */
340 int vld_not_set; /* value of VLD if bit2 in clock control is set */
341 int mn_diff; /* difference between M/N Value + mn_diff = M/N Register */
342 int mn_min; /* min value of M/N Value */
343 int mn_max; /* max value of M/N Value */
344 int vco_min; /* VCO Min in MHz */
345 int vco_max; /* VCO Max in MHz */
346};
347
348static const struct ctfb_chips_properties chips[] = {
349 {PCI_DEVICE_ID_CT_69000, 0x200000, 1, 4, -2, 3, 257, 100, 220},
350 {PCI_DEVICE_ID_CT_65555, 0x100000, 16, 4, 0, 1, 255, 48, 220}, /* NOT TESTED */
351 {0, 0, 0, 0, 0, 0, 0, 0, 0} /* Terminator */
352};
353
354/*************************************************
355 Video Modes:
356Colours 640x400 640x480 800x600 1024x768 1152x864 1280x1024 1600x1200
357--------+--------------------------------------------------------------
358 4 bits | ? ? 0x302 ? ? ? ?
359 8 bits | 0x300 0x301 0x303 0x305 0x161 0x307 0x31C
36015 bits | ? 0x310 0x313 0x316 0x162 0x319 0x31D
36116 bits | ? 0x311 0x314 0x317 0x163 0x31A 0x31E
36224 bits | ? 0x312 0x315 0x318 ? 0x31B 0x31F
36332 bits | ? ? ? ? 0x164 ?
364*/
365
366#define RES_MODE_640x480 0
367#define RES_MODE_800x600 1
368#define RES_MODE_1024x768 2
369#define RES_MODE_960_720 3
370#define RES_MODE_1152x864 4
371#define RES_MODES_COUNT 5
372
373#define VESA_MODES_COUNT 15
374
375static const struct ctfb_vesa_modes vesa_modes[VESA_MODES_COUNT] = {
376 {0x301, RES_MODE_640x480, 8},
377 {0x310, RES_MODE_640x480, 15},
378 {0x311, RES_MODE_640x480, 16},
379 {0x312, RES_MODE_640x480, 24},
380 {0x303, RES_MODE_800x600, 8},
381 {0x313, RES_MODE_800x600, 15},
382 {0x314, RES_MODE_800x600, 16},
383 {0x315, RES_MODE_800x600, 24},
384 {0x305, RES_MODE_1024x768, 8},
385 {0x316, RES_MODE_1024x768, 15},
386 {0x317, RES_MODE_1024x768, 16},
387 {0x318, RES_MODE_1024x768, 24},
388 {0x161, RES_MODE_1152x864, 8},
389 {0x162, RES_MODE_1152x864, 15},
390 {0x163, RES_MODE_1152x864, 16}
391};
392
393static const struct ctfb_res_modes res_mode_init[RES_MODES_COUNT] = {
394 /* x y pixclk le ri up lo hs vs s vmode */
395 {640, 480, 39721, 40, 24, 32, 11, 96, 2, 0,
396 FB_VMODE_NONINTERLACED},
397 {800, 600, 27778, 64, 24, 22, 1, 72, 2, 0, FB_VMODE_NONINTERLACED},
398 {1024, 768, 15384, 168, 8, 29, 3, 144, 4, 0,
399 FB_VMODE_NONINTERLACED},
400 {960, 720, 13100, 160, 40, 32, 8, 80, 4, 0,
401 FB_VMODE_NONINTERLACED},
402 {1152, 864, 12004, 200, 64, 32, 16, 80, 4, 0,
403 FB_VMODE_NONINTERLACED}
404};
405
406/*
407 * The Graphic Device
408 */
409GraphicDevice ctfb;
410
411/*******************************************************************************
412*
413* Low Level Routines
414*/
415
416/*******************************************************************************
417*
418* Read CT ISA register
419*/
420#ifdef VGA_DEBUG
421static unsigned char
422ctRead (unsigned short index)
423{
424 GraphicDevice *pGD = (GraphicDevice *) & ctfb;
425 if (index == CT_AR_O)
426 /* synch the Flip Flop */
427 in8 (pGD->isaBase + CT_STATUS_REG1_O);
428
429 return (in8 (pGD->isaBase + index));
430}
431#endif
432/*******************************************************************************
433*
434* Write CT ISA register
435*/
436static void
437ctWrite (unsigned short index, unsigned char val)
438{
439 GraphicDevice *pGD = (GraphicDevice *) & ctfb;
440
441 out8 ((pGD->isaBase + index), val);
442}
443
444/*******************************************************************************
445*
446* Read CT ISA register indexed
447*/
448static unsigned char
449ctRead_i (unsigned short index, char reg)
450{
451 GraphicDevice *pGD = (GraphicDevice *) & ctfb;
452 if (index == CT_AR_O)
453 /* synch the Flip Flop */
454 in8 (pGD->isaBase + CT_STATUS_REG1_O);
455 out8 ((pGD->isaBase + index), reg);
456 return (in8 (pGD->isaBase + index + 1));
457}
458
459/*******************************************************************************
460*
461* Write CT ISA register indexed
462*/
463static void
464ctWrite_i (unsigned short index, char reg, char val)
465{
466 GraphicDevice *pGD = (GraphicDevice *) & ctfb;
467 if (index == CT_AR_O) {
468 /* synch the Flip Flop */
469 in8 (pGD->isaBase + CT_STATUS_REG1_O);
470 out8 ((pGD->isaBase + index), reg);
471 out8 ((pGD->isaBase + index), val);
472 } else {
473 out8 ((pGD->isaBase + index), reg);
474 out8 ((pGD->isaBase + index + 1), val);
475 }
476}
477
478/*******************************************************************************
479*
480* Write a table of CT ISA register
481*/
482static void
483ctLoadRegs (unsigned short index, CT_CFG_TABLE * regTab)
484{
485 while (regTab->reg != 0xFF) {
486 ctWrite_i (index, regTab->reg, regTab->val);
487 regTab++;
488 }
489}
490
491/*****************************************************************************/
492static void
493SetArRegs (void)
494{
495 int i, tmp;
496
497 for (i = 0; i < 0x10; i++)
498 ctWrite_i (CT_AR_O, i, i);
499 if (text)
500 tmp = 0x04;
501 else
502 tmp = 0x41;
503
504 ctWrite_i (CT_AR_O, 0x10, tmp); /* Mode Control Register */
505 ctWrite_i (CT_AR_O, 0x11, 0x00); /* Overscan Color Register */
506 ctWrite_i (CT_AR_O, 0x12, 0x0f); /* Memory Plane Enable Register */
507 if (fntwidth == 9)
508 tmp = 0x08;
509 else
510 tmp = 0x00;
511 ctWrite_i (CT_AR_O, 0x13, tmp); /* Horizontal Pixel Panning */
512 ctWrite_i (CT_AR_O, 0x14, 0x00); /* Color Select Register */
513 ctWrite (CT_AR_O, 0x20); /* enable video */
514}
515
516/*****************************************************************************/
517static void
518SetGrRegs (void)
519{ /* Set Graphics Mode */
520 int i;
521
522 for (i = 0; i < 0x05; i++)
523 ctWrite_i (CT_GR_O, i, 0);
524 if (text) {
525 ctWrite_i (CT_GR_O, 0x05, 0x10);
526 ctWrite_i (CT_GR_O, 0x06, 0x02);
527 } else {
528 ctWrite_i (CT_GR_O, 0x05, 0x40);
529 ctWrite_i (CT_GR_O, 0x06, 0x05);
530 }
531 ctWrite_i (CT_GR_O, 0x07, 0x0f);
532 ctWrite_i (CT_GR_O, 0x08, 0xff);
533}
534
535/*****************************************************************************/
536static void
537SetSrRegs (void)
538{
539 int tmp = 0;
540
541 ctWrite_i (CT_SR_O, 0x00, 0x00); /* reset */
542 /*rr( sr, 0x01, tmp );
543 if( fntwidth == 8 ) tmp |= 0x01; else tmp &= ~0x01;
544 wr( sr, 0x01, tmp ); */
545 if (fntwidth == 8)
546 ctWrite_i (CT_SR_O, 0x01, 0x01); /* Clocking Mode Register */
547 else
548 ctWrite_i (CT_SR_O, 0x01, 0x00); /* Clocking Mode Register */
549 ctWrite_i (CT_SR_O, 0x02, 0x0f); /* Enable CPU wr access to given memory plane */
550 ctWrite_i (CT_SR_O, 0x03, 0x00); /* Character Map Select Register */
551 if (text)
552 tmp = 0x02;
553 else
554 tmp = 0x0e;
555 ctWrite_i (CT_SR_O, 0x04, tmp); /* Enable CPU accesses to the rest of the 256KB
556 total VGA memory beyond the first 64KB and set
557 fb mapping mode. */
558 ctWrite_i (CT_SR_O, 0x00, 0x03); /* enable */
559}
560
561/*****************************************************************************/
562static void
563SetBitsPerPixelIntoXrRegs (int bpp)
564{
565 unsigned int n = (bpp >> 3), tmp; /* only for 15, 8, 16, 24 bpp */
566 static char md[4] = { 0x04, 0x02, 0x05, 0x06 }; /* DisplayColorMode */
567 static char off[4] = { ~0x20, ~0x30, ~0x20, ~0x10 }; /* mask */
568 static char on[4] = { 0x10, 0x00, 0x10, 0x20 }; /* mask */
569 if (bpp == 15)
570 n = 0;
571 tmp = ctRead_i (CT_XR_O, 0x20);
572 tmp &= off[n];
573 tmp |= on[n];
574 ctWrite_i (CT_XR_O, 0x20, tmp); /* BitBLT Configuration */
575 ctWrite_i (CT_XR_O, 0x81, md[n]);
576}
577
578/*****************************************************************************/
579static void
580SetCrRegs (struct ctfb_res_modes *var, int bits_per_pixel)
581{ /* he -le- ht|0 hd -ri- hs -h- he */
582 unsigned char cr[0x7a];
583 int i, tmp;
584 unsigned int hd, hs, he, ht, hbe; /* Horizontal. */
585 unsigned int vd, vs, ve, vt; /* vertical */
586 unsigned int bpp, wd, dblscan, interlaced, bcast, CrtHalfLine;
587 unsigned int CompSyncCharClkDelay, CompSyncPixelClkDelay;
588 unsigned int NTSC_PAL_HorizontalPulseWidth, BlDelayCtrl;
589 unsigned int HorizontalEqualizationPulses;
590 unsigned int HorizontalSerration1Start, HorizontalSerration2Start;
591
592 const int LineCompare = 0x3ff;
593 unsigned int TextScanLines = 1; /* this is in fact a vertical zoom factor */
594 unsigned int RAMDAC_BlankPedestalEnable = 0; /* 1=en-, 0=disable, see XR82 */
595
596 hd = (var->xres) / 8; /* HDisp. */
597 hs = (var->xres + var->right_margin) / 8; /* HsStrt */
598 he = (var->xres + var->right_margin + var->hsync_len) / 8; /* HsEnd */
599 ht = (var->left_margin + var->xres + var->right_margin + var->hsync_len) / 8; /* HTotal */
600 hbe = ht - 1; /* HBlankEnable todo docu wants ht here, but it does not work */
601 /* ve -up- vt|0 vd -lo- vs -v- ve */
602 vd = var->yres; /* VDisplay */
603 vs = var->yres + var->lower_margin; /* VSyncStart */
604 ve = var->yres + var->lower_margin + var->vsync_len; /* VSyncEnd */
605 vt = var->upper_margin + var->yres + var->lower_margin + var->vsync_len; /* VTotal */
606 bpp = bits_per_pixel;
607 dblscan = (var->vmode & FB_VMODE_DOUBLE) ? 1 : 0;
608 interlaced = var->vmode & FB_VMODE_INTERLACED;
609 bcast = var->sync & FB_SYNC_BROADCAST;
610 CrtHalfLine = bcast ? (hd >> 1) : 0;
611 BlDelayCtrl = bcast ? 1 : 0;
612 CompSyncCharClkDelay = 0; /* 2 bit */
613 CompSyncPixelClkDelay = 0; /* 3 bit */
614 if (bcast) {
615 NTSC_PAL_HorizontalPulseWidth = 7; /*( var->hsync_len >> 1 ) + 1 */
616 HorizontalEqualizationPulses = 0; /* inverse value */
617 HorizontalSerration1Start = 31; /* ( ht >> 1 ) */
618 HorizontalSerration2Start = 89; /* ( ht >> 1 ) */
619 } else {
620 NTSC_PAL_HorizontalPulseWidth = 0;
621 /* 4 bit: hsync pulse width = ( ( CR74[4:0] - CR74[5] )
622 * / 2 ) + 1 --> CR74[4:0] = 2*(hs-1) + CR74[5] */
623 HorizontalEqualizationPulses = 1; /* inverse value */
624 HorizontalSerration1Start = 0; /* ( ht >> 1 ) */
625 HorizontalSerration2Start = 0; /* ( ht >> 1 ) */
626 }
627
628 if (bpp == 15)
629 bpp = 16;
630 wd = var->xres * bpp / 64; /* double words per line */
631 if (interlaced) { /* we divide all vertical timings, exept vd */
632 vs >>= 1;
633 ve >>= 1;
634 vt >>= 1;
635 }
636 memset (cr, 0, sizeof (cr));
637 cr[0x00] = 0xff & (ht - 5);
638 cr[0x01] = hd - 1; /* soll:4f ist 59 */
639 cr[0x02] = hd;
640 cr[0x03] = (hbe & 0x1F) | 0x80; /* hd + ht - hd */
641 cr[0x04] = hs;
642 cr[0x05] = ((hbe & 0x20) << 2) | (he & 0x1f);
643 cr[0x06] = (vt - 2) & 0xFF;
644 cr[0x30] = (vt - 2) >> 8;
645 cr[0x07] = ((vt & 0x100) >> 8)
646 | ((vd & 0x100) >> 7)
647 | ((vs & 0x100) >> 6)
648 | ((vs & 0x100) >> 5)
649 | ((LineCompare & 0x100) >> 4)
650 | ((vt & 0x200) >> 4)
651 | ((vd & 0x200) >> 3)
652 | ((vs & 0x200) >> 2);
653 cr[0x08] = 0x00;
654 cr[0x09] = (dblscan << 7)
655 | ((LineCompare & 0x200) >> 3)
656 | ((vs & 0x200) >> 4)
657 | (TextScanLines - 1);
658 cr[0x10] = vs & 0xff; /* VSyncPulseStart */
659 cr[0x32] = (vs & 0xf00) >> 8; /* VSyncPulseStart */
660 cr[0x11] = (ve & 0x0f); /* | 0x20; */
661 cr[0x12] = (vd - 1) & 0xff; /* LineCount */
662 cr[0x31] = ((vd - 1) & 0xf00) >> 8; /* LineCount */
663 cr[0x13] = wd & 0xff;
664 cr[0x41] = (wd & 0xf00) >> 8;
665 cr[0x15] = vs & 0xff;
666 cr[0x33] = (vs & 0xf00) >> 8;
667 cr[0x38] = (0x100 & (ht - 5)) >> 8;
668 cr[0x3C] = 0xc0 & hbe;
669 cr[0x16] = (vt - 1) & 0xff; /* vbe - docu wants vt here, */
670 cr[0x17] = 0xe3; /* but it does not work */
671 cr[0x18] = 0xff & LineCompare;
672 cr[0x22] = 0xff; /* todo? */
673 cr[0x70] = interlaced ? (0x80 | CrtHalfLine) : 0x00; /* check:0xa6 */
674 cr[0x71] = 0x80 | (RAMDAC_BlankPedestalEnable << 6)
675 | (BlDelayCtrl << 5)
676 | ((0x03 & CompSyncCharClkDelay) << 3)
677 | (0x07 & CompSyncPixelClkDelay); /* todo: see XR82 */
678 cr[0x72] = HorizontalSerration1Start;
679 cr[0x73] = HorizontalSerration2Start;
680 cr[0x74] = (HorizontalEqualizationPulses << 5)
681 | NTSC_PAL_HorizontalPulseWidth;
682 /* todo: ct69000 has also 0x75-79 */
683 /* now set the registers */
684 for (i = 0; i <= 0x0d; i++) { /*CR00 .. CR0D */
685 ctWrite_i (CT_CR_O, i, cr[i]);
686 }
687 for (i = 0x10; i <= 0x18; i++) { /*CR10 .. CR18 */
688 ctWrite_i (CT_CR_O, i, cr[i]);
689 }
690 i = 0x22; /*CR22 */
691 ctWrite_i (CT_CR_O, i, cr[i]);
692 for (i = 0x30; i <= 0x33; i++) { /*CR30 .. CR33 */
693 ctWrite_i (CT_CR_O, i, cr[i]);
694 }
695 i = 0x38; /*CR38 */
696 ctWrite_i (CT_CR_O, i, cr[i]);
697 i = 0x3C; /*CR3C */
698 ctWrite_i (CT_CR_O, i, cr[i]);
699 for (i = 0x40; i <= 0x41; i++) { /*CR40 .. CR41 */
700 ctWrite_i (CT_CR_O, i, cr[i]);
701 }
702 for (i = 0x70; i <= 0x74; i++) { /*CR70 .. CR74 */
703 ctWrite_i (CT_CR_O, i, cr[i]);
704 }
705 tmp = ctRead_i (CT_CR_O, 0x40);
706 tmp &= 0x0f;
707 tmp |= 0x80;
708 ctWrite_i (CT_CR_O, 0x40, tmp); /* StartAddressEnable */
709}
710
711/* pixelclock control */
712
713/*****************************************************************************
714 We have a rational number p/q and need an m/n which is very close to p/q
715 but has m and n within mnmin and mnmax. We have no floating point in the
716 kernel. We can use long long without divide. And we have time to compute...
717******************************************************************************/
718static unsigned int
719FindBestPQFittingMN (unsigned int p, unsigned int q, unsigned int mnmin,
720 unsigned int mnmax, unsigned int *pm, unsigned int *pn)
721{
722 /* this code is not for general purpose usable but good for our number ranges */
723 unsigned int n = mnmin, m = 0;
724 long long int L = 0, P = p, Q = q, H = P >> 1;
725 long long int D = 0x7ffffffffffffffLL;
726 for (n = mnmin; n <= mnmax; n++) {
727 m = mnmin; /* p/q ~ m/n -> p*n ~ m*q -> p*n-x*q ~ 0 */
728 L = P * n - m * Q; /* n * vco - m * fref should be near 0 */
729 while (L > 0 && m < mnmax) {
730 L -= q; /* difference is greater as 0 subtract fref */
731 m++; /* and increment m */
732 }
733 /* difference is less or equal than 0 or m > maximum */
734 if (m > mnmax)
735 break; /* no solution: if we increase n we get the same situation */
736 /* L is <= 0 now */
737 if (-L > H && m > mnmin) { /* if difference > the half fref */
738 L += q; /* we take the situation before */
739 m--; /* because its closer to 0 */
740 }
741 L = (L < 0) ? -L : +L; /* absolute value */
742 if (D < L) /* if last difference was better take next n */
743 continue;
744 D = L;
745 *pm = m;
746 *pn = n; /* keep improved data */
747 if (D == 0)
748 break; /* best result we can get */
749 }
750 return (unsigned int) (0xffffffff & D);
751}
752
753/* that is the hardware < 69000 we have to manage
754 +---------+ +-------------------+ +----------------------+ +--+
755 | REFCLK |__|NTSC Divisor Select|__|FVCO Reference Divisor|__|÷N|__
756 | 14.3MHz | |(NTSCDS) (÷1, ÷5) | |Select (RDS) (÷1, ÷4) | | | |
757 +---------+ +-------------------+ +----------------------+ +--+ |
758 ___________________________________________________________________|
759 |
760 | fvco fout
761 | +--------+ +------------+ +-----+ +-------------------+ +----+
762 +-| Phase |__|Charge Pump |__| VCO |_____|Post Divisor (PD) |___|CLK |--->
763 +-| Detect | |& Filter VCO| | | | |÷1, 2, 4, 8, 16, 32| | |
764 | +--------+ +------------+ +-----+ | +-------------------+ +----+
765 | |
766 | +--+ +---------------+ |
767 |____|÷M|___|VCO Loop Divide|__________|
768 | | |(VLD)(÷4, ÷16) |
769 +--+ +---------------+
770****************************************************************************
771 that is the hardware >= 69000 we have to manage
772 +---------+ +--+
773 | REFCLK |__|÷N|__
774 | 14.3MHz | | | |
775 +---------+ +--+ |
776 __________________|
777 |
778 | fvco fout
779 | +--------+ +------------+ +-----+ +-------------------+ +----+
780 +-| Phase |__|Charge Pump |__| VCO |_____|Post Divisor (PD) |___|CLK |--->
781 +-| Detect | |& Filter VCO| | | | |÷1, 2, 4, 8, 16, 32| | |
782 | +--------+ +------------+ +-----+ | +-------------------+ +----+
783 | |
784 | +--+ +---------------+ |
785 |____|÷M|___|VCO Loop Divide|__________|
786 | | |(VLD)(÷1, ÷4) |
787 +--+ +---------------+
788
789
790*/
791
792#define VIDEO_FREF 14318180; /* Hz */
793/*****************************************************************************/
794static int
795ReadPixClckFromXrRegsBack (struct ctfb_chips_properties *param)
796{
797 unsigned int m, n, vld, pd, PD, fref, xr_cb, i, pixclock;
798 i = 0;
799 pixclock = -1;
800 fref = VIDEO_FREF;
801 m = ctRead_i (CT_XR_O, 0xc8);
802 n = ctRead_i (CT_XR_O, 0xc9);
803 m -= param->mn_diff;
804 n -= param->mn_diff;
805 xr_cb = ctRead_i (CT_XR_O, 0xcb);
806 PD = (0x70 & xr_cb) >> 4;
807 pd = 1;
808 for (i = 0; i < PD; i++) {
809 pd *= 2;
810 }
811 vld = (0x04 & xr_cb) ? param->vld_set : param->vld_not_set;
812 if (n * vld * m) {
813 unsigned long long p = 1000000000000LL * pd * n;
814 unsigned long long q = (long long) fref * vld * m;
815 while ((p > 0xffffffffLL) || (q > 0xffffffffLL)) {
816 p >>= 1; /* can't divide with long long so we scale down */
817 q >>= 1;
818 }
819 pixclock = (unsigned) p / (unsigned) q;
820 } else
821 printf ("Invalid data in xr regs.\n");
822 return pixclock;
823}
824
825/*****************************************************************************/
826static void
827FindAndSetPllParamIntoXrRegs (unsigned int pixelclock,
828 struct ctfb_chips_properties *param)
829{
830 unsigned int m, n, vld, pd, PD, fref, xr_cb;
831 unsigned int fvcomin, fvcomax, pclckmin, pclckmax, pclk;
832 unsigned int pfreq, fvco, new_pixclock;
wdenk3e386912003-04-05 00:53:31 +0000833 unsigned int D,nback,mback;
wdenkc6097192002-11-03 00:24:07 +0000834
835 fref = VIDEO_FREF;
836 pd = 1;
837 PD = 0;
838 fvcomin = param->vco_min;
839 fvcomax = param->vco_max; /* MHz */
840 pclckmin = 1000000 / fvcomax + 1; /* 4546 */
841 pclckmax = 32000000 / fvcomin - 1; /* 666665 */
842 pclk = minmax (pclckmin, pixelclock, pclckmax); /* ps pp */
843 pfreq = 250 * (4000000000U / pclk);
844 fvco = pfreq; /* Hz */
845 new_pixclock = 0;
846 while (fvco < fvcomin * 1000000) {
847 /* double VCO starting with the pixelclock frequency
848 * as long as it is lower than the minimal VCO frequency */
849 fvco *= 2;
850 pd *= 2;
851 PD++;
852 }
853 /* fvco is exactly pd * pixelclock and higher than the ninmal VCO frequency */
wdenk3e386912003-04-05 00:53:31 +0000854 /* first try */
855 vld = param->vld_set;
856 D=FindBestPQFittingMN (fvco / vld, fref, param->mn_min, param->mn_max, &m, &n); /* rds = 1 */
857 mback=m;
858 nback=n;
859 /* second try */
860 vld = param->vld_not_set;
861 if(D<FindBestPQFittingMN (fvco / vld, fref, param->mn_min, param->mn_max, &m, &n)) { /* rds = 1 */
862 /* first try was better */
863 m=mback;
864 n=nback;
865 vld = param->vld_set;
866 }
wdenkc6097192002-11-03 00:24:07 +0000867 m += param->mn_diff;
868 n += param->mn_diff;
869 PRINTF ("VCO %d, pd %d, m %d n %d vld %d \n", fvco, pd, m, n, vld);
870 xr_cb = ((0x7 & PD) << 4) | (vld == param->vld_set ? 0x04 : 0);
871 /* All four of the registers used for dot clock 2 (XRC8 - XRCB) must be
872 * written, and in order from XRC8 to XRCB, before the hardware will
873 * update the synthesizer s settings.
874 */
875 ctWrite_i (CT_XR_O, 0xc8, m);
876 ctWrite_i (CT_XR_O, 0xc9, n); /* xrca does not exist in CT69000 and CT69030 */
877 ctWrite_i (CT_XR_O, 0xca, 0); /* because of a hw bug I guess, but we write */
878 ctWrite_i (CT_XR_O, 0xcb, xr_cb); /* 0 to it for savety */
879 new_pixclock = ReadPixClckFromXrRegsBack (param);
880 PRINTF ("pixelclock.set = %d, pixelclock.real = %d \n",
881 pixelclock, new_pixclock);
882}
883
884/*****************************************************************************/
885static void
886SetMsrRegs (struct ctfb_res_modes *mode)
887{
888 unsigned char h_synch_high, v_synch_high;
889
890 h_synch_high = (mode->sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : 0x40; /* horizontal Synch High active */
891 v_synch_high = (mode->sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : 0x80; /* vertical Synch High active */
892 ctWrite (CT_MSR_W_O, (h_synch_high | v_synch_high | 0x29));
893 /* upper64K==0x20, CLC2select==0x08, RAMenable==0x02!(todo), CGA==0x01
894 * Selects the upper 64KB page.Bit5=1
895 * CLK2 (left reserved in standard VGA) Bit3|2=1|0
896 * Disables CPU access to frame buffer. Bit1=0
897 * Sets the I/O address decode for ST01, FCR, and all CR registers
898 * to the 3Dx I/O address range (CGA emulation). Bit0=1
899 */
900}
901
902/************************************************************************************/
903#ifdef VGA_DUMP_REG
904
905static void
906ctDispRegs (unsigned short index, int from, int to)
907{
908 unsigned char status;
909 int i;
910
911 for (i = from; i < to; i++) {
912 status = ctRead_i (index, i);
913 printf ("%02X: is %02X\n", i, status);
914 }
915}
916
917void
918video_dump_reg (void)
919{
920 int i;
921
922 printf ("Extended Regs:\n");
923 ctDispRegs (CT_XR_O, 0, 0xC);
924 ctDispRegs (CT_XR_O, 0xe, 0xf);
925 ctDispRegs (CT_XR_O, 0x20, 0x21);
926 ctDispRegs (CT_XR_O, 0x40, 0x50);
927 ctDispRegs (CT_XR_O, 0x60, 0x64);
928 ctDispRegs (CT_XR_O, 0x67, 0x68);
929 ctDispRegs (CT_XR_O, 0x70, 0x72);
930 ctDispRegs (CT_XR_O, 0x80, 0x83);
931 ctDispRegs (CT_XR_O, 0xA0, 0xB0);
932 ctDispRegs (CT_XR_O, 0xC0, 0xD3);
933 printf ("Sequencer Regs:\n");
934 ctDispRegs (CT_SR_O, 0, 0x8);
935 printf ("Graphic Regs:\n");
936 ctDispRegs (CT_GR_O, 0, 0x9);
937 printf ("CRT Regs:\n");
938 ctDispRegs (CT_CR_O, 0, 0x19);
939 ctDispRegs (CT_CR_O, 0x22, 0x23);
940 ctDispRegs (CT_CR_O, 0x30, 0x34);
941 ctDispRegs (CT_CR_O, 0x38, 0x39);
942 ctDispRegs (CT_CR_O, 0x3C, 0x3D);
943 ctDispRegs (CT_CR_O, 0x40, 0x42);
944 ctDispRegs (CT_CR_O, 0x70, 0x80);
945 /* don't display the attributes */
946}
947
948#endif
949
950#ifdef CONFIG_VIDEO_HW_CURSOR
951/***************************************************************
952 * Set Hardware Cursor in Pixel
953 */
954void
955video_set_hw_cursor (int x, int y)
956{
957 int sig_x = 0, sig_y = 0;
958 if (x < 0) {
959 x *= -1;
960 sig_x = 1;
961 }
962 if (y < 0) {
963 y *= -1;
964 sig_y = 1;
965 }
966 ctWrite_i (CT_XR_O, 0xa4, x & 0xff);
967 ctWrite_i (CT_XR_O, 0xa5, (x >> 8) & 0x7);
968 ctWrite_i (CT_XR_O, 0xa6, y & 0xff);
969 ctWrite_i (CT_XR_O, 0xa7, (y >> 8) & 0x7);
970}
971
972/***************************************************************
973 * Init Hardware Cursor. To know the size of the Cursor,
974 * we have to know the Font size.
975 */
976void
977video_init_hw_cursor (int font_width, int font_height)
978{
979 unsigned char xr_80;
980 unsigned long *curs, pattern;
981 int i;
982 int cursor_start;
983 GraphicDevice *pGD = (GraphicDevice *) & ctfb;
984
985 cursor_start = pGD->dprBase;
986 xr_80 = ctRead_i (CT_XR_O, 0x80);
987 /* set start address */
988 ctWrite_i (CT_XR_O, 0xa2, (cursor_start >> 8) & 0xf0);
989 ctWrite_i (CT_XR_O, 0xa3, (cursor_start >> 16) & 0x3f);
990 /* set cursor shape */
991 curs = (unsigned long *) cursor_start;
992 i = 0;
993 while (i < 0x400) {
994 curs[i++] = 0xffffffff; /* AND mask */
995 curs[i++] = 0xffffffff; /* AND mask */
996 curs[i++] = 0; /* XOR mask */
997 curs[i++] = 0; /* XOR mask */
998 /* Transparent */
999 }
1000 pattern = 0xffffffff >> font_width;
1001 i = 0;
1002 while (i < (font_height * 2)) {
1003 curs[i++] = pattern; /* AND mask */
1004 curs[i++] = pattern; /* AND mask */
1005 curs[i++] = 0; /* XOR mask */
1006 curs[i++] = 0; /* XOR mask */
1007 /* Cursor Color 0 */
1008 }
1009 /* set blink rate */
1010 ctWrite_i (CT_FP_O, 0x19, 0xf);
1011
1012 /* set cursors colors */
1013 xr_80 = ctRead_i (CT_XR_O, 0x80);
1014 xr_80 |= 0x1; /* alternate palette select */
1015 ctWrite_i (CT_XR_O, 0x80, xr_80);
1016 video_set_lut (4, CONSOLE_FG_COL, CONSOLE_FG_COL, CONSOLE_FG_COL);
1017 /* position 4 is color 0 cursor 0 */
1018 xr_80 &= 0xfe; /* normal palette select */
1019 ctWrite_i (CT_XR_O, 0x80, xr_80);
1020 /* cursor enable */
1021 ctWrite_i (CT_XR_O, 0xa0, 0x91);
1022 xr_80 |= 0x10; /* enable hwcursor */
1023 ctWrite_i (CT_XR_O, 0x80, xr_80);
1024 video_set_hw_cursor (0, 0);
1025}
1026#endif /* CONFIG_VIDEO_HW_CURSOR */
1027
1028/***************************************************************
1029 * Wait for BitBlt ready
1030 */
1031static int
1032video_wait_bitblt (unsigned long addr)
1033{
1034 unsigned long br04;
1035 int i = 0;
1036 br04 = in32r (addr);
1037 while (br04 & 0x80000000) {
1038 udelay (1);
1039 br04 = in32r (addr);
1040 if (i++ > 1000000) {
1041 printf ("ERROR Timeout %lx\n", br04);
1042 return 1;
1043 }
1044 }
1045 return 0;
1046}
1047
1048/***************************************************************
1049 * Set up BitBlt Registrs
1050 */
1051static void
1052SetDrawingEngine (int bits_per_pixel)
1053{
1054 unsigned long br04, br00;
1055 unsigned char tmp;
1056
1057 GraphicDevice *pGD = (GraphicDevice *) & ctfb;
1058
1059 tmp = ctRead_i (CT_XR_O, 0x20); /* BitBLT Configuration */
1060 tmp |= 0x02; /* reset BitBLT */
1061 ctWrite_i (CT_XR_O, 0x20, tmp); /* BitBLT Configuration */
1062 udelay (10);
1063 tmp &= 0xfd; /* release reset BitBLT */
1064 ctWrite_i (CT_XR_O, 0x20, tmp); /* BitBLT Configuration */
1065 video_wait_bitblt (pGD->pciBase + BR04_o);
1066
1067 /* set pattern Address */
1068 out32r (pGD->pciBase + BR05_o, PATTERN_ADR & 0x003ffff8);
1069 br04 = 0;
1070 if (bits_per_pixel == 1) {
1071 br04 |= 0x00040000; /* monochome Pattern */
1072 br04 |= 0x00001000; /* monochome source */
1073 }
1074 br00 = ((pGD->winSizeX * pGD->gdfBytesPP) << 16) + (pGD->winSizeX * pGD->gdfBytesPP); /* bytes per scanline */
1075 out32r (pGD->pciBase + BR00_o, br00); /* */
1076 out32r (pGD->pciBase + BR08_o, (10 << 16) + 10); /* dummy */
1077 out32r (pGD->pciBase + BR04_o, br04); /* write all 0 */
1078 out32r (pGD->pciBase + BR07_o, 0); /* destination */
1079 video_wait_bitblt (pGD->pciBase + BR04_o);
1080}
1081
1082/************************************************************************
1083 * Get Parameters for the video mode:
1084 */
1085/*********************************************************************
1086 * returns the length to the next seperator
1087 */
1088static int
1089video_get_param_len (char *start, char sep)
1090{
1091 int i = 0;
1092 while ((*start != 0) && (*start != sep)) {
1093 start++;
1094 i++;
1095 }
1096 return i;
1097}
1098
1099static int
1100video_search_param (char *start, char *param)
1101{
1102 int len, totallen, i;
1103 char *p = start;
1104 len = strlen (param);
1105 totallen = len + strlen (start);
1106 for (i = 0; i < totallen; i++) {
1107 if (strncmp (p++, param, len) == 0)
1108 return (i);
1109 }
1110 return -1;
1111}
1112
1113/***************************************************************
1114* Get parameter via the environment as it is done for the
1115* linux kernel i.e:
1116* video=ctfb:x:800,xv:1280,y:600,yv:1024,depth:16,mode:0,pclk:25000,
1117* le:56,ri:48,up:26,lo:5,hs:152,vs:2,sync:0,vmode:0,accel:0
1118*
1119* penv is a pointer to the environment, containing the string, or the name of
1120* another environment variable. It could even be the term "bootargs"
1121*/
1122
1123#define GET_OPTION(name,var) \
1124 if(strncmp(p,name,strlen(name))==0) { \
1125 val_s=p+strlen(name); \
1126 var=simple_strtoul(val_s, NULL, 10); \
1127 }
1128
1129static int
1130video_get_params (struct ctfb_res_modes *pPar, char *penv)
1131{
1132 char *p, *s, *val_s;
1133 int i = 0, t;
1134 int bpp;
1135 int mode;
1136 /* first search for the environment containing the real param string */
1137 s = penv;
1138 if ((p = getenv (s)) != NULL) {
1139 s = p;
1140 }
1141 /* in case of the bootargs line, we have to start
1142 * after "video=ctfb:"
1143 */
1144 i = video_search_param (s, "video=ctfb:");
1145 if (i >= 0) {
1146 s += i;
1147 s += strlen ("video=ctfb:");
1148 }
1149 /* search for mode as a default value */
1150 p = s;
1151 t = 0;
1152 mode = 0; /* default */
1153 while ((i = video_get_param_len (p, ',')) != 0) {
1154 GET_OPTION ("mode:", mode)
1155 p += i;
1156 if (*p != 0)
1157 p++; /* skip ',' */
1158 }
1159 if (mode >= RES_MODES_COUNT)
1160 mode = 0;
1161 *pPar = res_mode_init[mode]; /* copy default values */
1162 bpp = 24 - ((mode % 3) * 8);
1163 p = s; /* restart */
1164 while ((i = video_get_param_len (p, ',')) != 0) {
1165 GET_OPTION ("x:", pPar->xres)
1166 GET_OPTION ("y:", pPar->yres)
1167 GET_OPTION ("le:", pPar->left_margin)
1168 GET_OPTION ("ri:", pPar->right_margin)
1169 GET_OPTION ("up:", pPar->upper_margin)
1170 GET_OPTION ("lo:", pPar->lower_margin)
1171 GET_OPTION ("hs:", pPar->hsync_len)
1172 GET_OPTION ("vs:", pPar->vsync_len)
1173 GET_OPTION ("sync:", pPar->sync)
1174 GET_OPTION ("vmode:", pPar->vmode)
1175 GET_OPTION ("pclk:", pPar->pixclock)
1176 GET_OPTION ("depth:", bpp)
1177 p += i;
1178 if (*p != 0)
1179 p++; /* skip ',' */
1180 }
1181 return bpp;
1182}
1183
1184/****************************************************************************
1185* supported Video Chips
1186*/
1187static struct pci_device_id supported[] = {
1188 {PCI_VENDOR_ID_CT, PCI_DEVICE_ID_CT_69000},
1189 {}
1190};
1191
1192/*******************************************************************************
1193*
1194* Init video chip
1195*/
1196void *
1197video_hw_init (void)
1198{
1199 GraphicDevice *pGD = (GraphicDevice *) & ctfb;
1200 unsigned short device_id;
1201 pci_dev_t devbusfn;
1202 int videomode;
1203 unsigned long t1, hsynch, vsynch;
1204 unsigned int pci_mem_base, *vm;
1205 int tmp, i, bits_per_pixel;
1206 char *penv;
1207 struct ctfb_res_modes *res_mode;
1208 struct ctfb_res_modes var_mode;
1209 struct ctfb_chips_properties *chips_param;
1210 /* Search for video chip */
1211
1212 if ((devbusfn = pci_find_devices (supported, 0)) < 0) {
1213#ifdef CONFIG_VIDEO_ONBOARD
1214 printf ("Video: Controller not found !\n");
1215#endif
1216 return (NULL);
1217 }
1218
1219 /* PCI setup */
1220 pci_write_config_dword (devbusfn, PCI_COMMAND,
1221 (PCI_COMMAND_MEMORY | PCI_COMMAND_IO));
1222 pci_read_config_word (devbusfn, PCI_DEVICE_ID, &device_id);
1223 pci_read_config_dword (devbusfn, PCI_BASE_ADDRESS_0, &pci_mem_base);
1224 pci_mem_base = pci_mem_to_phys (devbusfn, pci_mem_base);
1225
1226 /* get chips params */
1227 for (chips_param = (struct ctfb_chips_properties *) &chips[0];
1228 chips_param->device_id != 0; chips_param++) {
1229 if (chips_param->device_id == device_id)
1230 break;
1231 }
1232 if (chips_param->device_id == 0) {
1233#ifdef CONFIG_VIDEO_ONBOARD
1234 printf ("Video: controller 0x%X not supported\n", device_id);
1235#endif
1236 return NULL;
1237 }
1238 /* supported Video controller found */
1239 printf ("Video: ");
1240
1241 tmp = 0;
1242 videomode = 0x301;
1243 /* get video mode via environment */
1244 if ((penv = getenv ("videomode")) != NULL) {
1245 /* deceide if it is a string */
1246 if (penv[0] <= '9') {
1247 videomode = (int) simple_strtoul (penv, NULL, 16);
1248 tmp = 1;
1249 }
1250 } else {
1251 tmp = 1;
1252 }
1253 if (tmp) {
1254 /* parameter are vesa modes */
1255 /* search params */
1256 for (i = 0; i < VESA_MODES_COUNT; i++) {
1257 if (vesa_modes[i].vesanr == videomode)
1258 break;
1259 }
1260 if (i == VESA_MODES_COUNT) {
1261 printf ("no VESA Mode found, switching to mode 0x301 ");
1262 i = 0;
1263 }
1264 res_mode =
1265 (struct ctfb_res_modes *) &res_mode_init[vesa_modes[i].
1266 resindex];
1267 bits_per_pixel = vesa_modes[i].bits_per_pixel;
1268 } else {
1269
1270 res_mode = (struct ctfb_res_modes *) &var_mode;
1271 bits_per_pixel = video_get_params (res_mode, penv);
1272 }
1273
1274 /* calculate available color depth for controller memory */
1275 if (bits_per_pixel == 15)
1276 tmp = 2;
1277 else
1278 tmp = bits_per_pixel >> 3; /* /8 */
1279 if (((chips_param->max_mem -
1280 ACCELMEMORY) / (res_mode->xres * res_mode->yres)) < tmp) {
1281 tmp =
1282 ((chips_param->max_mem -
1283 ACCELMEMORY) / (res_mode->xres * res_mode->yres));
1284 if (tmp == 0) {
1285 printf
1286 ("No matching videomode found .-> reduce resolution\n");
1287 return NULL;
1288 } else {
1289 printf ("Switching back to %d Bits per Pixel ",
1290 tmp << 3);
1291 bits_per_pixel = tmp << 3;
1292 }
1293 }
1294
1295 /* calculate hsynch and vsynch freq (info only) */
1296 t1 = (res_mode->left_margin + res_mode->xres +
1297 res_mode->right_margin + res_mode->hsync_len) / 8;
1298 t1 *= 8;
1299 t1 *= res_mode->pixclock;
1300 t1 /= 1000;
1301 hsynch = 1000000000L / t1;
1302 t1 *=
1303 (res_mode->upper_margin + res_mode->yres +
1304 res_mode->lower_margin + res_mode->vsync_len);
1305 t1 /= 1000;
1306 vsynch = 1000000000L / t1;
1307
1308 /* fill in Graphic device struct */
1309 sprintf (pGD->modeIdent, "%dx%dx%d %ldkHz %ldHz", res_mode->xres,
1310 res_mode->yres, bits_per_pixel, (hsynch / 1000),
1311 (vsynch / 1000));
1312 printf ("%s\n", pGD->modeIdent);
1313 pGD->winSizeX = res_mode->xres;
1314 pGD->winSizeY = res_mode->yres;
1315 pGD->plnSizeX = res_mode->xres;
1316 pGD->plnSizeY = res_mode->yres;
1317 switch (bits_per_pixel) {
1318 case 8:
1319 pGD->gdfBytesPP = 1;
1320 pGD->gdfIndex = GDF__8BIT_INDEX;
1321 break;
1322 case 15:
1323 pGD->gdfBytesPP = 2;
1324 pGD->gdfIndex = GDF_15BIT_555RGB;
1325 break;
1326 case 16:
1327 pGD->gdfBytesPP = 2;
1328 pGD->gdfIndex = GDF_16BIT_565RGB;
1329 break;
1330 case 24:
1331 pGD->gdfBytesPP = 3;
1332 pGD->gdfIndex = GDF_24BIT_888RGB;
1333 break;
1334 }
1335 pGD->isaBase = CFG_ISA_IO_BASE_ADDRESS;
1336 pGD->pciBase = pci_mem_base;
1337 pGD->frameAdrs = pci_mem_base;
1338 pGD->memSize = chips_param->max_mem;
1339 /* Cursor Start Address */
1340 pGD->dprBase =
1341 (pGD->winSizeX * pGD->winSizeY * pGD->gdfBytesPP) + pci_mem_base;
1342 if ((pGD->dprBase & 0x0fff) != 0) {
1343 /* allign it */
1344 pGD->dprBase &= 0xfffff000;
1345 pGD->dprBase += 0x00001000;
1346 }
1347 PRINTF ("Cursor Start %x Pattern Start %x\n", pGD->dprBase,
1348 PATTERN_ADR);
1349 pGD->vprBase = pci_mem_base; /* Dummy */
1350 pGD->cprBase = pci_mem_base; /* Dummy */
1351 /* set up Hardware */
1352
1353 ctWrite (CT_MSR_W_O, 0x01);
1354
1355 /* set the extended Registers */
1356 ctLoadRegs (CT_XR_O, xreg);
1357 /* set atribute registers */
1358 SetArRegs ();
1359 /* set Graphics register */
1360 SetGrRegs ();
1361 /* set sequencer */
1362 SetSrRegs ();
1363
1364 /* set msr */
1365 SetMsrRegs (res_mode);
1366
1367 /* set CRT Registers */
1368 SetCrRegs (res_mode, bits_per_pixel);
1369 /* set color mode */
1370 SetBitsPerPixelIntoXrRegs (bits_per_pixel);
1371
1372 /* set PLL */
1373 FindAndSetPllParamIntoXrRegs (res_mode->pixclock, chips_param);
1374
1375 ctWrite_i (CT_SR_O, 0, 0x03); /* clear synchronous reset */
1376 /* Clear video memory */
1377 i = pGD->memSize / 4;
1378 vm = (unsigned int *) pGD->pciBase;
1379 while (i--)
1380 *vm++ = 0;
1381 SetDrawingEngine (bits_per_pixel);
1382#ifdef VGA_DUMP_REG
1383 video_dump_reg ();
1384#endif
1385
1386 return ((void *) &ctfb);
1387}
1388
1389 /*******************************************************************************
1390*
1391* Set a RGB color in the LUT (8 bit index)
1392*/
1393void
1394video_set_lut (unsigned int index, /* color number */
1395 unsigned char r, /* red */
1396 unsigned char g, /* green */
1397 unsigned char b /* blue */
1398 )
1399{
1400
1401 ctWrite (CT_LUT_MASK_O, 0xff);
1402
1403 ctWrite (CT_LUT_START_O, (char) index);
1404
1405 ctWrite (CT_LUT_RGB_O, r); /* red */
1406 ctWrite (CT_LUT_RGB_O, g); /* green */
1407 ctWrite (CT_LUT_RGB_O, b); /* blue */
1408 udelay (1);
1409 ctWrite (CT_LUT_MASK_O, 0xff);
1410}
1411
1412/*******************************************************************************
1413*
1414* Drawing engine fill on screen region
1415*/
1416void
1417video_hw_rectfill (unsigned int bpp, /* bytes per pixel */
1418 unsigned int dst_x, /* dest pos x */
1419 unsigned int dst_y, /* dest pos y */
1420 unsigned int dim_x, /* frame width */
1421 unsigned int dim_y, /* frame height */
1422 unsigned int color /* fill color */
1423 )
1424{
1425 GraphicDevice *pGD = (GraphicDevice *) & ctfb;
1426 unsigned long *p, br04;
1427
1428 video_wait_bitblt (pGD->pciBase + BR04_o);
1429
1430 p = (unsigned long *) PATTERN_ADR;
1431 dim_x *= bpp;
1432 if (bpp == 3)
1433 bpp++; /* 24Bit needs a 32bit pattern */
1434 memset (p, color, (bpp * sizeof (unsigned char) * 8 * 8)); /* 8 x 8 pattern data */
1435 out32r (pGD->pciBase + BR07_o, ((pGD->winSizeX * dst_y) + dst_x) * pGD->gdfBytesPP); /* destination */
1436 br04 = in32r (pGD->pciBase + BR04_o) & 0xffffff00;
1437 br04 |= 0xF0; /* write Pattern P -> D */
1438 out32r (pGD->pciBase + BR04_o, br04); /* */
1439 out32r (pGD->pciBase + BR08_o, (dim_y << 16) + dim_x); /* starts the BITBlt */
1440 video_wait_bitblt (pGD->pciBase + BR04_o);
1441}
1442
1443/*******************************************************************************
1444*
1445* Drawing engine bitblt with screen region
1446*/
1447void
1448video_hw_bitblt (unsigned int bpp, /* bytes per pixel */
1449 unsigned int src_x, /* source pos x */
1450 unsigned int src_y, /* source pos y */
1451 unsigned int dst_x, /* dest pos x */
1452 unsigned int dst_y, /* dest pos y */
1453 unsigned int dim_x, /* frame width */
1454 unsigned int dim_y /* frame height */
1455 )
1456{
1457 GraphicDevice *pGD = (GraphicDevice *) & ctfb;
1458 unsigned long br04;
1459
1460 br04 = in32r (pGD->pciBase + BR04_o);
1461
1462 /* to prevent data corruption due to overlap, we have to
1463 * find out if, and how the frames overlaps */
1464 if (src_x < dst_x) {
1465 /* src is more left than dest
1466 * the frame may overlap -> start from right to left */
1467 br04 |= 0x00000100; /* set bit 8 */
1468 src_x += dim_x;
1469 dst_x += dim_x;
1470 } else {
1471 br04 &= 0xfffffeff; /* clear bit 8 left to right */
1472 }
1473 if (src_y < dst_y) {
1474 /* src is higher than dst
1475 * the frame may overlap => start from bottom */
1476 br04 |= 0x00000200; /* set bit 9 */
1477 src_y += dim_y;
1478 dst_y += dim_y;
1479 } else {
1480 br04 &= 0xfffffdff; /* clear bit 9 top to bottom */
1481 }
1482 dim_x *= bpp;
1483 out32r (pGD->pciBase + BR06_o, ((pGD->winSizeX * src_y) + src_x) * pGD->gdfBytesPP); /* source */
1484 out32r (pGD->pciBase + BR07_o, ((pGD->winSizeX * dst_y) + dst_x) * pGD->gdfBytesPP); /* destination */
1485 br04 &= 0xffffff00;
1486 br04 |= 0x000000CC; /* S -> D */
1487 out32r (pGD->pciBase + BR04_o, br04); /* */
1488 out32r (pGD->pciBase + BR08_o, (dim_y << 16) + dim_x); /* start the BITBlt */
1489 video_wait_bitblt (pGD->pciBase + BR04_o);
1490}
1491
1492#endif /* CONFIG_CT69000 */
1493
1494#endif /* CONFIG_VIDEO */