1 /* $NetBSD: grf_obio.c,v 1.59 2019/07/26 10:48:44 rin Exp $ */
2
3 /*
4 * Copyright (C) 1998 Scott Reynolds
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 /*
30 * Copyright (c) 1995 Allen Briggs. All rights reserved.
31 *
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
34 * are met:
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 * 3. All advertising materials mentioning features or use of this software
41 * must display the following acknowledgement:
42 * This product includes software developed by Allen Briggs.
43 * 4. The name of the author may not be used to endorse or promote products
44 * derived from this software without specific prior written permission.
45 *
46 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
47 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
48 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
49 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
50 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
51 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
52 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
53 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
54 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
55 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
56 */
57 /*
58 * Graphics display driver for the Macintosh internal video for machines
59 * that don't map it into a fake nubus card.
60 */
61
62 #include <sys/cdefs.h>
63 __KERNEL_RCSID(0, "$NetBSD: grf_obio.c,v 1.59 2019/07/26 10:48:44 rin Exp $");
64
65 #include <sys/param.h>
66 #include <sys/device.h>
67 #include <sys/ioctl.h>
68 #include <sys/kmem.h>
69 #include <sys/file.h>
70 #include <sys/mman.h>
71 #include <sys/proc.h>
72 #include <sys/systm.h>
73
74 #include <machine/autoconf.h>
75 #include <machine/bus.h>
76 #include <machine/cpu.h>
77 #include <machine/grfioctl.h>
78 #include <machine/viareg.h>
79 #include <machine/video.h>
80
81 #include <mac68k/nubus/nubus.h>
82 #include <mac68k/obio/grf_obioreg.h>
83 #include <mac68k/obio/obiovar.h>
84 #include <mac68k/dev/grfvar.h>
85
86 static int grfiv_mode(struct grf_softc *, int, void *);
87 static int grfiv_match(device_t, cfdata_t, void *);
88 static void grfiv_attach(device_t, device_t, void *);
89
90 static void dafb_set_mapreg(void *, int, int, int, int);
91 static void civic_set_mapreg(void *, int, int, int, int);
92 static void valkyrie_set_mapreg(void *, int, int, int, int);
93 static void rbv_set_mapreg(void *, int, int, int, int);
94
95 CFATTACH_DECL_NEW(intvid, sizeof(struct grfbus_softc),
96 grfiv_match, grfiv_attach, NULL, NULL);
97
98 static int
grfiv_match(device_t parent,cfdata_t cf,void * aux)99 grfiv_match(device_t parent, cfdata_t cf, void *aux)
100 {
101 struct obio_attach_args *oa = (struct obio_attach_args *)aux;
102 bus_space_handle_t bsh;
103 int found;
104 u_int base;
105
106 found = 1;
107
108 switch (current_mac_model->class) {
109 case MACH_CLASSQ2:
110 if (current_mac_model->machineid != MACH_MACLC575) {
111 base = VALKYRIE_CONTROL_BASE;
112
113 if (bus_space_map(oa->oa_tag, base, 0x40, 0, &bsh))
114 return 0;
115
116 /* Disable interrupts */
117 bus_space_write_1(oa->oa_tag, bsh, 0x18, 0x1);
118
119 bus_space_unmap(oa->oa_tag, bsh, 0x40);
120 break;
121 }
122 /*
123 * Note: the only system in this class that does not have
124 * the Valkyrie chip -- at least, that we know of -- is
125 * the Performa/LC 57x series. This system has a version
126 * of the DAFB controller, instead.
127 *
128 * If this assumption proves false, we'll have to be more
129 * intelligent here.
130 */
131 /*FALLTHROUGH*/
132 case MACH_CLASSQ:
133 /*
134 * Assume DAFB for all of these, unless we can't
135 * access the memory.
136 */
137 base = DAFB_CONTROL_BASE;
138
139 if (bus_space_map(oa->oa_tag, base, 0x20, 0, &bsh))
140 return 0;
141
142 if (mac68k_bus_space_probe(oa->oa_tag, bsh, 0x1c, 4) == 0) {
143 bus_space_unmap(oa->oa_tag, bsh, 0x20);
144 return 0;
145 }
146
147 bus_space_unmap(oa->oa_tag, bsh, 0x20);
148
149 if (bus_space_map(oa->oa_tag, base + 0x100, 0x20, 0, &bsh))
150 return 0;
151
152 if (mac68k_bus_space_probe(oa->oa_tag, bsh, 0x04, 4) == 0) {
153 bus_space_unmap(oa->oa_tag, bsh, 0x20);
154 return 0;
155 }
156
157 /* Disable interrupts */
158 bus_space_write_4(oa->oa_tag, bsh, 0x04, 0);
159
160 /* Clear any interrupts */
161 bus_space_write_4(oa->oa_tag, bsh, 0x0C, 0);
162 bus_space_write_4(oa->oa_tag, bsh, 0x10, 0);
163 bus_space_write_4(oa->oa_tag, bsh, 0x14, 0);
164
165 bus_space_unmap(oa->oa_tag, bsh, 0x20);
166 break;
167 case MACH_CLASSAV:
168 base = CIVIC_CONTROL_BASE;
169
170 if (bus_space_map(oa->oa_tag, base, 0x1000, 0, &bsh))
171 return 0;
172
173 /* Disable interrupts */
174 bus_space_write_1(oa->oa_tag, bsh, 0x120, 0);
175
176 bus_space_unmap(oa->oa_tag, bsh, 0x1000);
177 break;
178 case MACH_CLASSIIci:
179 case MACH_CLASSIIsi:
180 if (mac68k_video.mv_len == 0 ||
181 (via2_reg(rMonitor) & RBVMonitorMask) == RBVMonIDNone)
182 found = 0;
183 break;
184 default:
185 if (mac68k_video.mv_len == 0)
186 found = 0;
187 break;
188 }
189
190 return found;
191 }
192
193 static void
grfiv_attach(device_t parent,device_t self,void * aux)194 grfiv_attach(device_t parent, device_t self, void *aux)
195 {
196 struct obio_attach_args *oa = (struct obio_attach_args *)aux;
197 struct grfbus_softc *sc;
198 struct grfmode *gm;
199 u_long base, length;
200 u_int32_t vbase1, vbase2;
201
202 sc = device_private(self);
203 sc->sc_dev = self;
204
205 sc->card_id = 0;
206
207 switch (current_mac_model->class) {
208 case MACH_CLASSQ2:
209 if (current_mac_model->machineid != MACH_MACLC575) {
210 sc->sc_basepa = VALKYRIE_FB_BASE;
211 length = 0x00100000; /* 1MB */
212
213 if (sc->sc_basepa <= mac68k_video.mv_phys &&
214 mac68k_video.mv_phys < (sc->sc_basepa + length)) {
215 sc->sc_fbofs =
216 mac68k_video.mv_phys - sc->sc_basepa;
217 } else {
218 sc->sc_basepa =
219 m68k_trunc_page(mac68k_video.mv_phys);
220 sc->sc_fbofs =
221 m68k_page_offset(mac68k_video.mv_phys);
222 length = mac68k_video.mv_len + sc->sc_fbofs;
223 }
224
225 if (bus_space_map(sc->sc_tag, VALKYRIE_CMAP_BASE,
226 VALKYRIE_CMAP_LEN, 0, &sc->sc_cmh) == 0)
227 sc->sc_set_mapreg = valkyrie_set_mapreg;
228
229 printf(" @ %lx: Valkyrie video subsystem\n",
230 sc->sc_basepa + sc->sc_fbofs);
231 break;
232 }
233 /* See note in grfiv_match() */
234 /*FALLTHROUGH*/
235 case MACH_CLASSQ:
236 base = DAFB_CONTROL_BASE;
237 sc->sc_tag = oa->oa_tag;
238 if (bus_space_map(sc->sc_tag, base, 0x20, 0, &sc->sc_regh)) {
239 printf(": failed to map DAFB register space\n");
240 return;
241 }
242
243 sc->sc_basepa = DAFB_FB_BASE;
244 length = 0x00100000; /* 1MB */
245
246 /* Compute the current frame buffer offset */
247 vbase1 = bus_space_read_4(sc->sc_tag, sc->sc_regh, 0x0) & 0xfff;
248 #if 1
249 /*
250 * XXX The following exists because the DAFB v7 in these
251 * systems doesn't return reasonable values to use for fbofs.
252 * Ken'ichi Ishizaka gets credit for this hack. (sar 19990426)
253 * (Does this get us the correct result for _all_ DAFB-
254 * equipped systems and monitor combinations? It seems
255 * possible, if not likely...)
256 */
257 switch (current_mac_model->machineid) {
258 case MACH_MACLC475:
259 case MACH_MACLC475_33:
260 case MACH_MACLC575:
261 case MACH_MACQ605:
262 case MACH_MACQ605_33:
263 vbase1 &= 0x3f;
264 break;
265 }
266 #endif
267 vbase2 = bus_space_read_4(sc->sc_tag, sc->sc_regh, 0x4) & 0xf;
268 sc->sc_fbofs = (vbase1 << 9) | (vbase2 << 5);
269
270 if (bus_space_map(sc->sc_tag, DAFB_CMAP_BASE, DAFB_CMAP_LEN,
271 0, &sc->sc_cmh) == 0) {
272 uint8_t *buf = kmem_zalloc(256 * 3, KM_SLEEP);
273 sc->sc_cmap.red = buf;
274 sc->sc_cmap.green = buf + 256;
275 sc->sc_cmap.blue = buf + 256 * 2;
276 sc->sc_set_mapreg = dafb_set_mapreg;
277 }
278
279 printf(" @ %lx: DAFB video subsystem, monitor sense %x\n",
280 sc->sc_basepa + sc->sc_fbofs,
281 (bus_space_read_4(sc->sc_tag, sc->sc_regh, 0x1c) & 0x7));
282
283 bus_space_unmap(sc->sc_tag, sc->sc_regh, 0x20);
284 break;
285 case MACH_CLASSAV:
286 sc->sc_basepa = CIVIC_FB_BASE;
287 length = 0x00200000; /* 2MB */
288 if (mac68k_video.mv_phys >= sc->sc_basepa &&
289 mac68k_video.mv_phys < (sc->sc_basepa + length)) {
290 sc->sc_fbofs = mac68k_video.mv_phys - sc->sc_basepa;
291 } else {
292 sc->sc_basepa = m68k_trunc_page(mac68k_video.mv_phys);
293 sc->sc_fbofs = m68k_page_offset(mac68k_video.mv_phys);
294 length = mac68k_video.mv_len + sc->sc_fbofs;
295 }
296
297 if (bus_space_map(sc->sc_tag, CIVIC_CMAP_BASE, CIVIC_CMAP_LEN,
298 0, &sc->sc_cmh) == 0)
299 sc->sc_set_mapreg = civic_set_mapreg;
300
301 printf(" @ %lx: CIVIC video subsystem\n",
302 sc->sc_basepa + sc->sc_fbofs);
303 break;
304 case MACH_CLASSIIci:
305 case MACH_CLASSIIsi:
306 sc->sc_basepa = m68k_trunc_page(mac68k_video.mv_phys);
307 sc->sc_fbofs = m68k_page_offset(mac68k_video.mv_phys);
308 length = mac68k_video.mv_len + sc->sc_fbofs;
309
310 if (bus_space_map(sc->sc_tag, RBV_CMAP_BASE, RBV_CMAP_LEN,
311 0, &sc->sc_cmh) == 0)
312 sc->sc_set_mapreg = rbv_set_mapreg;
313
314 printf(" @ %lx: RBV video subsystem, ",
315 sc->sc_basepa + sc->sc_fbofs);
316 switch (via2_reg(rMonitor) & RBVMonitorMask) {
317 case RBVMonIDBWP:
318 printf("15\" monochrome portrait");
319 break;
320 case RBVMonIDRGB12:
321 printf("12\" color");
322 break;
323 case RBVMonIDRGB15:
324 printf("15\" color");
325 break;
326 case RBVMonIDStd:
327 printf("Macintosh II");
328 break;
329 default:
330 printf("unrecognized");
331 break;
332 }
333 printf(" display\n");
334
335 break;
336 default:
337 sc->sc_basepa = m68k_trunc_page(mac68k_video.mv_phys);
338 sc->sc_fbofs = m68k_page_offset(mac68k_video.mv_phys);
339 length = mac68k_video.mv_len + sc->sc_fbofs;
340
341 /* XXX setpalette? */
342
343 printf(" @ %lx: On-board video\n",
344 sc->sc_basepa + sc->sc_fbofs);
345 break;
346 }
347
348 if (bus_space_map(sc->sc_tag, sc->sc_basepa, length, 0,
349 &sc->sc_handle)) {
350 printf("%s: failed to map video RAM\n", device_xname(sc->sc_dev));
351 return;
352 }
353
354 if (sc->sc_basepa <= mac68k_video.mv_phys &&
355 mac68k_video.mv_phys < (sc->sc_basepa + length)) {
356 /* XXX Hack */
357 mac68k_video.mv_kvaddr = sc->sc_handle.base + sc->sc_fbofs;
358 }
359
360 gm = &(sc->curr_mode);
361 gm->mode_id = 0;
362 gm->psize = mac68k_video.mv_depth;
363 gm->ptype = 0;
364 gm->width = mac68k_video.mv_width;
365 gm->height = mac68k_video.mv_height;
366 gm->rowbytes = mac68k_video.mv_stride;
367 gm->hres = 80; /* XXX hack */
368 gm->vres = 80; /* XXX hack */
369 gm->fbsize = gm->height * gm->rowbytes;
370 gm->fbbase = (void *)sc->sc_handle.base; /* XXX yet another hack */
371 gm->fboff = sc->sc_fbofs;
372
373 /* Perform common video attachment. */
374 grf_establish(sc, NULL, grfiv_mode);
375 }
376
377 static int
grfiv_mode(struct grf_softc * sc,int cmd,void * arg)378 grfiv_mode(struct grf_softc *sc, int cmd, void *arg)
379 {
380 switch (cmd) {
381 case GM_GRFON:
382 case GM_GRFOFF:
383 return 0;
384 case GM_CURRMODE:
385 break;
386 case GM_NEWMODE:
387 break;
388 case GM_LISTMODES:
389 break;
390 }
391 return EINVAL;
392 }
393
394 #define CHECK_INDEX(index) \
395 do { \
396 size_t depth = mac68k_video.mv_depth; \
397 if (depth == 1 || depth > 8 || (index) >= (1 << depth)) \
398 return; \
399 } while (0 /* CONSTCOND */)
400
401 static void
dafb_set_mapreg(void * cookie,int index,int r,int g,int b)402 dafb_set_mapreg(void *cookie, int index, int r, int g, int b)
403 {
404 struct grfbus_softc *sc = (struct grfbus_softc *)cookie;
405 static int last = -2;
406
407 CHECK_INDEX(index);
408
409 #define dafb_write_lut(val) \
410 bus_space_write_1(sc->sc_tag, sc->sc_cmh, DAFB_CMAP_LUT, val)
411
412 if (index != last + 1) {
413 bus_space_write_4(sc->sc_tag, sc->sc_cmh, DAFB_CMAP_RESET, 0);
414 for (int i = 0; i < index; i++) {
415 dafb_write_lut(sc->sc_cmap.red[i]);
416 dafb_write_lut(sc->sc_cmap.green[i]);
417 dafb_write_lut(sc->sc_cmap.blue[i]);
418 }
419 }
420
421 dafb_write_lut(r);
422 dafb_write_lut(g);
423 dafb_write_lut(b);
424
425 last = index;
426 sc->sc_cmap.red[index] = r;
427 sc->sc_cmap.green[index] = g;
428 sc->sc_cmap.blue[index] = b;
429
430 #undef dafb_write_lut
431
432 }
433
434 static void
civic_set_mapreg(void * cookie,int index,int r,int g,int b)435 civic_set_mapreg(void *cookie, int index, int r, int g, int b)
436 {
437 struct grfbus_softc *sc = (struct grfbus_softc *)cookie;
438 uint8_t status, junk = 0;
439
440 CHECK_INDEX(index);
441
442 #define civic_read_lut \
443 bus_space_read_1(sc->sc_tag, sc->sc_cmh, CIVIC_CMAP_LUT)
444 #define civic_write_lut(val) \
445 bus_space_write_1(sc->sc_tag, sc->sc_cmh, CIVIC_CMAP_LUT, val)
446
447 bus_space_write_1(sc->sc_tag, sc->sc_cmh, CIVIC_CMAP_ADDR, index);
448 status = bus_space_read_1(sc->sc_tag, sc->sc_cmh, CIVIC_CMAP_STATUS2);
449 if (status & 0x08) {
450 junk = civic_read_lut;
451 junk = civic_read_lut;
452 junk = civic_read_lut;
453 junk = civic_read_lut;
454 if (status & 0x0d) {
455 civic_write_lut(0);
456 civic_write_lut(0);
457 }
458 }
459 civic_write_lut(r);
460 civic_write_lut(g);
461 civic_write_lut(b);
462 civic_write_lut(junk);
463
464 #undef civic_read_lut
465 #undef civic_write_lut
466
467 }
468
469 static void
valkyrie_set_mapreg(void * cookie,int index,int r,int g,int b)470 valkyrie_set_mapreg(void *cookie, int index, int r, int g, int b)
471 {
472 struct grfbus_softc *sc = (struct grfbus_softc *)cookie;
473
474 CHECK_INDEX(index);
475
476 #define valkyrie_write_lut(val) \
477 bus_space_write_1(sc->sc_tag, sc->sc_cmh, VALKYRIE_CMAP_LUT, val)
478
479 bus_space_write_1(sc->sc_tag, sc->sc_cmh, VALKYRIE_CMAP_ADDR, index);
480 delay(1);
481 valkyrie_write_lut(r);
482 valkyrie_write_lut(g);
483 valkyrie_write_lut(b);
484
485 #undef valkyrie_write_lut
486
487 }
488
489 static void
rbv_set_mapreg(void * cookie,int index,int r,int g,int b)490 rbv_set_mapreg(void *cookie, int index, int r, int g, int b)
491 {
492 struct grfbus_softc *sc = (struct grfbus_softc *)cookie;
493
494 CHECK_INDEX(index);
495
496 #define rbv_write_lut(val) \
497 bus_space_write_1(sc->sc_tag, sc->sc_cmh, RBV_CMAP_LUT, val)
498
499 index += 256 - (1 << mac68k_video.mv_depth);
500 bus_space_write_1(sc->sc_tag, sc->sc_cmh, RBV_CMAP_CNTL, 0xff);
501 bus_space_write_1(sc->sc_tag, sc->sc_cmh, RBV_CMAP_ADDR, index);
502 rbv_write_lut(r);
503 rbv_write_lut(g);
504 rbv_write_lut(b);
505
506 #undef rbv_write_lut
507
508 }
509
510 #undef CHECK_INDEX
511