1 /* $NetBSD: gemini_pci.c,v 1.7 2008/12/04 00:36:33 cliff Exp $ */
4 * NetBSD: i80312_pci.c,v 1.9 2005/12/11 12:16:51 christos Exp
8 * Copyright (c) 2001 Wasabi Systems, Inc.
11 * Written by Jason R. Thorpe for Wasabi Systems, Inc.
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. All advertising materials mentioning features or use of this software
22 * must display the following acknowledgement:
23 * This product includes software developed for the NetBSD Project by
24 * Wasabi Systems, Inc.
25 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
26 * or promote products derived from this software without specific prior
29 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
31 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
32 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
33 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
34 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
35 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
36 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
37 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
39 * POSSIBILITY OF SUCH DAMAGE.
43 * PCI configuration support for i80312 Companion I/O chip.
46 #include <sys/cdefs.h>
47 __KERNEL_RCSID(0, "$NetBSD: gemini_pci.c,v 1.7 2008/12/04 00:36:33 cliff Exp $");
49 #include <sys/cdefs.h>
51 #include <sys/param.h>
52 #include <sys/systm.h>
53 #include <sys/device.h>
54 #include <sys/extent.h>
55 #include <sys/malloc.h>
57 #include <uvm/uvm_extern.h>
59 #include <machine/bus.h>
60 #include <machine/intr.h>
62 #include <arm/pic/picvar.h>
64 #include <arm/gemini/gemini_reg.h>
65 #include <arm/gemini/gemini_pcivar.h>
66 #include <arm/gemini/gemini_obiovar.h>
68 #include <dev/pci/pcivar.h>
69 #include <dev/pci/pcidevs.h>
70 #include <dev/pci/pciconf.h>
72 #include <machine/pci_machdep.h>
74 #include "opt_gemini.h"
78 void gemini_pci_attach_hook(struct device
*, struct device
*,
79 struct pcibus_attach_args
*);
80 int gemini_pci_bus_maxdevs(void *, int);
81 pcitag_t
gemini_pci_make_tag(void *, int, int, int);
82 void gemini_pci_decompose_tag(void *, pcitag_t
, int *, int *,
84 pcireg_t
gemini_pci_conf_read(void *, pcitag_t
, int);
85 void gemini_pci_conf_write(void *, pcitag_t
, int, pcireg_t
);
86 int gemini_pci_conf_hook(pci_chipset_tag_t
, int, int, int,
89 int gemini_pci_intr_map(struct pci_attach_args
*,
91 const char *gemini_pci_intr_string(void *, pci_intr_handle_t
);
92 const struct evcnt
*gemini_pci_intr_evcnt(void *, pci_intr_handle_t
);
93 void *gemini_pci_intr_establish(void *, pci_intr_handle_t
,
94 int, int (*)(void *), void *);
95 void gemini_pci_intr_disestablish(void *, void *);
96 int gemini_pci_intr_handler(void *v
);
98 #define PCI_CONF_LOCK(s) (s) = disable_interrupts(I32_bit)
99 #define PCI_CONF_UNLOCK(s) restore_interrupts((s))
101 struct gemini_pci_intrq
{
102 SIMPLEQ_ENTRY(gemini_pci_intrq
) iq_q
;
103 int (*iq_func
)(void *);
108 static SIMPLEQ_HEAD(, gemini_pci_intrq
) gemini_pci_intrq
=
109 SIMPLEQ_HEAD_INITIALIZER(gemini_pci_intrq
);
112 gemini_pci_intrq_empty(void)
114 return SIMPLEQ_EMPTY(&gemini_pci_intrq
);
118 gemini_pci_intrq_insert(void *ih
, int (*func
)(void *), void *arg
)
120 struct gemini_pci_intrq
*iqp
;
122 iqp
= malloc(sizeof(*iqp
), M_DEVBUF
, M_NOWAIT
|M_ZERO
);
124 printf("gemini_pci_intrq_insert: malloc failed\n");
131 SIMPLEQ_INSERT_TAIL(&gemini_pci_intrq
, iqp
, iq_q
);
137 gemini_pci_intrq_remove(void *cookie
)
139 struct gemini_pci_intrq
*iqp
;
141 SIMPLEQ_FOREACH(iqp
, &gemini_pci_intrq
, iq_q
) {
142 if ((void *)iqp
== cookie
) {
143 SIMPLEQ_REMOVE(&gemini_pci_intrq
,
144 iqp
, gemini_pci_intrq
, iq_q
);
152 gemini_pci_intrq_dispatch(void)
154 struct gemini_pci_intrq
*iqp
;
156 SIMPLEQ_FOREACH(iqp
, &gemini_pci_intrq
, iq_q
) {
157 (*iqp
->iq_func
)(iqp
->iq_arg
);
164 gemini_pci_init(pci_chipset_tag_t pc
, void *cookie
)
166 #if NPCI > 0 && defined(PCI_NETBSD_CONFIGURE)
167 struct obio_softc
*sc
= cookie
;
168 struct extent
*ioext
, *memext
;
171 pc
->pc_conf_v
= cookie
;
172 pc
->pc_attach_hook
= gemini_pci_attach_hook
;
173 pc
->pc_bus_maxdevs
= gemini_pci_bus_maxdevs
;
174 pc
->pc_make_tag
= gemini_pci_make_tag
;
175 pc
->pc_decompose_tag
= gemini_pci_decompose_tag
;
176 pc
->pc_conf_read
= gemini_pci_conf_read
;
177 pc
->pc_conf_write
= gemini_pci_conf_write
;
179 pc
->pc_intr_v
= cookie
;
180 pc
->pc_intr_map
= gemini_pci_intr_map
;
181 pc
->pc_intr_string
= gemini_pci_intr_string
;
182 pc
->pc_intr_evcnt
= gemini_pci_intr_evcnt
;
183 pc
->pc_intr_establish
= gemini_pci_intr_establish
;
184 pc
->pc_intr_disestablish
= gemini_pci_intr_disestablish
;
186 pc
->pc_conf_hook
= gemini_pci_conf_hook
;
189 * initialize copy of CFG_CMD
191 sc
->sc_pci_chipset
.pc_cfg_cmd
=
192 gemini_pci_conf_read(sc
, 0, GEMINI_PCI_CFG_CMD
);
194 #if NPCI > 0 && defined(PCI_NETBSD_CONFIGURE)
196 * Configure the PCI bus.
198 * XXX We need to revisit this. We only configure the Secondary
199 * bus (and its children). The bus configure code needs changes
200 * to support how the busses are arranged on this chip. We also
201 * need to only configure devices in the private device space on
205 aprint_normal("%s: configuring Secondary PCI bus\n",
206 device_xname(sc
->sc_dev
));
209 * XXX PCI IO addr should be inherited ?
211 ioext
= extent_create("pciio",
213 GEMINI_PCIIO_BASE
+ GEMINI_PCIIO_SIZE
- 1,
214 M_DEVBUF
, NULL
, 0, EX_NOWAIT
);
217 * XXX PCI mem addr should be inherited ?
219 memext
= extent_create("pcimem",
221 GEMINI_PCIMEM_BASE
+ GEMINI_PCIMEM_SIZE
- 1,
222 M_DEVBUF
, NULL
, 0, EX_NOWAIT
);
224 pci_configure_bus(pc
, ioext
, memext
, NULL
, 0, arm_dcache_align
);
226 gemini_pci_conf_write(sc
, 0, GEMINI_PCI_CFG_REG_MEM1
,
227 PCI_CFG_REG_MEM_BASE((GEMINI_DRAM_BASE
+ (GEMINI_BUSBASE
* 1024 * 1024)))
228 | gemini_pci_cfg_reg_mem_size(MEMSIZE
* 1024 * 1024));
230 extent_destroy(ioext
);
231 extent_destroy(memext
);
236 pci_conf_interrupt(pci_chipset_tag_t pc
, int a
, int b
, int c
, int d
, int *p
)
241 gemini_pci_conf_hook(pci_chipset_tag_t pc
, int bus
, int device
, int function
, pcireg_t id
)
251 gemini_pci_attach_hook(struct device
*parent
, struct device
*self
,
252 struct pcibus_attach_args
*pba
)
258 gemini_pci_bus_maxdevs(void *v
, int busno
)
264 gemini_pci_make_tag(void *v
, int b
, int d
, int f
)
266 return ((b
<< 16) | (d
<< 11) | (f
<< 8));
270 gemini_pci_decompose_tag(void *v
, pcitag_t tag
, int *bp
, int *dp
, int *fp
)
273 *bp
= (tag
>> 16) & 0xff;
275 *dp
= (tag
>> 11) & 0x1f;
277 *fp
= (tag
>> 8) & 0x7;
280 struct pciconf_state
{
281 uint32_t ps_addr_val
;
282 int ps_b
, ps_d
, ps_f
;
286 gemini_pci_conf_setup(struct obio_softc
*sc
, pcitag_t tag
, int offset
,
287 struct pciconf_state
*ps
)
289 gemini_pci_decompose_tag(sc
, tag
, &ps
->ps_b
, &ps
->ps_d
, &ps
->ps_f
);
293 | PCI_CFG_CMD_BUSn(ps
->ps_b
)
294 | PCI_CFG_CMD_DEVn(ps
->ps_d
)
295 | PCI_CFG_CMD_FUNCn(ps
->ps_f
)
296 | PCI_CFG_CMD_REGn(offset
);
302 gemini_pci_conf_read(void *v
, pcitag_t tag
, int offset
)
304 struct obio_softc
*sc
= v
;
305 struct pciconf_state ps
;
310 if (gemini_pci_conf_setup(sc
, tag
, offset
, &ps
))
311 return ((pcireg_t
) -1);
315 if (sc
->sc_pci_chipset
.pc_cfg_cmd
!= ps
.ps_addr_val
) {
316 sc
->sc_pci_chipset
.pc_cfg_cmd
= ps
.ps_addr_val
;
317 bus_space_write_4(sc
->sc_iot
, sc
->sc_pcicfg_ioh
,
318 GEMINI_PCI_CFG_CMD
, ps
.ps_addr_val
);
321 va
= (vaddr_t
) bus_space_vaddr(sc
->sc_iot
, sc
->sc_pcicfg_ioh
);
322 if (badaddr_read((void *) (va
+ GEMINI_PCI_CFG_DATA
), sizeof(rv
), &rv
)) {
324 * XXX Clear the Master Abort
327 printf("conf_read: %d/%d/%d bad address\n",
328 ps
.ps_b
, ps
.ps_d
, ps
.ps_f
);
339 gemini_pci_conf_write(void *v
, pcitag_t tag
, int offset
, pcireg_t val
)
341 struct obio_softc
*sc
= v
;
342 struct pciconf_state ps
;
345 if (gemini_pci_conf_setup(sc
, tag
, offset
, &ps
))
350 if (sc
->sc_pci_chipset
.pc_cfg_cmd
!= ps
.ps_addr_val
) {
351 sc
->sc_pci_chipset
.pc_cfg_cmd
= ps
.ps_addr_val
;
352 bus_space_write_4(sc
->sc_iot
, sc
->sc_pcicfg_ioh
,
353 GEMINI_PCI_CFG_CMD
, ps
.ps_addr_val
);
356 bus_space_write_4(sc
->sc_iot
, sc
->sc_pcicfg_ioh
,
357 GEMINI_PCI_CFG_DATA
, val
);
363 gemini_pci_intr_map(struct pci_attach_args
*pa
, pci_intr_handle_t
*ihp
)
374 gemini_pci_intr_string(void *v
, pci_intr_handle_t ih
)
376 const char *name
= "pci";
382 gemini_pci_intr_evcnt(void *v
, pci_intr_handle_t ih
)
388 gemini_pci_intr_establish(void *v
, pci_intr_handle_t pci_ih
, int ipl
,
389 int (*func
)(void *), void *arg
)
398 r
= gemini_pci_conf_read(v
, 0, GEMINI_PCI_CFG_REG_CTL2
);
399 r
|= CFG_REG_CTL2_INTMASK_INT_ABCD
;
400 gemini_pci_conf_write(v
, 0, GEMINI_PCI_CFG_REG_CTL2
, r
);
402 if (gemini_pci_intrq_empty())
403 ih
= intr_establish(irq
, ipl
, IST_LEVEL_HIGH
,
404 gemini_pci_intr_handler
, v
);
406 cookie
= gemini_pci_intrq_insert(ih
, func
, arg
);
407 if (cookie
== NULL
) {
408 if (gemini_pci_intrq_empty())
409 intr_disestablish(ih
);
416 gemini_pci_intr_disestablish(void *v
, void *cookie
)
419 struct gemini_pci_intrq
*iqp
= (struct gemini_pci_intrq
*)cookie
;
420 void *ih
= iqp
->iq_ih
;
422 gemini_pci_intrq_remove(cookie
);
423 if (gemini_pci_intrq_empty()) {
424 r
= gemini_pci_conf_read(v
, 0, GEMINI_PCI_CFG_REG_CTL2
);
425 r
&= ~CFG_REG_CTL2_INTMASK_INT_ABCD
;
426 gemini_pci_conf_write(v
, 0, GEMINI_PCI_CFG_REG_CTL2
, r
);
427 intr_disestablish(ih
);
432 gemini_pci_intr_handler(void *v
)
438 * dispatch PCI device interrupt handlers
440 rv
= gemini_pci_intrq_dispatch();
443 * ack Gemini PCI interrupts
445 r
= gemini_pci_conf_read(v
, 0, GEMINI_PCI_CFG_REG_CTL2
);
446 gemini_pci_conf_write(v
, 0, GEMINI_PCI_CFG_REG_CTL2
, r
);