1 /* $NetBSD: vrpciu.c,v 1.13.2.5 2004/12/18 09:31:03 skrll Exp $ */
4 * Copyright (c) 2001 Enami Tsugutomo.
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 REGENTS 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 REGENTS 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
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: vrpciu.c,v 1.13.2.5 2004/12/18 09:31:03 skrll Exp $");
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/device.h>
36 #include <machine/bus.h>
37 #include <machine/bus_space_hpcmips.h>
38 #include <machine/bus_dma_hpcmips.h>
39 #include <machine/config_hook.h>
40 #include <machine/platid.h>
41 #include <machine/platid_mask.h>
43 #include <dev/pci/pcivar.h>
44 #include <dev/pci/pcidevs.h>
45 #include <dev/pci/pciidereg.h>
47 #include <hpcmips/vr/icureg.h>
48 #include <hpcmips/vr/vripif.h>
49 #include <hpcmips/vr/vrpciureg.h>
54 #define DPRINTF(args) printf args
62 vrip_chipset_tag_t sc_vc
;
63 bus_space_tag_t sc_iot
;
64 bus_space_handle_t sc_ioh
;
67 struct vrc4173bcu_softc
*sc_bcu
; /* vrc4173bcu */
69 struct hpcmips_pci_chipset sc_pc
;
72 static void vrpciu_write(struct vrpciu_softc
*, int, u_int32_t
);
74 vrpciu_read(struct vrpciu_softc
*, int);
76 static void vrpciu_write_2(struct vrpciu_softc
*, int, u_int16_t
)
77 __attribute__((unused
));
79 vrpciu_read_2(struct vrpciu_softc
*, int);
81 static int vrpciu_match(struct device
*, struct cfdata
*, void *);
82 static void vrpciu_attach(struct device
*, struct device
*, void *);
83 static int vrpciu_intr(void *);
84 static void vrpciu_attach_hook(struct device
*, struct device
*,
85 struct pcibus_attach_args
*);
86 static int vrpciu_bus_maxdevs(pci_chipset_tag_t
, int);
87 static int vrpciu_bus_devorder(pci_chipset_tag_t
, int, char *);
88 static pcitag_t
vrpciu_make_tag(pci_chipset_tag_t
, int, int, int);
89 static void vrpciu_decompose_tag(pci_chipset_tag_t
, pcitag_t
, int *, int *,
91 static pcireg_t
vrpciu_conf_read(pci_chipset_tag_t
, pcitag_t
, int);
92 static void vrpciu_conf_write(pci_chipset_tag_t
, pcitag_t
, int, pcireg_t
);
93 static int vrpciu_intr_map(struct pci_attach_args
*, pci_intr_handle_t
*);
94 static const char *vrpciu_intr_string(pci_chipset_tag_t
, pci_intr_handle_t
);
95 static const struct evcnt
*vrpciu_intr_evcnt(pci_chipset_tag_t
,
97 static void *vrpciu_intr_establish(pci_chipset_tag_t
, pci_intr_handle_t
,
98 int, int (*)(void *), void *);
99 static void vrpciu_intr_disestablish(pci_chipset_tag_t
, void *);
101 CFATTACH_DECL(vrpciu
, sizeof(struct vrpciu_softc
),
102 vrpciu_match
, vrpciu_attach
, NULL
, NULL
);
105 vrpciu_write(struct vrpciu_softc
*sc
, int offset
, u_int32_t val
)
108 bus_space_write_4(sc
->sc_iot
, sc
->sc_ioh
, offset
, val
);
112 vrpciu_read(struct vrpciu_softc
*sc
, int offset
)
115 return (bus_space_read_4(sc
->sc_iot
, sc
->sc_ioh
, offset
));
120 vrpciu_write_2(struct vrpciu_softc
*sc
, int offset
, u_int16_t val
)
123 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, offset
, val
);
127 vrpciu_read_2(struct vrpciu_softc
*sc
, int offset
)
130 return (bus_space_read_2(sc
->sc_iot
, sc
->sc_ioh
, offset
));
135 vrpciu_match(struct device
*parent
, struct cfdata
*match
, void *aux
)
142 vrpciu_attach(struct device
*parent
, struct device
*self
, void *aux
)
144 struct vrpciu_softc
*sc
= (struct vrpciu_softc
*)self
;
145 pci_chipset_tag_t pc
= &sc
->sc_pc
;
146 struct vrip_attach_args
*va
= aux
;
147 #if defined(DEBUG) || NPCI > 0
151 struct bus_space_tag_hpcmips
*iot
;
153 struct pcibus_attach_args pba
;
156 sc
->sc_vc
= va
->va_vc
;
157 sc
->sc_iot
= va
->va_iot
;
158 if (bus_space_map(sc
->sc_iot
, va
->va_addr
, va
->va_size
, 0,
160 printf(": couldn't map io space\n");
164 sc
->sc_ih
= vrip_intr_establish(va
->va_vc
, va
->va_unit
, 0, IPL_TTY
,
166 if (sc
->sc_ih
== NULL
) {
167 printf(": couldn't establish interrupt\n");
171 /* Enable level 2 interrupt */
172 vrip_intr_setmask2(va
->va_vc
, sc
->sc_ih
, PCIINT_INT0
, 1);
177 #define DUMP_MAW(sc, name, reg) do { \
178 printf("%s: %s =\t0x%08x\n", (sc)->sc_dev.dv_xname, \
180 printf("%s:\tIBA/MASK =\t0x%08x/0x%08x (0x%08x - 0x%08x)\n", \
181 (sc)->sc_dev.dv_xname, \
182 reg & VRPCIU_MAW_IBAMASK, VRPCIU_MAW_ADDRMASK(reg), \
183 VRPCIU_MAW_ADDR(reg), \
184 VRPCIU_MAW_ADDR(reg) + VRPCIU_MAW_SIZE(reg)); \
185 printf("%s:\tWINEN =\t0x%08x\n", (sc)->sc_dev.dv_xname, \
186 reg & VRPCIU_MAW_WINEN); \
187 printf("%s:\tPCIADR =\t0x%08x\n", (sc)->sc_dev.dv_xname, \
188 VRPCIU_MAW_PCIADDR(reg)); \
190 #define DUMP_TAW(sc, name, reg) do { \
191 printf("%s: %s =\t\t0x%08x\n", (sc)->sc_dev.dv_xname, \
193 printf("%s:\tMASK =\t0x%08x\n", (sc)->sc_dev.dv_xname, \
194 VRPCIU_TAW_ADDRMASK(reg)); \
195 printf("%s:\tWINEN =\t0x%08x\n", (sc)->sc_dev.dv_xname, \
196 reg & VRPCIU_TAW_WINEN); \
197 printf("%s:\tIBA =\t0x%08x\n", (sc)->sc_dev.dv_xname, \
198 VRPCIU_TAW_IBA(reg)); \
200 reg
= vrpciu_read(sc
, VRPCIU_MMAW1REG
);
201 DUMP_MAW(sc
, "MMAW1", reg
);
202 reg
= vrpciu_read(sc
, VRPCIU_MMAW2REG
);
203 DUMP_MAW(sc
, "MMAW2", reg
);
204 reg
= vrpciu_read(sc
, VRPCIU_TAW1REG
);
205 DUMP_TAW(sc
, "TAW1", reg
);
206 reg
= vrpciu_read(sc
, VRPCIU_TAW2REG
);
207 DUMP_TAW(sc
, "TAW2", reg
);
208 reg
= vrpciu_read(sc
, VRPCIU_MIOAWREG
);
209 DUMP_MAW(sc
, "MIOAW", reg
);
210 printf("%s: BUSERRAD =\t0x%08x\n", sc
->sc_dev
.dv_xname
,
211 vrpciu_read(sc
, VRPCIU_BUSERRADREG
));
212 printf("%s: INTCNTSTA =\t0x%08x\n", sc
->sc_dev
.dv_xname
,
213 vrpciu_read(sc
, VRPCIU_INTCNTSTAREG
));
214 printf("%s: EXACC =\t0x%08x\n", sc
->sc_dev
.dv_xname
,
215 vrpciu_read(sc
, VRPCIU_EXACCREG
));
216 printf("%s: RECONT =\t0x%08x\n", sc
->sc_dev
.dv_xname
,
217 vrpciu_read(sc
, VRPCIU_RECONTREG
));
218 printf("%s: PCIEN =\t0x%08x\n", sc
->sc_dev
.dv_xname
,
219 vrpciu_read(sc
, VRPCIU_ENREG
));
220 printf("%s: CLOCKSEL =\t0x%08x\n", sc
->sc_dev
.dv_xname
,
221 vrpciu_read(sc
, VRPCIU_CLKSELREG
));
222 printf("%s: TRDYV =\t0x%08x\n", sc
->sc_dev
.dv_xname
,
223 vrpciu_read(sc
, VRPCIU_TRDYVREG
));
224 printf("%s: CLKRUN =\t0x%08x\n", sc
->sc_dev
.dv_xname
,
225 vrpciu_read_2(sc
, VRPCIU_CLKRUNREG
));
226 printf("%s: IDREG =\t0x%08x\n", sc
->sc_dev
.dv_xname
,
227 vrpciu_read(sc
, VRPCIU_CONF_BASE
+ PCI_ID_REG
));
228 reg
= vrpciu_read(sc
, VRPCIU_CONF_BASE
+ PCI_COMMAND_STATUS_REG
);
229 printf("%s: CSR =\t\t0x%08x\n", sc
->sc_dev
.dv_xname
, reg
);
230 vrpciu_write(sc
, VRPCIU_CONF_BASE
+ PCI_COMMAND_STATUS_REG
, reg
);
231 printf("%s: CSR =\t\t0x%08x\n", sc
->sc_dev
.dv_xname
,
232 vrpciu_read(sc
, VRPCIU_CONF_BASE
+ PCI_COMMAND_STATUS_REG
));
233 printf("%s: CLASS =\t0x%08x\n", sc
->sc_dev
.dv_xname
,
234 vrpciu_read(sc
, VRPCIU_CONF_BASE
+ PCI_CLASS_REG
));
235 printf("%s: BHLC =\t\t0x%08x\n", sc
->sc_dev
.dv_xname
,
236 vrpciu_read(sc
, VRPCIU_CONF_BASE
+ PCI_BHLC_REG
));
237 printf("%s: MAIL =\t\t0x%08x\n", sc
->sc_dev
.dv_xname
,
238 vrpciu_read(sc
, VRPCIU_CONF_BASE
+ VRPCIU_CONF_MAILREG
));
239 printf("%s: MBA1 =\t\t0x%08x\n", sc
->sc_dev
.dv_xname
,
240 vrpciu_read(sc
, VRPCIU_CONF_BASE
+ VRPCIU_CONF_MBA1REG
));
241 printf("%s: MBA2 =\t\t0x%08x\n", sc
->sc_dev
.dv_xname
,
242 vrpciu_read(sc
, VRPCIU_CONF_BASE
+ VRPCIU_CONF_MBA2REG
));
243 printf("%s: INTR =\t\t0x%08x\n", sc
->sc_dev
.dv_xname
,
244 vrpciu_read(sc
, VRPCIU_CONF_BASE
+ PCI_INTERRUPT_REG
));
246 vrpciu_write(sc
, VRPCIU_CONF_BASE
+ PCI_INTERRUPT_REG
,
247 vrpciu_read(sc
, VRPCIU_CONF_BASE
+ PCI_INTERRUPT_REG
) | 0x01);
248 printf("%s: INTR =\t\t0x%08x\n", sc
->sc_dev
.dv_xname
,
249 vrpciu_read(sc
, VRPCIU_CONF_BASE
+ PCI_INTERRUPT_REG
));
253 pc
->pc_dev
= &sc
->sc_dev
;
254 pc
->pc_attach_hook
= vrpciu_attach_hook
;
255 pc
->pc_bus_maxdevs
= vrpciu_bus_maxdevs
;
256 pc
->pc_bus_devorder
= vrpciu_bus_devorder
;
257 pc
->pc_make_tag
= vrpciu_make_tag
;
258 pc
->pc_decompose_tag
= vrpciu_decompose_tag
;
259 pc
->pc_conf_read
= vrpciu_conf_read
;
260 pc
->pc_conf_write
= vrpciu_conf_write
;
261 pc
->pc_intr_map
= vrpciu_intr_map
;
262 pc
->pc_intr_string
= vrpciu_intr_string
;
263 pc
->pc_intr_evcnt
= vrpciu_intr_evcnt
;
264 pc
->pc_intr_establish
= vrpciu_intr_establish
;
265 pc
->pc_intr_disestablish
= vrpciu_intr_disestablish
;
271 for (i
= 0; i
< 8; i
++)
272 printf("%s: ID_REG(0, 0, %d) = 0x%08x\n",
273 sc
->sc_dev
.dv_xname
, i
,
274 pci_conf_read(pc
, pci_make_tag(pc
, 0, 0, i
),
280 memset(&pba
, 0, sizeof(pba
));
282 /* For now, just inherit window mappings set by WinCE. XXX. */
284 iot
= hpcmips_alloc_bus_space_tag();
285 reg
= vrpciu_read(sc
, VRPCIU_MIOAWREG
);
286 snprintf(tmpbuf
, sizeof(tmpbuf
), "%s/iot",
287 sc
->sc_dev
.dv_xname
);
288 hpcmips_init_bus_space(iot
, (struct bus_space_tag_hpcmips
*)sc
->sc_iot
,
289 tmpbuf
, VRPCIU_MAW_ADDR(reg
), VRPCIU_MAW_SIZE(reg
));
290 pba
.pba_iot
= &iot
->bst
;
293 * Just use system bus space tag. It works since WinCE maps
294 * PCI bus space at same offset. But this isn't right thing
297 pba
.pba_memt
= sc
->sc_iot
;
298 pba
.pba_dmat
= &hpcmips_default_bus_dma_tag
.bdt
;
299 pba
.pba_dmat64
= NULL
;
301 pba
.pba_bridgetag
= NULL
;
303 if (platid_match(&platid
, &platid_mask_MACH_LASER5_L_BOARD
)) {
305 * fix PCI device configuration for L-Router.
307 /* change IDE controller to native mode */
308 reg
= pci_conf_read(pc
, pci_make_tag(pc
, 0, 16, 0),
310 reg
|= PCIIDE_INTERFACE_PCI(0) << PCI_INTERFACE_SHIFT
;
311 reg
|= PCIIDE_INTERFACE_PCI(1) << PCI_INTERFACE_SHIFT
;
312 pci_conf_write(pc
, pci_make_tag(pc
, 0, 16, 0), PCI_CLASS_REG
,
314 /* fix broken BAR setting of fxp0, fxp1 */
315 pci_conf_write(pc
, pci_make_tag(pc
, 0, 0, 0), PCI_MAPREG_START
,
317 pci_conf_write(pc
, pci_make_tag(pc
, 0, 1, 0), PCI_MAPREG_START
,
321 pba
.pba_flags
= PCI_FLAGS_IO_ENABLED
| PCI_FLAGS_MEM_ENABLED
|
325 config_found_ia(self
, "pcibus", &pba
, pcibusprint
);
330 * Handle PCI error interrupts.
333 vrpciu_intr(void *arg
)
335 struct vrpciu_softc
*sc
= (struct vrpciu_softc
*)arg
;
336 u_int32_t isr
, baddr
;
338 isr
= vrpciu_read(sc
, VRPCIU_INTCNTSTAREG
);
339 baddr
= vrpciu_read(sc
, VRPCIU_BUSERRADREG
);
340 printf("%s: status=0x%08x bad addr=0x%08x\n",
341 sc
->sc_dev
.dv_xname
, isr
, baddr
);
342 return ((isr
& 0x0f) ? 1 : 0);
346 vrpciu_attach_hook(struct device
*parent
, struct device
*self
,
347 struct pcibus_attach_args
*pba
)
354 vrpciu_bus_maxdevs(pci_chipset_tag_t pc
, int busno
)
361 vrpciu_bus_devorder(pci_chipset_tag_t pc
, int busno
, char *devs
)
365 static pcireg_t ids
[] = {
366 /* these devices should be attached first */
367 PCI_ID_CODE(PCI_VENDOR_NEC
, PCI_PRODUCT_NEC_VRC4173_BCU
),
370 /* scan PCI devices and check the id table */
371 memset(priorities
, 0, sizeof(priorities
));
372 for (dev
= 0; dev
< 32; dev
++) {
374 id
= pci_conf_read(pc
, pci_make_tag(pc
, 0, dev
, 0),PCI_ID_REG
);
375 for (i
= 0; i
< sizeof(ids
)/sizeof(*ids
); i
++)
380 /* fill order array */
381 for (i
= 1; 0 <= i
; i
--)
382 for (dev
= 0; dev
< 32; dev
++)
383 if (priorities
[dev
] == i
)
390 vrpciu_make_tag(pci_chipset_tag_t pc
, int bus
, int device
, int function
)
393 return ((bus
<< 16) | (device
<< 11) | (function
<< 8));
397 vrpciu_decompose_tag(pci_chipset_tag_t pc
, pcitag_t tag
, int *bp
, int *dp
,
402 *bp
= (tag
>> 16) & 0xff;
404 *dp
= (tag
>> 11) & 0x1f;
406 *fp
= (tag
>> 8) & 0x07;
410 vrpciu_conf_read(pci_chipset_tag_t pc
, pcitag_t tag
, int reg
)
412 struct vrpciu_softc
*sc
= (struct vrpciu_softc
*)pc
->pc_dev
;
414 int bus
, device
, function
;
416 pci_decompose_tag(pc
, tag
, &bus
, &device
, &function
);
419 return ((pcitag_t
)-1);
420 tag
= (1 << (device
+ 11)) | (function
<< 8); /* Type 0 */
422 tag
|= VRPCIU_CONF_TYPE1
;
424 vrpciu_write(sc
, VRPCIU_CONFAREG
, tag
| reg
);
425 val
= vrpciu_read(sc
, VRPCIU_CONFDREG
);
427 printf("%s: conf_read: tag = 0x%08x, reg = 0x%x, val = 0x%08x\n",
428 sc
->sc_dev
.dv_xname
, (u_int32_t
)tag
, reg
, val
);
434 vrpciu_conf_write(pci_chipset_tag_t pc
, pcitag_t tag
, int reg
,
437 struct vrpciu_softc
*sc
= (struct vrpciu_softc
*)pc
->pc_dev
;
438 int bus
, device
, function
;
441 printf("%s: conf_write: tag = 0x%08x, reg = 0x%x, val = 0x%08x\n",
442 sc
->sc_dev
.dv_xname
, (u_int32_t
)tag
, reg
, (u_int32_t
)data
);
444 vrpciu_decompose_tag(pc
, tag
, &bus
, &device
, &function
);
448 tag
= (1 << (device
+ 11)) | (function
<< 8); /* Type 0 */
450 tag
|= VRPCIU_CONF_TYPE1
;
452 vrpciu_write(sc
, VRPCIU_CONFAREG
, tag
| reg
);
453 vrpciu_write(sc
, VRPCIU_CONFDREG
, data
);
457 vrpciu_intr_map(struct pci_attach_args
*pa
, pci_intr_handle_t
*ihp
)
459 pci_chipset_tag_t pc
= pa
->pa_pc
;
460 pcitag_t intrtag
= pa
->pa_intrtag
;
463 int line
= pa
->pa_intrline
;
464 int pin
= pa
->pa_intrpin
;
467 pci_decompose_tag(pc
, intrtag
, &bus
, &dev
, &func
);
468 DPRINTF(("%s(%d, %d, %d): line = %d, pin = %d\n", pc
->pc_dev
->dv_xname
,
469 bus
, dev
, func
, line
, pin
));
471 *ihp
= CONFIG_HOOK_PCIINTR_ID(bus
, dev
, func
);
477 vrpciu_intr_string(pci_chipset_tag_t pc
, pci_intr_handle_t ih
)
479 static char irqstr
[sizeof("pciintr") + 16];
481 snprintf(irqstr
, sizeof(irqstr
), "pciintr %d:%d:%d",
482 CONFIG_HOOK_PCIINTR_BUS((int)ih
),
483 CONFIG_HOOK_PCIINTR_DEVICE((int)ih
),
484 CONFIG_HOOK_PCIINTR_FUNCTION((int)ih
));
490 vrpciu_intr_evcnt(pci_chipset_tag_t pc
, pci_intr_handle_t ih
)
493 /* XXX for now, no evcnt parent reported */
499 vrpciu_intr_establish(pci_chipset_tag_t pc
, pci_intr_handle_t ih
, int level
,
500 int (*func
)(void *), void *arg
)
505 DPRINTF(("vrpciu_intr_establish: %lx\n", ih
));
507 return (config_hook(CONFIG_HOOK_PCIINTR
, ih
, CONFIG_HOOK_EXCLUSIVE
,
508 (int (*)(void *, int, long, void *))func
, arg
));
512 vrpciu_intr_disestablish(pci_chipset_tag_t pc
, void *cookie
)
515 DPRINTF(("vrpciu_intr_disestablish: %p\n", cookie
));
516 config_unhook(cookie
);