1 /* $NetBSD: universe_pci.c,v 1.10 2009/03/16 23:11:16 dsl Exp $ */
5 * Matthias Drochner. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * Common functions for PCI-VME-interfaces using the
31 * Newbridge/Tundra Universe II chip (CA91C142).
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: universe_pci.c,v 1.10 2009/03/16 23:11:16 dsl Exp $");
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/device.h>
41 #include <dev/pci/pcireg.h>
42 #include <dev/pci/pcivar.h>
43 /*#include <dev/pci/pcidevs.h>*/
47 #include <dev/vme/vmereg.h>
48 #include <dev/vme/vmevar.h>
50 #include <dev/ic/universereg.h>
51 #include <dev/pci/universe_pci_var.h>
53 int univ_pci_intr(void *);
55 #define read_csr_4(d, reg) \
56 bus_space_read_4(d->csrt, d->csrh, offsetof(struct universereg, reg))
57 #define write_csr_4(d, reg, val) \
58 bus_space_write_4(d->csrt, d->csrh, offsetof(struct universereg, reg), val)
60 #define _pso(i) offsetof(struct universereg, __CONCAT(pcislv, i))
61 static int pcislvoffsets
[8] = {
62 _pso(0), _pso(1), _pso(2), _pso(3),
63 _pso(4), _pso(5), _pso(6), _pso(7)
67 #define read_pcislv(d, idx, reg) \
68 bus_space_read_4(d->csrt, d->csrh, \
69 pcislvoffsets[idx] + offsetof(struct universe_pcislvimg, reg))
70 #define write_pcislv(d, idx, reg, val) \
71 bus_space_write_4(d->csrt, d->csrh, \
72 pcislvoffsets[idx] + offsetof(struct universe_pcislvimg, reg), val)
75 #define _vso(i) offsetof(struct universereg, __CONCAT(vmeslv, i))
76 static int vmeslvoffsets
[8] = {
77 _vso(0), _vso(1), _vso(2), _vso(3),
78 _vso(4), _vso(5), _vso(6), _vso(7)
82 #define read_vmeslv(d, idx, reg) \
83 bus_space_read_4(d->csrt, d->csrh, \
84 vmeslvoffsets[idx] + offsetof(struct universe_vmeslvimg, reg))
85 #define write_vmeslv(d, idx, reg, val) \
86 bus_space_write_4(d->csrt, d->csrh, \
87 vmeslvoffsets[idx] + offsetof(struct universe_vmeslvimg, reg), val)
90 univ_pci_attach(struct univ_pci_data
*d
, struct pci_attach_args
*pa
, const char *name
, void (*inthdl
)(void *, int, int), void *intcookie
)
92 pci_chipset_tag_t pc
= pa
->pa_pc
;
94 const char *intrstr
= NULL
;
99 strncpy(d
->devname
, name
, sizeof(d
->devname
));
100 d
->devname
[sizeof(d
->devname
) - 1] = '\0';
102 if (pci_mapreg_map(pa
, 0x10,
103 PCI_MAPREG_TYPE_MEM
| PCI_MAPREG_MEM_TYPE_32BIT
,
104 0, &d
->csrt
, &d
->csrh
, NULL
, NULL
) &&
105 pci_mapreg_map(pa
, 0x14,
106 PCI_MAPREG_TYPE_MEM
| PCI_MAPREG_MEM_TYPE_32BIT
,
107 0, &d
->csrt
, &d
->csrh
, NULL
, NULL
) &&
108 pci_mapreg_map(pa
, 0x10,
110 0, &d
->csrt
, &d
->csrh
, NULL
, NULL
) &&
111 pci_mapreg_map(pa
, 0x14,
113 0, &d
->csrt
, &d
->csrh
, NULL
, NULL
))
116 /* name sure the chip is in a sane state */
117 write_csr_4(d
, lint_en
, 0); /* mask all PCI interrupts */
118 write_csr_4(d
, vint_en
, 0); /* mask all VME interrupts */
119 write_csr_4(d
, dgcs
, 0x40000000); /* stop DMA activity */
120 for (i
= 0; i
< 8; i
++) {
121 univ_pci_unmapvme(d
, i
);
122 univ_pci_unmappci(d
, i
);
124 write_csr_4(d
, slsi
, 0); /* disable "special PCI slave image" */
127 pci_conf_write(pc
, pa
->pa_tag
, PCI_COMMAND_STATUS_REG
,
128 pci_conf_read(pc
, pa
->pa_tag
, PCI_COMMAND_STATUS_REG
) |
129 PCI_COMMAND_MASTER_ENABLE
);
131 reg
= read_csr_4(d
, misc_ctl
);
132 aprint_normal("%s: ", name
);
133 if (reg
& 0x00020000) /* SYSCON */
134 aprint_normal("VME bus controller, ");
135 reg
= read_csr_4(d
, mast_ctl
);
136 aprint_normal("requesting at VME bus level %d\n", (reg
>> 22) & 3);
138 /* Map and establish the PCI interrupt. */
139 if (pci_intr_map(pa
, &ih
)) {
140 aprint_error("%s: couldn't map interrupt\n", name
);
143 intrstr
= pci_intr_string(pc
, ih
);
145 * Use a low interrupt level (the lowest?).
146 * We will raise before calling a subdevice's handler.
148 d
->ih
= pci_intr_establish(pc
, ih
, IPL_BIO
, univ_pci_intr
, d
);
150 aprint_error("%s: couldn't establish interrupt", name
);
152 aprint_error(" at %s", intrstr
);
156 aprint_normal("%s: interrupting at %s\n", name
, intrstr
);
158 /* handle all VME interrupts (XXX should be configurable) */
159 d
->vmeinthandler
= inthdl
;
160 d
->vmeintcookie
= intcookie
;
161 write_csr_4(d
, lint_stat
, 0x00ff37ff); /* ack all pending IRQs */
162 write_csr_4(d
, lint_en
, 0x000000fe); /* enable VME IRQ 1..7 */
168 univ_pci_mapvme(struct univ_pci_data
*d
, int wnd
, vme_addr_t vmebase
, u_int32_t len
, vme_am_t am
, vme_datasize_t datawidth
, u_int32_t pcibase
)
170 u_int32_t ctl
= 0x80000000;
172 switch (am
& VME_AM_ADRSIZEMASK
) {
184 if (am
& VME_AM_SUPER
)
186 if ((am
& VME_AM_MODEMASK
) == VME_AM_PRG
)
188 if (datawidth
& VME_D32
)
190 else if (datawidth
& VME_D16
)
192 else if (!(datawidth
& VME_D8
))
196 printf("%s: wnd %d, map VME %x-%x to %x, ctl=%x\n",
197 d
->devname
, wnd
, vmebase
, vmebase
+ len
, pcibase
, ctl
);
200 write_pcislv(d
, wnd
, lsi_bs
, pcibase
);
201 write_pcislv(d
, wnd
, lsi_bd
, pcibase
+ len
);
202 write_pcislv(d
, wnd
, lsi_to
, vmebase
- pcibase
);
203 write_pcislv(d
, wnd
, lsi_ctl
, ctl
);
208 univ_pci_unmapvme(struct univ_pci_data
*d
, int wnd
)
211 printf("%s: unmap VME wnd %d\n", d
->devname
, wnd
);
213 write_pcislv(d
, wnd
, lsi_ctl
, 0);
218 univ_pci_mappci(struct univ_pci_data
*d
, int wnd
, u_int32_t pcibase
, u_int32_t len
, vme_addr_t vmebase
, vme_am_t am
)
220 u_int32_t ctl
= 0x80000000;
222 switch (am
& VME_AM_ADRSIZEMASK
) {
234 if (am
& VME_AM_SUPER
)
237 ctl
|= 0x00300000; /* both */
238 if ((am
& VME_AM_MODEMASK
) == VME_AM_PRG
)
241 ctl
|= 0x00c00000; /* both */
244 printf("%s: wnd %d, map PCI %x-%x to %x, ctl=%x\n",
245 d
->devname
, wnd
, pcibase
, pcibase
+ len
, vmebase
, ctl
);
248 write_vmeslv(d
, wnd
, vsi_bs
, vmebase
);
249 write_vmeslv(d
, wnd
, vsi_bd
, vmebase
+ len
);
250 write_vmeslv(d
, wnd
, vsi_to
, pcibase
- vmebase
);
251 write_vmeslv(d
, wnd
, vsi_ctl
, ctl
);
256 univ_pci_unmappci(struct univ_pci_data
*d
, int wnd
)
259 printf("%s: unmap PCI wnd %d\n", d
->devname
, wnd
);
261 write_vmeslv(d
, wnd
, vsi_ctl
, 0);
265 univ_pci_vmebuserr(struct univ_pci_data
*d
, int clear
)
269 pcicsr
= read_csr_4(d
, pci_csr
);
270 if ((pcicsr
& 0xf8000000) && clear
)
271 write_csr_4(d
, pci_csr
, pcicsr
| 0xf8000000);
272 return (pcicsr
& 0x08000000); /* target abort */
276 univ_pci_intr(void *v
)
278 struct univ_pci_data
*d
= v
;
282 intcsr
= read_csr_4(d
, lint_stat
) & 0xffffff;
287 write_csr_4(d
, lint_stat
, intcsr
);
289 printf("%s: intr, lint_stat=%x\n", d
->devname
, intcsr
);
291 if (intcsr
& 0x000000fe) { /* VME interrupt */
292 for (i
= 7; i
>= 1; i
--) {
293 if (!(intcsr
& (1 << i
)))
295 vec
= read_csr_4(d
, v_statid
[i
- 1]);
297 printf("%s: err irq %d\n", d
->devname
, i
);
300 if (d
->vmeinthandler
)
301 (*d
->vmeinthandler
)(d
->vmeintcookie
, i
, vec
);