1/*	$NetBSD: gvpio.c,v 1.22 2021/08/07 16:18:41 thorpej Exp $ */
2
3/*
4 * Copyright (c) 1997 Ignatios Souvatzis
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 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include <sys/cdefs.h>
29__KERNEL_RCSID(0, "$NetBSD: gvpio.c,v 1.22 2021/08/07 16:18:41 thorpej Exp $");
30
31/*
32 * GVP I/O Extender
33 */
34
35#include <sys/types.h>
36
37#include <sys/conf.h>
38#include <sys/device.h>
39#include <sys/systm.h>
40#include <sys/param.h>
41#include <sys/bus.h>
42
43#include <machine/intr.h>
44
45#include <amiga/include/cpu.h>
46
47#include <amiga/amiga/device.h>
48#include <amiga/amiga/drcustom.h>
49
50#include <amiga/dev/supio.h>
51#include <amiga/dev/zbusvar.h>
52#include <amiga/dev/gvpbusvar.h>
53
54struct gvpio_softc {
55	struct bus_space_tag sc_bst;
56	void *sc_cntr;
57	LIST_HEAD(, gvpcom_int_hdl) sc_comhdls;
58	struct isr sc_comisr;
59};
60
61int gvpiomatch(device_t, cfdata_t, void *);
62void gvpioattach(device_t, device_t, void *);
63int gvpioprint(void *, const char *);
64int gvp_com_intr(void *);
65void gvp_com_intr_establish(device_t, struct gvpcom_int_hdl *);
66
67CFATTACH_DECL_NEW(gvpio, sizeof(struct gvpio_softc),
68    gvpiomatch, gvpioattach, NULL, NULL);
69
70int
71gvpiomatch(device_t parent, cfdata_t cf, void *aux)
72{
73
74	struct gvpbus_args *gap;
75
76	gap = aux;
77
78	if (gap->flags & GVP_IO)
79		return (1);
80
81	return (0);
82}
83
84struct gvpio_devs {
85	char *name;
86	int off;
87	int arg;
88	int ipl;
89} gvpiodevs[] = {
90	{ "com", 0x0b0, 115200 * 16 * 4, 6 },
91	{ "com", 0x130, 115200 * 16 * 4, 6 },
92	{ "lpt", 0x1b0, 0, 2 },
93	{ 0 }
94};
95
96void
97gvpioattach(device_t parent, device_t self, void *aux)
98{
99	struct gvpio_softc *giosc;
100	struct gvpio_devs  *giosd;
101	struct gvpbus_args *gap;
102	struct supio_attach_args supa;
103	volatile void *gbase;
104#ifdef __m68k__
105	u_int16_t needpsl;
106#endif
107
108	giosc = device_private(self);
109	gap = aux;
110
111	if (parent)
112		printf("\n");
113
114	gbase = gap->zargs.va;
115	giosc->sc_cntr = &gbase[0x41];
116	giosc->sc_bst.base = (u_long)gbase + 1;
117	giosc->sc_bst.absm = &amiga_bus_stride_2;
118	LIST_INIT(&giosc->sc_comhdls);
119	giosd = gvpiodevs;
120
121	supa.supio_iot = &giosc->sc_bst;
122
123	gbase[0x041] = 0;
124	gbase[0x161 + 1*2] = 0;
125	gbase[0x261 + 1*2] = 0;
126	gbase[0x361 + 2*2] = 0;
127	gbase[0x461] = 0xd0;
128
129	while (giosd->name) {
130		supa.supio_name = giosd->name;
131		supa.supio_iobase = giosd->off;
132		supa.supio_arg = giosd->arg;
133		supa.supio_ipl = giosd->ipl;
134		config_found(self, &supa, gvpioprint, CFARGS_NONE); /* XXX */
135		++giosd;
136	}
137	if (giosc->sc_comhdls.lh_first) {
138#ifdef __m68k__
139		/* XXX this should be really in the interrupt stuff */
140		needpsl = PSL_S|PSL_IPL6;
141		if (ipl2spl_table[IPL_SERIAL] < needpsl) {
142			printf("%s: raising ipl2spl_table[IPL_SERIAL] "
143			    "from 0x%x to 0x%x\n",
144			    device_xname(self), ipl2spl_table[IPL_SERIAL],
145			    needpsl);
146			ipl2spl_table[IPL_SERIAL] = needpsl;
147		}
148#endif
149		giosc->sc_comisr.isr_intr = gvp_com_intr;
150		giosc->sc_comisr.isr_arg = giosc;
151		giosc->sc_comisr.isr_ipl = 6;
152		add_isr(&giosc->sc_comisr);
153	}
154	gbase[0x041] = 0x08;
155}
156
157int
158gvpioprint(void *aux, const char *pnp)
159{
160	struct supio_attach_args *supa;
161
162	supa = aux;
163
164	if (pnp == NULL)
165		return(QUIET);
166
167	aprint_normal("%s at %s port 0x%02x ipl %d",
168	    supa->supio_name, pnp, supa->supio_iobase, supa->supio_ipl);
169
170	return(UNCONF);
171}
172
173void
174gvp_com_intr_establish(device_t self, struct gvpcom_int_hdl *p)
175{
176	struct gvpio_softc *sc;
177
178	sc = device_private(self);
179	LIST_INSERT_HEAD(&sc->sc_comhdls, p, next);
180
181}
182
183int
184gvp_com_intr(void *p)
185{
186	struct gvpio_softc *sc;
187	struct gvpcom_int_hdl *np;
188	volatile void *cntr;
189
190	sc = (struct gvpio_softc *)p;
191
192	cntr = sc->sc_cntr;
193
194	if (!(*cntr & 0x2))
195		return (0);
196
197	*cntr &= ~0xa;
198
199	for (np = sc->sc_comhdls.lh_first; np != NULL;
200	    np = np->next.le_next) {
201
202		(*np->f)(np->p);
203	}
204	*cntr |= 0x8;
205
206	return (1);
207}
208