1 /* $NetBSD: becc_pci.c,v 1.7 2005/12/11 12:16:51 christos Exp $ */
4 * Copyright (c) 2001, 2002 Wasabi Systems, Inc.
7 * Written by Jason R. Thorpe for Wasabi Systems, Inc.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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
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.
39 * PCI configuration support for the ADI Engineering Big Endian Companion
43 #include <sys/cdefs.h>
44 __KERNEL_RCSID(0, "$NetBSD: becc_pci.c,v 1.7 2005/12/11 12:16:51 christos Exp $");
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/device.h>
49 #include <sys/extent.h>
50 #include <sys/malloc.h>
52 #include <uvm/uvm_extern.h>
54 #include <machine/bus.h>
56 #include <arm/xscale/beccreg.h>
57 #include <arm/xscale/beccvar.h>
59 #include <dev/pci/ppbreg.h>
60 #include <dev/pci/pciconf.h>
65 void becc_pci_attach_hook(struct device
*, struct device
*,
66 struct pcibus_attach_args
*);
67 int becc_pci_bus_maxdevs(void *, int);
68 pcitag_t
becc_pci_make_tag(void *, int, int, int);
69 void becc_pci_decompose_tag(void *, pcitag_t
, int *, int *,
71 pcireg_t
becc_pci_conf_read(void *, pcitag_t
, int);
72 void becc_pci_conf_write(void *, pcitag_t
, int, pcireg_t
);
74 int becc_pci_intr_map(struct pci_attach_args
*,
76 const char *becc_pci_intr_string(void *, pci_intr_handle_t
);
77 const struct evcnt
*becc_pci_intr_evcnt(void *, pci_intr_handle_t
);
78 void *becc_pci_intr_establish(void *, pci_intr_handle_t
,
79 int, int (*)(void *), void *);
80 void becc_pci_intr_disestablish(void *, void *);
82 #define PCI_CONF_LOCK(s) (s) = disable_interrupts(I32_bit)
83 #define PCI_CONF_UNLOCK(s) restore_interrupts((s))
86 #define DPRINTF(x) printf(x)
92 becc_pci_init(pci_chipset_tag_t pc
, void *cookie
)
94 #if NPCI > 0 && defined(PCI_NETBSD_CONFIGURE)
95 struct becc_softc
*sc
= cookie
;
96 struct extent
*ioext
, *memext
;
99 pc
->pc_conf_v
= cookie
;
100 pc
->pc_attach_hook
= becc_pci_attach_hook
;
101 pc
->pc_bus_maxdevs
= becc_pci_bus_maxdevs
;
102 pc
->pc_make_tag
= becc_pci_make_tag
;
103 pc
->pc_decompose_tag
= becc_pci_decompose_tag
;
104 pc
->pc_conf_read
= becc_pci_conf_read
;
105 pc
->pc_conf_write
= becc_pci_conf_write
;
107 pc
->pc_intr_v
= cookie
;
108 pc
->pc_intr_map
= becc_pci_intr_map
;
109 pc
->pc_intr_string
= becc_pci_intr_string
;
110 pc
->pc_intr_evcnt
= becc_pci_intr_evcnt
;
111 pc
->pc_intr_establish
= becc_pci_intr_establish
;
112 pc
->pc_intr_disestablish
= becc_pci_intr_disestablish
;
114 #if NPCI > 0 && defined(PCI_NETBSD_CONFIGURE)
116 * Configure the PCI bus.
118 * XXX We need to revisit this. We only configure the Secondary
119 * bus (and its children). The bus configure code needs changes
120 * to support how the busses are arranged on this chip. We also
121 * need to only configure devices in the private device space on
125 /* Reserve the bottom 32K of the PCI address space. */
126 ioext
= extent_create("pciio", sc
->sc_ioout_xlate
+ (32 * 1024),
127 sc
->sc_ioout_xlate
+ (64 * 1024) - 1,
128 M_DEVBUF
, NULL
, 0, EX_NOWAIT
);
129 memext
= extent_create("pcimem", sc
->sc_owin_xlate
[0],
130 sc
->sc_owin_xlate
[0] + BECC_PCI_MEM1_SIZE
- 1,
131 M_DEVBUF
, NULL
, 0, EX_NOWAIT
);
133 aprint_normal("%s: configuring PCI bus\n", sc
->sc_dev
.dv_xname
);
134 pci_configure_bus(pc
, ioext
, memext
, NULL
, 0, arm_dcache_align
);
136 extent_destroy(ioext
);
137 extent_destroy(memext
);
142 pci_conf_interrupt(pci_chipset_tag_t pc
, int a
, int b
, int c
, int d
, int *p
)
147 becc_pci_attach_hook(struct device
*parent
, struct device
*self
,
148 struct pcibus_attach_args
*pba
)
155 becc_pci_bus_maxdevs(void *v
, int busno
)
162 becc_pci_make_tag(void *v
, int b
, int d
, int f
)
165 return ((b
<< 16) | (d
<< 11) | (f
<< 8));
169 becc_pci_decompose_tag(void *v
, pcitag_t tag
, int *bp
, int *dp
, int *fp
)
173 *bp
= (tag
>> 16) & 0xff;
175 *dp
= (tag
>> 11) & 0x1f;
177 *fp
= (tag
>> 8) & 0x7;
180 struct pciconf_state
{
183 int ps_b
, ps_d
, ps_f
;
188 becc_pci_conf_setup(struct becc_softc
*sc
, pcitag_t tag
, int offset
,
189 struct pciconf_state
*ps
)
192 becc_pci_decompose_tag(sc
, tag
, &ps
->ps_b
, &ps
->ps_d
, &ps
->ps_f
);
195 * If the bus # is the same as our own, then use Type 0 cycles,
199 /* XXX This is a platform-specific parameter. */
200 if (ps
->ps_d
> (14 - BECC_IDSEL_BIT
))
202 ps
->ps_offset
= (1U << (ps
->ps_d
+ BECC_IDSEL_BIT
)) |
203 (ps
->ps_f
<< 8) | offset
;
206 /* The tag is already in the correct format. */
207 ps
->ps_offset
= tag
| offset
| 1;
214 static int becc_pci_conf_cleanup(struct becc_softc
*sc
);
216 becc_pci_conf_cleanup(struct becc_softc
*sc
)
221 BECC_CSR_WRITE(BECC_POCR
, 0);
223 reg
= becc_pcicore_read(sc
, PCI_COMMAND_STATUS_REG
);
224 if (reg
& 0xf9000000) {
225 DPRINTF((" ** pci status error: %08x (%08x) **\n",
226 reg
, reg
& 0xf9000000));
229 becc_pcicore_write(sc
, PCI_COMMAND_STATUS_REG
,
231 reg
= becc_pcicore_read(sc
, PCI_COMMAND_STATUS_REG
);
233 DPRINTF((" ** pci status after clearing: %08x (%08x) **\n",
234 reg
, reg
& 0xf9000000));
236 reg
= BECC_CSR_READ(BECC_PMISR
);
237 if (reg
& 0x000f000d) {
238 DPRINTF((" ** pci master isr: %08x (%08x) **\n",
239 reg
, reg
& 0x000f000d));
242 BECC_CSR_WRITE(BECC_PMISR
, reg
& 0x000f000d);
243 reg
= BECC_CSR_READ(BECC_PMISR
);
245 DPRINTF((" ** pci master isr after clearing: %08x (%08x) **\n",
246 reg
, reg
& 0x000f000d));
248 reg
= BECC_CSR_READ(BECC_PSISR
);
249 if (reg
& 0x000f0210) {
250 DPRINTF((" ** pci slave isr: %08x (%08x) **\n",
251 reg
, reg
& 0x000f0210));
254 BECC_CSR_WRITE(BECC_PSISR
, reg
& 0x000f0210);
255 reg
= BECC_CSR_READ(BECC_PSISR
);
257 DPRINTF((" ** pci slave isr after clearing: %08x (%08x) **\n",
258 reg
, reg
& 0x000f0210));
265 becc_pci_conf_read(void *v
, pcitag_t tag
, int offset
)
267 struct becc_softc
*sc
= v
;
268 struct pciconf_state ps
;
273 if (becc_pci_conf_setup(sc
, tag
, offset
, &ps
))
274 return ((pcireg_t
) -1);
277 * Skip device 0 (the BECC itself). We don't want it
278 * to appear as part of the PCI device space.
280 if (ps
.ps_b
== 0 && ps
.ps_d
== 0)
281 return ((pcireg_t
) -1);
285 va
= sc
->sc_pci_cfg_base
+ ps
.ps_offset
;
286 BECC_CSR_WRITE(BECC_POCR
, ps
.ps_type
);
288 if (badaddr_read((void *) va
, sizeof(rv
), &rv
)) {
289 /* XXX Check master/target abort? */
291 printf("conf_read: %d/%d/%d bad address\n",
292 ps
.ps_b
, ps
.ps_d
, ps
.ps_f
);
297 if (becc_pci_conf_cleanup(sc
))
306 becc_pci_conf_write(void *v
, pcitag_t tag
, int offset
, pcireg_t val
)
308 struct becc_softc
*sc
= v
;
309 struct pciconf_state ps
;
313 if (becc_pci_conf_setup(sc
, tag
, offset
, &ps
))
317 BECC_CSR_WRITE(BECC_POCR
, ps
.ps_type
);
319 va
= sc
->sc_pci_cfg_base
+ ps
.ps_offset
;
321 *(volatile pcireg_t
*)va
= val
;
323 becc_pci_conf_cleanup(sc
);
329 becc_pci_intr_map(struct pci_attach_args
*pa
, pci_intr_handle_t
*ihp
)
333 if (pa
->pa_bus
== 0) {
334 switch (pa
->pa_device
) {
335 case 1: irq
= ICU_PCI_INTB
; break; /* Ethernet #0 */
336 case 2: irq
= ICU_PCI_INTC
; break; /* Ethernet #1 */
337 case 3: /* Card slot */
338 switch (pa
->pa_intrpin
) {
339 case 1: irq
= ICU_PCI_INTA
; break;
340 case 2: irq
= ICU_PCI_INTB
; break;
341 case 3: irq
= ICU_PCI_INTC
; break;
342 case 4: irq
= ICU_PCI_INTD
; break;
344 printf("becc_pci_intr_map: bogus pin: %d\n",
350 printf("becc_pci_intr_map: bogus device: %d\n",
355 switch (pa
->pa_intrpin
) {
356 case 1: irq
= ICU_PCI_INTA
; break;
357 case 2: irq
= ICU_PCI_INTB
; break;
358 case 3: irq
= ICU_PCI_INTC
; break;
359 case 4: irq
= ICU_PCI_INTD
; break;
361 printf("becc_pci_intr_map: bogus pin: %d\n",
372 becc_pci_intr_string(void *v
, pci_intr_handle_t ih
)
375 return (becc_irqnames
[ih
]);
379 becc_pci_intr_evcnt(void *v
, pci_intr_handle_t ih
)
387 becc_pci_intr_establish(void *v
, pci_intr_handle_t ih
, int ipl
,
388 int (*func
)(void *), void *arg
)
391 return (becc_intr_establish(ih
, ipl
, func
, arg
));
395 becc_pci_intr_disestablish(void *v
, void *cookie
)
398 becc_intr_disestablish(cookie
);