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