コード例 #1
0
static void
jmahci_attach(device_t parent, device_t self, void *aux)
{
	struct jmahci_attach_args *jma = aux;
	const struct pci_attach_args *pa = jma->jma_pa;
	struct ahci_softc *sc = device_private(self);
	uint32_t ahci_cap;

	aprint_naive(": AHCI disk controller\n");
	aprint_normal("\n");

	sc->sc_atac.atac_dev = self;
	sc->sc_ahcit = jma->jma_ahcit;
	sc->sc_ahcih = jma->jma_ahcih;

	ahci_cap = AHCI_READ(sc, AHCI_CAP);

	if (pci_dma64_available(jma->jma_pa) && (ahci_cap & AHCI_CAP_64BIT))
		sc->sc_dmat = jma->jma_pa->pa_dmat64;
	else
		sc->sc_dmat = jma->jma_pa->pa_dmat;

	if (PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_MASS_STORAGE_RAID)
		sc->sc_atac_capflags = ATAC_CAP_RAID;

	ahci_attach(sc);

	if (!pmf_device_register(self, NULL, jmahci_resume))
	    aprint_error_dev(self, "couldn't establish power handler\n");
}
コード例 #2
0
ファイル: ahci_generic.c プロジェクト: 2trill2spill/freebsd
static int
ahci_gen_attach(device_t dev)
{
	struct ahci_controller *ctlr = device_get_softc(dev);
	int	error;

	ctlr->r_rid = 0;
	ctlr->r_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &ctlr->r_rid,
	    RF_ACTIVE);
	if (ctlr->r_mem == NULL)
		return (ENXIO);

	/* Setup controller defaults. */
	ctlr->numirqs = 1;

	/* Reset controller */
	if ((error = ahci_gen_ctlr_reset(dev)) == 0)
		error = ahci_attach(dev);

	if (error != 0) {
		if (ctlr->r_mem != NULL)
			bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_rid,
			    ctlr->r_mem);
	}
	return error;
}
コード例 #3
0
ファイル: imxahci.c プロジェクト: enukane/openbsd-work
void
imxahci_attach(struct device *parent, struct device *self, void *args)
{
	struct armv7_attach_args *aa = args;
	struct imxahci_softc *imxsc = (struct imxahci_softc *) self;
	struct ahci_softc *sc = &imxsc->sc;
	uint32_t timeout = 0x100000;

	sc->sc_iot = aa->aa_iot;
	sc->sc_ios = aa->aa_dev->mem[0].size;
	sc->sc_dmat = aa->aa_dmat;

	if (bus_space_map(sc->sc_iot, aa->aa_dev->mem[0].addr,
	    aa->aa_dev->mem[0].size, 0, &sc->sc_ioh))
		panic("imxahci_attach: bus_space_map failed!");

	sc->sc_ih = arm_intr_establish(aa->aa_dev->irq[0], IPL_BIO,
	    ahci_intr, sc, sc->sc_dev.dv_xname);
	if (sc->sc_ih == NULL) {
		printf(": unable to establish interrupt\n");
		goto unmap;
	}

	/* power it up */
	imxccm_enable_sata();
	delay(100);

	/* power phy up */
	imxiomuxc_enable_sata();

	/* setup */
	bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYCR,
	    bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYCR) & ~SATA_P0PHYCR_TEST_PDDQ);

	bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_GHC, SATA_GHC_HR);

	while (!bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_VERSIONR));

	bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_CAP,
	    bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_CAP) | SATA_CAP_SSS);

	bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_PI, 1);

	bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_TIMER1MS, imxccm_get_ahbclk());

	while (!(bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_P0SSTS) & 0xF) && timeout--);

	if (ahci_attach(sc) != 0) {
		/* error printed by ahci_attach */
		goto irq;
	}

	return;
irq:
	arm_intr_disestablish(sc->sc_ih);
