📄 sdregb.c
字号:
return 0;
}
int sdhc_set_blklen (unsigned long blklen){
unsigned long rsp[4];
#if 0
// check blk len
if (blklen < (1 << CSD_RD_BLK_LEN(&g_csd)))
{
if (!CSD_RD_BLK_PARTIAL(&g_csd))
{
db ("sdhc_set_blklen: Card does not support partial read\n");
return -1;
}
}
else if (blklen > (1 << CSD_RD_BLK_LEN (&g_csd)))
{
db ("set_blklen: cannot read larger(%ld) than rd_blk_len (%lu)\n",
blklen, (1 << CSD_RD_BLK_LEN(&g_csd)));
return -1;
}
#endif
rsp[0] = blklen;
if (send_cmd (CMD_SET_BLKLEN, NORMAL, R48, 0, 1, 1, rsp) < 0) {
db ("sdhc_set_blklen: Set Block Length(CMD16) failed\n");
return -1;
}
if (rsp[0] & (R1_STAT_ERR | R1_STAT_BLK_LEN_ERR))
{
db ("sdhc_set_blklen: Set Block Length rejected by card\n");
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");
return -1;
}
if (rsp[0] & R1_STAT_ERR)
{
db ("sdhc_set_width: Set Width rejected by card\n");
decode_r1 (rsp[0]);
return -1;
}
if (width == 4)
SSD_REGWB(REG_u8HstCntl, SSD_REGRB(REG_u8HstCntl) | HCR_TRANS_WIDTH); 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 (CMD_IO_RW_DIRECT, NORMAL, R0, 0, 0, 0, rsp) < 0) { db ("IO reset failed\n");
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", fn, raw, addr, data);
rsp[0] = IO_WRITE_DIRECT (fn, raw, addr, data);
if (send_cmd (CMD_IO_RW_DIRECT, NORMAL, R48, 0, 1, 1, rsp) < 0) { db ("SDIO: io_write_byte failed\n");
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 (CMD_IO_RW_DIRECT, NORMAL, R48, 0, 1, 1, rsp) < 0) { db ("SDIO: io_read_byte (fn=%d, addr=0x%08lx) failed\n", fn, addr);
return -1;
}
else if (rsp[0] & R5_STAT_ERR) {
db ("SDIO: io_read_byte (fn=%d, addr=0x%08lx) failed\n", 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", 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", fn, addr, len);
for (i = 0; i < len; i++) {
rsp[0] = IO_WRITE_DIRECT (fn, 0, addr+i, data[i]);
if (send_cmd (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", fn, addr, len);
for (i = 0; i < len; i++) {
rsp[0] = IO_READ_DIRECT (fn, addr+i);
if (send_cmd (CMD_IO_RW_DIRECT, NORMAL, R48, 0, 1, 1, rsp) < 0) { db ("SDIO: direct read failed at offset=0x%x\n", 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", 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", 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;}#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 1/* db ("sdhc_read_ex: addr=0x%08lx, data=0x%08lx, blklen=%d, nblk=%ld, flags=0x%08lx\n", addr, (unsigned long)data, blklen, nblk, flags);*/#endif
if (RW_NOREAD_EN (flags)) { if (!RW_DMA_EN(flags)) { //debug ("sdhc_read_ex: dma must be enabled for RW_NOREAD_EN\n"); 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=nblk; // (DMA_BASE_END - data) / blklen;//update on 2005-11-23 //db ("sdhc_read_ex: blks_per_buf = %lu\n", 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 ( nblk ? CMD_RD_MULTIPLE : CMD_RD_SINGLE, NORMAL, R48, 1, 1, 1, rsp) < 0) {
debug ("sdhc_read_ex: Read Command(CMD%d) Failed\n", 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)) {
debug ("sdhc_read_ex: Read Command(CMD%d) rejected by card\n", 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", nblk, (unsigned long)blkcnt, SWAP16(event)); for(trial=0;trial<2000000;trial++) {
if( (nisr = SSD_REGRW(REG_u16NrmIntrStatus)) & event) { break;
} udelay(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", 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 c
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -