xref: /netbsd-src/sys/arch/amiga/dev/grf_cc.c (revision cda4f8f6ee55684e8d311b86c99ea59191e6b74f)
1 #include "grf.h"
2 #if NGRF > 0
3 
4 /* Graphics routines for the AMIGA native custom chip set. */
5 
6 #include "sys/param.h"
7 #include "sys/errno.h"
8 
9 #include "grfioctl.h"
10 #include "grfvar.h"
11 #include "grf_ccreg.h"
12 
13 #include "../include/cpu.h"
14 #include "../amiga/custom.h"
15 
16 
17 extern caddr_t CHIPMEMADDR;
18 extern caddr_t chipmem_steal ();
19 
20 struct ccfb ccfb = {
21 	DEF_DISP_WIDTH, DEF_DISP_HEIGHT, DEF_DISP_X, DEF_DISP_Y, DEF_DISP_Z,
22 	0,
23 	DEF_FB_WIDTH, DEF_FB_HEIGHT, DEF_FB_X, DEF_FB_Y, DEF_FB_Z,
24 	DEF_COL0, DEF_COL1
25 };
26 
27 /* Initialize one copper list.  We'll need two to make a nice interlaced display.  */
28 
29 /* maximum size needed for a copper list (4 planes hires laced) */
30 #define COPENTS (4 * (2 * 4 + 2 + 1 + 2 + 2 + 2 + 16 * 1 + 1))
31 
32 /* copper instructions */
33 #define MOVE(cl, reg, val)  \
34 	do { *cl++ = CUSTOM_OFS(reg); *cl++ = val; } while (0)
35 #define WAIT(cl, vp, hp, bfd, ve, he) \
36 	do { *cl++ = ((vp & 0xff)<<8)|(hp & 0xfe)|1; \
37 	*cl++ = (bfd<<15)|((ve & 0x7f)<<8)|(hp & 0xfe)|1; } while (0)
38 #define STOP(cl) \
39 	do { *cl++ = 0xffff; *cl++ = 0xffff; } while (0)
40 
41 static void
42 initcop (cop, othercop, shf, fb)
43 	u_short *cop;
44 	u_short *othercop;
45 	int	shf;
46 	struct ccfb *fb;
47 {
48   long scrmem;
49   int i;
50   u_short c, strt, stop, *orig_cop = cop;
51 
52   /* get PA of display area */
53   scrmem = (long) fb->fb - (long) CHIPMEMADDR;
54 
55   othercop = (u_short *) ((long)othercop - (long) CHIPMEMADDR);
56 
57   /* account for possible interlaced half-frame */
58   if (shf)
59     scrmem += fb->fb_width >> 3;
60 
61   /* account for oversized framebuffers */
62   scrmem += (fb->fb_x >> 3) + (fb->fb_y * (fb->fb_width >> 3));
63 
64   /* initialize bitplane pointers for all planes */
65   /* remember offset in copperlist to patch later */
66   if (! fb->bplstart_off)
67     fb->bplstart_off = cop - orig_cop;
68   for (i = 0; i < fb->disp_z; i++)
69     {
70       MOVE (cop, bplpth(i), scrmem >> 16);
71       MOVE (cop, bplptl(i), scrmem & 0xffff);
72       scrmem += (fb->fb_width >> 3) * fb->fb_height;
73     }
74 
75   /* modulo is one line for interlaced displays, plus difference between
76      virtual and effective framebuffer size */
77   MOVE (cop, bpl1mod, (fb->fb_width + (fb->fb_width - fb->disp_width)) >> 3);
78   MOVE (cop, bpl2mod, (fb->fb_width + (fb->fb_width - fb->disp_width)) >> 3);
79 
80   c =   0x8000 				/* HIRES */
81       | ((fb->disp_z & 7) << 12)	/* bitplane use */
82       | 0x0200				/* composite COLOR enable (whatever this is..) */
83       | 0x0004;				/* LACE */
84 
85   MOVE (cop, bplcon0, c);
86 
87   /* these use pre-ECS register interpretation. Might want to go ECS ? */
88   strt = (((fb->disp_y >> 1) & 0xff)<<8) | ((fb->disp_x >> 1) & 0xff);
89   MOVE (cop, diwstrt, strt);
90   stop = (((((fb->disp_y + fb->disp_height + 1-shf)>>1) & 0xff)<<8)
91           | (((fb->disp_x + fb->disp_width)>>1) & 0xff));
92   MOVE (cop, diwstop, stop);
93   /* NOTE: default values for strt: 0x2c81, stop: 0xf4c1 */
94 
95   /* these are from from HW-manual.. */
96   strt = ((strt & 0xff) - 9) >> 1;
97   MOVE (cop, ddfstrt, strt);
98   stop = strt + (((fb->disp_width >> 4) - 2) << 2);
99   MOVE (cop, ddfstop, stop);
100 
101   /* setup interlaced display by constantly toggling between two copperlists */
102   MOVE (cop, cop1lch, (long)othercop >> 16);
103   MOVE (cop, cop1lcl, (long)othercop & 0xffff);
104 
105   for (i = 0; i < (1 << fb->disp_z); i++)
106     MOVE (cop, color[i], fb->col[i]);
107 
108   /* wait forever */
109   STOP (cop);
110 }
111 
112 
113 #ifdef DEBUG
114 void
115 dump_copperlist (cl)
116     u_int *cl;
117 {
118   while (*cl != 0xffffffff)
119     {
120       if (!(*cl & 0x00010000))
121         printf ("MOVE (%x, %x)\t", *cl & 0xffff, *cl >> 16);
122       else
123         printf ("WAIT (%d, %d, %d, %d, %d)\t", *cl >> 24, (*cl & 0x00fe0000)>>16,
124 		(*cl & 0x8000)>> 15, (*cl & 0x7f00)>>8, (*cl & 0xfe));
125       cl++;
126     }
127   printf ("STOP ()\n");
128 
129 }
130 #endif
131 
132 
133 /*
134  * Initialize hardware.
135  * Must point g_display at a grfinfo structure describing the hardware.
136  * Returns 0 if hardware not present, non-zero ow.
137  */
138 cc_init(gp, ad)
139 	struct grf_softc *gp;
140 	struct amiga_device *ad;
141 {
142   register struct ccfb *fb = &ccfb;
143   struct grfinfo *gi = &gp->g_display;
144   u_char *fbp, save;
145   int fboff, fbsize;
146   int s;
147 
148   /* if already initialized, fail */
149   if (fb->fb)
150     return 0;
151 
152   /* testing for the result is really redundant because chipmem_steal
153      panics if it runs out of memory.. */
154   fbsize = (fb->fb_width >> 3) * fb->fb_height * fb->fb_z;
155   if (! (fb->fb = (u_char *) chipmem_steal (fbsize))
156       || !(fb->cop1 = (u_short *) chipmem_steal (COPENTS))
157       || !(fb->cop2 = (u_short *) chipmem_steal (COPENTS)))
158     return 0;
159 
160   /* clear the display. bzero only likes regions up to 64k, so call multiple times */
161   for (fboff = 0; fboff < fbsize; fboff += 64*1024)
162     bzero (fb->fb + fboff, fbsize - fboff > 64*1024 ? 64*1024 : fbsize - fboff);
163 
164   initcop (fb->cop1, fb->cop2, 0, fb);
165   initcop (fb->cop2, fb->cop1, 1, fb);
166 
167   /* Make sure no ex-sprites are streaking down the screen */
168   {
169     int i;
170     for(i = 0;i < 8;i++)
171       {
172         custom.spr[i].data = 0;
173         custom.spr[i].datb = 0;
174       }
175   }
176 
177   /* start the new display */
178   /* disable these */
179   custom.dmacon  = (DMAF_BLTDONE | DMAF_BLTNZERO | DMAF_BLITHOG | DMAF_BLITTER
180 		    | DMAF_SPRITE | DMAF_DISK
181  		    | DMAF_AUD3 | DMAF_AUD2 | DMAF_AUD1 | DMAF_AUD0);
182   /* enable these */
183   custom.dmacon  = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER;
184 
185 #if 0
186   /* ok, this is a bit rough.. */
187   s = splhigh ();
188   /* load a first guess copperlist, verify later whether we got the right
189      one */
190   custom.cop1lc  = (void *) ((long)fb->cop1 - (long) CHIPMEMADDR);
191   custom.copjmp1 = 0;
192   /* reset VBL */
193   custom.intreq = INTF_VERTB;
194   /* wait for VBL */
195   while (! (custom.intreqr & INTF_VERTB)) ;
196   /* reset VBL */
197   custom.intreq = INTF_VERTB;
198   /* now, in a safe location, set correct copperlist based on longframe/shortframe
199      bit */
200   if (custom.vposr & 0x8000)
201     {
202       custom.cop1lc = (void *) ((long)fb->cop1 - (long) CHIPMEMADDR);
203       custom.copjmp1 = 0;	/* strobe it */
204     }
205   else
206     {
207       custom.cop1lc = (void *) ((long)fb->cop2 - (long) CHIPMEMADDR);
208       custom.copjmp1 = 0;
209     }
210   /* wait for another VBL and reset int, then go back to previous int level */
211   while (! (custom.intreqr & INTF_VERTB)) ;
212   custom.intreq = INTF_VERTB;
213   splx (s);
214 #else
215   s = splhigh();
216   /* set up copper */
217   custom.cop1lc = (void *) ((long)fb->cop1 - (long) CHIPMEMADDR);
218   custom.copjmp1 = 0;
219 
220   /* reset vertical blank interrupt */
221   custom.intreq = INTF_VERTB;
222 
223   /* wait for vertical blank interrupt */
224   while ((custom.intreqr & INTF_VERTB) != INTF_VERTB)
225 	;
226 
227   /* set bitplane pointers based on LOF/SHF bit */
228   if (custom.vposr & 0x8000)
229     {
230       custom.cop1lc = (void *) ((long)fb->cop1 - (long) CHIPMEMADDR);
231       custom.copjmp1 = 0;
232     }
233   else
234     {
235       custom.cop1lc = (void *) ((long)fb->cop2 - (long) CHIPMEMADDR);
236       custom.copjmp1 = 0;
237     }
238   splx (s);
239 #endif
240 
241   /* tame the blitter. Copying one word onto itself should put it into
242      a consistent state. This is black magic... */
243   custom.bltapt =
244     custom.bltbpt =
245       custom.bltcpt =
246         custom.bltdpt = 0;
247   custom.bltamod =
248     custom.bltbmod =
249       custom.bltcmod =
250         custom.bltdmod = 0;
251   custom.bltafwm =
252     custom.bltalwn = 0xffff;
253   custom.bltcon0 = 0x09f0;
254   custom.bltcon1 = 0;
255   custom.bltsize = 1;
256 
257   /* enable VBR interrupts. This is also done in the serial driver, but it
258      really belongs here.. */
259   custom.intena = INTF_SETCLR | INTF_VERTB;
260 
261 #if 0
262 #ifdef DEBUG
263   /* prove the display is up.. */
264   for (fboff = 0; fboff < fbsize; fboff++)
265     {
266       fb->fb[fboff] = 0xff;
267       DELAY(10);
268     }
269   for (fboff = 0; fboff < fbsize; fboff++)
270     {
271       fb->fb[fboff] = 0;
272       DELAY(10);
273     }
274 #endif
275 #endif
276 
277   gi->gd_regaddr = (caddr_t) fb;	/* XXX */
278   gi->gd_regsize = 0;
279 
280   gi->gd_fbaddr  = fb->fb - (u_char *) CHIPMEMADDR;
281   gi->gd_fbsize  = fbsize;
282 
283   gi->gd_colors  = 1 << fb->fb_z;
284   gi->gd_planes  = fb->fb_z;
285 
286   gi->gd_fbwidth  = fb->fb_width;
287   gi->gd_fbheight = fb->fb_height;
288   gi->gd_fbx	  = fb->fb_x;
289   gi->gd_fby	  = fb->fb_y;
290   gi->gd_dwidth   = fb->disp_width;
291   gi->gd_dheight  = fb->disp_height;
292   gi->gd_dx	  = fb->disp_x;
293   gi->gd_dy	  = fb->disp_y;
294 
295   gp->g_regkva = 0;	/* builtin */
296   gp->g_fbkva  = fb->fb;
297 
298   return(1);
299 }
300 
301 cc_config(gp, di)
302 	register struct grf_softc *gp;
303 	struct grfdyninfo *di;
304 {
305   register struct ccfb *fb = &ccfb;
306   struct grfinfo *gi = &gp->g_display;
307   u_char *fbp, save;
308   int fboff, fbsize;
309   int s;
310 
311   /* bottom missing... */
312 
313 }
314 
315 /*
316  * Change the mode of the display.
317  * Right now all we can do is grfon/grfoff.
318  * Return a UNIX error number or 0 for success.
319  */
320 cc_mode(gp, cmd, arg)
321 	register struct grf_softc *gp;
322 	int cmd;
323 	void *arg;
324 {
325   switch (cmd)
326     {
327     case GM_GRFON:
328       custom.dmacon  = DMAF_SETCLR | DMAF_RASTER | DMAF_COPPER;
329       return 0;
330 
331     case GM_GRFOFF:
332       custom.dmacon  = DMAF_RASTER | DMAF_COPPER;
333       return 0;
334 
335     case GM_GRFCONFIG:
336       return cc_config (gp, (struct grfdyninfo *) arg);
337 
338     default:
339       break;
340     }
341 
342   return EINVAL;
343 }
344 
345 #endif
346