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