=================================================================== RCS file: /cvs/funnyos/dev/sdmmc/sdmmc_spi.c,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- funnyos/dev/sdmmc/sdmmc_spi.c 2007/12/20 15:23:15 1.1 +++ funnyos/dev/sdmmc/sdmmc_spi.c 2007/12/21 17:45:26 1.2 @@ -1,5 +1,5 @@ /* - * $Id: sdmmc_spi.c,v 1.1 2007/12/20 15:23:15 nbrk Exp $ + * $Id: sdmmc_spi.c,v 1.2 2007/12/21 17:45:26 nbrk Exp $ */ #include #include @@ -18,7 +18,15 @@ }; int spisdmmc_attach(struct device *, uint32_t, uint8_t); +void spisdmmc_send_command(struct spisdmmc_dd *ddp, uint8_t cmd, uint32_t arg, uint32_t crc); +uint8_t spisdmmc_get_response(struct spisdmmc_dd *ddp); +int spisdmmc_set_block_size(struct spisdmmc_dd *ddp, uint16_t blksize); +void spisdmmc_read_block(struct spisdmmc_dd *ddp, uint16_t nbytes, char *buffp); +uint8_t spisdmmc_get_token(struct spisdmmc_dd *ddp); +void spisdmmc_read_cid(struct spisdmmc_dd *ddp, struct sdmmc_cid *cidp); + + struct driver spisdmmc_dr = { sizeof(struct spisdmmc_dd), spisdmmc_attach, @@ -35,6 +43,8 @@ printf("SPI SD/MMC\n"); + spisdmmc_init(ddp); + return(0); } @@ -43,31 +53,64 @@ spisdmmc_init(struct spisdmmc_dd *ddp) { uint8_t i, resp; + struct sdmmc_cid cid; /* * Apply 80 clock pulses. * XXX assert CS. (NPCS0) */ + spi_cs_high(ddp->ss_sbhp); for (i = 0; i < 9; i++) spi_transmit(ddp->ss_sbhp, 0xff); - /* * Apply 16 clocks. * XXX deassert CS. */ - for (i = 0; i < 2; i ++) - spi_transmit(ddp->ss_sbhp, 0xff); +// for (i = 0; i < 2; i ++) +// spi_transmit(ddp->ss_sbhp, 0xff); /* * Send CMD0_GO_IDLE_STATE. */ + spi_cs_low(ddp->ss_sbhp); spisdmmc_send_command(ddp, CMD0_GO_IDLE_STATE, 0, CMD0_HARDCODED_CRC); - if (spisdmmc_get_response(ddp) != 0) { + + resp = spisdmmc_get_response(ddp); + + if (resp != 0) { printf("spisdmmc_init: CMD0_GO_IDLE_STATE failed with %d\n", resp); return(-1); } + printf("spisdmmc_init: Card replied to CMD0_GO_IDLE_STATE with 0x%x\n", resp); + /* + * Okay. Try to initialize the card. + * Periodically send CMD1 and poll for response with 0x01 cleared (card exit Idle state). + * CRC is off so we can set it 0xff. + * XXX send 0xff before. + */ +// spi_transmit(ddp->ss_sbhp, 0xff); + do { + spisdmmc_send_command(ddp, CMD1_SEND_OP_COND, 0, 0xff); + resp = spisdmmc_get_response(ddp); + } while(resp != 0x00); + + printf("spisdmmc_init: Card initialization completed\n"); + + /* + * Set block size to 512 bytes. + */ + if(spisdmmc_set_block_size(ddp, SDMMC_BLOCK_SIZE) == -1) { + printf("spisdmmc_init: failed to set block size\n"); + return(-1); + } + printf("spisdmmc_init: block size set to %d\n", SDMMC_BLOCK_SIZE); + + spisdmmc_read_cid(ddp, &cid); + printf("cid.pnm: %s%s%s%s%s\n", cid.cid_pnm[0], cid.cid_pnm[1], cid.cid_pnm[2], cid.cid_pnm[3], cid.cid_pnm[4]); + + return(0); } @@ -80,7 +123,8 @@ /* construct frame */ sdcf = sdmmc_command(cmd, arg, crc); - /* transmit token */ + printf("spisdmmc_send_command: sending cmd %d arg 0x%x crc 0x%x\n", sdcf.sc_cmd & ~0xc0, sdcf.sc_arg, sdcf.sc_crc); + /* transmit cmd */ spi_transmit(ddp->ss_sbhp, sdcf.sc_cmd); /* transmit 32 bit argument XXX MSB first */ @@ -88,8 +132,117 @@ spi_transmit(ddp->ss_sbhp, ((sdcf.sc_arg & (0xff000000 >> i)) >> (8 * (4 - i + 1))) ); /* transmit CRC field */ - spi_transmit(ddp->ss_sbhp, sdcf.sc_cmd) + spi_transmit(ddp->ss_sbhp, sdcf.sc_crc); + /* XXX Apply NCR clock pulses */ +// spi_transmit(ddp->ss_sbhp, 0xff); } + +uint8_t +spisdmmc_get_response(struct spisdmmc_dd *ddp) +{ + uint8_t i, resp; + /* + * Get response from card. + * After command response comes in 8 to 64 pulses (all this bits will be 1). + */ + + for(i = 0; i < 64; i++) { + resp = spi_transmit(ddp->ss_sbhp, 0xff); + + if (resp == 0x00 || resp == 0x01) + return(resp); + } +} + +uint8_t +spisdmmc_get_token(struct spisdmmc_dd *ddp) +{ + uint16_t i, token; + /* + * Get token. + */ + + for(i = 0; i < 1000; i++) { + token = spi_transmit(ddp->ss_sbhp, 0xff); + + if (token == TOK_READ_BLOCK || token == TOK_WRITE_BLOCK_MULTIPLE) + return(token); + } +} + + +int +spisdmmc_set_block_size(struct spisdmmc_dd *ddp, uint16_t blksize) +{ + uint8_t resp; + /* + * Set block size (CMD16). + */ + spisdmmc_send_command(ddp,CMD16_SET_BLOCKLEN, blksize, 0xff); + resp = spisdmmc_get_response(ddp); + if (resp != 0x00) { + printf("spisdmmc_set_block_size: set block size to %d failed (0x%x)\n", blksize, resp); + return(-1); + } + return(0); +} + +void +spisdmmc_read_cid(struct spisdmmc_dd *ddp, struct sdmmc_cid *cidp) +{ + uint8_t resp; + struct sdmmc_cid cid; + /* + * Read Card ID register. + */ + spisdmmc_send_command(ddp, CMD10_SEND_CID, 0, 0xff); + resp = spisdmmc_get_response(ddp); + printf("spisdmmc_read_cid: got r1 response 0x%x\n", resp); + + /* + * Wait R1 response. + */ + if (resp != 0x00) { + printf("spisdmmc_read_cid: bad response 0x%x\n", resp); + return; + } + + spisdmmc_read_block(ddp, 16, (char *)&cid); +} + + +void +spisdmmc_read_block(struct spisdmmc_dd *ddp, uint16_t nbytes, char *buffp) +{ + uint8_t token; + uint16_t crc; + /* + * Read block. + */ + token = spisdmmc_get_token(ddp); + printf("spisdmmc_read_block: got token 0x%x\n", token); + if (token != TOK_READ_BLOCK) { + printf("spisdmmc_read_block: error, foreign token\n"); + return; + } + /* + * Okay, next is the data. + */ + while(nbytes != 0) { + *buffp = spi_transmit(ddp->ss_sbhp, 0xff); + printf("byte read 0x%x\n", *buffp); + + buffp++; + nbytes--; + } + + /* + * Read CRC. + */ + crc = spi_transmit(ddp->ss_sbhp, 0xff); + crc <<= 8; + crc = spi_transmit(ddp->ss_sbhp, 0xff); +};