Support for the SH5 on-chip PCI bridge, and support for its deployment

in the Cayman board.
This commit is contained in:
scw 2002-09-28 11:16:36 +00:00
parent 171b08b4b9
commit 251ba05b3f
15 changed files with 1956 additions and 32 deletions

View File

@ -1,4 +1,4 @@
# $NetBSD: CAYMAN,v 1.5 2002/08/30 11:25:09 scw Exp $
# $NetBSD: CAYMAN,v 1.6 2002/09/28 11:16:37 scw Exp $
#
# Config file for SuperH "CAYMAN" SH-5 Evaluation board
@ -10,21 +10,28 @@ maxusers 2
options INCLUDE_CONFIG_FILE
#ident "CAYMAN-$Revision: 1.5 $"
#ident "CAYMAN-$Revision: 1.6 $"
# Uncomment this to build a 64-bit kernel
#makeoptions SH5_ABI=64
makeoptions DEFCOPTS="-g"
makeoptions DEBUG="-g"
#makeoptions DEFCOPTS="-g"
#makeoptions DEBUG="-g"
options SYMTAB_SPACE=0x40000
options DIAGNOSTIC
options DEBUG
options DDB
#options UVMHIST
#options UVMHIST_PRINT
options KTRACE # system call tracing via ktrace(1)
options SYSTRACE # system call vetting via systrace(1)
options SYSVMSG
options SYSVSEM
options SYSVSHM
file-system FFS
file-system NFS
file-system KERNFS
@ -61,7 +68,7 @@ cpu0 at superhyway0 pport 0x0d # A single CPU
pbridge0 at superhyway0 pport 0x09 # Peripheral Bridge
#dmac0 at superhyway0 pport 0x0e # DMA controller
femi0 at superhyway0 pport 0x08 # Flash/External memory
#pchb0 at superhyway0 pport 0x60 # PCI bus
pcibus0 at superhyway0 pport 0x40 # PCI bus
#
# The Peripheral Bridge and all its sub-devices are actually on the same
@ -91,6 +98,20 @@ clock0 at cprc0 # Primary clock generator
#
sysfpga0 at femi0 offset 0x4000000 # The main System FPGA chip
#
# PCIbus devices
#
options PCI_NETBSD_CONFIGURE
pci* at pcibus? bus ? # pci at PCIbus bridges
pci* at ppb? bus ? # pci at PCI-PCI bridges
ppb* at pci? dev ? function ? # PCI-PCI Bridges
# Ensoniq card on the Cayman
eap* at pci? dev ? function ? # Ensoniq AudioPCI
# Audio support
audio* at audiobus?
#
# The Super I/O chip is straight out of the x86 PeeCee world in that
# it implements a bunch if "standard" PeeCee type devices (although

View File

@ -1,4 +1,4 @@
# $NetBSD: files.evbsh5,v 1.3 2002/09/06 13:18:43 gehenna Exp $
# $NetBSD: files.evbsh5,v 1.4 2002/09/28 11:16:38 scw Exp $
# Config file for SuperH CAYMAN SH5 Evaluation Board
@ -11,6 +11,7 @@ include "dev/isa/files.isa"
file arch/evbsh5/evbsh5/machdep.c
file arch/evbsh5/evbsh5/cons_machdep.c
file arch/evbsh5/evbsh5/mainbus.c mainbus
file arch/evbsh5/pci/pci_intr_machdep.c sh5pci
device sysfpga { }
attach sysfpga at femi
@ -18,7 +19,7 @@ file arch/evbsh5/dev/sysfpga.c sysfpga
device superio {[offset=-1], [irq=-1]}: isabus
attach superio at sysfpga
file arch/evbsh5/dev/superio.c superio
file arch/evbsh5/dev/superio.c superio needs-flag
attach sm at superio with sm_superio
file arch/evbsh5/dev/if_sm_superio.c sm_superio needs-flag

View File

@ -1,4 +1,4 @@
/* $NetBSD: sysfpga.c,v 1.6 2002/09/27 20:31:38 thorpej Exp $ */
/* $NetBSD: sysfpga.c,v 1.7 2002/09/28 11:16:38 scw Exp $ */
/*
* Copyright 2002 Wasabi Systems, Inc.
@ -37,6 +37,9 @@
/* Cayman's System FPGA Chip */
#include "sh5pci.h"
#include "superio.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
@ -62,9 +65,15 @@ struct sysfpga_softc {
struct device sc_dev;
bus_space_tag_t sc_bust;
bus_space_handle_t sc_bush;
void *sc_ih[SYSFPGA_NGROUPS];
struct sysfpga_ihandler sc_ih_superio[SYSFPGA_SUPERIO_NINTR];
u_int8_t sc_intmr[SYSFPGA_NGROUPS];
void *sc_ih[SYSFPGA_NGROUPS];
#if NSUPERIO > 0
struct sysfpga_ihandler sc_ih_superio[SYSFPGA_SUPERIO_NINTR];
#endif
#if NSH5PCI > 0
struct sysfpga_ihandler sc_ih_pci1[SYSFPGA_PCI1_NINTR];
struct sysfpga_ihandler sc_ih_pci2[SYSFPGA_PCI1_NINTR];
#endif
};
static int sysfpgamatch(struct device *, struct cfdata *, void *);
@ -95,8 +104,14 @@ static struct sysfpga_device sysfpga_devices[] = {
#define sysfpga_reg_write(s,r,v) \
bus_space_write_4((s)->sc_bust, (s)->sc_bush, (r), (v))
#if NSUPERIO > 0
static int sysfpga_intr_handler_irl1(void *);
#endif
#if NSH5PCI > 0
static int sysfpga_intr_handler_irl2(void *);
static int sysfpga_intr_handler_irl3(void *);
#endif
static int sysfpga_intr_dispatch(struct sysfpga_softc *,
struct sysfpga_ihandler *, int);
@ -147,12 +162,20 @@ sysfpgaattach(struct device *parent, struct device *self, void *args)
sysfpga_cpuclksel[SYSFPGA_BDMR_CPUCLKSEL(reg)],
SYSFPGA_CPUMR_CLKMODE(sysfpga_reg_read(sc, SYSFPGA_REG_CPUMR)));
#if NSUPERIO > 0
memset(sc->sc_ih_superio, 0, sizeof(sc->sc_ih_superio));
#endif
#if NSH5PCI > 0
memset(sc->sc_ih_superio, 0, sizeof(sc->sc_ih_pci1));
memset(sc->sc_ih_superio, 0, sizeof(sc->sc_ih_pci2));
#endif
for (i = 0; i < SYSFPGA_NGROUPS; i++) {
sysfpga_reg_write(sc, SYSFPGA_REG_INTMR(i), 0);
sc->sc_intmr[i] = 0;
}
#if NSUPERIO > 0
/*
* Hook interrupts from the Super IO device
*/
@ -162,6 +185,23 @@ sysfpgaattach(struct device *parent, struct device *self, void *args)
if (sc->sc_ih[SYSFPGA_IGROUP_SUPERIO] == NULL)
panic("sysfpga: failed to register superio isr");
#endif
#if NSH5PCI > 0
/*
* Hook interrupts from the PCI1 and PCI2 pins
*/
sc->sc_ih[SYSFPGA_IGROUP_PCI1] =
sh5_intr_establish(INTC_INTEVT_IRL2, IST_LEVEL, IPL_SH5PCI,
sysfpga_intr_handler_irl2, sc);
sc->sc_ih[SYSFPGA_IGROUP_PCI2] =
sh5_intr_establish(INTC_INTEVT_IRL3, IST_LEVEL, IPL_SH5PCI,
sysfpga_intr_handler_irl3, sc);
if (sc->sc_ih[SYSFPGA_IGROUP_PCI1] == NULL ||
sc->sc_ih[SYSFPGA_IGROUP_PCI2] == NULL)
panic("sysfpga: failed to register pci isr");
#endif
#ifdef DEBUG
sysfpga_reg_write(sc, SYSFPGA_REG_NMIMR, 1);
@ -194,56 +234,145 @@ sysfpgaprint(void *arg, const char *cp)
return (UNCONF);
}
#if NSUPERIO > 0
static int
sysfpga_intr_handler_irl1(void *arg)
{
struct sysfpga_softc *sc = arg;
struct sysfpga_ihandler *ih;
u_int8_t intsr0;
int h = 0;
u_int8_t intsr, intmr;
int sr_reg, h = 0;
ih = sc->sc_ih_superio;
sr_reg = SYSFPGA_REG_INTSR(SYSFPGA_IGROUP_SUPERIO);
intmr = sc->sc_intmr[SYSFPGA_IGROUP_SUPERIO];
for (intsr0 = sysfpga_reg_read(sc, SYSFPGA_REG_INTSR(0));
(intsr0 & sc->sc_intmr[0]) != 0;
intsr0 = sysfpga_reg_read(sc, SYSFPGA_REG_INTSR(0))) {
intsr0 &= sc->sc_intmr[0];
for (intsr = sysfpga_reg_read(sc, sr_reg);
(intsr &= intmr) != 0;
intsr = sysfpga_reg_read(sc, sr_reg)) {
if (intsr0 & (1 << SYSFPGA_SUPERIO_INUM_UART1))
if (intsr & (1 << SYSFPGA_SUPERIO_INUM_UART1))
h |= sysfpga_intr_dispatch(sc, ih,
SYSFPGA_SUPERIO_INUM_UART1);
if (intsr0 & (1 << SYSFPGA_SUPERIO_INUM_UART2))
if (intsr & (1 << SYSFPGA_SUPERIO_INUM_UART2))
h |= sysfpga_intr_dispatch(sc, ih,
SYSFPGA_SUPERIO_INUM_UART2);
if (intsr0 & (1 << SYSFPGA_SUPERIO_INUM_MOUSE))
if (intsr & (1 << SYSFPGA_SUPERIO_INUM_MOUSE))
h |= sysfpga_intr_dispatch(sc, ih,
SYSFPGA_SUPERIO_INUM_MOUSE);
if (intsr0 & (1 << SYSFPGA_SUPERIO_INUM_KBD))
if (intsr & (1 << SYSFPGA_SUPERIO_INUM_KBD))
h |= sysfpga_intr_dispatch(sc, ih,
SYSFPGA_SUPERIO_INUM_KBD);
if (intsr0 & (1 << SYSFPGA_SUPERIO_INUM_LAN))
if (intsr & (1 << SYSFPGA_SUPERIO_INUM_LAN))
h |= sysfpga_intr_dispatch(sc, ih,
SYSFPGA_SUPERIO_INUM_LAN);
if (intsr0 & (1 << SYSFPGA_SUPERIO_INUM_IDE))
if (intsr & (1 << SYSFPGA_SUPERIO_INUM_IDE))
h |= sysfpga_intr_dispatch(sc, ih,
SYSFPGA_SUPERIO_INUM_IDE);
if (intsr0 & (1 << SYSFPGA_SUPERIO_INUM_LPT))
if (intsr & (1 << SYSFPGA_SUPERIO_INUM_LPT))
h |= sysfpga_intr_dispatch(sc, ih,
SYSFPGA_SUPERIO_INUM_LPT);
if (h == 0)
panic("sysfpga: unclaimed IRL1 interrupt: 0x%02x",
intsr0);
intsr);
}
return (h);
}
#endif
#if NSH5PCI > 0
static int
sysfpga_intr_handler_irl2(void *arg)
{
struct sysfpga_softc *sc = arg;
struct sysfpga_ihandler *ih;
u_int8_t intsr, intmr;
int sr_reg, h = 0;
ih = sc->sc_ih_pci1;
sr_reg = SYSFPGA_REG_INTSR(SYSFPGA_IGROUP_PCI1);
intmr = sc->sc_intmr[SYSFPGA_IGROUP_PCI1];
for (intsr = sysfpga_reg_read(sc, sr_reg);
(intsr &= intmr) != 0;
intsr = sysfpga_reg_read(sc, sr_reg)) {
if (intsr & (1 << SYSFPGA_PCI1_INTA))
h |= sysfpga_intr_dispatch(sc, ih, SYSFPGA_PCI1_INTA);
if (intsr & (1 << SYSFPGA_PCI1_INTB))
h |= sysfpga_intr_dispatch(sc, ih, SYSFPGA_PCI1_INTB);
if (intsr & (1 << SYSFPGA_PCI1_INTC))
h |= sysfpga_intr_dispatch(sc, ih, SYSFPGA_PCI1_INTC);
if (intsr & (1 << SYSFPGA_PCI1_INTD))
h |= sysfpga_intr_dispatch(sc, ih, SYSFPGA_PCI1_INTD);
if (h == 0)
panic("sysfpga: unclaimed IRL2 interrupt: 0x%02x",
intsr);
}
return (h);
}
static int
sysfpga_intr_handler_irl3(void *arg)
{
struct sysfpga_softc *sc = arg;
struct sysfpga_ihandler *ih;
u_int8_t intsr, intmr;
int sr_reg, h = 0;
ih = sc->sc_ih_pci2;
sr_reg = SYSFPGA_REG_INTSR(SYSFPGA_IGROUP_PCI2);
intmr = sc->sc_intmr[SYSFPGA_IGROUP_PCI2];
for (intsr = sysfpga_reg_read(sc, sr_reg);
(intsr &= intmr) != 0;
intsr = sysfpga_reg_read(sc, sr_reg)) {
if (intsr & (1 << SYSFPGA_PCI2_INTA))
h |= sysfpga_intr_dispatch(sc, ih, SYSFPGA_PCI2_INTA);
if (intsr & (1 << SYSFPGA_PCI2_INTB))
h |= sysfpga_intr_dispatch(sc, ih, SYSFPGA_PCI2_INTB);
if (intsr & (1 << SYSFPGA_PCI2_INTC))
h |= sysfpga_intr_dispatch(sc, ih, SYSFPGA_PCI2_INTC);
if (intsr & (1 << SYSFPGA_PCI2_INTD))
h |= sysfpga_intr_dispatch(sc, ih, SYSFPGA_PCI2_INTD);
if (intsr & (1 << SYSFPGA_PCI2_FAL))
h |= sysfpga_intr_dispatch(sc, ih, SYSFPGA_PCI2_FAL);
if (intsr & (1 << SYSFPGA_PCI2_DEG))
h |= sysfpga_intr_dispatch(sc, ih, SYSFPGA_PCI2_DEG);
if (intsr & (1 << SYSFPGA_PCI2_INTP))
h |= sysfpga_intr_dispatch(sc, ih, SYSFPGA_PCI2_INTP);
if (intsr & (1 << SYSFPGA_PCI2_INTS))
h |= sysfpga_intr_dispatch(sc, ih, SYSFPGA_PCI2_INTS);
if (h == 0)
panic("sysfpga: unclaimed IRL3 interrupt: 0x%02x",
intsr);
}
return (h);
}
#endif
static int
sysfpga_intr_dispatch(struct sysfpga_softc *sc, struct sysfpga_ihandler *ih,
@ -289,12 +418,26 @@ sysfpga_intr_establish(int group, int level, int inum,
int s;
switch (group) {
#if NSUPERIO > 0
case SYSFPGA_IGROUP_SUPERIO:
KDASSERT(inum < SYSFPGA_SUPERIO_NINTR);
KDASSERT(level >= IPL_SUPERIO);
ih = sc->sc_ih_superio;
break;
#endif
#if NSH5PCI > 0
case SYSFPGA_IGROUP_PCI1:
KDASSERT(inum < SYSFPGA_PCI1_NINTR);
KDASSERT(level >= IPL_SH5PCI);
ih = sc->sc_ih_pci1;
break;
case SYSFPGA_IGROUP_PCI2:
KDASSERT(inum < SYSFPGA_PCI2_NINTR);
KDASSERT(level >= IPL_SH5PCI);
ih = sc->sc_ih_pci2;
break;
#endif
default:
return (NULL);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: sysfpgavar.h,v 1.3 2002/09/22 20:51:09 scw Exp $ */
/* $NetBSD: sysfpgavar.h,v 1.4 2002/09/28 11:16:38 scw Exp $ */
/*
* Copyright 2002 Wasabi Systems, Inc.
@ -69,6 +69,28 @@ struct sysfpga_attach_args {
#define SYSFPGA_SUPERIO_INUM_IDE 7
#define SYSFPGA_SUPERIO_NINTR 8
/*
* PCI1 generates the following interrupts
*/
#define SYSFPGA_PCI1_INTA 0
#define SYSFPGA_PCI1_INTB 1
#define SYSFPGA_PCI1_INTC 2
#define SYSFPGA_PCI1_INTD 3
#define SYSFPGA_PCI1_NINTR 4
/*
* PCI2 generates the following interrupts
*/
#define SYSFPGA_PCI2_INTA 0
#define SYSFPGA_PCI2_INTB 1
#define SYSFPGA_PCI2_INTC 2
#define SYSFPGA_PCI2_INTD 3
#define SYSFPGA_PCI2_FAL 4 /* XXX: cPCI form-factor only */
#define SYSFPGA_PCI2_DEG 5 /* XXX: cPCI form-factor only */
#define SYSFPGA_PCI2_INTP 6 /* XXX: cPCI form-factor only */
#define SYSFPGA_PCI2_INTS 7 /* XXX: cPCI form-factor only */
#define SYSFPGA_PCI2_NINTR 8
struct evcnt;
extern struct evcnt *sysfpga_intr_evcnt(int);
extern void *sysfpga_intr_establish(int, int, int, int (*)(void *), void *);

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile,v 1.5 2002/08/26 10:58:38 scw Exp $
# $NetBSD: Makefile,v 1.6 2002/09/28 11:16:38 scw Exp $
KDIR= /sys/arch/evbsh5/include
INCSDIR= /usr/include/evbsh5
@ -13,7 +13,7 @@ INCS= ansi.h aout_machdep.h asm.h \
int_const.h int_fmtio.h int_limits.h int_mwgwtypes.h int_types.h \
limits.h lock.h \
math.h \
param.h pcb.h pmap.h pmc.h proc.h profile.h ptrace.h \
param.h pcb.h pci_machdep.h pmap.h pmc.h proc.h profile.h ptrace.h \
reg.h \
setjmp.h signal.h stdarg.h \
types.h \

View File

@ -1,4 +1,4 @@
/* $NetBSD: intr.h,v 1.1 2002/07/05 13:31:46 scw Exp $ */
/* $NetBSD: intr.h,v 1.2 2002/09/28 11:16:38 scw Exp $ */
/*
* Copyright 2002 Wasabi Systems, Inc.
@ -41,6 +41,7 @@
#include <sh5/intr.h>
#define IPL_SUPERIO 5 /* SuperIO interrupts at this level */
#define IPL_SH5PCI 6 /* PCI1 & PCI2 interrupt at this level */
#define splsuperio() splraise(IPL_SUPERIO)
#define spllpt() splsuperio()

View File

@ -0,0 +1,3 @@
/* $NetBSD: pci_machdep.h,v 1.1 2002/09/28 11:16:38 scw Exp $ */
#include <sh5/pci_machdep.h>

View File

@ -0,0 +1,305 @@
/* $NetBSD: pci_intr_machdep.c,v 1.1 2002/09/28 11:16:39 scw Exp $ */
/*
* Copyright 2002 Wasabi Systems, Inc.
* All rights reserved.
*
* Written by Steve C. Woodford for Wasabi Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the NetBSD Project by
* Wasabi Systems, Inc.
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
* or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Cayman's PCIbus has a somewhat "odd" interrupt routing.
*
* INT[A-D] on the primary PCIbus are routed to the Host-PCI bridge
* as you would expect.
*
* INT[A-D] from devices on the secondary bus, behind the PCI-PCI bridge
* at bus0, dev3 are routed to the P1 interrupt pins on the System FPGA.
*
* INT[A-D] from devices on the third bus, behind the 2nd PCI-PCI bridge
* at busN (where N is usually 1), dev0 are routed to the P2 interrupt
* pins on the System FPGA.
*
* XXX: Right now, assume no other PCI-PCI bridges are present on the
* primary and secondary buses (they would mess up the bus numbers, and
* confuse the code). The solution to this will be to scan the bus
* heirarchy to check subordinate bus numbers...
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/queue.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <machine/cpu.h>
#include <machine/bus.h>
#include <machine/intr.h>
#include <sh5/dev/intcreg.h>
#include <sh5/pci/sh5_pcivar.h>
#include <evbsh5/dev/sysfpgavar.h>
static void * cayman_intr_init(struct sh5_pci_chipset_tag *,
void **, int (*)(void *), void *,
void **, int (*)(void *), void *);
static void cayman_intr_conf(void *, int, int, int, int, int *);
static int cayman_intr_map(void *, struct pci_attach_args *,
pci_intr_handle_t *);
static struct sh5pci_ihead *cayman_intr_ihead(void *, pci_intr_handle_t);
static void * cayman_intr_establish(void *, pci_intr_handle_t,
int, int (*)(void *), void *);
static void cayman_intr_disestablish(void *, pci_intr_handle_t, void *);
struct sh5pci_intr_hooks cayman_pci_hooks = {
"cayman",
cayman_intr_init,
cayman_intr_conf,
cayman_intr_map,
cayman_intr_ihead,
cayman_intr_establish,
cayman_intr_disestablish
};
struct cayman_intr_softc {
void *sc_ct;
struct sh5pci_ihead sc_primary[PCI_INTERRUPT_PIN_MAX];
struct sh5pci_ihead sc_p1[PCI_INTERRUPT_PIN_MAX];
struct sh5pci_ihead sc_p2[PCI_INTERRUPT_PIN_MAX];
};
static struct cayman_intr_softc softc;
/*
* Magick values stuffed into the interrupt line to identify which
* interrupt controller the pin is routed to.
*/
#define CAYMAN_INTR_P1 0x10 /* SysFPGA P1 pins */
#define CAYMAN_INTR_P2 0x20 /* SysFPGA P2 pins */
#define CAYMAN_INTR_IS_PRIMARY(ih) ((SH5PCI_IH_LINE(ih) & 0x30) == 0)
#define CAYMAN_INTR_IS_P1(ih) ((SH5PCI_IH_LINE(ih) & 0x30) == 0x10)
#define CAYMAN_INTR_IS_P2(ih) ((SH5PCI_IH_LINE(ih) & 0x30) == 0x20)
/*
* Since there is only one SH5 board with PCI at this time, we
* simply return a pointer to the Cayman PCI interrupt hooks.
*
* At some future time, this function may well be specific to
* a class of SH5 machines, and will use the "ih_name" field of
* the sh5pci_intr_hooks structure to match the correct interrupt
* back-end.
*
* Actually, it's not quite ready to do all that. To make it truly
* workable, we'd need to know more about the "sh5pci" bridge to
* which the chipset tag refers.
*/
/*ARGSUSED*/
const struct sh5pci_intr_hooks *
sh5pci_get_intr_hooks(struct sh5_pci_chipset_tag *ct)
{
return (&cayman_pci_hooks);
}
static void *
cayman_intr_init(struct sh5_pci_chipset_tag *ct,
void **ih_serr, int (*fn_serr)(void *), void *arg_serr,
void **ih_err, int (*fn_err)(void *), void *arg_err)
{
struct cayman_intr_softc *sc = &softc;
struct sh5pci_ihead *ih;
int i;
/*
* Hook the ERR and SERR interrupts from the bridge, if required.
*/
if (ih_serr) {
*ih_serr = sh5_intr_establish(INTC_INTEVT_PCI_SERR,
IST_LEVEL, IPL_HIGH, fn_serr, arg_serr);
KDASSERT(*ih_serr);
}
if (ih_err) {
*ih_err = sh5_intr_establish(INTC_INTEVT_PCI_ERR,
IST_LEVEL, IPL_HIGH, fn_err, arg_err);
KDASSERT(*ih_err);
}
/*
* Initialise the sh5pci_ihead structures for the PCI INT[A-D] pins
*/
for (i = 0; i < PCI_INTERRUPT_PIN_MAX; i++) {
ih = &sc->sc_primary[i];
SLIST_INIT(&ih->ih_handlers);
ih->ih_cookie = NULL;
ih->ih_evcnt = NULL;
ih->ih_level = 0;
switch (i) {
case 0: ih->ih_intevt = INTC_INTEVT_PCI_INTA;
break;
case 1: ih->ih_intevt = INTC_INTEVT_PCI_INTB;
break;
case 2: ih->ih_intevt = INTC_INTEVT_PCI_INTC;
break;
case 3: ih->ih_intevt = INTC_INTEVT_PCI_INTD;
break;
}
}
for (i = 0; i < PCI_INTERRUPT_PIN_MAX; i++) {
ih = &sc->sc_p1[i];
SLIST_INIT(&ih->ih_handlers);
ih->ih_cookie = NULL;
ih->ih_evcnt = NULL;
ih->ih_level = 0;
ih->ih_intevt = INTC_INTEVT_IRL2;
}
for (i = 0; i < PCI_INTERRUPT_PIN_MAX; i++) {
ih = &sc->sc_p2[i];
SLIST_INIT(&ih->ih_handlers);
ih->ih_cookie = NULL;
ih->ih_evcnt = NULL;
ih->ih_level = 0;
ih->ih_intevt = INTC_INTEVT_IRL3;
}
sc->sc_ct = ct;
return (sc);
}
/*ARGSUSED*/
static void
cayman_intr_conf(void *arg, int bus, int dev, int pin, int swiz, int *line)
{
/*
* XXX: See comments at the top of this file regarding lack of
* support for more than the default set of PCI-PCI bridges...
*/
/*
* Use the defaults for primary bus.
*/
if (bus == 0) {
*line = ((swiz + (pin - 1)) & 3);
return;
}
if (bus == 1) {
*line = ((dev + pin - 1) & 3) | CAYMAN_INTR_P1;
return;
}
if (bus != 2)
panic("cayman_intr_conf: unsupported bus number");
*line = ((dev + pin - 1) & 3) | CAYMAN_INTR_P2;
}
/*ARGSUSED*/
static int
cayman_intr_map(void *arg, struct pci_attach_args *pa, pci_intr_handle_t *ih)
{
*ih = SH5PCI_IH_CREATE(pa->pa_intrline, pa->pa_intrpin, 0);
return (0);
}
static struct sh5pci_ihead *
cayman_intr_ihead(void *arg, pci_intr_handle_t ih)
{
struct cayman_intr_softc *sc = arg;
int pin;
if (SH5PCI_IH_PIN(ih) == PCI_INTERRUPT_PIN_NONE ||
SH5PCI_IH_PIN(ih) > PCI_INTERRUPT_PIN_MAX)
return (NULL);
pin = SH5PCI_IH_PIN(ih) - 1;
if (CAYMAN_INTR_IS_PRIMARY(ih))
return (&sc->sc_primary[pin]);
if (CAYMAN_INTR_IS_P1(ih))
return (&sc->sc_p1[pin]);
if (CAYMAN_INTR_IS_P2(ih))
return (&sc->sc_p2[pin]);
return (NULL);
}
/*ARGSUSED*/
static void *
cayman_intr_establish(void *arg, pci_intr_handle_t ih,
int level, int (*func)(void *), void *fnarg)
{
struct sh5pci_ihead *ihead;
int inum, group;
if ((ihead = cayman_intr_ihead(arg, ih)) == NULL)
return (NULL);
if (CAYMAN_INTR_IS_PRIMARY(ih)) {
return (sh5_intr_establish(ihead->ih_intevt, IST_LEVEL, level,
func, fnarg));
}
inum = SH5PCI_IH_LINE(ih) & 0x03;
if (CAYMAN_INTR_IS_P1(ih))
group = SYSFPGA_IGROUP_PCI1;
else
group = SYSFPGA_IGROUP_PCI2;
return (sysfpga_intr_establish(group, level, inum, func, fnarg));
}
/*ARGSUSED*/
static void
cayman_intr_disestablish(void *arg, pci_intr_handle_t ih, void *cookie)
{
if (CAYMAN_INTR_IS_PRIMARY(ih))
sh5_intr_disestablish(cookie);
else
sysfpga_intr_disestablish(cookie);
}

View File

@ -1,4 +1,4 @@
# $NetBSD: files.sh5,v 1.5 2002/09/06 13:18:43 gehenna Exp $
# $NetBSD: files.sh5,v 1.6 2002/09/28 11:16:36 scw Exp $
#
@ -95,6 +95,22 @@ include "dev/ata/files.ata"
# Memory Disk for install floppy
file dev/md_root.c memory_disk_hooks
#
# Machine Independent I2O drivers
#
include "dev/i2o/files.i2o"
#
# PCIbus support
#
device pcibus
attach pcibus at superhyway with sh5pci
file arch/sh5/pci/sh5_pci.c sh5pci needs-flag
include "dev/pci/files.pci"
# OSS audio driver compatibility
include "compat/ossaudio/files.ossaudio"
# Source files
file arch/sh5/sh5/autoconf.c

View File

@ -1,4 +1,4 @@
# $NetBSD: majors.sh5,v 1.2 2002/09/06 13:18:43 gehenna Exp $
# $NetBSD: majors.sh5,v 1.3 2002/09/28 11:16:36 scw Exp $
#
# Device majors for sh5
#
@ -43,3 +43,4 @@ device-major esh char 50 esh
device-major clockctl char 52 clockctl
device-major systrace char 53 systrace
device-major pci char 54 pci

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile,v 1.6 2002/08/30 10:50:55 scw Exp $
# $NetBSD: Makefile,v 1.7 2002/09/28 11:16:36 scw Exp $
KDIR= /sys/arch/sh5/include
INCSDIR= /usr/include/sh5
@ -14,6 +14,7 @@ INCS= ansi.h aout_machdep.h asm.h \
limits.h lock.h \
math.h \
param.h pcb.h pmap.h pmc.h proc.h profile.h pte.h ptrace.h \
pci_machdep.h \
reg.h \
setjmp.h signal.h stdarg.h \
trap.h types.h \

View File

@ -0,0 +1,116 @@
/* $NetBSD: pci_machdep.h,v 1.1 2002/09/28 11:16:36 scw Exp $ */
/*
* Copyright (c) 1996 Christopher G. Demetriou. All rights reserved.
* Copyright (c) 1994 Charles M. Hannum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Charles M. Hannum.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _SH5_PCI_MACHDEP_H
#define _SH5_PCI_MACHDEP_H
/*
* Types provided to machine-independent PCI code
*/
struct pci_attach_args;
struct sh5_pci_chipset_tag;
typedef const struct sh5_pci_chipset_tag *pci_chipset_tag_t;
typedef u_int32_t pcitag_t;
typedef u_int32_t pci_intr_handle_t;
/*
* sh5-specific PCI structure and type definitions.
* NOT TO BE USED DIRECTLY BY MACHINE INDEPENDENT CODE.
*/
/*
* Chipset tag.
* The current SH5 silicon has an on-chip PCI bridge.
* However, on the Cayman, this is supplemented by some resources
* provided by the SysFPGA chip.
* Therefore, we abstract the PCI services though a chipset tag
* which can be set up appropriately by board-specific code.
*/
struct sh5_pci_chipset_tag {
void *ct_cookie;
void (*ct_attach_hook)(void *, struct device *, struct device *,
struct pcibus_attach_args *);
int (*ct_bus_maxdevs)(void *, int);
pcitag_t (*ct_make_tag)(void *, int, int, int);
void (*ct_decompose_tag)(void *, pcitag_t, int *, int *, int *);
pcireg_t (*ct_conf_read)(void *, pcitag_t, int);
void (*ct_conf_write)(void *, pcitag_t, int, pcireg_t);
void (*ct_conf_interrupt)(void *, int, int, int, int, int *);
int (*ct_intr_map)(void *, struct pci_attach_args *,
pci_intr_handle_t *);
const char * (*ct_intr_string)(void *, pci_intr_handle_t);
const struct evcnt * (*ct_intr_evcnt)(void *, pci_intr_handle_t);
void * (*ct_intr_establish)(void *, pci_intr_handle_t,
int, int (*)(void *), void *);
void (*ct_intr_disestablish)(void *, void *);
};
/*
* Functions provided to machine-independent PCI code.
*/
#define pci_attach_hook(parent, self, pba) \
(*(pba)->pba_pc->ct_attach_hook)((pba)->pba_pc->ct_cookie, \
(parent), (self), (pba))
#define pci_bus_maxdevs(ct, busno) \
(*(ct)->ct_bus_maxdevs)((ct)->ct_cookie, (busno))
#define pci_make_tag(ct, bus, dev, func) \
(*(ct)->ct_make_tag)((ct)->ct_cookie, (bus), (dev), (func))
#define pci_decompose_tag(ct, tag, bp, dp, fp) \
(*(ct)->ct_decompose_tag)((ct)->ct_cookie, (tag), (bp), (dp), (fp))
#define pci_conf_read(ct, tag, reg) \
(*(ct)->ct_conf_read)((ct)->ct_cookie, (tag), (reg))
#define pci_conf_write(ct, tag, reg, data) \
(*(ct)->ct_conf_write)((ct)->ct_cookie, (tag), (reg), (data))
#define pci_conf_interrupt(ct, bn, dv, pn, swz, lp) \
(*(ct)->ct_conf_interrupt)((ct)->ct_cookie, (bn), (dv), \
(pn), (swz), (lp))
#define pci_intr_map(pa, ih) \
(*(pa)->pa_pc->ct_intr_map)((pa)->pa_pc->ct_cookie, (pa), (ih))
#define pci_intr_string(ct, ih) \
(*(ct)->ct_intr_string)((ct)->ct_cookie, (ih))
#define pci_intr_evcnt(ct, ih) \
(*(ct)->ct_intr_evcnt)((ct)->ct_cookie, (ih))
#define pci_intr_establish(ct, ih, l, fn, arg) \
(*(ct)->ct_intr_establish)((ct)->ct_cookie, (ih), (l), (fn), (arg))
#define pci_intr_disestablish(ct, cookie) \
(*(ct)->ct_intr_disestablish)((ct)->ct_cookie, (cookie))
/*
* Use the generic PCIbus enumeration code
*/
#define pci_enumerate_bus(sc, m, p) \
pci_enumerate_bus_generic((sc), (m), (p))
#endif /* _SH5_PCI_MACHDEP_H */

973
sys/arch/sh5/pci/sh5_pci.c Normal file
View File

@ -0,0 +1,973 @@
/* $NetBSD: sh5_pci.c,v 1.1 2002/09/28 11:16:37 scw Exp $ */
/*
* Copyright 2002 Wasabi Systems, Inc.
* All rights reserved.
*
* Written by Steve C. Woodford for Wasabi Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the NetBSD Project by
* Wasabi Systems, Inc.
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
* or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* SH-5 Host-PCI Bridge Controller
*/
#include "opt_pci.h"
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/extent.h>
#include <sys/malloc.h>
#include <sys/queue.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#if defined(PCI_NETBSD_CONFIGURE)
#include <dev/pci/pciconf.h>
#endif
#include <machine/cpu.h>
#include <machine/bus.h>
#include <machine/intr.h>
#include <sh5/dev/superhywayvar.h>
#include <sh5/pci/sh5_pcivar.h>
#include <sh5/pci/sh5_pcireg.h>
#include "locators.h"
/*
* XXX: The following is good enough for 1GB of RAM, starting
* at physical address 0x80000000.
*
* Need to revist this to make it configurable by board-specific
* code at runtime.
*/
#define SH5PCI_RAM_PHYS_BASE 0x80000000
struct sh5pci_map {
bus_addr_t m_start;
bus_addr_t m_end;
bus_addr_t m_pcibase;
};
struct sh5pci_softc {
struct device sc_dev;
bus_space_tag_t sc_bust;
bus_dma_tag_t sc_dmat;
bus_space_handle_t sc_csrh;
bus_addr_t sc_base;
struct sh5pci_map sc_map[SH5PCI_NUM_MBARS];
const struct sh5pci_intr_hooks *sc_intr;
void *sc_intr_arg;
void *sc_ih_serr;
void *sc_ih_err;
};
struct sh5pci_icookie {
pci_intr_handle_t ic_ih;
int (*ic_func)(void *);
void *ic_arg;
SLIST_ENTRY(sh5pci_icookie) ic_next;
};
static int sh5pcimatch(struct device *, struct cfdata *, void *);
static void sh5pciattach(struct device *, struct device *, void *);
static int sh5pciprint(void *, const char *);
struct cfattach sh5pci_ca = {
sizeof(struct sh5pci_softc), sh5pcimatch, sh5pciattach
};
extern struct cfdriver pcibus_cd;
static int sh5pci_dmamap_create(void *, bus_size_t, int, bus_size_t,
bus_size_t, int, bus_dmamap_t *);
static void sh5pci_dmamap_destroy(void *, bus_dmamap_t);
static int sh5pci_dmamap_load_direct(void *, bus_dmamap_t,
void *, bus_size_t, struct proc *, int);
static int sh5pci_dmamap_load_mbuf(void *,
bus_dmamap_t, struct mbuf *, int);
static int sh5pci_dmamap_load_uio(void *, bus_dmamap_t,
struct uio *, int);
static int sh5pci_dmamap_load_raw(void *,
bus_dmamap_t, bus_dma_segment_t *, int, bus_size_t, int);
static int sh5pci_dmamap_load_common(struct sh5pci_softc *, bus_dmamap_t);
static void sh5pci_dmamap_unload(void *, bus_dmamap_t);
static void sh5pci_dmamap_sync(void *, bus_dmamap_t, bus_addr_t,
bus_size_t, int);
static int sh5pci_dmamem_alloc(void *, bus_size_t, bus_size_t, bus_size_t,
bus_dma_segment_t *, int, int *, int);
static void sh5pci_dmamem_free(void *, bus_dma_segment_t *, int);
static int sh5pci_dmamem_map(void *, bus_dma_segment_t *, int, size_t,
caddr_t *, int);
static void sh5pci_dmamem_unmap(void *, caddr_t, size_t);
static paddr_t sh5pci_dmamem_mmap(void *, bus_dma_segment_t *, int,
off_t, int, int);
static int sh5pci_mem_map(void *, bus_addr_t, bus_size_t, int,
bus_space_handle_t *);
static int sh5pci_io_map(void *, bus_addr_t, bus_size_t, int,
bus_space_handle_t *);
static void sh5pci_attach_hook(void *, struct device *, struct device *,
struct pcibus_attach_args *);
static int sh5pci_maxdevs(void *, int);
static pcitag_t sh5pci_make_tag(void *, int, int, int);
static void sh5pci_decompose_tag(void *, pcitag_t, int *, int *, int *);
static pcireg_t sh5pci_conf_read(void *, pcitag_t, int);
static void sh5pci_conf_write(void *, pcitag_t, int, pcireg_t);
static void sh5pci_conf_interrupt(void *, int, int, int, int, int *);
static int sh5pci_intr_map(void *, struct pci_attach_args *,
pci_intr_handle_t *);
static const char *sh5pci_intr_string(void *, pci_intr_handle_t);
static const struct evcnt *sh5pci_intr_evcnt(void *, pci_intr_handle_t);
static void * sh5pci_intr_establish(void *, pci_intr_handle_t,
int, int (*)(void *), void *);
static void sh5pci_intr_disestablish(void *, void *);
static int sh5pci_intr_dispatch(void *);
static void sh5pci_bridge_init(struct sh5pci_softc *);
static int sh5pci_check_master_abort(struct sh5pci_softc *);
/*
* XXX: These should be allocated dynamically to allow multiple instances.
*/
static struct sh5_bus_space_tag sh5pci_mem_tag;
static struct sh5_bus_space_tag sh5pci_io_tag;
static struct sh5_bus_dma_tag sh5pci_dma_tag = {
NULL,
sh5pci_dmamap_create,
sh5pci_dmamap_destroy,
sh5pci_dmamap_load_direct,
sh5pci_dmamap_load_mbuf,
sh5pci_dmamap_load_uio,
sh5pci_dmamap_load_raw,
sh5pci_dmamap_unload,
sh5pci_dmamap_sync,
sh5pci_dmamem_alloc,
sh5pci_dmamem_free,
sh5pci_dmamem_map,
sh5pci_dmamem_unmap,
sh5pci_dmamem_mmap,
};
static struct sh5_pci_chipset_tag sh5pci_chipset_tag = {
NULL,
sh5pci_attach_hook,
sh5pci_maxdevs,
sh5pci_make_tag,
sh5pci_decompose_tag,
sh5pci_conf_read,
sh5pci_conf_write,
sh5pci_conf_interrupt,
sh5pci_intr_map,
sh5pci_intr_string,
sh5pci_intr_evcnt,
sh5pci_intr_establish,
sh5pci_intr_disestablish
};
#define sh5pci_csr_read(sc, reg) \
bus_space_read_4((sc)->sc_bust, (sc)->sc_csrh, (reg))
#define sh5pci_csr_write(sc, reg, val) \
bus_space_write_4((sc)->sc_bust, (sc)->sc_csrh, (reg), (val))
/*ARGSUSED*/
static int
sh5pcimatch(struct device *parent, struct cfdata *cf, void *args)
{
struct superhyway_attach_args *sa = args;
bus_space_handle_t bh;
bus_addr_t vcrbase;
u_int64_t vcr;
if (strcmp(sa->sa_name, pcibus_cd.cd_name))
return (0);
sa->sa_pport = 0;
vcrbase = SUPERHYWAY_PPORT_TO_BUSADDR(cf->cf_loc[SUPERHYWAYCF_PPORT]);
bus_space_map(sa->sa_bust, vcrbase + SH5PCI_VCR_OFFSET,
SUPERHYWAY_REG_SZ, 0, &bh);
vcr = bus_space_read_8(sa->sa_bust, bh, SUPERHYWAY_REG_VCR);
bus_space_unmap(sa->sa_bust, bh, SUPERHYWAY_REG_SZ);
if (SUPERHYWAY_VCR_MOD_ID(vcr) != SH5PCI_MODULE_ID)
return (0);
sa->sa_pport = cf->cf_loc[SUPERHYWAYCF_PPORT];
return (1);
}
/*ARGSUSED*/
static void
sh5pciattach(struct device *parent, struct device *self, void *args)
{
struct sh5pci_softc *sc = (struct sh5pci_softc *)self;
struct superhyway_attach_args *sa = args;
struct pcibus_attach_args pba;
bus_space_handle_t bh;
u_int64_t vcr;
#if defined(PCI_NETBSD_CONFIGURE)
struct extent *ioext, *memext;
u_long cfg_ioaddr;
#endif
sc->sc_bust = sa->sa_bust;
sc->sc_dmat = sa->sa_dmat;
sc->sc_base = SUPERHYWAY_PPORT_TO_BUSADDR(sa->sa_pport);
/* Fetch the VCR */
bus_space_map(sc->sc_bust, sc->sc_base + SH5PCI_VCR_OFFSET,
SUPERHYWAY_REG_SZ, 0, &bh);
vcr = bus_space_read_8(sc->sc_bust, bh, SUPERHYWAY_REG_VCR);
bus_space_unmap(sc->sc_bust, bh, SUPERHYWAY_REG_SZ);
/*
* Map the PCI CSR Registers
*/
bus_space_map(sa->sa_bust, sc->sc_base + SH5PCI_CSR_OFFSET,
SH5PCI_CSR_SIZE, 0, &sc->sc_csrh);
printf(": SH-5 PCIbus Bridge, Version 0x%x\n",
(int)SUPERHYWAY_VCR_MOD_VERS(vcr));
#ifdef DEBUG
printf("%s: CSR at %p\n", sc->sc_dev.dv_xname, (void *)sc->sc_csrh);
#endif
/*
* Fix up the memory and i/o tags by copying our
* parent's tag, and modifying the cookie and bus_space_map fields.
*
* This is a wee bit naughty; we really shouldn't interpret our
* parent's tag, but it's a lot more efficient than writing a whole
* bunch of stubs which just call the parent's methods.
*
* XXX: We get away with this because we *know* our parent is
* the base-level bus_space(9) implementation; which doesn't
* interpret the "cookie" field of the tag...
*/
sh5pci_mem_tag = *sc->sc_bust;
sh5pci_mem_tag.bs_cookie = sc;
sh5pci_mem_tag.bs_map = sh5pci_mem_map;
sh5pci_io_tag = *sc->sc_bust;
sh5pci_io_tag.bs_cookie = sc;
sh5pci_io_tag.bs_map = sh5pci_io_map;
/*
* Initialise our DMA tag
*/
sh5pci_dma_tag.bd_cookie = sc;
/*
* Initialise the cookie field of our chipset tag
*/
sh5pci_chipset_tag.ct_cookie = sc;
/*
* Connect to, and initialise, the board-specific interrupt
* routing interface.
*/
sc->sc_intr = sh5pci_get_intr_hooks(&sh5pci_chipset_tag);
sc->sc_intr_arg = (sc->sc_intr->ih_init)(&sh5pci_chipset_tag,
NULL, NULL, NULL, NULL, NULL, NULL);
/*
* Initialise the host-pci hardware
*/
sh5pci_bridge_init(sc);
#if defined(PCI_NETBSD_CONFIGURE)
/*
* Configure the devices on the PCIbus
*/
memext = extent_create("pcimem", sh5pci_csr_read(sc, SH5PCI_CSR_MBR),
sh5pci_csr_read(sc, SH5PCI_CSR_MBR) + (SH5PCI_MEMORY_SIZE - 1),
M_DEVBUF, NULL, 0, EX_NOWAIT);
ioext = extent_create("pciio", sh5pci_csr_read(sc, SH5PCI_CSR_IOBR),
sh5pci_csr_read(sc, SH5PCI_CSR_IOBR) + (SH5PCI_IO_SIZE - 1),
M_DEVBUF, NULL, 0, EX_NOWAIT);
/*
* Allocate some I/O space for the bridge's config registers
* before assigning addresses to any other device.
* (The bridge doesn't seem to be able to see its own config
* registers when doing config cycles. Let's hope they're
* visible if the bridge is running in non-host mode...)
*/
extent_alloc(ioext, 0x100, 0x100, 0, EX_NOWAIT, &cfg_ioaddr);
sh5pci_csr_write(sc, SH5PCI_CONF_IOBAR, cfg_ioaddr|PCI_MAPREG_TYPE_IO);
/*
* Configure up the PCI bus
*/
pci_configure_bus(&sh5pci_chipset_tag, ioext, memext, NULL, 0, 32);
extent_destroy(ioext);
extent_destroy(memext);
/* Clear any accumulated master aborts */
(void) sh5pci_check_master_abort(sc);
#endif
pba.pba_busname = "pci";
pba.pba_pc = &sh5pci_chipset_tag;
pba.pba_bus = 0;
pba.pba_bridgetag = NULL;
pba.pba_flags = PCI_FLAGS_IO_ENABLED | PCI_FLAGS_MEM_ENABLED;
pba.pba_dmat = &sh5pci_dma_tag;
pba.pba_iot = &sh5pci_io_tag;
pba.pba_memt = &sh5pci_mem_tag;
config_found(self, &pba, sh5pciprint);
}
/*ARGSUSED*/
static int
sh5pciprint(void *arg, const char *cp)
{
if (cp == NULL)
return (UNCONF);
return (QUIET);
}
static int
sh5pci_dmamap_create(void *arg, bus_size_t size, int nsegs,
bus_size_t maxsegsz, bus_size_t boundary, int flags, bus_dmamap_t *dmamp)
{
struct sh5pci_softc *sc = arg;
return (bus_dmamap_create(sc->sc_dmat, size, nsegs, maxsegsz,
boundary, flags, dmamp));
}
static void
sh5pci_dmamap_destroy(void *arg, bus_dmamap_t map)
{
struct sh5pci_softc *sc = arg;
bus_dmamap_destroy(sc->sc_dmat, map);
}
static int
sh5pci_dmamap_load_direct(void *arg, bus_dmamap_t map,
void *buf, bus_size_t buflen, struct proc *p, int flags)
{
struct sh5pci_softc *sc = arg;
int rv;
rv = bus_dmamap_load(sc->sc_dmat, map, buf, buflen, p, flags);
if (rv != 0)
return (rv);
return (sh5pci_dmamap_load_common(sc, map));
}
static int
sh5pci_dmamap_load_mbuf(void *arg, bus_dmamap_t map, struct mbuf *m, int flags)
{
struct sh5pci_softc *sc = arg;
int rv;
rv = bus_dmamap_load_mbuf(sc->sc_dmat, map, m, flags);
if (rv != 0)
return (rv);
return (sh5pci_dmamap_load_common(sc, map));
}
static int
sh5pci_dmamap_load_uio(void *arg, bus_dmamap_t map, struct uio *uio, int flags)
{
struct sh5pci_softc *sc = arg;
int rv;
rv = bus_dmamap_load_uio(sc->sc_dmat, map, uio, flags);
if (rv != 0)
return (rv);
return (sh5pci_dmamap_load_common(sc, map));
}
static int
sh5pci_dmamap_load_raw(void *arg, bus_dmamap_t map,
bus_dma_segment_t *segs, int nsegs, bus_size_t size, int flags)
{
struct sh5pci_softc *sc = arg;
int rv;
rv = bus_dmamap_load_raw(sc->sc_dmat, map, segs, nsegs, size, flags);
if (rv != 0)
return (rv);
return (sh5pci_dmamap_load_common(sc, map));
}
static int
sh5pci_dmamap_load_common(struct sh5pci_softc *sc, bus_dmamap_t map)
{
bus_dma_segment_t *ds;
u_int32_t mask;
int rv, i;
/*
* If all goes well, "rv" will be zero at the end of the loop.
* (It is decremented each time we successfully translate
* a segment).
*/
rv = map->dm_nsegs;
/*
* Traverse the list of segments which make up this map, and
* convert the cpu-relative addresses therein to PCIbus addresses.
*/
for (ds = &map->dm_segs[0]; ds < &map->dm_segs[map->dm_nsegs]; ds++) {
for (i = 0; i < SH5PCI_NUM_MBARS; i++) {
if (sc->sc_map[i].m_start == ~0)
continue;
if (ds->_ds_cpuaddr < sc->sc_map[i].m_start ||
(ds->_ds_cpuaddr + ds->ds_len) >=
sc->sc_map[i].m_end)
continue;
mask = sc->sc_map[i].m_end - sc->sc_map[i].m_start;
mask -= 1;
/*
* Looks like we found the window through which this
* segment is visible. Convert to PCIbus address.
*/
ds->ds_addr = sc->sc_map[i].m_pcibase +
(ds->_ds_cpuaddr & mask);
rv -= 1;
break;
}
}
return (rv ? 1 : 0);
}
static void
sh5pci_dmamap_unload(void *arg, bus_dmamap_t map)
{
struct sh5pci_softc *sc = arg;
/* XXX Deal with bounce buffers (for when we have > 1GB RAM) */
bus_dmamap_unload(sc->sc_dmat, map);
}
static void
sh5pci_dmamap_sync(void *arg, bus_dmamap_t map, bus_addr_t offset,
bus_size_t len, int ops)
{
struct sh5pci_softc *sc = arg;
/* XXX Deal with bounce buffers (for when we have > 1GB RAM) */
bus_dmamap_sync(sc->sc_dmat, map, offset, len, ops);
}
static int
sh5pci_dmamem_alloc(void *arg, bus_size_t size, bus_size_t alignment,
bus_size_t boundary, bus_dma_segment_t *segs, int nsegs,
int *rsegs, int flags)
{
struct sh5pci_softc *sc = arg;
/* XXX Deal with systems with > 1GB RAM */
/*
* Allocate physical memory.
*
* Note: This fills in the segments with cpu-relative physical
* addresses. A further call to bus_dmamap_load_raw() must be
* made before the addresses in the segments can be used.
* The segments of the dma map will then contain PCIbus-relative
* physical addresses of the memory allocated here.
*/
return (bus_dmamem_alloc(sc->sc_dmat, size, alignment, boundary,
segs, nsegs, rsegs, flags));
}
static void
sh5pci_dmamem_free(void *arg, bus_dma_segment_t *segs, int nsegs)
{
struct sh5pci_softc *sc = arg;
bus_dmamem_free(sc->sc_dmat, segs, nsegs);
}
static int
sh5pci_dmamem_map(void *arg, bus_dma_segment_t *segs, int nsegs,
size_t size, caddr_t *kvap, int flags)
{
struct sh5pci_softc *sc = arg;
return (bus_dmamem_map(sc->sc_dmat, segs, nsegs, size, kvap, flags));
}
static void
sh5pci_dmamem_unmap(void *arg, caddr_t kva, size_t size)
{
struct sh5pci_softc *sc = arg;
bus_dmamem_unmap(sc->sc_dmat, kva, size);
}
static paddr_t
sh5pci_dmamem_mmap(void *arg, bus_dma_segment_t *segs, int nsegs,
off_t off, int prot, int flags)
{
struct sh5pci_softc *sc = arg;
return (bus_dmamem_mmap(sc->sc_dmat, segs, nsegs, off, prot, flags));
}
static int
sh5pci_mem_map(void *arg, bus_addr_t addr, bus_size_t size, int flags,
bus_space_handle_t *bushp)
{
struct sh5pci_softc *sc = arg;
u_int32_t mbr;
mbr = sh5pci_csr_read(sc, SH5PCI_CSR_MBR);
/*
* Can we access the required PCIbus address range through
* our window?
*/
if (addr < mbr)
return (EINVAL);
/*
* Convert the PCIbus address to an offset within the window
*/
addr -= mbr;
/*
* One final check that the address range fits inside the window.
*/
if ((addr + size) >= SH5PCI_MEMORY_SIZE)
return (EINVAL);
/*
* Convert to the correct offset into our SuperHyway address space
* before mapping in the normal way.
*/
addr += sc->sc_base + SH5PCI_MEMORY_OFFSET;
return (bus_space_map(sc->sc_bust, addr, size, flags, bushp));
}
static int
sh5pci_io_map(void *arg, bus_addr_t addr, bus_size_t size, int flags,
bus_space_handle_t *bushp)
{
struct sh5pci_softc *sc = arg;
u_int32_t iobr;
iobr = sh5pci_csr_read(sc, SH5PCI_CSR_IOBR);
/*
* Can we access the required PCIbus address range through
* our window?
*/
if (addr < iobr)
return (EINVAL);
/*
* Convert the PCIbus address to an offset within the window
*/
addr -= iobr;
/*
* One final check that the address range fits inside the window.
*/
if ((addr + size) >= SH5PCI_IO_SIZE)
return (EINVAL);
/*
* Convert to the correct offset into our SuperHyway address space
* before mapping in the normal way.
*/
addr += sc->sc_base + SH5PCI_IO_OFFSET;
return (bus_space_map(sc->sc_bust, addr, size, flags, bushp));
}
/*ARGSUSED*/
static void
sh5pci_attach_hook(void *arg, struct device *parent, struct device *self,
struct pcibus_attach_args *pba)
{
}
/*ARGSUSED*/
static int
sh5pci_maxdevs(void *arg, int busno)
{
if (busno == 0)
return (4);
return (32);
}
/*ARGSUSED*/
static pcitag_t
sh5pci_make_tag(void *arg, int bus, int dev, int func)
{
return ((pcitag_t)SH5PCI_CSR_PAR_MAKE(bus, dev, func, 0));
}
/*ARGSUSED*/
static void
sh5pci_decompose_tag(void *arg, pcitag_t tag, int *bp, int *dp, int *fp)
{
if (bp != NULL)
*bp = (int)SH5PCI_CSR_PAR_PCI_BN(tag);
if (dp != NULL)
*dp = (int)SH5PCI_CSR_PAR_PCI_DN(tag);
if (fp != NULL)
*fp = (int)SH5PCI_CSR_PAR_PCI_FN(tag);
}
static pcireg_t
sh5pci_conf_read(void *arg, pcitag_t tag, int reg)
{
struct sh5pci_softc *sc = arg;
pcireg_t rv;
int s;
KDASSERT((reg & 3) == 0);
s = splhigh();
sh5pci_csr_write(sc, SH5PCI_CSR_PAR, (u_int32_t)(tag | (pcitag_t)reg));
rv = (pcireg_t)sh5pci_csr_read(sc, SH5PCI_CSR_PDR);
splx(s);
return (rv);
}
static void
sh5pci_conf_write(void *arg, pcitag_t tag, int reg, pcireg_t data)
{
struct sh5pci_softc *sc = arg;
int s;
KDASSERT((reg & 3) == 0);
s = splhigh();
sh5pci_csr_write(sc, SH5PCI_CSR_PAR, (u_int32_t)(tag | (pcitag_t)reg));
sh5pci_csr_write(sc, SH5PCI_CSR_PDR, (u_int32_t)data);
splx(s);
}
static void
sh5pci_conf_interrupt(void *arg, int bus, int dev, int pin, int swiz, int *line)
{
struct sh5pci_softc *sc = arg;
(*sc->sc_intr->ih_intr_conf)(sc->sc_intr_arg, bus, dev, pin,
swiz, line);
}
static int
sh5pci_intr_map(void *arg, struct pci_attach_args *pa, pci_intr_handle_t *ih)
{
struct sh5pci_softc *sc = arg;
return ((*sc->sc_intr->ih_intr_map)(sc->sc_intr_arg, pa, ih));
}
static const char *
sh5pci_intr_string(void *arg, pci_intr_handle_t ih)
{
struct sh5pci_softc *sc = arg;
struct sh5pci_ihead *ihead;
static char intstr[16];
ihead = (*sc->sc_intr->ih_intr_ihead)(sc->sc_intr_arg, ih);
if (ihead == NULL)
return (NULL);
if (ihead->ih_level)
sprintf(intstr, "ipl %d", ihead->ih_level);
else
sprintf(intstr, "intevt 0x%x", ihead->ih_intevt);
return (intstr);
}
static const struct evcnt *
sh5pci_intr_evcnt(void *arg, pci_intr_handle_t ih)
{
struct sh5pci_softc *sc = arg;
struct sh5pci_ihead *ihead;
ihead = (*sc->sc_intr->ih_intr_ihead)(sc->sc_intr_arg, ih);
if (ihead == NULL)
return (NULL);
return (ihead->ih_evcnt);
}
static void *
sh5pci_intr_establish(void *arg, pci_intr_handle_t ih,
int level, int (*func)(void *), void *fnarg)
{
struct sh5pci_softc *sc = arg;
struct sh5pci_ihead *ihead;
struct sh5pci_icookie *ic;
int s;
ihead = (*sc->sc_intr->ih_intr_ihead)(sc->sc_intr_arg, ih);
if (ihead == NULL)
return (NULL);
if ((ic = malloc(sizeof(*ic), M_DEVBUF, M_NOWAIT)) == NULL)
return (NULL);
s = splhigh();
if (ihead->ih_cookie != NULL && ihead->ih_level != level) {
splx(s);
free(ic, M_DEVBUF);
printf("sh5pci_intr_establish: shared level mismatch");
return (NULL);
}
ic->ic_ih = ih;
ic->ic_func = func;
ic->ic_arg = fnarg;
SLIST_INSERT_HEAD(&ihead->ih_handlers, ic, ic_next);
if (ihead->ih_cookie) {
splx(s);
return (ic);
}
/*
* First time through. Hook the real interrupt.
*/
ihead->ih_level = level;
ihead->ih_cookie = (*sc->sc_intr->ih_intr_establish)(sc->sc_intr_arg,
ih, level, sh5pci_intr_dispatch, ihead);
KDASSERT(ihead->ih_cookie);
splx(s);
return (ic);
}
static void
sh5pci_intr_disestablish(void *arg, void *cookie)
{
struct sh5pci_softc *sc = arg;
struct sh5pci_ihead *ihead;
struct sh5pci_icookie *ic = cookie;
int s;
ihead = (*sc->sc_intr->ih_intr_ihead)(sc->sc_intr_arg, ic->ic_ih);
if (ihead == NULL)
return; /* XXX: Panic instead? */
KDASSERT(ihead->ih_cookie != NULL);
s = splhigh();
SLIST_REMOVE(&ihead->ih_handlers, ic, sh5pci_icookie, ic_next);
/*
* If we're removing the last handler, unhook the interrupt
*/
if (SLIST_EMPTY(&ihead->ih_handlers)) {
(*sc->sc_intr->ih_intr_disestablish)(sc->sc_intr_arg,
ic->ic_ih, ihead->ih_cookie);
ihead->ih_cookie = NULL;
ihead->ih_level = 0;
}
splx(s);
free(ic, M_DEVBUF);
}
static int
sh5pci_intr_dispatch(void *arg)
{
struct sh5pci_ihead *ihead = arg;
struct sh5pci_icookie *ic;
int rv = 0;
/*
* Call all the handlers registered for a particular interrupt pin
* and accumulate their "handled" status.
*/
SLIST_FOREACH(ic, &ihead->ih_handlers, ic_next)
rv |= (*ic->ic_func)(ic->ic_arg);
return (rv);
}
static void
sh5pci_bridge_init(struct sh5pci_softc *sc)
{
u_int32_t reg;
int i;
/*
* Disable snoop
*/
sh5pci_csr_write(sc, SH5PCI_CSR_CSCR0, SH5PCI_CSR_CSCR_SNPMD_DISABLED);
sh5pci_csr_write(sc, SH5PCI_CSR_CSAR0, 0);
sh5pci_csr_write(sc, SH5PCI_CSR_CSCR1, SH5PCI_CSR_CSCR_SNPMD_DISABLED);
sh5pci_csr_write(sc, SH5PCI_CSR_CSAR1, 0);
/*
* Disable general, arbiter, and power-management interrupts.
*/
sh5pci_csr_write(sc, SH5PCI_CSR_INTM, 0);
sh5pci_csr_write(sc, SH5PCI_CSR_AINTM, 0);
sh5pci_csr_write(sc, SH5PCI_CSR_PINTM, 0);
/*
* Enable Memory and I/O spaces, and enable the bridge to
* be a bus master.
*/
reg = sh5pci_csr_read(sc, PCI_COMMAND_STATUS_REG);
reg &= (PCI_COMMAND_MASK << PCI_COMMAND_SHIFT);
reg |= (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE |
PCI_COMMAND_MASTER_ENABLE) << PCI_COMMAND_SHIFT;
sh5pci_csr_write(sc, PCI_COMMAND_STATUS_REG, reg);
/*
* Now enable the bridge.
*/
reg = SH5PCI_CSR_CR_PCI_FTO_WR(1); /* TRDY and IRDY Enable */
reg |= SH5PCI_CSR_CR_PCI_PFE_WR(1); /* Pre-fetch Enable */
reg |= SH5PCI_CSR_CR_PCI_BMAM_WR(1); /* Round-robin arbitration */
reg |= SH5PCI_CSR_CR_PCI_HOSTNS(1);
reg |= SH5PCI_CSR_CR_PCI_CLKENS(1);
sh5pci_csr_write(sc, SH5PCI_CSR_CR, reg);
reg |= SH5PCI_CSR_CR_PCI_CFINT_WR(1); /* Take bridge out of reset */
sh5pci_csr_write(sc, SH5PCI_CSR_CR, reg);
/*
* Specify the base addresses in PCI memory and I/O space to
* which SuperHyway accesses are mapped.
*
* For PCI memory space, we position this to the top 512MB
* of the PCIbus address space.
*
* For PCI i/o space, we position this at PCIbus address 0 to
* remain compatible with the PeeCee scheme of things.
*/
sh5pci_csr_write(sc, SH5PCI_CSR_MBMR,
SH5PCI_CSR_MBMR_PCI_MSBAMR(SH5PCI_MB2MSBAMR(512)));
sh5pci_csr_write(sc, SH5PCI_CSR_MBR, (~SH5PCI_MEMORY_SIZE) + 1);
sh5pci_csr_write(sc, SH5PCI_CSR_IOBMR,
SH5PCI_CSR_IOBMR_PCI_IOBAMR(SH5PCI_MB2IOBAMR(8)));
sh5pci_csr_write(sc, SH5PCI_CSR_IOBR, 0);
/*
* Set up the PCI target images such that other PCIbus Masters
* can access system memory.
*
* XXX: Really shouldn't hard-code these.
*/
sh5pci_csr_write(sc, SH5PCI_CSR_LSR(0),
SH5PCI_CSR_LSR_PCI_LSR_WR(SH5PCI_MB2LSR(512)) |
SH5PCI_CSR_LSR_PCI_MBARE);
sh5pci_csr_write(sc, SH5PCI_CSR_LAR(0), SH5PCI_RAM_PHYS_BASE);
sh5pci_csr_write(sc, SH5PCI_CONF_MBAR(0),
0x00000000 | PCI_MAPREG_TYPE_MEM |
PCI_MAPREG_MEM_TYPE_32BIT | PCI_MAPREG_MEM_PREFETCHABLE_MASK);
sh5pci_csr_write(sc, SH5PCI_CSR_LSR(1),
SH5PCI_CSR_LSR_PCI_LSR_WR(SH5PCI_MB2LSR(512)) |
SH5PCI_CSR_LSR_PCI_MBARE);
sh5pci_csr_write(sc, SH5PCI_CSR_LAR(1),
SH5PCI_RAM_PHYS_BASE + 0x20000000);
sh5pci_csr_write(sc, SH5PCI_CONF_MBAR(1),
0x20000000 | PCI_MAPREG_TYPE_MEM |
PCI_MAPREG_MEM_TYPE_32BIT | PCI_MAPREG_MEM_PREFETCHABLE_MASK);
/*
* Fetch the mapping registers for the benefit of bus_dma mappings.
*/
for (i = 0; i < SH5PCI_NUM_MBARS; i++) {
reg = sh5pci_csr_read(sc, SH5PCI_CSR_LSR(i));
if (reg & SH5PCI_CSR_LSR_PCI_MBARE) {
sc->sc_map[i].m_start =
sh5pci_csr_read(sc, SH5PCI_CSR_LAR(i));
sc->sc_map[i].m_end = sc->sc_map[i].m_start +
SH5PCI_CSR_LSR_PCI_LSR_SIZE(reg);
sc->sc_map[i].m_pcibase =
PCI_MAPREG_MEM_ADDR(sh5pci_csr_read(sc,
SH5PCI_CONF_MBAR(i)));
} else
sc->sc_map[i].m_start = ~0;
}
#if 0
/*
* XXX: Not yet
*
* Enable interrupts
*/
sh5pci_csr_write(sc, SH5PCI_CSR_INTM, 0);
sh5pci_csr_write(sc, SH5PCI_CSR_AINTM, 0);
#endif
}
static int
sh5pci_check_master_abort(struct sh5pci_softc *sc)
{
u_int32_t reg;
int s, rv = 0;
s = splhigh();
reg = sh5pci_csr_read(sc, PCI_COMMAND_STATUS_REG);
if ((reg & PCI_STATUS_MASTER_ABORT) != 0) {
sh5pci_csr_write(sc, PCI_COMMAND_STATUS_REG, reg);
sh5pci_csr_write(sc, SH5PCI_CSR_INT, SH5PCI_CSR_INT_PCI_MADIM);
rv = 1;
}
splx(s);
return (rv);
}

View File

@ -0,0 +1,244 @@
/* $NetBSD: sh5_pcireg.h,v 1.1 2002/09/28 11:16:37 scw Exp $ */
/*
* Copyright 2002 Wasabi Systems, Inc.
* All rights reserved.
*
* Written by Steve C. Woodford for Wasabi Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the NetBSD Project by
* Wasabi Systems, Inc.
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
* or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _SH5_PCIREG_H
#define _SH5_PCIREG_H
/*
* Offsets from the base of the PCI bridge's SuperHyWay p-port
*/
#define SH5PCI_MEMORY_OFFSET 0x00000000 /* PCI memory space */
#define SH5PCI_MEMORY_SIZE 0x20000000 /* 512MB */
#define SH5PCI_IO_OFFSET 0x20800000 /* PCI i/o space */
#define SH5PCI_IO_SIZE 0x800000 /* 8MB */
#define SH5PCI_VCR_OFFSET 0x20000000 /* Version Control Register */
#define SH5PCI_CSR_OFFSET 0x20040000 /* PCIbus control registers */
#define SH5PCI_CSR_SIZE 0x220
/*
* The PCI Module's "Module ID" as found in the VCR
*/
#define SH5PCI_MODULE_ID 0x204f
/*
* Offsets for the bridge's Memory and I/O BARs in PCI configuration space
*/
#define SH5PCI_CONF_IOBAR (PCI_MAPREG_START)
#define SH5PCI_CONF_MBAR(n) (PCI_MAPREG_START + 0x04 + ((n) * 4))
#define SH5PCI_NUM_MBARS 2
/*
* Offset for the CSR registers
*/
#define SH5PCI_CSR_CR 0x100 /* Control Register */
#define SH5PCI_CSR_LSR(n) (0x104+((n)*4)) /* Local Space Register */
#define SH5PCI_CSR_LAR(n) (0x10c+((n)*4)) /* Local Address Register */
#define SH5PCI_CSR_INT 0x114 /* Interrupt Register */
#define SH5PCI_CSR_INTM 0x118 /* Interrupt Msk Register */
#define SH5PCI_CSR_AIR 0x11c /* Error Addr Info Register */
#define SH5PCI_CSR_CIR 0x120 /* Error Comand Info Register */
#define SH5PCI_CSR_AINT 0x130 /* Arbiter Interrupt Register */
#define SH5PCI_CSR_AINTM 0x134 /* Arbiter Int Mask Register */
#define SH5PCI_CSR_BMIR 0x138 /* Arbiter BM Info Register */
#define SH5PCI_CSR_PAR 0x1c0 /* PIO Address Register */
#define SH5PCI_CSR_MBR 0x1c4 /* Memory Space Bank Register */
#define SH5PCI_CSR_IOBR 0x1c8 /* I/O Space Bank Register */
#define SH5PCI_CSR_PINT 0x1cc /* Power Mgmnt Int Register */
#define SH5PCI_CSR_PINTM 0x1d0 /* Power Mgt Int Msk Register */
#define SH5PCI_CSR_MBMR 0x1d8 /* Mem Spc Bank Mask Register */
#define SH5PCI_CSR_IOBMR 0x1dc /* I/O Spc Bank Mask Register */
#define SH5PCI_CSR_CSCR0 0x210 /* Cache Snoop Ctl Register 0 */
#define SH5PCI_CSR_CSCR1 0x214 /* Cache Snoop Ctl Register 1 */
#define SH5PCI_CSR_CSAR0 0x218 /* Cache Snoop Adr Register 0 */
#define SH5PCI_CSR_CSAR1 0x21c /* Cache Snoop Adr Register 1 */
#define SH5PCI_CSR_PDR 0x220 /* PIO Data Register */
/*
* Bit Definitons for SH5PCI_CSR_CR PCI Control Register
*/
#define SH5PCI_CSR_CR_PCI_DLLDLAY_WR(v) (0xa5000000 | (((v) & 0x1ff) << 15))
#define SH5PCI_CSR_CR_PCI_DLLDLAY(v) (((v) >> 15) & 0x1ff)
#define SH5PCI_CSR_CR_PCI_DLLLOCK_WR(v) (0xa5000000 | (((v) & 0x1) << 14))
#define SH5PCI_CSR_CR_PCI_DLLLOCK(v) (((v) >> 14) & 0x1)
#define SH5PCI_CSR_CR_PCI_PBAM_WR(v) (0xa5000000 | (((v) & 0x1) << 12))
#define SH5PCI_CSR_CR_PCI_PBAM(v) (((v) >> 12) & 0x1)
#define SH5PCI_CSR_CR_PCI_PFCS_WR(v) (0xa5000000 | (((v) & 0x1) << 11))
#define SH5PCI_CSR_CR_PCI_PFCS(v) (((v) >> 11) & 0x1)
#define SH5PCI_CSR_CR_PCI_FTO_WR(v) (0xa5000000 | (((v) & 0x1) << 10))
#define SH5PCI_CSR_CR_PCI_FTO(v) (((v) >> 10) & 0x1)
#define SH5PCI_CSR_CR_PCI_PFE_WR(v) (0xa5000000 | (((v) & 0x1) << 9))
#define SH5PCI_CSR_CR_PCI_PFE(v) (((v) >> 9) & 0x1)
#define SH5PCI_CSR_CR_PCI_TBS_WR(v) (0xa5000000 | (((v) & 0x1) << 8))
#define SH5PCI_CSR_CR_PCI_TBS(v) (((v) >> 8) & 0x1)
#define SH5PCI_CSR_CR_PCI_SPUE_WR(v) (0xa5000000 | (((v) & 0x1) << 7))
#define SH5PCI_CSR_CR_PCI_SPUE(v) (((v) >> 7) & 0x1)
#define SH5PCI_CSR_CR_PCI_BMAM_WR(v) (0xa5000000 | (((v) & 0x1) << 6))
#define SH5PCI_CSR_CR_PCI_BMAM(v) (((v) >> 6) & 0x1)
#define SH5PCI_CSR_CR_PCI_HOSTNS(v) (((v) >> 5) & 0x1)
#define SH5PCI_CSR_CR_PCI_CLKENS(v) (((v) >> 4) & 0x1)
#define SH5PCI_CSR_CR_PCI_SOCS_WR(v) (0xa5000000 | (((v) & 0x1) << 3))
#define SH5PCI_CSR_CR_PCI_SOCS(v) (((v) >> 3) & 0x1)
#define SH5PCI_CSR_CR_PCI_IOCS_WR(v) (0xa5000000 | (((v) & 0x1) << 2))
#define SH5PCI_CSR_CR_PCI_IOCS(v) (((v) >> 2) & 0x1)
#define SH5PCI_CSR_CR_PCI_CFINT_WR(v) (0xa5000000 | (((v) & 0x1) << 0))
#define SH5PCI_CSR_CR_PCI_CFINT(v) (((v) >> 0) & 0x1)
/*
* Bit Definitons for SH5PCI_CSR_LSR[01] PCI Local Space Register 0-1
*/
#define SH5PCI_CSR_LSR_PCI_LSR_WR(s) ((s) << 20)
#define SH5PCI_CSR_LSR_PCI_LSR_SIZE(s) (((s) | 0x000fffff) + 1)
#define SH5PCI_CSR_LSR_PCI_MBARE (1 << 0)
#define SH5PCI_MB2LSR(mb) ((mb) - 1)
/*
* Bit Definitons for SH5PCI_CSR_LAR[01] PCI Local Address Register 0-1
*/
#define SH5PCI_CSR_LAR_PCI_LAR(s,lsr) \
((s) & (0xc0000000 | ((~(lsr)) & 0x3ff00000)))
/*
* Bit Definitons for SH5PCI_CSR_INT PCI Interrupt Register
*/
#define SH5PCI_CSR_INT_PCI_TTADI (1 << 14) /* Master Tgt Abort */
#define SH5PCI_CSR_INT_PCI_TMTO (1 << 9) /* Target mem rd/wr timeout */
#define SH5PCI_CSR_INT_PCI_MDEI (1 << 8) /* Master Func. Disable Err */
#define SH5PCI_CSR_INT_PCI_APEDI (1 << 7) /* Target Addr Parity Error */
#define SH5PCI_CSR_INT_PCI_SDI (1 << 6) /* SERR Interrupt */
#define SH5PCI_CSR_INT_PCI_DPEITW (1 << 5) /* Target data wr par Err */
#define SH5PCI_CSR_INT_PCI_DEDITR (1 << 4) /* Target PERR read Err */
#define SH5PCI_CSR_INT_PCI_TADIM (1 << 3) /* Master Target Abort */
#define SH5PCI_CSR_INT_PCI_MADIM (1 << 2) /* Master Abort */
#define SH5PCI_CSR_INT_PCI_MWPDI (1 << 1) /* Master PERR write Err */
#define SH5PCI_CSR_INT_PCI_MRDPEI (1 << 0) /* Master data rd par Err */
/*
* Bit Definitons for SH5PCI_CSR_INTM PCI Interrupt Mask Register
*/
#define SH5PCI_CSR_INTM_PCI_TTADIM (1 << 14) /* Master Tgt Abort */
#define SH5PCI_CSR_INTM_PCI_TMTOM (1 << 9) /* Target mem rd/wr timeout */
#define SH5PCI_CSR_INTM_PCI_MDEIM (1 << 8) /* Master Func. Disable Err */
#define SH5PCI_CSR_INTM_PCI_APEDIM (1 << 7) /* Target Addr Parity Error */
#define SH5PCI_CSR_INTM_PCI_SDIM (1 << 6) /* SERR Interrupt */
#define SH5PCI_CSR_INTM_PCI_DPEITWM (1 << 5) /* Target data wr par Err */
#define SH5PCI_CSR_INTM_PCI_DEDITRM (1 << 4) /* Target PERR read Err */
#define SH5PCI_CSR_INTM_PCI_TADIMM (1 << 3) /* Master Target Abort */
#define SH5PCI_CSR_INTM_PCI_MADIMM (1 << 2) /* Master Abort */
#define SH5PCI_CSR_INTM_PCI_MWPDIM (1 << 1) /* Master PERR write Err */
#define SH5PCI_CSR_INTM_PCI_MRDPEIM (1 << 0) /* Master data rd par Err */
/*
* Bit Definitons for SH5PCI_CSR_CIR PCI Error Comand Info Register
*/
#define SH5PCI_CSR_CIR_PCI_PIOTEM (1 << 31) /* Master mem/io Xfer Error */
#define SH5PCI_CSR_CIR_PCI_RWTET (1 << 26) /* Target rd/wr Xfer Error */
#define SH5PCI_CSR_CIR_PCI_ECR(v) ((v)&0xf) /* Error Command Register */
/*
* Bit Definitons for SH5PCI_CSR_AINT PCI Arbiter Interrupt Register
*/
#define SH5PCI_CSR_AINT_PCI_MBI (1 << 13) /* Master Broken */
#define SH5PCI_CSR_AINT_PCI_TBTOI (1 << 12) /* Target Bus Timeout */
#define SH5PCI_CSR_AINT_PCI_MBTOI (1 << 11) /* Master Bus Timeout */
#define SH5PCI_CSR_AINT_PCI_TAI (1 << 3) /* Target Abort */
#define SH5PCI_CSR_AINT_PCI_MAI (1 << 2) /* Master Abort */
#define SH5PCI_CSR_AINT_PCI_RDPEI (1 << 1) /* Read Data Parity Error */
#define SH5PCI_CSR_AINT_PCI_WDPEI (1 << 0) /* Write Data Parity Error */
/*
* Bit Definitons for SH5PCI_CSR_AINTM PCI Arbiter Interrupt Mask Register
*/
#define SH5PCI_CSR_AINTM_PCI_MBIM (1 << 13) /* Master Broken */
#define SH5PCI_CSR_AINTM_PCI_TBTOIM (1 << 12) /* Target Bus Timeout */
#define SH5PCI_CSR_AINTM_PCI_MBTOIM (1 << 11) /* Master Bus Timeout */
#define SH5PCI_CSR_AINTM_PCI_TAIM (1 << 3) /* Target Abort */
#define SH5PCI_CSR_AINTM_PCI_MAIM (1 << 2) /* Master Abort */
#define SH5PCI_CSR_AINTM_PCI_RDPEIM (1 << 1) /* Read Data Parity Error */
#define SH5PCI_CSR_AINTM_PCI_WDPEIM (1 << 0) /* Write Data Parity Error */
/*
* Bit Definitons for SH5PCI_CSR_BMIR PCI Arbiter Bus Master Info Register
*/
#define SH5PCI_CSR_BMIR_PCI_REQBME(n) (1 << (n))
/*
* Bit Definitons for SH5PCI_CSR_PAR PCI PIO Address Register
*/
#define SH5PCI_CSR_PAR_PCI_CCIE (1 << 31)
#define SH5PCI_CSR_PAR_PCI_BN(v) (((v) >> 16) & 0xff)
#define SH5PCI_CSR_PAR_PCI_DN(v) (((v) >> 11) & 0x1f)
#define SH5PCI_CSR_PAR_PCI_FN(v) (((v) >> 8) & 0x07)
#define SH5PCI_CSR_PAR_PCI_CRA(v) ((v) & 0x0xff)
#define SH5PCI_CSR_PAR_MAKE(b,d,f,r) \
((((b)&0xff)<<16)|(((d)&0x1f)<<11)|(((f)&0x7)<<8)|((d)&0xfc))
/*
* Bit Definitons for SH5PCI_CSR_MBR PCI Memory Space Bank Register
* and SH5PCI_CSR_IOBR PCI I/O Space Bank Register
*/
#define SH5PCI_CSR_BR_PCI_PSBA(a) ((a) & 0xfffc0000)
/*
* Bit Definitons for SH5PCI_CSR_MBMR PCI Memory Space Bank Mask Register
*/
#define SH5PCI_CSR_MBMR_PCI_MSBAMR(s) ((s) << 18)
#define SH5PCI_KB2MSBAMR(kb) (((kb)==256)?0:1)
#define SH5PCI_MB2MSBAMR(mb) ((((mb) - 1) << 2) | 0x3)
/*
* Bit Definitons for SH5PCI_CSR_IOBMR PCI I/O Space Bank Mask Register
*/
#define SH5PCI_CSR_IOBMR_PCI_IOBAMR(s) ((s) << 18)
#define SH5PCI_KB2IOBAMR(kb) (((kb)==256)?0:1)
#define SH5PCI_MB2IOBAMR(mb) ((((mb) - 1) << 2) | 0x3)
/*
* Bit Definitons for SH5PCI_CSR_CSCR[01] PCI Cache Snoop Control Registers
*/
#define SH5PCI_CSR_CSCR_SNPMD_DISABLED 0
#define SH5PCI_CSR_CSCR_SNPMD_ISSUE_MISS 2
#define SH5PCI_CSR_CSCR_SNPMD_ISSUE_HIT 3
#define SH5PCI_CSR_CSCR_RANGE_4KB (0 << 2)
#define SH5PCI_CSR_CSCR_RANGE_64KB (1 << 2)
#define SH5PCI_CSR_CSCR_RANGE_1MB (2 << 2)
#define SH5PCI_CSR_CSCR_RANGE_16MB (3 << 2)
#define SH5PCI_CSR_CSCR_RANGE_32MB (4 << 2)
#define SH5PCI_CSR_CSCR_RANGE_64MB (5 << 2)
#define SH5PCI_CSR_CSCR_RANGE_128MB (6 << 2)
#define SH5PCI_CSR_CSCR_RANGE_256MB (7 << 2)
#endif /* _SH5_PCIREG_H */

View File

@ -0,0 +1,77 @@
/* $NetBSD: sh5_pcivar.h,v 1.1 2002/09/28 11:16:37 scw Exp $ */
/*
* Copyright 2002 Wasabi Systems, Inc.
* All rights reserved.
*
* Written by Steve C. Woodford for Wasabi Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the NetBSD Project by
* Wasabi Systems, Inc.
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
* or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _SH5_PCIVAR_H
#define _SH5_PCIVAR_H
#define SH5PCI_IH_LINE(ih) ((ih) & 0xff)
#define SH5PCI_IH_PIN(ih) (((ih) >> 8) & 0xff)
#define SH5PCI_IH_COOKIE(ih) (((ih) >> 16) & 0xffff)
#define SH5PCI_IH_CREATE(l,p,c) \
((pci_intr_handle_t)(((l) & 0xff) | \
(((p) & 0xff) << 8) | \
(((c) & 0xffff) << 16)))
struct sh5pci_icookie;
SLIST_HEAD(sh5pci_ilist, sh5pci_icookie);
struct sh5pci_ihead {
struct sh5pci_ilist ih_handlers;
void *ih_cookie;
struct evcnt *ih_evcnt;
int ih_level;
int ih_intevt;
};
struct sh5pci_intr_hooks {
const char *ih_name;
void * (*ih_init)(struct sh5_pci_chipset_tag *,
void **, int (*)(void *), void *,
void **, int (*)(void *), void *);
void (*ih_intr_conf)(void *, int, int, int, int, int *);
int (*ih_intr_map)(void *, struct pci_attach_args *,
pci_intr_handle_t *);
struct sh5pci_ihead * (*ih_intr_ihead)(void *, pci_intr_handle_t);
void * (*ih_intr_establish)(void *, pci_intr_handle_t, int,
int (*)(void *), void *);
void (*ih_intr_disestablish)(void *, pci_intr_handle_t, void *);
};
extern const struct sh5pci_intr_hooks *
sh5pci_get_intr_hooks(struct sh5_pci_chipset_tag *);
#endif /* _SH5_PCIVAR_H */