1 /* $NetBSD: i80312_pci.c,v 1.7.2.3 2004/09/21 13:13:42 skrll Exp $ */
4 * Copyright (c) 2001 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 i80312 Companion I/O chip.
42 #include <sys/cdefs.h>
43 __KERNEL_RCSID(0, "$NetBSD: i80312_pci.c,v 1.7.2.3 2004/09/21 13:13:42 skrll Exp $");
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/device.h>
48 #include <sys/extent.h>
49 #include <sys/malloc.h>
51 #include <uvm/uvm_extern.h>
53 #include <machine/bus.h>
55 #include <arm/xscale/i80312reg.h>
56 #include <arm/xscale/i80312var.h>
58 #include <dev/pci/ppbreg.h>
59 #include <dev/pci/pciconf.h>
64 void i80312_pci_attach_hook(struct device
*, struct device
*,
65 struct pcibus_attach_args
*);
66 int i80312_pci_bus_maxdevs(void *, int);
67 pcitag_t
i80312_pci_make_tag(void *, int, int, int);
68 void i80312_pci_decompose_tag(void *, pcitag_t
, int *, int *,
70 pcireg_t
i80312_pci_conf_read(void *, pcitag_t
, int);
71 void i80312_pci_conf_write(void *, pcitag_t
, int, pcireg_t
);
73 #define PCI_CONF_LOCK(s) (s) = disable_interrupts(I32_bit)
74 #define PCI_CONF_UNLOCK(s) restore_interrupts((s))
77 i80312_pci_init(pci_chipset_tag_t pc
, void *cookie
)
79 #if NPCI > 0 && defined(PCI_NETBSD_CONFIGURE)
80 struct i80312_softc
*sc
= cookie
;
81 struct extent
*ioext
, *memext
;
86 pc
->pc_conf_v
= cookie
;
87 pc
->pc_attach_hook
= i80312_pci_attach_hook
;
88 pc
->pc_bus_maxdevs
= i80312_pci_bus_maxdevs
;
89 pc
->pc_make_tag
= i80312_pci_make_tag
;
90 pc
->pc_decompose_tag
= i80312_pci_decompose_tag
;
91 pc
->pc_conf_read
= i80312_pci_conf_read
;
92 pc
->pc_conf_write
= i80312_pci_conf_write
;
94 #if NPCI > 0 && defined(PCI_NETBSD_CONFIGURE)
96 * Configure the PCI bus.
98 * XXX We need to revisit this. We only configure the Secondary
99 * bus (and its children). The bus configure code needs changes
100 * to support how the busses are arranged on this chip. We also
101 * need to only configure devices in the private device space on
105 binfo
= bus_space_read_4(sc
->sc_st
, sc
->sc_ppb_sh
, PPB_REG_BUSINFO
);
106 pbus
= PPB_BUSINFO_PRIMARY(binfo
);
107 sbus
= PPB_BUSINFO_SECONDARY(binfo
);
109 ioext
= extent_create("pciio", sc
->sc_sioout_base
,
110 sc
->sc_sioout_base
+ sc
->sc_sioout_size
- 1,
111 M_DEVBUF
, NULL
, 0, EX_NOWAIT
);
112 memext
= extent_create("pcimem", sc
->sc_smemout_base
,
113 sc
->sc_smemout_base
+ sc
->sc_smemout_size
- 1,
114 M_DEVBUF
, NULL
, 0, EX_NOWAIT
);
116 aprint_normal("%s: configuring Secondary PCI bus\n", sc
->sc_dev
.dv_xname
);
117 pci_configure_bus(pc
, ioext
, memext
, NULL
, sbus
, arm_dcache_align
);
119 extent_destroy(ioext
);
120 extent_destroy(memext
);
125 pci_conf_interrupt(pci_chipset_tag_t pc
, int a
, int b
, int c
, int d
, int *p
)
130 i80312_pci_attach_hook(struct device
*parent
, struct device
*self
,
131 struct pcibus_attach_args
*pba
)
138 i80312_pci_bus_maxdevs(void *v
, int busno
)
145 i80312_pci_make_tag(void *v
, int b
, int d
, int f
)
148 return ((b
<< 16) | (d
<< 11) | (f
<< 8));
152 i80312_pci_decompose_tag(void *v
, pcitag_t tag
, int *bp
, int *dp
, int *fp
)
156 *bp
= (tag
>> 16) & 0xff;
158 *dp
= (tag
>> 11) & 0x1f;
160 *fp
= (tag
>> 8) & 0x7;
163 struct pciconf_state
{
164 bus_addr_t ps_addr_reg
;
165 bus_addr_t ps_data_reg
;
166 bus_addr_t ps_csr_reg
;
167 uint32_t ps_addr_val
;
169 int ps_b
, ps_d
, ps_f
;
173 i80312_pci_conf_setup(struct i80312_softc
*sc
, pcitag_t tag
, int offset
,
174 struct pciconf_state
*ps
)
179 i80312_pci_decompose_tag(sc
, tag
, &ps
->ps_b
, &ps
->ps_d
, &ps
->ps_f
);
181 binfo
= bus_space_read_4(sc
->sc_st
, sc
->sc_ppb_sh
, PPB_REG_BUSINFO
);
182 pbus
= PPB_BUSINFO_PRIMARY(binfo
);
183 sbus
= PPB_BUSINFO_SECONDARY(binfo
);
186 * If the bus # is the Primary bus #, use the Primary
187 * Address/Data registers, otherwise use the Secondary
188 * Address/Data registers.
190 if (ps
->ps_b
== pbus
) {
191 ps
->ps_addr_reg
= I80312_ATU_POCCA
;
192 ps
->ps_data_reg
= I80312_ATU_POCCD
;
193 ps
->ps_csr_reg
= PCI_COMMAND_STATUS_REG
;
195 ps
->ps_addr_reg
= I80312_ATU_SOCCA
;
196 ps
->ps_data_reg
= I80312_ATU_SOCCD
;
197 ps
->ps_csr_reg
= I80312_ATU_SACS
;
201 * If the bus # is the Primary or Secondary bus #, then use
202 * Type 0 cycles, else use Type 1.
204 * XXX We should filter out all non-private devices here!
205 * XXX How does private space interact with PCI-PCI bridges?
207 if (ps
->ps_b
== pbus
|| ps
->ps_b
== sbus
) {
208 if (ps
->ps_d
> (31 - 11))
210 ps
->ps_addr_val
= (1U << (ps
->ps_d
+ 11)) | (ps
->ps_f
<< 8) |
213 /* The tag is already in the correct format. */
214 ps
->ps_addr_val
= tag
| offset
| 1;
221 i80312_pci_conf_read(void *v
, pcitag_t tag
, int offset
)
223 struct i80312_softc
*sc
= v
;
224 struct pciconf_state ps
;
229 if (i80312_pci_conf_setup(sc
, tag
, offset
, &ps
))
230 return ((pcireg_t
) -1);
234 bus_space_write_4(sc
->sc_st
, sc
->sc_atu_sh
, ps
.ps_addr_reg
,
237 va
= (vaddr_t
) bus_space_vaddr(sc
->sc_st
, sc
->sc_atu_sh
);
238 if (badaddr_read((void *) (va
+ ps
.ps_data_reg
), sizeof(rv
), &rv
)) {
240 * Clear the Master Abort by reading the PCI
243 (void) bus_space_read_4(sc
->sc_st
, sc
->sc_atu_sh
,
246 printf("conf_read: %d/%d/%d bad address\n",
247 ps
.ps_b
, ps
.ps_d
, ps
.ps_f
);
258 i80312_pci_conf_write(void *v
, pcitag_t tag
, int offset
, pcireg_t val
)
260 struct i80312_softc
*sc
= v
;
261 struct pciconf_state ps
;
264 if (i80312_pci_conf_setup(sc
, tag
, offset
, &ps
))
269 bus_space_write_4(sc
->sc_st
, sc
->sc_atu_sh
, ps
.ps_addr_reg
,
271 bus_space_write_4(sc
->sc_st
, sc
->sc_atu_sh
, ps
.ps_data_reg
, val
);