grf_cc.c revision 1.1.1.1 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