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