1 /* $NetBSD: igsfb_subr.c,v 1.6 2006/02/23 08:01:59 macallan Exp $ */ 2 3 /* 4 * Copyright (c) 2002 Valeriy E. Ushakov 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 /* 31 * Integraphics Systems IGA 168x and CyberPro series. 32 */ 33 #include <sys/cdefs.h> 34 __KERNEL_RCSID(0, "$NetBSD: igsfb_subr.c,v 1.6 2006/02/23 08:01:59 macallan Exp $"); 35 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/kernel.h> 39 #include <sys/device.h> 40 41 #include <machine/bus.h> 42 43 #include <dev/wscons/wsdisplayvar.h> 44 #include <dev/wscons/wsconsio.h> 45 #include <dev/rasops/rasops.h> 46 #include <dev/wscons/wsdisplay_vconsvar.h> 47 48 #include <dev/ic/igsfbreg.h> 49 #include <dev/ic/igsfbvar.h> 50 51 52 static void igsfb_init_seq(struct igsfb_devconfig *); 53 static void igsfb_init_crtc(struct igsfb_devconfig *); 54 static void igsfb_init_grfx(struct igsfb_devconfig *); 55 static void igsfb_init_attr(struct igsfb_devconfig *); 56 static void igsfb_init_ext(struct igsfb_devconfig *); 57 static void igsfb_init_dac(struct igsfb_devconfig *); 58 59 static void igsfb_freq_latch(struct igsfb_devconfig *); 60 static void igsfb_video_on(struct igsfb_devconfig *); 61 62 63 64 /* 65 * Enable chip. 66 */ 67 int 68 igsfb_enable(iot, iobase, ioflags) 69 bus_space_tag_t iot; 70 bus_addr_t iobase; 71 int ioflags; 72 { 73 bus_space_handle_t vdoh; 74 bus_space_handle_t vseh; 75 bus_space_handle_t regh; 76 int ret; 77 78 ret = bus_space_map(iot, iobase + IGS_VDO, 1, ioflags, &vdoh); 79 if (ret != 0) { 80 printf("unable to map VDO register\n"); 81 goto out0; 82 } 83 84 ret = bus_space_map(iot, iobase + IGS_VSE, 1, ioflags, &vseh); 85 if (ret != 0) { 86 printf("unable to map VSE register\n"); 87 goto out1; 88 } 89 90 ret = bus_space_map(iot, iobase + IGS_REG_BASE, IGS_REG_SIZE, ioflags, 91 ®h); 92 if (ret != 0) { 93 printf("unable to map I/O registers\n"); 94 goto out2; 95 } 96 97 /* 98 * Start decoding i/o space accesses. 99 */ 100 bus_space_write_1(iot, vdoh, 0, IGS_VDO_ENABLE | IGS_VDO_SETUP); 101 bus_space_write_1(iot, vseh, 0, IGS_VSE_ENABLE); 102 bus_space_write_1(iot, vdoh, 0, IGS_VDO_ENABLE); 103 104 /* 105 * Start decoding memory space accesses (XXX: move out of here? 106 * we program this register in igsfb_init_ext). 107 * While here, enable coprocessor and select IGS_COP_BASE_B. 108 */ 109 igs_ext_write(iot, regh, IGS_EXT_BIU_MISC_CTL, 110 (IGS_EXT_BIU_LINEAREN 111 | IGS_EXT_BIU_COPREN | IGS_EXT_BIU_COPASELB)); 112 113 bus_space_unmap(iot, regh, IGS_REG_SIZE); 114 out2: bus_space_unmap(iot, vseh, 1); 115 out1: bus_space_unmap(iot, vdoh, 1); 116 out0: return (ret); 117 } 118 119 120 /* 121 * Init sequencer. 122 * This is common for all video modes. 123 */ 124 static void 125 igsfb_init_seq(dc) 126 struct igsfb_devconfig *dc; 127 { 128 bus_space_tag_t iot = dc->dc_iot; 129 bus_space_handle_t ioh = dc->dc_ioh; 130 131 /* start messing with sequencer */ 132 igs_seq_write(iot, ioh, IGS_SEQ_RESET, 0); 133 134 igs_seq_write(iot, ioh, 1, 0x01); /* 8 dot clock */ 135 igs_seq_write(iot, ioh, 2, 0x0f); /* enable all maps */ 136 igs_seq_write(iot, ioh, 3, 0x00); /* character generator */ 137 igs_seq_write(iot, ioh, 4, 0x0e); /* memory mode */ 138 139 /* this selects color mode among other things */ 140 bus_space_write_1(iot, ioh, IGS_MISC_OUTPUT_W, 0xef); 141 142 /* normal sequencer operation */ 143 igs_seq_write(iot, ioh, IGS_SEQ_RESET, 144 IGS_SEQ_RESET_SYNC | IGS_SEQ_RESET_ASYNC); 145 } 146 147 /* 148 * Init CRTC to 640x480 8bpp at 60Hz 149 */ 150 static void 151 igsfb_init_crtc(dc) 152 struct igsfb_devconfig *dc; 153 { 154 bus_space_tag_t iot = dc->dc_iot; 155 bus_space_handle_t ioh = dc->dc_ioh; 156 157 igs_crtc_write(iot, ioh, 0x00, 0x5f); 158 igs_crtc_write(iot, ioh, 0x01, 0x4f); 159 igs_crtc_write(iot, ioh, 0x02, 0x50); 160 igs_crtc_write(iot, ioh, 0x03, 0x80); 161 igs_crtc_write(iot, ioh, 0x04, 0x52); 162 igs_crtc_write(iot, ioh, 0x05, 0x9d); 163 igs_crtc_write(iot, ioh, 0x06, 0x0b); 164 igs_crtc_write(iot, ioh, 0x07, 0x3e); 165 166 /* next block is almost constant, only bit 6 in reg 9 differs */ 167 igs_crtc_write(iot, ioh, 0x08, 0x00); 168 igs_crtc_write(iot, ioh, 0x09, 0x40); /* <- either 0x40 or 0x60 */ 169 igs_crtc_write(iot, ioh, 0x0a, 0x00); 170 igs_crtc_write(iot, ioh, 0x0b, 0x00); 171 igs_crtc_write(iot, ioh, 0x0c, 0x00); 172 igs_crtc_write(iot, ioh, 0x0d, 0x00); 173 igs_crtc_write(iot, ioh, 0x0e, 0x00); 174 igs_crtc_write(iot, ioh, 0x0f, 0x00); 175 176 igs_crtc_write(iot, ioh, 0x10, 0xe9); 177 igs_crtc_write(iot, ioh, 0x11, 0x8b); 178 igs_crtc_write(iot, ioh, 0x12, 0xdf); 179 igs_crtc_write(iot, ioh, 0x13, 0x50); 180 igs_crtc_write(iot, ioh, 0x14, 0x00); 181 igs_crtc_write(iot, ioh, 0x15, 0xe6); 182 igs_crtc_write(iot, ioh, 0x16, 0x04); 183 igs_crtc_write(iot, ioh, 0x17, 0xc3); 184 185 igs_crtc_write(iot, ioh, 0x18, 0xff); 186 } 187 188 189 /* 190 * Init graphics controller. 191 * This is common for all video modes. 192 */ 193 static void 194 igsfb_init_grfx(dc) 195 struct igsfb_devconfig *dc; 196 { 197 bus_space_tag_t iot = dc->dc_iot; 198 bus_space_handle_t ioh = dc->dc_ioh; 199 200 igs_grfx_write(iot, ioh, 0, 0x00); 201 igs_grfx_write(iot, ioh, 1, 0x00); 202 igs_grfx_write(iot, ioh, 2, 0x00); 203 igs_grfx_write(iot, ioh, 3, 0x00); 204 igs_grfx_write(iot, ioh, 4, 0x00); 205 igs_grfx_write(iot, ioh, 5, 0x60); /* SRMODE, MODE256 */ 206 igs_grfx_write(iot, ioh, 6, 0x05); /* 64k @ a0000, GRAPHICS */ 207 igs_grfx_write(iot, ioh, 7, 0x0f); /* color compare all */ 208 igs_grfx_write(iot, ioh, 8, 0xff); /* bitmask = all bits mutable */ 209 } 210 211 212 /* 213 * Init attribute controller. 214 * This is common for all video modes. 215 */ 216 static void 217 igsfb_init_attr(dc) 218 struct igsfb_devconfig *dc; 219 { 220 bus_space_tag_t iot = dc->dc_iot; 221 bus_space_handle_t ioh = dc->dc_ioh; 222 int i; 223 224 igs_attr_flip_flop(iot, ioh); /* reset attr flip-flop to address */ 225 226 for (i = 0; i < 16; ++i) /* crt palette */ 227 igs_attr_write(iot, ioh, i, i); 228 229 igs_attr_write(iot, ioh, 0x10, 0x01); /* select graphic mode */ 230 igs_attr_write(iot, ioh, 0x11, 0x00); /* crt overscan color */ 231 igs_attr_write(iot, ioh, 0x12, 0x0f); /* color plane enable */ 232 igs_attr_write(iot, ioh, 0x13, 0x00); 233 igs_attr_write(iot, ioh, 0x14, 0x00); 234 } 235 236 237 /* 238 * When done with ATTR controller, call this to unblank the screen. 239 */ 240 static void 241 igsfb_video_on(dc) 242 struct igsfb_devconfig *dc; 243 { 244 bus_space_tag_t iot = dc->dc_iot; 245 bus_space_handle_t ioh = dc->dc_ioh; 246 247 igs_attr_flip_flop(iot, ioh); 248 bus_space_write_1(iot, ioh, IGS_ATTR_IDX, 0x20); 249 bus_space_write_1(iot, ioh, IGS_ATTR_IDX, 0x20); 250 } 251 252 253 /* 254 * Latch VCLK (b0/b1) and MCLK (b2/b3) values. 255 */ 256 static void 257 igsfb_freq_latch(dc) 258 struct igsfb_devconfig *dc; 259 { 260 bus_space_tag_t iot = dc->dc_iot; 261 bus_space_handle_t ioh = dc->dc_ioh; 262 263 bus_space_write_1(iot, ioh, IGS_EXT_IDX, 0xb9); 264 bus_space_write_1(iot, ioh, IGS_EXT_PORT, 0x80); 265 bus_space_write_1(iot, ioh, IGS_EXT_PORT, 0x00); 266 } 267 268 269 static void 270 igsfb_init_ext(dc) 271 struct igsfb_devconfig *dc; 272 { 273 bus_space_tag_t iot = dc->dc_iot; 274 bus_space_handle_t ioh = dc->dc_ioh; 275 int is_cyberpro = (dc->dc_id >= 0x2000); 276 277 igs_ext_write(iot, ioh, 0x10, 0x10); /* IGS_EXT_START_ADDR enable */ 278 igs_ext_write(iot, ioh, 0x12, 0x00); /* IGS_EXT_IRQ_CTL disable */ 279 igs_ext_write(iot, ioh, 0x13, 0x00); /* MBZ for normal operation */ 280 281 igs_ext_write(iot, ioh, 0x31, 0x00); /* segment write ptr */ 282 igs_ext_write(iot, ioh, 0x32, 0x00); /* segment read ptr */ 283 284 /* IGS_EXT_BIU_MISC_CTL: linearen, copren, copaselb, segon */ 285 igs_ext_write(iot, ioh, 0x33, 0x1d); 286 287 /* sprite location */ 288 igs_ext_write(iot, ioh, 0x50, 0x00); 289 igs_ext_write(iot, ioh, 0x51, 0x00); 290 igs_ext_write(iot, ioh, 0x52, 0x00); 291 igs_ext_write(iot, ioh, 0x53, 0x00); 292 igs_ext_write(iot, ioh, 0x54, 0x00); 293 igs_ext_write(iot, ioh, 0x55, 0x00); 294 igs_ext_write(iot, ioh, 0x56, 0x00); /* sprite control */ 295 296 /* IGS_EXT_GRFX_MODE */ 297 igs_ext_write(iot, ioh, 0x57, 0x01); /* raster fb */ 298 299 /* overscan R/G/B */ 300 igs_ext_write(iot, ioh, 0x58, 0x00); 301 igs_ext_write(iot, ioh, 0x59, 0x00); 302 igs_ext_write(iot, ioh, 0x5A, 0x00); 303 304 /* 305 * Video memory size &c. We rely on firmware to program 306 * BUS_CTL(30), MEM_CTL1(71), MEM_CTL2(72) appropriately. 307 */ 308 309 /* ext memory ctl0 */ 310 igs_ext_write(iot, ioh, 0x70, 0x0B); /* enable fifo, seq */ 311 312 /* ext hidden ctl1 */ 313 igs_ext_write(iot, ioh, 0x73, 0x30); /* XXX: krups: 0x20 */ 314 315 /* ext fifo control */ 316 igs_ext_write(iot, ioh, 0x74, 0x10); /* XXX: krups: 0x1b */ 317 igs_ext_write(iot, ioh, 0x75, 0x10); /* XXX: krups: 0x1e */ 318 319 igs_ext_write(iot, ioh, 0x76, 0x00); /* ext seq. */ 320 igs_ext_write(iot, ioh, 0x7A, 0xC8); /* ext. hidden ctl */ 321 322 /* ext graphics ctl: GCEXTPATH. krups 1, nettrom 1, docs 3 */ 323 igs_ext_write(iot, ioh, 0x90, 0x01); 324 325 if (is_cyberpro) /* select normal vclk/mclk registers */ 326 igs_ext_write(iot, ioh, 0xBF, 0x00); 327 328 igs_ext_write(iot, ioh, 0xB0, 0xD2); /* VCLK = 25.175MHz */ 329 igs_ext_write(iot, ioh, 0xB1, 0xD3); 330 igs_ext_write(iot, ioh, 0xB2, 0xDB); /* MCLK = 75MHz*/ 331 igs_ext_write(iot, ioh, 0xB3, 0x54); 332 igsfb_freq_latch(dc); 333 334 if (is_cyberpro) 335 igs_ext_write(iot, ioh, 0xF8, 0x04); /* XXX: ??? */ 336 337 /* 640x480 8bpp at 60Hz */ 338 igs_ext_write(iot, ioh, 0x11, 0x00); 339 igs_ext_write(iot, ioh, 0x77, 0x01); /* 8bpp, indexed */ 340 igs_ext_write(iot, ioh, 0x14, 0x51); 341 igs_ext_write(iot, ioh, 0x15, 0x00); 342 } 343 344 345 static void 346 igsfb_init_dac(dc) 347 struct igsfb_devconfig *dc; 348 { 349 bus_space_tag_t iot = dc->dc_iot; 350 bus_space_handle_t ioh = dc->dc_ioh; 351 uint8_t reg; 352 353 /* RAMDAC address 2 select */ 354 reg = igs_ext_read(iot, ioh, IGS_EXT_SPRITE_CTL); 355 igs_ext_write(iot, ioh, IGS_EXT_SPRITE_CTL, 356 reg | IGS_EXT_SPRITE_DAC_PEL); 357 358 /* VREFEN, DAC8 */ 359 bus_space_write_1(iot, ioh, IGS_DAC_CMD, 0x06); 360 361 /* restore */ 362 igs_ext_write(iot, ioh, IGS_EXT_SPRITE_CTL, reg); 363 364 bus_space_write_1(iot, ioh, IGS_PEL_MASK, 0xff); 365 } 366 367 368 void 369 igsfb_1024x768_8bpp_60Hz(dc) 370 struct igsfb_devconfig *dc; 371 { 372 bus_space_tag_t iot = dc->dc_iot; 373 bus_space_handle_t ioh = dc->dc_ioh; 374 375 igs_crtc_write(iot, ioh, 0x11, 0x00); /* write enable CRTC 0..7 */ 376 377 igs_crtc_write(iot, ioh, 0x00, 0xa3); 378 igs_crtc_write(iot, ioh, 0x01, 0x7f); 379 igs_crtc_write(iot, ioh, 0x02, 0x7f); /* krups: 80 */ 380 igs_crtc_write(iot, ioh, 0x03, 0x85); /* krups: 84 */ 381 igs_crtc_write(iot, ioh, 0x04, 0x84); /* krups: 88 */ 382 igs_crtc_write(iot, ioh, 0x05, 0x95); /* krups: 99 */ 383 igs_crtc_write(iot, ioh, 0x06, 0x24); 384 igs_crtc_write(iot, ioh, 0x07, 0xfd); 385 386 /* next block is almost constant, only bit 6 in reg 9 differs */ 387 igs_crtc_write(iot, ioh, 0x08, 0x00); 388 igs_crtc_write(iot, ioh, 0x09, 0x60); /* <- either 0x40 or 0x60 */ 389 igs_crtc_write(iot, ioh, 0x0a, 0x00); 390 igs_crtc_write(iot, ioh, 0x0b, 0x00); 391 igs_crtc_write(iot, ioh, 0x0c, 0x00); 392 igs_crtc_write(iot, ioh, 0x0d, 0x00); 393 igs_crtc_write(iot, ioh, 0x0e, 0x00); 394 igs_crtc_write(iot, ioh, 0x0f, 0x00); 395 396 igs_crtc_write(iot, ioh, 0x10, 0x06); 397 igs_crtc_write(iot, ioh, 0x11, 0x8c); 398 igs_crtc_write(iot, ioh, 0x12, 0xff); 399 igs_crtc_write(iot, ioh, 0x13, 0x80); /* depends on BPP */ 400 igs_crtc_write(iot, ioh, 0x14, 0x0f); 401 igs_crtc_write(iot, ioh, 0x15, 0x02); 402 igs_crtc_write(iot, ioh, 0x16, 0x21); 403 igs_crtc_write(iot, ioh, 0x17, 0xe3); 404 igs_crtc_write(iot, ioh, 0x18, 0xff); 405 406 igs_ext_write(iot, ioh, 0xB0, 0xE2); /* VCLK */ 407 igs_ext_write(iot, ioh, 0xB1, 0x58); 408 #if 1 409 /* XXX: hmm, krups does this */ 410 igs_ext_write(iot, ioh, 0xB2, 0xE2); /* MCLK */ 411 igs_ext_write(iot, ioh, 0xB3, 0x58); 412 #endif 413 igsfb_freq_latch(dc); 414 415 igs_ext_write(iot, ioh, 0x11, 0x00); 416 igs_ext_write(iot, ioh, 0x77, 0x01); /* 8bpp, indexed */ 417 igs_ext_write(iot, ioh, 0x14, 0x81); 418 igs_ext_write(iot, ioh, 0x15, 0x00); 419 } 420 421 422 /* 423 * igs-video-init from krups prom 424 */ 425 void 426 igsfb_hw_setup(dc) 427 struct igsfb_devconfig *dc; 428 { 429 430 igsfb_init_seq(dc); 431 igsfb_init_crtc(dc); 432 igsfb_init_attr(dc); 433 igsfb_init_grfx(dc); 434 igsfb_init_ext(dc); 435 igsfb_init_dac(dc); 436 437 igsfb_1024x768_8bpp_60Hz(dc); 438 igsfb_video_on(dc); 439 } 440