FreeBSD/mips port. The FreeBSD/mips port targets mips32, mips64,
mips32r2 and mips64r2 (and close relatives) processors. There
presently is support for ADMtek ADM5120, A mips 4Kc in a malta board,
the RB533 routerboard (based on IDT RC32434) and some preliminary
support for sibtye/broadcom designs. Other hardware support will be
forthcomcing.
This port boots multiuser under gxemul emulating the malta board and
also bootstraps on the hardware whose support is forthcoming...
Oleksandr Tymoshenko, Wojciech Koszek, Warner Losh, Olivier Houchard,
Randall Stewert and others that have contributed to the mips2 and/or
mips2-jnpr perforce branches. Juniper contirbuted a generic mips port
late in the life cycle of the misp2 branch. Warner Losh merged the
mips2 and Juniper code bases, and others list above have worked for
the past several months to get to multiuser.
In addition, the mips2 work owe a debt to the trail blazing efforts of
the original mips branch in perforce done by Juli Mallett.
2008-04-13 07:44:55 +00:00
|
|
|
/* $NetBSD: gt_pci.c,v 1.4 2003/07/15 00:24:54 lukem Exp $ */
|
|
|
|
|
|
|
|
/*-
|
|
|
|
* Copyright (c) 2001, 2002 Wasabi Systems, Inc.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Written by Jason R. Thorpe for Wasabi Systems, Inc.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
|
|
* must display the following acknowledgement:
|
|
|
|
* This product includes software developed for the NetBSD Project by
|
|
|
|
* Wasabi Systems, Inc.
|
|
|
|
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
|
|
|
|
* or promote products derived from this software without specific prior
|
|
|
|
* written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
|
|
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* PCI configuration support for gt I/O Processor chip.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/cdefs.h>
|
|
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
|
|
|
|
|
|
|
#include <sys/bus.h>
|
|
|
|
#include <sys/interrupt.h>
|
|
|
|
#include <sys/malloc.h>
|
|
|
|
#include <sys/kernel.h>
|
|
|
|
#include <sys/module.h>
|
|
|
|
#include <sys/rman.h>
|
|
|
|
|
|
|
|
#include <vm/vm.h>
|
|
|
|
#include <vm/pmap.h>
|
|
|
|
#include <vm/vm_extern.h>
|
|
|
|
|
|
|
|
#include <machine/bus.h>
|
|
|
|
#include <machine/cpu.h>
|
|
|
|
#include <machine/pmap.h>
|
|
|
|
|
2008-09-10 03:49:08 +00:00
|
|
|
#include <mips/malta/maltareg.h>
|
FreeBSD/mips port. The FreeBSD/mips port targets mips32, mips64,
mips32r2 and mips64r2 (and close relatives) processors. There
presently is support for ADMtek ADM5120, A mips 4Kc in a malta board,
the RB533 routerboard (based on IDT RC32434) and some preliminary
support for sibtye/broadcom designs. Other hardware support will be
forthcomcing.
This port boots multiuser under gxemul emulating the malta board and
also bootstraps on the hardware whose support is forthcoming...
Oleksandr Tymoshenko, Wojciech Koszek, Warner Losh, Olivier Houchard,
Randall Stewert and others that have contributed to the mips2 and/or
mips2-jnpr perforce branches. Juniper contirbuted a generic mips port
late in the life cycle of the misp2 branch. Warner Losh merged the
mips2 and Juniper code bases, and others list above have worked for
the past several months to get to multiuser.
In addition, the mips2 work owe a debt to the trail blazing efforts of
the original mips branch in perforce done by Juli Mallett.
2008-04-13 07:44:55 +00:00
|
|
|
|
2008-09-10 03:49:08 +00:00
|
|
|
#include <mips/malta/gtreg.h>
|
|
|
|
#include <mips/malta/gtvar.h>
|
FreeBSD/mips port. The FreeBSD/mips port targets mips32, mips64,
mips32r2 and mips64r2 (and close relatives) processors. There
presently is support for ADMtek ADM5120, A mips 4Kc in a malta board,
the RB533 routerboard (based on IDT RC32434) and some preliminary
support for sibtye/broadcom designs. Other hardware support will be
forthcomcing.
This port boots multiuser under gxemul emulating the malta board and
also bootstraps on the hardware whose support is forthcoming...
Oleksandr Tymoshenko, Wojciech Koszek, Warner Losh, Olivier Houchard,
Randall Stewert and others that have contributed to the mips2 and/or
mips2-jnpr perforce branches. Juniper contirbuted a generic mips port
late in the life cycle of the misp2 branch. Warner Losh merged the
mips2 and Juniper code bases, and others list above have worked for
the past several months to get to multiuser.
In addition, the mips2 work owe a debt to the trail blazing efforts of
the original mips branch in perforce done by Juli Mallett.
2008-04-13 07:44:55 +00:00
|
|
|
|
|
|
|
#include <isa/isareg.h>
|
|
|
|
#include <dev/ic/i8259.h>
|
|
|
|
|
|
|
|
#include <dev/pci/pcireg.h>
|
|
|
|
#include <dev/pci/pcivar.h>
|
|
|
|
|
|
|
|
#include <dev/pci/pcib_private.h>
|
|
|
|
#include "pcib_if.h"
|
|
|
|
|
|
|
|
|
|
|
|
#define ICU_LEN 16 /* number of ISA IRQs */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* XXX: These defines are from NetBSD's <dev/ic/i8259reg.h>. Respective file
|
|
|
|
* from FreeBSD src tree <dev/ic/i8259.h> lacks some definitions.
|
|
|
|
*/
|
|
|
|
#define PIC_OCW1 1
|
|
|
|
#define PIC_OCW2 0
|
|
|
|
#define PIC_OCW3 0
|
|
|
|
|
|
|
|
#define OCW2_SELECT 0
|
|
|
|
#define OCW2_ILS(x) ((x) << 0) /* interrupt level select */
|
|
|
|
|
|
|
|
#define OCW3_POLL_IRQ(x) ((x) & 0x7f)
|
|
|
|
#define OCW3_POLL_PENDING (1U << 7)
|
|
|
|
|
|
|
|
struct gt_pci_softc {
|
|
|
|
device_t sc_dev;
|
|
|
|
bus_space_tag_t sc_st;
|
|
|
|
bus_space_tag_t sc_pciio;
|
|
|
|
bus_space_tag_t sc_pcimem;
|
|
|
|
bus_space_handle_t sc_ioh_icu1;
|
|
|
|
bus_space_handle_t sc_ioh_icu2;
|
|
|
|
bus_space_handle_t sc_ioh_elcr;
|
|
|
|
|
|
|
|
int sc_busno;
|
|
|
|
struct rman sc_mem_rman;
|
|
|
|
struct rman sc_io_rman;
|
|
|
|
struct rman sc_irq_rman;
|
|
|
|
uint32_t sc_mem;
|
|
|
|
uint32_t sc_io;
|
|
|
|
|
|
|
|
struct resource *sc_irq;
|
|
|
|
struct intr_event *sc_eventstab[ICU_LEN];
|
|
|
|
uint16_t sc_imask;
|
|
|
|
uint16_t sc_elcr;
|
|
|
|
|
|
|
|
uint16_t sc_reserved;
|
|
|
|
|
|
|
|
void *sc_ih;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
gt_pci_set_icus(struct gt_pci_softc *sc)
|
|
|
|
{
|
|
|
|
/* Enable the cascade IRQ (2) if 8-15 is enabled. */
|
|
|
|
if ((sc->sc_imask & 0xff00) != 0xff00)
|
|
|
|
sc->sc_imask &= ~(1U << 2);
|
|
|
|
else
|
|
|
|
sc->sc_imask |= (1U << 2);
|
|
|
|
|
|
|
|
bus_space_write_1(sc->sc_pciio, sc->sc_ioh_icu1, PIC_OCW1,
|
|
|
|
sc->sc_imask & 0xff);
|
|
|
|
bus_space_write_1(sc->sc_pciio, sc->sc_ioh_icu2, PIC_OCW1,
|
|
|
|
(sc->sc_imask >> 8) & 0xff);
|
|
|
|
|
|
|
|
bus_space_write_1(sc->sc_pciio, sc->sc_ioh_elcr, 0,
|
|
|
|
sc->sc_elcr & 0xff);
|
|
|
|
bus_space_write_1(sc->sc_pciio, sc->sc_ioh_elcr, 1,
|
|
|
|
(sc->sc_elcr >> 8) & 0xff);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
gt_pci_intr(void *v)
|
|
|
|
{
|
|
|
|
struct gt_pci_softc *sc = v;
|
|
|
|
struct intr_event *event;
|
|
|
|
struct intr_handler *ih;
|
|
|
|
int irq, thread;
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
bus_space_write_1(sc->sc_pciio, sc->sc_ioh_icu1, PIC_OCW3,
|
|
|
|
OCW3_SEL | OCW3_P);
|
|
|
|
irq = bus_space_read_1(sc->sc_pciio, sc->sc_ioh_icu1, PIC_OCW3);
|
|
|
|
if ((irq & OCW3_POLL_PENDING) == 0)
|
|
|
|
{
|
|
|
|
return FILTER_HANDLED;
|
|
|
|
}
|
|
|
|
|
|
|
|
irq = OCW3_POLL_IRQ(irq);
|
|
|
|
|
|
|
|
if (irq == 2) {
|
|
|
|
bus_space_write_1(sc->sc_pciio, sc->sc_ioh_icu2,
|
|
|
|
PIC_OCW3, OCW3_SEL | OCW3_P);
|
|
|
|
irq = bus_space_read_1(sc->sc_pciio, sc->sc_ioh_icu2,
|
|
|
|
PIC_OCW3);
|
|
|
|
if (irq & OCW3_POLL_PENDING)
|
|
|
|
irq = OCW3_POLL_IRQ(irq) + 8;
|
|
|
|
else
|
|
|
|
irq = 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
event = sc->sc_eventstab[irq];
|
|
|
|
thread = 0;
|
|
|
|
|
|
|
|
if (event && !TAILQ_EMPTY(&event->ie_handlers))
|
|
|
|
{
|
|
|
|
/* Execute fast handlers. */
|
|
|
|
TAILQ_FOREACH(ih, &event->ie_handlers, ih_next) {
|
|
|
|
if (ih->ih_filter == NULL)
|
|
|
|
thread = 1;
|
|
|
|
else
|
|
|
|
ih->ih_filter(ih->ih_argument);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Schedule thread if needed. */
|
|
|
|
if (thread)
|
|
|
|
intr_event_schedule_thread(event);
|
|
|
|
|
|
|
|
/* Send a specific EOI to the 8259. */
|
|
|
|
if (irq > 7) {
|
|
|
|
bus_space_write_1(sc->sc_pciio, sc->sc_ioh_icu2,
|
|
|
|
PIC_OCW2, OCW2_SELECT | OCW2_EOI | OCW2_SL |
|
|
|
|
OCW2_ILS(irq & 7));
|
|
|
|
irq = 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
bus_space_write_1(sc->sc_pciio, sc->sc_ioh_icu1, PIC_OCW2,
|
|
|
|
OCW2_SELECT | OCW2_EOI | OCW2_SL | OCW2_ILS(irq));
|
|
|
|
}
|
|
|
|
|
|
|
|
return FILTER_HANDLED;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
gt_pci_probe(device_t dev)
|
|
|
|
{
|
|
|
|
device_set_desc(dev, "GT64120 PCI bridge");
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
gt_pci_attach(device_t dev)
|
|
|
|
{
|
|
|
|
|
|
|
|
uint32_t busno;
|
|
|
|
struct gt_pci_softc *sc = device_get_softc(dev);
|
|
|
|
int rid;
|
|
|
|
|
|
|
|
busno = 0;
|
|
|
|
sc->sc_dev = dev;
|
|
|
|
sc->sc_busno = busno;
|
|
|
|
sc->sc_pciio = MIPS_BUS_SPACE_IO;
|
|
|
|
sc->sc_pcimem = MIPS_BUS_SPACE_MEM;
|
|
|
|
|
|
|
|
/* Use KSEG1 to access IO ports for it is uncached */
|
|
|
|
sc->sc_io = MIPS_PHYS_TO_KSEG1(MALTA_PCI0_IO_BASE);
|
|
|
|
sc->sc_io_rman.rm_type = RMAN_ARRAY;
|
|
|
|
sc->sc_io_rman.rm_descr = "GT64120 PCI I/O Ports";
|
|
|
|
if (rman_init(&sc->sc_io_rman) != 0 ||
|
|
|
|
rman_manage_region(&sc->sc_io_rman, 0, 0xffff) != 0) {
|
|
|
|
panic("gt_pci_attach: failed to set up I/O rman");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Use KSEG1 to access PCI memory for it is uncached */
|
|
|
|
sc->sc_mem = MIPS_PHYS_TO_KSEG1(MALTA_PCIMEM1_BASE);
|
|
|
|
sc->sc_mem_rman.rm_type = RMAN_ARRAY;
|
|
|
|
sc->sc_mem_rman.rm_descr = "GT64120 PCI Memory";
|
|
|
|
if (rman_init(&sc->sc_mem_rman) != 0 ||
|
|
|
|
rman_manage_region(&sc->sc_mem_rman,
|
|
|
|
sc->sc_mem, sc->sc_mem + MALTA_PCIMEM1_SIZE) != 0) {
|
|
|
|
panic("gt_pci_attach: failed to set up memory rman");
|
|
|
|
}
|
|
|
|
sc->sc_irq_rman.rm_type = RMAN_ARRAY;
|
|
|
|
sc->sc_irq_rman.rm_descr = "GT64120 PCI IRQs";
|
|
|
|
if (rman_init(&sc->sc_irq_rman) != 0 ||
|
|
|
|
rman_manage_region(&sc->sc_irq_rman, 1, 31) != 0)
|
|
|
|
panic("gt_pci_attach: failed to set up IRQ rman");
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Map the PIC/ELCR registers.
|
|
|
|
*/
|
|
|
|
#if 0
|
|
|
|
if (bus_space_map(sc->sc_pciio, 0x4d0, 2, 0, &sc->sc_ioh_elcr) != 0)
|
|
|
|
device_printf(dev, "unable to map ELCR registers\n");
|
|
|
|
if (bus_space_map(sc->sc_pciio, IO_ICU1, 2, 0, &sc->sc_ioh_icu1) != 0)
|
|
|
|
device_printf(dev, "unable to map ICU1 registers\n");
|
|
|
|
if (bus_space_map(sc->sc_pciio, IO_ICU2, 2, 0, &sc->sc_ioh_icu2) != 0)
|
|
|
|
device_printf(dev, "unable to map ICU2 registers\n");
|
|
|
|
#else
|
|
|
|
sc->sc_ioh_elcr = sc->sc_io + 0x4d0;
|
|
|
|
sc->sc_ioh_icu1 = sc->sc_io + IO_ICU1;
|
|
|
|
sc->sc_ioh_icu2 = sc->sc_io + IO_ICU2;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
/* All interrupts default to "masked off". */
|
|
|
|
sc->sc_imask = 0xffff;
|
|
|
|
|
|
|
|
/* All interrupts default to edge-triggered. */
|
|
|
|
sc->sc_elcr = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize the 8259s.
|
|
|
|
*/
|
|
|
|
/* reset, program device, 4 bytes */
|
|
|
|
bus_space_write_1(sc->sc_pciio, sc->sc_ioh_icu1, 0,
|
|
|
|
ICW1_RESET | ICW1_IC4);
|
|
|
|
/*
|
|
|
|
* XXX: values from NetBSD's <dev/ic/i8259reg.h>
|
|
|
|
*/
|
|
|
|
bus_space_write_1(sc->sc_pciio, sc->sc_ioh_icu1, 1,
|
|
|
|
0/*XXX*/);
|
|
|
|
bus_space_write_1(sc->sc_pciio, sc->sc_ioh_icu1, 1,
|
|
|
|
1 << 2);
|
|
|
|
bus_space_write_1(sc->sc_pciio, sc->sc_ioh_icu1, 1,
|
|
|
|
ICW4_8086);
|
|
|
|
|
|
|
|
/* mask all interrupts */
|
|
|
|
bus_space_write_1(sc->sc_pciio, sc->sc_ioh_icu1, 0,
|
|
|
|
sc->sc_imask & 0xff);
|
|
|
|
|
|
|
|
/* enable special mask mode */
|
|
|
|
bus_space_write_1(sc->sc_pciio, sc->sc_ioh_icu1, 1,
|
|
|
|
OCW3_SEL | OCW3_ESMM | OCW3_SMM);
|
|
|
|
|
|
|
|
/* read IRR by default */
|
|
|
|
bus_space_write_1(sc->sc_pciio, sc->sc_ioh_icu1, 1,
|
|
|
|
OCW3_SEL | OCW3_RR);
|
|
|
|
|
|
|
|
/* reset, program device, 4 bytes */
|
|
|
|
bus_space_write_1(sc->sc_pciio, sc->sc_ioh_icu2, 0,
|
|
|
|
ICW1_RESET | ICW1_IC4);
|
|
|
|
bus_space_write_1(sc->sc_pciio, sc->sc_ioh_icu2, 1,
|
|
|
|
0/*XXX*/);
|
|
|
|
bus_space_write_1(sc->sc_pciio, sc->sc_ioh_icu2, 1,
|
|
|
|
1 << 2);
|
|
|
|
bus_space_write_1(sc->sc_pciio, sc->sc_ioh_icu2, 1,
|
|
|
|
ICW4_8086);
|
|
|
|
|
|
|
|
/* mask all interrupts */
|
|
|
|
bus_space_write_1(sc->sc_pciio, sc->sc_ioh_icu2, 0,
|
|
|
|
sc->sc_imask & 0xff);
|
|
|
|
|
|
|
|
/* enable special mask mode */
|
|
|
|
bus_space_write_1(sc->sc_pciio, sc->sc_ioh_icu2, 1,
|
|
|
|
OCW3_SEL | OCW3_ESMM | OCW3_SMM);
|
|
|
|
|
|
|
|
/* read IRR by default */
|
|
|
|
bus_space_write_1(sc->sc_pciio, sc->sc_ioh_icu2, 1,
|
|
|
|
OCW3_SEL | OCW3_RR);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Default all interrupts to edge-triggered.
|
|
|
|
*/
|
|
|
|
bus_space_write_1(sc->sc_pciio, sc->sc_ioh_elcr, 0,
|
|
|
|
sc->sc_elcr & 0xff);
|
|
|
|
bus_space_write_1(sc->sc_pciio, sc->sc_ioh_elcr, 1,
|
|
|
|
(sc->sc_elcr >> 8) & 0xff);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Some ISA interrupts are reserved for devices that
|
|
|
|
* we know are hard-wired to certain IRQs.
|
|
|
|
*/
|
|
|
|
sc->sc_reserved =
|
|
|
|
(1U << 0) | /* timer */
|
|
|
|
(1U << 1) | /* keyboard controller (keyboard) */
|
|
|
|
(1U << 2) | /* PIC cascade */
|
|
|
|
(1U << 3) | /* COM 2 */
|
|
|
|
(1U << 4) | /* COM 1 */
|
|
|
|
(1U << 6) | /* floppy */
|
|
|
|
(1U << 7) | /* centronics */
|
|
|
|
(1U << 8) | /* RTC */
|
|
|
|
(1U << 9) | /* I2C */
|
|
|
|
(1U << 12) | /* keyboard controller (mouse) */
|
|
|
|
(1U << 14) | /* IDE primary */
|
|
|
|
(1U << 15); /* IDE secondary */
|
|
|
|
|
|
|
|
/* Hook up our interrupt handler. */
|
|
|
|
if ((sc->sc_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
|
|
|
|
MALTA_SOUTHBRIDGE_INTR, MALTA_SOUTHBRIDGE_INTR, 1,
|
|
|
|
RF_SHAREABLE | RF_ACTIVE)) == NULL) {
|
|
|
|
device_printf(dev, "unable to allocate IRQ resource\n");
|
|
|
|
return ENXIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_MISC,
|
|
|
|
gt_pci_intr, NULL, sc, &sc->sc_ih))) {
|
|
|
|
device_printf(dev,
|
|
|
|
"WARNING: unable to register interrupt handler\n");
|
|
|
|
return ENXIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Initialize memory and i/o rmans. */
|
|
|
|
device_add_child(dev, "pci", busno);
|
|
|
|
return (bus_generic_attach(dev));
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
gt_pci_maxslots(device_t dev)
|
|
|
|
{
|
|
|
|
return (PCI_SLOTMAX);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
gt_pci_conf_setup(struct gt_pci_softc *sc, int bus, int slot, int func,
|
|
|
|
int reg, uint32_t *addr)
|
|
|
|
{
|
|
|
|
*addr = (bus << 16) | (slot << 11) | (func << 8) | reg;
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint32_t
|
|
|
|
gt_pci_read_config(device_t dev, int bus, int slot, int func, int reg,
|
|
|
|
int bytes)
|
|
|
|
{
|
|
|
|
struct gt_pci_softc *sc = device_get_softc(dev);
|
|
|
|
uint32_t data;
|
|
|
|
uint32_t addr;
|
|
|
|
uint32_t shift, mask;
|
|
|
|
|
|
|
|
if (gt_pci_conf_setup(sc, bus, slot, func, reg & ~3, &addr))
|
|
|
|
return (uint32_t)(-1);
|
|
|
|
|
|
|
|
/* Clear cause register bits. */
|
|
|
|
GT_REGVAL(GT_INTR_CAUSE) = 0;
|
|
|
|
|
|
|
|
GT_REGVAL(GT_PCI0_CFG_ADDR) = (1 << 31) | addr;
|
|
|
|
data = GT_REGVAL(GT_PCI0_CFG_DATA);
|
|
|
|
|
|
|
|
/* Check for master abort. */
|
|
|
|
if (GT_REGVAL(GT_INTR_CAUSE) & (GTIC_MASABORT0 | GTIC_TARABORT0))
|
|
|
|
data = (uint32_t) -1;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* XXX: We assume that words readed from GT chip are BE.
|
|
|
|
* Should we set the mode explicitly during chip
|
|
|
|
* Initialization?
|
|
|
|
*/
|
|
|
|
switch(reg % 4)
|
|
|
|
{
|
|
|
|
case 3:
|
|
|
|
shift = 24;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
shift = 16;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
shift = 8;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
shift = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch(bytes)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
mask = 0xff;
|
|
|
|
data = (data >> shift) & mask;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
mask = 0xffff;
|
|
|
|
if(reg % 4 == 0)
|
|
|
|
data = data & mask;
|
|
|
|
else
|
|
|
|
data = (data >> 16) & mask;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
panic("gt_pci_readconfig: wrong bytes count");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#if 0
|
|
|
|
printf("PCICONF_READ(%02x:%02x.%02x[%04x] -> %02x(%d)\n",
|
|
|
|
bus, slot, func, reg, data, bytes);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return (data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gt_pci_write_config(device_t dev, int bus, int slot, int func, int reg,
|
|
|
|
uint32_t data, int bytes)
|
|
|
|
{
|
|
|
|
struct gt_pci_softc *sc = device_get_softc(dev);
|
|
|
|
uint32_t addr;
|
|
|
|
uint32_t reg_data;
|
|
|
|
uint32_t shift, mask;
|
|
|
|
|
|
|
|
if(bytes != 4)
|
|
|
|
{
|
|
|
|
reg_data = gt_pci_read_config(dev, bus, slot, func, reg, 4);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* XXX: We assume that words readed from GT chip are BE.
|
|
|
|
* Should we set the mode explicitly during chip
|
|
|
|
* Initialization?
|
|
|
|
*/
|
|
|
|
switch(reg % 4)
|
|
|
|
{
|
|
|
|
case 3:
|
|
|
|
shift = 24;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
shift = 16;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
shift = 8;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
shift = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch(bytes)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
mask = 0xff;
|
|
|
|
data = (reg_data & ~ (mask << shift)) | (data << shift);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
mask = 0xffff;
|
|
|
|
if(reg % 4 == 0)
|
|
|
|
data = (reg_data & ~mask) | data;
|
|
|
|
else
|
|
|
|
data = (reg_data & ~ (mask << shift)) |
|
|
|
|
(data << shift);
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
panic("gt_pci_readconfig: wrong bytes count");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gt_pci_conf_setup(sc, bus, slot, func, reg & ~3, &addr))
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* The galileo has problems accessing device 31. */
|
|
|
|
if (bus == 0 && slot == 31)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* XXX: no support for bus > 0 yet */
|
|
|
|
if (bus > 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Clear cause register bits. */
|
|
|
|
GT_REGVAL(GT_INTR_CAUSE) = 0;
|
|
|
|
|
|
|
|
GT_REGVAL(GT_PCI0_CFG_ADDR) = (1 << 31) | addr;
|
|
|
|
GT_REGVAL(GT_PCI0_CFG_DATA) = data;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
gt_pci_route_interrupt(device_t pcib, device_t dev, int pin)
|
|
|
|
{
|
|
|
|
int bus;
|
|
|
|
int device;
|
|
|
|
int func;
|
|
|
|
/* struct gt_pci_softc *sc = device_get_softc(pcib); */
|
|
|
|
bus = pci_get_bus(dev);
|
|
|
|
device = pci_get_slot(dev);
|
|
|
|
func = pci_get_function(dev);
|
|
|
|
/*
|
|
|
|
* XXXMIPS: We need routing logic. This is just a stub .
|
|
|
|
*/
|
|
|
|
switch (device) {
|
|
|
|
case 9: /*
|
|
|
|
* PIIX4 IDE adapter. HW IRQ0
|
|
|
|
*/
|
|
|
|
return 0;
|
|
|
|
default:
|
|
|
|
printf("No mapping for %d/%d/%d/%d\n", bus, device, func, pin);
|
|
|
|
|
|
|
|
}
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
gt_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
|
|
|
|
{
|
|
|
|
struct gt_pci_softc *sc = device_get_softc(dev);
|
|
|
|
switch (which) {
|
|
|
|
case PCIB_IVAR_DOMAIN:
|
|
|
|
*result = 0;
|
|
|
|
return (0);
|
|
|
|
case PCIB_IVAR_BUS:
|
|
|
|
*result = sc->sc_busno;
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
}
|
|
|
|
return (ENOENT);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
gt_write_ivar(device_t dev, device_t child, int which, uintptr_t result)
|
|
|
|
{
|
|
|
|
struct gt_pci_softc * sc = device_get_softc(dev);
|
|
|
|
|
|
|
|
switch (which) {
|
|
|
|
case PCIB_IVAR_BUS:
|
|
|
|
sc->sc_busno = result;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
return (ENOENT);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct resource *
|
|
|
|
gt_pci_alloc_resource(device_t bus, device_t child, int type, int *rid,
|
|
|
|
u_long start, u_long end, u_long count, u_int flags)
|
|
|
|
{
|
|
|
|
struct gt_pci_softc *sc = device_get_softc(bus);
|
|
|
|
struct resource *rv = NULL;
|
|
|
|
struct rman *rm;
|
|
|
|
bus_space_tag_t bt = 0;
|
|
|
|
bus_space_handle_t bh = 0;
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case SYS_RES_IRQ:
|
|
|
|
rm = &sc->sc_irq_rman;
|
|
|
|
break;
|
|
|
|
case SYS_RES_MEMORY:
|
|
|
|
rm = &sc->sc_mem_rman;
|
|
|
|
bt = sc->sc_pcimem;
|
|
|
|
bh = sc->sc_mem;
|
|
|
|
break;
|
|
|
|
case SYS_RES_IOPORT:
|
|
|
|
rm = &sc->sc_io_rman;
|
|
|
|
bt = sc->sc_pciio;
|
|
|
|
bh = sc->sc_io;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
rv = rman_reserve_resource(rm, start, end, count, flags, child);
|
|
|
|
if (rv == NULL)
|
|
|
|
return (NULL);
|
|
|
|
rman_set_rid(rv, *rid);
|
|
|
|
if (type != SYS_RES_IRQ) {
|
|
|
|
bh += (rman_get_start(rv));
|
|
|
|
|
|
|
|
rman_set_bustag(rv, bt);
|
|
|
|
rman_set_bushandle(rv, bh);
|
|
|
|
if (flags & RF_ACTIVE) {
|
|
|
|
if (bus_activate_resource(child, type, *rid, rv)) {
|
|
|
|
rman_release_resource(rv);
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return (rv);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
gt_pci_activate_resource(device_t bus, device_t child, int type, int rid,
|
|
|
|
struct resource *r)
|
|
|
|
{
|
|
|
|
bus_space_handle_t p;
|
|
|
|
int error;
|
|
|
|
|
|
|
|
if ((type == SYS_RES_MEMORY) || (type == SYS_RES_IOPORT)) {
|
|
|
|
error = bus_space_map(rman_get_bustag(r),
|
|
|
|
rman_get_bushandle(r), rman_get_size(r), 0, &p);
|
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
rman_set_bushandle(r, p);
|
|
|
|
}
|
|
|
|
return (rman_activate_resource(r));
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
gt_pci_setup_intr(device_t dev, device_t child, struct resource *ires,
|
|
|
|
int flags, driver_filter_t *filt, driver_intr_t *handler,
|
|
|
|
void *arg, void **cookiep)
|
|
|
|
{
|
|
|
|
struct gt_pci_softc *sc = device_get_softc(dev);
|
|
|
|
struct intr_event *event;
|
|
|
|
int irq, error;
|
|
|
|
|
|
|
|
irq = rman_get_start(ires);
|
|
|
|
if (irq >= ICU_LEN || irq == 2)
|
|
|
|
panic("%s: bad irq or type", __func__);
|
|
|
|
|
|
|
|
event = sc->sc_eventstab[irq];
|
|
|
|
if (event == NULL) {
|
2008-09-18 15:15:42 +00:00
|
|
|
error = intr_event_create(&event, (void *)irq, 0, 0,
|
FreeBSD/mips port. The FreeBSD/mips port targets mips32, mips64,
mips32r2 and mips64r2 (and close relatives) processors. There
presently is support for ADMtek ADM5120, A mips 4Kc in a malta board,
the RB533 routerboard (based on IDT RC32434) and some preliminary
support for sibtye/broadcom designs. Other hardware support will be
forthcomcing.
This port boots multiuser under gxemul emulating the malta board and
also bootstraps on the hardware whose support is forthcoming...
Oleksandr Tymoshenko, Wojciech Koszek, Warner Losh, Olivier Houchard,
Randall Stewert and others that have contributed to the mips2 and/or
mips2-jnpr perforce branches. Juniper contirbuted a generic mips port
late in the life cycle of the misp2 branch. Warner Losh merged the
mips2 and Juniper code bases, and others list above have worked for
the past several months to get to multiuser.
In addition, the mips2 work owe a debt to the trail blazing efforts of
the original mips branch in perforce done by Juli Mallett.
2008-04-13 07:44:55 +00:00
|
|
|
(mask_fn)mips_mask_irq, (mask_fn)mips_unmask_irq,
|
|
|
|
(mask_fn)mips_unmask_irq, NULL, "gt_pci intr%d:", irq);
|
|
|
|
if (error)
|
|
|
|
return 0;
|
|
|
|
sc->sc_eventstab[irq] = event;
|
|
|
|
}
|
|
|
|
|
|
|
|
intr_event_add_handler(event, device_get_nameunit(child), filt,
|
|
|
|
handler, arg, intr_priority(flags), flags, cookiep);
|
|
|
|
|
|
|
|
/* Enable it, set trigger mode. */
|
|
|
|
sc->sc_imask &= ~(1 << irq);
|
|
|
|
sc->sc_elcr &= ~(1 << irq);
|
|
|
|
|
|
|
|
gt_pci_set_icus(sc);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
gt_pci_teardown_intr(device_t dev, device_t child, struct resource *res,
|
|
|
|
void *cookie)
|
|
|
|
{
|
|
|
|
return (intr_event_remove_handler(cookie));
|
|
|
|
}
|
|
|
|
|
|
|
|
static device_method_t gt_pci_methods[] = {
|
|
|
|
/* Device interface */
|
|
|
|
DEVMETHOD(device_probe, gt_pci_probe),
|
|
|
|
DEVMETHOD(device_attach, gt_pci_attach),
|
|
|
|
DEVMETHOD(device_shutdown, bus_generic_shutdown),
|
|
|
|
DEVMETHOD(device_suspend, bus_generic_suspend),
|
|
|
|
DEVMETHOD(device_resume, bus_generic_resume),
|
|
|
|
|
|
|
|
/* Bus interface */
|
|
|
|
DEVMETHOD(bus_print_child, bus_generic_print_child),
|
|
|
|
DEVMETHOD(bus_read_ivar, gt_read_ivar),
|
|
|
|
DEVMETHOD(bus_write_ivar, gt_write_ivar),
|
|
|
|
DEVMETHOD(bus_alloc_resource, gt_pci_alloc_resource),
|
|
|
|
DEVMETHOD(bus_release_resource, bus_generic_release_resource),
|
|
|
|
DEVMETHOD(bus_activate_resource, gt_pci_activate_resource),
|
|
|
|
DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
|
|
|
|
DEVMETHOD(bus_setup_intr, gt_pci_setup_intr),
|
|
|
|
DEVMETHOD(bus_teardown_intr, gt_pci_teardown_intr),
|
|
|
|
|
|
|
|
/* pcib interface */
|
|
|
|
DEVMETHOD(pcib_maxslots, gt_pci_maxslots),
|
|
|
|
DEVMETHOD(pcib_read_config, gt_pci_read_config),
|
|
|
|
DEVMETHOD(pcib_write_config, gt_pci_write_config),
|
|
|
|
DEVMETHOD(pcib_route_interrupt, gt_pci_route_interrupt),
|
|
|
|
|
|
|
|
{0, 0}
|
|
|
|
};
|
|
|
|
|
|
|
|
static driver_t gt_pci_driver = {
|
|
|
|
"pcib",
|
|
|
|
gt_pci_methods,
|
|
|
|
sizeof(struct gt_pci_softc),
|
|
|
|
};
|
|
|
|
|
|
|
|
static devclass_t gt_pci_devclass;
|
|
|
|
|
|
|
|
DRIVER_MODULE(gt_pci, gt, gt_pci_driver, gt_pci_devclass, 0, 0);
|