1 /* $NetBSD: ite_rt.c,v 1.18 2002/01/28 09:57:00 aymeric Exp $ */ 2 3 /* 4 * Copyright (c) 1993 Markus Wild 5 * Copyright (c) 1993 Lutz Vieweg 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by Lutz Vieweg. 19 * 4. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <sys/cdefs.h> 35 __KERNEL_RCSID(0, "$NetBSD: ite_rt.c,v 1.18 2002/01/28 09:57:00 aymeric Exp $"); 36 37 #include "grfrt.h" 38 #if NGRFRT > 0 39 40 #include <sys/param.h> 41 #include <sys/conf.h> 42 #include <sys/proc.h> 43 #include <sys/device.h> 44 #include <sys/ioctl.h> 45 #include <sys/tty.h> 46 #include <sys/systm.h> 47 #include <dev/cons.h> 48 #include <machine/cpu.h> 49 #include <amiga/amiga/device.h> 50 #include <amiga/dev/itevar.h> 51 #include <amiga/dev/grfioctl.h> 52 #include <amiga/dev/grfvar.h> 53 #include <amiga/dev/grf_rtreg.h> 54 55 int retina_console = 1; 56 57 void retina_cursor(struct ite_softc *, int); 58 void retina_scroll(struct ite_softc *, int, int, int, int); 59 void retina_deinit(struct ite_softc *); 60 void retina_clear(struct ite_softc *, int, int, int, int); 61 void retina_putc(struct ite_softc *, int, int, int, int); 62 void retina_init(struct ite_softc *); 63 64 #ifdef RETINA_SPEED_HACK 65 static void screen_up(struct ite_softc *, int, int, int); 66 static void screen_down(struct ite_softc *, int, int, int); 67 #endif 68 69 /* 70 * this function is called from grf_rt to init the grf_softc->g_conpri 71 * field each time a retina is attached. 72 */ 73 int 74 grfrt_cnprobe(void) 75 { 76 static int done; 77 int rv; 78 79 if (retina_console && done == 0) 80 rv = CN_INTERNAL; 81 else 82 rv = CN_NORMAL; 83 done = 1; 84 return(rv); 85 } 86 87 /* 88 * init the required fields in the grf_softc struct for a 89 * grf to function as an ite. 90 */ 91 void 92 grfrt_iteinit(struct grf_softc *gp) 93 { 94 gp->g_iteinit = retina_init; 95 gp->g_itedeinit = retina_deinit; 96 gp->g_iteclear = retina_clear; 97 gp->g_iteputc = retina_putc; 98 gp->g_itescroll = retina_scroll; 99 gp->g_itecursor = retina_cursor; 100 } 101 102 103 void 104 retina_init(struct ite_softc *ip) 105 { 106 struct MonDef *md; 107 108 ip->priv = ip->grf->g_data; 109 md = (struct MonDef *) ip->priv; 110 111 ip->cols = md->TX; 112 ip->rows = md->TY; 113 } 114 115 116 void 117 retina_cursor(struct ite_softc *ip, int flag) 118 { 119 volatile caddr_t ba = ip->grf->g_regkva; 120 121 if (flag == ERASE_CURSOR) 122 { 123 /* disable cursor */ 124 WCrt (ba, CRT_ID_CURSOR_START, RCrt (ba, CRT_ID_CURSOR_START) | 0x20); 125 } 126 else 127 { 128 int pos = ip->curx + ip->cury * ip->cols; 129 130 /* make sure to enable cursor */ 131 WCrt (ba, CRT_ID_CURSOR_START, RCrt (ba, CRT_ID_CURSOR_START) & ~0x20); 132 133 /* and position it */ 134 WCrt (ba, CRT_ID_CURSOR_LOC_HIGH, (u_char) (pos >> 8)); 135 WCrt (ba, CRT_ID_CURSOR_LOC_LOW, (u_char) pos); 136 137 ip->cursorx = ip->curx; 138 ip->cursory = ip->cury; 139 } 140 } 141 142 143 144 #ifdef RETINA_SPEED_HACK 145 static void 146 screen_up(struct ite_softc *ip, int top, int bottom, int lines) 147 { 148 volatile caddr_t ba = ip->grf->g_regkva; 149 volatile caddr_t fb = ip->grf->g_fbkva; 150 const struct MonDef * md = (struct MonDef *) ip->priv; 151 #ifdef BANKEDDEVPAGER 152 int bank; 153 #endif 154 155 /* do some bounds-checking here.. */ 156 if (top >= bottom) 157 return; 158 159 if (top + lines >= bottom) 160 { 161 retina_clear (ip, top, 0, bottom - top, ip->cols); 162 return; 163 } 164 165 166 #ifdef BANKEDDEVPAGER 167 /* make sure to save/restore active bank (and if it's only 168 for tests of the feature in text-mode..) */ 169 bank = (RSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO) 170 | (RSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI) << 8)); 171 #endif 172 173 /* the trick here is to use a feature of the NCR chip. It can 174 optimize data access in various read/write modes. One of 175 the modes is able to read/write from/to different zones. 176 177 Thus, by setting the read-offset to lineN, and the write-offset 178 to line0, we just cause read/write cycles for all characters 179 up to the last line, and have the chip transfer the data. The 180 `addqb' are the cheapest way to cause read/write cycles (DONT 181 use `tas' on the Amiga!), their results are completely ignored 182 by the NCR chip, it just replicates what it just read. */ 183 184 /* write to primary, read from secondary */ 185 WSeq (ba, SEQ_ID_EXTENDED_MEM_ENA, 186 (RSeq(ba, SEQ_ID_EXTENDED_MEM_ENA) & 0x1f) | 0 ); 187 /* clear extended chain4 mode */ 188 WSeq (ba, SEQ_ID_EXT_VIDEO_ADDR, RSeq(ba, SEQ_ID_EXT_VIDEO_ADDR) & ~0x02); 189 190 /* set write mode 1, "[...] data in the read latches is written 191 to memory during CPU memory write cycles. [...]" */ 192 WGfx (ba, GCT_ID_GRAPHICS_MODE, 193 (RGfx(ba, GCT_ID_GRAPHICS_MODE) & 0xfc) | 1); 194 195 { 196 /* write to line TOP */ 197 long toploc = top * (md->TX / 16); 198 WSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO, ((unsigned char)toploc)); 199 WSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI, ((unsigned char)(toploc >> 8))); 200 } 201 { 202 /* read from line TOP + LINES */ 203 long fromloc = (top+lines) * (md->TX / 16); 204 WSeq (ba, SEQ_ID_SEC_HOST_OFF_LO, ((unsigned char)fromloc)) ; 205 WSeq (ba, SEQ_ID_SEC_HOST_OFF_HI, ((unsigned char)(fromloc >> 8))) ; 206 } 207 { 208 caddr_t p = (caddr_t)fb; 209 /* transfer all characters but LINES lines, unroll by 16 */ 210 short x = (1 + bottom - (top + lines)) * (md->TX / 16) - 1; 211 do { 212 asm volatile("addqb #1,%0@+" : "=a" (p) : "0" (p)); 213 asm volatile("addqb #1,%0@+" : "=a" (p) : "0" (p)); 214 asm volatile("addqb #1,%0@+" : "=a" (p) : "0" (p)); 215 asm volatile("addqb #1,%0@+" : "=a" (p) : "0" (p)); 216 asm volatile("addqb #1,%0@+" : "=a" (p) : "0" (p)); 217 asm volatile("addqb #1,%0@+" : "=a" (p) : "0" (p)); 218 asm volatile("addqb #1,%0@+" : "=a" (p) : "0" (p)); 219 asm volatile("addqb #1,%0@+" : "=a" (p) : "0" (p)); 220 asm volatile("addqb #1,%0@+" : "=a" (p) : "0" (p)); 221 asm volatile("addqb #1,%0@+" : "=a" (p) : "0" (p)); 222 asm volatile("addqb #1,%0@+" : "=a" (p) : "0" (p)); 223 asm volatile("addqb #1,%0@+" : "=a" (p) : "0" (p)); 224 asm volatile("addqb #1,%0@+" : "=a" (p) : "0" (p)); 225 asm volatile("addqb #1,%0@+" : "=a" (p) : "0" (p)); 226 asm volatile("addqb #1,%0@+" : "=a" (p) : "0" (p)); 227 asm volatile("addqb #1,%0@+" : "=a" (p) : "0" (p)); 228 } while (x--); 229 } 230 231 /* reset to default values */ 232 WSeq (ba, SEQ_ID_SEC_HOST_OFF_HI, 0); 233 WSeq (ba, SEQ_ID_SEC_HOST_OFF_LO, 0); 234 WSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI, 0); 235 WSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO, 0); 236 /* write mode 0 */ 237 WGfx (ba, GCT_ID_GRAPHICS_MODE, 238 (RGfx(ba, GCT_ID_GRAPHICS_MODE) & 0xfc) | 0); 239 /* extended chain4 enable */ 240 WSeq (ba, SEQ_ID_EXT_VIDEO_ADDR, 241 RSeq(ba, SEQ_ID_EXT_VIDEO_ADDR) | 0x02); 242 /* read/write to primary on A0, secondary on B0 */ 243 WSeq (ba, SEQ_ID_EXTENDED_MEM_ENA, 244 (RSeq(ba, SEQ_ID_EXTENDED_MEM_ENA) & 0x1f) | 0x40); 245 246 247 /* fill the free lines with spaces */ 248 249 { /* feed latches with value */ 250 unsigned short * f = (unsigned short *) fb; 251 252 f += (1 + bottom - lines) * md->TX * 2; 253 *f = 0x2010; 254 } 255 256 /* clear extended chain4 mode */ 257 WSeq (ba, SEQ_ID_EXT_VIDEO_ADDR, RSeq(ba, SEQ_ID_EXT_VIDEO_ADDR) & ~0x02); 258 /* set write mode 1, "[...] data in the read latches is written 259 to memory during CPU memory write cycles. [...]" */ 260 WGfx (ba, GCT_ID_GRAPHICS_MODE, (RGfx(ba, GCT_ID_GRAPHICS_MODE) & 0xfc) | 1); 261 262 { 263 unsigned long * p = (unsigned long *) fb; 264 short x = (lines * (md->TX/16)) - 1; 265 const unsigned long dummyval = 0; 266 267 p += (1 + bottom - lines) * (md->TX/4); 268 269 do { 270 *p++ = dummyval; 271 *p++ = dummyval; 272 *p++ = dummyval; 273 *p++ = dummyval; 274 } while (x--); 275 } 276 277 /* write mode 0 */ 278 WGfx (ba, GCT_ID_GRAPHICS_MODE, (RGfx(ba, GCT_ID_GRAPHICS_MODE) & 0xfc) | 0); 279 /* extended chain4 enable */ 280 WSeq (ba, SEQ_ID_EXT_VIDEO_ADDR , RSeq(ba, SEQ_ID_EXT_VIDEO_ADDR) | 0x02); 281 282 #ifdef BANKEDDEVPAGER 283 /* restore former bank */ 284 WSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO, (unsigned char) bank); 285 bank >>= 8; 286 WSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI, (unsigned char) bank); 287 #endif 288 }; 289 290 291 static void 292 screen_down(struct ite_softc *ip, int top, int bottom, int lines) 293 { 294 volatile caddr_t ba = ip->grf->g_regkva; 295 volatile caddr_t fb = ip->grf->g_fbkva; 296 const struct MonDef * md = (struct MonDef *) ip->priv; 297 #ifdef BANKEDDEVPAGER 298 int bank; 299 #endif 300 301 /* do some bounds-checking here.. */ 302 if (top >= bottom) 303 return; 304 305 if (top + lines >= bottom) 306 { 307 retina_clear (ip, top, 0, bottom - top, ip->cols); 308 return; 309 } 310 311 #ifdef BANKEDDEVPAGER 312 /* make sure to save/restore active bank (and if it's only 313 for tests of the feature in text-mode..) */ 314 bank = (RSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO) 315 | (RSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI) << 8)); 316 #endif 317 /* see screen_up() for explanation of chip-tricks */ 318 319 /* write to primary, read from secondary */ 320 WSeq (ba, SEQ_ID_EXTENDED_MEM_ENA, 321 (RSeq(ba, SEQ_ID_EXTENDED_MEM_ENA) & 0x1f) | 0 ); 322 /* clear extended chain4 mode */ 323 WSeq (ba, SEQ_ID_EXT_VIDEO_ADDR, RSeq(ba, SEQ_ID_EXT_VIDEO_ADDR) & ~0x02); 324 325 /* set write mode 1, "[...] data in the read latches is written 326 to memory during CPU memory write cycles. [...]" */ 327 WGfx (ba, GCT_ID_GRAPHICS_MODE, (RGfx(ba, GCT_ID_GRAPHICS_MODE) & 0xfc) | 1); 328 329 { 330 /* write to line TOP + LINES */ 331 long toloc = (top + lines) * (md->TX / 16); 332 WSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO, ((unsigned char)toloc)); 333 WSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI, ((unsigned char)(toloc >> 8))); 334 } 335 { 336 /* read from line TOP */ 337 long fromloc = top * (md->TX / 16); 338 WSeq (ba, SEQ_ID_SEC_HOST_OFF_LO, ((unsigned char)fromloc)); 339 WSeq (ba, SEQ_ID_SEC_HOST_OFF_HI, ((unsigned char)(fromloc >> 8))) ; 340 } 341 342 { 343 caddr_t p = (caddr_t)fb; 344 short x = (1 + bottom - (top + lines)) * (md->TX / 16) - 1; 345 p += (1 + bottom - (top + lines)) * md->TX; 346 do { 347 asm volatile("addqb #1,%0@-" : "=a" (p) : "0" (p)); 348 asm volatile("addqb #1,%0@-" : "=a" (p) : "0" (p)); 349 asm volatile("addqb #1,%0@-" : "=a" (p) : "0" (p)); 350 asm volatile("addqb #1,%0@-" : "=a" (p) : "0" (p)); 351 asm volatile("addqb #1,%0@-" : "=a" (p) : "0" (p)); 352 asm volatile("addqb #1,%0@-" : "=a" (p) : "0" (p)); 353 asm volatile("addqb #1,%0@-" : "=a" (p) : "0" (p)); 354 asm volatile("addqb #1,%0@-" : "=a" (p) : "0" (p)); 355 asm volatile("addqb #1,%0@-" : "=a" (p) : "0" (p)); 356 asm volatile("addqb #1,%0@-" : "=a" (p) : "0" (p)); 357 asm volatile("addqb #1,%0@-" : "=a" (p) : "0" (p)); 358 asm volatile("addqb #1,%0@-" : "=a" (p) : "0" (p)); 359 asm volatile("addqb #1,%0@-" : "=a" (p) : "0" (p)); 360 asm volatile("addqb #1,%0@-" : "=a" (p) : "0" (p)); 361 asm volatile("addqb #1,%0@-" : "=a" (p) : "0" (p)); 362 asm volatile("addqb #1,%0@-" : "=a" (p) : "0" (p)); 363 } while (x--); 364 } 365 366 WSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI, 0); 367 WSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO, 0); 368 WSeq (ba, SEQ_ID_SEC_HOST_OFF_HI, 0); 369 WSeq (ba, SEQ_ID_SEC_HOST_OFF_LO, 0); 370 371 /* write mode 0 */ 372 WGfx (ba, GCT_ID_GRAPHICS_MODE, 373 (RGfx(ba, GCT_ID_GRAPHICS_MODE) & 0xfc) | 0); 374 /* extended chain4 enable */ 375 WSeq (ba, SEQ_ID_EXT_VIDEO_ADDR , RSeq(ba, SEQ_ID_EXT_VIDEO_ADDR) | 0x02); 376 /* read/write to primary on A0, secondary on B0 */ 377 WSeq (ba, SEQ_ID_EXTENDED_MEM_ENA, 378 (RSeq(ba, SEQ_ID_EXTENDED_MEM_ENA) & 0x1f) | 0x40 ); 379 380 /* fill the free lines with spaces */ 381 382 { /* feed latches with value */ 383 unsigned short * f = (unsigned short *) fb; 384 385 f += top * md->TX * 2; 386 *f = 0x2010; 387 } 388 389 /* clear extended chain4 mode */ 390 WSeq (ba, SEQ_ID_EXT_VIDEO_ADDR, RSeq(ba, SEQ_ID_EXT_VIDEO_ADDR) & ~0x02); 391 /* set write mode 1, "[...] data in the read latches is written 392 to memory during CPU memory write cycles. [...]" */ 393 WGfx (ba, GCT_ID_GRAPHICS_MODE, (RGfx(ba, GCT_ID_GRAPHICS_MODE) & 0xfc) | 1); 394 395 { 396 unsigned long * p = (unsigned long *) fb; 397 short x = (lines * (md->TX/16)) - 1; 398 const unsigned long dummyval = 0; 399 400 p += top * (md->TX/4); 401 402 do { 403 *p++ = dummyval; 404 *p++ = dummyval; 405 *p++ = dummyval; 406 *p++ = dummyval; 407 } while (x--); 408 } 409 410 /* write mode 0 */ 411 WGfx (ba, GCT_ID_GRAPHICS_MODE, (RGfx(ba, GCT_ID_GRAPHICS_MODE) & 0xfc) | 0); 412 /* extended chain4 enable */ 413 WSeq (ba, SEQ_ID_EXT_VIDEO_ADDR , RSeq(ba, SEQ_ID_EXT_VIDEO_ADDR) | 0x02); 414 415 #ifdef BANKEDDEVPAGER 416 /* restore former bank */ 417 WSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO, (unsigned char) bank); 418 bank >>= 8; 419 WSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI, (unsigned char) bank); 420 #endif 421 }; 422 #endif /* RETINA_SPEED_HACK */ 423 424 425 void 426 retina_deinit(struct ite_softc *ip) 427 { 428 ip->flags &= ~ITE_INITED; 429 } 430 431 432 void 433 retina_putc(struct ite_softc *ip, int c, int dy, int dx, int mode) 434 { 435 volatile caddr_t fb = ip->grf->g_fbkva; 436 register u_char attr; 437 438 attr = (mode & ATTR_INV) ? 0x21 : 0x10; 439 if (mode & ATTR_UL) attr = 0x01; /* ???????? */ 440 if (mode & ATTR_BOLD) attr |= 0x08; 441 if (mode & ATTR_BLINK) attr |= 0x80; 442 443 fb += 4 * (dy * ip->cols + dx); 444 *fb++ = c; *fb = attr; 445 } 446 447 448 void 449 retina_clear(struct ite_softc *ip, int sy, int sx, int h, int w) 450 { 451 u_short * fb = (u_short *) ip->grf->g_fbkva; 452 short x; 453 const u_short fillval = 0x2010; 454 455 /* could probably be optimized just like the scrolling functions !! */ 456 fb += 2 * (sy * ip->cols + sx); 457 while (h--) 458 { 459 for (x = 2 * (w - 1); x >= 0; x -= 2) 460 fb[x] = fillval; 461 fb += 2 * ip->cols; 462 } 463 } 464 465 466 /* 467 * RETINA_SPEED_HACK code seems to work on some boards and on others 468 * it causes text to smear horizontally 469 */ 470 void 471 retina_scroll(struct ite_softc *ip, int sy, int sx, int count, int dir) 472 { 473 volatile caddr_t ba; 474 u_long *fb; 475 476 ba = ip->grf->g_regkva; 477 fb = (u_long *)ip->grf->g_fbkva; 478 479 retina_cursor(ip, ERASE_CURSOR); 480 481 if (dir == SCROLL_UP) { 482 #ifdef RETINA_SPEED_HACK 483 screen_up(ip, sy - count, ip->bottom_margin, count); 484 #else 485 bcopy(fb + sy * ip->cols, fb + (sy - count) * ip->cols, 486 4 * (ip->bottom_margin - sy + 1) * ip->cols); 487 retina_clear(ip, ip->bottom_margin + 1 - count, 0, count, 488 ip->cols); 489 #endif 490 } else if (dir == SCROLL_DOWN) { 491 #ifdef RETINA_SPEED_HACK 492 screen_down(ip, sy, ip->bottom_margin, count); 493 #else 494 bcopy(fb + sy * ip->cols, fb + (sy + count) * ip->cols, 495 4 * (ip->bottom_margin - sy - count + 1) * ip->cols); 496 retina_clear(ip, sy, 0, count, ip->cols); 497 #endif 498 } else if (dir == SCROLL_RIGHT) { 499 bcopy(fb + sx + sy * ip->cols, fb + sx + sy * ip->cols + count, 500 4 * (ip->cols - (sx + count))); 501 retina_clear(ip, sy, sx, 1, count); 502 } else { 503 bcopy(fb + sx + sy * ip->cols, fb + sx - count + sy * ip->cols, 504 4 * (ip->cols - sx)); 505 retina_clear(ip, sy, ip->cols - count, 1, count); 506 } 507 #ifndef RETINA_SPEED_HACK 508 retina_cursor(ip, !ERASE_CURSOR); 509 #endif 510 } 511 512 #endif /* NGRFRT */ 513