mirror of
https://github.com/fail0verflow/mini.git
synced 2024-11-28 06:04:19 +01:00
removed more useless SD code
This commit is contained in:
parent
661a30fc21
commit
fa08fede1e
253
sdhc.c
253
sdhc.c
@ -36,12 +36,13 @@
|
|||||||
#include "ipc.h"
|
#include "ipc.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct sdhc_host sc_host;
|
||||||
|
|
||||||
//#define SDHC_DEBUG
|
//#define SDHC_DEBUG
|
||||||
|
|
||||||
#define SDHC_COMMAND_TIMEOUT 500
|
#define SDHC_COMMAND_TIMEOUT 500
|
||||||
#define SDHC_TRANSFER_TIMEOUT 5000
|
#define SDHC_TRANSFER_TIMEOUT 5000
|
||||||
|
|
||||||
#define sdmmc_delay(t) udelay(t)
|
|
||||||
#define sdhc_wait_intr(a,b,c) sdhc_wait_intr_debug(__func__, __LINE__, a, b, c)
|
#define sdhc_wait_intr(a,b,c) sdhc_wait_intr_debug(__func__, __LINE__, a, b, c)
|
||||||
|
|
||||||
static inline u32 bus_space_read_4(bus_space_handle_t ioh, u32 reg)
|
static inline u32 bus_space_read_4(bus_space_handle_t ioh, u32 reg)
|
||||||
@ -142,11 +143,8 @@ void sdhc_dump_regs(struct sdhc_host *);
|
|||||||
* host controller standard register set. (1.3)
|
* host controller standard register set. (1.3)
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
sdhc_host_found(struct sdhc_softc *sc, bus_space_tag_t iot,
|
sdhc_host_found(bus_space_tag_t iot, bus_space_handle_t ioh, int usedma)
|
||||||
bus_space_handle_t ioh, int usedma)
|
|
||||||
{
|
{
|
||||||
struct sdmmcbus_attach_args saa;
|
|
||||||
struct sdhc_host *hp;
|
|
||||||
u_int32_t caps;
|
u_int32_t caps;
|
||||||
int error = 1;
|
int error = 1;
|
||||||
|
|
||||||
@ -166,46 +164,38 @@ sdhc_host_found(struct sdhc_softc *sc, bus_space_tag_t iot,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Allocate one more host structure. */
|
memset(&sc_host, 0, sizeof(sc_host));
|
||||||
if (sc->sc_nhosts < SDHC_MAX_HOSTS) {
|
|
||||||
sc->sc_nhosts++;
|
|
||||||
hp = &sc->sc_host[sc->sc_nhosts - 1];
|
|
||||||
memset(hp, 0, sizeof(*hp));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* Fill in the new host structure. */
|
/* Fill in the new host structure. */
|
||||||
hp->sc = sc;
|
sc_host.iot = iot;
|
||||||
hp->iot = iot;
|
sc_host.ioh = ioh;
|
||||||
hp->ioh = ioh;
|
sc_host.data_command = 0;
|
||||||
hp->data_command = 0;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reset the host controller and enable interrupts.
|
* Reset the host controller and enable interrupts.
|
||||||
*/
|
*/
|
||||||
(void)sdhc_host_reset(hp);
|
(void)sdhc_host_reset(&sc_host);
|
||||||
|
|
||||||
/* Determine host capabilities. */
|
/* Determine host capabilities. */
|
||||||
caps = HREAD4(hp, SDHC_CAPABILITIES);
|
caps = HREAD4(&sc_host, SDHC_CAPABILITIES);
|
||||||
|
|
||||||
/* Use DMA if the host system and the controller support it. */
|
/* Use DMA if the host system and the controller support it. */
|
||||||
if (usedma && ISSET(caps, SDHC_DMA_SUPPORT))
|
if (usedma && ISSET(caps, SDHC_DMA_SUPPORT))
|
||||||
SET(hp->flags, SHF_USE_DMA);
|
SET(sc_host.flags, SHF_USE_DMA);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Determine the base clock frequency. (2.2.24)
|
* Determine the base clock frequency. (2.2.24)
|
||||||
*/
|
*/
|
||||||
if (SDHC_BASE_FREQ_KHZ(caps) != 0)
|
if (SDHC_BASE_FREQ_KHZ(caps) != 0)
|
||||||
hp->clkbase = SDHC_BASE_FREQ_KHZ(caps);
|
sc_host.clkbase = SDHC_BASE_FREQ_KHZ(caps);
|
||||||
if (hp->clkbase == 0) {
|
if (sc_host.clkbase == 0) {
|
||||||
/* The attachment driver must tell us. */
|
/* The attachment driver must tell us. */
|
||||||
gecko_printf("sdhc: base clock frequency unknown\n");
|
gecko_printf("sdhc: base clock frequency unknown\n");
|
||||||
goto err;
|
goto err;
|
||||||
} else if (hp->clkbase < 10000 || hp->clkbase > 63000) {
|
} else if (sc_host.clkbase < 10000 || sc_host.clkbase > 63000) {
|
||||||
/* SDHC 1.0 supports only 10-63 MHz. */
|
/* SDHC 1.0 supports only 10-63 MHz. */
|
||||||
gecko_printf("sdhc: base clock frequency out of range: %u MHz\n",
|
gecko_printf("sdhc: base clock frequency out of range: %u MHz\n",
|
||||||
hp->clkbase / 1000);
|
sc_host.clkbase / 1000);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,41 +204,17 @@ sdhc_host_found(struct sdhc_softc *sc, bus_space_tag_t iot,
|
|||||||
* capabilities. (2.2.15)
|
* capabilities. (2.2.15)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
SET(hp->ocr, MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V);
|
SET(sc_host.ocr, MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V);
|
||||||
|
|
||||||
/*
|
|
||||||
* Determine the maximum block length supported by the host
|
|
||||||
* controller. (2.2.24)
|
|
||||||
*/
|
|
||||||
switch((caps >> SDHC_MAX_BLK_LEN_SHIFT) & SDHC_MAX_BLK_LEN_MASK) {
|
|
||||||
case SDHC_MAX_BLK_LEN_512:
|
|
||||||
hp->maxblklen = 512;
|
|
||||||
break;
|
|
||||||
case SDHC_MAX_BLK_LEN_1024:
|
|
||||||
hp->maxblklen = 1024;
|
|
||||||
break;
|
|
||||||
case SDHC_MAX_BLK_LEN_2048:
|
|
||||||
hp->maxblklen = 2048;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
hp->maxblklen = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Attach the generic SD/MMC bus driver. (The bus driver must
|
* Attach the generic SD/MMC bus driver. (The bus driver must
|
||||||
* not invoke any chipset functions before it is attached.)
|
* not invoke any chipset functions before it is attached.)
|
||||||
*/
|
*/
|
||||||
bzero(&saa, sizeof(saa));
|
sdmmc_attach(&sc_host);
|
||||||
saa.saa_busname = "sdmmc";
|
|
||||||
saa.sch = hp;
|
|
||||||
|
|
||||||
sdmmc_attach(hp, "sdhc", ioh);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
sc->sc_nhosts--;
|
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -257,17 +223,10 @@ err:
|
|||||||
* Shutdown hook established by or called from attachment driver.
|
* Shutdown hook established by or called from attachment driver.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
sdhc_shutdown(void *arg)
|
sdhc_shutdown(void)
|
||||||
{
|
{
|
||||||
struct sdhc_softc *sc = arg;
|
|
||||||
struct sdhc_host *hp;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
/* XXX chip locks up if we don't disable it before reboot. */
|
/* XXX chip locks up if we don't disable it before reboot. */
|
||||||
for (i = 0; i < sc->sc_nhosts; i++) {
|
(void)sdhc_host_reset(&sc_host);
|
||||||
hp = &sc->sc_host[i];
|
|
||||||
(void)sdhc_host_reset(hp);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -276,9 +235,8 @@ sdhc_shutdown(void *arg)
|
|||||||
* cards are removed, upon resume, and during error recovery.
|
* cards are removed, upon resume, and during error recovery.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
sdhc_host_reset(sdmmc_chipset_handle_t sch)
|
sdhc_host_reset(struct sdhc_host *hp)
|
||||||
{
|
{
|
||||||
struct sdhc_host *hp = sch;
|
|
||||||
u_int16_t imask;
|
u_int16_t imask;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
@ -313,27 +271,12 @@ sdhc_host_reset(sdmmc_chipset_handle_t sch)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
u_int32_t
|
|
||||||
sdhc_host_ocr(sdmmc_chipset_handle_t sch)
|
|
||||||
{
|
|
||||||
struct sdhc_host *hp = sch;
|
|
||||||
return hp->ocr;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
sdhc_host_maxblklen(sdmmc_chipset_handle_t sch)
|
|
||||||
{
|
|
||||||
struct sdhc_host *hp = sch;
|
|
||||||
return hp->maxblklen;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return non-zero if the card is currently inserted.
|
* Return non-zero if the card is currently inserted.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
sdhc_card_detect(sdmmc_chipset_handle_t sch)
|
sdhc_card_detect(struct sdhc_host *hp)
|
||||||
{
|
{
|
||||||
struct sdhc_host *hp = sch;
|
|
||||||
return ISSET(HREAD4(hp, SDHC_PRESENT_STATE), SDHC_CARD_INSERTED) ?
|
return ISSET(HREAD4(hp, SDHC_PRESENT_STATE), SDHC_CARD_INSERTED) ?
|
||||||
1 : 0;
|
1 : 0;
|
||||||
}
|
}
|
||||||
@ -343,10 +286,8 @@ sdhc_card_detect(sdmmc_chipset_handle_t sch)
|
|||||||
* Return zero on success.
|
* Return zero on success.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
sdhc_bus_power(sdmmc_chipset_handle_t sch, u_int32_t ocr)
|
sdhc_bus_power(struct sdhc_host *hp, u_int32_t ocr)
|
||||||
{
|
{
|
||||||
struct sdhc_host *hp = sch;
|
|
||||||
|
|
||||||
gecko_printf("sdhc_bus_power(%u)\n", ocr);
|
gecko_printf("sdhc_bus_power(%u)\n", ocr);
|
||||||
/* Disable bus power before voltage change. */
|
/* Disable bus power before voltage change. */
|
||||||
HWRITE1(hp, SDHC_POWER_CTL, 0);
|
HWRITE1(hp, SDHC_POWER_CTL, 0);
|
||||||
@ -363,7 +304,7 @@ sdhc_bus_power(sdmmc_chipset_handle_t sch, u_int32_t ocr)
|
|||||||
*/
|
*/
|
||||||
HWRITE1(hp, SDHC_POWER_CTL, (SDHC_VOLTAGE_3_3V << SDHC_VOLTAGE_SHIFT) |
|
HWRITE1(hp, SDHC_POWER_CTL, (SDHC_VOLTAGE_3_3V << SDHC_VOLTAGE_SHIFT) |
|
||||||
SDHC_BUS_POWER);
|
SDHC_BUS_POWER);
|
||||||
sdmmc_delay(10000);
|
udelay(10000);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The host system may not power the bus due to battery low,
|
* The host system may not power the bus due to battery low,
|
||||||
@ -399,12 +340,10 @@ sdhc_clock_divisor(struct sdhc_host *hp, u_int freq)
|
|||||||
* Return zero on success.
|
* Return zero on success.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
sdhc_bus_clock(sdmmc_chipset_handle_t sch, int freq)
|
sdhc_bus_clock(struct sdhc_host *hp, int freq)
|
||||||
{
|
{
|
||||||
struct sdhc_host *hp = sch;
|
|
||||||
int div;
|
int div;
|
||||||
int timo;
|
int timo;
|
||||||
int error = 0;
|
|
||||||
|
|
||||||
gecko_printf("%s(%d)\n", __FUNCTION__, freq);
|
gecko_printf("%s(%d)\n", __FUNCTION__, freq);
|
||||||
#ifdef DIAGNOSTIC
|
#ifdef DIAGNOSTIC
|
||||||
@ -414,52 +353,39 @@ sdhc_bus_clock(sdmmc_chipset_handle_t sch, int freq)
|
|||||||
gecko_printf("sdhc_sdclk_frequency_select: command in progress\n");
|
gecko_printf("sdhc_sdclk_frequency_select: command in progress\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/* Stop SD clock before changing the frequency. */
|
||||||
* Stop SD clock before changing the frequency.
|
|
||||||
*/
|
|
||||||
HWRITE2(hp, SDHC_CLOCK_CTL, 0);
|
HWRITE2(hp, SDHC_CLOCK_CTL, 0);
|
||||||
if (freq == SDMMC_SDCLK_OFF)
|
if (freq == SDMMC_SDCLK_OFF)
|
||||||
goto ret;
|
return 0;
|
||||||
|
|
||||||
/*
|
/* Set the minimum base clock frequency divisor. */
|
||||||
* Set the minimum base clock frequency divisor.
|
|
||||||
*/
|
|
||||||
if ((div = sdhc_clock_divisor(hp, freq)) < 0) {
|
if ((div = sdhc_clock_divisor(hp, freq)) < 0) {
|
||||||
/* Invalid base clock frequency or `freq' value. */
|
/* Invalid base clock frequency or `freq' value. */
|
||||||
error = EINVAL;
|
return EINVAL;
|
||||||
goto ret;
|
|
||||||
}
|
}
|
||||||
HWRITE2(hp, SDHC_CLOCK_CTL, div << SDHC_SDCLK_DIV_SHIFT);
|
HWRITE2(hp, SDHC_CLOCK_CTL, div << SDHC_SDCLK_DIV_SHIFT);
|
||||||
|
|
||||||
/*
|
/* Start internal clock. Wait 10ms for stabilization. */
|
||||||
* Start internal clock. Wait 10ms for stabilization.
|
|
||||||
*/
|
|
||||||
HSET2(hp, SDHC_CLOCK_CTL, SDHC_INTCLK_ENABLE);
|
HSET2(hp, SDHC_CLOCK_CTL, SDHC_INTCLK_ENABLE);
|
||||||
for (timo = 1000; timo > 0; timo--) {
|
for (timo = 1000; timo > 0; timo--) {
|
||||||
if (ISSET(HREAD2(hp, SDHC_CLOCK_CTL), SDHC_INTCLK_STABLE))
|
if (ISSET(HREAD2(hp, SDHC_CLOCK_CTL), SDHC_INTCLK_STABLE))
|
||||||
break;
|
break;
|
||||||
sdmmc_delay(10);
|
udelay(10);
|
||||||
}
|
}
|
||||||
if (timo == 0) {
|
if (timo == 0) {
|
||||||
gecko_printf("sdhc: internal clock never stabilized\n");
|
gecko_printf("sdhc: internal clock never stabilized\n");
|
||||||
error = ETIMEDOUT;
|
return ETIMEDOUT;
|
||||||
goto ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* Enable SD clock. */
|
||||||
* Enable SD clock.
|
|
||||||
*/
|
|
||||||
HSET2(hp, SDHC_CLOCK_CTL, SDHC_SDCLK_ENABLE);
|
HSET2(hp, SDHC_CLOCK_CTL, SDHC_SDCLK_ENABLE);
|
||||||
|
|
||||||
ret:
|
return 0;
|
||||||
return error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
sdhc_card_intr_mask(sdmmc_chipset_handle_t sch, int enable)
|
sdhc_card_intr_mask(struct sdhc_host *hp, int enable)
|
||||||
{
|
{
|
||||||
struct sdhc_host *hp = sch;
|
|
||||||
|
|
||||||
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);
|
||||||
@ -470,10 +396,8 @@ sdhc_card_intr_mask(sdmmc_chipset_handle_t sch, int enable)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
sdhc_card_intr_ack(sdmmc_chipset_handle_t sch)
|
sdhc_card_intr_ack(struct sdhc_host *hp)
|
||||||
{
|
{
|
||||||
struct sdhc_host *hp = sch;
|
|
||||||
|
|
||||||
HSET2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT);
|
HSET2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -487,16 +411,15 @@ sdhc_wait_state(struct sdhc_host *hp, u_int32_t mask, u_int32_t value)
|
|||||||
if (((state = HREAD4(hp, SDHC_PRESENT_STATE)) & mask)
|
if (((state = HREAD4(hp, SDHC_PRESENT_STATE)) & mask)
|
||||||
== value)
|
== value)
|
||||||
return 0;
|
return 0;
|
||||||
sdmmc_delay(10000);
|
udelay(10000);
|
||||||
}
|
}
|
||||||
DPRINTF(0,("sdhc: timeout waiting for %x (state=%d)\n", value, state));
|
DPRINTF(0,("sdhc: timeout waiting for %x (state=%d)\n", value, state));
|
||||||
return ETIMEDOUT;
|
return ETIMEDOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
sdhc_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd)
|
sdhc_exec_command(struct sdhc_host *hp, struct sdmmc_command *cmd)
|
||||||
{
|
{
|
||||||
struct sdhc_host *hp = sch;
|
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
if (cmd->c_datalen > 0)
|
if (cmd->c_datalen > 0)
|
||||||
@ -509,8 +432,7 @@ sdhc_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd)
|
|||||||
cmd->c_timeout = SDHC_COMMAND_TIMEOUT;
|
cmd->c_timeout = SDHC_COMMAND_TIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hp->intr_status = 0;
|
||||||
sdhc_reset_intr_status(hp);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Start the MMC command, or mark `cmd' as failed and return.
|
* Start the MMC command, or mark `cmd' as failed and return.
|
||||||
@ -563,9 +485,6 @@ sdhc_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd)
|
|||||||
if (cmd->c_error == 0 && cmd->c_datalen > 0)
|
if (cmd->c_error == 0 && cmd->c_datalen > 0)
|
||||||
sdhc_transfer_data(hp, cmd);
|
sdhc_transfer_data(hp, cmd);
|
||||||
|
|
||||||
/* Turn off the LED. */
|
|
||||||
HCLR1(hp, SDHC_HOST_CTL, SDHC_LED_ON);
|
|
||||||
|
|
||||||
DPRINTF(1,("sdhc: cmd %u done (flags=%#x error=%d prev state=%d)\n",
|
DPRINTF(1,("sdhc: cmd %u done (flags=%#x error=%d prev state=%d)\n",
|
||||||
cmd->c_opcode, cmd->c_flags, cmd->c_error, (cmd->c_resp[0] >> 9) & 15));
|
cmd->c_opcode, cmd->c_flags, cmd->c_error, (cmd->c_resp[0] >> 9) & 15));
|
||||||
SET(cmd->c_flags, SCF_ITSDONE);
|
SET(cmd->c_flags, SCF_ITSDONE);
|
||||||
@ -647,9 +566,6 @@ sdhc_start_command(struct sdhc_host *hp, struct sdmmc_command *cmd)
|
|||||||
if ((error = sdhc_wait_state(hp, SDHC_CMD_INHIBIT_MASK, 0)) != 0)
|
if ((error = sdhc_wait_state(hp, SDHC_CMD_INHIBIT_MASK, 0)) != 0)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
/* Alert the user not to remove the card. */
|
|
||||||
HSET1(hp, SDHC_HOST_CTL, SDHC_LED_ON);
|
|
||||||
|
|
||||||
if (ISSET(hp->flags, SHF_USE_DMA) && cmd->c_datalen > 0) {
|
if (ISSET(hp->flags, SHF_USE_DMA) && cmd->c_datalen > 0) {
|
||||||
cmd->c_resid = blkcount;
|
cmd->c_resid = blkcount;
|
||||||
cmd->c_buf = cmd->c_data;
|
cmd->c_buf = cmd->c_data;
|
||||||
@ -751,7 +667,7 @@ sdhc_soft_reset(struct sdhc_host *hp, int mask)
|
|||||||
for (timo = 10; timo > 0; timo--) {
|
for (timo = 10; timo > 0; timo--) {
|
||||||
if (!ISSET(HREAD1(hp, SDHC_SOFTWARE_RESET), mask))
|
if (!ISSET(HREAD1(hp, SDHC_SOFTWARE_RESET), mask))
|
||||||
break;
|
break;
|
||||||
sdmmc_delay(10000);
|
udelay(10000);
|
||||||
HWRITE1(hp, SDHC_SOFTWARE_RESET, 0);
|
HWRITE1(hp, SDHC_SOFTWARE_RESET, 0);
|
||||||
}
|
}
|
||||||
if (timo == 0) {
|
if (timo == 0) {
|
||||||
@ -762,12 +678,6 @@ sdhc_soft_reset(struct sdhc_host *hp, int mask)
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void sdhc_reset_intr_status(struct sdhc_host *hp)
|
|
||||||
{
|
|
||||||
hp->intr_status = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
sdhc_wait_intr_debug(const char *funcname, int line, struct sdhc_host *hp, int mask, int timo)
|
sdhc_wait_intr_debug(const char *funcname, int line, struct sdhc_host *hp, int mask, int timo)
|
||||||
{
|
{
|
||||||
@ -778,7 +688,6 @@ sdhc_wait_intr_debug(const char *funcname, int line, struct sdhc_host *hp, int m
|
|||||||
|
|
||||||
status = hp->intr_status & mask;
|
status = hp->intr_status & mask;
|
||||||
|
|
||||||
|
|
||||||
for (; timo > 0; timo--) {
|
for (; timo > 0; timo--) {
|
||||||
#ifndef CAN_HAZ_IRQ
|
#ifndef CAN_HAZ_IRQ
|
||||||
sdhc_irq(); // seems backwards but ok
|
sdhc_irq(); // seems backwards but ok
|
||||||
@ -825,78 +734,61 @@ sdhc_wait_intr_debug(const char *funcname, int line, struct sdhc_host *hp, int m
|
|||||||
* Established by attachment driver at interrupt priority IPL_SDMMC.
|
* Established by attachment driver at interrupt priority IPL_SDMMC.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
sdhc_intr(void *arg)
|
sdhc_intr(void)
|
||||||
{
|
{
|
||||||
struct sdhc_softc *sc = arg;
|
|
||||||
int host;
|
|
||||||
int done = 0;
|
|
||||||
|
|
||||||
/* We got an interrupt, but we don't know from which slot. */
|
|
||||||
for (host = 0; host < sc->sc_nhosts; host++) {
|
|
||||||
struct sdhc_host *hp = &sc->sc_host[host];
|
|
||||||
u_int16_t status;
|
u_int16_t status;
|
||||||
|
|
||||||
if (hp == NULL)
|
DPRINTF(1,("shdc_intr():\n"));
|
||||||
continue;
|
sdhc_dump_regs(&sc_host);
|
||||||
|
|
||||||
DPRINTF(1,("shdc_intr(%d):\n", host));
|
|
||||||
sdhc_dump_regs(hp);
|
|
||||||
|
|
||||||
/* Find out which interrupts are pending. */
|
/* Find out which interrupts are pending. */
|
||||||
status = HREAD2(hp, SDHC_NINTR_STATUS);
|
status = HREAD2(&sc_host, SDHC_NINTR_STATUS);
|
||||||
if (!ISSET(status, SDHC_NINTR_STATUS_MASK))
|
if (!ISSET(status, SDHC_NINTR_STATUS_MASK)) {
|
||||||
continue; /* no interrupt for us */
|
DPRINTF(1, ("unknown interrupt\n"));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Acknowledge the interrupts we are about to handle. */
|
/* Acknowledge the interrupts we are about to handle. */
|
||||||
HWRITE2(hp, SDHC_NINTR_STATUS, status);
|
HWRITE2(&sc_host, SDHC_NINTR_STATUS, status);
|
||||||
DPRINTF(2,("sdhc: interrupt status=%d\n", status));
|
DPRINTF(2,("sdhc: interrupt status=%d\n", status));
|
||||||
|
|
||||||
|
/* Service error interrupts. */
|
||||||
/* Claim this interrupt. */
|
|
||||||
done = 1;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Service error interrupts.
|
|
||||||
*/
|
|
||||||
if (ISSET(status, SDHC_ERROR_INTERRUPT)) {
|
if (ISSET(status, SDHC_ERROR_INTERRUPT)) {
|
||||||
u_int16_t error;
|
u_int16_t error;
|
||||||
u_int16_t signal;
|
u_int16_t signal;
|
||||||
|
|
||||||
/* Acknowledge error interrupts. */
|
/* Acknowledge error interrupts. */
|
||||||
error = HREAD2(hp, SDHC_EINTR_STATUS);
|
error = HREAD2(&sc_host, SDHC_EINTR_STATUS);
|
||||||
signal = HREAD2(hp, SDHC_EINTR_SIGNAL_EN);
|
signal = HREAD2(&sc_host, SDHC_EINTR_SIGNAL_EN);
|
||||||
HWRITE2(hp, SDHC_EINTR_SIGNAL_EN, 0);
|
HWRITE2(&sc_host, SDHC_EINTR_SIGNAL_EN, 0);
|
||||||
(void)sdhc_soft_reset(hp, SDHC_RESET_DAT|SDHC_RESET_CMD);
|
(void)sdhc_soft_reset(&sc_host, SDHC_RESET_DAT|SDHC_RESET_CMD);
|
||||||
if (hp->data_command == 1) {
|
if (sc_host.data_command == 1) {
|
||||||
hp->data_command = 0;
|
sc_host.data_command = 0;
|
||||||
|
|
||||||
// TODO: add a way to send commands from irq
|
// TODO: add a way to send commands from irq
|
||||||
// context and uncomment this
|
// context and uncomment this
|
||||||
// sdmmc_abort();
|
// sdmmc_abort();
|
||||||
}
|
}
|
||||||
HWRITE2(hp, SDHC_EINTR_STATUS, error);
|
HWRITE2(&sc_host, SDHC_EINTR_STATUS, error);
|
||||||
HWRITE2(hp, SDHC_EINTR_SIGNAL_EN, signal);
|
HWRITE2(&sc_host, SDHC_EINTR_SIGNAL_EN, signal);
|
||||||
|
|
||||||
DPRINTF(2,("sdhc: error interrupt, status=%d\n", error));
|
DPRINTF(2,("sdhc: error interrupt, status=%d\n", error));
|
||||||
|
|
||||||
if (ISSET(error, SDHC_CMD_TIMEOUT_ERROR|
|
if (ISSET(error, SDHC_CMD_TIMEOUT_ERROR|
|
||||||
SDHC_DATA_TIMEOUT_ERROR)) {
|
SDHC_DATA_TIMEOUT_ERROR)) {
|
||||||
hp->intr_error_status |= error;
|
sc_host.intr_error_status |= error;
|
||||||
hp->intr_status |= status;
|
sc_host.intr_status |= status;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CAN_HAZ_IPC
|
#ifdef CAN_HAZ_IPC
|
||||||
/*
|
/* Wake up the sdmmc event thread to scan for cards. */
|
||||||
* Wake up the sdmmc event thread to scan for cards.
|
|
||||||
*/
|
|
||||||
if (ISSET(status, SDHC_CARD_REMOVAL|SDHC_CARD_INSERTION)) {
|
if (ISSET(status, SDHC_CARD_REMOVAL|SDHC_CARD_INSERTION)) {
|
||||||
// this pushes a request to the slow queue so that we
|
// this pushes a request to the slow queue so that we
|
||||||
// don't block other IRQs.
|
// don't block other IRQs.
|
||||||
ipc_enqueue_slow(IPC_DEV_SDHC, IPC_SDHC_DISCOVER, 0);
|
ipc_enqueue_slow(IPC_DEV_SDHC, IPC_SDHC_DISCOVER, 0);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Wake up the blocking process to service command
|
* Wake up the blocking process to service command
|
||||||
* related interrupt(s).
|
* related interrupt(s).
|
||||||
@ -904,19 +796,15 @@ sdhc_intr(void *arg)
|
|||||||
if (ISSET(status, SDHC_BUFFER_READ_READY|
|
if (ISSET(status, SDHC_BUFFER_READ_READY|
|
||||||
SDHC_BUFFER_WRITE_READY|SDHC_COMMAND_COMPLETE|
|
SDHC_BUFFER_WRITE_READY|SDHC_COMMAND_COMPLETE|
|
||||||
SDHC_TRANSFER_COMPLETE|SDHC_DMA_INTERRUPT)) {
|
SDHC_TRANSFER_COMPLETE|SDHC_DMA_INTERRUPT)) {
|
||||||
hp->intr_status |= status;
|
sc_host.intr_status |= status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* Service SD card interrupts. */
|
||||||
* Service SD card interrupts.
|
|
||||||
*/
|
|
||||||
if (ISSET(status, SDHC_CARD_INTERRUPT)) {
|
if (ISSET(status, SDHC_CARD_INTERRUPT)) {
|
||||||
// DPRINTF(0,("%s: card interrupt\n", HDEVNAME(hp)));
|
DPRINTF(0,("sdhc: card interrupt\n"));
|
||||||
HCLR2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT);
|
HCLR2(&sc_host, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT);
|
||||||
// sdmmc_card_intr(hp->sdmmc);
|
|
||||||
}
|
}
|
||||||
}
|
return 1;
|
||||||
return done;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SDHC_DEBUG
|
#ifdef SDHC_DEBUG
|
||||||
@ -947,15 +835,10 @@ sdhc_dump_regs(struct sdhc_host *hp)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "hollywood.h"
|
#include "hollywood.h"
|
||||||
#ifdef LOADER
|
|
||||||
static struct sdhc_softc __softc;
|
|
||||||
#else
|
|
||||||
static struct sdhc_softc __softc MEM2_BSS;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void sdhc_irq(void)
|
void sdhc_irq(void)
|
||||||
{
|
{
|
||||||
sdhc_intr(&__softc);
|
sdhc_intr();
|
||||||
}
|
}
|
||||||
|
|
||||||
void sdhc_init(void)
|
void sdhc_init(void)
|
||||||
@ -963,10 +846,7 @@ void sdhc_init(void)
|
|||||||
#ifdef CAN_HAZ_IRQ
|
#ifdef CAN_HAZ_IRQ
|
||||||
irq_enable(IRQ_SDHC);
|
irq_enable(IRQ_SDHC);
|
||||||
#endif
|
#endif
|
||||||
memset(&__softc, 0, sizeof(__softc));
|
sdhc_host_found(0, SDHC_REG_BASE, 1);
|
||||||
sdhc_host_found(&__softc, 0, SDHC_REG_BASE, 1);
|
|
||||||
// sdhc_host_found(&__softc, 0, SDHC_REG_BASE + 0x100, 1);
|
|
||||||
// sdhc_host_found(&__softc, 0, 0x0d080000, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void sdhc_exit(void)
|
void sdhc_exit(void)
|
||||||
@ -987,6 +867,7 @@ void sdhc_ipc(volatile ipc_request *req)
|
|||||||
case IPC_SDHC_EXIT:
|
case IPC_SDHC_EXIT:
|
||||||
sdhc_exit();
|
sdhc_exit();
|
||||||
ipc_post(req->code, req->tag, 0);
|
ipc_post(req->code, req->tag, 0);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
14
sdhc.h
14
sdhc.h
@ -25,16 +25,10 @@
|
|||||||
#include "ipc.h"
|
#include "ipc.h"
|
||||||
#endif
|
#endif
|
||||||
#include "sdmmc.h"
|
#include "sdmmc.h"
|
||||||
|
|
||||||
#define SDHC_MAX_HOSTS 4
|
|
||||||
|
|
||||||
struct sdhc_host {
|
struct sdhc_host {
|
||||||
struct sdhc_softc *sc; /* host controller device */
|
|
||||||
struct device *sdmmc; /* generic SD/MMC device */
|
|
||||||
bus_space_tag_t iot; /* host register set tag */
|
bus_space_tag_t iot; /* host register set tag */
|
||||||
bus_space_handle_t ioh; /* host register set handle */
|
bus_space_handle_t ioh; /* host register set handle */
|
||||||
u_int clkbase; /* base clock frequency in KHz */
|
u_int clkbase; /* base clock frequency in KHz */
|
||||||
int maxblklen; /* maximum block length */
|
|
||||||
int flags; /* flags for this host */
|
int flags; /* flags for this host */
|
||||||
u_int32_t ocr; /* OCR value from capabilities */
|
u_int32_t ocr; /* OCR value from capabilities */
|
||||||
u_int8_t regs[14]; /* host controller state */
|
u_int8_t regs[14]; /* host controller state */
|
||||||
@ -174,11 +168,6 @@ void sdhc_ipc(volatile ipc_request *req);
|
|||||||
#define SDHC_VOLTAGE_SUPP_3_3V (1<<24)
|
#define SDHC_VOLTAGE_SUPP_3_3V (1<<24)
|
||||||
#define SDHC_DMA_SUPPORT (1<<22)
|
#define SDHC_DMA_SUPPORT (1<<22)
|
||||||
#define SDHC_HIGH_SPEED_SUPP (1<<21)
|
#define SDHC_HIGH_SPEED_SUPP (1<<21)
|
||||||
#define SDHC_MAX_BLK_LEN_512 0
|
|
||||||
#define SDHC_MAX_BLK_LEN_1024 1
|
|
||||||
#define SDHC_MAX_BLK_LEN_2048 2
|
|
||||||
#define SDHC_MAX_BLK_LEN_SHIFT 16
|
|
||||||
#define SDHC_MAX_BLK_LEN_MASK 0x3
|
|
||||||
#define SDHC_BASE_FREQ_SHIFT 8
|
#define SDHC_BASE_FREQ_SHIFT 8
|
||||||
#define SDHC_BASE_FREQ_MASK 0x3f
|
#define SDHC_BASE_FREQ_MASK 0x3f
|
||||||
#define SDHC_TIMEOUT_FREQ_UNIT (1<<7) /* 0=KHz, 1=MHz */
|
#define SDHC_TIMEOUT_FREQ_UNIT (1<<7) /* 0=KHz, 1=MHz */
|
||||||
@ -208,12 +197,9 @@ void sdhc_ipc(volatile ipc_request *req);
|
|||||||
#define SDHC_VENDOR_VERSION(hcv) \
|
#define SDHC_VENDOR_VERSION(hcv) \
|
||||||
(((hcv) >> SDHC_VENDOR_VERS_SHIFT) & SDHC_VENDOR_VERS_MASK)
|
(((hcv) >> SDHC_VENDOR_VERS_SHIFT) & SDHC_VENDOR_VERS_MASK)
|
||||||
|
|
||||||
//typedef void *sdmmc_chipset_handle_t;
|
|
||||||
struct sdmmc_command;
|
struct sdmmc_command;
|
||||||
|
|
||||||
int sdhc_host_reset(struct sdhc_host *hp);
|
int sdhc_host_reset(struct sdhc_host *hp);
|
||||||
u_int32_t sdhc_host_ocr(struct sdhc_host *hp);
|
|
||||||
int sdhc_host_maxblklen(struct sdhc_host *hp);
|
|
||||||
int sdhc_card_detect(struct sdhc_host *hp);
|
int sdhc_card_detect(struct sdhc_host *hp);
|
||||||
int sdhc_bus_power(struct sdhc_host *hp, u_int32_t);
|
int sdhc_bus_power(struct sdhc_host *hp, u_int32_t);
|
||||||
int sdhc_bus_clock(struct sdhc_host *hp, int);
|
int sdhc_bus_clock(struct sdhc_host *hp, int);
|
||||||
|
150
sdmmc.c
150
sdmmc.c
@ -25,10 +25,7 @@ static int sdmmcdebug = 0;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct sdmmc_card {
|
struct sdmmc_card {
|
||||||
struct sdmmc_chip_functions *functions;
|
|
||||||
sdmmc_chipset_handle_t handle;
|
sdmmc_chipset_handle_t handle;
|
||||||
char name[30];
|
|
||||||
int no;
|
|
||||||
int inserted;
|
int inserted;
|
||||||
int sdhc_blockmode;
|
int sdhc_blockmode;
|
||||||
int selected;
|
int selected;
|
||||||
@ -41,35 +38,22 @@ struct sdmmc_card {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#ifdef LOADER
|
#ifdef LOADER
|
||||||
static struct sdmmc_card cards[SDHC_MAX_HOSTS];
|
static struct sdmmc_card card;
|
||||||
#else
|
#else
|
||||||
static struct sdmmc_card cards[SDHC_MAX_HOSTS] MEM2_BSS;
|
static struct sdmmc_card card MEM2_BSS;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int n_cards = 0;
|
void sdmmc_attach(sdmmc_chipset_handle_t handle)
|
||||||
|
|
||||||
void sdmmc_attach(sdmmc_chipset_handle_t handle, const char *name, int no)
|
|
||||||
{
|
{
|
||||||
struct sdmmc_card *c;
|
memset(&card, 0, sizeof(card));
|
||||||
|
|
||||||
if (n_cards >= SDHC_MAX_HOSTS) {
|
card.handle = handle;
|
||||||
gecko_printf("n_cards(%d) >= %d!\n", n_cards, SDHC_MAX_HOSTS);
|
|
||||||
gecko_printf("starlet is soo going to crash very soon...\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
c = &cards[n_cards++];
|
DPRINTF(0, ("sdmmc: attached new SD/MMC card\n"));
|
||||||
memset(c, 0, sizeof(*c));
|
|
||||||
|
|
||||||
c->handle = handle;
|
sdhc_host_reset(card.handle);
|
||||||
c->no = no;
|
|
||||||
strlcpy(c->name, name, sizeof(c->name));
|
|
||||||
|
|
||||||
DPRINTF(0, ("sdmmc: attached new SD/MMC card %d for host [%s:%d]\n",
|
if (sdhc_card_detect(card.handle)) {
|
||||||
n_cards-1, c->name, c->no));
|
|
||||||
|
|
||||||
sdhc_host_reset(c->handle);
|
|
||||||
|
|
||||||
if (sdhc_card_detect(c->handle)) {
|
|
||||||
DPRINTF(1, ("card is inserted. starting init sequence.\n"));
|
DPRINTF(1, ("card is inserted. starting init sequence.\n"));
|
||||||
sdmmc_needs_discover();
|
sdmmc_needs_discover();
|
||||||
}
|
}
|
||||||
@ -83,33 +67,32 @@ void sdmmc_abort(void) {
|
|||||||
cmd.c_opcode = MMC_STOP_TRANSMISSION;
|
cmd.c_opcode = MMC_STOP_TRANSMISSION;
|
||||||
cmd.c_arg = 0;
|
cmd.c_arg = 0;
|
||||||
cmd.c_flags = SCF_RSP_R1B;
|
cmd.c_flags = SCF_RSP_R1B;
|
||||||
sdhc_exec_command(&cards[0].handle, &cmd);
|
sdhc_exec_command(card.handle, &cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sdmmc_needs_discover(void)
|
void sdmmc_needs_discover(void)
|
||||||
{
|
{
|
||||||
struct sdmmc_card *c = &cards[0];
|
|
||||||
struct sdmmc_command cmd;
|
struct sdmmc_command cmd;
|
||||||
u32 ocr;
|
u32 ocr;
|
||||||
|
|
||||||
DPRINTF(0, ("sdmmc: card needs discovery.\n"));
|
DPRINTF(0, ("sdmmc: card needs discovery.\n"));
|
||||||
sdhc_host_reset(c->handle);
|
sdhc_host_reset(card.handle);
|
||||||
c->new_card = 1;
|
card.new_card = 1;
|
||||||
|
|
||||||
if (!sdhc_card_detect(c->handle)) {
|
if (!sdhc_card_detect(card.handle)) {
|
||||||
DPRINTF(1, ("sdmmc: card (no longer?) inserted.\n"));
|
DPRINTF(1, ("sdmmc: card (no longer?) inserted.\n"));
|
||||||
c->inserted = 0;
|
card.inserted = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DPRINTF(1, ("sdmmc: enabling power\n"));
|
DPRINTF(1, ("sdmmc: enabling power\n"));
|
||||||
if (sdhc_bus_power(c->handle, 1) != 0) {
|
if (sdhc_bus_power(card.handle, 1) != 0) {
|
||||||
gecko_printf("sdmmc: powerup failed for card\n");
|
gecko_printf("sdmmc: powerup failed for card\n");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
DPRINTF(1, ("sdmmc: enabling clock\n"));
|
DPRINTF(1, ("sdmmc: enabling clock\n"));
|
||||||
if (sdhc_bus_clock(c->handle, SDMMC_DEFAULT_CLOCK) != 0) {
|
if (sdhc_bus_clock(card.handle, SDMMC_DEFAULT_CLOCK) != 0) {
|
||||||
gecko_printf("sdmmc: could not enable clock for card\n");
|
gecko_printf("sdmmc: could not enable clock for card\n");
|
||||||
goto out_power;
|
goto out_power;
|
||||||
}
|
}
|
||||||
@ -119,7 +102,7 @@ void sdmmc_needs_discover(void)
|
|||||||
memset(&cmd, 0, sizeof(cmd));
|
memset(&cmd, 0, sizeof(cmd));
|
||||||
cmd.c_opcode = MMC_GO_IDLE_STATE;
|
cmd.c_opcode = MMC_GO_IDLE_STATE;
|
||||||
cmd.c_flags = SCF_RSP_R0;
|
cmd.c_flags = SCF_RSP_R0;
|
||||||
sdhc_exec_command(c->handle, &cmd);
|
sdhc_exec_command(card.handle, &cmd);
|
||||||
|
|
||||||
if (cmd.c_error) {
|
if (cmd.c_error) {
|
||||||
gecko_printf("sdmmc: GO_IDLE_STATE failed with %d\n", cmd.c_error);
|
gecko_printf("sdmmc: GO_IDLE_STATE failed with %d\n", cmd.c_error);
|
||||||
@ -134,9 +117,9 @@ void sdmmc_needs_discover(void)
|
|||||||
cmd.c_arg = 0x1aa;
|
cmd.c_arg = 0x1aa;
|
||||||
cmd.c_flags = SCF_RSP_R7;
|
cmd.c_flags = SCF_RSP_R7;
|
||||||
cmd.c_timeout = 100;
|
cmd.c_timeout = 100;
|
||||||
sdhc_exec_command(c->handle, &cmd);
|
sdhc_exec_command(card.handle, &cmd);
|
||||||
|
|
||||||
ocr = sdhc_host_ocr(c->handle);
|
ocr = card.handle->ocr;
|
||||||
if (cmd.c_error || (cmd.c_resp[0] & 0xff) != 0xaa)
|
if (cmd.c_error || (cmd.c_resp[0] & 0xff) != 0xaa)
|
||||||
ocr &= ~SD_OCR_SDHC_CAP;
|
ocr &= ~SD_OCR_SDHC_CAP;
|
||||||
else
|
else
|
||||||
@ -151,7 +134,7 @@ void sdmmc_needs_discover(void)
|
|||||||
cmd.c_opcode = MMC_APP_CMD;
|
cmd.c_opcode = MMC_APP_CMD;
|
||||||
cmd.c_arg = 0;
|
cmd.c_arg = 0;
|
||||||
cmd.c_flags = SCF_RSP_R1;
|
cmd.c_flags = SCF_RSP_R1;
|
||||||
sdhc_exec_command(c->handle, &cmd);
|
sdhc_exec_command(card.handle, &cmd);
|
||||||
|
|
||||||
if (cmd.c_error)
|
if (cmd.c_error)
|
||||||
continue;
|
continue;
|
||||||
@ -160,7 +143,7 @@ void sdmmc_needs_discover(void)
|
|||||||
cmd.c_opcode = SD_APP_OP_COND;
|
cmd.c_opcode = SD_APP_OP_COND;
|
||||||
cmd.c_arg = ocr;
|
cmd.c_arg = ocr;
|
||||||
cmd.c_flags = SCF_RSP_R3;
|
cmd.c_flags = SCF_RSP_R3;
|
||||||
sdhc_exec_command(c->handle, &cmd);
|
sdhc_exec_command(card.handle, &cmd);
|
||||||
if (cmd.c_error)
|
if (cmd.c_error)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -175,10 +158,10 @@ void sdmmc_needs_discover(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ISSET(MMC_R1(cmd.c_resp), SD_OCR_SDHC_CAP))
|
if (ISSET(MMC_R1(cmd.c_resp), SD_OCR_SDHC_CAP))
|
||||||
c->sdhc_blockmode = 1;
|
card.sdhc_blockmode = 1;
|
||||||
else
|
else
|
||||||
c->sdhc_blockmode = 0;
|
card.sdhc_blockmode = 0;
|
||||||
DPRINTF(2, ("sdmmc: SDHC: %d\n", c->sdhc_blockmode));
|
DPRINTF(2, ("sdmmc: SDHC: %d\n", card.sdhc_blockmode));
|
||||||
|
|
||||||
u8 *resp;
|
u8 *resp;
|
||||||
DPRINTF(2, ("sdmmc: MMC_ALL_SEND_CID\n"));
|
DPRINTF(2, ("sdmmc: MMC_ALL_SEND_CID\n"));
|
||||||
@ -186,13 +169,13 @@ void sdmmc_needs_discover(void)
|
|||||||
cmd.c_opcode = MMC_ALL_SEND_CID;
|
cmd.c_opcode = MMC_ALL_SEND_CID;
|
||||||
cmd.c_arg = 0;
|
cmd.c_arg = 0;
|
||||||
cmd.c_flags = SCF_RSP_R2;
|
cmd.c_flags = SCF_RSP_R2;
|
||||||
sdhc_exec_command(c->handle, &cmd);
|
sdhc_exec_command(card.handle, &cmd);
|
||||||
if (cmd.c_error) {
|
if (cmd.c_error) {
|
||||||
gecko_printf("sdmmc: MMC_ALL_SEND_CID failed with %d\n", cmd.c_error);
|
gecko_printf("sdmmc: MMC_ALL_SEND_CID failed with %d\n", cmd.c_error);
|
||||||
goto out_clock;
|
goto out_clock;
|
||||||
}
|
}
|
||||||
|
|
||||||
c->cid = MMC_R1(cmd.c_resp);
|
card.cid = MMC_R1(cmd.c_resp);
|
||||||
resp = (u8 *)cmd.c_resp;
|
resp = (u8 *)cmd.c_resp;
|
||||||
gecko_printf("CID: mid=%02x name='%c%c%c%c%c%c%c' prv=%d.%d psn=%02x%02x%02x%02x mdt=%d/%d\n", resp[14],
|
gecko_printf("CID: mid=%02x name='%c%c%c%c%c%c%c' prv=%d.%d psn=%02x%02x%02x%02x mdt=%d/%d\n", resp[14],
|
||||||
resp[13],resp[12],resp[11],resp[10],resp[9],resp[8],resp[7], resp[6], resp[5] >> 4, resp[5] & 0xf,
|
resp[13],resp[12],resp[11],resp[10],resp[9],resp[8],resp[7], resp[6], resp[5] >> 4, resp[5] & 0xf,
|
||||||
@ -203,23 +186,23 @@ void sdmmc_needs_discover(void)
|
|||||||
cmd.c_opcode = SD_SEND_RELATIVE_ADDR;
|
cmd.c_opcode = SD_SEND_RELATIVE_ADDR;
|
||||||
cmd.c_arg = 0;
|
cmd.c_arg = 0;
|
||||||
cmd.c_flags = SCF_RSP_R6;
|
cmd.c_flags = SCF_RSP_R6;
|
||||||
sdhc_exec_command(c->handle, &cmd);
|
sdhc_exec_command(card.handle, &cmd);
|
||||||
if (cmd.c_error) {
|
if (cmd.c_error) {
|
||||||
gecko_printf("sdmmc: SD_SEND_RCA failed with %d\n", cmd.c_error);
|
gecko_printf("sdmmc: SD_SEND_RCA failed with %d\n", cmd.c_error);
|
||||||
goto out_clock;
|
goto out_clock;
|
||||||
}
|
}
|
||||||
|
|
||||||
c->rca = MMC_R1(cmd.c_resp)>>16;
|
card.rca = MMC_R1(cmd.c_resp)>>16;
|
||||||
DPRINTF(2, ("sdmmc: rca: %08x\n", c->rca));
|
DPRINTF(2, ("sdmmc: rca: %08x\n", card.rca));
|
||||||
|
|
||||||
c->selected = 0;
|
card.selected = 0;
|
||||||
c->inserted = 1;
|
card.inserted = 1;
|
||||||
|
|
||||||
memset(&cmd, 0, sizeof(cmd));
|
memset(&cmd, 0, sizeof(cmd));
|
||||||
cmd.c_opcode = MMC_SEND_CSD;
|
cmd.c_opcode = MMC_SEND_CSD;
|
||||||
cmd.c_arg = ((u32)c->rca)<<16;
|
cmd.c_arg = ((u32)card.rca)<<16;
|
||||||
cmd.c_flags = SCF_RSP_R2;
|
cmd.c_flags = SCF_RSP_R2;
|
||||||
sdhc_exec_command(c->handle, &cmd);
|
sdhc_exec_command(card.handle, &cmd);
|
||||||
if (cmd.c_error) {
|
if (cmd.c_error) {
|
||||||
gecko_printf("sdmmc: MMC_SEND_CSD failed with %d\n", cmd.c_error);
|
gecko_printf("sdmmc: MMC_SEND_CSD failed with %d\n", cmd.c_error);
|
||||||
goto out_power;
|
goto out_power;
|
||||||
@ -235,8 +218,8 @@ void sdmmc_needs_discover(void)
|
|||||||
if (resp[13] == 0xe) { // sdhc
|
if (resp[13] == 0xe) { // sdhc
|
||||||
unsigned int c_size = resp[7] << 16 | resp[6] << 8 | resp[5];
|
unsigned int c_size = resp[7] << 16 | resp[6] << 8 | resp[5];
|
||||||
gecko_printf("sdmmc: sdhc mode, c_size=%u, card size = %uk\n", c_size, (c_size + 1)* 512);
|
gecko_printf("sdmmc: sdhc mode, c_size=%u, card size = %uk\n", c_size, (c_size + 1)* 512);
|
||||||
c->timeout = 250 * 1000000; // spec says read timeout is 100ms and write/erase timeout is 250ms
|
card.timeout = 250 * 1000000; // spec says read timeout is 100ms and write/erase timeout is 250ms
|
||||||
c->num_sectors = (c_size + 1) * 1024; // number of 512-byte sectors
|
card.num_sectors = (c_size + 1) * 1024; // number of 512-byte sectors
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
unsigned int taac, nsac, read_bl_len, c_size, c_size_mult;
|
unsigned int taac, nsac, read_bl_len, c_size, c_size_mult;
|
||||||
@ -253,9 +236,9 @@ void sdmmc_needs_discover(void)
|
|||||||
taac, nsac, read_bl_len, c_size, c_size_mult, (c_size + 1) * (4 << c_size_mult) * (1 << read_bl_len));
|
taac, nsac, read_bl_len, c_size, c_size_mult, (c_size + 1) * (4 << c_size_mult) * (1 << read_bl_len));
|
||||||
static const unsigned int time_unit[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000};
|
static const unsigned int time_unit[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000};
|
||||||
static const unsigned int time_value[] = {1, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80}; // must div by 10
|
static const unsigned int time_value[] = {1, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80}; // must div by 10
|
||||||
c->timeout = time_unit[taac & 7] * time_value[(taac >> 3) & 0xf] / 10;
|
card.timeout = time_unit[taac & 7] * time_value[(taac >> 3) & 0xf] / 10;
|
||||||
gecko_printf("calculated timeout = %uns\n", c->timeout);
|
gecko_printf("calculated timeout = %uns\n", card.timeout);
|
||||||
c->num_sectors = (c_size + 1) * (4 << c_size_mult) * (1 << read_bl_len) / 512;
|
card.num_sectors = (c_size + 1) * (4 << c_size_mult) * (1 << read_bl_len) / 512;
|
||||||
}
|
}
|
||||||
|
|
||||||
sdmmc_select();
|
sdmmc_select();
|
||||||
@ -264,19 +247,19 @@ void sdmmc_needs_discover(void)
|
|||||||
cmd.c_opcode = MMC_SET_BLOCKLEN;
|
cmd.c_opcode = MMC_SET_BLOCKLEN;
|
||||||
cmd.c_arg = SDMMC_DEFAULT_BLOCKLEN;
|
cmd.c_arg = SDMMC_DEFAULT_BLOCKLEN;
|
||||||
cmd.c_flags = SCF_RSP_R1;
|
cmd.c_flags = SCF_RSP_R1;
|
||||||
sdhc_exec_command(c->handle, &cmd);
|
sdhc_exec_command(card.handle, &cmd);
|
||||||
if (cmd.c_error) {
|
if (cmd.c_error) {
|
||||||
gecko_printf("sdmmc: MMC_SET_BLOCKLEN failed with %d\n", cmd.c_error);
|
gecko_printf("sdmmc: MMC_SET_BLOCKLEN failed with %d\n", cmd.c_error);
|
||||||
c->inserted = c->selected = 0;
|
card.inserted = card.selected = 0;
|
||||||
goto out_clock;
|
goto out_clock;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
out_clock:
|
out_clock:
|
||||||
sdhc_bus_clock(c->handle, SDMMC_SDCLK_OFF);
|
sdhc_bus_clock(card.handle, SDMMC_SDCLK_OFF);
|
||||||
|
|
||||||
out_power:
|
out_power:
|
||||||
sdhc_bus_power(c->handle, 0);
|
sdhc_bus_power(card.handle, 0);
|
||||||
out:
|
out:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -284,17 +267,16 @@ out:
|
|||||||
|
|
||||||
int sdmmc_select(void)
|
int sdmmc_select(void)
|
||||||
{
|
{
|
||||||
struct sdmmc_card *c = &cards[0];
|
|
||||||
struct sdmmc_command cmd;
|
struct sdmmc_command cmd;
|
||||||
|
|
||||||
DPRINTF(2, ("sdmmc: MMC_SELECT_CARD\n"));
|
DPRINTF(2, ("sdmmc: MMC_SELECT_CARD\n"));
|
||||||
memset(&cmd, 0, sizeof(cmd));
|
memset(&cmd, 0, sizeof(cmd));
|
||||||
cmd.c_opcode = MMC_SELECT_CARD;
|
cmd.c_opcode = MMC_SELECT_CARD;
|
||||||
cmd.c_arg = ((u32)c->rca)<<16;
|
cmd.c_arg = ((u32)card.rca)<<16;
|
||||||
cmd.c_flags = SCF_RSP_R1B;
|
cmd.c_flags = SCF_RSP_R1B;
|
||||||
sdhc_exec_command(c->handle, &cmd);
|
sdhc_exec_command(card.handle, &cmd);
|
||||||
gecko_printf("%s: resp=%x\n", __FUNCTION__, MMC_R1(cmd.c_resp));
|
gecko_printf("%s: resp=%x\n", __FUNCTION__, MMC_R1(cmd.c_resp));
|
||||||
sdhc_dump_regs(c->handle);
|
sdhc_dump_regs(card.handle);
|
||||||
|
|
||||||
// gecko_printf("present state = %x\n", HREAD4(hp, SDHC_PRESENT_STATE));
|
// gecko_printf("present state = %x\n", HREAD4(hp, SDHC_PRESENT_STATE));
|
||||||
if (cmd.c_error) {
|
if (cmd.c_error) {
|
||||||
@ -302,18 +284,16 @@ int sdmmc_select(void)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
c->selected = 1;
|
card.selected = 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sdmmc_check_card(void)
|
int sdmmc_check_card(void)
|
||||||
{
|
{
|
||||||
struct sdmmc_card *c = &cards[0];
|
if (card.inserted == 0)
|
||||||
|
|
||||||
if (c->inserted == 0)
|
|
||||||
return SDMMC_NO_CARD;
|
return SDMMC_NO_CARD;
|
||||||
|
|
||||||
if (c->new_card == 1)
|
if (card.new_card == 1)
|
||||||
return SDMMC_NEW_CARD;
|
return SDMMC_NEW_CARD;
|
||||||
|
|
||||||
return SDMMC_INSERTED;
|
return SDMMC_INSERTED;
|
||||||
@ -321,10 +301,8 @@ int sdmmc_check_card(void)
|
|||||||
|
|
||||||
int sdmmc_ack_card(void)
|
int sdmmc_ack_card(void)
|
||||||
{
|
{
|
||||||
struct sdmmc_card *c = &cards[0];
|
if (card.new_card == 1) {
|
||||||
|
card.new_card = 0;
|
||||||
if (c->new_card == 1) {
|
|
||||||
c->new_card = 0;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -333,23 +311,22 @@ int sdmmc_ack_card(void)
|
|||||||
|
|
||||||
int sdmmc_read(u32 blk_start, u32 blk_count, void *data)
|
int sdmmc_read(u32 blk_start, u32 blk_count, void *data)
|
||||||
{
|
{
|
||||||
struct sdmmc_card *c = &cards[0];
|
|
||||||
struct sdmmc_command cmd;
|
struct sdmmc_command cmd;
|
||||||
|
|
||||||
gecko_printf("%s(%u, %u, %p)\n", __FUNCTION__, blk_start, blk_count, data);
|
gecko_printf("%s(%u, %u, %p)\n", __FUNCTION__, blk_start, blk_count, data);
|
||||||
if (c->inserted == 0) {
|
if (card.inserted == 0) {
|
||||||
gecko_printf("sdmmc: READ: no card inserted.\n");
|
gecko_printf("sdmmc: READ: no card inserted.\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c->selected == 0) {
|
if (card.selected == 0) {
|
||||||
if (sdmmc_select() < 0) {
|
if (sdmmc_select() < 0) {
|
||||||
gecko_printf("sdmmc: READ: cannot select card.\n");
|
gecko_printf("sdmmc: READ: cannot select card.\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c->new_card == 1) {
|
if (card.new_card == 1) {
|
||||||
gecko_printf("sdmmc: new card inserted but not acknowledged yet.\n");
|
gecko_printf("sdmmc: new card inserted but not acknowledged yet.\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -357,7 +334,7 @@ int sdmmc_read(u32 blk_start, u32 blk_count, void *data)
|
|||||||
DPRINTF(2, ("sdmmc: MMC_READ_BLOCK_MULTIPLE\n"));
|
DPRINTF(2, ("sdmmc: MMC_READ_BLOCK_MULTIPLE\n"));
|
||||||
memset(&cmd, 0, sizeof(cmd));
|
memset(&cmd, 0, sizeof(cmd));
|
||||||
cmd.c_opcode = MMC_READ_BLOCK_MULTIPLE;
|
cmd.c_opcode = MMC_READ_BLOCK_MULTIPLE;
|
||||||
if (c->sdhc_blockmode)
|
if (card.sdhc_blockmode)
|
||||||
cmd.c_arg = blk_start;
|
cmd.c_arg = blk_start;
|
||||||
else
|
else
|
||||||
cmd.c_arg = blk_start * SDMMC_DEFAULT_BLOCKLEN;
|
cmd.c_arg = blk_start * SDMMC_DEFAULT_BLOCKLEN;
|
||||||
@ -365,7 +342,7 @@ int sdmmc_read(u32 blk_start, u32 blk_count, void *data)
|
|||||||
cmd.c_datalen = blk_count * SDMMC_DEFAULT_BLOCKLEN;
|
cmd.c_datalen = blk_count * SDMMC_DEFAULT_BLOCKLEN;
|
||||||
cmd.c_blklen = SDMMC_DEFAULT_BLOCKLEN;
|
cmd.c_blklen = SDMMC_DEFAULT_BLOCKLEN;
|
||||||
cmd.c_flags = SCF_RSP_R1 | SCF_CMD_READ;
|
cmd.c_flags = SCF_RSP_R1 | SCF_CMD_READ;
|
||||||
sdhc_exec_command(c->handle, &cmd);
|
sdhc_exec_command(card.handle, &cmd);
|
||||||
|
|
||||||
if (cmd.c_error) {
|
if (cmd.c_error) {
|
||||||
gecko_printf("sdmmc: MMC_READ_BLOCK_MULTIPLE failed with %d\n", cmd.c_error);
|
gecko_printf("sdmmc: MMC_READ_BLOCK_MULTIPLE failed with %d\n", cmd.c_error);
|
||||||
@ -379,22 +356,21 @@ int sdmmc_read(u32 blk_start, u32 blk_count, void *data)
|
|||||||
#ifndef LOADER
|
#ifndef LOADER
|
||||||
int sdmmc_write(u32 blk_start, u32 blk_count, void *data)
|
int sdmmc_write(u32 blk_start, u32 blk_count, void *data)
|
||||||
{
|
{
|
||||||
struct sdmmc_card *c = &cards[0];
|
|
||||||
struct sdmmc_command cmd;
|
struct sdmmc_command cmd;
|
||||||
|
|
||||||
if (c->inserted == 0) {
|
if (card.inserted == 0) {
|
||||||
gecko_printf("sdmmc: READ: no card inserted.\n");
|
gecko_printf("sdmmc: READ: no card inserted.\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c->selected == 0) {
|
if (card.selected == 0) {
|
||||||
if (sdmmc_select() < 0) {
|
if (sdmmc_select() < 0) {
|
||||||
gecko_printf("sdmmc: READ: cannot select card.\n");
|
gecko_printf("sdmmc: READ: cannot select card.\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c->new_card == 1) {
|
if (card.new_card == 1) {
|
||||||
gecko_printf("sdmmc: new card inserted but not acknowledged yet.\n");
|
gecko_printf("sdmmc: new card inserted but not acknowledged yet.\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -402,7 +378,7 @@ int sdmmc_write(u32 blk_start, u32 blk_count, void *data)
|
|||||||
DPRINTF(2, ("sdmmc: MMC_WRITE_BLOCK_MULTIPLE\n"));
|
DPRINTF(2, ("sdmmc: MMC_WRITE_BLOCK_MULTIPLE\n"));
|
||||||
memset(&cmd, 0, sizeof(cmd));
|
memset(&cmd, 0, sizeof(cmd));
|
||||||
cmd.c_opcode = MMC_WRITE_BLOCK_MULTIPLE;
|
cmd.c_opcode = MMC_WRITE_BLOCK_MULTIPLE;
|
||||||
if (c->sdhc_blockmode)
|
if (card.sdhc_blockmode)
|
||||||
cmd.c_arg = blk_start;
|
cmd.c_arg = blk_start;
|
||||||
else
|
else
|
||||||
cmd.c_arg = blk_start * SDMMC_DEFAULT_BLOCKLEN;
|
cmd.c_arg = blk_start * SDMMC_DEFAULT_BLOCKLEN;
|
||||||
@ -410,7 +386,7 @@ int sdmmc_write(u32 blk_start, u32 blk_count, void *data)
|
|||||||
cmd.c_datalen = blk_count * SDMMC_DEFAULT_BLOCKLEN;
|
cmd.c_datalen = blk_count * SDMMC_DEFAULT_BLOCKLEN;
|
||||||
cmd.c_blklen = SDMMC_DEFAULT_BLOCKLEN;
|
cmd.c_blklen = SDMMC_DEFAULT_BLOCKLEN;
|
||||||
cmd.c_flags = SCF_RSP_R1;
|
cmd.c_flags = SCF_RSP_R1;
|
||||||
sdhc_exec_command(c->handle, &cmd);
|
sdhc_exec_command(card.handle, &cmd);
|
||||||
|
|
||||||
if (cmd.c_error) {
|
if (cmd.c_error) {
|
||||||
gecko_printf("sdmmc: MMC_READ_BLOCK_MULTIPLE failed with %d\n", cmd.c_error);
|
gecko_printf("sdmmc: MMC_READ_BLOCK_MULTIPLE failed with %d\n", cmd.c_error);
|
||||||
@ -423,21 +399,19 @@ int sdmmc_write(u32 blk_start, u32 blk_count, void *data)
|
|||||||
|
|
||||||
int sdmmc_get_sectors(void)
|
int sdmmc_get_sectors(void)
|
||||||
{
|
{
|
||||||
struct sdmmc_card *c = &cards[0];
|
if (card.inserted == 0) {
|
||||||
|
|
||||||
if (c->inserted == 0) {
|
|
||||||
gecko_printf("sdmmc: READ: no card inserted.\n");
|
gecko_printf("sdmmc: READ: no card inserted.\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c->new_card == 1) {
|
if (card.new_card == 1) {
|
||||||
gecko_printf("sdmmc: new card inserted but not acknowledged yet.\n");
|
gecko_printf("sdmmc: new card inserted but not acknowledged yet.\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// sdhc_error(sdhci->reg_base, "num sectors = %u", sdhci->num_sectors);
|
// sdhc_error(sdhci->reg_base, "num sectors = %u", sdhci->num_sectors);
|
||||||
|
|
||||||
return c->num_sectors;
|
return card.num_sectors;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
5
sdmmc.h
5
sdmmc.h
@ -15,8 +15,7 @@ Copyright (C) 2008, 2009 Sven Peter <svenpeter@gmail.com>
|
|||||||
|
|
||||||
struct sdmmc_command;
|
struct sdmmc_command;
|
||||||
|
|
||||||
typedef struct sdmmc_chip_functions *sdmmc_chipset_tag_t;
|
typedef struct sdhc_host * sdmmc_chipset_handle_t;
|
||||||
typedef void *sdmmc_chipset_handle_t;
|
|
||||||
|
|
||||||
/* clock frequencies for sdmmc_chip_bus_clock() */
|
/* clock frequencies for sdmmc_chip_bus_clock() */
|
||||||
#define SDMMC_SDCLK_OFF 0
|
#define SDMMC_SDCLK_OFF 0
|
||||||
@ -157,7 +156,7 @@ struct sdmmc_function {
|
|||||||
#define SDMMC_NEW_CARD 2
|
#define SDMMC_NEW_CARD 2
|
||||||
#define SDMMC_INSERTED 3
|
#define SDMMC_INSERTED 3
|
||||||
|
|
||||||
void sdmmc_attach(sdmmc_chipset_handle_t handle, const char *name, int no);
|
void sdmmc_attach(sdmmc_chipset_handle_t handle);
|
||||||
void sdmmc_needs_discover(void);
|
void sdmmc_needs_discover(void);
|
||||||
int sdmmc_select(void);
|
int sdmmc_select(void);
|
||||||
int sdmmc_check_card(void);
|
int sdmmc_check_card(void);
|
||||||
|
Loading…
Reference in New Issue
Block a user