1/* $NetBSD: nextdisplay.c,v 1.31 2024/02/02 15:59:30 tsutsui Exp $ */
2
3/*
4 * Copyright (c) 1998 Matt DeBergalis
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. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *      This product includes software developed by Matt DeBergalis
18 * 4. The name of the author may not be used to endorse or promote products
19 *    derived from this software without specific prior written permission
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33#include <sys/cdefs.h>
34__KERNEL_RCSID(0, "$NetBSD: nextdisplay.c,v 1.31 2024/02/02 15:59:30 tsutsui Exp $");
35
36#include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
37
38#include <sys/param.h>
39#include <sys/systm.h>
40#include <sys/kernel.h>
41#include <sys/device.h>
42#include <sys/kmem.h>
43
44#include <machine/bus.h>
45#include <machine/cpu.h>
46
47#include <next68k/next68k/nextrom.h>
48#include <next68k/next68k/isr.h>
49
50#include <next68k/dev/intiovar.h>
51#include <next68k/dev/nextdisplayvar.h>
52#include <dev/wscons/wsconsio.h>
53
54#include <dev/rcons/raster.h>
55#include <dev/wscons/wscons_raster.h>
56#include <dev/wscons/wsdisplayvar.h>
57
58extern int turbo;
59
60int nextdisplay_match(device_t, cfdata_t, void *);
61void nextdisplay_attach(device_t, device_t, void *);
62
63CFATTACH_DECL_NEW(nextdisplay, sizeof(struct nextdisplay_softc),
64    nextdisplay_match, nextdisplay_attach, NULL, NULL);
65
66const struct wsdisplay_emulops nextdisplay_mono_emulops = {
67	rcons_cursor,
68	rcons_mapchar,
69	rcons_putchar,
70	rcons_copycols,
71	rcons_erasecols,
72	rcons_copyrows,
73	rcons_eraserows,
74	rcons_allocattr
75};
76
77struct wsscreen_descr nextdisplay_mono = {
78	"mono",
79	0, 0, /* will be filled in -- XXX shouldn't, it's global */
80	&nextdisplay_mono_emulops,
81	0, 0
82};
83
84struct wsscreen_descr nextdisplay_color = {
85        "color",
86        0, 0, /* again, filled in */
87        &nextdisplay_mono_emulops,
88        0, 0
89};
90
91const struct wsscreen_descr *_nextdisplay_scrlist_mono[] = {
92	&nextdisplay_mono,
93};
94
95const struct wsscreen_descr *_nextdisplay_scrlist_color[] = {
96        &nextdisplay_color,
97};
98
99const struct wsscreen_list nextdisplay_screenlist_mono = {
100	sizeof(_nextdisplay_scrlist_mono) / sizeof(struct wsscreen_descr *),
101	_nextdisplay_scrlist_mono
102};
103
104const struct wsscreen_list nextdisplay_screenlist_color = {
105	sizeof(_nextdisplay_scrlist_color) / sizeof(struct wsscreen_descr *),
106	_nextdisplay_scrlist_color
107};
108
109static int	nextdisplay_ioctl(void *, void *, u_long, void *, int,
110		    struct lwp *);
111static paddr_t	nextdisplay_mmap(void *, void *, off_t, int);
112static int	nextdisplay_alloc_screen(void *, const struct wsscreen_descr *,
113		void **, int *, int *, long *);
114static void	nextdisplay_free_screen(void *, void *);
115static int	nextdisplay_show_screen(void *, void *, int,
116					void (*) (void *, int, int), void *);
117static int	nextdisplay_load_font(void *, void *, struct wsdisplay_font *);
118
119const struct wsdisplay_accessops nextdisplay_accessops = {
120	nextdisplay_ioctl,
121	nextdisplay_mmap,
122	nextdisplay_alloc_screen,
123	nextdisplay_free_screen,
124	nextdisplay_show_screen,
125	nextdisplay_load_font
126};
127
128void nextdisplay_init(struct nextdisplay_config *, int);
129int nextdisplay_intr(void *);
130
131vaddr_t nextdisplay_consaddr;
132static int nextdisplay_is_console(vaddr_t);
133
134static struct nextdisplay_config nextdisplay_console_dc;
135
136static int
137nextdisplay_is_console(vaddr_t addr)
138{
139	return nextdisplay_console_dc.isconsole &&
140	    addr == nextdisplay_consaddr;
141}
142
143int
144nextdisplay_match(device_t parent, cfdata_t match, void *aux)
145{
146	if (rom_machine_type == NeXT_WARP9 ||
147	    rom_machine_type == NeXT_X15 ||
148	    rom_machine_type == NeXT_WARP9C ||
149	    rom_machine_type == NeXT_TURBO_MONO ||
150	    rom_machine_type == NeXT_TURBO_COLOR ||
151	    rom_machine_type == NeXT_CUBE_TURBO)
152		return 1;
153	else
154		return 0;
155}
156
157void
158nextdisplay_init(struct nextdisplay_config *dc, int color)
159{
160	struct raster *rap;
161	struct rcons *rcp;
162	int i;
163
164	/* printf("in nextdisplay_init\n"); */
165
166	dc->dc_vaddr = fbbase;
167	dc->dc_paddr = fbbasepa;
168	dc->dc_size = color ? NEXT_P_C16_VIDEOSIZE : NEXT_P_VIDEOSIZE;
169
170	dc->dc_wid = 1120;
171	dc->dc_ht = 832;
172	dc->dc_depth = color ? 16 : 2;
173	dc->dc_cmsize = color ? 256 : 4;
174	dc->dc_rowbytes = (turbo ? 1120 : 1152) * dc->dc_depth / 8;
175
176	dc->dc_videobase = dc->dc_vaddr;
177
178#if 0
179	printf("intiobase at: %08x\n", intiobase);
180	printf("intiolimit at: %08x\n", intiolimit);
181	printf("videobase at: %08x\n", fbbase);
182	printf("videolimit at: %08x\n", fblimit);
183
184	printf("virtual fb at: %08x\n", dc->dc_vaddr);
185	printf("physical fb at: %08x\n", dc->dc_paddr);
186	printf("fb size: %08x\n", dc->dc_size);
187
188	printf("dc_wid: %08x\n", dc->dc_wid);
189	printf("dc_ht: %08x\n", dc->dc_ht);
190	printf("dc_depth: %08x\n", dc->dc_depth);
191	printf("dc_rowbytes: %08x\n", dc->dc_rowbytes);
192	printf("dc_videobase: %08x\n", dc->dc_videobase);
193#endif
194
195	/* clear the screen */
196	for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(uint32_t))
197		*(uint32_t *)(dc->dc_videobase + i) =
198		    color ? 0x0 : 0xffffffff;
199
200	rap = &dc->dc_raster;
201	rap->width = dc->dc_wid;
202	rap->height = dc->dc_ht;
203	rap->depth = color ? 16 : 2;
204	rap->linelongs = dc->dc_rowbytes / sizeof(uint32_t);
205	rap->pixels = (uint32_t *)dc->dc_videobase;
206
207	/* initialize the raster console blitter */
208	rcp = &dc->dc_rcons;
209	rcp->rc_sp = rap;
210	rcp->rc_crow = rcp->rc_ccol = -1;
211	rcp->rc_crowp = &rcp->rc_crow;
212	rcp->rc_ccolp = &rcp->rc_ccol;
213	rcons_init(rcp, 34, 80);
214
215	if (color) {
216		nextdisplay_color.nrows = dc->dc_rcons.rc_maxrow;
217		nextdisplay_color.ncols = dc->dc_rcons.rc_maxcol;
218	} else {
219		nextdisplay_mono.nrows = dc->dc_rcons.rc_maxrow;
220		nextdisplay_mono.ncols = dc->dc_rcons.rc_maxcol;
221	}
222}
223
224void
225nextdisplay_attach(device_t parent, device_t self, void *aux)
226{
227	struct nextdisplay_softc *sc = device_private(self);
228	struct wsemuldisplaydev_attach_args waa;
229	int isconsole;
230	vaddr_t addr;
231
232	sc->sc_dev = self;
233
234	addr = fbbase;
235
236	isconsole = nextdisplay_is_console(addr);
237
238	if (isconsole) {
239		sc->sc_dc = &nextdisplay_console_dc;
240		sc->nscreens = 1;
241	} else {
242		sc->sc_dc = kmem_alloc(sizeof(struct nextdisplay_config),
243		    KM_SLEEP);
244		nextdisplay_init(sc->sc_dc, iscolor);
245	}
246
247	printf(": %d x %d, %dbpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht,
248	    sc->sc_dc->dc_depth);
249
250	if (iscolor && !turbo) {
251#if 0
252		uint8_t x;
253
254		x = *(volatile uint8_t *)IIOV(NEXT_P_C16_CMD_REG);
255		aprint_debug_dev(sc->sc_dev, "cmd=%02x\n", x);
256#endif
257		*(volatile uint8_t *)IIOV(NEXT_P_C16_CMD_REG) = 0x05;
258		isrlink_autovec(nextdisplay_intr, sc,
259		    NEXT_I_IPL(NEXT_I_C16_VIDEO), 1, NULL);
260		INTR_ENABLE(NEXT_I_C16_VIDEO);
261	}
262
263	sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
264
265	/* initialize the raster */
266	waa.console = isconsole;
267	waa.scrdata = iscolor ?
268	    &nextdisplay_screenlist_color : &nextdisplay_screenlist_mono;
269	waa.accessops = &nextdisplay_accessops;
270	waa.accesscookie = sc;
271#if 0
272	printf("nextdisplay: access cookie is %p\n", sc);
273#endif
274	config_found(self, &waa, wsemuldisplaydevprint, CFARGS_NONE);
275}
276
277int
278nextdisplay_intr(void *arg)
279{
280#if 0
281	uint8_t x;
282#endif
283
284	if (!INTR_OCCURRED(NEXT_I_C16_VIDEO))
285		return 0;
286#if 0
287	x = *(volatile uint8_t *)IIOV(NEXT_P_C16_CMD_REG);
288	printf("I%02x", x);
289#endif
290	*(volatile uint8_t *)IIOV(NEXT_P_C16_CMD_REG) = 0x05;
291	return 1;
292}
293
294int
295nextdisplay_ioctl(void *v, void *vs, u_long cmd, void *data, int flag,
296    struct lwp *l)
297{
298	struct nextdisplay_softc *sc = v;
299	struct nextdisplay_config *dc = sc->sc_dc;
300	int new_mode;
301
302	switch (cmd) {
303	case WSDISPLAYIO_GTYPE:
304		*(int *)data = dc->dc_type;
305		return 0;
306
307	case WSDISPLAYIO_SCURSOR:
308		printf("nextdisplay_ioctl: wsdisplayio_scursor\n");
309		return EPASSTHROUGH;
310
311	case WSDISPLAYIO_SCURPOS:
312		printf("nextdisplay_ioctl: wsdisplayio_scurpos\n");
313		return EPASSTHROUGH;
314
315	case WSDISPLAYIO_GINFO:
316#define wsd_fbip ((struct wsdisplay_fbinfo *)data)
317		wsd_fbip->height = dc->dc_ht;
318		wsd_fbip->width = dc->dc_wid;
319		wsd_fbip->depth = dc->dc_depth;
320		wsd_fbip->cmsize = dc->dc_cmsize;
321#undef wsd_fbip
322                return 0;
323
324	case WSDISPLAYIO_LINEBYTES:
325		*(u_int *)data = dc->dc_rowbytes;
326		return 0;
327
328	case WSDISPLAYIO_SMODE:
329		new_mode = *(int *)data;
330		if (new_mode != sc->sc_mode) {
331			sc->sc_mode = new_mode;
332		}
333		return 0;
334
335	case WSDISPLAYIO_GETCMAP:
336	case WSDISPLAYIO_PUTCMAP:
337	case WSDISPLAYIO_GVIDEO:
338	case WSDISPLAYIO_SVIDEO:
339	case WSDISPLAYIO_GCURPOS:
340	case WSDISPLAYIO_GCURMAX:
341	case WSDISPLAYIO_GCURSOR:
342		printf("nextdisplay_ioctl: listed but unsupported ioctl\n");
343		return EPASSTHROUGH;
344	}
345
346	return EPASSTHROUGH;
347}
348
349static paddr_t
350nextdisplay_mmap(void *v, void *vs, off_t offset, int prot)
351{
352	struct nextdisplay_softc *sc = v;
353	struct nextdisplay_config *dc = sc->sc_dc;
354	paddr_t cookie = -1;
355
356	switch (sc->sc_mode) {
357	case WSDISPLAYIO_MODE_DUMBFB:
358		if (offset >= 0 && offset < dc->dc_size)
359			cookie = m68k_btop(dc->dc_paddr + offset);
360		break;
361	}
362
363	return cookie;
364}
365
366int
367nextdisplay_alloc_screen(void *v, const struct wsscreen_descr *type,
368    void **cookiep, int *curxp, int *curyp, long *defattrp)
369{
370	struct nextdisplay_softc *sc = v;
371	long defattr;
372
373	/* only allow one screen */
374	if (sc->nscreens > 0)
375		return ENOMEM;
376
377	*cookiep = &sc->sc_dc->dc_rcons; /* one and only for now */
378	*curxp = 0;
379	*curyp = 0;
380	rcons_allocattr(&sc->sc_dc->dc_rcons, 0, 0,
381	    (strcmp(type->name, "color") == 0) ? 0 : WSATTR_REVERSE, &defattr);
382	*defattrp = defattr;
383	sc->nscreens++;
384#if 0
385	printf("nextdisplay: allocating screen\n");
386#endif
387	return 0;
388}
389
390void
391nextdisplay_free_screen(void *v, void *cookie)
392{
393	struct nextdisplay_softc *sc = v;
394
395	if (sc->sc_dc == &nextdisplay_console_dc)
396		panic("nextdisplay_free_screen: console");
397
398	sc->nscreens--;
399}
400
401int
402nextdisplay_show_screen(void *v, void *cookie, int waitok,
403    void (*cb)(void *, int, int), void *cbarg)
404{
405
406	return 0;
407}
408
409static int
410nextdisplay_load_font(void *v, void *cookie, struct wsdisplay_font *font)
411{
412
413	return EPASSTHROUGH;
414}
415
416int
417nextdisplay_cnattach(void)
418{
419	struct nextdisplay_config *dc = &nextdisplay_console_dc;
420	long defattr;
421
422	/* set up the display */
423	nextdisplay_init(&nextdisplay_console_dc, iscolor);
424	nextdisplay_consaddr = nextdisplay_console_dc.dc_vaddr;
425
426	rcons_allocattr(&dc->dc_rcons, 0, 0,
427	    iscolor ? 0 : WSATTR_REVERSE, &defattr);
428
429	wsdisplay_cnattach(iscolor ? &nextdisplay_color : &nextdisplay_mono,
430	    &dc->dc_rcons, 0, 0, defattr);
431
432	dc->isconsole = 1;
433	return 0;
434}
435