vrc4173bcu.c revision 1.4
1/*	$NetBSD: vrc4173bcu.c,v 1.4 2002/01/05 06:45:32 takemura Exp $	*/
2
3/*-
4 * Copyright (c) 2001,2002 Enami Tsugutomo.
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 REGENTS AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/param.h>
30#include <sys/systm.h>
31#include <sys/device.h>
32
33#include <machine/bus.h>
34
35#include <dev/pci/pcivar.h>
36#include <dev/pci/pcidevs.h>
37
38#include <machine/platid.h>
39#include <machine/platid_mask.h>
40
41#include <hpcmips/vr/vrc4173bcuvar.h>
42#include <hpcmips/vr/vrc4173icureg.h>
43#include <hpcmips/vr/vrc4173cmureg.h>
44
45#define	VRC4173BCU_BADR		0x10
46#ifdef DEBUG
47#define	DPRINTF(args)	printf args
48#else
49#define	DPRINTF(args)
50#endif
51
52#define USE_WINCE_CLKMASK	(~0)
53
54static int	vrc4173bcu_match(struct device *, struct cfdata *, void *);
55static void	vrc4173bcu_attach(struct device *, struct device *, void *);
56static int	vrc4173bcu_print(void *, const char *);
57
58/*
59 * machine dependent info
60 */
61static struct vrc4173bcu_platdep {
62	platid_mask_t *platidmask;
63	u_int32_t clkmask;
64	int intr_port;	/* GPIO port to which VRCINT is connected to. XXX */
65} platdep_table[] = {
66	{
67		&platid_mask_MACH_VICTOR_INTERLINK_MPC303,
68		USE_WINCE_CLKMASK,	/* clock mask */
69		1,			/* intrrupt port# */
70	},
71	{
72		&platid_mask_MACH_VICTOR_INTERLINK_MPC304,
73		USE_WINCE_CLKMASK,	/* clock mask */
74		1,			/* intrrupt port# */
75	},
76	{
77		&platid_mask_MACH_NEC_MCR_SIGMARION2,
78		USE_WINCE_CLKMASK,	/* clock mask */
79		0,			/* intrrupt port# */
80	},
81	{
82		&platid_wild,
83		USE_WINCE_CLKMASK,	/* XXX */
84		-1,
85	},
86};
87
88struct vrc4173bcu_softc {
89	struct device sc_dev;
90
91	pci_chipset_tag_t sc_pc;
92	bus_space_tag_t sc_iot;
93	bus_space_handle_t sc_ioh;
94	bus_size_t sc_size;
95
96	bus_space_handle_t sc_icuh;	/* I/O handle for ICU. */
97	bus_space_handle_t sc_cmuh;	/* I/O handle for CMU. */
98	void *sc_ih;
99
100#define	VRC4173BCU_NINTRHAND	(16)	/* XXX */
101	struct intrhand {
102		int (*ih_func)(void *);
103		void *ih_arg;
104	} sc_intrhand[VRC4173BCU_NINTRHAND];
105
106	struct vrc4173bcu_platdep *sc_platdep;
107};
108
109struct cfattach vrc4173bcu_ca = {
110	sizeof(struct vrc4173bcu_softc), vrc4173bcu_match, vrc4173bcu_attach,
111};
112
113int
114vrc4173bcu_match(struct device *parent, struct cfdata *match, void *aux)
115{
116	struct pci_attach_args *pa = (struct pci_attach_args *)aux;
117
118	if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_NEC &&
119	    PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_NEC_VRC4173_BCU)
120		return (1);
121
122	return (0);
123}
124
125void
126vrc4173bcu_attach(struct device *parent, struct device *self, void *aux)
127{
128	struct vrc4173bcu_softc *sc = (struct vrc4173bcu_softc *)self;
129	struct pci_attach_args *pa = (struct pci_attach_args *)aux;
130	pci_chipset_tag_t pc = pa->pa_pc;
131	pcitag_t tag = pa->pa_tag;
132	pcireg_t csr;
133	char devinfo[256];
134	int i;
135	u_int16_t reg;
136#ifdef DEBUG
137	char buf[80];
138#endif
139
140	pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo);
141	printf(": %s (rev. 0x%02x)\n", devinfo, PCI_REVISION(pa->pa_class));
142
143#if 0
144	printf("%s: ", sc->sc_dev.dv_xname);
145	pci_conf_print(pa->pa_pc, pa->pa_tag, NULL);
146#endif
147
148	csr = pci_conf_read(pc, tag, VRC4173BCU_BADR);
149	DPRINTF(("%s: base addr = 0x%08x\n", sc->sc_dev.dv_xname, csr));
150
151	sc->sc_platdep = platid_search(&platid, platdep_table,
152	    sizeof(platdep_table)/sizeof(*platdep_table),
153	    sizeof(*platdep_table));
154
155	/* Map I/O registers */
156	if (pci_mapreg_map(pa, VRC4173BCU_BADR, PCI_MAPREG_TYPE_IO, 0,
157	    &sc->sc_iot, &sc->sc_ioh, NULL, &sc->sc_size)) {
158		printf("%s: can't map mem space\n", sc->sc_dev.dv_xname);
159		return;
160	}
161
162	sc->sc_pc = pc;
163
164	/* Enable the device. */
165	csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
166	DPRINTF(("%s: csr = 0x%08x", sc->sc_dev.dv_xname, csr));
167	pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG,
168	    csr | PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_IO_ENABLE);
169	csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
170	DPRINTF((" -> 0x%08x\n", csr));
171
172	csr = pci_conf_read(pc, tag, VRC4173BCU_BADR);
173	DPRINTF(("%s: base addr = %x@0x%08x\n", sc->sc_dev.dv_xname,
174	    (int)sc->sc_size, csr));
175	DPRINTF(("%s: iot = 0x%08x, ioh = 0x%08x\n", sc->sc_dev.dv_xname,
176	    (int)sc->sc_iot, (int)sc->sc_ioh));
177
178	/*
179	 * Map I/O space for ICU.
180	 */
181	if (bus_space_subregion(sc->sc_iot, sc->sc_ioh,
182	    VRC4173ICU_IOBASE, VRC4173ICU_IOSIZE, &sc->sc_icuh)) {
183		printf(": can't map ICU i/o space\n");
184		return;
185	}
186
187	/*
188	 * Map I/O space for CMU.
189	 */
190	if (bus_space_subregion(sc->sc_iot, sc->sc_ioh,
191	    VRC4173CMU_IOBASE, VRC4173CMU_IOSIZE, &sc->sc_cmuh)) {
192		printf(": can't map CMU i/o space\n");
193		return;
194	}
195
196	/* machine dependent setup */
197	if (sc->sc_platdep->clkmask == USE_WINCE_CLKMASK) {
198		/* XXX, You can nothing! */
199		reg = bus_space_read_2(sc->sc_iot, sc->sc_cmuh,
200		    VRC4173CMU_CLKMSK);
201		printf("%s: default clock mask is %04x\n",
202		    sc->sc_dev.dv_xname, reg);
203	} else {
204		/* assert all reset bits */
205		bus_space_write_2(sc->sc_iot, sc->sc_cmuh, VRC4173CMU_SRST,
206		    VRC4173CMU_SRST_AC97 | VRC4173CMU_SRST_USB |
207		    VRC4173CMU_SRST_CARD2 | VRC4173CMU_SRST_CARD1);
208		/* set clock mask */
209		bus_space_write_2(sc->sc_iot, sc->sc_cmuh,
210		    VRC4173CMU_CLKMSK, sc->sc_platdep->clkmask);
211		/* clear reset bit */
212		bus_space_write_2(sc->sc_iot, sc->sc_cmuh, VRC4173CMU_SRST, 0);
213	}
214
215#ifdef DEBUG
216	reg = bus_space_read_2(sc->sc_iot, sc->sc_icuh, VRC4173ICU_SYSINT1);
217	bitmask_snprintf(reg,
218	    "\20\1USB\2PCMCIA2\3PCMCIA1\4PS2CH2\5PS2CH1\6PIU\7AIU\10KIU"
219	    "\11GIU\12AC97\13AC97-1\14B11\15B12\16DOZEPIU\17B14\20B15",
220	    buf, sizeof(buf));
221	printf("%s: SYSINT1 = 0x%s\n", sc->sc_dev.dv_xname, buf);
222
223	reg = bus_space_read_2(sc->sc_iot, sc->sc_icuh, VRC4173ICU_MKIUINT);
224	bitmask_snprintf(reg,
225	    "\20\1SCANINT\2KDATRDY\3KDATLOST\4B3\5B4\6B5\7B6\10B7"
226	    "\11B8\12B9\13B10\14B11\15B12\16B13\17B14\20B15",
227	    buf, sizeof(buf));
228	printf("%s: MKIUINT = 0x%s\n", sc->sc_dev.dv_xname, buf);
229
230	reg = bus_space_read_2(sc->sc_iot, sc->sc_icuh, VRC4173ICU_MSYSINT1);
231	bitmask_snprintf(reg,
232	    "\20\1USB\2PCMCIA2\3PCMCIA1\4PS2CH2\5PS2CH1\6PIU\7AIU\10KIU"
233	    "\11GIU\12AC97\13AC97-1\14B11\15B12\16DOZEPIU\17B14\20B15",
234	    buf, sizeof(buf));
235	printf("%s: MSYSINT1 = 0x%s\n", sc->sc_dev.dv_xname, buf);
236
237#if 1
238	reg = VRC4173ICU_USBINTR | VRC4173ICU_PIUINTR | VRC4173ICU_KIUINTR |
239	    VRC4173ICU_DOZEPIUINTR;
240	bus_space_write_2(sc->sc_iot, sc->sc_icuh, VRC4173ICU_MSYSINT1, reg);
241
242	reg = bus_space_read_2(sc->sc_iot, sc->sc_icuh, VRC4173ICU_MSYSINT1);
243	bitmask_snprintf(reg,
244	    "\20\1USB\2PCMCIA2\3PCMCIA1\4PS2CH2\5PS2CH1\6PIU\7AIU\10KIU"
245	    "\11GIU\12AC97\13AC97-1\14B11\15B12\16DOZEPIU\17B14\20B15",
246	    buf, sizeof(buf));
247	printf("%s: MSYSINT1 = 0x%s\n", sc->sc_dev.dv_xname, buf);
248#endif
249#endif
250
251	for (i = 0; i < VRC4173BCU_NINTRHAND; i++)
252		sc->sc_intrhand[i].ih_func = NULL;
253
254	/*
255	 * Attach sub units found in vrc4173.  XXX.
256	 */
257	config_found(self, "vrc4173cmu", vrc4173bcu_print);
258	config_found(self, "vrc4173giu", vrc4173bcu_print);
259	config_found(self, "vrc4173piu", vrc4173bcu_print);
260	config_found(self, "vrc4173kiu", vrc4173bcu_print);
261	config_found(self, "vrc4173aiu", vrc4173bcu_print);
262	config_found(self, "vrc4173ps2u", vrc4173bcu_print);
263
264	/*
265	 * Establish VRCINT interrupt.  Normally connected to one of
266	 * GPIO pin in VR41xx.  XXX.
267	 */
268	if (0 <= sc->sc_platdep->intr_port) {
269		sc->sc_ih = pci_vrcintr_establish(pc,
270		    sc->sc_platdep->intr_port, vrc4173bcu_intr, sc);
271		if (sc->sc_ih != NULL)
272			printf("%s: interrupting at %p\n", sc->sc_dev.dv_xname,
273			    sc->sc_ih);
274	} else {
275		printf("%s: interrupt port isn't specified\n",
276		    sc->sc_dev.dv_xname);
277	}
278}
279
280int
281vrc4173bcu_print(void *aux, const char *pnp)
282{
283	const char *name = aux;
284
285	if (pnp)
286		printf("%s at %s", name, pnp);
287
288	return (UNCONF);
289}
290
291int
292vrc4173bcu_intr(void *arg)
293{
294	struct vrc4173bcu_softc *sc = (struct vrc4173bcu_softc *)arg;
295	struct intrhand *ih;
296	u_int16_t reg;
297	int i, handled;
298
299	reg = bus_space_read_2(sc->sc_iot, sc->sc_icuh, VRC4173ICU_SYSINT1);
300	if (reg == 0)
301		return (0);
302
303#if 0
304    {
305	char buf[80];
306	bitmask_snprintf(reg,
307	    "\20\1USB\2PCMCIA2\3PCMCIA1\4PS2CH2\5PS2CH1\6PIU\7AIU\10KIU"
308	    "\11GIU\12AC97\13AC97-1\14B11\15B12\16DOZEPIU\17B14\20B15",
309	    buf, sizeof(buf));
310	printf("%s: %s\n", sc->sc_dev.dv_xname, buf);
311    }
312#endif
313	for (handled = i = 0; i < VRC4173BCU_NINTRHAND; i++) {
314		ih = &sc->sc_intrhand[i];
315		if (ih->ih_func != NULL && (reg & (1 << i)) != 0) {
316			handled = 1;
317			(*ih->ih_func)(ih->ih_arg);
318		}
319	}
320
321	return (handled);
322}
323
324void *
325vrc4173bcu_intr_establish(struct vrc4173bcu_softc *sc, int kind,
326    int (*func)(void *), void *arg)
327{
328	struct intrhand *ih;
329
330	DPRINTF(("vrc4173bcu_intr_establish: %d, %p, %p\n", kind, func, arg));
331	if (kind < 0 || kind >= VRC4173BCU_NINTRHAND)
332		return (NULL);
333
334	ih = &sc->sc_intrhand[kind];
335	if (ih->ih_func != NULL)
336		return (NULL);
337
338	ih->ih_func = func;
339	ih->ih_arg = arg;
340	return (ih);
341}
342
343void
344vrc4173bcu_intr_disestablish(struct vrc4173bcu_softc *sc, void *ihp)
345{
346	struct intrhand *ih = ihp;
347
348	if (ih < &sc->sc_intrhand[0] ||
349	    ih >= &sc->sc_intrhand[VRC4173BCU_NINTRHAND])
350		return;
351
352	ih->ih_func = NULL;
353}
354
355int
356vrc4173bcu_pci_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
357{
358	pci_chipset_tag_t pc = pa->pa_pc;
359	pcitag_t intrtag = pa->pa_intrtag;
360	int bus, dev, func;
361#ifdef DEBUG
362	int line = pa->pa_intrline;
363	int pin = pa->pa_intrpin;
364#endif
365
366	pci_decompose_tag(pc, intrtag, &bus, &dev, &func);
367	DPRINTF(("%s(%d, %d, %d): line = %d, pin = %d\n", pc->pc_dev->dv_xname,
368	    bus, dev, func, line, pin));
369
370	*ihp = -1;
371	switch (dev) {
372	case 1:				/* CARDU0 */
373		*ihp = VRC4173ICU_PCMCIA1INTR;
374		break;
375	case 2:				/* CARDU1 */
376		*ihp = VRC4173ICU_PCMCIA2INTR;
377		break;
378	case 12:			/* VRC4173 (SigmarionII) */
379	case 19:			/* VRC4173 (MP-C303) */
380		switch (func) {
381		case 2:
382			*ihp = VRC4173ICU_USBINTR;
383			break;
384		}
385		break;
386	}
387
388	return (*ihp == -1);
389}
390
391const char *
392vrc4173bcu_pci_intr_string(pci_chipset_tag_t pc, pci_intr_handle_t ih)
393{
394	static char irqstr[8 + sizeof("vrc4173 intr")];
395
396	snprintf(irqstr, sizeof(irqstr), "vrc4173 intr %d", (int)ih);
397	return (irqstr);
398}
399
400const struct evcnt *
401vrc4173bcu_pci_intr_evcnt(pci_chipset_tag_t pc, pci_intr_handle_t ih)
402{
403
404	/* XXX for now, no evcnt parent reported */
405	return (NULL);
406}
407
408