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