Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/sdhci/sdhci_xenon.c
Show First 20 Lines • Show All 77 Lines • ▼ Show 20 Lines | |||||
#endif | #endif | ||||
{ NULL, 0 } | { NULL, 0 } | ||||
}; | }; | ||||
struct sdhci_xenon_softc { | struct sdhci_xenon_softc { | ||||
device_t dev; /* Controller device */ | device_t dev; /* Controller device */ | ||||
int slot_id; /* Controller ID */ | int slot_id; /* Controller ID */ | ||||
phandle_t node; /* FDT node */ | phandle_t node; /* FDT node */ | ||||
uint32_t quirks; /* Chip specific quirks */ | |||||
uint32_t caps; /* If we override SDHCI_CAPABILITIES */ | |||||
uint32_t max_clk; /* Max possible freq */ | |||||
struct resource *irq_res; /* IRQ resource */ | struct resource *irq_res; /* IRQ resource */ | ||||
void *intrhand; /* Interrupt handle */ | void *intrhand; /* Interrupt handle */ | ||||
struct sdhci_fdt_gpio *gpio; /* GPIO pins for CD detection. */ | struct sdhci_fdt_gpio *gpio; /* GPIO pins for CD detection. */ | ||||
struct sdhci_slot *slot; /* SDHCI internal data */ | struct sdhci_slot *slot; /* SDHCI internal data */ | ||||
struct resource *mem_res; /* Memory resource */ | struct resource *mem_res; /* Memory resource */ | ||||
uint8_t znr; /* PHY ZNR */ | uint8_t znr; /* PHY ZNR */ | ||||
uint8_t zpr; /* PHY ZPR */ | uint8_t zpr; /* PHY ZPR */ | ||||
bool no_18v; /* No 1.8V support */ | |||||
bool slow_mode; /* PHY slow mode */ | bool slow_mode; /* PHY slow mode */ | ||||
struct mmc_fdt_helper mmc_helper; /* MMC helper for parsing FDT */ | struct mmc_fdt_helper mmc_helper; /* MMC helper for parsing FDT */ | ||||
}; | }; | ||||
static uint8_t | static uint8_t | ||||
sdhci_xenon_read_1(device_t dev, struct sdhci_slot *slot __unused, | sdhci_xenon_read_1(device_t dev, struct sdhci_slot *slot __unused, | ||||
bus_size_t off) | bus_size_t off) | ||||
▲ Show 20 Lines • Show All 397 Lines • ▼ Show 20 Lines | case vccq_180: | ||||
return EAGAIN; | return EAGAIN; | ||||
default: | default: | ||||
device_printf(brdev, | device_printf(brdev, | ||||
"Attempt to set unsupported signaling voltage\n"); | "Attempt to set unsupported signaling voltage\n"); | ||||
return EINVAL; | return EINVAL; | ||||
} | } | ||||
} | } | ||||
static int | static void | ||||
sdhci_xenon_probe(device_t dev) | sdhci_xenon_fdt_parse(device_t dev, struct sdhci_slot *slot) | ||||
{ | { | ||||
struct sdhci_xenon_softc *sc = device_get_softc(dev); | struct sdhci_xenon_softc *sc = device_get_softc(dev); | ||||
pcell_t cid; | pcell_t cid; | ||||
sc->quirks = 0; | mmc_fdt_parse(dev, 0, &sc->mmc_helper, &slot->host); | ||||
sc->slot_id = 0; | |||||
sc->max_clk = XENON_MMC_MAX_CLK; | |||||
if (!ofw_bus_status_okay(dev)) | |||||
return (ENXIO); | |||||
if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) | |||||
return (ENXIO); | |||||
sc->node = ofw_bus_get_node(dev); | |||||
device_set_desc(dev, "Armada Xenon SDHCI controller"); | |||||
/* Allow dts to patch quirks, slots, and max-frequency. */ | /* Allow dts to patch quirks, slots, and max-frequency. */ | ||||
if ((OF_getencprop(sc->node, "quirks", &cid, sizeof(cid))) > 0) | if ((OF_getencprop(sc->node, "quirks", &cid, sizeof(cid))) > 0) | ||||
sc->quirks = cid; | slot->quirks = cid; | ||||
if ((OF_getencprop(sc->node, "max-frequency", &cid, sizeof(cid))) > 0) | |||||
sc->max_clk = cid; | |||||
if (OF_hasprop(sc->node, "no-1-8-v")) | |||||
sc->no_18v = true; | |||||
if (OF_hasprop(sc->node, "marvell,xenon-phy-slow-mode")) | if (OF_hasprop(sc->node, "marvell,xenon-phy-slow-mode")) | ||||
sc->slow_mode = true; | sc->slow_mode = true; | ||||
sc->znr = XENON_ZNR_DEF_VALUE; | sc->znr = XENON_ZNR_DEF_VALUE; | ||||
if ((OF_getencprop(sc->node, "marvell,xenon-phy-znr", &cid, | if ((OF_getencprop(sc->node, "marvell,xenon-phy-znr", &cid, | ||||
sizeof(cid))) > 0) | sizeof(cid))) > 0) | ||||
sc->znr = cid & XENON_ZNR_MASK; | sc->znr = cid & XENON_ZNR_MASK; | ||||
sc->zpr = XENON_ZPR_DEF_VALUE; | sc->zpr = XENON_ZPR_DEF_VALUE; | ||||
if ((OF_getencprop(sc->node, "marvell,xenon-phy-zpr", &cid, | if ((OF_getencprop(sc->node, "marvell,xenon-phy-zpr", &cid, | ||||
sizeof(cid))) > 0) | sizeof(cid))) > 0) | ||||
sc->zpr = cid & XENON_ZPR_MASK; | sc->zpr = cid & XENON_ZPR_MASK; | ||||
} | |||||
static int | |||||
sdhci_xenon_probe(device_t dev) | |||||
{ | |||||
if (!ofw_bus_status_okay(dev)) | |||||
return (ENXIO); | |||||
if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) | |||||
return (ENXIO); | |||||
device_set_desc(dev, "Armada Xenon SDHCI controller"); | |||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
sdhci_xenon_attach(device_t dev) | sdhci_xenon_attach(device_t dev) | ||||
{ | { | ||||
struct sdhci_xenon_softc *sc = device_get_softc(dev); | struct sdhci_xenon_softc *sc = device_get_softc(dev); | ||||
struct sdhci_slot *slot; | struct sdhci_slot *slot; | ||||
int err, rid; | int err, rid; | ||||
uint32_t reg; | uint32_t reg; | ||||
sc->dev = dev; | sc->dev = dev; | ||||
sc->slot_id = 0; | |||||
sc->node = ofw_bus_get_node(dev); | |||||
/* Allocate IRQ. */ | /* Allocate IRQ. */ | ||||
rid = 0; | rid = 0; | ||||
sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, | sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, | ||||
RF_ACTIVE); | RF_ACTIVE); | ||||
if (sc->irq_res == NULL) { | if (sc->irq_res == NULL) { | ||||
device_printf(dev, "Can't allocate IRQ\n"); | device_printf(dev, "Can't allocate IRQ\n"); | ||||
return (ENOMEM); | return (ENOMEM); | ||||
} | } | ||||
/* Allocate memory. */ | /* Allocate memory. */ | ||||
rid = 0; | rid = 0; | ||||
sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, | sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, | ||||
&rid, RF_ACTIVE); | &rid, RF_ACTIVE); | ||||
if (sc->mem_res == NULL) { | if (sc->mem_res == NULL) { | ||||
bus_release_resource(dev, SYS_RES_IRQ, | bus_release_resource(dev, SYS_RES_IRQ, | ||||
rman_get_rid(sc->irq_res), sc->irq_res); | rman_get_rid(sc->irq_res), sc->irq_res); | ||||
device_printf(dev, "Can't allocate memory for slot\n"); | device_printf(dev, "Can't allocate memory for slot\n"); | ||||
return (ENOMEM); | return (ENOMEM); | ||||
} | } | ||||
slot = malloc(sizeof(*slot), M_DEVBUF, M_ZERO | M_WAITOK); | slot = malloc(sizeof(*slot), M_DEVBUF, M_ZERO | M_WAITOK); | ||||
/* | |||||
* Set up any gpio pin handling described in the FDT data. This cannot | |||||
* fail; see comments in sdhci_fdt_gpio.h for details. | |||||
*/ | |||||
sc->gpio = sdhci_fdt_gpio_setup(dev, slot); | |||||
sdhci_xenon_fdt_parse(dev, slot); | |||||
slot->max_clk = XENON_MMC_MAX_CLK; | |||||
if (slot->host.f_max > 0) | |||||
slot->max_clk = slot->host.f_max; | |||||
/* Check if the device is flagged as non-removable. */ | /* Check if the device is flagged as non-removable. */ | ||||
if (OF_hasprop(sc->node, "non-removable")) { | if (sc->mmc_helper.props & MMC_PROP_NON_REMOVABLE) { | ||||
slot->opt |= SDHCI_NON_REMOVABLE; | slot->opt |= SDHCI_NON_REMOVABLE; | ||||
if (bootverbose) | if (bootverbose) | ||||
device_printf(dev, "Non-removable media\n"); | device_printf(dev, "Non-removable media\n"); | ||||
} | } | ||||
slot->quirks = sc->quirks; | |||||
slot->caps = sc->caps; | |||||
slot->max_clk = sc->max_clk; | |||||
sc->slot = slot; | sc->slot = slot; | ||||
/* | |||||
* Set up any gpio pin handling described in the FDT data. This cannot | |||||
* fail; see comments in sdhci_fdt_gpio.h for details. | |||||
*/ | |||||
sc->gpio = sdhci_fdt_gpio_setup(dev, slot); | |||||
mmc_fdt_parse(dev, 0, &sc->mmc_helper, &sc->slot->host); | |||||
if (sdhci_init_slot(dev, sc->slot, 0)) | if (sdhci_init_slot(dev, sc->slot, 0)) | ||||
goto fail; | goto fail; | ||||
/* 1.2V signaling is not supported. */ | /* 1.2V signaling is not supported. */ | ||||
sc->slot->host.caps &= ~MMC_CAP_SIGNALING_120; | sc->slot->host.caps &= ~MMC_CAP_SIGNALING_120; | ||||
/* Disable UHS in case of lack of 1.8V VCCQ or the PHY slow mode. */ | /* Disable UHS in case of the PHY slow mode. */ | ||||
if (sc->no_18v || sc->slow_mode) | if (sc->slow_mode) | ||||
sc->slot->host.caps &= ~MMC_CAP_SIGNALING_180; | sc->slot->host.caps &= ~MMC_CAP_SIGNALING_180; | ||||
/* Activate the interrupt */ | /* Activate the interrupt */ | ||||
err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE, | err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE, | ||||
NULL, sdhci_xenon_intr, sc, &sc->intrhand); | NULL, sdhci_xenon_intr, sc, &sc->intrhand); | ||||
if (err) { | if (err) { | ||||
device_printf(dev, "Cannot setup IRQ\n"); | device_printf(dev, "Cannot setup IRQ\n"); | ||||
goto fail; | goto fail; | ||||
▲ Show 20 Lines • Show All 116 Lines • Show Last 20 Lines |