📄 sdreg.c
字号:
if (rsp[0] & (R1_STAT_ERR | R1_STAT_BLK_LEN_ERR)) { db ("sdhc_set_blklen: Set Block Length rejected by card\n\r"); decode_r1 (rsp[0]); return -1; } return 0;}int sdhc_set_width (unsigned short g_rca, int width){ unsigned long rsp[4]; rsp[0] = (g_rca << 16) | 0x0000FFFFUL; rsp[1] = 0xFFFFFFFCUL | (width == 1 ? 0UL : 2UL); // 2'b00=1-bit, 2'b10=4-bit if (send_app_cmd (ACMD_SET_BUS_WIDTH, NORMAL, R48, 1, 1, rsp) < 0) { db ("sdhc_set_width: Set Width (ACMD6) failed\n\r"); return -1; } if (rsp[0] & R1_STAT_ERR) { db ("sdhc_set_width: Set Width rejected by card\n\r"); decode_r1 (rsp[0]); return -1; } if (width == 4) { SSD_REGWB(REG_u8HstCntl, SSD_REGRB(REG_u8HstCntl) | HCR_TRANS_WIDTH); myprintf("Host Control Register Value is %x , and HCR_TRANS_WIDTH is %x\n\r",SSD_REGRB(REG_u8HstCntl),HCR_TRANS_WIDTH); myprintf("SET DATA BUS WIDTH IS 4 \n\r"); } else if (width == 1) SSD_REGWB(REG_u8HstCntl, SSD_REGRB(REG_u8HstCntl) & ~HCR_TRANS_WIDTH); return 0;}//// start of mostly sdio functions//#define IO_READ_DIRECT(fn,addr) ((((fn) & 0x07UL) << 28) | ((addr) << 9))#define IO_WRITE_DIRECT(fn,raw,addr,data) ((1UL << 31) | (((fn) & 0x07UL) << 28) |\ ((raw) ? (1 << 27) : 0) |\ ((addr) << 9) |\ ((data) & 0xFFUL))#define IO_RW_EXT_WRITE BIT(31)#define IO_RW_EXT_MULTIBLK BIT(27)#define IO_RW_EXT_OPCODE BIT(26)#define IO_READ_EXT(fn,flags,addr,nblk,blklen) \ ((((fn) & 0x7) << 28) | \ (RW_MULTIBLK_EN((flags)) ? ((nblk == 0) ? 0 : IO_RW_EXT_MULTIBLK) : 0) |\ (RW_IO_INCR_EN((flags)) ? IO_RW_EXT_OPCODE : 0) |\ (((addr) & 0x1FFFF) << 9) |\ ((((nblk) == 0) ? (blklen) : \ (((nblk) > 0) ? (nblk) : 0)) & 0x1FF)) #define IO_WRITE_EXT(fn,flags,addr,nblk,blklen) \ (IO_RW_EXT_WRITE | \ (((fn) & 0x7) << 28) | \ (RW_MULTIBLK_EN((flags)) ? ((nblk == 0) ? 0 : IO_RW_EXT_MULTIBLK) : 0) |\ (RW_IO_INCR_EN((flags)) ? IO_RW_EXT_OPCODE : 0) |\ (((addr) & 0x1FFFF) << 9) |\ ((((nblk) == 0) ? (blklen) : \ (((nblk) > 0) ? (nblk) : 0)) & 0x1FF))int io_reset () { unsigned long rsp[4]; rsp[0] = IO_WRITE_DIRECT (0, 0, CCCR_ASR, CCCR_ASR_RESET); if (send_cmd_SD (CMD_IO_RW_DIRECT, NORMAL, R0, 0, 0, 0, rsp) < 0) { //db ("IO reset failed\n\r"); return -1; } return 0;}int io_write_byte (int fn, int raw, unsigned long addr, unsigned char data){ unsigned long rsp[4]; //db ("io_write_byte: fn=%d, raw=%d, addr=0x%08lx, data=0x%02x\n\r", fn, raw, addr, data); rsp[0] = IO_WRITE_DIRECT (fn, raw, addr, data); if (send_cmd_SD (CMD_IO_RW_DIRECT, NORMAL, R48, 0, 1, 1, rsp) < 0) { //db ("SDIO: io_write_byte failed\n\r"); return -1; } else if (rsp[0] & R5_STAT_ERR) { decode_r5 (rsp[0]); return -1; } return raw ? rsp[0] & 0xFFUL : 0;}int io_read_byte (int fn, unsigned long addr, unsigned char *data){ unsigned long rsp[4]; rsp[0] = IO_READ_DIRECT (fn, addr); if (send_cmd_SD (CMD_IO_RW_DIRECT, NORMAL, R48, 0, 1, 1, rsp) < 0) { //db ("SDIO: io_read_byte (fn=%d, addr=0x%08lx) failed\n\r", fn, addr); return -1; } else if (rsp[0] & R5_STAT_ERR) { //db ("SDIO: io_read_byte (fn=%d, addr=0x%08lx) failed\n\r", fn, addr); decode_r5 (rsp[0]); return -1; } *data = (unsigned char) (rsp[0] & 0xffUL); //db ("io_read_byte: fn=%d, addr=0x%08lx data=0x%02x\n\r", fn, addr, *data); return 0;}int io_write_direct (int fn, unsigned long addr, unsigned char *data, int len){ int i; unsigned long rsp[4]; //db ("io_write_direct: fn=%d, raw=0, addr=0x%08lx len=%d\n\r", fn, addr, len); for (i = 0; i < len; i++) { rsp[0] = IO_WRITE_DIRECT (fn, 0, addr+i, data[i]); if (send_cmd_SD (CMD_IO_RW_DIRECT, NORMAL, R48, 0, 1, 1, rsp) < 0) { //db ("SDIO: direct write failed at offset=0x%x", i); return -1; } else if (rsp[0] & R5_STAT_ERR) { decode_r5 (rsp[0]); return -1; } } return 0;}int io_read_direct (int fn, unsigned long addr, unsigned char *data, int len){ int i; unsigned long rsp[4]; //db ("io_read_direct: fn=%d, addr=0x%08lx len=%d\n\r", fn, addr, len); for (i = 0; i < len; i++) { rsp[0] = IO_READ_DIRECT (fn, addr+i); if (send_cmd_SD (CMD_IO_RW_DIRECT, NORMAL, R48, 0, 1, 1, rsp) < 0) { //db ("SDIO: direct read failed at offset=0x%x\n\r", i); return -1; } else if (rsp[0] & R5_STAT_ERR) { decode_r5 (rsp[0]); return -1; } else data[i] = (unsigned char) (rsp[0] & 0xffUL); } return 0;}// end of mostly sdio functions/* rw flags * byte0 - for sdhc hw options, eg. dma & autocmd12 * byte1 - reserved * byte2 - for rd api * byte3 - for wr api */#define RWF_DMA 0x00000001UL#define RWF_AUTOCMD12 0x00000002UL#define RWF_MULTIBLK 0x00000004UL // set only for IO && when Multi block transfer is enabled#define RWF_IO_INCR 0x00000008UL // set only for IO, OP Code bit in IO_RW_EXTENDED, 0=fixed,1=incr#define RWF_IO 0x00000010UL // set for IO and cleared for Memory Read/Write#define RWF_CONT 0x00000100UL // not used#define RWF_END 0x00000200UL // not used#define RWF_CURR_BUF 0x00000400UL // used when RW_NOFILL_EN or RW_NOREAD_EN is enabled to signal selected buffer#define RWF_SYNC 0x00000800UL // used by interrupt routines#define RWF_BYTECMP 0x00010000UL#define RWF_BLKCMP 0x00020000UL#define RWF_FILESAVE 0x00040000UL#define RWF_NOREAD 0x00080000UL#define RWF_BYTEFILL 0x01000000UL#define RWF_BLKFILL 0x02000000UL#define RWF_FILEFILL 0x04000000UL#define RWF_NOFILL 0x08000000UL// for both write & read#define RW_DMA_EN(x) ((x) & RWF_DMA)#define RW_AUTOCMD12_EN(x) ((x) & RWF_AUTOCMD12)#define RW_MULTIBLK_EN(x) ((x) & RWF_MULTIBLK) // checked for SDIO only#define RW_IO_INCR_EN(x) ((x) & RWF_IO_INCR) // checked for SDIO only#define RW_IO_EN(x) ((x) & RWF_IO) // checked for memory or SDIO access// for continuous mode write via internal memory (RW_NOFILLE_EN=1)#define RW_CONT_EN(x) ((x) & RWF_CONT)#define RW_END_EN(x) ((x) & RWF_END)#define RW_CURR_BUF(x) ((x) & RWF_CURR_BUF)#define RW_SYNC_EN(x) ((x) & RWF_SYNC)// for read_data#define RW_BYTECMP_EN(x) ((x) & RWF_BYTECMP)#define RW_BLKCMP_EN(x) ((x) & RWF_BLKCMP)#define RW_FILESAVE_EN(x) ((x) & RWF_FILESAVE)#define RW_NOREAD_EN(x) ((x) & RWF_NOREAD)// for write_data#define RW_BYTEFILL_EN(x) ((x) & RWF_BYTEFILL)#define RW_BLKFILL_EN(x) ((x) & RWF_BLKFILL)#define RW_FILEFILL_EN(x) ((x) & RWF_FILEFILL)#define RW_NOFILL_EN(x) ((x) & RWF_NOFILL)/*int fifo_reset (SDHCEXT_T *ext){ int i; ext->u16FIFOCntl |= SWAP16(0x0001); for (i = 0; i < MAX_WAIT; i++) { delay_us (1); if (!(ext->u16FIFOCntl & SWAP16(0x0001))) break; } return 0;}int fifo_readback (SDHCEXT_T *ext, int n, unsigned char *data, int len){#define FIFOCNTL_RST BIT16(0)#define FIFOCNTL_RDBK BIT16(1)#define FIFOCNTL_SYSBUFSEL BIT16(8)#define FIFOCNTL_SIBUFSEL BIT16(9) int i; // turn on fifo readback bit in the extension register // select the sys_buf_sel 0=fifo0, 1=fifo1 // copy data from fifo upto len bytes into g_data //db ("fifo_readback: status before reset: SYSBUFSEL=%d, SIBUFSEL=%d\n\r", // SWAP16(ext->u16FIFOCntl & FIFOCNTL_SYSBUFSEL) ? 1:0, // SWAP16(ext->u16FIFOCntl & FIFOCNTL_SIBUFSEL) ? 1:0); sdhc_reset (SW_RESET_DATA); sdhc_reset (SW_RESET_CMD); ext->u16FIFOCntl |= FIFOCNTL_RST; for (i = 0; i < MAX_WAIT; i++) { delay_us (1); if (!(ext->u16FIFOCntl & FIFOCNTL_RST)) break; } ext->u16FIFOCntl |= FIFOCNTL_RDBK; if (n) ext->u16FIFOCntl |= FIFOCNTL_SYSBUFSEL; else ext->u16FIFOCntl &= ~FIFOCNTL_SYSBUFSEL; //db ("fifo_readback: FIFOCNTL = 0x%04x, SYSBUFSEL=%d\n\r", SWAP16(ext->u16FIFOCntl), n); for (i = 0; i < len; i++) *data++ = SSD_REGRB(REG_u8DataPort); ext->u16FIFOCntl &= ~FIFOCNTL_RDBK; sdhc_reset (SW_RESET_DATA); sdhc_reset (SW_RESET_CMD); return 0;}*/#ifndef __KERNEL__ //kevin #ifdef __KERNEL__void sdhc_interrupt (void){ // interrupts are turned off here // interrupts are enabled in sdhc_write_th SSD_REGWW(REG_u16NrmIntrSignalEn , 0); SSD_REGWW(REG_u16ErrIntrSignalEn , 0); return;}int sdhc_read_ex ( unsigned long addr, unsigned long data, // dma start address in amazon memory int blklen, long nblk, unsigned long flags, void *param){ int error = 0; unsigned short event = 0; unsigned short nisr = 0; unsigned short blkcnt = 0; unsigned long tmp; unsigned long rsp[4]; unsigned long blks_per_buf = 0; // number of blocks that will fit into one dma buffer unsigned long status = 0; // nblk = 0 -> single // nblk > 0 -> multiple // nblk < 0 -> not supported for sdhc_read_ex/sdhc_write#if 0 db ("sdhc_read_ex: addr=0x%08lx, data=0x%08lx, blklen=%d, nblk=%ld, flags=0x%08lx\n\r", addr, (unsigned long)data, blklen, nblk, flags);#endif if (RW_NOREAD_EN (flags)) { if (!RW_DMA_EN(flags)) { myprintf ("sdhc_read_ex: dma must be enabled for RW_NOREAD_EN\n\r"); return -1; } } CEIL (nblk, 65535); SSD_REGWW(REG_u16NrmIntrStatus , (RW_DMA_EN(flags) ? INTR_DMA : INTR_BUF_RD_RDY)); // enable the data status registers SSD_REGWW(REG_u16NrmIntrStatusEn, SSD_REGRW(REG_u16NrmIntrStatusEn)& ~(INTR_BUF_RD_RDY | INTR_DMA)); SSD_REGWW(REG_u16NrmIntrStatusEn, SSD_REGRW(REG_u16NrmIntrStatusEn) | (INTR_DAT_COMPLETE | INTR_DMA | INTR_ERR)); SSD_REGWW(REG_u16ErrIntrStatusEn, SSD_REGRW(REG_u16ErrIntrStatusEn) | (EINTR_DAT_TOUT | EINTR_DAT_CRC | EINTR_DAT_END | EINTR_AUTOCMD12 |EINTR_VS_RSP_DIR | EINTR_VS_DAT_CONFLICT));#if 0 SSD_REGWW(REG_u16NrmIntrSignalEn |= (INTR_DAT_COMPLETE | INTR_DMA | INTR_ERR); SSD_REGWW(REG_u16ErrIntrSignalEn |= (EINTR_DAT_TOUT | EINTR_DAT_CRC | EINTR_DAT_END | EINTR_AUTOCMD12 | EINTR_VS_RSP_DIR | EINTR_VS_DAT_CONFLICT);#endif SSD_REGWW(REG_u16BlkSize , 0); SSD_REGWW(REG_u16TrnsfrMode , TMR_RD_EN); // make sure direction bit toggles SSD_REGWW(REG_u16TrnsfrMode , 0); SSD_REGWW(REG_u16TrnsfrMode, SSD_REGRW(REG_u16TrnsfrMode)| TMR_RD_EN | TMR_AUTOCMD12_EN | (nblk != 0 ? TMR_MULTI_EN : 0) | // nblk > 0 or nblk < 0 -> enable multiple (nblk > 0 ? TMR_BLKCNT_EN : 0)); // setup for read transfer SSD_REGWW(REG_u16BlkCount , (unsigned short) SWAP32 (nblk)); SSD_REGWW(REG_u16BlkSize , SWAP16 (blklen)); event = INTR_ERR; // calculate how many blocks can fit into the buffer without crossing the boundary blks_per_buf = (DMA_BASE_END - data) / blklen; //db ("sdhc_read_ex: blks_per_buf = %lu\n\r", blks_per_buf); SSD_REGWW(REG_u16TrnsfrMode, SSD_REGRW(REG_u16TrnsfrMode) | TMR_DMA_EN); SSD_REGWW(REG_u16BlkSize ,SSD_REGRW(REG_u16BlkSize)| SWAP16 (HST_BNDRY_512KB << 12)); SSD_REGWL(REG_u32DMAAddr , SWAP32 (data)); // start timer here rsp[0] = addr; if (send_cmd_SD ( nblk ? CMD_RD_MULTIPLE : CMD_RD_SINGLE, NORMAL, R48, 1, 1, 1, rsp) < 0) { myprintf ("sdhc_read_ex: Read Command(CMD%d) Failed\n\r", nblk ? CMD_RD_MULTIPLE : CMD_RD_SINGLE); error = 1; goto l_err; } if (rsp[0] & (R1_STAT_ERR | R1_STAT_ADDR_ERR | R1_STAT_OORANGE)) { myprintf ("sdhc_read_ex: Read Command(CMD%d) rejected by card\n\r", nblk ? CMD_RD_MULTIPLE : CMD_RD_SINGLE); decode_r1 (rsp[0]); error = 1; goto l_err; } blkcnt = 0; event |= ((nblk <= blks_per_buf) ? INTR_DAT_COMPLETE : INTR_DMA); // start receiving data do { int trial; // for IO, INTR_DAT_COMPLETE is only set when the last block has been read out from the FIFO. // for DMA, INTR_DAT_COMPLETE is set when the last block has been transferred from FIFO into // amazon memory even though the last address may not be on a DMA host boundary db ("sdhc_read_ex: nblk=%ld, blks_read = %lu event=0x%04x\n\r",nblk, (unsigned long)blkcnt, SWAP16(event)); for(trial=0;trial<2000000;trial++) { if( (nisr = SSD_REGRW(REG_u16NrmIntrStatus)) & event) { break; } mdelay(10); } //while (!(nisr = SSD_REGWW(REG_u16NrmIntrStatus) & event) // ; // any errors if (SSD_REGRW(REG_u16ErrIntrStatus)) { db ("sdhc_read_ex: (Error!) NISR = 0x%x, EISR =0x%x\n\r", SWAP16 (SSD_REGRW(REG_u16NrmIntrStatus)), SWAP16(SSD_REGRW(REG_u16ErrIntrStatus))); error = 1; break; } SSD_REGWW(REG_u16NrmIntrStatus , ((event & INTR_DMA) ? INTR_DMA : INTR_DAT_COMPLETE)); if (event & INTR_DMA) { // set the next address here to continue the dma before any overrun // occurs SSD_REGWL(REG_u32DMAAddr , SWAP32(data)); blkcnt += blks_per_buf; event = INTR_ERR | (((nblk - blkcnt) <= blks_per_buf) ? INTR_DAT_COMPLETE : INTR_DMA); } else { // we got a INTR_DAT_COMPLETE tmp = nblk ? (nblk - blkcnt) : 1; blkcnt += tmp; } } while (nblk && blkcnt < nblk); // stop timer here if (error) { sdhc_reset (SW_RESET_DATA); sdhc_reset (SW_RESET_CMD); } // though an autocmd12 could have been sent, we could have reached this point from error // reset or normal completion. In any case, get status should indicate that the card is // in transfer state if (!nblk) goto l_err; // no need to send abort for single read if (sdhc_get_status (&status) == 0) { if (R1_STATE_NR(status) == R1_STATE_DATA) { rsp[0] = 0xFFFFFFFF; if (send_cmd_SD (CMD_STOP_TRANSMISSION, ABORT, R48b, 0, 1, 1, rsp) < 0) { db ("sdhc_read_ex: get status failed\n\r"); g_card_err = 1; error = 1; goto l_err; } if ((sdhc_get_status (&status) < 0) || (R1_STATE_NR(status) != R1_STATE_TRAN)) { g_card_err = 1; error = 1; goto l_err; } } else if (R1_STATE_NR (status) != R1_STATE_TRAN) { db ("sdhc_read_ex: card is in unexpected state (%s)\n\r", R1_STATE(status)); g_card_err = 1; error = 1; } } else { db ("sdhc_read_ex: first get status failed\n\
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -