Merge WIP from p4:
o recognize ixp435 cpu o change memory layout for for ixp4xx to not assume memory is aliases to 0x10000000 (Cambria/ixp435 memory starts at zero) o handle 64 irqs for ixp435 o dual EHCI USB 2.0 controller integral to ixp435 o overhaul NPE code for ixp435 and better MAC+MII naming o updated NPE firmware (including NPE-A image for ixp435/ixp465) o Gateworks Cambria board support: - IDE compact flash - MCU - front panel LED on i2c bus - Octal LED latch Sanity-tested with NFS-root on Avila and Cambria boards. Requires pending boot2 mods for CF-boot on Cambria.
This commit is contained in:
parent
366eaf1e2d
commit
d212022417
sys
arm
arm
conf
include
xscale/ixp425
conf
contrib/dev/npe
dev/usb
@ -1211,7 +1211,7 @@ set_cpufuncs()
|
||||
#endif /* CPU_XSCALE_PXA2X0 */
|
||||
#ifdef CPU_XSCALE_IXP425
|
||||
if (cputype == CPU_ID_IXP425_533 || cputype == CPU_ID_IXP425_400 ||
|
||||
cputype == CPU_ID_IXP425_266) {
|
||||
cputype == CPU_ID_IXP425_266 || cputype == CPU_ID_IXP435) {
|
||||
|
||||
cpufuncs = xscale_cpufuncs;
|
||||
#if defined(PERFCTRS)
|
||||
|
@ -300,6 +300,10 @@ const struct cpuidtab cpuids[] = {
|
||||
{ CPU_ID_IXP425_266, CPU_CLASS_XSCALE, "IXP425 266MHz",
|
||||
ixp425_steppings },
|
||||
|
||||
/* XXX ixp435 steppings? */
|
||||
{ CPU_ID_IXP435, CPU_CLASS_XSCALE, "IXP435",
|
||||
ixp425_steppings },
|
||||
|
||||
{ CPU_ID_ARM1136JS, CPU_CLASS_ARM11J, "ARM1136J-S",
|
||||
generic_steppings },
|
||||
{ CPU_ID_ARM1136JSR1, CPU_CLASS_ARM11J, "ARM1136J-S R1",
|
||||
|
@ -20,20 +20,18 @@
|
||||
|
||||
ident AVILA
|
||||
|
||||
options PHYSADDR=0x10000000
|
||||
options KERNPHYSADDR=0x10200000
|
||||
options KERNVIRTADDR=0xc0200000 # Used in ldscript.arm
|
||||
options FLASHADDR=0x50000000
|
||||
options LOADERRAMADDR=0x00000000
|
||||
options STARTUP_PAGETABLE_ADDR=0x10000000
|
||||
|
||||
include "../xscale/ixp425/std.ixp425"
|
||||
# NB: memory mapping is defined in std.avila
|
||||
include "../xscale/ixp425/std.avila"
|
||||
options XSCALE_CACHE_READ_WRITE_ALLOCATE
|
||||
#options ARM_USE_SMALL_ALLOC
|
||||
#To statically compile in device wiring instead of /boot/device.hints
|
||||
hints "AVILA.hints" #Default places to look for devices.
|
||||
makeoptions MODULES_OVERRIDE=""
|
||||
|
||||
makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols
|
||||
makeoptions CONF_CFLAGS=-mcpu=xscale
|
||||
makeoptions MODULES_OVERRIDE=""
|
||||
#options HZ=1000
|
||||
options HZ=100
|
||||
options DEVICE_POLLING
|
||||
@ -42,34 +40,18 @@ options DEVICE_POLLING
|
||||
options KDB
|
||||
#options GDB
|
||||
options DDB #Enable the kernel debugger
|
||||
#options INVARIANTS #Enable calls of extra sanity checking
|
||||
#options INVARIANT_SUPPORT #Extra sanity checks of internal structures, required by INVARIANTS
|
||||
options INVARIANTS #Enable calls of extra sanity checking
|
||||
options INVARIANT_SUPPORT #Extra sanity checks of internal structures, required by INVARIANTS
|
||||
#options WITNESS #Enable checks to detect deadlocks and cycles
|
||||
#options WITNESS_SKIPSPIN #Don't run witness on spinlocks for speed
|
||||
#options DIAGNOSTIC
|
||||
|
||||
options SCHED_4BSD #4BSD scheduler
|
||||
options INET #InterNETworking
|
||||
options INET6 #IPv6 communications protocols
|
||||
options FFS #Berkeley Fast Filesystem
|
||||
options SOFTUPDATES #Enable FFS soft updates support
|
||||
options UFS_ACL #Support for access control lists
|
||||
options UFS_DIRHASH #Improve performance on big directories
|
||||
options NFSCLIENT #Network Filesystem Client
|
||||
options NFSSERVER #Network Filesystem Server
|
||||
options NFSLOCKD #Network Lock Manager
|
||||
options NFS_ROOT #NFS usable as /, requires NFSCLIENT
|
||||
#options MSDOSFS #MSDOS Filesystem
|
||||
options CD9660 #ISO 9660 Filesystem
|
||||
#options PROCFS #Process filesystem (requires PSEUDOFS)
|
||||
options PSEUDOFS #Pseudo-filesystem framework
|
||||
options SCSI_DELAY=5000 #Delay (in ms) before probing SCSI
|
||||
options KTRACE #ktrace(1) support
|
||||
options SYSVSHM #SYSV-style shared memory
|
||||
options SYSVMSG #SYSV-style message queues
|
||||
options SYSVSEM #SYSV-style semaphores
|
||||
options _KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions
|
||||
options KBD_INSTALL_CDEV # install a CDEV entry in /dev
|
||||
options BOOTP
|
||||
options BOOTP_NFSROOT
|
||||
options BOOTP_NFSV3
|
||||
@ -106,7 +88,6 @@ device npe_fw
|
||||
device firmware
|
||||
device qmgr # Q Manager (required by npe)
|
||||
device miibus # NB: required by npe
|
||||
device rl # RealTek 8129/8139
|
||||
device ether
|
||||
device bpf
|
||||
|
||||
@ -114,37 +95,48 @@ device pty
|
||||
device loop
|
||||
device if_bridge
|
||||
|
||||
options XSCALE_CACHE_READ_WRITE_ALLOCATE
|
||||
device md
|
||||
device random # Entropy device
|
||||
|
||||
#options ARM_USE_SMALL_ALLOC
|
||||
|
||||
# Wireless NIC cards
|
||||
device wlan # 802.11 support
|
||||
options IEEE80211_DEBUG
|
||||
device wlan_wep # 802.11 WEP support
|
||||
device wlan_ccmp # 802.11 CCMP support
|
||||
device wlan_tkip # 802.11 TKIP support
|
||||
device wlan_xauth
|
||||
device ath # Atheros pci/cardbus NIC's
|
||||
device ath_hal # Atheros HAL (Hardware Access Layer)
|
||||
options AH_SUPPORT_AR5416 # enable AR5416 tx/rx descriptors
|
||||
device ath_rate_sample # SampleRate tx rate control for ath
|
||||
options ATH_DEBUG
|
||||
|
||||
#device crypto
|
||||
#device cryptodev
|
||||
#device hifn # NB: Soekris minipci card known to work
|
||||
device ath # Atheros pci/cardbus NIC's
|
||||
options ATH_DEBUG
|
||||
options ATH_DIAGAPI
|
||||
#options ATH_TX99_DIAG
|
||||
device ath_rate_sample # SampleRate tx rate control for ath
|
||||
|
||||
#options AH_DEBUG
|
||||
#options AH_ASSERT
|
||||
#device ath_ar5210
|
||||
#device ath_ar5211
|
||||
device ath_ar5212
|
||||
device ath_rf2413
|
||||
device ath_rf2417
|
||||
device ath_rf2425
|
||||
device ath_rf5111
|
||||
device ath_rf5112
|
||||
device ath_rf5413
|
||||
#
|
||||
device ath_ar5416
|
||||
options AH_SUPPORT_AR5416
|
||||
device ath_ar9160
|
||||
|
||||
device usb
|
||||
options USB_DEBUG
|
||||
#options USB_DEBUG
|
||||
device ohci
|
||||
device ehci
|
||||
device ugen
|
||||
device umass
|
||||
device scbus # SCSI bus (required for SCSI)
|
||||
device da # Direct Access (disks)
|
||||
#device umass
|
||||
#device scbus # SCSI bus (required for SCSI)
|
||||
#device da # Direct Access (disks)
|
||||
|
||||
device ural
|
||||
device zyd
|
||||
device wlan_amrr
|
||||
#device ural
|
||||
#device zyd
|
||||
#device wlan_amrr
|
||||
|
@ -17,21 +17,22 @@ hint.uart.1.irq=13
|
||||
# NPE Hardware Queue Manager
|
||||
hint.ixpqmgr.0.at="ixp0"
|
||||
|
||||
# NPE wireless NIC's, requires ixpqmgr
|
||||
# NPE wired NIC's, requires ixpqmgr
|
||||
hint.npe.0.at="ixp0"
|
||||
hint.npe.0.mac="A"
|
||||
hint.npe.0.mii="A"
|
||||
hint.npe.0.npeid="B"
|
||||
hint.npe.0.mac="B"
|
||||
hint.npe.0.mii="B"
|
||||
hint.npe.0.phy=0
|
||||
hint.npe.1.at="ixp0"
|
||||
hint.npe.1.mac="B"
|
||||
# NB: on 2348 boards all PHY's are addressed through MAC A
|
||||
hint.npe.1.mii="A"
|
||||
hint.npe.1.npeid="C"
|
||||
hint.npe.1.mac="C"
|
||||
hint.npe.1.mii="B"
|
||||
hint.npe.1.phy=1
|
||||
|
||||
# CF IDE controller
|
||||
hint.ata_avila.0.at="ixp0"
|
||||
|
||||
# LED connected to gpio
|
||||
# Front Panel LED
|
||||
hint.led_avila.0.at="ixp0"
|
||||
|
||||
# Analog Devices AD7418 temperature sensor
|
||||
|
@ -174,6 +174,7 @@
|
||||
#define CPU_ID_IXP425_533 0x690541c0
|
||||
#define CPU_ID_IXP425_400 0x690541d0
|
||||
#define CPU_ID_IXP425_266 0x690541f0
|
||||
#define CPU_ID_IXP435 0x69054040
|
||||
|
||||
/* ARM3-specific coprocessor 15 registers */
|
||||
#define ARM3_CP15_FLUSH 1
|
||||
|
@ -39,6 +39,7 @@
|
||||
#ifndef _MACHINE_INTR_H_
|
||||
#define _MACHINE_INTR_H_
|
||||
|
||||
/* XXX move to std.* files? */
|
||||
#ifdef CPU_XSCALE_81342
|
||||
#define NIRQ 128
|
||||
#elif defined(CPU_XSCALE_PXA2X0)
|
||||
@ -46,7 +47,8 @@
|
||||
#define NIRQ IRQ_GPIO_MAX
|
||||
#elif defined(SOC_MV_DISCOVERY)
|
||||
#define NIRQ 96
|
||||
#elif defined(CPU_ARM9) || defined(SOC_MV_KIRKWOOD)
|
||||
#elif defined(CPU_ARM9) || defined(SOC_MV_KIRKWOOD) || \
|
||||
defined(CPU_XSCALE_IXP435)
|
||||
#define NIRQ 64
|
||||
#else
|
||||
#define NIRQ 32
|
||||
|
@ -67,13 +67,64 @@ __FBSDID("$FreeBSD$");
|
||||
#include <dev/ata/ata-all.h>
|
||||
#include <ata_if.h>
|
||||
|
||||
#define AVILA_IDE_GPIN 12 /* GPIO pin # */
|
||||
#define AVILA_IDE_IRQ IXP425_INT_GPIO_12
|
||||
#define AVILA_IDE_CTRL 0x06 /* control register */
|
||||
#define AVILA_IDE_CTRL 0x06
|
||||
|
||||
#define PRONGHORN_IDE_GPIN 0 /* GPIO pin # */
|
||||
#define PRONGHORN_IDE_IRQ IXP425_INT_GPIO_0
|
||||
#define PRONGHORN_IDE_CNTRL 0x06 /* control register */
|
||||
struct ata_config {
|
||||
const char *desc; /* description for probe */
|
||||
uint8_t gpin; /* GPIO pin */
|
||||
uint8_t irq; /* IRQ */
|
||||
uint32_t base16; /* CS base addr for 16-bit */
|
||||
uint32_t size16; /* CS size for 16-bit */
|
||||
uint32_t off16; /* CS offset for 16-bit */
|
||||
uint32_t basealt; /* CS base addr for alt */
|
||||
uint32_t sizealt; /* CS size for alt */
|
||||
uint32_t offalt; /* CS offset for alt */
|
||||
};
|
||||
|
||||
static const struct ata_config *
|
||||
ata_getconfig(struct ixp425_softc *sa)
|
||||
{
|
||||
static const struct ata_config configs[] = {
|
||||
{ .desc = "Gateworks Avila IDE/CF Controller",
|
||||
.gpin = 12,
|
||||
.irq = IXP425_INT_GPIO_12,
|
||||
.base16 = IXP425_EXP_BUS_CS1_HWBASE,
|
||||
.size16 = IXP425_EXP_BUS_CS1_SIZE,
|
||||
.off16 = EXP_TIMING_CS1_OFFSET,
|
||||
.basealt = IXP425_EXP_BUS_CS2_HWBASE,
|
||||
.sizealt = IXP425_EXP_BUS_CS2_SIZE,
|
||||
.offalt = EXP_TIMING_CS2_OFFSET,
|
||||
},
|
||||
{ .desc = "Gateworks Cambria IDE/CF Controller",
|
||||
.gpin = 12,
|
||||
.irq = IXP425_INT_GPIO_12,
|
||||
.base16 = CAMBRIA_CFSEL0_HWBASE,
|
||||
.size16 = CAMBRIA_CFSEL0_SIZE,
|
||||
.off16 = EXP_TIMING_CS3_OFFSET,
|
||||
.basealt = CAMBRIA_CFSEL1_HWBASE,
|
||||
.sizealt = CAMBRIA_CFSEL1_SIZE,
|
||||
.offalt = EXP_TIMING_CS4_OFFSET,
|
||||
},
|
||||
{ .desc = "ADI Pronghorn Metro IDE/CF Controller",
|
||||
.gpin = 0,
|
||||
.irq = IXP425_INT_GPIO_0,
|
||||
.base16 = IXP425_EXP_BUS_CS3_HWBASE,
|
||||
.size16 = IXP425_EXP_BUS_CS3_SIZE,
|
||||
.off16 = EXP_TIMING_CS3_OFFSET,
|
||||
.basealt = IXP425_EXP_BUS_CS4_HWBASE,
|
||||
.sizealt = IXP425_EXP_BUS_CS4_SIZE,
|
||||
.offalt = EXP_TIMING_CS4_OFFSET,
|
||||
},
|
||||
};
|
||||
|
||||
/* XXX honor hint? (but then no multi-board support) */
|
||||
/* XXX total hack */
|
||||
if ((cpu_id() & CPU_ID_CPU_MASK) == CPU_ID_IXP435)
|
||||
return &configs[1]; /* Cambria */
|
||||
if (EXP_BUS_READ_4(sa, EXP_TIMING_CS2_OFFSET) != 0)
|
||||
return &configs[0]; /* Avila */
|
||||
return &configs[2]; /* Pronghorn */
|
||||
}
|
||||
|
||||
struct ata_avila_softc {
|
||||
device_t sc_dev;
|
||||
@ -105,14 +156,14 @@ static int
|
||||
ata_avila_probe(device_t dev)
|
||||
{
|
||||
struct ixp425_softc *sa = device_get_softc(device_get_parent(dev));
|
||||
const struct ata_config *config;
|
||||
|
||||
/* XXX any way to check? */
|
||||
if (EXP_BUS_READ_4(sa, EXP_TIMING_CS2_OFFSET) != 0)
|
||||
device_set_desc_copy(dev, "Gateworks Avila IDE/CF Controller");
|
||||
else
|
||||
device_set_desc_copy(dev,
|
||||
"ADI Pronghorn Metro IDE/CF Controller");
|
||||
return 0;
|
||||
config = ata_getconfig(sa);
|
||||
if (config != NULL) {
|
||||
device_set_desc_copy(dev, config->desc);
|
||||
return 0;
|
||||
}
|
||||
return ENXIO;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -120,41 +171,25 @@ ata_avila_attach(device_t dev)
|
||||
{
|
||||
struct ata_avila_softc *sc = device_get_softc(dev);
|
||||
struct ixp425_softc *sa = device_get_softc(device_get_parent(dev));
|
||||
u_int32_t alt_t_off, ide_gpin, ide_irq;
|
||||
const struct ata_config *config;
|
||||
|
||||
config = ata_getconfig(sa);
|
||||
KASSERT(config != NULL, ("no board config"));
|
||||
|
||||
sc->sc_dev = dev;
|
||||
/* NB: borrow from parent */
|
||||
sc->sc_iot = sa->sc_iot;
|
||||
sc->sc_exp_ioh = sa->sc_exp_ioh;
|
||||
if (EXP_BUS_READ_4(sc, EXP_TIMING_CS2_OFFSET) != 0) {
|
||||
/* Avila board */
|
||||
if (bus_space_map(sc->sc_iot, IXP425_EXP_BUS_CS1_HWBASE,
|
||||
IXP425_EXP_BUS_CS1_SIZE, 0, &sc->sc_ioh))
|
||||
panic("%s: unable to map Expansion Bus CS1 window",
|
||||
__func__);
|
||||
if (bus_space_map(sc->sc_iot, IXP425_EXP_BUS_CS2_HWBASE,
|
||||
IXP425_EXP_BUS_CS2_SIZE, 0, &sc->sc_alt_ioh))
|
||||
panic("%s: unable to map Expansion Bus CS2 window",
|
||||
__func__);
|
||||
ide_gpin = AVILA_IDE_GPIN;
|
||||
ide_irq = AVILA_IDE_IRQ;
|
||||
sc->sc_16bit_off = EXP_TIMING_CS1_OFFSET;
|
||||
alt_t_off = EXP_TIMING_CS2_OFFSET;
|
||||
} else {
|
||||
/* Pronghorn */
|
||||
if (bus_space_map(sc->sc_iot, IXP425_EXP_BUS_CS3_HWBASE,
|
||||
IXP425_EXP_BUS_CS3_SIZE, 0, &sc->sc_ioh))
|
||||
panic("%s: unable to map Expansion Bus CS3 window",
|
||||
__func__);
|
||||
if (bus_space_map(sc->sc_iot, IXP425_EXP_BUS_CS4_HWBASE,
|
||||
IXP425_EXP_BUS_CS4_SIZE, 0, &sc->sc_alt_ioh))
|
||||
panic("%s: unable to map Expansion Bus CS4 window",
|
||||
__func__);
|
||||
ide_gpin = PRONGHORN_IDE_GPIN;
|
||||
ide_irq = PRONGHORN_IDE_IRQ;
|
||||
sc->sc_16bit_off = EXP_TIMING_CS3_OFFSET;
|
||||
alt_t_off = EXP_TIMING_CS4_OFFSET;
|
||||
}
|
||||
|
||||
if (bus_space_map(sc->sc_iot, config->base16, config->size16,
|
||||
0, &sc->sc_ioh))
|
||||
panic("%s: cannot map 16-bit window (0x%x/0x%x)",
|
||||
__func__, config->base16, config->size16);
|
||||
if (bus_space_map(sc->sc_iot, config->basealt, config->sizealt,
|
||||
0, &sc->sc_alt_ioh))
|
||||
panic("%s: cannot map alt window (0x%x/0x%x)",
|
||||
__func__, config->basealt, config->sizealt);
|
||||
sc->sc_16bit_off = config->off16;
|
||||
|
||||
/*
|
||||
* Craft special resource for ATA bus space ops
|
||||
@ -184,30 +219,30 @@ ata_avila_attach(device_t dev)
|
||||
rman_set_bushandle(&sc->sc_alt_ata, sc->sc_alt_ioh);
|
||||
|
||||
GPIO_CONF_WRITE_4(sa, IXP425_GPIO_GPOER,
|
||||
GPIO_CONF_READ_4(sa, IXP425_GPIO_GPOER) | (1<<ide_gpin));
|
||||
GPIO_CONF_READ_4(sa, IXP425_GPIO_GPOER) | (1<<config->gpin));
|
||||
/* set interrupt type */
|
||||
GPIO_CONF_WRITE_4(sa, GPIO_TYPE_REG(ide_gpin),
|
||||
(GPIO_CONF_READ_4(sa, GPIO_TYPE_REG(ide_gpin)) &~
|
||||
GPIO_TYPE(ide_gpin, GPIO_TYPE_MASK)) |
|
||||
GPIO_TYPE(ide_gpin, GPIO_TYPE_EDG_RISING));
|
||||
GPIO_CONF_WRITE_4(sa, GPIO_TYPE_REG(config->gpin),
|
||||
(GPIO_CONF_READ_4(sa, GPIO_TYPE_REG(config->gpin)) &~
|
||||
GPIO_TYPE(config->gpin, GPIO_TYPE_MASK)) |
|
||||
GPIO_TYPE(config->gpin, GPIO_TYPE_EDG_RISING));
|
||||
|
||||
/* clear ISR */
|
||||
GPIO_CONF_WRITE_4(sa, IXP425_GPIO_GPISR, (1<<ide_gpin));
|
||||
GPIO_CONF_WRITE_4(sa, IXP425_GPIO_GPISR, (1<<config->gpin));
|
||||
|
||||
/* configure CS1/3 window, leaving timing unchanged */
|
||||
EXP_BUS_WRITE_4(sc, sc->sc_16bit_off,
|
||||
EXP_BUS_READ_4(sc, sc->sc_16bit_off) |
|
||||
EXP_BYTE_EN | EXP_WR_EN | EXP_BYTE_RD16 | EXP_CS_EN);
|
||||
/* configure CS2/4 window, leaving timing unchanged */
|
||||
EXP_BUS_WRITE_4(sc, alt_t_off,
|
||||
EXP_BUS_READ_4(sc, alt_t_off) |
|
||||
EXP_BUS_WRITE_4(sc, config->offalt,
|
||||
EXP_BUS_READ_4(sc, config->offalt) |
|
||||
EXP_BYTE_EN | EXP_WR_EN | EXP_BYTE_RD16 | EXP_CS_EN);
|
||||
|
||||
/* setup interrupt */
|
||||
sc->sc_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->sc_rid,
|
||||
ide_irq, ide_irq, 1, RF_ACTIVE);
|
||||
config->irq, config->irq, 1, RF_ACTIVE);
|
||||
if (!sc->sc_irq)
|
||||
panic("Unable to allocate irq %u.\n", ide_irq);
|
||||
panic("Unable to allocate irq %u.\n", config->irq);
|
||||
bus_setup_intr(dev, sc->sc_irq,
|
||||
INTR_TYPE_BIO | INTR_MPSAFE | INTR_ENTROPY,
|
||||
NULL, ata_avila_intr, sc, &sc->sc_ih);
|
||||
@ -230,9 +265,9 @@ ata_avila_detach(device_t dev)
|
||||
|
||||
/* detach & delete all children */
|
||||
if (device_get_children(dev, &children, &nc) == 0) {
|
||||
if (nc > 0)
|
||||
device_delete_child(dev, children[0]);
|
||||
free(children, M_TEMP);
|
||||
if (nc > 0)
|
||||
device_delete_child(dev, children[0]);
|
||||
free(children, M_TEMP);
|
||||
}
|
||||
|
||||
bus_teardown_intr(dev, sc->sc_irq, sc->sc_ih);
|
||||
@ -308,7 +343,7 @@ ata_avila_teardown_intr(device_t dev, device_t child, struct resource *irq,
|
||||
/*
|
||||
* Enable/disable 16-bit ops on the expansion bus.
|
||||
*/
|
||||
static void __inline
|
||||
static __inline void
|
||||
enable_16(struct ata_avila_softc *sc)
|
||||
{
|
||||
EXP_BUS_WRITE_4(sc, sc->sc_16bit_off,
|
||||
@ -316,7 +351,7 @@ enable_16(struct ata_avila_softc *sc)
|
||||
DELAY(100); /* XXX? */
|
||||
}
|
||||
|
||||
static void __inline
|
||||
static __inline void
|
||||
disable_16(struct ata_avila_softc *sc)
|
||||
{
|
||||
DELAY(100); /* XXX? */
|
||||
|
@ -37,22 +37,19 @@ __FBSDID("$FreeBSD$");
|
||||
#include <dev/led/led.h>
|
||||
|
||||
#define GPIO_LED_STATUS 3
|
||||
#define GPIO_LED_STATUS_BIT (1U << GPIO_LED_STATUS)
|
||||
|
||||
static struct cdev *gpioled;
|
||||
#define GPIO_LED_STATUS_BIT (1U << GPIO_LED_STATUS)
|
||||
|
||||
struct led_avila_softc {
|
||||
device_t sc_dev;
|
||||
bus_space_tag_t sc_iot;
|
||||
bus_space_handle_t sc_gpio_ioh;
|
||||
struct cdev *sc_led;
|
||||
};
|
||||
|
||||
static struct led_avila_softc *led_avila_sc = NULL;
|
||||
|
||||
static void
|
||||
led_func(void *unused, int onoff)
|
||||
led_func(void *arg, int onoff)
|
||||
{
|
||||
struct led_avila_softc *sc = led_avila_sc;
|
||||
struct led_avila_softc *sc = arg;
|
||||
uint32_t reg;
|
||||
|
||||
reg = GPIO_CONF_READ_4(sc, IXP425_GPIO_GPOUTR);
|
||||
@ -66,7 +63,7 @@ led_func(void *unused, int onoff)
|
||||
static int
|
||||
led_avila_probe(device_t dev)
|
||||
{
|
||||
device_set_desc(dev, "Gateworks Avila GPIO connected LED");
|
||||
device_set_desc(dev, "Gateworks Avila Front Panel LED");
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -75,31 +72,35 @@ led_avila_attach(device_t dev)
|
||||
{
|
||||
struct led_avila_softc *sc = device_get_softc(dev);
|
||||
struct ixp425_softc *sa = device_get_softc(device_get_parent(dev));
|
||||
void *led = NULL;
|
||||
uint32_t reg;
|
||||
|
||||
led_avila_sc = sc;
|
||||
|
||||
sc->sc_dev = dev;
|
||||
sc->sc_iot = sa->sc_iot;
|
||||
sc->sc_gpio_ioh = sa->sc_gpio_ioh;
|
||||
|
||||
/* Configure LED GPIO pin as output */
|
||||
reg = GPIO_CONF_READ_4(sc, IXP425_GPIO_GPOER);
|
||||
reg &= ~GPIO_LED_STATUS_BIT;
|
||||
GPIO_CONF_WRITE_4(sc, IXP425_GPIO_GPOER, reg);
|
||||
GPIO_CONF_WRITE_4(sc, IXP425_GPIO_GPOER,
|
||||
GPIO_CONF_READ_4(sc, IXP425_GPIO_GPOER) &~ GPIO_LED_STATUS_BIT);
|
||||
|
||||
gpioled = led_create(led_func, led, "gpioled");
|
||||
sc->sc_led = led_create(led_func, sc, "gpioled");
|
||||
|
||||
/* Turn on LED */
|
||||
led_func(led, 1);
|
||||
led_func(sc, 1); /* Turn on LED */
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
led_avila_detach(device_t dev)
|
||||
{
|
||||
struct led_avila_softc *sc = device_get_softc(dev);
|
||||
|
||||
if (sc->sc_led != NULL)
|
||||
led_destroy(sc->sc_led);
|
||||
}
|
||||
|
||||
static device_method_t led_avila_methods[] = {
|
||||
DEVMETHOD(device_probe, led_avila_probe),
|
||||
DEVMETHOD(device_attach, led_avila_attach),
|
||||
DEVMETHOD(device_detach, led_avila_detach),
|
||||
|
||||
{0, 0},
|
||||
};
|
||||
|
@ -95,6 +95,11 @@ __FBSDID("$FreeBSD$");
|
||||
#include <arm/xscale/ixp425/ixp425reg.h>
|
||||
#include <arm/xscale/ixp425/ixp425var.h>
|
||||
|
||||
/* kernel text starts where we were loaded at boot */
|
||||
#define KERNEL_TEXT_OFF (KERNPHYSADDR - PHYSADDR)
|
||||
#define KERNEL_TEXT_BASE (KERNBASE + KERNEL_TEXT_OFF)
|
||||
#define KERNEL_TEXT_PHYS (PHYSADDR + KERNEL_TEXT_OFF)
|
||||
|
||||
#define KERNEL_PT_SYS 0 /* Page table for mapping proc0 zero page */
|
||||
#define KERNEL_PT_IO 1
|
||||
#define KERNEL_PT_IO_NUM 3
|
||||
@ -142,114 +147,109 @@ static struct trapframe proc0_tf;
|
||||
/* Static device mappings. */
|
||||
static const struct pmap_devmap ixp425_devmap[] = {
|
||||
/* Physical/Virtual address for I/O space */
|
||||
{
|
||||
IXP425_IO_VBASE,
|
||||
IXP425_IO_HWBASE,
|
||||
IXP425_IO_SIZE,
|
||||
VM_PROT_READ|VM_PROT_WRITE,
|
||||
PTE_NOCACHE,
|
||||
},
|
||||
{ IXP425_IO_VBASE, IXP425_IO_HWBASE, IXP425_IO_SIZE,
|
||||
VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, },
|
||||
|
||||
/* Expansion Bus */
|
||||
{
|
||||
IXP425_EXP_VBASE,
|
||||
IXP425_EXP_HWBASE,
|
||||
IXP425_EXP_SIZE,
|
||||
VM_PROT_READ|VM_PROT_WRITE,
|
||||
PTE_NOCACHE,
|
||||
},
|
||||
{ IXP425_EXP_VBASE, IXP425_EXP_HWBASE, IXP425_EXP_SIZE,
|
||||
VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, },
|
||||
|
||||
/* IXP425 PCI Configuration */
|
||||
{
|
||||
IXP425_PCI_VBASE,
|
||||
IXP425_PCI_HWBASE,
|
||||
IXP425_PCI_SIZE,
|
||||
VM_PROT_READ|VM_PROT_WRITE,
|
||||
PTE_NOCACHE,
|
||||
},
|
||||
{ IXP425_PCI_VBASE, IXP425_PCI_HWBASE, IXP425_PCI_SIZE,
|
||||
VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, },
|
||||
|
||||
/* SDRAM Controller */
|
||||
{
|
||||
IXP425_MCU_VBASE,
|
||||
IXP425_MCU_HWBASE,
|
||||
IXP425_MCU_SIZE,
|
||||
VM_PROT_READ|VM_PROT_WRITE,
|
||||
PTE_NOCACHE,
|
||||
},
|
||||
{ IXP425_MCU_VBASE, IXP425_MCU_HWBASE, IXP425_MCU_SIZE,
|
||||
VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, },
|
||||
|
||||
/* PCI Memory Space */
|
||||
{
|
||||
IXP425_PCI_MEM_VBASE,
|
||||
IXP425_PCI_MEM_HWBASE,
|
||||
IXP425_PCI_MEM_SIZE,
|
||||
VM_PROT_READ|VM_PROT_WRITE,
|
||||
PTE_NOCACHE,
|
||||
},
|
||||
/* NPE-A Memory Space */
|
||||
{
|
||||
IXP425_NPE_A_VBASE,
|
||||
IXP425_NPE_A_HWBASE,
|
||||
IXP425_NPE_A_SIZE,
|
||||
VM_PROT_READ|VM_PROT_WRITE,
|
||||
PTE_NOCACHE,
|
||||
},
|
||||
/* NPE-B Memory Space */
|
||||
{
|
||||
IXP425_NPE_B_VBASE,
|
||||
IXP425_NPE_B_HWBASE,
|
||||
IXP425_NPE_B_SIZE,
|
||||
VM_PROT_READ|VM_PROT_WRITE,
|
||||
PTE_NOCACHE,
|
||||
},
|
||||
/* NPE-C Memory Space */
|
||||
{
|
||||
IXP425_NPE_C_VBASE,
|
||||
IXP425_NPE_C_HWBASE,
|
||||
IXP425_NPE_C_SIZE,
|
||||
VM_PROT_READ|VM_PROT_WRITE,
|
||||
PTE_NOCACHE,
|
||||
},
|
||||
/* MAC-A Memory Space */
|
||||
{
|
||||
IXP425_MAC_A_VBASE,
|
||||
IXP425_MAC_A_HWBASE,
|
||||
IXP425_MAC_A_SIZE,
|
||||
VM_PROT_READ|VM_PROT_WRITE,
|
||||
PTE_NOCACHE,
|
||||
},
|
||||
/* MAC-B Memory Space */
|
||||
{
|
||||
IXP425_MAC_B_VBASE,
|
||||
IXP425_MAC_B_HWBASE,
|
||||
IXP425_MAC_B_SIZE,
|
||||
VM_PROT_READ|VM_PROT_WRITE,
|
||||
PTE_NOCACHE,
|
||||
},
|
||||
/* Q-Mgr Memory Space */
|
||||
{
|
||||
IXP425_QMGR_VBASE,
|
||||
IXP425_QMGR_HWBASE,
|
||||
IXP425_QMGR_SIZE,
|
||||
VM_PROT_READ|VM_PROT_WRITE,
|
||||
PTE_NOCACHE,
|
||||
},
|
||||
{ IXP425_PCI_MEM_VBASE, IXP425_PCI_MEM_HWBASE, IXP425_PCI_MEM_SIZE,
|
||||
VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, },
|
||||
|
||||
{
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
}
|
||||
/* Q-Mgr Memory Space */
|
||||
{ IXP425_QMGR_VBASE, IXP425_QMGR_HWBASE, IXP425_QMGR_SIZE,
|
||||
VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, },
|
||||
|
||||
/* NPE-A Memory Space */
|
||||
{ IXP425_NPE_A_VBASE, IXP425_NPE_A_HWBASE, IXP425_NPE_A_SIZE,
|
||||
VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, },
|
||||
/* NPE-B Memory Space */
|
||||
{ IXP425_NPE_B_VBASE, IXP425_NPE_B_HWBASE, IXP425_NPE_B_SIZE,
|
||||
VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, },
|
||||
/* NPE-C Memory Space */
|
||||
{ IXP425_NPE_C_VBASE, IXP425_NPE_C_HWBASE, IXP425_NPE_C_SIZE,
|
||||
VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, },
|
||||
|
||||
/* MAC-B Memory Space */
|
||||
{ IXP425_MAC_B_VBASE, IXP425_MAC_B_HWBASE, IXP425_MAC_B_SIZE,
|
||||
VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, },
|
||||
/* MAC-C Memory Space */
|
||||
{ IXP425_MAC_C_VBASE, IXP425_MAC_C_HWBASE, IXP425_MAC_C_SIZE,
|
||||
VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, },
|
||||
|
||||
{ 0 },
|
||||
};
|
||||
|
||||
#define SDRAM_START 0x10000000
|
||||
/* Static device mappings. */
|
||||
static const struct pmap_devmap ixp435_devmap[] = {
|
||||
/* Physical/Virtual address for I/O space */
|
||||
{ IXP425_IO_VBASE, IXP425_IO_HWBASE, IXP425_IO_SIZE,
|
||||
VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, },
|
||||
|
||||
/* Expansion Bus */
|
||||
{ IXP425_EXP_VBASE, IXP425_EXP_HWBASE, IXP425_EXP_SIZE,
|
||||
VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, },
|
||||
|
||||
/* IXP425 PCI Configuration */
|
||||
{ IXP425_PCI_VBASE, IXP425_PCI_HWBASE, IXP425_PCI_SIZE,
|
||||
VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, },
|
||||
|
||||
/* DDRII Controller NB: mapped same place as IXP425 */
|
||||
{ IXP425_MCU_VBASE, IXP435_MCU_HWBASE, IXP425_MCU_SIZE,
|
||||
VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, },
|
||||
|
||||
/* PCI Memory Space */
|
||||
{ IXP425_PCI_MEM_VBASE, IXP425_PCI_MEM_HWBASE, IXP425_PCI_MEM_SIZE,
|
||||
VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, },
|
||||
|
||||
/* Q-Mgr Memory Space */
|
||||
{ IXP425_QMGR_VBASE, IXP425_QMGR_HWBASE, IXP425_QMGR_SIZE,
|
||||
VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, },
|
||||
|
||||
/* NPE-A Memory Space */
|
||||
{ IXP425_NPE_A_VBASE, IXP425_NPE_A_HWBASE, IXP425_NPE_A_SIZE,
|
||||
VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, },
|
||||
/* NPE-C Memory Space */
|
||||
{ IXP425_NPE_C_VBASE, IXP425_NPE_C_HWBASE, IXP425_NPE_C_SIZE,
|
||||
VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, },
|
||||
|
||||
/* MAC-C Memory Space */
|
||||
{ IXP425_MAC_C_VBASE, IXP425_MAC_C_HWBASE, IXP425_MAC_C_SIZE,
|
||||
VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, },
|
||||
/* MAC-B Memory Space */
|
||||
{ IXP425_MAC_B_VBASE, IXP425_MAC_B_HWBASE, IXP425_MAC_B_SIZE,
|
||||
VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, },
|
||||
/* MAC-A Memory Space */
|
||||
{ IXP435_MAC_A_VBASE, IXP435_MAC_A_HWBASE, IXP435_MAC_A_SIZE,
|
||||
VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, },
|
||||
|
||||
/* USB1 Memory Space */
|
||||
{ IXP435_USB1_VBASE, IXP435_USB1_HWBASE, IXP435_USB1_SIZE,
|
||||
VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, },
|
||||
/* USB2 Memory Space */
|
||||
{ IXP435_USB2_VBASE, IXP435_USB2_HWBASE, IXP435_USB2_SIZE,
|
||||
VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, },
|
||||
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
extern vm_offset_t xscale_cache_clean_addr;
|
||||
|
||||
void *
|
||||
initarm(void *arg, void *arg2)
|
||||
{
|
||||
#define next_chunk2(a,b) (((a) + (b)) &~ ((b)-1))
|
||||
#define next_page(a) next_chunk2(a,PAGE_SIZE)
|
||||
struct pv_addr kernel_l1pt;
|
||||
int loop, i;
|
||||
u_int l1pagetable;
|
||||
@ -260,25 +260,40 @@ initarm(void *arg, void *arg2)
|
||||
vm_offset_t lastaddr;
|
||||
uint32_t memsize;
|
||||
|
||||
set_cpufuncs();
|
||||
set_cpufuncs(); /* NB: sets cputype */
|
||||
lastaddr = fake_preload_metadata();
|
||||
pcpu_init(pcpup, 0, sizeof(struct pcpu));
|
||||
PCPU_SET(curthread, &thread0);
|
||||
|
||||
freemempos = 0x10200000;
|
||||
/* Define a macro to simplify memory allocation */
|
||||
#define valloc_pages(var, np) \
|
||||
alloc_pages((var).pv_pa, (np)); \
|
||||
(var).pv_va = (var).pv_pa + 0xb0000000;
|
||||
/*
|
||||
* We allocate memory downwards from where we were loaded
|
||||
* by RedBoot; first the L1 page table, then NUM_KERNEL_PTS
|
||||
* entries in the L2 page table. Past that we re-align the
|
||||
* allocation boundary so later data structures (stacks, etc)
|
||||
* can be mapped with different attributes (write-back vs
|
||||
* write-through). Note this leaves a gap for expansion
|
||||
* (or might be repurposed).
|
||||
*/
|
||||
freemempos = KERNPHYSADDR;
|
||||
|
||||
#define alloc_pages(var, np) \
|
||||
freemempos -= (np * PAGE_SIZE); \
|
||||
(var) = freemempos; \
|
||||
memset((char *)(var), 0, ((np) * PAGE_SIZE));
|
||||
/* macros to simplify initial memory allocation */
|
||||
#define alloc_pages(var, np) do { \
|
||||
freemempos -= (np * PAGE_SIZE); \
|
||||
(var) = freemempos; \
|
||||
/* NB: this works because locore maps PA=VA */ \
|
||||
memset((char *)(var), 0, ((np) * PAGE_SIZE)); \
|
||||
} while (0)
|
||||
#define valloc_pages(var, np) do { \
|
||||
alloc_pages((var).pv_pa, (np)); \
|
||||
(var).pv_va = (var).pv_pa + (KERNVIRTADDR - KERNPHYSADDR); \
|
||||
} while (0)
|
||||
|
||||
/* force L1 page table alignment */
|
||||
while (((freemempos - L1_TABLE_SIZE) & (L1_TABLE_SIZE - 1)) != 0)
|
||||
freemempos -= PAGE_SIZE;
|
||||
/* allocate contiguous L1 page table */
|
||||
valloc_pages(kernel_l1pt, L1_TABLE_SIZE / PAGE_SIZE);
|
||||
/* now allocate L2 page tables; they are linked to L1 below */
|
||||
for (loop = 0; loop < NUM_KERNEL_PTS; ++loop) {
|
||||
if (!(loop % (PAGE_SIZE / L2_TABLE_SIZE_REAL))) {
|
||||
valloc_pages(kernel_pt_table[loop],
|
||||
@ -288,11 +303,18 @@ initarm(void *arg, void *arg2)
|
||||
(loop % (PAGE_SIZE / L2_TABLE_SIZE_REAL)) *
|
||||
L2_TABLE_SIZE_REAL;
|
||||
kernel_pt_table[loop].pv_va =
|
||||
kernel_pt_table[loop].pv_pa + 0xb0000000;
|
||||
kernel_pt_table[loop].pv_pa +
|
||||
(KERNVIRTADDR - KERNPHYSADDR);
|
||||
}
|
||||
}
|
||||
freemem_pt = freemempos;
|
||||
freemempos = 0x10100000;
|
||||
freemem_pt = freemempos; /* base of allocated pt's */
|
||||
|
||||
/*
|
||||
* Re-align allocation boundary so we can map the area
|
||||
* write-back instead of write-through for the stacks and
|
||||
* related structures allocated below.
|
||||
*/
|
||||
freemempos = PHYSADDR + 0x100000;
|
||||
/*
|
||||
* Allocate a page for the system page mapped to V0x00000000
|
||||
* This page will just contain the system vectors and can be
|
||||
@ -308,30 +330,25 @@ initarm(void *arg, void *arg2)
|
||||
alloc_pages(minidataclean.pv_pa, 1);
|
||||
valloc_pages(msgbufpv, round_page(MSGBUF_SIZE) / PAGE_SIZE);
|
||||
#ifdef ARM_USE_SMALL_ALLOC
|
||||
#error "I am broken" /* XXX save people grief */
|
||||
freemempos -= PAGE_SIZE;
|
||||
freemem_pt = trunc_page(freemem_pt);
|
||||
freemem_after = freemempos - ((freemem_pt - 0x10100000) /
|
||||
PAGE_SIZE) * sizeof(struct arm_small_page);
|
||||
arm_add_smallalloc_pages((void *)(freemem_after + 0xb0000000)
|
||||
arm_add_smallalloc_pages((void *)(freemem_after + (KERNVIRTADDR - KERNPHYSADDR)
|
||||
, (void *)0xc0100000, freemem_pt - 0x10100000, 1);
|
||||
freemem_after -= ((freemem_after - 0x10001000) / PAGE_SIZE) *
|
||||
sizeof(struct arm_small_page);
|
||||
arm_add_smallalloc_pages((void *)(freemem_after + 0xb0000000)
|
||||
arm_add_smallalloc_pages((void *)(freemem_after + (KEYVIRTADDR - KERNPHYSADDR))
|
||||
, (void *)0xc0001000, trunc_page(freemem_after) - 0x10001000, 0);
|
||||
freemempos = trunc_page(freemem_after);
|
||||
freemempos -= PAGE_SIZE;
|
||||
#endif
|
||||
/*
|
||||
* Allocate memory for the l1 and l2 page tables. The scheme to avoid
|
||||
* wasting memory by allocating the l1pt on the first 16k memory was
|
||||
* taken from NetBSD rpc_machdep.c. NKPT should be greater than 12 for
|
||||
* this to work (which is supposed to be the case).
|
||||
*/
|
||||
|
||||
/*
|
||||
* Now we start construction of the L1 page table
|
||||
* We start by mapping the L2 page tables into the L1.
|
||||
* This means that we can replace L1 mappings later on if necessary
|
||||
* Now construct the L1 page table. First map the L2
|
||||
* page tables into the L1 so we can replace L1 mappings
|
||||
* later on if necessary
|
||||
*/
|
||||
l1pagetable = kernel_l1pt.pv_va;
|
||||
|
||||
@ -339,30 +356,28 @@ initarm(void *arg, void *arg2)
|
||||
pmap_link_l2pt(l1pagetable, ARM_VECTORS_HIGH & ~(0x00100000 - 1),
|
||||
&kernel_pt_table[KERNEL_PT_SYS]);
|
||||
pmap_link_l2pt(l1pagetable, IXP425_IO_VBASE,
|
||||
&kernel_pt_table[KERNEL_PT_IO]);
|
||||
&kernel_pt_table[KERNEL_PT_IO]);
|
||||
pmap_link_l2pt(l1pagetable, IXP425_MCU_VBASE,
|
||||
&kernel_pt_table[KERNEL_PT_IO + 1]);
|
||||
&kernel_pt_table[KERNEL_PT_IO + 1]);
|
||||
pmap_link_l2pt(l1pagetable, IXP425_PCI_MEM_VBASE,
|
||||
&kernel_pt_table[KERNEL_PT_IO + 2]);
|
||||
&kernel_pt_table[KERNEL_PT_IO + 2]);
|
||||
pmap_link_l2pt(l1pagetable, KERNBASE,
|
||||
&kernel_pt_table[KERNEL_PT_BEFOREKERN]);
|
||||
pmap_map_chunk(l1pagetable, KERNBASE, SDRAM_START, 0x100000,
|
||||
pmap_map_chunk(l1pagetable, KERNBASE, PHYSADDR, 0x100000,
|
||||
VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
|
||||
pmap_map_chunk(l1pagetable, KERNBASE + 0x100000, SDRAM_START + 0x100000,
|
||||
pmap_map_chunk(l1pagetable, KERNBASE + 0x100000, PHYSADDR + 0x100000,
|
||||
0x100000, VM_PROT_READ|VM_PROT_WRITE, PTE_PAGETABLE);
|
||||
pmap_map_chunk(l1pagetable, KERNBASE + 0x200000, SDRAM_START + 0x200000,
|
||||
(((uint32_t)(lastaddr) - KERNBASE - 0x200000) + L1_S_SIZE) & ~(L1_S_SIZE - 1),
|
||||
pmap_map_chunk(l1pagetable, KERNEL_TEXT_BASE, KERNEL_TEXT_PHYS,
|
||||
next_chunk2(((uint32_t)lastaddr) - KERNEL_TEXT_BASE, L1_S_SIZE),
|
||||
VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
|
||||
freemem_after = ((int)lastaddr + PAGE_SIZE) & ~(PAGE_SIZE - 1);
|
||||
afterkern = round_page(((vm_offset_t)lastaddr + L1_S_SIZE) & ~(L1_S_SIZE
|
||||
- 1));
|
||||
freemem_after = next_page((int)lastaddr);
|
||||
afterkern = round_page(next_chunk2((vm_offset_t)lastaddr, L1_S_SIZE));
|
||||
for (i = 0; i < KERNEL_PT_AFKERNEL_NUM; i++) {
|
||||
pmap_link_l2pt(l1pagetable, afterkern + i * 0x00100000,
|
||||
&kernel_pt_table[KERNEL_PT_AFKERNEL + i]);
|
||||
}
|
||||
pmap_map_entry(l1pagetable, afterkern, minidataclean.pv_pa,
|
||||
VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
|
||||
|
||||
|
||||
#ifdef ARM_USE_SMALL_ALLOC
|
||||
if ((freemem_after + 2 * PAGE_SIZE) <= afterkern) {
|
||||
@ -380,7 +395,10 @@ initarm(void *arg, void *arg2)
|
||||
/* Map the vector page. */
|
||||
pmap_map_entry(l1pagetable, ARM_VECTORS_HIGH, systempage.pv_pa,
|
||||
VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
|
||||
pmap_devmap_bootstrap(l1pagetable, ixp425_devmap);
|
||||
if (cpu_is_ixp43x())
|
||||
pmap_devmap_bootstrap(l1pagetable, ixp435_devmap);
|
||||
else
|
||||
pmap_devmap_bootstrap(l1pagetable, ixp425_devmap);
|
||||
/*
|
||||
* Give the XScale global cache clean code an appropriately
|
||||
* sized chunk of unmapped VA space starting at 0xff000000
|
||||
@ -392,6 +410,7 @@ initarm(void *arg, void *arg2)
|
||||
setttb(kernel_l1pt.pv_pa);
|
||||
cpu_tlb_flushID();
|
||||
cpu_domains(DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2));
|
||||
|
||||
/*
|
||||
* Pages were allocated during the secondary bootstrap for the
|
||||
* stacks for different CPU modes.
|
||||
@ -400,16 +419,9 @@ initarm(void *arg, void *arg2)
|
||||
* Since the ARM stacks use STMFD etc. we must set r13 to the top end
|
||||
* of the stack memory.
|
||||
*/
|
||||
|
||||
|
||||
set_stackptr(PSR_IRQ32_MODE,
|
||||
irqstack.pv_va + IRQ_STACK_SIZE * PAGE_SIZE);
|
||||
set_stackptr(PSR_ABT32_MODE,
|
||||
abtstack.pv_va + ABT_STACK_SIZE * PAGE_SIZE);
|
||||
set_stackptr(PSR_UND32_MODE,
|
||||
undstack.pv_va + UND_STACK_SIZE * PAGE_SIZE);
|
||||
|
||||
|
||||
set_stackptr(PSR_IRQ32_MODE, irqstack.pv_va + IRQ_STACK_SIZE*PAGE_SIZE);
|
||||
set_stackptr(PSR_ABT32_MODE, abtstack.pv_va + ABT_STACK_SIZE*PAGE_SIZE);
|
||||
set_stackptr(PSR_UND32_MODE, undstack.pv_va + UND_STACK_SIZE*PAGE_SIZE);
|
||||
|
||||
/*
|
||||
* We must now clean the cache again....
|
||||
@ -422,21 +434,25 @@ initarm(void *arg, void *arg2)
|
||||
* this problem will not occur after initarm().
|
||||
*/
|
||||
cpu_idcache_wbinv_all();
|
||||
/*
|
||||
* Fetch the SDRAM start/size from the ixp425 SDRAM configration
|
||||
* registers.
|
||||
*/
|
||||
/* ready to setup the console (XXX move earlier if possible) */
|
||||
cninit();
|
||||
memsize = ixp425_sdram_size();
|
||||
/*
|
||||
* Fetch the RAM size from the MCU registers. The
|
||||
* expansion bus was mapped above so we can now read 'em.
|
||||
*/
|
||||
if (cpu_is_ixp43x())
|
||||
memsize = ixp435_ddram_size();
|
||||
else
|
||||
memsize = ixp425_sdram_size();
|
||||
physmem = memsize / PAGE_SIZE;
|
||||
|
||||
/* Set stack for exception handlers */
|
||||
|
||||
|
||||
data_abort_handler_address = (u_int)data_abort_handler;
|
||||
prefetch_abort_handler_address = (u_int)prefetch_abort_handler;
|
||||
undefined_handler_address = (u_int)undefinedinstruction_bounce;
|
||||
undefined_init();
|
||||
|
||||
|
||||
proc_linkup0(&proc0, &thread0);
|
||||
thread0.td_kstack = kernelstack.pv_va;
|
||||
thread0.td_pcb = (struct pcb *)
|
||||
@ -444,38 +460,33 @@ initarm(void *arg, void *arg2)
|
||||
thread0.td_pcb->pcb_flags = 0;
|
||||
thread0.td_frame = &proc0_tf;
|
||||
pcpup->pc_curpcb = thread0.td_pcb;
|
||||
|
||||
/* Enable MMU, I-cache, D-cache, write buffer. */
|
||||
|
||||
arm_vector_init(ARM_VECTORS_HIGH, ARM_VEC_ALL);
|
||||
|
||||
|
||||
|
||||
pmap_curmaxkvaddr = afterkern + PAGE_SIZE;
|
||||
dump_avail[0] = 0x10000000;
|
||||
dump_avail[1] = 0x10000000 + memsize;
|
||||
dump_avail[0] = PHYSADDR;
|
||||
dump_avail[1] = PHYSADDR + memsize;
|
||||
dump_avail[2] = 0;
|
||||
dump_avail[3] = 0;
|
||||
|
||||
pmap_bootstrap(pmap_curmaxkvaddr,
|
||||
0xd0000000, &kernel_l1pt);
|
||||
|
||||
pmap_bootstrap(pmap_curmaxkvaddr, 0xd0000000, &kernel_l1pt);
|
||||
msgbufp = (void*)msgbufpv.pv_va;
|
||||
msgbufinit(msgbufp, MSGBUF_SIZE);
|
||||
mutex_init();
|
||||
|
||||
|
||||
i = 0;
|
||||
#ifdef ARM_USE_SMALL_ALLOC
|
||||
phys_avail[i++] = 0x10000000;
|
||||
phys_avail[i++] = 0x10001000; /*
|
||||
phys_avail[i++] = PHYSADDR;
|
||||
phys_avail[i++] = PHYSADDR + PAGE_SIZE; /*
|
||||
*XXX: Gross hack to get our
|
||||
* pages in the vm_page_array
|
||||
. */
|
||||
#endif
|
||||
phys_avail[i++] = round_page(virtual_avail - KERNBASE + SDRAM_START);
|
||||
phys_avail[i++] = trunc_page(0x10000000 + memsize - 1);
|
||||
phys_avail[i++] = round_page(virtual_avail - KERNBASE + PHYSADDR);
|
||||
phys_avail[i++] = trunc_page(PHYSADDR + memsize - 1);
|
||||
phys_avail[i++] = 0;
|
||||
phys_avail[i] = 0;
|
||||
|
||||
|
||||
/* Do basic tuning, hz etc */
|
||||
init_param1();
|
||||
init_param2(physmem);
|
||||
@ -487,4 +498,6 @@ initarm(void *arg, void *arg2)
|
||||
|
||||
return ((void *)(kernelstack.pv_va + USPACE_SVC_STACK_TOP -
|
||||
sizeof(struct pcb)));
|
||||
#undef next_page
|
||||
#undef next_chunk2
|
||||
}
|
||||
|
108
sys/arm/xscale/ixp425/cambria_fled.c
Normal file
108
sys/arm/xscale/ixp425/cambria_fled.c
Normal file
@ -0,0 +1,108 @@
|
||||
/*-
|
||||
* Copyright (c) 2008 Sam Leffler. 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
/*
|
||||
* Cambria Front Panel LED sitting on the I2C bus.
|
||||
*/
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/bus.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
|
||||
#include <dev/iicbus/iiconf.h>
|
||||
#include <dev/led/led.h>
|
||||
|
||||
#include "iicbus_if.h"
|
||||
|
||||
#define IIC_M_WR 0 /* write operation */
|
||||
#define LED_ADDR 0xae /* slave address */
|
||||
|
||||
struct fled_softc {
|
||||
struct cdev *sc_led;
|
||||
};
|
||||
|
||||
static int
|
||||
fled_probe(device_t dev)
|
||||
{
|
||||
device_set_desc(dev, "Gateworks Cambria Front Panel LED");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
fled_cb(void *arg, int onoff)
|
||||
{
|
||||
uint8_t data[1];
|
||||
struct iic_msg msgs[1] = {
|
||||
{ LED_ADDR, IIC_M_WR, 1, data },
|
||||
};
|
||||
device_t dev = arg;
|
||||
|
||||
data[0] = (onoff == 0); /* NB: low true */
|
||||
(void) iicbus_transfer(dev, msgs, 1);
|
||||
}
|
||||
|
||||
static int
|
||||
fled_attach(device_t dev)
|
||||
{
|
||||
struct fled_softc *sc = device_get_softc(dev);
|
||||
|
||||
sc->sc_led = led_create(fled_cb, dev, "front");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
fled_detach(device_t dev)
|
||||
{
|
||||
struct fled_softc *sc = device_get_softc(dev);
|
||||
|
||||
if (sc->sc_led != NULL)
|
||||
led_destroy(sc->sc_led);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static device_method_t fled_methods[] = {
|
||||
DEVMETHOD(device_probe, fled_probe),
|
||||
DEVMETHOD(device_attach, fled_attach),
|
||||
DEVMETHOD(device_detach, fled_detach),
|
||||
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
static driver_t fled_driver = {
|
||||
"fled",
|
||||
fled_methods,
|
||||
sizeof(struct fled_softc),
|
||||
};
|
||||
static devclass_t fled_devclass;
|
||||
|
||||
DRIVER_MODULE(fled, iicbus, fled_driver, fled_devclass, 0, 0);
|
||||
MODULE_VERSION(fled, 1);
|
||||
MODULE_DEPEND(fled, iicbus, 1, 1, 1);
|
132
sys/arm/xscale/ixp425/cambria_led.c
Normal file
132
sys/arm/xscale/ixp425/cambria_led.c
Normal file
@ -0,0 +1,132 @@
|
||||
/*-
|
||||
* Copyright (c) 2008 Sam Leffler. 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/*
|
||||
* Gateworks Cambria Octal LED Latch driver.
|
||||
*/
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/bus.h>
|
||||
|
||||
#include <machine/armreg.h>
|
||||
|
||||
#include <arm/xscale/ixp425/ixp425reg.h>
|
||||
#include <arm/xscale/ixp425/ixp425var.h>
|
||||
|
||||
#include <dev/led/led.h>
|
||||
|
||||
struct led_softc {
|
||||
device_t sc_dev;
|
||||
bus_space_tag_t sc_iot;
|
||||
bus_space_handle_t sc_ioh;
|
||||
struct cdev *sc_leds[8];
|
||||
uint8_t sc_latch;
|
||||
};
|
||||
|
||||
static void
|
||||
update_latch(struct led_softc *sc, int bit, int onoff)
|
||||
{
|
||||
if (onoff)
|
||||
sc->sc_latch &= ~bit;
|
||||
else
|
||||
sc->sc_latch |= bit;
|
||||
bus_space_write_1(sc->sc_iot, sc->sc_ioh, 0, sc->sc_latch);
|
||||
}
|
||||
static void led_A(void *arg, int onoff) { update_latch(arg, 1<<0, onoff); }
|
||||
static void led_B(void *arg, int onoff) { update_latch(arg, 1<<1, onoff); }
|
||||
static void led_C(void *arg, int onoff) { update_latch(arg, 1<<2, onoff); }
|
||||
static void led_D(void *arg, int onoff) { update_latch(arg, 1<<3, onoff); }
|
||||
static void led_E(void *arg, int onoff) { update_latch(arg, 1<<4, onoff); }
|
||||
static void led_F(void *arg, int onoff) { update_latch(arg, 1<<5, onoff); }
|
||||
static void led_G(void *arg, int onoff) { update_latch(arg, 1<<6, onoff); }
|
||||
static void led_H(void *arg, int onoff) { update_latch(arg, 1<<7, onoff); }
|
||||
|
||||
static int
|
||||
led_probe(device_t dev)
|
||||
{
|
||||
device_set_desc(dev, "Gateworks Octal LED Latch");
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
led_attach(device_t dev)
|
||||
{
|
||||
struct led_softc *sc = device_get_softc(dev);
|
||||
struct ixp425_softc *sa = device_get_softc(device_get_parent(dev));
|
||||
|
||||
sc->sc_dev = dev;
|
||||
sc->sc_iot = sa->sc_iot;
|
||||
/* NB: write anywhere works, use first location */
|
||||
if (bus_space_map(sc->sc_iot, CAMBRIA_OCTAL_LED_HWBASE, sizeof(uint8_t),
|
||||
0, &sc->sc_ioh)) {
|
||||
device_printf(dev, "cannot map LED latch (0x%lx)",
|
||||
CAMBRIA_OCTAL_LED_HWBASE);
|
||||
return ENXIO;
|
||||
}
|
||||
|
||||
sc->sc_leds[0] = led_create(led_A, sc, "A");
|
||||
sc->sc_leds[1] = led_create(led_B, sc, "B");
|
||||
sc->sc_leds[2] = led_create(led_C, sc, "C");
|
||||
sc->sc_leds[3] = led_create(led_D, sc, "D");
|
||||
sc->sc_leds[4] = led_create(led_E, sc, "E");
|
||||
sc->sc_leds[5] = led_create(led_F, sc, "F");
|
||||
sc->sc_leds[6] = led_create(led_G, sc, "G");
|
||||
sc->sc_leds[7] = led_create(led_H, sc, "H");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
led_detach(device_t dev)
|
||||
{
|
||||
struct led_softc *sc = device_get_softc(dev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
struct cdev *led = sc->sc_leds[i];
|
||||
if (led != NULL)
|
||||
led_destroy(led);
|
||||
}
|
||||
}
|
||||
|
||||
static device_method_t led_methods[] = {
|
||||
DEVMETHOD(device_probe, led_probe),
|
||||
DEVMETHOD(device_attach, led_attach),
|
||||
DEVMETHOD(device_attach, led_detach),
|
||||
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
static driver_t led_driver = {
|
||||
"led_cambria",
|
||||
led_methods,
|
||||
sizeof(struct led_softc),
|
||||
};
|
||||
static devclass_t led_devclass;
|
||||
DRIVER_MODULE(led_cambria, ixp, led_driver, led_devclass, 0, 0);
|
@ -2,4 +2,6 @@
|
||||
arm/xscale/ixp425/avila_machdep.c standard
|
||||
arm/xscale/ixp425/avila_ata.c optional avila_ata
|
||||
arm/xscale/ixp425/avila_led.c optional avila_led
|
||||
arm/xscale/ixp425/cambria_led.c optional cambria_led
|
||||
arm/xscale/ixp425/cambria_fled.c optional cambria_fled
|
||||
arm/xscale/ixp425/ixdp425_pci.c optional pci
|
||||
|
@ -44,3 +44,5 @@ IxNpeMicrocode.dat optional npe_fw \
|
||||
# Q-Manager support
|
||||
#
|
||||
arm/xscale/ixp425/ixp425_qmgr.c optional qmgr
|
||||
#
|
||||
arm/xscale/ixp425/ixp435_ehci.c optional ehci
|
||||
|
@ -85,6 +85,8 @@ __FBSDID("$FreeBSD$");
|
||||
#include <dev/mii/miivar.h>
|
||||
#include <arm/xscale/ixp425/if_npereg.h>
|
||||
|
||||
#include <machine/armreg.h>
|
||||
|
||||
#include "miibus_if.h"
|
||||
|
||||
/*
|
||||
@ -121,6 +123,7 @@ struct npe_softc {
|
||||
bus_space_handle_t sc_ioh; /* MAC register window */
|
||||
device_t sc_mii; /* child miibus */
|
||||
bus_space_handle_t sc_miih; /* MII register window */
|
||||
int sc_npeid;
|
||||
struct ixpnpe_softc *sc_npe; /* NPE support */
|
||||
int sc_debug; /* DPRINTF* control */
|
||||
int sc_tickinterval;
|
||||
@ -143,7 +146,7 @@ struct npe_softc {
|
||||
};
|
||||
|
||||
/*
|
||||
* Per-unit static configuration for IXP425. The tx and
|
||||
* Static configuration for IXP425. The tx and
|
||||
* rx free Q id's are fixed by the NPE microcode. The
|
||||
* rx Q id's are programmed to be separate to simplify
|
||||
* multi-port processing. It may be better to handle
|
||||
@ -154,39 +157,39 @@ struct npe_softc {
|
||||
* assumptions probably need to be handled through hints.
|
||||
*/
|
||||
static const struct {
|
||||
const char *desc; /* device description */
|
||||
int npeid; /* NPE assignment */
|
||||
uint32_t imageid; /* NPE firmware image id */
|
||||
uint32_t regbase;
|
||||
int regsize;
|
||||
uint32_t imageid; /* default fw image */
|
||||
uint32_t macbase;
|
||||
uint32_t miibase;
|
||||
int miisize;
|
||||
int phy; /* phy id */
|
||||
uint8_t rx_qid;
|
||||
uint8_t rx_freeqid;
|
||||
uint8_t tx_qid;
|
||||
uint8_t tx_doneqid;
|
||||
} npeconfig[NPE_PORTS_MAX] = {
|
||||
{ .desc = "IXP NPE-B",
|
||||
.npeid = NPE_B,
|
||||
} npeconfig[NPE_MAX] = {
|
||||
[NPE_A] = {
|
||||
.imageid = IXP425_NPE_A_IMAGEID,
|
||||
.macbase = IXP435_MAC_A_HWBASE,
|
||||
.miibase = IXP425_MAC_C_HWBASE,
|
||||
.phy = 2,
|
||||
.rx_qid = 4,
|
||||
.rx_freeqid = 26,
|
||||
.tx_qid = 23,
|
||||
.tx_doneqid = 31
|
||||
},
|
||||
[NPE_B] = {
|
||||
.imageid = IXP425_NPE_B_IMAGEID,
|
||||
.regbase = IXP425_MAC_A_HWBASE,
|
||||
.regsize = IXP425_MAC_A_SIZE,
|
||||
.miibase = IXP425_MAC_A_HWBASE,
|
||||
.miisize = IXP425_MAC_A_SIZE,
|
||||
.macbase = IXP425_MAC_B_HWBASE,
|
||||
.miibase = IXP425_MAC_C_HWBASE,
|
||||
.phy = 0,
|
||||
.rx_qid = 4,
|
||||
.rx_freeqid = 27,
|
||||
.tx_qid = 24,
|
||||
.tx_doneqid = 31
|
||||
},
|
||||
{ .desc = "IXP NPE-C",
|
||||
.npeid = NPE_C,
|
||||
[NPE_C] = {
|
||||
.imageid = IXP425_NPE_C_IMAGEID,
|
||||
.regbase = IXP425_MAC_B_HWBASE,
|
||||
.regsize = IXP425_MAC_B_SIZE,
|
||||
.miibase = IXP425_MAC_A_HWBASE,
|
||||
.miisize = IXP425_MAC_A_SIZE,
|
||||
.macbase = IXP425_MAC_C_HWBASE,
|
||||
.miibase = IXP425_MAC_C_HWBASE,
|
||||
.phy = 1,
|
||||
.rx_qid = 12,
|
||||
.rx_freeqid = 28,
|
||||
@ -219,6 +222,7 @@ WR4(struct npe_softc *sc, bus_size_t off, uint32_t val)
|
||||
|
||||
static devclass_t npe_devclass;
|
||||
|
||||
static int override_npeid(device_t, const char *resname, int *val);
|
||||
static int npe_activate(device_t dev);
|
||||
static void npe_deactivate(device_t dev);
|
||||
static int npe_ifmedia_update(struct ifnet *ifp);
|
||||
@ -238,6 +242,7 @@ static int npeioctl(struct ifnet * ifp, u_long, caddr_t);
|
||||
|
||||
static int npe_setrxqosentry(struct npe_softc *, int classix,
|
||||
int trafclass, int qid);
|
||||
static int npe_setfirewallmode(struct npe_softc *, int onoff);
|
||||
static int npe_updatestats(struct npe_softc *);
|
||||
#if 0
|
||||
static int npe_getstats(struct npe_softc *);
|
||||
@ -248,11 +253,11 @@ static int npe_setloopback(struct npe_softc *, int ena);
|
||||
/* NB: all tx done processing goes through one queue */
|
||||
static int tx_doneqid = -1;
|
||||
|
||||
SYSCTL_NODE(_hw, OID_AUTO, npe, CTLFLAG_RD, 0, "IXP425 NPE driver parameters");
|
||||
SYSCTL_NODE(_hw, OID_AUTO, npe, CTLFLAG_RD, 0, "IXP4XX NPE driver parameters");
|
||||
|
||||
static int npe_debug = 0;
|
||||
SYSCTL_INT(_hw_npe, OID_AUTO, debug, CTLFLAG_RW, &npe_debug,
|
||||
0, "IXP425 NPE network interface debug msgs");
|
||||
0, "IXP4XX NPE network interface debug msgs");
|
||||
TUNABLE_INT("hw.npe.npe", &npe_debug);
|
||||
#define DPRINTF(sc, fmt, ...) do { \
|
||||
if (sc->sc_debug) device_printf(sc->sc_dev, fmt, __VA_ARGS__); \
|
||||
@ -274,17 +279,39 @@ SYSCTL_INT(_hw_npe, OID_AUTO, txbuf, CTLFLAG_RD, &npe_txbuf,
|
||||
0, "tx buffers allocated");
|
||||
TUNABLE_INT("hw.npe.txbuf", &npe_txbuf);
|
||||
|
||||
static int
|
||||
unit2npeid(int unit)
|
||||
{
|
||||
static const int npeidmap[2][3] = {
|
||||
/* on 425 A is for HSS, B & C are for Ethernet */
|
||||
{ NPE_B, NPE_C, -1 }, /* IXP425 */
|
||||
/* 435 only has A & C, order C then A */
|
||||
{ NPE_C, NPE_A, -1 }, /* IXP435 */
|
||||
};
|
||||
/* XXX check feature register instead */
|
||||
return (unit < 3 ? npeidmap[
|
||||
(cpu_id() & CPU_ID_CPU_MASK) == CPU_ID_IXP435][unit] : -1);
|
||||
}
|
||||
|
||||
static int
|
||||
npe_probe(device_t dev)
|
||||
{
|
||||
int unit = device_get_unit(dev);
|
||||
static const char *desc[NPE_MAX] = {
|
||||
[NPE_A] = "IXP NPE-A",
|
||||
[NPE_B] = "IXP NPE-B",
|
||||
[NPE_C] = "IXP NPE-C"
|
||||
};
|
||||
int npeid;
|
||||
|
||||
if (unit >= NPE_PORTS_MAX) {
|
||||
device_printf(dev, "unit %d not supported\n", unit);
|
||||
npeid = -1;
|
||||
if (!override_npeid(dev, "npeid", &npeid))
|
||||
npeid = unit2npeid(device_get_unit(dev));
|
||||
if (npeid == -1) {
|
||||
device_printf(dev, "unit not supported\n");
|
||||
return EINVAL;
|
||||
}
|
||||
/* XXX check feature register to see if enabled */
|
||||
device_set_desc(dev, npeconfig[unit].desc);
|
||||
device_set_desc(dev, desc[npeid]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -295,7 +322,7 @@ npe_attach(device_t dev)
|
||||
struct ixp425_softc *sa = device_get_softc(device_get_parent(dev));
|
||||
struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev);
|
||||
struct sysctl_oid *tree = device_get_sysctl_tree(dev);
|
||||
struct ifnet *ifp = NULL;
|
||||
struct ifnet *ifp;
|
||||
int error;
|
||||
u_char eaddr[6];
|
||||
|
||||
@ -306,26 +333,23 @@ npe_attach(device_t dev)
|
||||
sc->sc_debug = npe_debug;
|
||||
sc->sc_tickinterval = npe_tickinterval;
|
||||
|
||||
sc->sc_npe = ixpnpe_attach(dev);
|
||||
if (sc->sc_npe == NULL) {
|
||||
ifp = if_alloc(IFT_ETHER);
|
||||
if (ifp == NULL) {
|
||||
device_printf(dev, "cannot allocate ifnet\n");
|
||||
error = EIO; /* XXX */
|
||||
goto out;
|
||||
}
|
||||
/* NB: must be setup prior to invoking mii code */
|
||||
sc->sc_ifp = ifp;
|
||||
|
||||
error = npe_activate(dev);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
npe_getmac(sc, eaddr);
|
||||
|
||||
/* NB: must be setup prior to invoking mii code */
|
||||
sc->sc_ifp = ifp = if_alloc(IFT_ETHER);
|
||||
if (mii_phy_probe(dev, &sc->sc_mii, npe_ifmedia_update, npe_ifmedia_status)) {
|
||||
device_printf(dev, "Cannot find my PHY.\n");
|
||||
error = ENXIO;
|
||||
if (error) {
|
||||
device_printf(dev, "cannot activate npe\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
npe_getmac(sc, eaddr);
|
||||
|
||||
ifp->if_softc = sc;
|
||||
if_initname(ifp, device_get_name(dev), device_get_unit(dev));
|
||||
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
|
||||
@ -350,9 +374,10 @@ npe_attach(device_t dev)
|
||||
ether_ifattach(ifp, eaddr);
|
||||
return 0;
|
||||
out:
|
||||
npe_deactivate(dev);
|
||||
if (ifp != NULL)
|
||||
if_free(ifp);
|
||||
NPE_LOCK_DESTROY(sc);
|
||||
npe_deactivate(dev);
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -373,8 +398,6 @@ npe_detach(device_t dev)
|
||||
}
|
||||
NPE_LOCK_DESTROY(sc);
|
||||
npe_deactivate(dev);
|
||||
if (sc->sc_npe != NULL)
|
||||
ixpnpe_detach(sc->sc_npe);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -536,7 +559,6 @@ npe_dma_destroy(struct npe_softc *sc, struct npedma *dma)
|
||||
}
|
||||
bus_dmamap_unload(dma->buf_tag, dma->buf_map);
|
||||
bus_dmamem_free(dma->buf_tag, dma->hwbuf, dma->buf_map);
|
||||
bus_dmamap_destroy(dma->buf_tag, dma->buf_map);
|
||||
}
|
||||
if (dma->buf != NULL)
|
||||
free(dma->buf, M_TEMP);
|
||||
@ -548,7 +570,7 @@ npe_dma_destroy(struct npe_softc *sc, struct npedma *dma)
|
||||
}
|
||||
|
||||
static int
|
||||
override_addr(device_t dev, const char *resname, int *base, int *size)
|
||||
override_addr(device_t dev, const char *resname, int *base)
|
||||
{
|
||||
int unit = device_get_unit(dev);
|
||||
const char *resval;
|
||||
@ -558,13 +580,38 @@ override_addr(device_t dev, const char *resname, int *base, int *size)
|
||||
return 0;
|
||||
switch (resval[0]) {
|
||||
case 'A':
|
||||
*base = IXP425_MAC_A_HWBASE;
|
||||
*size = IXP425_MAC_A_SIZE;
|
||||
*base = IXP435_MAC_A_HWBASE;
|
||||
break;
|
||||
case 'B':
|
||||
*base = IXP425_MAC_B_HWBASE;
|
||||
*size = IXP425_MAC_B_SIZE;
|
||||
break;
|
||||
case 'C':
|
||||
*base = IXP425_MAC_C_HWBASE;
|
||||
break;
|
||||
default:
|
||||
device_printf(dev, "Warning, bad value %s for "
|
||||
"npe.%d.%s ignored\n", resval, unit, resname);
|
||||
return 0;
|
||||
}
|
||||
if (bootverbose)
|
||||
device_printf(dev, "using npe.%d.%s=%s override\n",
|
||||
unit, resname, resval);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
override_npeid(device_t dev, const char *resname, int *npeid)
|
||||
{
|
||||
int unit = device_get_unit(dev);
|
||||
const char *resval;
|
||||
|
||||
/* XXX warn for wrong hint type */
|
||||
if (resource_string_value("npe", unit, resname, &resval) != 0)
|
||||
return 0;
|
||||
switch (resval[0]) {
|
||||
case 'A': *npeid = NPE_A; break;
|
||||
case 'B': *npeid = NPE_B; break;
|
||||
case 'C': *npeid = NPE_C; break;
|
||||
default:
|
||||
device_printf(dev, "Warning, bad value %s for "
|
||||
"npe.%d.%s ignored\n", resval, unit, resname);
|
||||
@ -597,13 +644,82 @@ override_unit(device_t dev, const char *resname, int *val, int min, int max)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
override_imageid(device_t dev, const char *resname, uint32_t *val)
|
||||
{
|
||||
int unit = device_get_unit(dev);
|
||||
int resval;
|
||||
|
||||
if (resource_int_value("npe", unit, resname, &resval) != 0)
|
||||
return 0;
|
||||
/* XXX validate */
|
||||
if (bootverbose)
|
||||
device_printf(dev, "using npe.%d.%s=0x%x override\n",
|
||||
unit, resname, resval);
|
||||
*val = resval;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
npe_mac_reset(struct npe_softc *sc)
|
||||
{
|
||||
/*
|
||||
* Reset MAC core.
|
||||
*/
|
||||
WR4(sc, NPE_MAC_CORE_CNTRL, NPE_CORE_RESET);
|
||||
DELAY(NPE_MAC_RESET_DELAY);
|
||||
/* configure MAC to generate MDC clock */
|
||||
WR4(sc, NPE_MAC_CORE_CNTRL, NPE_CORE_MDC_EN);
|
||||
}
|
||||
|
||||
static int
|
||||
npe_activate(device_t dev)
|
||||
{
|
||||
struct npe_softc * sc = device_get_softc(dev);
|
||||
int unit = device_get_unit(dev);
|
||||
int error, i, regbase, regsize, miibase, miisize;
|
||||
uint32_t imageid;
|
||||
int error, i, macbase, miibase;
|
||||
uint32_t imageid, msg[2];
|
||||
|
||||
/*
|
||||
* Setup NEP ID, MAC, and MII bindings. We allow override
|
||||
* via hints to handle unexpected board configs.
|
||||
*/
|
||||
if (!override_npeid(dev, "npeid", &sc->sc_npeid))
|
||||
sc->sc_npeid = unit2npeid(device_get_unit(dev));
|
||||
sc->sc_npe = ixpnpe_attach(dev, sc->sc_npeid);
|
||||
if (sc->sc_npe == NULL) {
|
||||
device_printf(dev, "cannot attach ixpnpe\n");
|
||||
return EIO; /* XXX */
|
||||
}
|
||||
|
||||
/* MAC */
|
||||
if (!override_addr(dev, "mac", &macbase))
|
||||
macbase = npeconfig[sc->sc_npeid].macbase;
|
||||
device_printf(sc->sc_dev, "MAC at 0x%x\n", macbase);
|
||||
if (bus_space_map(sc->sc_iot, macbase, IXP425_REG_SIZE, 0, &sc->sc_ioh)) {
|
||||
device_printf(dev, "cannot map mac registers 0x%x:0x%x\n",
|
||||
macbase, IXP425_REG_SIZE);
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
/* PHY */
|
||||
if (!override_unit(dev, "phy", &sc->sc_phy, 0, MII_NPHY-1))
|
||||
sc->sc_phy = npeconfig[sc->sc_npeid].phy;
|
||||
if (!override_addr(dev, "mii", &miibase))
|
||||
miibase = npeconfig[sc->sc_npeid].miibase;
|
||||
device_printf(sc->sc_dev, "MII at 0x%x\n", miibase);
|
||||
if (miibase != macbase) {
|
||||
/*
|
||||
* PHY is mapped through a different MAC, setup an
|
||||
* additional mapping for frobbing the PHY registers.
|
||||
*/
|
||||
if (bus_space_map(sc->sc_iot, miibase, IXP425_REG_SIZE, 0, &sc->sc_miih)) {
|
||||
device_printf(dev,
|
||||
"cannot map MII registers 0x%x:0x%x\n",
|
||||
miibase, IXP425_REG_SIZE);
|
||||
return ENOMEM;
|
||||
}
|
||||
} else
|
||||
sc->sc_miih = sc->sc_ioh;
|
||||
|
||||
/*
|
||||
* Load NPE firmware and start it running. We assume
|
||||
@ -611,47 +727,38 @@ npe_activate(device_t dev)
|
||||
* the firmware image starting with the expected version
|
||||
* and then bump the minor version up to the max.
|
||||
*/
|
||||
imageid = npeconfig[unit].imageid;
|
||||
if (!override_imageid(dev, "imageid", &imageid))
|
||||
imageid = npeconfig[sc->sc_npeid].imageid;
|
||||
for (;;) {
|
||||
error = ixpnpe_init(sc->sc_npe, "npe_fw", imageid);
|
||||
if (error == 0)
|
||||
break;
|
||||
/* ESRCH is returned when the requested image is not present */
|
||||
if (error != ESRCH)
|
||||
if (error != ESRCH) {
|
||||
device_printf(dev, "cannot init NPE (error %d)\n",
|
||||
error);
|
||||
return error;
|
||||
}
|
||||
/* bump the minor version up to the max possible */
|
||||
if (NPEIMAGE_MINOR(imageid) == 0xff)
|
||||
if (NPEIMAGE_MINOR(imageid) == 0xff) {
|
||||
device_printf(dev, "cannot locate firmware "
|
||||
"(imageid 0x%08x)\n", imageid);
|
||||
return error;
|
||||
}
|
||||
imageid++;
|
||||
}
|
||||
|
||||
if (!override_addr(dev, "mac", ®base, ®size)) {
|
||||
regbase = npeconfig[unit].regbase;
|
||||
regbase = npeconfig[unit].regsize;
|
||||
}
|
||||
if (bus_space_map(sc->sc_iot, regbase, regsize, 0, &sc->sc_ioh)) {
|
||||
device_printf(dev, "Cannot map registers 0x%x:0x%x\n",
|
||||
regbase, regsize);
|
||||
return ENOMEM;
|
||||
/* NB: firmware should respond with a status msg */
|
||||
if (ixpnpe_recvmsg_sync(sc->sc_npe, msg) != 0) {
|
||||
device_printf(dev, "firmware did not respond as expected\n");
|
||||
return EIO;
|
||||
}
|
||||
|
||||
if (!override_addr(dev, "mii", &miibase, &miisize)) {
|
||||
miibase = npeconfig[unit].miibase;
|
||||
miisize = npeconfig[unit].miisize;
|
||||
/* probe for PHY */
|
||||
if (mii_phy_probe(dev, &sc->sc_mii, npe_ifmedia_update, npe_ifmedia_status)) {
|
||||
device_printf(dev, "cannot find PHY %d.\n", sc->sc_phy);
|
||||
return ENXIO;
|
||||
}
|
||||
if (miibase != regbase) {
|
||||
/*
|
||||
* PHY is mapped through a different MAC, setup an
|
||||
* additional mapping for frobbing the PHY registers.
|
||||
*/
|
||||
if (bus_space_map(sc->sc_iot, miibase, miisize, 0, &sc->sc_miih)) {
|
||||
device_printf(dev,
|
||||
"Cannot map MII registers 0x%x:0x%x\n",
|
||||
miibase, miisize);
|
||||
return ENOMEM;
|
||||
}
|
||||
} else
|
||||
sc->sc_miih = sc->sc_ioh;
|
||||
|
||||
error = npe_dma_setup(sc, &sc->txdma, "tx", npe_txbuf, NPE_MAXSEG);
|
||||
if (error != 0)
|
||||
return error;
|
||||
@ -685,8 +792,6 @@ npe_activate(device_t dev)
|
||||
}
|
||||
sc->sc_stats_phys = sc->buf_phys;
|
||||
|
||||
/* XXX disable half-bridge LEARNING+FILTERING feature */
|
||||
|
||||
/*
|
||||
* Setup h/w rx/tx queues. There are four q's:
|
||||
* rx inbound q of rx'd frames
|
||||
@ -703,22 +808,24 @@ npe_activate(device_t dev)
|
||||
* when the rx q has at least one frame. These setings can
|
||||
* changed at the time the q is configured.
|
||||
*/
|
||||
sc->rx_qid = npeconfig[unit].rx_qid;
|
||||
sc->rx_qid = npeconfig[sc->sc_npeid].rx_qid;
|
||||
ixpqmgr_qconfig(sc->rx_qid, npe_rxbuf, 0, 1,
|
||||
IX_QMGR_Q_SOURCE_ID_NOT_E, npe_rxdone, sc);
|
||||
sc->rx_freeqid = npeconfig[unit].rx_freeqid;
|
||||
sc->rx_freeqid = npeconfig[sc->sc_npeid].rx_freeqid;
|
||||
ixpqmgr_qconfig(sc->rx_freeqid, npe_rxbuf, 0, npe_rxbuf/2, 0, NULL, sc);
|
||||
/* tell the NPE to direct all traffic to rx_qid */
|
||||
#if 0
|
||||
/*
|
||||
* Setup the NPE to direct all traffic to rx_qid.
|
||||
* When QoS is enabled in the firmware there are
|
||||
* 8 traffic classes; otherwise just 4.
|
||||
*/
|
||||
for (i = 0; i < 8; i++)
|
||||
#else
|
||||
device_printf(sc->sc_dev, "remember to fix rx q setup\n");
|
||||
for (i = 0; i < 4; i++)
|
||||
#endif
|
||||
npe_setrxqosentry(sc, i, 0, sc->rx_qid);
|
||||
|
||||
sc->tx_qid = npeconfig[unit].tx_qid;
|
||||
sc->tx_doneqid = npeconfig[unit].tx_doneqid;
|
||||
/* disable firewall mode just in case (should be off) */
|
||||
npe_setfirewallmode(sc, 0);
|
||||
|
||||
sc->tx_qid = npeconfig[sc->sc_npeid].tx_qid;
|
||||
sc->tx_doneqid = npeconfig[sc->sc_npeid].tx_doneqid;
|
||||
ixpqmgr_qconfig(sc->tx_qid, npe_txbuf, 0, npe_txbuf, 0, NULL, sc);
|
||||
if (tx_doneqid == -1) {
|
||||
ixpqmgr_qconfig(sc->tx_doneqid, npe_txbuf, 0, 2,
|
||||
@ -726,16 +833,9 @@ device_printf(sc->sc_dev, "remember to fix rx q setup\n");
|
||||
tx_doneqid = sc->tx_doneqid;
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup phy port number. We allow override via hints
|
||||
* to handle different board configs.
|
||||
*/
|
||||
if (!override_unit(dev, "phy", &sc->sc_phy, 0, MII_NPHY-1))
|
||||
sc->sc_phy = npeconfig[unit].phy;
|
||||
|
||||
KASSERT(npes[npeconfig[unit].npeid] == NULL,
|
||||
("npe %u already setup", npeconfig[unit].npeid));
|
||||
npes[npeconfig[unit].npeid] = sc;
|
||||
KASSERT(npes[sc->sc_npeid] == NULL,
|
||||
("npe %u already setup", sc->sc_npeid));
|
||||
npes[sc->sc_npeid] = sc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -744,33 +844,26 @@ static void
|
||||
npe_deactivate(device_t dev)
|
||||
{
|
||||
struct npe_softc *sc = device_get_softc(dev);
|
||||
int unit = device_get_unit(dev);
|
||||
|
||||
npes[npeconfig[unit].npeid] = NULL;
|
||||
npes[sc->sc_npeid] = NULL;
|
||||
|
||||
/* XXX disable q's */
|
||||
if (sc->sc_npe != NULL)
|
||||
if (sc->sc_npe != NULL) {
|
||||
ixpnpe_stop(sc->sc_npe);
|
||||
ixpnpe_detach(sc->sc_npe);
|
||||
}
|
||||
if (sc->sc_stats != NULL) {
|
||||
bus_dmamap_unload(sc->sc_stats_tag, sc->sc_stats_map);
|
||||
bus_dmamem_free(sc->sc_stats_tag, sc->sc_stats,
|
||||
sc->sc_stats_map);
|
||||
bus_dmamap_destroy(sc->sc_stats_tag, sc->sc_stats_map);
|
||||
}
|
||||
if (sc->sc_stats_tag != NULL)
|
||||
bus_dma_tag_destroy(sc->sc_stats_tag);
|
||||
npe_dma_destroy(sc, &sc->txdma);
|
||||
npe_dma_destroy(sc, &sc->rxdma);
|
||||
bus_generic_detach(sc->sc_dev);
|
||||
if (sc->sc_mii)
|
||||
if (sc->sc_mii != NULL)
|
||||
device_delete_child(sc->sc_dev, sc->sc_mii);
|
||||
#if 0
|
||||
/* XXX sc_ioh and sc_miih */
|
||||
if (sc->mem_res)
|
||||
bus_release_resource(dev, SYS_RES_IOPORT,
|
||||
rman_get_rid(sc->mem_res), sc->mem_res);
|
||||
sc->mem_res = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@ -867,7 +960,7 @@ npe_tick(void *xsc)
|
||||
* code that talks via the mailbox's (except at setup).
|
||||
* This likely can be handled better.
|
||||
*/
|
||||
if (ixpnpe_recvmsg(sc->sc_npe, msg) == 0 && msg[0] == ACK) {
|
||||
if (ixpnpe_recvmsg_async(sc->sc_npe, msg) == 0 && msg[0] == ACK) {
|
||||
bus_dmamap_sync(sc->sc_stats_tag, sc->sc_stats_map,
|
||||
BUS_DMASYNC_POSTREAD);
|
||||
npe_addstats(sc);
|
||||
@ -1139,10 +1232,7 @@ if (ifp->if_drv_flags & IFF_DRV_RUNNING) return;/*XXX*/
|
||||
/*
|
||||
* Reset MAC core.
|
||||
*/
|
||||
WR4(sc, NPE_MAC_CORE_CNTRL, NPE_CORE_RESET);
|
||||
DELAY(NPE_MAC_RESET_DELAY);
|
||||
/* configure MAC to generate MDC clock */
|
||||
WR4(sc, NPE_MAC_CORE_CNTRL, NPE_CORE_MDC_EN);
|
||||
npe_mac_reset(sc);
|
||||
|
||||
/* disable transmitter and reciver in the MAC */
|
||||
WR4(sc, NPE_MAC_RX_CNTRL1,
|
||||
@ -1470,12 +1560,22 @@ npeioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
|
||||
static int
|
||||
npe_setrxqosentry(struct npe_softc *sc, int classix, int trafclass, int qid)
|
||||
{
|
||||
int npeid = npeconfig[device_get_unit(sc->sc_dev)].npeid;
|
||||
uint32_t msg[2];
|
||||
|
||||
msg[0] = (NPE_SETRXQOSENTRY << 24) | (npeid << 20) | classix;
|
||||
msg[0] = (NPE_SETRXQOSENTRY << 24) | (sc->sc_npeid << 20) | classix;
|
||||
msg[1] = (trafclass << 24) | (1 << 23) | (qid << 16) | (qid << 4);
|
||||
return ixpnpe_sendandrecvmsg(sc->sc_npe, msg, msg);
|
||||
return ixpnpe_sendandrecvmsg_sync(sc->sc_npe, msg, msg);
|
||||
}
|
||||
|
||||
static int
|
||||
npe_setfirewallmode(struct npe_softc *sc, int onoff)
|
||||
{
|
||||
uint32_t msg[2];
|
||||
|
||||
/* XXX honor onoff */
|
||||
msg[0] = (NPE_SETFIREWALLMODE << 24) | (sc->sc_npeid << 20);
|
||||
msg[1] = 0;
|
||||
return ixpnpe_sendandrecvmsg_sync(sc->sc_npe, msg, msg);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1488,7 +1588,7 @@ npe_updatestats(struct npe_softc *sc)
|
||||
|
||||
msg[0] = NPE_RESETSTATS << NPE_MAC_MSGID_SHL;
|
||||
msg[1] = sc->sc_stats_phys; /* physical address of stat block */
|
||||
return ixpnpe_sendmsg(sc->sc_npe, msg); /* NB: no recv */
|
||||
return ixpnpe_sendmsg_async(sc->sc_npe, msg);
|
||||
}
|
||||
|
||||
#if 0
|
||||
@ -1515,7 +1615,7 @@ npe_getimageid(struct npe_softc *sc)
|
||||
|
||||
msg[0] = NPE_GETSTATUS << NPE_MAC_MSGID_SHL;
|
||||
msg[1] = 0;
|
||||
return ixpnpe_sendandrecvmsg(sc->sc_npe, msg, msg) == 0 ? msg[1] : 0;
|
||||
return ixpnpe_sendandrecvmsg_sync(sc->sc_npe, msg, msg) == 0 ? msg[1] : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1528,7 +1628,7 @@ npe_setloopback(struct npe_softc *sc, int ena)
|
||||
|
||||
msg[0] = (NPE_SETLOOPBACK << NPE_MAC_MSGID_SHL) | (ena != 0);
|
||||
msg[1] = 0;
|
||||
return ixpnpe_sendandrecvmsg(sc->sc_npe, msg, msg);
|
||||
return ixpnpe_sendandrecvmsg_sync(sc->sc_npe, msg, msg);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1545,10 +1645,13 @@ npe_child_detached(device_t dev, device_t child)
|
||||
/*
|
||||
* MII bus support routines.
|
||||
*/
|
||||
#define MII_RD4(sc, reg) bus_space_read_4(sc->sc_iot, sc->sc_miih, reg)
|
||||
#define MII_WR4(sc, reg, v) \
|
||||
bus_space_write_4(sc->sc_iot, sc->sc_miih, reg, v)
|
||||
|
||||
static uint32_t
|
||||
npe_mii_mdio_read(struct npe_softc *sc, int reg)
|
||||
{
|
||||
#define MII_RD4(sc, reg) bus_space_read_4(sc->sc_iot, sc->sc_miih, reg)
|
||||
uint32_t v;
|
||||
|
||||
/* NB: registers are known to be sequential */
|
||||
@ -1557,37 +1660,34 @@ npe_mii_mdio_read(struct npe_softc *sc, int reg)
|
||||
v |= (MII_RD4(sc, reg+8) & 0xff) << 16;
|
||||
v |= (MII_RD4(sc, reg+12) & 0xff) << 24;
|
||||
return v;
|
||||
#undef MII_RD4
|
||||
}
|
||||
|
||||
static void
|
||||
npe_mii_mdio_write(struct npe_softc *sc, int reg, uint32_t cmd)
|
||||
{
|
||||
#define MII_WR4(sc, reg, v) \
|
||||
bus_space_write_4(sc->sc_iot, sc->sc_miih, reg, v)
|
||||
|
||||
/* NB: registers are known to be sequential */
|
||||
MII_WR4(sc, reg+0, cmd & 0xff);
|
||||
MII_WR4(sc, reg+4, (cmd >> 8) & 0xff);
|
||||
MII_WR4(sc, reg+8, (cmd >> 16) & 0xff);
|
||||
MII_WR4(sc, reg+12, (cmd >> 24) & 0xff);
|
||||
#undef MII_WR4
|
||||
}
|
||||
|
||||
static int
|
||||
npe_mii_mdio_wait(struct npe_softc *sc)
|
||||
{
|
||||
#define MAXTRIES 100 /* XXX */
|
||||
uint32_t v;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAXTRIES; i++) {
|
||||
/* NB: typically this takes 25-30 trips */
|
||||
for (i = 0; i < 1000; i++) {
|
||||
v = npe_mii_mdio_read(sc, NPE_MAC_MDIO_CMD);
|
||||
if ((v & NPE_MII_GO) == 0)
|
||||
return 1;
|
||||
DELAY(1);
|
||||
}
|
||||
device_printf(sc->sc_dev, "%s: timeout after ~1ms, cmd 0x%x\n",
|
||||
__func__, v);
|
||||
return 0; /* NB: timeout */
|
||||
#undef MAXTRIES
|
||||
}
|
||||
|
||||
static int
|
||||
@ -1598,15 +1698,13 @@ npe_miibus_readreg(device_t dev, int phy, int reg)
|
||||
|
||||
if (phy != sc->sc_phy) /* XXX no auto-detect */
|
||||
return 0xffff;
|
||||
v = (phy << NPE_MII_ADDR_SHL) | (reg << NPE_MII_REG_SHL)
|
||||
| NPE_MII_GO;
|
||||
v = (phy << NPE_MII_ADDR_SHL) | (reg << NPE_MII_REG_SHL) | NPE_MII_GO;
|
||||
npe_mii_mdio_write(sc, NPE_MAC_MDIO_CMD, v);
|
||||
if (npe_mii_mdio_wait(sc))
|
||||
v = npe_mii_mdio_read(sc, NPE_MAC_MDIO_STS);
|
||||
else
|
||||
v = 0xffff | NPE_MII_READ_FAIL;
|
||||
return (v & NPE_MII_READ_FAIL) ? 0xffff : (v & 0xffff);
|
||||
#undef MAXTRIES
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -84,12 +84,6 @@ struct npehwbuf {
|
||||
} ix_ne[NPE_MAXSEG];
|
||||
};
|
||||
|
||||
/* NPE ID's */
|
||||
#define NPE_A 0
|
||||
#define NPE_B 1
|
||||
#define NPE_C 2
|
||||
#define NPE_MAX (NPE_C+1)
|
||||
|
||||
#define NPE_PORTS_MAX 2 /* logical ports */
|
||||
#define NPE_FRAME_SIZE_DEFAULT 1536
|
||||
#define NPE_FRAME_SIZE_MAX (65536-64)
|
||||
|
@ -58,59 +58,16 @@ __FBSDID("$FreeBSD$");
|
||||
volatile uint32_t intr_enabled;
|
||||
uint32_t intr_steer = 0;
|
||||
|
||||
/* ixp43x et. al have +32 IRQ's */
|
||||
volatile uint32_t intr_enabled2;
|
||||
uint32_t intr_steer2 = 0;
|
||||
|
||||
struct ixp425_softc *ixp425_softc = NULL;
|
||||
|
||||
static int ixp425_probe(device_t);
|
||||
static void ixp425_identify(driver_t *, device_t);
|
||||
static int ixp425_attach(device_t);
|
||||
|
||||
static struct {
|
||||
uint32_t hwbase;
|
||||
uint32_t size;
|
||||
uint32_t vbase;
|
||||
} hwvtrans[] = {
|
||||
{ IXP425_IO_HWBASE, IXP425_IO_SIZE, IXP425_IO_VBASE },
|
||||
{ IXP425_EXP_HWBASE, IXP425_EXP_SIZE, IXP425_EXP_VBASE },
|
||||
{ IXP425_PCI_HWBASE, IXP425_PCI_SIZE, IXP425_PCI_VBASE },
|
||||
{ IXP425_PCI_MEM_HWBASE,IXP425_PCI_MEM_SIZE, IXP425_PCI_MEM_VBASE },
|
||||
#if 0
|
||||
{ IXP425_PCI_IO_HWBASE, IXP425_PCI_IO_SIZE, IXP425_PCI_IO_VBASE },
|
||||
#endif
|
||||
{ IXP425_MCU_HWBASE, IXP425_MCU_SIZE, IXP425_MCU_VBASE },
|
||||
{ IXP425_QMGR_HWBASE, IXP425_QMGR_SIZE, IXP425_QMGR_VBASE },
|
||||
{ IXP425_NPE_A_HWBASE, IXP425_NPE_A_SIZE, IXP425_NPE_A_VBASE },
|
||||
{ IXP425_NPE_B_HWBASE, IXP425_NPE_B_SIZE, IXP425_NPE_B_VBASE },
|
||||
{ IXP425_NPE_C_HWBASE, IXP425_NPE_C_SIZE, IXP425_NPE_C_VBASE },
|
||||
{ IXP425_MAC_A_HWBASE, IXP425_MAC_A_SIZE, IXP425_MAC_A_VBASE },
|
||||
{ IXP425_MAC_B_HWBASE, IXP425_MAC_B_SIZE, IXP425_MAC_B_VBASE },
|
||||
/* Gateworks Avila IDE/CF is mapped here */
|
||||
{ IXP425_EXP_BUS_CS1_HWBASE, IXP425_EXP_BUS_SIZE,
|
||||
IXP425_EXP_BUS_CS1_VBASE },
|
||||
{ IXP425_EXP_BUS_CS2_HWBASE, IXP425_EXP_BUS_SIZE,
|
||||
IXP425_EXP_BUS_CS2_VBASE },
|
||||
/* ADI Pronghorn Metro IDE/CF is mapped here */
|
||||
{ IXP425_EXP_BUS_CS3_HWBASE, IXP425_EXP_BUS_SIZE,
|
||||
IXP425_EXP_BUS_CS3_VBASE },
|
||||
{ IXP425_EXP_BUS_CS4_HWBASE, IXP425_EXP_BUS_SIZE,
|
||||
IXP425_EXP_BUS_CS4_VBASE },
|
||||
};
|
||||
|
||||
int
|
||||
getvbase(uint32_t hwbase, uint32_t size, uint32_t *vbase)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sizeof hwvtrans / sizeof *hwvtrans; i++) {
|
||||
if (hwbase >= hwvtrans[i].hwbase &&
|
||||
hwbase + size <= hwvtrans[i].hwbase + hwvtrans[i].size) {
|
||||
*vbase = hwbase - hwvtrans[i].hwbase + hwvtrans[i].vbase;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
return (ENOENT);
|
||||
}
|
||||
|
||||
struct arm32_dma_range *
|
||||
bus_dma_get_range(void)
|
||||
{
|
||||
@ -146,11 +103,16 @@ arm_mask_irq(uintptr_t nb)
|
||||
int i;
|
||||
|
||||
i = disable_interrupts(I32_bit);
|
||||
intr_enabled &= ~(1 << nb);
|
||||
ixp425_set_intrmask();
|
||||
if (nb < 32) {
|
||||
intr_enabled &= ~(1 << nb);
|
||||
ixp425_set_intrmask();
|
||||
} else {
|
||||
intr_enabled2 &= ~(1 << (nb - 32));
|
||||
ixp435_set_intrmask();
|
||||
}
|
||||
restore_interrupts(i);
|
||||
/*XXX; If it's a GPIO interrupt, ACK it know. Can it be a problem ?*/
|
||||
if ((1 << nb) & IXP425_INT_GPIOMASK)
|
||||
if (nb < 32 && ((1 << nb) & IXP425_INT_GPIOMASK))
|
||||
IXPREG(IXP425_GPIO_VBASE + IXP425_GPIO_GPISR) =
|
||||
ixp425_irq2gpio_bit(nb);
|
||||
}
|
||||
@ -161,8 +123,13 @@ arm_unmask_irq(uintptr_t nb)
|
||||
int i;
|
||||
|
||||
i = disable_interrupts(I32_bit);
|
||||
intr_enabled |= (1 << nb);
|
||||
ixp425_set_intrmask();
|
||||
if (nb < 32) {
|
||||
intr_enabled |= (1 << nb);
|
||||
ixp425_set_intrmask();
|
||||
} else {
|
||||
intr_enabled2 |= (1 << (nb - 32));
|
||||
ixp435_set_intrmask();
|
||||
}
|
||||
restore_interrupts(i);
|
||||
}
|
||||
|
||||
@ -172,13 +139,21 @@ ixp425_irq_read(void)
|
||||
return IXPREG(IXP425_INT_STATUS) & intr_enabled;
|
||||
}
|
||||
|
||||
static __inline uint32_t
|
||||
ixp435_irq_read(void)
|
||||
{
|
||||
return IXPREG(IXP435_INT_STATUS2) & intr_enabled2;
|
||||
}
|
||||
|
||||
int
|
||||
arm_get_next_irq(void)
|
||||
{
|
||||
int irq;
|
||||
uint32_t irq;
|
||||
|
||||
if ((irq = ixp425_irq_read()))
|
||||
return (ffs(irq) - 1);
|
||||
if (cpu_is_ixp43x() && (irq = ixp435_irq_read()))
|
||||
return (32 + ffs(irq) - 1);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
@ -206,7 +181,7 @@ ixp425_identify(driver_t *driver, device_t parent)
|
||||
static int
|
||||
ixp425_probe(device_t dev)
|
||||
{
|
||||
device_set_desc(dev, "Intel IXP425");
|
||||
device_set_desc(dev, "Intel IXP4XX");
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -217,29 +192,34 @@ ixp425_attach(device_t dev)
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
sc->sc_iot = &ixp425_bs_tag;
|
||||
KASSERT(ixp425_softc == NULL, ("ixp425_attach called twice?"));
|
||||
KASSERT(ixp425_softc == NULL, ("%s called twice?", __func__));
|
||||
ixp425_softc = sc;
|
||||
|
||||
intr_enabled = 0;
|
||||
ixp425_set_intrmask();
|
||||
ixp425_set_intrsteer();
|
||||
if (cpu_is_ixp43x()) {
|
||||
intr_enabled2 = 0;
|
||||
ixp435_set_intrmask();
|
||||
ixp435_set_intrsteer();
|
||||
}
|
||||
|
||||
if (bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT,
|
||||
BUS_SPACE_MAXADDR, NULL, NULL, 0xffffffff, 0xff, 0xffffffff, 0,
|
||||
NULL, NULL, &sc->sc_dmat))
|
||||
panic("couldn't create the IXP425 dma tag !");
|
||||
panic("%s: failed to create dma tag", __func__);
|
||||
|
||||
sc->sc_irq_rman.rm_type = RMAN_ARRAY;
|
||||
sc->sc_irq_rman.rm_descr = "IXP425 IRQs";
|
||||
sc->sc_irq_rman.rm_descr = "IXP4XX IRQs";
|
||||
if (rman_init(&sc->sc_irq_rman) != 0 ||
|
||||
rman_manage_region(&sc->sc_irq_rman, 0, 31) != 0)
|
||||
panic("ixp425_attach: failed to set up IRQ rman");
|
||||
rman_manage_region(&sc->sc_irq_rman, 0, cpu_is_ixp43x() ? 63 : 31) != 0)
|
||||
panic("%s: failed to set up IRQ rman", __func__);
|
||||
|
||||
sc->sc_mem_rman.rm_type = RMAN_ARRAY;
|
||||
sc->sc_mem_rman.rm_descr = "IXP425 Memory";
|
||||
sc->sc_mem_rman.rm_descr = "IXP4XX Memory";
|
||||
if (rman_init(&sc->sc_mem_rman) != 0 ||
|
||||
rman_manage_region(&sc->sc_mem_rman, 0, ~0) != 0)
|
||||
panic("ixp425_attach: failed to set up memory rman");
|
||||
panic("%s: failed to set up memory rman", __func__);
|
||||
|
||||
BUS_ADD_CHILD(dev, 0, "pcib", 0);
|
||||
BUS_ADD_CHILD(dev, 0, "ixpclk", 0);
|
||||
@ -252,10 +232,10 @@ ixp425_attach(device_t dev)
|
||||
|
||||
if (bus_space_map(sc->sc_iot, IXP425_GPIO_HWBASE, IXP425_GPIO_SIZE,
|
||||
0, &sc->sc_gpio_ioh))
|
||||
panic("ixp425_attach: unable to map GPIO registers");
|
||||
panic("%s: unable to map GPIO registers", __func__);
|
||||
if (bus_space_map(sc->sc_iot, IXP425_EXP_HWBASE, IXP425_EXP_SIZE,
|
||||
0, &sc->sc_exp_ioh))
|
||||
panic("ixp425_attach: unable to map Expansion Bus registers");
|
||||
panic("%s: unable to map Expansion Bus registers", __func__);
|
||||
|
||||
bus_generic_probe(dev);
|
||||
bus_generic_attach(dev);
|
||||
@ -317,6 +297,44 @@ ixp425_read_ivar(device_t bus, device_t child, int which, u_char *result)
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* NB: This table handles P->V translations for regions mapped
|
||||
* through bus_alloc_resource. Anything done with bus_space_map
|
||||
* is handled elsewhere and does not require an entry here.
|
||||
*
|
||||
* XXX getvbase is also used by uart_cpu_getdev (hence public)
|
||||
*/
|
||||
static const struct {
|
||||
uint32_t hwbase;
|
||||
uint32_t size;
|
||||
uint32_t vbase;
|
||||
} hwvtrans[] = {
|
||||
{ IXP425_IO_HWBASE, IXP425_IO_SIZE, IXP425_IO_VBASE },
|
||||
{ IXP425_PCI_HWBASE, IXP425_PCI_SIZE, IXP425_PCI_VBASE },
|
||||
{ IXP425_PCI_MEM_HWBASE,IXP425_PCI_MEM_SIZE, IXP425_PCI_MEM_VBASE },
|
||||
/* NB: needed only for uart_cpu_getdev */
|
||||
{ IXP425_UART0_HWBASE, IXP425_REG_SIZE, IXP425_UART0_VBASE },
|
||||
{ IXP425_UART1_HWBASE, IXP425_REG_SIZE, IXP425_UART1_VBASE },
|
||||
/* NB: need for ixp435 ehci controllers */
|
||||
{ IXP435_USB1_HWBASE, IXP435_USB1_SIZE, IXP435_USB1_VBASE },
|
||||
{ IXP435_USB2_HWBASE, IXP435_USB2_SIZE, IXP435_USB2_VBASE },
|
||||
};
|
||||
|
||||
int
|
||||
getvbase(uint32_t hwbase, uint32_t size, uint32_t *vbase)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sizeof hwvtrans / sizeof *hwvtrans; i++) {
|
||||
if (hwbase >= hwvtrans[i].hwbase &&
|
||||
hwbase + size <= hwvtrans[i].hwbase + hwvtrans[i].size) {
|
||||
*vbase = hwbase - hwvtrans[i].hwbase + hwvtrans[i].vbase;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
return (ENOENT);
|
||||
}
|
||||
|
||||
static struct resource *
|
||||
ixp425_alloc_resource(device_t dev, device_t child, int type, int *rid,
|
||||
u_long start, u_long end, u_long count, u_int flags)
|
||||
@ -346,8 +364,12 @@ ixp425_alloc_resource(device_t dev, device_t child, int type, int *rid,
|
||||
start = addr;
|
||||
end = start + 0x1000; /* XXX */
|
||||
}
|
||||
if (getvbase(start, end - start, &vbase))
|
||||
if (getvbase(start, end - start, &vbase) != 0) {
|
||||
/* likely means above table needs to be updated */
|
||||
device_printf(dev, "%s: no mapping for 0x%lx:0x%lx\n",
|
||||
__func__, start, end-start);
|
||||
return NULL;
|
||||
}
|
||||
rv = rman_reserve_resource(rmanp, start, end, count,
|
||||
flags, child);
|
||||
if (rv != NULL) {
|
||||
@ -366,22 +388,43 @@ ixp425_alloc_resource(device_t dev, device_t child, int type, int *rid,
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int
|
||||
ixp425_setup_intr(device_t dev, device_t child,
|
||||
struct resource *ires, int flags, driver_filter_t *filt,
|
||||
driver_intr_t *intr, void *arg, void **cookiep)
|
||||
static __inline void
|
||||
get_masks(struct resource *res, uint32_t *mask, uint32_t *mask2)
|
||||
{
|
||||
uint32_t mask;
|
||||
int i;
|
||||
|
||||
BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags, filt, intr,
|
||||
*mask = 0;
|
||||
for (i = rman_get_start(res); i < 32 && i <= rman_get_end(res); i++)
|
||||
*mask |= 1 << i;
|
||||
*mask2 = 0;
|
||||
for (; i <= rman_get_end(res); i++)
|
||||
*mask2 |= 1 << (i - 32);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
update_masks(uint32_t mask, uint32_t mask2)
|
||||
{
|
||||
|
||||
intr_enabled = mask;
|
||||
ixp425_set_intrmask();
|
||||
if (cpu_is_ixp43x()) {
|
||||
intr_enabled2 = mask2;
|
||||
ixp435_set_intrmask();
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
ixp425_setup_intr(device_t dev, device_t child,
|
||||
struct resource *res, int flags, driver_filter_t *filt,
|
||||
driver_intr_t *intr, void *arg, void **cookiep)
|
||||
{
|
||||
uint32_t mask, mask2;
|
||||
|
||||
BUS_SETUP_INTR(device_get_parent(dev), child, res, flags, filt, intr,
|
||||
arg, cookiep);
|
||||
|
||||
mask = 0;
|
||||
for (i = rman_get_start(ires); i <= rman_get_end(ires); i++)
|
||||
mask |= 1 << i;
|
||||
intr_enabled |= mask;
|
||||
ixp425_set_intrmask();
|
||||
get_masks(res, &mask, &mask2);
|
||||
update_masks(intr_enabled | mask, intr_enabled2 | mask2);
|
||||
|
||||
return (0);
|
||||
}
|
||||
@ -390,14 +433,10 @@ static int
|
||||
ixp425_teardown_intr(device_t dev, device_t child, struct resource *res,
|
||||
void *cookie)
|
||||
{
|
||||
uint32_t mask;
|
||||
int i;
|
||||
uint32_t mask, mask2;
|
||||
|
||||
mask = 0;
|
||||
for (i = rman_get_start(res); i <= rman_get_end(res); i++)
|
||||
mask |= 1 << i;
|
||||
intr_enabled &= ~mask;
|
||||
ixp425_set_intrmask();
|
||||
get_masks(res, &mask, &mask2);
|
||||
update_masks(intr_enabled &~ mask, intr_enabled2 &~ mask2);
|
||||
|
||||
return (BUS_TEARDOWN_INTR(device_get_parent(dev), child, res, cookie));
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ static struct ixpiic_softc *ixpiic_sc = NULL;
|
||||
static int
|
||||
ixpiic_probe(device_t dev)
|
||||
{
|
||||
device_set_desc(dev, "IXP425 GPIO-Based I2C Interface");
|
||||
device_set_desc(dev, "IXP4XX GPIO-Based I2C Interface");
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
@ -69,81 +69,21 @@ ixp425_set_intrsteer(void)
|
||||
IXPREG(IXP425_INT_SELECT) = intr_steer & IXP425_INT_HWMASK;
|
||||
}
|
||||
|
||||
#define INT_SWMASK \
|
||||
((1U << IXP425_INT_bit31) | (1U << IXP425_INT_bit30) | \
|
||||
(1U << IXP425_INT_bit14) | (1U << IXP425_INT_bit11))
|
||||
extern __volatile uint32_t intr_enabled2;
|
||||
extern uint32_t intr_steer2;
|
||||
|
||||
#if 0
|
||||
static __inline void __attribute__((__unused__))
|
||||
ixp425_splx(int new)
|
||||
ixp435_set_intrmask(void)
|
||||
{
|
||||
extern __volatile uint32_t intr_enabled;
|
||||
extern __volatile int current_spl_level;
|
||||
extern __volatile int ixp425_ipending;
|
||||
extern void ixp425_do_pending(void);
|
||||
int oldirqstate, hwpend;
|
||||
|
||||
/* Don't let the compiler re-order this code with preceding code */
|
||||
__insn_barrier();
|
||||
|
||||
current_spl_level = new;
|
||||
|
||||
hwpend = (ixp425_ipending & IXP425_INT_HWMASK) & ~new;
|
||||
if (hwpend != 0) {
|
||||
oldirqstate = disable_interrupts(I32_bit);
|
||||
intr_enabled |= hwpend;
|
||||
ixp425_set_intrmask();
|
||||
restore_interrupts(oldirqstate);
|
||||
}
|
||||
|
||||
if ((ixp425_ipending & INT_SWMASK) & ~new)
|
||||
ixp425_do_pending();
|
||||
IXPREG(IXP435_INT_ENABLE2) = intr_enabled2 & IXP435_INT_HWMASK;
|
||||
}
|
||||
|
||||
static __inline int __attribute__((__unused__))
|
||||
ixp425_splraise(int ipl)
|
||||
static __inline void
|
||||
ixp435_set_intrsteer(void)
|
||||
{
|
||||
extern __volatile int current_spl_level;
|
||||
extern int ixp425_imask[];
|
||||
int old;
|
||||
|
||||
old = current_spl_level;
|
||||
current_spl_level |= ixp425_imask[ipl];
|
||||
|
||||
/* Don't let the compiler re-order this code with subsequent code */
|
||||
__insn_barrier();
|
||||
|
||||
return (old);
|
||||
IXPREG(IXP435_INT_SELECT2) = intr_steer2 & IXP435_INT_HWMASK;
|
||||
}
|
||||
|
||||
static __inline int __attribute__((__unused__))
|
||||
ixp425_spllower(int ipl)
|
||||
{
|
||||
extern __volatile int current_spl_level;
|
||||
extern int ixp425_imask[];
|
||||
int old = current_spl_level;
|
||||
|
||||
ixp425_splx(ixp425_imask[ipl]);
|
||||
return(old);
|
||||
}
|
||||
|
||||
#endif
|
||||
#if !defined(EVBARM_SPL_NOINLINE)
|
||||
|
||||
#define splx(new) ixp425_splx(new)
|
||||
#define _spllower(ipl) ixp425_spllower(ipl)
|
||||
#define _splraise(ipl) ixp425_splraise(ipl)
|
||||
void _setsoftintr(int);
|
||||
|
||||
#else
|
||||
|
||||
int _splraise(int);
|
||||
int _spllower(int);
|
||||
void splx(int);
|
||||
void _setsoftintr(int);
|
||||
|
||||
#endif /* ! EVBARM_SPL_NOINLINE */
|
||||
|
||||
#endif /* _LOCORE */
|
||||
|
||||
#endif /* _IXP425_INTR_H_ */
|
||||
|
@ -62,11 +62,10 @@ static uint32_t sdram_other[] = {
|
||||
0, 0
|
||||
};
|
||||
|
||||
#define MCU_REG_READ(x) (*(volatile uint32_t *)(IXP425_MCU_VBASE + (x)))
|
||||
|
||||
uint32_t
|
||||
ixp425_sdram_size(void)
|
||||
{
|
||||
#define MCU_REG_READ(x) (*(volatile uint32_t *)(IXP425_MCU_VBASE + (x)))
|
||||
uint32_t size, sdr_config;
|
||||
|
||||
sdr_config = MCU_REG_READ(MCU_SDR_CONFIG);
|
||||
@ -82,4 +81,22 @@ ixp425_sdram_size(void)
|
||||
}
|
||||
|
||||
return (size);
|
||||
#undef MCU_REG_READ
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ixp435_ddram_size(void)
|
||||
{
|
||||
#define MCU_REG_READ(x) (*(volatile uint32_t *)(IXP425_MCU_VBASE + (x)))
|
||||
uint32_t sbr0;
|
||||
|
||||
/*
|
||||
* Table 198, page 516 shows DDR-I/II SDRAM bank sizes
|
||||
* for SBR0 and SBR1. The manual states both banks must
|
||||
* be programmed to be the same size. We just assume
|
||||
* it's done right and calculate 2x for the memory size.
|
||||
*/
|
||||
sbr0 = MCU_REG_READ(MCU_DDR_SBR0);
|
||||
return 2 * 16*(sbr0 & 0x7f) * 1024 * 1024;
|
||||
#undef MCU_REG_READ
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -95,11 +95,18 @@
|
||||
#define NPEFW_B_DMA 0x01020100 /* DMA only */
|
||||
/* XXX ... more not include */
|
||||
|
||||
#define IXP425_NPE_B_IMAGEID 0x01000200
|
||||
#define IXP425_NPE_C_IMAGEID 0x02000200
|
||||
/* NPE ID's */
|
||||
#define NPE_A 0
|
||||
#define NPE_B 1
|
||||
#define NPE_C 2
|
||||
#define NPE_MAX (NPE_C+1)
|
||||
|
||||
#define IXP425_NPE_A_IMAGEID 0x10820200
|
||||
#define IXP425_NPE_B_IMAGEID 0x01020201
|
||||
#define IXP425_NPE_C_IMAGEID 0x02050201
|
||||
|
||||
struct ixpnpe_softc;
|
||||
struct ixpnpe_softc *ixpnpe_attach(device_t);
|
||||
struct ixpnpe_softc *ixpnpe_attach(device_t, int npeid);
|
||||
void ixpnpe_detach(struct ixpnpe_softc *);
|
||||
int ixpnpe_stopandreset(struct ixpnpe_softc *);
|
||||
int ixpnpe_start(struct ixpnpe_softc *);
|
||||
@ -108,8 +115,9 @@ int ixpnpe_init(struct ixpnpe_softc *,
|
||||
const char *imageName, uint32_t imageId);
|
||||
int ixpnpe_getfunctionality(struct ixpnpe_softc *sc);
|
||||
|
||||
int ixpnpe_sendmsg(struct ixpnpe_softc *, const uint32_t msg[2]);
|
||||
int ixpnpe_recvmsg(struct ixpnpe_softc *, uint32_t msg[2]);
|
||||
int ixpnpe_sendandrecvmsg(struct ixpnpe_softc *, const uint32_t send[2],
|
||||
uint32_t recv[2]);
|
||||
int ixpnpe_sendmsg_async(struct ixpnpe_softc *, const uint32_t msg[2]);
|
||||
int ixpnpe_recvmsg_async(struct ixpnpe_softc *, uint32_t msg[2]);
|
||||
int ixpnpe_sendandrecvmsg_sync(struct ixpnpe_softc *,
|
||||
const uint32_t send[2], uint32_t recv[2]);
|
||||
int ixpnpe_recvmsg_sync(struct ixpnpe_softc *, uint32_t msg[2]);
|
||||
#endif /* _IXP425_NPEVAR_H_ */
|
||||
|
@ -89,8 +89,7 @@ static pcib_route_interrupt_t ixppcib_route_interrupt;
|
||||
static int
|
||||
ixppcib_probe(device_t dev)
|
||||
{
|
||||
|
||||
device_set_desc(dev, "IXP425 PCI Bus");
|
||||
device_set_desc(dev, "IXP4XX PCI Bus");
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -130,8 +129,8 @@ ixppcib_attach(device_t dev)
|
||||
if (sc->sc_mem == NULL)
|
||||
panic("cannot allocate PCI MEM space");
|
||||
|
||||
#define AHB_OFFSET 0x10000000UL
|
||||
if (bus_dma_tag_create(NULL, 1, 0, AHB_OFFSET + 64 * 1024 * 1024,
|
||||
/* NB: PCI dma window is 64M so anything above must be bounced */
|
||||
if (bus_dma_tag_create(NULL, 1, 0, IXP425_AHB_OFFSET + 64 * 1024 * 1024,
|
||||
BUS_SPACE_MAXADDR, NULL, NULL, 0xffffffff, 0xff, 0xffffffff, 0,
|
||||
NULL, NULL, &sc->sc_dmat))
|
||||
panic("couldn't create the PCI dma tag !");
|
||||
@ -153,7 +152,7 @@ ixppcib_attach(device_t dev)
|
||||
|
||||
/* Initialize memory and i/o rmans. */
|
||||
sc->sc_io_rman.rm_type = RMAN_ARRAY;
|
||||
sc->sc_io_rman.rm_descr = "IXP425 PCI I/O Ports";
|
||||
sc->sc_io_rman.rm_descr = "IXP4XX PCI I/O Ports";
|
||||
if (rman_init(&sc->sc_io_rman) != 0 ||
|
||||
rman_manage_region(&sc->sc_io_rman, 0,
|
||||
IXP425_PCI_IO_SIZE) != 0) {
|
||||
@ -161,7 +160,7 @@ ixppcib_attach(device_t dev)
|
||||
}
|
||||
|
||||
sc->sc_mem_rman.rm_type = RMAN_ARRAY;
|
||||
sc->sc_mem_rman.rm_descr = "IXP425 PCI Memory";
|
||||
sc->sc_mem_rman.rm_descr = "IXP4XX PCI Memory";
|
||||
if (rman_init(&sc->sc_mem_rman) != 0 ||
|
||||
rman_manage_region(&sc->sc_mem_rman, IXP425_PCI_MEM_HWBASE,
|
||||
IXP425_PCI_MEM_HWBASE + IXP425_PCI_MEM_SIZE) != 0) {
|
||||
@ -173,20 +172,20 @@ ixppcib_attach(device_t dev)
|
||||
* begin at the physical memory start + OFFSET
|
||||
*/
|
||||
PCI_CSR_WRITE_4(sc, PCI_AHBMEMBASE,
|
||||
(AHB_OFFSET & 0xFF000000) +
|
||||
((AHB_OFFSET & 0xFF000000) >> 8) +
|
||||
((AHB_OFFSET & 0xFF000000) >> 16) +
|
||||
((AHB_OFFSET & 0xFF000000) >> 24) +
|
||||
(IXP425_AHB_OFFSET & 0xFF000000) +
|
||||
((IXP425_AHB_OFFSET & 0xFF000000) >> 8) +
|
||||
((IXP425_AHB_OFFSET & 0xFF000000) >> 16) +
|
||||
((IXP425_AHB_OFFSET & 0xFF000000) >> 24) +
|
||||
0x00010203);
|
||||
|
||||
#define IXPPCIB_WRITE_CONF(sc, reg, val) \
|
||||
ixp425_pci_conf_reg_write(sc, reg, val)
|
||||
/* Write Mapping registers PCI Configuration Registers */
|
||||
/* Base Address 0 - 3 */
|
||||
IXPPCIB_WRITE_CONF(sc, PCI_MAPREG_BAR0, AHB_OFFSET + 0x00000000);
|
||||
IXPPCIB_WRITE_CONF(sc, PCI_MAPREG_BAR1, AHB_OFFSET + 0x01000000);
|
||||
IXPPCIB_WRITE_CONF(sc, PCI_MAPREG_BAR2, AHB_OFFSET + 0x02000000);
|
||||
IXPPCIB_WRITE_CONF(sc, PCI_MAPREG_BAR3, AHB_OFFSET + 0x03000000);
|
||||
IXPPCIB_WRITE_CONF(sc, PCI_MAPREG_BAR0, IXP425_AHB_OFFSET + 0x00000000);
|
||||
IXPPCIB_WRITE_CONF(sc, PCI_MAPREG_BAR1, IXP425_AHB_OFFSET + 0x01000000);
|
||||
IXPPCIB_WRITE_CONF(sc, PCI_MAPREG_BAR2, IXP425_AHB_OFFSET + 0x02000000);
|
||||
IXPPCIB_WRITE_CONF(sc, PCI_MAPREG_BAR3, IXP425_AHB_OFFSET + 0x03000000);
|
||||
|
||||
/* Base Address 4 */
|
||||
IXPPCIB_WRITE_CONF(sc, PCI_MAPREG_BAR4, 0xffffffff);
|
||||
|
@ -161,7 +161,7 @@ struct ixpqmgr_softc {
|
||||
|
||||
static int qmgr_debug = 0;
|
||||
SYSCTL_INT(_debug, OID_AUTO, qmgr, CTLFLAG_RW, &qmgr_debug,
|
||||
0, "IXP425 Q-Manager debug msgs");
|
||||
0, "IXP4XX Q-Manager debug msgs");
|
||||
TUNABLE_INT("debug.qmgr", &qmgr_debug);
|
||||
#define DPRINTF(dev, fmt, ...) do { \
|
||||
if (qmgr_debug) printf(fmt, __VA_ARGS__); \
|
||||
@ -204,7 +204,7 @@ aqm_reg_write(struct ixpqmgr_softc *sc, bus_size_t off, uint32_t val)
|
||||
static int
|
||||
ixpqmgr_probe(device_t dev)
|
||||
{
|
||||
device_set_desc(dev, "IXP425 Q-Manager");
|
||||
device_set_desc(dev, "IXP4XX Q-Manager");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -86,14 +86,14 @@ static struct timecounter ixp425_timer_timecounter = {
|
||||
NULL, /* no poll_pps */
|
||||
~0u, /* counter_mask */
|
||||
COUNTS_PER_SEC, /* frequency */
|
||||
"IXP425 Timer", /* name */
|
||||
"IXP4XX Timer", /* name */
|
||||
1000, /* quality */
|
||||
};
|
||||
|
||||
static int
|
||||
ixpclk_probe(device_t dev)
|
||||
{
|
||||
device_set_desc(dev, "IXP425 Timer");
|
||||
device_set_desc(dev, "IXP4XX Timer");
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,7 @@
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/*
|
||||
* IXP425 Watchdog Timer Support.
|
||||
* IXP4XX Watchdog Timer Support.
|
||||
*/
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
@ -88,7 +88,7 @@ ixp425_watchdog(void *arg, u_int cmd, int *error)
|
||||
static int
|
||||
ixpwdog_probe(device_t dev)
|
||||
{
|
||||
device_set_desc(dev, "IXP425 Watchdog Timer");
|
||||
device_set_desc(dev, "IXP4XX Watchdog Timer");
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
@ -64,31 +64,52 @@
|
||||
*
|
||||
* 4000 0000 ---------------------------
|
||||
* SDRAM
|
||||
* 1000 0000 ---------------------------
|
||||
* 0000 0000 ---------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
* Virtual memory map for the Intel IXP425 integrated devices
|
||||
* Virtual memory map for the Intel IXP425/IXP435 integrated devices
|
||||
*/
|
||||
/*
|
||||
* FFFF FFFF ---------------------------
|
||||
*
|
||||
* Global cache clean area
|
||||
* FF00 0000 ---------------------------
|
||||
*
|
||||
* FC00 0000 ---------------------------
|
||||
* PCI Data (memory space)
|
||||
* F800 0000 ---------------------------
|
||||
* F800 0000 --------------------------- IXP425_PCI_MEM_VBASE
|
||||
*
|
||||
* F020 1000 ---------------------------
|
||||
* SDRAM Controller
|
||||
* F020 0000 ---------------------------
|
||||
* SDRAM/DDR Memory Controller
|
||||
* F020 0000 --------------------------- IXP425_MCU_VBASE
|
||||
*
|
||||
* F001 2000 ---------------------------
|
||||
* PCI Configuration and Status Registers
|
||||
* F001 1000 ---------------------------
|
||||
* Expansion bus Configuration Registers
|
||||
* F001 0000 ---------------------------
|
||||
* System and Peripheral Registers
|
||||
* VA F000 0000 = PA C800 0000 (SIZE 0x10000)
|
||||
* F000 0000 ---------------------------
|
||||
* F001 7000 EHCI USB 2 (IXP435)
|
||||
* F001 6000 EHCI USB 1 (IXP435)
|
||||
* F020 6000 ---------------------------
|
||||
* Queue manager
|
||||
* F001 2000 --------------------------- IXP425_QMGR_VBASE
|
||||
* PCI Configuration and Status
|
||||
* F001 1000 --------------------------- IXP425_PCI_VBASE
|
||||
* Expansion Bus Configuration
|
||||
* F001 0000 --------------------------- IXP425_EXP_VBASE
|
||||
* F000 F000 Expansion Bus Chip Select 4
|
||||
* F000 E000 Expansion Bus Chip Select 3
|
||||
* F000 D000 Expansion Bus Chip Select 2
|
||||
* F000 C000 Expansion Bus Chip Select 1
|
||||
* F000 B000 USB (option on IXP425)
|
||||
* F000 A000 MAC-B (IXP425) | MAC-C (IXP435)
|
||||
* F000 9000 MAC-A
|
||||
* F000 8000 NPE-C
|
||||
* F000 7000 NPE-B (IXP425)
|
||||
* F000 6000 NPE-A
|
||||
* F000 5000 Timers
|
||||
* F000 4000 GPIO Controller
|
||||
* F000 3000 Interrupt Controller
|
||||
* F000 2000 Performance Monitor Controller (PMC)
|
||||
* F000 1000 UART 1 (IXP425)
|
||||
* F000 0000 UART 0
|
||||
* F000 0000 --------------------------- IXP425_IO_VBASE
|
||||
*
|
||||
* 0000 0000 ---------------------------
|
||||
*
|
||||
@ -111,9 +132,10 @@
|
||||
#define IXP425_NPE_A_OFFSET 0x00006000UL /* Not User Programmable */
|
||||
#define IXP425_NPE_B_OFFSET 0x00007000UL /* Not User Programmable */
|
||||
#define IXP425_NPE_C_OFFSET 0x00008000UL /* Not User Programmable */
|
||||
#define IXP425_MAC_A_OFFSET 0x00009000UL
|
||||
#define IXP425_MAC_B_OFFSET 0x0000a000UL
|
||||
#define IXP425_MAC_B_OFFSET 0x00009000UL /* Ethernet MAC on NPE-B */
|
||||
#define IXP425_MAC_C_OFFSET 0x0000a000UL /* Ethernet MAC on NPE-C */
|
||||
#define IXP425_USB_OFFSET 0x0000b000UL
|
||||
#define IXP435_MAC_A_OFFSET 0x0000c000UL /* Ethernet MAC on NPE-A */
|
||||
|
||||
#define IXP425_REG_SIZE 0x1000
|
||||
|
||||
@ -142,7 +164,6 @@
|
||||
|
||||
/*
|
||||
* Timers
|
||||
*
|
||||
*/
|
||||
#define IXP425_TIMER_HWBASE (IXP425_IO_HWBASE + IXP425_TIMER_OFFSET)
|
||||
#define IXP425_TIMER_VBASE (IXP425_IO_VBASE + IXP425_TIMER_OFFSET)
|
||||
@ -224,6 +245,18 @@
|
||||
#define IXP425_INT_NPE_B 1 /* NPE B */
|
||||
#define IXP425_INT_NPE_A 0 /* NPE A */
|
||||
|
||||
/* NB: IXP435 has an additional 32 IRQ's */
|
||||
#define IXP435_INT_STATUS2 (IXP425_IRQ_VBASE + 0x20)
|
||||
#define IXP435_INT_ENABLE2 (IXP425_IRQ_VBASE + 0x24)
|
||||
#define IXP435_INT_SELECT2 (IXP425_IRQ_VBASE + 0x28)
|
||||
#define IXP435_IRQ_STATUS2 (IXP425_IRQ_VBASE + 0x2C)
|
||||
#define IXP435_FIQ_STATUS2 (IXP425_IRQ_VBASE + 0x30)
|
||||
|
||||
#define IXP435_INT_USB0 32 /* USB Host 2.0 Host 0 */
|
||||
#define IXP435_INT_USB1 33 /* USB Host 2.0 Host 1 */
|
||||
#define IXP435_INT_QMGR_PER 60 /* Queue manager parity error */
|
||||
#define IXP435_INT_ECC 61 /* Single or multi-bit ECC error */
|
||||
|
||||
/*
|
||||
* software interrupt
|
||||
*/
|
||||
@ -239,6 +272,11 @@
|
||||
(1 << IXP425_INT_bit11)))
|
||||
#define IXP425_INT_GPIOMASK (0x3ff800c0u)
|
||||
|
||||
#define IXP435_INT_HWMASK ((1 << (IXP435_INT_USB0 - 32)) | \
|
||||
(1 << (IXP435_INT_USB1 - 32)) | \
|
||||
(1 << (IXP435_INT_QMGR_PER - 32)) | \
|
||||
(1 << (IXP435_INT_ECC - 32)))
|
||||
|
||||
/*
|
||||
* GPIO
|
||||
*/
|
||||
@ -383,6 +421,8 @@
|
||||
/* 0xf0011000 */
|
||||
#define IXP425_PCI_SIZE IXP425_REG_SIZE /* 0x1000 */
|
||||
|
||||
#define IXP425_AHB_OFFSET 0x00000000UL /* AHB bus */
|
||||
|
||||
/*
|
||||
* Mapping registers of IXP425 PCI Configuration
|
||||
*/
|
||||
@ -490,6 +530,28 @@
|
||||
#define MCU_SDR_REFRESH 0x04
|
||||
#define MCU_SDR_IR 0x08
|
||||
|
||||
/*
|
||||
* IXP435 DDR MCU Registers
|
||||
*/
|
||||
#define IXP435_MCU_HWBASE 0xcc00e500UL
|
||||
#define MCU_DDR_SDIR 0x00 /* DDR SDAM Initialization Reg*/
|
||||
#define MCU_DDR_SDCR0 0x04 /* DDR SDRAM Control Reg 0 */
|
||||
#define MCU_DDR_SDCR1 0x08 /* DDR SDRAM Control Reg 1 */
|
||||
#define MCU_DDR_SDBR 0x0c /* SDRAM Base Register */
|
||||
#define MCU_DDR_SBR0 0x10 /* SDRAM Boundary Register 0 */
|
||||
#define MCU_DDR_SBR1 0x14 /* SDRAM Boundary Register 1 */
|
||||
#define MCU_DDR_ECCR 0x1c /* ECC Control Register */
|
||||
#define MCU_DDR_ELOG0 0x20 /* ECC Log Register 0 */
|
||||
#define MCU_DDR_ELOG1 0x24 /* ECC Log Register 1 */
|
||||
#define MCU_DDR_ECAR0 0x28 /* ECC Address Register 0 */
|
||||
#define MCU_DDR_ECAR1 0x2c /* ECC Address Register 1 */
|
||||
#define MCU_DDR_ECTST 0x30 /* ECC Test Register */
|
||||
#define MCU_DDR_MCISR 0x34 /* MC Interrupt Status Reg */
|
||||
#define MCU_DDR_MPTCR 0x3c /* MC Port Transaction Cnt Reg*/
|
||||
#define MCU_DDR_RFR 0x48 /* Refresh Frequency Register */
|
||||
#define MCU_DDR_SDPR(n) (0x50+(n)*4) /* SDRAM Page Register 0-7 */
|
||||
/* NB: RCVDLY at 0x1050 and LEGOVERIDE at 0x1074 */
|
||||
|
||||
/*
|
||||
* Performance Monitoring Unit (CP14)
|
||||
*
|
||||
@ -549,14 +611,18 @@
|
||||
#define IXP425_NPE_C_VBASE (IXP425_IO_VBASE + IXP425_NPE_C_OFFSET)
|
||||
#define IXP425_NPE_C_SIZE 0x1000 /* Actually only 256 bytes */
|
||||
|
||||
#define IXP425_MAC_A_HWBASE (IXP425_IO_HWBASE + IXP425_MAC_A_OFFSET)
|
||||
#define IXP425_MAC_A_VBASE (IXP425_IO_VBASE + IXP425_MAC_A_OFFSET)
|
||||
#define IXP425_MAC_A_SIZE 0x1000 /* Actually only 256 bytes */
|
||||
|
||||
#define IXP425_MAC_B_HWBASE (IXP425_IO_HWBASE + IXP425_MAC_B_OFFSET)
|
||||
#define IXP425_MAC_B_VBASE (IXP425_IO_VBASE + IXP425_MAC_B_OFFSET)
|
||||
#define IXP425_MAC_B_SIZE 0x1000 /* Actually only 256 bytes */
|
||||
|
||||
#define IXP425_MAC_C_HWBASE (IXP425_IO_HWBASE + IXP425_MAC_C_OFFSET)
|
||||
#define IXP425_MAC_C_VBASE (IXP425_IO_VBASE + IXP425_MAC_C_OFFSET)
|
||||
#define IXP425_MAC_C_SIZE 0x1000 /* Actually only 256 bytes */
|
||||
|
||||
#define IXP435_MAC_A_HWBASE (IXP425_IO_HWBASE + IXP435_MAC_A_OFFSET)
|
||||
#define IXP435_MAC_A_VBASE (IXP425_IO_VBASE + IXP435_MAC_A_OFFSET)
|
||||
#define IXP435_MAC_A_SIZE 0x1000 /* Actually only 256 bytes */
|
||||
|
||||
/*
|
||||
* Expansion Bus Data Space.
|
||||
*/
|
||||
@ -565,7 +631,6 @@
|
||||
|
||||
#define IXP425_EXP_BUS_CSx_HWBASE(i) \
|
||||
(IXP425_EXP_BUS_HWBASE + (i)*IXP425_EXP_BUS_SIZE)
|
||||
|
||||
#define IXP425_EXP_BUS_CSx_VBASE(i) \
|
||||
(IXP425_MAC_B_VBASE + (i)*IXP425_MAC_B_SIZE)
|
||||
|
||||
@ -588,4 +653,26 @@
|
||||
#define IXP425_EXP_BUS_CS6_HWBASE IXP425_EXP_BUS_CSx_HWBASE(6)
|
||||
#define IXP425_EXP_BUS_CS7_HWBASE IXP425_EXP_BUS_CSx_HWBASE(7)
|
||||
|
||||
/*
|
||||
* IXP435/Gateworks Cambria
|
||||
*/
|
||||
#define CAMBRIA_GPS_HWBASE 0x53FC0000UL /* optional GPS Serial Port */
|
||||
#define CAMBRIA_GPS_SIZE 0x40000
|
||||
#define CAMBRIA_RS485_HWBASE 0x53F80000UL /* optional RS485 Serial Port */
|
||||
#define CAMBRIA_RS485_SIZE 0x40000
|
||||
#define CAMBRIA_OCTAL_LED_HWBASE 0x53F40000UL /* Octal Status LED Latch */
|
||||
#define CAMBRIA_OCTAL_LED_SIZE 0x1000
|
||||
#define CAMBRIA_CFSEL1_HWBASE 0x53E40000UL /* Compact Flash Socket Sel 0 */
|
||||
#define CAMBRIA_CFSEL1_SIZE 0x40000
|
||||
#define CAMBRIA_CFSEL0_HWBASE 0x53E00000UL /* Compact Flash Socket Sel 1 */
|
||||
#define CAMBRIA_CFSEL0_SIZE 0x40000
|
||||
|
||||
#define IXP435_USB1_HWBASE 0xcd000000UL /* USB host controller 1 */
|
||||
#define IXP435_USB1_VBASE (IXP425_QMGR_VBASE + IXP425_QMGR_SIZE)
|
||||
#define IXP435_USB1_SIZE 0x1000 /* NB: only uses 0x300 */
|
||||
|
||||
#define IXP435_USB2_HWBASE 0xce000000UL /* USB host controller 2 */
|
||||
#define IXP435_USB2_VBASE (IXP435_USB1_VBASE + IXP435_USB1_SIZE)
|
||||
#define IXP435_USB2_SIZE 0x1000 /* NB: only uses 0x300 */
|
||||
|
||||
#endif /* _IXP425REG_H_ */
|
||||
|
@ -47,6 +47,10 @@
|
||||
#include <dev/pci/pcivar.h>
|
||||
#include <sys/rman.h>
|
||||
|
||||
/* NB: cputype is setup by set_cpufuncs */
|
||||
#define cpu_is_ixp43x() (cputype == CPU_ID_IXP435)
|
||||
#define cpu_is_ixp46x() (cputype == CPU_ID_IXP465)
|
||||
|
||||
struct ixp425_softc {
|
||||
device_t sc_dev;
|
||||
bus_space_tag_t sc_iot;
|
||||
@ -94,6 +98,7 @@ void ixp425_io_bs_init(bus_space_tag_t, void *);
|
||||
void ixp425_mem_bs_init(bus_space_tag_t, void *);
|
||||
|
||||
uint32_t ixp425_sdram_size(void);
|
||||
uint32_t ixp435_ddram_size(void);
|
||||
|
||||
int ixp425_md_route_interrupt(device_t, device_t, int);
|
||||
void ixp425_md_attach(device_t);
|
||||
|
357
sys/arm/xscale/ixp425/ixp435_ehci.c
Normal file
357
sys/arm/xscale/ixp425/ixp435_ehci.c
Normal file
@ -0,0 +1,357 @@
|
||||
/*-
|
||||
* Copyright (c) 2008 Sam Leffler. 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* IXP435 attachment driver for the USB Enhanced Host Controller.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "opt_bus.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/endian.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/lockmgr.h>
|
||||
#include <sys/rman.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
#include <machine/resource.h>
|
||||
|
||||
#include <dev/usb/usb.h>
|
||||
#include <dev/usb/usbdi.h>
|
||||
#include <dev/usb/usbdivar.h>
|
||||
#include <dev/usb/usb_mem.h>
|
||||
|
||||
#include <dev/usb/ehcireg.h>
|
||||
#include <dev/usb/ehcivar.h>
|
||||
|
||||
#include <arm/xscale/ixp425/ixp425reg.h>
|
||||
#include <arm/xscale/ixp425/ixp425var.h>
|
||||
|
||||
#define EHCI_VENDORID_IXP4XX 0x42fa05
|
||||
#define EHCI_HC_DEVSTR "IXP4XX Integrated USB 2.0 controller"
|
||||
|
||||
struct ixp_ehci_softc {
|
||||
ehci_softc_t base; /* storage for EHCI code */
|
||||
bus_space_tag_t iot;
|
||||
bus_space_handle_t ioh;
|
||||
struct bus_space tag; /* tag for private bus space ops */
|
||||
};
|
||||
|
||||
static int ehci_ixp_detach(device_t self);
|
||||
|
||||
static uint8_t ehci_bs_r_1(void *, bus_space_handle_t, bus_size_t);
|
||||
static void ehci_bs_w_1(void *, bus_space_handle_t, bus_size_t, u_int8_t);
|
||||
static uint16_t ehci_bs_r_2(void *, bus_space_handle_t, bus_size_t);
|
||||
static void ehci_bs_w_2(void *, bus_space_handle_t, bus_size_t, uint16_t);
|
||||
static uint32_t ehci_bs_r_4(void *, bus_space_handle_t, bus_size_t);
|
||||
static void ehci_bs_w_4(void *, bus_space_handle_t, bus_size_t, uint32_t);
|
||||
|
||||
static int
|
||||
ehci_ixp_suspend(device_t self)
|
||||
{
|
||||
ehci_softc_t *sc;
|
||||
int err;
|
||||
|
||||
err = bus_generic_suspend(self);
|
||||
if (err == 0) {
|
||||
sc = device_get_softc(self);
|
||||
ehci_power(PWR_SUSPEND, sc);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
ehci_ixp_resume(device_t self)
|
||||
{
|
||||
ehci_softc_t *sc = device_get_softc(self);
|
||||
|
||||
ehci_power(PWR_RESUME, sc);
|
||||
bus_generic_resume(self);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ehci_ixp_shutdown(device_t self)
|
||||
{
|
||||
ehci_softc_t *sc;
|
||||
int err;
|
||||
|
||||
err = bus_generic_shutdown(self);
|
||||
if (err == 0) {
|
||||
sc = device_get_softc(self);
|
||||
ehci_shutdown(sc);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
ehci_ixp_probe(device_t self)
|
||||
{
|
||||
device_set_desc(self, EHCI_HC_DEVSTR);
|
||||
return BUS_PROBE_DEFAULT;
|
||||
}
|
||||
|
||||
static int
|
||||
ehci_ixp_attach(device_t self)
|
||||
{
|
||||
struct ixp_ehci_softc *isc = device_get_softc(self);
|
||||
ehci_softc_t *sc = &isc->base;
|
||||
int err, rid;
|
||||
|
||||
sc->sc_bus.usbrev = USBREV_2_0;
|
||||
|
||||
/* NB: hints fix the memory location and irq */
|
||||
|
||||
rid = 0;
|
||||
sc->io_res = bus_alloc_resource_any(self, SYS_RES_MEMORY,
|
||||
&rid, RF_ACTIVE);
|
||||
if (sc->io_res == NULL) {
|
||||
device_printf(self, "Could not map memory\n");
|
||||
return ENXIO;
|
||||
}
|
||||
|
||||
/*
|
||||
* Craft special resource for bus space ops that handle
|
||||
* byte-alignment of non-word addresses. Also, since
|
||||
* we're already intercepting bus space ops we handle
|
||||
* the register window offset that could otherwise be
|
||||
* done with bus_space_subregion.
|
||||
*/
|
||||
isc->iot = rman_get_bustag(sc->io_res);
|
||||
isc->tag.bs_cookie = isc->iot;
|
||||
/* read single */
|
||||
isc->tag.bs_r_1 = ehci_bs_r_1,
|
||||
isc->tag.bs_r_2 = ehci_bs_r_2,
|
||||
isc->tag.bs_r_4 = ehci_bs_r_4,
|
||||
/* write (single) */
|
||||
isc->tag.bs_w_1 = ehci_bs_w_1,
|
||||
isc->tag.bs_w_2 = ehci_bs_w_2,
|
||||
isc->tag.bs_w_4 = ehci_bs_w_4,
|
||||
|
||||
sc->iot = &isc->tag;
|
||||
sc->ioh = rman_get_bushandle(sc->io_res);
|
||||
sc->sc_size = IXP435_USB1_SIZE - 0x100;
|
||||
|
||||
rid = 0;
|
||||
sc->irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ,
|
||||
&rid, RF_ACTIVE);
|
||||
if (sc->irq_res == NULL) {
|
||||
device_printf(self, "Could not allocate irq\n");
|
||||
ehci_ixp_detach(self);
|
||||
return ENXIO;
|
||||
}
|
||||
sc->sc_bus.bdev = device_add_child(self, "usb", -1);
|
||||
if (!sc->sc_bus.bdev) {
|
||||
device_printf(self, "Could not add USB device\n");
|
||||
ehci_ixp_detach(self);
|
||||
return ENOMEM;
|
||||
}
|
||||
device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus);
|
||||
|
||||
sprintf(sc->sc_vendor, "Intel");
|
||||
sc->sc_id_vendor = EHCI_VENDORID_IXP4XX;
|
||||
|
||||
err = bus_setup_intr(self, sc->irq_res, INTR_TYPE_BIO,
|
||||
NULL, (driver_intr_t*)ehci_intr, sc, &sc->ih);
|
||||
if (err) {
|
||||
device_printf(self, "Could not setup irq, %d\n", err);
|
||||
sc->ih = NULL;
|
||||
ehci_ixp_detach(self);
|
||||
return ENXIO;
|
||||
}
|
||||
|
||||
/* There are no companion USB controllers */
|
||||
sc->sc_ncomp = 0;
|
||||
|
||||
/* Allocate a parent dma tag for DMA maps */
|
||||
err = bus_dma_tag_create(bus_get_dma_tag(self), 1, 0,
|
||||
BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
|
||||
BUS_SPACE_MAXSIZE_32BIT, USB_DMA_NSEG, BUS_SPACE_MAXSIZE_32BIT, 0,
|
||||
NULL, NULL, &sc->sc_bus.parent_dmatag);
|
||||
if (err) {
|
||||
device_printf(self, "Could not allocate parent DMA tag (%d)\n",
|
||||
err);
|
||||
ehci_ixp_detach(self);
|
||||
return ENXIO;
|
||||
}
|
||||
|
||||
/* Allocate a dma tag for transfer buffers */
|
||||
err = bus_dma_tag_create(sc->sc_bus.parent_dmatag, 1, 0,
|
||||
BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
|
||||
BUS_SPACE_MAXSIZE_32BIT, USB_DMA_NSEG, BUS_SPACE_MAXSIZE_32BIT, 0,
|
||||
busdma_lock_mutex, &Giant, &sc->sc_bus.buffer_dmatag);
|
||||
if (err) {
|
||||
device_printf(self, "Could not allocate buffer DMA tag (%d)\n",
|
||||
err);
|
||||
ehci_ixp_detach(self);
|
||||
return ENXIO;
|
||||
}
|
||||
|
||||
/*
|
||||
* Arrange to force Host mode, select big-endian byte alignment,
|
||||
* and arrange to not terminate reset operations (the adapter
|
||||
* will ignore it if we do but might as well save a reg write).
|
||||
* Also, the controller has an embedded Transaction Translator
|
||||
* which means port speed must be read from the Port Status
|
||||
* register following a port enable.
|
||||
*/
|
||||
sc->sc_flags |= EHCI_SCFLG_SETMODE
|
||||
| EHCI_SCFLG_NORESTERM
|
||||
| EHCI_SCFLG_FORCESPEED
|
||||
| EHCI_SCFLG_BIGEDESC
|
||||
;
|
||||
err = ehci_init(sc);
|
||||
if (!err) {
|
||||
sc->sc_flags |= EHCI_SCFLG_DONEINIT;
|
||||
err = device_probe_and_attach(sc->sc_bus.bdev);
|
||||
}
|
||||
|
||||
if (err) {
|
||||
device_printf(self, "USB init failed err=%d\n", err);
|
||||
ehci_ixp_detach(self);
|
||||
return EIO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ehci_ixp_detach(device_t self)
|
||||
{
|
||||
struct ixp_ehci_softc *isc = device_get_softc(self);
|
||||
ehci_softc_t *sc = &isc->base;
|
||||
int err;
|
||||
|
||||
if (sc->sc_flags & EHCI_SCFLG_DONEINIT) {
|
||||
ehci_detach(sc, 0);
|
||||
sc->sc_flags &= ~EHCI_SCFLG_DONEINIT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Disable interrupts that might have been switched on in ehci_init()
|
||||
*/
|
||||
if (sc->iot && sc->ioh)
|
||||
bus_space_write_4(sc->iot, sc->ioh, EHCI_USBINTR, 0);
|
||||
if (sc->sc_bus.parent_dmatag != NULL)
|
||||
bus_dma_tag_destroy(sc->sc_bus.parent_dmatag);
|
||||
if (sc->sc_bus.buffer_dmatag != NULL)
|
||||
bus_dma_tag_destroy(sc->sc_bus.buffer_dmatag);
|
||||
|
||||
if (sc->irq_res && sc->ih) {
|
||||
err = bus_teardown_intr(self, sc->irq_res, sc->ih);
|
||||
|
||||
if (err)
|
||||
device_printf(self, "Could not tear down irq, %d\n",
|
||||
err);
|
||||
sc->ih = NULL;
|
||||
}
|
||||
if (sc->sc_bus.bdev != NULL) {
|
||||
device_delete_child(self, sc->sc_bus.bdev);
|
||||
sc->sc_bus.bdev = NULL;
|
||||
}
|
||||
if (sc->irq_res != NULL) {
|
||||
bus_release_resource(self, SYS_RES_IRQ, 0, sc->irq_res);
|
||||
sc->irq_res = NULL;
|
||||
}
|
||||
if (sc->io_res != NULL) {
|
||||
bus_release_resource(self, SYS_RES_MEMORY, 0, sc->io_res);
|
||||
sc->io_res = NULL;
|
||||
}
|
||||
sc->iot = 0;
|
||||
sc->ioh = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Bus space accessors for PIO operations.
|
||||
*/
|
||||
|
||||
static uint8_t
|
||||
ehci_bs_r_1(void *t, bus_space_handle_t h, bus_size_t o)
|
||||
{
|
||||
return bus_space_read_1((bus_space_tag_t) t, h,
|
||||
0x100 + (o &~ 3) + (3 - (o & 3)));
|
||||
}
|
||||
|
||||
static void
|
||||
ehci_bs_w_1(void *t, bus_space_handle_t h, bus_size_t o, u_int8_t v)
|
||||
{
|
||||
panic("%s", __func__);
|
||||
}
|
||||
|
||||
static uint16_t
|
||||
ehci_bs_r_2(void *t, bus_space_handle_t h, bus_size_t o)
|
||||
{
|
||||
return bus_space_read_2((bus_space_tag_t) t, h,
|
||||
0x100 + (o &~ 3) + (2 - (o & 3)));
|
||||
}
|
||||
|
||||
static void
|
||||
ehci_bs_w_2(void *t, bus_space_handle_t h, bus_size_t o, uint16_t v)
|
||||
{
|
||||
panic("%s", __func__);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
ehci_bs_r_4(void *t, bus_space_handle_t h, bus_size_t o)
|
||||
{
|
||||
return bus_space_read_4((bus_space_tag_t) t, h, 0x100 + o);
|
||||
}
|
||||
|
||||
static void
|
||||
ehci_bs_w_4(void *t, bus_space_handle_t h, bus_size_t o, uint32_t v)
|
||||
{
|
||||
bus_space_write_4((bus_space_tag_t) t, h, 0x100 + o, v);
|
||||
}
|
||||
|
||||
static device_method_t ehci_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, ehci_ixp_probe),
|
||||
DEVMETHOD(device_attach, ehci_ixp_attach),
|
||||
DEVMETHOD(device_detach, ehci_ixp_detach),
|
||||
DEVMETHOD(device_suspend, ehci_ixp_suspend),
|
||||
DEVMETHOD(device_resume, ehci_ixp_resume),
|
||||
DEVMETHOD(device_shutdown, ehci_ixp_shutdown),
|
||||
|
||||
/* Bus interface */
|
||||
DEVMETHOD(bus_print_child, bus_generic_print_child),
|
||||
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
static driver_t ehci_driver = {
|
||||
"ehci",
|
||||
ehci_methods,
|
||||
sizeof(struct ixp_ehci_softc),
|
||||
};
|
||||
static devclass_t ehci_devclass;
|
||||
DRIVER_MODULE(ehci, ixp, ehci_driver, ehci_devclass, 0, 0);
|
@ -1,6 +1,22 @@
|
||||
#GW2348-4 board configuration
|
||||
#$FreeBSD$
|
||||
include "../xscale/ixp425/std.ixp425"
|
||||
|
||||
#
|
||||
# Gateworks GW23XX board configuration
|
||||
#
|
||||
files "../xscale/ixp425/files.avila"
|
||||
makeoptions KERNPHYSADDR=0x10200000
|
||||
#
|
||||
# Physical memory starts at 0. We assume images are loaded at
|
||||
# 0x200000, e.g. from redboot with load -b 0x200000 kernel.
|
||||
#
|
||||
# Redboot is expected to handle unmapping the flash memory that
|
||||
# appears at 0 on boot. Likewise we expect the expansion bus to
|
||||
# be remapped away from 0.
|
||||
#
|
||||
options PHYSADDR=0x00000000
|
||||
options KERNPHYSADDR=0x00200000
|
||||
makeoptions KERNPHYSADDR=0x00200000
|
||||
options KERNVIRTADDR=0xc0200000 # Used in ldscript.arm
|
||||
makeoptions KERNVIRTADDR=0xc0200000
|
||||
options FLASHADDR=0x50000000
|
||||
options LOADERRAMADDR=0x00000000
|
||||
options STARTUP_PAGETABLE_ADDR=0x00000000
|
||||
|
8
sys/arm/xscale/ixp425/std.ixp435
Normal file
8
sys/arm/xscale/ixp425/std.ixp435
Normal file
@ -0,0 +1,8 @@
|
||||
#XScale IXP435 generic configuration
|
||||
#$FreeBSD$
|
||||
|
||||
files "../xscale/ixp425/files.ixp425"
|
||||
include "../xscale/std.xscale"
|
||||
cpu CPU_XSCALE_IXP435
|
||||
cpu CPU_XSCALE_IXP425
|
||||
makeoption ARM_BIG_ENDIAN
|
@ -1476,6 +1476,7 @@ dev/ubsec/ubsec.c optional ubsec
|
||||
#
|
||||
# USB support
|
||||
dev/usb/ehci.c optional ehci
|
||||
dev/usb/ehci_ddb.c optional ehci
|
||||
dev/usb/ehci_pci.c optional ehci pci
|
||||
dev/usb/hid.c optional usb
|
||||
dev/usb/if_aue.c optional aue
|
||||
|
@ -15,6 +15,7 @@ CPU_XSCALE_80219 opt_global.h
|
||||
CPU_XSCALE_80321 opt_global.h
|
||||
CPU_XSCALE_81342 opt_global.h
|
||||
CPU_XSCALE_IXP425 opt_global.h
|
||||
CPU_XSCALE_IXP435 opt_global.h
|
||||
CPU_XSCALE_PXA2X0 opt_global.h
|
||||
FLASHADDR opt_global.h
|
||||
KERNPHYSADDR opt_global.h
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
255
sys/dev/usb/ehci_ddb.c
Normal file
255
sys/dev/usb/ehci_ddb.c
Normal file
@ -0,0 +1,255 @@
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "opt_ddb.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/endian.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/lockmgr.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
#include <machine/endian.h>
|
||||
|
||||
#include <dev/usb/usb.h>
|
||||
#include <dev/usb/usbdi.h>
|
||||
#include <dev/usb/usbdivar.h>
|
||||
|
||||
#include <dev/usb/ehcireg.h>
|
||||
#include <dev/usb/ehcivar.h>
|
||||
|
||||
#ifdef DDB
|
||||
#include <ddb/ddb.h>
|
||||
#include <ddb/db_sym.h>
|
||||
#else
|
||||
#define db_printf printf
|
||||
#endif
|
||||
|
||||
extern ehci_softc_t *theehci; /* XXX */
|
||||
|
||||
void
|
||||
ehci_dump_regs(ehci_softc_t *sc)
|
||||
{
|
||||
int i;
|
||||
db_printf("cmd=0x%08x, sts=0x%08x, ien=0x%08x\n",
|
||||
EOREAD4(sc, EHCI_USBCMD),
|
||||
EOREAD4(sc, EHCI_USBSTS),
|
||||
EOREAD4(sc, EHCI_USBINTR));
|
||||
db_printf("frindex=0x%08x ctrdsegm=0x%08x periodic=0x%08x async=0x%08x\n",
|
||||
EOREAD4(sc, EHCI_FRINDEX),
|
||||
EOREAD4(sc, EHCI_CTRLDSSEGMENT),
|
||||
EOREAD4(sc, EHCI_PERIODICLISTBASE),
|
||||
EOREAD4(sc, EHCI_ASYNCLISTADDR));
|
||||
for (i = 1; i <= sc->sc_noport; i++)
|
||||
db_printf("port %d status=0x%08x\n", i,
|
||||
EOREAD4(sc, EHCI_PORTSC(i)));
|
||||
}
|
||||
|
||||
static void
|
||||
ehci_dump_link(ehci_softc_t *sc, ehci_link_t link, int type)
|
||||
{
|
||||
link = hc32toh(sc, link);
|
||||
db_printf("0x%08x", link);
|
||||
if (link & EHCI_LINK_TERMINATE)
|
||||
db_printf("<T>");
|
||||
else {
|
||||
db_printf("<");
|
||||
if (type) {
|
||||
switch (EHCI_LINK_TYPE(link)) {
|
||||
case EHCI_LINK_ITD: db_printf("ITD"); break;
|
||||
case EHCI_LINK_QH: db_printf("QH"); break;
|
||||
case EHCI_LINK_SITD: db_printf("SITD"); break;
|
||||
case EHCI_LINK_FSTN: db_printf("FSTN"); break;
|
||||
}
|
||||
}
|
||||
db_printf(">");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ehci_dump_sqtds(ehci_softc_t *sc, ehci_soft_qtd_t *sqtd)
|
||||
{
|
||||
int i;
|
||||
u_int32_t stop;
|
||||
|
||||
stop = 0;
|
||||
for (i = 0; sqtd && i < 20 && !stop; sqtd = sqtd->nextqtd, i++) {
|
||||
ehci_dump_sqtd(sc, sqtd);
|
||||
stop = sqtd->qtd.qtd_next & htohc32(sc, EHCI_LINK_TERMINATE);
|
||||
}
|
||||
if (sqtd)
|
||||
db_printf("dump aborted, too many TDs\n");
|
||||
}
|
||||
|
||||
void
|
||||
ehci_dump_qtd(ehci_softc_t *sc, ehci_qtd_t *qtd)
|
||||
{
|
||||
u_int32_t s;
|
||||
|
||||
db_printf(" next="); ehci_dump_link(sc, qtd->qtd_next, 0);
|
||||
db_printf(" altnext="); ehci_dump_link(sc, qtd->qtd_altnext, 0);
|
||||
db_printf("\n");
|
||||
s = hc32toh(sc, qtd->qtd_status);
|
||||
db_printf(" status=0x%08x: toggle=%d bytes=0x%x ioc=%d c_page=0x%x\n",
|
||||
s, EHCI_QTD_GET_TOGGLE(s), EHCI_QTD_GET_BYTES(s),
|
||||
EHCI_QTD_GET_IOC(s), EHCI_QTD_GET_C_PAGE(s));
|
||||
db_printf(" cerr=%d pid=%d stat=%b\n", EHCI_QTD_GET_CERR(s),
|
||||
EHCI_QTD_GET_PID(s),
|
||||
EHCI_QTD_GET_STATUS(s), EHCI_QTD_STATUS_BITS);
|
||||
for (s = 0; s < 5; s++)
|
||||
db_printf(" buffer[%d]=0x%08x\n", s, hc32toh(sc, qtd->qtd_buffer[s]));
|
||||
}
|
||||
|
||||
void
|
||||
ehci_dump_sqtd(ehci_softc_t *sc, ehci_soft_qtd_t *sqtd)
|
||||
{
|
||||
db_printf("QTD(%p) at 0x%08x:\n", sqtd, sqtd->physaddr);
|
||||
ehci_dump_qtd(sc, &sqtd->qtd);
|
||||
}
|
||||
|
||||
void
|
||||
ehci_dump_sqh(ehci_softc_t *sc, ehci_soft_qh_t *sqh)
|
||||
{
|
||||
ehci_qh_t *qh = &sqh->qh;
|
||||
u_int32_t endp, endphub;
|
||||
|
||||
db_printf("QH(%p) at 0x%08x:\n", sqh, sqh->physaddr);
|
||||
db_printf(" sqtd=%p inactivesqtd=%p\n", sqh->sqtd, sqh->inactivesqtd);
|
||||
db_printf(" link="); ehci_dump_link(sc, qh->qh_link, 1); db_printf("\n");
|
||||
endp = hc32toh(sc, qh->qh_endp);
|
||||
db_printf(" endp=0x%08x\n", endp);
|
||||
db_printf(" addr=0x%02x inact=%d endpt=%d eps=%d dtc=%d hrecl=%d\n",
|
||||
EHCI_QH_GET_ADDR(endp), EHCI_QH_GET_INACT(endp),
|
||||
EHCI_QH_GET_ENDPT(endp), EHCI_QH_GET_EPS(endp),
|
||||
EHCI_QH_GET_DTC(endp), EHCI_QH_GET_HRECL(endp));
|
||||
db_printf(" mpl=0x%x ctl=%d nrl=%d\n",
|
||||
EHCI_QH_GET_MPL(endp), EHCI_QH_GET_CTL(endp),
|
||||
EHCI_QH_GET_NRL(endp));
|
||||
endphub = hc32toh(sc, qh->qh_endphub);
|
||||
db_printf(" endphub=0x%08x\n", endphub);
|
||||
db_printf(" smask=0x%02x cmask=0x%02x huba=0x%02x port=%d mult=%d\n",
|
||||
EHCI_QH_GET_SMASK(endphub), EHCI_QH_GET_CMASK(endphub),
|
||||
EHCI_QH_GET_HUBA(endphub), EHCI_QH_GET_PORT(endphub),
|
||||
EHCI_QH_GET_MULT(endphub));
|
||||
db_printf(" curqtd="); ehci_dump_link(sc, qh->qh_curqtd, 0); db_printf("\n");
|
||||
db_printf("Overlay qTD:\n");
|
||||
ehci_dump_qtd(sc, &qh->qh_qtd);
|
||||
}
|
||||
|
||||
void
|
||||
ehci_dump_itd(ehci_softc_t *sc, struct ehci_soft_itd *itd)
|
||||
{
|
||||
ehci_isoc_trans_t t;
|
||||
ehci_isoc_bufr_ptr_t b, b2, b3;
|
||||
int i;
|
||||
|
||||
db_printf("ITD: next phys=%X\n", itd->itd.itd_next);
|
||||
|
||||
for (i = 0; i < 8;i++) {
|
||||
t = hc32toh(sc, itd->itd.itd_ctl[i]);
|
||||
db_printf("ITDctl %d: stat=%X len=%X ioc=%X pg=%X offs=%X\n", i,
|
||||
EHCI_ITD_GET_STATUS(t), EHCI_ITD_GET_LEN(t),
|
||||
EHCI_ITD_GET_IOC(t), EHCI_ITD_GET_PG(t),
|
||||
EHCI_ITD_GET_OFFS(t));
|
||||
}
|
||||
db_printf("ITDbufr: ");
|
||||
for (i = 0; i < 7; i++)
|
||||
db_printf("%X,", EHCI_ITD_GET_BPTR(hc32toh(sc, itd->itd.itd_bufr[i])));
|
||||
|
||||
b = hc32toh(sc, itd->itd.itd_bufr[0]);
|
||||
b2 = hc32toh(sc, itd->itd.itd_bufr[1]);
|
||||
b3 = hc32toh(sc, itd->itd.itd_bufr[2]);
|
||||
db_printf("\nep=%X daddr=%X dir=%d maxpkt=%X multi=%X\n",
|
||||
EHCI_ITD_GET_EP(b), EHCI_ITD_GET_DADDR(b), EHCI_ITD_GET_DIR(b2),
|
||||
EHCI_ITD_GET_MAXPKT(b2), EHCI_ITD_GET_MULTI(b3));
|
||||
}
|
||||
|
||||
void
|
||||
ehci_dump_sitd(ehci_softc_t *sc, struct ehci_soft_itd *itd)
|
||||
{
|
||||
db_printf("SITD %p next=%p prev=%p xfernext=%p physaddr=%X slot=%d\n",
|
||||
itd, itd->u.frame_list.next, itd->u.frame_list.prev,
|
||||
itd->xfer_next, itd->physaddr, itd->slot);
|
||||
}
|
||||
|
||||
void
|
||||
ehci_dump_exfer(struct ehci_xfer *ex)
|
||||
{
|
||||
#ifdef DIAGNOSTIC
|
||||
db_printf("%p: sqtdstart %p end %p itdstart %p end %p isdone %d\n",
|
||||
ex, ex->sqtdstart, ex->sqtdend, ex->itdstart,
|
||||
ex->itdend, ex->isdone);
|
||||
#else
|
||||
db_printf("%p: sqtdstart %p end %p itdstart %p end %p\n",
|
||||
ex, ex->sqtdstart, ex->sqtdend, ex->itdstart, ex->itdend);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef DDB
|
||||
DB_SHOW_COMMAND(ehci, db_show_ehci)
|
||||
{
|
||||
if (!have_addr) {
|
||||
db_printf("usage: show ehci <addr>\n");
|
||||
return;
|
||||
}
|
||||
ehci_dump_regs((ehci_softc_t *) addr);
|
||||
}
|
||||
|
||||
DB_SHOW_COMMAND(ehci_sqtds, db_show_ehci_sqtds)
|
||||
{
|
||||
if (!have_addr) {
|
||||
db_printf("usage: show ehci_sqtds <addr>\n");
|
||||
return;
|
||||
}
|
||||
ehci_dump_sqtds(theehci, (ehci_soft_qtd_t *) addr);
|
||||
}
|
||||
|
||||
DB_SHOW_COMMAND(ehci_qtd, db_show_ehci_qtd)
|
||||
{
|
||||
if (!have_addr) {
|
||||
db_printf("usage: show ehci_qtd <addr>\n");
|
||||
return;
|
||||
}
|
||||
ehci_dump_qtd(theehci, (ehci_qtd_t *) addr);
|
||||
}
|
||||
|
||||
DB_SHOW_COMMAND(ehci_sqh, db_show_ehci_sqh)
|
||||
{
|
||||
if (!have_addr) {
|
||||
db_printf("usage: show ehci_sqh <addr>\n");
|
||||
return;
|
||||
}
|
||||
ehci_dump_sqh(theehci, (ehci_soft_qh_t *) addr);
|
||||
}
|
||||
|
||||
DB_SHOW_COMMAND(ehci_itd, db_show_ehci_itd)
|
||||
{
|
||||
if (!have_addr) {
|
||||
db_printf("usage: show ehci_itd <addr>\n");
|
||||
return;
|
||||
}
|
||||
ehci_dump_itd(theehci, (struct ehci_soft_itd *) addr);
|
||||
}
|
||||
|
||||
DB_SHOW_COMMAND(ehci_sitd, db_show_ehci_sitd)
|
||||
{
|
||||
if (!have_addr) {
|
||||
db_printf("usage: show ehci_sitd <addr>\n");
|
||||
return;
|
||||
}
|
||||
ehci_dump_itd(theehci, (struct ehci_soft_itd *) addr);
|
||||
}
|
||||
|
||||
DB_SHOW_COMMAND(ehci_xfer, db_show_ehci_xfer)
|
||||
{
|
||||
if (!have_addr) {
|
||||
db_printf("usage: show ehci_xfer <addr>\n");
|
||||
return;
|
||||
}
|
||||
ehci_dump_exfer((struct ehci_xfer *) addr);
|
||||
}
|
||||
#endif /* DDB */
|
@ -61,8 +61,10 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/bus.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/lockmgr.h>
|
||||
#include <machine/bus.h>
|
||||
#include <sys/rman.h>
|
||||
#include <sys/endian.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
#include <machine/resource.h>
|
||||
|
||||
#include <dev/pci/pcivar.h>
|
||||
|
@ -173,6 +173,15 @@
|
||||
#define EHCI_PS_CS 0x00000001 /* RO connect status */
|
||||
#define EHCI_PS_CLEAR (EHCI_PS_OCC|EHCI_PS_PEC|EHCI_PS_CSC)
|
||||
|
||||
#define EHCI_USBMODE 0x68 /* RW USB Device mode register */
|
||||
#define EHCI_UM_CM 0x00000003 /* R/WO Controller Mode */
|
||||
#define EHCI_UM_CM_IDLE 0x0 /* Idle */
|
||||
#define EHCI_UM_CM_HOST 0x3 /* Host Controller */
|
||||
#define EHCI_UM_ES 0x00000004 /* R/WO Endian Select */
|
||||
#define EHCI_UM_ES_LE 0x0 /* Little-endian byte alignment */
|
||||
#define EHCI_UM_ES_BE 0x4 /* Big-endian byte alignment */
|
||||
#define EHCI_UM_SDIS 0x00000010 /* R/WO Stream Disable Mode */
|
||||
|
||||
#define EHCI_PORT_RESET_COMPLETE 2 /* ms */
|
||||
|
||||
#define EHCI_FLALIGN_ALIGN 0x1000
|
||||
@ -279,6 +288,9 @@ typedef struct {
|
||||
} ehci_qtd_t;
|
||||
#define EHCI_QTD_ALIGN 32
|
||||
|
||||
#define EHCI_QTD_STATUS_BITS \
|
||||
"\20\10ACTIVE\7HALTED\6BUFERR\5BABBLE\4XACTERR\3MISSED\2SPLIT\1PING"
|
||||
|
||||
/* Queue Head */
|
||||
typedef struct {
|
||||
ehci_link_t qh_link;
|
||||
|
@ -125,6 +125,7 @@ struct ehci_soft_islot {
|
||||
#define EHCI_SCFLG_SETMODE 0x0004 /* set bridge mode again after init (Marvell) */
|
||||
#define EHCI_SCFLG_FORCESPEED 0x0008 /* force speed (Marvell) */
|
||||
#define EHCI_SCFLG_NORESTERM 0x0010 /* don't terminate reset sequence (Marvell) */
|
||||
#define EHCI_SCFLG_BIGEDESC 0x0020 /* big-endian byte order descriptors */
|
||||
|
||||
typedef struct ehci_softc {
|
||||
struct usbd_bus sc_bus; /* base device */
|
||||
@ -132,22 +133,16 @@ typedef struct ehci_softc {
|
||||
bus_space_tag_t iot;
|
||||
bus_space_handle_t ioh;
|
||||
bus_size_t sc_size;
|
||||
#if defined(__FreeBSD__)
|
||||
void *ih;
|
||||
|
||||
struct resource *io_res;
|
||||
struct resource *irq_res;
|
||||
#endif
|
||||
u_int sc_offs; /* offset to operational regs */
|
||||
|
||||
char sc_vendor[32]; /* vendor string for root hub */
|
||||
int sc_id_vendor; /* vendor ID for root hub */
|
||||
|
||||
u_int32_t sc_cmd; /* shadow of cmd reg during suspend */
|
||||
#if defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
void *sc_powerhook; /* cookie from power hook */
|
||||
void *sc_shutdownhook; /* cookie from shutdown hook */
|
||||
#endif
|
||||
|
||||
u_int sc_ncomp;
|
||||
u_int sc_npcomp;
|
||||
@ -156,9 +151,6 @@ typedef struct ehci_softc {
|
||||
usb_dma_t sc_fldma;
|
||||
ehci_link_t *sc_flist;
|
||||
u_int sc_flsize;
|
||||
#ifndef __FreeBSD__
|
||||
u_int sc_rand; /* XXX need proper intr scheduling */
|
||||
#endif
|
||||
|
||||
struct ehci_soft_islot sc_islots[EHCI_INTRQHS];
|
||||
|
||||
@ -192,9 +184,6 @@ typedef struct ehci_softc {
|
||||
struct callout sc_tmo_intrlist;
|
||||
|
||||
char sc_dying;
|
||||
#if defined(__NetBSD__)
|
||||
struct usb_dma_reserve sc_dma_reserve;
|
||||
#endif
|
||||
} ehci_softc_t;
|
||||
|
||||
#define EREAD1(sc, a) bus_space_read_1((sc)->iot, (sc)->ioh, (a))
|
||||
@ -210,14 +199,48 @@ typedef struct ehci_softc {
|
||||
#define EOWRITE2(sc, a, x) bus_space_write_2((sc)->iot, (sc)->ioh, (sc)->sc_offs+(a), (x))
|
||||
#define EOWRITE4(sc, a, x) bus_space_write_4((sc)->iot, (sc)->ioh, (sc)->sc_offs+(a), (x))
|
||||
|
||||
/*
|
||||
* Handle byte order conversion between host and ``host controller''.
|
||||
* Typically the latter is little-endian but some controllers require
|
||||
* big-endian in which case we may need to manually swap.
|
||||
*/
|
||||
static __inline uint32_t
|
||||
htohc32(const struct ehci_softc *sc, const uint32_t v)
|
||||
{
|
||||
return sc->sc_flags & EHCI_SCFLG_BIGEDESC ? htobe32(v) : htole32(v);
|
||||
}
|
||||
|
||||
static __inline uint16_t
|
||||
htohc16(const struct ehci_softc *sc, const uint16_t v)
|
||||
{
|
||||
return sc->sc_flags & EHCI_SCFLG_BIGEDESC ? htobe16(v) : htole16(v);
|
||||
}
|
||||
|
||||
static __inline uint32_t
|
||||
hc32toh(const struct ehci_softc *sc, const uint32_t v)
|
||||
{
|
||||
return sc->sc_flags & EHCI_SCFLG_BIGEDESC ? be32toh(v) : le32toh(v);
|
||||
}
|
||||
|
||||
static __inline uint16_t
|
||||
hc16toh(const struct ehci_softc *sc, const uint16_t v)
|
||||
{
|
||||
return sc->sc_flags & EHCI_SCFLG_BIGEDESC ? be16toh(v) : le16toh(v);
|
||||
}
|
||||
|
||||
usbd_status ehci_init(ehci_softc_t *);
|
||||
int ehci_intr(void *);
|
||||
int ehci_detach(ehci_softc_t *, int);
|
||||
#if defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
int ehci_activate(device_t, enum devact);
|
||||
#endif
|
||||
void ehci_power(int state, void *priv);
|
||||
void ehci_shutdown(void *v);
|
||||
|
||||
#define MS_TO_TICKS(ms) ((ms) * hz / 1000)
|
||||
|
||||
void ehci_dump_regs(ehci_softc_t *);
|
||||
void ehci_dump_sqtds(ehci_softc_t *, ehci_soft_qtd_t *);
|
||||
void ehci_dump_qtd(ehci_softc_t *, ehci_qtd_t *);
|
||||
void ehci_dump_sqtd(ehci_softc_t *, ehci_soft_qtd_t *);
|
||||
void ehci_dump_sqh(ehci_softc_t *, ehci_soft_qh_t *);
|
||||
void ehci_dump_itd(ehci_softc_t *, struct ehci_soft_itd *);
|
||||
void ehci_dump_sitd(ehci_softc_t *, struct ehci_soft_itd *);
|
||||
void ehci_dump_exfer(struct ehci_xfer *);
|
||||
|
@ -256,7 +256,8 @@ struct usb_attach_arg {
|
||||
#define USBD_SHOW_DEVICE_CLASS 0x1
|
||||
#define USBD_SHOW_INTERFACE_CLASS 0x2
|
||||
|
||||
int usbd_driver_load(module_t mod, int what, void *arg);
|
||||
struct module;
|
||||
int usbd_driver_load(struct module *mod, int what, void *arg);
|
||||
|
||||
static inline int
|
||||
usb_get_port(device_t dev)
|
||||
|
Loading…
x
Reference in New Issue
Block a user