1110603Sphk/*	$NetBSD: cgtwo.c,v 1.58 2023/12/20 05:33:18 thorpej Exp $ */
2110603Sphk
3110603Sphk/*
4110603Sphk * Copyright (c) 1992, 1993
5110603Sphk *	The Regents of the University of California.  All rights reserved.
6110603Sphk *
7110603Sphk * This software was developed by the Computer Systems Engineering group
8110603Sphk * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
9110603Sphk * contributed to Berkeley.
10110603Sphk *
11110603Sphk * All advertising materials mentioning features or use of this software
12110603Sphk * must display the following acknowledgement:
13110603Sphk *	This product includes software developed by the University of
14110603Sphk *	California, Lawrence Berkeley Laboratory.
15110603Sphk *
16110603Sphk * Redistribution and use in source and binary forms, with or without
17110603Sphk * modification, are permitted provided that the following conditions
18110603Sphk * are met:
19110603Sphk * 1. Redistributions of source code must retain the above copyright
20110603Sphk *    notice, this list of conditions and the following disclaimer.
21110603Sphk * 2. Redistributions in binary form must reproduce the above copyright
22110603Sphk *    notice, this list of conditions and the following disclaimer in the
23110603Sphk *    documentation and/or other materials provided with the distribution.
24110603Sphk * 3. Neither the name of the University nor the names of its contributors
25110603Sphk *    may be used to endorse or promote products derived from this software
26110603Sphk *    without specific prior written permission.
27110603Sphk *
28110603Sphk * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29110603Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30110603Sphk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31110603Sphk * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32110603Sphk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33110603Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34110603Sphk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35110603Sphk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36110603Sphk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37110603Sphk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38110603Sphk * SUCH DAMAGE.
39110603Sphk *
40110603Sphk *	from: @(#)cgthree.c	8.2 (Berkeley) 10/30/93
41110603Sphk */
42110603Sphk
43110603Sphk/*
44110603Sphk * color display (cgtwo) driver.
45110603Sphk *
46110603Sphk * Does not handle interrupts, even though they can occur.
47110603Sphk *
48110603Sphk * XXX should defer colormap updates to vertical retrace interrupts
49110603Sphk */
50110603Sphk
51110603Sphk#include <sys/cdefs.h>
52110603Sphk__KERNEL_RCSID(0, "$NetBSD: cgtwo.c,v 1.58 2023/12/20 05:33:18 thorpej Exp $");
53110603Sphk
54110603Sphk#include <sys/param.h>
55110603Sphk#include <sys/systm.h>
56110603Sphk#include <sys/buf.h>
57110603Sphk#include <sys/device.h>
58234107Sjmallett#include <sys/ioctl.h>
59242130Sjh#include <sys/mman.h>
60242130Sjh#include <sys/tty.h>
61110603Sphk#include <sys/conf.h>
62110603Sphk
63110603Sphk#include <uvm/uvm_extern.h>
64110603Sphk
65110603Sphk#include <machine/autoconf.h>
66110603Sphk
67110603Sphk#include <dev/sun/fbio.h>
68110603Sphk#include <dev/sun/fbvar.h>
69110603Sphk
70110603Sphk#include <dev/vme/vmevar.h>
71110603Sphk
72110603Sphk#include <machine/eeprom.h>
73181463Sdes#include <machine/cgtworeg.h>
74110603Sphk
75126786Sjhb
76110603Sphk/* per-display variables */
77110603Sphkstruct cgtwo_softc {
78253249Shrs	struct	fbdevice sc_fb;		/* frame buffer device */
79234107Sjmallett	vme_addr_t		sc_paddr;
80110603Sphk	vme_chipset_tag_t	sc_ct;
81253249Shrs	bus_space_tag_t		sc_bt;
82110603Sphk	volatile struct cg2statusreg *sc_reg;	/* CG2 control registers */
83110603Sphk	volatile u_short *sc_cmap;
84110603Sphk#define sc_redmap(sc)	((sc)->sc_cmap)
85110603Sphk#define sc_greenmap(sc)	((sc)->sc_cmap + CG2_CMSIZE)
86110603Sphk#define sc_bluemap(sc)	((sc)->sc_cmap + 2 * CG2_CMSIZE)
87110603Sphk};
88110603Sphk
89180369Slulf/* autoconfiguration driver */
90242130Sjhstatic int	cgtwomatch(device_t, cfdata_t, void *);
91242130Sjhstatic void	cgtwoattach(device_t, device_t, void *);
92180369Slulfstatic void	cgtwounblank(device_t);
93180369Slulfint		cgtwogetcmap(struct cgtwo_softc *, struct fbcmap *);
94180369Slulfint		cgtwoputcmap(struct cgtwo_softc *, struct fbcmap *);
95180369Slulf
96126786SjhbCFATTACH_DECL_NEW(cgtwo, sizeof(struct cgtwo_softc),
97126786Sjhb    cgtwomatch, cgtwoattach, NULL, NULL);
98126786Sjhb
99126786Sjhbextern struct cfdriver cgtwo_cd;
100110603Sphk
101110603Sphkdev_type_open(cgtwoopen);
102110603Sphkdev_type_ioctl(cgtwoioctl);
103110603Sphkdev_type_mmap(cgtwommap);
104180369Slulf
105242130Sjhconst struct cdevsw cgtwo_cdevsw = {
106242130Sjh	.d_open = cgtwoopen,
107180369Slulf	.d_close = nullclose,
108180369Slulf	.d_read = noread,
109180369Slulf	.d_write = nowrite,
110180369Slulf	.d_ioctl = cgtwoioctl,
111126786Sjhb	.d_stop = nostop,
112126786Sjhb	.d_tty = notty,
113126786Sjhb	.d_poll = nopoll,
114126786Sjhb	.d_mmap = cgtwommap,
115126786Sjhb	.d_kqfilter = nokqfilter,
116110603Sphk	.d_discard = nodiscard,
117110603Sphk	.d_flag = 0
118110603Sphk};
119126786Sjhb
120110603Sphk/* frame buffer generic driver */
121110603Sphkstatic struct fbdriver cgtwofbdriver = {
122110603Sphk	cgtwounblank, cgtwoopen, nullclose, cgtwoioctl, nopoll, cgtwommap,
123110603Sphk	nokqfilter
124180369Slulf};
125242130Sjh
126242130Sjh/*
127180369Slulf * Match a cgtwo.
128180369Slulf */
129180369Slulfstatic int
130180369Slulfcgtwomatch(device_t parent, cfdata_t cf, void *aux)
131126786Sjhb{
132126786Sjhb	struct vme_attach_args	*va = aux;
133126786Sjhb	vme_chipset_tag_t	ct = va->va_vct;
134126786Sjhb	vme_am_t		mod;
135110603Sphk
136110603Sphk	/*
137110603Sphk	 * Mask out invalid flags from the user.
138126786Sjhb	 */
139110603Sphk	cf->cf_flags &= FB_USERMASK;
140110603Sphk
141110603Sphk	mod = 0x3d; /* VME_AM_A24 | VME_AM_MBO | VME_AM_SUPER | VME_AM_DATA */
142126786Sjhb	if (vme_probe(ct, va->r[0].offset + CG2_CTLREG_OFF, 2, mod, VME_D16,
143110603Sphk			  0, 0)) {
144110603Sphk		return (0);
145110603Sphk	}
146110603Sphk
147180369Slulf	return (1);
148242130Sjh}
149242130Sjh
150180369Slulf/*
151180369Slulf * Attach a display.  We need to notice if it is the console, too.
152180369Slulf */
153180369Slulfstatic void
154126786Sjhbcgtwoattach(device_t parent, device_t self, void *aux)
155126786Sjhb{
156126786Sjhb	struct vme_attach_args	*va = aux;
157126786Sjhb	vme_chipset_tag_t	ct = va->va_vct;
158126786Sjhb	bus_space_tag_t		bt;
159110603Sphk	bus_space_handle_t	bh;
160110603Sphk	vme_am_t		mod;
161110603Sphk	vme_mapresc_t resc;
162126786Sjhb	struct cgtwo_softc *sc = device_private(self);
163110603Sphk	struct fbdevice *fb = &sc->sc_fb;
164110603Sphk	struct eeprom *eep = (struct eeprom *)eeprom_va;
165110603Sphk	int isconsole = 0;
166110603Sphk
167126786Sjhb	sc->sc_ct = ct;
168110603Sphk	fb->fb_driver = &cgtwofbdriver;
169110603Sphk	fb->fb_device = self;
170110603Sphk	fb->fb_type.fb_type = FBTYPE_SUN2COLOR;
171126786Sjhb	fb->fb_flags = device_cfdata(self)->cf_flags;
172110603Sphk
173110603Sphk	fb->fb_type.fb_depth = 8;
174110603Sphk	fb_setsize_eeprom(fb, fb->fb_type.fb_depth, 1152, 900);
175126786Sjhb
176110603Sphk	fb->fb_type.fb_cmsize = 256;
177110603Sphk	fb->fb_type.fb_size = roundup(CG2_MAPPED_SIZE, PAGE_SIZE);
178110603Sphk	printf(": cgtwo, %d x %d",
179126786Sjhb	       fb->fb_type.fb_width, fb->fb_type.fb_height);
180110603Sphk
181110603Sphk	/*
182110603Sphk	 * When the ROM has mapped in a cgtwo display, the address
183110603Sphk	 * maps only the video RAM, so in any case we have to map the
184110603Sphk	 * registers ourselves.  We only need the video RAM if we are
185110603Sphk	 * going to print characters via rconsole.
186110603Sphk	 */
187110603Sphk	sc->sc_paddr = va->r[0].offset;
188110603Sphk	mod = 0x3d; /* VME_AM_A24 | VME_AM_MBO | VME_AM_SUPER | VME_AM_DATA */
189110603Sphk
190110603Sphk	if (vme_space_map(ct, sc->sc_paddr + CG2_ROPMEM_OFF +
191110603Sphk				offsetof(struct cg2fb, status.reg),
192110603Sphk			sizeof(struct cg2statusreg), mod, VME_D16, 0,
193242130Sjh			&bt, &bh, &resc) != 0)
194242130Sjh		panic("cgtwo: vme_map status");
195242130Sjh	sc->sc_bt = bt;
196242130Sjh	sc->sc_reg = (volatile struct cg2statusreg *)bh; /* XXX */
197242130Sjh
198242130Sjh	if (vme_space_map(ct, sc->sc_paddr + CG2_ROPMEM_OFF +
199180369Slulf				offsetof(struct cg2fb, redmap[0]),
200242130Sjh			3 * CG2_CMSIZE, mod, VME_D16, 0,
201242130Sjh			&bt, &bh, &resc) != 0)
202180369Slulf		panic("cgtwo: vme_map cmap");
203180369Slulf	sc->sc_cmap = (volatile u_short *)bh; /* XXX */
204180369Slulf
205180369Slulf	/*
206110603Sphk	 * Assume this is the console if there's no eeprom info
207110603Sphk	 * to be found.
208110603Sphk	 */
209110603Sphk	if (eep == NULL || eep->eeConsole == EE_CONS_COLOR)
210110603Sphk		isconsole = fb_is_console(0);
211110603Sphk	else
212110603Sphk		isconsole = 0;
213126786Sjhb
214110603Sphk	if (isconsole) {
215110603Sphk		if (vme_space_map(ct, sc->sc_paddr + CG2_PIXMAP_OFF,
216126786Sjhb				CG2_PIXMAP_SIZE, mod, VME_D16, 0,
217110603Sphk				  &bt, &bh, &resc) != 0)
218110603Sphk			panic("cgtwo: vme_map pixels");
219126786Sjhb
220110603Sphk		fb->fb_pixels = (void *)bh; /* XXX */
221110603Sphk		printf(" (console)\n");
222110603Sphk#ifdef RASTERCONSOLE
223110603Sphk		fbrcons_init(fb);
224126786Sjhb#endif
225110603Sphk	} else
226110603Sphk		printf("\n");
227110603Sphk
228110603Sphk	fb_attach(fb, isconsole);
229126786Sjhb}
230110603Sphk
231110603Sphkint
232110603Sphkcgtwoopen(dev_t dev, int flags, int mode, struct lwp *l)
233126786Sjhb{
234110603Sphk	int unit = minor(dev);
235110603Sphk
236110603Sphk	if (device_lookup(&cgtwo_cd, unit) == NULL)
237126786Sjhb		return (ENXIO);
238110603Sphk	return (0);
239110603Sphk}
240110603Sphk
241110603Sphkint
242126786Sjhbcgtwoioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l)
243110603Sphk{
244110603Sphk	register struct cgtwo_softc *sc = device_lookup_private(&cgtwo_cd,
245110603Sphk								minor(dev));
246202454Sdelphij	register struct fbgattr *fba;
247202454Sdelphij
248202454Sdelphij	switch (cmd) {
249202454Sdelphij
250202454Sdelphij	case FBIOGTYPE:
251202454Sdelphij		*(struct fbtype *)data = sc->sc_fb.fb_type;
252202454Sdelphij		break;
253202454Sdelphij
254202454Sdelphij	case FBIOGATTR:
255202454Sdelphij		fba = (struct fbgattr *)data;
256110603Sphk		fba->real_type = sc->sc_fb.fb_type.fb_type;
257110603Sphk		fba->owner = 0;		/* XXX ??? */
258110603Sphk		fba->fbtype = sc->sc_fb.fb_type;
259110603Sphk		fba->sattr.flags = 0;
260110603Sphk		fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type;
261110603Sphk		fba->sattr.dev_specific[0] = -1;
262110603Sphk		fba->emu_types[0] = sc->sc_fb.fb_type.fb_type;
263180369Slulf		fba->emu_types[1] = -1;
264180369Slulf		break;
265242130Sjh
266242130Sjh	case FBIOGETCMAP:
267180369Slulf		return cgtwogetcmap(sc, (struct fbcmap *) data);
268180369Slulf
269180369Slulf	case FBIOPUTCMAP:
270180369Slulf		return cgtwoputcmap(sc, (struct fbcmap *) data);
271126786Sjhb
272180369Slulf	case FBIOGVIDEO:
273242130Sjh		*(int *)data = sc->sc_reg->video_enab;
274242130Sjh		break;
275180369Slulf
276180369Slulf	case FBIOSVIDEO:
277180369Slulf		sc->sc_reg->video_enab = (*(int*)data) & 1;
278180369Slulf		break;
279126786Sjhb
280126786Sjhb	default:
281110603Sphk		return (ENOTTY);
282110603Sphk	}
283110603Sphk	return (0);
284110603Sphk}
285253469Sscottl
286112340Sphk/*
287253469Sscottl * Undo the effect of an FBIOSVIDEO that turns the video off.
288110603Sphk */
289110603Sphkstatic void
290110603Sphkcgtwounblank(device_t dev)
291110603Sphk{
292110603Sphk	struct cgtwo_softc *sc = device_private(dev);
293110603Sphk	sc->sc_reg->video_enab = 1;
294110603Sphk}
295110603Sphk
296110603Sphk/*
297110603Sphk */
298110603Sphkint
299110603Sphkcgtwogetcmap(struct cgtwo_softc *sc, struct fbcmap *cmap)
300110603Sphk{
301110603Sphk	u_char red[CG2_CMSIZE], green[CG2_CMSIZE], blue[CG2_CMSIZE];
302110603Sphk	int error, start, count, ecount;
303110603Sphk	register u_int i;
304110603Sphk	register volatile u_short *p;
305110603Sphk
306110603Sphk	start = cmap->index;
307110603Sphk	count = cmap->count;
308110603Sphk	ecount = start + count;
309110603Sphk	if (start >= CG2_CMSIZE || count > CG2_CMSIZE - start)
310110603Sphk		return (EINVAL);
311110603Sphk
312110603Sphk	/* XXX - Wait for retrace? */
313110603Sphk
314110603Sphk	/* Copy hardware to local arrays. */
315110603Sphk	p = &sc_redmap(sc)[start];
316110603Sphk	for (i = start; i < ecount; i++)
317110603Sphk		red[i] = *p++;
318110603Sphk	p = &sc_greenmap(sc)[start];
319110603Sphk	for (i = start; i < ecount; i++)
320110603Sphk		green[i] = *p++;
321110603Sphk	p = &sc_bluemap(sc)[start];
322110603Sphk	for (i = start; i < ecount; i++)
323110603Sphk		blue[i] = *p++;
324110603Sphk
325110603Sphk	/* Copy local arrays to user space. */
326110603Sphk	if ((error = copyout(red + start, cmap->red, count)) != 0)
327110603Sphk		return (error);
328110603Sphk	if ((error = copyout(green + start, cmap->green, count)) != 0)
329110603Sphk		return (error);
330110603Sphk	if ((error = copyout(blue + start, cmap->blue, count)) != 0)
331110603Sphk		return (error);
332110603Sphk
333110603Sphk	return (0);
334110603Sphk}
335110603Sphk
336110603Sphk/*
337112340Sphk */
338110603Sphkint
339234107Sjmallettcgtwoputcmap(struct cgtwo_softc *sc, struct fbcmap *cmap)
340110603Sphk{
341234107Sjmallett	u_char red[CG2_CMSIZE], green[CG2_CMSIZE], blue[CG2_CMSIZE];
342234107Sjmallett	int error;
343234107Sjmallett	u_int start, count, ecount;
344110603Sphk	register u_int i;
345110603Sphk	register volatile u_short *p;
346110603Sphk
347110603Sphk	start = cmap->index;
348110603Sphk	count = cmap->count;
349110603Sphk	ecount = start + count;
350110603Sphk	if (start >= CG2_CMSIZE || count > CG2_CMSIZE - start)
351110603Sphk		return (EINVAL);
352110603Sphk
353110603Sphk	/* Copy from user space to local arrays. */
354110603Sphk	if ((error = copyin(cmap->red, red + start, count)) != 0)
355110603Sphk		return (error);
356242130Sjh	if ((error = copyin(cmap->green, green + start, count)) != 0)
357110603Sphk		return (error);
358110603Sphk	if ((error = copyin(cmap->blue, blue + start, count)) != 0)
359126786Sjhb		return (error);
360110603Sphk
361213451Semaste	/* XXX - Wait for retrace? */
362213451Semaste
363110603Sphk	/* Copy from local arrays to hardware. */
364213451Semaste	p = &sc_redmap(sc)[start];
365213451Semaste	for (i = start; i < ecount; i++)
366110603Sphk		*p++ = red[i];
367213451Semaste	p = &sc_greenmap(sc)[start];
368110603Sphk	for (i = start; i < ecount; i++)
369242130Sjh		*p++ = green[i];
370242130Sjh	p = &sc_bluemap(sc)[start];
371110603Sphk	for (i = start; i < ecount; i++)
372110603Sphk		*p++ = blue[i];
373110603Sphk
374110603Sphk	return (0);
375242130Sjh}
376242130Sjh
377242130Sjh/*
378242130Sjh * Return the address that would map the given device at the given
379242130Sjh * offset, allowing for the given protection, or return -1 for error.
380242130Sjh */
381213451Semastepaddr_t
382242130Sjhcgtwommap(dev_t dev, off_t off, int prot)
383213451Semaste{
384242130Sjh	extern int sparc_vme_mmap_cookie(vme_addr_t, vme_am_t,
385213451Semaste					 bus_space_handle_t *);
386234107Sjmallett
387234107Sjmallett	register struct cgtwo_softc *sc = device_lookup_private(&cgtwo_cd,
388234107Sjmallett								minor(dev));
389233646Sjmallett	vme_am_t mod;
390234107Sjmallett	bus_space_handle_t bh;
391110603Sphk
392126786Sjhb	if (off & PGOFSET)
393234107Sjmallett		panic("cgtwommap");
394234107Sjmallett
395234107Sjmallett	if (off >= sc->sc_fb.fb_type.fb_size)
396234107Sjmallett		return (-1);
397126786Sjhb
398234107Sjmallett	/* Apparently, the pixels are in 32-bit data space */
399234107Sjmallett	mod = 0x3d; /* VME_AM_A24 | VME_AM_MBO | VME_AM_SUPER | VME_AM_DATA */
400234107Sjmallett
401234107Sjmallett	if (sparc_vme_mmap_cookie(sc->sc_paddr + off, mod, &bh) != 0)
402126786Sjhb		panic("cgtwommap");
403234107Sjmallett
404234107Sjmallett	return ((paddr_t)bh);
405234107Sjmallett}
406234107Sjmallett