Exemple #1
0
static void
uninorth_conf_write_v3(void *cookie, pcitag_t tag, int reg, pcireg_t data)
{
	pci_chipset_tag_t pc = cookie;
	int32_t *daddr = pc->pc_data;
	int bus, dev, func, s;
	uint32_t x;

	if ((unsigned int)reg >= PCI_CONF_SIZE)
		return;

	/* UniNorth seems to have a 64bit data port */
	if (reg & 0x04)
		daddr++;

	pci_decompose_tag(pc, tag, &bus, &dev, &func);

	x = (bus << 16) | (dev << 11) | (func << 8) | (reg & 0xfc) | 1;
	/* Set extended register bits */
	x |= (reg >> 8) << 28;

	s = splhigh();

	out32rb(pc->pc_addr, x);
	in32rb(pc->pc_addr);
	out32rb(daddr, data);
	out32rb(pc->pc_addr, 0);
	in32rb(pc->pc_addr);

	splx(s);
}
Exemple #2
0
/*
 * Reset and enable bmac by heathrow FCR.
 */
void
bmac_reset_chip(struct bmac_softc *sc)
{
	u_int v;

	dbdma_reset(sc->sc_txdma);
	dbdma_reset(sc->sc_rxdma);

	v = in32rb(heathrow_FCR);

	v |= EnetEnable;
	out32rb(heathrow_FCR, v);
	delay(50000);

	/* assert reset */
	v |= ResetEnetCell;
	out32rb(heathrow_FCR, v);
	delay(50000);

	/* deassert reset */
	v &= ~ResetEnetCell;
	out32rb(heathrow_FCR, v);
	delay(50000);

	/* enable */
	v |= EnetEnable;
	out32rb(heathrow_FCR, v);
	delay(50000);

	/* make certain they stay set? */
	out32rb(heathrow_FCR, v);
	v = in32rb(heathrow_FCR);
}
Exemple #3
0
static void
grackle_write_config(device_t dev, u_int bus, u_int slot, u_int func,
    u_int reg, u_int32_t val, int width)
{
	struct		grackle_softc *sc;
	vm_offset_t	caoff;

	sc = device_get_softc(dev);
	caoff = sc->sc_data + (reg & 0x03);

	if (grackle_enable_config(sc, bus, slot, func, reg)) {
		switch (width) {
		case 1:
			out8rb(caoff, val);
			(void)in8rb(caoff);
			break;
		case 2:
			out16rb(caoff, val);
			(void)in16rb(caoff);
			break;
		case 4:
			out32rb(caoff, val);
			(void)in32rb(caoff);
			break;
		}
	}
	grackle_disable_config(sc);
}
Exemple #4
0
void
macobio_modem_power(int enable)
{
	u_int32_t val;
	struct macobio_softc *sc = macobio_cd.cd_devs[0];
	if (PCI_PRODUCT(sc->sc_id) == PCI_PRODUCT_APPLE_KEYLARGO ||
	    PCI_PRODUCT(sc->sc_id) == PCI_PRODUCT_APPLE_INTREPID) {
		val = in32rb(sc->obiomem + 0x40);
		if (enable)
			val = val & ~((u_int32_t)1<<25);
		else 
			val = val | ((u_int32_t)1<<25);
		out32rb(sc->obiomem + 0x40, val);
	}
	if (PCI_PRODUCT(sc->sc_id) == PCI_PRODUCT_APPLE_PANGEA_MACIO) {
		if (enable) {
			/* set reset */
			out8(sc->obiomem + 0x006a + 0x03, 0x04);
			/* power modem on */
			out8(sc->obiomem + 0x006a + 0x02, 0x04);
			/* unset reset */
			out8(sc->obiomem + 0x006a + 0x03, 0x05);
		}  else {
			/* disable it how? */
		}
	}
}
pcireg_t
prep_pci_direct_conf_read(void *v, pcitag_t tag, int reg)
{
	pcireg_t data;
	int bus, device, function;
	int s;

	prep_pci_direct_decompose_tag(v, tag, &bus, &device, &function);

	if (bus == 0) {
		/* Check if device selector is within selector range. */
		if (1 << device & ~PCI_DCONF_DEV) {
			data = ~0;
			goto out;
		}
		tag = (1 << device) | (function << PCI_DCONF_FUNC_SHIFT);
	}

	s = splhigh();
	data = in32rb(PCI_DCONF_BASE | tag | reg);
	splx(s);

out:
	return data;
}
Exemple #6
0
static status_t
grackle_read_pci_config(void *cookie, uint8 bus, uint8 device, uint8 function,
	uint8 offset, uint8 size, uint32 *value)
{
	grackle_host_bridge *bridge = (grackle_host_bridge*)cookie;
	TRACE("grackle_read_pci_config(bus=%u, dev=%u, func=%u, offset=%u, "
		"size=%u)\n", (int)bus, (int)device, (int)function, (int)offset,
		(int)size);

	out32rb(bridge->address_registers, (1 << 31)
		| (bus << 16) | ((device & 0x1f) << 11) | ((function & 0x7) << 8)
		| (offset & 0xfc));

	addr_t dataAddress = bridge->data_registers + (offset & 0x3);
	switch (size) {
		case 1:
			*value = in8rb(dataAddress);
			break;
		case 2:
			*value = in16rb(dataAddress);
			break;
		case 4:
			*value = in32rb(dataAddress);
			break;
		default:
			*value = 0xffffffff;
			break;
	}

	out32rb(bridge->address_registers, 0);

	return B_OK;
}
Exemple #7
0
static int
uninorth_enable_config(struct uninorth_softc *sc, u_int bus, u_int slot,
    u_int func, u_int reg)
{
	u_int32_t	cfgval;

	if (sc->sc_bus == bus) {
		/*
		 * No slots less than 11 on the primary bus
		 */
		if (slot < 11)
			return (0);

		cfgval = (1 << slot) | (func << 8) | (reg & 0xfc);
	} else {
		cfgval = (bus << 16) | (slot << 11) | (func << 8) |
		    (reg & 0xfc) | 1;
	}
        
	do {
		out32rb(sc->sc_addr, cfgval);
	} while (in32rb(sc->sc_addr) != cfgval);

	return (1);
}
Exemple #8
0
static u_int32_t
uninorth_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg,
    int width)
{
	struct		uninorth_softc *sc;
	vm_offset_t	caoff;

	sc = device_get_softc(dev);
	caoff = sc->sc_data + (reg & 0x07);

	if (uninorth_enable_config(sc, bus, slot, func, reg) != 0) {
		switch (width) {
		case 1:
			return (in8rb(caoff));
			break;
		case 2:
			return (in16rb(caoff));
			break;
		case 4:
			return (in32rb(caoff));
			break;
		}
	}

	return (0xffffffff);
}
Exemple #9
0
void
pchbattach(struct device *parent, struct device *self, void *aux)
{
	struct pci_attach_args *pa = aux;
	char devinfo[256];
#if NAGP > 0
	struct agpbus_attach_args apa;
#endif
	volatile unsigned char *python;
	uint32_t v;
	
	aprint_normal("\n");

	/*
	 * All we do is print out a description.  Eventually, we
	 * might want to add code that does something that's
	 * possibly chipset-specific.
	 */

	pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo, sizeof(devinfo));
	aprint_normal("%s: %s (rev. 0x%02x)\n", self->dv_xname, devinfo,
	    PCI_REVISION(pa->pa_class));

	switch (PCI_VENDOR(pa->pa_id)) {
	case PCI_VENDOR_IBM:
		switch (PCI_PRODUCT(pa->pa_id)) {
		case PCI_PRODUCT_IBM_82660:
			ibm82660_print(pa, self);
			break;
		case PCI_PRODUCT_IBM_PYTHON:
			python = mapiodev(0xfeff6000, 0x60);
			v = 0x88b78e01; /* taken from linux */
			out32rb(python+0x30, v);
			v = in32rb(python+0x30);
			aprint_debug("Reset python reg 30 to 0x%x\n", v);
			break;
		}
		break;
	case PCI_VENDOR_MOT:
		switch (PCI_PRODUCT(pa->pa_id)) {
		case PCI_PRODUCT_MOT_MPC105:
			mpc105_print(pa, self);
			break;
		case PCI_PRODUCT_MOT_MPC106:
			mpc106_print(pa, self);
			break;
		}
		break;
	}

