=================================================================== RCS file: /cvs/funnyos/dev/sdmmc/sdmmc_spi.c,v retrieving revision 1.1 retrieving revision 1.4 diff -u -r1.1 -r1.4 --- funnyos/dev/sdmmc/sdmmc_spi.c 2007/12/20 15:23:15 1.1 +++ funnyos/dev/sdmmc/sdmmc_spi.c 2007/12/25 14:10:51 1.4 @@ -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.4 2007/12/25 14:10:51 nbrk Exp $ */ #include #include @@ -8,17 +8,33 @@ #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); +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); + + struct driver spisdmmc_dr = { sizeof(struct spisdmmc_dd), spisdmmc_attach, @@ -35,61 +51,134 @@ printf("SPI SD/MMC\n"); + /* + * 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; - /* - * 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). */ - for (i = 0; i < 9; i++) - spi_transmit(ddp->ss_sbhp, 0xff); - /* - * Apply 16 clocks. - * XXX deassert CS. - */ - for (i = 0; i < 2; i ++) + /* CS high */ + spi_cs_high(ddp->ss_sbhp); + /* 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. */ - spisdmmc_send_command(ddp, CMD0_GO_IDLE_STATE, 0, CMD0_HARDCODED_CRC); - if (spisdmmc_get_response(ddp) != 0) { - printf("spisdmmc_init: CMD0_GO_IDLE_STATE failed with %d\n", resp); + resp = spisdmmc_send_command(ddp, CMD0_GO_IDLE_STATE, 0, 0x95); + printf("spisdmmc_init: CMD0 reply 0x%x\n", resp); - return(-1); - } - + 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); - /* 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); + /* 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_cmd) + 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); + + /* read response */ + /* XXX what about non-R1 responses? */ + while(to < SPISDMMC_RESP_TIMEOUT) { + resp = spi_transmit(ddp->ss_sbhp, 0xff); + +// if (resp & 0x80 == 0) { + if (resp != 0xff) { + /* seems like R1 response */ + spi_cs_high(ddp->ss_sbhp); + + return(resp); + } + + to++; + } + + /* timeout */ + spi_cs_high(ddp->ss_sbhp); + + DPRINTF("spisdmmc_send_command: response timeout for cmd %d arg 0x%x crc 0x%x\n", cmd, arg, crc); + + return(0xff); /* error */ } + +uint8_t +spisdmmc_set_block_size(void *dd, uint16_t blksize) +{ + struct spisdmmc_dd *ddp = dd; + uint8_t resp; + /* + * Set block size (CMD16). + */ + + return(0); +} + + +uint8_t +spisdmmc_read_block(void *dd, uint32_t addr, char *buff) +{ + struct spisdmmc_dd *ddp = dd; + /* + * Read block. + */ +};