version 1.9.2.1, 2012/04/17 00:08:03 |
version 1.9.2.2, 2012/10/30 17:22:01 |
Line 88 struct sdhc_host { |
|
Line 88 struct sdhc_host { |
|
}; |
}; |
|
|
#define HDEVNAME(hp) (device_xname((hp)->sc->sc_dev)) |
#define HDEVNAME(hp) (device_xname((hp)->sc->sc_dev)) |
|
#define HDEVINST(hp) ((int)(((hp)-(hp)->sc->sc_host[0])/sizeof(*(hp)))) |
|
|
static uint8_t |
static uint8_t |
hread1(struct sdhc_host *hp, bus_size_t reg) |
hread1(struct sdhc_host *hp, bus_size_t reg) |
Line 216 static struct sdmmc_chip_functions sdhc_ |
|
Line 217 static struct sdmmc_chip_functions sdhc_ |
|
sdhc_card_intr_ack |
sdhc_card_intr_ack |
}; |
}; |
|
|
|
static int |
|
sdhc_cfprint(void *aux, const char *pnp) |
|
{ |
|
const struct sdmmcbus_attach_args * const saa = aux; |
|
const struct sdhc_host * const hp = saa->saa_sch; |
|
|
|
if (pnp) { |
|
aprint_normal("sdmmc at %s", pnp); |
|
} |
|
aprint_normal(" slot %d", HDEVINST(hp)); |
|
|
|
return UNCONF; |
|
} |
|
|
/* |
/* |
* Called by attachment driver. For each SD card slot there is one SD |
* Called by attachment driver. For each SD card slot there is one SD |
* host controller standard register set. (1.3) |
* host controller standard register set. (1.3) |
Line 277 sdhc_host_found(struct sdhc_softc *sc, b |
|
Line 292 sdhc_host_found(struct sdhc_softc *sc, b |
|
(void)sdhc_host_reset(hp); |
(void)sdhc_host_reset(hp); |
|
|
/* Determine host capabilities. */ |
/* Determine host capabilities. */ |
mutex_enter(&hp->host_mtx); |
if (ISSET(sc->sc_flags, SDHC_FLAG_HOSTCAPS)) { |
caps = HREAD4(hp, SDHC_CAPABILITIES); |
caps = sc->sc_caps; |
mutex_exit(&hp->host_mtx); |
} else { |
|
mutex_enter(&hp->host_mtx); |
|
caps = HREAD4(hp, SDHC_CAPABILITIES); |
|
mutex_exit(&hp->host_mtx); |
|
} |
|
|
#if notyet |
|
/* Use DMA if the host system and the controller support it. */ |
/* Use DMA if the host system and the controller support it. */ |
if (ISSET(sc->sc_flags, SDHC_FLAG_FORCE_DMA) |
if (ISSET(sc->sc_flags, SDHC_FLAG_FORCE_DMA) || |
|| ((ISSET(sc->sc_flags, SDHC_FLAG_USE_DMA) |
(ISSET(sc->sc_flags, SDHC_FLAG_USE_DMA && |
&& ISSET(caps, SDHC_DMA_SUPPORT)))) { |
ISSET(caps, SDHC_DMA_SUPPORT)))) { |
SET(hp->flags, SHF_USE_DMA); |
SET(hp->flags, SHF_USE_DMA); |
aprint_normal_dev(sc->sc_dev, "using DMA transfer\n"); |
aprint_normal_dev(sc->sc_dev, "using DMA transfer\n"); |
} |
} |
#endif |
|
|
|
/* |
/* |
* Determine the base clock frequency. (2.2.24) |
* Determine the base clock frequency. (2.2.24) |
*/ |
*/ |
hp->clkbase = SDHC_BASE_FREQ_KHZ(caps); |
if (hp->specver == SDHC_SPEC_VERS_300) { |
|
hp->clkbase = SDHC_BASE_V3_FREQ_KHZ(caps); |
|
} else { |
|
hp->clkbase = SDHC_BASE_FREQ_KHZ(caps); |
|
} |
if (hp->clkbase == 0) { |
if (hp->clkbase == 0) { |
if (sc->sc_clkbase == 0) { |
if (sc->sc_clkbase == 0) { |
/* The attachment driver must tell us. */ |
/* The attachment driver must tell us. */ |
Line 319 sdhc_host_found(struct sdhc_softc *sc, b |
|
Line 340 sdhc_host_found(struct sdhc_softc *sc, b |
|
* capabilities. (2.2.15) |
* capabilities. (2.2.15) |
*/ |
*/ |
HWRITE1(hp, SDHC_TIMEOUT_CTL, SDHC_TIMEOUT_MAX); |
HWRITE1(hp, SDHC_TIMEOUT_CTL, SDHC_TIMEOUT_MAX); |
#if 0 |
#if 1 |
if (ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) |
if (ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) |
HWRITE4(hp, SDHC_NINTR_STATUS, SDHC_CMD_TIMEOUT_ERROR << 16); |
HWRITE4(hp, SDHC_NINTR_STATUS, SDHC_CMD_TIMEOUT_ERROR << 16); |
#endif |
#endif |
Line 386 sdhc_host_found(struct sdhc_softc *sc, b |
|
Line 407 sdhc_host_found(struct sdhc_softc *sc, b |
|
saa.saa_caps |= SMC_CAPS_8BIT_MODE; |
saa.saa_caps |= SMC_CAPS_8BIT_MODE; |
if (ISSET(caps, SDHC_HIGH_SPEED_SUPP)) |
if (ISSET(caps, SDHC_HIGH_SPEED_SUPP)) |
saa.saa_caps |= SMC_CAPS_SD_HIGHSPEED; |
saa.saa_caps |= SMC_CAPS_SD_HIGHSPEED; |
#if notyet |
if (ISSET(hp->flags, SHF_USE_DMA)) { |
if (ISSET(hp->flags, SHF_USE_DMA)) |
|
saa.saa_caps |= SMC_CAPS_DMA; |
saa.saa_caps |= SMC_CAPS_DMA; |
#endif |
if (hp->specver == SDHC_SPEC_VERS_100) { |
hp->sdmmc = config_found(sc->sc_dev, &saa, NULL); |
saa.saa_caps |= SMC_CAPS_MULTI_SEG_DMA; |
|
} |
|
} |
|
if (ISSET(sc->sc_flags, SDHC_FLAG_SINGLE_ONLY)) |
|
saa.saa_caps |= SMC_CAPS_SINGLE_ONLY; |
|
hp->sdmmc = config_found(sc->sc_dev, &saa, sdhc_cfprint); |
|
|
return 0; |
return 0; |
|
|
Line 533 sdhc_host_reset1(sdmmc_chipset_handle_t |
|
Line 558 sdhc_host_reset1(sdmmc_chipset_handle_t |
|
|
|
/* Set data timeout counter value to max for now. */ |
/* Set data timeout counter value to max for now. */ |
HWRITE1(hp, SDHC_TIMEOUT_CTL, SDHC_TIMEOUT_MAX); |
HWRITE1(hp, SDHC_TIMEOUT_CTL, SDHC_TIMEOUT_MAX); |
#if 0 |
#if 1 |
if (ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) |
if (ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) |
HWRITE4(hp, SDHC_NINTR_STATUS, SDHC_CMD_TIMEOUT_ERROR << 16); |
HWRITE4(hp, SDHC_NINTR_STATUS, SDHC_CMD_TIMEOUT_ERROR << 16); |
#endif |
#endif |
|
|
/* Enable interrupts. */ |
/* Enable interrupts. */ |
|
mutex_enter(&hp->intr_mtx); |
sdhcimask = SDHC_CARD_REMOVAL | SDHC_CARD_INSERTION | |
sdhcimask = SDHC_CARD_REMOVAL | SDHC_CARD_INSERTION | |
SDHC_BUFFER_READ_READY | SDHC_BUFFER_WRITE_READY | |
SDHC_BUFFER_READ_READY | SDHC_BUFFER_WRITE_READY | |
SDHC_DMA_INTERRUPT | SDHC_BLOCK_GAP_EVENT | |
SDHC_DMA_INTERRUPT | SDHC_BLOCK_GAP_EVENT | |
Line 557 sdhc_host_reset1(sdmmc_chipset_handle_t |
|
Line 583 sdhc_host_reset1(sdmmc_chipset_handle_t |
|
HWRITE2(hp, SDHC_NINTR_SIGNAL_EN, sdhcimask); |
HWRITE2(hp, SDHC_NINTR_SIGNAL_EN, sdhcimask); |
HWRITE2(hp, SDHC_EINTR_SIGNAL_EN, SDHC_EINTR_SIGNAL_MASK); |
HWRITE2(hp, SDHC_EINTR_SIGNAL_EN, SDHC_EINTR_SIGNAL_MASK); |
} |
} |
|
mutex_exit(&hp->intr_mtx); |
|
|
out: |
out: |
return error; |
return error; |
Line 600 sdhc_card_detect(sdmmc_chipset_handle_t |
|
Line 627 sdhc_card_detect(sdmmc_chipset_handle_t |
|
struct sdhc_host *hp = (struct sdhc_host *)sch; |
struct sdhc_host *hp = (struct sdhc_host *)sch; |
int r; |
int r; |
|
|
|
if (hp->sc->sc_vendor_card_detect) |
|
return (*hp->sc->sc_vendor_card_detect)(hp->sc); |
|
|
mutex_enter(&hp->host_mtx); |
mutex_enter(&hp->host_mtx); |
r = ISSET(HREAD4(hp, SDHC_PRESENT_STATE), SDHC_CARD_INSERTED); |
r = ISSET(HREAD4(hp, SDHC_PRESENT_STATE), SDHC_CARD_INSERTED); |
mutex_exit(&hp->host_mtx); |
mutex_exit(&hp->host_mtx); |
Line 616 sdhc_write_protect(sdmmc_chipset_handle_ |
|
Line 646 sdhc_write_protect(sdmmc_chipset_handle_ |
|
struct sdhc_host *hp = (struct sdhc_host *)sch; |
struct sdhc_host *hp = (struct sdhc_host *)sch; |
int r; |
int r; |
|
|
|
if (hp->sc->sc_vendor_write_protect) |
|
return (*hp->sc->sc_vendor_write_protect)(hp->sc); |
|
|
mutex_enter(&hp->host_mtx); |
mutex_enter(&hp->host_mtx); |
r = ISSET(HREAD4(hp, SDHC_PRESENT_STATE), SDHC_WRITE_PROTECT_SWITCH); |
r = ISSET(HREAD4(hp, SDHC_PRESENT_STATE), SDHC_WRITE_PROTECT_SWITCH); |
mutex_exit(&hp->host_mtx); |
mutex_exit(&hp->host_mtx); |
Line 633 sdhc_bus_power(sdmmc_chipset_handle_t sc |
|
Line 666 sdhc_bus_power(sdmmc_chipset_handle_t sc |
|
struct sdhc_host *hp = (struct sdhc_host *)sch; |
struct sdhc_host *hp = (struct sdhc_host *)sch; |
uint8_t vdd; |
uint8_t vdd; |
int error = 0; |
int error = 0; |
|
const uint32_t pcmask = |
|
~(SDHC_BUS_POWER | (SDHC_VOLTAGE_MASK << SDHC_VOLTAGE_SHIFT)); |
|
|
mutex_enter(&hp->host_mtx); |
mutex_enter(&hp->host_mtx); |
|
|
Line 671 sdhc_bus_power(sdmmc_chipset_handle_t sc |
|
Line 706 sdhc_bus_power(sdmmc_chipset_handle_t sc |
|
* voltage ramp until power rises. |
* voltage ramp until power rises. |
*/ |
*/ |
HWRITE1(hp, SDHC_POWER_CTL, |
HWRITE1(hp, SDHC_POWER_CTL, |
(vdd << SDHC_VOLTAGE_SHIFT) | SDHC_BUS_POWER); |
HREAD1(hp, SDHC_POWER_CTL) & pcmask); |
|
sdmmc_delay(1); |
|
HWRITE1(hp, SDHC_POWER_CTL, (vdd << SDHC_VOLTAGE_SHIFT)); |
|
sdmmc_delay(1); |
|
HSET1(hp, SDHC_POWER_CTL, SDHC_BUS_POWER); |
sdmmc_delay(10000); |
sdmmc_delay(10000); |
|
|
/* |
/* |
Line 706 sdhc_clock_divisor(struct sdhc_host *hp, |
|
Line 745 sdhc_clock_divisor(struct sdhc_host *hp, |
|
*divp = SDHC_SDCLK_CGM |
*divp = SDHC_SDCLK_CGM |
| ((div & 0x300) << SDHC_SDCLK_XDIV_SHIFT) |
| ((div & 0x300) << SDHC_SDCLK_XDIV_SHIFT) |
| ((div & 0x0ff) << SDHC_SDCLK_DIV_SHIFT); |
| ((div & 0x0ff) << SDHC_SDCLK_DIV_SHIFT); |
|
//freq = hp->clkbase / div; |
return true; |
return true; |
} |
} |
} |
} |
Line 723 sdhc_clock_divisor(struct sdhc_host *hp, |
|
Line 763 sdhc_clock_divisor(struct sdhc_host *hp, |
|
DPRINTF(2, |
DPRINTF(2, |
("%s: divisor for freq %u is %u * %u\n", |
("%s: divisor for freq %u is %u * %u\n", |
HDEVNAME(hp), freq, div * 2, dvs + 1)); |
HDEVNAME(hp), freq, div * 2, dvs + 1)); |
|
//freq = hp->clkbase / (div * 2) * (dvs + 1); |
return true; |
return true; |
} |
} |
/* |
/* |
Line 730 sdhc_clock_divisor(struct sdhc_host *hp, |
|
Line 771 sdhc_clock_divisor(struct sdhc_host *hp, |
|
*/ |
*/ |
roundup |= dvs & 1; |
roundup |= dvs & 1; |
} |
} |
panic("%s: can't find divisor for freq %u", HDEVNAME(hp), freq); |
/* No divisor found. */ |
|
return false; |
} else { |
} else { |
for (div = 1; div <= 256; div *= 2) { |
if (hp->sc->sc_clkmsk != 0) |
if ((hp->clkbase / div) <= freq) { |
*divp = (hp->clkbase / freq) << |
*divp = (div / 2) << SDHC_SDCLK_DIV_SHIFT; |
(ffs(hp->sc->sc_clkmsk) - 1); |
return true; |
else |
} |
*divp = (hp->clkbase / freq) << SDHC_SDCLK_DIV_SHIFT; |
} |
return true; |
} |
} |
/* No divisor found. */ |
/* No divisor found. */ |
return false; |
return false; |
Line 753 sdhc_bus_clock(sdmmc_chipset_handle_t sc |
|
Line 795 sdhc_bus_clock(sdmmc_chipset_handle_t sc |
|
struct sdhc_host *hp = (struct sdhc_host *)sch; |
struct sdhc_host *hp = (struct sdhc_host *)sch; |
u_int div; |
u_int div; |
u_int timo; |
u_int timo; |
|
int16_t reg; |
int error = 0; |
int error = 0; |
#ifdef DIAGNOSTIC |
#ifdef DIAGNOSTIC |
bool present; |
bool present; |
Line 763 sdhc_bus_clock(sdmmc_chipset_handle_t sc |
|
Line 806 sdhc_bus_clock(sdmmc_chipset_handle_t sc |
|
|
|
/* Must not stop the clock if commands are in progress. */ |
/* Must not stop the clock if commands are in progress. */ |
if (present && sdhc_card_detect(hp)) { |
if (present && sdhc_card_detect(hp)) { |
printf("%s: sdhc_sdclk_frequency_select: command in progress\n", |
aprint_normal_dev(hp->sc->sc_dev, |
device_xname(hp->sc->sc_dev)); |
"%s: command in progress\n", __func__); |
} |
} |
#endif |
#endif |
|
|
Line 780 sdhc_bus_clock(sdmmc_chipset_handle_t sc |
|
Line 823 sdhc_bus_clock(sdmmc_chipset_handle_t sc |
|
goto out; |
goto out; |
} |
} |
} else { |
} else { |
HWRITE2(hp, SDHC_CLOCK_CTL, 0); |
HCLR2(hp, SDHC_CLOCK_CTL, SDHC_SDCLK_ENABLE); |
if (freq == SDMMC_SDCLK_OFF) |
if (freq == SDMMC_SDCLK_OFF) |
goto out; |
goto out; |
} |
} |
Line 797 sdhc_bus_clock(sdmmc_chipset_handle_t sc |
|
Line 840 sdhc_bus_clock(sdmmc_chipset_handle_t sc |
|
HWRITE4(hp, SDHC_CLOCK_CTL, |
HWRITE4(hp, SDHC_CLOCK_CTL, |
div | (SDHC_TIMEOUT_MAX << 16)); |
div | (SDHC_TIMEOUT_MAX << 16)); |
} else { |
} else { |
HWRITE2(hp, SDHC_CLOCK_CTL, div); |
reg = HREAD2(hp, SDHC_CLOCK_CTL); |
|
reg &= (SDHC_INTCLK_STABLE | SDHC_INTCLK_ENABLE); |
|
HWRITE2(hp, SDHC_CLOCK_CTL, reg | div); |
} |
} |
|
|
/* |
/* |
Line 902 sdhc_bus_width(sdmmc_chipset_handle_t sc |
|
Line 947 sdhc_bus_width(sdmmc_chipset_handle_t sc |
|
static int |
static int |
sdhc_bus_rod(sdmmc_chipset_handle_t sch, int on) |
sdhc_bus_rod(sdmmc_chipset_handle_t sch, int on) |
{ |
{ |
|
struct sdhc_host *hp = (struct sdhc_host *)sch; |
|
|
|
if (hp->sc->sc_vendor_rod) |
|
return (*hp->sc->sc_vendor_rod)(hp->sc, on); |
|
|
/* Nothing ?? */ |
|
return 0; |
return 0; |
} |
} |
|
|
Line 913 sdhc_card_enable_intr(sdmmc_chipset_hand |
|
Line 961 sdhc_card_enable_intr(sdmmc_chipset_hand |
|
struct sdhc_host *hp = (struct sdhc_host *)sch; |
struct sdhc_host *hp = (struct sdhc_host *)sch; |
|
|
if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) { |
if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) { |
mutex_enter(&hp->host_mtx); |
mutex_enter(&hp->intr_mtx); |
if (enable) { |
if (enable) { |
HSET2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT); |
HSET2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT); |
HSET2(hp, SDHC_NINTR_SIGNAL_EN, SDHC_CARD_INTERRUPT); |
HSET2(hp, SDHC_NINTR_SIGNAL_EN, SDHC_CARD_INTERRUPT); |
Line 921 sdhc_card_enable_intr(sdmmc_chipset_hand |
|
Line 969 sdhc_card_enable_intr(sdmmc_chipset_hand |
|
HCLR2(hp, SDHC_NINTR_SIGNAL_EN, SDHC_CARD_INTERRUPT); |
HCLR2(hp, SDHC_NINTR_SIGNAL_EN, SDHC_CARD_INTERRUPT); |
HCLR2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT); |
HCLR2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT); |
} |
} |
mutex_exit(&hp->host_mtx); |
mutex_exit(&hp->intr_mtx); |
} |
} |
} |
} |
|
|
Line 931 sdhc_card_intr_ack(sdmmc_chipset_handle_ |
|
Line 979 sdhc_card_intr_ack(sdmmc_chipset_handle_ |
|
struct sdhc_host *hp = (struct sdhc_host *)sch; |
struct sdhc_host *hp = (struct sdhc_host *)sch; |
|
|
if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) { |
if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) { |
mutex_enter(&hp->host_mtx); |
mutex_enter(&hp->intr_mtx); |
HSET2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT); |
HSET2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT); |
mutex_exit(&hp->host_mtx); |
mutex_exit(&hp->intr_mtx); |
} |
} |
} |
} |
|
|
Line 959 sdhc_exec_command(sdmmc_chipset_handle_t |
|
Line 1007 sdhc_exec_command(sdmmc_chipset_handle_t |
|
struct sdhc_host *hp = (struct sdhc_host *)sch; |
struct sdhc_host *hp = (struct sdhc_host *)sch; |
int error; |
int error; |
|
|
#if 0 |
if (cmd->c_data && ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) { |
if (cmd->c_data) { |
|
const uint16_t ready = SDHC_BUFFER_READ_READY | SDHC_BUFFER_WRITE_READY; |
const uint16_t ready = SDHC_BUFFER_READ_READY | SDHC_BUFFER_WRITE_READY; |
|
mutex_enter(&hp->intr_mtx); |
if (ISSET(hp->flags, SHF_USE_DMA)) { |
if (ISSET(hp->flags, SHF_USE_DMA)) { |
HCLR2(hp, SDHC_NINTR_SIGNAL_EN, ready); |
HCLR2(hp, SDHC_NINTR_SIGNAL_EN, ready); |
HCLR2(hp, SDHC_NINTR_STATUS_EN, ready); |
HCLR2(hp, SDHC_NINTR_STATUS_EN, ready); |
Line 969 sdhc_exec_command(sdmmc_chipset_handle_t |
|
Line 1017 sdhc_exec_command(sdmmc_chipset_handle_t |
|
HSET2(hp, SDHC_NINTR_SIGNAL_EN, ready); |
HSET2(hp, SDHC_NINTR_SIGNAL_EN, ready); |
HSET2(hp, SDHC_NINTR_STATUS_EN, ready); |
HSET2(hp, SDHC_NINTR_STATUS_EN, ready); |
} |
} |
|
mutex_exit(&hp->intr_mtx); |
} |
} |
#endif |
|
|
|
/* |
/* |
* Start the MMC command, or mark `cmd' as failed and return. |
* Start the MMC command, or mark `cmd' as failed and return. |
Line 997 sdhc_exec_command(sdmmc_chipset_handle_t |
|
Line 1045 sdhc_exec_command(sdmmc_chipset_handle_t |
|
*/ |
*/ |
mutex_enter(&hp->host_mtx); |
mutex_enter(&hp->host_mtx); |
if (cmd->c_error == 0 && ISSET(cmd->c_flags, SCF_RSP_PRESENT)) { |
if (cmd->c_error == 0 && ISSET(cmd->c_flags, SCF_RSP_PRESENT)) { |
|
cmd->c_resp[0] = HREAD4(hp, SDHC_RESPONSE + 0); |
if (ISSET(cmd->c_flags, SCF_RSP_136)) { |
if (ISSET(cmd->c_flags, SCF_RSP_136)) { |
uint8_t *p = (uint8_t *)cmd->c_resp; |
cmd->c_resp[1] = HREAD4(hp, SDHC_RESPONSE + 4); |
int i; |
cmd->c_resp[2] = HREAD4(hp, SDHC_RESPONSE + 8); |
|
cmd->c_resp[3] = HREAD4(hp, SDHC_RESPONSE + 12); |
for (i = 0; i < 15; i++) |
if (ISSET(hp->sc->sc_flags, SDHC_FLAG_RSP136_CRC)) { |
*p++ = HREAD1(hp, SDHC_RESPONSE + i); |
cmd->c_resp[0] = (cmd->c_resp[0] >> 8) | |
} else { |
(cmd->c_resp[1] << 24); |
cmd->c_resp[0] = HREAD4(hp, SDHC_RESPONSE); |
cmd->c_resp[1] = (cmd->c_resp[1] >> 8) | |
|
(cmd->c_resp[2] << 24); |
|
cmd->c_resp[2] = (cmd->c_resp[2] >> 8) | |
|
(cmd->c_resp[3] << 24); |
|
cmd->c_resp[3] = (cmd->c_resp[3] >> 8); |
|
} |
} |
} |
} |
} |
mutex_exit(&hp->host_mtx); |
mutex_exit(&hp->host_mtx); |
Line 1018 sdhc_exec_command(sdmmc_chipset_handle_t |
|
Line 1072 sdhc_exec_command(sdmmc_chipset_handle_t |
|
sdhc_transfer_data(hp, cmd); |
sdhc_transfer_data(hp, cmd); |
|
|
out: |
out: |
#if 0 |
if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED) |
if (cmd->c_dmamap != NULL && cmd->c_error == 0 |
&& !ISSET(hp->sc->sc_flags, SDHC_FLAG_NO_LED_ON)) { |
&& ISSET(hp->flags, SHF_USE_DMA) |
|
&& ISSET(cmd->c_flags, SCF_CMD_READ) { |
|
if (((uintptr_t)cmd->c_data & PAGE_MASK) + cmd->c_datalen > PAGE_SIZE) { |
|
memcpy(cmd->c_data, |
|
(void *)hp->sc->dma_map->dm_segs[0].ds_addr, |
|
cmd->c_datalen); |
|
} |
|
bus_dmamap_unload(hp->sc->dt, hp->sc->dma_map); |
|
} |
|
#endif |
|
|
|
if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) { |
|
mutex_enter(&hp->host_mtx); |
mutex_enter(&hp->host_mtx); |
/* Turn off the LED. */ |
/* Turn off the LED. */ |
HCLR1(hp, SDHC_HOST_CTL, SDHC_LED_ON); |
HCLR1(hp, SDHC_HOST_CTL, SDHC_LED_ON); |
Line 1082 sdhc_start_command(struct sdhc_host *hp, |
|
Line 1124 sdhc_start_command(struct sdhc_host *hp, |
|
} |
} |
|
|
/* Prepare transfer mode register value. (2.2.5) */ |
/* Prepare transfer mode register value. (2.2.5) */ |
mode = 0; |
mode = SDHC_BLOCK_COUNT_ENABLE; |
if (ISSET(cmd->c_flags, SCF_CMD_READ)) |
if (ISSET(cmd->c_flags, SCF_CMD_READ)) |
mode |= SDHC_READ_MODE; |
mode |= SDHC_READ_MODE; |
if (blkcount > 0) { |
if (blkcount > 1) { |
mode |= SDHC_BLOCK_COUNT_ENABLE; |
mode |= SDHC_MULTI_BLOCK_MODE; |
if (blkcount > 1) { |
/* XXX only for memory commands? */ |
mode |= SDHC_MULTI_BLOCK_MODE; |
mode |= SDHC_AUTO_CMD12_ENABLE; |
/* XXX only for memory commands? */ |
|
mode |= SDHC_AUTO_CMD12_ENABLE; |
|
} |
|
} |
} |
if (cmd->c_dmamap != NULL && cmd->c_datalen > 0) { |
if (cmd->c_dmamap != NULL && cmd->c_datalen > 0) { |
if (cmd->c_dmamap->dm_nsegs == 1) { |
mode |= SDHC_DMA_ENABLE; |
mode |= SDHC_DMA_ENABLE; |
|
} else { |
|
cmd->c_dmamap = NULL; |
|
} |
|
} |
} |
|
|
/* |
/* |
Line 1130 sdhc_start_command(struct sdhc_host *hp, |
|
Line 1165 sdhc_start_command(struct sdhc_host *hp, |
|
DPRINTF(1,("%s: writing cmd: blksize=%d blkcnt=%d mode=%04x cmd=%04x\n", |
DPRINTF(1,("%s: writing cmd: blksize=%d blkcnt=%d mode=%04x cmd=%04x\n", |
HDEVNAME(hp), blksize, blkcount, mode, command)); |
HDEVNAME(hp), blksize, blkcount, mode, command)); |
|
|
|
blksize |= (MAX(0, PAGE_SHIFT - 12) & SDHC_DMA_BOUNDARY_MASK) << |
|
SDHC_DMA_BOUNDARY_SHIFT; /* PAGE_SIZE DMA boundary */ |
|
|
mutex_enter(&hp->host_mtx); |
mutex_enter(&hp->host_mtx); |
|
|
if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) { |
if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) { |
Line 1150 sdhc_start_command(struct sdhc_host *hp, |
|
Line 1188 sdhc_start_command(struct sdhc_host *hp, |
|
HWRITE4(hp, SDHC_ARGUMENT, cmd->c_arg); |
HWRITE4(hp, SDHC_ARGUMENT, cmd->c_arg); |
HWRITE4(hp, SDHC_TRANSFER_MODE, mode | (command << 16)); |
HWRITE4(hp, SDHC_TRANSFER_MODE, mode | (command << 16)); |
} else { |
} else { |
HWRITE2(hp, SDHC_TRANSFER_MODE, mode); |
|
HWRITE2(hp, SDHC_BLOCK_SIZE, blksize); |
HWRITE2(hp, SDHC_BLOCK_SIZE, blksize); |
if (blkcount > 1) |
HWRITE2(hp, SDHC_BLOCK_COUNT, blkcount); |
HWRITE2(hp, SDHC_BLOCK_COUNT, blkcount); |
|
HWRITE4(hp, SDHC_ARGUMENT, cmd->c_arg); |
HWRITE4(hp, SDHC_ARGUMENT, cmd->c_arg); |
|
HWRITE2(hp, SDHC_TRANSFER_MODE, mode); |
HWRITE2(hp, SDHC_COMMAND, command); |
HWRITE2(hp, SDHC_COMMAND, command); |
} |
} |
|
|
Line 1196 sdhc_transfer_data(struct sdhc_host *hp, |
|
Line 1233 sdhc_transfer_data(struct sdhc_host *hp, |
|
static int |
static int |
sdhc_transfer_data_dma(struct sdhc_host *hp, struct sdmmc_command *cmd) |
sdhc_transfer_data_dma(struct sdhc_host *hp, struct sdmmc_command *cmd) |
{ |
{ |
bus_dmamap_t dmap = cmd->c_dmamap; |
bus_dma_segment_t *dm_segs = cmd->c_dmamap->dm_segs; |
uint16_t blklen = cmd->c_blklen; |
bus_addr_t posaddr; |
uint16_t blkcnt = cmd->c_datalen / blklen; |
bus_addr_t segaddr; |
uint16_t remain; |
bus_size_t seglen; |
|
u_int seg = 0; |
int error = 0; |
int error = 0; |
|
int status; |
|
|
KASSERT(HREAD2(hp, SDHC_NINTR_STATUS_EN) & SDHC_DMA_INTERRUPT); |
KASSERT(HREAD2(hp, SDHC_NINTR_STATUS_EN) & SDHC_DMA_INTERRUPT); |
KASSERT(HREAD2(hp, SDHC_NINTR_SIGNAL_EN) & SDHC_DMA_INTERRUPT); |
KASSERT(HREAD2(hp, SDHC_NINTR_SIGNAL_EN) & SDHC_DMA_INTERRUPT); |
Line 1208 sdhc_transfer_data_dma(struct sdhc_host |
|
Line 1247 sdhc_transfer_data_dma(struct sdhc_host |
|
KASSERT(HREAD2(hp, SDHC_NINTR_SIGNAL_EN) & SDHC_TRANSFER_COMPLETE); |
KASSERT(HREAD2(hp, SDHC_NINTR_SIGNAL_EN) & SDHC_TRANSFER_COMPLETE); |
|
|
for (;;) { |
for (;;) { |
if (!sdhc_wait_intr(hp, |
status = sdhc_wait_intr(hp, |
SDHC_DMA_INTERRUPT|SDHC_TRANSFER_COMPLETE, |
SDHC_DMA_INTERRUPT|SDHC_TRANSFER_COMPLETE, |
SDHC_DMA_TIMEOUT)) { |
SDHC_DMA_TIMEOUT); |
|
|
|
if (status & SDHC_TRANSFER_COMPLETE) { |
|
break; |
|
} |
|
if (!status) { |
error = ETIMEDOUT; |
error = ETIMEDOUT; |
break; |
break; |
} |
} |
|
if ((status & SDHC_DMA_INTERRUPT) == 0) { |
|
continue; |
|
} |
|
|
/* single block mode */ |
/* DMA Interrupt (boundary crossing) */ |
if (blkcnt == 1) |
|
break; |
|
|
|
/* multi block mode */ |
segaddr = dm_segs[seg].ds_addr; |
remain = HREAD2(hp, SDHC_BLOCK_COUNT); |
seglen = dm_segs[seg].ds_len; |
if (remain == 0) |
mutex_enter(&hp->host_mtx); |
break; |
posaddr = HREAD4(hp, SDHC_DMA_ADDR); |
|
mutex_exit(&hp->host_mtx); |
|
|
HWRITE4(hp, SDHC_DMA_ADDR, |
if ((seg == (cmd->c_dmamap->dm_nsegs-1)) && (posaddr == (segaddr + seglen))) { |
dmap->dm_segs[0].ds_addr + (blkcnt - remain) * blklen); |
break; |
|
} |
|
mutex_enter(&hp->host_mtx); |
|
if ((posaddr >= segaddr) && (posaddr < (segaddr + seglen))) |
|
HWRITE4(hp, SDHC_DMA_ADDR, posaddr); |
|
else if ((posaddr >= segaddr) && (posaddr == (segaddr + seglen)) && (seg + 1) < cmd->c_dmamap->dm_nsegs) |
|
HWRITE4(hp, SDHC_DMA_ADDR, dm_segs[++seg].ds_addr); |
|
mutex_exit(&hp->host_mtx); |
|
KASSERT(seg < cmd->c_dmamap->dm_nsegs); |
} |
} |
|
|
#if 0 |
|
if (error == 0 && !sdhc_wait_intr(hp, SDHC_TRANSFER_COMPLETE, |
|
SDHC_TRANSFER_TIMEOUT)) |
|
error = ETIMEDOUT; |
|
#endif |
|
|
|
return error; |
return error; |
} |
} |
|
|
Line 1272 sdhc_transfer_data_pio(struct sdhc_host |
|
Line 1320 sdhc_transfer_data_pio(struct sdhc_host |
|
|
|
while (datalen > 0) { |
while (datalen > 0) { |
if (!ISSET(HREAD4(hp, SDHC_PRESENT_STATE), imask)) { |
if (!ISSET(HREAD4(hp, SDHC_PRESENT_STATE), imask)) { |
|
mutex_enter(&hp->intr_mtx); |
if (ISSET(hp->sc->sc_flags, SDHC_FLAG_32BIT_ACCESS)) { |
if (ISSET(hp->sc->sc_flags, SDHC_FLAG_32BIT_ACCESS)) { |
HSET4(hp, SDHC_NINTR_SIGNAL_EN, imask); |
HSET4(hp, SDHC_NINTR_SIGNAL_EN, imask); |
} else { |
} else { |
HSET2(hp, SDHC_NINTR_SIGNAL_EN, imask); |
HSET2(hp, SDHC_NINTR_SIGNAL_EN, imask); |
} |
} |
|
mutex_exit(&hp->intr_mtx); |
if (!sdhc_wait_intr(hp, imask, SDHC_BUFFER_TIMEOUT)) { |
if (!sdhc_wait_intr(hp, imask, SDHC_BUFFER_TIMEOUT)) { |
error = ETIMEDOUT; |
error = ETIMEDOUT; |
break; |
break; |
Line 1309 sdhc_read_data_pio(struct sdhc_host *hp, |
|
Line 1359 sdhc_read_data_pio(struct sdhc_host *hp, |
|
|
|
if (((__uintptr_t)data & 3) == 0) { |
if (((__uintptr_t)data & 3) == 0) { |
while (datalen > 3) { |
while (datalen > 3) { |
*(uint32_t *)data = HREAD4(hp, SDHC_DATA); |
*(uint32_t *)data = le32toh(HREAD4(hp, SDHC_DATA)); |
data += 4; |
data += 4; |
datalen -= 4; |
datalen -= 4; |
} |
} |
if (datalen > 1) { |
if (datalen > 1) { |
*(uint16_t *)data = HREAD2(hp, SDHC_DATA); |
*(uint16_t *)data = le16toh(HREAD2(hp, SDHC_DATA)); |
data += 2; |
data += 2; |
datalen -= 2; |
datalen -= 2; |
} |
} |
Line 1325 sdhc_read_data_pio(struct sdhc_host *hp, |
|
Line 1375 sdhc_read_data_pio(struct sdhc_host *hp, |
|
} |
} |
} else if (((__uintptr_t)data & 1) == 0) { |
} else if (((__uintptr_t)data & 1) == 0) { |
while (datalen > 1) { |
while (datalen > 1) { |
*(uint16_t *)data = HREAD2(hp, SDHC_DATA); |
*(uint16_t *)data = le16toh(HREAD2(hp, SDHC_DATA)); |
data += 2; |
data += 2; |
datalen -= 2; |
datalen -= 2; |
} |
} |
Line 1349 sdhc_write_data_pio(struct sdhc_host *hp |
|
Line 1399 sdhc_write_data_pio(struct sdhc_host *hp |
|
|
|
if (((__uintptr_t)data & 3) == 0) { |
if (((__uintptr_t)data & 3) == 0) { |
while (datalen > 3) { |
while (datalen > 3) { |
HWRITE4(hp, SDHC_DATA, *(uint32_t *)data); |
HWRITE4(hp, SDHC_DATA, htole32(*(uint32_t *)data)); |
data += 4; |
data += 4; |
datalen -= 4; |
datalen -= 4; |
} |
} |
if (datalen > 1) { |
if (datalen > 1) { |
HWRITE2(hp, SDHC_DATA, *(uint16_t *)data); |
HWRITE2(hp, SDHC_DATA, htole16(*(uint16_t *)data)); |
data += 2; |
data += 2; |
datalen -= 2; |
datalen -= 2; |
} |
} |
Line 1365 sdhc_write_data_pio(struct sdhc_host *hp |
|
Line 1415 sdhc_write_data_pio(struct sdhc_host *hp |
|
} |
} |
} else if (((__uintptr_t)data & 1) == 0) { |
} else if (((__uintptr_t)data & 1) == 0) { |
while (datalen > 1) { |
while (datalen > 1) { |
HWRITE2(hp, SDHC_DATA, *(uint16_t *)data); |
HWRITE2(hp, SDHC_DATA, htole16(*(uint16_t *)data)); |
data += 2; |
data += 2; |
datalen -= 2; |
datalen -= 2; |
} |
} |
Line 1389 esdhc_read_data_pio(struct sdhc_host *hp |
|
Line 1439 esdhc_read_data_pio(struct sdhc_host *hp |
|
uint16_t status = HREAD2(hp, SDHC_NINTR_STATUS); |
uint16_t status = HREAD2(hp, SDHC_NINTR_STATUS); |
uint32_t v; |
uint32_t v; |
|
|
|
const size_t watermark = (HREAD4(hp, SDHC_WATERMARK_LEVEL) >> SDHC_WATERMARK_READ_SHIFT) & SDHC_WATERMARK_READ_MASK; |
|
size_t count = 0; |
|
|
while (datalen > 3 && !ISSET(status, SDHC_TRANSFER_COMPLETE)) { |
while (datalen > 3 && !ISSET(status, SDHC_TRANSFER_COMPLETE)) { |
|
if (count == 0) { |
|
/* |
|
* If we've drained "watermark" words, we need to wait |
|
* a little bit so the read FIFO can refill. |
|
*/ |
|
sdmmc_delay(10); |
|
count = watermark; |
|
} |
v = HREAD4(hp, SDHC_DATA); |
v = HREAD4(hp, SDHC_DATA); |
v = le32toh(v); |
v = le32toh(v); |
*(uint32_t *)data = v; |
*(uint32_t *)data = v; |
data += 4; |
data += 4; |
datalen -= 4; |
datalen -= 4; |
status = HREAD2(hp, SDHC_NINTR_STATUS); |
status = HREAD2(hp, SDHC_NINTR_STATUS); |
|
count--; |
} |
} |
if (datalen > 0 && !ISSET(status, SDHC_TRANSFER_COMPLETE)) { |
if (datalen > 0 && !ISSET(status, SDHC_TRANSFER_COMPLETE)) { |
|
if (count == 0) { |
|
sdmmc_delay(10); |
|
} |
v = HREAD4(hp, SDHC_DATA); |
v = HREAD4(hp, SDHC_DATA); |
v = le32toh(v); |
v = le32toh(v); |
do { |
do { |
Line 1413 esdhc_write_data_pio(struct sdhc_host *h |
|
Line 1478 esdhc_write_data_pio(struct sdhc_host *h |
|
uint16_t status = HREAD2(hp, SDHC_NINTR_STATUS); |
uint16_t status = HREAD2(hp, SDHC_NINTR_STATUS); |
uint32_t v; |
uint32_t v; |
|
|
|
const size_t watermark = (HREAD4(hp, SDHC_WATERMARK_LEVEL) >> SDHC_WATERMARK_WRITE_SHIFT) & SDHC_WATERMARK_WRITE_MASK; |
|
size_t count = watermark; |
|
|
while (datalen > 3 && !ISSET(status, SDHC_TRANSFER_COMPLETE)) { |
while (datalen > 3 && !ISSET(status, SDHC_TRANSFER_COMPLETE)) { |
|
if (count == 0) { |
|
sdmmc_delay(10); |
|
count = watermark; |
|
} |
v = *(uint32_t *)data; |
v = *(uint32_t *)data; |
v = htole32(v); |
v = htole32(v); |
HWRITE4(hp, SDHC_DATA, v); |
HWRITE4(hp, SDHC_DATA, v); |
data += 4; |
data += 4; |
datalen -= 4; |
datalen -= 4; |
status = HREAD2(hp, SDHC_NINTR_STATUS); |
status = HREAD2(hp, SDHC_NINTR_STATUS); |
|
count--; |
} |
} |
if (datalen > 0 && !ISSET(status, SDHC_TRANSFER_COMPLETE)) { |
if (datalen > 0 && !ISSET(status, SDHC_TRANSFER_COMPLETE)) { |
|
if (count == 0) { |
|
sdmmc_delay(10); |
|
} |
v = *(uint32_t *)data; |
v = *(uint32_t *)data; |
v = htole32(v); |
v = htole32(v); |
HWRITE4(hp, SDHC_DATA, v); |
HWRITE4(hp, SDHC_DATA, v); |
Line 1516 sdhc_intr(void *arg) |
|
Line 1592 sdhc_intr(void *arg) |
|
uint32_t xstatus = HREAD4(hp, SDHC_NINTR_STATUS); |
uint32_t xstatus = HREAD4(hp, SDHC_NINTR_STATUS); |
status = xstatus; |
status = xstatus; |
error = xstatus >> 16; |
error = xstatus >> 16; |
status |= (error ? SDHC_ERROR_INTERRUPT : 0); |
if (error) |
if (!ISSET(status, SDHC_NINTR_STATUS_MASK)) |
xstatus |= SDHC_ERROR_INTERRUPT; |
|
else if (!ISSET(status, SDHC_NINTR_STATUS_MASK)) |
continue; /* no interrupt for us */ |
continue; /* no interrupt for us */ |
/* Acknowledge the interrupts we are about to handle. */ |
/* Acknowledge the interrupts we are about to handle. */ |
HWRITE4(hp, SDHC_NINTR_STATUS, xstatus); |
HWRITE4(hp, SDHC_NINTR_STATUS, xstatus); |
Line 1539 sdhc_intr(void *arg) |
|
Line 1616 sdhc_intr(void *arg) |
|
DPRINTF(2,("%s: interrupt status=%x error=%x\n", HDEVNAME(hp), |
DPRINTF(2,("%s: interrupt status=%x error=%x\n", HDEVNAME(hp), |
status, error)); |
status, error)); |
|
|
|
mutex_enter(&hp->intr_mtx); |
|
|
/* Claim this interrupt. */ |
/* Claim this interrupt. */ |
done = 1; |
done = 1; |
|
|
Line 1589 sdhc_intr(void *arg) |
|
Line 1668 sdhc_intr(void *arg) |
|
HCLR2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT); |
HCLR2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT); |
sdmmc_card_intr(hp->sdmmc); |
sdmmc_card_intr(hp->sdmmc); |
} |
} |
|
mutex_exit(&hp->intr_mtx); |
} |
} |
|
|
return done; |
return done; |