#if NAGP > 0
	if (pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_AGP,
			       NULL, NULL) != 0) {
		apa.apa_pci_args = *pa;
		config_found_ia(self, "agpbus", &apa, agpbusprint);
	}
#endif /* NAGP */
}
Exemple #10
0
static pcireg_t
uninorth_conf_read(void *cookie, pcitag_t tag, int reg)
{
	pci_chipset_tag_t pc = cookie;
	int32_t *daddr = pc->pc_data;
	pcireg_t data;
	int bus, dev, func, s;
	uint32_t x;

	if ((unsigned int)reg >= PCI_CONF_SIZE)
		return (pcireg_t) -1;

	/* UniNorth seems to have a 64bit data port */
	if (reg & 0x04)
		daddr++;

	pci_decompose_tag(pc, tag, &bus, &dev, &func);

	/*
	 * bandit's minimum device number of the first bus is 11.
	 * So we behave as if there is no device when dev < 11.
	 */
	if (func > 7)
		panic("pci_conf_read: func > 7");

	if (bus == pc->pc_bus) {
		if (dev < 11)
			return 0xffffffff;
		x = (1 << dev) | (func << 8) | reg;
	} else
		x = tag | reg | 1;

	s = splhigh();

	out32rb(pc->pc_addr, x);
	in32rb(pc->pc_addr);
	data = 0xffffffff;
	if (!badaddr(daddr, 4))
		data = in32rb(daddr);
	out32rb(pc->pc_addr, 0);
	in32rb(pc->pc_addr);
	splx(s);

	return data;
}
Exemple #11
0
u_int32_t
keylargo_fcr_read(int offset)
{
	struct macobio_softc *sc = macobio_cd.cd_devs[0];
	if (sc->obiomem == 0)
		return -1;

	return in32rb(sc->obiomem + offset);
}
Exemple #12
0
/* enable an IRQ on the IOCC */
static void
iocc_enable_irq(struct pic_ops *pic, int irq, int type)
{
        uint32_t mask;

        mask = in32rb(RS6000_BUS_SPACE_IO + IOCC_IEE);
        mask |= 1 << irq;
        out32rb(RS6000_BUS_SPACE_IO + IOCC_IEE, mask);
}
Exemple #13
0
/* disable an IRQ on the IOCC */
static void
iocc_disable_irq(struct pic_ops *pic, int irq)
{
        uint32_t mask;

        mask = in32rb(RS6000_BUS_SPACE_IO + IOCC_IEE);
        mask &= ~(1 << irq);
        out32rb(RS6000_BUS_SPACE_IO + IOCC_IEE, mask);
}
Exemple #14
0
void
macobio_disable(int offset, u_int32_t bits)
{
	struct macobio_softc *sc = macobio_cd.cd_devs[0];
	if (sc->obiomem == 0)
		return;

	bits =  in32rb(sc->obiomem + offset) & ~bits;
	out32rb(sc->obiomem + offset, bits);
}
Exemple #15
0
void
keylargo_fcr_enable(int offset, u_int32_t bits)
{
	struct macobio_softc *sc = macobio_cd.cd_devs[0];
	if (sc->obiomem == 0)
		return;

	bits |=  in32rb(sc->obiomem + offset);
	out32rb(sc->obiomem + offset, bits);
}
Exemple #16
0
static void
ibm82660_print(struct pci_attach_args *pa, struct device *self)
{
	pcireg_t reg1;
#ifdef PREP_BUS_SPACE_IO
	pcireg_t reg2;
#endif
	const char *s1, *s2;

	reg1 = pci_conf_read(pa->pa_pc, pa->pa_tag,
	    IBM_82660_CACHE_STATUS);
#ifdef PREP_BUS_SPACE_IO
	reg2 = in32rb(PREP_BUS_SPACE_IO+IBM_82660_SYSTEM_CTRL);
	if (reg2 & IBM_82660_SYSTEM_CTRL_L2_EN) {
		if (reg1 & IBM_82660_CACHE_STATUS_L2_EN)
			s1 = "internal enabled";
		else
			s1 = "enabled";
		if (reg2 & IBM_82660_SYSTEM_CTRL_L2_MI)
			s2 = "(normal operation)";
		else
			s2 = "(miss updates inhibited)";
	} else {
		s1 = "disabled";
		s2 = "";
	}
#else
	if (reg1 & IBM_82660_CACHE_STATUS_L2_EN)
		s1 = "enabled";
	else
		s1 = "disabled";
	s2 = "";
#endif
	aprint_normal("%s: L1: %s L2: %s %s\n", self->dv_xname,
	    (reg1 & IBM_82660_CACHE_STATUS_L1_EN) ? "enabled" : "disabled",
	    s1, s2);

	reg1 = pci_conf_read(pa->pa_pc, pa->pa_tag, IBM_82660_OPTIONS_1);
	aprint_verbose("%s: MCP# assertion %s "
	    "TEA# assertion %s\n", self->dv_xname,
	    (reg1 & IBM_82660_OPTIONS_1_MCP) ? "enabled" : "disabled",
	    (reg1 & IBM_82660_OPTIONS_1_TEA) ? "enabled" : "disabled");
	aprint_verbose("%s: PCI/ISA I/O mapping %s\n", self->dv_xname,
	    (reg1 & IBM_82660_OPTIONS_1_ISA) ? "contiguous" : "non-contiguous");

	reg1 = pci_conf_read(pa->pa_pc, pa->pa_tag, IBM_82660_OPTIONS_3);
	aprint_normal("%s: DRAM %s (%s) SRAM %s\n", self->dv_xname,
	    (reg1 & IBM_82660_OPTIONS_3_DRAM) ? "EDO" : "standard",
	    (reg1 & IBM_82660_OPTIONS_3_ECC) ? "ECC" : "parity",
	    (reg1 & IBM_82660_OPTIONS_3_SRAM) ? "sync" : "async");
	aprint_verbose("%s: Snoop mode %s\n", self->dv_xname,
	    (reg1 & IBM_82660_OPTIONS_3_SNOOP) ? "603" : "601/604");
}
Exemple #17
0
/*
 * The Kahlua documentation says that "reg" should be left-shifted by two
 * and be in bits 2-7.  Apparently not.  It doesn't work that way, and the
 * DINK32 ROM doesn't do it that way (I peeked at 0xfec00000 after running
 * the DINK32 "pcf" command).
 */
