1 /* $NetBSD: ite_rt.c,v 1.12 1995/02/16 21:57:45 chopps 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 /* 61 * this function is called from grf_rt to init the grf_softc->g_conpri 62 * field each time a retina is attached. 63 */ 64 int 65 grfrt_cnprobe() 66 { 67 static int done; 68 int rv; 69 70 if (retina_console && done == 0) 71 rv = CN_INTERNAL; 72 else 73 rv = CN_NORMAL; 74 done = 1; 75 return(rv); 76 } 77 78 /* 79 * init the required fields in the grf_softc struct for a 80 * grf to function as an ite. 81 */ 82 void 83 grfrt_iteinit(gp) 84 struct grf_softc *gp; 85 { 86 gp->g_iteinit = retina_init; 87 gp->g_itedeinit = retina_deinit; 88 gp->g_iteclear = retina_clear; 89 gp->g_iteputc = retina_putc; 90 gp->g_itescroll = retina_scroll; 91 gp->g_itecursor = retina_cursor; 92 } 93 94 void 95 retina_init(ip) 96 struct ite_softc *ip; 97 { 98 struct MonDef *md; 99 100 ip->priv = ip->grf->g_data; 101 md = (struct MonDef *) ip->priv; 102 103 ip->cols = md->TX; 104 ip->rows = md->TY; 105 } 106 107 108 void retina_cursor(struct ite_softc *ip, int flag) 109 { 110 volatile u_char *ba = ip->grf->g_regkva; 111 112 if (flag == ERASE_CURSOR) 113 { 114 /* disable cursor */ 115 WCrt (ba, CRT_ID_CURSOR_START, RCrt (ba, CRT_ID_CURSOR_START) | 0x20); 116 } 117 else 118 { 119 int pos = ip->curx + ip->cury * ip->cols; 120 121 /* make sure to enable cursor */ 122 WCrt (ba, CRT_ID_CURSOR_START, RCrt (ba, CRT_ID_CURSOR_START) & ~0x20); 123 124 /* and position it */ 125 WCrt (ba, CRT_ID_CURSOR_LOC_HIGH, (u_char) (pos >> 8)); 126 WCrt (ba, CRT_ID_CURSOR_LOC_LOW, (u_char) pos); 127 128 ip->cursorx = ip->curx; 129 ip->cursory = ip->cury; 130 } 131 } 132 133 134 135 static void screen_up (struct ite_softc *ip, int top, int bottom, int lines) 136 { 137 volatile u_char * ba = ip->grf->g_regkva; 138 volatile u_char * fb = ip->grf->g_fbkva; 139 const struct MonDef * md = (struct MonDef *) ip->priv; 140 #ifdef BANKEDDEVPAGER 141 int bank; 142 #endif 143 144 /* do some bounds-checking here.. */ 145 if (top >= bottom) 146 return; 147 148 if (top + lines >= bottom) 149 { 150 retina_clear (ip, top, 0, bottom - top, ip->cols); 151 return; 152 } 153 154 155 #ifdef BANKEDDEVPAGER 156 /* make sure to save/restore active bank (and if it's only 157 for tests of the feature in text-mode..) */ 158 bank = (RSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO) 159 | (RSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI) << 8)); 160 #endif 161 162 /* the trick here is to use a feature of the NCR chip. It can 163 optimize data access in various read/write modes. One of 164 the modes is able to read/write from/to different zones. 165 166 Thus, by setting the read-offset to lineN, and the write-offset 167 to line0, we just cause read/write cycles for all characters 168 up to the last line, and have the chip transfer the data. The 169 `addqb' are the cheapest way to cause read/write cycles (DONT 170 use `tas' on the Amiga!), their results are completely ignored 171 by the NCR chip, it just replicates what it just read. */ 172 173 /* write to primary, read from secondary */ 174 WSeq (ba, SEQ_ID_EXTENDED_MEM_ENA, (RSeq(ba, SEQ_ID_EXTENDED_MEM_ENA) & 0x1f) | 0 ); 175 /* clear extended chain4 mode */ 176 WSeq (ba, SEQ_ID_EXT_VIDEO_ADDR, RSeq(ba, SEQ_ID_EXT_VIDEO_ADDR) & ~0x02); 177 178 /* set write mode 1, "[...] data in the read latches is written 179 to memory during CPU memory write cycles. [...]" */ 180 WGfx (ba, GCT_ID_GRAPHICS_MODE, (RGfx(ba, GCT_ID_GRAPHICS_MODE) & 0xfc) | 1); 181 182 { 183 /* write to line TOP */ 184 long toploc = top * (md->TX / 16); 185 WSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO, ((unsigned char)toploc)); 186 WSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI, ((unsigned char)(toploc >> 8))); 187 } 188 { 189 /* read from line TOP + LINES */ 190 long fromloc = (top+lines) * (md->TX / 16); 191 WSeq (ba, SEQ_ID_SEC_HOST_OFF_LO, ((unsigned char)fromloc)) ; 192 WSeq (ba, SEQ_ID_SEC_HOST_OFF_HI, ((unsigned char)(fromloc >> 8))) ; 193 } 194 { 195 unsigned char * p = (unsigned char *) fb; 196 /* transfer all characters but LINES lines, unroll by 16 */ 197 short x = (1 + bottom - (top + lines)) * (md->TX / 16) - 1; 198 do { 199 asm volatile("addqb #1,%0@+" : "=a" (p) : "0" (p)); 200 asm volatile("addqb #1,%0@+" : "=a" (p) : "0" (p)); 201 asm volatile("addqb #1,%0@+" : "=a" (p) : "0" (p)); 202 asm volatile("addqb #1,%0@+" : "=a" (p) : "0" (p)); 203 asm volatile("addqb #1,%0@+" : "=a" (p) : "0" (p)); 204 asm volatile("addqb #1,%0@+" : "=a" (p) : "0" (p)); 205 asm volatile("addqb #1,%0@+" : "=a" (p) : "0" (p)); 206 asm volatile("addqb #1,%0@+" : "=a" (p) : "0" (p)); 207 asm volatile("addqb #1,%0@+" : "=a" (p) : "0" (p)); 208 asm volatile("addqb #1,%0@+" : "=a" (p) : "0" (p)); 209 asm volatile("addqb #1,%0@+" : "=a" (p) : "0" (p)); 210 asm volatile("addqb #1,%0@+" : "=a" (p) : "0" (p)); 211 asm volatile("addqb #1,%0@+" : "=a" (p) : "0" (p)); 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 } while (x--); 216 } 217 218 /* reset to default values */ 219 WSeq (ba, SEQ_ID_SEC_HOST_OFF_HI, 0); 220 WSeq (ba, SEQ_ID_SEC_HOST_OFF_LO, 0); 221 WSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI, 0); 222 WSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO, 0); 223 /* write mode 0 */ 224 WGfx (ba, GCT_ID_GRAPHICS_MODE, (RGfx(ba, GCT_ID_GRAPHICS_MODE) & 0xfc) | 0); 225 /* extended chain4 enable */ 226 WSeq (ba, SEQ_ID_EXT_VIDEO_ADDR , RSeq(ba, SEQ_ID_EXT_VIDEO_ADDR) | 0x02); 227 /* read/write to primary on A0, secondary on B0 */ 228 WSeq (ba, SEQ_ID_EXTENDED_MEM_ENA, (RSeq(ba, SEQ_ID_EXTENDED_MEM_ENA) & 0x1f) | 0x40 ); 229 230 231 /* fill the free lines with spaces */ 232 233 { /* feed latches with value */ 234 unsigned short * f = (unsigned short *) fb; 235 236 f += (1 + bottom - lines) * md->TX * 2; 237 *f = 0x2010; 238 { 239 volatile unsigned short dummy = *((volatile unsigned short *)f); 240 } 241 } 242 243 /* clear extended chain4 mode */ 244 WSeq (ba, SEQ_ID_EXT_VIDEO_ADDR, RSeq(ba, SEQ_ID_EXT_VIDEO_ADDR) & ~0x02); 245 /* set write mode 1, "[...] data in the read latches is written 246 to memory during CPU memory write cycles. [...]" */ 247 WGfx (ba, GCT_ID_GRAPHICS_MODE, (RGfx(ba, GCT_ID_GRAPHICS_MODE) & 0xfc) | 1); 248 249 { 250 unsigned long * p = (unsigned long *) fb; 251 short x = (lines * (md->TX/16)) - 1; 252 const unsigned long dummyval = 0; 253 254 p += (1 + bottom - lines) * (md->TX/4); 255 256 do { 257 *p++ = dummyval; 258 *p++ = dummyval; 259 *p++ = dummyval; 260 *p++ = dummyval; 261 } while (x--); 262 } 263 264 /* write mode 0 */ 265 WGfx (ba, GCT_ID_GRAPHICS_MODE, (RGfx(ba, GCT_ID_GRAPHICS_MODE) & 0xfc) | 0); 266 /* extended chain4 enable */ 267 WSeq (ba, SEQ_ID_EXT_VIDEO_ADDR , RSeq(ba, SEQ_ID_EXT_VIDEO_ADDR) | 0x02); 268 269 #ifdef BANKEDDEVPAGER 270 /* restore former bank */ 271 WSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO, (unsigned char) bank); 272 bank >>= 8; 273 WSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI, (unsigned char) bank); 274 #endif 275 }; 276 277 static void screen_down (struct ite_softc *ip, int top, int bottom, int lines) 278 { 279 volatile u_char * ba = ip->grf->g_regkva; 280 volatile u_char * fb = ip->grf->g_fbkva; 281 const struct MonDef * md = (struct MonDef *) ip->priv; 282 #ifdef BANKEDDEVPAGER 283 int bank; 284 #endif 285 286 /* do some bounds-checking here.. */ 287 if (top >= bottom) 288 return; 289 290 if (top + lines >= bottom) 291 { 292 retina_clear (ip, top, 0, bottom - top, ip->cols); 293 return; 294 } 295 296 #ifdef BANKEDDEVPAGER 297 /* make sure to save/restore active bank (and if it's only 298 for tests of the feature in text-mode..) */ 299 bank = (RSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO) 300 | (RSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI) << 8)); 301 #endif 302 /* see screen_up() for explanation of chip-tricks */ 303 304 /* write to primary, read from secondary */ 305 WSeq (ba, SEQ_ID_EXTENDED_MEM_ENA, (RSeq(ba, SEQ_ID_EXTENDED_MEM_ENA) & 0x1f) | 0 ); 306 /* clear extended chain4 mode */ 307 WSeq (ba, SEQ_ID_EXT_VIDEO_ADDR, RSeq(ba, SEQ_ID_EXT_VIDEO_ADDR) & ~0x02); 308 309 /* set write mode 1, "[...] data in the read latches is written 310 to memory during CPU memory write cycles. [...]" */ 311 WGfx (ba, GCT_ID_GRAPHICS_MODE, (RGfx(ba, GCT_ID_GRAPHICS_MODE) & 0xfc) | 1); 312 313 { 314 /* write to line TOP + LINES */ 315 long toloc = (top + lines) * (md->TX / 16); 316 WSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO, ((unsigned char)toloc)); 317 WSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI, ((unsigned char)(toloc >> 8))); 318 } 319 { 320 /* read from line TOP */ 321 long fromloc = top * (md->TX / 16); 322 WSeq (ba, SEQ_ID_SEC_HOST_OFF_LO, ((unsigned char)fromloc)); 323 WSeq (ba, SEQ_ID_SEC_HOST_OFF_HI, ((unsigned char)(fromloc >> 8))) ; 324 } 325 326 { 327 unsigned char * p = (unsigned char *) fb; 328 short x = (1 + bottom - (top + lines)) * (md->TX / 16) - 1; 329 p += (1 + bottom - (top + lines)) * md->TX; 330 do { 331 asm volatile("addqb #1,%0@-" : "=a" (p) : "0" (p)); 332 asm volatile("addqb #1,%0@-" : "=a" (p) : "0" (p)); 333 asm volatile("addqb #1,%0@-" : "=a" (p) : "0" (p)); 334 asm volatile("addqb #1,%0@-" : "=a" (p) : "0" (p)); 335 asm volatile("addqb #1,%0@-" : "=a" (p) : "0" (p)); 336 asm volatile("addqb #1,%0@-" : "=a" (p) : "0" (p)); 337 asm volatile("addqb #1,%0@-" : "=a" (p) : "0" (p)); 338 asm volatile("addqb #1,%0@-" : "=a" (p) : "0" (p)); 339 asm volatile("addqb #1,%0@-" : "=a" (p) : "0" (p)); 340 asm volatile("addqb #1,%0@-" : "=a" (p) : "0" (p)); 341 asm volatile("addqb #1,%0@-" : "=a" (p) : "0" (p)); 342 asm volatile("addqb #1,%0@-" : "=a" (p) : "0" (p)); 343 asm volatile("addqb #1,%0@-" : "=a" (p) : "0" (p)); 344 asm volatile("addqb #1,%0@-" : "=a" (p) : "0" (p)); 345 asm volatile("addqb #1,%0@-" : "=a" (p) : "0" (p)); 346 asm volatile("addqb #1,%0@-" : "=a" (p) : "0" (p)); 347 } while (x--); 348 } 349 350 WSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI, 0); 351 WSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO, 0); 352 WSeq (ba, SEQ_ID_SEC_HOST_OFF_HI, 0); 353 WSeq (ba, SEQ_ID_SEC_HOST_OFF_LO, 0); 354 355 /* write mode 0 */ 356 WGfx (ba, GCT_ID_GRAPHICS_MODE, (RGfx(ba, GCT_ID_GRAPHICS_MODE) & 0xfc) | 0); 357 /* extended chain4 enable */ 358 WSeq (ba, SEQ_ID_EXT_VIDEO_ADDR , RSeq(ba, SEQ_ID_EXT_VIDEO_ADDR) | 0x02); 359 /* read/write to primary on A0, secondary on B0 */ 360 WSeq (ba, SEQ_ID_EXTENDED_MEM_ENA, (RSeq(ba, SEQ_ID_EXTENDED_MEM_ENA) & 0x1f) | 0x40 ); 361 362 /* fill the free lines with spaces */ 363 364 { /* feed latches with value */ 365 unsigned short * f = (unsigned short *) fb; 366 367 f += top * md->TX * 2; 368 *f = 0x2010; 369 { 370 volatile unsigned short dummy = *((volatile unsigned short *)f); 371 } 372 } 373 374 /* clear extended chain4 mode */ 375 WSeq (ba, SEQ_ID_EXT_VIDEO_ADDR, RSeq(ba, SEQ_ID_EXT_VIDEO_ADDR) & ~0x02); 376 /* set write mode 1, "[...] data in the read latches is written 377 to memory during CPU memory write cycles. [...]" */ 378 WGfx (ba, GCT_ID_GRAPHICS_MODE, (RGfx(ba, GCT_ID_GRAPHICS_MODE) & 0xfc) | 1); 379 380 { 381 unsigned long * p = (unsigned long *) fb; 382 short x = (lines * (md->TX/16)) - 1; 383 const unsigned long dummyval = 0; 384 385 p += top * (md->TX/4); 386 387 do { 388 *p++ = dummyval; 389 *p++ = dummyval; 390 *p++ = dummyval; 391 *p++ = dummyval; 392 } while (x--); 393 } 394 395 /* write mode 0 */ 396 WGfx (ba, GCT_ID_GRAPHICS_MODE, (RGfx(ba, GCT_ID_GRAPHICS_MODE) & 0xfc) | 0); 397 /* extended chain4 enable */ 398 WSeq (ba, SEQ_ID_EXT_VIDEO_ADDR , RSeq(ba, SEQ_ID_EXT_VIDEO_ADDR) | 0x02); 399 400 #ifdef BANKEDDEVPAGER 401 /* restore former bank */ 402 WSeq (ba, SEQ_ID_PRIM_HOST_OFF_LO, (unsigned char) bank); 403 bank >>= 8; 404 WSeq (ba, SEQ_ID_PRIM_HOST_OFF_HI, (unsigned char) bank); 405 #endif 406 }; 407 408 void retina_deinit(struct ite_softc *ip) 409 { 410 ip->flags &= ~ITE_INITED; 411 } 412 413 414 void retina_putc(struct ite_softc *ip, int c, int dy, int dx, int mode) 415 { 416 volatile u_char * ba = ip->grf->g_regkva; 417 volatile u_char * fb = ip->grf->g_fbkva; 418 register u_char attr; 419 420 attr = (mode & ATTR_INV) ? 0x21 : 0x10; 421 if (mode & ATTR_UL) attr = 0x01; /* ???????? */ 422 if (mode & ATTR_BOLD) attr |= 0x08; 423 if (mode & ATTR_BLINK) attr |= 0x80; 424 425 fb += 4 * (dy * ip->cols + dx); 426 *fb++ = c; *fb = attr; 427 } 428 429 void retina_clear(struct ite_softc *ip, int sy, int sx, int h, int w) 430 { 431 volatile u_char * ba = ip->grf->g_regkva; 432 u_short * fb = (u_short *) ip->grf->g_fbkva; 433 short x; 434 const u_short fillval = 0x2010; 435 /* could probably be optimized just like the scrolling functions !! */ 436 fb += 2 * (sy * ip->cols + sx); 437 while (h--) 438 { 439 for (x = 2 * (w - 1); x >= 0; x -= 2) 440 fb[x] = fillval; 441 fb += 2 * ip->cols; 442 } 443 } 444 445 void retina_scroll(struct ite_softc *ip, int sy, int sx, int count, int dir) 446 { 447 volatile u_char * ba = ip->grf->g_regkva; 448 u_long * fb = (u_long *) ip->grf->g_fbkva; 449 register int height, dy, i; 450 451 retina_cursor(ip, ERASE_CURSOR); 452 453 if (dir == SCROLL_UP) 454 { 455 screen_up (ip, sy - count, ip->bottom_margin, count); 456 /* bcopy (fb + sy * ip->cols, fb + (sy - count) * ip->cols, 4 * (ip->bottom_margin - sy + 1) * ip->cols); */ 457 /* retina_clear (ip, ip->bottom_margin + 1 - count, 0, count, ip->cols); */ 458 } 459 else if (dir == SCROLL_DOWN) 460 { 461 screen_down (ip, sy, ip->bottom_margin, count); 462 /* bcopy (fb + sy * ip->cols, fb + (sy + count) * ip->cols, 4 * (ip->bottom_margin - sy - count + 1) * ip->cols); */ 463 /* retina_clear (ip, sy, 0, count, ip->cols); */ 464 } 465 else if (dir == SCROLL_RIGHT) 466 { 467 bcopy (fb + sx + sy * ip->cols, fb + sx + sy * ip->cols + count, 4 * (ip->cols - (sx + count))); 468 retina_clear (ip, sy, sx, 1, count); 469 } 470 else 471 { 472 bcopy (fb + sx + sy * ip->cols, fb + sx - count + sy * ip->cols, 4 * (ip->cols - sx)); 473 retina_clear (ip, sy, ip->cols - count, 1, count); 474 } 475 } 476 477 #endif /* NGRFRT */ 478