1 #include <linux/kernel.h>
2 #include <linux/errno.h>
3 #include <linux/string.h>
4 #include <linux/mm.h>
5 #include <linux/tty.h>
6 #include <linux/slab.h>
7 #include <linux/delay.h>
8 #include <linux/interrupt.h>
9 #include <asm/setup.h>
10 #include <asm/segment.h>
11 #include <asm/system.h>
12 #include <asm/irq.h>
13 #include <asm/amigahw.h>
14 #include <asm/amigaints.h>
15 #include <asm/apollohw.h>
16 #include <linux/fb.h>
17 #include <linux/module.h>
18 #include <video/fbcon.h>
19 #include <video/fbcon-mfb.h>
20 #include "dn_accel.h"
21 
22 /* apollo video HW definitions */
23 
24 /*
25  * Control Registers.   IOBASE + $x
26  *
27  * Note: these are the Memory/IO BASE definitions for a mono card set to the
28  * alternate address
29  *
30  * Control 3A and 3B serve identical functions except that 3A
31  * deals with control 1 and 3b deals with Color LUT reg.
32  */
33 
34 #define AP_IOBASE       0x3d0          /* Base address of 1 plane board. */
35 #define AP_STATUS       isaIO2mem(AP_IOBASE+0) /* Status register.  Read */
36 #define AP_WRITE_ENABLE isaIO2mem(AP_IOBASE+0) /* Write Enable Register Write */
37 #define AP_DEVICE_ID    isaIO2mem(AP_IOBASE+1) /* Device ID Register. Read */
38 #define AP_ROP_1        isaIO2mem(AP_IOBASE+2) /* Raster Operation reg. Write Word */
39 #define AP_DIAG_MEM_REQ isaIO2mem(AP_IOBASE+4) /* Diagnostic Memory Request. Write Word */
40 #define AP_CONTROL_0    isaIO2mem(AP_IOBASE+8) /* Control Register 0.  Read/Write */
41 #define AP_CONTROL_1    isaIO2mem(AP_IOBASE+0xa) /* Control Register 1.  Read/Write */
42 #define AP_CONTROL_2    isaIO2mem(AP_IOBASE+0xc) /* Control Register 2. Read/Write */
43 #define AP_CONTROL_3A   isaIO2mem(AP_IOBASE+0xe) /* Control Register 3a. Read/Write */
44 #define AP_LUT_RED     isaIO2mem(AP_IOBASE+9) /* Red Lookup Table register. Write */
45 #define AP_LUT_GREEN  isaIO2mem(AP_IOBASE+0xb) /* Green Lookup Table register. Write */
46 #define AP_LUT_BLUE   isaIO2mem(AP_IOBASE+0xd) /* Blue Lookup Table register. Write */
47 #define AP_AD_CHANNEL   isaIO2mem(AP_IOBASE+0xf) /* A/D Result/Channel register. Read/Write */
48 
49 
50 #define FRAME_BUFFER_START 0x0A0000
51 #define FRAME_BUFFER_LEN 0x20000
52 
53 /* CREG 0 */
54 #define VECTOR_MODE 0x40 /* 010x.xxxx */
55 #define DBLT_MODE   0x80 /* 100x.xxxx */
56 #define NORMAL_MODE 0xE0 /* 111x.xxxx */
57 #define SHIFT_BITS  0x1F /* xxx1.1111 */
58         /* other bits are Shift value */
59 
60 /* CREG 1 */
61 #define AD_BLT      0x80 /* 1xxx.xxxx */
62 
63 #define ROP_EN          0x10 /* xxx1.xxxx */
64 #define DST_EQ_SRC      0x00 /* xxx0.xxxx */
65 #define nRESET_SYNC     0x08 /* xxxx.1xxx */
66 #define SYNC_ENAB       0x02 /* xxxx.xx1x */
67 
68 #define BLANK_DISP      0x00 /* xxxx.xxx0 */
69 #define ENAB_DISP       0x01 /* xxxx.xxx1 */
70 
71 #define NORM_CREG1      (nRESET_SYNC | SYNC_ENAB | ENAB_DISP) /* no reset sync */
72 
73 /* CREG 2B */
74 
75 /*
76  * Following 3 defines are common to 1, 4 and 8 plane.
77  */
78 
79 #define S_DATA_1s   0x00 /* 00xx.xxxx */ /* set source to all 1's -- vector drawing */
80 #define S_DATA_PIX  0x40 /* 01xx.xxxx */ /* takes source from ls-bits and replicates over 16 bits */
81 #define S_DATA_PLN  0xC0 /* 11xx.xxxx */ /* normal, each data access =16-bits in
82  one plane of image mem */
83 
84 /* CREG 3A/CREG 3B */
85 #       define RESET_CREG 0x80 /* 1000.0000 */
86 
87 /* ROP REG  -  all one nibble */
88 /*      ********* NOTE : this is used r0,r1,r2,r3 *********** */
89 #define ROP(r2,r3,r0,r1) ( (U_SHORT)((r0)|((r1)<<4)|((r2)<<8)|((r3)<<12)) )
90 #define DEST_ZERO               0x0
91 #define SRC_AND_DEST    0x1
92 #define SRC_AND_nDEST   0x2
93 #define SRC                             0x3
94 #define nSRC_AND_DEST   0x4
95 #define DEST                    0x5
96 #define SRC_XOR_DEST    0x6
97 #define SRC_OR_DEST             0x7
98 #define SRC_NOR_DEST    0x8
99 #define SRC_XNOR_DEST   0x9
100 #define nDEST                   0xA
101 #define SRC_OR_nDEST    0xB
102 #define nSRC                    0xC
103 #define nSRC_OR_DEST    0xD
104 #define SRC_NAND_DEST   0xE
105 #define DEST_ONE                0xF
106 
107 #define SWAP(A) ((A>>8) | ((A&0xff) <<8))
108 
109 
110 /* frame buffer operations */
111 
112 static int dn_fb_get_fix(struct fb_fix_screeninfo *fix, int con,
113 			 struct fb_info *info);
114 static int dn_fb_get_var(struct fb_var_screeninfo *var, int con,
115 			 struct fb_info *info);
116 static int dn_fb_set_var(struct fb_var_screeninfo *var, int isactive,
117 			 struct fb_info *info);
118 static int dn_fb_get_cmap(struct fb_cmap *cmap,int kspc,int con,
119 			  struct fb_info *info);
120 static int dn_fb_set_cmap(struct fb_cmap *cmap,int kspc,int con,
121 			  struct fb_info *info);
122 
123 static int dnfbcon_switch(int con,struct fb_info *info);
124 static int dnfbcon_updatevar(int con,struct fb_info *info);
125 static void dnfbcon_blank(int blank,struct fb_info *info);
126 
127 static void dn_fb_set_disp(int con,struct fb_info *info);
128 
129 static struct display disp[MAX_NR_CONSOLES];
130 static struct fb_info fb_info;
131 static struct fb_ops dn_fb_ops = {
132 	owner:		THIS_MODULE,
133 	fb_get_fix:	dn_fb_get_fix,
134 	fb_get_var:	dn_fb_get_var,
135 	fb_set_var:	dn_fb_set_var,
136 	fb_get_cmap:	dn_fb_get_cmap,
137 	fb_set_cmap:	dn_fb_set_cmap,
138 };
139 
140 static int currcon=0;
141 
142 #define NUM_TOTAL_MODES 1
143 struct fb_var_screeninfo dn_fb_predefined[] = {
144 
145 	{ 0, },
146 
147 };
148 
149 static char dn_fb_name[]="Apollo ";
150 
151 /* accel stuff */
152 #define USE_DN_ACCEL
153 
154 static struct display_switch dispsw_apollofb;
155 
dn_fb_get_fix(struct fb_fix_screeninfo * fix,int con,struct fb_info * info)156 static int dn_fb_get_fix(struct fb_fix_screeninfo *fix, int con,
157 			 struct fb_info *info) {
158 
159 	strcpy(fix->id,"Apollo Color4");
160 	fix->smem_start=(FRAME_BUFFER_START+IO_BASE);
161 	fix->smem_len=FRAME_BUFFER_LEN;
162 	fix->type=FB_TYPE_PACKED_PIXELS;
163 	fix->type_aux=0;
164 	fix->visual=FB_VISUAL_MONO10;
165 	fix->xpanstep=0;
166 	fix->ypanstep=0;
167 	fix->ywrapstep=0;
168         fix->line_length=128;
169 
170 	return 0;
171 
172 }
173 
dn_fb_get_var(struct fb_var_screeninfo * var,int con,struct fb_info * info)174 static int dn_fb_get_var(struct fb_var_screeninfo *var, int con,
175 			 struct fb_info *info) {
176 
177 	var->xres=1024;
178 	var->yres=800;
179 	var->xres_virtual=1024;
180 	var->yres_virtual=1024;
181 	var->xoffset=0;
182 	var->yoffset=0;
183 	var->bits_per_pixel=1;
184 	var->grayscale=0;
185 	var->nonstd=0;
186 	var->activate=0;
187 	var->height=-1;
188 	var->width=-1;
189 	var->pixclock=0;
190 	var->left_margin=0;
191 	var->right_margin=0;
192 	var->hsync_len=0;
193 	var->vsync_len=0;
194 	var->sync=0;
195 	var->vmode=FB_VMODE_NONINTERLACED;
196 
197 	return 0;
198 
199 }
200 
dn_fb_set_var(struct fb_var_screeninfo * var,int con,struct fb_info * info)201 static int dn_fb_set_var(struct fb_var_screeninfo *var, int con,
202 			 struct fb_info *info) {
203 
204         printk("fb_set_var\n");
205 	if(var->xres!=1024)
206 		return -EINVAL;
207 	if(var->yres!=800)
208 		return -EINVAL;
209 	if(var->xres_virtual!=1024)
210 		return -EINVAL;
211 	if(var->yres_virtual!=1024)
212 		return -EINVAL;
213 	if(var->xoffset!=0)
214 		return -EINVAL;
215 	if(var->yoffset!=0)
216 		return -EINVAL;
217 	if(var->bits_per_pixel!=1)
218 		return -EINVAL;
219 	if(var->grayscale!=0)
220 		return -EINVAL;
221 	if(var->nonstd!=0)
222 		return -EINVAL;
223 	if(var->activate!=0)
224 		return -EINVAL;
225 	if(var->pixclock!=0)
226 		return -EINVAL;
227 	if(var->left_margin!=0)
228 		return -EINVAL;
229 	if(var->right_margin!=0)
230 		return -EINVAL;
231 	if(var->hsync_len!=0)
232 		return -EINVAL;
233 	if(var->vsync_len!=0)
234 		return -EINVAL;
235 	if(var->sync!=0)
236 		return -EINVAL;
237 	if(var->vmode!=FB_VMODE_NONINTERLACED)
238 		return -EINVAL;
239 
240 	return 0;
241 
242 }
243 
dn_fb_get_cmap(struct fb_cmap * cmap,int kspc,int con,struct fb_info * info)244 static int dn_fb_get_cmap(struct fb_cmap *cmap,int kspc,int con,
245 			  struct fb_info *info) {
246 
247 	printk("get cmap not supported\n");
248 
249 	return -EINVAL;
250 }
251 
dn_fb_set_cmap(struct fb_cmap * cmap,int kspc,int con,struct fb_info * info)252 static int dn_fb_set_cmap(struct fb_cmap *cmap,int kspc,int con,
253 			  struct fb_info *info) {
254 
255 	printk("set cmap not supported\n");
256 
257 	return -EINVAL;
258 
259 }
260 
dn_fb_set_disp(int con,struct fb_info * info)261 static void dn_fb_set_disp(int con, struct fb_info *info) {
262 
263   struct fb_fix_screeninfo fix;
264   struct display *display;
265 
266 
267   dn_fb_get_fix(&fix,con, info);
268 
269   if (con>=0)
270 	display=&fb_display[con];
271   else
272 	display=&disp[0];
273 
274   if(con==-1)
275     con=0;
276 
277    display->screen_base = (u_char *)fix.smem_start;
278 printk("screenbase: %lx\n",fix.smem_start);
279    display->visual = fix.visual;
280    display->type = fix.type;
281    display->type_aux = fix.type_aux;
282    display->ypanstep = fix.ypanstep;
283    display->ywrapstep = fix.ywrapstep;
284    display->can_soft_blank = 1;
285    display->inverse = 0;
286    display->line_length = fix.line_length;
287    display->scrollmode = SCROLL_YREDRAW;
288 #ifdef FBCON_HAS_MFB
289    display->dispsw = &fbcon_mfb;
290 #else
291    display->dispsw=&fbcon_dummy;
292 #endif
293 
294 }
295 
dnfb_init(unsigned long mem_start)296 unsigned long dnfb_init(unsigned long mem_start) {
297 
298 	int err;
299 
300 printk("dn_fb_init\n");
301 
302 	fb_info.changevar=NULL;
303 	strcpy(&fb_info.modename[0],dn_fb_name);
304 	fb_info.fontname[0]=0;
305 	fb_info.disp=disp;
306 	fb_info.switch_con=&dnfbcon_switch;
307 	fb_info.updatevar=&dnfbcon_updatevar;
308 	fb_info.blank=&dnfbcon_blank;
309 	fb_info.node = -1;
310 	fb_info.fbops = &dn_fb_ops;
311 	fb_info.flags = FBINFO_FLAG_DEFAULT;
312 
313         dn_fb_get_var(&disp[0].var,0, &fb_info);
314 	dn_fb_set_disp(-1, &fb_info);
315 
316 printk("dn_fb_init: register\n");
317 	err=register_framebuffer(&fb_info);
318 	if(err < 0) {
319 		panic("unable to register apollo frame buffer\n");
320 	}
321 
322 	/* now we have registered we can safely setup the hardware */
323 
324         outb(RESET_CREG,  AP_CONTROL_3A);
325         outb(NORMAL_MODE, AP_CONTROL_0);
326         outb((AD_BLT | DST_EQ_SRC | NORM_CREG1),  AP_CONTROL_1);
327         outb(S_DATA_PLN,  AP_CONTROL_2);
328         outw(SWAP(0x3), AP_ROP_1);
329 
330         printk("apollo frame buffer alive and kicking !\n");
331 
332 
333 	return mem_start;
334 
335 }
336 
337 
dnfbcon_switch(int con,struct fb_info * info)338 static int dnfbcon_switch(int con,  struct fb_info *info) {
339 
340 	currcon=con;
341 
342 	return 0;
343 
344 }
345 
dnfbcon_updatevar(int con,struct fb_info * info)346 static int dnfbcon_updatevar(int con,  struct fb_info *info) {
347 
348 	return 0;
349 
350 }
351 
dnfbcon_blank(int blank,struct fb_info * info)352 static void dnfbcon_blank(int blank,  struct fb_info *info) {
353 
354 	if(blank)  {
355         	outb(0x0,  AP_CONTROL_3A);
356 	}
357 	else {
358 	        outb(0x1,  AP_CONTROL_3A);
359 	}
360 
361 	return ;
362 
363 }
364 
dn_bitblt(struct display * p,int x_src,int y_src,int x_dest,int y_dest,int x_count,int y_count)365 void dn_bitblt(struct display *p,int x_src,int y_src, int x_dest, int y_dest,
366                int x_count, int y_count) {
367 
368 	int incr,y_delta,pre_read=0,x_end,x_word_count;
369 	ushort *src,dummy;
370 	uint start_mask,end_mask,dest;
371 	short i,j;
372 
373 	incr=(y_dest<=y_src) ? 1 : -1 ;
374 
375 	src=(ushort *)(p->screen_base+ y_src*p->next_line+(x_src >> 4));
376 	dest=y_dest*(p->next_line >> 1)+(x_dest >> 4);
377 
378 	if(incr>0) {
379 		y_delta=(p->next_line*8)-x_src-x_count;
380 		x_end=x_dest+x_count-1;
381 		x_word_count=(x_end>>4) - (x_dest >> 4) + 1;
382 		start_mask=0xffff0000 >> (x_dest & 0xf);
383 		end_mask=0x7ffff >> (x_end & 0xf);
384 		outb((((x_dest & 0xf) - (x_src &0xf))  % 16)|(0x4 << 5),AP_CONTROL_0);
385 		if((x_dest & 0xf) < (x_src & 0xf))
386 			pre_read=1;
387 	}
388 	else {
389 		y_delta=-((p->next_line*8)-x_src-x_count);
390 		x_end=x_dest-x_count+1;
391 		x_word_count=(x_dest>>4) - (x_end >> 4) + 1;
392 		start_mask=0x7ffff >> (x_dest & 0xf);
393 		end_mask=0xffff0000 >> (x_end & 0xf);
394 		outb(((-((x_src & 0xf) - (x_dest &0xf))) % 16)|(0x4 << 5),AP_CONTROL_0);
395 		if((x_dest & 0xf) > (x_src & 0xf))
396 			pre_read=1;
397 	}
398 
399 	for(i=0;i<y_count;i++) {
400 
401 		if(pre_read) {
402 			dummy=*src;
403 			src+=incr;
404 		}
405 
406 		if(x_word_count) {
407 			outb(start_mask,AP_WRITE_ENABLE);
408 			*src=dest;
409 			src+=incr;
410 			dest+=incr;
411 			outb(0,AP_WRITE_ENABLE);
412 
413 			for(j=1;j<(x_word_count-1);j++) {
414 				*src=dest;
415 				src+=incr;
416 				dest+=incr;
417 			}
418 
419 			outb(start_mask,AP_WRITE_ENABLE);
420 			*src=dest;
421 			dest+=incr;
422 			src+=incr;
423 		}
424 		else {
425 			outb(start_mask | end_mask, AP_WRITE_ENABLE);
426 			*src=dest;
427 			dest+=incr;
428 			src+=incr;
429 		}
430 		src+=(y_delta/16);
431 		dest+=(y_delta/16);
432 	}
433 	outb(NORMAL_MODE,AP_CONTROL_0);
434 }
435 
bmove_apollofb(struct display * p,int sy,int sx,int dy,int dx,int height,int width)436 static void bmove_apollofb(struct display *p, int sy, int sx, int dy, int dx,
437 		      int height, int width)
438 {
439 
440    int fontheight,fontwidth;
441 
442     fontheight=fontheight(p);
443     fontwidth=fontwidth(p);
444 
445 #ifdef USE_DN_ACCEL
446     dn_bitblt(p,sx,sy*fontheight,dx,dy*fontheight,width*fontwidth,
447 	      height*fontheight);
448 #else
449     u_char *src, *dest;
450     u_int rows;
451 
452     if (sx == 0 && dx == 0 && width == p->next_line) {
453 	src = p->screen_base+sy*fontheight*width;
454 	dest = p->screen_base+dy*fontheight*width;
455 	mymemmove(dest, src, height*fontheight*width);
456     } else if (dy <= sy) {
457 	src = p->screen_base+sy*fontheight*p->next_line+sx;
458 	dest = p->screen_base+dy*fontheight*p->next_line+dx;
459 	for (rows = height*fontheight; rows--;) {
460 	    mymemmove(dest, src, width);
461 	    src += p->next_line;
462 	    dest += p->next_line;
463 	}
464     } else {
465 	src = p->screen_base+((sy+height)*fontheight-1)*p->next_line+sx;
466 	dest = p->screen_base+((dy+height)*fontheight-1)*p->next_line+dx;
467 	for (rows = height*fontheight; rows--;) {
468 	    mymemmove(dest, src, width);
469 	    src -= p->next_line;
470 	    dest -= p->next_line;
471 	}
472     }
473 #endif
474 }
475 
clear_apollofb(struct vc_data * conp,struct display * p,int sy,int sx,int height,int width)476 static void clear_apollofb(struct vc_data *conp, struct display *p, int sy, int sx,
477 		      int height, int width)
478 {
479 	fbcon_mfb_clear(conp,p,sy,sx,height,width);
480 }
481 
putc_apollofb(struct vc_data * conp,struct display * p,int c,int yy,int xx)482 static void putc_apollofb(struct vc_data *conp, struct display *p, int c, int yy,
483 		     int xx)
484 {
485 	fbcon_mfb_putc(conp,p,c,yy,xx);
486 }
487 
putcs_apollofb(struct vc_data * conp,struct display * p,const unsigned short * s,int count,int yy,int xx)488 static void putcs_apollofb(struct vc_data *conp, struct display *p, const unsigned short *s,
489 		      int count, int yy, int xx)
490 {
491 	fbcon_mfb_putcs(conp,p,s,count,yy,xx);
492 }
493 
rev_char_apollofb(struct display * p,int xx,int yy)494 static void rev_char_apollofb(struct display *p, int xx, int yy)
495 {
496 	fbcon_mfb_revc(p,xx,yy);
497 }
498 
499 static struct display_switch dispsw_apollofb = {
500     setup:		fbcon_mfb_setup,
501     bmove:		bmove_apollofb,
502     clear:		clear_apollofb,
503     putc:		putc_apollofb,
504     putcs:		putcs_apollofb,
505     revc:		rev_char_apollofb,
506     fontwidthmask:	FONTWIDTH(8)
507 };
508 
509 MODULE_LICENSE("GPL");
510