Home | History | Annotate | Line # | Download | only in dev
      1 /*	$NetBSD: ite_rt.c,v 1.25 2014/01/22 00:25:16 christos Exp $ */
      2 
      3 /*
      4  * Copyright (c) 1993 Markus Wild
      5  * Copyright (c) 1993 Lutz Vieweg
      6  * All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     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
     21  *
     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.
     32  */
     33 
     34 #include <sys/cdefs.h>
     35 __KERNEL_RCSID(0, "$NetBSD: ite_rt.c,v 1.25 2014/01/22 00:25:16 christos Exp $");
     36 
     37 #include "grfrt.h"
     38 #if NGRFRT > 0
     39 
     40 #include <sys/param.h>
     41 #include <sys/conf.h>
     42 #include <sys/proc.h>
     43 #include <sys/device.h>
     44 #include <sys/ioctl.h>
     45 #include <sys/tty.h>
     46 #include <sys/systm.h>
     47 #include <dev/cons.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>
     54 
     55 int retina_console = 1;
     56 
     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 *);
     63 
     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);
     67 #endif
     68 
     69 /*
     70  * this function is called from grf_rt to init the grf_softc->g_conpri
     71  * field each time a retina is attached.
     72  */
     73 int
     74 grfrt_cnprobe(void)
     75 {
     76 	static int done;
     77 	int rv;
     78 
     79 	if (retina_console && done == 0)
     80 		rv = CN_INTERNAL;
     81 	else
     82 		rv = CN_NORMAL;
     83 	done = 1;
     84 	return(rv);
     85 }
     86 
     87 /*
     88  * init the required fields in the grf_softc struct for a
     89  * grf to function as an ite.
     90  */
     91 void
     92 grfrt_iteinit(struct grf_softc *gp)
     93 {
     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;
    100 }
    101 
    102 
    103 void
    104 retina_init(struct ite_softc *ip)
    105 {
    106 	struct MonDef *md;
    107 
    108 	ip->priv = ip->grf->g_data;
    109 	md = (struct MonDef *) ip->priv;
    110 
    111 	ip->cols = md->TX;
    112 	ip->rows = md->TY;
    113 }
    114 
    115 
    116 void
    117 retina_cursor(struct ite_softc *ip, int flag)
    118 {
    119       volatile void *ba = ip->grf->g_regkva;
    120 
    121       if (flag == ERASE_CURSOR)
    122         {
    123 	  /* disable cursor */
    124           WCrt (ba, CRT_ID_CURSOR_START, RCrt (ba, CRT_ID_CURSOR_START) | 0x20);
    125         }
    126       else
    127 	{
    128 	  int pos = ip->curx + ip->cury * ip->cols;
    129 
    130 	  /* make sure to enable cursor */
    131           WCrt (ba, CRT_ID_CURSOR_START, RCrt (ba, CRT_ID_CURSOR_START) & ~0x20);
    132 
    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);
    136 
    137 	  ip->cursorx = ip->curx;
    138 	  ip->cursory = ip->cury;
    139 	}
    140 }
    141 
    142 
    143 
    144 #ifdef	RETINA_SPEED_HACK
    145 static void
    146 screen_up(struct ite_softc *ip, int top, int bottom, int lines)
    147 {
    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;
    151 
    152 	/* do some bounds-checking here.. */
    153 	if (top >= bottom)
    154 	  return;
    155 
    156 	if (top + lines >= bottom)
    157 	  {
    158 	    retina_clear (ip, top, 0, bottom - top, ip->cols);
    159 	    return;
    160 	  }
    161 
    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.
    165 
    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. */
    172 
    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);
    178 
    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);
    183 
    184 	{
    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)));
    189 	}
    190 	{
    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))) ;
    195 	}
    196 	{
    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;
    200 		do {
    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));
    217 		} while (x--);
    218 	}
    219 
    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);
    225 		/* write mode 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);
    234 
    235 
    236 	/* fill the free lines with spaces */
    237 
    238 	{  /* feed latches with value */
    239 		unsigned short * f = (unsigned short *) fb;
    240 
    241 		f += (1 + bottom - lines) * md->TX * 2;
    242 		*f = 0x2010;
    243 	}
    244 
    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);
    250 
    251 	{
    252 		unsigned long * p = (unsigned long *) fb;
    253 		short x = (lines * (md->TX/16)) - 1;
    254 		const unsigned long dummyval = 0;
    255 
    256 		p += (1 + bottom - lines) * (md->TX/4);
    257 
    258 		do {
    259 			*p++ = dummyval;
    260 			*p++ = dummyval;
    261 			*p++ = dummyval;
    262 			*p++ = dummyval;
    263 		} while (x--);
    264 	}
    265 
    266 	   /* write mode 0 */
    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);
    270 };
    271 
    272 
    273 static void
    274 screen_down(struct ite_softc *ip, int top, int bottom, int lines)
    275 {
    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;
    279 
    280 	/* do some bounds-checking here.. */
    281 	if (top >= bottom)
    282 	  return;
    283 
    284 	if (top + lines >= bottom)
    285 	  {
    286 	    retina_clear (ip, top, 0, bottom - top, ip->cols);
    287 	    return;
    288 	  }
    289 
    290 	/* see screen_up() for explanation of chip-tricks */
    291 
    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);
    297 
    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);
    301 
    302 	{
    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)));
    307 	}
    308 	{
    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))) ;
    313 	}
    314 
    315 	{
    316 		void *p = (void *)fb;
    317 		short x = (1 + bottom - (top + lines)) * (md->TX / 16) - 1;
    318 		p += (1 + bottom - (top + lines)) * md->TX;
    319 		do {
    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));
    336 		} while (x--);
    337 	}
    338 
    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);
    343 
    344 		/* write mode 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 );
    352 
    353 	/* fill the free lines with spaces */
    354 
    355 	{  /* feed latches with value */
    356 		unsigned short * f = (unsigned short *) fb;
    357 
    358 		f += top * md->TX * 2;
    359 		*f = 0x2010;
    360 	}
    361 
    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);
    367 
    368 	{
    369 		unsigned long * p = (unsigned long *) fb;
    370 		short x = (lines * (md->TX/16)) - 1;
    371 		const unsigned long dummyval = 0;
    372 
    373 		p += top * (md->TX/4);
    374 
    375 		do {
    376 			*p++ = dummyval;
    377 			*p++ = dummyval;
    378 			*p++ = dummyval;
    379 			*p++ = dummyval;
    380 		} while (x--);
    381 	}
    382 
    383 	   /* write mode 0 */
    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);
    387 };
    388 #endif	/* RETINA_SPEED_HACK */
    389 
    390 
    391 void
    392 retina_deinit(struct ite_softc *ip)
    393 {
    394 	ip->flags &= ~ITE_INITED;
    395 }
    396 
    397 
    398 void
    399 retina_putc(struct ite_softc *ip, int c, int dy, int dx, int mode)
    400 {
    401 	volatile char *fb = (volatile char*)ip->grf->g_fbkva;
    402 	register u_char attr;
    403 
    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;
    408 
    409 	fb += 4 * (dy * ip->cols + dx);
    410 	*fb++ = c; *fb = attr;
    411 }
    412 
    413 
    414 void
    415 retina_clear(struct ite_softc *ip, int sy, int sx, int h, int w)
    416 {
    417 	volatile u_short * fb = (volatile u_short *) ip->grf->g_fbkva;
    418 	short x;
    419 	const u_short fillval = 0x2010;
    420 
    421 	/* could probably be optimized just like the scrolling functions !! */
    422 	fb += 2 * (sy * ip->cols + sx);
    423 	while (h--)
    424 	  {
    425 	    for (x = 2 * (w - 1); x >= 0; x -= 2)
    426 	      fb[x] = fillval;
    427 	    fb += 2 * ip->cols;
    428 	  }
    429 }
    430 
    431 
    432 /*
    433  * RETINA_SPEED_HACK code seems to work on some boards and on others
    434  * it causes text to smear horizontally
    435  */
    436 void
    437 retina_scroll(struct ite_softc *ip, int sy, int sx, int count, int dir)
    438 {
    439 	u_long *fb;
    440 
    441 	fb = (u_long *)__UNVOLATILE(ip->grf->g_fbkva);
    442 
    443 	retina_cursor(ip, ERASE_CURSOR);
    444 
    445 	if (dir == SCROLL_UP) {
    446 #ifdef	RETINA_SPEED_HACK
    447 		screen_up(ip, sy - count, ip->bottom_margin, count);
    448 #else
    449 		memcpy(fb + (sy - count) * ip->cols, fb + sy * ip->cols,
    450 		    4 * (ip->bottom_margin - sy + 1) * ip->cols);
    451 		retina_clear(ip, ip->bottom_margin + 1 - count, 0, count,
    452 		    ip->cols);
    453 #endif
    454 	} else if (dir == SCROLL_DOWN) {
    455 #ifdef	RETINA_SPEED_HACK
    456 		screen_down(ip, sy, ip->bottom_margin, count);
    457 #else
    458 		memcpy(fb + (sy + count) * ip->cols, fb + sy * ip->cols,
    459 		    4 * (ip->bottom_margin - sy - count + 1) * ip->cols);
    460 		retina_clear(ip, sy, 0, count, ip->cols);
    461 #endif
    462 	} else if (dir == SCROLL_RIGHT) {
    463 		memcpy(fb + sx + sy * ip->cols + count, fb + sx + sy * ip->cols,
    464 		    4 * (ip->cols - (sx + count)));
    465 		retina_clear(ip, sy, sx, 1, count);
    466 	} else {
    467 		memcpy(fb + sx - count + sy * ip->cols, fb + sx + sy * ip->cols,
    468 		    4 * (ip->cols - sx));
    469 		retina_clear(ip, sy, ip->cols - count, 1, count);
    470 	}
    471 #ifndef	RETINA_SPEED_HACK
    472 	retina_cursor(ip, !ERASE_CURSOR);
    473 #endif
    474 }
    475 
    476 #endif /* NGRFRT */
    477