1/*	$NetBSD: cg2.c,v 1.32 2023/12/20 05:18:00 thorpej Exp $	*/
2
3/*
4 * Copyright (c) 1992, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * This software was developed by the Computer Systems Engineering group
8 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
9 * contributed to Berkeley.
10 *
11 * All advertising materials mentioning features or use of this software
12 * must display the following acknowledgement:
13 *	This product includes software developed by the University of
14 *	California, Lawrence Berkeley Laboratory.
15 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 * 1. Redistributions of source code must retain the above copyright
20 *    notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 *    notice, this list of conditions and the following disclaimer in the
23 *    documentation and/or other materials provided with the distribution.
24 * 3. Neither the name of the University nor the names of its contributors
25 *    may be used to endorse or promote products derived from this software
26 *    without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 *
40 *	from: @(#)cgthree.c	8.2 (Berkeley) 10/30/93
41 */
42
43/*
44 * color display (cg2) driver.
45 *
46 * Does not handle interrupts, even though they can occur.
47 *
48 * XXX should defer colormap updates to vertical retrace interrupts
49 */
50
51#include <sys/cdefs.h>
52__KERNEL_RCSID(0, "$NetBSD: cg2.c,v 1.32 2023/12/20 05:18:00 thorpej Exp $");
53
54#include <sys/param.h>
55#include <sys/systm.h>
56#include <sys/conf.h>
57#include <sys/device.h>
58#include <sys/ioctl.h>
59#include <sys/mman.h>
60#include <sys/proc.h>
61#include <sys/tty.h>
62
63#include <uvm/uvm_extern.h>
64
65#include <dev/sun/fbio.h>
66#include <machine/autoconf.h>
67#include <machine/pmap.h>
68#include <machine/cg2reg.h>
69
70#include "ioconf.h"
71#include "fbvar.h"
72
73#define	CMSIZE 256
74
75/* offset to and size of mapped part of frame buffer */
76#define PLANEMAP_SIZE		0x100000
77#define PIXELMAP_SIZE		0x100000
78#define ROWOPMAP_SIZE		0x100000
79
80#define	CTLREGS_OFF 		0x300000
81#define	CTLREGS_SIZE		 0x10600
82
83#define	CG2_MAPPED_OFFSET	(PLANEMAP_SIZE + PIXELMAP_SIZE)
84#define	CG2_MAPPED_SIZE 	(CTLREGS_OFF + CTLREGS_SIZE)
85
86/* per-display variables */
87struct cg2_softc {
88	device_t sc_dev;		/* base device */
89	struct	fbdevice sc_fb;		/* frame buffer device */
90	int 	sc_phys;		/* display RAM (phys addr) */
91	int 	sc_pmtype;		/* pmap type bits */
92	struct	cg2fb *sc_ctlreg;	/* control registers */
93};
94
95/* autoconfiguration driver */
96static int	cg2match(device_t, cfdata_t, void *);
97static void	cg2attach(device_t, device_t, void *);
98
99CFATTACH_DECL_NEW(cgtwo, sizeof(struct cg2_softc),
100    cg2match, cg2attach, NULL, NULL);
101
102dev_type_open(cg2open);
103dev_type_ioctl(cg2ioctl);
104dev_type_mmap(cg2mmap);
105
106const struct cdevsw cgtwo_cdevsw = {
107	.d_open = cg2open,
108	.d_close = nullclose,
109	.d_read = noread,
110	.d_write = nowrite,
111	.d_ioctl = cg2ioctl,
112	.d_stop = nostop,
113	.d_tty = notty,
114	.d_poll = nopoll,
115	.d_mmap = cg2mmap,
116	.d_kqfilter = nokqfilter,
117	.d_discard = nodiscard,
118	.d_flag = 0
119};
120
121static int cg2gattr(struct fbdevice *,  void *);
122static int cg2gvideo(struct fbdevice *, void *);
123static int cg2svideo(struct fbdevice *, void *);
124static int cg2getcmap(struct fbdevice *, void *);
125static int cg2putcmap(struct fbdevice *, void *);
126
127static struct fbdriver cg2fbdriver = {
128	cg2open, nullclose, cg2mmap, nokqfilter, cg2gattr,
129	cg2gvideo, cg2svideo,
130	cg2getcmap, cg2putcmap };
131
132static int cg2intr(void *);
133
134/*
135 * Match a cg2.
136 */
137static int
138cg2match(device_t parent, cfdata_t cf, void *aux)
139{
140	struct confargs *ca = aux;
141	int probe_addr;
142
143	/* No default VME address. */
144	if (ca->ca_paddr == -1)
145		return 0;
146
147	/* Make sure something is there... */
148	probe_addr = ca->ca_paddr + CTLREGS_OFF;
149	if (bus_peek(ca->ca_bustype, probe_addr, 1) == -1)
150		return 0;
151
152	/* XXX: look at the ID reg? */
153	/* aprint_debug("cg2: id=0x%x\n", x); */
154
155	/* Default interrupt priority. */
156	if (ca->ca_intpri == -1)
157		ca->ca_intpri = 4;
158
159	return 1;
160}
161
162/*
163 * Attach a display.  We need to notice if it is the console, too.
164 */
165static void
166cg2attach(device_t parent, device_t self, void *args)
167{
168	struct cg2_softc *sc = device_private(self);
169	struct fbdevice *fb = &sc->sc_fb;
170	struct confargs *ca = args;
171	struct fbtype *fbt;
172
173	sc->sc_dev = self;
174	sc->sc_phys = ca->ca_paddr;
175	sc->sc_pmtype = PMAP_NC | PMAP_VME16;
176
177	sc->sc_ctlreg = (struct cg2fb *)bus_mapin(ca->ca_bustype,
178	    ca->ca_paddr + CTLREGS_OFF, CTLREGS_SIZE);
179
180	isr_add_vectored(cg2intr, sc, ca->ca_intpri, ca->ca_intvec);
181
182	/*
183	 * XXX - Initialize?  Determine type?
184	 */
185	sc->sc_ctlreg->intrptvec.reg = ca->ca_intvec;
186	sc->sc_ctlreg->status.word = 1;
187
188	fb->fb_driver = &cg2fbdriver;
189	fb->fb_private = sc;
190	fb->fb_name = device_xname(self);
191
192	fbt = &fb->fb_fbtype;
193	fbt->fb_type = FBTYPE_SUN2COLOR;
194	fbt->fb_depth = 8;
195	fbt->fb_cmsize = CMSIZE;
196
197	fbt->fb_width = 1152;
198	fbt->fb_height = 900;
199	fbt->fb_size = CG2_MAPPED_SIZE;
200
201	aprint_normal(" (%dx%d)\n", fbt->fb_width, fbt->fb_height);
202	fb_attach(fb, 2);
203}
204
205int
206cg2open(dev_t dev, int flags, int mode, struct lwp *l)
207{
208	struct cg2_softc *sc;
209	int unit = minor(dev);
210
211	sc = device_lookup_private(&cgtwo_cd, unit);
212	if (sc == NULL)
213		return ENXIO;
214	return 0;
215}
216
217int
218cg2ioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l)
219{
220	struct cg2_softc *sc = device_lookup_private(&cgtwo_cd, minor(dev));
221
222	return fbioctlfb(&sc->sc_fb, cmd, data);
223}
224
225/*
226 * Return the address that would map the given device at the given
227 * offset, allowing for the given protection, or return -1 for error.
228 */
229paddr_t
230cg2mmap(dev_t dev, off_t off, int prot)
231{
232	struct cg2_softc *sc = device_lookup_private(&cgtwo_cd, minor(dev));
233
234	if (off & PGOFSET)
235		panic("%s: bad offset", __func__);
236
237	if (off >= CG2_MAPPED_SIZE)
238		return -1;
239
240	/*
241	 * I turned on PMAP_NC here to disable the cache as I was
242	 * getting horribly broken behaviour with it on.
243	 */
244	return (sc->sc_phys + off) | sc->sc_pmtype;
245}
246
247/*
248 * Internal ioctl functions.
249 */
250
251/* FBIOGATTR: */
252static int
253cg2gattr(struct fbdevice *fb, void *data)
254{
255	struct fbgattr *fba = data;
256
257	fba->real_type = fb->fb_fbtype.fb_type;
258	fba->owner = 0;		/* XXX - TIOCCONS stuff? */
259	fba->fbtype = fb->fb_fbtype;
260	fba->sattr.flags = 0;
261	fba->sattr.emu_type = fb->fb_fbtype.fb_type;
262	fba->sattr.dev_specific[0] = -1;
263	fba->emu_types[0] = fb->fb_fbtype.fb_type;
264	fba->emu_types[1] = -1;
265	return 0;
266}
267
268/* FBIOGVIDEO: */
269static int
270cg2gvideo(struct fbdevice *fb, void *data)
271{
272	int *on = data;
273	struct cg2_softc *sc = fb->fb_private;
274
275	*on = sc->sc_ctlreg->status.reg.video_enab;
276	return 0;
277}
278
279/* FBIOSVIDEO: */
280static int
281cg2svideo(struct fbdevice *fb, void *data)
282{
283	int *on = data;
284	struct cg2_softc *sc = fb->fb_private;
285
286	sc->sc_ctlreg->status.reg.video_enab = (*on) & 1;
287
288	return 0;
289}
290
291/* FBIOGETCMAP: */
292static int
293cg2getcmap(struct fbdevice *fb, void *data)
294{
295	struct fbcmap *cmap = data;
296	struct cg2_softc *sc = fb->fb_private;
297	uint8_t red[CMSIZE], green[CMSIZE], blue[CMSIZE];
298	int error, start, count, ecount;
299	u_int i;
300	uint16_t *p;
301
302	start = cmap->index;
303	count = cmap->count;
304	ecount = start + count;
305	if (start >= CMSIZE || count > CMSIZE - start)
306		return EINVAL;
307
308	/* XXX - Wait for retrace? */
309
310	/* Copy hardware to local arrays. */
311	p = &sc->sc_ctlreg->redmap[start];
312	for (i = start; i < ecount; i++)
313		red[i] = *p++;
314	p = &sc->sc_ctlreg->greenmap[start];
315	for (i = start; i < ecount; i++)
316		green[i] = *p++;
317	p = &sc->sc_ctlreg->bluemap[start];
318	for (i = start; i < ecount; i++)
319		blue[i] = *p++;
320
321	/* Copy local arrays to user space. */
322	if ((error = copyout(red + start, cmap->red, count)) != 0)
323		return error;
324	if ((error = copyout(green + start, cmap->green, count)) != 0)
325		return error;
326	if ((error = copyout(blue + start, cmap->blue, count)) != 0)
327		return error;
328
329	return 0;
330}
331
332/* FBIOPUTCMAP: */
333static int
334cg2putcmap(struct fbdevice *fb, void *data)
335{
336	struct fbcmap *cmap = data;
337	struct cg2_softc *sc = fb->fb_private;
338	uint8_t red[CMSIZE], green[CMSIZE], blue[CMSIZE];
339	int error;
340	u_int start, count, ecount;
341	u_int i;
342	uint16_t *p;
343
344	start = cmap->index;
345	count = cmap->count;
346	ecount = start + count;
347	if (start >= CMSIZE || count > CMSIZE - start)
348		return EINVAL;
349
350	/* Copy from user space to local arrays. */
351	if ((error = copyin(cmap->red, red + start, count)) != 0)
352		return error;
353	if ((error = copyin(cmap->green, green + start, count)) != 0)
354		return error;
355	if ((error = copyin(cmap->blue, blue + start, count)) != 0)
356		return error;
357
358	/* XXX - Wait for retrace? */
359
360	/* Copy from local arrays to hardware. */
361	p = &sc->sc_ctlreg->redmap[start];
362	for (i = start; i < ecount; i++)
363		*p++ = red[i];
364	p = &sc->sc_ctlreg->greenmap[start];
365	for (i = start; i < ecount; i++)
366		*p++ = green[i];
367	p = &sc->sc_ctlreg->bluemap[start];
368	for (i = start; i < ecount; i++)
369		*p++ = blue[i];
370
371	return 0;
372
373}
374
375static int
376cg2intr(void *vsc)
377{
378	struct cg2_softc *sc = vsc;
379
380	/* XXX - Just disable interrupts for now. */
381	sc->sc_ctlreg->status.reg.inten = 0;
382
383	printf("cg2intr\n");
384	return 1;
385}
386