1 /* $NetBSD: et4000.c,v 1.19 2009/03/18 17:06:43 cegger Exp $ */
3 * Copyright (c) 1998 The NetBSD Foundation, Inc.
6 * This code is derived from software contributed to The NetBSD Foundation
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
37 * for their help and for code that I could refer to when writing this driver.
39 * Defining DEBUG_ET4000 will cause the driver to *always* attach. Use for
40 * debugging register settings.
47 #include <sys/cdefs.h>
48 __KERNEL_RCSID(0, "$NetBSD: et4000.c,v 1.19 2009/03/18 17:06:43 cegger Exp $");
50 #include <sys/param.h>
51 #include <sys/ioctl.h>
52 #include <sys/queue.h>
53 #include <sys/malloc.h>
54 #include <sys/device.h>
55 #include <sys/systm.h>
57 #include <sys/event.h>
58 #include <atari/vme/vmevar.h>
60 #include <machine/iomap.h>
61 #include <machine/video.h>
62 #include <machine/mfp.h>
63 #include <machine/cpu.h>
64 #include <atari/atari/device.h>
65 #include <atari/dev/grfioctl.h>
66 #include <atari/dev/grf_etreg.h>
69 * Allow a 8Kb io-region and a 1MB frame buffer to be mapped. This
70 * is more or less required by the XFree server. The X server also
71 * requires that the frame buffer be mapped above 0x3fffff.
73 #define REG_MAPPABLE (8 * 1024) /* 0x2000 */
74 #define FRAME_MAPPABLE (1 * 1024 * 1024) /* 0x100000 */
75 #define FRAME_BASE (4 * 1024 * 1024) /* 0x400000 */
76 #define VGA_MAPPABLE (128 * 1024) /* 0x20000 */
77 #define VGA_BASE 0xa0000
79 static int et_vme_match(struct device
*, struct cfdata
*, void *);
80 static void et_vme_attach(struct device
*, struct device
*, void *);
81 static int et_probe_addresses(struct vme_attach_args
*);
82 static void et_start(bus_space_tag_t
*, bus_space_handle_t
*, int *,
84 static void et_stop(bus_space_tag_t
*, bus_space_handle_t
*, int *,
86 static int et_detect(bus_space_tag_t
*, bus_space_tag_t
*,
87 bus_space_handle_t
*, bus_space_handle_t
*, u_int
);
92 /* Register and screen memory addresses for ET4000 based VME cards */
93 static struct et_addresses
{
99 { 0xfebf0000, REG_MAPPABLE
, 0xfec00000, FRAME_MAPPABLE
}, /* Crazy Dots VME & II */
100 { 0xfed00000, REG_MAPPABLE
, 0xfec00000, FRAME_MAPPABLE
}, /* Spektrum I & HC */
101 { 0xfed80000, REG_MAPPABLE
, 0xfec00000, FRAME_MAPPABLE
} /* Spektrum TC */
104 #define NETSTD (sizeof(etstd) / sizeof(etstd[0]))
106 struct grfabs_et_priv
{
107 volatile void * regkva
;
108 volatile void * memkva
;
114 struct device sc_dev
;
115 bus_space_tag_t sc_iot
;
116 bus_space_tag_t sc_memt
;
117 bus_space_handle_t sc_ioh
;
118 bus_space_handle_t sc_memh
;
126 #define ET_SC_FLAGS_INUSE 1
128 CFATTACH_DECL(et
, sizeof(struct et_softc
),
129 et_vme_match
, et_vme_attach
, NULL
, NULL
);
131 extern struct cfdriver et_cd
;
133 dev_type_open(etopen
);
134 dev_type_close(etclose
);
135 dev_type_read(etread
);
136 dev_type_write(etwrite
);
137 dev_type_ioctl(etioctl
);
138 dev_type_mmap(etmmap
);
140 const struct cdevsw et_cdevsw
= {
141 etopen
, etclose
, etread
, etwrite
, etioctl
,
142 nostop
, notty
, nopoll
, etmmap
, nokqfilter
,
146 * Look for a ET4000 (Crazy Dots) card on the VME bus. We might
147 * match Spektrum cards too (untested).
150 et_vme_match(struct device
*pdp
, struct cfdata
*cfp
, void *auxp
)
152 struct vme_attach_args
*va
= auxp
;
154 return(et_probe_addresses(va
));
158 et_probe_addresses(struct vme_attach_args
*va
)
162 bus_space_tag_t memt
;
163 bus_space_handle_t ioh
;
164 bus_space_handle_t memh
;
169 /* Loop around our possible addresses looking for a match */
170 for (i
= 0; i
< NETSTD
; i
++) {
171 struct et_addresses
*et_ap
= &etstd
[i
];
172 struct vme_attach_args vat
= *va
;
174 if (vat
.va_irq
!= VMECF_IRQ_DEFAULT
) {
175 printf("et probe: config error: no irq support\n");
178 if (vat
.va_iobase
== VMECF_IOPORT_DEFAULT
)
179 vat
.va_iobase
= et_ap
->io_addr
;
180 if (vat
.va_maddr
== VMECF_MEM_DEFAULT
)
181 vat
.va_maddr
= et_ap
->mem_addr
;
182 if (vat
.va_iosize
== VMECF_IOSIZE_DEFAULT
)
183 vat
.va_iosize
= et_ap
->io_size
;
184 if (vat
.va_msize
== VMECF_MEMSIZ_DEFAULT
)
185 vat
.va_msize
= et_ap
->mem_size
;
186 if (bus_space_map(iot
, vat
.va_iobase
, vat
.va_iosize
, 0,
188 printf("et probe: cannot map io area\n");
191 if (bus_space_map(memt
, vat
.va_maddr
, vat
.va_msize
,
192 BUS_SPACE_MAP_LINEAR
|BUS_SPACE_MAP_CACHEABLE
,
194 bus_space_unmap(iot
, ioh
, vat
.va_iosize
);
195 printf("et probe: cannot map memory area\n");
198 found
= et_detect(&iot
, &memt
, &ioh
, &memh
, vat
.va_msize
);
199 bus_space_unmap(iot
, ioh
, vat
.va_iosize
);
200 bus_space_unmap(memt
, memh
, vat
.va_msize
);
210 et_start(bus_space_tag_t
*iot
, bus_space_handle_t
*ioh
, int *vgabase
, u_char
*saved
)
213 bus_space_write_1(*iot
, *ioh
, GREG_VIDEOSYSENABLE
, 0x01);
214 /* Check whether colour (base = 3d0) or mono (base = 3b0) mode */
215 *vgabase
= (bus_space_read_1(*iot
, *ioh
, GREG_MISC_OUTPUT_R
) & 0x01)
217 /* Enable 'Tseng Extensions' - writes to CRTC and ATC[16] */
218 bus_space_write_1(*iot
, *ioh
, GREG_HERCULESCOMPAT
, 0x03);
219 bus_space_write_1(*iot
, *ioh
, *vgabase
+ 0x08, 0xa0);
220 /* Set up 16 bit I/O, memory, Tseng addressing and linear mapping */
221 bus_space_write_1(*iot
, *ioh
, *vgabase
+ 0x04, 0x36);
222 bus_space_write_1(*iot
, *ioh
, *vgabase
+ 0x05, 0xf0);
223 /* Enable writes to CRTC[0..7] */
224 bus_space_write_1(*iot
, *ioh
, *vgabase
+ 0x04, 0x11);
225 *saved
= bus_space_read_1(*iot
, *ioh
, *vgabase
+ 0x05);
226 bus_space_write_1(*iot
, *ioh
, *vgabase
+ 0x05, *saved
& 0x7f);
227 /* Map all memory for video modes */
228 bus_space_write_1(*iot
, *ioh
, 0x3ce, 0x06);
229 bus_space_write_1(*iot
, *ioh
, 0x3cf, 0x01);
233 et_stop(bus_space_tag_t
*iot
, bus_space_handle_t
*ioh
, int *vgabase
, u_char
*saved
)
235 /* Restore writes to CRTC[0..7] */
236 bus_space_write_1(*iot
, *ioh
, *vgabase
+ 0x04, 0x11);
237 *saved
= bus_space_read_1(*iot
, *ioh
, *vgabase
+ 0x05);
238 bus_space_write_1(*iot
, *ioh
, *vgabase
+ 0x05, *saved
| 0x80);
239 /* Disable 'Tseng Extensions' */
240 bus_space_write_1(*iot
, *ioh
, *vgabase
+ 0x08, 0x00);
241 bus_space_write_1(*iot
, *ioh
, GREG_DISPMODECONTROL
, 0x29);
242 bus_space_write_1(*iot
, *ioh
, GREG_HERCULESCOMPAT
, 0x01);
246 et_detect(bus_space_tag_t
*iot
, bus_space_tag_t
*memt
, bus_space_handle_t
*ioh
, bus_space_handle_t
*memh
, u_int memsize
)
248 u_char orig
, new, saved
;
251 /* Test accessibility of registers and memory */
252 if(!bus_space_peek_1(*iot
, *ioh
, GREG_STATUS1_R
))
254 if(!bus_space_peek_1(*memt
, *memh
, 0))
257 et_start(iot
, ioh
, &vgabase
, &saved
);
259 /* Is the card a Tseng card? Check read/write of ATC[16] */
260 (void)bus_space_read_1(*iot
, *ioh
, vgabase
+ 0x0a);
261 bus_space_write_1(*iot
, *ioh
, ACT_ADDRESS
, 0x16 | 0x20);
262 orig
= bus_space_read_1(*iot
, *ioh
, ACT_ADDRESS_R
);
263 bus_space_write_1(*iot
, *ioh
, ACT_ADDRESS_W
, (orig
^ 0x10));
264 bus_space_write_1(*iot
, *ioh
, ACT_ADDRESS
, 0x16 | 0x20);
265 new = bus_space_read_1(*iot
, *ioh
, ACT_ADDRESS_R
);
266 bus_space_write_1(*iot
, *ioh
, ACT_ADDRESS
, orig
);
267 if (new != (orig
^ 0x10)) {
269 printf("et4000: ATC[16] failed (%x != %x)\n",
272 et_stop(iot
, ioh
, &vgabase
, &saved
);
276 /* Is the card and ET4000? Check read/write of CRTC[33] */
277 bus_space_write_1(*iot
, *ioh
, vgabase
+ 0x04, 0x33);
278 orig
= bus_space_read_1(*iot
, *ioh
, vgabase
+ 0x05);
279 bus_space_write_1(*iot
, *ioh
, vgabase
+ 0x05, (orig
^ 0x0f));
280 new = bus_space_read_1(*iot
, *ioh
, vgabase
+ 0x05);
281 bus_space_write_1(*iot
, *ioh
, vgabase
+ 0x05, orig
);
282 if (new != (orig
^ 0x0f)) {
284 printf("et4000: CRTC[33] failed (%x != %x)\n",
287 et_stop(iot
, ioh
, &vgabase
, &saved
);
292 /* Set up video memory so we can read & write it */
293 bus_space_write_1(*iot
, *ioh
, 0x3c4, 0x04);
294 bus_space_write_1(*iot
, *ioh
, 0x3c5, 0x06);
295 bus_space_write_1(*iot
, *ioh
, 0x3c4, 0x07);
296 bus_space_write_1(*iot
, *ioh
, 0x3c5, 0xa8);
297 bus_space_write_1(*iot
, *ioh
, 0x3ce, 0x01);
298 bus_space_write_1(*iot
, *ioh
, 0x3cf, 0x00);
299 bus_space_write_1(*iot
, *ioh
, 0x3ce, 0x03);
300 bus_space_write_1(*iot
, *ioh
, 0x3cf, 0x00);
301 bus_space_write_1(*iot
, *ioh
, 0x3ce, 0x05);
302 bus_space_write_1(*iot
, *ioh
, 0x3cf, 0x40);
304 #define TEST_PATTERN 0xa5a5a5a5
306 bus_space_write_4(*memt
, *memh
, 0x0, TEST_PATTERN
);
307 if (bus_space_read_4(*memt
, *memh
, 0x0) != TEST_PATTERN
)
310 printf("et4000: Video base write/read failed\n");
312 et_stop(iot
, ioh
, &vgabase
, &saved
);
316 bus_space_write_4(*memt
, *memh
, memsize
- 4, TEST_PATTERN
);
317 if (bus_space_read_4(*memt
, *memh
, memsize
- 4) != TEST_PATTERN
)
320 printf("et4000: Video top write/read failed\n");
322 et_stop(iot
, ioh
, &vgabase
, &saved
);
327 et_stop(iot
, ioh
, &vgabase
, &saved
);
332 et_vme_attach(struct device
*parent
, struct device
*self
, void *aux
)
334 struct et_softc
*sc
= (struct et_softc
*)self
;
335 struct vme_attach_args
*va
= aux
;
336 bus_space_handle_t ioh
;
337 bus_space_handle_t memh
;
341 if (bus_space_map(va
->va_iot
, va
->va_iobase
, va
->va_iosize
, 0, &ioh
))
342 panic("et attach: cannot map io area");
343 if (bus_space_map(va
->va_memt
, va
->va_maddr
, va
->va_msize
, 0, &memh
))
344 panic("et attach: cannot map mem area");
346 sc
->sc_iot
= va
->va_iot
;
348 sc
->sc_memt
= va
->va_memt
;
351 sc
->sc_iobase
= va
->va_iobase
;
352 sc
->sc_maddr
= va
->va_maddr
;
353 sc
->sc_iosize
= va
->va_iosize
;
354 sc
->sc_msize
= va
->va_msize
;
356 et_priv
.regkva
= (volatile void *)ioh
;
357 et_priv
.memkva
= (volatile void *)memh
;
358 et_priv
.regsz
= va
->va_iosize
;
359 et_priv
.memsz
= va
->va_msize
;
363 etopen(dev_t dev
, int flags
, int devtype
, struct lwp
*l
)
367 sc
= device_lookup_private(&et_cd
, minor(dev
));
370 if (sc
->sc_flags
& ET_SC_FLAGS_INUSE
)
372 sc
->sc_flags
|= ET_SC_FLAGS_INUSE
;
377 etclose(dev_t dev
, int flags
, int devtype
, struct lwp
*l
)
382 * XXX: Should we reset to a default mode?
384 sc
= device_lookup_private(&et_cd
, minor(dev
));
385 sc
->sc_flags
&= ~ET_SC_FLAGS_INUSE
;
390 etread(dev_t dev
, struct uio
*uio
, int flags
)
396 etwrite(dev_t dev
, struct uio
*uio
, int flags
)
402 etioctl(dev_t dev
, u_long cmd
, void *data
, int flags
, struct lwp
*l
)
404 struct grfinfo g_display
;
407 sc
= device_lookup_private(&et_cd
, minor(dev
));
416 g_display
.gd_fbaddr
= (void *) (sc
->sc_maddr
);
417 g_display
.gd_fbsize
= sc
->sc_msize
;
418 g_display
.gd_linbase
= FRAME_BASE
;
419 g_display
.gd_regaddr
= (void *) (sc
->sc_iobase
);
420 g_display
.gd_regsize
= sc
->sc_iosize
;
421 g_display
.gd_vgaaddr
= (void *) (sc
->sc_maddr
);
422 g_display
.gd_vgasize
= VGA_MAPPABLE
;
423 g_display
.gd_vgabase
= VGA_BASE
;
424 g_display
.gd_colors
= 16;
425 g_display
.gd_planes
= 4;
426 g_display
.gd_fbwidth
= 640; /* XXX: should be 'unknown' */
427 g_display
.gd_fbheight
= 400; /* XXX: should be 'unknown' */
428 g_display
.gd_fbx
= 0;
429 g_display
.gd_fby
= 0;
430 g_display
.gd_dwidth
= 0;
431 g_display
.gd_dheight
= 0;
434 g_display
.gd_bank_size
= 0;
435 memcpy(data
, (void *)&g_display
, sizeof(struct grfinfo
));
451 etmmap(dev_t dev
, off_t offset
, int prot
)
455 sc
= device_lookup_private(&et_cd
, minor(dev
));
459 * mapped from offset 0x0 to REG_MAPPABLE
461 if (offset
>= 0 && offset
<= sc
->sc_iosize
)
462 return(m68k_btop(sc
->sc_iobase
+ offset
));
466 * mapped from offset 0xa0000 to 0xc0000
468 if (offset
>= VGA_BASE
&& offset
< (VGA_MAPPABLE
+ VGA_BASE
))
469 return(m68k_btop(sc
->sc_maddr
+ offset
- VGA_BASE
));
473 * mapped from offset 0x400000 to 0x4fffff
475 if (offset
>= FRAME_BASE
&& offset
< sc
->sc_msize
+ FRAME_BASE
)
476 return(m68k_btop(sc
->sc_maddr
+ offset
- FRAME_BASE
));
486 if (minor(dev
) >= et_cd
.cd_ndevs
)
488 sc
= device_lookup_private(&et_cd
, minor(dev
));