unmap:
	bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
}
コード例 #4
0
static void
ahci_pci_attach(device_t parent, device_t self, void *aux)
{
	struct pci_attach_args *pa = aux;
	struct ahci_pci_softc *psc = device_private(self);
	struct ahci_softc *sc = &psc->ah_sc;
	bus_size_t size;
	char devinfo[256];
	const char *intrstr;
	pci_intr_handle_t intrhandle;
	void *ih;

	sc->sc_atac.atac_dev = self;

	if (pci_mapreg_map(pa, AHCI_PCI_ABAR,
	    PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT, 0,
	    &sc->sc_ahcit, &sc->sc_ahcih, NULL, &size) != 0) {
		aprint_error_dev(self, "can't map ahci registers\n");
		return;
	}
	psc->sc_pc = pa->pa_pc;
	psc->sc_pcitag = pa->pa_tag;

	pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo, sizeof(devinfo));
	aprint_naive(": AHCI disk controller\n");
	aprint_normal(": %s\n", devinfo);
	
	if (pci_intr_map(pa, &intrhandle) != 0) {
		aprint_error("%s: couldn't map interrupt\n", AHCINAME(sc));
		return;
	}
	intrstr = pci_intr_string(pa->pa_pc, intrhandle);
	ih = pci_intr_establish(pa->pa_pc, intrhandle, IPL_BIO, ahci_intr, sc);
	if (ih == NULL) {
		aprint_error("%s: couldn't establish interrupt", AHCINAME(sc));
		return;
	}
	aprint_normal("%s: interrupting at %s\n", AHCINAME(sc),
	    intrstr ? intrstr : "unknown interrupt");
	sc->sc_dmat = pa->pa_dmat;

	if (PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_MASS_STORAGE_RAID) {
		AHCIDEBUG_PRINT(("%s: RAID mode\n", AHCINAME(sc)), DEBUG_PROBE);
		sc->sc_atac_capflags = ATAC_CAP_RAID;
	} else {
		AHCIDEBUG_PRINT(("%s: SATA mode\n", AHCINAME(sc)), DEBUG_PROBE);
	}

	ahci_attach(sc);

	if (!pmf_device_register(self, NULL, ahci_pci_resume))
		aprint_error_dev(self, "couldn't establish power handler\n");
}
コード例 #5
0
ファイル: ahci_pci.c プロジェクト: SylvestreG/bitrig
void
ahci_pci_attach(struct device *parent, struct device *self, void *aux)
{
	struct ahci_pci_softc		*psc = (struct ahci_pci_softc *)self;
	struct ahci_softc		*sc = &psc->psc_ahci;
	struct pci_attach_args		*pa = aux;
	const struct ahci_device	*ad;
	pci_intr_handle_t		ih;
	int				mapped = 0;

	psc->psc_pc = pa->pa_pc;
	psc->psc_tag = pa->pa_tag;
	sc->sc_dmat = pa->pa_dmat;

	ad = ahci_lookup_device(pa);
	if (ad != NULL && ad->ad_attach != NULL) {
		if (ad->ad_attach(sc, pa) != 0) {
			/* error should be printed by ad_attach */
			return;
		}
	}

	if (!(sc->sc_flags & AHCI_F_NO_MSI))
		mapped = pci_intr_map_msi(pa, &ih) != 0 ? 0 : 1;
	
	if (!mapped && pci_intr_map(pa, &ih) != 0) {
		printf(": unable to map interrupt\n");
		return;
	}
	printf(": %s,", pci_intr_string(pa->pa_pc, ih));

	if (ahci_map_regs(psc, pa) != 0) {
		/* error already printed by ahci_map_regs */
		return;
	}

	if (ahci_map_intr(psc, pa, ih) != 0) {
		/* error already printed by ahci_map_intr */
		goto unmap;
	}

	if (ahci_attach(sc) != 0) {
		/* error printed by ahci_attach */
		goto unmap;
	}

	return;

unmap:
	ahci_unmap_regs(psc);
	return;
}
コード例 #6
0
static void
tegra_ahcisata_attach(device_t parent, device_t self, void *aux)
{
    struct tegra_ahcisata_softc * const sc = device_private(self);
    struct tegraio_attach_args * const tio = aux;
    const struct tegra_locators * const loc = &tio->tio_loc;
    prop_dictionary_t prop = device_properties(self);
    const char *pin;

    sc->sc_bst = tio->tio_bst;
    bus_space_subregion(tio->tio_bst, tio->tio_bsh,
                        loc->loc_offset, loc->loc_size, &sc->sc_bsh);

    sc->sc.sc_atac.atac_dev = self;
    sc->sc.sc_dmat = tio->tio_dmat;
    sc->sc.sc_ahcit = tio->tio_bst;
    sc->sc.sc_ahcis = loc->loc_size - TEGRA_AHCISATA_OFFSET;
    bus_space_subregion(tio->tio_bst, tio->tio_bsh,
                        loc->loc_offset + TEGRA_AHCISATA_OFFSET,
                        loc->loc_size - TEGRA_AHCISATA_OFFSET, &sc->sc.sc_ahcih);
    sc->sc.sc_ahci_quirks = AHCI_QUIRK_SKIP_RESET;

    aprint_naive("\n");
    aprint_normal(": SATA\n");

    if (prop_dictionary_get_cstring_nocopy(prop, "power-gpio", &pin)) {
        sc->sc_pin_power = tegra_gpio_acquire(pin, GPIO_PIN_OUTPUT);
        if (sc->sc_pin_power)
            tegra_gpio_write(sc->sc_pin_power, 1);
    }

    tegra_car_periph_sata_enable();

    tegra_xusbpad_sata_enable();

    tegra_ahcisata_init(sc);

    sc->sc_ih = intr_establish(loc->loc_intr, IPL_BIO, IST_LEVEL,
                               ahci_intr, &sc->sc);
    if (sc->sc_ih == NULL) {
        aprint_error_dev(self, "couldn't establish interrupt %d\n",
                         loc->loc_intr);
        return;
    }
    aprint_normal_dev(self, "interrupting on irq %d\n", loc->loc_intr);

    ahci_attach(&sc->sc);
}
コード例 #7
0
static void
imx6_ahcisata_attach(device_t parent, device_t self, void *aux)
{
	struct imx_ahci_softc *sc;
	struct ahci_softc *ahci_sc;
	struct axi_attach_args *aa;

	aa = aux;
	sc = device_private(self);
	sc->sc_dev = self;
	sc->sc_iot = aa->aa_iot;

	if (aa->aa_size == AXICF_SIZE_DEFAULT)
		aa->aa_size = IMX6_SATA_SIZE;

	aprint_naive("\n");
	aprint_normal(": AHCI Controller\n");

	if (bus_space_map(aa->aa_iot, aa->aa_addr, aa->aa_size, 0,
	    &sc->sc_ioh)) {
		aprint_error_dev(self, "cannot map registers\n");
		return;
	}

	if (ixm6_ahcisata_init(sc) != 0) {
		aprint_error_dev(self, "couldn't init ahci\n");
		return;
	}

	ahci_sc = &sc->sc_ahcisc;
	ahci_sc->sc_atac.atac_dev = sc->sc_dev;
	ahci_sc->sc_ahci_ports = 1;
	ahci_sc->sc_dmat = aa->aa_dmat;
	ahci_sc->sc_ahcis = aa->aa_size;
	ahci_sc->sc_ahcit = sc->sc_iot;
	ahci_sc->sc_ahcih = sc->sc_ioh;

	sc->sc_ih = intr_establish(aa->aa_irq, IPL_BIO, IST_LEVEL,
	    ahci_intr, ahci_sc);
	if (sc->sc_ih == NULL) {
		aprint_error_dev(self, "unable to establish interrupt\n");
		return;
	}

	ahci_attach(ahci_sc);
}
コード例 #8
0
ファイル: a10_ahci.c プロジェクト: outbackdingo/uBSD
static int
ahci_a10_attach(device_t dev)
{
	int error;
	struct ahci_controller *ctlr;

	ctlr = device_get_softc(dev);
	ctlr->quirks = AHCI_Q_NOPMP;
	ctlr->vendorid = 0;
	ctlr->deviceid = 0;
	ctlr->subvendorid = 0;
	ctlr->subdeviceid = 0;
	ctlr->r_rid = 0;
	if (!(ctlr->r_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
	    &ctlr->r_rid, RF_ACTIVE)))
		return (ENXIO);

	/* Turn on the PLL for SATA */
	a10_clk_ahci_activate();

	/* Reset controller */
	if ((error = ahci_a10_ctlr_reset(dev)) != 0) {
		bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_rid,
		    ctlr->r_mem);
		return (error);
	};

	/*
	 * No MSI registers on this platform.
	 */
	ctlr->msi = 0;
	ctlr->numirqs = 1;

	/* Channel start callback(). */
	ctlr->ch_start = ahci_a10_ch_start;

	/*
	 * Note: ahci_attach will release ctlr->r_mem on errors automatically
	 */
	return (ahci_attach(dev));
}
コード例 #9
0
static void
ahci_pci_attach(device_t parent, device_t self, void *aux)
{
	struct pci_attach_args *pa = aux;
	struct ahci_pci_softc *psc = device_private(self);
	struct ahci_softc *sc = &psc->ah_sc;
	const char *intrstr;
	bool ahci_cap_64bit;
	bool ahci_bad_64bit;
	pci_intr_handle_t intrhandle;

	sc->sc_atac.atac_dev = self;

	if (pci_mapreg_map(pa, AHCI_PCI_ABAR,
	    PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT, 0,
	    &sc->sc_ahcit, &sc->sc_ahcih, NULL, &sc->sc_ahcis) != 0) {
		aprint_error_dev(self, "can't map ahci registers\n");
		return;
	}
	psc->sc_pc = pa->pa_pc;
	psc->sc_pcitag = pa->pa_tag;

	pci_aprint_devinfo(pa, "AHCI disk controller");
	
	if (pci_intr_map(pa, &intrhandle) != 0) {
		aprint_error_dev(self, "couldn't map interrupt\n");
		return;
	}
	intrstr = pci_intr_string(pa->pa_pc, intrhandle);
	psc->sc_ih = pci_intr_establish(pa->pa_pc, intrhandle, IPL_BIO, ahci_intr, sc);
	if (psc->sc_ih == NULL) {
		aprint_error_dev(self, "couldn't establish interrupt\n");
		return;
	}
	aprint_normal_dev(self, "interrupting at %s\n",
	    intrstr ? intrstr : "unknown interrupt");

	sc->sc_dmat = pa->pa_dmat;

	sc->sc_ahci_quirks = ahci_pci_has_quirk(PCI_VENDOR(pa->pa_id),
					    PCI_PRODUCT(pa->pa_id));

	ahci_cap_64bit = (AHCI_READ(sc, AHCI_CAP) & AHCI_CAP_64BIT) != 0;
	ahci_bad_64bit = ((sc->sc_ahci_quirks & AHCI_PCI_QUIRK_BAD64) != 0);

	if (pci_dma64_available(pa) && ahci_cap_64bit) {
		if (!ahci_bad_64bit)
			sc->sc_dmat = pa->pa_dmat64;
		aprint_verbose_dev(self, "64-bit DMA%s\n",
		    (sc->sc_dmat == pa->pa_dmat) ? " unavailable" : "");
	}

	if (PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_MASS_STORAGE_RAID) {
		AHCIDEBUG_PRINT(("%s: RAID mode\n", AHCINAME(sc)), DEBUG_PROBE);
		sc->sc_atac_capflags = ATAC_CAP_RAID;
	} else {
		AHCIDEBUG_PRINT(("%s: SATA mode\n", AHCINAME(sc)), DEBUG_PROBE);
	}

	ahci_attach(sc);

	if (!pmf_device_register(self, NULL, ahci_pci_resume))
		aprint_error_dev(self, "couldn't establish power handler\n");
}
コード例 #10
0
ファイル: imx6_ahci.c プロジェクト: 2trill2spill/freebsd
static int
imx6_ahci_attach(device_t dev)
{
	struct ahci_controller* ctlr;
	uint16_t pllstat;
	uint32_t v;
	int error, timeout;

	ctlr = device_get_softc(dev);

	/* Power up the controller and phy. */
	error = imx6_ccm_sata_enable();
	if (error != 0) {
		device_printf(dev, "error enabling controller and phy\n");
		return (error);
	}

	ctlr->vendorid = 0;
	ctlr->deviceid = 0;
	ctlr->subvendorid = 0;
	ctlr->subdeviceid = 0;
	ctlr->numirqs = 1;
	ctlr->r_rid = 0;
	if ((ctlr->r_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
	    &ctlr->r_rid, RF_ACTIVE)) == NULL) {
		return (ENXIO);
	}

	v = imx_iomux_gpr_get(IOMUX_GPR13);
	/* Clear out existing values; these numbers are bitmasks. */
	v &= ~(IOMUX_GPR13_SATA_PHY_8(7) 	|
	       IOMUX_GPR13_SATA_PHY_7(0x1f) 	|
	       IOMUX_GPR13_SATA_PHY_6(7) 	|
	       IOMUX_GPR13_SATA_SPEED(1) 	|
	       IOMUX_GPR13_SATA_PHY_5(1) 	|
	       IOMUX_GPR13_SATA_PHY_4(7) 	|
	       IOMUX_GPR13_SATA_PHY_3(0xf) 	|
	       IOMUX_GPR13_SATA_PHY_2(0x1f) 	|
	       IOMUX_GPR13_SATA_PHY_1(1) 	|
	       IOMUX_GPR13_SATA_PHY_0(1));
	/* setting */
	v |= IOMUX_GPR13_SATA_PHY_8(5) 		|     /* Rx 3.0db */
	     IOMUX_GPR13_SATA_PHY_7(0x12) 	|     /* Rx SATA2m */
	     IOMUX_GPR13_SATA_PHY_6(3) 		|     /* Rx DPLL mode */
	     IOMUX_GPR13_SATA_SPEED(1) 		|     /* 3.0GHz */
	     IOMUX_GPR13_SATA_PHY_5(0) 		|     /* SpreadSpectram */
	     IOMUX_GPR13_SATA_PHY_4(4) 		|     /* Tx Attenuation 9/16 */
	     IOMUX_GPR13_SATA_PHY_3(0) 		|     /* Tx Boost 0db */
	     IOMUX_GPR13_SATA_PHY_2(0x11) 	|     /* Tx Level 1.104V */
	     IOMUX_GPR13_SATA_PHY_1(1);               /* PLL clock enable */
	imx_iomux_gpr_set(IOMUX_GPR13, v);

	/* phy reset */
	error = imx6_ahci_phy_write(ctlr, SATA_PHY_CLOCK_RESET,
	    SATA_PHY_CLOCK_RESET_RST);
	if (error != 0) {
		device_printf(dev, "cannot reset PHY\n");
		goto fail;
	}

	for (timeout = 50; timeout > 0; --timeout) {
		DELAY(100);
		error = imx6_ahci_phy_read(ctlr, SATA_PHY_LANE0_OUT_STAT,
		    &pllstat);
		if (error != 0) {
			device_printf(dev, "cannot read LANE0 status\n");
			goto fail;
		}
		if (pllstat & SATA_PHY_LANE0_OUT_STAT_RX_PLL_STATE) {
			break;
		}
	}
	if (timeout <= 0) {
		device_printf(dev, "time out reading LANE0 status\n");
		error = ETIMEDOUT;
		goto fail;
	}

	/* Support Staggered Spin-up */
	v = ATA_INL(ctlr->r_mem, AHCI_CAP);
	ATA_OUTL(ctlr->r_mem, AHCI_CAP, v | AHCI_CAP_SSS);

	/* Ports Implemented. must set 1 */
	v = ATA_INL(ctlr->r_mem, AHCI_PI);
	ATA_OUTL(ctlr->r_mem, AHCI_PI, v | (1 << 0));

	/* set 1ms-timer = AHB clock / 1000 */
	ATA_OUTL(ctlr->r_mem, SATA_TIMER1MS,
		 imx_ccm_ahb_hz() / 1000);

	/*
	 * Note: ahci_attach will release ctlr->r_mem on errors automatically
	 */
	return (ahci_attach(dev));

