Enable Synopsys DesignWare Mobile Storage Host Controller

driver on Rockchip boards. It currently supports PIO mode
and dma mode needs external dma controller to be used.

Submitted by:   jmcneill
Approved by:    stas (mentor)
This commit is contained in:
Ganbold Tsagaankhuu 2015-01-20 09:07:28 +00:00
parent b9d056f3d6
commit e2763dca83
7 changed files with 163 additions and 35 deletions

View File

@ -76,8 +76,9 @@ options DIAGNOSTIC
options ROOTDEVNAME=\"ufs:/dev/da0s2\"
# MMC/SD/SDIO Card slot support
#device mmc # mmc/sd bus
#device mmcsd # mmc/sd flash cards
device mmc # mmc/sd bus
device mmcsd # mmc/sd flash cards
device dwmmc
# Console and misc
device uart

View File

@ -19,3 +19,5 @@ arm/rockchip/rk30xx_grf.c standard
arm/rockchip/rk30xx_wdog.c standard
arm/rockchip/rk30xx_gpio.c optional gpio
arm/rockchip/rk30xx_mp.c optional smp
dev/mmc/host/dwmmc.c optional dwmmc

View File

@ -48,6 +48,10 @@
status = "okay";
};
mmc@10214000 {
status = "okay";
};
};
chosen {

View File

@ -48,6 +48,10 @@
status = "okay";
};
mmc@10214000 {
status = "okay";
};
};
chosen {

View File

@ -231,22 +231,26 @@
};
mmc@10214000 {
compatible = "rockchip,rk30xx-mmc";
compatible = "rockchip,rk2928-dw-mshc";
reg = <0x10214000 0x1000>;
interrupts = <55>;
#address-cells = <1>;
#size-cells = <0>;
clock-frequency = <24000000>; /* TODO: verify freq */
bus-frequency = <48000000>; /* TODO: verify freq */
fifo-depth = <0x40>;
num-slots = <1>;
status = "disabled";
};
mmc@10218000 {
compatible = "rockchip,rk30xx-mmc";
compatible = "rockchip,rk2928-dw-mshc";
reg = <0x10218000 0x1000>;
interrupts = <56>;
#address-cells = <1>;
#size-cells = <0>;
clock-frequency = <24000000>; /* TODO: verify freq */
bus-frequency = <48000000>; /* TODO: verify freq */
fifo-depth = <0x40>;
num-slots = <1>;
status = "disabled";
};
};

View File

