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