removed more useless SD code

This commit is contained in:
bushing 2009-10-26 14:41:40 -07:00
parent 661a30fc21
commit fa08fede1e
4 changed files with 175 additions and 335 deletions

337
sdhc.c
View File

@ -36,12 +36,13 @@
#include "ipc.h"
#endif
struct sdhc_host sc_host;
//#define SDHC_DEBUG
#define SDHC_COMMAND_TIMEOUT 500
#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)
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)
*/
int
sdhc_host_found(struct sdhc_softc *sc, bus_space_tag_t iot,
bus_space_handle_t ioh, int usedma)
sdhc_host_found(bus_space_tag_t iot, bus_space_handle_t ioh, int usedma)
{
struct sdmmcbus_attach_args saa;
struct sdhc_host *hp;
u_int32_t caps;
int error = 1;
@ -166,46 +164,38 @@ sdhc_host_found(struct sdhc_softc *sc, bus_space_tag_t iot,
}
#endif
/* Allocate one more host structure. */
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;
memset(&sc_host, 0, sizeof(sc_host));
/* Fill in the new host structure. */
hp->sc = sc;
hp->iot = iot;
hp->ioh = ioh;
hp->data_command = 0;
sc_host.iot = iot;
sc_host.ioh = ioh;
sc_host.data_command = 0;
/*
* Reset the host controller and enable interrupts.
*/
(void)sdhc_host_reset(hp);
(void)sdhc_host_reset(&sc_host);
/* 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. */
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)
*/
if (SDHC_BASE_FREQ_KHZ(caps) != 0)
hp->clkbase = SDHC_BASE_FREQ_KHZ(caps);
if (hp->clkbase == 0) {
sc_host.clkbase = SDHC_BASE_FREQ_KHZ(caps);
if (sc_host.clkbase == 0) {
/* The attachment driver must tell us. */
gecko_printf("sdhc: base clock frequency unknown\n");
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. */
gecko_printf("sdhc: base clock frequency out of range: %u MHz\n",
hp->clkbase / 1000);
sc_host.clkbase / 1000);
goto err;
}
@ -214,41 +204,17 @@ sdhc_host_found(struct sdhc_softc *sc, bus_space_tag_t iot,
* capabilities. (2.2.15)
*/
SET(hp->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;
}
SET(sc_host.ocr, MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V);
/*
* Attach the generic SD/MMC bus driver. (The bus driver must
* not invoke any chipset functions before it is attached.)
*/
bzero(&saa, sizeof(saa));
saa.saa_busname = "sdmmc";
saa.sch = hp;
sdmmc_attach(hp, "sdhc", ioh);
sdmmc_attach(&sc_host);
return 0;
err:
sc->sc_nhosts--;
return (error);
}
@ -257,17 +223,10 @@ err:
* Shutdown hook established by or called from attachment driver.
*/
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. */
for (i = 0; i < sc->sc_nhosts; i++) {
hp = &sc->sc_host[i];
(void)sdhc_host_reset(hp);
}
(void)sdhc_host_reset(&sc_host);
}
#endif
@ -276,9 +235,8 @@ sdhc_shutdown(void *arg)
* cards are removed, upon resume, and during error recovery.
*/
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;
int error;
@ -313,27 +271,12 @@ sdhc_host_reset(sdmmc_chipset_handle_t sch)
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.
*/
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) ?
1 : 0;
}
@ -343,10 +286,8 @@ sdhc_card_detect(sdmmc_chipset_handle_t sch)
* Return zero on success.
*/
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);
/* Disable bus power before voltage change. */
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) |
SDHC_BUS_POWER);
sdmmc_delay(10000);
udelay(10000);
/*
* 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.
*/
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 timo;
int error = 0;
gecko_printf("%s(%d)\n", __FUNCTION__, freq);
#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");
#endif
/*
* Stop SD clock before changing the frequency.
*/
/* Stop SD clock before changing the frequency. */
HWRITE2(hp, SDHC_CLOCK_CTL, 0);
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) {
/* Invalid base clock frequency or `freq' value. */
error = EINVAL;
goto ret;
return EINVAL;
}
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);
for (timo = 1000; timo > 0; timo--) {
if (ISSET(HREAD2(hp, SDHC_CLOCK_CTL), SDHC_INTCLK_STABLE))
break;
sdmmc_delay(10);
udelay(10);
}
if (timo == 0) {
gecko_printf("sdhc: internal clock never stabilized\n");
error = ETIMEDOUT;
goto ret;
return ETIMEDOUT;
}
/*
* Enable SD clock.
*/
/* Enable SD clock. */
HSET2(hp, SDHC_CLOCK_CTL, SDHC_SDCLK_ENABLE);
ret:
return error;
return 0;
}
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) {
HSET2(hp, SDHC_NINTR_STATUS_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
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);
}
@ -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)
== value)
return 0;
sdmmc_delay(10000);
udelay(10000);
}
DPRINTF(0,("sdhc: timeout waiting for %x (state=%d)\n", value, state));
return ETIMEDOUT;
}
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;
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;
}
sdhc_reset_intr_status(hp);
hp->intr_status = 0;
/*
* 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)
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",
cmd->c_opcode, cmd->c_flags, cmd->c_error, (cmd->c_resp[0] >> 9) & 15));
SET(cmd->c_flags, SCF_ITSDONE);
@ -581,7 +500,7 @@ sdhc_start_command(struct sdhc_host *hp, struct sdmmc_command *cmd)
u_int16_t command;
int error;
DPRINTF(1,("sdhc: start cmd %u arg=%#x data=%p dlen=%d flags=%#x\n",
DPRINTF(1,("sdhc: start cmd %u arg=%#x data=%p dlen=%d flags=%#x\n",
cmd->c_opcode, cmd->c_arg, cmd->c_data, cmd->c_datalen, cmd->c_flags));
/*
@ -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)
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) {
cmd->c_resid = blkcount;
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--) {
if (!ISSET(HREAD1(hp, SDHC_SOFTWARE_RESET), mask))
break;
sdmmc_delay(10000);
udelay(10000);
HWRITE1(hp, SDHC_SOFTWARE_RESET, 0);
}
if (timo == 0) {
@ -762,12 +678,6 @@ sdhc_soft_reset(struct sdhc_host *hp, int mask)
return (0);
}
void sdhc_reset_intr_status(struct sdhc_host *hp)
{
hp->intr_status = 0;
}
int
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;
for (; timo > 0; timo--) {
#ifndef CAN_HAZ_IRQ
sdhc_irq(); // seems backwards but ok
@ -795,14 +704,14 @@ sdhc_wait_intr_debug(const char *funcname, int line, struct sdhc_host *hp, int m
}
hp->intr_status &= ~status;
DPRINTF(2,("sdhc: funcname=%s, line=%d, timo=%d status=%#x intr status=%#x error %#x\n",
DPRINTF(2,("sdhc: funcname=%s, line=%d, timo=%d status=%#x intr status=%#x error %#x\n",
funcname, line, timo, status, hp->intr_status, hp->intr_error_status));
/* Command timeout has higher priority than command complete. */
if (ISSET(status, SDHC_ERROR_INTERRUPT)) {
gecko_printf("resetting due to error interrupt\n");
sdhc_dump_regs(hp);
hp->intr_error_status = 0;
(void)sdhc_soft_reset(hp, SDHC_RESET_DAT|SDHC_RESET_CMD);
status = 0;
@ -812,7 +721,7 @@ sdhc_wait_intr_debug(const char *funcname, int line, struct sdhc_host *hp, int m
if (ISSET(status, SDHC_ERROR_TIMEOUT)) {
gecko_printf("not resetting due to timeout\n");
sdhc_dump_regs(hp);
hp->intr_error_status = 0;
// (void)sdhc_soft_reset(hp, SDHC_RESET_DAT|SDHC_RESET_CMD);
status = 0;
@ -825,98 +734,77 @@ sdhc_wait_intr_debug(const char *funcname, int line, struct sdhc_host *hp, int m
* Established by attachment driver at interrupt priority IPL_SDMMC.
*/
int
sdhc_intr(void *arg)
sdhc_intr(void)
{
struct sdhc_softc *sc = arg;
int host;
int done = 0;
u_int16_t status;
/* 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;
DPRINTF(1,("shdc_intr():\n"));
sdhc_dump_regs(&sc_host);
/* Find out which interrupts are pending. */
status = HREAD2(&sc_host, SDHC_NINTR_STATUS);
if (!ISSET(status, SDHC_NINTR_STATUS_MASK)) {
DPRINTF(1, ("unknown interrupt\n"));
return 0;
}
/* Acknowledge the interrupts we are about to handle. */
HWRITE2(&sc_host, SDHC_NINTR_STATUS, status);
DPRINTF(2,("sdhc: interrupt status=%d\n", status));
if (hp == NULL)
continue;
/* Service error interrupts. */
if (ISSET(status, SDHC_ERROR_INTERRUPT)) {
u_int16_t error;
u_int16_t signal;
DPRINTF(1,("shdc_intr(%d):\n", host));
sdhc_dump_regs(hp);
/* Acknowledge error interrupts. */
error = HREAD2(&sc_host, SDHC_EINTR_STATUS);
signal = HREAD2(&sc_host, SDHC_EINTR_SIGNAL_EN);
HWRITE2(&sc_host, SDHC_EINTR_SIGNAL_EN, 0);
(void)sdhc_soft_reset(&sc_host, SDHC_RESET_DAT|SDHC_RESET_CMD);
if (sc_host.data_command == 1) {
sc_host.data_command = 0;
/* Find out which interrupts are pending. */
status = HREAD2(hp, SDHC_NINTR_STATUS);
if (!ISSET(status, SDHC_NINTR_STATUS_MASK))
continue; /* no interrupt for us */
/* Acknowledge the interrupts we are about to handle. */
HWRITE2(hp, SDHC_NINTR_STATUS, status);
DPRINTF(2,("sdhc: interrupt status=%d\n", status));
/* Claim this interrupt. */
done = 1;
/*
* Service error interrupts.
*/
if (ISSET(status, SDHC_ERROR_INTERRUPT)) {
u_int16_t error;
u_int16_t signal;
/* Acknowledge error interrupts. */
error = HREAD2(hp, SDHC_EINTR_STATUS);
signal = HREAD2(hp, SDHC_EINTR_SIGNAL_EN);
HWRITE2(hp, SDHC_EINTR_SIGNAL_EN, 0);
(void)sdhc_soft_reset(hp, SDHC_RESET_DAT|SDHC_RESET_CMD);
if (hp->data_command == 1) {
hp->data_command = 0;
// TODO: add a way to send commands from irq
// context and uncomment this
// sdmmc_abort();
}
HWRITE2(hp, SDHC_EINTR_STATUS, error);
HWRITE2(hp, SDHC_EINTR_SIGNAL_EN, signal);
DPRINTF(2,("sdhc: error interrupt, status=%d\n", error));
if (ISSET(error, SDHC_CMD_TIMEOUT_ERROR|
SDHC_DATA_TIMEOUT_ERROR)) {
hp->intr_error_status |= error;
hp->intr_status |= status;
}
// TODO: add a way to send commands from irq
// context and uncomment this
// sdmmc_abort();
}
HWRITE2(&sc_host, SDHC_EINTR_STATUS, error);
HWRITE2(&sc_host, SDHC_EINTR_SIGNAL_EN, signal);
#ifdef CAN_HAZ_IPC
/*
* Wake up the sdmmc event thread to scan for cards.
*/
if (ISSET(status, SDHC_CARD_REMOVAL|SDHC_CARD_INSERTION)) {
// this pushes a request to the slow queue so that we
// don't block other IRQs.
ipc_enqueue_slow(IPC_DEV_SDHC, IPC_SDHC_DISCOVER, 0);
}
#endif
DPRINTF(2,("sdhc: error interrupt, status=%d\n", error));
/*
* Wake up the blocking process to service command
* related interrupt(s).
*/
if (ISSET(status, SDHC_BUFFER_READ_READY|
SDHC_BUFFER_WRITE_READY|SDHC_COMMAND_COMPLETE|
SDHC_TRANSFER_COMPLETE|SDHC_DMA_INTERRUPT)) {
hp->intr_status |= status;
}
/*
* Service SD card interrupts.
*/
if (ISSET(status, SDHC_CARD_INTERRUPT)) {
// DPRINTF(0,("%s: card interrupt\n", HDEVNAME(hp)));
HCLR2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT);
// sdmmc_card_intr(hp->sdmmc);
if (ISSET(error, SDHC_CMD_TIMEOUT_ERROR|
SDHC_DATA_TIMEOUT_ERROR)) {
sc_host.intr_error_status |= error;
sc_host.intr_status |= status;
}
}
return done;
#ifdef CAN_HAZ_IPC
/* Wake up the sdmmc event thread to scan for cards. */
if (ISSET(status, SDHC_CARD_REMOVAL|SDHC_CARD_INSERTION)) {
// this pushes a request to the slow queue so that we
// don't block other IRQs.
ipc_enqueue_slow(IPC_DEV_SDHC, IPC_SDHC_DISCOVER, 0);
}
#endif
/*
* Wake up the blocking process to service command
* related interrupt(s).
*/
if (ISSET(status, SDHC_BUFFER_READ_READY|
SDHC_BUFFER_WRITE_READY|SDHC_COMMAND_COMPLETE|
SDHC_TRANSFER_COMPLETE|SDHC_DMA_INTERRUPT)) {
sc_host.intr_status |= status;
}
/* Service SD card interrupts. */
if (ISSET(status, SDHC_CARD_INTERRUPT)) {
DPRINTF(0,("sdhc: card interrupt\n"));
HCLR2(&sc_host, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT);
}
return 1;
}
#ifdef SDHC_DEBUG
@ -947,15 +835,10 @@ sdhc_dump_regs(struct sdhc_host *hp)
#endif
#include "hollywood.h"
#ifdef LOADER
static struct sdhc_softc __softc;
#else
static struct sdhc_softc __softc MEM2_BSS;
#endif
void sdhc_irq(void)
{
sdhc_intr(&__softc);
sdhc_intr();
}
void sdhc_init(void)
@ -963,18 +846,15 @@ void sdhc_init(void)
#ifdef CAN_HAZ_IRQ
irq_enable(IRQ_SDHC);
#endif
memset(&__softc, 0, sizeof(__softc));
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);
sdhc_host_found(0, SDHC_REG_BASE, 1);
}
void sdhc_exit(void)
{
#ifdef CAN_HAZ_IRQ
irq_disable(IRQ_SDHC);
irq_disable(IRQ_SDHC);
#endif
sdhc_shutdown();
sdhc_shutdown();
}
#ifdef CAN_HAZ_IPC
@ -987,6 +867,7 @@ void sdhc_ipc(volatile ipc_request *req)
case IPC_SDHC_EXIT:
sdhc_exit();
ipc_post(req->code, req->tag, 0);
break;
}
}
#endif

14
sdhc.h
View File

@ -25,16 +25,10 @@
#include "ipc.h"
#endif
#include "sdmmc.h"
#define SDHC_MAX_HOSTS 4
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_handle_t ioh; /* host register set handle */
u_int clkbase; /* base clock frequency in KHz */
int maxblklen; /* maximum block length */
int flags; /* flags for this host */
u_int32_t ocr; /* OCR value from capabilities */
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_DMA_SUPPORT (1<<22)
#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_MASK 0x3f
#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) \
(((hcv) >> SDHC_VENDOR_VERS_SHIFT) & SDHC_VENDOR_VERS_MASK)
//typedef void *sdmmc_chipset_handle_t;
struct sdmmc_command;
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_bus_power(struct sdhc_host *hp, u_int32_t);
int sdhc_bus_clock(struct sdhc_host *hp, int);

152
sdmmc.c
View File

@ -25,10 +25,7 @@ static int sdmmcdebug = 0;
#endif
struct sdmmc_card {
struct sdmmc_chip_functions *functions;
sdmmc_chipset_handle_t handle;
char name[30];
int no;
int inserted;
int sdhc_blockmode;
int selected;
@ -41,35 +38,22 @@ struct sdmmc_card {
};
#ifdef LOADER
static struct sdmmc_card cards[SDHC_MAX_HOSTS];
static struct sdmmc_card card;
#else
static struct sdmmc_card cards[SDHC_MAX_HOSTS] MEM2_BSS;
static struct sdmmc_card card MEM2_BSS;
#endif
static int n_cards = 0;
void sdmmc_attach(sdmmc_chipset_handle_t handle, const char *name, int no)
void sdmmc_attach(sdmmc_chipset_handle_t handle)
{
struct sdmmc_card *c;
memset(&card, 0, sizeof(card));
if (n_cards >= SDHC_MAX_HOSTS) {
gecko_printf("n_cards(%d) >= %d!\n", n_cards, SDHC_MAX_HOSTS);
gecko_printf("starlet is soo going to crash very soon...\n");
}
card.handle = handle;
c = &cards[n_cards++];
memset(c, 0, sizeof(*c));
DPRINTF(0, ("sdmmc: attached new SD/MMC card\n"));
c->handle = handle;
c->no = no;
strlcpy(c->name, name, sizeof(c->name));
sdhc_host_reset(card.handle);
DPRINTF(0, ("sdmmc: attached new SD/MMC card %d for host [%s:%d]\n",
n_cards-1, c->name, c->no));
sdhc_host_reset(c->handle);
if (sdhc_card_detect(c->handle)) {
if (sdhc_card_detect(card.handle)) {
DPRINTF(1, ("card is inserted. starting init sequence.\n"));
sdmmc_needs_discover();
}
@ -83,33 +67,32 @@ void sdmmc_abort(void) {
cmd.c_opcode = MMC_STOP_TRANSMISSION;
cmd.c_arg = 0;
cmd.c_flags = SCF_RSP_R1B;
sdhc_exec_command(&cards[0].handle, &cmd);
sdhc_exec_command(card.handle, &cmd);
}
void sdmmc_needs_discover(void)
{
struct sdmmc_card *c = &cards[0];
struct sdmmc_command cmd;
u32 ocr;
DPRINTF(0, ("sdmmc: card needs discovery.\n"));
sdhc_host_reset(c->handle);
c->new_card = 1;
sdhc_host_reset(card.handle);
card.new_card = 1;
if (!sdhc_card_detect(c->handle)) {
if (!sdhc_card_detect(card.handle)) {
DPRINTF(1, ("sdmmc: card (no longer?) inserted.\n"));
c->inserted = 0;
card.inserted = 0;
return;
}
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");
goto out;
}
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");
goto out_power;
}
@ -119,7 +102,7 @@ void sdmmc_needs_discover(void)
memset(&cmd, 0, sizeof(cmd));
cmd.c_opcode = MMC_GO_IDLE_STATE;
cmd.c_flags = SCF_RSP_R0;
sdhc_exec_command(c->handle, &cmd);
sdhc_exec_command(card.handle, &cmd);
if (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_flags = SCF_RSP_R7;
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)
ocr &= ~SD_OCR_SDHC_CAP;
else
@ -151,7 +134,7 @@ void sdmmc_needs_discover(void)
cmd.c_opcode = MMC_APP_CMD;
cmd.c_arg = 0;
cmd.c_flags = SCF_RSP_R1;
sdhc_exec_command(c->handle, &cmd);
sdhc_exec_command(card.handle, &cmd);
if (cmd.c_error)
continue;
@ -160,7 +143,7 @@ void sdmmc_needs_discover(void)
cmd.c_opcode = SD_APP_OP_COND;
cmd.c_arg = ocr;
cmd.c_flags = SCF_RSP_R3;
sdhc_exec_command(c->handle, &cmd);
sdhc_exec_command(card.handle, &cmd);
if (cmd.c_error)
continue;
@ -175,10 +158,10 @@ void sdmmc_needs_discover(void)
}
if (ISSET(MMC_R1(cmd.c_resp), SD_OCR_SDHC_CAP))
c->sdhc_blockmode = 1;
card.sdhc_blockmode = 1;
else
c->sdhc_blockmode = 0;
DPRINTF(2, ("sdmmc: SDHC: %d\n", c->sdhc_blockmode));
card.sdhc_blockmode = 0;
DPRINTF(2, ("sdmmc: SDHC: %d\n", card.sdhc_blockmode));
u8 *resp;
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_arg = 0;
cmd.c_flags = SCF_RSP_R2;
sdhc_exec_command(c->handle, &cmd);
sdhc_exec_command(card.handle, &cmd);
if (cmd.c_error) {
gecko_printf("sdmmc: MMC_ALL_SEND_CID failed with %d\n", cmd.c_error);
goto out_clock;
}
c->cid = MMC_R1(cmd.c_resp);
card.cid = MMC_R1(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],
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_arg = 0;
cmd.c_flags = SCF_RSP_R6;
sdhc_exec_command(c->handle, &cmd);
sdhc_exec_command(card.handle, &cmd);
if (cmd.c_error) {
gecko_printf("sdmmc: SD_SEND_RCA failed with %d\n", cmd.c_error);
goto out_clock;
}
c->rca = MMC_R1(cmd.c_resp)>>16;
DPRINTF(2, ("sdmmc: rca: %08x\n", c->rca));
card.rca = MMC_R1(cmd.c_resp)>>16;
DPRINTF(2, ("sdmmc: rca: %08x\n", card.rca));
c->selected = 0;
c->inserted = 1;
card.selected = 0;
card.inserted = 1;
memset(&cmd, 0, sizeof(cmd));
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;
sdhc_exec_command(c->handle, &cmd);
sdhc_exec_command(card.handle, &cmd);
if (cmd.c_error) {
gecko_printf("sdmmc: MMC_SEND_CSD failed with %d\n", cmd.c_error);
goto out_power;
@ -235,8 +218,8 @@ void sdmmc_needs_discover(void)
if (resp[13] == 0xe) { // sdhc
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);
c->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.timeout = 250 * 1000000; // spec says read timeout is 100ms and write/erase timeout is 250ms
card.num_sectors = (c_size + 1) * 1024; // number of 512-byte sectors
}
else {
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));
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
c->timeout = time_unit[taac & 7] * time_value[(taac >> 3) & 0xf] / 10;
gecko_printf("calculated timeout = %uns\n", c->timeout);
c->num_sectors = (c_size + 1) * (4 << c_size_mult) * (1 << read_bl_len) / 512;
card.timeout = time_unit[taac & 7] * time_value[(taac >> 3) & 0xf] / 10;
gecko_printf("calculated timeout = %uns\n", card.timeout);
card.num_sectors = (c_size + 1) * (4 << c_size_mult) * (1 << read_bl_len) / 512;
}
sdmmc_select();
@ -264,19 +247,19 @@ void sdmmc_needs_discover(void)
cmd.c_opcode = MMC_SET_BLOCKLEN;
cmd.c_arg = SDMMC_DEFAULT_BLOCKLEN;
cmd.c_flags = SCF_RSP_R1;
sdhc_exec_command(c->handle, &cmd);
sdhc_exec_command(card.handle, &cmd);
if (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;
}
return;
out_clock:
sdhc_bus_clock(c->handle, SDMMC_SDCLK_OFF);
sdhc_bus_clock(card.handle, SDMMC_SDCLK_OFF);
out_power:
sdhc_bus_power(c->handle, 0);
sdhc_bus_power(card.handle, 0);
out:
return;
}
@ -284,36 +267,33 @@ out:
int sdmmc_select(void)
{
struct sdmmc_card *c = &cards[0];
struct sdmmc_command cmd;
DPRINTF(2, ("sdmmc: MMC_SELECT_CARD\n"));
memset(&cmd, 0, sizeof(cmd));
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;
sdhc_exec_command(c->handle, &cmd);
sdhc_exec_command(card.handle, &cmd);
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));
if (cmd.c_error) {
gecko_printf("sdmmc: MMC_SELECT card failed with %d.\n", cmd.c_error);
return -1;
}
c->selected = 1;
card.selected = 1;
return 0;
}
int sdmmc_check_card(void)
{
struct sdmmc_card *c = &cards[0];
if (c->inserted == 0)
if (card.inserted == 0)
return SDMMC_NO_CARD;
if (c->new_card == 1)
if (card.new_card == 1)
return SDMMC_NEW_CARD;
return SDMMC_INSERTED;
@ -321,10 +301,8 @@ int sdmmc_check_card(void)
int sdmmc_ack_card(void)
{
struct sdmmc_card *c = &cards[0];
if (c->new_card == 1) {
c->new_card = 0;
if (card.new_card == 1) {
card.new_card = 0;
return 0;
}
@ -333,23 +311,22 @@ int sdmmc_ack_card(void)
int sdmmc_read(u32 blk_start, u32 blk_count, void *data)
{
struct sdmmc_card *c = &cards[0];
struct sdmmc_command cmd;
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");
return -1;
}
if (c->selected == 0) {
if (card.selected == 0) {
if (sdmmc_select() < 0) {
gecko_printf("sdmmc: READ: cannot select card.\n");
return -1;
}
}
if (c->new_card == 1) {
if (card.new_card == 1) {
gecko_printf("sdmmc: new card inserted but not acknowledged yet.\n");
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"));
memset(&cmd, 0, sizeof(cmd));
cmd.c_opcode = MMC_READ_BLOCK_MULTIPLE;
if (c->sdhc_blockmode)
if (card.sdhc_blockmode)
cmd.c_arg = blk_start;
else
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_blklen = SDMMC_DEFAULT_BLOCKLEN;
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) {
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
int sdmmc_write(u32 blk_start, u32 blk_count, void *data)
{
struct sdmmc_card *c = &cards[0];
struct sdmmc_command cmd;
if (c->inserted == 0) {
if (card.inserted == 0) {
gecko_printf("sdmmc: READ: no card inserted.\n");
return -1;
}
if (c->selected == 0) {
if (card.selected == 0) {
if (sdmmc_select() < 0) {
gecko_printf("sdmmc: READ: cannot select card.\n");
return -1;
}
}
if (c->new_card == 1) {
if (card.new_card == 1) {
gecko_printf("sdmmc: new card inserted but not acknowledged yet.\n");
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"));
memset(&cmd, 0, sizeof(cmd));
cmd.c_opcode = MMC_WRITE_BLOCK_MULTIPLE;
if (c->sdhc_blockmode)
if (card.sdhc_blockmode)
cmd.c_arg = blk_start;
else
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_blklen = SDMMC_DEFAULT_BLOCKLEN;
cmd.c_flags = SCF_RSP_R1;
sdhc_exec_command(c->handle, &cmd);
sdhc_exec_command(card.handle, &cmd);
if (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)
{
struct sdmmc_card *c = &cards[0];
if (c->inserted == 0) {
if (card.inserted == 0) {
gecko_printf("sdmmc: READ: no card inserted.\n");
return -1;
}
if (c->new_card == 1) {
if (card.new_card == 1) {
gecko_printf("sdmmc: new card inserted but not acknowledged yet.\n");
return -1;
}
// sdhc_error(sdhci->reg_base, "num sectors = %u", sdhci->num_sectors);
return c->num_sectors;
return card.num_sectors;
}
#endif

View File

@ -15,8 +15,7 @@ Copyright (C) 2008, 2009 Sven Peter <svenpeter@gmail.com>
struct sdmmc_command;
typedef struct sdmmc_chip_functions *sdmmc_chipset_tag_t;
typedef void *sdmmc_chipset_handle_t;
typedef struct sdhc_host * sdmmc_chipset_handle_t;
/* clock frequencies for sdmmc_chip_bus_clock() */
#define SDMMC_SDCLK_OFF 0
@ -157,7 +156,7 @@ struct sdmmc_function {
#define SDMMC_NEW_CARD 2
#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);
int sdmmc_select(void);
int sdmmc_check_card(void);
@ -304,7 +303,7 @@ void sdmmc_ipc(volatile ipc_request *req);
#define SD_CSD_CAPACITY(resp) ((SD_CSD_C_SIZE((resp))+1) << \
(SD_CSD_C_SIZE_MULT((resp))+2))
#define SD_CSD_V2_C_SIZE(resp) MMC_RSP_BITS((resp), 48, 22)
#define SD_CSD_V2_CAPACITY(resp) ((SD_CSD_V2_C_SIZE((resp))+1) << 10)
#define SD_CSD_V2_CAPACITY(resp) ((SD_CSD_V2_C_SIZE((resp))+1) << 10)
#define SD_CSD_V2_BL_LEN 0x9 /* 512 */
#define SD_CSD_VDD_R_CURR_MIN(resp) MMC_RSP_BITS((resp), 59, 3)
#define SD_CSD_VDD_R_CURR_MAX(resp) MMC_RSP_BITS((resp), 56, 3)