Convert Freescale PowerPC platforms to FDT convention.

The following systems are affected:

  - MPC8555CDS
  - MPC8572DS

This overhaul covers the following major changes:

  - All integrated peripherals drivers for Freescale MPC85XX SoC, which are
    currently in the FreeBSD source tree are reworked and adjusted so they
    derive config data out of the device tree blob (instead of hard coded /
    tabelarized values).

  - This includes: LBC, PCI / PCI-Express, I2C, DS1553, OpenPIC, TSEC, SEC,
    QUICC, UART, CFI.

  - Thanks to the common FDT infrastrucutre (fdtbus, simplebus) we retire
    ocpbus(4) driver, which was based on hard-coded config data.

Note that world for these platforms has to be built WITH_FDT.

Reviewed by:	imp
Sponsored by:	The FreeBSD Foundation
This commit is contained in:
raj 2010-07-11 21:08:29 +00:00
parent 710dc13ac9
commit 6496d826cc
35 changed files with 1993 additions and 2508 deletions

View File

@ -30,6 +30,8 @@ S= ../../..
.endif
.include "$S/conf/kern.pre.mk"
INCLUDES+= -I$S/contrib/libfdt
CFLAGS+= -msoft-float
DDB_ENABLED!= grep DDB opt_ddb.h || true

View File

@ -14,7 +14,6 @@ font.h optional sc \
no-obj no-implicit-rule before-depend \
clean "font.h ${SC_DFLT_FONT}-8x14 ${SC_DFLT_FONT}-8x16 ${SC_DFLT_FONT}-8x8"
#
crypto/blowfish/bf_enc.c optional crypto | ipsec
crypto/des/des_enc.c optional crypto | ipsec | netsmb
dev/bm/if_bm.c optional bm powermac
@ -23,21 +22,23 @@ dev/adb/adb_kbd.c optional adb
dev/adb/adb_mouse.c optional adb
dev/adb/adb_hb_if.m optional adb
dev/adb/adb_if.m optional adb
dev/cfi/cfi_bus_lbc.c optional cfi
dev/cfi/cfi_bus_fdt.c optional cfi fdt
dev/fb/fb.c optional sc
dev/fdt/fdt_powerpc.c optional fdt
dev/hwpmc/hwpmc_powerpc.c optional hwpmc
dev/kbd/kbd.c optional sc
dev/ofw/openfirm.c optional aim
dev/ofw/openfirmio.c optional aim
dev/ofw/ofw_bus_if.m optional aim
dev/ofw/ofw_if.m optional aim
dev/ofw/ofw_bus_subr.c optional aim
dev/ofw/openfirm.c optional aim | fdt
dev/ofw/openfirmio.c optional aim | fdt
dev/ofw/ofw_bus_if.m optional aim | fdt
dev/ofw/ofw_if.m optional aim | fdt
dev/ofw/ofw_bus_subr.c optional aim | fdt
dev/ofw/ofw_console.c optional aim
dev/ofw/ofw_disk.c optional ofwd aim
dev/ofw/ofw_fdt.c optional fdt
dev/ofw/ofw_iicbus.c optional iicbus aim
dev/ofw/ofw_standard.c optional aim
dev/powermac_nvram/powermac_nvram.c optional powermac_nvram powermac
dev/quicc/quicc_bfe_ocp.c optional quicc mpc85xx
dev/quicc/quicc_bfe_fdt.c optional quicc mpc85xx
dev/scc/scc_bfe_macio.c optional scc powermac
dev/sec/sec.c optional sec mpc85xx
dev/sound/macio/aoa.c optional snd_davbus | snd_ai2s powermac
@ -49,9 +50,8 @@ dev/syscons/scgfbrndr.c optional sc
dev/syscons/scterm-teken.c optional sc
dev/syscons/scvtb.c optional sc
dev/tsec/if_tsec.c optional tsec
dev/tsec/if_tsec_ocp.c optional tsec mpc85xx
dev/uart/uart_bus_ocp.c optional uart mpc85xx
dev/uart/uart_cpu_powerpc.c optional uart
dev/tsec/if_tsec_fdt.c optional tsec fdt
dev/uart/uart_cpu_powerpc.c optional uart aim
kern/syscalls.c optional ktr
libkern/ashldi3.c standard
libkern/ashrdi3.c standard
@ -63,6 +63,7 @@ libkern/ffsl.c standard
libkern/fls.c standard
libkern/flsl.c standard
libkern/lshrdi3.c standard
libkern/memchr.c optional fdt
libkern/memmove.c standard
libkern/memset.c standard
libkern/moddi3.c standard
@ -109,16 +110,15 @@ powerpc/fpu/fpu_mul.c optional fpu_emu
powerpc/fpu/fpu_sqrt.c optional fpu_emu
powerpc/fpu/fpu_subr.c optional fpu_emu
powerpc/mpc85xx/atpic.c optional mpc85xx isa
powerpc/mpc85xx/ds1553_bus_lbc.c optional ds1553
powerpc/mpc85xx/ds1553_bus_fdt.c optional ds1553 fdt
powerpc/mpc85xx/ds1553_core.c optional ds1553
powerpc/mpc85xx/i2c.c optional iicbus mpc85xx
powerpc/mpc85xx/i2c.c optional iicbus fdt
powerpc/mpc85xx/isa.c optional mpc85xx isa
powerpc/mpc85xx/lbc.c optional mpc85xx
powerpc/mpc85xx/mpc85xx.c optional mpc85xx
powerpc/mpc85xx/nexus.c optional mpc85xx
powerpc/mpc85xx/ocpbus.c optional mpc85xx
powerpc/mpc85xx/opic.c optional mpc85xx
powerpc/mpc85xx/pci_ocp.c optional pci mpc85xx
powerpc/mpc85xx/openpic_fdt.c optional fdt
powerpc/mpc85xx/pci_fdt.c optional pci mpc85xx
powerpc/ofw/ofw_cpu.c optional aim
powerpc/ofw/ofw_pcibus.c optional pci aim
powerpc/ofw/ofw_pcib_pci.c optional pci aim

View File

