366 lines
8.8 KiB
C
366 lines
8.8 KiB
C
/* $NetBSD: firepower.c,v 1.10 2003/07/15 02:46:30 lukem Exp $ */
|
|
|
|
/*
|
|
* Copyright 2001 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.
|
|
*/
|
|
|
|
/*
|
|
* Support routines for Firepower systems.
|
|
*/
|
|
|
|
#include <sys/cdefs.h>
|
|
__KERNEL_RCSID(0, "$NetBSD: firepower.c,v 1.10 2003/07/15 02:46:30 lukem Exp $");
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/device.h>
|
|
#include <sys/termios.h>
|
|
#include <dev/cons.h>
|
|
|
|
#include <dev/ofw/openfirm.h>
|
|
|
|
#include <dev/pci/pcivar.h>
|
|
#include <dev/pci/pcidevs.h>
|
|
#include <dev/scsipi/scsi_all.h>
|
|
#include <dev/scsipi/scsipi_all.h>
|
|
#include <dev/scsipi/scsiconf.h>
|
|
#include <dev/ata/atavar.h>
|
|
#include <dev/ata/wdvar.h>
|
|
#include <dev/ic/wdcvar.h>
|
|
|
|
#include <machine/autoconf.h>
|
|
#include <machine/bat.h>
|
|
#include <machine/intr.h>
|
|
#include <machine/platform.h>
|
|
|
|
#include <powerpc/pio.h>
|
|
|
|
#include <ofppc/firepower/firepowerreg.h>
|
|
#include <ofppc/firepower/firepowervar.h>
|
|
|
|
void firepower_init(void);
|
|
void firepower_cons_init(void);
|
|
void firepower_device_register(struct device *, void *);
|
|
|
|
extern char bootpath[];
|
|
extern char cbootpath[];
|
|
|
|
/*
|
|
* firepower_init:
|
|
*
|
|
* Platform initialization function.
|
|
*/
|
|
void
|
|
firepower_init(void)
|
|
{
|
|
|
|
platform.cons_init = firepower_cons_init;
|
|
platform.device_register = firepower_device_register;
|
|
platform.softintr_init = firepower_softintr_init;
|
|
|
|
/*
|
|
* Map VA==PA the region that includes ISA I/O, PCI Config,
|
|
* and PCI I/O.
|
|
*
|
|
* XXX This is actually a lot larger than 256M.
|
|
*/
|
|
oea_iobat_add(0x80000000, BAT_BL_256M);
|
|
|
|
/*
|
|
* Map VA==PA the region that includes PCI Memory.
|
|
*
|
|
* XXX This is actually a lot larger than 256M.
|
|
*/
|
|
oea_iobat_add(0xc0000000, BAT_BL_256M);
|
|
|
|
/*
|
|
* Map VA==PA the region that includes the System registers.
|
|
*/
|
|
oea_iobat_add(0xf0000000, BAT_BL_256M);
|
|
|
|
firepower_intr_init();
|
|
}
|
|
|
|
/*
|
|
* firepower_cons_init:
|
|
*
|
|
* Initialize the console on a Firepower system.
|
|
*/
|
|
void
|
|
firepower_cons_init(void)
|
|
{
|
|
}
|
|
|
|
#define DEVICE_IS(dev, name) \
|
|
(!strncmp((dev)->dv_xname, (name), sizeof(name) - 1) && \
|
|
(dev)->dv_xname[sizeof(name) - 1] >= '0' && \
|
|
(dev)->dv_xname[sizeof(name) - 1] <= '9')
|
|
|
|
/*
|
|
* firepower_device_register:
|
|
*
|
|
* A device has been attached; notify machine-dependent code.
|
|
* We use this to find the boot device.
|
|
*/
|
|
void
|
|
firepower_device_register(struct device *dev, void *aux)
|
|
{
|
|
static struct device *parent;
|
|
static char *bp = bootpath + 1, *cp = cbootpath + 1;
|
|
unsigned long addr;
|
|
char *pnext, *paddr;
|
|
int clen;
|
|
|
|
if (booted_device)
|
|
return;
|
|
|
|
/* Skip over devices not represented in the OF tree. */
|
|
if (DEVICE_IS(dev, "mainbus")) {
|
|
parent = dev;
|
|
return;
|
|
}
|
|
if (DEVICE_IS(dev, "atapibus") || DEVICE_IS(dev, "scsibus"))
|
|
return;
|
|
|
|
if (DEVICE_IS(dev->dv_parent, "atapibus") ||
|
|
DEVICE_IS(dev->dv_parent, "scsibus")) {
|
|
if (dev->dv_parent->dv_parent != parent)
|
|
return;
|
|
} else if (dev->dv_parent != parent) {
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Get the address part of the current path component.
|
|
*/
|
|
pnext = strchr(cp, '/');
|
|
if (pnext) {
|
|
clen = pnext - cp;
|
|
pnext++;
|
|
} else {
|
|
clen = strlen(cp);
|
|
}
|
|
addr = 0;
|
|
paddr = strchr(cp, '@');
|
|
if (pnext && paddr > pnext) {
|
|
paddr = NULL;
|
|
} else if (!paddr && bp) {
|
|
paddr = strchr(bp, '@');
|
|
}
|
|
if (paddr) {
|
|
addr = strtoul(paddr + 1, NULL, 0x10);
|
|
}
|
|
|
|
if (DEVICE_IS(dev->dv_parent, "mainbus")) {
|
|
struct ofbus_attach_args *oba = aux;
|
|
|
|
if (strcmp(oba->oba_busname, "cpu") == 0)
|
|
return;
|
|
} else if (DEVICE_IS(dev->dv_parent, "ofbus")) {
|
|
struct ofbus_attach_args *oba = aux;
|
|
|
|
if (strncmp(oba->oba_ofname, cp, clen))
|
|
return;
|
|
} else if (DEVICE_IS(dev->dv_parent, "pci")) {
|
|
struct pci_attach_args *pa = aux;
|
|
|
|
if (addr != pa->pa_device)
|
|
return;
|
|
} else if (DEVICE_IS(dev->dv_parent, "scsibus") ||
|
|
DEVICE_IS(dev->dv_parent, "atapibus")) {
|
|
struct scsipibus_attach_args *sa = aux;
|
|
|
|
/* periph_target is target for scsi, drive # for atapi */
|
|
if (addr != sa->sa_periph->periph_target)
|
|
return;
|
|
} else
|
|
return;
|
|
|
|
/*
|
|
* If we reach this point, then dev is a match for the current
|
|
* path component.
|
|
*/
|
|
|
|
if (pnext && *pnext) {
|
|
parent = dev;
|
|
cp = pnext;
|
|
bp = strchr(bp, '/');
|
|
if (bp)
|
|
bp++;
|
|
return;
|
|
} else {
|
|
booted_device = dev;
|
|
return;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* XXX We may want to move this stuff into a separate "Powerhouse"
|
|
* driver at some point.
|
|
*/
|
|
|
|
int firepower_match(struct device *, struct cfdata *, void *);
|
|
void firepower_attach(struct device *, struct device *, void *);
|
|
|
|
CFATTACH_DECL(firepower, sizeof(struct firepower_softc),
|
|
firepower_match, firepower_attach, NULL, NULL);
|
|
|
|
int firepower_print(void *, const char *);
|
|
|
|
/* There can be only one. */
|
|
struct firepower_config firepower_configuration;
|
|
int firepower_found;
|
|
|
|
/*
|
|
* firepower_chipset_init:
|
|
*
|
|
* Set up the Firepower's chipset function pointers.
|
|
*/
|
|
void
|
|
firepower_chipset_init(struct firepower_config *cp, int mallocsafe)
|
|
{
|
|
|
|
cp->c_mallocsafe = mallocsafe;
|
|
|
|
cp->c_type = CSR_READ2(FPR_PCI_DEVICE_ID);
|
|
|
|
if (cp->c_initted == 0) {
|
|
/* don't do these twice since they set up extents */
|
|
firepower_bus_io_init(&cp->c_iot, cp);
|
|
firepower_bus_mem_init(&cp->c_memt, cp);
|
|
}
|
|
cp->c_mallocsafe = mallocsafe;
|
|
|
|
firepower_pci_init(&cp->c_pc, cp);
|
|
firepower_pci_intr_init(&cp->c_pc, cp);
|
|
|
|
cp->c_initted = 1;
|
|
}
|
|
|
|
int
|
|
firepower_match(struct device *parent, struct cfdata *cfdata, void *aux)
|
|
{
|
|
struct ofbus_attach_args *oba = aux;
|
|
char name[32];
|
|
|
|
switch (platid) {
|
|
case PLATID_FIREPOWER_ES:
|
|
case PLATID_FIREPOWER_MX:
|
|
case PLATID_FIREPOWER_LX:
|
|
break;
|
|
|
|
default:
|
|
return (0);
|
|
}
|
|
|
|
if (strcmp(oba->oba_busname, "ofw") != 0)
|
|
return (0);
|
|
|
|
if (OF_getprop(oba->oba_phandle, "device_type", name,
|
|
sizeof(name)) <= 3)
|
|
return (0);
|
|
|
|
if (strcmp(name, "pci") == 0) {
|
|
if (firepower_found)
|
|
panic("firepower_match: already found?");
|
|
return (10); /* beat ofbus */
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
void
|
|
firepower_attach(struct device *parent, struct device *self, void *aux)
|
|
{
|
|
struct firepower_softc *sc = (void *) self;
|
|
struct firepower_config *cp;
|
|
struct pcibus_attach_args pba;
|
|
const char *name;
|
|
char namestore[sizeof("0xXXXXXXXX")];
|
|
|
|
/* Note that we've attached the chipset; can't have two. */
|
|
firepower_found = 1;
|
|
|
|
/*
|
|
* Set up the chipset's info; done once at console init time
|
|
* (maybe), but doesn't hurt to do it twice.
|
|
*/
|
|
cp = sc->sc_cp = &firepower_configuration;
|
|
firepower_chipset_init(cp, 1);
|
|
|
|
switch (cp->c_type) {
|
|
case PCI_PRODUCT_POWERHOUSE_POWERPRO:
|
|
name = "PowerPro";
|
|
break;
|
|
|
|
case PCI_PRODUCT_POWERHOUSE_POWERTOP:
|
|
name = "PowerTop";
|
|
break;
|
|
|
|
default:
|
|
sprintf(namestore, "0x%08x", cp->c_type);
|
|
name = namestore;
|
|
break;
|
|
}
|
|
|
|
printf(": Powerhouse %s Core Logic chipset, rev. %u\n",
|
|
name, CSR_READ1(FPR_PCI_REVISION));
|
|
|
|
firepower_dma_init(cp);
|
|
|
|
pba.pba_busname = "pci";
|
|
pba.pba_iot = &cp->c_iot;
|
|
pba.pba_memt = &cp->c_memt;
|
|
pba.pba_dmat = &cp->c_dmat_pci;
|
|
pba.pba_dmat64 = NULL;
|
|
pba.pba_pc = &cp->c_pc;
|
|
pba.pba_bus = 0;
|
|
pba.pba_bridgetag = NULL;
|
|
pba.pba_flags = PCI_FLAGS_IO_ENABLED | PCI_FLAGS_MEM_ENABLED |
|
|
PCI_FLAGS_MRL_OKAY | PCI_FLAGS_MRM_OKAY | PCI_FLAGS_MWI_OKAY;
|
|
(void) config_found(self, &pba, firepower_print);
|
|
}
|
|
|
|
int
|
|
firepower_print(void *aux, const char *pnp)
|
|
{
|
|
struct pcibus_attach_args *pba = aux;
|
|
|
|
if (pnp)
|
|
aprint_normal("%s at %s", pba->pba_busname, pnp);
|
|
aprint_normal(" bus %d", pba->pba_bus);
|
|
|
|
return (UNCONF);
|
|
}
|