1 /* $NetBSD: ite_rt.c,v 1.16 1996/04/23 22:53:12 veego 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 #include "grfrt.h" 34 #if NGRFRT > 0 35 36 #include <sys/param.h> 37 #include <sys/conf.h> 38 #include <sys/proc.h> 39 #include <sys/device.h> 40 #include <sys/ioctl.h> 41 #include <sys/tty.h> 42 #include <sys/systm.h> 43 #include <dev/cons.h> 44 #include <machine/cpu.h> 45 #include <amiga/amiga/device.h> 46 #include <amiga/dev/itevar.h> 47 #include <amiga/dev/grfioctl.h> 48 #include <amiga/dev/grfvar.h> 49 #include <amiga/dev/grf_rtreg.h> 50 51 int retina_console = 1; 52 53 void retina_cursor __P((struct ite_softc *,int)); 54 void retina_scroll __P((struct ite_softc *,int,int,int,int)); 55 void retina_deinit __P((struct ite_softc *)); 56 void retina_clear __P((struct ite_softc *,int,int,int,int)); 57 void retina_putc __P((struct ite_softc *,int,int,int,int)); 58 void retina_init __P((struct ite_softc *)); 59 60 #ifdef RETINA_SPEED_HACK 61 static void screen_up __P((struct ite_softc *, int, int, int)); 62 static void screen_down __P((struct ite_softc *, int, int, int)); 63 #endif 64 65 /* 66 * this function is called from grf_rt to init the grf_softc->g_conpri 67 * field each time a retina is attached. 68 */ 69 int 70 grfrt_cnprobe() 71 { 72 static int done; 73 int rv; 74 75 if (retina_console && done == 0) 76 rv = CN_INTERNAL; 77 else 78 rv = CN_NORMAL; 79 done = 1; 80 return(rv); 81 } 82 83 /* 84 * init the required fields in the grf_softc struct for a 85 * grf to function as an ite. 86 */ 87 void 88 grfrt_iteinit(gp) 89 struct grf_softc *gp; 90 { 91 gp->g_iteinit = retina_init; 92 gp->g_itedeinit = retina_deinit; 93 gp->g_iteclear = retina_clear; 94 gp->g_iteputc = retina_putc; 95 gp->g_itescroll = retina_scroll; 96 gp->g_itecursor = retina_cursor; 97 } 98 99 100 void 101 retina_init(ip) 102 struct ite_softc *ip; 103 { 104 struct MonDef *md; 105 106 ip->priv = ip->grf->g_data; 107 md = (struct MonDef *) ip->priv; 108 109 ip->cols = md->TX; 110 ip->rows = md->TY; 111 } 112 113 114 void 115 retina_cursor(ip, flag) 116 struct ite_softc *ip; 117 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(ip, top, bottom, lines) 147 struct ite_softc *ip; 148 int top; 149 int bottom; 150 int lines; 151 { 152 volatile caddr_t ba = ip->grf->g_regkva; 153 volatile caddr_t fb = ip->grf->g_fbkva; 154 const struct MonDef * md = (struct MonDef *) ip->priv; 155 #ifdef BANKEDDEVPAGER 156 int bank; 157 #endif 158 159 /* do some bounds-checking here.. */ 160 if (top >= bottom) 161 return; 162 163 if (top + lines >= bottom) 164 { 165 retina_clear (ip, top, 0, bottom - top, ip->cols); 166 return; 167 } 168 169 170 #ifdef BANKEDDEVPAGER 171 /* make sure to save/restore active bank (and if it's only 172 for tests of the feature in text-mode..) */ 173 bank = (RSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO) 174 | (RSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI) << 8)); 175 #endif 176 177 /* the trick here is to use a feature of the NCR chip. It can 178 optimize data access in various read/write modes. One of 179 the modes is able to read/write from/to different zones. 180 181 Thus, by setting the read-offset to lineN, and the write-offset 182 to line0, we just cause read/write cycles for all characters 183 up to the last line, and have the chip transfer the data. The 184 `addqb' are the cheapest way to cause read/write cycles (DONT 185 use `tas' on the Amiga!), their results are completely ignored 186 by the NCR chip, it just replicates what it just read. */ 187 188 /* write to primary, read from secondary */ 189 WSeq (ba, SEQ_ID_EXTENDED_MEM_ENA, 190 (RSeq(ba, SEQ_ID_EXTENDED_MEM_ENA) & 0x1f) | 0 ); 191 /* clear extended chain4 mode */ 192 WSeq (ba, SEQ_ID_EXT_VIDEO_ADDR, RSeq(ba, SEQ_ID_EXT_VIDEO_ADDR) & ~0x02); 193 194 /* set write mode 1, "[...] data in the read latches is written 195 to memory during CPU memory write cycles. [...]" */ 196 WGfx (ba, GCT_ID_GRAPHICS_MODE, 197 (RGfx(ba, GCT_ID_GRAPHICS_MODE) & 0xfc) | 1); 198 199 { 200 /* write to line TOP */ 201 long toploc = top * (md->TX / 16); 202 WSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO, ((unsigned char)toploc)); 203 WSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI, ((unsigned char)(toploc >> 8))); 204 } 205 { 206 /* read from line TOP + LINES */ 207 long fromloc = (top+lines) * (md->TX / 16); 208 WSeq (ba, SEQ_ID_SEC_HOST_OFF_LO, ((unsigned char)fromloc)) ; 209 WSeq (ba, SEQ_ID_SEC_HOST_OFF_HI, ((unsigned char)(fromloc >> 8))) ; 210 } 211 { 212 caddr_t p = (caddr_t)fb; 213 /* transfer all characters but LINES lines, unroll by 16 */ 214 short x = (1 + bottom - (top + lines)) * (md->TX / 16) - 1; 215 do { 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 asm volatile("addqb #1,%0@+" : "=a" (p) : "0" (p)); 229 asm volatile("addqb #1,%0@+" : "=a" (p) : "0" (p)); 230 asm volatile("addqb #1,%0@+" : "=a" (p) : "0" (p)); 231 asm volatile("addqb #1,%0@+" : "=a" (p) : "0" (p)); 232 } while (x--); 233 } 234 235 /* reset to default values */ 236 WSeq (ba, SEQ_ID_SEC_HOST_OFF_HI, 0); 237 WSeq (ba, SEQ_ID_SEC_HOST_OFF_LO, 0); 238 WSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI, 0); 239 WSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO, 0); 240 /* write mode 0 */ 241 WGfx (ba, GCT_ID_GRAPHICS_MODE, 242 (RGfx(ba, GCT_ID_GRAPHICS_MODE) & 0xfc) | 0); 243 /* extended chain4 enable */ 244 WSeq (ba, SEQ_ID_EXT_VIDEO_ADDR, 245 RSeq(ba, SEQ_ID_EXT_VIDEO_ADDR) | 0x02); 246 /* read/write to primary on A0, secondary on B0 */ 247 WSeq (ba, SEQ_ID_EXTENDED_MEM_ENA, 248 (RSeq(ba, SEQ_ID_EXTENDED_MEM_ENA) & 0x1f) | 0x40); 249 250 251 /* fill the free lines with spaces */ 252 253 { /* feed latches with value */ 254 unsigned short * f = (unsigned short *) fb; 255 256 f += (1 + bottom - lines) * md->TX * 2; 257 *f = 0x2010; 258 } 259 260 /* clear extended chain4 mode */ 261 WSeq (ba, SEQ_ID_EXT_VIDEO_ADDR, RSeq(ba, SEQ_ID_EXT_VIDEO_ADDR) & ~0x02); 262 /* set write mode 1, "[...] data in the read latches is written 263 to memory during CPU memory write cycles. [...]" */ 264 WGfx (ba, GCT_ID_GRAPHICS_MODE, (RGfx(ba, GCT_ID_GRAPHICS_MODE) & 0xfc) | 1); 265 266 { 267 unsigned long * p = (unsigned long *) fb; 268 short x = (lines * (md->TX/16)) - 1; 269 const unsigned long dummyval = 0; 270 271 p += (1 + bottom - lines) * (md->TX/4); 272 273 do { 274 *p++ = dummyval; 275 *p++ = dummyval; 276 *p++ = dummyval; 277 *p++ = dummyval; 278 } while (x--); 279 } 280 281 /* write mode 0 */ 282 WGfx (ba, GCT_ID_GRAPHICS_MODE, (RGfx(ba, GCT_ID_GRAPHICS_MODE) & 0xfc) | 0); 283 /* extended chain4 enable */ 284 WSeq (ba, SEQ_ID_EXT_VIDEO_ADDR , RSeq(ba, SEQ_ID_EXT_VIDEO_ADDR) | 0x02); 285 286 #ifdef BANKEDDEVPAGER 287 /* restore former bank */ 288 WSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO, (unsigned char) bank); 289 bank >>= 8; 290 WSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI, (unsigned char) bank); 291 #endif 292 }; 293 294 295 static void 296 screen_down(ip, top, bottom, lines) 297 struct ite_softc *ip; 298 int top; 299 int bottom; 300 int lines; 301 { 302 volatile caddr_t ba = ip->grf->g_regkva; 303 volatile caddr_t fb = ip->grf->g_fbkva; 304 const struct MonDef * md = (struct MonDef *) ip->priv; 305 #ifdef BANKEDDEVPAGER 306 int bank; 307 #endif 308 309 /* do some bounds-checking here.. */ 310 if (top >= bottom) 311 return; 312 313 if (top + lines >= bottom) 314 { 315 retina_clear (ip, top, 0, bottom - top, ip->cols); 316 return; 317 } 318 319 #ifdef BANKEDDEVPAGER 320 /* make sure to save/restore active bank (and if it's only 321 for tests of the feature in text-mode..) */ 322 bank = (RSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO) 323 | (RSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI) << 8)); 324 #endif 325 /* see screen_up() for explanation of chip-tricks */ 326 327 /* write to primary, read from secondary */ 328 WSeq (ba, SEQ_ID_EXTENDED_MEM_ENA, 329 (RSeq(ba, SEQ_ID_EXTENDED_MEM_ENA) & 0x1f) | 0 ); 330 /* clear extended chain4 mode */ 331 WSeq (ba, SEQ_ID_EXT_VIDEO_ADDR, RSeq(ba, SEQ_ID_EXT_VIDEO_ADDR) & ~0x02); 332 333 /* set write mode 1, "[...] data in the read latches is written 334 to memory during CPU memory write cycles. [...]" */ 335 WGfx (ba, GCT_ID_GRAPHICS_MODE, (RGfx(ba, GCT_ID_GRAPHICS_MODE) & 0xfc) | 1); 336 337 { 338 /* write to line TOP + LINES */ 339 long toloc = (top + lines) * (md->TX / 16); 340 WSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO, ((unsigned char)toloc)); 341 WSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI, ((unsigned char)(toloc >> 8))); 342 } 343 { 344 /* read from line TOP */ 345 long fromloc = top * (md->TX / 16); 346 WSeq (ba, SEQ_ID_SEC_HOST_OFF_LO, ((unsigned char)fromloc)); 347 WSeq (ba, SEQ_ID_SEC_HOST_OFF_HI, ((unsigned char)(fromloc >> 8))) ; 348 } 349 350 { 351 caddr_t p = (caddr_t)fb; 352 short x = (1 + bottom - (top + lines)) * (md->TX / 16) - 1; 353 p += (1 + bottom - (top + lines)) * md->TX; 354 do { 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 asm volatile("addqb #1,%0@-" : "=a" (p) : "0" (p)); 364 asm volatile("addqb #1,%0@-" : "=a" (p) : "0" (p)); 365 asm volatile("addqb #1,%0@-" : "=a" (p) : "0" (p)); 366 asm volatile("addqb #1,%0@-" : "=a" (p) : "0" (p)); 367 asm volatile("addqb #1,%0@-" : "=a" (p) : "0" (p)); 368 asm volatile("addqb #1,%0@-" : "=a" (p) : "0" (p)); 369 asm volatile("addqb #1,%0@-" : "=a" (p) : "0" (p)); 370 asm volatile("addqb #1,%0@-" : "=a" (p) : "0" (p)); 371 } while (x--); 372 } 373 374 WSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI, 0); 375 WSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO, 0); 376 WSeq (ba, SEQ_ID_SEC_HOST_OFF_HI, 0); 377 WSeq (ba, SEQ_ID_SEC_HOST_OFF_LO, 0); 378 379 /* write mode 0 */ 380 WGfx (ba, GCT_ID_GRAPHICS_MODE, 381 (RGfx(ba, GCT_ID_GRAPHICS_MODE) & 0xfc) | 0); 382 /* extended chain4 enable */ 383 WSeq (ba, SEQ_ID_EXT_VIDEO_ADDR , RSeq(ba, SEQ_ID_EXT_VIDEO_ADDR) | 0x02); 384 /* read/write to primary on A0, secondary on B0 */ 385 WSeq (ba, SEQ_ID_EXTENDED_MEM_ENA, 386 (RSeq(ba, SEQ_ID_EXTENDED_MEM_ENA) & 0x1f) | 0x40 ); 387 388 /* fill the free lines with spaces */ 389 390 { /* feed latches with value */ 391 unsigned short * f = (unsigned short *) fb; 392 393 f += top * md->TX * 2; 394 *f = 0x2010; 395 } 396 397 /* clear extended chain4 mode */ 398 WSeq (ba, SEQ_ID_EXT_VIDEO_ADDR, RSeq(ba, SEQ_ID_EXT_VIDEO_ADDR) & ~0x02); 399 /* set write mode 1, "[...] data in the read latches is written 400 to memory during CPU memory write cycles. [...]" */ 401 WGfx (ba, GCT_ID_GRAPHICS_MODE, (RGfx(ba, GCT_ID_GRAPHICS_MODE) & 0xfc) | 1); 402 403 { 404 unsigned long * p = (unsigned long *) fb; 405 short x = (lines * (md->TX/16)) - 1; 406 const unsigned long dummyval = 0; 407 408 p += top * (md->TX/4); 409 410 do { 411 *p++ = dummyval; 412 *p++ = dummyval; 413 *p++ = dummyval; 414 *p++ = dummyval; 415 } while (x--); 416 } 417 418 /* write mode 0 */ 419 WGfx (ba, GCT_ID_GRAPHICS_MODE, (RGfx(ba, GCT_ID_GRAPHICS_MODE) & 0xfc) | 0); 420 /* extended chain4 enable */ 421 WSeq (ba, SEQ_ID_EXT_VIDEO_ADDR , RSeq(ba, SEQ_ID_EXT_VIDEO_ADDR) | 0x02); 422 423 #ifdef BANKEDDEVPAGER 424 /* restore former bank */ 425 WSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO, (unsigned char) bank); 426 bank >>= 8; 427 WSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI, (unsigned char) bank); 428 #endif 429 }; 430 #endif /* RETINA_SPEED_HACK */ 431 432 433 void 434 retina_deinit(ip) 435 struct ite_softc *ip; 436 { 437 ip->flags &= ~ITE_INITED; 438 } 439 440 441 void 442 retina_putc(ip, c, dy, dx, mode) 443 struct ite_softc *ip; 444 int c; 445 int dy; 446 int dx; 447 int mode; 448 { 449 volatile caddr_t fb = ip->grf->g_fbkva; 450 register u_char attr; 451 452 attr = (mode & ATTR_INV) ? 0x21 : 0x10; 453 if (mode & ATTR_UL) attr = 0x01; /* ???????? */ 454 if (mode & ATTR_BOLD) attr |= 0x08; 455 if (mode & ATTR_BLINK) attr |= 0x80; 456 457 fb += 4 * (dy * ip->cols + dx); 458 *fb++ = c; *fb = attr; 459 } 460 461 462 void 463 retina_clear(ip, sy, sx, h, w) 464 struct ite_softc *ip; 465 int sy; 466 int sx; 467 int h; 468 int w; 469 { 470 u_short * fb = (u_short *) ip->grf->g_fbkva; 471 short x; 472 const u_short fillval = 0x2010; 473 474 /* could probably be optimized just like the scrolling functions !! */ 475 fb += 2 * (sy * ip->cols + sx); 476 while (h--) 477 { 478 for (x = 2 * (w - 1); x >= 0; x -= 2) 479 fb[x] = fillval; 480 fb += 2 * ip->cols; 481 } 482 } 483 484 485 /* 486 * RETINA_SPEED_HACK code seems to work on some boards and on others 487 * it causes text to smear horizontally 488 */ 489 void 490 retina_scroll(ip, sy, sx, count, dir) 491 struct ite_softc *ip; 492 int sy; 493 int sx; 494 int count; 495 int dir; 496 { 497 volatile caddr_t ba; 498 u_long *fb; 499 500 ba = ip->grf->g_regkva; 501 fb = (u_long *)ip->grf->g_fbkva; 502 503 retina_cursor(ip, ERASE_CURSOR); 504 505 if (dir == SCROLL_UP) { 506 #ifdef RETINA_SPEED_HACK 507 screen_up(ip, sy - count, ip->bottom_margin, count); 508 #else 509 bcopy(fb + sy * ip->cols, fb + (sy - count) * ip->cols, 510 4 * (ip->bottom_margin - sy + 1) * ip->cols); 511 retina_clear(ip, ip->bottom_margin + 1 - count, 0, count, 512 ip->cols); 513 #endif 514 } else if (dir == SCROLL_DOWN) { 515 #ifdef RETINA_SPEED_HACK 516 screen_down(ip, sy, ip->bottom_margin, count); 517 #else 518 bcopy(fb + sy * ip->cols, fb + (sy + count) * ip->cols, 519 4 * (ip->bottom_margin - sy - count + 1) * ip->cols); 520 retina_clear(ip, sy, 0, count, ip->cols); 521 #endif 522 } else if (dir == SCROLL_RIGHT) { 523 bcopy(fb + sx + sy * ip->cols, fb + sx + sy * ip->cols + count, 524 4 * (ip->cols - (sx + count))); 525 retina_clear(ip, sy, sx, 1, count); 526 } else { 527 bcopy(fb + sx + sy * ip->cols, fb + sx - count + sy * ip->cols, 528 4 * (ip->cols - sx)); 529 retina_clear(ip, sy, ip->cols - count, 1, count); 530 } 531 #ifndef RETINA_SPEED_HACK 532 retina_cursor(ip, !ERASE_CURSOR); 533 #endif 534 } 535 536 #endif /* NGRFRT */ 537