📄 sdhc.c
字号:
/*************************************************************************************** * Project Name : S3C6400 Validation** Copyright 2006 by Samsung Electronics, Inc.* All rights reserved.** Project Description :* This software is only for validating functions of the S3C6400.* Anybody can use this software without our permission.* *--------------------------------------------------------------------------------------* * File Name : sdhc.c* * File Description : This file implements the API functon for High Speed MMC.** Author : Youngmin.Kim* Dept. : AP Development Team* Created Date : 08.OCT.2005* Version : 0.2 * * History* 1) 1st Made* 2) add SDIO, SDHC, CE-ATA interface and code compaction by youngbo.song* **************************************************************************************/#include <stdio.h>#include <string.h>#include <stdlib.h>#include "def.h"#include "option.h"#include "library.h"#include "sfr6400.h"#include "system.h"#include "intc.h"#include "gpio.h"#include "sdhc.h"#ifdef DBG_SDHC#define sdDbg(x) Dbg x#else#define sdDbg(x) printf x#endif// HighSpeed mode separator#define SDHC_CARD_DELAY_ON_CLOCK 35000000#define SDHC_MMC_HIGH_SPEED_CLOCK 25000000#define SDHC_SD_HIGH_SPEED_CLOCK 25000000//////////// File Name : SDHC_SetBlockCountReg (Inline Macro)// File Description : This function set block count register.// Input : SDHC, block count // Output : NONE.#define SDHC_SetBlockCountReg( sCh, uBlkCnt) \ Outp16( (sCh)->m_uBaseAddr + SDHC_BLK_COUNT, (uBlkCnt) );//////////// File Name : SDHC_SetSystemAddressReg (Inline Macro)// File Description : This function set DMA start address.// Input : SDHC, start address.// Output : NONE.#define SDHC_SetSystemAddressReg( sCh, SysAddr) \ Outp32( (sCh)->m_uBaseAddr + SDHC_SYS_ADDR, (SysAddr) );//////////// File Name : SDHC_SetBlockSizeReg (Inline Macro)// File Description : This function set block size and buffer size.// Input : SDHC, DMA buffer boundary, One block size.// Output : NONE.#define SDHC_SetBlockSizeReg( sCh, uDmaBufBoundary, uBlkSize ) \ Outp16( (sCh)->m_uBaseAddr + SDHC_BLK_SIZE, (((uDmaBufBoundary)<<12)|(uBlkSize)) );//////////// File Name : SDHC_INT_WAIT_CLEAR (Inline Macro)// File Description : Interrupt wait and clear.// Input : SDHC, interrupt bit, timeout loop count // Output : NONE. // 0x7F000000 youngbo.song#define SDHC_INT_WAIT_CLEAR(sCh,bit,loop) \ loop=0x7F000000; \ while ( !(Inp16( (sCh)->m_uBaseAddr + SDHC_NORMAL_INT_STAT ) & (1<<bit) ) ) { \ if ( --loop == 0 ) { \ sdDbg(( "***********Time out Error : bit : %d, Line:%d \n", bit, __LINE__ )); \ break; } } \ do { Outp32( (sCh)->m_uBaseAddr + SDHC_NORMAL_INT_STAT, (1<<bit) ); \ } while( Inp16( (sCh)->m_uBaseAddr + SDHC_NORMAL_INT_STAT ) & (1<<bit) );//// [7:6] Command Type// [5] Data Present Select// [4] Command Index Check Enable// [3] CRC Check Enable// [1:0] Response Type Selectconst unsigned char SDHC_cmd_sfr_data[] = { (unsigned char)((0<<4)|(0<<3)|(0<<0)), // RES_NO_TYPE (unsigned char)((1<<4)|(1<<3)|(2<<0)), // RES_R1_TYPE, (unsigned char)((1<<4)|(1<<3)|(3<<0)), // RES_R1B_TYPE, (unsigned char)((0<<4)|(1<<3)|(1<<0)), // RES_R2_TYPE, (unsigned char)((0<<4)|(0<<3)|(2<<0)), // RES_R3_TYPE, (unsigned char)((0<<4)|(0<<3)|(2<<0)), // RES_R4_TYPE, (unsigned char)((1<<4)|(1<<3)|(2<<0)), // RES_R5_TYPE, (unsigned char)((1<<4)|(1<<3)|(2<<0)), // RES_R6_TYPE, // check need. (unsigned char)((1<<4)|(1<<3)|(2<<0)), // RES_R7_TYPE, // check need.};SDHC* SDHC_curr_card[SDHC_CHANNEL_CNT];//////////// File Name : SDHC_writeIntHandler// File Description : This function is interrupt service routine for common writing.// Input : SDHC channel, Interrupt Index// Output : NONE.void SDHC_writeIntHandler(SDHC* sCh, u32 intIndex) {// if ( !( Inp16( (sCh)->m_uBaseAddr + SDHC_NORMAL_INT_STAT ) & (1<<4) ) ) {// printf( "Interrupt Delay~!!!\n" );// } SDHC_WriteOneBlock( sCh, 0 ); if ( sCh->m_uRemainBlock == 0 ) { INTC_Disable(intIndex); } else { INTC_Enable(intIndex); }}//////////// File Name : SDHC_WriteInt0// File Description : This function is interrupt service routine for writing channel 0.// Input : NONE.// Output : NONE.void __irq SDHC_WriteInt0(void) { SDHC_writeIntHandler( SDHC_curr_card[SDHC_CHANNEL_0], NUM_HSMMC0); INTC_ClearVectAddr();}//////////// File Name : SDHC_WriteInt1// File Description : This function is interrupt service routine for writing channel 1.// Input : NONE.// Output : NONE.void __irq SDHC_WriteInt1(void) { SDHC_writeIntHandler( SDHC_curr_card[SDHC_CHANNEL_1], NUM_HSMMC1); INTC_ClearVectAddr();}//////////// File Name : SDHC_WriteInt2// File Description : This function is interrupt service routine for writing channel 2.// Input : NONE.// Output : NONE.void __irq SDHC_WriteInt2(void) { SDHC_writeIntHandler( SDHC_curr_card[SDHC_CHANNEL_2], NUM_SPI1); INTC_ClearVectAddr();}//////////// File Name : SDHC_InterruptInspector// File Description : Print and handle the normal interrupt status register - for debugging usage.// Input : SDHC channel.// Output : NONE.void SDHC_InterruptInspector( SDHC* sCh ) { u16 status; int i=0; while ( (status = Inp16(sCh->m_uBaseAddr+SDHC_NORMAL_INT_STAT)) == 0 ) i++; if ( i != 0 ) printf ( "Int Status:%4x, loop count : %dn", status, i ); if ( status & SDHC_SD_ADDRESS_INT3_EN ) { Outp16(sCh->m_uBaseAddr+SDHC_NORMAL_INT_STAT, SDHC_SD_ADDRESS_INT3_EN); while( Inp16(sCh->m_uBaseAddr+SDHC_NORMAL_INT_STAT) & SDHC_SD_ADDRESS_INT3_EN ); sdDbg(( "14," )); } if ( status & SDHC_SD_ADDRESS_INT2_EN ) { Outp16(sCh->m_uBaseAddr+SDHC_NORMAL_INT_STAT, SDHC_SD_ADDRESS_INT2_EN); while( Inp16(sCh->m_uBaseAddr+SDHC_NORMAL_INT_STAT) & SDHC_SD_ADDRESS_INT2_EN ); sdDbg(( "13," )); } if ( status & SDHC_SD_ADDRESS_INT1_EN ) { Outp16(sCh->m_uBaseAddr+SDHC_NORMAL_INT_STAT, SDHC_SD_ADDRESS_INT1_EN); while( Inp16(sCh->m_uBaseAddr+SDHC_NORMAL_INT_STAT) & SDHC_SD_ADDRESS_INT1_EN ); sdDbg(( "12," )); } if ( status & SDHC_SD_ADDRESS_INT0_EN ) { Outp16(sCh->m_uBaseAddr+SDHC_NORMAL_INT_STAT, SDHC_SD_ADDRESS_INT0_EN); while( Inp16(sCh->m_uBaseAddr+SDHC_NORMAL_INT_STAT) & SDHC_SD_ADDRESS_INT0_EN ); sdDbg(( "11," )); } if ( status & SDHC_READWAIT_SIG_INT_EN ) { Outp16(sCh->m_uBaseAddr+SDHC_NORMAL_INT_STAT, SDHC_READWAIT_SIG_INT_EN); while( Inp16(sCh->m_uBaseAddr+SDHC_NORMAL_INT_STAT) & SDHC_READWAIT_SIG_INT_EN ); sdDbg(( "10," )); } if ( status & SDHC_CCS_INTERRUPT_STATUS_EN ) { sdDbg(( "9," )); } if ( status & SDHC_CARD_SIG_INT_EN ) { Outp16(sCh->m_uBaseAddr+SDHC_NORMAL_INT_STAT, SDHC_CARD_SIG_INT_EN); sdDbg(( "8," )); } if ( status & SDHC_CARD_REMOVAL_SIG_INT_EN ) { sdDbg(( "7," )); } if ( status & SDHC_CARD_INSERT_SIG_INT_EN ) { sdDbg(( "6," )); } if ( status & SDHC_BUFFER_READREADY_SIG_INT_EN ) { sdDbg(( "5," )); } if ( status & SDHC_BUFFER_WRITEREADY_SIG_INT_EN ) { sdDbg(( "4," )); } if ( status & SDHC_DMA_SIG_INT_EN ) { sdDbg(( "3," )); } if ( status & SDHC_BLOCKGAP_EVENT_SIG_INT_EN ) { Outp16(sCh->m_uBaseAddr+SDHC_NORMAL_INT_STAT, SDHC_BLOCKGAP_EVENT_SIG_INT_EN);// while( Inp16(sCh->m_uBaseAddr+SDHC_NORMAL_INT_STAT) & SDHC_BLOCKGAP_EVENT_SIG_INT_EN ); sdDbg(( "2," )); } if ( status & SDHC_TRANSFERCOMPLETE_SIG_INT_EN ) { sdDbg(( "1," )); } if ( status & SDHC_COMMANDCOMPLETE_SIG_INT_EN ) { sdDbg(( "0," )); } sdDbg(( ":go Inthandler\n"));}//////////// File Name : SDHC_readIntHandler// File Description : This function is interrupt service routine for common usage.// Input : NONE.// Output : NONE.void SDHC_readIntHandler( SDHC* sCh, u32 intIndex ) {// if ( !( Inp16( (sCh)->m_uBaseAddr + SDHC_NORMAL_INT_STAT ) & (1<<5) ) ) {// sdDbg(( "Interrupt Delay~!!!\n" );// } SDHC_ReadOneBlock( sCh, 0 ); if ( sCh->m_uRemainBlock == 0 ) { INTC_Disable(intIndex); } else { INTC_Enable(intIndex); }}//////////// File Name : SDHC_ReadInt0// File Description : This function is interrupt service routine for reading channel 0.// Input : NONE.// Output : NONE.void __irq SDHC_ReadInt0(void) { SDHC_readIntHandler(SDHC_curr_card[SDHC_CHANNEL_0], NUM_HSMMC0); INTC_ClearVectAddr();}//////////// File Name : SDHC_ReadInt1// File Description : This function is interrupt service routine for reading channel 1.// Input : NONE.// Output : NONE.void __irq SDHC_ReadInt1(void) { SDHC_readIntHandler(SDHC_curr_card[SDHC_CHANNEL_1], NUM_HSMMC1); INTC_ClearVectAddr();}//////////// File Name : SDHC_ReadInt2// File Description : This function is interrupt service routine for reading channel 2.// Input : NONE.// Output : NONE.void __irq SDHC_ReadInt2(void) { SDHC_readIntHandler(SDHC_curr_card[SDHC_CHANNEL_2], NUM_SPI1); INTC_ClearVectAddr();}//////////// File Name : SDHC_DMAIntHandler// File Description : This function is interrupt service routine for Common DMA Handling.// Input : NONE.// Output : NONE.void SDHC_DMAIntHandler(SDHC * sCh, u32 intIndex) { int i; // youngbo.song// SDHC_InterruptInspector(sCh);// sdDbg(("\nISR rHM_NORINTSTS = %x", Inp16(sCh->m_uBaseAddr+SDHC_NORMAL_INT_STAT ) ));// sdDbg(("block size :%d \n" , Inp16( sCh->m_uBaseAddr+SDHC_BLK_COUNT ) )); if ( Inp16(sCh->m_uBaseAddr+SDHC_NORMAL_INT_STAT) & SDHC_BLOCKGAP_EVENT_SIG_INT_EN ) { Inp16(sCh->m_uBaseAddr+SDHC_NORMAL_INT_STAT) = SDHC_BLOCKGAP_EVENT_SIG_INT_EN; } if( ( Inp16(sCh->m_uBaseAddr+SDHC_NORMAL_INT_STAT) & SDHC_TRANSFERCOMPLETE_SIG_INT_EN ) ) // When SDIO suspend mode, there is transfercomplete event, but transfer not yet completed.// && ( Inp16( sCh->m_uBaseAddr+SDHC_BLK_COUNT) == 0 ) ) {// sdDbg(("\nTransfer Complete\n"));// sdDbg(("T")); SDHC_INT_WAIT_CLEAR( sCh, 1, i); //SDHC_TRANSFERCOMPLETE_STS_INT_EN sCh->m_uRemainBlock=0; INTC_Disable(intIndex); } if ( Inp16(sCh->m_uBaseAddr+SDHC_NORMAL_INT_STAT) & SDHC_DMA_SIG_INT_EN ) {// sdDbg((" DMA buffer boundary is detected!\n"));// sdDbg(("B")); SDHC_INT_WAIT_CLEAR( sCh, 3, i); //SDHC_TRANSFERCOMPLETE_STS_INT_EN SDHC_SetSystemAddressReg(sCh, Inp32(sCh->m_uBaseAddr+SDHC_SYS_ADDR) ); } if ( Inp16(sCh->m_uBaseAddr+SDHC_NORMAL_INT_STAT) & SDHC_CCS_INTERRUPT_STATUS_EN ) { SDHC_INT_WAIT_CLEAR( sCh, 9, i); //SDHC_CCS_INTERRUPT_STATUS_EN sCh->m_uCCSResponse=0;// sdDbg(("SDHC_CCS_INTERRUPT_STATUS_EN----------------\n"));// sdDbg(("C")); }}//////////// File Name : SDHC_DMADone// File Description : DMA done interrupt handler for channel 0// Input : NONE.// Output : NONE.void __irq SDHC_DMAInt0(void) { SDHC_DMAIntHandler( SDHC_curr_card[SDHC_CHANNEL_0], NUM_HSMMC0); INTC_ClearVectAddr();}//////////// File Name : SDHC_DMAInt1// File Description : DMA done interrupt handler for channel 1// Input : NONE.// Output : NONE.void __irq SDHC_DMAInt1(void) { SDHC_DMAIntHandler( SDHC_curr_card[SDHC_CHANNEL_1], NUM_HSMMC1); INTC_ClearVectAddr();}//////////// File Name : SDHC_DMAInt2// File Description : DMA done interrupt handler for channel 2// Input : NONE.// Output : NONE.void __irq SDHC_DMAInt2(void) { SDHC_DMAIntHandler( SDHC_curr_card[SDHC_CHANNEL_2], NUM_SPI1); INTC_ClearVectAddr();}//////////// File Name : SDHC_normalIntHandler// File Description : Print Normal interrupt status register.// Input : SDHC Pointer// Output : NONE.void SDHC_normalIntHandler(SDHC* sCh) {// SDHC_InterruptInspector(sCh); sdDbg(( "Interrupt Status : %x\n", Inp16( sCh->m_uBaseAddr + SDHC_NORMAL_INT_STAT ) )); if ( Inp16( sCh->m_uBaseAddr + SDHC_NORMAL_INT_STAT ) & (0x3<<6) ) { if ( Inp16( sCh->m_uBaseAddr + SDHC_NORMAL_INT_STAT ) & (1<<6) ) sdDbg(( "Insert\n" )); if ( Inp16( sCh->m_uBaseAddr + SDHC_NORMAL_INT_STAT ) & (1<<7) ) sdDbg(( "Remove\n" )); } // Card Insert Remove. do { Outp16( sCh->m_uBaseAddr + SDHC_NORMAL_INT_STAT , Inp16( sCh->m_uBaseAddr + SDHC_NORMAL_INT_STAT ) ); } while( Inp16( sCh->m_uBaseAddr + SDHC_NORMAL_INT_STAT ) & (0x3<<6) ); INTC_ClearVectAddr();// INTC_Disable( sCh->m_ucIntChannelNum );}//////////// File Name : SDHC_normalInt0// File Description : Normal Interrupt Handler 0// Input : NONE// Output : NONE.void __irq SDHC_normalInt0(void) { SDHC_normalIntHandler( SDHC_curr_card[SDHC_CHANNEL_0] ); INTC_ClearVectAddr();}//////////// File Name : SDHC_normalInt1// File Description : Normal Interrupt Handler 1// Input : NONE// Output : NONE.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -