xref: /netbsd-src/sys/arch/arm/xscale/becc_pci.c (revision 001c68bd94f75ce9270b69227c4199fbf34ee396)
1 /*	$NetBSD: becc_pci.c,v 1.3 2003/05/23 05:21:26 briggs Exp $	*/
2 
3 /*
4  * Copyright (c) 2001, 2002 Wasabi Systems, Inc.
5  * All rights reserved.
6  *
7  * Written by Jason R. Thorpe for Wasabi Systems, Inc.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *	This product includes software developed for the NetBSD Project by
20  *	Wasabi Systems, Inc.
21  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22  *    or promote products derived from this software without specific prior
23  *    written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
29  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35  * POSSIBILITY OF SUCH DAMAGE.
36  */
37 
38 /*
39  * PCI configuration support for the ADI Engineering Big Endian Companion
40  * Chip.
41  */
42 
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/device.h>
46 #include <sys/extent.h>
47 #include <sys/malloc.h>
48 
49 #include <uvm/uvm_extern.h>
50 
51 #include <machine/bus.h>
52 
53 #include <arm/xscale/beccreg.h>
54 #include <arm/xscale/beccvar.h>
55 
56 #include <dev/pci/ppbreg.h>
57 #include <dev/pci/pciconf.h>
58 
59 #include "opt_pci.h"
60 #include "pci.h"
61 
62 void		becc_pci_attach_hook(struct device *, struct device *,
63 		    struct pcibus_attach_args *);
64 int		becc_pci_bus_maxdevs(void *, int);
65 pcitag_t	becc_pci_make_tag(void *, int, int, int);
66 void		becc_pci_decompose_tag(void *, pcitag_t, int *, int *,
67 		    int *);
68 pcireg_t	becc_pci_conf_read(void *, pcitag_t, int);
69 void		becc_pci_conf_write(void *, pcitag_t, int, pcireg_t);
70 
71 int		becc_pci_intr_map(struct pci_attach_args *,
72 		    pci_intr_handle_t *);
73 const char	*becc_pci_intr_string(void *, pci_intr_handle_t);
74 const struct evcnt *becc_pci_intr_evcnt(void *, pci_intr_handle_t);
75 void		*becc_pci_intr_establish(void *, pci_intr_handle_t,
76 		    int, int (*)(void *), void *);
77 void		becc_pci_intr_disestablish(void *, void *);
78 
79 #define	PCI_CONF_LOCK(s)	(s) = disable_interrupts(I32_bit)
80 #define	PCI_CONF_UNLOCK(s)	restore_interrupts((s))
81 
82 #if 0
83 #define DPRINTF(x) printf(x)
84 #else
85 #define DPRINTF(x)
86 #endif
87 
88 void
89 becc_pci_init(pci_chipset_tag_t pc, void *cookie)
90 {
91 #if NPCI > 0 && defined(PCI_NETBSD_CONFIGURE)
92 	struct becc_softc *sc = cookie;
93 	struct extent *ioext, *memext;
94 #endif
95 
96 	pc->pc_conf_v = cookie;
97 	pc->pc_attach_hook = becc_pci_attach_hook;
98 	pc->pc_bus_maxdevs = becc_pci_bus_maxdevs;
99 	pc->pc_make_tag = becc_pci_make_tag;
100 	pc->pc_decompose_tag = becc_pci_decompose_tag;
101 	pc->pc_conf_read = becc_pci_conf_read;
102 	pc->pc_conf_write = becc_pci_conf_write;
103 
104 	pc->pc_intr_v = cookie;
105 	pc->pc_intr_map = becc_pci_intr_map;
106 	pc->pc_intr_string = becc_pci_intr_string;
107 	pc->pc_intr_evcnt = becc_pci_intr_evcnt;
108 	pc->pc_intr_establish = becc_pci_intr_establish;
109 	pc->pc_intr_disestablish = becc_pci_intr_disestablish;
110 
111 #if NPCI > 0 && defined(PCI_NETBSD_CONFIGURE)
112 	/*
113 	 * Configure the PCI bus.
114 	 *
115 	 * XXX We need to revisit this.  We only configure the Secondary
116 	 * bus (and its children).  The bus configure code needs changes
117 	 * to support how the busses are arranged on this chip.  We also
118 	 * need to only configure devices in the private device space on
119 	 * the Secondary bus.
120 	 */
121 
122 	/* Reserve the bottom 32K of the PCI address space. */
123 	ioext  = extent_create("pciio", sc->sc_ioout_xlate + (32 * 1024),
124 	    sc->sc_ioout_xlate + (64 * 1024) - 1,
125 	    M_DEVBUF, NULL, 0, EX_NOWAIT);
126 	memext = extent_create("pcimem", sc->sc_owin_xlate[0],
127 	    sc->sc_owin_xlate[0] + BECC_PCI_MEM1_SIZE - 1,
128 	    M_DEVBUF, NULL, 0, EX_NOWAIT);
129 
130 	aprint_normal("%s: configuring PCI bus\n", sc->sc_dev.dv_xname);
131 	pci_configure_bus(pc, ioext, memext, NULL, 0, arm_dcache_align);
132 
133 	extent_destroy(ioext);
134 	extent_destroy(memext);
135 #endif
136 }
137 
138 void
139 pci_conf_interrupt(pci_chipset_tag_t pc, int a, int b, int c, int d, int *p)
140 {
141 }
142 
143 void
144 becc_pci_attach_hook(struct device *parent, struct device *self,
145     struct pcibus_attach_args *pba)
146 {
147 
148 	/* Nothing to do. */
149 }
150 
151 int
152 becc_pci_bus_maxdevs(void *v, int busno)
153 {
154 
155 	return (32);
156 }
157 
158 pcitag_t
159 becc_pci_make_tag(void *v, int b, int d, int f)
160 {
161 
162 	return ((b << 16) | (d << 11) | (f << 8));
163 }
164 
165 void
166 becc_pci_decompose_tag(void *v, pcitag_t tag, int *bp, int *dp, int *fp)
167 {
168 
169 	if (bp != NULL)
170 		*bp = (tag >> 16) & 0xff;
171 	if (dp != NULL)
172 		*dp = (tag >> 11) & 0x1f;
173 	if (fp != NULL)
174 		*fp = (tag >> 8) & 0x7;
175 }
176 
177 struct pciconf_state {
178 	uint32_t ps_offset;
179 
180 	int ps_b, ps_d, ps_f;
181 	int ps_type;
182 };
183 
184 static int
185 becc_pci_conf_setup(struct becc_softc *sc, pcitag_t tag, int offset,
186     struct pciconf_state *ps)
187 {
188 
189 	becc_pci_decompose_tag(sc, tag, &ps->ps_b, &ps->ps_d, &ps->ps_f);
190 
191 	/*
192 	 * If the bus # is the same as our own, then use Type 0 cycles,
193 	 * else use Type 1.
194 	 */
195 	if (ps->ps_b == 0) {
196 		/* XXX This is a platform-specific parameter. */
197 		if (ps->ps_d > (14 - BECC_IDSEL_BIT))
198 			return (1);
199 		ps->ps_offset = (1U << (ps->ps_d + BECC_IDSEL_BIT)) |
200 		    (ps->ps_f << 8) | offset;
201 		ps->ps_type = 0;
202 	} else {
203 		/* The tag is already in the correct format. */
204 		ps->ps_offset = tag | offset | 1;
205 		ps->ps_type = 1;
206 	}
207 
208 	return (0);
209 }
210 
211 static int becc_pci_conf_cleanup(struct becc_softc *sc);
212 static int
213 becc_pci_conf_cleanup(struct becc_softc *sc)
214 {
215 	uint32_t reg;
216 	int	err=0;
217 
218 	BECC_CSR_WRITE(BECC_POCR, 0);
219 
220 	reg = becc_pcicore_read(sc, PCI_COMMAND_STATUS_REG);
221 	if (reg & 0xf9000000) {
222 		DPRINTF((" ** pci status error: %08x (%08x) **\n",
223 		    reg, reg & 0xf9000000));
224 
225 		err = 1;
226 		becc_pcicore_write(sc, PCI_COMMAND_STATUS_REG,
227 		    reg & 0xf900ffff);
228 		reg = becc_pcicore_read(sc, PCI_COMMAND_STATUS_REG);
229 
230 		DPRINTF((" ** pci status after clearing: %08x (%08x) **\n",
231 		    reg, reg & 0xf9000000));
232 	}
233 	reg = BECC_CSR_READ(BECC_PMISR);
234 	if (reg & 0x000f000d) {
235 		DPRINTF((" ** pci master isr: %08x (%08x) **\n",
236 		    reg, reg & 0x000f000d));
237 
238 		err = 1;
239 		BECC_CSR_WRITE(BECC_PMISR, reg & 0x000f000d);
240 		reg = BECC_CSR_READ(BECC_PMISR);
241 
242 		DPRINTF((" ** pci master isr after clearing: %08x (%08x) **\n",
243 		    reg, reg & 0x000f000d));
244 	}
245 	reg = BECC_CSR_READ(BECC_PSISR);
246 	if (reg & 0x000f0210) {
247 		DPRINTF((" ** pci slave isr: %08x (%08x) **\n",
248 		    reg, reg & 0x000f0210));
249 
250 		err = 1;
251 		BECC_CSR_WRITE(BECC_PSISR, reg & 0x000f0210);
252 		reg = BECC_CSR_READ(BECC_PSISR);
253 
254 		DPRINTF((" ** pci slave isr after clearing: %08x (%08x) **\n",
255 		    reg, reg & 0x000f0210));
256 	}
257 
258 	return err;
259 }
260 
261 pcireg_t
262 becc_pci_conf_read(void *v, pcitag_t tag, int offset)
263 {
264 	struct becc_softc *sc = v;
265 	struct pciconf_state ps;
266 	vaddr_t va;
267 	pcireg_t rv;
268 	u_int s;
269 
270 	if (becc_pci_conf_setup(sc, tag, offset, &ps))
271 		return ((pcireg_t) -1);
272 
273 	/*
274 	 * Skip device 0 (the BECC itself).  We don't want it
275 	 * to appear as part of the PCI device space.
276 	 */
277 	if (ps.ps_b == 0 && ps.ps_d == 0)
278 		return ((pcireg_t) -1);
279 
280 	PCI_CONF_LOCK(s);
281 
282 	va = sc->sc_pci_cfg_base + ps.ps_offset;
283 	BECC_CSR_WRITE(BECC_POCR, ps.ps_type);
284 
285 	if (badaddr_read((void *) va, sizeof(rv), &rv)) {
286 		/* XXX Check master/target abort? */
287 #if 0
288 		printf("conf_read: %d/%d/%d bad address\n",
289 		    ps.ps_b, ps.ps_d, ps.ps_f);
290 #endif
291 		rv = (pcireg_t) -1;
292 	}
293 
294 	if (becc_pci_conf_cleanup(sc))
295 		rv = (pcireg_t) -1;
296 
297 	PCI_CONF_UNLOCK(s);
298 
299 	return (rv);
300 }
301 
302 void
303 becc_pci_conf_write(void *v, pcitag_t tag, int offset, pcireg_t val)
304 {
305 	struct becc_softc *sc = v;
306 	struct pciconf_state ps;
307 	vaddr_t va;
308 	u_int s;
309 
310 	if (becc_pci_conf_setup(sc, tag, offset, &ps))
311 		return;
312 
313 	PCI_CONF_LOCK(s);
314 	BECC_CSR_WRITE(BECC_POCR, ps.ps_type);
315 
316 	va = sc->sc_pci_cfg_base + ps.ps_offset;
317 
318 	*(__volatile pcireg_t *)va = val;
319 
320 	becc_pci_conf_cleanup(sc);
321 
322 	PCI_CONF_UNLOCK(s);
323 }
324 
325 int
326 becc_pci_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
327 {
328 	int irq;
329 
330 	if (pa->pa_bus == 0) {
331 		switch (pa->pa_device) {
332 		case 1: irq = ICU_PCI_INTB; break; /* Ethernet #0 */
333 		case 2: irq = ICU_PCI_INTC; break; /* Ethernet #1 */
334 		case 3:				   /* Card slot */
335 			switch (pa->pa_intrpin) {
336 			case 1:		irq = ICU_PCI_INTA; break;
337 			case 2:		irq = ICU_PCI_INTB; break;
338 			case 3:		irq = ICU_PCI_INTC; break;
339 			case 4:		irq = ICU_PCI_INTD; break;
340 			default:
341 				printf("becc_pci_intr_map: bogus pin: %d\n",
342 				    pa->pa_intrpin);
343 				return (1);
344 			}
345 			break;
346 		default:
347 			break;
348 		}
349 	} else {
350 		switch (pa->pa_intrpin) {
351 		case 1:		irq = ICU_PCI_INTA; break;
352 		case 2:		irq = ICU_PCI_INTB; break;
353 		case 3:		irq = ICU_PCI_INTC; break;
354 		case 4:		irq = ICU_PCI_INTD; break;
355 		default:
356 			printf("becc_pci_intr_map: bogus pin: %d\n",
357 			    pa->pa_intrpin);
358 			return (1);
359 		}
360 	}
361 
362 	*ihp = irq;
363 	return (0);
364 }
365 
366 const char *
367 becc_pci_intr_string(void *v, pci_intr_handle_t ih)
368 {
369 
370 	return (becc_irqnames[ih]);
371 }
372 
373 const struct evcnt *
374 becc_pci_intr_evcnt(void *v, pci_intr_handle_t ih)
375 {
376 
377 	/* XXX For now. */
378 	return (NULL);
379 }
380 
381 void *
382 becc_pci_intr_establish(void *v, pci_intr_handle_t ih, int ipl,
383     int (*func)(void *), void *arg)
384 {
385 
386 	return (becc_intr_establish(ih, ipl, func, arg));
387 }
388 
389 void
390 becc_pci_intr_disestablish(void *v, void *cookie)
391 {
392 
393 	becc_intr_disestablish(cookie);
394 }
395