fail:
	bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_rid, ctlr->r_mem);
	return (error);
}
コード例 #11
0
ファイル: tegra_ahci.c プロジェクト: jaredmcneill/freebsd
static int
tegra_ahci_attach(device_t dev)
{
	struct tegra_ahci_sc *sc;
	struct ahci_controller *ctlr;
	phandle_t node;
	int rv, rid;

	sc = device_get_softc(dev);
	sc->dev = dev;
	ctlr = &sc->ctlr;
	node = ofw_bus_get_node(dev);

	ctlr->r_rid = 0;
	ctlr->r_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
	    &ctlr->r_rid, RF_ACTIVE);
	if (ctlr->r_mem == NULL)
		return (ENXIO);

	rid = 1;
	sc->sata_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
	    &rid, RF_ACTIVE);
	if (sc->sata_mem == NULL) {
		rv = ENXIO;
		goto fail;
	}
	rv = get_fdt_resources(sc, node);
	if (rv != 0) {
		device_printf(sc->dev, "Failed to allocate FDT resource(s)\n");
		goto fail;
	}

	rv = enable_fdt_resources(sc);
	if (rv != 0) {
		device_printf(sc->dev, "Failed to enable FDT resource(s)\n");
		goto fail;
	}
	rv = tegra_ahci_ctrl_init(sc);
	if (rv != 0) {
		device_printf(sc->dev, "Failed to initialize controller)\n");
		goto fail;
	}

	/* Setup controller defaults. */
	ctlr->msi = 0;
	ctlr->numirqs = 1;
	ctlr->ccc = 0;

	/* Reset controller. */
	rv = tegra_ahci_ctlr_reset(dev);
	if (rv != 0)
		goto fail;
	rv = ahci_attach(dev);
	return (rv);

