[BACK]Return to sdmmc_spi.c CVS log [TXT][DIR] Up to [local] / funnyos / dev / sdmmc

Diff for /funnyos/dev/sdmmc/sdmmc_spi.c between version 1.3 and 1.4

version 1.3, 2007/12/24 15:49:40 version 1.4, 2007/12/25 14:10:51
Line 8 
Line 8 
 #include <dev/sdmmc/sdmmcvar.h>  #include <dev/sdmmc/sdmmcvar.h>
 #include <libkern/printf.h>  #include <libkern/printf.h>
   
   #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.   * SD/MMC conversation over SPI bus.
  */   */
 struct spisdmmc_dd {  struct spisdmmc_dd {
         struct spi_bus_handle *ss_sbhp;          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);
 void    spisdmmc_send_command(struct spisdmmc_dd *ddp, uint8_t cmd, uint32_t arg, uint32_t crc);  uint8_t         spisdmmc_init(void *dd);
 uint8_t spisdmmc_get_response(struct spisdmmc_dd *ddp);  uint8_t         spisdmmc_send_command(void *dd, uint8_t cmd, uint32_t arg, uint8_t crc);
 int     spisdmmc_set_block_size(struct spisdmmc_dd *ddp, uint16_t blksize);  uint8_t         spisdmmc_set_block_size(void *dd, uint16_t size);
 void    spisdmmc_read_block(struct spisdmmc_dd *ddp, uint16_t nbytes, char *buffp);  uint8_t         spisdmmc_read_block(void *dd, uint32_t addr, char *buffp);
 uint8_t spisdmmc_get_token(struct spisdmmc_dd *ddp);  
 void    spisdmmc_read_cid(struct spisdmmc_dd *ddp, struct sdmmc_cid *cidp);  
   
   
   
Line 43 
Line 51 
   
         printf("SPI SD/MMC\n");          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);          return(0);
 }  }
   
   
 int  uint8_t
 spisdmmc_init(struct spisdmmc_dd *ddp)  spisdmmc_init(void *dd)
 {  {
           struct spisdmmc_dd *ddp = dd;
         uint8_t i, resp;          uint8_t i, resp;
         struct sdmmc_cid cid;  
   
         /*          /*
          * Apply 80 clock pulses.           * Initialize SD/MMC card so it can accept generic read/write commands.
          * XXX assert CS. (NPCS0)           * Remember that we should hold CS signal low during all transactions (cmd, resp, data).
          */           */
   
           /* CS high */
         spi_cs_high(ddp->ss_sbhp);          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);                  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);          resp = spisdmmc_send_command(ddp, CMD0_GO_IDLE_STATE, 0, 0x95);
         spisdmmc_send_command(ddp, CMD0_GO_IDLE_STATE, 0, CMD0_HARDCODED_CRC);          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);          return(0);
 }  }
   
   
 void  uint8_t
 spisdmmc_send_command(struct spisdmmc_dd *ddp, uint8_t cmd, uint32_t arg, uint32_t crc)  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;          struct sdmmc_cmdframe sdcf;
         uint8_t i;          uint8_t to = 0;
   
         /* construct frame */          /* construct frame */
         sdcf = sdmmc_command(cmd, arg, crc);          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);  //      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 */          /* transmit cmd */
         spi_transmit(ddp->ss_sbhp, sdcf.sc_cmd);          spi_transmit(ddp->ss_sbhp, sdcf.sc_cmd);
   
         /* transmit 32 bit argument XXX MSB first */          /* transmit 32 bit argument MSB first */
         for(i = 0; i < 4; i++)          spi_transmit(ddp->ss_sbhp, sdcf.sc_arg >> 24 );
                 spi_transmit(ddp->ss_sbhp, ((sdcf.sc_arg & (0xff000000 >> i)) >> (8 * (4 - i + 1))) );          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 */          /* transmit CRC field */
         spi_transmit(ddp->ss_sbhp, sdcf.sc_crc);          spi_transmit(ddp->ss_sbhp, sdcf.sc_crc);
   
           /* CS high */
           spi_cs_high(ddp->ss_sbhp);
   
         /* XXX Apply NCR clock pulses */          /* XXX Apply NCR clock pulses */
         spi_transmit(ddp->ss_sbhp, 0xff);          spi_transmit(ddp->ss_sbhp, 0xff);
 }  
   
           /* CS low */
           spi_cs_low(ddp->ss_sbhp);
   
 uint8_t          /* read response */
 spisdmmc_get_response(struct spisdmmc_dd *ddp)          /* XXX what about non-R1 responses? */
 {          while(to < SPISDMMC_RESP_TIMEOUT) {
         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);                  resp = spi_transmit(ddp->ss_sbhp, 0xff);
   
 //              if (resp == 0 || resp == 1)  //              if (resp & 0x80 == 0) {
                 if (resp != 0xff)                  if (resp != 0xff) {
                           /* seems like R1 response */
                           spi_cs_high(ddp->ss_sbhp);
   
                         return(resp);                          return(resp);
                   }
   
                   to++;
         }          }
 }  
   
 uint8_t          /* timeout */
 spisdmmc_get_token(struct spisdmmc_dd *ddp)          spi_cs_high(ddp->ss_sbhp);
 {  
         uint16_t i, token;  
         /*  
          * Get token.  
          */  
   
         for(i = 0; i < 1000; i++) {          DPRINTF("spisdmmc_send_command: response timeout for cmd %d arg 0x%x crc 0x%x\n", cmd, arg, crc);
                 token = spi_transmit(ddp->ss_sbhp, 0xff);  
   
                 if (token == TOK_READ_BLOCK || token == TOK_WRITE_BLOCK_MULTIPLE)          return(0xff);   /* error */
                         return(token);  
         }  
 }  }
   
   
 int  uint8_t
 spisdmmc_set_block_size(struct spisdmmc_dd *ddp, uint16_t blksize)  spisdmmc_set_block_size(void *dd, uint16_t blksize)
 {  {
           struct spisdmmc_dd *ddp = dd;
         uint8_t resp;          uint8_t resp;
         /*          /*
          * Set block size (CMD16).           * 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);          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);  
   
         /*  uint8_t
          * Wait R1 response.  spisdmmc_read_block(void *dd, uint32_t addr, char *buff)
          */  
         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;          struct spisdmmc_dd *ddp = dd;
         uint16_t crc;  
         /*          /*
          * Read block.           * 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);  
 };  };
   

Legend:
Removed from v.1.3  
changed lines
  Added in v.1.4

CVSweb