=================================================================== RCS file: /cvs/funnyos/dev/sdmmc/sdmmc_spi.c,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- funnyos/dev/sdmmc/sdmmc_spi.c 2007/12/24 15:49:40 1.3 +++ funnyos/dev/sdmmc/sdmmc_spi.c 2007/12/25 14:10:51 1.4 @@ -1,5 +1,5 @@ /* - * $Id: sdmmc_spi.c,v 1.3 2007/12/24 15:49:40 nbrk Exp $ + * $Id: sdmmc_spi.c,v 1.4 2007/12/25 14:10:51 nbrk Exp $ */ #include #include @@ -8,22 +8,30 @@ #include #include +#define SPISDMMC_DEBUG + +#ifdef SPISDMMC_DEBUG +#define DPRINTF(x...) do { printf(x); } while (0) +#else +#define DPRINTF(x...) { } +#endif + +#define SPISDMMC_RESP_TIMEOUT 64 + /* * SD/MMC conversation over SPI bus. */ struct spisdmmc_dd { struct spi_bus_handle *ss_sbhp; -// struct sdmmc_bus_handle; + struct sdmmc_bus_handle ss_smbh; }; -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); +int spisdmmc_attach(struct device *, uint32_t, uint8_t); +uint8_t spisdmmc_init(void *dd); +uint8_t spisdmmc_send_command(void *dd, uint8_t cmd, uint32_t arg, uint8_t crc); +uint8_t spisdmmc_set_block_size(void *dd, uint16_t size); +uint8_t spisdmmc_read_block(void *dd, uint32_t addr, char *buffp); @@ -43,205 +51,134 @@ printf("SPI SD/MMC\n"); - spisdmmc_init(ddp); + /* + * Interface to children. + */ + ddp->ss_smbh.sb_init = spisdmmc_init; + ddp->ss_smbh.sb_send_command = spisdmmc_send_command; + ddp->ss_smbh.sb_set_block_size = spisdmmc_set_block_size; +// ddp->ss_smbh.sb_read_block = spisdmmc_read_block; +// ddp->ss_smbh.sb_write_block = spisdmmc_write_block; + ddp->ss_smbh.sb_dd = ddp; + self->dv_aux = &ddp->ss_smbh; + return(0); } -int -spisdmmc_init(struct spisdmmc_dd *ddp) +uint8_t +spisdmmc_init(void *dd) { + struct spisdmmc_dd *ddp = dd; uint8_t i, resp; - struct sdmmc_cid cid; - /* - * Apply 80 clock pulses. - * XXX assert CS. (NPCS0) + * Initialize SD/MMC card so it can accept generic read/write commands. + * Remember that we should hold CS signal low during all transactions (cmd, resp, data). */ + + /* CS high */ spi_cs_high(ddp->ss_sbhp); - for (i = 0; i < 9; i++) + /* wait 80 pulses */ + for (i =0; i < 9; i++) spi_transmit(ddp->ss_sbhp, 0xff); /* - * Send CMD0_GO_IDLE_STATE. + * Send CMD0_GO_IDLE_STATE + * CS line will go low in send_command and up before return here. */ - spi_cs_low(ddp->ss_sbhp); - spisdmmc_send_command(ddp, CMD0_GO_IDLE_STATE, 0, CMD0_HARDCODED_CRC); + resp = spisdmmc_send_command(ddp, CMD0_GO_IDLE_STATE, 0, 0x95); + printf("spisdmmc_init: CMD0 reply 0x%x\n", resp); - resp = spisdmmc_get_response(ddp); - - if (resp & R1_IN_IDLE_STATE != 1) { - 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. - */ - do { - spi_cs_high(ddp->ss_sbhp); - spi_transmit(ddp->ss_sbhp, 0xff); - - spi_cs_low(ddp->ss_sbhp); - - 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); } -void -spisdmmc_send_command(struct spisdmmc_dd *ddp, uint8_t cmd, uint32_t arg, uint32_t crc) +uint8_t +spisdmmc_send_command(void *dd, uint8_t cmd, uint32_t arg, uint8_t crc) { + struct spisdmmc_dd *ddp = dd; + uint8_t resp; + /* + * Construct command frame and send command to the card. + * Try to read reply SASPI_RESP_TIMEOUT times and return it if it's R1 response. + * Return 255 if timeout. + */ struct sdmmc_cmdframe sdcf; - uint8_t i; + uint8_t to = 0; /* construct frame */ sdcf = sdmmc_command(cmd, arg, crc); // printf("spisdmmc_send_command: sending cmd %d arg 0x%x crc 0x%x\n", sdcf.sc_cmd & ~0xc0, sdcf.sc_arg, sdcf.sc_crc); + /* CS low */ + spi_cs_low(ddp->ss_sbhp); + /* transmit cmd */ spi_transmit(ddp->ss_sbhp, sdcf.sc_cmd); - /* transmit 32 bit argument XXX MSB first */ - for(i = 0; i < 4; i++) - spi_transmit(ddp->ss_sbhp, ((sdcf.sc_arg & (0xff000000 >> i)) >> (8 * (4 - i + 1))) ); + /* transmit 32 bit argument MSB first */ + spi_transmit(ddp->ss_sbhp, sdcf.sc_arg >> 24 ); + spi_transmit(ddp->ss_sbhp, sdcf.sc_arg >> 16 ); + spi_transmit(ddp->ss_sbhp, sdcf.sc_arg >> 8 ); + spi_transmit(ddp->ss_sbhp, sdcf.sc_arg ); /* transmit CRC field */ spi_transmit(ddp->ss_sbhp, sdcf.sc_crc); + /* CS high */ + spi_cs_high(ddp->ss_sbhp); + /* XXX Apply NCR clock pulses */ spi_transmit(ddp->ss_sbhp, 0xff); -} + /* CS low */ + spi_cs_low(ddp->ss_sbhp); -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++) { + /* read response */ + /* XXX what about non-R1 responses? */ + while(to < SPISDMMC_RESP_TIMEOUT) { resp = spi_transmit(ddp->ss_sbhp, 0xff); -// if (resp == 0 || resp == 1) - if (resp != 0xff) +// if (resp & 0x80 == 0) { + if (resp != 0xff) { + /* seems like R1 response */ + spi_cs_high(ddp->ss_sbhp); + return(resp); + } + + to++; } -} -uint8_t -spisdmmc_get_token(struct spisdmmc_dd *ddp) -{ - uint16_t i, token; - /* - * Get token. - */ + /* timeout */ + spi_cs_high(ddp->ss_sbhp); - for(i = 0; i < 1000; i++) { - token = spi_transmit(ddp->ss_sbhp, 0xff); + DPRINTF("spisdmmc_send_command: response timeout for cmd %d arg 0x%x crc 0x%x\n", cmd, arg, crc); - if (token == TOK_READ_BLOCK || token == TOK_WRITE_BLOCK_MULTIPLE) - return(token); - } + return(0xff); /* error */ } -int -spisdmmc_set_block_size(struct spisdmmc_dd *ddp, uint16_t blksize) +uint8_t +spisdmmc_set_block_size(void *dd, uint16_t blksize) { + struct spisdmmc_dd *ddp = dd; 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 +spisdmmc_read_block(void *dd, uint32_t addr, char *buff) { - uint8_t token; - uint16_t crc; + struct spisdmmc_dd *ddp = dd; /* * 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); };