@ -35,49 +35,39 @@ __FBSDID("$FreeBSD$");
#include <sys/bus.h>
#include <sys/conf.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/rman.h>
#include <sys/sysctl.h>
#include <machine/bus.h>
#include <dev/cfi/cfi_var.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
#include <powerpc/mpc85xx/lbc.h>
static int cfi_fdt_probe(device_t);
static int cfi_lbc_probe(device_t);
static device_method_t cfi_lbc_methods[] = {
static device_method_t cfi_fdt_methods[] = {
/* device interface */
DEVMETHOD(device_probe, cfi_lbc_probe),
DEVMETHOD(device_probe, cfi_fdt_probe),
DEVMETHOD(device_attach, cfi_attach),
DEVMETHOD(device_detach, cfi_detach),
{0, 0}
};
static driver_t cfi_lbc_driver = {
static driver_t cfi_fdt_driver = {
cfi_driver_name,
cfi_lbc_methods,
cfi_fdt_methods,
sizeof(struct cfi_softc),
};
DRIVER_MODULE (cfi, lbc, cfi_lbc_driver, cfi_devclass, 0, 0);
DRIVER_MODULE (cfi, lbc, cfi_fdt_driver, cfi_devclass, 0, 0);
static int
cfi_lbc_probe(device_t dev)
cfi_fdt_probe(device_t dev)
{
uintptr_t devtype;
int error;
error = BUS_READ_IVAR(device_get_parent(dev), dev, LBC_IVAR_DEVTYPE,
&devtype);
if (error)
return (error);
if (devtype != LBC_DEVTYPE_CFI)
return (EINVAL);
if (!ofw_bus_is_compatible(dev, "cfi-flash"))
return (ENXIO);
return (cfi_probe(dev));
}

View File

@ -325,8 +325,9 @@ fdt_pci_route_intr(int bus, int slot, int func, int pin,
debugf("decoded intr = %d, trig = %d, pol = %d\n", *interrupt,
trig, pol);
/* XXX we should probably call powerpc_config() here... */
#if defined(__powerpc__)
powerpc_config_intr(INTR_VEC(intr_par, *interrupt), trig, pol);
#endif
return (0);
next:

View File

@ -41,15 +41,15 @@ __FBSDID("$FreeBSD$");
#include <sys/tty.h>
#include <machine/bus.h>
#include <machine/ocpbus.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
#include <dev/quicc/quicc_bfe.h>
static int quicc_ocp_probe(device_t dev);
static int quicc_fdt_probe(device_t dev);
static device_method_t quicc_ocp_methods[] = {
static device_method_t quicc_fdt_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, quicc_ocp_probe),
DEVMETHOD(device_probe, quicc_fdt_probe),
DEVMETHOD(device_attach, quicc_bfe_attach),
DEVMETHOD(device_detach, quicc_bfe_detach),
@ -65,30 +65,26 @@ static device_method_t quicc_ocp_methods[] = {
{ 0, 0 }
};
static driver_t quicc_ocp_driver = {
static driver_t quicc_fdt_driver = {
quicc_driver_name,
quicc_ocp_methods,
quicc_fdt_methods,
sizeof(struct quicc_softc),
};
static int
quicc_ocp_probe(device_t dev)
quicc_fdt_probe(device_t dev)
{
device_t parent;
uintptr_t clock, devtype;
int error;
phandle_t par;
pcell_t clock;
parent = device_get_parent(dev);
error = BUS_READ_IVAR(parent, dev, OCPBUS_IVAR_DEVTYPE, &devtype);
if (error)
return (error);
if (devtype != OCPBUS_DEVTYPE_QUICC)
if (!ofw_bus_is_compatible(dev, "fsl,cpm2"))
return (ENXIO);
if (BUS_READ_IVAR(parent, dev, OCPBUS_IVAR_CLOCK, &clock))
par = OF_parent(ofw_bus_get_node(dev));
if (OF_getprop(par, "bus-frequency", &clock, sizeof(clock)) <= 0)
clock = 0;
return (quicc_bfe_probe(dev, clock));
return (quicc_bfe_probe(dev, (uintptr_t)clock));
}
DRIVER_MODULE(quicc, ocpbus, quicc_ocp_driver, quicc_devclass, 0, 0);
DRIVER_MODULE(quicc, simplebus, quicc_fdt_driver, quicc_devclass, 0, 0);

View File

@ -45,12 +45,12 @@ __FBSDID("$FreeBSD$");
#include <sys/rman.h>
#include <machine/bus.h>
#include <machine/ocpbus.h>
#include <machine/resource.h>
#include <opencrypto/cryptodev.h>
#include "cryptodev_if.h"
#include <dev/ofw/ofw_bus_subr.h>
#include <dev/sec/sec.h>
static int sec_probe(device_t dev);
@ -153,7 +153,7 @@ static driver_t sec_driver = {
};
static devclass_t sec_devclass;
DRIVER_MODULE(sec, ocpbus, sec_driver, sec_devclass, 0, 0);
DRIVER_MODULE(sec, simplebus, sec_driver, sec_devclass, 0, 0);
MODULE_DEPEND(sec, crypto, 1, 1, 1);
static struct sec_eu_methods sec_eus[] = {
@ -201,24 +201,16 @@ static int
sec_probe(device_t dev)
{
struct sec_softc *sc;
device_t parent;
uintptr_t devtype;
uint64_t id;
int error;
parent = device_get_parent(dev);
error = BUS_READ_IVAR(parent, dev, OCPBUS_IVAR_DEVTYPE, &devtype);
if (error)
return (error);
if (devtype != OCPBUS_DEVTYPE_SEC)
if (!ofw_bus_is_compatible(dev, "fsl,sec2.0"))
return (ENXIO);
sc = device_get_softc(dev);
sc->sc_rrid = 0;
sc->sc_rres = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->sc_rrid,
0ul, ~0ul, SEC_IO_SIZE, RF_ACTIVE);
sc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rrid,
RF_ACTIVE);
if (sc->sc_rres == NULL)
return (ENXIO);
@ -276,8 +268,8 @@ sec_attach(device_t dev)
/* Allocate I/O memory for SEC registers */
sc->sc_rrid = 0;
sc->sc_rres = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->sc_rrid,
0ul, ~0ul, SEC_IO_SIZE, RF_ACTIVE);
sc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rrid,
RF_ACTIVE);
if (sc->sc_rres == NULL) {
device_printf(dev, "could not allocate I/O memory!\n");
@ -295,12 +287,15 @@ sec_attach(device_t dev)
if (error)
goto fail2;
sc->sc_sec_irid = 1;
error = sec_setup_intr(sc, &sc->sc_sec_ires, &sc->sc_sec_ihand,
&sc->sc_sec_irid, sec_secondary_intr, "secondary");
if (error)
goto fail3;
if (sc->sc_version == 3) {
sc->sc_sec_irid = 1;
error = sec_setup_intr(sc, &sc->sc_sec_ires, &sc->sc_sec_ihand,
&sc->sc_sec_irid, sec_secondary_intr, "secondary");
if (error)
goto fail3;
}
/* Alloc DMA memory for descriptors and link tables */
error = sec_alloc_dma_mem(sc, &(sc->sc_desc_dmem),

View File

@ -1,6 +1,6 @@
/*-
* Copyright (C) 2007-2008 Semihalf, Rafal Jaworowski <raj@semihalf.com>
* Copyright (C) 2006-2007 Semihalf, Piotr Kruszynski <ppk@semihalf.com>
* Copyright (C) 2007-2008 Semihalf, Rafal Jaworowski
* Copyright (C) 2006-2007 Semihalf, Piotr Kruszynski
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -1563,7 +1563,7 @@ tsec_miibus_readreg(device_t dev, int phy, int reg)
sc = device_get_softc(dev);
if (device_get_unit(dev) != phy)
if (sc->phyaddr != phy)
return (0);
sc = tsec0_sc;
@ -1591,9 +1591,8 @@ tsec_miibus_writereg(device_t dev, int phy, int reg, int value)
sc = device_get_softc(dev);
if (device_get_unit(dev) != phy)
device_printf(dev, "Trying to write to an alien PHY(%d)\n",
phy);
if (sc->phyaddr != phy)
return (0);
sc = tsec0_sc;

View File

@ -1,5 +1,5 @@
/*-
* Copyright (C) 2006-2007 Semihalf, Piotr Kruszynski <ppk@semihalf.com>
* Copyright (C) 2006-2007 Semihalf, Piotr Kruszynski
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -28,6 +28,8 @@
#ifndef _IF_TSEC_H
#define _IF_TSEC_H
#include <dev/ofw/openfirm.h>
#define TSEC_RX_NUM_DESC 256
#define TSEC_TX_NUM_DESC 256
@ -49,6 +51,7 @@ struct tsec_softc {
struct mtx transmit_lock; /* transmitter lock */
struct mtx receive_lock; /* receiver lock */
phandle_t node;
device_t dev;
device_t tsec_miibus;
struct mii_data *tsec_mii; /* MII media control */
@ -128,6 +131,8 @@ struct tsec_softc {
/* currently received frame */
struct mbuf *frame;
int phyaddr;
};
/* interface to get/put generic objects */

View File

@ -1,6 +1,6 @@
/*-
* Copyright (C) 2007-2008 Semihalf, Rafal Jaworowski <raj@semihalf.com>
* Copyright (C) 2006-2007 Semihalf, Piotr Kruszynski <ppk@semihalf.com>
* Copyright (C) 2007-2008 Semihalf, Rafal Jaworowski
* Copyright (C) 2006-2007 Semihalf, Piotr Kruszynski
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -22,10 +22,12 @@
* 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.
*
* From: FreeBSD: head/sys/dev/tsec/if_tsec_ocp.c 188712 2009-02-17 14:59:47Z raj
*/
/*
* OCP attachment driver for Freescale TSEC controller.
* FDT 'simple-bus' attachment for Freescale TSEC controller.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
@ -50,36 +52,37 @@ __FBSDID("$FreeBSD$");
#include <net/if_media.h>
#include <net/if_arp.h>
#include <dev/fdt/fdt_common.h>
#include <dev/mii/mii.h>
#include <dev/mii/miivar.h>
#include <machine/bootinfo.h>
#include <machine/ocpbus.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
#include <dev/ofw/openfirm.h>
#include <dev/tsec/if_tsec.h>
#include <dev/tsec/if_tsecreg.h>
#include "miibus_if.h"
#define OCP_TSEC_RID_TXIRQ 0
#define OCP_TSEC_RID_RXIRQ 1
#define OCP_TSEC_RID_ERRIRQ 2
#define TSEC_RID_TXIRQ 0
#define TSEC_RID_RXIRQ 1
#define TSEC_RID_ERRIRQ 2
extern struct tsec_softc *tsec0_sc;
static int tsec_ocp_probe(device_t dev);
static int tsec_ocp_attach(device_t dev);
static int tsec_ocp_detach(device_t dev);
static int tsec_setup_intr(struct tsec_softc *sc, struct resource **ires,
static int tsec_fdt_probe(device_t dev);
static int tsec_fdt_attach(device_t dev);
static int tsec_fdt_detach(device_t dev);
static int tsec_setup_intr(struct tsec_softc *sc, struct resource **ires,
void **ihand, int *irid, driver_intr_t handler, const char *iname);
static void tsec_release_intr(struct tsec_softc *sc, struct resource *ires,
static void tsec_release_intr(struct tsec_softc *sc, struct resource *ires,
void *ihand, int irid, const char *iname);
static device_method_t tsec_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, tsec_ocp_probe),
DEVMETHOD(device_attach, tsec_ocp_attach),
DEVMETHOD(device_detach, tsec_ocp_detach),
DEVMETHOD(device_probe, tsec_fdt_probe),
DEVMETHOD(device_attach, tsec_fdt_attach),
DEVMETHOD(device_detach, tsec_fdt_detach),
DEVMETHOD(device_shutdown, tsec_shutdown),
DEVMETHOD(device_suspend, tsec_suspend),
@ -96,38 +99,30 @@ static device_method_t tsec_methods[] = {
{ 0, 0 }
};
static driver_t tsec_ocp_driver = {
static driver_t tsec_fdt_driver = {
"tsec",
tsec_methods,
sizeof(struct tsec_softc),
};
DRIVER_MODULE(tsec, ocpbus, tsec_ocp_driver, tsec_devclass, 0, 0);
MODULE_DEPEND(tsec, ocpbus, 1, 1, 1);
DRIVER_MODULE(tsec, simplebus, tsec_fdt_driver, tsec_devclass, 0, 0);
MODULE_DEPEND(tsec, simplebus, 1, 1, 1);
MODULE_DEPEND(tsec, ether, 1, 1, 1);
static int
tsec_ocp_probe(device_t dev)
tsec_fdt_probe(device_t dev)
{
struct tsec_softc *sc;
device_t parent;
uintptr_t devtype;
int error;
uint32_t id;
parent = device_get_parent(dev);
error = BUS_READ_IVAR(parent, dev, OCPBUS_IVAR_DEVTYPE, &devtype);
if (error)
return (error);
if (devtype != OCPBUS_DEVTYPE_TSEC)
if (!ofw_bus_is_compatible(dev, "gianfar"))
return (ENXIO);
sc = device_get_softc(dev);
sc->sc_rrid = 0;
sc->sc_rres = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->sc_rrid,
0ul, ~0ul, TSEC_IO_SIZE, RF_ACTIVE);
sc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rrid,
RF_ACTIVE);
if (sc->sc_rres == NULL)
return (ENXIO);
@ -155,18 +150,23 @@ tsec_ocp_probe(device_t dev)
}
static int
tsec_ocp_attach(device_t dev)
tsec_fdt_attach(device_t dev)
{
struct tsec_softc *sc;
int error = 0;
sc = device_get_softc(dev);
sc->dev = dev;
sc->node = ofw_bus_get_node(dev);
/* XXX add comment on weird FSL's MII registers access design */
if (device_get_unit(dev) == 0)
tsec0_sc = sc;
/* Get phy address from fdt */
if (fdt_get_phyaddr(sc->node, &sc->phyaddr) != 0)
return (ENXIO);
/* Init timer */
callout_init(&sc->tsec_callout, 1);
@ -177,11 +177,11 @@ tsec_ocp_attach(device_t dev)
MTX_DEF);
mtx_init(&sc->ic_lock, device_get_nameunit(dev), "TSEC IC lock",
MTX_DEF);
/* Allocate IO memory for TSEC registers */
sc->sc_rrid = 0;
sc->sc_rres = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->sc_rrid,
0ul, ~0ul, TSEC_IO_SIZE, RF_ACTIVE);
sc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rrid,
RF_ACTIVE);
if (sc->sc_rres == NULL) {
device_printf(dev, "could not allocate IO memory range!\n");
goto fail1;
@ -196,21 +196,21 @@ tsec_ocp_attach(device_t dev)
}
/* Set up interrupts (TX/RX/ERR) */
sc->sc_transmit_irid = OCP_TSEC_RID_TXIRQ;
sc->sc_transmit_irid = TSEC_RID_TXIRQ;
error = tsec_setup_intr(sc, &sc->sc_transmit_ires,
&sc->sc_transmit_ihand, &sc->sc_transmit_irid,
tsec_transmit_intr, "TX");
if (error)
goto fail2;
sc->sc_receive_irid = OCP_TSEC_RID_RXIRQ;
sc->sc_receive_irid = TSEC_RID_RXIRQ;
error = tsec_setup_intr(sc, &sc->sc_receive_ires,
&sc->sc_receive_ihand, &sc->sc_receive_irid,
tsec_receive_intr, "RX");
if (error)
goto fail3;
sc->sc_error_irid = OCP_TSEC_RID_ERRIRQ;
sc->sc_error_irid = TSEC_RID_ERRIRQ;
error = tsec_setup_intr(sc, &sc->sc_error_ires,
&sc->sc_error_ihand, &sc->sc_error_irid,
tsec_error_intr, "ERR");
@ -239,8 +239,8 @@ tsec_setup_intr(struct tsec_softc *sc, struct resource **ires, void **ihand,
{
int error;
(*ires) = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, irid, RF_ACTIVE);
if ((*ires) == NULL) {
*ires = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, irid, RF_ACTIVE);
if (*ires == NULL) {
device_printf(sc->dev, "could not allocate %s IRQ\n", iname);
return (ENXIO);
}
@ -250,7 +250,7 @@ tsec_setup_intr(struct tsec_softc *sc, struct resource **ires, void **ihand,
device_printf(sc->dev, "failed to set up %s IRQ\n", iname);
if (bus_release_resource(sc->dev, SYS_RES_IRQ, *irid, *ires))
device_printf(sc->dev, "could not release %s IRQ\n", iname);
(*ires) = NULL;
*ires = NULL;
return (error);
}
return (0);
@ -277,7 +277,7 @@ tsec_release_intr(struct tsec_softc *sc, struct resource *ires, void *ihand,
}
static int
tsec_ocp_detach(device_t dev)
tsec_fdt_detach(device_t dev)
{
struct tsec_softc *sc;
int error;
@ -322,14 +322,15 @@ tsec_get_hwaddr(struct tsec_softc *sc, uint8_t *addr)
uint8_t addr[6];
} curmac;
uint32_t a[6];
device_t parent;
uintptr_t macaddr;
uint8_t lma[6];
int i;
parent = device_get_parent(sc->dev);
if (BUS_READ_IVAR(parent, sc->dev, OCPBUS_IVAR_MACADDR,
&macaddr) == 0) {
bcopy((uint8_t *)macaddr, addr, 6);
/*
* Retrieve hw address from the device tree.
*/
i = OF_getprop(sc->node, "local-mac-address", (void *)lma, 6);
if (i == 6) {
bcopy(lma, addr, 6);
return;
}

View File

@ -1,88 +0,0 @@
/*-
* Copyright 2006 by Juniper Networks.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/conf.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/tty.h>
#include <machine/bus.h>
#include <machine/ocpbus.h>
#include <dev/uart/uart.h>
#include <dev/uart/uart_bus.h>
static int uart_ocp_probe(device_t);
static device_method_t uart_ocp_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, uart_ocp_probe),
DEVMETHOD(device_attach, uart_bus_attach),
DEVMETHOD(device_detach, uart_bus_detach),
{ 0, 0 }
};
static driver_t uart_ocp_driver = {
uart_driver_name,
uart_ocp_methods,
sizeof(struct uart_softc),
};
static int
uart_ocp_probe(device_t dev)
{
device_t parent;
struct uart_softc *sc;
uintptr_t clock, devtype;
int error;
parent = device_get_parent(dev);
error = BUS_READ_IVAR(parent, dev, OCPBUS_IVAR_DEVTYPE, &devtype);
if (error)
return (error);
if (devtype != OCPBUS_DEVTYPE_UART)
return (ENXIO);
sc = device_get_softc(dev);
sc->sc_class = &uart_ns8250_class;
if (BUS_READ_IVAR(parent, dev, OCPBUS_IVAR_CLOCK, &clock))
clock = 0;
return (uart_bus_probe(dev, 0, clock, 0, 0));
}
DRIVER_MODULE(uart, ocpbus, uart_ocp_driver, uart_devclass, 0, 0);

View File

@ -27,57 +27,28 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_platform.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <vm/vm.h>
#include <vm/pmap.h>
#include <machine/bus.h>
#ifndef MPC85XX
#include <dev/ofw/openfirm.h>
#include <machine/ofw_machdep.h>
#endif
#include <dev/ofw/openfirm.h>
#include <dev/uart/uart.h>
#include <dev/uart/uart_cpu.h>
#ifdef MPC85XX
bus_space_tag_t uart_bus_space_io = &bs_be_tag;
bus_space_tag_t uart_bus_space_mem = &bs_be_tag;
#else
bus_space_tag_t uart_bus_space_io = &bs_le_tag;
bus_space_tag_t uart_bus_space_mem = &bs_le_tag;
#endif
int
uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2)
{
#ifdef MPC85XX
return ((b1->bsh == b2->bsh) ? 1 : 0);
#else
return ((pmap_kextract(b1->bsh) == pmap_kextract(b2->bsh)) ? 1 : 0);
#endif
}
#ifdef MPC85XX
int
uart_cpu_getdev(int devtype, struct uart_devinfo *di)
{
struct uart_class *class;
class = &uart_ns8250_class;
if (class == NULL)
class = &uart_quicc_class;
if (class == NULL)
return (ENXIO);
/* Check the environment. */
return (uart_getenv(devtype, di, class));
}
#else
static int
ofw_get_uart_console(phandle_t opts, phandle_t *result, const char *inputdev,
const char *outputdev)
@ -174,4 +145,3 @@ uart_cpu_getdev(int devtype, struct uart_devinfo *di)
di->parity = UART_PARITY_NONE;
return (0);
}
#endif

View File

@ -39,7 +39,6 @@
#include <machine/trap.h>
#include <machine/vmparam.h>
#include <machine/tlb.h>
#include <machine/bootinfo.h>
#define TMPSTACKSZ 16384

View File

@ -130,13 +130,14 @@ __FBSDID("$FreeBSD$");
#include <machine/mmuvar.h>
#include <machine/sigframe.h>
#include <machine/metadata.h>
#include <machine/bootinfo.h>
#include <machine/platform.h>
#include <sys/linker.h>
#include <sys/reboot.h>
#include <powerpc/mpc85xx/ocpbus.h>
#include <dev/fdt/fdt_common.h>
#include <dev/ofw/openfirm.h>
#include <powerpc/mpc85xx/mpc85xx.h>
#ifdef DDB
@ -169,8 +170,6 @@ int cold = 1;
long realmem = 0;
long Maxmem = 0;
struct bootinfo *bootinfo;
char machine[] = "powerpc";
SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD, machine, 0, "");
@ -185,7 +184,6 @@ static void cpu_e500_startup(void *);
SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_e500_startup, NULL);
void print_kernel_section_addr(void);
void print_bootinfo(void);
void print_kenv(void);
u_int e500_init(u_int32_t, u_int32_t, void *);
@ -258,40 +256,6 @@ print_kenv(void)
debugf(" %x %s\n", (u_int32_t)cp, cp);
}
void
print_bootinfo(void)
{
struct bi_mem_region *mr;
struct bi_eth_addr *eth;
int i, j;
debugf("bootinfo:\n");
if (bootinfo == NULL) {
debugf(" no bootinfo, null ptr\n");
return;
}
debugf(" version = 0x%08x\n", bootinfo->bi_version);
debugf(" ccsrbar = 0x%08x\n", bootinfo->bi_bar_base);
debugf(" cpu_clk = 0x%08x\n", bootinfo->bi_cpu_clk);
debugf(" bus_clk = 0x%08x\n", bootinfo->bi_bus_clk);
debugf(" mem regions:\n");
mr = (struct bi_mem_region *)bootinfo->bi_data;
for (i = 0; i < bootinfo->bi_mem_reg_no; i++, mr++)
debugf(" #%d, base = 0x%08x, size = 0x%08x\n", i,
mr->mem_base, mr->mem_size);
debugf(" eth addresses:\n");
eth = (struct bi_eth_addr *)mr;
for (i = 0; i < bootinfo->bi_eth_addr_no; i++, eth++) {
debugf(" #%d, addr = ", i);
for (j = 0; j < 6; j++)
debugf("%02x ", eth->mac_addr[j]);
debugf("\n");
}
}
void
print_kernel_section_addr(void)
{
@ -306,54 +270,29 @@ print_kernel_section_addr(void)
debugf(" _end = 0x%08x\n", (uint32_t)_end);
}
struct bi_mem_region *
bootinfo_mr(void)
{
return ((struct bi_mem_region *)bootinfo->bi_data);
}
struct bi_eth_addr *
bootinfo_eth(void)
{
struct bi_mem_region *mr;
struct bi_eth_addr *eth;
int i;
/* Advance to the eth section */
mr = bootinfo_mr();
for (i = 0; i < bootinfo->bi_mem_reg_no; i++, mr++)
;
eth = (struct bi_eth_addr *)mr;
return (eth);
}
u_int
e500_init(u_int32_t startkernel, u_int32_t endkernel, void *mdp)
{
struct pcpu *pc;
void *kmdp;
vm_offset_t end;
vm_offset_t dtbp, end;
uint32_t csr;
kmdp = NULL;
end = endkernel;
dtbp = (vm_offset_t)NULL;
/*
* Parse metadata and fetch parameters. This must be done as the first
* step as we need bootinfo data to at least init the console
* Parse metadata and fetch parameters.
*/
if (mdp != NULL) {
preload_metadata = mdp;
kmdp = preload_search_by_type("elf kernel");
if (kmdp != NULL) {
bootinfo = (struct bootinfo *)preload_search_info(kmdp,
MODINFO_METADATA | MODINFOMD_BOOTINFO);
boothowto = MD_FETCH(kmdp, MODINFOMD_HOWTO, int);
kern_envp = MD_FETCH(kmdp, MODINFOMD_ENVP, char *);
dtbp = MD_FETCH(kmdp, MODINFOMD_DTBP, vm_offset_t);
end = MD_FETCH(kmdp, MODINFOMD_KERNEND, vm_offset_t);
#ifdef DDB
ksym_start = MD_FETCH(kmdp, MODINFOMD_SSYM, uintptr_t);
@ -362,8 +301,7 @@ e500_init(u_int32_t startkernel, u_int32_t endkernel, void *mdp)
}
} else {
/*
* We should scream but how? - without CCSR bar (in bootinfo)
* cannot even output anything...
* We should scream but how? Cannot even output anything...
*/
/*
@ -372,11 +310,22 @@ e500_init(u_int32_t startkernel, u_int32_t endkernel, void *mdp)
* restore everything as the TLB have all been reprogrammed
* in the locore etc...)
*/
while(1);
while (1);
}
if (OF_install(OFW_FDT, 0) == FALSE)
while (1);
if (OF_init((void *)dtbp) != 0)
while (1);
if (fdt_immr_addr() != 0)
while (1);
OF_interpret("perform-fixup", 0);
/* Initialize TLB1 handling */
tlb1_init(bootinfo->bi_bar_base);
tlb1_init(fdt_immr_pa);
/* Reset Time Base */
mttb(0);
@ -417,7 +366,8 @@ e500_init(u_int32_t startkernel, u_int32_t endkernel, void *mdp)
csr = ccsr_read4(OCP85XX_L2CTL);
debugf(" L2CTL = 0x%08x\n", csr);
print_bootinfo();
debugf(" dtbp = 0x%08x\n", (uint32_t)dtbp);
print_kernel_section_addr();
print_kenv();
//tlb1_print_entries();

View File

@ -35,7 +35,6 @@ __FBSDID("$FreeBSD$");
#include <sys/proc.h>
#include <sys/smp.h>
#include <machine/bootinfo.h>
#include <machine/bus.h>
#include <machine/cpu.h>
#include <machine/hid.h>
@ -45,8 +44,12 @@ __FBSDID("$FreeBSD$");
#include <machine/spr.h>
#include <machine/vmparam.h>
#include <dev/fdt/fdt_common.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
#include <dev/ofw/openfirm.h>
#include <powerpc/mpc85xx/mpc85xx.h>
#include <powerpc/mpc85xx/ocpbus.h>
#include "platform_if.h"
@ -91,7 +94,8 @@ PLATFORM_DEF(bare_platform);
static int
bare_probe(platform_t plat)
{
uint32_t ver;
uint32_t ver, sr;
int i, law_max, tgt;
ver = SVR_VER(mfspr(SPR_SVR));
if (ver == SVR_MPC8572E || ver == SVR_MPC8572)
@ -99,6 +103,23 @@ bare_probe(platform_t plat)
else
maxcpu = 1;
/*
* Clear local access windows. Skip DRAM entries, so we don't shoot
* ourselves in the foot.
*/
law_max = law_getmax();
for (i = 0; i < law_max; i++) {
sr = ccsr_read4(OCP85XX_LAWSR(i));
if ((sr & 0x80000000) == 0)
continue;
tgt = (sr & 0x01f00000) >> 20;
if (tgt == OCP85XX_TGTIF_RAM1 || tgt == OCP85XX_TGTIF_RAM2 ||
tgt == OCP85XX_TGTIF_RAM_INTL)
continue;
ccsr_write4(OCP85XX_LAWSR(i), sr & 0x7fffffff);
}
return (BUS_PROBE_GENERIC);
}
@ -109,24 +130,22 @@ void
bare_mem_regions(platform_t plat, struct mem_region **phys, int *physsz,
struct mem_region **avail, int *availsz)
{
struct bi_mem_region *mr;
int i;
uint32_t memsize;
int i, rv;
/* Initialize memory regions table */
mr = bootinfo_mr();
for (i = 0; i < bootinfo->bi_mem_reg_no; i++, mr++) {
if (i == MEM_REGIONS)
break;
if (mr->mem_base < 1048576) {
rv = fdt_get_mem_regions(avail_regions, availsz, &memsize);
if (rv != 0)
return;
for (i = 0; i < *availsz; i++) {
if (avail_regions[i].mr_start < 1048576) {
avail_regions[i].mr_size =
avail_regions[i].mr_size -
(1048576 - avail_regions[i].mr_start);
avail_regions[i].mr_start = 1048576;
avail_regions[i].mr_size = mr->mem_size -
(1048576 - mr->mem_base);
} else {
avail_regions[i].mr_start = mr->mem_base;
avail_regions[i].mr_size = mr->mem_size;
}
}
*availsz = i;
*avail = avail_regions;
/* On the bare metal platform phys == avail memory */
@ -138,12 +157,24 @@ static u_long
bare_timebase_freq(platform_t plat, struct cpuref *cpuref)
{
u_long ticks = -1;
phandle_t cpus, child;
pcell_t freq;
if ((cpus = OF_finddevice("/cpus")) == 0)
goto out;
if ((child = OF_child(cpus)) == 0)
goto out;
if (OF_getprop(child, "bus-frequency", (void *)&freq,
sizeof(freq)) <= 0)
goto out;
/*
* Time Base and Decrementer are updated every 8 CCB bus clocks.
* HID0[SEL_TBCLK] = 0
*/
ticks = bootinfo->bi_bus_clk / 8;
ticks = freq / 8;
out:
if (ticks <= 0)
panic("Unable to determine timebase frequency!");

View File

@ -77,7 +77,6 @@ __FBSDID("$FreeBSD$");
#include <vm/vm_pager.h>
#include <vm/uma.h>
#include <machine/bootinfo.h>
#include <machine/cpu.h>
#include <machine/pcb.h>
#include <machine/platform.h>
@ -2507,7 +2506,6 @@ struct pmap_md *
mmu_booke_scan_md(mmu_t mmu, struct pmap_md *prev)
{
static struct pmap_md md;
struct bi_mem_region *mr;
pte_t *pte;
vm_offset_t va;
@ -2565,16 +2563,18 @@ mmu_booke_scan_md(mmu_t mmu, struct pmap_md *prev)
return (NULL);
}
} else { /* minidumps */
mr = bootinfo_mr();
mem_regions(&physmem_regions, &physmem_regions_sz,
&availmem_regions, &availmem_regions_sz);
if (prev == NULL) {
/* first physical chunk. */
md.md_paddr = mr->mem_base;
md.md_size = mr->mem_size;
md.md_paddr = physmem_regions[0].mr_start;
md.md_size = physmem_regions[0].mr_size;
md.md_vaddr = ~0UL;
md.md_index = 1;
} else if (md.md_index < bootinfo->bi_mem_reg_no) {
md.md_paddr = mr[md.md_index].mem_base;
md.md_size = mr[md.md_index].mem_size;
} else if (md.md_index < physmem_regions_sz) {
md.md_paddr = physmem_regions[md.md_index].mr_start;
md.md_size = physmem_regions[md.md_index].mr_size;
md.md_vaddr = ~0UL;
md.md_index++;
} else {

View File

@ -24,8 +24,10 @@ options COMPAT_43
options DDB
#options DEADLKRES
options DEVICE_POLLING
options HZ=1000
#options DIAGNOSTIC
options FDT
makeoptions FDT_DTS_FILE=mpc8572ds.dts
#makeoptions FDT_DTS_FILE=mpc8555cds.dts
options FFS
options GDB
options GEOM_PART_GPT
@ -64,7 +66,7 @@ device ether
device fxp
device iic
device iicbus
device isa
#device isa
device loop
device md
device miibus

View File

@ -1,72 +0,0 @@
/*-
* Copyright (C) 2006-2008 Semihalf, Marian Balakowicz <m8@semihalf.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef _MACHINE_BOOTINFO_H_
#define _MACHINE_BOOTINFO_H_
#if !defined(LOCORE)
/* Platform hardware spec, received from loader(8) */
#define BI_VERSION 1
struct bi_mem_region {
vm_paddr_t mem_base;
vm_size_t mem_size;
};
struct bi_eth_addr {
u_int8_t mac_addr[6];
};
struct bootinfo {
u_int32_t bi_version;
vm_offset_t bi_bar_base;
u_int32_t bi_cpu_clk;
u_int32_t bi_bus_clk;
u_int8_t bi_mem_reg_no;
u_int8_t bi_eth_addr_no;
u_int8_t bi_data[1];
/*
* The bi_data container is allocated in run time and has the
* following layout:
*
* - bi_mem_reg_no elements of struct bi_mem_region
* - bi_eth_addr_no elements of struct bi_eth_addr
*/
};
extern struct bootinfo *bootinfo;
struct bi_mem_region *bootinfo_mr(void);
struct bi_eth_addr *bootinfo_eth(void);
#endif
#endif /* _MACHINE_BOOTINFO_H_ */

54
sys/powerpc/include/fdt.h Normal file
View File

@ -0,0 +1,54 @@
/*-
* Copyright (c) 2010 The FreeBSD Foundation
* All rights reserved.
*
* This software was developed by Semihalf under sponsorship from
* the FreeBSD Foundation.
*
* 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
*
* $FreeBSD$
*/
#ifndef _MACHINE_FDT_H_
#define _MACHINE_FDT_H_
#include <machine/bus.h>
#include <machine/intr_machdep.h>
#include <machine/platform.h>
#include <machine/vmparam.h>
/*
* This is the base virtual address the internal mem-mapped registers (IMMR)
* range is available at.
*/
#define FDT_IMMR_VA CCSRBAR_VA
/* Max interrupt number */
#define FDT_INTR_MAX INTR_VECTORS
/*
* Bus space tag. XXX endianess info needs to be derived from the blob.
*/
#define fdtbus_bs_tag (&bs_be_tag)
#endif /* _MACHINE_FDT_H_ */

View File

@ -32,7 +32,6 @@
#define MODINFOMD_ENVP 0x1001
#define MODINFOMD_HOWTO 0x1002
#define MODINFOMD_KERNEND 0x1003
#define MODINFOMD_BOOTINFO 0x1004
#define MODINFOMD_DTBP 0x1005
#define MODINFOMD_DTBP 0x1004
#endif /* !_MACHINE_METADATA_H_ */

View File

@ -1,51 +0,0 @@
/*-
* Copyright (c) 2006 Juniper Networks
* 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.
*
* $FreeBSD$
*/
#ifndef _MACHINE_OCPBUS_H_
#define _MACHINE_OCPBUS_H_
#define OCPBUS_IVAR_DEVTYPE 1
#define OCPBUS_IVAR_CLOCK 2
#define OCPBUS_IVAR_HWUNIT 3
#define OCPBUS_IVAR_MACADDR 4
/* Device types. */
#define OCPBUS_DEVTYPE_PIC 1
#define OCPBUS_DEVTYPE_TSEC 2
#define OCPBUS_DEVTYPE_UART 3
#define OCPBUS_DEVTYPE_QUICC 4
#define OCPBUS_DEVTYPE_PCIB 5
#define OCPBUS_DEVTYPE_LBC 6
#define OCPBUS_DEVTYPE_I2C 7
#define OCPBUS_DEVTYPE_SEC 8
/* PIC IDs */
#define OPIC_ID 0
#define ATPIC_ID 1
#endif /* _MACHINE_OCPBUS_H_ */

View File

@ -39,7 +39,7 @@ __FBSDID("$FreeBSD$");
#include <machine/ocpbus.h>
#include <machine/pio.h>
#include <powerpc/mpc85xx/ocpbus.h>
#include <powerpc/mpc85xx/mpc85xx.h>
#include <dev/ic/i8259.h>

View File

@ -23,6 +23,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* From: FreeBSD: src/sys/powerpc/mpc85xx/ds1553_bus_lbc.c,v 1.2 2009/06/24 15:48:20 raj
*/
#include <sys/cdefs.h>
@ -43,9 +44,9 @@ __FBSDID("$FreeBSD$");
#include <machine/bus.h>
#include <machine/resource.h>
#include <powerpc/mpc85xx/ds1553_reg.h>
#include <powerpc/mpc85xx/lbc.h>
#include <dev/ofw/ofw_bus_subr.h>
#include "ds1553_reg.h"
#include "clock_if.h"
static devclass_t rtc_devclass;
@ -76,20 +77,12 @@ DRIVER_MODULE(rtc, lbc, rtc_driver, rtc_devclass, 0, 0);
static int
rtc_probe(device_t dev)
{
uintptr_t devtype;
int error;
error = BUS_READ_IVAR(device_get_parent(dev), dev, LBC_IVAR_DEVTYPE,
&devtype);
if (error)
return (error);
if (devtype != LBC_DEVTYPE_RTC)
return (EINVAL);
if (!ofw_bus_is_compatible(dev, "dallas,ds1553"))
return (ENXIO);
device_set_desc(dev, "Dallas Semiconductor DS1553 RTC");
return (0);
return (BUS_PROBE_DEFAULT);
}
static int

View File

@ -36,7 +36,6 @@ __FBSDID("$FreeBSD$");
#include <machine/bus.h>
#include <machine/resource.h>
#include <machine/ocpbus.h>
#include <sys/rman.h>
#include <sys/lock.h>
@ -46,7 +45,8 @@ __FBSDID("$FreeBSD$");
#include <dev/iicbus/iicbus.h>
#include "iicbus_if.h"
#include <powerpc/mpc85xx/ocpbus.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
#define I2C_ADDR_REG 0x00 /* I2C slave address register */
#define I2C_FDR_REG 0x04 /* I2C frequency divider register */
@ -124,7 +124,7 @@ static driver_t i2c_driver = {
};
static devclass_t i2c_devclass;
DRIVER_MODULE(i2c, ocpbus, i2c_driver, i2c_devclass, 0, 0);
DRIVER_MODULE(i2c, simplebus, i2c_driver, i2c_devclass, 0, 0);
DRIVER_MODULE(iicbus, i2c, iicbus_driver, iicbus_devclass, 0, 0);
static __inline void
@ -157,7 +157,7 @@ i2c_do_wait(device_t dev, struct i2c_softc *sc, int write, int start)
int err;
uint8_t status;
status = i2c_read_reg(sc,I2C_STATUS_REG);
status = i2c_read_reg(sc, I2C_STATUS_REG);
if (status & I2CSR_MIF) {
if (write && start && (status & I2CSR_RXAK)) {
debugf("no ack %s", start ?
@ -188,19 +188,9 @@ i2c_do_wait(device_t dev, struct i2c_softc *sc, int write, int start)
static int
i2c_probe(device_t dev)
{
device_t parent;
struct i2c_softc *sc;
uintptr_t devtype;
int error;
parent = device_get_parent(dev);
error = BUS_READ_IVAR(parent, dev, OCPBUS_IVAR_DEVTYPE, &devtype);
if (error)
return (error);
if (devtype != OCPBUS_DEVTYPE_I2C)
if (!ofw_bus_is_compatible(dev, "fsl-i2c"))
return (ENXIO);
sc = device_get_softc(dev);
@ -209,7 +199,7 @@ i2c_probe(device_t dev)
sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->rid,
RF_ACTIVE);
if (sc->res == NULL) {
device_printf(dev, "could not allocate resources");
device_printf(dev, "could not allocate resources\n");
return (ENXIO);
}

View File

@ -1,8 +1,12 @@
/*-
* Copyright (c) 2006-2008, Juniper Networks, Inc.
* Copyright (c) 2008 Semihalf, Rafal Czubak
* Copyright (c) 2009 The FreeBSD Foundation
* All rights reserved.
*
* Portions of this software were developed by Semihalf
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@ -39,102 +43,28 @@ __FBSDID("$FreeBSD$");
#include <sys/bus.h>
#include <sys/rman.h>
#include <machine/bus.h>
#include <machine/ocpbus.h>
#include <vm/vm.h>
#include <vm/pmap.h>
#include <powerpc/mpc85xx/lbc.h>
#include <dev/fdt/fdt_common.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
#include <powerpc/mpc85xx/mpc85xx.h>
#include <powerpc/mpc85xx/ocpbus.h>
struct lbc_softc {
device_t sc_dev;
#include "ofw_bus_if.h"
#include "lbc.h"
struct resource *sc_res;
bus_space_handle_t sc_bsh;
bus_space_tag_t sc_bst;
int sc_rid;
#define DEBUG
#undef DEBUG
struct rman sc_rman;
vm_offset_t sc_kva[LBC_DEV_MAX];
};
struct lbc_devinfo {
int lbc_devtype;
/* LBC child unit. It also represents resource table entry number */
int lbc_unit;
};
/* Resources for MPC8555CDS system */
const struct lbc_resource mpc85xx_lbc_resources[] = {
/* Boot flash bank */
{
LBC_DEVTYPE_CFI, 0, 0xff800000, 0x00800000, 16,
LBCRES_MSEL_GPCM, LBCRES_DECC_DISABLED,
LBCRES_ATOM_DISABLED, 0
},
/* Second flash bank */
{
LBC_DEVTYPE_CFI, 1, 0xff000000, 0x00800000, 16,
LBCRES_MSEL_GPCM, LBCRES_DECC_DISABLED,
LBCRES_ATOM_DISABLED, 0
},
/* DS1553 RTC/NVRAM */
{
LBC_DEVTYPE_RTC, 2, 0xf8000000, 0x8000, 8,
LBCRES_MSEL_GPCM, LBCRES_DECC_DISABLED,
LBCRES_ATOM_DISABLED, 0
},
{0}
};
static int lbc_probe(device_t);
static int lbc_attach(device_t);
static int lbc_shutdown(device_t);
static int lbc_get_resource(device_t, device_t, int, int, u_long *,
u_long *);
static struct resource *lbc_alloc_resource(device_t, device_t, int, int *,
u_long, u_long, u_long, u_int);
static int lbc_print_child(device_t, device_t);
static int lbc_release_resource(device_t, device_t, int, int,
struct resource *);
static int lbc_read_ivar(device_t, device_t, int, uintptr_t *);
/*
* Bus interface definition
*/
static device_method_t lbc_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, lbc_probe),
DEVMETHOD(device_attach, lbc_attach),
DEVMETHOD(device_shutdown, lbc_shutdown),
/* Bus interface */
DEVMETHOD(bus_print_child, lbc_print_child),
DEVMETHOD(bus_read_ivar, lbc_read_ivar),
DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
DEVMETHOD(bus_teardown_intr, NULL),
DEVMETHOD(bus_get_resource, NULL),
DEVMETHOD(bus_alloc_resource, lbc_alloc_resource),
DEVMETHOD(bus_release_resource, lbc_release_resource),
DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
{ 0, 0 }
};
static driver_t lbc_driver = {
"lbc",
lbc_methods,
sizeof(struct lbc_softc)
};
devclass_t lbc_devclass;
DRIVER_MODULE(lbc, ocpbus, lbc_driver, lbc_devclass, 0, 0);
#ifdef DEBUG
#define debugf(fmt, args...) do { printf("%s(): ", __func__); \
printf(fmt,##args); } while (0)
#else
#define debugf(fmt, args...)
#endif
static __inline void
lbc_write_reg(struct lbc_softc *sc, bus_size_t off, uint32_t val)
@ -150,6 +80,58 @@ lbc_read_reg(struct lbc_softc *sc, bus_size_t off)
return (bus_space_read_4(sc->sc_bst, sc->sc_bsh, off));
}
static MALLOC_DEFINE(M_LBC, "localbus", "localbus devices information");
static int lbc_probe(device_t);
static int lbc_attach(device_t);
static int lbc_shutdown(device_t);
static struct resource *lbc_alloc_resource(device_t, device_t, int, int *,
u_long, u_long, u_long, u_int);
static int lbc_print_child(device_t, device_t);
static int lbc_release_resource(device_t, device_t, int, int,
struct resource *);
static const struct ofw_bus_devinfo *lbc_get_devinfo(device_t, device_t);
/*
* Bus interface definition
*/
static device_method_t lbc_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, lbc_probe),
DEVMETHOD(device_attach, lbc_attach),
DEVMETHOD(device_shutdown, lbc_shutdown),
/* Bus interface */
DEVMETHOD(bus_print_child, lbc_print_child),
DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
DEVMETHOD(bus_teardown_intr, NULL),
DEVMETHOD(bus_alloc_resource, lbc_alloc_resource),
DEVMETHOD(bus_release_resource, lbc_release_resource),
DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
/* OFW bus interface */
DEVMETHOD(ofw_bus_get_devinfo, lbc_get_devinfo),
DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat),
DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model),
DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name),
DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node),
DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type),
{ 0, 0 }
};
static driver_t lbc_driver = {
"lbc",
lbc_methods,
sizeof(struct lbc_softc)
};
devclass_t lbc_devclass;
DRIVER_MODULE(lbc, fdtbus, lbc_driver, lbc_devclass, 0, 0);
/*
* Calculate address mask used by OR(n) registers. Use memory region size to
* determine mask value. The size must be a power of two and within the range
@ -176,103 +158,101 @@ lbc_address_mask(uint32_t size)
return (0xffff8000 << (n - 15));
}
static device_t
lbc_mk_child(device_t dev, const struct lbc_resource *lbcres)
static void
lbc_banks_unmap(struct lbc_softc *sc)
{
struct lbc_devinfo *dinfo;
device_t child;
int i;
if (lbcres->lbr_unit > LBC_DEV_MAX - 1)
return (NULL);
for (i = 0; i < LBC_DEV_MAX; i++) {
if (sc->sc_banks[i].size == 0)
continue;
child = device_add_child(dev, NULL, -1);
if (child == NULL) {
device_printf(dev, "could not add LBC child device\n");
return (NULL);
law_disable(OCP85XX_TGTIF_LBC, sc->sc_banks[i].pa,
sc->sc_banks[i].size);
pmap_unmapdev(sc->sc_banks[i].va, sc->sc_banks[i].size);
}
dinfo = malloc(sizeof(struct lbc_devinfo), M_DEVBUF, M_WAITOK | M_ZERO);
dinfo->lbc_devtype = lbcres->lbr_devtype;
dinfo->lbc_unit = lbcres->lbr_unit;
device_set_ivars(child, dinfo);
return (child);
}
static int
lbc_init_child(device_t dev, device_t child)
lbc_banks_map(struct lbc_softc *sc)
{
struct lbc_softc *sc;
struct lbc_devinfo *dinfo;
const struct lbc_resource *res;
u_long start, size;
uint32_t regbuff;
int error, unit;
int error, i;
sc = device_get_softc(dev);
dinfo = device_get_ivars(child);
res = mpc85xx_lbc_resources;
regbuff = 0;
unit = -1;
for (; res->lbr_devtype; res++) {
if (res->lbr_unit != dinfo->lbc_unit)
for (i = 0; i < LBC_DEV_MAX; i++) {
if (sc->sc_banks[i].size == 0)
continue;
start = res->lbr_base_addr;
size = res->lbr_size;
unit = res->lbr_unit;
/* Physical address start/size. */
start = sc->sc_banks[i].pa;
size = sc->sc_banks[i].size;
/*
* Configure LAW for this LBC device and map its physical
* memory region into KVA
* Configure LAW for this LBC bank (CS) and map its physical
* memory region into KVA.
*/
error = law_enable(OCP85XX_TGTIF_LBC, start, size);
if (error)
return (error);
sc->sc_kva[unit] = (vm_offset_t)pmap_mapdev(start, size);
if (sc->sc_kva[unit] == 0) {
law_disable(OCP85XX_TGTIF_LBC, start, size);
sc->sc_banks[i].va = (vm_offset_t)pmap_mapdev(start, size);
if (sc->sc_banks[i].va == 0) {
lbc_banks_unmap(sc);
return (ENOSPC);
}
}
return (0);
}
static int
lbc_banks_enable(struct lbc_softc *sc)
{
u_long size;
uint32_t regval;
int error, i;
for (i = 0; i < LBC_DEV_MAX; i++) {
size = sc->sc_banks[i].size;
if (size == 0)
continue;
/*
* Compute and program BR value
* Compute and program BR value.
*/
regbuff |= start;
regval = 0;
regval |= sc->sc_banks[i].pa;
switch (res->lbr_port_size) {
switch (sc->sc_banks[i].width) {
case 8:
regbuff |= (1 << 11);
regval |= (1 << 11);
break;
case 16:
regbuff |= (2 << 11);
regval |= (2 << 11);
break;
case 32:
regbuff |= (3 << 11);
regval |= (3 << 11);
break;
default:
error = EINVAL;
goto fail;
}
regbuff |= (res->lbr_decc << 9);
regbuff |= (res->lbr_wp << 8);
regbuff |= (res->lbr_msel << 5);
regbuff |= (res->lbr_atom << 2);
regbuff |= 1;
regval |= (sc->sc_banks[i].decc << 9);
regval |= (sc->sc_banks[i].wp << 8);
regval |= (sc->sc_banks[i].msel << 5);
regval |= (sc->sc_banks[i].atom << 2);
regval |= 1;
lbc_write_reg(sc, LBC85XX_BR(unit), regbuff);
lbc_write_reg(sc, LBC85XX_BR(i), regval);
/*
* Compute and program OR value
* Compute and program OR value.
*/
regbuff = 0;
regbuff |= lbc_address_mask(size);
regval = 0;
regval |= lbc_address_mask(size);
switch (res->lbr_msel) {
switch (sc->sc_banks[i].msel) {
case LBCRES_MSEL_GPCM:
/* TODO Add flag support for option registers */
regbuff |= 0x00000ff7;
regval |= 0x00000ff7;
break;
case LBCRES_MSEL_FCM:
printf("FCM mode not supported yet!");
@ -285,35 +265,114 @@ lbc_init_child(device_t dev, device_t child)
error = ENOSYS;
goto fail;
}
lbc_write_reg(sc, LBC85XX_OR(unit), regbuff);
return (0);
lbc_write_reg(sc, LBC85XX_OR(i), regval);
}
/*
* Initialize configuration register:
* - enable Local Bus
* - set data buffer control signal function
* - disable parity byte select
* - set ECC parity type
* - set bus monitor timing and timer prescale
*/
lbc_write_reg(sc, LBC85XX_LBCR, 0);
/*
* Initialize clock ratio register:
* - disable PLL bypass mode
* - configure LCLK delay cycles for the assertion of LALE
* - set system clock divider
*/
lbc_write_reg(sc, LBC85XX_LCRR, 0x00030008);
return (0);
fail:
if (unit != -1) {
law_disable(OCP85XX_TGTIF_LBC, start, size);
pmap_unmapdev(sc->sc_kva[unit], size);
return (error);
} else
return (ENOENT);
lbc_banks_unmap(sc);
return (error);
}
static void
fdt_lbc_fixup(phandle_t node, struct lbc_softc *sc, struct lbc_devinfo *di)
{
pcell_t width;
int bank;
if (OF_getprop(node, "bank-width", (void *)&width, sizeof(width)) <= 0)
return;
bank = di->di_bank;
if (sc->sc_banks[bank].size == 0)
return;
/* Express width in bits. */
sc->sc_banks[bank].width = width * 8;
}
static int
fdt_lbc_reg_decode(phandle_t node, struct lbc_softc *sc,
struct lbc_devinfo *di)
{
u_long start, end, count;
pcell_t *reg, *regptr;
pcell_t addr_cells, size_cells;
int tuple_size, tuples;
int i, rv, bank;
if (fdt_addrsize_cells(OF_parent(node), &addr_cells, &size_cells) != 0)
return (ENXIO);
tuple_size = sizeof(pcell_t) * (addr_cells + size_cells);
tuples = OF_getprop_alloc(node, "reg", tuple_size, (void **)&reg);
debugf("addr_cells = %d, size_cells = %d\n", addr_cells, size_cells);
debugf("tuples = %d, tuple size = %d\n", tuples, tuple_size);
if (tuples <= 0)
/* No 'reg' property in this node. */
return (0);
regptr = reg;
for (i = 0; i < tuples; i++) {
bank = fdt_data_get((void *)reg, 1);
di->di_bank = bank;
reg += 1;
/* Get address/size. */
rv = fdt_data_to_res(reg, addr_cells - 1, size_cells, &start,
&count);
if (rv != 0) {
resource_list_free(&di->di_res);
goto out;
}
reg += addr_cells - 1 + size_cells;
/* Calculate address range relative to VA base. */
start = sc->sc_banks[bank].va + start;
end = start + count - 1;
debugf("reg addr bank = %d, start = %lx, end = %lx, "
"count = %lx\n", bank, start, end, count);
/* Use bank (CS) cell as rid. */
resource_list_add(&di->di_res, SYS_RES_MEMORY, bank, start,
end, count);
}
rv = 0;
out:
free(regptr, M_OFWPROP);
return (rv);
}
static int
lbc_probe(device_t dev)
{
device_t parent;
uintptr_t devtype;
int error;
parent = device_get_parent(dev);
error = BUS_READ_IVAR(parent, dev, OCPBUS_IVAR_DEVTYPE, &devtype);
if (error)
return (error);
if (devtype != OCPBUS_DEVTYPE_LBC)
if (!(ofw_bus_is_compatible(dev, "fsl,lbc") ||
ofw_bus_is_compatible(dev, "fsl,elbc")))
return (ENXIO);
device_set_desc(dev, "Freescale MPC85xx Local Bus Controller");
device_set_desc(dev, "Freescale Local Bus Controller");
return (BUS_PROBE_DEFAULT);
}
@ -321,9 +380,15 @@ static int
lbc_attach(device_t dev)
{
struct lbc_softc *sc;
struct lbc_devinfo *di;
struct rman *rm;
const struct lbc_resource *lbcres;
int error;
u_long offset, start, size;
device_t cdev;
phandle_t node, child;
pcell_t *ranges, *rangesptr;
int tuple_size, tuples;
int par_addr_cells;
int bank, error, i;
sc = device_get_softc(dev);
sc->sc_dev = dev;
@ -336,10 +401,11 @@ lbc_attach(device_t dev)
sc->sc_bst = rman_get_bustag(sc->sc_res);
sc->sc_bsh = rman_get_bushandle(sc->sc_res);
rangesptr = NULL;
rm = &sc->sc_rman;
rm->rm_type = RMAN_ARRAY;
rm->rm_descr = "MPC85XX Local Bus Space";
rm->rm_descr = "Local Bus Space";
rm->rm_start = 0UL;
rm->rm_end = ~0UL;
error = rman_init(rm);
@ -353,34 +419,139 @@ lbc_attach(device_t dev)
}
/*
* Initialize configuration register:
* - enable Local Bus
* - set data buffer control signal function
* - disable parity byte select
* - set ECC parity type
* - set bus monitor timing and timer prescale
* Process 'ranges' property.
*/
lbc_write_reg(sc, LBC85XX_LBCR, 0x00000000);
node = ofw_bus_get_node(dev);
if ((fdt_addrsize_cells(node, &sc->sc_addr_cells,
&sc->sc_size_cells)) != 0) {
error = ENXIO;
goto fail;
}
/*
* Initialize clock ratio register:
* - disable PLL bypass mode
* - configure LCLK delay cycles for the assertion of LALE
* - set system clock divider
*/
lbc_write_reg(sc, LBC85XX_LCRR, 0x00030008);
par_addr_cells = fdt_parent_addr_cells(node);
if (par_addr_cells > 2) {
device_printf(dev, "unsupported parent #addr-cells\n");
error = ERANGE;
goto fail;
}
tuple_size = sizeof(pcell_t) * (sc->sc_addr_cells + par_addr_cells +
sc->sc_size_cells);
lbcres = mpc85xx_lbc_resources;
tuples = OF_getprop_alloc(node, "ranges", tuple_size,
(void **)&ranges);
if (tuples < 0) {
device_printf(dev, "could not retrieve 'ranges' property\n");
error = ENXIO;
goto fail;
}
rangesptr = ranges;
for (; lbcres->lbr_devtype; lbcres++)
if (!lbc_mk_child(dev, lbcres)) {
error = ENXIO;
debugf("par addr_cells = %d, addr_cells = %d, size_cells = %d, "
"tuple_size = %d, tuples = %d\n", par_addr_cells,
sc->sc_addr_cells, sc->sc_size_cells, tuple_size, tuples);
start = 0;
size = 0;
for (i = 0; i < tuples; i++) {
/* The first cell is the bank (chip select) number. */
bank = fdt_data_get((void *)ranges, 1);
if (bank < 0 || bank > LBC_DEV_MAX) {
device_printf(dev, "bank out of range: %d\n", bank);
error = ERANGE;
goto fail;
}
ranges += 1;
/*
* Remaining cells of the child address define offset into
* this CS.
*/
offset = fdt_data_get((void *)ranges, sc->sc_addr_cells - 1);
ranges += sc->sc_addr_cells - 1;
/* Parent bus start address of this bank. */
start = fdt_data_get((void *)ranges, par_addr_cells);
ranges += par_addr_cells;
size = fdt_data_get((void *)ranges, sc->sc_size_cells);
ranges += sc->sc_size_cells;
debugf("bank = %d, start = %lx, size = %lx\n", bank,
start, size);
sc->sc_banks[bank].pa = start + offset;
sc->sc_banks[bank].size = size;
/*
* Attributes for the bank.
*
* XXX Note there are no DT bindings defined for them at the
* moment, so we need to provide some defaults.
*/
sc->sc_banks[bank].width = 16;
sc->sc_banks[bank].msel = LBCRES_MSEL_GPCM;
sc->sc_banks[bank].decc = LBCRES_DECC_DISABLED;
sc->sc_banks[bank].atom = LBCRES_ATOM_DISABLED;
sc->sc_banks[bank].wp = 0;
}
/*
* Initialize mem-mappings for the LBC banks (i.e. chip selects).
*/
error = lbc_banks_map(sc);
if (error)
goto fail;
/*
* Walk the localbus and add direct subordinates as our children.
*/
for (child = OF_child(node); child != 0; child = OF_peer(child)) {
di = malloc(sizeof(*di), M_LBC, M_WAITOK | M_ZERO);
if (ofw_bus_gen_setup_devinfo(&di->di_ofw, child) != 0) {
free(di, M_LBC);
device_printf(dev, "could not set up devinfo\n");
continue;
}
resource_list_init(&di->di_res);
if (fdt_lbc_reg_decode(child, sc, di)) {
device_printf(dev, "could not process 'reg' "
"property\n");
ofw_bus_gen_destroy_devinfo(&di->di_ofw);
free(di, M_LBC);
continue;
}
fdt_lbc_fixup(child, sc, di);
/* Add newbus device for this FDT node */
cdev = device_add_child(dev, NULL, -1);
if (cdev == NULL) {
device_printf(dev, "could not add child: %s\n",
di->di_ofw.obd_name);
resource_list_free(&di->di_res);
ofw_bus_gen_destroy_devinfo(&di->di_ofw);
free(di, M_LBC);
continue;
}
debugf("added child name='%s', node=%p\n", di->di_ofw.obd_name,
(void *)child);
device_set_ivars(cdev, di);
}
/*
* Enable the LBC.
*/
lbc_banks_enable(sc);
free(rangesptr, M_OFWPROP);
return (bus_generic_attach(dev));
fail:
free(rangesptr, M_OFWPROP);
bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rid, sc->sc_res);
return (error);
}
@ -394,137 +565,114 @@ lbc_shutdown(device_t dev)
}
static struct resource *
lbc_alloc_resource(device_t dev, device_t child, int type, int *rid,
lbc_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 lbc_softc *sc;
struct lbc_devinfo *dinfo;
struct resource *rv;
struct lbc_devinfo *di;
struct resource_list_entry *rle;
struct resource *res;
struct rman *rm;
int error;
sc = device_get_softc(dev);
dinfo = device_get_ivars(child);
if (type != SYS_RES_MEMORY && type != SYS_RES_IRQ)
return (NULL);
int needactivate;
/* We only support default allocations. */
if (start != 0ul || end != ~0ul)
return (NULL);
sc = device_get_softc(bus);
if (type == SYS_RES_IRQ)
return (bus_alloc_resource(dev, type, rid, start, end, count,
return (bus_alloc_resource(bus, type, rid, start, end, count,
flags));
if (!sc->sc_kva[dinfo->lbc_unit]) {
error = lbc_init_child(dev, child);
if (error)
return (NULL);
}
error = lbc_get_resource(dev, child, type, *rid, &start, &count);
if (error)
/*
* Request for the default allocation with a given rid: use resource
* list stored in the local device info.
*/
if ((di = device_get_ivars(child)) == NULL)
return (NULL);
rm = &sc->sc_rman;
end = start + count - 1;
rv = rman_reserve_resource(rm, start, end, count, flags, child);
if (rv != NULL) {
rman_set_bustag(rv, &bs_be_tag);
rman_set_bushandle(rv, rman_get_start(rv));
if (type == SYS_RES_IOPORT)
type = SYS_RES_MEMORY;
rid = &di->di_bank;
rle = resource_list_find(&di->di_res, type, *rid);
if (rle == NULL) {
device_printf(bus, "no default resources for "
"rid = %d, type = %d\n", *rid, type);
return (NULL);
}
return (rv);
start = rle->start;
count = rle->count;
end = start + count - 1;
sc = device_get_softc(bus);
needactivate = flags & RF_ACTIVE;
flags &= ~RF_ACTIVE;
rm = &sc->sc_rman;
res = rman_reserve_resource(rm, start, end, count, flags, child);
if (res == NULL) {
device_printf(bus, "failed to reserve resource %#lx - %#lx "
"(%#lx)\n", start, end, count);
return (NULL);
}
rman_set_rid(res, *rid);
rman_set_bustag(res, &bs_be_tag);
rman_set_bushandle(res, rman_get_start(res));
if (needactivate)
if (bus_activate_resource(child, type, *rid, res)) {
device_printf(child, "resource activation failed\n");
rman_release_resource(res);
return (NULL);
}
return (res);
}
static int
lbc_print_child(device_t dev, device_t child)
{
u_long size, start;
int error, retval, rid;
struct lbc_devinfo *di;
struct resource_list *rl;
int rv;
retval = bus_print_child_header(dev, child);
di = device_get_ivars(child);
rl = &di->di_res;
rid = 0;
while (1) {
error = lbc_get_resource(dev, child, SYS_RES_MEMORY, rid,
&start, &size);
if (error)
break;
retval += (rid == 0) ? printf(" iomem ") : printf(",");
retval += printf("%#lx", start);
if (size > 1)
retval += printf("-%#lx", start + size - 1);
rid++;
}
rv = 0;
rv += bus_print_child_header(dev, child);
rv += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx");
rv += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
rv += bus_print_child_footer(dev, child);
retval += bus_print_child_footer(dev, child);
return (retval);
}
static int
lbc_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
{
struct lbc_devinfo *dinfo;
if (device_get_parent(child) != dev)
return (EINVAL);
dinfo = device_get_ivars(child);
switch (index) {
case LBC_IVAR_DEVTYPE:
*result = dinfo->lbc_devtype;
return (0);
default:
break;
}
return (EINVAL);
return (rv);
}
static int
lbc_release_resource(device_t dev, device_t child, int type, int rid,
struct resource *res)
{
int err;
if (rman_get_flags(res) & RF_ACTIVE) {
err = bus_deactivate_resource(child, type, rid, res);
if (err)
return (err);
}
return (rman_release_resource(res));
}
static int
lbc_get_resource(device_t dev, device_t child, int type, int rid,
u_long *startp, u_long *countp)
static const struct ofw_bus_devinfo *
lbc_get_devinfo(device_t bus, device_t child)
{
struct lbc_softc *sc;
struct lbc_devinfo *dinfo;
const struct lbc_resource *lbcres;
struct lbc_devinfo *di;
if (type != SYS_RES_MEMORY)
return (ENOENT);
/* Currently all LBC devices have a single RID per type. */
if (rid != 0)
return (ENOENT);
sc = device_get_softc(dev);
dinfo = device_get_ivars(child);
if ((dinfo->lbc_unit < 0) || (dinfo->lbc_unit > (LBC_DEV_MAX - 1)))
return (EINVAL);
lbcres = mpc85xx_lbc_resources;
switch (dinfo->lbc_devtype) {
case LBC_DEVTYPE_CFI:
case LBC_DEVTYPE_RTC:
for (; lbcres->lbr_devtype; lbcres++) {
if (dinfo->lbc_unit == lbcres->lbr_unit) {
*startp = sc->sc_kva[lbcres->lbr_unit];
*countp = lbcres->lbr_size;
return (0);
}
}
default:
return (EDOOFUS);
}
return (0);
di = device_get_ivars(child);
return (&di->di_ofw);
}

View File

@ -29,15 +29,9 @@
#ifndef _MACHINE_LBC_H_
#define _MACHINE_LBC_H_
#define LBC_IVAR_DEVTYPE 1
/* Maximum number of devices on Local Bus */
#define LBC_DEV_MAX 8
/* Device types. */
#define LBC_DEVTYPE_CFI 1
#define LBC_DEVTYPE_RTC 2
/* Local access registers */
#define LBC85XX_BR(n) (8 * n)
#define LBC85XX_OR(n) (4 + (8 * n))
@ -61,18 +55,42 @@
#define LBCRES_ATOM_RAWA 1
#define LBCRES_ATOM_WARA 2
struct lbc_resource {
int lbr_devtype; /* LBC device type */
int lbr_unit; /* Resource table entry number */
vm_paddr_t lbr_base_addr; /* Device mem region base address */
size_t lbr_size; /* Device mem region size */
int lbr_port_size; /* Data bus width */
uint8_t lbr_msel; /* LBC machine select */
uint8_t lbr_decc; /* Data error checking mode */
uint8_t lbr_atom; /* Atomic operation mode */
uint8_t lbr_wp; /* Write protect */
struct lbc_bank {
u_long pa; /* physical addr of the bank */
u_long size; /* bank size */
vm_offset_t va; /* VA of the bank */
/*
* XXX the following bank attributes do not have properties specified
* in the LBC DTS bindings yet (11.2009), so they are mainly a
* placeholder for future extensions.
*/
int width; /* data bus width */
uint8_t msel; /* machine select */
uint8_t atom; /* atomic op mode */
uint8_t wp; /* write protect */
uint8_t decc; /* data error checking */
};
extern const struct lbc_resource mpc85xx_lbc_resources[];
struct lbc_softc {
device_t sc_dev;
struct resource *sc_res;
bus_space_handle_t sc_bsh;
bus_space_tag_t sc_bst;
int sc_rid;
struct rman sc_rman;
int sc_addr_cells;
int sc_size_cells;
struct lbc_bank sc_banks[LBC_DEV_MAX];
};
struct lbc_devinfo {
struct ofw_bus_devinfo di_ofw;
struct resource_list di_res;
int di_bank;
};
#endif /* _MACHINE_LBC_H_ */

View File

@ -29,6 +29,9 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/rman.h>
#include <vm/vm.h>
#include <vm/vm_param.h>
@ -37,7 +40,6 @@ __FBSDID("$FreeBSD$");
#include <machine/cpufunc.h>
#include <machine/spr.h>
#include <powerpc/mpc85xx/ocpbus.h>
#include <powerpc/mpc85xx/mpc85xx.h>
/*
@ -129,6 +131,39 @@ law_disable(int trgt, u_long addr, u_long size)
return (ENOENT);
}
int
law_pci_target(struct resource *res, int *trgt_mem, int *trgt_io)
{
u_long start;
uint32_t ver;
int trgt, rv;
ver = SVR_VER(mfspr(SPR_SVR));
start = rman_get_start(res) & 0xf000;
rv = 0;
trgt = -1;
switch (start) {
case 0x8000:
trgt = 0;
break;
case 0x9000:
trgt = 1;
break;
case 0xa000:
if (ver == SVR_MPC8572E || ver == SVR_MPC8572)
trgt = 2;
else
rv = EINVAL;
break;
default:
rv = ENXIO;
}
*trgt_mem = *trgt_io = trgt;
return (rv);
}
void
cpu_reset(void)
{

View File

@ -1,5 +1,6 @@
/*-
* Copyright (C) 2008 Semihalf, Rafal Jaworowski
* Copyright 2006 by Juniper Networks.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -29,10 +30,61 @@
#ifndef _MPC85XX_H_
#define _MPC85XX_H_
/*
* Configuration control and status registers
*/
#define OCP85XX_CCSRBAR (CCSRBAR_VA + 0x0)
#define OCP85XX_BPTR (CCSRBAR_VA + 0x20)
/*
* E500 Coherency Module registers
*/
#define OCP85XX_EEBPCR (CCSRBAR_VA + 0x1010)
/*
* Local access registers
*/
#define OCP85XX_LAWBAR(n) (CCSRBAR_VA + 0xc08 + 0x20 * (n))
#define OCP85XX_LAWSR(n) (CCSRBAR_VA + 0xc10 + 0x20 * (n))
#define OCP85XX_TGTIF_LBC 4
#define OCP85XX_TGTIF_RAM_INTL 11
#define OCP85XX_TGTIF_RIO 12
#define OCP85XX_TGTIF_RAM1 15
#define OCP85XX_TGTIF_RAM2 22
/*
* L2 cache registers
*/
#define OCP85XX_L2CTL (CCSRBAR_VA + 0x20000)
/*
* Power-On Reset configuration
*/
#define OCP85XX_PORDEVSR (CCSRBAR_VA + 0xe000c)
#define OCP85XX_PORDEVSR_IO_SEL 0x00780000
#define OCP85XX_PORDEVSR_IO_SEL_SHIFT 19
#define OCP85XX_PORDEVSR2 (CCSRBAR_VA + 0xe0014)
#define OCP85XX_DEVDISR (CCSRBAR_VA + 0xe0070)
#define OCP85XX_DEVDISR_PCIE0 0x20000000
#define OCP85XX_DEVDISR_PCIE1 0x04000000
#define OCP85XX_DEVDISR_PCIE2 0x02000000
/*
* Status Registers.
*/
#define OCP85XX_RSTCR (CCSRBAR_VA + 0xe00b0)
/*
* Prototypes.
*/
uint32_t ccsr_read4(uintptr_t addr);
void ccsr_write4(uintptr_t addr, uint32_t val);
int law_enable(int trgt, u_long addr, u_long size);
int law_disable(int trgt, u_long addr, u_long size);
int law_getmax(void);
int law_pci_target(struct resource *, int *, int *);
#endif /* _MPC85XX_H_ */

View File

@ -112,13 +112,10 @@ static int
nexus_probe (device_t dev)
{
/*
* Add OCP (on-chip peripheral) bus
*/
device_add_child(dev, "ocpbus", 0);
device_add_child(dev, "fdtbus", 0);
device_quiet(dev);
device_set_desc(dev, "MPC85xx Nexus device");
return (0);
return (BUS_PROBE_DEFAULT);
}
static int

View File

@ -1,622 +0,0 @@
/*-
* Copyright 2006 by Juniper Networks. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/ktr.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/bus.h>
#include <sys/rman.h>
#include <sys/malloc.h>
#include <machine/spr.h>
#include <machine/ocpbus.h>
#include <machine/intr_machdep.h>
#include <machine/md_var.h>
#include <machine/vmparam.h>
#include <machine/bootinfo.h>
#include <powerpc/mpc85xx/ocpbus.h>
#include <powerpc/mpc85xx/mpc85xx.h>
#include "pic_if.h"
extern struct bus_space bs_be_tag;
struct ocpbus_softc {
struct rman sc_mem;
struct rman sc_irq;
};
struct ocp_devinfo {
int ocp_devtype;
int ocp_unit;
};
static int ocpbus_probe(device_t);
static int ocpbus_attach(device_t);
static int ocpbus_shutdown(device_t);
static int ocpbus_get_resource(device_t, device_t, int, int, u_long *,
u_long *);
static struct resource *ocpbus_alloc_resource(device_t, device_t, int, int *,
u_long, u_long, u_long, u_int);
static int ocpbus_print_child(device_t, device_t);
static int ocpbus_release_resource(device_t, device_t, int, int,
struct resource *);
static int ocpbus_read_ivar(device_t, device_t, int, uintptr_t *);
static int ocpbus_setup_intr(device_t, device_t, struct resource *, int,
driver_filter_t *, driver_intr_t *, void *, void **);
static int ocpbus_teardown_intr(device_t, device_t, struct resource *, void *);
static int ocpbus_config_intr(device_t, int, enum intr_trigger,
enum intr_polarity);
/*
* Bus interface definition
*/
static device_method_t ocpbus_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, ocpbus_probe),
DEVMETHOD(device_attach, ocpbus_attach),
DEVMETHOD(device_shutdown, ocpbus_shutdown),
/* Bus interface */
DEVMETHOD(bus_print_child, ocpbus_print_child),
DEVMETHOD(bus_read_ivar, ocpbus_read_ivar),
DEVMETHOD(bus_setup_intr, ocpbus_setup_intr),
DEVMETHOD(bus_teardown_intr, ocpbus_teardown_intr),
DEVMETHOD(bus_config_intr, ocpbus_config_intr),
DEVMETHOD(bus_get_resource, ocpbus_get_resource),
DEVMETHOD(bus_alloc_resource, ocpbus_alloc_resource),
DEVMETHOD(bus_release_resource, ocpbus_release_resource),
DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
{ 0, 0 }
};
static driver_t ocpbus_driver = {
"ocpbus",
ocpbus_methods,
sizeof(struct ocpbus_softc)
};
devclass_t ocpbus_devclass;
DRIVER_MODULE(ocpbus, nexus, ocpbus_driver, ocpbus_devclass, 0, 0);
static device_t
ocpbus_mk_child(device_t dev, int type, int unit)
{
struct ocp_devinfo *dinfo;
device_t child;
child = device_add_child(dev, NULL, -1);
if (child == NULL) {
device_printf(dev, "could not add child device\n");
return (NULL);
}
dinfo = malloc(sizeof(struct ocp_devinfo), M_DEVBUF, M_WAITOK|M_ZERO);
dinfo->ocp_devtype = type;
dinfo->ocp_unit = unit;
device_set_ivars(child, dinfo);
return (child);
}
static int
ocpbus_write_law(int trgt, int type, u_long *startp, u_long *countp)
{
u_long addr, size;
switch (type) {
case SYS_RES_MEMORY:
switch (trgt) {
case OCP85XX_TGTIF_PCI0:
addr = 0x80000000;
size = 0x10000000;
break;
case OCP85XX_TGTIF_PCI1:
addr = 0x90000000;
size = 0x10000000;
break;
case OCP85XX_TGTIF_PCI2:
addr = 0xA0000000;
size = 0x10000000;
break;
case OCP85XX_TGTIF_PCI3:
addr = 0xB0000000;
size = 0x10000000;
break;
default:
return (EINVAL);
}
break;
case SYS_RES_IOPORT:
switch (trgt) {
case OCP85XX_TGTIF_PCI0:
addr = 0xfee00000;
size = 0x00010000;
break;
case OCP85XX_TGTIF_PCI1:
addr = 0xfee10000;
size = 0x00010000;
break;
case OCP85XX_TGTIF_PCI2:
addr = 0xfee20000;
size = 0x00010000;
break;
case OCP85XX_TGTIF_PCI3:
addr = 0xfee30000;
size = 0x00010000;
break;
default:
return (EINVAL);
}
break;
default:
return (EINVAL);
}
*startp = addr;
*countp = size;
return (law_enable(trgt, *startp, *countp));
}
static int
ocpbus_probe(device_t dev)
{
device_set_desc(dev, "Freescale on-chip peripherals bus");
return (BUS_PROBE_DEFAULT);
}
static int
ocpbus_attach(device_t dev)
{
struct ocpbus_softc *sc;
int error, i, tgt, law_max;
uint32_t sr;
u_long start, end;
sc = device_get_softc(dev);
ocpbus_mk_child(dev, OCPBUS_DEVTYPE_I2C, 0);
ocpbus_mk_child(dev, OCPBUS_DEVTYPE_I2C, 1);
ocpbus_mk_child(dev, OCPBUS_DEVTYPE_UART, 0);
ocpbus_mk_child(dev, OCPBUS_DEVTYPE_UART, 1);
ocpbus_mk_child(dev, OCPBUS_DEVTYPE_LBC, 0);
ocpbus_mk_child(dev, OCPBUS_DEVTYPE_PCIB, 0);
ocpbus_mk_child(dev, OCPBUS_DEVTYPE_PCIB, 1);
ocpbus_mk_child(dev, OCPBUS_DEVTYPE_PCIB, 2);
ocpbus_mk_child(dev, OCPBUS_DEVTYPE_PCIB, 3);
ocpbus_mk_child(dev, OCPBUS_DEVTYPE_TSEC, 0);
ocpbus_mk_child(dev, OCPBUS_DEVTYPE_TSEC, 1);
ocpbus_mk_child(dev, OCPBUS_DEVTYPE_TSEC, 2);
ocpbus_mk_child(dev, OCPBUS_DEVTYPE_TSEC, 3);
ocpbus_mk_child(dev, OCPBUS_DEVTYPE_PIC, 0);
ocpbus_mk_child(dev, OCPBUS_DEVTYPE_QUICC, 0);
ocpbus_mk_child(dev, OCPBUS_DEVTYPE_SEC, 0);
/* Set up IRQ rman */
start = 0;
end = INTR_VECTORS - 1;
sc->sc_irq.rm_start = start;
sc->sc_irq.rm_end = end;
sc->sc_irq.rm_type = RMAN_ARRAY;
sc->sc_irq.rm_descr = "Interrupt request lines";
if (rman_init(&sc->sc_irq) ||
rman_manage_region(&sc->sc_irq, start, end))
panic("ocpbus_attach IRQ rman");
/* Set up I/O mem rman */
sc->sc_mem.rm_type = RMAN_ARRAY;
sc->sc_mem.rm_descr = "OCPBus Device Memory";
error = rman_init(&sc->sc_mem);
if (error) {
device_printf(dev, "rman_init() failed. error = %d\n", error);
return (error);
}
error = rman_manage_region(&sc->sc_mem, CCSRBAR_VA,
CCSRBAR_VA + CCSRBAR_SIZE - 1);
if (error) {
device_printf(dev, "rman_manage_region() failed. error = %d\n",
error);
return (error);
}
/*
* Clear local access windows. Skip DRAM entries, so we don't shoot
* ourselves in the foot.
*/
law_max = law_getmax();
for (i = 0; i < law_max; i++) {
sr = ccsr_read4(OCP85XX_LAWSR(i));
if ((sr & 0x80000000) == 0)
continue;
tgt = (sr & 0x01f00000) >> 20;
if (tgt == OCP85XX_TGTIF_RAM1 || tgt == OCP85XX_TGTIF_RAM2 ||
tgt == OCP85XX_TGTIF_RAM_INTL)
continue;
ccsr_write4(OCP85XX_LAWSR(i), sr & 0x7fffffff);
}
if (bootverbose)
device_printf(dev, "PORDEVSR=%08x, PORDEVSR2=%08x\n",
ccsr_read4(OCP85XX_PORDEVSR),
ccsr_read4(OCP85XX_PORDEVSR2));
/*
* Internal interrupt are always active-high. Since the sense cannot
* be specified, we program as edge-triggered to make sure we write
* a 0 value to the reserved bit in the OpenPIC compliant PIC. This
* is not to say anything about the sense of any of the internal
* interrupt sources.
*/
for (i = PIC_IRQ_INT(0); i < PIC_IRQ_INT(32); i++)
powerpc_config_intr(i, INTR_TRIGGER_EDGE, INTR_POLARITY_HIGH);
return (bus_generic_attach(dev));
}
static int
ocpbus_shutdown(device_t dev)
{
return(0);
}
struct ocp_resource {
int sr_devtype;
int sr_unit;
int sr_resource;
int sr_rid;
int sr_offset;
int sr_size;
};
const struct ocp_resource mpc8555_resources[] = {
{OCPBUS_DEVTYPE_PIC, 0, SYS_RES_MEMORY, 0, OCP85XX_OPENPIC_OFF,
OCP85XX_OPENPIC_SIZE},
{OCPBUS_DEVTYPE_QUICC, 0, SYS_RES_MEMORY, 0, OCP85XX_QUICC_OFF,
OCP85XX_QUICC_SIZE},
{OCPBUS_DEVTYPE_QUICC, 0, SYS_RES_IRQ, 0, 30, 1},
{OCPBUS_DEVTYPE_TSEC, 0, SYS_RES_MEMORY, 0, OCP85XX_TSEC0_OFF,
OCP85XX_TSEC_SIZE},
{OCPBUS_DEVTYPE_TSEC, 0, SYS_RES_IRQ, 0, 13, 1},
{OCPBUS_DEVTYPE_TSEC, 0, SYS_RES_IRQ, 1, 14, 1},
{OCPBUS_DEVTYPE_TSEC, 0, SYS_RES_IRQ, 2, 18, 1},
{OCPBUS_DEVTYPE_TSEC, 1, SYS_RES_MEMORY, 0, OCP85XX_TSEC1_OFF,
OCP85XX_TSEC_SIZE},
{OCPBUS_DEVTYPE_TSEC, 1, SYS_RES_IRQ, 0, 19, 1},
{OCPBUS_DEVTYPE_TSEC, 1, SYS_RES_IRQ, 1, 20, 1},
{OCPBUS_DEVTYPE_TSEC, 1, SYS_RES_IRQ, 2, 24, 1},
{OCPBUS_DEVTYPE_TSEC, 2, SYS_RES_MEMORY, 0, OCP85XX_TSEC2_OFF,
OCP85XX_TSEC_SIZE},
{OCPBUS_DEVTYPE_TSEC, 2, SYS_RES_IRQ, 0, 15, 1},
{OCPBUS_DEVTYPE_TSEC, 2, SYS_RES_IRQ, 1, 16, 1},
{OCPBUS_DEVTYPE_TSEC, 2, SYS_RES_IRQ, 2, 17, 1},
{OCPBUS_DEVTYPE_TSEC, 3, SYS_RES_MEMORY, 0, OCP85XX_TSEC3_OFF,
OCP85XX_TSEC_SIZE},
{OCPBUS_DEVTYPE_TSEC, 3, SYS_RES_IRQ, 0, 21, 1},
{OCPBUS_DEVTYPE_TSEC, 3, SYS_RES_IRQ, 1, 22, 1},
{OCPBUS_DEVTYPE_TSEC, 3, SYS_RES_IRQ, 2, 23, 1},
{OCPBUS_DEVTYPE_UART, 0, SYS_RES_MEMORY, 0, OCP85XX_UART0_OFF,
OCP85XX_UART_SIZE},
{OCPBUS_DEVTYPE_UART, 0, SYS_RES_IRQ, 0, 26, 1},
{OCPBUS_DEVTYPE_UART, 1, SYS_RES_MEMORY, 0, OCP85XX_UART1_OFF,
OCP85XX_UART_SIZE},
{OCPBUS_DEVTYPE_UART, 1, SYS_RES_IRQ, 0, 26, 1},
{OCPBUS_DEVTYPE_PCIB, 0, SYS_RES_MEMORY, 0, OCP85XX_PCI0_OFF,
OCP85XX_PCI_SIZE},
{OCPBUS_DEVTYPE_PCIB, 0, SYS_RES_MEMORY, 1, 0, OCP85XX_TGTIF_PCI0},
{OCPBUS_DEVTYPE_PCIB, 0, SYS_RES_IOPORT, 1, 0, OCP85XX_TGTIF_PCI0},
{OCPBUS_DEVTYPE_PCIB, 1, SYS_RES_MEMORY, 0, OCP85XX_PCI1_OFF,
OCP85XX_PCI_SIZE},
{OCPBUS_DEVTYPE_PCIB, 1, SYS_RES_MEMORY, 1, 0, OCP85XX_TGTIF_PCI1},
{OCPBUS_DEVTYPE_PCIB, 1, SYS_RES_IOPORT, 1, 0, OCP85XX_TGTIF_PCI1},
{OCPBUS_DEVTYPE_PCIB, 2, SYS_RES_MEMORY, 0, OCP85XX_PCI2_OFF,
OCP85XX_PCI_SIZE},
{OCPBUS_DEVTYPE_PCIB, 2, SYS_RES_MEMORY, 1, 0, OCP85XX_TGTIF_PCI2},
{OCPBUS_DEVTYPE_PCIB, 2, SYS_RES_IOPORT, 1, 0, OCP85XX_TGTIF_PCI2},
{OCPBUS_DEVTYPE_PCIB, 3, SYS_RES_MEMORY, 0, OCP85XX_PCI3_OFF,
OCP85XX_PCI_SIZE},
{OCPBUS_DEVTYPE_PCIB, 3, SYS_RES_MEMORY, 1, 0, OCP85XX_TGTIF_PCI3},
{OCPBUS_DEVTYPE_PCIB, 3, SYS_RES_IOPORT, 1, 0, OCP85XX_TGTIF_PCI3},
{OCPBUS_DEVTYPE_LBC, 0, SYS_RES_MEMORY, 0, OCP85XX_LBC_OFF,
OCP85XX_LBC_SIZE},
{OCPBUS_DEVTYPE_I2C, 0, SYS_RES_MEMORY, 0, OCP85XX_I2C0_OFF,
OCP85XX_I2C_SIZE},
{OCPBUS_DEVTYPE_I2C, 0, SYS_RES_IRQ, 0, 27, 1},
{OCPBUS_DEVTYPE_I2C, 1, SYS_RES_MEMORY, 0, OCP85XX_I2C1_OFF,
OCP85XX_I2C_SIZE},
{OCPBUS_DEVTYPE_I2C, 1, SYS_RES_IRQ, 0, 27, 1},
{OCPBUS_DEVTYPE_SEC, 0, SYS_RES_MEMORY, 0, OCP85XX_SEC_OFF,
OCP85XX_SEC_SIZE},
{OCPBUS_DEVTYPE_SEC, 0, SYS_RES_IRQ, 0, 29, 1},
{OCPBUS_DEVTYPE_SEC, 0, SYS_RES_IRQ, 1, 42, 1},
{0}
};
static int
ocpbus_get_resource(device_t dev, device_t child, int type, int rid,
u_long *startp, u_long *countp)
{
const struct ocp_resource *res;
struct ocp_devinfo *dinfo;
u_long start = 0, count = 0;
int error;
dinfo = device_get_ivars(child);
/*
* Lookup the correct values.
*/
res = mpc8555_resources;
for (; res->sr_devtype; res++) {
if (res->sr_devtype != dinfo->ocp_devtype)
continue;
if (res->sr_unit != dinfo->ocp_unit)
continue;
if (res->sr_rid != rid)
continue;
if (res->sr_resource != type)
continue;
if (res->sr_offset != 0) {
error = 0;
switch (type) {
case SYS_RES_MEMORY:
start = res->sr_offset + CCSRBAR_VA;
break;
case SYS_RES_IRQ:
start = PIC_IRQ_INT(res->sr_offset);
break;
default:
error = EINVAL;
break;
}
count = res->sr_size;
} else
error = ocpbus_write_law(res->sr_size, type, &start,
&count);
if (!error) {
if (startp != NULL)
*startp = start;
if (countp != NULL)
*countp = count;
}
return (error);
}
return (ENOENT);
}
static struct resource *
ocpbus_alloc_resource(device_t dev, device_t child, int type, int *rid,
u_long start, u_long end, u_long count, u_int flags)
{
struct ocpbus_softc *sc;
struct resource *rv;
int error;
sc = device_get_softc(dev);
switch (type) {
case SYS_RES_IRQ:
if (start == 0ul && end == ~0ul) {
error = ocpbus_get_resource(dev, child, type, *rid,
&start, &count);
if (error)
return (NULL);
}
rv = rman_reserve_resource(&sc->sc_irq, start,
start + count - 1, count, flags, child);
if (rv == NULL)
return (NULL);
break;
case SYS_RES_MEMORY:
if (start != 0ul || end != ~0ul)
return (NULL);
error = ocpbus_get_resource(dev, child, type, *rid, &start,
&count);
if (error)
return (NULL);
rv = rman_reserve_resource(&sc->sc_mem, start,
start + count - 1, count, flags, child);
if (rv == NULL)
return (NULL);
rman_set_bustag(rv, &bs_be_tag);
rman_set_bushandle(rv, rman_get_start(rv));
break;
default:
return (NULL);
}
rman_set_rid(rv, *rid);
return (rv);
}
static int
ocpbus_print_child(device_t dev, device_t child)
{
u_long size, start;
int error, retval, rid;
retval = bus_print_child_header(dev, child);
rid = 0;
while (1) {
error = ocpbus_get_resource(dev, child, SYS_RES_MEMORY, rid,
&start, &size);
if (error)
break;
retval += (rid == 0) ? printf(" iomem ") : printf(",");
retval += printf("%#lx", start);
if (size > 1)
retval += printf("-%#lx", start + size - 1);
rid++;
}
/*
* The SYS_RES_IOPORT resource of the PCIB has rid 1 because the
* the SYS_RES_MEMORY resource related to the decoding window also
* has rid 1. This is friendlier for the PCIB child...
*/
rid = 1;
while (1) {
error = ocpbus_get_resource(dev, child, SYS_RES_IOPORT, rid,
&start, &size);
if (error)
break;
retval += (rid == 1) ? printf(" ioport ") : printf(",");
retval += printf("%#lx", start);
if (size > 1)
retval += printf("-%#lx", start + size - 1);
rid++;
}
rid = 0;
while (1) {
error = ocpbus_get_resource(dev, child, SYS_RES_IRQ, rid,
&start, &size);
if (error)
break;
retval += (rid == 0) ? printf(" irq ") : printf(",");
retval += printf("%ld", start);
rid++;
}
retval += bus_print_child_footer(dev, child);
return (retval);
}
static int
ocpbus_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
{
struct ocp_devinfo *dinfo;
struct bi_eth_addr *eth;
int unit;
if (device_get_parent(child) != dev)
return (EINVAL);
dinfo = device_get_ivars(child);
switch (index) {
case OCPBUS_IVAR_CLOCK:
*result = bootinfo->bi_bus_clk;
return (0);
case OCPBUS_IVAR_DEVTYPE:
*result = dinfo->ocp_devtype;
return (0);
case OCPBUS_IVAR_HWUNIT:
*result = dinfo->ocp_unit;
return (0);
case OCPBUS_IVAR_MACADDR:
unit = device_get_unit(child);
if (unit > bootinfo->bi_eth_addr_no - 1)
return (EINVAL);
eth = bootinfo_eth() + unit;
*result = (uintptr_t)eth;
return (0);
}
return (EINVAL);
}
static int
ocpbus_release_resource(device_t dev, device_t child, int type, int rid,
struct resource *res)
{
return (rman_release_resource(res));
}
static int
ocpbus_setup_intr(device_t dev, device_t child, struct resource *res, int flags,
driver_filter_t *filter, driver_intr_t *ihand, void *arg, void **cookiep)
{
int error;
if (res == NULL)
panic("ocpbus_setup_intr: NULL irq resource!");
*cookiep = 0;
if ((rman_get_flags(res) & RF_SHAREABLE) == 0)
flags |= INTR_EXCL;
/*
* We depend here on rman_activate_resource() being idempotent.
*/
error = rman_activate_resource(res);
if (error)
return (error);
error = powerpc_setup_intr(device_get_nameunit(child),
rman_get_start(res), filter, ihand, arg, flags, cookiep);
return (error);
}
static int
ocpbus_teardown_intr(device_t dev, device_t child, struct resource *res,
void *cookie)
{
return (powerpc_teardown_intr(cookie));
}
static int
ocpbus_config_intr(device_t dev, int irq, enum intr_trigger trig,
enum intr_polarity pol)
{
return (powerpc_config_intr(irq, trig, pol));
}

View File

@ -1,112 +0,0 @@
/*-
* Copyright 2006 by Juniper Networks. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef _MACHINE_OCP85XX_H_
#define _MACHINE_OCP85XX_H_
/*
* Configuration control and status registers
*/
#define OCP85XX_CCSRBAR (CCSRBAR_VA + 0x0)
#define OCP85XX_BPTR (CCSRBAR_VA + 0x20)
/*
* E500 Coherency Module registers
*/
#define OCP85XX_EEBPCR (CCSRBAR_VA + 0x1010)
/*
* Local access registers
*/
#define OCP85XX_LAWBAR(n) (CCSRBAR_VA + 0xc08 + 0x20 * (n))
#define OCP85XX_LAWSR(n) (CCSRBAR_VA + 0xc10 + 0x20 * (n))
#define OCP85XX_TGTIF_PCI0 0
#define OCP85XX_TGTIF_PCI1 1
#define OCP85XX_TGTIF_PCI2 2
#define OCP85XX_TGTIF_PCI3 3
#define OCP85XX_TGTIF_LBC 4
#define OCP85XX_TGTIF_RAM_INTL 11
#define OCP85XX_TGTIF_RIO 12
#define OCP85XX_TGTIF_RAM1 15
#define OCP85XX_TGTIF_RAM2 22
/*
* L2 cache registers
*/
#define OCP85XX_L2CTL (CCSRBAR_VA + 0x20000)
/*
* Power-On Reset configuration
*/
#define OCP85XX_PORDEVSR (CCSRBAR_VA + 0xe000c)
#define OCP85XX_PORDEVSR2 (CCSRBAR_VA + 0xe0014)
/*
* Status Registers.
*/
#define OCP85XX_RSTCR (CCSRBAR_VA + 0xe00b0)
/*
* OCP Bus Definitions
*/
#define OCP85XX_I2C0_OFF 0x03000
#define OCP85XX_I2C1_OFF 0x03100
#define OCP85XX_I2C_SIZE 0x16
#define OCP85XX_UART0_OFF 0x04500
#define OCP85XX_UART1_OFF 0x04600
#define OCP85XX_UART_SIZE 0x10
#define OCP85XX_LBC_OFF 0x05000
#define OCP85XX_LBC_SIZE 0x1000
#define OCP85XX_PCI0_OFF 0x08000
#define OCP85XX_PCI1_OFF 0x09000
#define OCP85XX_PCI2_OFF 0x0A000
#define OCP85XX_PCI3_OFF 0x0B000
#define OCP85XX_PCI_SIZE 0x1000
#define OCP85XX_TSEC0_OFF 0x24000
#define OCP85XX_TSEC1_OFF 0x25000
#define OCP85XX_TSEC2_OFF 0x26000
#define OCP85XX_TSEC3_OFF 0x27000
#define OCP85XX_TSEC_SIZE 0x1000
#define OCP85XX_OPENPIC_OFF 0x40000
#define OCP85XX_OPENPIC_SIZE 0x200B4
#define OCP85XX_QUICC_OFF 0x80000
#define OCP85XX_QUICC_SIZE 0x20000
#define OCP85XX_SEC_OFF 0x30000
#define OCP85XX_SEC_SIZE 0x10000
/*
* PIC definitions
*/
#define ISA_IRQ(n) (INTR_VEC(ATPIC_ID, n))
#define PIC_IRQ_EXT(n) (INTR_VEC(OPIC_ID, (n)))
#define PIC_IRQ_INT(n) (INTR_VEC(OPIC_ID, (16 + (n))))
#endif /* _MACHINE_OCP85XX_H */

View File

@ -0,0 +1,93 @@
/*-
* Copyright (c) 2009-2010 The FreeBSD Foundation
* All rights reserved.
*
* This software was developed by Semihalf under sponsorship from
* the FreeBSD Foundation.
*
* 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$");
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/bus.h>
#include <machine/bus.h>
#include <machine/intr_machdep.h>
#include <machine/openpicvar.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
#include "pic_if.h"
static int openpic_fdt_probe(device_t);
static uint32_t openpic_fdt_id(device_t);
static device_method_t openpic_fdt_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, openpic_fdt_probe),
DEVMETHOD(device_attach, openpic_attach),
/* PIC interface */
DEVMETHOD(pic_bind, openpic_bind),
DEVMETHOD(pic_config, openpic_config),
DEVMETHOD(pic_dispatch, openpic_dispatch),
DEVMETHOD(pic_enable, openpic_enable),
DEVMETHOD(pic_eoi, openpic_eoi),
DEVMETHOD(pic_ipi, openpic_ipi),
DEVMETHOD(pic_mask, openpic_mask),
DEVMETHOD(pic_unmask, openpic_unmask),
DEVMETHOD(pic_id, openpic_fdt_id),
{ 0, 0 },
};
static driver_t openpic_fdt_driver = {
"openpic",
openpic_fdt_methods,
sizeof(struct openpic_softc)
};
DRIVER_MODULE(openpic, simplebus, openpic_fdt_driver, openpic_devclass, 0, 0);
static int
openpic_fdt_probe(device_t dev)
{
if (!ofw_bus_is_compatible(dev, "chrp,open-pic"))
return (ENXIO);
device_set_desc(dev, OPENPIC_DEVSTR);
return (BUS_PROBE_DEFAULT);
}
static uint32_t
openpic_fdt_id(device_t dev)
{
return (ofw_bus_get_node(dev));
}

View File

@ -1,105 +0,0 @@
/*-
* Copyright 2006 by Juniper Networks. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/bus.h>
#include <sys/rman.h>
#include <sys/bus.h>
#include <machine/bus.h>
#include <machine/intr_machdep.h>
#include <machine/openpicvar.h>
#include <machine/ocpbus.h>
#include "pic_if.h"
/*
* OpenPIC attachment to ocpbus
*/
static int openpic_ocpbus_probe(device_t);
static uint32_t openpic_ocpbus_id(device_t);
static device_method_t openpic_ocpbus_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, openpic_ocpbus_probe),
DEVMETHOD(device_attach, openpic_attach),
/* PIC interface */
DEVMETHOD(pic_bind, openpic_bind),
DEVMETHOD(pic_config, openpic_config),
DEVMETHOD(pic_dispatch, openpic_dispatch),
DEVMETHOD(pic_enable, openpic_enable),
DEVMETHOD(pic_eoi, openpic_eoi),
DEVMETHOD(pic_ipi, openpic_ipi),
DEVMETHOD(pic_mask, openpic_mask),
DEVMETHOD(pic_unmask, openpic_unmask),
DEVMETHOD(pic_id, openpic_ocpbus_id),
{ 0, 0 },
};
static driver_t openpic_ocpbus_driver = {
"openpic",
openpic_ocpbus_methods,
sizeof(struct openpic_softc)
};
DRIVER_MODULE(openpic, ocpbus, openpic_ocpbus_driver, openpic_devclass, 0, 0);
static int
openpic_ocpbus_probe (device_t dev)
{
device_t parent;
uintptr_t devtype;
int error;
parent = device_get_parent(dev);
error = BUS_READ_IVAR(parent, dev, OCPBUS_IVAR_DEVTYPE, &devtype);
if (error)
return (error);
if (devtype != OCPBUS_DEVTYPE_PIC)
return (ENXIO);
device_set_desc(dev, OPENPIC_DEVSTR);
return (BUS_PROBE_DEFAULT);
}
static uint32_t
openpic_ocpbus_id (device_t dev)
{
return (OPIC_ID);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,850 +0,0 @@
/*-
* Copyright 2006-2007 by Juniper Networks.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/ktr.h>
#include <sys/sockio.h>
#include <sys/mbuf.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/socket.h>
#include <sys/queue.h>
#include <sys/bus.h>
#include <sys/rman.h>
#include <sys/endian.h>
#include <vm/vm.h>
#include <vm/pmap.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcib_private.h>
#include "pcib_if.h"
#include <machine/resource.h>
#include <machine/bus.h>
#include <machine/intr_machdep.h>
#include <machine/ocpbus.h>
#include <machine/spr.h>
#include <powerpc/mpc85xx/ocpbus.h>
#define REG_CFG_ADDR 0x0000
#define CONFIG_ACCESS_ENABLE 0x80000000
#define REG_CFG_DATA 0x0004
#define REG_INT_ACK 0x0008
#define REG_POTAR(n) (0x0c00 + 0x20 * (n))
#define REG_POTEAR(n) (0x0c04 + 0x20 * (n))
#define REG_POWBAR(n) (0x0c08 + 0x20 * (n))
#define REG_POWAR(n) (0x0c10 + 0x20 * (n))
#define REG_PITAR(n) (0x0e00 - 0x20 * (n))
#define REG_PIWBAR(n) (0x0e08 - 0x20 * (n))
#define REG_PIWBEAR(n) (0x0e0c - 0x20 * (n))
#define REG_PIWAR(n) (0x0e10 - 0x20 * (n))
#define PCIR_FSL_LTSSM 0x404
#define FSL_LTSSM_L0 0x16
#define DEVFN(b, s, f) ((b << 16) | (s << 8) | f)
struct pci_ocp_softc {
device_t sc_dev;
struct rman sc_iomem;
bus_addr_t sc_iomem_va; /* Virtual mapping. */
bus_addr_t sc_iomem_alloc; /* Next allocation. */
struct rman sc_ioport;
bus_addr_t sc_ioport_va; /* Virtual mapping. */
bus_addr_t sc_ioport_alloc; /* Next allocation. */
struct resource *sc_res;
bus_space_handle_t sc_bsh;
bus_space_tag_t sc_bst;
int sc_rid;
int sc_busnr;
uint8_t sc_pcie_cap;
/* Devices that need special attention. */
int sc_devfn_tundra;
int sc_devfn_via_ide;
};
static int pci_ocp_attach(device_t);
static int pci_ocp_probe(device_t);
static struct resource *pci_ocp_alloc_resource(device_t, device_t, int, int *,
u_long, u_long, u_long, u_int);
static int pci_ocp_read_ivar(device_t, device_t, int, uintptr_t *);
static int pci_ocp_release_resource(device_t, device_t, int, int,
struct resource *);
static int pci_ocp_write_ivar(device_t, device_t, int, uintptr_t);
static int pci_ocp_maxslots(device_t);
static uint32_t pci_ocp_read_config(device_t, u_int, u_int, u_int, u_int, int);
static void pci_ocp_write_config(device_t, u_int, u_int, u_int, u_int,
uint32_t, int);
/*
* Bus interface definitions.
*/
static device_method_t pci_ocp_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, pci_ocp_probe),
DEVMETHOD(device_attach, pci_ocp_attach),
/* Bus interface */
DEVMETHOD(bus_print_child, bus_generic_print_child),
DEVMETHOD(bus_read_ivar, pci_ocp_read_ivar),
DEVMETHOD(bus_write_ivar, pci_ocp_write_ivar),
DEVMETHOD(bus_alloc_resource, pci_ocp_alloc_resource),
DEVMETHOD(bus_release_resource, pci_ocp_release_resource),
DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
/* pcib interface */
DEVMETHOD(pcib_maxslots, pci_ocp_maxslots),
DEVMETHOD(pcib_read_config, pci_ocp_read_config),
DEVMETHOD(pcib_write_config, pci_ocp_write_config),
DEVMETHOD(pcib_route_interrupt, pcib_route_interrupt),
{ 0, 0 }
};
static driver_t pci_ocp_driver = {
"pcib",
pci_ocp_methods,
sizeof(struct pci_ocp_softc),
};
devclass_t pcib_devclass;
DRIVER_MODULE(pcib, ocpbus, pci_ocp_driver, pcib_devclass, 0, 0);
static uint32_t
pci_ocp_cfgread(struct pci_ocp_softc *sc, u_int bus, u_int slot, u_int func,
u_int reg, int bytes)
{
uint32_t addr, data;
if (bus == sc->sc_busnr)
bus = 0;
addr = CONFIG_ACCESS_ENABLE;
addr |= (bus & 0xff) << 16;
addr |= (slot & 0x1f) << 11;
addr |= (func & 0x7) << 8;
addr |= reg & 0xfc;
if (sc->sc_pcie_cap)
addr |= (reg & 0xf00) << 16;
bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_CFG_ADDR, addr);
switch (bytes) {
case 1:
data = bus_space_read_1(sc->sc_bst, sc->sc_bsh,
REG_CFG_DATA + (reg & 3));
break;
case 2:
data = le16toh(bus_space_read_2(sc->sc_bst, sc->sc_bsh,
REG_CFG_DATA + (reg & 2)));
break;
case 4:
data = le32toh(bus_space_read_4(sc->sc_bst, sc->sc_bsh,
REG_CFG_DATA));
break;
default:
data = ~0;
break;
}
return (data);
}
static void
pci_ocp_cfgwrite(struct pci_ocp_softc *sc, u_int bus, u_int slot, u_int func,
u_int reg, uint32_t data, int bytes)
{
uint32_t addr;
if (bus == sc->sc_busnr)
bus = 0;
addr = CONFIG_ACCESS_ENABLE;
addr |= (bus & 0xff) << 16;
addr |= (slot & 0x1f) << 11;
addr |= (func & 0x7) << 8;
addr |= reg & 0xfc;
if (sc->sc_pcie_cap)
addr |= (reg & 0xf00) << 16;
bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_CFG_ADDR, addr);
switch (bytes) {
case 1:
bus_space_write_1(sc->sc_bst, sc->sc_bsh,
REG_CFG_DATA + (reg & 3), data);
break;
case 2:
bus_space_write_2(sc->sc_bst, sc->sc_bsh,
REG_CFG_DATA + (reg & 2), htole16(data));
break;
case 4:
bus_space_write_4(sc->sc_bst, sc->sc_bsh,
REG_CFG_DATA, htole32(data));
break;
}
}
#if 0
static void
dump(struct pci_ocp_softc *sc)
{
unsigned int i;
#define RD(o) bus_space_read_4(sc->sc_bst, sc->sc_bsh, o)
for (i = 0; i < 5; i++) {
printf("POTAR%u =0x%08x\n", i, RD(REG_POTAR(i)));
printf("POTEAR%u =0x%08x\n", i, RD(REG_POTEAR(i)));
printf("POWBAR%u =0x%08x\n", i, RD(REG_POWBAR(i)));
printf("POWAR%u =0x%08x\n", i, RD(REG_POWAR(i)));
}
printf("\n");
for (i = 1; i < 4; i++) {
printf("PITAR%u =0x%08x\n", i, RD(REG_PITAR(i)));
printf("PIWBAR%u =0x%08x\n", i, RD(REG_PIWBAR(i)));
printf("PIWBEAR%u=0x%08x\n", i, RD(REG_PIWBEAR(i)));
printf("PIWAR%u =0x%08x\n", i, RD(REG_PIWAR(i)));
}
printf("\n");
#undef RD
for (i = 0; i < 0x48; i += 4) {
printf("cfg%02x=0x%08x\n", i, pci_ocp_cfgread(sc, 0, 0, 0,
i, 4));
}
}
#endif
static int
pci_ocp_maxslots(device_t dev)
{
struct pci_ocp_softc *sc = device_get_softc(dev);
return ((sc->sc_pcie_cap) ? 0 : 31);
}
static uint32_t
pci_ocp_read_config(device_t dev, u_int bus, u_int slot, u_int func,
u_int reg, int bytes)
{
struct pci_ocp_softc *sc = device_get_softc(dev);
u_int devfn;
if (bus == sc->sc_busnr && !sc->sc_pcie_cap && slot < 10)
return (~0);
devfn = DEVFN(bus, slot, func);
/*
* For the host controller itself, pretend to be a standard
* PCI bridge, rather than a PowerPC processor. That way the
* generic PCI code will enumerate all subordinate busses
* and devices as usual.
*/
if (sc->sc_pcie_cap && devfn == 0) {
if (reg == PCIR_CLASS && bytes == 1)
return (PCIC_BRIDGE);
if (reg == PCIR_SUBCLASS && bytes == 1)
return (PCIS_BRIDGE_PCI);
}
if (devfn == sc->sc_devfn_tundra)
return (~0);
if (devfn == sc->sc_devfn_via_ide && reg == PCIR_INTPIN)
return (1);
return (pci_ocp_cfgread(sc, bus, slot, func, reg, bytes));
}
static void
pci_ocp_write_config(device_t dev, u_int bus, u_int slot, u_int func,
u_int reg, uint32_t val, int bytes)
{
struct pci_ocp_softc *sc = device_get_softc(dev);
if (bus == sc->sc_busnr && !sc->sc_pcie_cap && slot < 10)
return;
pci_ocp_cfgwrite(sc, bus, slot, func, reg, val, bytes);
}
static int
pci_ocp_probe(device_t dev)
{
char buf[128];
struct pci_ocp_softc *sc;
const char *type;
device_t parent;
u_long start, size;
uintptr_t devtype;
uint32_t cfgreg;
uint8_t capptr;
int error;
parent = device_get_parent(dev);
error = BUS_READ_IVAR(parent, dev, OCPBUS_IVAR_DEVTYPE, &devtype);
if (error)
return (error);
if (devtype != OCPBUS_DEVTYPE_PCIB)
return (ENXIO);
sc = device_get_softc(dev);
sc->sc_dev = dev;
sc->sc_rid = 0;
sc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rid,
RF_ACTIVE);
if (sc->sc_res == NULL)
return (ENXIO);
sc->sc_bst = rman_get_bustag(sc->sc_res);
sc->sc_bsh = rman_get_bushandle(sc->sc_res);
sc->sc_busnr = 0;
error = ENOENT;
cfgreg = pci_ocp_cfgread(sc, 0, 0, 0, PCIR_VENDOR, 2);
if (cfgreg != 0x1057 && cfgreg != 0x1957)
goto out;
cfgreg = pci_ocp_cfgread(sc, 0, 0, 0, PCIR_CLASS, 1);
if (cfgreg != PCIC_PROCESSOR)
goto out;
cfgreg = pci_ocp_cfgread(sc, 0, 0, 0, PCIR_SUBCLASS, 1);
if (cfgreg != PCIS_PROCESSOR_POWERPC)
goto out;
cfgreg = pci_ocp_cfgread(sc, 0, 0, 0, PCIR_PROGIF, 1);
if (cfgreg != 0) /* RC mode = 0, EP mode = 1 */
goto out;
type = "PCI";
capptr = pci_ocp_cfgread(sc, 0, 0, 0, PCIR_CAP_PTR, 1);
while (capptr != 0) {
cfgreg = pci_ocp_cfgread(sc, 0, 0, 0, capptr, 2);
switch (cfgreg & 0xff) {
case PCIY_PCIX: /* PCI-X */
type = "PCI-X";
break;
case PCIY_EXPRESS: /* PCI Express */
type = "PCI Express";
sc->sc_pcie_cap = capptr;
break;
}
capptr = (cfgreg >> 8) & 0xff;
}
error = bus_get_resource(dev, SYS_RES_MEMORY, 1, &start, &size);
if (error || start == 0 || size == 0)
goto out;
snprintf(buf, sizeof(buf),
"Freescale on-chip %s host controller", type);
device_set_desc_copy(dev, buf);
error = BUS_PROBE_DEFAULT;
out:
bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rid, sc->sc_res);
return (error);
}
static void
pci_ocp_init_via(struct pci_ocp_softc *sc, uint16_t device, int bus,
int slot, int fn)
{
if (device == 0x0686) {
pci_ocp_write_config(sc->sc_dev, bus, slot, fn, 0x52, 0x34, 1);
pci_ocp_write_config(sc->sc_dev, bus, slot, fn, 0x77, 0x00, 1);
pci_ocp_write_config(sc->sc_dev, bus, slot, fn, 0x83, 0x98, 1);
pci_ocp_write_config(sc->sc_dev, bus, slot, fn, 0x85, 0x03, 1);
} else if (device == 0x0571) {
sc->sc_devfn_via_ide = DEVFN(bus, slot, fn);
pci_ocp_write_config(sc->sc_dev, bus, slot, fn, 0x40, 0x0b, 1);
}
}
static int
pci_ocp_init_bar(struct pci_ocp_softc *sc, int bus, int slot, int func,
int barno)
{
bus_addr_t *allocp;
uint32_t addr, mask, size;
int reg, width;
reg = PCIR_BAR(barno);
if (DEVFN(bus, slot, func) == sc->sc_devfn_via_ide) {
switch (barno) {
case 0: addr = 0x1f0; break;
case 1: addr = 0x3f4; break;
case 2: addr = 0x170; break;
case 3: addr = 0x374; break;
case 4: addr = 0xcc0; break;
default: return (1);
}
pci_ocp_write_config(sc->sc_dev, bus, slot, func, reg, addr, 4);
return (1);
}
pci_ocp_write_config(sc->sc_dev, bus, slot, func, reg, ~0, 4);
size = pci_ocp_read_config(sc->sc_dev, bus, slot, func, reg, 4);
if (size == 0)
return (1);
width = ((size & 7) == 4) ? 2 : 1;
if (size & 1) { /* I/O port */
allocp = &sc->sc_ioport_alloc;
size &= ~3;
if ((size & 0xffff0000) == 0)
size |= 0xffff0000;
} else { /* memory */
allocp = &sc->sc_iomem_alloc;
size &= ~15;
}
mask = ~size;
size = mask + 1;
/* Sanity check (must be a power of 2). */
if (size & mask)
return (width);
addr = (*allocp + mask) & ~mask;
*allocp = addr + size;
if (bootverbose)
printf("PCI %u:%u:%u:%u: reg %x: size=%08x: addr=%08x\n",
device_get_unit(sc->sc_dev), bus, slot, func, reg,
size, addr);
pci_ocp_write_config(sc->sc_dev, bus, slot, func, reg, addr, 4);
if (width == 2)
pci_ocp_write_config(sc->sc_dev, bus, slot, func, reg + 4,
0, 4);
return (width);
}
static u_int
pci_ocp_route_int(struct pci_ocp_softc *sc, u_int bus, u_int slot, u_int func,
u_int intpin)
{
u_int devfn, intline;
devfn = DEVFN(bus, slot, func);
if (devfn == sc->sc_devfn_via_ide)
intline = INTR_VEC(ATPIC_ID, 14);
else if (devfn == sc->sc_devfn_via_ide + 1)
intline = INTR_VEC(ATPIC_ID, 10);
else if (devfn == sc->sc_devfn_via_ide + 2)
intline = INTR_VEC(ATPIC_ID, 10);
else {
if (intpin != 0) {
intline = intpin - 1;
intline += (bus != sc->sc_busnr) ? slot : 0;
intline = PIC_IRQ_EXT(intline & 3);
} else
intline = 0xff;
}
if (bootverbose)
printf("PCI %u:%u:%u:%u: intpin %u: intline=%u\n",
device_get_unit(sc->sc_dev), bus, slot, func,
intpin, intline);
return (intline);
}
static int
pci_ocp_init(struct pci_ocp_softc *sc, int bus, int nslots)
{
int secbus, slot;
int func, maxfunc;
int bar, maxbar;
uint16_t vendor, device;
uint8_t command, hdrtype, class, subclass;
uint8_t intline, intpin;
secbus = bus;
for (slot = 0; slot < nslots; slot++) {
maxfunc = 0;
for (func = 0; func <= maxfunc; func++) {
hdrtype = pci_ocp_read_config(sc->sc_dev, bus, slot,
func, PCIR_HDRTYPE, 1);
if ((hdrtype & PCIM_HDRTYPE) > PCI_MAXHDRTYPE)
continue;
if (func == 0 && (hdrtype & PCIM_MFDEV))
maxfunc = PCI_FUNCMAX;
vendor = pci_ocp_read_config(sc->sc_dev, bus, slot,
func, PCIR_VENDOR, 2);
device = pci_ocp_read_config(sc->sc_dev, bus, slot,
func, PCIR_DEVICE, 2);
if (vendor == 0x1957 && device == 0x3fff) {
sc->sc_devfn_tundra = DEVFN(bus, slot, func);
continue;
}
command = pci_ocp_read_config(sc->sc_dev, bus, slot,
func, PCIR_COMMAND, 1);
command &= ~(PCIM_CMD_MEMEN | PCIM_CMD_PORTEN);
pci_ocp_write_config(sc->sc_dev, bus, slot, func,
PCIR_COMMAND, command, 1);
if (vendor == 0x1106)
pci_ocp_init_via(sc, device, bus, slot, func);
/* Program the base address registers. */
maxbar = (hdrtype & PCIM_HDRTYPE) ? 1 : 6;
bar = 0;
while (bar < maxbar)
bar += pci_ocp_init_bar(sc, bus, slot, func,
bar);
/* Perform interrupt routing. */
intpin = pci_ocp_read_config(sc->sc_dev, bus, slot,
func, PCIR_INTPIN, 1);
intline = pci_ocp_route_int(sc, bus, slot, func,
intpin);
pci_ocp_write_config(sc->sc_dev, bus, slot, func,
PCIR_INTLINE, intline, 1);
command |= PCIM_CMD_MEMEN | PCIM_CMD_PORTEN;
pci_ocp_write_config(sc->sc_dev, bus, slot, func,
PCIR_COMMAND, command, 1);
/*
* Handle PCI-PCI bridges
*/
class = pci_ocp_read_config(sc->sc_dev, bus, slot,
func, PCIR_CLASS, 1);
if (class != PCIC_BRIDGE)
continue;
subclass = pci_ocp_read_config(sc->sc_dev, bus, slot,
func, PCIR_SUBCLASS, 1);
if (subclass != PCIS_BRIDGE_PCI)
continue;
secbus++;
/* Program I/O decoder. */
pci_ocp_write_config(sc->sc_dev, bus, slot, func,
PCIR_IOBASEL_1, sc->sc_ioport.rm_start >> 8, 1);
pci_ocp_write_config(sc->sc_dev, bus, slot, func,
PCIR_IOLIMITL_1, sc->sc_ioport.rm_end >> 8, 1);
pci_ocp_write_config(sc->sc_dev, bus, slot, func,
PCIR_IOBASEH_1, sc->sc_ioport.rm_start >> 16, 2);
pci_ocp_write_config(sc->sc_dev, bus, slot, func,
PCIR_IOLIMITH_1, sc->sc_ioport.rm_end >> 16, 2);
/* Program (non-prefetchable) memory decoder. */
pci_ocp_write_config(sc->sc_dev, bus, slot, func,
PCIR_MEMBASE_1, sc->sc_iomem.rm_start >> 16, 2);
pci_ocp_write_config(sc->sc_dev, bus, slot, func,
PCIR_MEMLIMIT_1, sc->sc_iomem.rm_end >> 16, 2);
/* Program prefetchable memory decoder. */
pci_ocp_write_config(sc->sc_dev, bus, slot, func,
PCIR_PMBASEL_1, 0x0010, 2);
pci_ocp_write_config(sc->sc_dev, bus, slot, func,
PCIR_PMLIMITL_1, 0x000f, 2);
pci_ocp_write_config(sc->sc_dev, bus, slot, func,
PCIR_PMBASEH_1, 0x00000000, 4);
pci_ocp_write_config(sc->sc_dev, bus, slot, func,
PCIR_PMLIMITH_1, 0x00000000, 4);
pci_ocp_write_config(sc->sc_dev, bus, slot, func,
PCIR_PRIBUS_1, bus, 1);
pci_ocp_write_config(sc->sc_dev, bus, slot, func,
PCIR_SECBUS_1, secbus, 1);
pci_ocp_write_config(sc->sc_dev, bus, slot, func,
PCIR_SUBBUS_1, 0xff, 1);
secbus = pci_ocp_init(sc, secbus,
(subclass == PCIS_BRIDGE_PCI) ? 32 : 1);
pci_ocp_write_config(sc->sc_dev, bus, slot, func,
PCIR_SUBBUS_1, secbus, 1);
}
}
return (secbus);
}
static void
pci_ocp_inbound(struct pci_ocp_softc *sc, int wnd, int tgt, u_long start,
u_long size, u_long pci_start)
{
uint32_t attr, bar, tar;
KASSERT(wnd > 0, ("%s: inbound window 0 is invalid", __func__));
switch (tgt) {
case OCP85XX_TGTIF_RAM1:
attr = 0xa0f55000 | (ffsl(size) - 2);
break;
default:
attr = 0;
break;
}
tar = start >> 12;
bar = pci_start >> 12;
bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_PITAR(wnd), tar);
bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_PIWBEAR(wnd), 0);
bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_PIWBAR(wnd), bar);
bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_PIWAR(wnd), attr);
}
static void
pci_ocp_outbound(struct pci_ocp_softc *sc, int wnd, int res, u_long start,
u_long size, u_long pci_start)
{
uint32_t attr, bar, tar;
switch (res) {
case SYS_RES_MEMORY:
attr = 0x80044000 | (ffsl(size) - 2);
break;
case SYS_RES_IOPORT:
attr = 0x80088000 | (ffsl(size) - 2);
break;
default:
attr = 0x0004401f;
break;
}
bar = start >> 12;
tar = pci_start >> 12;
bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_POTAR(wnd), tar);
bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_POTEAR(wnd), 0);
bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_POWBAR(wnd), bar);
bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_POWAR(wnd), attr);
}
static int
pci_ocp_iorange(struct pci_ocp_softc *sc, int type, int wnd)
{
struct rman *rm;
u_long start, end, size, alloc;
bus_addr_t pci_start, pci_end;
bus_addr_t *vap, *allocp;
int error;
error = bus_get_resource(sc->sc_dev, type, 1, &start, &size);
if (error)
return (error);
end = start + size - 1;
switch (type) {
case SYS_RES_IOPORT:
rm = &sc->sc_ioport;
pci_start = 0x0000;
pci_end = 0xffff;
alloc = 0x1000;
vap = &sc->sc_ioport_va;
allocp = &sc->sc_ioport_alloc;
break;
case SYS_RES_MEMORY:
rm = &sc->sc_iomem;
pci_start = start;
pci_end = end;
alloc = 0;
vap = &sc->sc_iomem_va;
allocp = &sc->sc_iomem_alloc;
break;
default:
return (EINVAL);
}
rm->rm_type = RMAN_ARRAY;
rm->rm_start = pci_start;
rm->rm_end = pci_end;
error = rman_init(rm);
if (error)
return (error);
error = rman_manage_region(rm, pci_start, pci_end);
if (error) {
rman_fini(rm);
return (error);
}
*allocp = pci_start + alloc;
*vap = (uintptr_t)pmap_mapdev(start, size);
if (wnd != -1)
pci_ocp_outbound(sc, wnd, type, start, size, pci_start);
return (0);
}
static int
pci_ocp_attach(device_t dev)
{
struct pci_ocp_softc *sc;
uint32_t cfgreg;
int error, nslots;
sc = device_get_softc(dev);
sc->sc_dev = dev;
sc->sc_rid = 0;
sc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rid,
RF_ACTIVE);
if (sc->sc_res == NULL) {
device_printf(dev, "could not map I/O memory\n");
return (ENXIO);
}
sc->sc_bst = rman_get_bustag(sc->sc_res);
sc->sc_bsh = rman_get_bushandle(sc->sc_res);
cfgreg = pci_ocp_cfgread(sc, 0, 0, 0, PCIR_COMMAND, 2);
cfgreg |= PCIM_CMD_SERRESPEN | PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN |
PCIM_CMD_PORTEN;
pci_ocp_cfgwrite(sc, 0, 0, 0, PCIR_COMMAND, cfgreg, 2);
pci_ocp_outbound(sc, 0, -1, 0, 0, 0);
error = pci_ocp_iorange(sc, SYS_RES_MEMORY, 1);
error = pci_ocp_iorange(sc, SYS_RES_IOPORT, 2);
pci_ocp_outbound(sc, 3, -1, 0, 0, 0);
pci_ocp_outbound(sc, 4, -1, 0, 0, 0);
pci_ocp_inbound(sc, 1, -1, 0, 0, 0);
pci_ocp_inbound(sc, 2, -1, 0, 0, 0);
pci_ocp_inbound(sc, 3, OCP85XX_TGTIF_RAM1, 0, 2U*1024U*1024U*1024U, 0);
sc->sc_devfn_tundra = -1;
sc->sc_devfn_via_ide = -1;
/*
* PCI Express host controllers require a link. We don't
* fail the attach if there's no link, but we also don't
* create a child pci(4) device.
*/
if (sc->sc_pcie_cap) {
cfgreg = pci_ocp_cfgread(sc, 0, 0, 0, PCIR_FSL_LTSSM, 4);
if (cfgreg < FSL_LTSSM_L0)
return (0);
}
nslots = (sc->sc_pcie_cap) ? 1 : 32;
pci_ocp_init(sc, sc->sc_busnr, nslots);
device_add_child(dev, "pci", -1);
return (bus_generic_attach(dev));
}
static struct resource *
pci_ocp_alloc_resource(device_t dev, device_t child, int type, int *rid,
u_long start, u_long end, u_long count, u_int flags)
{
struct pci_ocp_softc *sc = device_get_softc(dev);
struct rman *rm;
struct resource *res;
bus_addr_t va;
switch (type) {
case SYS_RES_IOPORT:
rm = &sc->sc_ioport;
va = sc->sc_ioport_va;
break;
case SYS_RES_MEMORY:
rm = &sc->sc_iomem;
va = sc->sc_iomem_va;
break;
case SYS_RES_IRQ:
if (INTR_IGN(start) == powerpc_ign_lookup(ATPIC_ID)) {
device_printf(dev, "%s requested ISA interrupt %lu\n",
device_get_nameunit(child), start);
}
flags |= RF_SHAREABLE;
return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
type, rid, start, end, count, flags));
default:
return (NULL);
}
res = rman_reserve_resource(rm, start, end, count, flags, child);
if (res == NULL)
return (NULL);
rman_set_bustag(res, &bs_le_tag);
rman_set_bushandle(res, va + rman_get_start(res) - rm->rm_start);
return (res);
}
static int
pci_ocp_release_resource(device_t dev, device_t child, int type, int rid,
struct resource *res)
{
return (rman_release_resource(res));
}
static int
pci_ocp_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
{
struct pci_ocp_softc *sc = device_get_softc(dev);
switch (which) {
case PCIB_IVAR_BUS:
*result = sc->sc_busnr;
return (0);
case PCIB_IVAR_DOMAIN:
*result = device_get_unit(dev);
return (0);
}
return (ENOENT);
}
static int
pci_ocp_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
{
struct pci_ocp_softc *sc = device_get_softc(dev);
switch (which) {
case PCIB_IVAR_BUS:
sc->sc_busnr = value;
return (0);
}
return (ENOENT);
}

View File

@ -60,8 +60,6 @@
* $FreeBSD$
*/
#include "opt_platform.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>