ite_rt.c revision 1.10 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