mirror of
https://git.rtems.org/rtems-libbsd/
synced 2025-05-14 01:39:57 +08:00
mpc85xx: Import from FreeBSD
This commit is contained in:
parent
3c9c9f19ba
commit
1e81e38a30
677
freebsd/sys/dev/ofw/ofwpci.c
Normal file
677
freebsd/sys/dev/ofw/ofwpci.c
Normal file
@ -0,0 +1,677 @@
|
||||
#include <machine/rtems-bsd-kernel-space.h>
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2011 Nathan Whitehorn
|
||||
* 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 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/systm.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/rman.h>
|
||||
|
||||
#include <dev/ofw/openfirm.h>
|
||||
#include <dev/ofw/ofw_pci.h>
|
||||
#include <dev/ofw/ofw_bus.h>
|
||||
#include <dev/ofw/ofw_bus_subr.h>
|
||||
#include <dev/ofw/ofwpci.h>
|
||||
|
||||
#include <dev/pci/pcivar.h>
|
||||
#include <dev/pci/pcireg.h>
|
||||
#include <dev/pci/pcib_private.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
#include <machine/md_var.h>
|
||||
#include <machine/resource.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/pmap.h>
|
||||
|
||||
#include <rtems/bsd/local/pcib_if.h>
|
||||
|
||||
/*
|
||||
* If it is necessary to set another value of this for
|
||||
* some platforms it should be set at fdt.h file
|
||||
*/
|
||||
#ifndef PCI_MAP_INTR
|
||||
#define PCI_MAP_INTR 4
|
||||
#endif
|
||||
|
||||
#define PCI_INTR_PINS 4
|
||||
|
||||
/*
|
||||
* bus interface.
|
||||
*/
|
||||
static struct resource * ofw_pci_alloc_resource(device_t, device_t,
|
||||
int, int *, rman_res_t, rman_res_t, rman_res_t, u_int);
|
||||
static int ofw_pci_release_resource(device_t, device_t, int, int,
|
||||
struct resource *);
|
||||
static int ofw_pci_activate_resource(device_t, device_t, int, int,
|
||||
struct resource *);
|
||||
static int ofw_pci_deactivate_resource(device_t, device_t, int, int,
|
||||
struct resource *);
|
||||
static int ofw_pci_adjust_resource(device_t, device_t, int,
|
||||
struct resource *, rman_res_t, rman_res_t);
|
||||
|
||||
#ifdef __powerpc__
|
||||
static bus_space_tag_t ofw_pci_bus_get_bus_tag(device_t, device_t);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* pcib interface
|
||||
*/
|
||||
static int ofw_pci_maxslots(device_t);
|
||||
|
||||
/*
|
||||
* ofw_bus interface
|
||||
*/
|
||||
static phandle_t ofw_pci_get_node(device_t, device_t);
|
||||
|
||||
/*
|
||||
* local methods
|
||||
*/
|
||||
static int ofw_pci_fill_ranges(phandle_t, struct ofw_pci_range *);
|
||||
static struct rman *ofw_pci_get_rman(struct ofw_pci_softc *, int, u_int);
|
||||
|
||||
/*
|
||||
* Driver methods.
|
||||
*/
|
||||
static device_method_t ofw_pci_methods[] = {
|
||||
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_attach, ofw_pci_attach),
|
||||
|
||||
/* Bus interface */
|
||||
DEVMETHOD(bus_print_child, bus_generic_print_child),
|
||||
DEVMETHOD(bus_read_ivar, ofw_pci_read_ivar),
|
||||
DEVMETHOD(bus_write_ivar, ofw_pci_write_ivar),
|
||||
DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
|
||||
DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
|
||||
DEVMETHOD(bus_alloc_resource, ofw_pci_alloc_resource),
|
||||
DEVMETHOD(bus_release_resource, ofw_pci_release_resource),
|
||||
DEVMETHOD(bus_activate_resource, ofw_pci_activate_resource),
|
||||
DEVMETHOD(bus_deactivate_resource, ofw_pci_deactivate_resource),
|
||||
DEVMETHOD(bus_adjust_resource, ofw_pci_adjust_resource),
|
||||
#ifdef __powerpc__
|
||||
DEVMETHOD(bus_get_bus_tag, ofw_pci_bus_get_bus_tag),
|
||||
#endif
|
||||
|
||||
/* pcib interface */
|
||||
DEVMETHOD(pcib_maxslots, ofw_pci_maxslots),
|
||||
DEVMETHOD(pcib_route_interrupt, ofw_pci_route_interrupt),
|
||||
DEVMETHOD(pcib_request_feature, pcib_request_feature_allow),
|
||||
|
||||
/* ofw_bus interface */
|
||||
DEVMETHOD(ofw_bus_get_node, ofw_pci_get_node),
|
||||
|
||||
DEVMETHOD_END
|
||||
};
|
||||
|
||||
DEFINE_CLASS_0(ofw_pci, ofw_pci_driver, ofw_pci_methods, 0);
|
||||
|
||||
int
|
||||
ofw_pci_init(device_t dev)
|
||||
{
|
||||
struct ofw_pci_softc *sc;
|
||||
phandle_t node;
|
||||
u_int32_t busrange[2];
|
||||
struct ofw_pci_range *rp;
|
||||
int i, error;
|
||||
struct ofw_pci_cell_info *cell_info;
|
||||
|
||||
node = ofw_bus_get_node(dev);
|
||||
sc = device_get_softc(dev);
|
||||
sc->sc_initialized = 1;
|
||||
sc->sc_range = NULL;
|
||||
sc->sc_pci_domain = device_get_unit(dev);
|
||||
|
||||
cell_info = (struct ofw_pci_cell_info *)malloc(sizeof(*cell_info),
|
||||
M_DEVBUF, M_WAITOK | M_ZERO);
|
||||
|
||||
sc->sc_cell_info = cell_info;
|
||||
|
||||
if (OF_getencprop(node, "bus-range", busrange, sizeof(busrange)) != 8)
|
||||
busrange[0] = 0;
|
||||
|
||||
sc->sc_dev = dev;
|
||||
sc->sc_node = node;
|
||||
sc->sc_bus = busrange[0];
|
||||
|
||||
if (sc->sc_quirks & OFW_PCI_QUIRK_RANGES_ON_CHILDREN) {
|
||||
phandle_t c;
|
||||
int n, i;
|
||||
|
||||
sc->sc_nrange = 0;
|
||||
for (c = OF_child(node); c != 0; c = OF_peer(c)) {
|
||||
n = ofw_pci_nranges(c, cell_info);
|
||||
if (n > 0)
|
||||
sc->sc_nrange += n;
|
||||
}
|
||||
if (sc->sc_nrange == 0) {
|
||||
error = ENXIO;
|
||||
goto out;
|
||||
}
|
||||
sc->sc_range = malloc(sc->sc_nrange * sizeof(sc->sc_range[0]),
|
||||
M_DEVBUF, M_WAITOK);
|
||||
i = 0;
|
||||
for (c = OF_child(node); c != 0; c = OF_peer(c)) {
|
||||
n = ofw_pci_fill_ranges(c, &sc->sc_range[i]);
|
||||
if (n > 0)
|
||||
i += n;
|
||||
}
|
||||
KASSERT(i == sc->sc_nrange, ("range count mismatch"));
|
||||
} else {
|
||||
sc->sc_nrange = ofw_pci_nranges(node, cell_info);
|
||||
if (sc->sc_nrange <= 0) {
|
||||
device_printf(dev, "could not getranges\n");
|
||||
error = ENXIO;
|
||||
goto out;
|
||||
}
|
||||
sc->sc_range = malloc(sc->sc_nrange * sizeof(sc->sc_range[0]),
|
||||
M_DEVBUF, M_WAITOK);
|
||||
ofw_pci_fill_ranges(node, sc->sc_range);
|
||||
}
|
||||
|
||||
sc->sc_io_rman.rm_type = RMAN_ARRAY;
|
||||
sc->sc_io_rman.rm_descr = "PCI I/O Ports";
|
||||
error = rman_init(&sc->sc_io_rman);
|
||||
if (error != 0) {
|
||||
device_printf(dev, "rman_init() failed. error = %d\n", error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
sc->sc_mem_rman.rm_type = RMAN_ARRAY;
|
||||
sc->sc_mem_rman.rm_descr = "PCI Non Prefetchable Memory";
|
||||
error = rman_init(&sc->sc_mem_rman);
|
||||
if (error != 0) {
|
||||
device_printf(dev, "rman_init() failed. error = %d\n", error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
sc->sc_pmem_rman.rm_type = RMAN_ARRAY;
|
||||
sc->sc_pmem_rman.rm_descr = "PCI Prefetchable Memory";
|
||||
error = rman_init(&sc->sc_pmem_rman);
|
||||
if (error != 0) {
|
||||
device_printf(dev, "rman_init() failed. error = %d\n", error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < sc->sc_nrange; i++) {
|
||||
error = 0;
|
||||
rp = sc->sc_range + i;
|
||||
|
||||
if (sc->sc_range_mask & ((uint64_t)1 << i))
|
||||
continue;
|
||||
switch (rp->pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) {
|
||||
case OFW_PCI_PHYS_HI_SPACE_CONFIG:
|
||||
break;
|
||||
case OFW_PCI_PHYS_HI_SPACE_IO:
|
||||
error = rman_manage_region(&sc->sc_io_rman, rp->pci,
|
||||
rp->pci + rp->size - 1);
|
||||
break;
|
||||
case OFW_PCI_PHYS_HI_SPACE_MEM32:
|
||||
case OFW_PCI_PHYS_HI_SPACE_MEM64:
|
||||
if (rp->pci_hi & OFW_PCI_PHYS_HI_PREFETCHABLE) {
|
||||
sc->sc_have_pmem = 1;
|
||||
error = rman_manage_region(&sc->sc_pmem_rman,
|
||||
rp->pci, rp->pci + rp->size - 1);
|
||||
} else {
|
||||
error = rman_manage_region(&sc->sc_mem_rman,
|
||||
rp->pci, rp->pci + rp->size - 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (error != 0) {
|
||||
device_printf(dev,
|
||||
"rman_manage_region(%x, %#jx, %#jx) failed. "
|
||||
"error = %d\n", rp->pci_hi &
|
||||
OFW_PCI_PHYS_HI_SPACEMASK, rp->pci,
|
||||
rp->pci + rp->size - 1, error);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
ofw_bus_setup_iinfo(node, &sc->sc_pci_iinfo, sizeof(cell_t));
|
||||
return (0);
|
||||
|
||||
out:
|
||||
free(cell_info, M_DEVBUF);
|
||||
free(sc->sc_range, M_DEVBUF);
|
||||
rman_fini(&sc->sc_io_rman);
|
||||
rman_fini(&sc->sc_mem_rman);
|
||||
rman_fini(&sc->sc_pmem_rman);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
ofw_pci_attach(device_t dev)
|
||||
{
|
||||
struct ofw_pci_softc *sc;
|
||||
int error;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
if (!sc->sc_initialized) {
|
||||
error = ofw_pci_init(dev);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
}
|
||||
|
||||
device_add_child(dev, "pci", -1);
|
||||
return (bus_generic_attach(dev));
|
||||
}
|
||||
|
||||
static int
|
||||
ofw_pci_maxslots(device_t dev)
|
||||
{
|
||||
|
||||
return (PCI_SLOTMAX);
|
||||
}
|
||||
|
||||
int
|
||||
ofw_pci_route_interrupt(device_t bus, device_t dev, int pin)
|
||||
{
|
||||
struct ofw_pci_softc *sc;
|
||||
struct ofw_pci_register reg;
|
||||
uint32_t pintr, mintr[PCI_MAP_INTR];
|
||||
int intrcells;
|
||||
phandle_t iparent;
|
||||
|
||||
sc = device_get_softc(bus);
|
||||
pintr = pin;
|
||||
|
||||
/* Fabricate imap information in case this isn't an OFW device */
|
||||
bzero(®, sizeof(reg));
|
||||
reg.phys_hi = (pci_get_bus(dev) << OFW_PCI_PHYS_HI_BUSSHIFT) |
|
||||
(pci_get_slot(dev) << OFW_PCI_PHYS_HI_DEVICESHIFT) |
|
||||
(pci_get_function(dev) << OFW_PCI_PHYS_HI_FUNCTIONSHIFT);
|
||||
|
||||
intrcells = ofw_bus_lookup_imap(ofw_bus_get_node(dev),
|
||||
&sc->sc_pci_iinfo, ®, sizeof(reg), &pintr, sizeof(pintr),
|
||||
mintr, sizeof(mintr), &iparent);
|
||||
if (intrcells != 0) {
|
||||
pintr = ofw_bus_map_intr(dev, iparent, intrcells, mintr);
|
||||
return (pintr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Maybe it's a real interrupt, not an intpin
|
||||
*/
|
||||
if (pin > PCI_INTR_PINS)
|
||||
return (pin);
|
||||
|
||||
device_printf(bus, "could not route pin %d for device %d.%d\n",
|
||||
pin, pci_get_slot(dev), pci_get_function(dev));
|
||||
return (PCI_INVALID_IRQ);
|
||||
}
|
||||
|
||||
int
|
||||
ofw_pci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
|
||||
{
|
||||
struct ofw_pci_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
switch (which) {
|
||||
case PCIB_IVAR_DOMAIN:
|
||||
*result = sc->sc_pci_domain;
|
||||
return (0);
|
||||
case PCIB_IVAR_BUS:
|
||||
*result = sc->sc_bus;
|
||||
return (0);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return (ENOENT);
|
||||
}
|
||||
|
||||
int
|
||||
ofw_pci_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
|
||||
{
|
||||
struct ofw_pci_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
switch (which) {
|
||||
case PCIB_IVAR_BUS:
|
||||
sc->sc_bus = value;
|
||||
return (0);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return (ENOENT);
|
||||
}
|
||||
|
||||
int
|
||||
ofw_pci_nranges(phandle_t node, struct ofw_pci_cell_info *info)
|
||||
{
|
||||
ssize_t nbase_ranges;
|
||||
|
||||
if (info == NULL)
|
||||
return (-1);
|
||||
|
||||
info->host_address_cells = 1;
|
||||
info->size_cells = 2;
|
||||
info->pci_address_cell = 3;
|
||||
|
||||
OF_getencprop(OF_parent(node), "#address-cells",
|
||||
&(info->host_address_cells), sizeof(info->host_address_cells));
|
||||
OF_getencprop(node, "#address-cells",
|
||||
&(info->pci_address_cell), sizeof(info->pci_address_cell));
|
||||
OF_getencprop(node, "#size-cells", &(info->size_cells),
|
||||
sizeof(info->size_cells));
|
||||
|
||||
nbase_ranges = OF_getproplen(node, "ranges");
|
||||
if (nbase_ranges <= 0)
|
||||
return (-1);
|
||||
|
||||
return (nbase_ranges / sizeof(cell_t) /
|
||||
(info->pci_address_cell + info->host_address_cells +
|
||||
info->size_cells));
|
||||
}
|
||||
|
||||
static struct resource *
|
||||
ofw_pci_alloc_resource(device_t bus, device_t child, int type, int *rid,
|
||||
rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
|
||||
{
|
||||
struct ofw_pci_softc *sc;
|
||||
struct resource *rv;
|
||||
struct rman *rm;
|
||||
int needactivate;
|
||||
|
||||
|
||||
needactivate = flags & RF_ACTIVE;
|
||||
flags &= ~RF_ACTIVE;
|
||||
|
||||
sc = device_get_softc(bus);
|
||||
|
||||
#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
|
||||
if (type == PCI_RES_BUS) {
|
||||
return (pci_domain_alloc_bus(sc->sc_pci_domain, child, rid,
|
||||
start, end, count, flags | needactivate));
|
||||
}
|
||||
#endif
|
||||
|
||||
rm = ofw_pci_get_rman(sc, type, flags);
|
||||
if (rm == NULL) {
|
||||
return (bus_generic_alloc_resource(bus, child, type, rid,
|
||||
start, end, count, flags | needactivate));
|
||||
}
|
||||
|
||||
rv = rman_reserve_resource(rm, start, end, count, flags, child);
|
||||
if (rv == NULL) {
|
||||
device_printf(bus, "failed to reserve resource for %s\n",
|
||||
device_get_nameunit(child));
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
rman_set_rid(rv, *rid);
|
||||
|
||||
if (needactivate) {
|
||||
if (bus_activate_resource(child, type, *rid, rv) != 0) {
|
||||
device_printf(bus,
|
||||
"failed to activate resource for %s\n",
|
||||
device_get_nameunit(child));
|
||||
rman_release_resource(rv);
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return (rv);
|
||||
}
|
||||
|
||||
static int
|
||||
ofw_pci_release_resource(device_t bus, device_t child, int type, int rid,
|
||||
struct resource *res)
|
||||
{
|
||||
struct ofw_pci_softc *sc;
|
||||
struct rman *rm;
|
||||
int error;
|
||||
|
||||
sc = device_get_softc(bus);
|
||||
|
||||
#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
|
||||
if (type == PCI_RES_BUS)
|
||||
return (pci_domain_release_bus(sc->sc_pci_domain, child, rid,
|
||||
res));
|
||||
#endif
|
||||
|
||||
rm = ofw_pci_get_rman(sc, type, rman_get_flags(res));
|
||||
if (rm == NULL) {
|
||||
return (bus_generic_release_resource(bus, child, type, rid,
|
||||
res));
|
||||
}
|
||||
KASSERT(rman_is_region_manager(res, rm), ("rman mismatch"));
|
||||
|
||||
if (rman_get_flags(res) & RF_ACTIVE) {
|
||||
error = bus_deactivate_resource(child, type, rid, res);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
}
|
||||
return (rman_release_resource(res));
|
||||
}
|
||||
|
||||
static int
|
||||
ofw_pci_activate_resource(device_t bus, device_t child, int type, int rid,
|
||||
struct resource *res)
|
||||
{
|
||||
struct ofw_pci_softc *sc;
|
||||
bus_space_handle_t handle;
|
||||
bus_space_tag_t tag;
|
||||
struct ofw_pci_range *rp;
|
||||
vm_paddr_t start;
|
||||
int space;
|
||||
int rv;
|
||||
|
||||
sc = device_get_softc(bus);
|
||||
|
||||
if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY) {
|
||||
return (bus_generic_activate_resource(bus, child, type, rid,
|
||||
res));
|
||||
}
|
||||
|
||||
start = (vm_paddr_t)rman_get_start(res);
|
||||
|
||||
/*
|
||||
* Map this through the ranges list
|
||||
*/
|
||||
for (rp = sc->sc_range; rp < sc->sc_range + sc->sc_nrange &&
|
||||
rp->pci_hi != 0; rp++) {
|
||||
if (start < rp->pci || start >= rp->pci + rp->size)
|
||||
continue;
|
||||
|
||||
switch (rp->pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) {
|
||||
case OFW_PCI_PHYS_HI_SPACE_IO:
|
||||
space = SYS_RES_IOPORT;
|
||||
break;
|
||||
case OFW_PCI_PHYS_HI_SPACE_MEM32:
|
||||
case OFW_PCI_PHYS_HI_SPACE_MEM64:
|
||||
space = SYS_RES_MEMORY;
|
||||
break;
|
||||
default:
|
||||
space = -1;
|
||||
}
|
||||
|
||||
if (type == space) {
|
||||
start += (rp->host - rp->pci);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (bootverbose)
|
||||
printf("ofw_pci mapdev: start %jx, len %jd\n",
|
||||
(rman_res_t)start, rman_get_size(res));
|
||||
|
||||
tag = BUS_GET_BUS_TAG(child, child);
|
||||
if (tag == NULL)
|
||||
return (ENOMEM);
|
||||
|
||||
rman_set_bustag(res, tag);
|
||||
rv = bus_space_map(tag, start,
|
||||
rman_get_size(res), 0, &handle);
|
||||
if (rv != 0)
|
||||
return (ENOMEM);
|
||||
|
||||
rman_set_bushandle(res, handle);
|
||||
rman_set_virtual(res, (void *)handle); /* XXX for powerpc only ? */
|
||||
|
||||
return (rman_activate_resource(res));
|
||||
}
|
||||
|
||||
#ifdef __powerpc__
|
||||
static bus_space_tag_t
|
||||
ofw_pci_bus_get_bus_tag(device_t bus, device_t child)
|
||||
{
|
||||
|
||||
return (&bs_le_tag);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
ofw_pci_deactivate_resource(device_t bus, device_t child, int type, int rid,
|
||||
struct resource *res)
|
||||
{
|
||||
vm_size_t psize;
|
||||
|
||||
if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY) {
|
||||
return (bus_generic_deactivate_resource(bus, child, type, rid,
|
||||
res));
|
||||
}
|
||||
|
||||
psize = rman_get_size(res);
|
||||
pmap_unmapdev((vm_offset_t)rman_get_virtual(res), psize);
|
||||
|
||||
return (rman_deactivate_resource(res));
|
||||
}
|
||||
|
||||
static int
|
||||
ofw_pci_adjust_resource(device_t bus, device_t child, int type,
|
||||
struct resource *res, rman_res_t start, rman_res_t end)
|
||||
{
|
||||
struct rman *rm;
|
||||
struct ofw_pci_softc *sc;
|
||||
|
||||
sc = device_get_softc(bus);
|
||||
#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
|
||||
if (type == PCI_RES_BUS)
|
||||
return (pci_domain_adjust_bus(sc->sc_pci_domain, child, res,
|
||||
start, end));
|
||||
#endif
|
||||
|
||||
rm = ofw_pci_get_rman(sc, type, rman_get_flags(res));
|
||||
if (rm == NULL) {
|
||||
return (bus_generic_adjust_resource(bus, child, type, res,
|
||||
start, end));
|
||||
}
|
||||
KASSERT(rman_is_region_manager(res, rm), ("rman mismatch"));
|
||||
KASSERT(!(rman_get_flags(res) & RF_ACTIVE),
|
||||
("active resources cannot be adjusted"));
|
||||
|
||||
return (rman_adjust_resource(res, start, end));
|
||||
}
|
||||
|
||||
static phandle_t
|
||||
ofw_pci_get_node(device_t bus, device_t dev)
|
||||
{
|
||||
struct ofw_pci_softc *sc;
|
||||
|
||||
sc = device_get_softc(bus);
|
||||
/* We only have one child, the PCI bus, which needs our own node. */
|
||||
|
||||
return (sc->sc_node);
|
||||
}
|
||||
|
||||
static int
|
||||
ofw_pci_fill_ranges(phandle_t node, struct ofw_pci_range *ranges)
|
||||
{
|
||||
int host_address_cells = 1, pci_address_cells = 3, size_cells = 2;
|
||||
cell_t *base_ranges;
|
||||
ssize_t nbase_ranges;
|
||||
int nranges;
|
||||
int i, j, k;
|
||||
|
||||
OF_getencprop(OF_parent(node), "#address-cells", &host_address_cells,
|
||||
sizeof(host_address_cells));
|
||||
OF_getencprop(node, "#address-cells", &pci_address_cells,
|
||||
sizeof(pci_address_cells));
|
||||
OF_getencprop(node, "#size-cells", &size_cells, sizeof(size_cells));
|
||||
|
||||
nbase_ranges = OF_getproplen(node, "ranges");
|
||||
if (nbase_ranges <= 0)
|
||||
return (-1);
|
||||
nranges = nbase_ranges / sizeof(cell_t) /
|
||||
(pci_address_cells + host_address_cells + size_cells);
|
||||
|
||||
base_ranges = malloc(nbase_ranges, M_DEVBUF, M_WAITOK);
|
||||
OF_getencprop(node, "ranges", base_ranges, nbase_ranges);
|
||||
|
||||
for (i = 0, j = 0; i < nranges; i++) {
|
||||
ranges[i].pci_hi = base_ranges[j++];
|
||||
ranges[i].pci = 0;
|
||||
for (k = 0; k < pci_address_cells - 1; k++) {
|
||||
ranges[i].pci <<= 32;
|
||||
ranges[i].pci |= base_ranges[j++];
|
||||
}
|
||||
ranges[i].host = 0;
|
||||
for (k = 0; k < host_address_cells; k++) {
|
||||
ranges[i].host <<= 32;
|
||||
ranges[i].host |= base_ranges[j++];
|
||||
}
|
||||
ranges[i].size = 0;
|
||||
for (k = 0; k < size_cells; k++) {
|
||||
ranges[i].size <<= 32;
|
||||
ranges[i].size |= base_ranges[j++];
|
||||
}
|
||||
}
|
||||
|
||||
free(base_ranges, M_DEVBUF);
|
||||
return (nranges);
|
||||
}
|
||||
|
||||
static struct rman *
|
||||
ofw_pci_get_rman(struct ofw_pci_softc *sc, int type, u_int flags)
|
||||
{
|
||||
|
||||
switch (type) {
|
||||
case SYS_RES_IOPORT:
|
||||
return (&sc->sc_io_rman);
|
||||
case SYS_RES_MEMORY:
|
||||
if (sc->sc_have_pmem && (flags & RF_PREFETCHABLE))
|
||||
return (&sc->sc_pmem_rman);
|
||||
else
|
||||
return (&sc->sc_mem_rman);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
87
freebsd/sys/dev/ofw/ofwpci.h
Normal file
87
freebsd/sys/dev/ofw/ofwpci.h
Normal file
@ -0,0 +1,87 @@
|
||||
/*-
|
||||
* Copyright (c) 2011 Nathan Whitehorn
|
||||
* 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 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 _DEV_OFW_OFWPCI_H_
|
||||
#define _DEV_OFW_OFWPCI_H_
|
||||
|
||||
/*
|
||||
* Export class definition for inheritance purposes
|
||||
*/
|
||||
DECLARE_CLASS(ofw_pci_driver);
|
||||
|
||||
struct ofw_pci_cell_info {
|
||||
pcell_t host_address_cells;
|
||||
pcell_t pci_address_cell;
|
||||
pcell_t size_cells;
|
||||
};
|
||||
|
||||
struct ofw_pci_range {
|
||||
uint32_t pci_hi;
|
||||
uint64_t pci;
|
||||
uint64_t host;
|
||||
uint64_t size;
|
||||
};
|
||||
|
||||
/*
|
||||
* Quirks for some adapters
|
||||
*/
|
||||
enum {
|
||||
OFW_PCI_QUIRK_RANGES_ON_CHILDREN = 1,
|
||||
};
|
||||
|
||||
struct ofw_pci_softc {
|
||||
device_t sc_dev;
|
||||
phandle_t sc_node;
|
||||
int sc_bus;
|
||||
int sc_initialized;
|
||||
int sc_quirks;
|
||||
int sc_have_pmem;
|
||||
|
||||
struct ofw_pci_range *sc_range;
|
||||
int sc_nrange;
|
||||
uint64_t sc_range_mask;
|
||||
struct ofw_pci_cell_info *sc_cell_info;
|
||||
|
||||
struct rman sc_io_rman;
|
||||
struct rman sc_mem_rman;
|
||||
struct rman sc_pmem_rman;
|
||||
bus_space_tag_t sc_memt;
|
||||
bus_dma_tag_t sc_dmat;
|
||||
int sc_pci_domain;
|
||||
|
||||
struct ofw_bus_iinfo sc_pci_iinfo;
|
||||
};
|
||||
|
||||
int ofw_pci_init(device_t);
|
||||
int ofw_pci_attach(device_t);
|
||||
int ofw_pci_read_ivar(device_t, device_t, int, uintptr_t *);
|
||||
int ofw_pci_write_ivar(device_t, device_t, int, uintptr_t);
|
||||
int ofw_pci_route_interrupt(device_t, device_t, int);
|
||||
int ofw_pci_nranges(phandle_t, struct ofw_pci_cell_info *);
|
||||
|
||||
#endif /* _DEV_OFW_OFWPCI_H_ */
|
388
freebsd/sys/dev/pci/pci_subr.c
Normal file
388
freebsd/sys/dev/pci/pci_subr.c
Normal file
@ -0,0 +1,388 @@
|
||||
#include <machine/rtems-bsd-kernel-space.h>
|
||||
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (c) 2011 Hudson River Trading LLC
|
||||
* Written by: John H. Baldwin <jhb@FreeBSD.org>
|
||||
* 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 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$");
|
||||
|
||||
/*
|
||||
* Support APIs for Host to PCI bridge drivers and drivers that
|
||||
* provide PCI domains.
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/rman.h>
|
||||
#include <sys/systm.h>
|
||||
|
||||
#include <dev/pci/pcireg.h>
|
||||
#include <dev/pci/pcivar.h>
|
||||
#include <dev/pci/pcib_private.h>
|
||||
|
||||
/*
|
||||
* Try to read the bus number of a host-PCI bridge using appropriate config
|
||||
* registers.
|
||||
*/
|
||||
int
|
||||
host_pcib_get_busno(pci_read_config_fn read_config, int bus, int slot, int func,
|
||||
uint8_t *busnum)
|
||||
{
|
||||
uint32_t id;
|
||||
|
||||
id = read_config(bus, slot, func, PCIR_DEVVENDOR, 4);
|
||||
if (id == 0xffffffff)
|
||||
return (0);
|
||||
|
||||
switch (id) {
|
||||
case 0x12258086:
|
||||
/* Intel 824?? */
|
||||
/* XXX This is a guess */
|
||||
/* *busnum = read_config(bus, slot, func, 0x41, 1); */
|
||||
*busnum = bus;
|
||||
break;
|
||||
case 0x84c48086:
|
||||
/* Intel 82454KX/GX (Orion) */
|
||||
*busnum = read_config(bus, slot, func, 0x4a, 1);
|
||||
break;
|
||||
case 0x84ca8086:
|
||||
/*
|
||||
* For the 450nx chipset, there is a whole bundle of
|
||||
* things pretending to be host bridges. The MIOC will
|
||||
* be seen first and isn't really a pci bridge (the
|
||||
* actual buses are attached to the PXB's). We need to
|
||||
* read the registers of the MIOC to figure out the
|
||||
* bus numbers for the PXB channels.
|
||||
*
|
||||
* Since the MIOC doesn't have a pci bus attached, we
|
||||
* pretend it wasn't there.
|
||||
*/
|
||||
return (0);
|
||||
case 0x84cb8086:
|
||||
switch (slot) {
|
||||
case 0x12:
|
||||
/* Intel 82454NX PXB#0, Bus#A */
|
||||
*busnum = read_config(bus, 0x10, func, 0xd0, 1);
|
||||
break;
|
||||
case 0x13:
|
||||
/* Intel 82454NX PXB#0, Bus#B */
|
||||
*busnum = read_config(bus, 0x10, func, 0xd1, 1) + 1;
|
||||
break;
|
||||
case 0x14:
|
||||
/* Intel 82454NX PXB#1, Bus#A */
|
||||
*busnum = read_config(bus, 0x10, func, 0xd3, 1);
|
||||
break;
|
||||
case 0x15:
|
||||
/* Intel 82454NX PXB#1, Bus#B */
|
||||
*busnum = read_config(bus, 0x10, func, 0xd4, 1) + 1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
/* ServerWorks -- vendor 0x1166 */
|
||||
case 0x00051166:
|
||||
case 0x00061166:
|
||||
case 0x00081166:
|
||||
case 0x00091166:
|
||||
case 0x00101166:
|
||||
case 0x00111166:
|
||||
case 0x00171166:
|
||||
case 0x01011166:
|
||||
case 0x010f1014:
|
||||
case 0x01101166:
|
||||
case 0x02011166:
|
||||
case 0x02251166:
|
||||
case 0x03021014:
|
||||
*busnum = read_config(bus, slot, func, 0x44, 1);
|
||||
break;
|
||||
|
||||
/* Compaq/HP -- vendor 0x0e11 */
|
||||
case 0x60100e11:
|
||||
*busnum = read_config(bus, slot, func, 0xc8, 1);
|
||||
break;
|
||||
default:
|
||||
/* Don't know how to read bus number. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef NEW_PCIB
|
||||
/*
|
||||
* Return a pointer to a pretty name for a PCI device. If the device
|
||||
* has a driver attached, the device's name is used, otherwise a name
|
||||
* is generated from the device's PCI address.
|
||||
*/
|
||||
const char *
|
||||
pcib_child_name(device_t child)
|
||||
{
|
||||
static char buf[64];
|
||||
|
||||
if (device_get_nameunit(child) != NULL)
|
||||
return (device_get_nameunit(child));
|
||||
snprintf(buf, sizeof(buf), "pci%d:%d:%d:%d", pci_get_domain(child),
|
||||
pci_get_bus(child), pci_get_slot(child), pci_get_function(child));
|
||||
return (buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* Some Host-PCI bridge drivers know which resource ranges they can
|
||||
* decode and should only allocate subranges to child PCI devices.
|
||||
* This API provides a way to manage this. The bridge driver should
|
||||
* initialize this structure during attach and call
|
||||
* pcib_host_res_decodes() on each resource range it decodes. It can
|
||||
* then use pcib_host_res_alloc() and pcib_host_res_adjust() as helper
|
||||
* routines for BUS_ALLOC_RESOURCE() and BUS_ADJUST_RESOURCE(). This
|
||||
* API assumes that resources for any decoded ranges can be safely
|
||||
* allocated from the parent via bus_generic_alloc_resource().
|
||||
*/
|
||||
int
|
||||
pcib_host_res_init(device_t pcib, struct pcib_host_resources *hr)
|
||||
{
|
||||
|
||||
hr->hr_pcib = pcib;
|
||||
resource_list_init(&hr->hr_rl);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
pcib_host_res_free(device_t pcib, struct pcib_host_resources *hr)
|
||||
{
|
||||
|
||||
resource_list_free(&hr->hr_rl);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
pcib_host_res_decodes(struct pcib_host_resources *hr, int type, rman_res_t start,
|
||||
rman_res_t end, u_int flags)
|
||||
{
|
||||
struct resource_list_entry *rle;
|
||||
int rid;
|
||||
|
||||
if (bootverbose)
|
||||
device_printf(hr->hr_pcib, "decoding %d %srange %#jx-%#jx\n",
|
||||
type, flags & RF_PREFETCHABLE ? "prefetchable ": "", start,
|
||||
end);
|
||||
rid = resource_list_add_next(&hr->hr_rl, type, start, end,
|
||||
end - start + 1);
|
||||
if (flags & RF_PREFETCHABLE) {
|
||||
KASSERT(type == SYS_RES_MEMORY,
|
||||
("only memory is prefetchable"));
|
||||
rle = resource_list_find(&hr->hr_rl, type, rid);
|
||||
rle->flags = RLE_PREFETCH;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
struct resource *
|
||||
pcib_host_res_alloc(struct pcib_host_resources *hr, device_t dev, int type,
|
||||
int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
|
||||
{
|
||||
struct resource_list_entry *rle;
|
||||
struct resource *r;
|
||||
rman_res_t new_start, new_end;
|
||||
|
||||
if (flags & RF_PREFETCHABLE)
|
||||
KASSERT(type == SYS_RES_MEMORY,
|
||||
("only memory is prefetchable"));
|
||||
|
||||
rle = resource_list_find(&hr->hr_rl, type, 0);
|
||||
if (rle == NULL) {
|
||||
/*
|
||||
* No decoding ranges for this resource type, just pass
|
||||
* the request up to the parent.
|
||||
*/
|
||||
return (bus_generic_alloc_resource(hr->hr_pcib, dev, type, rid,
|
||||
start, end, count, flags));
|
||||
}
|
||||
|
||||
restart:
|
||||
/* Try to allocate from each decoded range. */
|
||||
for (; rle != NULL; rle = STAILQ_NEXT(rle, link)) {
|
||||
if (rle->type != type)
|
||||
continue;
|
||||
if (((flags & RF_PREFETCHABLE) != 0) !=
|
||||
((rle->flags & RLE_PREFETCH) != 0))
|
||||
continue;
|
||||
new_start = ummax(start, rle->start);
|
||||
new_end = ummin(end, rle->end);
|
||||
if (new_start > new_end ||
|
||||
new_start + count - 1 > new_end ||
|
||||
new_start + count < new_start)
|
||||
continue;
|
||||
r = bus_generic_alloc_resource(hr->hr_pcib, dev, type, rid,
|
||||
new_start, new_end, count, flags);
|
||||
if (r != NULL) {
|
||||
if (bootverbose)
|
||||
device_printf(hr->hr_pcib,
|
||||
"allocated type %d (%#jx-%#jx) for rid %x of %s\n",
|
||||
type, rman_get_start(r), rman_get_end(r),
|
||||
*rid, pcib_child_name(dev));
|
||||
return (r);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we failed to find a prefetch range for a memory
|
||||
* resource, try again without prefetch.
|
||||
*/
|
||||
if (flags & RF_PREFETCHABLE) {
|
||||
flags &= ~RF_PREFETCHABLE;
|
||||
rle = resource_list_find(&hr->hr_rl, type, 0);
|
||||
goto restart;
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
int
|
||||
pcib_host_res_adjust(struct pcib_host_resources *hr, device_t dev, int type,
|
||||
struct resource *r, rman_res_t start, rman_res_t end)
|
||||
{
|
||||
struct resource_list_entry *rle;
|
||||
|
||||
rle = resource_list_find(&hr->hr_rl, type, 0);
|
||||
if (rle == NULL) {
|
||||
/*
|
||||
* No decoding ranges for this resource type, just pass
|
||||
* the request up to the parent.
|
||||
*/
|
||||
return (bus_generic_adjust_resource(hr->hr_pcib, dev, type, r,
|
||||
start, end));
|
||||
}
|
||||
|
||||
/* Only allow adjustments that stay within a decoded range. */
|
||||
for (; rle != NULL; rle = STAILQ_NEXT(rle, link)) {
|
||||
if (rle->start <= start && rle->end >= end)
|
||||
return (bus_generic_adjust_resource(hr->hr_pcib, dev,
|
||||
type, r, start, end));
|
||||
}
|
||||
return (ERANGE);
|
||||
}
|
||||
|
||||
#ifdef PCI_RES_BUS
|
||||
struct pci_domain {
|
||||
int pd_domain;
|
||||
struct rman pd_bus_rman;
|
||||
TAILQ_ENTRY(pci_domain) pd_link;
|
||||
};
|
||||
|
||||
static TAILQ_HEAD(, pci_domain) domains = TAILQ_HEAD_INITIALIZER(domains);
|
||||
|
||||
/*
|
||||
* Each PCI domain maintains its own resource manager for PCI bus
|
||||
* numbers in that domain. Domain objects are created on first use.
|
||||
* Host to PCI bridge drivers and PCI-PCI bridge drivers should
|
||||
* allocate their bus ranges from their domain.
|
||||
*/
|
||||
static struct pci_domain *
|
||||
pci_find_domain(int domain)
|
||||
{
|
||||
struct pci_domain *d;
|
||||
char buf[64];
|
||||
int error;
|
||||
|
||||
TAILQ_FOREACH(d, &domains, pd_link) {
|
||||
if (d->pd_domain == domain)
|
||||
return (d);
|
||||
}
|
||||
|
||||
snprintf(buf, sizeof(buf), "PCI domain %d bus numbers", domain);
|
||||
d = malloc(sizeof(*d) + strlen(buf) + 1, M_DEVBUF, M_WAITOK | M_ZERO);
|
||||
d->pd_domain = domain;
|
||||
d->pd_bus_rman.rm_start = 0;
|
||||
d->pd_bus_rman.rm_end = PCI_BUSMAX;
|
||||
d->pd_bus_rman.rm_type = RMAN_ARRAY;
|
||||
strcpy((char *)(d + 1), buf);
|
||||
d->pd_bus_rman.rm_descr = (char *)(d + 1);
|
||||
error = rman_init(&d->pd_bus_rman);
|
||||
if (error == 0)
|
||||
error = rman_manage_region(&d->pd_bus_rman, 0, PCI_BUSMAX);
|
||||
if (error)
|
||||
panic("Failed to initialize PCI domain %d rman", domain);
|
||||
TAILQ_INSERT_TAIL(&domains, d, pd_link);
|
||||
return (d);
|
||||
}
|
||||
|
||||
struct resource *
|
||||
pci_domain_alloc_bus(int domain, device_t dev, int *rid, rman_res_t start,
|
||||
rman_res_t end, rman_res_t count, u_int flags)
|
||||
{
|
||||
struct pci_domain *d;
|
||||
struct resource *res;
|
||||
|
||||
if (domain < 0 || domain > PCI_DOMAINMAX)
|
||||
return (NULL);
|
||||
d = pci_find_domain(domain);
|
||||
res = rman_reserve_resource(&d->pd_bus_rman, start, end, count, flags,
|
||||
dev);
|
||||
if (res == NULL)
|
||||
return (NULL);
|
||||
|
||||
rman_set_rid(res, *rid);
|
||||
return (res);
|
||||
}
|
||||
|
||||
int
|
||||
pci_domain_adjust_bus(int domain, device_t dev, struct resource *r,
|
||||
rman_res_t start, rman_res_t end)
|
||||
{
|
||||
#ifdef INVARIANTS
|
||||
struct pci_domain *d;
|
||||
#endif
|
||||
|
||||
if (domain < 0 || domain > PCI_DOMAINMAX)
|
||||
return (EINVAL);
|
||||
#ifdef INVARIANTS
|
||||
d = pci_find_domain(domain);
|
||||
KASSERT(rman_is_region_manager(r, &d->pd_bus_rman), ("bad resource"));
|
||||
#endif
|
||||
return (rman_adjust_resource(r, start, end));
|
||||
}
|
||||
|
||||
int
|
||||
pci_domain_release_bus(int domain, device_t dev, int rid, struct resource *r)
|
||||
{
|
||||
#ifdef INVARIANTS
|
||||
struct pci_domain *d;
|
||||
#endif
|
||||
|
||||
if (domain < 0 || domain > PCI_DOMAINMAX)
|
||||
return (EINVAL);
|
||||
#ifdef INVARIANTS
|
||||
d = pci_find_domain(domain);
|
||||
KASSERT(rman_is_region_manager(r, &d->pd_bus_rman), ("bad resource"));
|
||||
#endif
|
||||
return (rman_release_resource(r));
|
||||
}
|
||||
#endif /* PCI_RES_BUS */
|
||||
|
||||
#endif /* NEW_PCIB */
|
224
freebsd/sys/powerpc/include/machine/hid.h
Normal file
224
freebsd/sys/powerpc/include/machine/hid.h
Normal file
@ -0,0 +1,224 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Copyright (c) 2000 Tsubai Masanari. 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.
|
||||
*
|
||||
* $NetBSD: hid.h,v 1.2 2001/08/22 21:05:25 matt Exp $
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _POWERPC_HID_H_
|
||||
#define _POWERPC_HID_H_
|
||||
|
||||
/* Hardware Implementation Dependent registers for the PowerPC */
|
||||
#define HID0_RADIX 0x0080000000000000 /* Enable Radix page tables (POWER9) */
|
||||
|
||||
#define HID0_EMCP 0x80000000 /* Enable machine check pin */
|
||||
#define HID0_DBP 0x40000000 /* Disable 60x bus parity generation */
|
||||
#define HID0_EBA 0x20000000 /* Enable 60x bus address parity checking */
|
||||
#define HID0_EBD 0x10000000 /* Enable 60x bus data parity checking */
|
||||
#define HID0_BCLK 0x08000000 /* CLK_OUT clock type selection */
|
||||
#define HID0_EICE 0x04000000 /* Enable ICE output */
|
||||
#define HID0_ECLK 0x02000000 /* CLK_OUT clock type selection */
|
||||
#define HID0_PAR 0x01000000 /* Disable precharge of ARTRY */
|
||||
#define HID0_STEN 0x01000000 /* Software table search enable (7450) */
|
||||
#define HID0_DEEPNAP 0x01000000 /* Enable deep nap mode (970) */
|
||||
#define HID0_HBATEN 0x00800000 /* High BAT enable (74[45][578]) */
|
||||
#define HID0_DOZE 0x00800000 /* Enable doze mode */
|
||||
#define HID0_NAP 0x00400000 /* Enable nap mode */
|
||||
#define HID0_SLEEP 0x00200000 /* Enable sleep mode */
|
||||
#define HID0_DPM 0x00100000 /* Enable Dynamic power management */
|
||||
#define HID0_RISEG 0x00080000 /* Read I-SEG */
|
||||
#define HID0_TG 0x00040000 /* Timebase Granularity (OEA64) */
|
||||
#define HID0_BHTCLR 0x00040000 /* Clear branch history table (7450) */
|
||||
#define HID0_EIEC 0x00040000 /* Enable internal error checking */
|
||||
#define HID0_XAEN 0x00020000 /* Enable eXtended Addressing (7450) */
|
||||
#define HID0_NHR 0x00010000 /* Not hard reset */
|
||||
#define HID0_ICE 0x00008000 /* Enable i-cache */
|
||||
#define HID0_DCE 0x00004000 /* Enable d-cache */
|
||||
#define HID0_ILOCK 0x00002000 /* i-cache lock */
|
||||
#define HID0_DLOCK 0x00001000 /* d-cache lock */
|
||||
#define HID0_ICFI 0x00000800 /* i-cache flush invalidate */
|
||||
#define HID0_DCFI 0x00000400 /* d-cache flush invalidate */
|
||||
#define HID0_SPD 0x00000200 /* Disable speculative cache access */
|
||||
#define HID0_XBSEN 0x00000100 /* Extended BAT block-size enable (7457) */
|
||||
#define HID0_IFEM 0x00000100 /* Enable M-bit for I-fetch */
|
||||
#define HID0_XBSEN 0x00000100 /* Extended BAT block size enable (7455+)*/
|
||||
#define HID0_SGE 0x00000080 /* Enable store gathering */
|
||||
#define HID0_DCFA 0x00000040 /* Data cache flush assist */
|
||||
#define HID0_BTIC 0x00000020 /* Enable BTIC */
|
||||
#define HID0_LRSTK 0x00000010 /* Link register stack enable (7450) */
|
||||
#define HID0_ABE 0x00000008 /* Enable address broadcast */
|
||||
#define HID0_FOLD 0x00000008 /* Branch folding enable (7450) */
|
||||
#define HID0_BHT 0x00000004 /* Enable branch history table */
|
||||
#define HID0_NOPTI 0x00000001 /* No-op the dcbt(st) */
|
||||
|
||||
#define HID0_AIM_TBEN 0x04000000 /* Time base enable (7450) */
|
||||
|
||||
#define HID0_E500_TBEN 0x00004000 /* Time Base and decr. enable */
|
||||
#define HID0_E500_SEL_TBCLK 0x00002000 /* Select Time Base clock */
|
||||
#define HID0_E500_MAS7UPDEN 0x00000080 /* Enable MAS7 update (e500v2) */
|
||||
|
||||
#define HID0_E500MC_L2MMU_MHD 0x40000000 /* L2MMU Multiple Hit Detection */
|
||||
|
||||
#define HID0_BITMASK \
|
||||
"\20" \
|
||||
"\040EMCP\037DBP\036EBA\035EBD\034BCLK\033EICE\032ECLK\031PAR" \
|
||||
"\030DOZE\027NAP\026SLEEP\025DPM\024RISEG\023EIEC\022res\021NHR" \
|
||||
"\020ICE\017DCE\016ILOCK\015DLOCK\014ICFI\013DCFI\012SPD\011IFEM" \
|
||||
"\010SGE\007DCFA\006BTIC\005FBIOB\004ABE\003BHT\002NOPDST\001NOPTI"
|
||||
|
||||
#define HID0_7450_BITMASK \
|
||||
"\20" \
|
||||
"\040EMCP\037b1\036b2\035b3\034b4\033TBEN\032b6\031STEN" \
|
||||
"\030HBATEN\027NAP\026SLEEP\025DPM\024b12\023BHTCLR\022XAEN\021NHR" \
|
||||
"\020ICE\017DCE\016ILOCK\015DLOCK\014ICFI\013DCFI\012SPD\011XBSEN" \
|
||||
"\010SGE\007b25\006BTIC\005LRSTK\004FOLD\003BHT\002NOPDST\001NOPTI"
|
||||
|
||||
#define HID0_E500_BITMASK \
|
||||
"\20" \
|
||||
"\040EMCP\037b1\036b2\035b3\034b4\033b5\032b6\031b7" \
|
||||
"\030DOZE\027NAP\026SLEEP\025b11\024b12\023b13\022b14\021b15" \
|
||||
"\020b16\017TBEN\016SEL_TBCLK\015b19\014b20\013b21\012b22\011b23" \
|
||||
"\010EN_MAS7_UPDATE\007DCFA\006b26\005b27\004b28\003b29\002b30\001NOPTI"
|
||||
|
||||
#define HID0_970_BITMASK \
|
||||
"\20" \
|
||||
"\040ONEPPC\037SINGLE\036ISYNCSC\035SERGP\031DEEPNAP\030DOZE" \
|
||||
"\027NAP\025DPM\023TG\022HANGDETECT\021NHR\020INORDER" \
|
||||
"\016TBCTRL\015TBEN\012CIABREN\011HDICEEN\001ENATTN"
|
||||
|
||||
#define HID0_E500MC_BITMASK \
|
||||
"\20" \
|
||||
"\040EMCP\037EN_L2MMU_MHD\036b2\035b3\034b4\033b5\032b6\031b7" \
|
||||
"\030b8\027b9\026b10\025b11\024b12\023b13\022b14\021b15" \
|
||||
"\020b16\017b17\016b18\015b19\014b20\013b21\012b22\011b23" \
|
||||
"\010EN_MAS7_UPDATE\007DCFA\006b26\005CIGLSO\004b28\003b29\002b30\001NOPTI"
|
||||
|
||||
#define HID0_E5500_BITMASK \
|
||||
"\20" \
|
||||
"\040EMCP\037EN_L2MMU_MHD\036b2\035b3\034b4\033b5\032b6\031b7" \
|
||||
"\030b8\027b9\026b10\025b11\024b12\023b13\022b14\021b15" \
|
||||
"\020b16\017b17\016b18\015b19\014b20\013b21\012b22\011b23" \
|
||||
"\010b24\007DCFA\006b26\005CIGLSO\004b28\003b29\002b30\001NOPTI"
|
||||
|
||||
/*
|
||||
* HID0 bit definitions per cpu model
|
||||
*
|
||||
* bit 603 604 750 7400 7410 7450 7457 e500
|
||||
* 0 EMCP EMCP EMCP EMCP EMCP - - EMCP
|
||||
* 1 - ECP DBP - - - - -
|
||||
* 2 EBA EBA EBA EBA EDA - - -
|
||||
* 3 EBD EBD EBD EBD EBD - - -
|
||||
* 4 SBCLK - BCLK BCKL BCLK - - -
|
||||
* 5 EICE - - - - TBEN TBEN -
|
||||
* 6 ECLK - ECLK ECLK ECLK - - -
|
||||
* 7 PAR PAR PAR PAR PAR STEN STEN -
|
||||
* 8 DOZE - DOZE DOZE DOZE - HBATEN DOZE
|
||||
* 9 NAP - NAP NAP NAP NAP NAP NAP
|
||||
* 10 SLEEP - SLEEP SLEEP SLEEP SLEEP SLEEP SLEEP
|
||||
* 11 DPM - DPM DPM DPM DPM DPM -
|
||||
* 12 RISEG - - RISEG - - - -
|
||||
* 13 - - - EIEC EIEC BHTCLR BHTCLR -
|
||||
* 14 - - - - - XAEN XAEN -
|
||||
* 15 - NHR NHR NHR NHR NHR NHR -
|
||||
* 16 ICE ICE ICE ICE ICE ICE ICE -
|
||||
* 17 DCE DCE DCE DCE DCE DCE DCE TBEN
|
||||
* 18 ILOCK ILOCK ILOCK ILOCK ILOCK ILOCK ILOCK SEL_TBCLK
|
||||
* 19 DLOCK DLOCK DLOCK DLOCK DLOCK DLOCK DLOCK -
|
||||
* 20 ICFI ICFI ICFI ICFI ICFI ICFI ICFI -
|
||||
* 21 DCFI DCFI DCFI DCFI DCFI DCFI DCFI -
|
||||
* 22 - - SPD SPD SPG SPD SPD -
|
||||
* 23 - - IFEM IFTT IFTT - XBSEN -
|
||||
* 24 - SIE SGE SGE SGE SGE SGE EN_MAS7_UPDATE
|
||||
* 25 - - DCFA DCFA DCFA - - DCFA
|
||||
* 26 - - BTIC BTIC BTIC BTIC BTIC -
|
||||
* 27 FBIOB - - - - LRSTK LRSTK -
|
||||
* 28 - - ABE - - FOLD FOLD -
|
||||
* 29 - BHT BHT BHT BHT BHT BHT -
|
||||
* 30 - - - NOPDST NOPDST NOPDST NOPDST -
|
||||
* 31 NOOPTI - NOOPTI NOPTI NOPTI NOPTI NOPTI NOPTI
|
||||
*
|
||||
* bit e500mc e5500
|
||||
* 0 EMCP EMCP
|
||||
* 1 EN_L2MMU_MHD EN_L2MMU_MHD
|
||||
* 2 - -
|
||||
* 3 - -
|
||||
* 4 - -
|
||||
* 5 - -
|
||||
* 6 - -
|
||||
* 7 - -
|
||||
* 8 - -
|
||||
* 9 - -
|
||||
* 10 - -
|
||||
* 11 - -
|
||||
* 12 - -
|
||||
* 13 - -
|
||||
* 14 - -
|
||||
* 15 - -
|
||||
* 16 - -
|
||||
* 17 - -
|
||||
* 18 - -
|
||||
* 19 - -
|
||||
* 20 - -
|
||||
* 21 - -
|
||||
* 22 - -
|
||||
* 23 - -
|
||||
* 24 EN_MAS7_UPDATE -
|
||||
* 25 DCFA DCFA
|
||||
* 26 - -
|
||||
* 27 CIGLSO CIGLSO
|
||||
* 28 - -
|
||||
* 29 - -
|
||||
* 30 - -
|
||||
* 31 NOPTI NOPTI
|
||||
*
|
||||
* 604: ECP = Enable cache parity checking
|
||||
* 604: SIE = Serial instruction execution disable
|
||||
* 7450: TBEN = Time Base Enable
|
||||
* 7450: STEN = Software table lookup enable
|
||||
* 7450: BHTCLR = Branch history clear
|
||||
* 7450: XAEN = Extended Addressing Enabled
|
||||
* 7450: LRSTK = Link Register Stack Enable
|
||||
* 7450: FOLD = Branch folding enable
|
||||
* 7457: HBATEN = High BAT Enable
|
||||
* 7457: XBSEN = Extended BAT Block Size Enable
|
||||
*/
|
||||
|
||||
#define HID1_E500_ABE 0x00001000 /* Address broadcast enable */
|
||||
#define HID1_E500_ASTME 0x00002000 /* Address bus streaming mode enable */
|
||||
#define HID1_E500_RFXE 0x00020000 /* Read fault exception enable */
|
||||
|
||||
#define HID0_E500_DEFAULT_SET (HID0_EMCP | HID0_E500_TBEN | \
|
||||
HID0_E500_MAS7UPDEN)
|
||||
#define HID1_E500_DEFAULT_SET (HID1_E500_ABE | HID1_E500_ASTME)
|
||||
#define HID0_E500MC_DEFAULT_SET (HID0_EMCP | HID0_E500MC_L2MMU_MHD | \
|
||||
HID0_E500_MAS7UPDEN)
|
||||
#define HID0_E5500_DEFAULT_SET (HID0_EMCP | HID0_E500MC_L2MMU_MHD)
|
||||
|
||||
#define HID5_970_DCBZ_SIZE_HI 0x00000080UL /* dcbz does a 32-byte store */
|
||||
#define HID4_970_DISABLE_LG_PG 0x00000004ULL /* disables large pages */
|
||||
|
||||
#endif /* _POWERPC_HID_H_ */
|
306
freebsd/sys/powerpc/include/machine/pio.h
Normal file
306
freebsd/sys/powerpc/include/machine/pio.h
Normal file
@ -0,0 +1,306 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-4-Clause
|
||||
*
|
||||
* Copyright (c) 1997 Per Fogelstrom, Opsycon AB and RTMX Inc, USA.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed under OpenBSD by
|
||||
* Per Fogelstrom Opsycon AB for RTMX Inc, North Carolina, USA.
|
||||
* 4. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $NetBSD: pio.h,v 1.1 1998/05/15 10:15:54 tsubai Exp $
|
||||
* $OpenBSD: pio.h,v 1.1 1997/10/13 10:53:47 pefo Exp $
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _MACHINE_PIO_H_
|
||||
#define _MACHINE_PIO_H_
|
||||
/*
|
||||
* I/O macros.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Use sync so that bus space operations cannot sneak out the bottom of
|
||||
* mutex-protected sections (mutex release does not guarantee completion of
|
||||
* accesses to caching-inhibited memory on some systems)
|
||||
*/
|
||||
#define powerpc_iomb() __asm __volatile("sync" : : : "memory")
|
||||
|
||||
static __inline void
|
||||
__outb(volatile u_int8_t *a, u_int8_t v)
|
||||
{
|
||||
*a = v;
|
||||
powerpc_iomb();
|
||||
}
|
||||
|
||||
static __inline void
|
||||
__outw(volatile u_int16_t *a, u_int16_t v)
|
||||
{
|
||||
*a = v;
|
||||
powerpc_iomb();
|
||||
}
|
||||
|
||||
static __inline void
|
||||
__outl(volatile u_int32_t *a, u_int32_t v)
|
||||
{
|
||||
*a = v;
|
||||
powerpc_iomb();
|
||||
}
|
||||
|
||||
static __inline void
|
||||
__outll(volatile u_int64_t *a, u_int64_t v)
|
||||
{
|
||||
*a = v;
|
||||
powerpc_iomb();
|
||||
}
|
||||
|
||||
static __inline void
|
||||
__outwrb(volatile u_int16_t *a, u_int16_t v)
|
||||
{
|
||||
__asm__ volatile("sthbrx %0, 0, %1" :: "r"(v), "r"(a));
|
||||
powerpc_iomb();
|
||||
}
|
||||
|
||||
static __inline void
|
||||
__outlrb(volatile u_int32_t *a, u_int32_t v)
|
||||
{
|
||||
__asm__ volatile("stwbrx %0, 0, %1" :: "r"(v), "r"(a));
|
||||
powerpc_iomb();
|
||||
}
|
||||
|
||||
static __inline u_int8_t
|
||||
__inb(volatile u_int8_t *a)
|
||||
{
|
||||
u_int8_t _v_;
|
||||
|
||||
_v_ = *a;
|
||||
powerpc_iomb();
|
||||
return _v_;
|
||||
}
|
||||
|
||||
static __inline u_int16_t
|
||||
__inw(volatile u_int16_t *a)
|
||||
{
|
||||
u_int16_t _v_;
|
||||
|
||||
_v_ = *a;
|
||||
powerpc_iomb();
|
||||
return _v_;
|
||||
}
|
||||
|
||||
static __inline u_int32_t
|
||||
__inl(volatile u_int32_t *a)
|
||||
{
|
||||
u_int32_t _v_;
|
||||
|
||||
_v_ = *a;
|
||||
powerpc_iomb();
|
||||
return _v_;
|
||||
}
|
||||
|
||||
static __inline u_int64_t
|
||||
__inll(volatile u_int64_t *a)
|
||||
{
|
||||
u_int64_t _v_;
|
||||
|
||||
_v_ = *a;
|
||||
powerpc_iomb();
|
||||
return _v_;
|
||||
}
|
||||
|
||||
static __inline u_int16_t
|
||||
__inwrb(volatile u_int16_t *a)
|
||||
{
|
||||
u_int16_t _v_;
|
||||
|
||||
__asm__ volatile("lhbrx %0, 0, %1" : "=r"(_v_) : "r"(a));
|
||||
powerpc_iomb();
|
||||
return _v_;
|
||||
}
|
||||
|
||||
static __inline u_int32_t
|
||||
__inlrb(volatile u_int32_t *a)
|
||||
{
|
||||
u_int32_t _v_;
|
||||
|
||||
__asm__ volatile("lwbrx %0, 0, %1" : "=r"(_v_) : "r"(a));
|
||||
powerpc_iomb();
|
||||
return _v_;
|
||||
}
|
||||
|
||||
#define outb(a,v) (__outb((volatile u_int8_t *)(a), v))
|
||||
#define out8(a,v) outb(a,v)
|
||||
#define outw(a,v) (__outw((volatile u_int16_t *)(a), v))
|
||||
#define out16(a,v) outw(a,v)
|
||||
#define outl(a,v) (__outl((volatile u_int32_t *)(a), v))
|
||||
#define out32(a,v) outl(a,v)
|
||||
#define outll(a,v) (__outll((volatile u_int64_t *)(a), v))
|
||||
#define out64(a,v) outll(a,v)
|
||||
#define inb(a) (__inb((volatile u_int8_t *)(a)))
|
||||
#define in8(a) inb(a)
|
||||
#define inw(a) (__inw((volatile u_int16_t *)(a)))
|
||||
#define in16(a) inw(a)
|
||||
#define inl(a) (__inl((volatile u_int32_t *)(a)))
|
||||
#define in32(a) inl(a)
|
||||
#define inll(a) (__inll((volatile u_int64_t *)(a)))
|
||||
#define in64(a) inll(a)
|
||||
|
||||
#define out8rb(a,v) outb(a,v)
|
||||
#define outwrb(a,v) (__outwrb((volatile u_int16_t *)(a), v))
|
||||
#define out16rb(a,v) outwrb(a,v)
|
||||
#define outlrb(a,v) (__outlrb((volatile u_int32_t *)(a), v))
|
||||
#define out32rb(a,v) outlrb(a,v)
|
||||
#define in8rb(a) inb(a)
|
||||
#define inwrb(a) (__inwrb((volatile u_int16_t *)(a)))
|
||||
#define in16rb(a) inwrb(a)
|
||||
#define inlrb(a) (__inlrb((volatile u_int32_t *)(a)))
|
||||
#define in32rb(a) inlrb(a)
|
||||
|
||||
|
||||
static __inline void
|
||||
__outsb(volatile u_int8_t *a, const u_int8_t *s, size_t c)
|
||||
{
|
||||
while (c--)
|
||||
*a = *s++;
|
||||
powerpc_iomb();
|
||||
}
|
||||
|
||||
static __inline void
|
||||
__outsw(volatile u_int16_t *a, const u_int16_t *s, size_t c)
|
||||
{
|
||||
while (c--)
|
||||
*a = *s++;
|
||||
powerpc_iomb();
|
||||
}
|
||||
|
||||
static __inline void
|
||||
__outsl(volatile u_int32_t *a, const u_int32_t *s, size_t c)
|
||||
{
|
||||
while (c--)
|
||||
*a = *s++;
|
||||
powerpc_iomb();
|
||||
}
|
||||
|
||||
static __inline void
|
||||
__outsll(volatile u_int64_t *a, const u_int64_t *s, size_t c)
|
||||
{
|
||||
while (c--)
|
||||
*a = *s++;
|
||||
powerpc_iomb();
|
||||
}
|
||||
|
||||
static __inline void
|
||||
__outswrb(volatile u_int16_t *a, const u_int16_t *s, size_t c)
|
||||
{
|
||||
while (c--)
|
||||
__asm__ volatile("sthbrx %0, 0, %1" :: "r"(*s++), "r"(a));
|
||||
powerpc_iomb();
|
||||
}
|
||||
|
||||
static __inline void
|
||||
__outslrb(volatile u_int32_t *a, const u_int32_t *s, size_t c)
|
||||
{
|
||||
while (c--)
|
||||
__asm__ volatile("stwbrx %0, 0, %1" :: "r"(*s++), "r"(a));
|
||||
powerpc_iomb();
|
||||
}
|
||||
|
||||
static __inline void
|
||||
__insb(volatile u_int8_t *a, u_int8_t *d, size_t c)
|
||||
{
|
||||
while (c--)
|
||||
*d++ = *a;
|
||||
powerpc_iomb();
|
||||
}
|
||||
|
||||
static __inline void
|
||||
__insw(volatile u_int16_t *a, u_int16_t *d, size_t c)
|
||||
{
|
||||
while (c--)
|
||||
*d++ = *a;
|
||||
powerpc_iomb();
|
||||
}
|
||||
|
||||
static __inline void
|
||||
__insl(volatile u_int32_t *a, u_int32_t *d, size_t c)
|
||||
{
|
||||
while (c--)
|
||||
*d++ = *a;
|
||||
powerpc_iomb();
|
||||
}
|
||||
|
||||
static __inline void
|
||||
__insll(volatile u_int64_t *a, u_int64_t *d, size_t c)
|
||||
{
|
||||
while (c--)
|
||||
*d++ = *a;
|
||||
powerpc_iomb();
|
||||
}
|
||||
|
||||
static __inline void
|
||||
__inswrb(volatile u_int16_t *a, u_int16_t *d, size_t c)
|
||||
{
|
||||
while (c--)
|
||||
__asm__ volatile("lhbrx %0, 0, %1" : "=r"(*d++) : "r"(a));
|
||||
powerpc_iomb();
|
||||
}
|
||||
|
||||
static __inline void
|
||||
__inslrb(volatile u_int32_t *a, u_int32_t *d, size_t c)
|
||||
{
|
||||
while (c--)
|
||||
__asm__ volatile("lwbrx %0, 0, %1" : "=r"(*d++) : "r"(a));
|
||||
powerpc_iomb();
|
||||
}
|
||||
|
||||
#define outsb(a,s,c) (__outsb((volatile u_int8_t *)(a), s, c))
|
||||
#define outs8(a,s,c) outsb(a,s,c)
|
||||
#define outsw(a,s,c) (__outsw((volatile u_int16_t *)(a), s, c))
|
||||
#define outs16(a,s,c) outsw(a,s,c)
|
||||
#define outsl(a,s,c) (__outsl((volatile u_int32_t *)(a), s, c))
|
||||
#define outs32(a,s,c) outsl(a,s,c)
|
||||
#define outsll(a,s,c) (__outsll((volatile u_int64_t *)(a), s, c))
|
||||
#define outs64(a,s,c) outsll(a,s,c)
|
||||
#define insb(a,d,c) (__insb((volatile u_int8_t *)(a), d, c))
|
||||
#define ins8(a,d,c) insb(a,d,c)
|
||||
#define insw(a,d,c) (__insw((volatile u_int16_t *)(a), d, c))
|
||||
#define ins16(a,d,c) insw(a,d,c)
|
||||
#define insl(a,d,c) (__insl((volatile u_int32_t *)(a), d, c))
|
||||
#define ins32(a,d,c) insl(a,d,c)
|
||||
#define insll(a,d,c) (__insll((volatile u_int64_t *)(a), d, c))
|
||||
#define ins64(a,d,c) insll(a,d,c)
|
||||
|
||||
#define outs8rb(a,s,c) outsb(a,s,c)
|
||||
#define outswrb(a,s,c) (__outswrb((volatile u_int16_t *)(a), s, c))
|
||||
#define outs16rb(a,s,c) outswrb(a,s,c)
|
||||
#define outslrb(a,s,c) (__outslrb((volatile u_int32_t *)(a), s, c))
|
||||
#define outs32rb(a,s,c) outslrb(a,s,c)
|
||||
#define ins8rb(a,d,c) insb(a,d,c)
|
||||
#define inswrb(a,d,c) (__inswrb((volatile u_int16_t *)(a), d, c))
|
||||
#define ins16rb(a,d,c) inswrb(a,d,c)
|
||||
#define inslrb(a,d,c) (__inslrb((volatile u_int32_t *)(a), d, c))
|
||||
#define ins32rb(a,d,c) inslrb(a,d,c)
|
||||
|
||||
#endif /*_MACHINE_PIO_H_*/
|
91
freebsd/sys/powerpc/include/machine/platformvar.h
Normal file
91
freebsd/sys/powerpc/include/machine/platformvar.h
Normal file
@ -0,0 +1,91 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (c) 2005 Peter Grehan
|
||||
* 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 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_PLATFORMVAR_H_
|
||||
#define _MACHINE_PLATFORMVAR_H_
|
||||
|
||||
/*
|
||||
* A PowerPC platform implementation is declared with a kernel object and
|
||||
* an associated method table, similar to a device driver.
|
||||
*
|
||||
* e.g.
|
||||
*
|
||||
* static platform_method_t chrp_methods[] = {
|
||||
* PLATFORMMETHOD(platform_probe, chrp_probe),
|
||||
* PLATFORMMETHOD(platform_mem_regions, ofw_mem_regions),
|
||||
* ...
|
||||
* PLATFORMMETHOD(platform_smp_first_cpu, chrp_smp_first_cpu),
|
||||
* { 0, 0 }
|
||||
* };
|
||||
*
|
||||
* static platform_def_t chrp_platform = {
|
||||
* "chrp",
|
||||
* chrp_methods,
|
||||
* sizeof(chrp_platform_softc), // or 0 if no softc
|
||||
* };
|
||||
*
|
||||
* PLATFORM_DEF(chrp_platform);
|
||||
*/
|
||||
|
||||
#include <sys/kobj.h>
|
||||
|
||||
struct platform_kobj {
|
||||
/*
|
||||
* A platform instance is a kernel object
|
||||
*/
|
||||
KOBJ_FIELDS;
|
||||
|
||||
/*
|
||||
* Utility elements that an instance may use
|
||||
*/
|
||||
struct mtx platform_mtx; /* available for instance use */
|
||||
void *platform_iptr; /* instance data pointer */
|
||||
|
||||
/*
|
||||
* Opaque data that can be overlaid with an instance-private
|
||||
* structure. Platform code can test that this is large enough at
|
||||
* compile time with a sizeof() test againt it's softc. There
|
||||
* is also a run-time test when the platform kernel object is
|
||||
* registered.
|
||||
*/
|
||||
#define PLATFORM_OPAQUESZ 64
|
||||
u_int platform_opaque[PLATFORM_OPAQUESZ];
|
||||
};
|
||||
|
||||
typedef struct platform_kobj *platform_t;
|
||||
typedef struct kobj_class platform_def_t;
|
||||
#define platform_method_t kobj_method_t
|
||||
|
||||
#define PLATFORMMETHOD KOBJMETHOD
|
||||
#define PLATFORMMETHOD_END KOBJMETHOD_END
|
||||
|
||||
#define PLATFORM_DEF(name) DATA_SET(platform_set, name)
|
||||
|
||||
#endif /* _MACHINE_PLATFORMVAR_H_ */
|
361
freebsd/sys/powerpc/mpc85xx/mpc85xx.c
Normal file
361
freebsd/sys/powerpc/mpc85xx/mpc85xx.c
Normal file
@ -0,0 +1,361 @@
|
||||
#include <machine/rtems-bsd-kernel-space.h>
|
||||
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (C) 2008 Semihalf, Rafal Jaworowski
|
||||
* 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 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 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 <rtems/bsd/local/opt_platform.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/reboot.h>
|
||||
#include <sys/rman.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_param.h>
|
||||
#include <vm/pmap.h>
|
||||
|
||||
#include <machine/cpu.h>
|
||||
#include <machine/cpufunc.h>
|
||||
#ifndef __rtems__
|
||||
#include <machine/machdep.h>
|
||||
#endif /* __rtems__ */
|
||||
#include <machine/pio.h>
|
||||
#include <machine/spr.h>
|
||||
|
||||
#include <dev/fdt/fdt_common.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>
|
||||
|
||||
|
||||
/*
|
||||
* MPC85xx system specific routines
|
||||
*/
|
||||
|
||||
uint32_t
|
||||
ccsr_read4(uintptr_t addr)
|
||||
{
|
||||
volatile uint32_t *ptr = (void *)addr;
|
||||
|
||||
return (*ptr);
|
||||
}
|
||||
|
||||
void
|
||||
ccsr_write4(uintptr_t addr, uint32_t val)
|
||||
{
|
||||
volatile uint32_t *ptr = (void *)addr;
|
||||
|
||||
*ptr = val;
|
||||
powerpc_iomb();
|
||||
}
|
||||
|
||||
int
|
||||
law_getmax(void)
|
||||
{
|
||||
uint32_t ver;
|
||||
int law_max;
|
||||
|
||||
ver = SVR_VER(mfspr(SPR_SVR));
|
||||
switch (ver) {
|
||||
case SVR_MPC8555:
|
||||
case SVR_MPC8555E:
|
||||
law_max = 8;
|
||||
break;
|
||||
case SVR_MPC8533:
|
||||
case SVR_MPC8533E:
|
||||
case SVR_MPC8548:
|
||||
case SVR_MPC8548E:
|
||||
law_max = 10;
|
||||
break;
|
||||
case SVR_P5020:
|
||||
case SVR_P5020E:
|
||||
case SVR_P5021:
|
||||
case SVR_P5021E:
|
||||
case SVR_P5040:
|
||||
case SVR_P5040E:
|
||||
law_max = 32;
|
||||
break;
|
||||
default:
|
||||
law_max = 8;
|
||||
}
|
||||
|
||||
return (law_max);
|
||||
}
|
||||
|
||||
static inline void
|
||||
law_write(uint32_t n, uint64_t bar, uint32_t sr)
|
||||
{
|
||||
|
||||
if (mpc85xx_is_qoriq()) {
|
||||
ccsr_write4(OCP85XX_LAWBARH(n), bar >> 32);
|
||||
ccsr_write4(OCP85XX_LAWBARL(n), bar);
|
||||
ccsr_write4(OCP85XX_LAWSR_QORIQ(n), sr);
|
||||
ccsr_read4(OCP85XX_LAWSR_QORIQ(n));
|
||||
} else {
|
||||
ccsr_write4(OCP85XX_LAWBAR(n), bar >> 12);
|
||||
ccsr_write4(OCP85XX_LAWSR_85XX(n), sr);
|
||||
ccsr_read4(OCP85XX_LAWSR_85XX(n));
|
||||
}
|
||||
|
||||
/*
|
||||
* The last write to LAWAR should be followed by a read
|
||||
* of LAWAR before any device try to use any of windows.
|
||||
* What more the read of LAWAR should be followed by isync
|
||||
* instruction.
|
||||
*/
|
||||
|
||||
isync();
|
||||
}
|
||||
|
||||
static inline void
|
||||
law_read(uint32_t n, uint64_t *bar, uint32_t *sr)
|
||||
{
|
||||
|
||||
if (mpc85xx_is_qoriq()) {
|
||||
*bar = (uint64_t)ccsr_read4(OCP85XX_LAWBARH(n)) << 32 |
|
||||
ccsr_read4(OCP85XX_LAWBARL(n));
|
||||
*sr = ccsr_read4(OCP85XX_LAWSR_QORIQ(n));
|
||||
} else {
|
||||
*bar = (uint64_t)ccsr_read4(OCP85XX_LAWBAR(n)) << 12;
|
||||
*sr = ccsr_read4(OCP85XX_LAWSR_85XX(n));
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
law_find_free(void)
|
||||
{
|
||||
uint32_t i,sr;
|
||||
uint64_t bar;
|
||||
int law_max;
|
||||
|
||||
law_max = law_getmax();
|
||||
/* Find free LAW */
|
||||
for (i = 0; i < law_max; i++) {
|
||||
law_read(i, &bar, &sr);
|
||||
if ((sr & 0x80000000) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return (i);
|
||||
}
|
||||
|
||||
#define _LAW_SR(trgt,size) (0x80000000 | (trgt << 20) | \
|
||||
(flsl(size + (size - 1)) - 2))
|
||||
|
||||
int
|
||||
law_enable(int trgt, uint64_t bar, uint32_t size)
|
||||
{
|
||||
uint64_t bar_tmp;
|
||||
uint32_t sr, sr_tmp;
|
||||
int i, law_max;
|
||||
|
||||
if (size == 0)
|
||||
return (0);
|
||||
|
||||
law_max = law_getmax();
|
||||
sr = _LAW_SR(trgt, size);
|
||||
|
||||
/* Bail if already programmed. */
|
||||
for (i = 0; i < law_max; i++) {
|
||||
law_read(i, &bar_tmp, &sr_tmp);
|
||||
if (sr == sr_tmp && bar == bar_tmp)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Find an unused access window. */
|
||||
i = law_find_free();
|
||||
|
||||
if (i == law_max)
|
||||
return (ENOSPC);
|
||||
|
||||
law_write(i, bar, sr);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
law_disable(int trgt, uint64_t bar, uint32_t size)
|
||||
{
|
||||
uint64_t bar_tmp;
|
||||
uint32_t sr, sr_tmp;
|
||||
int i, law_max;
|
||||
|
||||
law_max = law_getmax();
|
||||
sr = _LAW_SR(trgt, size);
|
||||
|
||||
/* Find and disable requested LAW. */
|
||||
for (i = 0; i < law_max; i++) {
|
||||
law_read(i, &bar_tmp, &sr_tmp);
|
||||
if (sr == sr_tmp && bar == bar_tmp) {
|
||||
law_write(i, 0, 0);
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
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 0x0000:
|
||||
case 0x8000:
|
||||
trgt = 0;
|
||||
break;
|
||||
case 0x1000:
|
||||
case 0x9000:
|
||||
trgt = 1;
|
||||
break;
|
||||
case 0x2000:
|
||||
case 0xa000:
|
||||
if (ver == SVR_MPC8548E || ver == SVR_MPC8548)
|
||||
trgt = 3;
|
||||
else
|
||||
trgt = 2;
|
||||
break;
|
||||
case 0x3000:
|
||||
case 0xb000:
|
||||
if (ver == SVR_MPC8548E || ver == SVR_MPC8548)
|
||||
rv = EINVAL;
|
||||
else
|
||||
trgt = 3;
|
||||
break;
|
||||
default:
|
||||
rv = ENXIO;
|
||||
}
|
||||
if (rv == 0) {
|
||||
*trgt_mem = trgt;
|
||||
*trgt_io = trgt;
|
||||
}
|
||||
return (rv);
|
||||
}
|
||||
|
||||
static void
|
||||
l3cache_inval(void)
|
||||
{
|
||||
|
||||
/* Flash invalidate the CPC and clear all the locks */
|
||||
ccsr_write4(OCP85XX_CPC_CSR0, OCP85XX_CPC_CSR0_FI |
|
||||
OCP85XX_CPC_CSR0_LFC);
|
||||
while (ccsr_read4(OCP85XX_CPC_CSR0) & (OCP85XX_CPC_CSR0_FI |
|
||||
OCP85XX_CPC_CSR0_LFC))
|
||||
;
|
||||
}
|
||||
|
||||
static void
|
||||
l3cache_enable(void)
|
||||
{
|
||||
|
||||
ccsr_write4(OCP85XX_CPC_CSR0, OCP85XX_CPC_CSR0_CE |
|
||||
OCP85XX_CPC_CSR0_PE);
|
||||
/* Read back to sync write */
|
||||
ccsr_read4(OCP85XX_CPC_CSR0);
|
||||
}
|
||||
|
||||
void
|
||||
mpc85xx_enable_l3_cache(void)
|
||||
{
|
||||
uint32_t csr, size, ver;
|
||||
|
||||
/* Enable L3 CoreNet Platform Cache (CPC) */
|
||||
ver = SVR_VER(mfspr(SPR_SVR));
|
||||
if (ver == SVR_P2041 || ver == SVR_P2041E || ver == SVR_P3041 ||
|
||||
ver == SVR_P3041E || ver == SVR_P5020 || ver == SVR_P5020E) {
|
||||
csr = ccsr_read4(OCP85XX_CPC_CSR0);
|
||||
if ((csr & OCP85XX_CPC_CSR0_CE) == 0) {
|
||||
l3cache_inval();
|
||||
l3cache_enable();
|
||||
}
|
||||
|
||||
csr = ccsr_read4(OCP85XX_CPC_CSR0);
|
||||
if ((boothowto & RB_VERBOSE) != 0 ||
|
||||
(csr & OCP85XX_CPC_CSR0_CE) == 0) {
|
||||
size = OCP85XX_CPC_CFG0_SZ_K(ccsr_read4(OCP85XX_CPC_CFG0));
|
||||
printf("L3 Corenet Platform Cache: %d KB %sabled\n",
|
||||
size, (csr & OCP85XX_CPC_CSR0_CE) == 0 ?
|
||||
"dis" : "en");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
mpc85xx_is_qoriq(void)
|
||||
{
|
||||
uint16_t pvr = mfpvr() >> 16;
|
||||
|
||||
/* QorIQ register set is only in e500mc and derivative core based SoCs. */
|
||||
if (pvr == FSL_E500mc || pvr == FSL_E5500 || pvr == FSL_E6500)
|
||||
return (1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
mpc85xx_get_platform_clock(void)
|
||||
{
|
||||
phandle_t soc;
|
||||
static uint32_t freq;
|
||||
|
||||
if (freq != 0)
|
||||
return (freq);
|
||||
|
||||
soc = OF_finddevice("/soc");
|
||||
|
||||
/* freq isn't modified on error. */
|
||||
OF_getencprop(soc, "bus-frequency", (void *)&freq, sizeof(freq));
|
||||
|
||||
return (freq);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
mpc85xx_get_system_clock(void)
|
||||
{
|
||||
uint32_t freq;
|
||||
|
||||
freq = mpc85xx_get_platform_clock();
|
||||
|
||||
return (freq / 2);
|
||||
}
|
177
freebsd/sys/powerpc/mpc85xx/mpc85xx.h
Normal file
177
freebsd/sys/powerpc/mpc85xx/mpc85xx.h
Normal file
@ -0,0 +1,177 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* 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
|
||||
* 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 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 _MPC85XX_H_
|
||||
#define _MPC85XX_H_
|
||||
|
||||
#include <machine/platformvar.h>
|
||||
|
||||
/*
|
||||
* Configuration control and status registers
|
||||
*/
|
||||
extern vm_offset_t ccsrbar_va;
|
||||
extern vm_paddr_t ccsrbar_pa;
|
||||
extern vm_size_t ccsrbar_size;
|
||||
#define CCSRBAR_VA ccsrbar_va
|
||||
#define OCP85XX_CCSRBAR (CCSRBAR_VA + 0x0)
|
||||
#define OCP85XX_BPTR (CCSRBAR_VA + 0x20)
|
||||
|
||||
#define OCP85XX_BSTRH (CCSRBAR_VA + 0x20)
|
||||
#define OCP85XX_BSTRL (CCSRBAR_VA + 0x24)
|
||||
#define OCP85XX_BSTAR (CCSRBAR_VA + 0x28)
|
||||
|
||||
#define OCP85XX_COREDISR (CCSRBAR_VA + 0xE0094)
|
||||
#define OCP85XX_BRR (CCSRBAR_VA + 0xE00E4)
|
||||
|
||||
/*
|
||||
* Run Control and Power Management registers
|
||||
*/
|
||||
#define CCSR_CTBENR (CCSRBAR_VA + 0xE2084)
|
||||
#define CCSR_CTBCKSELR (CCSRBAR_VA + 0xE208C)
|
||||
#define CCSR_CTBCHLTCR (CCSRBAR_VA + 0xE2094)
|
||||
|
||||
/*
|
||||
* DDR Memory controller.
|
||||
*/
|
||||
#define OCP85XX_DDR1_CS0_CONFIG (CCSRBAR_VA + 0x8080)
|
||||
|
||||
/*
|
||||
* E500 Coherency Module registers
|
||||
*/
|
||||
#define OCP85XX_EEBPCR (CCSRBAR_VA + 0x1010)
|
||||
|
||||
/*
|
||||
* Local access registers
|
||||
*/
|
||||
/* Write order: OCP_LAWBARH -> OCP_LAWBARL -> OCP_LAWSR */
|
||||
#define OCP85XX_LAWBARH(n) (CCSRBAR_VA + 0xc00 + 0x10 * (n))
|
||||
#define OCP85XX_LAWBARL(n) (CCSRBAR_VA + 0xc04 + 0x10 * (n))
|
||||
#define OCP85XX_LAWSR_QORIQ(n) (CCSRBAR_VA + 0xc08 + 0x10 * (n))
|
||||
#define OCP85XX_LAWBAR(n) (CCSRBAR_VA + 0xc08 + 0x10 * (n))
|
||||
#define OCP85XX_LAWSR_85XX(n) (CCSRBAR_VA + 0xc10 + 0x10 * (n))
|
||||
#define OCP85XX_LAWSR(n) (mpc85xx_is_qoriq() ? OCP85XX_LAWSR_QORIQ(n) : \
|
||||
OCP85XX_LAWSR_85XX(n))
|
||||
|
||||
/* Attribute register */
|
||||
#define OCP85XX_ENA_MASK 0x80000000
|
||||
#define OCP85XX_DIS_MASK 0x7fffffff
|
||||
|
||||
#define OCP85XX_TGTIF_LBC_QORIQ 0x1f
|
||||
#define OCP85XX_TGTIF_RAM_INTL_QORIQ 0x14
|
||||
#define OCP85XX_TGTIF_RAM1_QORIQ 0x10
|
||||
#define OCP85XX_TGTIF_RAM2_QORIQ 0x11
|
||||
#define OCP85XX_TGTIF_BMAN 0x18
|
||||
#define OCP85XX_TGTIF_DCSR 0x1D
|
||||
#define OCP85XX_TGTIF_QMAN 0x3C
|
||||
#define OCP85XX_TRGT_SHIFT_QORIQ 20
|
||||
|
||||
#define OCP85XX_TGTIF_LBC_85XX 0x04
|
||||
#define OCP85XX_TGTIF_RAM_INTL_85XX 0x0b
|
||||
#define OCP85XX_TGTIF_RIO_85XX 0x0c
|
||||
#define OCP85XX_TGTIF_RAM1_85XX 0x0f
|
||||
#define OCP85XX_TGTIF_RAM2_85XX 0x16
|
||||
|
||||
#define OCP85XX_TGTIF_LBC \
|
||||
(mpc85xx_is_qoriq() ? OCP85XX_TGTIF_LBC_QORIQ : OCP85XX_TGTIF_LBC_85XX)
|
||||
#define OCP85XX_TGTIF_RAM_INTL \
|
||||
(mpc85xx_is_qoriq() ? OCP85XX_TGTIF_RAM_INTL_QORIQ : OCP85XX_TGTIF_RAM_INTL_85XX)
|
||||
#define OCP85XX_TGTIF_RIO \
|
||||
(mpc85xx_is_qoriq() ? OCP85XX_TGTIF_RIO_QORIQ : OCP85XX_TGTIF_RIO_85XX)
|
||||
#define OCP85XX_TGTIF_RAM1 \
|
||||
(mpc85xx_is_qoriq() ? OCP85XX_TGTIF_RAM1_QORIQ : OCP85XX_TGTIF_RAM1_85XX)
|
||||
#define OCP85XX_TGTIF_RAM2 \
|
||||
(mpc85xx_is_qoriq() ? OCP85XX_TGTIF_RAM2_QORIQ : OCP85XX_TGTIF_RAM2_85XX)
|
||||
|
||||
/*
|
||||
* L2 cache registers
|
||||
*/
|
||||
#define OCP85XX_L2CTL (CCSRBAR_VA + 0x20000)
|
||||
|
||||
/*
|
||||
* L3 CoreNet platform cache (CPC) registers
|
||||
*/
|
||||
#define OCP85XX_CPC_CSR0 (CCSRBAR_VA + 0x10000)
|
||||
#define OCP85XX_CPC_CSR0_CE 0x80000000
|
||||
#define OCP85XX_CPC_CSR0_PE 0x40000000
|
||||
#define OCP85XX_CPC_CSR0_FI 0x00200000
|
||||
#define OCP85XX_CPC_CSR0_WT 0x00080000
|
||||
#define OCP85XX_CPC_CSR0_FL 0x00000800
|
||||
#define OCP85XX_CPC_CSR0_LFC 0x00000400
|
||||
#define OCP85XX_CPC_CFG0 (CCSRBAR_VA + 0x10008)
|
||||
#define OCP85XX_CPC_CFG_SZ_MASK 0x00003fff
|
||||
#define OCP85XX_CPC_CFG0_SZ_K(x) (((x) & OCP85XX_CPC_CFG_SZ_MASK) << 6)
|
||||
|
||||
/*
|
||||
* 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)
|
||||
|
||||
/*
|
||||
* Status Registers.
|
||||
*/
|
||||
#define OCP85XX_RSTCR (CCSRBAR_VA + 0xe00b0)
|
||||
|
||||
#define OCP85XX_CLKDVDR (CCSRBAR_VA + 0xe0800)
|
||||
#define OCP85XX_CLKDVDR_PXCKEN 0x80000000
|
||||
#define OCP85XX_CLKDVDR_SSICKEN 0x20000000
|
||||
#define OCP85XX_CLKDVDR_PXCKINV 0x10000000
|
||||
#define OCP85XX_CLKDVDR_PXCLK_MASK 0x00FF0000
|
||||
#define OCP85XX_CLKDVDR_SSICLK_MASK 0x000000FF
|
||||
|
||||
/*
|
||||
* Run Control/Power Management Registers.
|
||||
*/
|
||||
#define OCP85XX_RCPM_CDOZSR (CCSRBAR_VA + 0xe2004)
|
||||
#define OCP85XX_RCPM_CDOZCR (CCSRBAR_VA + 0xe200c)
|
||||
|
||||
/*
|
||||
* Prototypes.
|
||||
*/
|
||||
uint32_t ccsr_read4(uintptr_t addr);
|
||||
void ccsr_write4(uintptr_t addr, uint32_t val);
|
||||
int law_enable(int trgt, uint64_t bar, uint32_t size);
|
||||
int law_disable(int trgt, uint64_t bar, uint32_t size);
|
||||
int law_getmax(void);
|
||||
int law_pci_target(struct resource *, int *, int *);
|
||||
|
||||
DECLARE_CLASS(mpc85xx_platform);
|
||||
int mpc85xx_attach(platform_t);
|
||||
|
||||
void mpc85xx_enable_l3_cache(void);
|
||||
int mpc85xx_is_qoriq(void);
|
||||
uint32_t mpc85xx_get_platform_clock(void);
|
||||
uint32_t mpc85xx_get_system_clock(void);
|
||||
|
||||
#endif /* _MPC85XX_H_ */
|
959
freebsd/sys/powerpc/mpc85xx/pci_mpc85xx.c
Normal file
959
freebsd/sys/powerpc/mpc85xx/pci_mpc85xx.c
Normal file
@ -0,0 +1,959 @@
|
||||
#include <machine/rtems-bsd-kernel-space.h>
|
||||
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Copyright 2006-2007 by Juniper Networks.
|
||||
* Copyright 2008 Semihalf.
|
||||
* Copyright 2010 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:
|
||||
* 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.
|
||||
*
|
||||
* From: FreeBSD: src/sys/powerpc/mpc85xx/pci_ocp.c,v 1.9 2010/03/23 23:46:28 marcel
|
||||
*/
|
||||
|
||||
#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/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/rman.h>
|
||||
#include <sys/endian.h>
|
||||
#include <sys/vmem.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/pmap.h>
|
||||
|
||||
#include <dev/ofw/ofw_pci.h>
|
||||
#include <dev/ofw/ofw_bus.h>
|
||||
#include <dev/ofw/ofw_bus_subr.h>
|
||||
#include <dev/ofw/ofwpci.h>
|
||||
#include <dev/pci/pcivar.h>
|
||||
#include <dev/pci/pcireg.h>
|
||||
#include <dev/pci/pcib_private.h>
|
||||
|
||||
#include <rtems/bsd/local/ofw_bus_if.h>
|
||||
#include <rtems/bsd/local/pcib_if.h>
|
||||
#include <rtems/bsd/local/pic_if.h>
|
||||
|
||||
#include <machine/resource.h>
|
||||
#include <machine/bus.h>
|
||||
#include <machine/intr_machdep.h>
|
||||
|
||||
#include <powerpc/mpc85xx/mpc85xx.h>
|
||||
|
||||
#define REG_CFG_ADDR 0x0000
|
||||
#define CONFIG_ACCESS_ENABLE 0x80000000
|
||||
|
||||
#define REG_CFG_DATA 0x0004
|
||||
#define REG_INT_ACK 0x0008
|
||||
|
||||
#define REG_PEX_IP_BLK_REV1 0x0bf8
|
||||
#define IP_MJ_M 0x0000ff00
|
||||
#define IP_MJ_S 8
|
||||
#define IP_MN_M 0x000000ff
|
||||
#define IP_MN_S 0
|
||||
|
||||
#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 PIWAR_EN 0x80000000
|
||||
#define PIWAR_PF 0x40000000
|
||||
#define PIWAR_TRGT_M 0x00f00000
|
||||
#define PIWAR_TRGT_S 20
|
||||
#define PIWAR_TRGT_CCSR 0xe
|
||||
#define PIWAR_TRGT_LOCAL 0xf
|
||||
|
||||
#define REG_PEX_MES_DR 0x0020
|
||||
#define REG_PEX_MES_IER 0x0028
|
||||
#define REG_PEX_ERR_DR 0x0e00
|
||||
#define REG_PEX_ERR_EN 0x0e08
|
||||
|
||||
#define REG_PEX_ERR_DR 0x0e00
|
||||
#define REG_PEX_ERR_DR_ME 0x80000000
|
||||
#define REG_PEX_ERR_DR_PCT 0x800000
|
||||
#define REG_PEX_ERR_DR_PAT 0x400000
|
||||
#define REG_PEX_ERR_DR_PCAC 0x200000
|
||||
#define REG_PEX_ERR_DR_PNM 0x100000
|
||||
#define REG_PEX_ERR_DR_CDNSC 0x80000
|
||||
#define REG_PEX_ERR_DR_CRSNC 0x40000
|
||||
#define REG_PEX_ERR_DR_ICCA 0x20000
|
||||
#define REG_PEX_ERR_DR_IACA 0x10000
|
||||
#define REG_PEX_ERR_DR_CRST 0x8000
|
||||
#define REG_PEX_ERR_DR_MIS 0x4000
|
||||
#define REG_PEX_ERR_DR_IOIS 0x2000
|
||||
#define REG_PEX_ERR_DR_CIS 0x1000
|
||||
#define REG_PEX_ERR_DR_CIEP 0x800
|
||||
#define REG_PEX_ERR_DR_IOIEP 0x400
|
||||
#define REG_PEX_ERR_DR_OAC 0x200
|
||||
#define REG_PEX_ERR_DR_IOIA 0x100
|
||||
#define REG_PEX_ERR_DR_IMBA 0x80
|
||||
#define REG_PEX_ERR_DR_IIOBA 0x40
|
||||
#define REG_PEX_ERR_DR_LDDE 0x20
|
||||
#define REG_PEX_ERR_EN 0x0e08
|
||||
|
||||
#define PCIR_LTSSM 0x404
|
||||
#define LTSSM_STAT_L0 0x16
|
||||
|
||||
#define DEVFN(b, s, f) ((b << 16) | (s << 8) | f)
|
||||
|
||||
#define FSL_NUM_MSIS 256 /* 8 registers of 32 bits (8 hardware IRQs) */
|
||||
|
||||
struct fsl_pcib_softc {
|
||||
struct ofw_pci_softc pci_sc;
|
||||
device_t sc_dev;
|
||||
struct mtx sc_cfg_mtx;
|
||||
int sc_ip_maj;
|
||||
int sc_ip_min;
|
||||
|
||||
int sc_iomem_target;
|
||||
bus_addr_t sc_iomem_start, sc_iomem_end;
|
||||
int sc_ioport_target;
|
||||
bus_addr_t sc_ioport_start, sc_ioport_end;
|
||||
|
||||
struct resource *sc_res;
|
||||
bus_space_handle_t sc_bsh;
|
||||
bus_space_tag_t sc_bst;
|
||||
int sc_rid;
|
||||
|
||||
struct resource *sc_irq_res;
|
||||
void *sc_ih;
|
||||
|
||||
int sc_busnr;
|
||||
int sc_pcie;
|
||||
uint8_t sc_pcie_capreg; /* PCI-E Capability Reg Set */
|
||||
};
|
||||
|
||||
struct fsl_pcib_err_dr {
|
||||
const char *msg;
|
||||
uint32_t err_dr_mask;
|
||||
};
|
||||
|
||||
struct fsl_msi_map {
|
||||
SLIST_ENTRY(fsl_msi_map) slist;
|
||||
uint32_t irq_base;
|
||||
bus_addr_t target;
|
||||
};
|
||||
|
||||
SLIST_HEAD(msi_head, fsl_msi_map) fsl_msis = SLIST_HEAD_INITIALIZER(msi_head);
|
||||
|
||||
static const struct fsl_pcib_err_dr pci_err[] = {
|
||||
{"ME", REG_PEX_ERR_DR_ME},
|
||||
{"PCT", REG_PEX_ERR_DR_PCT},
|
||||
{"PAT", REG_PEX_ERR_DR_PAT},
|
||||
{"PCAC", REG_PEX_ERR_DR_PCAC},
|
||||
{"PNM", REG_PEX_ERR_DR_PNM},
|
||||
{"CDNSC", REG_PEX_ERR_DR_CDNSC},
|
||||
{"CRSNC", REG_PEX_ERR_DR_CRSNC},
|
||||
{"ICCA", REG_PEX_ERR_DR_ICCA},
|
||||
{"IACA", REG_PEX_ERR_DR_IACA},
|
||||
{"CRST", REG_PEX_ERR_DR_CRST},
|
||||
{"MIS", REG_PEX_ERR_DR_MIS},
|
||||
{"IOIS", REG_PEX_ERR_DR_IOIS},
|
||||
{"CIS", REG_PEX_ERR_DR_CIS},
|
||||
{"CIEP", REG_PEX_ERR_DR_CIEP},
|
||||
{"IOIEP", REG_PEX_ERR_DR_IOIEP},
|
||||
{"OAC", REG_PEX_ERR_DR_OAC},
|
||||
{"IOIA", REG_PEX_ERR_DR_IOIA},
|
||||
{"IMBA", REG_PEX_ERR_DR_IMBA},
|
||||
{"IIOBA", REG_PEX_ERR_DR_IIOBA},
|
||||
{"LDDE", REG_PEX_ERR_DR_LDDE}
|
||||
};
|
||||
|
||||
/* Local forward declerations. */
|
||||
static uint32_t fsl_pcib_cfgread(struct fsl_pcib_softc *, u_int, u_int, u_int,
|
||||
u_int, int);
|
||||
static void fsl_pcib_cfgwrite(struct fsl_pcib_softc *, u_int, u_int, u_int,
|
||||
u_int, uint32_t, int);
|
||||
static int fsl_pcib_decode_win(phandle_t, struct fsl_pcib_softc *);
|
||||
static void fsl_pcib_err_init(device_t);
|
||||
static void fsl_pcib_inbound(struct fsl_pcib_softc *, int, int, uint64_t,
|
||||
uint64_t, uint64_t);
|
||||
static void fsl_pcib_outbound(struct fsl_pcib_softc *, int, int, uint64_t,
|
||||
uint64_t, uint64_t);
|
||||
|
||||
/* Forward declerations. */
|
||||
static int fsl_pcib_attach(device_t);
|
||||
static int fsl_pcib_detach(device_t);
|
||||
static int fsl_pcib_probe(device_t);
|
||||
|
||||
static int fsl_pcib_maxslots(device_t);
|
||||
static uint32_t fsl_pcib_read_config(device_t, u_int, u_int, u_int, u_int, int);
|
||||
static void fsl_pcib_write_config(device_t, u_int, u_int, u_int, u_int,
|
||||
uint32_t, int);
|
||||
static int fsl_pcib_alloc_msi(device_t dev, device_t child,
|
||||
int count, int maxcount, int *irqs);
|
||||
static int fsl_pcib_release_msi(device_t dev, device_t child,
|
||||
int count, int *irqs);
|
||||
static int fsl_pcib_alloc_msix(device_t dev, device_t child, int *irq);
|
||||
static int fsl_pcib_release_msix(device_t dev, device_t child, int irq);
|
||||
static int fsl_pcib_map_msi(device_t dev, device_t child,
|
||||
int irq, uint64_t *addr, uint32_t *data);
|
||||
|
||||
static vmem_t *msi_vmem; /* Global MSI vmem, holds all MSI ranges. */
|
||||
|
||||
/*
|
||||
* Bus interface definitions.
|
||||
*/
|
||||
static device_method_t fsl_pcib_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, fsl_pcib_probe),
|
||||
DEVMETHOD(device_attach, fsl_pcib_attach),
|
||||
DEVMETHOD(device_detach, fsl_pcib_detach),
|
||||
|
||||
/* pcib interface */
|
||||
DEVMETHOD(pcib_maxslots, fsl_pcib_maxslots),
|
||||
DEVMETHOD(pcib_read_config, fsl_pcib_read_config),
|
||||
DEVMETHOD(pcib_write_config, fsl_pcib_write_config),
|
||||
DEVMETHOD(pcib_alloc_msi, fsl_pcib_alloc_msi),
|
||||
DEVMETHOD(pcib_release_msi, fsl_pcib_release_msi),
|
||||
DEVMETHOD(pcib_alloc_msix, fsl_pcib_alloc_msix),
|
||||
DEVMETHOD(pcib_release_msix, fsl_pcib_release_msix),
|
||||
DEVMETHOD(pcib_map_msi, fsl_pcib_map_msi),
|
||||
|
||||
DEVMETHOD_END
|
||||
};
|
||||
|
||||
static devclass_t fsl_pcib_devclass;
|
||||
|
||||
DEFINE_CLASS_1(pcib, fsl_pcib_driver, fsl_pcib_methods,
|
||||
sizeof(struct fsl_pcib_softc), ofw_pci_driver);
|
||||
EARLY_DRIVER_MODULE(pcib, ofwbus, fsl_pcib_driver, fsl_pcib_devclass, 0, 0,
|
||||
BUS_PASS_BUS);
|
||||
|
||||
static void
|
||||
fsl_pcib_err_intr(void *v)
|
||||
{
|
||||
struct fsl_pcib_softc *sc;
|
||||
device_t dev;
|
||||
uint32_t err_reg, clear_reg;
|
||||
uint8_t i;
|
||||
|
||||
dev = (device_t)v;
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
clear_reg = 0;
|
||||
err_reg = bus_space_read_4(sc->sc_bst, sc->sc_bsh, REG_PEX_ERR_DR);
|
||||
|
||||
/* Check which one error occurred */
|
||||
for (i = 0; i < sizeof(pci_err)/sizeof(struct fsl_pcib_err_dr); i++) {
|
||||
if (err_reg & pci_err[i].err_dr_mask) {
|
||||
device_printf(dev, "PCI %d: report %s error\n",
|
||||
device_get_unit(dev), pci_err[i].msg);
|
||||
clear_reg |= pci_err[i].err_dr_mask;
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear pending errors */
|
||||
bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_PEX_ERR_DR, clear_reg);
|
||||
}
|
||||
|
||||
static int
|
||||
fsl_pcib_probe(device_t dev)
|
||||
{
|
||||
|
||||
if (ofw_bus_get_type(dev) == NULL ||
|
||||
strcmp(ofw_bus_get_type(dev), "pci") != 0)
|
||||
return (ENXIO);
|
||||
|
||||
if (!(ofw_bus_is_compatible(dev, "fsl,mpc8540-pci") ||
|
||||
ofw_bus_is_compatible(dev, "fsl,mpc8540-pcie") ||
|
||||
ofw_bus_is_compatible(dev, "fsl,mpc8548-pcie") ||
|
||||
ofw_bus_is_compatible(dev, "fsl,p5020-pcie") ||
|
||||
ofw_bus_is_compatible(dev, "fsl,qoriq-pcie-v2.2") ||
|
||||
ofw_bus_is_compatible(dev, "fsl,qoriq-pcie")))
|
||||
return (ENXIO);
|
||||
|
||||
device_set_desc(dev, "Freescale Integrated PCI/PCI-E Controller");
|
||||
return (BUS_PROBE_DEFAULT);
|
||||
}
|
||||
|
||||
static int
|
||||
fsl_pcib_attach(device_t dev)
|
||||
{
|
||||
struct fsl_pcib_softc *sc;
|
||||
phandle_t node;
|
||||
uint32_t cfgreg, brctl, ipreg;
|
||||
int error, rid;
|
||||
uint8_t ltssm, capptr;
|
||||
|
||||
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);
|
||||
sc->sc_busnr = 0;
|
||||
|
||||
ipreg = bus_read_4(sc->sc_res, REG_PEX_IP_BLK_REV1);
|
||||
sc->sc_ip_min = (ipreg & IP_MN_M) >> IP_MN_S;
|
||||
sc->sc_ip_maj = (ipreg & IP_MJ_M) >> IP_MJ_S;
|
||||
mtx_init(&sc->sc_cfg_mtx, "pcicfg", NULL, MTX_SPIN);
|
||||
|
||||
cfgreg = fsl_pcib_cfgread(sc, 0, 0, 0, PCIR_VENDOR, 2);
|
||||
if (cfgreg != 0x1057 && cfgreg != 0x1957)
|
||||
goto err;
|
||||
|
||||
capptr = fsl_pcib_cfgread(sc, 0, 0, 0, PCIR_CAP_PTR, 1);
|
||||
while (capptr != 0) {
|
||||
cfgreg = fsl_pcib_cfgread(sc, 0, 0, 0, capptr, 2);
|
||||
switch (cfgreg & 0xff) {
|
||||
case PCIY_PCIX:
|
||||
break;
|
||||
case PCIY_EXPRESS:
|
||||
sc->sc_pcie = 1;
|
||||
sc->sc_pcie_capreg = capptr;
|
||||
break;
|
||||
}
|
||||
capptr = (cfgreg >> 8) & 0xff;
|
||||
}
|
||||
|
||||
node = ofw_bus_get_node(dev);
|
||||
|
||||
/*
|
||||
* Initialize generic OF PCI interface (ranges, etc.)
|
||||
*/
|
||||
|
||||
error = ofw_pci_init(dev);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/*
|
||||
* Configure decode windows for PCI(E) access.
|
||||
*/
|
||||
if (fsl_pcib_decode_win(node, sc) != 0)
|
||||
goto err;
|
||||
|
||||
cfgreg = fsl_pcib_cfgread(sc, 0, 0, 0, PCIR_COMMAND, 2);
|
||||
cfgreg |= PCIM_CMD_SERRESPEN | PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN |
|
||||
PCIM_CMD_PORTEN;
|
||||
fsl_pcib_cfgwrite(sc, 0, 0, 0, PCIR_COMMAND, cfgreg, 2);
|
||||
|
||||
/* Reset the bus. Needed for Radeon video cards. */
|
||||
brctl = fsl_pcib_read_config(sc->sc_dev, 0, 0, 0,
|
||||
PCIR_BRIDGECTL_1, 1);
|
||||
brctl |= PCIB_BCR_SECBUS_RESET;
|
||||
fsl_pcib_write_config(sc->sc_dev, 0, 0, 0,
|
||||
PCIR_BRIDGECTL_1, brctl, 1);
|
||||
DELAY(100000);
|
||||
brctl &= ~PCIB_BCR_SECBUS_RESET;
|
||||
fsl_pcib_write_config(sc->sc_dev, 0, 0, 0,
|
||||
PCIR_BRIDGECTL_1, brctl, 1);
|
||||
DELAY(100000);
|
||||
|
||||
if (sc->sc_pcie) {
|
||||
ltssm = fsl_pcib_cfgread(sc, 0, 0, 0, PCIR_LTSSM, 1);
|
||||
if (ltssm < LTSSM_STAT_L0) {
|
||||
if (bootverbose)
|
||||
printf("PCI %d: no PCIE link, skipping\n",
|
||||
device_get_unit(dev));
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate irq */
|
||||
rid = 0;
|
||||
sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
|
||||
RF_ACTIVE | RF_SHAREABLE);
|
||||
if (sc->sc_irq_res == NULL) {
|
||||
error = fsl_pcib_detach(dev);
|
||||
if (error != 0) {
|
||||
device_printf(dev,
|
||||
"Detach of the driver failed with error %d\n",
|
||||
error);
|
||||
}
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
/* Setup interrupt handler */
|
||||
error = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
|
||||
NULL, fsl_pcib_err_intr, dev, &sc->sc_ih);
|
||||
if (error != 0) {
|
||||
device_printf(dev, "Could not setup irq, %d\n", error);
|
||||
sc->sc_ih = NULL;
|
||||
error = fsl_pcib_detach(dev);
|
||||
if (error != 0) {
|
||||
device_printf(dev,
|
||||
"Detach of the driver failed with error %d\n",
|
||||
error);
|
||||
}
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
fsl_pcib_err_init(dev);
|
||||
|
||||
return (ofw_pci_attach(dev));
|
||||
|
||||
err:
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
fsl_pcib_cfgread(struct fsl_pcib_softc *sc, u_int bus, u_int slot, u_int func,
|
||||
u_int reg, int bytes)
|
||||
{
|
||||
uint32_t addr, data;
|
||||
|
||||
addr = CONFIG_ACCESS_ENABLE;
|
||||
addr |= (bus & 0xff) << 16;
|
||||
addr |= (slot & 0x1f) << 11;
|
||||
addr |= (func & 0x7) << 8;
|
||||
addr |= reg & 0xfc;
|
||||
if (sc->sc_pcie)
|
||||
addr |= (reg & 0xf00) << 16;
|
||||
|
||||
mtx_lock_spin(&sc->sc_cfg_mtx);
|
||||
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;
|
||||
}
|
||||
mtx_unlock_spin(&sc->sc_cfg_mtx);
|
||||
return (data);
|
||||
}
|
||||
|
||||
static void
|
||||
fsl_pcib_cfgwrite(struct fsl_pcib_softc *sc, u_int bus, u_int slot, u_int func,
|
||||
u_int reg, uint32_t data, int bytes)
|
||||
{
|
||||
uint32_t addr;
|
||||
|
||||
addr = CONFIG_ACCESS_ENABLE;
|
||||
addr |= (bus & 0xff) << 16;
|
||||
addr |= (slot & 0x1f) << 11;
|
||||
addr |= (func & 0x7) << 8;
|
||||
addr |= reg & 0xfc;
|
||||
if (sc->sc_pcie)
|
||||
addr |= (reg & 0xf00) << 16;
|
||||
|
||||
mtx_lock_spin(&sc->sc_cfg_mtx);
|
||||
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;
|
||||
}
|
||||
mtx_unlock_spin(&sc->sc_cfg_mtx);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void
|
||||
dump(struct fsl_pcib_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, fsl_pcib_cfgread(sc, 0, 0, 0,
|
||||
i, 4));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
fsl_pcib_maxslots(device_t dev)
|
||||
{
|
||||
struct fsl_pcib_softc *sc = device_get_softc(dev);
|
||||
|
||||
return ((sc->sc_pcie) ? 0 : PCI_SLOTMAX);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
fsl_pcib_read_config(device_t dev, u_int bus, u_int slot, u_int func,
|
||||
u_int reg, int bytes)
|
||||
{
|
||||
struct fsl_pcib_softc *sc = device_get_softc(dev);
|
||||
u_int devfn;
|
||||
|
||||
if (bus == sc->sc_busnr && !sc->sc_pcie && slot < 10)
|
||||
return (~0);
|
||||
devfn = DEVFN(bus, slot, func);
|
||||
|
||||
return (fsl_pcib_cfgread(sc, bus, slot, func, reg, bytes));
|
||||
}
|
||||
|
||||
static void
|
||||
fsl_pcib_write_config(device_t dev, u_int bus, u_int slot, u_int func,
|
||||
u_int reg, uint32_t val, int bytes)
|
||||
{
|
||||
struct fsl_pcib_softc *sc = device_get_softc(dev);
|
||||
|
||||
if (bus == sc->sc_busnr && !sc->sc_pcie && slot < 10)
|
||||
return;
|
||||
fsl_pcib_cfgwrite(sc, bus, slot, func, reg, val, bytes);
|
||||
}
|
||||
|
||||
static void
|
||||
fsl_pcib_inbound(struct fsl_pcib_softc *sc, int wnd, int tgt, uint64_t start,
|
||||
uint64_t size, uint64_t pci_start)
|
||||
{
|
||||
uint32_t attr, bar, tar;
|
||||
|
||||
KASSERT(wnd > 0, ("%s: inbound window 0 is invalid", __func__));
|
||||
|
||||
attr = PIWAR_EN;
|
||||
|
||||
switch (tgt) {
|
||||
case -1:
|
||||
attr &= ~PIWAR_EN;
|
||||
break;
|
||||
case PIWAR_TRGT_LOCAL:
|
||||
attr |= (ffsl(size) - 2);
|
||||
default:
|
||||
attr |= (tgt << PIWAR_TRGT_S);
|
||||
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
|
||||
fsl_pcib_outbound(struct fsl_pcib_softc *sc, int wnd, int res, uint64_t start,
|
||||
uint64_t size, uint64_t pci_start)
|
||||
{
|
||||
uint32_t attr, bar, tar;
|
||||
|
||||
switch (res) {
|
||||
case SYS_RES_MEMORY:
|
||||
attr = 0x80044000 | (ffsll(size) - 2);
|
||||
break;
|
||||
case SYS_RES_IOPORT:
|
||||
attr = 0x80088000 | (ffsll(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 void
|
||||
fsl_pcib_err_init(device_t dev)
|
||||
{
|
||||
struct fsl_pcib_softc *sc;
|
||||
uint16_t sec_stat, dsr;
|
||||
uint32_t dcr, err_en;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
sec_stat = fsl_pcib_cfgread(sc, 0, 0, 0, PCIR_SECSTAT_1, 2);
|
||||
if (sec_stat)
|
||||
fsl_pcib_cfgwrite(sc, 0, 0, 0, PCIR_SECSTAT_1, 0xffff, 2);
|
||||
if (sc->sc_pcie) {
|
||||
/* Clear error bits */
|
||||
bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_PEX_MES_IER,
|
||||
0xffffffff);
|
||||
bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_PEX_MES_DR,
|
||||
0xffffffff);
|
||||
bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_PEX_ERR_DR,
|
||||
0xffffffff);
|
||||
|
||||
dsr = fsl_pcib_cfgread(sc, 0, 0, 0,
|
||||
sc->sc_pcie_capreg + PCIER_DEVICE_STA, 2);
|
||||
if (dsr)
|
||||
fsl_pcib_cfgwrite(sc, 0, 0, 0,
|
||||
sc->sc_pcie_capreg + PCIER_DEVICE_STA,
|
||||
0xffff, 2);
|
||||
|
||||
/* Enable all errors reporting */
|
||||
err_en = 0x00bfff00;
|
||||
bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_PEX_ERR_EN,
|
||||
err_en);
|
||||
|
||||
/* Enable error reporting: URR, FER, NFER */
|
||||
dcr = fsl_pcib_cfgread(sc, 0, 0, 0,
|
||||
sc->sc_pcie_capreg + PCIER_DEVICE_CTL, 4);
|
||||
dcr |= PCIEM_CTL_URR_ENABLE | PCIEM_CTL_FER_ENABLE |
|
||||
PCIEM_CTL_NFER_ENABLE;
|
||||
fsl_pcib_cfgwrite(sc, 0, 0, 0,
|
||||
sc->sc_pcie_capreg + PCIER_DEVICE_CTL, dcr, 4);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
fsl_pcib_detach(device_t dev)
|
||||
{
|
||||
struct fsl_pcib_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
mtx_destroy(&sc->sc_cfg_mtx);
|
||||
|
||||
return (bus_generic_detach(dev));
|
||||
}
|
||||
|
||||
static int
|
||||
fsl_pcib_decode_win(phandle_t node, struct fsl_pcib_softc *sc)
|
||||
{
|
||||
device_t dev;
|
||||
int error, i, trgt;
|
||||
|
||||
dev = sc->sc_dev;
|
||||
|
||||
fsl_pcib_outbound(sc, 0, -1, 0, 0, 0);
|
||||
|
||||
/*
|
||||
* Configure LAW decode windows.
|
||||
*/
|
||||
error = law_pci_target(sc->sc_res, &sc->sc_iomem_target,
|
||||
&sc->sc_ioport_target);
|
||||
if (error != 0) {
|
||||
device_printf(dev, "could not retrieve PCI LAW target info\n");
|
||||
return (error);
|
||||
}
|
||||
|
||||
for (i = 0; i < sc->pci_sc.sc_nrange; i++) {
|
||||
switch (sc->pci_sc.sc_range[i].pci_hi &
|
||||
OFW_PCI_PHYS_HI_SPACEMASK) {
|
||||
case OFW_PCI_PHYS_HI_SPACE_CONFIG:
|
||||
continue;
|
||||
case OFW_PCI_PHYS_HI_SPACE_IO:
|
||||
trgt = sc->sc_ioport_target;
|
||||
fsl_pcib_outbound(sc, 2, SYS_RES_IOPORT,
|
||||
sc->pci_sc.sc_range[i].host,
|
||||
sc->pci_sc.sc_range[i].size,
|
||||
sc->pci_sc.sc_range[i].pci);
|
||||
sc->sc_ioport_start = sc->pci_sc.sc_range[i].pci;
|
||||
sc->sc_ioport_end = sc->pci_sc.sc_range[i].pci +
|
||||
sc->pci_sc.sc_range[i].size - 1;
|
||||
break;
|
||||
case OFW_PCI_PHYS_HI_SPACE_MEM32:
|
||||
case OFW_PCI_PHYS_HI_SPACE_MEM64:
|
||||
trgt = sc->sc_iomem_target;
|
||||
fsl_pcib_outbound(sc, 1, SYS_RES_MEMORY,
|
||||
sc->pci_sc.sc_range[i].host,
|
||||
sc->pci_sc.sc_range[i].size,
|
||||
sc->pci_sc.sc_range[i].pci);
|
||||
sc->sc_iomem_start = sc->pci_sc.sc_range[i].pci;
|
||||
sc->sc_iomem_end = sc->pci_sc.sc_range[i].pci +
|
||||
sc->pci_sc.sc_range[i].size - 1;
|
||||
break;
|
||||
default:
|
||||
panic("Unknown range type %#x\n",
|
||||
sc->pci_sc.sc_range[i].pci_hi &
|
||||
OFW_PCI_PHYS_HI_SPACEMASK);
|
||||
}
|
||||
error = law_enable(trgt, sc->pci_sc.sc_range[i].host,
|
||||
sc->pci_sc.sc_range[i].size);
|
||||
if (error != 0) {
|
||||
device_printf(dev, "could not program LAW for range "
|
||||
"%d\n", i);
|
||||
return (error);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Set outbout and inbound windows.
|
||||
*/
|
||||
fsl_pcib_outbound(sc, 3, -1, 0, 0, 0);
|
||||
fsl_pcib_outbound(sc, 4, -1, 0, 0, 0);
|
||||
|
||||
fsl_pcib_inbound(sc, 1, -1, 0, 0, 0);
|
||||
fsl_pcib_inbound(sc, 2, -1, 0, 0, 0);
|
||||
fsl_pcib_inbound(sc, 3, PIWAR_TRGT_LOCAL, 0,
|
||||
ptoa(Maxmem), 0);
|
||||
|
||||
/* Direct-map the CCSR for MSIs. */
|
||||
/* Freescale PCIe 2.x has a dedicated MSI window. */
|
||||
/* inbound window 8 makes it hit 0xD00 offset, the MSI window. */
|
||||
if (sc->sc_ip_maj >= 2)
|
||||
fsl_pcib_inbound(sc, 8, PIWAR_TRGT_CCSR, ccsrbar_pa,
|
||||
ccsrbar_size, ccsrbar_pa);
|
||||
else
|
||||
fsl_pcib_inbound(sc, 1, PIWAR_TRGT_CCSR, ccsrbar_pa,
|
||||
ccsrbar_size, ccsrbar_pa);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int fsl_pcib_alloc_msi(device_t dev, device_t child,
|
||||
int count, int maxcount, int *irqs)
|
||||
{
|
||||
struct fsl_pcib_softc *sc;
|
||||
vmem_addr_t start;
|
||||
int err, i;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
if (msi_vmem == NULL)
|
||||
return (ENODEV);
|
||||
|
||||
err = vmem_xalloc(msi_vmem, count, powerof2(count), 0, 0,
|
||||
VMEM_ADDR_MIN, VMEM_ADDR_MAX, M_BESTFIT | M_WAITOK, &start);
|
||||
|
||||
if (err)
|
||||
return (err);
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
irqs[i] = start + i;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int fsl_pcib_release_msi(device_t dev, device_t child,
|
||||
int count, int *irqs)
|
||||
{
|
||||
if (msi_vmem == NULL)
|
||||
return (ENODEV);
|
||||
|
||||
vmem_xfree(msi_vmem, irqs[0], count);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int fsl_pcib_alloc_msix(device_t dev, device_t child, int *irq)
|
||||
{
|
||||
return (fsl_pcib_alloc_msi(dev, child, 1, 1, irq));
|
||||
}
|
||||
|
||||
static int fsl_pcib_release_msix(device_t dev, device_t child, int irq)
|
||||
{
|
||||
return (fsl_pcib_release_msi(dev, child, 1, &irq));
|
||||
}
|
||||
|
||||
static int fsl_pcib_map_msi(device_t dev, device_t child,
|
||||
int irq, uint64_t *addr, uint32_t *data)
|
||||
{
|
||||
struct fsl_msi_map *mp;
|
||||
|
||||
SLIST_FOREACH(mp, &fsl_msis, slist) {
|
||||
if (irq >= mp->irq_base && irq < mp->irq_base + FSL_NUM_MSIS)
|
||||
break;
|
||||
}
|
||||
|
||||
if (mp == NULL)
|
||||
return (ENODEV);
|
||||
|
||||
*data = (irq & 255);
|
||||
*addr = ccsrbar_pa + mp->target;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Linux device trees put the msi@<x> as children of the SoC, with ranges based
|
||||
* on the CCSR. Since rman doesn't permit overlapping or sub-ranges between
|
||||
* devices (bus_space_subregion(9) could do it, but let's not touch the PIC
|
||||
* driver just to allocate a subregion for a sibling driver). This driver will
|
||||
* use ccsr_write() and ccsr_read() instead.
|
||||
*/
|
||||
|
||||
#define FSL_NUM_IRQS 8
|
||||
#define FSL_NUM_MSI_PER_IRQ 32
|
||||
#define FSL_MSI_TARGET 0x140
|
||||
|
||||
struct fsl_msi_softc {
|
||||
vm_offset_t sc_base;
|
||||
vm_offset_t sc_target;
|
||||
int sc_msi_base_irq;
|
||||
struct fsl_msi_map sc_map;
|
||||
struct fsl_msi_irq {
|
||||
/* This struct gets passed as the filter private data. */
|
||||
struct fsl_msi_softc *sc_ptr; /* Pointer back to softc. */
|
||||
struct resource *res;
|
||||
int irq;
|
||||
void *cookie;
|
||||
int vectors[FSL_NUM_MSI_PER_IRQ];
|
||||
vm_offset_t reg;
|
||||
} sc_msi_irq[FSL_NUM_IRQS];
|
||||
};
|
||||
|
||||
static int
|
||||
fsl_msi_intr_filter(void *priv)
|
||||
{
|
||||
struct fsl_msi_irq *data = priv;
|
||||
uint32_t reg;
|
||||
int i;
|
||||
|
||||
reg = ccsr_read4(ccsrbar_va + data->reg);
|
||||
i = 0;
|
||||
while (reg != 0) {
|
||||
if (reg & 1)
|
||||
powerpc_dispatch_intr(data->vectors[i], NULL);
|
||||
reg >>= 1;
|
||||
i++;
|
||||
}
|
||||
|
||||
return (FILTER_HANDLED);
|
||||
}
|
||||
|
||||
static int
|
||||
fsl_msi_probe(device_t dev)
|
||||
{
|
||||
if (!ofw_bus_is_compatible(dev, "fsl,mpic-msi"))
|
||||
return (ENXIO);
|
||||
|
||||
device_set_desc(dev, "Freescale MSI");
|
||||
|
||||
return (BUS_PROBE_DEFAULT);
|
||||
}
|
||||
|
||||
static int
|
||||
fsl_msi_attach(device_t dev)
|
||||
{
|
||||
struct fsl_msi_softc *sc;
|
||||
struct fsl_msi_irq *irq;
|
||||
int i;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
if (msi_vmem == NULL)
|
||||
msi_vmem = vmem_create("MPIC MSI", 0, 0, 1, 0, M_BESTFIT | M_WAITOK);
|
||||
|
||||
/* Manually play with resource entries. */
|
||||
sc->sc_base = bus_get_resource_start(dev, SYS_RES_MEMORY, 0);
|
||||
sc->sc_map.target = bus_get_resource_start(dev, SYS_RES_MEMORY, 1);
|
||||
|
||||
if (sc->sc_map.target == 0)
|
||||
sc->sc_map.target = sc->sc_base + FSL_MSI_TARGET;
|
||||
|
||||
for (i = 0; i < FSL_NUM_IRQS; i++) {
|
||||
irq = &sc->sc_msi_irq[i];
|
||||
irq->irq = i;
|
||||
irq->reg = sc->sc_base + 16 * i;
|
||||
irq->res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
|
||||
&irq->irq, RF_ACTIVE);
|
||||
bus_setup_intr(dev, irq->res, INTR_TYPE_MISC | INTR_MPSAFE,
|
||||
fsl_msi_intr_filter, NULL, irq, &irq->cookie);
|
||||
}
|
||||
sc->sc_map.irq_base = powerpc_register_pic(dev, ofw_bus_get_node(dev),
|
||||
FSL_NUM_MSIS, 0, 0);
|
||||
|
||||
/* Let vmem and the IRQ subsystem work their magic for allocations. */
|
||||
vmem_add(msi_vmem, sc->sc_map.irq_base, FSL_NUM_MSIS, M_WAITOK);
|
||||
|
||||
SLIST_INSERT_HEAD(&fsl_msis, &sc->sc_map, slist);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
fsl_msi_enable(device_t dev, u_int irq, u_int vector, void **priv)
|
||||
{
|
||||
struct fsl_msi_softc *sc;
|
||||
struct fsl_msi_irq *irqd;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
irqd = &sc->sc_msi_irq[irq / FSL_NUM_MSI_PER_IRQ];
|
||||
irqd->vectors[irq % FSL_NUM_MSI_PER_IRQ] = vector;
|
||||
}
|
||||
|
||||
static device_method_t fsl_msi_methods[] = {
|
||||
DEVMETHOD(device_probe, fsl_msi_probe),
|
||||
DEVMETHOD(device_attach, fsl_msi_attach),
|
||||
|
||||
DEVMETHOD(pic_enable, fsl_msi_enable),
|
||||
DEVMETHOD_END
|
||||
};
|
||||
|
||||
static devclass_t fsl_msi_devclass;
|
||||
|
||||
static driver_t fsl_msi_driver = {
|
||||
"fsl_msi",
|
||||
fsl_msi_methods,
|
||||
sizeof(struct fsl_msi_softc)
|
||||
};
|
||||
|
||||
EARLY_DRIVER_MODULE(fsl_msi, simplebus, fsl_msi_driver, fsl_msi_devclass, 0, 0,
|
||||
BUS_PASS_INTERRUPT + 1);
|
111
freebsd/sys/powerpc/mpc85xx/pci_mpc85xx_pcib.c
Normal file
111
freebsd/sys/powerpc/mpc85xx/pci_mpc85xx_pcib.c
Normal file
@ -0,0 +1,111 @@
|
||||
#include <machine/rtems-bsd-kernel-space.h>
|
||||
|
||||
/*-
|
||||
* Copyright 2015 Justin Hibbits
|
||||
* 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.
|
||||
*
|
||||
* From: FreeBSD: src/sys/powerpc/mpc85xx/pci_ocp.c,v 1.9 2010/03/23 23:46:28 marcel
|
||||
*/
|
||||
|
||||
#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/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/rman.h>
|
||||
#include <sys/endian.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/pmap.h>
|
||||
|
||||
#include <dev/ofw/openfirm.h>
|
||||
#include <dev/ofw/ofw_pci.h>
|
||||
#include <dev/ofw/ofw_bus.h>
|
||||
#include <dev/ofw/ofw_bus_subr.h>
|
||||
|
||||
#include <dev/pci/pcivar.h>
|
||||
#include <dev/pci/pcireg.h>
|
||||
#include <dev/pci/pcib_private.h>
|
||||
|
||||
#include <machine/intr_machdep.h>
|
||||
|
||||
#include <rtems/bsd/local/pcib_if.h>
|
||||
|
||||
DECLARE_CLASS(ofw_pcib_pci_driver);
|
||||
|
||||
struct fsl_pcib_softc {
|
||||
/*
|
||||
* This is here so that we can use pci bridge methods, too - the
|
||||
* generic routines only need the dev, secbus and subbus members
|
||||
* filled.
|
||||
*
|
||||
* XXX: This should be extracted from ofw_pcib_pci.c, and shared in a
|
||||
* header.
|
||||
*/
|
||||
struct pcib_softc ops_pcib_sc;
|
||||
phandle_t ops_node;
|
||||
struct ofw_bus_iinfo ops_iinfo;
|
||||
};
|
||||
|
||||
static int
|
||||
fsl_pcib_rc_probe(device_t dev)
|
||||
{
|
||||
|
||||
if (pci_get_vendor(dev) != 0x1957)
|
||||
return (ENXIO);
|
||||
if (pci_get_progif(dev) != 0)
|
||||
return (ENXIO);
|
||||
if (pci_get_class(dev) != PCIC_PROCESSOR)
|
||||
return (ENXIO);
|
||||
if (pci_get_subclass(dev) != PCIS_PROCESSOR_POWERPC)
|
||||
return (ENXIO);
|
||||
|
||||
device_set_desc(dev, "MPC85xx Root Complex bridge");
|
||||
|
||||
return (BUS_PROBE_DEFAULT);
|
||||
}
|
||||
|
||||
static device_method_t fsl_pcib_rc_methods[] = {
|
||||
DEVMETHOD(device_probe, fsl_pcib_rc_probe),
|
||||
DEVMETHOD_END
|
||||
};
|
||||
|
||||
static devclass_t fsl_pcib_rc_devclass;
|
||||
DEFINE_CLASS_1(pcib, fsl_pcib_rc_driver, fsl_pcib_rc_methods,
|
||||
sizeof(struct fsl_pcib_softc), ofw_pcib_pci_driver);
|
||||
EARLY_DRIVER_MODULE(rcpcib, pci, fsl_pcib_rc_driver, fsl_pcib_rc_devclass, 0, 0,
|
||||
BUS_PASS_BUS);
|
710
freebsd/sys/powerpc/mpc85xx/platform_mpc85xx.c
Normal file
710
freebsd/sys/powerpc/mpc85xx/platform_mpc85xx.c
Normal file
@ -0,0 +1,710 @@
|
||||
#include <machine/rtems-bsd-kernel-space.h>
|
||||
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (c) 2008-2012 Semihalf.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <rtems/bsd/local/opt_platform.h>
|
||||
#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/pcpu.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/smp.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
#include <machine/cpu.h>
|
||||
#include <machine/hid.h>
|
||||
#include <machine/_inttypes.h>
|
||||
#include <machine/machdep.h>
|
||||
#include <machine/md_var.h>
|
||||
#include <machine/platform.h>
|
||||
#include <machine/platformvar.h>
|
||||
#include <machine/smp.h>
|
||||
#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 <vm/vm.h>
|
||||
#include <vm/pmap.h>
|
||||
#include <vm/vm_extern.h>
|
||||
|
||||
#include <powerpc/mpc85xx/mpc85xx.h>
|
||||
|
||||
#include <rtems/bsd/local/platform_if.h>
|
||||
|
||||
#ifdef SMP
|
||||
extern void *ap_pcpu;
|
||||
extern vm_paddr_t kernload; /* Kernel physical load address */
|
||||
extern uint8_t __boot_page[]; /* Boot page body */
|
||||
extern uint32_t bp_kernload;
|
||||
extern vm_offset_t __startkernel;
|
||||
|
||||
struct cpu_release {
|
||||
uint32_t entry_h;
|
||||
uint32_t entry_l;
|
||||
uint32_t r3_h;
|
||||
uint32_t r3_l;
|
||||
uint32_t reserved;
|
||||
uint32_t pir;
|
||||
};
|
||||
#endif
|
||||
|
||||
extern uint32_t *bootinfo;
|
||||
vm_paddr_t ccsrbar_pa;
|
||||
vm_offset_t ccsrbar_va;
|
||||
vm_size_t ccsrbar_size;
|
||||
|
||||
static int cpu, maxcpu;
|
||||
|
||||
static device_t rcpm_dev;
|
||||
static void dummy_freeze(device_t, bool);
|
||||
|
||||
static void (*freeze_timebase)(device_t, bool) = dummy_freeze;
|
||||
|
||||
static int mpc85xx_probe(platform_t);
|
||||
static void mpc85xx_mem_regions(platform_t, struct mem_region *phys,
|
||||
int *physsz, struct mem_region *avail, int *availsz);
|
||||
static u_long mpc85xx_timebase_freq(platform_t, struct cpuref *cpuref);
|
||||
static int mpc85xx_smp_first_cpu(platform_t, struct cpuref *cpuref);
|
||||
static int mpc85xx_smp_next_cpu(platform_t, struct cpuref *cpuref);
|
||||
static int mpc85xx_smp_get_bsp(platform_t, struct cpuref *cpuref);
|
||||
static int mpc85xx_smp_start_cpu(platform_t, struct pcpu *cpu);
|
||||
static void mpc85xx_smp_timebase_sync(platform_t, u_long tb, int ap);
|
||||
|
||||
static void mpc85xx_reset(platform_t);
|
||||
|
||||
static platform_method_t mpc85xx_methods[] = {
|
||||
PLATFORMMETHOD(platform_probe, mpc85xx_probe),
|
||||
PLATFORMMETHOD(platform_attach, mpc85xx_attach),
|
||||
PLATFORMMETHOD(platform_mem_regions, mpc85xx_mem_regions),
|
||||
PLATFORMMETHOD(platform_timebase_freq, mpc85xx_timebase_freq),
|
||||
|
||||
PLATFORMMETHOD(platform_smp_first_cpu, mpc85xx_smp_first_cpu),
|
||||
PLATFORMMETHOD(platform_smp_next_cpu, mpc85xx_smp_next_cpu),
|
||||
PLATFORMMETHOD(platform_smp_get_bsp, mpc85xx_smp_get_bsp),
|
||||
PLATFORMMETHOD(platform_smp_start_cpu, mpc85xx_smp_start_cpu),
|
||||
PLATFORMMETHOD(platform_smp_timebase_sync, mpc85xx_smp_timebase_sync),
|
||||
|
||||
PLATFORMMETHOD(platform_reset, mpc85xx_reset),
|
||||
|
||||
PLATFORMMETHOD_END
|
||||
};
|
||||
|
||||
DEFINE_CLASS_0(mpc85xx, mpc85xx_platform, mpc85xx_methods, 0);
|
||||
|
||||
PLATFORM_DEF(mpc85xx_platform);
|
||||
|
||||
static int
|
||||
mpc85xx_probe(platform_t plat)
|
||||
{
|
||||
u_int pvr = (mfpvr() >> 16) & 0xFFFF;
|
||||
|
||||
switch (pvr) {
|
||||
case FSL_E500v1:
|
||||
case FSL_E500v2:
|
||||
case FSL_E500mc:
|
||||
case FSL_E5500:
|
||||
case FSL_E6500:
|
||||
return (BUS_PROBE_DEFAULT);
|
||||
}
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
int
|
||||
mpc85xx_attach(platform_t plat)
|
||||
{
|
||||
phandle_t cpus, child, ccsr;
|
||||
const char *soc_name_guesses[] = {"/soc", "soc", NULL};
|
||||
const char **name;
|
||||
pcell_t ranges[6], acells, pacells, scells;
|
||||
uint64_t ccsrbar, ccsrsize;
|
||||
int i;
|
||||
|
||||
if ((cpus = OF_finddevice("/cpus")) != -1) {
|
||||
for (maxcpu = 0, child = OF_child(cpus); child != 0;
|
||||
child = OF_peer(child), maxcpu++)
|
||||
;
|
||||
} else
|
||||
maxcpu = 1;
|
||||
|
||||
/*
|
||||
* Locate CCSR region. Irritatingly, there is no way to find it
|
||||
* unless you already know where it is. Try to infer its location
|
||||
* from the device tree.
|
||||
*/
|
||||
|
||||
ccsr = -1;
|
||||
for (name = soc_name_guesses; *name != NULL && ccsr == -1; name++)
|
||||
ccsr = OF_finddevice(*name);
|
||||
if (ccsr == -1) {
|
||||
char type[64];
|
||||
|
||||
/* That didn't work. Search for devices of type "soc" */
|
||||
child = OF_child(OF_peer(0));
|
||||
for (OF_child(child); child != 0; child = OF_peer(child)) {
|
||||
if (OF_getprop(child, "device_type", type, sizeof(type))
|
||||
<= 0)
|
||||
continue;
|
||||
|
||||
if (strcmp(type, "soc") == 0) {
|
||||
ccsr = child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ccsr == -1)
|
||||
panic("Could not locate CCSR window!");
|
||||
|
||||
OF_getprop(ccsr, "#size-cells", &scells, sizeof(scells));
|
||||
OF_getprop(ccsr, "#address-cells", &acells, sizeof(acells));
|
||||
OF_searchprop(OF_parent(ccsr), "#address-cells", &pacells,
|
||||
sizeof(pacells));
|
||||
OF_getprop(ccsr, "ranges", ranges, sizeof(ranges));
|
||||
ccsrbar = ccsrsize = 0;
|
||||
for (i = acells; i < acells + pacells; i++) {
|
||||
ccsrbar <<= 32;
|
||||
ccsrbar |= ranges[i];
|
||||
}
|
||||
for (i = acells + pacells; i < acells + pacells + scells; i++) {
|
||||
ccsrsize <<= 32;
|
||||
ccsrsize |= ranges[i];
|
||||
}
|
||||
ccsrbar_va = pmap_early_io_map(ccsrbar, ccsrsize);
|
||||
ccsrbar_pa = ccsrbar;
|
||||
ccsrbar_size = ccsrsize;
|
||||
|
||||
mpc85xx_enable_l3_cache();
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
mpc85xx_mem_regions(platform_t plat, struct mem_region *phys, int *physsz,
|
||||
struct mem_region *avail, int *availsz)
|
||||
{
|
||||
|
||||
ofw_mem_regions(phys, physsz, avail, availsz);
|
||||
}
|
||||
|
||||
static u_long
|
||||
mpc85xx_timebase_freq(platform_t plat, struct cpuref *cpuref)
|
||||
{
|
||||
u_long ticks;
|
||||
phandle_t cpus, child;
|
||||
pcell_t freq;
|
||||
|
||||
if (bootinfo != NULL) {
|
||||
if (bootinfo[0] == 1) {
|
||||
/* Backward compatibility. See 8-STABLE. */
|
||||
ticks = bootinfo[3] >> 3;
|
||||
} else {
|
||||
/* Compatibility with Juniper's loader. */
|
||||
ticks = bootinfo[5] >> 3;
|
||||
}
|
||||
} else
|
||||
ticks = 0;
|
||||
|
||||
if ((cpus = OF_finddevice("/cpus")) == -1)
|
||||
goto out;
|
||||
|
||||
if ((child = OF_child(cpus)) == 0)
|
||||
goto out;
|
||||
|
||||
switch (OF_getproplen(child, "timebase-frequency")) {
|
||||
case 4:
|
||||
{
|
||||
uint32_t tbase;
|
||||
OF_getprop(child, "timebase-frequency", &tbase, sizeof(tbase));
|
||||
ticks = tbase;
|
||||
return (ticks);
|
||||
}
|
||||
case 8:
|
||||
{
|
||||
uint64_t tbase;
|
||||
OF_getprop(child, "timebase-frequency", &tbase, sizeof(tbase));
|
||||
ticks = tbase;
|
||||
return (ticks);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
freq = 0;
|
||||
if (OF_getprop(child, "bus-frequency", (void *)&freq,
|
||||
sizeof(freq)) <= 0)
|
||||
goto out;
|
||||
|
||||
if (freq == 0)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Time Base and Decrementer are updated every 8 CCB bus clocks.
|
||||
* HID0[SEL_TBCLK] = 0
|
||||
*/
|
||||
if (mpc85xx_is_qoriq())
|
||||
ticks = freq / 32;
|
||||
else
|
||||
ticks = freq / 8;
|
||||
|
||||
out:
|
||||
if (ticks <= 0)
|
||||
panic("Unable to determine timebase frequency!");
|
||||
|
||||
return (ticks);
|
||||
}
|
||||
|
||||
static int
|
||||
mpc85xx_smp_first_cpu(platform_t plat, struct cpuref *cpuref)
|
||||
{
|
||||
|
||||
cpu = 0;
|
||||
cpuref->cr_cpuid = cpu;
|
||||
cpuref->cr_hwref = cpuref->cr_cpuid;
|
||||
if (bootverbose)
|
||||
printf("powerpc_smp_first_cpu: cpuid %d\n", cpuref->cr_cpuid);
|
||||
cpu++;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
mpc85xx_smp_next_cpu(platform_t plat, struct cpuref *cpuref)
|
||||
{
|
||||
|
||||
if (cpu >= maxcpu)
|
||||
return (ENOENT);
|
||||
|
||||
cpuref->cr_cpuid = cpu++;
|
||||
cpuref->cr_hwref = cpuref->cr_cpuid;
|
||||
if (bootverbose)
|
||||
printf("powerpc_smp_next_cpu: cpuid %d\n", cpuref->cr_cpuid);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
mpc85xx_smp_get_bsp(platform_t plat, struct cpuref *cpuref)
|
||||
{
|
||||
|
||||
cpuref->cr_cpuid = mfspr(SPR_PIR);
|
||||
cpuref->cr_hwref = cpuref->cr_cpuid;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
#ifdef SMP
|
||||
static int
|
||||
mpc85xx_smp_start_cpu_epapr(platform_t plat, struct pcpu *pc)
|
||||
{
|
||||
vm_paddr_t rel_pa, bptr;
|
||||
volatile struct cpu_release *rel;
|
||||
vm_offset_t rel_va, rel_page;
|
||||
phandle_t node;
|
||||
int i;
|
||||
|
||||
/* If we're calling this, the node already exists. */
|
||||
node = OF_finddevice("/cpus");
|
||||
for (i = 0, node = OF_child(node); i < pc->pc_cpuid;
|
||||
i++, node = OF_peer(node))
|
||||
;
|
||||
if (OF_getencprop(node, "cpu-release-addr", (pcell_t *)&rel_pa,
|
||||
sizeof(rel_pa)) == -1) {
|
||||
return (ENOENT);
|
||||
}
|
||||
|
||||
rel_page = kva_alloc(PAGE_SIZE);
|
||||
if (rel_page == 0)
|
||||
return (ENOMEM);
|
||||
|
||||
critical_enter();
|
||||
rel_va = rel_page + (rel_pa & PAGE_MASK);
|
||||
pmap_kenter(rel_page, rel_pa & ~PAGE_MASK);
|
||||
rel = (struct cpu_release *)rel_va;
|
||||
bptr = pmap_kextract((uintptr_t)__boot_page);
|
||||
cpu_flush_dcache(__DEVOLATILE(struct cpu_release *,rel), sizeof(*rel));
|
||||
rel->pir = pc->pc_cpuid; __asm __volatile("sync");
|
||||
rel->entry_h = (bptr >> 32);
|
||||
rel->entry_l = bptr; __asm __volatile("sync");
|
||||
cpu_flush_dcache(__DEVOLATILE(struct cpu_release *,rel), sizeof(*rel));
|
||||
if (bootverbose)
|
||||
printf("Waking up CPU %d via CPU release page %p\n",
|
||||
pc->pc_cpuid, rel);
|
||||
critical_exit();
|
||||
pmap_kremove(rel_page);
|
||||
kva_free(rel_page, PAGE_SIZE);
|
||||
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
mpc85xx_smp_start_cpu(platform_t plat, struct pcpu *pc)
|
||||
{
|
||||
#ifdef SMP
|
||||
vm_paddr_t bptr;
|
||||
uint32_t reg;
|
||||
int timeout;
|
||||
uintptr_t brr;
|
||||
int cpuid;
|
||||
int epapr_boot = 0;
|
||||
uint32_t tgt;
|
||||
|
||||
if (mpc85xx_is_qoriq()) {
|
||||
reg = ccsr_read4(OCP85XX_COREDISR);
|
||||
cpuid = pc->pc_cpuid;
|
||||
|
||||
if ((reg & (1 << cpuid)) != 0) {
|
||||
printf("%s: CPU %d is disabled!\n", __func__, pc->pc_cpuid);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
brr = OCP85XX_BRR;
|
||||
} else {
|
||||
brr = OCP85XX_EEBPCR;
|
||||
cpuid = pc->pc_cpuid + 24;
|
||||
}
|
||||
bp_kernload = kernload;
|
||||
/*
|
||||
* bp_kernload is in the boot page. Sync the cache because ePAPR
|
||||
* booting has the other core(s) already running.
|
||||
*/
|
||||
cpu_flush_dcache(&bp_kernload, sizeof(bp_kernload));
|
||||
|
||||
ap_pcpu = pc;
|
||||
__asm __volatile("msync; isync");
|
||||
|
||||
/* First try the ePAPR way. */
|
||||
if (mpc85xx_smp_start_cpu_epapr(plat, pc) == 0) {
|
||||
epapr_boot = 1;
|
||||
goto spin_wait;
|
||||
}
|
||||
|
||||
reg = ccsr_read4(brr);
|
||||
if ((reg & (1 << cpuid)) != 0) {
|
||||
printf("SMP: CPU %d already out of hold-off state!\n",
|
||||
pc->pc_cpuid);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
/* Flush caches to have our changes hit DRAM. */
|
||||
cpu_flush_dcache(__boot_page, 4096);
|
||||
|
||||
bptr = pmap_kextract((uintptr_t)__boot_page);
|
||||
KASSERT((bptr & 0xfff) == 0,
|
||||
("%s: boot page is not aligned (%#jx)", __func__, (uintmax_t)bptr));
|
||||
if (mpc85xx_is_qoriq()) {
|
||||
/*
|
||||
* Read DDR controller configuration to select proper BPTR target ID.
|
||||
*
|
||||
* On P5020 bit 29 of DDR1_CS0_CONFIG enables DDR controllers
|
||||
* interleaving. If this bit is set, we have to use
|
||||
* OCP85XX_TGTIF_RAM_INTL as BPTR target ID. On other QorIQ DPAA SoCs,
|
||||
* this bit is reserved and always 0.
|
||||
*/
|
||||
|
||||
reg = ccsr_read4(OCP85XX_DDR1_CS0_CONFIG);
|
||||
if (reg & (1 << 29))
|
||||
tgt = OCP85XX_TGTIF_RAM_INTL;
|
||||
else
|
||||
tgt = OCP85XX_TGTIF_RAM1;
|
||||
|
||||
/*
|
||||
* Set BSTR to the physical address of the boot page
|
||||
*/
|
||||
ccsr_write4(OCP85XX_BSTRH, bptr >> 32);
|
||||
ccsr_write4(OCP85XX_BSTRL, bptr);
|
||||
ccsr_write4(OCP85XX_BSTAR, OCP85XX_ENA_MASK |
|
||||
(tgt << OCP85XX_TRGT_SHIFT_QORIQ) | (ffsl(PAGE_SIZE) - 2));
|
||||
|
||||
/* Read back OCP85XX_BSTAR to synchronize write */
|
||||
ccsr_read4(OCP85XX_BSTAR);
|
||||
|
||||
/*
|
||||
* Enable and configure time base on new CPU.
|
||||
*/
|
||||
|
||||
/* Set TB clock source to platform clock / 32 */
|
||||
reg = ccsr_read4(CCSR_CTBCKSELR);
|
||||
ccsr_write4(CCSR_CTBCKSELR, reg & ~(1 << pc->pc_cpuid));
|
||||
|
||||
/* Enable TB */
|
||||
reg = ccsr_read4(CCSR_CTBENR);
|
||||
ccsr_write4(CCSR_CTBENR, reg | (1 << pc->pc_cpuid));
|
||||
} else {
|
||||
/*
|
||||
* Set BPTR to the physical address of the boot page
|
||||
*/
|
||||
bptr = (bptr >> 12) | 0x80000000u;
|
||||
ccsr_write4(OCP85XX_BPTR, bptr);
|
||||
__asm __volatile("isync; msync");
|
||||
}
|
||||
|
||||
/*
|
||||
* Release AP from hold-off state
|
||||
*/
|
||||
reg = ccsr_read4(brr);
|
||||
ccsr_write4(brr, reg | (1 << cpuid));
|
||||
__asm __volatile("isync; msync");
|
||||
|
||||
spin_wait:
|
||||
timeout = 500;
|
||||
while (!pc->pc_awake && timeout--)
|
||||
DELAY(1000); /* wait 1ms */
|
||||
|
||||
/*
|
||||
* Disable boot page translation so that the 4K page at the default
|
||||
* address (= 0xfffff000) isn't permanently remapped and thus not
|
||||
* usable otherwise.
|
||||
*/
|
||||
if (!epapr_boot) {
|
||||
if (mpc85xx_is_qoriq())
|
||||
ccsr_write4(OCP85XX_BSTAR, 0);
|
||||
else
|
||||
ccsr_write4(OCP85XX_BPTR, 0);
|
||||
__asm __volatile("isync; msync");
|
||||
}
|
||||
|
||||
if (!pc->pc_awake)
|
||||
panic("SMP: CPU %d didn't wake up.\n", pc->pc_cpuid);
|
||||
return ((pc->pc_awake) ? 0 : EBUSY);
|
||||
#else
|
||||
/* No SMP support */
|
||||
return (ENXIO);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
mpc85xx_reset(platform_t plat)
|
||||
{
|
||||
|
||||
/*
|
||||
* Try the dedicated reset register first.
|
||||
* If the SoC doesn't have one, we'll fall
|
||||
* back to using the debug control register.
|
||||
*/
|
||||
ccsr_write4(OCP85XX_RSTCR, 2);
|
||||
|
||||
/* Clear DBCR0, disables debug interrupts and events. */
|
||||
mtspr(SPR_DBCR0, 0);
|
||||
__asm __volatile("isync");
|
||||
|
||||
/* Enable Debug Interrupts in MSR. */
|
||||
mtmsr(mfmsr() | PSL_DE);
|
||||
|
||||
/* Enable debug interrupts and issue reset. */
|
||||
mtspr(SPR_DBCR0, mfspr(SPR_DBCR0) | DBCR0_IDM | DBCR0_RST_SYSTEM);
|
||||
|
||||
printf("Reset failed...\n");
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
static void
|
||||
mpc85xx_smp_timebase_sync(platform_t plat, u_long tb, int ap)
|
||||
{
|
||||
static volatile bool tb_ready;
|
||||
static volatile int cpu_done;
|
||||
|
||||
if (ap) {
|
||||
/* APs. Hold off until we get a stable timebase. */
|
||||
while (!tb_ready)
|
||||
atomic_thread_fence_seq_cst();
|
||||
mttb(tb);
|
||||
atomic_add_int(&cpu_done, 1);
|
||||
while (cpu_done < mp_ncpus)
|
||||
atomic_thread_fence_seq_cst();
|
||||
} else {
|
||||
/* BSP */
|
||||
freeze_timebase(rcpm_dev, true);
|
||||
tb_ready = true;
|
||||
mttb(tb);
|
||||
atomic_add_int(&cpu_done, 1);
|
||||
while (cpu_done < mp_ncpus)
|
||||
atomic_thread_fence_seq_cst();
|
||||
freeze_timebase(rcpm_dev, false);
|
||||
}
|
||||
}
|
||||
|
||||
/* Fallback freeze. In case no real handler is found in the device tree. */
|
||||
static void
|
||||
dummy_freeze(device_t dev, bool freeze)
|
||||
{
|
||||
/* Nothing to do here, move along. */
|
||||
}
|
||||
|
||||
|
||||
/* QorIQ Run control/power management timebase management. */
|
||||
|
||||
#define RCPM_CTBENR 0x00000084
|
||||
struct mpc85xx_rcpm_softc {
|
||||
struct resource *sc_mem;
|
||||
};
|
||||
|
||||
static void
|
||||
mpc85xx_rcpm_freeze_timebase(device_t dev, bool freeze)
|
||||
{
|
||||
struct mpc85xx_rcpm_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
if (freeze)
|
||||
bus_write_4(sc->sc_mem, RCPM_CTBENR, 0);
|
||||
else
|
||||
bus_write_4(sc->sc_mem, RCPM_CTBENR, (1 << maxcpu) - 1);
|
||||
}
|
||||
|
||||
static int
|
||||
mpc85xx_rcpm_probe(device_t dev)
|
||||
{
|
||||
if (!ofw_bus_is_compatible(dev, "fsl,qoriq-rcpm-1.0"))
|
||||
return (ENXIO);
|
||||
|
||||
device_set_desc(dev, "QorIQ Run control and power management");
|
||||
return (BUS_PROBE_GENERIC);
|
||||
}
|
||||
|
||||
static int
|
||||
mpc85xx_rcpm_attach(device_t dev)
|
||||
{
|
||||
struct mpc85xx_rcpm_softc *sc;
|
||||
int rid;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
freeze_timebase = mpc85xx_rcpm_freeze_timebase;
|
||||
rcpm_dev = dev;
|
||||
|
||||
rid = 0;
|
||||
sc->sc_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
|
||||
RF_ACTIVE | RF_SHAREABLE);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static device_method_t mpc85xx_rcpm_methods[] = {
|
||||
DEVMETHOD(device_probe, mpc85xx_rcpm_probe),
|
||||
DEVMETHOD(device_attach, mpc85xx_rcpm_attach),
|
||||
DEVMETHOD_END
|
||||
};
|
||||
|
||||
static devclass_t mpc85xx_rcpm_devclass;
|
||||
|
||||
static driver_t mpc85xx_rcpm_driver = {
|
||||
"rcpm",
|
||||
mpc85xx_rcpm_methods,
|
||||
sizeof(struct mpc85xx_rcpm_softc)
|
||||
};
|
||||
|
||||
EARLY_DRIVER_MODULE(mpc85xx_rcpm, simplebus, mpc85xx_rcpm_driver,
|
||||
mpc85xx_rcpm_devclass, 0, 0, BUS_PASS_BUS);
|
||||
|
||||
|
||||
/* "Global utilities" power management/Timebase management. */
|
||||
|
||||
#define GUTS_DEVDISR 0x00000070
|
||||
#define DEVDISR_TB0 0x00004000
|
||||
#define DEVDISR_TB1 0x00001000
|
||||
|
||||
struct mpc85xx_guts_softc {
|
||||
struct resource *sc_mem;
|
||||
};
|
||||
|
||||
static void
|
||||
mpc85xx_guts_freeze_timebase(device_t dev, bool freeze)
|
||||
{
|
||||
struct mpc85xx_guts_softc *sc;
|
||||
uint32_t devdisr;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
devdisr = bus_read_4(sc->sc_mem, GUTS_DEVDISR);
|
||||
if (freeze)
|
||||
bus_write_4(sc->sc_mem, GUTS_DEVDISR,
|
||||
devdisr | (DEVDISR_TB0 | DEVDISR_TB1));
|
||||
else
|
||||
bus_write_4(sc->sc_mem, GUTS_DEVDISR,
|
||||
devdisr & ~(DEVDISR_TB0 | DEVDISR_TB1));
|
||||
}
|
||||
|
||||
static int
|
||||
mpc85xx_guts_probe(device_t dev)
|
||||
{
|
||||
if (!ofw_bus_is_compatible(dev, "fsl,mpc8572-guts") &&
|
||||
!ofw_bus_is_compatible(dev, "fsl,p1020-guts") &&
|
||||
!ofw_bus_is_compatible(dev, "fsl,p1021-guts") &&
|
||||
!ofw_bus_is_compatible(dev, "fsl,p1022-guts") &&
|
||||
!ofw_bus_is_compatible(dev, "fsl,p1023-guts") &&
|
||||
!ofw_bus_is_compatible(dev, "fsl,p2020-guts"))
|
||||
return (ENXIO);
|
||||
|
||||
device_set_desc(dev, "MPC85xx Global Utilities");
|
||||
return (BUS_PROBE_GENERIC);
|
||||
}
|
||||
|
||||
static int
|
||||
mpc85xx_guts_attach(device_t dev)
|
||||
{
|
||||
struct mpc85xx_rcpm_softc *sc;
|
||||
int rid;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
freeze_timebase = mpc85xx_guts_freeze_timebase;
|
||||
rcpm_dev = dev;
|
||||
|
||||
rid = 0;
|
||||
sc->sc_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
|
||||
RF_ACTIVE | RF_SHAREABLE);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static device_method_t mpc85xx_guts_methods[] = {
|
||||
DEVMETHOD(device_probe, mpc85xx_guts_probe),
|
||||
DEVMETHOD(device_attach, mpc85xx_guts_attach),
|
||||
DEVMETHOD_END
|
||||
};
|
||||
|
||||
static driver_t mpc85xx_guts_driver = {
|
||||
"guts",
|
||||
mpc85xx_guts_methods,
|
||||
sizeof(struct mpc85xx_guts_softc)
|
||||
};
|
||||
|
||||
static devclass_t mpc85xx_guts_devclass;
|
||||
|
||||
EARLY_DRIVER_MODULE(mpc85xx_guts, simplebus, mpc85xx_guts_driver,
|
||||
mpc85xx_guts_devclass, 0, 0, BUS_PASS_BUS);
|
178
freebsd/sys/powerpc/ofw/ofw_pcib_pci.c
Normal file
178
freebsd/sys/powerpc/ofw/ofw_pcib_pci.c
Normal file
@ -0,0 +1,178 @@
|
||||
#include <machine/rtems-bsd-kernel-space.h>
|
||||
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (c) 2000 Michael Smith
|
||||
* Copyright (c) 2000 BSDi
|
||||
* 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 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/systm.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/kernel.h>
|
||||
|
||||
#include <dev/ofw/openfirm.h>
|
||||
#include <dev/ofw/ofw_pci.h>
|
||||
#include <dev/ofw/ofw_bus.h>
|
||||
#include <dev/ofw/ofw_bus_subr.h>
|
||||
|
||||
#include <dev/pci/pcivar.h>
|
||||
#include <dev/pci/pcireg.h>
|
||||
#include <dev/pci/pcib_private.h>
|
||||
|
||||
#include <machine/intr_machdep.h>
|
||||
|
||||
#include <rtems/bsd/local/pcib_if.h>
|
||||
|
||||
static int ofw_pcib_pci_probe(device_t bus);
|
||||
static int ofw_pcib_pci_attach(device_t bus);
|
||||
static phandle_t ofw_pcib_pci_get_node(device_t bus, device_t dev);
|
||||
static int ofw_pcib_pci_route_interrupt(device_t bridge, device_t dev,
|
||||
int intpin);
|
||||
|
||||
static device_method_t ofw_pcib_pci_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, ofw_pcib_pci_probe),
|
||||
DEVMETHOD(device_attach, ofw_pcib_pci_attach),
|
||||
|
||||
/* pcib interface */
|
||||
DEVMETHOD(pcib_route_interrupt, ofw_pcib_pci_route_interrupt),
|
||||
DEVMETHOD(pcib_request_feature, pcib_request_feature_allow),
|
||||
|
||||
/* ofw_bus interface */
|
||||
DEVMETHOD(ofw_bus_get_node, ofw_pcib_pci_get_node),
|
||||
|
||||
DEVMETHOD_END
|
||||
};
|
||||
|
||||
static devclass_t pcib_devclass;
|
||||
|
||||
struct ofw_pcib_softc {
|
||||
/*
|
||||
* This is here so that we can use pci bridge methods, too - the
|
||||
* generic routines only need the dev, secbus and subbus members
|
||||
* filled.
|
||||
*/
|
||||
struct pcib_softc ops_pcib_sc;
|
||||
phandle_t ops_node;
|
||||
struct ofw_bus_iinfo ops_iinfo;
|
||||
};
|
||||
|
||||
DEFINE_CLASS_1(pcib, ofw_pcib_pci_driver, ofw_pcib_pci_methods,
|
||||
sizeof(struct ofw_pcib_softc), pcib_driver);
|
||||
EARLY_DRIVER_MODULE(ofw_pcib, pci, ofw_pcib_pci_driver, pcib_devclass, 0, 0,
|
||||
BUS_PASS_BUS);
|
||||
|
||||
static int
|
||||
ofw_pcib_pci_probe(device_t dev)
|
||||
{
|
||||
|
||||
if ((pci_get_class(dev) != PCIC_BRIDGE) ||
|
||||
(pci_get_subclass(dev) != PCIS_BRIDGE_PCI)) {
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
if (ofw_bus_get_node(dev) == -1)
|
||||
return (ENXIO);
|
||||
|
||||
device_set_desc(dev, "OFW PCI-PCI bridge");
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
ofw_pcib_pci_attach(device_t dev)
|
||||
{
|
||||
struct ofw_pcib_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
sc->ops_pcib_sc.dev = dev;
|
||||
sc->ops_node = ofw_bus_get_node(dev);
|
||||
|
||||
ofw_bus_setup_iinfo(sc->ops_node, &sc->ops_iinfo,
|
||||
sizeof(cell_t));
|
||||
|
||||
pcib_attach_common(dev);
|
||||
return (pcib_attach_child(dev));
|
||||
}
|
||||
|
||||
static phandle_t
|
||||
ofw_pcib_pci_get_node(device_t bridge, device_t dev)
|
||||
{
|
||||
/* We have only one child, the PCI bus, so pass it our node */
|
||||
|
||||
return (ofw_bus_get_node(bridge));
|
||||
}
|
||||
|
||||
static int
|
||||
ofw_pcib_pci_route_interrupt(device_t bridge, device_t dev, int intpin)
|
||||
{
|
||||
struct ofw_pcib_softc *sc;
|
||||
struct ofw_bus_iinfo *ii;
|
||||
struct ofw_pci_register reg;
|
||||
cell_t pintr, mintr[2];
|
||||
int intrcells;
|
||||
phandle_t iparent;
|
||||
|
||||
sc = device_get_softc(bridge);
|
||||
ii = &sc->ops_iinfo;
|
||||
if (ii->opi_imapsz > 0) {
|
||||
pintr = intpin;
|
||||
|
||||
/* Fabricate imap information if this isn't an OFW device */
|
||||
bzero(®, sizeof(reg));
|
||||
reg.phys_hi = (pci_get_bus(dev) << OFW_PCI_PHYS_HI_BUSSHIFT) |
|
||||
(pci_get_slot(dev) << OFW_PCI_PHYS_HI_DEVICESHIFT) |
|
||||
(pci_get_function(dev) << OFW_PCI_PHYS_HI_FUNCTIONSHIFT);
|
||||
|
||||
intrcells = ofw_bus_lookup_imap(ofw_bus_get_node(dev), ii, ®,
|
||||
sizeof(reg), &pintr, sizeof(pintr), mintr, sizeof(mintr),
|
||||
&iparent);
|
||||
if (intrcells) {
|
||||
/*
|
||||
* If we've found a mapping, return it and don't map
|
||||
* it again on higher levels - that causes problems
|
||||
* in some cases, and never seems to be required.
|
||||
*/
|
||||
mintr[0] = ofw_bus_map_intr(dev, iparent, intrcells,
|
||||
mintr);
|
||||
return (mintr[0]);
|
||||
}
|
||||
} else if (intpin >= 1 && intpin <= 4) {
|
||||
/*
|
||||
* When an interrupt map is missing, we need to do the
|
||||
* standard PCI swizzle and continue mapping at the parent.
|
||||
*/
|
||||
return (pcib_route_interrupt(bridge, dev, intpin));
|
||||
}
|
||||
return (PCIB_ROUTE_INTERRUPT(device_get_parent(device_get_parent(
|
||||
bridge)), bridge, intpin));
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user