pcireg_t
pci_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg)
{
	pcireg_t data;

	if ((unsigned int)reg >= PCI_CONF_SIZE)
		return (pcireg_t) -1;

	out32rb(SANDPOINT_PCI_CONFIG_ADDR, tag | reg);
	data = in32rb(SANDPOINT_PCI_CONFIG_DATA);
	out32rb(SANDPOINT_PCI_CONFIG_ADDR, 0);
	return data;
}
pcireg_t
ibmnws_pci_indirect_conf_read(void *v, pcitag_t tag, int reg)
{
	pcireg_t data;
	int s;

	s = splhigh();
	out32rb(PCI_MODE1_ADDRESS_REG, tag | reg);
	data = in32rb(PCI_MODE1_DATA_REG);
	out32rb(PCI_MODE1_ADDRESS_REG, 0);
	splx(s);

	return data;
}
Exemple #19
0
static void
uninorth_conf_write(void *cookie, pcitag_t tag, int reg, pcireg_t data)
{
	pci_chipset_tag_t pc = cookie;
	int32_t *daddr = pc->pc_data;
	int bus, dev, func, s;
	uint32_t x;

	if ((unsigned int)reg >= PCI_CONF_SIZE)
		return;

	/* UniNorth seems to have a 64bit data port */
	if (reg & 0x04)
		daddr++;

	pci_decompose_tag(pc, tag, &bus, &dev, &func);

	if (func > 7)
		panic("pci_conf_write: func > 7");

	if (bus == pc->pc_bus) {
		if (dev < 11)
			panic("pci_conf_write: dev < 11");
		x = (1 << dev) | (func << 8) | reg;
	} else
		x = tag | reg | 1;

	s = splhigh();

	out32rb(pc->pc_addr, x);
	in32rb(pc->pc_addr);
	out32rb(daddr, data);
	out32rb(pc->pc_addr, 0);
	in32rb(pc->pc_addr);

	splx(s);
}
Exemple #20
0
/*
 * the IOCC IER is a bitmask of pending IRQs, where only 0-15 are valid
 */
