#include <sys/param.h>
#include <sys/systm.h>
#include <machine/bus.h>
#include <machine/fdt.h>
#include <machine/intr.h>
#include <armv7/marvell/mvmbusvar.h>
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_clock.h>
#include <dev/ofw/ofw_pinctrl.h>
#include <dev/ofw/fdt.h>
#include <dev/sdmmc/sdhcreg.h>
#include <dev/sdmmc/sdhcvar.h>
#define MVPXA_READ(sc, reg) \
bus_space_read_4((sc)->sc_iot, (sc)->mbus_ioh, (reg))
#define MVPXA_WRITE(sc, reg, val) \
bus_space_write_4((sc)->sc_iot, (sc)->mbus_ioh, (reg), (val))
#define MVPXA_NWINDOW 8
#define MVPXA_CTRL(x) (0x80 + ((x) << 3))
#define MVPXA_BASE(x) (0x84 + ((x) << 3))
#define MVPXA_TARGET(target) (((target) & 0xf) << 4)
#define MVPXA_ATTR(attr) (((attr) & 0xff) << 8)
#define MVPXA_SIZE(size) (((size) - 1) & 0xffff0000)
#define MVPXA_WINEN (1 << 0)
struct mvpxa_softc {
struct sdhc_softc sc;
bus_space_tag_t sc_iot;
bus_space_handle_t sc_ioh;
bus_space_handle_t mbus_ioh;
bus_space_handle_t conf_ioh;
bus_size_t sc_size;
void *sc_ih;
struct sdhc_host *sc_host;
};
int mvpxa_match(struct device *, void *, void *);
void mvpxa_attach(struct device *, struct device *, void *);
struct cfdriver mvpxa_cd = {
NULL, "mvpxa", DV_DULL
};
const struct cfattach mvpxa_ca = {
sizeof(struct mvpxa_softc), mvpxa_match, mvpxa_attach
};
void mvpxa_wininit(struct mvpxa_softc *);
void
mvpxa_wininit(struct mvpxa_softc *sc)
{
int i;
if (mvmbus_dram_info == NULL)
panic("%s: mbus dram information not set up", __func__);
for (i = 0; i < MVPXA_NWINDOW; i++) {
MVPXA_WRITE(sc, MVPXA_CTRL(i), 0);
MVPXA_WRITE(sc, MVPXA_BASE(i), 0);
}
for (i = 0; i < mvmbus_dram_info->numcs; i++) {
struct mbus_dram_window *win = &mvmbus_dram_info->cs[i];
MVPXA_WRITE(sc, MVPXA_CTRL(i),
MVPXA_WINEN |
MVPXA_TARGET(mvmbus_dram_info->targetid) |
MVPXA_ATTR(win->attr) |
MVPXA_SIZE(win->size));
MVPXA_WRITE(sc, MVPXA_BASE(i), win->base);
}
}
int
mvpxa_match(struct device *parent, void *match, void *aux)
{
struct fdt_attach_args *faa = aux;
return OF_is_compatible(faa->fa_node, "marvell,armada-380-sdhci");
}
void
mvpxa_attach(struct device *parent, struct device *self, void *aux)
{
struct mvpxa_softc *sc = (struct mvpxa_softc *)self;
struct fdt_attach_args *faa = aux;
uint64_t capmask = 0, capset = 0;
if (faa->fa_nreg < 3) {
printf(": not enough registers\n");
return;
}
sc->sc_iot = faa->fa_iot;
sc->sc_size = faa->fa_reg[0].size;
if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
printf(": can't map registers\n");
return;
}
if (bus_space_map(sc->sc_iot, faa->fa_reg[1].addr,
faa->fa_reg[1].size, 0, &sc->mbus_ioh)) {
printf(": can't map registers\n");
bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_size);
return;
}
if (bus_space_map(sc->sc_iot, faa->fa_reg[2].addr,
faa->fa_reg[2].size, 0, &sc->conf_ioh)) {
printf(": can't map registers\n");
bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_size);
bus_space_unmap(sc->sc_iot, sc->mbus_ioh, faa->fa_reg[1].size);
return;
}
pinctrl_byname(faa->fa_node, "default");
clock_enable_all(faa->fa_node);
reset_deassert_all(faa->fa_node);
mvpxa_wininit(sc);
sc->sc_ih = arm_intr_establish_fdt(faa->fa_node, IPL_BIO,
sdhc_intr, sc, sc->sc.sc_dev.dv_xname);
if (sc->sc_ih == NULL) {
printf(": can't establish interrupt\n");
goto unmap;
}
printf("\n");
sc->sc.sc_host = &sc->sc_host;
sc->sc.sc_dmat = faa->fa_dmat;
if (OF_getproplen(faa->fa_node, "no-1-8-v") >= 0)
capmask |= SDHC_VOLTAGE_SUPP_1_8V;
sdhc_host_found(&sc->sc, sc->sc_iot, sc->sc_ioh, sc->sc_size, 1,
capmask, capset);
return;
unmap:
bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_size);
bus_space_unmap(sc->sc_iot, sc->mbus_ioh, faa->fa_reg[1].size);
bus_space_unmap(sc->sc_iot, sc->conf_ioh, faa->fa_reg[2].size);
}