1 /* $NetBSD: ite_rt.c,v 1.23 2009/03/18 17:06:42 cegger Exp $ */
4 * Copyright (c) 1993 Markus Wild
5 * Copyright (c) 1993 Lutz Vieweg
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by Lutz Vieweg.
19 * 4. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: ite_rt.c,v 1.23 2009/03/18 17:06:42 cegger Exp $");
40 #include <sys/param.h>
43 #include <sys/device.h>
44 #include <sys/ioctl.h>
46 #include <sys/systm.h>
48 #include <machine/cpu.h>
49 #include <amiga/amiga/device.h>
50 #include <amiga/dev/itevar.h>
51 #include <amiga/dev/grfioctl.h>
52 #include <amiga/dev/grfvar.h>
53 #include <amiga/dev/grf_rtreg.h>
55 int retina_console
= 1;
57 void retina_cursor(struct ite_softc
*, int);
58 void retina_scroll(struct ite_softc
*, int, int, int, int);
59 void retina_deinit(struct ite_softc
*);
60 void retina_clear(struct ite_softc
*, int, int, int, int);
61 void retina_putc(struct ite_softc
*, int, int, int, int);
62 void retina_init(struct ite_softc
*);
64 #ifdef RETINA_SPEED_HACK
65 static void screen_up(struct ite_softc
*, int, int, int);
66 static void screen_down(struct ite_softc
*, int, int, int);
70 * this function is called from grf_rt to init the grf_softc->g_conpri
71 * field each time a retina is attached.
79 if (retina_console
&& done
== 0)
88 * init the required fields in the grf_softc struct for a
89 * grf to function as an ite.
92 grfrt_iteinit(struct grf_softc
*gp
)
94 gp
->g_iteinit
= retina_init
;
95 gp
->g_itedeinit
= retina_deinit
;
96 gp
->g_iteclear
= retina_clear
;
97 gp
->g_iteputc
= retina_putc
;
98 gp
->g_itescroll
= retina_scroll
;
99 gp
->g_itecursor
= retina_cursor
;
104 retina_init(struct ite_softc
*ip
)
108 ip
->priv
= ip
->grf
->g_data
;
109 md
= (struct MonDef
*) ip
->priv
;
117 retina_cursor(struct ite_softc
*ip
, int flag
)
119 volatile void *ba
= ip
->grf
->g_regkva
;
121 if (flag
== ERASE_CURSOR
)
124 WCrt (ba
, CRT_ID_CURSOR_START
, RCrt (ba
, CRT_ID_CURSOR_START
) | 0x20);
128 int pos
= ip
->curx
+ ip
->cury
* ip
->cols
;
130 /* make sure to enable cursor */
131 WCrt (ba
, CRT_ID_CURSOR_START
, RCrt (ba
, CRT_ID_CURSOR_START
) & ~0x20);
133 /* and position it */
134 WCrt (ba
, CRT_ID_CURSOR_LOC_HIGH
, (u_char
) (pos
>> 8));
135 WCrt (ba
, CRT_ID_CURSOR_LOC_LOW
, (u_char
) pos
);
137 ip
->cursorx
= ip
->curx
;
138 ip
->cursory
= ip
->cury
;
144 #ifdef RETINA_SPEED_HACK
146 screen_up(struct ite_softc
*ip
, int top
, int bottom
, int lines
)
148 volatile void *ba
= ip
->grf
->g_regkva
;
149 volatile void *fb
= ip
->grf
->g_fbkva
;
150 const struct MonDef
* md
= (struct MonDef
*) ip
->priv
;
152 /* do some bounds-checking here.. */
156 if (top
+ lines
>= bottom
)
158 retina_clear (ip
, top
, 0, bottom
- top
, ip
->cols
);
162 /* the trick here is to use a feature of the NCR chip. It can
163 optimize data access in various read/write modes. One of
164 the modes is able to read/write from/to different zones.
166 Thus, by setting the read-offset to lineN, and the write-offset
167 to line0, we just cause read/write cycles for all characters
168 up to the last line, and have the chip transfer the data. The
169 `addqb' are the cheapest way to cause read/write cycles (DONT
170 use `tas' on the Amiga!), their results are completely ignored
171 by the NCR chip, it just replicates what it just read. */
173 /* write to primary, read from secondary */
174 WSeq (ba
, SEQ_ID_EXTENDED_MEM_ENA
,
175 (RSeq(ba
, SEQ_ID_EXTENDED_MEM_ENA
) & 0x1f) | 0 );
176 /* clear extended chain4 mode */
177 WSeq (ba
, SEQ_ID_EXT_VIDEO_ADDR
, RSeq(ba
, SEQ_ID_EXT_VIDEO_ADDR
) & ~0x02);
179 /* set write mode 1, "[...] data in the read latches is written
180 to memory during CPU memory write cycles. [...]" */
181 WGfx (ba
, GCT_ID_GRAPHICS_MODE
,
182 (RGfx(ba
, GCT_ID_GRAPHICS_MODE
) & 0xfc) | 1);
185 /* write to line TOP */
186 long toploc
= top
* (md
->TX
/ 16);
187 WSeq (ba
, SEQ_ID_PRIM_HOST_OFF_LO
, ((unsigned char)toploc
));
188 WSeq (ba
, SEQ_ID_PRIM_HOST_OFF_HI
, ((unsigned char)(toploc
>> 8)));
191 /* read from line TOP + LINES */
192 long fromloc
= (top
+lines
) * (md
->TX
/ 16);
193 WSeq (ba
, SEQ_ID_SEC_HOST_OFF_LO
, ((unsigned char)fromloc
)) ;
194 WSeq (ba
, SEQ_ID_SEC_HOST_OFF_HI
, ((unsigned char)(fromloc
>> 8))) ;
197 void *p
= (void *)fb
;
198 /* transfer all characters but LINES lines, unroll by 16 */
199 short x
= (1 + bottom
- (top
+ lines
)) * (md
->TX
/ 16) - 1;
201 __asm
volatile("addqb #1,%0@+" : "=a" (p
) : "0" (p
));
202 __asm
volatile("addqb #1,%0@+" : "=a" (p
) : "0" (p
));
203 __asm
volatile("addqb #1,%0@+" : "=a" (p
) : "0" (p
));
204 __asm
volatile("addqb #1,%0@+" : "=a" (p
) : "0" (p
));
205 __asm
volatile("addqb #1,%0@+" : "=a" (p
) : "0" (p
));
206 __asm
volatile("addqb #1,%0@+" : "=a" (p
) : "0" (p
));
207 __asm
volatile("addqb #1,%0@+" : "=a" (p
) : "0" (p
));
208 __asm
volatile("addqb #1,%0@+" : "=a" (p
) : "0" (p
));
209 __asm
volatile("addqb #1,%0@+" : "=a" (p
) : "0" (p
));
210 __asm
volatile("addqb #1,%0@+" : "=a" (p
) : "0" (p
));
211 __asm
volatile("addqb #1,%0@+" : "=a" (p
) : "0" (p
));
212 __asm
volatile("addqb #1,%0@+" : "=a" (p
) : "0" (p
));
213 __asm
volatile("addqb #1,%0@+" : "=a" (p
) : "0" (p
));
214 __asm
volatile("addqb #1,%0@+" : "=a" (p
) : "0" (p
));
215 __asm
volatile("addqb #1,%0@+" : "=a" (p
) : "0" (p
));
216 __asm
volatile("addqb #1,%0@+" : "=a" (p
) : "0" (p
));
220 /* reset to default values */
221 WSeq (ba
, SEQ_ID_SEC_HOST_OFF_HI
, 0);
222 WSeq (ba
, SEQ_ID_SEC_HOST_OFF_LO
, 0);
223 WSeq (ba
, SEQ_ID_PRIM_HOST_OFF_HI
, 0);
224 WSeq (ba
, SEQ_ID_PRIM_HOST_OFF_LO
, 0);
226 WGfx (ba
, GCT_ID_GRAPHICS_MODE
,
227 (RGfx(ba
, GCT_ID_GRAPHICS_MODE
) & 0xfc) | 0);
228 /* extended chain4 enable */
229 WSeq (ba
, SEQ_ID_EXT_VIDEO_ADDR
,
230 RSeq(ba
, SEQ_ID_EXT_VIDEO_ADDR
) | 0x02);
231 /* read/write to primary on A0, secondary on B0 */
232 WSeq (ba
, SEQ_ID_EXTENDED_MEM_ENA
,
233 (RSeq(ba
, SEQ_ID_EXTENDED_MEM_ENA
) & 0x1f) | 0x40);
236 /* fill the free lines with spaces */
238 { /* feed latches with value */
239 unsigned short * f
= (unsigned short *) fb
;
241 f
+= (1 + bottom
- lines
) * md
->TX
* 2;
245 /* clear extended chain4 mode */
246 WSeq (ba
, SEQ_ID_EXT_VIDEO_ADDR
, RSeq(ba
, SEQ_ID_EXT_VIDEO_ADDR
) & ~0x02);
247 /* set write mode 1, "[...] data in the read latches is written
248 to memory during CPU memory write cycles. [...]" */
249 WGfx (ba
, GCT_ID_GRAPHICS_MODE
, (RGfx(ba
, GCT_ID_GRAPHICS_MODE
) & 0xfc) | 1);
252 unsigned long * p
= (unsigned long *) fb
;
253 short x
= (lines
* (md
->TX
/16)) - 1;
254 const unsigned long dummyval
= 0;
256 p
+= (1 + bottom
- lines
) * (md
->TX
/4);
267 WGfx (ba
, GCT_ID_GRAPHICS_MODE
, (RGfx(ba
, GCT_ID_GRAPHICS_MODE
) & 0xfc) | 0);
268 /* extended chain4 enable */
269 WSeq (ba
, SEQ_ID_EXT_VIDEO_ADDR
, RSeq(ba
, SEQ_ID_EXT_VIDEO_ADDR
) | 0x02);
274 screen_down(struct ite_softc
*ip
, int top
, int bottom
, int lines
)
276 volatile void *ba
= ip
->grf
->g_regkva
;
277 volatile void *fb
= ip
->grf
->g_fbkva
;
278 const struct MonDef
* md
= (struct MonDef
*) ip
->priv
;
280 /* do some bounds-checking here.. */
284 if (top
+ lines
>= bottom
)
286 retina_clear (ip
, top
, 0, bottom
- top
, ip
->cols
);
290 /* see screen_up() for explanation of chip-tricks */
292 /* write to primary, read from secondary */
293 WSeq (ba
, SEQ_ID_EXTENDED_MEM_ENA
,
294 (RSeq(ba
, SEQ_ID_EXTENDED_MEM_ENA
) & 0x1f) | 0 );
295 /* clear extended chain4 mode */
296 WSeq (ba
, SEQ_ID_EXT_VIDEO_ADDR
, RSeq(ba
, SEQ_ID_EXT_VIDEO_ADDR
) & ~0x02);
298 /* set write mode 1, "[...] data in the read latches is written
299 to memory during CPU memory write cycles. [...]" */
300 WGfx (ba
, GCT_ID_GRAPHICS_MODE
, (RGfx(ba
, GCT_ID_GRAPHICS_MODE
) & 0xfc) | 1);
303 /* write to line TOP + LINES */
304 long toloc
= (top
+ lines
) * (md
->TX
/ 16);
305 WSeq (ba
, SEQ_ID_PRIM_HOST_OFF_LO
, ((unsigned char)toloc
));
306 WSeq (ba
, SEQ_ID_PRIM_HOST_OFF_HI
, ((unsigned char)(toloc
>> 8)));
309 /* read from line TOP */
310 long fromloc
= top
* (md
->TX
/ 16);
311 WSeq (ba
, SEQ_ID_SEC_HOST_OFF_LO
, ((unsigned char)fromloc
));
312 WSeq (ba
, SEQ_ID_SEC_HOST_OFF_HI
, ((unsigned char)(fromloc
>> 8))) ;
316 void *p
= (void *)fb
;
317 short x
= (1 + bottom
- (top
+ lines
)) * (md
->TX
/ 16) - 1;
318 p
+= (1 + bottom
- (top
+ lines
)) * md
->TX
;
320 __asm
volatile("addqb #1,%0@-" : "=a" (p
) : "0" (p
));
321 __asm
volatile("addqb #1,%0@-" : "=a" (p
) : "0" (p
));
322 __asm
volatile("addqb #1,%0@-" : "=a" (p
) : "0" (p
));
323 __asm
volatile("addqb #1,%0@-" : "=a" (p
) : "0" (p
));
324 __asm
volatile("addqb #1,%0@-" : "=a" (p
) : "0" (p
));
325 __asm
volatile("addqb #1,%0@-" : "=a" (p
) : "0" (p
));
326 __asm
volatile("addqb #1,%0@-" : "=a" (p
) : "0" (p
));
327 __asm
volatile("addqb #1,%0@-" : "=a" (p
) : "0" (p
));
328 __asm
volatile("addqb #1,%0@-" : "=a" (p
) : "0" (p
));
329 __asm
volatile("addqb #1,%0@-" : "=a" (p
) : "0" (p
));
330 __asm
volatile("addqb #1,%0@-" : "=a" (p
) : "0" (p
));
331 __asm
volatile("addqb #1,%0@-" : "=a" (p
) : "0" (p
));
332 __asm
volatile("addqb #1,%0@-" : "=a" (p
) : "0" (p
));
333 __asm
volatile("addqb #1,%0@-" : "=a" (p
) : "0" (p
));
334 __asm
volatile("addqb #1,%0@-" : "=a" (p
) : "0" (p
));
335 __asm
volatile("addqb #1,%0@-" : "=a" (p
) : "0" (p
));
339 WSeq (ba
, SEQ_ID_PRIM_HOST_OFF_HI
, 0);
340 WSeq (ba
, SEQ_ID_PRIM_HOST_OFF_LO
, 0);
341 WSeq (ba
, SEQ_ID_SEC_HOST_OFF_HI
, 0);
342 WSeq (ba
, SEQ_ID_SEC_HOST_OFF_LO
, 0);
345 WGfx (ba
, GCT_ID_GRAPHICS_MODE
,
346 (RGfx(ba
, GCT_ID_GRAPHICS_MODE
) & 0xfc) | 0);
347 /* extended chain4 enable */
348 WSeq (ba
, SEQ_ID_EXT_VIDEO_ADDR
, RSeq(ba
, SEQ_ID_EXT_VIDEO_ADDR
) | 0x02);
349 /* read/write to primary on A0, secondary on B0 */
350 WSeq (ba
, SEQ_ID_EXTENDED_MEM_ENA
,
351 (RSeq(ba
, SEQ_ID_EXTENDED_MEM_ENA
) & 0x1f) | 0x40 );
353 /* fill the free lines with spaces */
355 { /* feed latches with value */
356 unsigned short * f
= (unsigned short *) fb
;
358 f
+= top
* md
->TX
* 2;
362 /* clear extended chain4 mode */
363 WSeq (ba
, SEQ_ID_EXT_VIDEO_ADDR
, RSeq(ba
, SEQ_ID_EXT_VIDEO_ADDR
) & ~0x02);
364 /* set write mode 1, "[...] data in the read latches is written
365 to memory during CPU memory write cycles. [...]" */
366 WGfx (ba
, GCT_ID_GRAPHICS_MODE
, (RGfx(ba
, GCT_ID_GRAPHICS_MODE
) & 0xfc) | 1);
369 unsigned long * p
= (unsigned long *) fb
;
370 short x
= (lines
* (md
->TX
/16)) - 1;
371 const unsigned long dummyval
= 0;
373 p
+= top
* (md
->TX
/4);
384 WGfx (ba
, GCT_ID_GRAPHICS_MODE
, (RGfx(ba
, GCT_ID_GRAPHICS_MODE
) & 0xfc) | 0);
385 /* extended chain4 enable */
386 WSeq (ba
, SEQ_ID_EXT_VIDEO_ADDR
, RSeq(ba
, SEQ_ID_EXT_VIDEO_ADDR
) | 0x02);
388 #endif /* RETINA_SPEED_HACK */
392 retina_deinit(struct ite_softc
*ip
)
394 ip
->flags
&= ~ITE_INITED
;
399 retina_putc(struct ite_softc
*ip
, int c
, int dy
, int dx
, int mode
)
401 volatile char *fb
= (volatile char*)ip
->grf
->g_fbkva
;
402 register u_char attr
;
404 attr
= (mode
& ATTR_INV
) ? 0x21 : 0x10;
405 if (mode
& ATTR_UL
) attr
= 0x01; /* ???????? */
406 if (mode
& ATTR_BOLD
) attr
|= 0x08;
407 if (mode
& ATTR_BLINK
) attr
|= 0x80;
409 fb
+= 4 * (dy
* ip
->cols
+ dx
);
410 *fb
++ = c
; *fb
= attr
;
415 retina_clear(struct ite_softc
*ip
, int sy
, int sx
, int h
, int w
)
417 volatile u_short
* fb
= (volatile u_short
*) ip
->grf
->g_fbkva
;
419 const u_short fillval
= 0x2010;
421 /* could probably be optimized just like the scrolling functions !! */
422 fb
+= 2 * (sy
* ip
->cols
+ sx
);
425 for (x
= 2 * (w
- 1); x
>= 0; x
-= 2)
433 * RETINA_SPEED_HACK code seems to work on some boards and on others
434 * it causes text to smear horizontally
437 retina_scroll(struct ite_softc
*ip
, int sy
, int sx
, int count
, int dir
)
442 ba
= ip
->grf
->g_regkva
;
443 fb
= (u_long
*)__UNVOLATILE(ip
->grf
->g_fbkva
);
445 retina_cursor(ip
, ERASE_CURSOR
);
447 if (dir
== SCROLL_UP
) {
448 #ifdef RETINA_SPEED_HACK
449 screen_up(ip
, sy
- count
, ip
->bottom_margin
, count
);
451 memcpy(fb
+ (sy
- count
) * ip
->cols
, fb
+ sy
* ip
->cols
,
452 4 * (ip
->bottom_margin
- sy
+ 1) * ip
->cols
);
453 retina_clear(ip
, ip
->bottom_margin
+ 1 - count
, 0, count
,
456 } else if (dir
== SCROLL_DOWN
) {
457 #ifdef RETINA_SPEED_HACK
458 screen_down(ip
, sy
, ip
->bottom_margin
, count
);
460 memcpy(fb
+ (sy
+ count
) * ip
->cols
, fb
+ sy
* ip
->cols
,
461 4 * (ip
->bottom_margin
- sy
- count
+ 1) * ip
->cols
);
462 retina_clear(ip
, sy
, 0, count
, ip
->cols
);
464 } else if (dir
== SCROLL_RIGHT
) {
465 memcpy(fb
+ sx
+ sy
* ip
->cols
+ count
, fb
+ sx
+ sy
* ip
->cols
,
466 4 * (ip
->cols
- (sx
+ count
)));
467 retina_clear(ip
, sy
, sx
, 1, count
);
469 memcpy(fb
+ sx
- count
+ sy
* ip
->cols
, fb
+ sx
+ sy
* ip
->cols
,
470 4 * (ip
->cols
- sx
));
471 retina_clear(ip
, sy
, ip
->cols
- count
, 1, count
);
473 #ifndef RETINA_SPEED_HACK
474 retina_cursor(ip
, !ERASE_CURSOR
);