Home | History | Annotate | Line # | Download | only in iomd
vidc20config.c revision 1.1
      1 /*	$NetBSD: vidc20config.c,v 1.1 2001/10/05 22:27:43 reinoud Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2001 Reinoud Zandijk
      5  * Copyright (c) 1996 Mark Brinicombe
      6  * Copyright (c) 1996 Robert Black
      7  * Copyright (c) 1994-1995 Melvyn Tang-Richardson
      8  * Copyright (c) 1994-1995 RiscBSD kernel team
      9  * All rights reserved.
     10  *
     11  * Redistribution and use in source and binary forms, with or without
     12  * modification, are permitted provided that the following conditions
     13  * are met:
     14  * 1. Redistributions of source code must retain the above copyright
     15  *    notice, this list of conditions and the following disclaimer.
     16  * 2. Redistributions in binary form must reproduce the above copyright
     17  *    notice, this list of conditions and the following disclaimer in the
     18  *    documentation and/or other materials provided with the distribution.
     19  * 3. All advertising materials mentioning features or use of this software
     20  *    must display the following acknowledgement:
     21  *	This product includes software developed by the RiscBSD kernel team
     22  * 4. The name of the company nor the name of the author may be used to
     23  *    endorse or promote products derived from this software without specific
     24  *    prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE RISCBSD TEAM ``AS IS'' AND ANY EXPRESS
     27  * OR IMPLIED  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     28  * WARRANTIES OF  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     29  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
     30  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
     36  * THE POSSIBILITY OF SUCH DAMAGE.
     37  *
     38  * NetBSD kernel project
     39  *
     40  * vidcvideo.c
     41  *
     42  * This file is the lower basis of the wscons driver for VIDC based ARM machines.
     43  * It features the initialisation and all VIDC writing and keeps in internal state
     44  * copy.
     45  * Its currenly set up as a library file and not as a device; it could be named
     46  * vidcvideo0 eventually.
     47  */
     48 
     49 #include <sys/cdefs.h>
     50 #include <sys/types.h>
     51 #include <sys/param.h>
     52 #include <arm/iomd/vidc.h>
     53 #include <machine/katelib.h>
     54 #include <machine/bootconfig.h>
     55 #include <machine/irqhandler.h>
     56 
     57 #include <sys/systm.h>
     58 #include <sys/device.h>
     59 #include <uvm/uvm_extern.h>
     60 
     61 #include <arm/iomd/iomdreg.h>
     62 #include <arm/iomd/iomdvar.h>
     63 #include <arm/iomd/vidc20config.h>
     64 
     65 /*
     66  * A structure containing ALL the information required to restore
     67  * the VIDC20 to any given state.  ALL vidc transactions should
     68  * go through these procedures, which record the vidc's state.
     69  * it may be an idea to set the permissions of the vidc base address
     70  * so we get a fault, so the fault routine can record the state but
     71  * I guess that's not really necessary for the time being, since we
     72  * can make the kernel more secure later on.  Also, it is possible
     73  * to write a routine to allow 'reading' of the vidc registers.
     74  */
     75 
     76 static struct vidc_state vidc_lookup = {
     77 	{ 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
     78           0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
     79           0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
     80           0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
     81           0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
     82           0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
     83           0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
     84           0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0
     85 	},
     86 
     87 	VIDC_PALREG,
     88 	VIDC_BCOL,
     89 	VIDC_CP1 ,
     90 	VIDC_CP2,
     91 	VIDC_CP3,
     92 	VIDC_HCR,
     93 	VIDC_HSWR,
     94 	VIDC_HBSR,
     95 	VIDC_HDSR,
     96 	VIDC_HDER,
     97 	VIDC_HBER,
     98 	VIDC_HCSR,
     99 	VIDC_HIR,
    100 	VIDC_VCR,
    101 	VIDC_VSWR,
    102 	VIDC_VBSR,
    103 	VIDC_VDSR,
    104 	VIDC_VDER,
    105 	VIDC_VBER,
    106 	VIDC_VCSR,
    107 	VIDC_VCER,
    108 	VIDC_EREG,
    109 	VIDC_FSYNREG,
    110 	VIDC_CONREG,
    111 	VIDC_DCTL
    112 };
    113 
    114 struct vidc_state vidc_current[1];
    115 
    116 
    117 /*
    118  * Structures defining clock frequenties and their settings...
    119  * move to a constants header file ?
    120  */
    121 
    122 #ifdef RC7500
    123 struct vfreq {
    124 	u_int frqcon;
    125 	int freq;
    126 };
    127 
    128 static struct vfreq vfreq[] = {
    129 	{ VIDFREQ_25_18, 25175},
    130 	{ VIDFREQ_25_18, 25180},
    131 	{ VIDFREQ_28_32, 28320},
    132 	{ VIDFREQ_31_50, 31500},
    133 	{ VIDFREQ_36_00, 36000},
    134 	{ VIDFREQ_40_00, 40000},
    135 	{ VIDFREQ_44_90, 44900},
    136 	{ VIDFREQ_50_00, 50000},
    137 	{ VIDFREQ_65_00, 65000},
    138 	{ VIDFREQ_72_00, 72000},
    139 	{ VIDFREQ_75_00, 75000},
    140 	{ VIDFREQ_77_00, 77000},
    141 	{ VIDFREQ_80_00, 80000},
    142 	{ VIDFREQ_94_50, 94500},
    143 	{ VIDFREQ_110_0, 110000},
    144 	{ VIDFREQ_120_0, 120000},
    145 	{ VIDFREQ_130_0, 130000}
    146 };
    147 
    148 #define NFREQ	(sizeof (vfreq) / sizeof(struct vfreq))
    149 u_int vfreqcon = 0;
    150 #else /* RC7500 */
    151 
    152 struct fsyn {
    153 	int r, v, f;
    154 };
    155 
    156 static struct fsyn fsyn_pref[] = {
    157 	{ 6,   2,  8000 },
    158 	{ 4,   2, 12000 },
    159 	{ 3,   2, 16000 },
    160 	{ 2,   2, 24000 },
    161 	{ 41, 43, 25171 },
    162 	{ 50, 59, 28320 },
    163 	{ 3,   4, 32000 },
    164 	{ 2,   3, 36000 },
    165 	{ 31, 58, 44903 },
    166 	{ 12, 35, 70000 },
    167 	{ 0,   0, 00000 }
    168 };
    169 #endif /* RC7500 */
    170 
    171 
    172 /*
    173  * XXX global display variables XXX ... should be a structure
    174  */
    175 static int cold_init = 0;		/* flags initialisation */
    176 extern videomemory_t videomemory;
    177 
    178 static struct vidc_mode vidc_initialmode;
    179 static struct vidc_mode *vidc_currentmode;
    180 
    181 unsigned int dispstart;
    182 unsigned int dispsize;
    183 unsigned int dispbase;
    184 unsigned int dispend;
    185 unsigned int ptov;
    186 unsigned int vmem_base;
    187 unsigned int phys_base;
    188 unsigned int transfersize;
    189 
    190 
    191 /* cursor stuff */
    192 char *cursor_normal;
    193 char *cursor_transparent;
    194 int p_cursor_normal;
    195 int p_cursor_transparent;
    196 int cursor_width;
    197 int cursor_height;
    198 
    199 
    200 /*
    201  * VIDC mode definitions
    202  * generated from RISC OS mode definition file by an `awk' script
    203  */
    204 extern struct vidc_mode vidcmodes[];
    205 
    206 
    207 /*
    208  * configuration printing
    209  *
    210  */
    211 
    212 void
    213 vidcvideo_printdetails(void)
    214 {
    215         printf(": refclk=%dMHz %dKB %s ", (vidc_fref / 1000000),
    216             videomemory.vidm_size / 1024,
    217             (videomemory.vidm_type == VIDEOMEM_TYPE_VRAM) ? "VRAM" : "DRAM");
    218 }
    219 
    220 /*
    221  * Common functions to directly access VIDC registers
    222  */
    223 int
    224 vidcvideo_write(reg, value)
    225 	u_int reg;
    226 	int value;
    227 {
    228 	int counter;
    229 
    230 	int *current;
    231 	int *tab;
    232 
    233 	tab 	= (int *)&vidc_lookup;
    234 	current = (int *)vidc_current;
    235 
    236 
    237 	/*
    238 	 * OK, the VIDC_PALETTE register is handled differently
    239 	 * to the others on the VIDC, so take that into account here
    240 	 */
    241 	if (reg==VIDC_PALREG) {
    242 		vidc_current->palreg = 0;
    243 		WriteWord(vidc_base, reg | value);
    244 		return 0;
    245 	}
    246 
    247 	if (reg==VIDC_PALETTE) {
    248 		WriteWord(vidc_base, reg | value);
    249 		vidc_current->palette[vidc_current->palreg] = value;
    250 		vidc_current->palreg++;
    251 		vidc_current->palreg = vidc_current->palreg & 0xff;
    252 		return 0;
    253 	}
    254 
    255 	/*
    256 	 * Undefine SAFER if you wish to speed things up (a little)
    257 	 * although this means the function will assume things abou
    258 	 * the structure of vidc_state. i.e. the first 256 words are
    259 	 * the palette array
    260 	 */
    261 
    262 #define SAFER
    263 
    264 #ifdef 	SAFER
    265 #define INITVALUE 0
    266 #else
    267 #define INITVALUE 256
    268 #endif
    269 
    270 	for ( counter=INITVALUE; counter<= sizeof(struct vidc_state); counter++ ) {
    271 		if ( reg==tab[counter] ) {
    272 			WriteWord ( vidc_base, reg | value );
    273 			current[counter] = value;
    274 			return 0;
    275 		}
    276 	}
    277 	return -1;
    278 }
    279 
    280 
    281 void
    282 vidcvideo_setpalette(vidc)
    283 	struct vidc_state *vidc;
    284 {
    285 	int counter = 0;
    286 
    287 	vidcvideo_write(VIDC_PALREG, 0x00000000);
    288 	for (counter = 0; counter < 255; counter++)
    289 		vidcvideo_write(VIDC_PALETTE, vidc->palette[counter]);
    290 }
    291 
    292 
    293 void
    294 vidcvideo_setstate(vidc)
    295 	struct vidc_state *vidc;
    296 {
    297 	vidcvideo_write ( VIDC_PALREG,	vidc->palreg 	);
    298 	vidcvideo_write ( VIDC_BCOL,		vidc->bcol	);
    299 	vidcvideo_write ( VIDC_CP1,		vidc->cp1	);
    300 	vidcvideo_write ( VIDC_CP2,		vidc->cp2	);
    301 	vidcvideo_write ( VIDC_CP3,		vidc->cp3	);
    302 	vidcvideo_write ( VIDC_HCR,		vidc->hcr	);
    303 	vidcvideo_write ( VIDC_HSWR,		vidc->hswr	);
    304 	vidcvideo_write ( VIDC_HBSR,		vidc->hbsr	);
    305 	vidcvideo_write ( VIDC_HDSR,		vidc->hdsr	);
    306 	vidcvideo_write ( VIDC_HDER,		vidc->hder	);
    307 	vidcvideo_write ( VIDC_HBER,		vidc->hber	);
    308 	vidcvideo_write ( VIDC_HCSR,		vidc->hcsr	);
    309 	vidcvideo_write ( VIDC_HIR,		vidc->hir	);
    310 	vidcvideo_write ( VIDC_VCR,		vidc->vcr	);
    311 	vidcvideo_write ( VIDC_VSWR,		vidc->vswr	);
    312 	vidcvideo_write ( VIDC_VBSR,		vidc->vbsr	);
    313 	vidcvideo_write ( VIDC_VDSR,		vidc->vdsr	);
    314 	vidcvideo_write ( VIDC_VDER,		vidc->vder	);
    315 	vidcvideo_write ( VIDC_VBER,		vidc->vber	);
    316 	vidcvideo_write ( VIDC_VCSR,		vidc->vcsr	);
    317 	vidcvideo_write ( VIDC_VCER,		vidc->vcer	);
    318 /*
    319  * Right, dunno what to set these to yet, but let's keep RiscOS's
    320  * ones for now, until the time is right to finish this code
    321  */
    322 
    323 /*	vidcvideo_write ( VIDC_EREG,		vidc->ereg	);	*/
    324 /*	vidcvideo_write ( VIDC_FSYNREG,	vidc->fsynreg	);	*/
    325 /*	vidcvideo_write ( VIDC_CONREG,	vidc->conreg	);	*/
    326 /*	vidcvideo_write ( VIDC_DCTL,		vidc->dctl	);	*/
    327 
    328 }
    329 
    330 
    331 void
    332 vidcvideo_getstate(vidc)
    333 	struct vidc_state *vidc;
    334 {
    335 	*vidc = *vidc_current;
    336 }
    337 
    338 
    339 void
    340 vidcvideo_getmode(mode)
    341 	struct vidc_mode *mode;
    342 {
    343 	*mode = *vidc_currentmode;
    344 }
    345 
    346 
    347 void
    348 vidcvideo_stdpalette()
    349 {
    350         WriteWord(vidc_base, VIDC_PALREG | 0x00000000);
    351         WriteWord(vidc_base, VIDC_PALETTE | VIDC_COL(  0,   0,   0));
    352         WriteWord(vidc_base, VIDC_PALETTE | VIDC_COL(255,   0,   0));
    353         WriteWord(vidc_base, VIDC_PALETTE | VIDC_COL(  0, 255,   0));
    354         WriteWord(vidc_base, VIDC_PALETTE | VIDC_COL(255, 255,   0));
    355         WriteWord(vidc_base, VIDC_PALETTE | VIDC_COL(  0,   0, 255));
    356         WriteWord(vidc_base, VIDC_PALETTE | VIDC_COL(255,   0, 255));
    357         WriteWord(vidc_base, VIDC_PALETTE | VIDC_COL(  0, 255, 255));
    358         WriteWord(vidc_base, VIDC_PALETTE | VIDC_COL(255, 255, 255));
    359         WriteWord(vidc_base, VIDC_PALETTE | VIDC_COL(128, 128, 128));
    360         WriteWord(vidc_base, VIDC_PALETTE | VIDC_COL(255, 128, 128));
    361         WriteWord(vidc_base, VIDC_PALETTE | VIDC_COL(128, 255, 128));
    362         WriteWord(vidc_base, VIDC_PALETTE | VIDC_COL(255, 255, 128));
    363         WriteWord(vidc_base, VIDC_PALETTE | VIDC_COL(128, 128, 255));
    364         WriteWord(vidc_base, VIDC_PALETTE | VIDC_COL(255, 128, 255));
    365         WriteWord(vidc_base, VIDC_PALETTE | VIDC_COL(128, 255, 255));
    366         WriteWord(vidc_base, VIDC_PALETTE | VIDC_COL(255, 255, 255));
    367 }
    368 
    369 
    370 /* small inline mod function ... why here? */
    371 static __inline int
    372 mod(int n)
    373 {
    374 	if (n < 0)
    375 		return(-n);
    376 	else
    377 		return(n);
    378 }
    379 
    380 
    381 static int
    382 vidcvideo_coldinit(void)
    383 {
    384 	int found;
    385 	int loop;
    386 
    387 	/* Blank out the cursor */
    388 
    389 	vidcvideo_write(VIDC_CP1, 0x0);
    390 	vidcvideo_write(VIDC_CP2, 0x0);
    391 	vidcvideo_write(VIDC_CP3, 0x0);
    392 
    393 	/* Try to determine the current mode */
    394 	vidc_initialmode.hder     = bootconfig.width+1;
    395 	vidc_initialmode.vder     = bootconfig.height+1;
    396 	vidc_initialmode.log2_bpp = bootconfig.log2_bpp;
    397 
    398 	dispbase = vmem_base = dispstart = videomemory.vidm_vbase;
    399 	phys_base = videomemory.vidm_pbase;
    400 
    401 	/* Nut - should be using videomemory.vidm_size - mark */
    402 	if (videomemory.vidm_type == VIDEOMEM_TYPE_DRAM) {
    403 		dispsize = videomemory.vidm_size;
    404 		transfersize = 16;
    405 	} else {
    406 		dispsize = bootconfig.vram[0].pages * NBPG;
    407 		transfersize = dispsize >> 10;
    408 	};
    409 
    410 	ptov = dispbase - phys_base;
    411 
    412 	dispend = dispstart+dispsize;
    413 
    414 	/* try to find the current mode from the bootloader in my table */
    415 	vidc_currentmode = &vidcmodes[0];
    416 	loop = 0;
    417 	found = 0;
    418 	while (vidcmodes[loop].pixel_rate != 0) {
    419   		if (vidcmodes[loop].hder == (bootconfig.width + 1)
    420   		    && vidcmodes[loop].vder == (bootconfig.height + 1)
    421 		    && vidcmodes[loop].frame_rate == bootconfig.framerate) {
    422 			vidc_currentmode = &vidcmodes[loop];
    423 			found = 1;
    424 		}
    425 		++loop;
    426 	}
    427 
    428 	/* if not found choose first mode but dont be picky on the framerate */
    429 	if (!found) {
    430 		vidc_currentmode = &vidcmodes[0];
    431 		loop = 0;
    432 		found = 0;
    433 
    434 		while (vidcmodes[loop].pixel_rate != 0) {
    435 			if (vidcmodes[loop].hder == (bootconfig.width + 1)
    436  			    && vidcmodes[loop].vder == (bootconfig.height + 1)) {
    437  				vidc_currentmode = &vidcmodes[loop];
    438  				found = 1;
    439  			}
    440  			++loop;
    441  		}
    442 	}
    443 
    444 	vidc_currentmode->log2_bpp = bootconfig.log2_bpp;
    445 
    446 	dispstart = dispbase;
    447 	dispend = dispstart+dispsize;
    448 
    449 	IOMD_WRITE_WORD(IOMD_VIDINIT, dispstart-ptov);
    450 	IOMD_WRITE_WORD(IOMD_VIDSTART, dispstart-ptov);
    451 	IOMD_WRITE_WORD(IOMD_VIDEND, (dispend-transfersize)-ptov);
    452 	return 0;
    453 }
    454 
    455 
    456 /* simple function to abstract vidc variables ; returns virt start address of screen */
    457 /* XXX asumption that video memory is mapped in twice */
    458 void *vidcvideo_hwscroll(int bytes) {
    459 	dispstart += bytes;
    460 	if (dispstart >= dispbase + dispsize) dispstart -= dispsize;
    461 	if (dispstart <  dispbase)            dispstart += dispsize;
    462 	dispend = dispstart+dispsize;
    463 
    464 	/* return the start of the bit map of the screen (left top) */
    465 	return (void *) dispstart;
    466 }
    467 
    468 
    469 /* reset the HW scroll to be at the start for the benefit of f.e. X */
    470 void *vidcvideo_hwscroll_reset(void) {
    471 	void *cookie = (void *) dispstart;
    472 
    473 	dispstart = dispbase;
    474 	dispend = dispstart + dispsize;
    475 	return cookie;
    476 }
    477 
    478 
    479 /* put HW scroll back to where it was */
    480 void *vidcvideo_hwscroll_back(void *cookie) {
    481 	dispstart = (int) cookie;
    482 	dispend = dispstart + dispsize;
    483 	return cookie;
    484 }
    485 
    486 
    487 /* this function is to be called at vsync */
    488 void vidcvideo_progr_scroll(void) {
    489 	IOMD_WRITE_WORD(IOMD_VIDINIT, dispstart-ptov);
    490 	IOMD_WRITE_WORD(IOMD_VIDSTART, dispstart-ptov);
    491 	IOMD_WRITE_WORD(IOMD_VIDEND, (dispend-transfersize)-ptov);
    492 }
    493 
    494 
    495 /*
    496  * Select a new mode by reprogramming the VIDC chip
    497  * XXX this part is known not to work for 32bpp
    498  */
    499 
    500 struct vidc_mode newmode;
    501 
    502 static const int bpp_mask_table[] = {
    503 	0,  /* 1bpp */
    504 	1,  /* 2bpp */
    505 	2,  /* 4bpp */
    506 	3,  /* 8bpp */
    507 	4,  /* 16bpp */
    508 	6   /* 32bpp */
    509 };
    510 
    511 
    512 void
    513 vidcvideo_setmode(struct vidc_mode *mode)
    514 {
    515 	register int acc;
    516 	int bpp_mask;
    517 #ifndef RC7500
    518         int ereg;
    519 
    520 	int best_r, best_v, best_match;
    521 #endif
    522 
    523 #ifdef NC
    524 return;
    525 #endif
    526 	/*
    527 	 * Find out what bit mask we need to or with the vidc20 control register
    528 	 * in order to generate the desired number of bits per pixel.
    529 	 * log_bpp is log base 2 of the number of bits per pixel.
    530 	 */
    531 
    532 	bpp_mask = bpp_mask_table[mode->log2_bpp];
    533 
    534 	newmode = *mode;
    535 	vidc_currentmode = &newmode;
    536 
    537 #ifdef RC7500
    538 	{
    539 		int i;
    540 		int old, new;
    541 		u_int nfreq;
    542 
    543 		old = vfreq[0].freq;
    544 		nfreq = vfreq[0].frqcon;
    545 		for (i = 0; i < (NFREQ - 1); i++) {
    546 			new = vfreq[i].freq - mode->pixel_rate;
    547 			if (new < 0)
    548 				new = -new;
    549 			if (new < old) {
    550 				nfreq = vfreq[i].frqcon;
    551 				old = new;
    552 			}
    553 			if (new == 0)
    554 				break;
    555 		}
    556 		nfreq |= (vfreqcon & 0xf0);
    557 		vfreqcon = nfreq;
    558 	}
    559 #else /* RC7500 */
    560 	/* Program the VCO Look-up to a preferred value before choosing one */
    561 	{
    562 		int least_error = mod(fsyn_pref[0].f - vidc_currentmode->pixel_rate);
    563 		int counter;
    564 		best_r = fsyn_pref[0].r;
    565 		best_match = fsyn_pref[0].f;
    566 		best_v = fsyn_pref[0].v;
    567 
    568 		/* Look up */
    569 		counter=0;
    570 		while (fsyn_pref[counter].r != 0) {
    571 			if (least_error > mod(fsyn_pref[counter].f - vidc_currentmode->pixel_rate)) {
    572 				best_match = fsyn_pref[counter].f;
    573 				least_error = mod(fsyn_pref[counter].f - vidc_currentmode->pixel_rate);
    574 				best_r = fsyn_pref[counter].r;
    575 				best_v = fsyn_pref[counter].v;
    576 			}
    577 			counter++;
    578 		}
    579 
    580 		if (least_error > 0) { /* Accuracy of 1000Hz */
    581 			int r, v, f;
    582 			for (v = 63; v > 0; v--)
    583 				for (r = 63; r > 0; r--) {
    584 					f = ((v * vidc_fref) /1000) / r;
    585 					if (least_error >= mod(f - vidc_currentmode->pixel_rate)) {
    586 						best_match = f;
    587 						least_error = mod(f - vidc_currentmode->pixel_rate);
    588 						best_r = r;
    589 						best_v = v;
    590 					}
    591 				}
    592 		}
    593 
    594 		if (best_r > 63) best_r=63;
    595 		if (best_v > 63) best_v=63;
    596 		if (best_r < 1)  best_r= 1;
    597 		if (best_v < 1)  best_v= 1;
    598 
    599 	}
    600 #endif /* RC7500 */
    601 
    602 #ifdef RC7500
    603 	outb(FREQCON, vfreqcon);
    604 	/*
    605 	 * Need to program the control register first.
    606 	 */
    607 	if (dispsize>1024*1024) {
    608 		if (vidc_currentmode->hder>=800)
    609 			vidcvideo_write(VIDC_CONREG, 7<<8 | bpp_mask<<5);
    610 		else
    611 			vidcvideo_write(VIDC_CONREG, 6<<8 | bpp_mask<<5);
    612 	} else {
    613 		vidcvideo_write(VIDC_CONREG, 7<<8 | bpp_mask<<5);
    614 	}
    615 
    616 	/*
    617 	 * We don't use VIDC_FSYNREG.  Program it low.
    618 	 */
    619 	vidcvideo_write(VIDC_FSYNREG, 0x2020);
    620 #else /* RC7500 */
    621 	vidcvideo_write(VIDC_FSYNREG, (best_v-1)<<8 | (best_r-1)<<0);
    622 #endif /* RC7500 */
    623 	acc=0;
    624 	acc+=vidc_currentmode->hswr;	vidcvideo_write(VIDC_HSWR, (acc - 8 ) & (~1));
    625 	acc+=vidc_currentmode->hbsr;	vidcvideo_write(VIDC_HBSR, (acc - 12) & (~1));
    626 	acc+=vidc_currentmode->hdsr;	vidcvideo_write(VIDC_HDSR, (acc - 18) & (~1));
    627 	acc+=vidc_currentmode->hder;	vidcvideo_write(VIDC_HDER, (acc - 18) & (~1));
    628 	acc+=vidc_currentmode->hber;	vidcvideo_write(VIDC_HBER, (acc - 12) & (~1));
    629 	acc+=vidc_currentmode->hcr;	vidcvideo_write(VIDC_HCR,  (acc - 8 ) & (~3));
    630 
    631 	acc=0;
    632 	acc+=vidc_currentmode->vswr;	vidcvideo_write(VIDC_VSWR, (acc - 1));
    633 	acc+=vidc_currentmode->vbsr;	vidcvideo_write(VIDC_VBSR, (acc - 1));
    634 	acc+=vidc_currentmode->vdsr;	vidcvideo_write(VIDC_VDSR, (acc - 1));
    635 	acc+=vidc_currentmode->vder;	vidcvideo_write(VIDC_VDER, (acc - 1));
    636 	acc+=vidc_currentmode->vber;	vidcvideo_write(VIDC_VBER, (acc - 1));
    637 	acc+=vidc_currentmode->vcr;	vidcvideo_write(VIDC_VCR,  (acc - 1));
    638 
    639 #ifdef RC7500
    640 	vidcvideo_write(VIDC_DCTL, vidc_currentmode->hder>>2 | 1<<16 | 1<<12);
    641 	if (vidc_currentmode->hder>=800)
    642 		vidcvideo_write(VIDC_EREG, 0x41<<12);
    643 	else
    644 		vidcvideo_write(VIDC_EREG, 0x51<<12);
    645 #else
    646 	IOMD_WRITE_WORD(IOMD_FSIZE, vidc_currentmode->vcr
    647 	    + vidc_currentmode->vswr
    648 	    + vidc_currentmode->vber
    649 	    + vidc_currentmode->vbsr - 1);
    650 
    651 	if (dispsize <= 1024*1024)
    652 		vidcvideo_write(VIDC_DCTL, vidc_currentmode->hder>>2 | 1<<16 | 1<<12);
    653 	else
    654 		vidcvideo_write(VIDC_DCTL, vidc_currentmode->hder>>2 | 3<<16 | 1<<12);
    655 
    656 	ereg = 1<<12;
    657 	if (vidc_currentmode->sync_pol & 0x01)
    658 		ereg |= 1<<16;
    659 	if (vidc_currentmode->sync_pol & 0x02)
    660 		ereg |= 1<<18;
    661 	vidcvideo_write(VIDC_EREG, ereg);
    662 	if (dispsize > 1024*1024) {
    663 		if (vidc_currentmode->hder >= 800)
    664  			vidcvideo_write(VIDC_CONREG, 7<<8 | bpp_mask<<5);
    665 		else
    666 			vidcvideo_write(VIDC_CONREG, 6<<8 | bpp_mask<<5);
    667 	} else {
    668 		vidcvideo_write(VIDC_CONREG, 7<<8 | bpp_mask<<5);
    669 	}
    670 #endif
    671 }
    672 
    673 
    674 /* not used for now */
    675 void
    676 vidcvideo_set_display_base(base)
    677 	u_int base;
    678 {
    679 	dispstart = dispstart-dispbase + base;
    680 	dispbase = vmem_base = base;
    681 	dispend = base + dispsize;
    682 	ptov = dispbase - phys_base;
    683 }
    684 
    685 
    686 /*
    687  * Main initialisation routine for now
    688  */
    689 
    690 static int cursor_init = 0;
    691 
    692 int
    693 vidcvideo_init(void)
    694 {
    695 	vidcvideo_coldinit();
    696 	if (cold_init && (cursor_init == 0))
    697 		/*	vidcvideo_flash_go() */;
    698 
    699 	/* setting a mode goes wrong in 32 bpp ... 8 and 16 seem OK */
    700 	vidcvideo_setmode(vidc_currentmode);
    701 	vidcvideo_blank(0);			/* display on */
    702 
    703 	vidcvideo_textpalette();
    704 
    705 	if (cold_init == 0) {
    706 		vidcvideo_write(VIDC_CP1, 0x0);
    707 		vidcvideo_write(VIDC_CP2, 0x0);
    708 		vidcvideo_write(VIDC_CP3, 0x0);
    709 	} else {
    710 		vidcvideo_cursor_init(CURSOR_MAX_WIDTH, CURSOR_MAX_HEIGHT);
    711 	};
    712 
    713 	cold_init=1;
    714 	return 0;
    715 }
    716 
    717 
    718 /* reinitialise the vidcvideo */
    719 void
    720 vidcvideo_reinit()
    721 {
    722 	vidcvideo_coldinit();
    723 	vidcvideo_setmode(vidc_currentmode);
    724 }
    725 
    726 
    727 paddr_t
    728 vidcvideo_mmap(vc, offset, nprot)
    729 	struct vconsole *vc;
    730 	off_t offset;
    731 	int nprot;
    732 {
    733 	if ((u_int)offset >= videomemory.vidm_size)
    734 		return (-1);
    735 	return(arm_byte_to_page(((videomemory.vidm_pbase) + (offset))));
    736 }
    737 
    738 
    739 int
    740 vidcvideo_cursor_init(int width, int height)
    741 {
    742 	static char *cursor_data = NULL;
    743 	int counter;
    744 	int line;
    745 	paddr_t pa;
    746 
    747 	cursor_width  = width;
    748 	cursor_height = height;
    749 
    750 	if (!cursor_data) {
    751 		/* Allocate cursor memory first time round */
    752 		cursor_data = (char *)uvm_km_zalloc(kernel_map, NBPG);
    753 		if (!cursor_data)
    754 			panic("Cannot allocate memory for hardware cursor\n");
    755 		(void) pmap_extract(pmap_kernel(), (vaddr_t)cursor_data, &pa);
    756 		IOMD_WRITE_WORD(IOMD_CURSINIT, pa);
    757 	}
    758 
    759 	/* Blank the cursor while initialising it's sprite */
    760 
    761 	vidcvideo_write ( VIDC_CP1, 0x0 );
    762 	vidcvideo_write ( VIDC_CP2, 0x0 );
    763 	vidcvideo_write ( VIDC_CP3, 0x0 );
    764 
    765  	cursor_normal       = cursor_data;
    766 	cursor_transparent  = cursor_data + (height * width);
    767 
    768  	cursor_transparent += 32;					/* ALIGN */
    769 	cursor_transparent = (char *)((int)cursor_transparent & (~31) );
    770 
    771 	for ( line = 0; line<height; ++ line )
    772 	{
    773 	    for ( counter=0; counter<width/4;counter++ )
    774 		cursor_normal[line * width + counter]=0x55;		/* why 0x55 ? */
    775 	    for ( ; counter<8; counter++ )
    776 		cursor_normal[line * width + counter]=0;
    777 	}
    778 
    779 	for ( line = 0; line<height; ++ line )
    780 	{
    781 	    for ( counter=0; counter<width/4;counter++ )
    782 		cursor_transparent[line * width + counter]=0x00;
    783 	    for ( ; counter<8; counter++ )
    784 		cursor_transparent[line * width + counter]=0;
    785 	}
    786 
    787 
    788 	(void) pmap_extract(pmap_kernel(), (vaddr_t)cursor_normal,
    789 	    (paddr_t *)&p_cursor_normal);
    790 	(void) pmap_extract(pmap_kernel(), (vaddr_t)cursor_transparent,
    791 	    (paddr_t *)&p_cursor_transparent);
    792 
    793 	memset ( cursor_normal, 0x55, width*height );			/* white? */
    794 	memset ( cursor_transparent, 0x00, width*height );		/* to see the diffence */
    795 
    796 	/* Ok, now program the cursor; should be blank */
    797 	vidcvideo_enablecursor(0);
    798 
    799         return 0;
    800 }
    801 
    802 
    803 void
    804 vidcvideo_updatecursor(xcur, ycur)
    805 	int xcur, ycur;
    806 {
    807 	int frontporch = vidc_currentmode->hswr + vidc_currentmode->hbsr + vidc_currentmode->hdsr;
    808 	int topporch   = vidc_currentmode->vswr + vidc_currentmode->vbsr + vidc_currentmode->vdsr;
    809 
    810 	vidcvideo_write(VIDC_HCSR, frontporch -17 + xcur);
    811 	vidcvideo_write(VIDC_VCSR, topporch   -2  + (ycur+1)-2 + 3 - cursor_height);
    812 	vidcvideo_write(VIDC_VCER, topporch   -2  + (ycur+3)+2 + 3 );
    813 	return;
    814 }
    815 
    816 
    817 void
    818 vidcvideo_enablecursor(on)
    819 	int on;
    820 {
    821 	if (on) {
    822 		IOMD_WRITE_WORD(IOMD_CURSINIT,p_cursor_normal);
    823 	} else {
    824 		IOMD_WRITE_WORD(IOMD_CURSINIT,p_cursor_transparent);
    825 	};
    826 	vidcvideo_write ( VIDC_CP1, 0xffffff );		/* enable */
    827 
    828 	return;
    829 }
    830 
    831 
    832 int
    833 vidcvideo_textpalette()
    834 {
    835 	vidcvideo_write(VIDC_PALREG, 0x00000000);
    836 	vidcvideo_write(VIDC_PALETTE, VIDC_COL(  0,   0,   0));
    837 	vidcvideo_write(VIDC_PALETTE, VIDC_COL(255,   0,   0));
    838 	vidcvideo_write(VIDC_PALETTE, VIDC_COL(  0, 255,   0));
    839 	vidcvideo_write(VIDC_PALETTE, VIDC_COL(255, 255,   0));
    840 	vidcvideo_write(VIDC_PALETTE, VIDC_COL(  0,   0, 255));
    841 	vidcvideo_write(VIDC_PALETTE, VIDC_COL(255,   0, 255));
    842 	vidcvideo_write(VIDC_PALETTE, VIDC_COL(  0, 255, 255));
    843 	vidcvideo_write(VIDC_PALETTE, VIDC_COL(255, 255, 255));
    844 	vidcvideo_write(VIDC_PALETTE, VIDC_COL(128, 128, 128));
    845 	vidcvideo_write(VIDC_PALETTE, VIDC_COL(255, 128, 128));
    846 	vidcvideo_write(VIDC_PALETTE, VIDC_COL(128, 255, 128));
    847 	vidcvideo_write(VIDC_PALETTE, VIDC_COL(255, 255, 128));
    848 	vidcvideo_write(VIDC_PALETTE, VIDC_COL(128, 128, 255));
    849 	vidcvideo_write(VIDC_PALETTE, VIDC_COL(255, 128, 255));
    850 	vidcvideo_write(VIDC_PALETTE, VIDC_COL(255, 255, 255));
    851 
    852 	return 0;
    853 }
    854 
    855 int
    856 vidcvideo_blank(video_off)
    857 	int video_off;
    858 {
    859         int ereg;
    860 
    861 	ereg = 1<<12;
    862 	if (vidc_currentmode->sync_pol & 0x01)
    863 		ereg |= 1<<16;
    864 	if (vidc_currentmode->sync_pol & 0x02)
    865 		ereg |= 1<<18;
    866 
    867 	if (!video_off) {
    868 #ifdef RC7500
    869 		vidcvideo_write(VIDC_EREG, 0x51<<12);
    870 #else
    871     		vidcvideo_write(VIDC_EREG, ereg);
    872 #endif
    873 	} else {
    874 		vidcvideo_write(VIDC_EREG, 0);
    875 	};
    876 	return 0;
    877 }
    878 
    879 /* end of vidc20config.c */
    880