1 1.37 andvar /* $NetBSD: vidc20config.c,v 1.37 2024/05/18 19:04:45 andvar Exp $ */ 2 1.1 reinoud 3 1.1 reinoud /* 4 1.1 reinoud * Copyright (c) 2001 Reinoud Zandijk 5 1.1 reinoud * Copyright (c) 1996 Mark Brinicombe 6 1.1 reinoud * Copyright (c) 1996 Robert Black 7 1.1 reinoud * Copyright (c) 1994-1995 Melvyn Tang-Richardson 8 1.1 reinoud * Copyright (c) 1994-1995 RiscBSD kernel team 9 1.1 reinoud * All rights reserved. 10 1.1 reinoud * 11 1.1 reinoud * Redistribution and use in source and binary forms, with or without 12 1.1 reinoud * modification, are permitted provided that the following conditions 13 1.1 reinoud * are met: 14 1.1 reinoud * 1. Redistributions of source code must retain the above copyright 15 1.1 reinoud * notice, this list of conditions and the following disclaimer. 16 1.1 reinoud * 2. Redistributions in binary form must reproduce the above copyright 17 1.1 reinoud * notice, this list of conditions and the following disclaimer in the 18 1.1 reinoud * documentation and/or other materials provided with the distribution. 19 1.1 reinoud * 3. All advertising materials mentioning features or use of this software 20 1.1 reinoud * must display the following acknowledgement: 21 1.1 reinoud * This product includes software developed by the RiscBSD kernel team 22 1.1 reinoud * 4. The name of the company nor the name of the author may be used to 23 1.1 reinoud * endorse or promote products derived from this software without specific 24 1.1 reinoud * prior written permission. 25 1.1 reinoud * 26 1.1 reinoud * THIS SOFTWARE IS PROVIDED BY THE RISCBSD TEAM ``AS IS'' AND ANY EXPRESS 27 1.1 reinoud * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 28 1.1 reinoud * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 1.1 reinoud * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE 30 1.1 reinoud * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 1.1 reinoud * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 1.1 reinoud * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 1.1 reinoud * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 1.1 reinoud * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 1.1 reinoud * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 36 1.1 reinoud * THE POSSIBILITY OF SUCH DAMAGE. 37 1.1 reinoud * 38 1.1 reinoud * NetBSD kernel project 39 1.1 reinoud * 40 1.1 reinoud * vidcvideo.c 41 1.1 reinoud * 42 1.1 reinoud * This file is the lower basis of the wscons driver for VIDC based ARM machines. 43 1.1 reinoud * It features the initialisation and all VIDC writing and keeps in internal state 44 1.1 reinoud * copy. 45 1.36 andvar * Its currently set up as a library file and not as a device; it could be named 46 1.1 reinoud * vidcvideo0 eventually. 47 1.1 reinoud */ 48 1.1 reinoud 49 1.1 reinoud #include <sys/cdefs.h> 50 1.7 bjh21 51 1.37 andvar __KERNEL_RCSID(0, "$NetBSD: vidc20config.c,v 1.37 2024/05/18 19:04:45 andvar Exp $"); 52 1.7 bjh21 53 1.1 reinoud #include <sys/types.h> 54 1.1 reinoud #include <sys/param.h> 55 1.1 reinoud #include <arm/iomd/vidc.h> 56 1.1 reinoud #include <machine/bootconfig.h> 57 1.4 thorpej #include <machine/intr.h> 58 1.1 reinoud 59 1.1 reinoud #include <sys/systm.h> 60 1.1 reinoud #include <sys/device.h> 61 1.1 reinoud #include <uvm/uvm_extern.h> 62 1.1 reinoud 63 1.1 reinoud #include <arm/iomd/iomdreg.h> 64 1.1 reinoud #include <arm/iomd/iomdvar.h> 65 1.1 reinoud #include <arm/iomd/vidc20config.h> 66 1.1 reinoud 67 1.34 skrll #define WriteWord(a, b) \ 68 1.34 skrll *((volatile unsigned int *)(a)) = (b) 69 1.34 skrll 70 1.34 skrll #define ReadWord(a) \ 71 1.34 skrll (*((volatile unsigned int *)(a))) 72 1.9 reinoud 73 1.1 reinoud /* 74 1.1 reinoud * A structure containing ALL the information required to restore 75 1.1 reinoud * the VIDC20 to any given state. ALL vidc transactions should 76 1.1 reinoud * go through these procedures, which record the vidc's state. 77 1.1 reinoud * it may be an idea to set the permissions of the vidc base address 78 1.1 reinoud * so we get a fault, so the fault routine can record the state but 79 1.1 reinoud * I guess that's not really necessary for the time being, since we 80 1.1 reinoud * can make the kernel more secure later on. Also, it is possible 81 1.1 reinoud * to write a routine to allow 'reading' of the vidc registers. 82 1.1 reinoud */ 83 1.1 reinoud 84 1.1 reinoud static struct vidc_state vidc_lookup = { 85 1.1 reinoud { 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, 86 1.1 reinoud 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, 87 1.1 reinoud 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, 88 1.1 reinoud 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, 89 1.1 reinoud 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, 90 1.1 reinoud 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, 91 1.1 reinoud 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, 92 1.1 reinoud 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 93 1.1 reinoud }, 94 1.1 reinoud 95 1.1 reinoud VIDC_PALREG, 96 1.1 reinoud VIDC_BCOL, 97 1.1 reinoud VIDC_CP1 , 98 1.1 reinoud VIDC_CP2, 99 1.1 reinoud VIDC_CP3, 100 1.1 reinoud VIDC_HCR, 101 1.1 reinoud VIDC_HSWR, 102 1.1 reinoud VIDC_HBSR, 103 1.1 reinoud VIDC_HDSR, 104 1.1 reinoud VIDC_HDER, 105 1.1 reinoud VIDC_HBER, 106 1.1 reinoud VIDC_HCSR, 107 1.1 reinoud VIDC_HIR, 108 1.1 reinoud VIDC_VCR, 109 1.1 reinoud VIDC_VSWR, 110 1.1 reinoud VIDC_VBSR, 111 1.1 reinoud VIDC_VDSR, 112 1.1 reinoud VIDC_VDER, 113 1.1 reinoud VIDC_VBER, 114 1.1 reinoud VIDC_VCSR, 115 1.1 reinoud VIDC_VCER, 116 1.1 reinoud VIDC_EREG, 117 1.1 reinoud VIDC_FSYNREG, 118 1.1 reinoud VIDC_CONREG, 119 1.1 reinoud VIDC_DCTL 120 1.1 reinoud }; 121 1.1 reinoud 122 1.1 reinoud struct vidc_state vidc_current[1]; 123 1.1 reinoud 124 1.1 reinoud 125 1.1 reinoud /* 126 1.1 reinoud * XXX global display variables XXX ... should be a structure 127 1.1 reinoud */ 128 1.1 reinoud static int cold_init = 0; /* flags initialisation */ 129 1.1 reinoud extern videomemory_t videomemory; 130 1.1 reinoud 131 1.25 bjh21 static struct vidc_mode vidc_currentmode; 132 1.1 reinoud 133 1.1 reinoud unsigned int dispstart; 134 1.1 reinoud unsigned int dispsize; 135 1.1 reinoud unsigned int dispbase; 136 1.1 reinoud unsigned int dispend; 137 1.1 reinoud unsigned int ptov; 138 1.1 reinoud unsigned int vmem_base; 139 1.1 reinoud unsigned int phys_base; 140 1.1 reinoud unsigned int transfersize; 141 1.1 reinoud 142 1.1 reinoud 143 1.1 reinoud /* cursor stuff */ 144 1.1 reinoud char *cursor_normal; 145 1.1 reinoud char *cursor_transparent; 146 1.9 reinoud int p_cursor_normal; 147 1.9 reinoud int p_cursor_transparent; 148 1.9 reinoud int cursor_width; 149 1.9 reinoud int cursor_height; 150 1.1 reinoud 151 1.1 reinoud 152 1.1 reinoud /* 153 1.1 reinoud * VIDC mode definitions 154 1.1 reinoud * generated from RISC OS mode definition file by an `awk' script 155 1.1 reinoud */ 156 1.25 bjh21 extern const struct videomode vidc_videomode_list[]; 157 1.25 bjh21 extern const int vidc_videomode_count; 158 1.1 reinoud 159 1.1 reinoud 160 1.1 reinoud /* 161 1.1 reinoud * configuration printing 162 1.1 reinoud * 163 1.1 reinoud */ 164 1.1 reinoud 165 1.1 reinoud void 166 1.1 reinoud vidcvideo_printdetails(void) 167 1.1 reinoud { 168 1.1 reinoud printf(": refclk=%dMHz %dKB %s ", (vidc_fref / 1000000), 169 1.1 reinoud videomemory.vidm_size / 1024, 170 1.1 reinoud (videomemory.vidm_type == VIDEOMEM_TYPE_VRAM) ? "VRAM" : "DRAM"); 171 1.1 reinoud } 172 1.1 reinoud 173 1.9 reinoud 174 1.1 reinoud /* 175 1.1 reinoud * Common functions to directly access VIDC registers 176 1.1 reinoud */ 177 1.1 reinoud int 178 1.21 bjh21 vidcvideo_write(u_int reg, int value) 179 1.1 reinoud { 180 1.1 reinoud int counter; 181 1.1 reinoud 182 1.1 reinoud int *current; 183 1.1 reinoud int *tab; 184 1.1 reinoud 185 1.1 reinoud tab = (int *)&vidc_lookup; 186 1.1 reinoud current = (int *)vidc_current; 187 1.1 reinoud 188 1.1 reinoud 189 1.1 reinoud /* 190 1.1 reinoud * OK, the VIDC_PALETTE register is handled differently 191 1.1 reinoud * to the others on the VIDC, so take that into account here 192 1.1 reinoud */ 193 1.21 bjh21 if (reg == VIDC_PALREG) { 194 1.1 reinoud vidc_current->palreg = 0; 195 1.1 reinoud WriteWord(vidc_base, reg | value); 196 1.1 reinoud return 0; 197 1.1 reinoud } 198 1.1 reinoud 199 1.21 bjh21 if (reg == VIDC_PALETTE) { 200 1.1 reinoud WriteWord(vidc_base, reg | value); 201 1.1 reinoud vidc_current->palette[vidc_current->palreg] = value; 202 1.1 reinoud vidc_current->palreg++; 203 1.1 reinoud vidc_current->palreg = vidc_current->palreg & 0xff; 204 1.1 reinoud return 0; 205 1.1 reinoud } 206 1.1 reinoud 207 1.1 reinoud /* 208 1.1 reinoud * Undefine SAFER if you wish to speed things up (a little) 209 1.37 andvar * although this means the function will assume things about 210 1.1 reinoud * the structure of vidc_state. i.e. the first 256 words are 211 1.1 reinoud * the palette array 212 1.1 reinoud */ 213 1.1 reinoud 214 1.1 reinoud #define SAFER 215 1.1 reinoud 216 1.1 reinoud #ifdef SAFER 217 1.1 reinoud #define INITVALUE 0 218 1.1 reinoud #else 219 1.1 reinoud #define INITVALUE 256 220 1.1 reinoud #endif 221 1.1 reinoud 222 1.21 bjh21 for (counter = INITVALUE; 223 1.21 bjh21 counter <= sizeof(struct vidc_state); 224 1.21 bjh21 counter++) { 225 1.21 bjh21 if (reg == tab[counter]) { 226 1.1 reinoud WriteWord ( vidc_base, reg | value ); 227 1.1 reinoud current[counter] = value; 228 1.1 reinoud return 0; 229 1.1 reinoud } 230 1.1 reinoud } 231 1.1 reinoud return -1; 232 1.1 reinoud } 233 1.1 reinoud 234 1.1 reinoud 235 1.1 reinoud void 236 1.21 bjh21 vidcvideo_setpalette(struct vidc_state *vidc) 237 1.1 reinoud { 238 1.1 reinoud int counter = 0; 239 1.1 reinoud 240 1.1 reinoud vidcvideo_write(VIDC_PALREG, 0x00000000); 241 1.15 reinoud for (counter = 0; counter <= 255; counter++) 242 1.1 reinoud vidcvideo_write(VIDC_PALETTE, vidc->palette[counter]); 243 1.1 reinoud } 244 1.1 reinoud 245 1.1 reinoud 246 1.1 reinoud void 247 1.21 bjh21 vidcvideo_setstate(struct vidc_state *vidc) 248 1.1 reinoud { 249 1.9 reinoud vidcvideo_write ( VIDC_PALREG, vidc->palreg ); 250 1.1 reinoud vidcvideo_write ( VIDC_BCOL, vidc->bcol ); 251 1.1 reinoud vidcvideo_write ( VIDC_CP1, vidc->cp1 ); 252 1.1 reinoud vidcvideo_write ( VIDC_CP2, vidc->cp2 ); 253 1.1 reinoud vidcvideo_write ( VIDC_CP3, vidc->cp3 ); 254 1.1 reinoud vidcvideo_write ( VIDC_HCR, vidc->hcr ); 255 1.1 reinoud vidcvideo_write ( VIDC_HSWR, vidc->hswr ); 256 1.1 reinoud vidcvideo_write ( VIDC_HBSR, vidc->hbsr ); 257 1.1 reinoud vidcvideo_write ( VIDC_HDSR, vidc->hdsr ); 258 1.1 reinoud vidcvideo_write ( VIDC_HDER, vidc->hder ); 259 1.1 reinoud vidcvideo_write ( VIDC_HBER, vidc->hber ); 260 1.1 reinoud vidcvideo_write ( VIDC_HCSR, vidc->hcsr ); 261 1.1 reinoud vidcvideo_write ( VIDC_HIR, vidc->hir ); 262 1.1 reinoud vidcvideo_write ( VIDC_VCR, vidc->vcr ); 263 1.1 reinoud vidcvideo_write ( VIDC_VSWR, vidc->vswr ); 264 1.1 reinoud vidcvideo_write ( VIDC_VBSR, vidc->vbsr ); 265 1.1 reinoud vidcvideo_write ( VIDC_VDSR, vidc->vdsr ); 266 1.1 reinoud vidcvideo_write ( VIDC_VDER, vidc->vder ); 267 1.1 reinoud vidcvideo_write ( VIDC_VBER, vidc->vber ); 268 1.1 reinoud vidcvideo_write ( VIDC_VCSR, vidc->vcsr ); 269 1.1 reinoud vidcvideo_write ( VIDC_VCER, vidc->vcer ); 270 1.1 reinoud /* 271 1.1 reinoud * Right, dunno what to set these to yet, but let's keep RiscOS's 272 1.1 reinoud * ones for now, until the time is right to finish this code 273 1.1 reinoud */ 274 1.1 reinoud 275 1.1 reinoud /* vidcvideo_write ( VIDC_EREG, vidc->ereg ); */ 276 1.1 reinoud /* vidcvideo_write ( VIDC_FSYNREG, vidc->fsynreg ); */ 277 1.1 reinoud /* vidcvideo_write ( VIDC_CONREG, vidc->conreg ); */ 278 1.1 reinoud /* vidcvideo_write ( VIDC_DCTL, vidc->dctl ); */ 279 1.1 reinoud 280 1.15 reinoud vidcvideo_setpalette(vidc); 281 1.1 reinoud } 282 1.1 reinoud 283 1.1 reinoud 284 1.1 reinoud void 285 1.21 bjh21 vidcvideo_getstate(struct vidc_state *vidc) 286 1.1 reinoud { 287 1.21 bjh21 288 1.1 reinoud *vidc = *vidc_current; 289 1.1 reinoud } 290 1.1 reinoud 291 1.1 reinoud 292 1.1 reinoud void 293 1.21 bjh21 vidcvideo_getmode(struct vidc_mode *mode) 294 1.1 reinoud { 295 1.21 bjh21 296 1.25 bjh21 *mode = vidc_currentmode; 297 1.1 reinoud } 298 1.1 reinoud 299 1.1 reinoud 300 1.1 reinoud static int 301 1.1 reinoud vidcvideo_coldinit(void) 302 1.1 reinoud { 303 1.26 bjh21 struct videomode const *modes; 304 1.27 bjh21 unsigned besterror; 305 1.26 bjh21 int count; 306 1.23 bjh21 int i; 307 1.24 bjh21 unsigned framerate; 308 1.1 reinoud 309 1.1 reinoud /* Blank out the cursor */ 310 1.1 reinoud 311 1.1 reinoud vidcvideo_write(VIDC_CP1, 0x0); 312 1.1 reinoud vidcvideo_write(VIDC_CP2, 0x0); 313 1.1 reinoud vidcvideo_write(VIDC_CP3, 0x0); 314 1.1 reinoud 315 1.1 reinoud dispbase = vmem_base = dispstart = videomemory.vidm_vbase; 316 1.1 reinoud phys_base = videomemory.vidm_pbase; 317 1.1 reinoud 318 1.1 reinoud /* Nut - should be using videomemory.vidm_size - mark */ 319 1.1 reinoud if (videomemory.vidm_type == VIDEOMEM_TYPE_DRAM) { 320 1.1 reinoud dispsize = videomemory.vidm_size; 321 1.1 reinoud transfersize = 16; 322 1.1 reinoud } else { 323 1.16 thorpej dispsize = bootconfig.vram[0].pages * PAGE_SIZE; 324 1.1 reinoud transfersize = dispsize >> 10; 325 1.21 bjh21 } 326 1.1 reinoud 327 1.1 reinoud ptov = dispbase - phys_base; 328 1.1 reinoud 329 1.1 reinoud dispend = dispstart+dispsize; 330 1.1 reinoud 331 1.26 bjh21 if (vidc_videomode_count > 0) { 332 1.26 bjh21 modes = vidc_videomode_list; 333 1.26 bjh21 count = vidc_videomode_count; 334 1.26 bjh21 } else { 335 1.26 bjh21 modes = videomode_list; 336 1.26 bjh21 count = videomode_count; 337 1.26 bjh21 } 338 1.26 bjh21 339 1.1 reinoud /* try to find the current mode from the bootloader in my table */ 340 1.26 bjh21 vidc_currentmode.timings = modes[0]; 341 1.27 bjh21 besterror = 1000000; 342 1.26 bjh21 for (i = 0; i < count; i++) { 343 1.28 bjh21 /* We don't support interlace or doublescan */ 344 1.28 bjh21 if (modes[i].flags & (VID_INTERLACE | VID_DBLSCAN)) 345 1.28 bjh21 continue; 346 1.24 bjh21 /* 347 1.24 bjh21 * We jump through a few hoops here to ensure that we 348 1.24 bjh21 * round roughly to the nearest integer without too 349 1.24 bjh21 * much danger of overflow. 350 1.24 bjh21 */ 351 1.26 bjh21 framerate = (modes[i].dot_clock * 1000 / 352 1.26 bjh21 modes[i].htotal * 2 / modes[i].vtotal + 1) / 2; 353 1.26 bjh21 if (modes[i].hdisplay == bootconfig.width + 1 354 1.26 bjh21 && modes[i].vdisplay == bootconfig.height + 1 355 1.27 bjh21 && abs(framerate - bootconfig.framerate) < besterror) { 356 1.26 bjh21 vidc_currentmode.timings = modes[i]; 357 1.27 bjh21 besterror = abs(framerate - bootconfig.framerate); 358 1.1 reinoud } 359 1.1 reinoud } 360 1.1 reinoud 361 1.25 bjh21 vidc_currentmode.log2_bpp = bootconfig.log2_bpp; 362 1.1 reinoud 363 1.1 reinoud dispstart = dispbase; 364 1.1 reinoud dispend = dispstart+dispsize; 365 1.1 reinoud 366 1.1 reinoud IOMD_WRITE_WORD(IOMD_VIDINIT, dispstart-ptov); 367 1.1 reinoud IOMD_WRITE_WORD(IOMD_VIDSTART, dispstart-ptov); 368 1.1 reinoud IOMD_WRITE_WORD(IOMD_VIDEND, (dispend-transfersize)-ptov); 369 1.1 reinoud return 0; 370 1.1 reinoud } 371 1.1 reinoud 372 1.1 reinoud 373 1.1 reinoud /* simple function to abstract vidc variables ; returns virt start address of screen */ 374 1.35 andvar /* XXX assumption that video memory is mapped in twice */ 375 1.21 bjh21 void *vidcvideo_hwscroll(int bytes) 376 1.21 bjh21 { 377 1.21 bjh21 378 1.1 reinoud dispstart += bytes; 379 1.1 reinoud if (dispstart >= dispbase + dispsize) dispstart -= dispsize; 380 1.1 reinoud if (dispstart < dispbase) dispstart += dispsize; 381 1.1 reinoud dispend = dispstart+dispsize; 382 1.1 reinoud 383 1.1 reinoud /* return the start of the bit map of the screen (left top) */ 384 1.21 bjh21 return (void *)dispstart; 385 1.1 reinoud } 386 1.1 reinoud 387 1.1 reinoud 388 1.1 reinoud /* reset the HW scroll to be at the start for the benefit of f.e. X */ 389 1.21 bjh21 void *vidcvideo_hwscroll_reset(void) 390 1.21 bjh21 { 391 1.21 bjh21 void *cookie = (void *)dispstart; 392 1.1 reinoud 393 1.1 reinoud dispstart = dispbase; 394 1.1 reinoud dispend = dispstart + dispsize; 395 1.1 reinoud return cookie; 396 1.1 reinoud } 397 1.1 reinoud 398 1.1 reinoud 399 1.1 reinoud /* put HW scroll back to where it was */ 400 1.21 bjh21 void *vidcvideo_hwscroll_back(void *cookie) 401 1.21 bjh21 { 402 1.21 bjh21 403 1.21 bjh21 dispstart = (int)cookie; 404 1.1 reinoud dispend = dispstart + dispsize; 405 1.1 reinoud return cookie; 406 1.1 reinoud } 407 1.1 reinoud 408 1.1 reinoud 409 1.36 andvar /* this function is to be called preferably at vsync */ 410 1.21 bjh21 void vidcvideo_progr_scroll(void) 411 1.21 bjh21 { 412 1.21 bjh21 413 1.1 reinoud IOMD_WRITE_WORD(IOMD_VIDINIT, dispstart-ptov); 414 1.1 reinoud IOMD_WRITE_WORD(IOMD_VIDSTART, dispstart-ptov); 415 1.1 reinoud IOMD_WRITE_WORD(IOMD_VIDEND, (dispend-transfersize)-ptov); 416 1.1 reinoud } 417 1.1 reinoud 418 1.1 reinoud 419 1.1 reinoud /* 420 1.1 reinoud * Select a new mode by reprogramming the VIDC chip 421 1.1 reinoud * XXX this part is known not to work for 32bpp 422 1.1 reinoud */ 423 1.1 reinoud 424 1.1 reinoud struct vidc_mode newmode; 425 1.1 reinoud 426 1.1 reinoud static const int bpp_mask_table[] = { 427 1.1 reinoud 0, /* 1bpp */ 428 1.1 reinoud 1, /* 2bpp */ 429 1.1 reinoud 2, /* 4bpp */ 430 1.1 reinoud 3, /* 8bpp */ 431 1.1 reinoud 4, /* 16bpp */ 432 1.1 reinoud 6 /* 32bpp */ 433 1.1 reinoud }; 434 1.1 reinoud 435 1.1 reinoud 436 1.1 reinoud void 437 1.1 reinoud vidcvideo_setmode(struct vidc_mode *mode) 438 1.1 reinoud { 439 1.23 bjh21 struct videomode *vm; 440 1.1 reinoud int bpp_mask; 441 1.1 reinoud int ereg; 442 1.5 bjh21 int best_r, best_v; 443 1.5 bjh21 int least_error; 444 1.5 bjh21 int r, v, f; 445 1.1 reinoud 446 1.1 reinoud /* 447 1.21 bjh21 * Find out what bit mask we need to or with the vidc20 448 1.21 bjh21 * control register in order to generate the desired number of 449 1.21 bjh21 * bits per pixel. log_bpp is log base 2 of the number of 450 1.21 bjh21 * bits per pixel. 451 1.1 reinoud */ 452 1.1 reinoud 453 1.1 reinoud bpp_mask = bpp_mask_table[mode->log2_bpp]; 454 1.1 reinoud 455 1.25 bjh21 vidc_currentmode = *mode; 456 1.25 bjh21 vm = &vidc_currentmode.timings; 457 1.1 reinoud 458 1.5 bjh21 least_error = INT_MAX; 459 1.5 bjh21 best_r = 0; best_v = 0; 460 1.5 bjh21 461 1.5 bjh21 for (v = 63; v > 0; v--) { 462 1.5 bjh21 for (r = 63; r > 0; r--) { 463 1.5 bjh21 f = ((v * vidc_fref) /1000) / r; 464 1.23 bjh21 if (least_error >= abs(f - vm->dot_clock)) { 465 1.23 bjh21 least_error = abs(f - vm->dot_clock); 466 1.5 bjh21 best_r = r; 467 1.5 bjh21 best_v = v; 468 1.1 reinoud } 469 1.1 reinoud } 470 1.5 bjh21 } 471 1.1 reinoud 472 1.5 bjh21 if (best_r > 63) best_r=63; 473 1.5 bjh21 if (best_v > 63) best_v=63; 474 1.5 bjh21 if (best_r < 1) best_r= 1; 475 1.5 bjh21 if (best_v < 1) best_v= 1; 476 1.1 reinoud 477 1.2 reinoud vidcvideo_write(VIDC_FSYNREG, (best_v-1)<<8 | (best_r-1)<<0); 478 1.1 reinoud 479 1.23 bjh21 /* 480 1.23 bjh21 * The translation from struct videomode to VIDC timings is made 481 1.23 bjh21 * fun by the fact that the VIDC counts from the start of the sync 482 1.23 bjh21 * pulse while struct videomode counts from the start of the display. 483 1.23 bjh21 */ 484 1.23 bjh21 vidcvideo_write(VIDC_HSWR, (vm->hsync_end - vm->hsync_start - 8) & ~1); 485 1.23 bjh21 vidcvideo_write(VIDC_HBSR, (vm->htotal - vm->hsync_start - 12) & ~1); 486 1.23 bjh21 vidcvideo_write(VIDC_HDSR, (vm->htotal - vm->hsync_start - 18) & ~1); 487 1.23 bjh21 vidcvideo_write(VIDC_HDER, 488 1.23 bjh21 (vm->htotal - vm->hsync_start + vm->hdisplay - 18) & ~1); 489 1.23 bjh21 vidcvideo_write(VIDC_HBER, 490 1.23 bjh21 (vm->htotal - vm->hsync_start + vm->hdisplay - 12) & ~1); 491 1.23 bjh21 vidcvideo_write(VIDC_HCR, (vm->htotal - 8) & ~3); 492 1.23 bjh21 493 1.23 bjh21 vidcvideo_write(VIDC_VSWR, vm->vsync_end - vm->vsync_start - 1); 494 1.23 bjh21 vidcvideo_write(VIDC_VBSR, vm->vtotal - vm->vsync_start - 1); 495 1.23 bjh21 vidcvideo_write(VIDC_VDSR, vm->vtotal - vm->vsync_start - 1); 496 1.23 bjh21 vidcvideo_write(VIDC_VDER, 497 1.23 bjh21 vm->vtotal - vm->vsync_start + vm->vdisplay - 1); 498 1.23 bjh21 vidcvideo_write(VIDC_VBER, 499 1.23 bjh21 vm->vtotal - vm->vsync_start + vm->vdisplay - 1); 500 1.23 bjh21 /* XXX VIDC20 data sheet say to subtract 2 */ 501 1.23 bjh21 vidcvideo_write(VIDC_VCR, vm->vtotal - 1); 502 1.23 bjh21 503 1.29 bjh21 IOMD_WRITE_WORD(IOMD_FSIZE, vm->vtotal - vm->vdisplay - 1); 504 1.1 reinoud 505 1.1 reinoud if (dispsize <= 1024*1024) 506 1.23 bjh21 vidcvideo_write(VIDC_DCTL, vm->hdisplay>>2 | 1<<16 | 1<<12); 507 1.1 reinoud else 508 1.23 bjh21 vidcvideo_write(VIDC_DCTL, vm->hdisplay>>2 | 3<<16 | 1<<12); 509 1.1 reinoud 510 1.1 reinoud ereg = 1<<12; 511 1.23 bjh21 if (vm->flags & VID_NHSYNC) 512 1.1 reinoud ereg |= 1<<16; 513 1.23 bjh21 if (vm->flags & VID_NVSYNC) 514 1.1 reinoud ereg |= 1<<18; 515 1.1 reinoud vidcvideo_write(VIDC_EREG, ereg); 516 1.30 bjh21 517 1.30 bjh21 /* 518 1.30 bjh21 * Set the video FIFO preload value and bit depth. Chapter 6 519 1.30 bjh21 * of the VIDC20 Data Sheet has full details of the FIFO 520 1.30 bjh21 * preload, but we don't do anything clever and just use the 521 1.30 bjh21 * largest possible value, which is 7 when the VIDC20 is in 522 1.30 bjh21 * 32-bit mode (0MB or 1MB VRAM) and 6 when it is in 64-bit 523 1.30 bjh21 * mode (2MB VRAM). 524 1.30 bjh21 */ 525 1.30 bjh21 if (dispsize > 1024*1024) 526 1.30 bjh21 vidcvideo_write(VIDC_CONREG, 6<<8 | bpp_mask<<5); 527 1.30 bjh21 else 528 1.1 reinoud vidcvideo_write(VIDC_CONREG, 7<<8 | bpp_mask<<5); 529 1.1 reinoud } 530 1.1 reinoud 531 1.1 reinoud 532 1.7 bjh21 #if 0 533 1.1 reinoud /* not used for now */ 534 1.1 reinoud void 535 1.31 dsl vidcvideo_set_display_base(u_int base) 536 1.1 reinoud { 537 1.1 reinoud dispstart = dispstart-dispbase + base; 538 1.1 reinoud dispbase = vmem_base = base; 539 1.1 reinoud dispend = base + dispsize; 540 1.1 reinoud ptov = dispbase - phys_base; 541 1.1 reinoud } 542 1.7 bjh21 #endif 543 1.1 reinoud 544 1.1 reinoud 545 1.1 reinoud /* 546 1.1 reinoud * Main initialisation routine for now 547 1.1 reinoud */ 548 1.1 reinoud 549 1.1 reinoud static int cursor_init = 0; 550 1.1 reinoud 551 1.1 reinoud int 552 1.1 reinoud vidcvideo_init(void) 553 1.1 reinoud { 554 1.1 reinoud vidcvideo_coldinit(); 555 1.1 reinoud if (cold_init && (cursor_init == 0)) 556 1.1 reinoud /* vidcvideo_flash_go() */; 557 1.1 reinoud 558 1.1 reinoud /* setting a mode goes wrong in 32 bpp ... 8 and 16 seem OK */ 559 1.25 bjh21 vidcvideo_setmode(&vidc_currentmode); 560 1.1 reinoud vidcvideo_blank(0); /* display on */ 561 1.1 reinoud 562 1.12 bjh21 vidcvideo_stdpalette(); 563 1.1 reinoud 564 1.1 reinoud if (cold_init == 0) { 565 1.1 reinoud vidcvideo_write(VIDC_CP1, 0x0); 566 1.1 reinoud vidcvideo_write(VIDC_CP2, 0x0); 567 1.1 reinoud vidcvideo_write(VIDC_CP3, 0x0); 568 1.21 bjh21 } else 569 1.1 reinoud vidcvideo_cursor_init(CURSOR_MAX_WIDTH, CURSOR_MAX_HEIGHT); 570 1.1 reinoud 571 1.21 bjh21 cold_init = 1; 572 1.1 reinoud return 0; 573 1.1 reinoud } 574 1.1 reinoud 575 1.1 reinoud 576 1.1 reinoud /* reinitialise the vidcvideo */ 577 1.1 reinoud void 578 1.32 cegger vidcvideo_reinit(void) 579 1.1 reinoud { 580 1.21 bjh21 581 1.1 reinoud vidcvideo_coldinit(); 582 1.25 bjh21 vidcvideo_setmode(&vidc_currentmode); 583 1.1 reinoud } 584 1.1 reinoud 585 1.1 reinoud 586 1.1 reinoud int 587 1.1 reinoud vidcvideo_cursor_init(int width, int height) 588 1.1 reinoud { 589 1.1 reinoud static char *cursor_data = NULL; 590 1.1 reinoud int counter; 591 1.1 reinoud int line; 592 1.1 reinoud paddr_t pa; 593 1.1 reinoud 594 1.1 reinoud cursor_width = width; 595 1.1 reinoud cursor_height = height; 596 1.1 reinoud 597 1.1 reinoud if (!cursor_data) { 598 1.1 reinoud /* Allocate cursor memory first time round */ 599 1.19 yamt cursor_data = (char *)uvm_km_alloc(kernel_map, PAGE_SIZE, 0, 600 1.19 yamt UVM_KMF_WIRED | UVM_KMF_ZERO); 601 1.1 reinoud if (!cursor_data) 602 1.14 provos panic("Cannot allocate memory for hardware cursor"); 603 1.1 reinoud (void) pmap_extract(pmap_kernel(), (vaddr_t)cursor_data, &pa); 604 1.1 reinoud IOMD_WRITE_WORD(IOMD_CURSINIT, pa); 605 1.1 reinoud } 606 1.1 reinoud 607 1.33 snj /* Blank the cursor while initialising its sprite */ 608 1.1 reinoud 609 1.1 reinoud vidcvideo_write ( VIDC_CP1, 0x0 ); 610 1.1 reinoud vidcvideo_write ( VIDC_CP2, 0x0 ); 611 1.1 reinoud vidcvideo_write ( VIDC_CP3, 0x0 ); 612 1.1 reinoud 613 1.1 reinoud cursor_normal = cursor_data; 614 1.1 reinoud cursor_transparent = cursor_data + (height * width); 615 1.1 reinoud 616 1.1 reinoud cursor_transparent += 32; /* ALIGN */ 617 1.1 reinoud cursor_transparent = (char *)((int)cursor_transparent & (~31) ); 618 1.1 reinoud 619 1.21 bjh21 for ( line = 0; line<height; ++line ) { 620 1.21 bjh21 for ( counter=0; counter<width/4;counter++ ) 621 1.21 bjh21 cursor_normal[line * width + counter]=0x55; /* why 0x55 ? */ 622 1.21 bjh21 for ( ; counter<8; counter++ ) 623 1.21 bjh21 cursor_normal[line * width + counter]=0; 624 1.1 reinoud } 625 1.1 reinoud 626 1.21 bjh21 for ( line = 0; line<height; ++line ) { 627 1.21 bjh21 for ( counter=0; counter<width/4;counter++ ) 628 1.21 bjh21 cursor_transparent[line * width + counter]=0x00; 629 1.21 bjh21 for ( ; counter<8; counter++ ) 630 1.21 bjh21 cursor_transparent[line * width + counter]=0; 631 1.1 reinoud } 632 1.1 reinoud 633 1.1 reinoud 634 1.1 reinoud (void) pmap_extract(pmap_kernel(), (vaddr_t)cursor_normal, 635 1.17 matt (void *)&p_cursor_normal); 636 1.1 reinoud (void) pmap_extract(pmap_kernel(), (vaddr_t)cursor_transparent, 637 1.17 matt (void *)&p_cursor_transparent); 638 1.1 reinoud 639 1.21 bjh21 memset(cursor_normal, 0x55, width*height); /* white? */ 640 1.21 bjh21 memset(cursor_transparent, 0x00, width*height);/* to see the diffence */ 641 1.1 reinoud 642 1.1 reinoud /* Ok, now program the cursor; should be blank */ 643 1.1 reinoud vidcvideo_enablecursor(0); 644 1.1 reinoud 645 1.1 reinoud return 0; 646 1.1 reinoud } 647 1.1 reinoud 648 1.1 reinoud 649 1.1 reinoud void 650 1.21 bjh21 vidcvideo_updatecursor(int xcur, int ycur) 651 1.1 reinoud { 652 1.25 bjh21 int frontporch = vidc_currentmode.timings.htotal - 653 1.25 bjh21 vidc_currentmode.timings.hsync_start; 654 1.25 bjh21 int topporch = vidc_currentmode.timings.vtotal - 655 1.25 bjh21 vidc_currentmode.timings.vsync_start; 656 1.1 reinoud 657 1.1 reinoud vidcvideo_write(VIDC_HCSR, frontporch -17 + xcur); 658 1.21 bjh21 vidcvideo_write(VIDC_VCSR, topporch -2 + (ycur+1)-2 + 3 - 659 1.21 bjh21 cursor_height); 660 1.1 reinoud vidcvideo_write(VIDC_VCER, topporch -2 + (ycur+3)+2 + 3 ); 661 1.1 reinoud } 662 1.1 reinoud 663 1.1 reinoud 664 1.1 reinoud void 665 1.21 bjh21 vidcvideo_enablecursor(int on) 666 1.1 reinoud { 667 1.21 bjh21 668 1.21 bjh21 if (on) 669 1.1 reinoud IOMD_WRITE_WORD(IOMD_CURSINIT,p_cursor_normal); 670 1.21 bjh21 else 671 1.1 reinoud IOMD_WRITE_WORD(IOMD_CURSINIT,p_cursor_transparent); 672 1.1 reinoud vidcvideo_write ( VIDC_CP1, 0xffffff ); /* enable */ 673 1.1 reinoud } 674 1.1 reinoud 675 1.11 bjh21 676 1.12 bjh21 void 677 1.32 cegger vidcvideo_stdpalette(void) 678 1.11 bjh21 { 679 1.12 bjh21 int i; 680 1.11 bjh21 681 1.25 bjh21 switch (vidc_currentmode.log2_bpp) { 682 1.12 bjh21 case 0: /* 1 bpp */ 683 1.12 bjh21 case 1: /* 2 bpp */ 684 1.12 bjh21 case 2: /* 4 bpp */ 685 1.12 bjh21 case 3: /* 8 bpp */ 686 1.12 bjh21 vidcvideo_write(VIDC_PALREG, 0x00000000); 687 1.12 bjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL( 0, 0, 0)); 688 1.12 bjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL(255, 0, 0)); 689 1.12 bjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL( 0, 255, 0)); 690 1.12 bjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL(255, 255, 0)); 691 1.12 bjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL( 0, 0, 255)); 692 1.12 bjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL(255, 0, 255)); 693 1.12 bjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL( 0, 255, 255)); 694 1.12 bjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL(255, 255, 255)); 695 1.12 bjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL(128, 128, 128)); 696 1.12 bjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL(255, 128, 128)); 697 1.12 bjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL(128, 255, 128)); 698 1.12 bjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL(255, 255, 128)); 699 1.12 bjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL(128, 128, 255)); 700 1.12 bjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL(255, 128, 255)); 701 1.12 bjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL(255, 255, 255)); 702 1.12 bjh21 break; 703 1.12 bjh21 case 4: /* 16 bpp */ 704 1.12 bjh21 /* 705 1.12 bjh21 * The use of the palette in 16-bit modes is quite 706 1.12 bjh21 * fun. Comments in linux/drivers/video/acornfb.c 707 1.12 bjh21 * imply that it goes something like this: 708 1.12 bjh21 * 709 1.12 bjh21 * red = LUT[pixel[7:0]].red 710 1.12 bjh21 * green = LUT[pixel[11:4]].green 711 1.12 bjh21 * blue = LUT[pixel[15:8]].blue 712 1.12 bjh21 * 713 1.13 bjh21 * We use 6:5:5 R:G:B cos that's what Xarm32VIDC wants. 714 1.12 bjh21 */ 715 1.13 bjh21 #define RBITS 6 716 1.13 bjh21 #define GBITS 5 717 1.13 bjh21 #define BBITS 5 718 1.12 bjh21 vidcvideo_write(VIDC_PALREG, 0x00000000); 719 1.12 bjh21 for (i = 0; i < 256; i++) { 720 1.13 bjh21 int r, g, b; 721 1.12 bjh21 722 1.13 bjh21 r = i & ((1 << RBITS) - 1); 723 1.13 bjh21 g = (i >> (RBITS - 4)) & ((1 << GBITS) - 1); 724 1.13 bjh21 b = (i >> (RBITS + GBITS - 8)) & ((1 << BBITS) - 1); 725 1.12 bjh21 vidcvideo_write(VIDC_PALETTE, 726 1.13 bjh21 VIDC_COL(r << (8 - RBITS) | r >> (2 * RBITS - 8), 727 1.13 bjh21 g << (8 - GBITS) | g >> (2 * GBITS - 8), 728 1.13 bjh21 b << (8 - BBITS) | b >> (2 * BBITS - 8))); 729 1.12 bjh21 } 730 1.12 bjh21 break; 731 1.12 bjh21 case 5: /* 32 bpp */ 732 1.12 bjh21 vidcvideo_write(VIDC_PALREG, 0x00000000); 733 1.12 bjh21 for (i = 0; i < 256; i++) 734 1.12 bjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL(i, i, i)); 735 1.12 bjh21 break; 736 1.12 bjh21 } 737 1.11 bjh21 } 738 1.1 reinoud 739 1.1 reinoud int 740 1.21 bjh21 vidcvideo_blank(int video_off) 741 1.1 reinoud { 742 1.1 reinoud int ereg; 743 1.1 reinoud 744 1.1 reinoud ereg = 1<<12; 745 1.25 bjh21 if (vidc_currentmode.timings.flags & VID_NHSYNC) 746 1.1 reinoud ereg |= 1<<16; 747 1.25 bjh21 if (vidc_currentmode.timings.flags & VID_NVSYNC) 748 1.1 reinoud ereg |= 1<<18; 749 1.1 reinoud 750 1.21 bjh21 if (!video_off) 751 1.1 reinoud vidcvideo_write(VIDC_EREG, ereg); 752 1.21 bjh21 else 753 1.1 reinoud vidcvideo_write(VIDC_EREG, 0); 754 1.1 reinoud return 0; 755 1.1 reinoud } 756 1.1 reinoud 757 1.1 reinoud /* end of vidc20config.c */ 758