vrc4172pci.c revision 1.2
1/*	$NetBSD: vrc4172pci.c,v 1.2 2002/04/14 08:00:00 takemura Exp $	*/
2
3/*-
4 * Copyright (c) 2002 TAKEMURA Shin
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. Neither the name of the project nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/device.h>
35
36#include <machine/bus.h>
37#include <machine/bus_space_hpcmips.h>
38#include <machine/bus_dma_hpcmips.h>
39#include <machine/config_hook.h>
40#include <machine/platid.h>
41#include <machine/platid_mask.h>
42
43#include <dev/pci/pcivar.h>
44#include <dev/pci/pcidevs.h>
45#include <dev/pci/pciidereg.h>
46
47#include <hpcmips/vr/icureg.h>
48#include <hpcmips/vr/vripif.h>
49#include <hpcmips/vr/vrc4172pcireg.h>
50
51#include "pci.h"
52
53#ifdef DEBUG
54#define	DPRINTF(args)	printf args
55#else
56#define	DPRINTF(args)
57#endif
58
59struct vrc4172pci_softc {
60	struct device sc_dev;
61
62	bus_space_tag_t sc_iot;
63	bus_space_handle_t sc_ioh;
64
65	struct hpcmips_pci_chipset sc_pc;
66};
67
68static int	vrc4172pci_match(struct device *, struct cfdata *, void *);
69static void	vrc4172pci_attach(struct device *, struct device *, void *);
70#if NPCI > 0
71static int	vrc4172pci_print(void *, const char *);
72#endif
73static void	vrc4172pci_attach_hook(struct device *, struct device *,
74		    struct pcibus_attach_args *);
75static int	vrc4172pci_bus_maxdevs(pci_chipset_tag_t, int);
76static int	vrc4172pci_bus_devorder(pci_chipset_tag_t, int, char *);
77static pcitag_t	vrc4172pci_make_tag(pci_chipset_tag_t, int, int, int);
78static void	vrc4172pci_decompose_tag(pci_chipset_tag_t, pcitag_t, int *,
79		    int *, int *);
80static pcireg_t	vrc4172pci_conf_read(pci_chipset_tag_t, pcitag_t, int);
81static void	vrc4172pci_conf_write(pci_chipset_tag_t, pcitag_t, int,
82		    pcireg_t);
83static int	vrc4172pci_intr_map(struct pci_attach_args *,
84		    pci_intr_handle_t *);
85static const char *vrc4172pci_intr_string(pci_chipset_tag_t,pci_intr_handle_t);
86static const struct evcnt *vrc4172pci_intr_evcnt(pci_chipset_tag_t,
87		    pci_intr_handle_t);
88static void	*vrc4172pci_intr_establish(pci_chipset_tag_t,
89		    pci_intr_handle_t, int, int (*)(void *), void *);
90static void	vrc4172pci_intr_disestablish(pci_chipset_tag_t, void *);
91
92struct cfattach vrc4172pci_ca = {
93	sizeof(struct vrc4172pci_softc), vrc4172pci_match, vrc4172pci_attach
94};
95
96static inline void
97vrc4172pci_write(struct vrc4172pci_softc *sc, int offset, u_int32_t val)
98{
99
100	bus_space_write_4(sc->sc_iot, sc->sc_ioh, offset, val);
101}
102
103static inline u_int32_t
104vrc4172pci_read(struct vrc4172pci_softc *sc, int offset)
105{
106	u_int32_t res;
107
108	if (bus_space_peek(sc->sc_iot, sc->sc_ioh, offset, 4, &res) < 0) {
109		res = 0xffffffff;
110	}
111
112	return (res);
113}
114
115static int
116vrc4172pci_match(struct device *parent, struct cfdata *match, void *aux)
117{
118
119	return (1);
120}
121
122static void
123vrc4172pci_attach(struct device *parent, struct device *self, void *aux)
124{
125	struct vrc4172pci_softc *sc = (struct vrc4172pci_softc *)self;
126	pci_chipset_tag_t pc = &sc->sc_pc;
127	struct vrip_attach_args *va = aux;
128#if NPCI > 0
129	struct pcibus_attach_args pba;
130#endif
131
132	sc->sc_iot = va->va_iot;
133	if (bus_space_map(sc->sc_iot, va->va_addr, va->va_size, 0,
134	    &sc->sc_ioh)) {
135		printf(": couldn't map io space\n");
136		return;
137	}
138	printf("\n");
139
140	pc->pc_dev = &sc->sc_dev;
141	pc->pc_attach_hook = vrc4172pci_attach_hook;
142	pc->pc_bus_maxdevs = vrc4172pci_bus_maxdevs;
143	pc->pc_bus_devorder = vrc4172pci_bus_devorder;
144	pc->pc_make_tag = vrc4172pci_make_tag;
145	pc->pc_decompose_tag = vrc4172pci_decompose_tag;
146	pc->pc_conf_read = vrc4172pci_conf_read;
147	pc->pc_conf_write = vrc4172pci_conf_write;
148	pc->pc_intr_map = vrc4172pci_intr_map;
149	pc->pc_intr_string = vrc4172pci_intr_string;
150	pc->pc_intr_evcnt = vrc4172pci_intr_evcnt;
151	pc->pc_intr_establish = vrc4172pci_intr_establish;
152	pc->pc_intr_disestablish = vrc4172pci_intr_disestablish;
153
154#if 0
155	{
156		int i;
157
158		for (i = 0; i < 2; i++)
159			printf("%s: ID_REG(0, 0, %d) = 0x%08x\n",
160			    sc->sc_dev.dv_xname, i,
161			    pci_conf_read(pc, pci_make_tag(pc, 0, 0, i),
162				PCI_ID_REG));
163	}
164#endif
165
166#if NPCI > 0
167	memset(&pba, 0, sizeof(pba));
168	pba.pba_busname = "pci";
169	pba.pba_iot = sc->sc_iot;
170	pba.pba_memt = sc->sc_iot;
171	pba.pba_dmat = &hpcmips_default_bus_dma_tag.bdt;
172	pba.pba_bus = 0;
173	pba.pba_flags = PCI_FLAGS_IO_ENABLED | PCI_FLAGS_MEM_ENABLED |
174	    PCI_FLAGS_MRL_OKAY;
175	pba.pba_pc = pc;
176
177	config_found(self, &pba, vrc4172pci_print);
178#endif
179}
180
181#if NPCI > 0
182static int
183vrc4172pci_print(void *aux, const char *pnp)
184{
185	struct pcibus_attach_args *pba = aux;
186
187	if (pnp != NULL)
188		printf("%s at %s", pba->pba_busname, pnp);
189	else
190		printf(" bus %d", pba->pba_bus);
191
192	return (UNCONF);
193}
194#endif
195
196void
197vrc4172pci_attach_hook(struct device *parent, struct device *self,
198    struct pcibus_attach_args *pba)
199{
200
201	return;
202}
203
204int
205vrc4172pci_bus_maxdevs(pci_chipset_tag_t pc, int busno)
206{
207
208	return (1);	/* Vrc4172 has only one device */
209}
210
211int
212vrc4172pci_bus_devorder(pci_chipset_tag_t pc, int busno, char *devs)
213{
214	int i;
215
216	*devs++ = 0;
217	for (i = 1; i < 32; i++)
218		*devs++ = -1;
219
220	return (1);
221}
222
223pcitag_t
224vrc4172pci_make_tag(pci_chipset_tag_t pc, int bus, int device, int function)
225{
226
227	return ((bus << 16) | (device << 11) | (function << 8));
228}
229
230void
231vrc4172pci_decompose_tag(pci_chipset_tag_t pc, pcitag_t tag, int *bp, int *dp,
232    int *fp)
233{
234
235	if (bp != NULL)
236		*bp = (tag >> 16) & 0xff;
237	if (dp != NULL)
238		*dp = (tag >> 11) & 0x1f;
239	if (fp != NULL)
240		*fp = (tag >> 8) & 0x07;
241}
242
243pcireg_t
244vrc4172pci_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg)
245{
246	struct vrc4172pci_softc *sc = (struct vrc4172pci_softc *)pc->pc_dev;
247	u_int32_t val;
248
249	tag |= VRC4172PCI_CONFADDR_CONFIGEN;
250
251	vrc4172pci_write(sc, VRC4172PCI_CONFAREG, tag | reg);
252	val = vrc4172pci_read(sc, VRC4172PCI_CONFDREG);
253	DPRINTF(("%s: conf_read: tag = 0x%08x, reg = 0x%x, val = 0x%08x\n",
254	    sc->sc_dev.dv_xname, (u_int32_t)tag, reg, val));
255
256	return (val);
257}
258
259void
260vrc4172pci_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg,
261    pcireg_t data)
262{
263	struct vrc4172pci_softc *sc = (struct vrc4172pci_softc *)pc->pc_dev;
264
265	DPRINTF(("%s: conf_write: tag = 0x%08x, reg = 0x%x, val = 0x%08x\n",
266	    sc->sc_dev.dv_xname, (u_int32_t)tag, reg, (u_int32_t)data));
267	tag |= VRC4172PCI_CONFADDR_CONFIGEN;
268
269	vrc4172pci_write(sc, VRC4172PCI_CONFAREG, tag | reg);
270	vrc4172pci_write(sc, VRC4172PCI_CONFDREG, data);
271}
272
273int
274vrc4172pci_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
275{
276	pci_chipset_tag_t pc = pa->pa_pc;
277	pcitag_t intrtag = pa->pa_intrtag;
278	int bus, dev, func;
279
280	pci_decompose_tag(pc, intrtag, &bus, &dev, &func);
281	DPRINTF(("%s(%d, %d, %d): line = %d, pin = %d\n", pc->pc_dev->dv_xname,
282	    bus, dev, func, pa->pa_intrline, pa->pa_intrpin));
283
284	*ihp = CONFIG_HOOK_PCIINTR_ID(bus, dev, func);
285
286	return (0);
287}
288
289const char *
290vrc4172pci_intr_string(pci_chipset_tag_t pc, pci_intr_handle_t ih)
291{
292	static char irqstr[sizeof("pciintr") + 16];
293
294	snprintf(irqstr, sizeof(irqstr), "pciintr %d:%d:%d",
295	    CONFIG_HOOK_PCIINTR_BUS((int)ih),
296	    CONFIG_HOOK_PCIINTR_DEVICE((int)ih),
297	    CONFIG_HOOK_PCIINTR_FUNCTION((int)ih));
298
299	return (irqstr);
300}
301
302const struct evcnt *
303vrc4172pci_intr_evcnt(pci_chipset_tag_t pc, pci_intr_handle_t ih)
304{
305
306	return (NULL);
307}
308
309void *
310vrc4172pci_intr_establish(pci_chipset_tag_t pc, pci_intr_handle_t ih,
311    int level, int (*func)(void *), void *arg)
312{
313
314	if (ih == -1)
315		return (NULL);
316	DPRINTF(("vrc4172pci_intr_establish: %lx\n", ih));
317
318	return (config_hook(CONFIG_HOOK_PCIINTR, ih, CONFIG_HOOK_EXCLUSIVE,
319	    (int (*)(void *, int, long, void *))func, arg));
320}
321
322void
323vrc4172pci_intr_disestablish(pci_chipset_tag_t pc, void *cookie)
324{
325
326	DPRINTF(("vrc4172pci_intr_disestablish: %p\n", cookie));
327	config_unhook(cookie);
328}
329