Changeset View
Changeset View
Standalone View
Standalone View
sys/arm/allwinner/a10_ahci.c
Show First 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | |||||
#include <sys/module.h> | #include <sys/module.h> | ||||
#include <machine/bus.h> | #include <machine/bus.h> | ||||
#include <dev/ofw/ofw_bus.h> | #include <dev/ofw/ofw_bus.h> | ||||
#include <dev/ofw/ofw_bus_subr.h> | #include <dev/ofw/ofw_bus_subr.h> | ||||
#include <dev/ahci/ahci.h> | #include <dev/ahci/ahci.h> | ||||
#include <dev/extres/clk/clk.h> | #include <dev/extres/clk/clk.h> | ||||
#include <dev/extres/regulator/regulator.h> | |||||
/* | /* | ||||
* Allwinner a1x/a2x/a8x SATA attachment. This is just the AHCI register | * Allwinner a1x/a2x/a8x SATA attachment. This is just the AHCI register | ||||
* set with a few extra implementation-specific registers that need to | * set with a few extra implementation-specific registers that need to | ||||
* be accounted for. There's only one PHY in the system, and it needs | * be accounted for. There's only one PHY in the system, and it needs | ||||
* to be trained to bring the link up. In addition, there's some DMA | * to be trained to bring the link up. In addition, there's some DMA | ||||
* specific things that need to be done as well. These things are also | * specific things that need to be done as well. These things are also | ||||
* just about completely undocumented, except in ugly code in the Linux | * just about completely undocumented, except in ugly code in the Linux | ||||
▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | |||||
#define AHCI_RWCR 0x00FC | #define AHCI_RWCR 0x00FC | ||||
#define AHCI_P0DMACR 0x0070 | #define AHCI_P0DMACR 0x0070 | ||||
#define AHCI_P0PHYCR 0x0078 | #define AHCI_P0PHYCR 0x0078 | ||||
#define AHCI_P0PHYSR 0x007C | #define AHCI_P0PHYSR 0x007C | ||||
#define PLL_FREQ 100000000 | #define PLL_FREQ 100000000 | ||||
struct ahci_a10_softc { | |||||
struct ahci_controller ahci_ctlr; | |||||
regulator_t ahci_reg; | |||||
}; | |||||
static void inline | static void inline | ||||
ahci_set(struct resource *m, bus_size_t off, uint32_t set) | ahci_set(struct resource *m, bus_size_t off, uint32_t set) | ||||
{ | { | ||||
uint32_t val = ATA_INL(m, off); | uint32_t val = ATA_INL(m, off); | ||||
val |= set; | val |= set; | ||||
ATA_OUTL(m, off, val); | ATA_OUTL(m, off, val); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 161 Lines • ▼ Show 20 Lines | ahci_a10_probe(device_t dev) | ||||
return (BUS_PROBE_DEFAULT); | return (BUS_PROBE_DEFAULT); | ||||
} | } | ||||
static int | static int | ||||
ahci_a10_attach(device_t dev) | ahci_a10_attach(device_t dev) | ||||
{ | { | ||||
int error; | int error; | ||||
struct ahci_a10_softc *sc; | |||||
struct ahci_controller *ctlr; | struct ahci_controller *ctlr; | ||||
clk_t clk_pll, clk_gate; | clk_t clk_pll, clk_gate; | ||||
ctlr = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
ctlr = &sc->ahci_ctlr; | |||||
clk_pll = clk_gate = NULL; | clk_pll = clk_gate = NULL; | ||||
ctlr->quirks = AHCI_Q_NOPMP; | ctlr->quirks = AHCI_Q_NOPMP; | ||||
ctlr->vendorid = 0; | ctlr->vendorid = 0; | ||||
ctlr->deviceid = 0; | ctlr->deviceid = 0; | ||||
ctlr->subvendorid = 0; | ctlr->subvendorid = 0; | ||||
ctlr->subdeviceid = 0; | ctlr->subdeviceid = 0; | ||||
ctlr->r_rid = 0; | ctlr->r_rid = 0; | ||||
if (!(ctlr->r_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, | if (!(ctlr->r_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, | ||||
&ctlr->r_rid, RF_ACTIVE))) | &ctlr->r_rid, RF_ACTIVE))) | ||||
return (ENXIO); | return (ENXIO); | ||||
/* Enable the regulator */ | |||||
error = regulator_get_by_ofw_property(dev, 0, "target-supply", | |||||
&sc->ahci_reg); | |||||
if (error != 0) { | |||||
device_printf(dev, "Cannot get regulator\n"); | |||||
goto fail; | |||||
} | |||||
error = regulator_enable(sc->ahci_reg); | |||||
if (error != 0) { | |||||
device_printf(dev, "Could not enable regulator\n"); | |||||
goto fail; | |||||
} | |||||
/* Enable clocks */ | /* Enable clocks */ | ||||
error = clk_get_by_ofw_index(dev, 0, 0, &clk_gate); | error = clk_get_by_ofw_index(dev, 0, 0, &clk_gate); | ||||
if (error != 0) { | if (error != 0) { | ||||
device_printf(dev, "Cannot get gate clock\n"); | device_printf(dev, "Cannot get gate clock\n"); | ||||
goto fail; | goto fail; | ||||
} | } | ||||
error = clk_get_by_ofw_index(dev, 0, 1, &clk_pll); | error = clk_get_by_ofw_index(dev, 0, 1, &clk_pll); | ||||
if (error != 0) { | if (error != 0) { | ||||
Show All 30 Lines | ahci_a10_attach(device_t dev) | ||||
ctlr->ch_start = ahci_a10_ch_start; | ctlr->ch_start = ahci_a10_ch_start; | ||||
/* | /* | ||||
* Note: ahci_attach will release ctlr->r_mem on errors automatically | * Note: ahci_attach will release ctlr->r_mem on errors automatically | ||||
*/ | */ | ||||
return (ahci_attach(dev)); | return (ahci_attach(dev)); | ||||
fail: | fail: | ||||
if (sc->ahci_reg != 0) | |||||
regulator_disable(sc->ahci_reg); | |||||
if (clk_gate != NULL) | if (clk_gate != NULL) | ||||
clk_release(clk_gate); | clk_release(clk_gate); | ||||
if (clk_pll != NULL) | if (clk_pll != NULL) | ||||
clk_release(clk_pll); | clk_release(clk_pll); | ||||
bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_rid, ctlr->r_mem); | bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_rid, ctlr->r_mem); | ||||
return (error); | return (error); | ||||
} | } | ||||
Show All 15 Lines | static device_method_t ahci_ata_methods[] = { | ||||
DEVMETHOD(bus_teardown_intr,ahci_teardown_intr), | DEVMETHOD(bus_teardown_intr,ahci_teardown_intr), | ||||
DEVMETHOD(bus_child_location_str, ahci_child_location_str), | DEVMETHOD(bus_child_location_str, ahci_child_location_str), | ||||
DEVMETHOD_END | DEVMETHOD_END | ||||
}; | }; | ||||
static driver_t ahci_ata_driver = { | static driver_t ahci_ata_driver = { | ||||
"ahci", | "ahci", | ||||
ahci_ata_methods, | ahci_ata_methods, | ||||
sizeof(struct ahci_controller) | sizeof(struct ahci_a10_softc) | ||||
}; | }; | ||||
DRIVER_MODULE(a10_ahci, simplebus, ahci_ata_driver, ahci_devclass, 0, 0); | DRIVER_MODULE(a10_ahci, simplebus, ahci_ata_driver, ahci_devclass, 0, 0); |