fail:
	/* XXX FDT  stuff */
	if (sc->sata_mem != NULL)
		bus_release_resource(dev, SYS_RES_MEMORY, 1, sc->sata_mem);
	if (ctlr->r_mem != NULL)
		bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_rid,
		    ctlr->r_mem);
	return (rv);
}
コード例 #12
0
static void
awin_ahci_attach(device_t parent, device_t self, void *aux)
{
	struct awin_ahci_softc * const asc = device_private(self);
	struct ahci_softc * const sc = &asc->asc_sc;
	struct awinio_attach_args * const aio = aux;
	const struct awin_locators * const loc = &aio->aio_loc;

	awin_ahci_enable(aio->aio_core_bst, aio->aio_ccm_bsh);

        sc->sc_atac.atac_dev = self;
	sc->sc_dmat = aio->aio_dmat;
	sc->sc_ahcit = aio->aio_core_bst;
	sc->sc_ahcis = loc->loc_size;
	sc->sc_ahci_ports = 1;
	sc->sc_ahci_quirks = AHCI_QUIRK_BADPMP;
	sc->sc_save_init_data = true;
	sc->sc_channel_start = awin_ahci_channel_start;

	bus_space_subregion(aio->aio_core_bst, aio->aio_core_bsh,
	    loc->loc_offset, loc->loc_size, &sc->sc_ahcih);

	aprint_naive(": AHCI SATA controller\n");
	aprint_normal(": AHCI SATA controller\n");

	/*
	 * Bring up the PHY.
	 */
	awin_ahci_phy_init(asc);

	/*
	 * If there is a GPIO to turn on power, do it now.
	 */
	const char *pin_name;
	prop_dictionary_t dict = device_properties(self);
	if (prop_dictionary_get_cstring_nocopy(dict, "power-gpio", &pin_name)) {
		if (awin_gpio_pin_reserve(pin_name, &asc->asc_gpio_pin)) {
			awin_gpio_pindata_write(&asc->asc_gpio_pin, 1);
		} else {
			aprint_error_dev(self,
			    "failed to reserve GPIO \"%s\"\n", pin_name);
		}
	}

	/*
	 * Establish the interrupt
	 */
	asc->asc_ih = intr_establish(loc->loc_intr, IPL_BIO, IST_LEVEL,
	    ahci_intr, sc);
	if (asc->asc_ih == NULL) {
		aprint_error_dev(self, "failed to establish interrupt %d\n",
		     loc->loc_intr);
		goto fail;
	}
	aprint_normal_dev(self, "interrupting on irq %d\n", loc->loc_intr);

	ahci_attach(sc);

	return;

fail:
	if (asc->asc_ih) {
		intr_disestablish(asc->asc_ih);
		asc->asc_ih = NULL;
	}
}