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