1 /* $NetBSD: grfabs_fal.c,v 1.25 2009/07/19 05:43:22 tsutsui Exp $ */
4 * Copyright (c) 1995 Thomas Gerner.
5 * Copyright (c) 1995 Leo Weppelman.
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.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: grfabs_fal.c,v 1.25 2009/07/19 05:43:22 tsutsui Exp $");
34 * atari abstract graphics driver: Falcon-interface
36 #include <sys/param.h>
37 #include <sys/queue.h>
38 #include <sys/malloc.h>
39 #include <sys/device.h>
40 #include <sys/systm.h>
42 #include <uvm/uvm_extern.h>
44 #include <machine/iomap.h>
45 #include <machine/video.h>
46 #include <machine/mfp.h>
47 #include <atari/atari/device.h>
48 #include <atari/atari/stalloc.h>
49 #include <atari/dev/grfabs_reg.h>
50 #include <atari/dev/grfabs_fal.h>
55 static void init_view(view_t
*, bmap_t
*, dmode_t
*, box_t
*);
56 static bmap_t
*alloc_bitmap(u_long
, u_long
, u_char
);
57 static colormap_t
*alloc_colormap(dmode_t
*);
58 static void free_bitmap(bmap_t
*);
59 static void falcon_display_view(view_t
*);
60 static view_t
*falcon_alloc_view(dmode_t
*, dimen_t
*, u_char
);
61 static void falcon_free_view(view_t
*);
62 static void falcon_remove_view(view_t
*);
63 static void falcon_save_view(view_t
*);
64 static int falcon_use_colormap(view_t
*, colormap_t
*);
65 static void falcon_detect(dmode_t
*);
66 static struct videl
*falcon_getreg(u_short
);
69 * Our function switch table
71 struct grfabs_sw fal_vid_sw
= {
80 struct falcon_hwregs
{
81 u_short fal_mode
; /* falcon mode */
82 struct videl
*fal_regs
; /* videl register values */
84 #define vm_mode(dm) (((struct falcon_hwregs*)(dm->data))->fal_mode)
85 #define vm_regs(dm) (((struct falcon_hwregs*)(dm->data))->fal_regs)
88 * Note that the order of this table *must* match the order of
91 static struct falcon_hwregs fal_hwregs
[] = {
105 static dmode_t vid_modes
[] = {
106 { {NULL
,NULL
}, "falauto", { 0, 0 }, 0, NULL
, &fal_vid_sw
},
107 { {NULL
,NULL
}, "sthigh", { 640,400 }, 1, NULL
, &fal_vid_sw
},
108 { {NULL
,NULL
}, "stmid", { 640,200 }, 2, NULL
, &fal_vid_sw
},
109 { {NULL
,NULL
}, "stlow", { 320,200 }, 4, NULL
, &fal_vid_sw
},
110 { {NULL
,NULL
}, "ttlow", { 320,480 }, 8, NULL
, &fal_vid_sw
},
111 { {NULL
,NULL
}, "vga2", { 640,480 }, 1, NULL
, &fal_vid_sw
},
112 { {NULL
,NULL
}, "vga4", { 640,480 }, 2, NULL
, &fal_vid_sw
},
113 { {NULL
,NULL
}, "vga16", { 640,480 }, 4, NULL
, &fal_vid_sw
},
114 { {NULL
,NULL
}, "vga256", { 640,480 }, 8, NULL
, &fal_vid_sw
},
115 { {NULL
,NULL
}, "highcol", { 320,200 }, 16, NULL
, &fal_vid_sw
},
116 { {NULL
,NULL
}, NULL
, }
120 * The following table contains timing values for the various video modes.
121 * I have only a multisync display, therefore I can not say if this values
122 * are useful at other displays.
123 * Use other video modes at YOUR OWN RISK.
124 * THERE IS NO WARRENTY ABOUT THIS VALUES TO WORK WITH A PARTICULAR
127 static struct videl videlinit
[] = {
128 { RES_FALAUTO
, /* autodedect */
129 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
130 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
132 { FAL_VGA
| RES_FAL_STHIGH
, /* sthigh, 640x400, 2 colors */
133 0x2, 0x0, 0x28, 0x0, 0x400, 0xc6, 0x8d, 0x15, 0x273, 0x50, 0x96, 0x0,
134 0x0, 0x419, 0x3af, 0x8f, 0x8f, 0x3af, 0x415, 0x186, 0x8 },
137 { FAL_SM
| RES_FAL_STHIGH
, /* sthigh, 640x400, 2 colors */
138 0x0, 0x0, 0x28, 0x2, 0x0, 0x1a, 0x0, 0x0, 0x20f, 0xc, 0x14, 0x0,
139 0x0, 0x3e9, 0x0, 0x0, 0x43, 0x363, 0x3e7, 0x80, 0x8 },
142 { FAL_VGA
| RES_FAL_STMID
, /* stmid, 640x200, 4 colors */
143 0x2, 0x0, 0x50, 0x1, 0x0, 0x17, 0x12, 0x1, 0x20e, 0xd, 0x11, 0x0,
144 0x0, 0x419, 0x3af, 0x8f, 0x8f, 0x3af, 0x415, 0x186, 0x9 },
146 { FAL_VGA
| RES_FAL_STLOW
, /* stlow, 320x200, 16 colors */
147 0x2, 0x0, 0x50, 0x0, 0x0, 0x17, 0x12, 0x1, 0x20e, 0xd, 0x11, 0x0,
148 0x0, 0x419, 0x3af, 0x8f, 0x8f, 0x3af, 0x415, 0x186, 0x5 },
150 { FAL_VGA
| RES_FAL_TTLOW
, /* ttlow, 320x480, 256 colors */
151 0x2, 0x0, 0xa0, 0x0, 0x10, 0xc6, 0x8d, 0x15, 0x29a, 0x7b, 0x96, 0x0,
152 0x0, 0x419, 0x3ff, 0x3f, 0x3f, 0x3ff, 0x415, 0x186, 0x4 },
154 { FAL_VGA
| RES_VGA2
, /* vga, 640x480, 2 colors */
155 0x2, 0x0, 0x28, 0x0, 0x400, 0xc6, 0x8d, 0x15, 0x273, 0x50, 0x96, 0x0,
156 0x0, 0x419, 0x3ff, 0x3f, 0x3f, 0x3ff, 0x415, 0x186, 0x8 },
158 { FAL_VGA
| RES_VGA4
, /* vga, 640x480, 4 colors */
159 0x2, 0x0, 0x50, 0x1, 0x0, 0x17, 0x12, 0x1, 0x20e, 0xd, 0x11, 0x0,
160 0x0, 0x419, 0x3ff, 0x3f, 0x3f, 0x3ff, 0x415, 0x186, 0x8 },
162 { FAL_VGA
| RES_VGA16
, /* vga, 640x480, 16 colors */
163 0x2, 0x0, 0xa0, 0x1, 0x0, 0xc6, 0x8d, 0x15, 0x2a3, 0x7c, 0x96, 0x0,
164 0x0, 0x419, 0x3ff, 0x3f, 0x3f, 0x3ff, 0x415, 0x186, 0x8 },
166 { FAL_VGA
| RES_VGA256
, /* vga, 640x480, 256 colors */
167 0x2, 0x0, 0x140, 0x1, 0x10, 0xc6, 0x8d, 0x15, 0x2ab, 0x84, 0x96, 0x0,
168 0x0, 0x419, 0x3ff, 0x3f, 0x3f, 0x3ff, 0x415, 0x186, 0x8 },
170 { FAL_VGA
| RES_DIRECT
, /* direct video, 320x200, 65536 colors */
171 0x2, 0x0, 0x140, 0x0, 0x100, 0xc6, 0x8d, 0x15, 0x2ac, 0x91, 0x96, 0x0,
172 0x0, 0x419, 0x3ff, 0x3f, 0x3f, 0x3ff, 0x415, 0x186, 0x4 },
174 { 0xffff } /* end of list */
177 static u_short mon_type
;
179 * XXX: called from ite console init routine.
180 * Initialize list of possible video modes.
183 falcon_probe_video(MODES
*modelp
)
189 mon_type
= *(volatile unsigned char *)(AD_FAL_MON_TYPE
);
190 mon_type
= (mon_type
& 0xc0) << 2;
193 * get all possible modes
196 for (i
= 0; (dm
= &vid_modes
[i
])->name
!= NULL
; i
++) {
197 dm
->data
= (void *)&fal_hwregs
[i
];
198 if (vm_mode(dm
) == RES_FALAUTO
) {
199 vm_regs(dm
) = falcon_getreg(RES_FALAUTO
);
201 LIST_INSERT_HEAD(modelp
, dm
, link
);
203 vregs
= falcon_getreg(vm_mode(dm
) | mon_type
);
206 LIST_INSERT_HEAD(modelp
, dm
, link
);
212 * This seems to prevent bordered screens.
214 for (i
=0; i
< 16; i
++)
215 VIDEO
->vd_fal_rgb
[i
] = CM_L2FAL(gra_def_color16
[i
]);
218 static struct videl
*
219 falcon_getreg(u_short mode
)
224 for (i
= 0; (vregs
= &videlinit
[i
])->video_mode
!= 0xffff; i
++)
225 if ((vregs
->video_mode
) == mode
)
228 return NULL
; /* mode not found */
232 falcon_detect(dmode_t
*dm
)
234 u_short falshift
, stshift
;
235 struct videl
*vregs
= vm_regs(dm
);
238 * First get the videl register values
241 vregs
->vd_syncmode
= VIDEO
->vd_sync
;
242 vregs
->vd_line_wide
= VIDEO
->vd_line_wide
;
243 vregs
->vd_vert_wrap
= VIDEO
->vd_vert_wrap
;
244 vregs
->vd_st_res
= VIDEO
->vd_st_res
;
245 vregs
->vd_fal_res
= VIDEO
->vd_fal_res
;
246 vregs
->vd_h_hold_tim
= VIDEO
->vd_h_hold_tim
;
247 vregs
->vd_h_bord_beg
= VIDEO
->vd_h_bord_beg
;
248 vregs
->vd_h_bord_end
= VIDEO
->vd_h_bord_end
;
249 vregs
->vd_h_dis_beg
= VIDEO
->vd_h_dis_beg
;
250 vregs
->vd_h_dis_end
= VIDEO
->vd_h_dis_end
;
251 vregs
->vd_h_ss
= VIDEO
->vd_h_ss
;
252 vregs
->vd_h_fs
= VIDEO
->vd_h_fs
;
253 vregs
->vd_h_hh
= VIDEO
->vd_h_hh
;
254 vregs
->vd_v_freq_tim
= VIDEO
->vd_v_freq_tim
;
255 vregs
->vd_v_bord_beg
= VIDEO
->vd_v_bord_beg
;
256 vregs
->vd_v_bord_end
= VIDEO
->vd_v_bord_end
;
257 vregs
->vd_v_dis_beg
= VIDEO
->vd_v_dis_beg
;
258 vregs
->vd_v_dis_end
= VIDEO
->vd_v_dis_end
;
259 vregs
->vd_v_ss
= VIDEO
->vd_v_ss
;
260 vregs
->vd_fal_ctrl
= VIDEO
->vd_fal_ctrl
;
261 vregs
->vd_fal_mode
= VIDEO
->vd_fal_mode
;
265 * Calculate the depth of the screen
268 falshift
= vregs
->vd_fal_res
;
269 stshift
= vregs
->vd_st_res
;
271 if (falshift
& 0x400) /* 2 color */
273 else if (falshift
& 0x100) /* high color, direct */
275 else if (falshift
& 0x10) /* 256 color */
277 else if (stshift
== 0) /* 16 color */
279 else if (stshift
== 1) /* 4 color */
281 else dm
->depth
= 1; /* 2 color */
284 * Now calculate the screen hight
287 dm
->size
.height
= vregs
->vd_v_dis_end
- vregs
->vd_v_dis_beg
;
288 if (!((vregs
->vd_fal_mode
& 0x2) >> 1)) /* if not interlaced */
289 dm
->size
.height
>>=1;
290 if (vregs
->vd_fal_mode
& 0x1) /* if doublescan */
291 dm
->size
.height
>>=1;
297 dm
->size
.width
= vregs
->vd_vert_wrap
* 16 / dm
->depth
;
301 u_long falcon_needs_vbl
;
302 void falcon_display_switch(void);
305 falcon_display_view(view_t
*v
)
307 dmode_t
*dm
= v
->mode
;
310 static u_short last_mode
= 0xffff;
312 if (dm
->current_view
) {
314 * Mark current view for this mode as no longer displayed
316 dm
->current_view
->flags
&= ~VF_DISPLAY
;
318 dm
->current_view
= v
;
319 v
->flags
|= VF_DISPLAY
;
320 vregs
= vm_regs(v
->mode
);
322 falcon_use_colormap(v
, v
->colormap
);
325 VIDEO
->vd_ramh
= ((u_long
)bm
->hw_address
>> 16) & 0xff;
326 VIDEO
->vd_ramm
= ((u_long
)bm
->hw_address
>> 8) & 0xff;
327 VIDEO
->vd_raml
= (u_long
)bm
->hw_address
& 0xff;
329 if (last_mode
!= vregs
->video_mode
) {
330 last_mode
= vregs
->video_mode
;
332 if (dm
->depth
== 1) {
334 * Set the resolution registers to a mode, which guarantee
335 * no shifting when the register are written during vbl.
337 VIDEO
->vd_fal_res
= 0;
338 VIDEO
->vd_st_res
= 0;
342 * Arrange for them to be activated
343 * at the second vbl interrupt.
345 falcon_needs_vbl
= (u_long
)v
;
350 falcon_display_switch(void)
354 static int vbl_count
= 1;
356 if(vbl_count
--) return;
358 v
= (view_t
*)falcon_needs_vbl
;
361 falcon_needs_vbl
= 0;
364 * Write to videl registers only on VGA displays
365 * This is only a hack. Must be fixed soon. XXX -- Thomas
367 if(mon_type
!= FAL_VGA
) return;
369 vregs
= vm_regs(v
->mode
);
371 VIDEO
->vd_v_freq_tim
= vregs
->vd_v_freq_tim
;
372 VIDEO
->vd_v_ss
= vregs
->vd_v_ss
;
373 VIDEO
->vd_v_bord_beg
= vregs
->vd_v_bord_beg
;
374 VIDEO
->vd_v_bord_end
= vregs
->vd_v_bord_end
;
375 VIDEO
->vd_v_dis_beg
= vregs
->vd_v_dis_beg
;
376 VIDEO
->vd_v_dis_end
= vregs
->vd_v_dis_end
;
377 VIDEO
->vd_h_hold_tim
= vregs
->vd_h_hold_tim
;
378 VIDEO
->vd_h_ss
= vregs
->vd_h_ss
;
379 VIDEO
->vd_h_bord_beg
= vregs
->vd_h_bord_beg
;
380 VIDEO
->vd_h_bord_end
= vregs
->vd_h_bord_end
;
381 VIDEO
->vd_h_dis_beg
= vregs
->vd_h_dis_beg
;
382 VIDEO
->vd_h_dis_end
= vregs
->vd_h_dis_end
;
383 #if 0 /* This seems not to be necessary -- Thomas */
384 VIDEO
->vd_h_fs
= vregs
->vd_h_fs
;
385 VIDEO
->vd_h_hh
= vregs
->vd_h_hh
;
387 VIDEO
->vd_sync
= vregs
->vd_syncmode
;
388 VIDEO
->vd_fal_res
= 0;
389 if (v
->mode
->depth
== 2)
390 VIDEO
->vd_st_res
= vregs
->vd_st_res
;
392 VIDEO
->vd_st_res
= 0;
393 VIDEO
->vd_fal_res
= vregs
->vd_fal_res
;
395 VIDEO
->vd_vert_wrap
= vregs
->vd_vert_wrap
;
396 VIDEO
->vd_line_wide
= vregs
->vd_line_wide
;
397 VIDEO
->vd_fal_ctrl
= vregs
->vd_fal_ctrl
;
398 VIDEO
->vd_fal_mode
= vregs
->vd_fal_mode
;
402 falcon_remove_view(view_t
*v
)
404 dmode_t
*mode
= v
->mode
;
406 if (mode
->current_view
== v
) {
408 if (v
->flags
& VF_DISPLAY
)
409 panic("Cannot shutdown display"); /* XXX */
411 mode
->current_view
= NULL
;
413 v
->flags
&= ~VF_DISPLAY
;
417 falcon_save_view(view_t
*v
)
422 falcon_free_view(view_t
*v
)
425 falcon_remove_view(v
);
426 if (v
->colormap
!= &gra_con_cmap
)
427 free(v
->colormap
, M_DEVBUF
);
428 free_bitmap(v
->bitmap
);
429 if (v
!= &gra_con_view
)
435 falcon_use_colormap(view_t
*v
, colormap_t
*cm
)
438 volatile u_short
*creg
;
439 volatile u_long
*fcreg
;
451 * I guess it seems reasonable to require the maps to be
452 * of the same type...
454 if (cm
->type
!= vcm
->type
)
458 * First get the colormap addresses an calculate
459 * howmany colors are in it.
461 if (dm
->depth
== 16) /* direct color, no colormap;
462 but also not (yet) supported */
464 fcreg
= &VIDEO
->vd_fal_rgb
[0];
465 creg
= &VIDEO
->vd_st_rgb
[0];
466 ncreg
= 1 << dm
->depth
;
468 /* If first entry specified beyond capabilities -> error */
469 if (cm
->first
>= ncreg
)
473 * A little tricky, the actual colormap pointer will be NULL
474 * when view is not displaying, valid otherwise.
476 if (v
->flags
& VF_DISPLAY
) {
477 creg
= &creg
[cm
->first
];
478 fcreg
= &fcreg
[cm
->first
];
484 vcreg
= &vcm
->entry
[cm
->first
];
486 last_streg
= 16 - cm
->first
;
487 if (cm
->size
> ncreg
)
491 for (i
= 0, src
= cm
->entry
; i
< ncreg
; i
++, vcreg
++) {
495 * If displaying, also update actual color register.
498 *fcreg
++ = CM_L2FAL(*vcreg
);
500 *creg
++ = CM_L2ST(*vcreg
);
507 falcon_alloc_view(dmode_t
*mode
, dimen_t
*dim
, u_char depth
)
512 if (!atari_realconfig
)
514 else v
= malloc(sizeof(*v
), M_DEVBUF
, M_NOWAIT
);
518 bm
= alloc_bitmap(mode
->size
.width
, mode
->size
.height
, mode
->depth
);
522 v
->colormap
= alloc_colormap(mode
);
524 INIT_BOX(&box
,0,0,mode
->size
.width
,mode
->size
.height
);
525 init_view(v
, bm
, mode
, &box
);
530 if (v
!= &gra_con_view
)
536 init_view(view_t
*v
, bmap_t
*bm
, dmode_t
*mode
, box_t
*dbox
)
541 memcpy(&v
->display
, dbox
, sizeof(box_t
));
544 /* bitmap functions */
547 alloc_bitmap(u_long width
, u_long height
, u_char depth
)
549 u_long total_size
, bm_size
;
554 * Sigh, it seems for mapping to work we need the bitplane data to
555 * 1: be aligned on a page boundry.
556 * 2: be n pages large.
558 * why? because the user gets a page aligned address, if this is before
559 * your allocation, too bad. Also it seems that the mapping routines
560 * do not watch to closely to the allowable length. so if you go over
561 * n pages by less than another page, the user gets to write all over
562 * the entire page. Since you did not allocate up to a page boundry
563 * (or more) the user writes into someone elses memory. -ch
565 bm_size
= m68k_round_page((width
* height
* depth
) / NBBY
);
566 total_size
= bm_size
+ sizeof(bmap_t
) + PAGE_SIZE
;
568 if ((bm
= (bmap_t
*)alloc_stmem(total_size
, &hw_address
)) == NULL
)
571 bm
->plane
= (u_char
*)bm
+ sizeof(bmap_t
);
572 bm
->plane
= (u_char
*)m68k_round_page(bm
->plane
);
573 bm
->hw_address
= (u_char
*)hw_address
+ sizeof(bmap_t
);
574 bm
->hw_address
= (u_char
*)m68k_round_page(bm
->hw_address
);
575 bm
->bytes_per_row
= (width
* depth
) / NBBY
;
578 bm
->phys_mappable
= (depth
* width
* height
) / NBBY
;
582 bm
->vga_address
= NULL
;
583 bm
->vga_mappable
= 0;
587 memset(bm
->plane
, 0, bm_size
);
592 free_bitmap(bmap_t
*bm
)
599 alloc_colormap(dmode_t
*dm
)
603 u_char type
= CM_COLOR
;
605 if (dm
->depth
== 16) /* direct color, no colormap;
606 not (yet) supported */
609 nentries
= 1 << dm
->depth
;
611 if (!atari_realconfig
) {
613 cm
->entry
= gra_con_colors
;
618 size
= sizeof(*cm
) + (nentries
* sizeof(cm
->entry
[0]));
619 cm
= malloc(size
, M_DEVBUF
, M_NOWAIT
);
622 cm
->entry
= (long *)&cm
[1];
626 if ((cm
->type
= type
) == CM_COLOR
)
627 cm
->red_mask
= cm
->green_mask
= cm
->blue_mask
= 0x3f;
632 for (i
= 0; i
< nentries
; i
++)
633 cm
->entry
[i
] = gra_def_color16
[i
% 16];
636 #endif /* FALCON_VIDEO */