@ -129,6 +129,8 @@ struct dwmmc_softc {
uint32_t flags;
uint32_t hwtype;
uint32_t use_auto_stop;
uint32_t use_pio;
uint32_t pwren_inverted;
bus_dma_tag_t desc_tag;
bus_dmamap_t desc_map;
@ -152,6 +154,8 @@ static void dwmmc_next_operation(struct dwmmc_softc *);
static int dwmmc_setup_bus(struct dwmmc_softc *, int);
static int dma_done(struct dwmmc_softc *, struct mmc_command *);
static int dma_stop(struct dwmmc_softc *);
static void pio_read(struct dwmmc_softc *, struct mmc_command *);
static void pio_write(struct dwmmc_softc *, struct mmc_command *);
static struct resource_spec dwmmc_spec[] = {
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
@ -163,6 +167,7 @@ enum {
HWTYPE_NONE,
HWTYPE_ALTERA,
HWTYPE_EXYNOS,
HWTYPE_ROCKCHIP,
};
#define HWTYPE_MASK (0x0000ffff)
@ -171,6 +176,7 @@ enum {
static struct ofw_compat_data compat_data[] = {
{"altr,socfpga-dw-mshc", HWTYPE_ALTERA},
{"samsung,exynos5420-dw-mshc", HWTYPE_EXYNOS},
{"rockchip,rk2928-dw-mshc", HWTYPE_ROCKCHIP},
{NULL, HWTYPE_NONE},
};
@ -395,8 +401,10 @@ dwmmc_intr(void *arg)
dprintf("data err 0x%08x cmd 0x%08x\n",
reg, cmd->opcode);
cmd->error = MMC_ERR_FAILED;
dma_done(sc, cmd);
dma_stop(sc);
if (!sc->use_pio) {
dma_done(sc, cmd);
dma_stop(sc);
}
}
if (reg & SDMMC_INTMASK_CMD_DONE) {
@ -421,15 +429,24 @@ dwmmc_intr(void *arg)
}
}
/* Now handle DMA interrupts */
reg = READ4(sc, SDMMC_IDSTS);
if (reg) {
dprintf("dma intr 0x%08x\n", reg);
if (reg & (SDMMC_IDINTEN_TI | SDMMC_IDINTEN_RI)) {
WRITE4(sc, SDMMC_IDSTS, (SDMMC_IDINTEN_TI |
SDMMC_IDINTEN_RI));
WRITE4(sc, SDMMC_IDSTS, SDMMC_IDINTEN_NI);
dma_done(sc, cmd);
if (sc->use_pio) {
if (reg & (SDMMC_INTMASK_RXDR|SDMMC_INTMASK_DTO)) {
pio_read(sc, cmd);
}
if (reg & (SDMMC_INTMASK_TXDR|SDMMC_INTMASK_DTO)) {
pio_write(sc, cmd);
}
} else {
/* Now handle DMA interrupts */
reg = READ4(sc, SDMMC_IDSTS);
if (reg) {
dprintf("dma intr 0x%08x\n", reg);
if (reg & (SDMMC_IDINTEN_TI | SDMMC_IDINTEN_RI)) {
WRITE4(sc, SDMMC_IDSTS, (SDMMC_IDINTEN_TI |
SDMMC_IDINTEN_RI));
WRITE4(sc, SDMMC_IDSTS, SDMMC_IDINTEN_NI);
dma_done(sc, cmd);
}
}
}
@ -560,17 +577,29 @@ dwmmc_attach(device_t dev)
device_printf(dev, "Hardware version ID is %04x\n",
READ4(sc, SDMMC_VERID) & 0xffff);
WRITE4(sc, EMMCP_MPSBEGIN0, 0);
WRITE4(sc, EMMCP_SEND0, 0);
WRITE4(sc, EMMCP_CTRL0, (MPSCTRL_SECURE_READ_BIT |
MPSCTRL_SECURE_WRITE_BIT |
MPSCTRL_NON_SECURE_READ_BIT |
MPSCTRL_NON_SECURE_WRITE_BIT |
MPSCTRL_VALID));
sc->use_pio = 0;
sc->pwren_inverted = 0;
if ((sc->hwtype & HWTYPE_MASK) == HWTYPE_ROCKCHIP) {
sc->use_pio = 1;
sc->pwren_inverted = 1;
} else {
WRITE4(sc, EMMCP_MPSBEGIN0, 0);
WRITE4(sc, EMMCP_SEND0, 0);
WRITE4(sc, EMMCP_CTRL0, (MPSCTRL_SECURE_READ_BIT |
MPSCTRL_SECURE_WRITE_BIT |
MPSCTRL_NON_SECURE_READ_BIT |
MPSCTRL_NON_SECURE_WRITE_BIT |
MPSCTRL_VALID));
}
/* XXX: we support operation for slot index 0 only */
slot = 0;
WRITE4(sc, SDMMC_PWREN, (1 << slot));
if (sc->pwren_inverted) {
WRITE4(sc, SDMMC_PWREN, (0 << slot));
} else {
WRITE4(sc, SDMMC_PWREN, (1 << slot));
}
/* Reset all */
if (dwmmc_ctrl_reset(sc, (SDMMC_CTRL_RESET |
@ -580,17 +609,19 @@ dwmmc_attach(device_t dev)
dwmmc_setup_bus(sc, sc->host.f_min);
if (dma_setup(sc))
return (ENXIO);
if (!sc->use_pio) {
if (dma_setup(sc))
return (ENXIO);
/* Install desc base */
WRITE4(sc, SDMMC_DBADDR, sc->desc_ring_paddr);
/* Install desc base */
WRITE4(sc, SDMMC_DBADDR, sc->desc_ring_paddr);
/* Enable DMA interrupts */
WRITE4(sc, SDMMC_IDSTS, SDMMC_IDINTEN_MASK);
WRITE4(sc, SDMMC_IDINTEN, (SDMMC_IDINTEN_NI |
SDMMC_IDINTEN_RI |
SDMMC_IDINTEN_TI));
/* Enable DMA interrupts */
WRITE4(sc, SDMMC_IDSTS, SDMMC_IDINTEN_MASK);
WRITE4(sc, SDMMC_IDINTEN, (SDMMC_IDINTEN_NI |
SDMMC_IDINTEN_RI |
SDMMC_IDINTEN_TI));
}
/* Clear and disable interrups for a while */
WRITE4(sc, SDMMC_RINTSTS, 0xffffffff);
@ -797,6 +828,79 @@ dma_prepare(struct dwmmc_softc *sc, struct mmc_command *cmd)
return (0);
}
static int
pio_prepare(struct dwmmc_softc *sc, struct mmc_command *cmd)
{
struct mmc_data *data;
int reg;
data = cmd->data;
data->xfer_len = 0;
reg = (DEF_MSIZE << SDMMC_FIFOTH_MSIZE_S);
reg |= ((sc->fifo_depth / 2) - 1) << SDMMC_FIFOTH_RXWMARK_S;
reg |= (sc->fifo_depth / 2) << SDMMC_FIFOTH_TXWMARK_S;
WRITE4(sc, SDMMC_FIFOTH, reg);
wmb();
return (0);
}
static void
pio_read(struct dwmmc_softc *sc, struct mmc_command *cmd)
{
struct mmc_data *data;
uint32_t *p, status;
if (cmd == NULL || cmd->data == NULL)
return;
data = cmd->data;
if ((data->flags & MMC_DATA_READ) == 0)
return;
KASSERT((data->xfer_len & 3) == 0, ("xfer_len not aligned"));
p = (uint32_t *)data->data + (data->xfer_len >> 2);
while (data->xfer_len < data->len) {
status = READ4(sc, SDMMC_STATUS);
if (status & SDMMC_STATUS_FIFO_EMPTY)
break;
*p++ = READ4(sc, SDMMC_DATA);
data->xfer_len += 4;
}
WRITE4(sc, SDMMC_RINTSTS, SDMMC_INTMASK_RXDR);
}
static void
pio_write(struct dwmmc_softc *sc, struct mmc_command *cmd)
{
struct mmc_data *data;
uint32_t *p, status;
if (cmd == NULL || cmd->data == NULL)
return;
data = cmd->data;
if ((data->flags & MMC_DATA_WRITE) == 0)
return;
KASSERT((data->xfer_len & 3) == 0, ("xfer_len not aligned"));
p = (uint32_t *)data->data + (data->xfer_len >> 2);
while (data->xfer_len < data->len) {
status = READ4(sc, SDMMC_STATUS);
if (status & SDMMC_STATUS_FIFO_FULL)
break;
WRITE4(sc, SDMMC_DATA, *p++);
data->xfer_len += 4;
}
WRITE4(sc, SDMMC_RINTSTS, SDMMC_INTMASK_TXDR);
}
static void
dwmmc_start_cmd(struct dwmmc_softc *sc, struct mmc_command *cmd)
{
@ -807,6 +911,9 @@ dwmmc_start_cmd(struct dwmmc_softc *sc, struct mmc_command *cmd)
sc->curcmd = cmd;
data = cmd->data;
if ((sc->hwtype & HWTYPE_MASK) == HWTYPE_ROCKCHIP)
dwmmc_setup_bus(sc, sc->host.ios.clock);
/* XXX Upper layers don't always set this */
cmd->mrq = sc->req;
@ -861,7 +968,11 @@ dwmmc_start_cmd(struct dwmmc_softc *sc, struct mmc_command *cmd)
data->len : MMC_SECTOR_SIZE;
WRITE4(sc, SDMMC_BLKSIZ, blksz);
dma_prepare(sc, cmd);
if (sc->use_pio) {
pio_prepare(sc, cmd);
} else {
dma_prepare(sc, cmd);
}
wmb();
}

View File

@ -91,6 +91,8 @@
#define SDMMC_RINTSTS 0x44 /* Raw Interrupt Status Register */
#define SDMMC_STATUS 0x48 /* Status Register */
#define SDMMC_STATUS_DATA_BUSY (1 << 9) /* card_data[0] */
#define SDMMC_STATUS_FIFO_FULL (1 << 3) /* FIFO full */
#define SDMMC_STATUS_FIFO_EMPTY (1 << 2) /* FIFO empty */
#define SDMMC_FIFOTH 0x4C /* FIFO Threshold Watermark Register */
#define SDMMC_FIFOTH_MSIZE_S 28 /* Burst size of multiple transaction */
#define SDMMC_FIFOTH_RXWMARK_S 16 /* FIFO threshold watermark level */