static int
iocc_get_irq(struct pic_ops *pic, int mode)
{
        int irq;
        uint32_t rv = 0;

        rv = in32rb(RS6000_BUS_SPACE_IO + IOCC_IRR);
        if (rv == 0)
                return 255;

        irq = 31 - __builtin_clz(rv);
        if (irq >= 0 && irq < 16)
                return irq;
        return 255;
}
Exemple #21
0
static int
grackle_enable_config(struct grackle_softc *sc, u_int bus, u_int slot,
    u_int func, u_int reg)
{
	u_int32_t	cfgval;

	/*
	 * Unlike UniNorth, the format of the config word is the same
	 * for local (0) and remote busses.
	 */
	cfgval = (bus << 16) | (slot << 11) | (func << 8) | (reg & 0xFC)
	    | GRACKLE_CFG_ENABLE;

	out32rb(sc->sc_addr, cfgval);
	(void) in32rb(sc->sc_addr);

	return (1);
}
Exemple #22
0
static pcireg_t
grackle_conf_read(void *cookie, pcitag_t tag, int reg)
{
	pci_chipset_tag_t pc = cookie;
	pcireg_t data;
	int s;

	s = splhigh();

	out32rb(pc->pc_addr, tag | reg);
	data = 0xffffffff;
	if (!badaddr(pc->pc_data, 4))
		data = in32rb(pc->pc_data);
	out32rb(pc->pc_addr, 0);

	splx(s);

	return data;
}
Exemple #23
0
static int
uninorth_enable_config(struct uninorth_softc *sc, u_int bus, u_int slot,
    u_int func, u_int reg)
{
	uint32_t	cfgval;
	uint32_t	pass;

	if (resource_int_value(device_get_name(sc->pci_sc.sc_dev),
	        device_get_unit(sc->pci_sc.sc_dev), "skipslot", &pass) == 0) {
		if (pass == slot)
			return (0);
	}

	/*
	 * Issue type 0 configuration space accesses for the root bus.
	 *
	 * NOTE: On U4, issue only type 1 accesses. There is a secret
	 * PCI Express <-> PCI Express bridge not present in the device tree,
	 * and we need to route all of our configuration space through it.
	 */
	if (sc->pci_sc.sc_bus == bus && sc->sc_ver < 4) {
		/*
		 * No slots less than 11 on the primary bus on U3 and lower
		 */
		if (slot < 11)
			return (0);

		cfgval = (1 << slot) | (func << 8) | (reg & 0xfc);
	} else {
		cfgval = (bus << 16) | (slot << 11) | (func << 8) |
		    (reg & 0xfc) | 1;
	}

	/* Set extended register bits on U4 */
	if (sc->sc_ver == 4)
		cfgval |= (reg >> 8) << 28;

	do {
		out32rb(sc->sc_addr, cfgval);
	} while (in32rb(sc->sc_addr) != cfgval);

	return (1);
}
Exemple #24
0
static u_int32_t
grackle_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg,
    int width)
{
	struct		grackle_softc *sc;
	vm_offset_t	caoff;
	u_int32_t	retval = 0xffffffff;

	sc = device_get_softc(dev);
	caoff = sc->sc_data + (reg & 0x03);

	if (grackle_enable_config(sc, bus, slot, func, reg) != 0) {

		/*
		 * Config probes to non-existent devices on the
		 * secondary bus generates machine checks. Be sure
		 * to catch these.
		 */
		if (bus > 0) {
		  if (badaddr((void *)sc->sc_data, 4)) {
			  return (retval);
		  }
		}

		switch (width) {
		case 1:
			retval = (in8rb(caoff));
			break;
		case 2:
			retval = (in16rb(caoff));
			break;
		case 4:
			retval = (in32rb(caoff));
			break;
		}
	}
	grackle_disable_config(sc);

	return (retval);
}
Exemple #25
0
static void
battery_attach(struct device *parent, struct device *self, void *aux)
{
	struct battery_attach_args *baa = aux;
	struct battery_softc *sc = (struct battery_softc *)self;
	uint32_t reg;

	sc->sc_pmu_ops = baa->baa_pmu_ops;
	printf(": legacy battery ");

	reg = in32rb(0xf3000034);
	DPRINTF("reg: %08x\n", reg);
	if (reg & 0x20000000) {
		sc->sc_type = BTYPE_HOOPER;
		sc->sc_vmax_charged = 330;
		sc->sc_vmax_charging = 365;
		printf("[hooper]\n");
	} else {
		sc->sc_type = BTYPE_COMET;
		sc->sc_vmax_charged = 189;
		sc->sc_vmax_charging = 213;
		printf("[comet]\n");
	}
	battery_update(sc, 1);
	/* trigger a status update */
	sc->sc_oflags = ~sc->sc_flags;

	battery_setup_envsys(sc);
	sc->sc_pmu_ops->register_callback(sc->sc_pmu_ops->cookie, battery_poll,
	    sc);

	memset(&sc->sc_sm_acpower, 0, sizeof(struct sysmon_pswitch));
	sc->sc_sm_acpower.smpsw_name = "AC Power";
	sc->sc_sm_acpower.smpsw_type = PSWITCH_TYPE_ACADAPTER;
	if (sysmon_pswitch_register(&sc->sc_sm_acpower) != 0)
		printf("%s: unable to register AC power status with sysmon\n",
		    sc->sc_dev.dv_xname);

}
Exemple #26
0
void
xlights_attach(struct device *parent, struct device *self, void *aux)
{
	struct xlights_softc *sc = (struct xlights_softc *)self;
	struct confargs *ca = aux;
	int nseg, error, intr[6];
	u_int32_t reg[4];
	int type;

	sc->sc_node = OF_child(ca->ca_node);

	OF_getprop(sc->sc_node, "reg", reg, sizeof(reg));
	ca->ca_reg[0] += ca->ca_baseaddr;
	ca->ca_reg[2] += ca->ca_baseaddr;

	if ((sc->sc_reg = mapiodev(ca->ca_reg[0], ca->ca_reg[1])) == NULL) {
		printf(": cannot map registers\n");
		return;
	}
	sc->sc_dmat = ca->ca_dmat;

	if ((sc->sc_dma = mapiodev(ca->ca_reg[2], ca->ca_reg[3])) == NULL) {
		printf(": cannot map DMA registers\n");
		goto nodma;
	}

	if ((sc->sc_dbdma = dbdma_alloc(sc->sc_dmat, BL_DBDMA_CMDS)) == NULL) {
		printf(": cannot alloc DMA descriptors\n");
		goto nodbdma;
	 }
	sc->sc_dmacmd = sc->sc_dbdma->d_addr;

	if ((error = bus_dmamem_alloc(sc->sc_dmat, BL_BUFSZ, 0, 0,
		sc->sc_bufseg, 1, &nseg, BUS_DMA_NOWAIT))) {
		printf(": cannot allocate DMA mem (%d)\n", error);
		goto nodmamem;
	}

	if ((error = bus_dmamem_map(sc->sc_dmat, sc->sc_bufseg, nseg,
	    BL_BUFSZ, (caddr_t *)&sc->sc_buf, BUS_DMA_NOWAIT))) {
		printf(": cannot map DMA mem (%d)\n", error);
		goto nodmamap;
	}
	sc->sc_bufpos = sc->sc_buf;

	if ((error = bus_dmamap_create(sc->sc_dmat, BL_BUFSZ, 1, BL_BUFSZ, 0,
	    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &sc->sc_bufmap))) {
		printf(": cannot create DMA map (%d)\n", error);
		goto nodmacreate;
	}

	if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_bufmap, sc->sc_buf,
	    BL_BUFSZ, NULL, BUS_DMA_NOWAIT))) {
		printf(": cannot load DMA map (%d)\n", error);
		goto nodmaload;
	}
	/* XXX: Should probably extract this from the clock data
	 * property of the soundchip node */
	sc->sc_freq = 16384;

	OF_getprop(sc->sc_node, "interrupts", intr, sizeof(intr));
	/* output interrupt */
	sc->sc_intr = intr[2];
	type = intr[3] ? IST_LEVEL : IST_EDGE;

	printf(": irq %d\n", sc->sc_intr);

	macobio_enable(I2SClockOffset, I2S0EN);
	out32rb(sc->sc_reg + I2S_INT, I2S_INT_CLKSTOPPEND);
	macobio_disable(I2SClockOffset, I2S0CLKEN);
	for (error = 0; error < 1000; error++) {
		if (in32rb(sc->sc_reg + I2S_INT) & I2S_INT_CLKSTOPPEND) {
			error = 0;
			break;
		}
		delay(1);
	}
	if (error) {
		printf("%s: i2s timeout\n", sc->sc_dev.dv_xname);
		goto nodmaload;
	}

	mac_intr_establish(parent, sc->sc_intr, intr[3] ? IST_LEVEL :
	    type, IPL_AUDIO, xlights_intr, sc, sc->sc_dev.dv_xname);

	out32rb(sc->sc_reg + I2S_FORMAT, CLKSRC_VS);
	macobio_enable(I2SClockOffset, I2S0CLKEN);

	kthread_create_deferred(xlights_deferred, sc);
	timeout_set(&sc->sc_tmo, xlights_timeout, sc);
	return;
