#include <sys/param.h>
#include <sys/device.h>
#include <sys/systm.h>
#include <machine/bus.h>
#include <dev/cardbus/rbus.h>
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_pci.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pccbbreg.h>
struct rbustag rbus_null;
rbus_tag_t
rbus_pccbb_parent_mem(struct device *self, struct pci_attach_args *pa)
{
struct ofw_pci_register addr[5];
int naddr, len, i;
int space, reg;
int node = PCITAG_NODE(pa->pa_tag);
char buf[32];
if (OF_getprop(node, "name", &buf, sizeof(buf)) > 0 &&
strcmp(buf, "pcma") == 0) {
len = OF_getprop(PCITAG_NODE(pa->pa_tag), "assigned-addresses",
&addr, sizeof(addr));
naddr = len / sizeof(struct ofw_pci_register);
for (i = 0; i < naddr; i++) {
space = addr[i].phys_hi & OFW_PCI_PHYS_HI_SPACEMASK;
if (space != OFW_PCI_PHYS_HI_SPACE_MEM32)
continue;
reg = addr[i].phys_hi & OFW_PCI_PHYS_HI_REGISTERMASK;
if (reg < PCI_CB_MEMBASE0 || reg > PCI_CB_IOLIMIT1)
continue;
return (rbus_new_root_delegate(pa->pa_memt,
addr[i].phys_lo, addr[i].size_lo));
}
}
len = OF_getprop(OF_parent(node), "available", &addr, sizeof(addr));
naddr = len / sizeof(struct ofw_pci_register);
for (i = 0; i < naddr; i++) {
space = addr[i].phys_hi & OFW_PCI_PHYS_HI_SPACEMASK;
if (space != OFW_PCI_PHYS_HI_SPACE_MEM32)
continue;
if (addr[i].size_hi == 0 && addr[i].size_lo < 0x10000000)
continue;
return (rbus_new_root_delegate(pa->pa_memt,
addr[i].phys_lo, addr[i].size_lo));
}
return &rbus_null;
}
rbus_tag_t
rbus_pccbb_parent_io(struct device *self, struct pci_attach_args *pa)
{
struct ofw_pci_register addr[5];
int naddr, len, i;
int space, reg;
int node = PCITAG_NODE(pa->pa_tag);
char buf[32];
if (OF_getprop(node, "name", &buf, sizeof(buf)) > 0 &&
strcmp(buf, "pcma") == 0) {
len = OF_getprop(PCITAG_NODE(pa->pa_tag), "assigned-addresses",
&addr, sizeof(addr));
naddr = len / sizeof(struct ofw_pci_register);
for (i = 0; i < naddr; i++) {
space = addr[i].phys_hi & OFW_PCI_PHYS_HI_SPACEMASK;
if (space != OFW_PCI_PHYS_HI_SPACE_IO)
continue;
reg = addr[i].phys_hi & OFW_PCI_PHYS_HI_REGISTERMASK;
if (reg < PCI_CB_MEMBASE0 || reg > PCI_CB_IOLIMIT1)
continue;
return (rbus_new_root_delegate(pa->pa_iot,
addr[i].phys_lo, addr[i].size_lo));
}
}
len = OF_getprop(OF_parent(node), "available", &addr, sizeof(addr));
naddr = len / sizeof(struct ofw_pci_register);
for (i = 0; i < naddr; i++) {
space = addr[i].phys_hi & OFW_PCI_PHYS_HI_SPACEMASK;
if (space != OFW_PCI_PHYS_HI_SPACE_IO)
continue;
if (addr[i].size_hi == 0 && addr[i].size_lo < 0x00001000)
continue;
return (rbus_new_root_delegate(pa->pa_iot,
addr[i].phys_lo, addr[i].size_lo));
}
return &rbus_null;
}
void
pccbb_attach_hook(struct device *parent, struct device *self,
struct pci_attach_args *pa)
{
pci_chipset_tag_t pc = pa->pa_pc;
int node = PCITAG_NODE(pa->pa_tag);
int bus, busrange[2];
pcireg_t bir;
bir = pci_conf_read(pc, pa->pa_tag, PCI_BUSNUM);
if (((bir >> 8) & 0xff) != 0)
return;
if (OF_getprop(OF_parent(node), "bus-range", &busrange,
sizeof(busrange)) != sizeof(busrange))
return;
bus = busrange[0] + 1;
while (bus < 256 && pc->busnode[bus])
bus++;
if (bus == 256)
return;
pc->busnode[bus] = node;
bir &= ~0x0000ff00;
bir |= (bus << 8);
pci_conf_write(pc, pa->pa_tag, PCI_BUSNUM, bir);
}