dma for sdhc.

it still fails after having read a few blocks
This commit is contained in:
Sven Peter 2009-04-12 14:40:35 +02:00 committed by bushing
parent 2ad64f59a8
commit 5ba315148b
5 changed files with 164 additions and 16 deletions

5
ipc.c
View File

@ -149,9 +149,12 @@ static u32 process_slow(volatile ipc_request *req)
case IPC_DEV_NAND: case IPC_DEV_NAND:
nand_ipc(req); nand_ipc(req);
break; break;
case IPC_DEV_SD: case IPC_DEV_SDHC:
sdhc_ipc(req); sdhc_ipc(req);
break; break;
case IPC_DEV_SDMMC:
sdmmc_ipc(req);
break;
case IPC_DEV_KEYS: case IPC_DEV_KEYS:
crypto_ipc(req); crypto_ipc(req);
break; break;

9
ipc.h
View File

@ -31,11 +31,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#define IPC_DEV_SYS 0x00 #define IPC_DEV_SYS 0x00
#define IPC_DEV_NAND 0x01 #define IPC_DEV_NAND 0x01
#define IPC_DEV_SD 0x02 #define IPC_DEV_SDHC 0x02
#define IPC_DEV_KEYS 0x03 #define IPC_DEV_KEYS 0x03
#define IPC_DEV_AES 0x04 #define IPC_DEV_AES 0x04
#define IPC_DEV_BOOT2 0x05 #define IPC_DEV_BOOT2 0x05
#define IPC_DEV_PPC 0x06 #define IPC_DEV_PPC 0x06
#define IPC_DEV_SDMMC 0x07
#define IPC_SYS_PING 0x0000 #define IPC_SYS_PING 0x0000
#define IPC_SYS_JUMP 0x0001 #define IPC_SYS_JUMP 0x0001
@ -62,7 +63,11 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#define IPC_NAND_ERASE 0x0004 #define IPC_NAND_ERASE 0x0004
#define IPC_NAND_STATUS 0x0005 #define IPC_NAND_STATUS 0x0005
#define IPC_SD_DISCOVER 0x0000 #define IPC_SDHC_DISCOVER 0x0000
#define IPC_SDMMC_ACK 0x0000
#define IPC_SDMMC_READ 0x0001
#define IPC_SDMMC_WRITE 0x0002
/*#define IPC_SD_MOUNT 0x0000 /*#define IPC_SD_MOUNT 0x0000
#define IPC_SD_SELECT 0x0001 #define IPC_SD_SELECT 0x0001
#define IPC_SD_GETSTATE 0x0002 #define IPC_SD_GETSTATE 0x0002

74
sdhc.c
View File

@ -44,8 +44,9 @@
#include "irq.h" #include "irq.h"
#include "utils.h" #include "utils.h"
#include "ipc.h" #include "ipc.h"
#include "memory.h"
#define SDHC_DEBUG 1 //#define SDHC_DEBUG 1
#define SDHC_COMMAND_TIMEOUT 0 #define SDHC_COMMAND_TIMEOUT 0
#define SDHC_BUFFER_TIMEOUT 0 #define SDHC_BUFFER_TIMEOUT 0
@ -728,16 +729,14 @@ sdhc_start_command(struct sdhc_host *hp, struct sdmmc_command *cmd)
mode |= SDHC_READ_MODE; mode |= SDHC_READ_MODE;
if (blkcount > 0) { if (blkcount > 0) {
mode |= SDHC_BLOCK_COUNT_ENABLE; mode |= SDHC_BLOCK_COUNT_ENABLE;
if (blkcount > 1) { // if (blkcount > 1) {
mode |= SDHC_MULTI_BLOCK_MODE; mode |= SDHC_MULTI_BLOCK_MODE;
/* XXX only for memory commands? */ /* XXX only for memory commands? */
mode |= SDHC_AUTO_CMD12_ENABLE; mode |= SDHC_AUTO_CMD12_ENABLE;
} // }
} }
#ifdef notyet
if (ISSET(hp->flags, SHF_USE_DMA)) if (ISSET(hp->flags, SHF_USE_DMA))
mode |= SDHC_DMA_ENABLE; mode |= SDHC_DMA_ENABLE;
#endif
/* /*
* Prepare command register value. (2.2.6) * Prepare command register value. (2.2.6)
@ -770,7 +769,18 @@ sdhc_start_command(struct sdhc_host *hp, struct sdmmc_command *cmd)
/* Alert the user not to remove the card. */ /* Alert the user not to remove the card. */
HSET1(hp, SDHC_HOST_CTL, SDHC_LED_ON); HSET1(hp, SDHC_HOST_CTL, SDHC_LED_ON);
/* XXX: Set DMA start address if SHF_USE_DMA is set. */ if (ISSET(hp->flags, SHF_USE_DMA) && cmd->c_datalen > 0) {
cmd->c_resid = blkcount;
cmd->c_buf = cmd->c_data;
if (ISSET(cmd->c_flags, SCF_CMD_READ)) {
dc_invalidaterange(cmd->c_data, cmd->c_datalen);
} else {
dc_flushrange(cmd->c_data, cmd->c_datalen);
ahb_flush_to(AHB_SDHC);
}
HWRITE4(hp, SDHC_DMA_ADDR, dma_addr(cmd->c_data));
}
DPRINTF(1,("%s: cmd=%#x mode=%#x blksize=%d blkcount=%d\n", DPRINTF(1,("%s: cmd=%#x mode=%#x blksize=%d blkcount=%d\n",
HDEVNAME(hp), command, mode, blksize, blkcount)); HDEVNAME(hp), command, mode, blksize, blkcount));
@ -780,7 +790,7 @@ sdhc_start_command(struct sdhc_host *hp, struct sdmmc_command *cmd)
* of the SDHC_COMMAND register triggers the SD command. (1.5) * of the SDHC_COMMAND register triggers the SD command. (1.5)
*/ */
HWRITE2(hp, SDHC_BLOCK_SIZE, blksize); HWRITE2(hp, SDHC_BLOCK_SIZE, blksize);
if (blkcount > 1) if (blkcount > 0)
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);
HWRITE4(hp, SDHC_TRANSFER_MODE, ((u32)command<<16)|mode); HWRITE4(hp, SDHC_TRANSFER_MODE, ((u32)command<<16)|mode);
@ -798,14 +808,45 @@ sdhc_transfer_data(struct sdhc_host *hp, struct sdmmc_command *cmd)
int i, datalen; int i, datalen;
int mask; int mask;
int error; int error;
int status;
int left, blkcnt;
mask = ISSET(cmd->c_flags, SCF_CMD_READ) ? mask = ISSET(cmd->c_flags, SCF_CMD_READ) ?
SDHC_BUFFER_READ_ENABLE : SDHC_BUFFER_WRITE_ENABLE; SDHC_BUFFER_READ_ENABLE : SDHC_BUFFER_WRITE_ENABLE;
error = 0; error = 0;
datalen = cmd->c_datalen; datalen = cmd->c_datalen;
blkcnt = (cmd->c_datalen / 512);
DPRINTF(1,("%s: resp=%#x datalen=%d\n", HDEVNAME(hp), DPRINTF(1,("%s: resp=%#x datalen=%d\n", HDEVNAME(hp),
MMC_R1(cmd->c_resp), datalen)); MMC_R1(cmd->c_resp), datalen));
if (ISSET(hp->flags, SHF_USE_DMA)) {
for(;;) {
status = sdhc_wait_intr(hp, SDHC_TRANSFER_COMPLETE |
SDHC_DMA_INTERRUPT,
SDHC_TRANSFER_TIMEOUT);
if (!status) {
error = ETIMEDOUT;
break;
}
if (ISSET(status, SDHC_DMA_INTERRUPT)) {
left = HREAD2(hp, SDHC_BLOCK_COUNT);
DPRINTF(2,("%s: dma left:%#x\n", HDEVNAME(hp),
left));
cmd->c_buf = cmd->c_data + (blkcnt - left)*512;
HWRITE4(hp, SDHC_DMA_ADDR,
dma_addr(cmd->c_buf));
continue;
}
if (ISSET(status, SDHC_TRANSFER_COMPLETE)) {
gecko_printf("transfer complete!\n");
break;
}
}
} else
gecko_printf("fail.\n");
#ifdef SDHC_DEBUG #ifdef SDHC_DEBUG
/* XXX I forgot why I wanted to know when this happens :-( */ /* XXX I forgot why I wanted to know when this happens :-( */
@ -814,7 +855,17 @@ sdhc_transfer_data(struct sdhc_host *hp, struct sdmmc_command *cmd)
gecko_printf("%s: CMD52/53 error response flags %#x\n", gecko_printf("%s: CMD52/53 error response flags %#x\n",
HDEVNAME(hp), MMC_R1(cmd->c_resp) & 0xff00); HDEVNAME(hp), MMC_R1(cmd->c_resp) & 0xff00);
#endif #endif
if (ISSET(cmd->c_flags, SCF_CMD_READ))
ahb_flush_from(AHB_SDHC);
if (error != 0)
cmd->c_error = error;
SET(cmd->c_flags, SCF_ITSDONE);
DPRINTF(1,("%s: data transfer done (error=%d)\n",
HDEVNAME(hp), cmd->c_error));
return;
#if 0
while (datalen > 0) { while (datalen > 0) {
if (!sdhc_wait_intr(hp, SDHC_BUFFER_READ_READY| if (!sdhc_wait_intr(hp, SDHC_BUFFER_READ_READY|
SDHC_BUFFER_WRITE_READY, SDHC_BUFFER_TIMEOUT)) { SDHC_BUFFER_WRITE_READY, SDHC_BUFFER_TIMEOUT)) {
@ -845,6 +896,7 @@ sdhc_transfer_data(struct sdhc_host *hp, struct sdmmc_command *cmd)
DPRINTF(1,("%s: data transfer done (error=%d)\n", DPRINTF(1,("%s: data transfer done (error=%d)\n",
HDEVNAME(hp), cmd->c_error)); HDEVNAME(hp), cmd->c_error));
#endif
} }
void void
@ -852,8 +904,10 @@ sdhc_read_data(struct sdhc_host *hp, u_char *datap, int datalen)
{ {
while (datalen > 3) { while (datalen > 3) {
*(u_int32_t *)datap = HREAD4(hp, SDHC_DATA); *(u_int32_t *)datap = HREAD4(hp, SDHC_DATA);
gecko_printf("next_data: %08x\n", *datap);
datap += 4; datap += 4;
datalen -= 4; datalen -= 4;
udelay(1000);
} }
if (datalen > 0) { if (datalen > 0) {
u_int32_t rv = HREAD4(hp, SDHC_DATA); u_int32_t rv = HREAD4(hp, SDHC_DATA);
@ -1007,8 +1061,8 @@ sdhc_intr(void *arg)
if (ISSET(status, SDHC_CARD_REMOVAL|SDHC_CARD_INSERTION)) { if (ISSET(status, SDHC_CARD_REMOVAL|SDHC_CARD_INSERTION)) {
ipc_request req; ipc_request req;
memset(&req, 0, sizeof(req)); memset(&req, 0, sizeof(req));
req.device = IPC_DEV_SD; req.device = IPC_DEV_SDHC;
req.req = IPC_SD_DISCOVER; req.req = IPC_SDHC_DISCOVER;
req.args[0] = hp->sdmmc; req.args[0] = hp->sdmmc;
ipc_add_slow(&req); ipc_add_slow(&req);
} }
@ -1083,7 +1137,7 @@ void sdhc_init(void)
void sdhc_ipc(volatile ipc_request *req) void sdhc_ipc(volatile ipc_request *req)
{ {
switch (req->req) { switch (req->req) {
case IPC_SD_DISCOVER: case IPC_SDHC_DISCOVER:
sdmmc_needs_discover((struct device *)req->args[0]); sdmmc_needs_discover((struct device *)req->args[0]);
break; break;
} }

90
sdmmc.c
View File

@ -30,11 +30,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "gecko.h" #include "gecko.h"
#include "string.h" #include "string.h"
#include "utils.h" #include "utils.h"
#include "memory.h"
#define SDMMC_DEBUG 1 #define SDMMC_DEBUG 1
#ifdef SDMMC_DEBUG #ifdef SDMMC_DEBUG
static int sdmmcdebug = 5; static int sdmmcdebug = 0;
#define DPRINTF(n,s) do { if ((n) <= sdmmcdebug) gecko_printf s; } while (0) #define DPRINTF(n,s) do { if ((n) <= sdmmcdebug) gecko_printf s; } while (0)
#else #else
#define DPRINTF(n,s) do {} while(0) #define DPRINTF(n,s) do {} while(0)
@ -216,6 +217,7 @@ void sdmmc_needs_discover(struct device *dev)
c->sdhc_blockmode = 1; c->sdhc_blockmode = 1;
else else
c->sdhc_blockmode = 0; c->sdhc_blockmode = 0;
DPRINTF(2, ("sdmmc: SDHC: %d\n", c->sdhc_blockmode));
DPRINTF(2, ("sdmmc: MMC_ALL_SEND_CID\n")); DPRINTF(2, ("sdmmc: MMC_ALL_SEND_CID\n"));
memset(&cmd, 0, sizeof(cmd)); memset(&cmd, 0, sizeof(cmd));
@ -356,6 +358,8 @@ int sdmmc_read(struct device *dev, u32 blk_start, u32 blk_count, void *data)
struct sdmmc_card *c = &cards[no]; struct sdmmc_card *c = &cards[no];
struct sdmmc_command cmd; struct sdmmc_command cmd;
gecko_printf("reading %d bytes to %p\n", blk_count*512,data);
if (c->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;
@ -375,7 +379,10 @@ int sdmmc_read(struct device *dev, 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; if (blk_count == 1)
cmd.c_opcode = MMC_READ_BLOCK_MULTIPLE;
else
cmd.c_opcode = MMC_READ_BLOCK_MULTIPLE;
if (c->sdhc_blockmode) if (c->sdhc_blockmode)
cmd.c_arg = blk_start; cmd.c_arg = blk_start;
else else
@ -386,12 +393,89 @@ int sdmmc_read(struct device *dev, u32 blk_start, u32 blk_count, void *data)
cmd.c_flags = SCF_RSP_R1 | SCF_CMD_READ; cmd.c_flags = SCF_RSP_R1 | SCF_CMD_READ;
sdmmc_host_exec_command(c, &cmd); sdmmc_host_exec_command(c, &cmd);
gecko_printf("arg: %08x %08x\n", cmd.c_arg, blk_start);
if (cmd.c_error) { if (cmd.c_error) {
gecko_printf("sdmmc: MMC_READ_BLOCK_MULTIPLE failed for " gecko_printf("sdmmc: MMC_READ_BLOCK_MULTIPLE failed for "
"card %d with %d", no, cmd.c_error); "card %d with %d", no, cmd.c_error);
return -1; return -1;
} }
gecko_printf("success!!\n"); DPRINTF(2, ("sdmmc: MMC_READ_BLOCK_MULTIPLE done\n"));
return 0; return 0;
} }
int sdmmc_write(struct device *dev, u32 blk_start, u32 blk_count, void *data)
{
int no = (int)dev;
struct sdmmc_card *c = &cards[no];
struct sdmmc_command cmd;
if (c->inserted == 0) {
gecko_printf("sdmmc: READ: no card inserted.\n");
return -1;
}
if (c->selected == 0) {
if (sdmmc_select(dev) < 0) {
gecko_printf("sdmmc: READ: cannot select card.\n");
return -1;
}
}
if (c->new_card == 1) {
gecko_printf("sdmmc: new card inserted but not acknowledged yet.\n");
return -1;
}
DPRINTF(2, ("sdmmc: MMC_WRITE_BLOCK_MULTIPLE\n"));
memset(&cmd, 0, sizeof(cmd));
if (blk_count == 1)
cmd.c_opcode = MMC_WRITE_BLOCK_SINGLE;
else
cmd.c_opcode = MMC_WRITE_BLOCK_MULTIPLE;
if (c->sdhc_blockmode)
cmd.c_arg = blk_start;
else
cmd.c_arg = blk_start * SDMMC_DEFAULT_BLOCKLEN;
cmd.c_data = data;
cmd.c_datalen = blk_count * SDMMC_DEFAULT_BLOCKLEN;
cmd.c_blklen = SDMMC_DEFAULT_BLOCKLEN;
cmd.c_flags = SCF_RSP_R1;
sdmmc_host_exec_command(c, &cmd);
if (cmd.c_error) {
gecko_printf("sdmmc: MMC_READ_BLOCK_MULTIPLE failed for "
"card %d with %d", no, cmd.c_error);
return -1;
}
DPRINTF(2, ("sdmmc: MMC_WRITE_BLOCK_MULTIPLE done\n"));
return 0;
}
void sdmmc_ipc(volatile ipc_request *req)
{
int ret;
switch (req->req) {
case IPC_SDMMC_ACK:
sdmmc_ack_card(SDMMC_DEFAULT_DEVICE);
ipc_post(req->code, req->tag, 1);
break;
case IPC_SDMMC_READ:
ret = sdmmc_read(SDMMC_DEFAULT_DEVICE, req->args[0],
req->args[1], (void *)req->args[2]);
dc_flushrange((void *)req->args[2],
req->args[1]*SDMMC_DEFAULT_BLOCKLEN);
ipc_post(req->code, req->tag, 1);
break;
case IPC_SDMMC_WRITE:
dc_invalidaterange((void *)req->args[2],
req->args[1]*SDMMC_DEFAULT_BLOCKLEN);
ret = sdmmc_write(SDMMC_DEFAULT_DEVICE, req->args[0],
req->args[1], (void *)req->args[2]);
ipc_post(req->code, req->tag, 1);
break;
}
}

View File

@ -25,6 +25,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "bsdtypes.h" #include "bsdtypes.h"
#include "sdmmcchip.h" #include "sdmmcchip.h"
#include "sdmmcvar.h" #include "sdmmcvar.h"
#include "ipc.h"
#define SDMMC_DEFAULT_CLOCK 25000 #define SDMMC_DEFAULT_CLOCK 25000
#define SDMMC_DEFAULT_BLOCKLEN 512 #define SDMMC_DEFAULT_BLOCKLEN 512
@ -43,4 +44,5 @@ int sdmmc_select(struct device *dev);
int sdmmc_check_card(struct device *dev); int sdmmc_check_card(struct device *dev);
void sdmmc_ack_card(struct device *dev); void sdmmc_ack_card(struct device *dev);
int sdmmc_read(struct device *dev, u32 blk_start, u32 blk_count, void *data); int sdmmc_read(struct device *dev, u32 blk_start, u32 blk_count, void *data);
void sdmmc_ipc(volatile ipc_request *req);
#endif #endif