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