nodmaload:
	bus_dmamap_destroy(sc->sc_dmat, sc->sc_bufmap);
nodmacreate:
	bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_buf, BL_BUFSZ);
nodmamap:
	bus_dmamem_free(sc->sc_dmat, sc->sc_bufseg, nseg);
nodmamem:
	dbdma_free(sc->sc_dbdma);
nodbdma:
	unmapiodev((void *)sc->sc_dma, ca->ca_reg[3]);
nodma:
	unmapiodev(sc->sc_reg, ca->ca_reg[1]);
}
void
wdc_obio_attach(device_t parent, device_t self, void *aux)
{
	struct wdc_obio_softc *sc = device_private(self);
	struct wdc_regs *wdr;
	struct confargs *ca = aux;
	struct ata_channel *chp = &sc->sc_channel;
	int intr, i, type = IST_EDGE;
	int use_dma = 0;
	char path[80];

	sc->sc_wdcdev.sc_atac.atac_dev = self;
	if (device_cfdata(sc->sc_wdcdev.sc_atac.atac_dev)->cf_flags &
	    WDC_OPTIONS_DMA) {
		if (ca->ca_nreg >= 16 || ca->ca_nintr == -1)
			use_dma = 1;	/* XXX Don't work yet. */
	}

	if (ca->ca_nintr >= 4 && ca->ca_nreg >= 8) {
		intr = ca->ca_intr[0];
		aprint_normal(" irq %d", intr);
		if (ca->ca_nintr > 8) {
			type = ca->ca_intr[1] ? IST_LEVEL : IST_EDGE;
		}
		aprint_normal(", %s triggered", (type == IST_EDGE) ? "edge" : "level");
	} else if (ca->ca_nintr == -1) {
		intr = WDC_DEFAULT_PIO_IRQ;
		aprint_normal(" irq property not found; using %d", intr);
	} else {
		aprint_error(": couldn't get irq property\n");
		return;
	}

	if (use_dma)
		aprint_normal(": DMA transfer");

	aprint_normal("\n");

	sc->sc_wdcdev.regs = wdr = &sc->sc_wdc_regs;

	wdr->cmd_iot = wdr->ctl_iot = ca->ca_tag;

	if (bus_space_map(wdr->cmd_iot, ca->ca_baseaddr + ca->ca_reg[0],
	    WDC_REG_NPORTS << 4, 0, &wdr->cmd_baseioh) ||
	    bus_space_subregion(wdr->cmd_iot, wdr->cmd_baseioh,
			WDC_AUXREG_OFFSET << 4, 1, &wdr->ctl_ioh)) {
		aprint_error_dev(self, "couldn't map registers\n");
		return;
	}

	for (i = 0; i < WDC_NREG; i++) {
		if (bus_space_subregion(wdr->cmd_iot, wdr->cmd_baseioh, i << 4,
		    i == 0 ? 4 : 1, &wdr->cmd_iohs[i]) != 0) {
			bus_space_unmap(wdr->cmd_iot, wdr->cmd_baseioh,
			    WDC_REG_NPORTS << 4);
			aprint_error_dev(self,
			    "couldn't subregion registers\n");
			return;
		}
	}
#if 0
	wdr->data32iot = wdr->cmd_iot;
	wdr->data32ioh = wdr->cmd_ioh;
#endif

	sc->sc_ih = intr_establish(intr, type, IPL_BIO, wdcintr, chp);

	if (use_dma) {
		sc->sc_dmacmd = dbdma_alloc(sizeof(dbdma_command_t) * 20);
		/*
		 * XXX
		 * we don't use ca->ca_reg[3] for size here because at least
		 * on the PB3400c it says 0x200 for both IDE channels ( the
		 * one on the mainboard and the other on the mediabay ) but
		 * their start addresses are only 0x100 apart. Since those
		 * DMA registers are always 0x100 or less we don't really 
		 * have to care though
		 */
		if (bus_space_map(wdr->cmd_iot, ca->ca_baseaddr + ca->ca_reg[2],
		    0x100, BUS_SPACE_MAP_LINEAR, &sc->sc_dmaregh)) {

			aprint_error_dev(self,
			    "unable to map DMA registers (%08x)\n",
			    ca->ca_reg[2]);
			/* should unmap stuff here */
			return;
		}
		sc->sc_dmareg = bus_space_vaddr(wdr->cmd_iot, sc->sc_dmaregh);

		sc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_DMA;
		sc->sc_wdcdev.sc_atac.atac_dma_cap = 2;
		if (strcmp(ca->ca_name, "ata-4") == 0) {
			sc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_UDMA;
			sc->sc_wdcdev.sc_atac.atac_udma_cap = 4;
			sc->sc_wdcdev.sc_atac.atac_set_modes = 
			    ata4_adjust_timing;
		} else {
			sc->sc_wdcdev.sc_atac.atac_set_modes = adjust_timing;
		}
#ifdef notyet
		/* Minimum cycle time is 150ns (DMA MODE 1) on ohare. */
		if (ohare) {
			sc->sc_wdcdev.sc_atac.atac_pio_cap = 3;
			sc->sc_wdcdev.sc_atac.atac_dma_cap = 1;
		}
#endif
	} else {
		/* all non-DMA controllers can use adjust_timing */
		sc->sc_wdcdev.sc_atac.atac_set_modes = adjust_timing;
	}

	sc->sc_wdcdev.sc_atac.atac_pio_cap = 4;
	sc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_DATA16;
	sc->sc_chanptr = chp;
	sc->sc_wdcdev.sc_atac.atac_channels = &sc->sc_chanptr;
	sc->sc_wdcdev.sc_atac.atac_nchannels = 1;
	sc->sc_wdcdev.wdc_maxdrives = 2;
	sc->sc_wdcdev.dma_arg = sc;
	sc->sc_wdcdev.dma_init = wdc_obio_dma_init;
	sc->sc_wdcdev.dma_start = wdc_obio_dma_start;
	sc->sc_wdcdev.dma_finish = wdc_obio_dma_finish;
	chp->ch_channel = 0;
	chp->ch_atac = &sc->sc_wdcdev.sc_atac;
	chp->ch_queue = &sc->sc_chqueue;

	wdc_init_shadow_regs(chp);

#define OHARE_FEATURE_REG	0xf3000038

	/* XXX Enable wdc1 by feature reg. */
	memset(path, 0, sizeof(path));
	OF_package_to_path(ca->ca_node, path, sizeof(path));
	if (strcmp(path, "/bandit@F2000000/ohare@10/ata@21000") == 0) {
		u_int x;

		x = in32rb(OHARE_FEATURE_REG);
		x |= 8;
		out32rb(OHARE_FEATURE_REG, x);
	}

	wdcattach(chp);
}
static void
mbattach(struct device *parent, struct device *self, void *aux)
{
	struct mainbus_softc *sc = (struct mainbus_softc *)self;
	struct confargs nca;
	char name[64], *t = NULL;
	int reg[4], cpucnt;
	int node, len, slen;

	node = OF_peer(0);
	len = OF_getprop(node, "model", name, sizeof(name));
	if (len > 1) {
		name[len] = '\0';
		slen = strlen(name)+1;
		if ((t = malloc(slen, M_DEVBUF, M_NOWAIT)) != NULL)
			strlcpy(t, name, slen);

	}

	len = OF_getprop(node, "compatible", name, sizeof(name));
	if (len > 1) {
		name[len] = '\0';
		/* Old World Macintosh */
		if ((strncmp(name, "AAPL", 4)) == 0) {
			hw_vendor = "Apple Computer, Inc.";
			slen = strlen(t) + strlen(name) - 3;
			if ((hw_prod = malloc(slen, M_DEVBUF, M_NOWAIT)) != NULL) {
				snprintf(hw_prod, slen, "%s %s", t, name + 5);
				free(t, M_DEVBUF);
			}
		} else {
			/* New World Macintosh or Unknown */
			hw_vendor = "Apple Computer, Inc.";
			hw_prod = t;
		}
	}
	printf(": model %s\n", hw_prod);

	sc->sc_bus.bh_dv = (struct device *)sc;
	sc->sc_bus.bh_type = BUS_MAIN;
	sc->sc_bus.bh_intr_establish = mb_intr_establish;
	sc->sc_bus.bh_intr_disestablish = mb_intr_disestablish;
	sc->sc_bus.bh_matchname = mb_matchname;

	/*
	 * Try to find and attach all of the CPUs in the machine.
	 */

	cpucnt = 0;
	node = OF_finddevice("/cpus");
	if (node != -1) {
		for (node = OF_child(node); node != 0; node = OF_peer(node)) {
			u_int32_t cpunum;
			int len;
			len = OF_getprop(node, "reg", &cpunum, sizeof cpunum);
			if (len == 4 && cpucnt == cpunum) {
				nca.ca_name = "cpu";
				nca.ca_bus = &sc->sc_bus;
				nca.ca_reg = reg;
				reg[0] = cpucnt;
				config_found(self, &nca, mbprint);
				cpucnt++;
			}
		}
	}
	if (cpucnt == 0) {
		nca.ca_name = "cpu";
		nca.ca_bus = &sc->sc_bus;
		nca.ca_reg = reg;
		reg[0] = 0;
		config_found(self, &nca, mbprint);
	}

	/*
	 * Special hack for SMP old world macs which lack /cpus and only have
	 * one cpu node.
	 */
	node = OF_finddevice("/hammerhead");
	if (node != -1) {
		len = OF_getprop(node, "reg", reg, sizeof(reg));
		if (len >= 2) {
			u_char *hh_base;
			int twoway = 0;

			if ((hh_base = mapiodev(reg[0], reg[1])) != NULL) {
				twoway = in32rb(hh_base + HH_REG_CONF) & 0x02;
				unmapiodev(hh_base, reg[1]);
			}
			if (twoway) {
				nca.ca_name = "cpu";
				nca.ca_bus = &sc->sc_bus;
				nca.ca_reg = reg;
				reg[0] = 1;
				config_found(self, &nca, mbprint);
			}
		}
	}

	for (node = OF_child(OF_peer(0)); node; node=OF_peer(node)) {
		bzero (name, sizeof(name));
		if (OF_getprop(node, "device_type", name,
		    sizeof(name)) <= 0) {
			if (OF_getprop(node, "name", name,
			    sizeof(name)) <= 0)
				printf ("name not found on node %x\n",
				    node);
				continue;
		}
		if (strcmp(name, "memory") == 0) {
			nca.ca_name = "mem";
			nca.ca_node = node;
			nca.ca_bus = &sc->sc_bus;
			config_found(self, &nca, mbprint);
		}
		if (strcmp(name, "memory-controller") == 0) {
			nca.ca_name = "memc";
			nca.ca_node = node;
			nca.ca_bus = &sc->sc_bus;
			config_found(self, &nca, mbprint);
		}
		if (strcmp(name, "pci") == 0) {
			nca.ca_name = "mpcpcibr";
			nca.ca_node = node;
			nca.ca_bus = &sc->sc_bus;
			config_found(self, &nca, mbprint);
		}
		if (strcmp(name, "ht") == 0) {
			nca.ca_name = "ht";
			nca.ca_node = node;
			nca.ca_bus = &sc->sc_bus;
			config_found(self, &nca, mbprint);
		}
		if (strcmp(name, "smu") == 0) {
			nca.ca_name = "smu";
			nca.ca_node = node;
			nca.ca_bus = &sc->sc_bus;
			config_found(self, &nca, mbprint);
		}
	}
}