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