📄 mmc_io.c
字号:
/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Copyright (C) 2002 Motorola Semiconductors HK Ltd * *//****************************************************************************** * * Copyright (C) 2001, Motorola All Rights Reserved * * File Name: mmcsd.c * * Progammers: Yiwei Zhao * * Date of Creations: 30 DEC,2001 * * Synopsis: * * Modification History: * 30 DEC, 2001 * *****************************************************************************//* Functions List: * * * *//* * Implementation of the MMCSD Driver. */#include <linux/config.h>#include "mmc_def.h"#include "mmc_main.h"static u32 cur_perclk2;//pd25void _mmcsd_socket1_irq_set(){ _reg_GPIO_GIUS(GPIOD) |= 0x02000000; _reg_GPIO_DDIR(GPIOD) &= ~0x02000000; _reg_GPIO_IMR(GPIOD) |= 0x02000000;//enable _reg_GPIO_ICR2(GPIOD) |= 0x000c0000;//negative level trigger _reg_GPIO_PUEN(GPIOD) &= ~0x02000000; // pull up enable interrupt}void _mmcsd_socket1_clear_irq(){ _reg_GPIO_ISR(GPIOD) = 0x02000000;}/****************************************************************************** * Function Name: _MMCSD_CheckHardwareRevision * * Input: * * Value Returned: * * Description: * *Modification History: * 30 DEC,2001, Initial version. Yiwei Zhao ******************************************************************************/u32 _MMCSD_ChectHardwareRevision(int port){ u32 HardwareID;#ifdef CONFIG_ARCH_MX1ADS HardwareID = mmcsdr_rev_no; TRACE("rev_no = %x \n",mmcsdr_rev_no); if(HardwareID!=0x0390) { TRACE("HardwareID = 0x%x, return = %d", HardwareID,1); return 1; //Hardware Revision Error; }#endif#ifdef CONFIG_ARCH_MX2ADS if(port == 0) { HardwareID = mmcsdr_rev_no; } else if(port == 1) { HardwareID = mmcsdr_rev_no_2; } if(HardwareID!=0x0400) { TRACE("HardwareID = 0x%x, return = %d", HardwareID,1); return 1; //Hardware Revision Error; }#endif return 0;}/****************************************************************************** * Function Name: _MMCSD_SoftReset * * Input: * * Value Returned: * * Description: * *Modification History: * 30 DEC,2001, Initial version. Yiwei Zhao ******************************************************************************/u32 _MMCSD_SoftReset(int port){ #ifdef CONFIG_ARCH_MX1ADS // System Reset Start_Stop_Clk(0x8); // System Reset, MMC core enable & Stop CLk Start_Stop_Clk(0xD); // MMC Core enable & Stop Clk Start_Stop_Clk(0x5); Start_Stop_Clk(0x5); Start_Stop_Clk(0x5); Start_Stop_Clk(0x5); Start_Stop_Clk(0x5); Start_Stop_Clk(0x5); Start_Stop_Clk(0x5); Start_Stop_Clk(0x5);#ifdef MMCSD_DMA_ENDIAN_ERR // PLAM -- choose big endian FIFO mode mmcsdr_str_stp_clk |= 0x00000020; // end PLAM#else mmcsdr_str_stp_clk &= ~0x00000020;#endif //Set MMC Response Time-Out Register mmcsdr_res_to=0xffff; //Set Block length register mmcsdr_blk_len=MMCSD_MINIMUM_BLK_SIZE ;//2002/04/19 //Set MMC Number of Blocks Register mmcsdr_nob=1;//2002/04/19#endif#ifdef CONFIG_ARCH_MX2ADS // System Reset Start_Stop_Clk(0x8,port); // System Reset, MMC core enable & Stop CLk Start_Stop_Clk(0xD,port); // MMC Core enable & Stop Clk Start_Stop_Clk(0x5,port); Start_Stop_Clk(0x5,port); Start_Stop_Clk(0x5,port); Start_Stop_Clk(0x5,port); Start_Stop_Clk(0x5,port); Start_Stop_Clk(0x5,port); Start_Stop_Clk(0x5,port); Start_Stop_Clk(0x5,port); if(port == 0) { mmcsdr_str_stp_clk &= ~0x00000020; //Set MMC Response Time-Out Register mmcsdr_res_to=0xffff; //Set Block length register mmcsdr_blk_len=MMCSD_MINIMUM_BLK_SIZE ; //Set MMC Number of Blocks Register mmcsdr_nob=1; } else if(port == 1) { mmcsdr_str_stp_clk_2 &= ~0x00000020; //Set MMC Response Time-Out Register mmcsdr_res_to_2=0xffff; //Set Block length register mmcsdr_blk_len_2=MMCSD_MINIMUM_BLK_SIZE ; //Set MMC Number of Blocks Register mmcsdr_nob_2=1; } #endif return 0; }void _MMCSD_ReadTimeOut(u32 arg,int port){ arg = 0x2db4; if(port == 1) mmcsdr_read_to_2=0x2db4; else mmcsdr_read_to=0x2db4;}/****************************************************************************** * Function Name: _MMCSD_SetCmd * * Input: * * Value Returned: * * Description: * *Modification History: * 30 DEC,2001, Initial version. Yiwei Zhao ******************************************************************************/void _MMCSD_SetCmd(u8 cmd,u32 arg,u32 ctrl,int port){#ifdef MMCSD_CMD TRACE(" ----------------------------------------"); TRACE(" CMD%02d Arg: 0x%08lX Ctrl: 0x%04lX\n",cmd,arg,ctrl);#endif if(port == 1) { mmcsdr_cmd_2=cmd; mmcsdr_argumenth_2=arg>>16; mmcsdr_argumentl_2=arg&0xFFFF; mmcsdr_cmd_dat_cont_2=ctrl; } else { mmcsdr_cmd=cmd; mmcsdr_argumenth=arg>>16; mmcsdr_argumentl=arg&0xFFFF; mmcsdr_cmd_dat_cont=ctrl; }}/****************************************************************************** * Function Name: _MMCSD_IsRun * * Input: * * Value Returned: * * Description: * *Modification History: * 30 DEC,2001, Initial version. Yiwei Zhao ******************************************************************************/u32 _MMCSD_IsRun(int port){ if(port == 1) return (mmcsdr_status_2)&0x100; else return (mmcsdr_status)&0x100;}/****************************************************************************** * Function Name: _MMCSD_StartClk * * Input: * * Value Returned: * * Description: * *Modification History: * 30 DEC,2001, Initial version. Yiwei Zhao ******************************************************************************/void _MMCSD_StartClk(int port){ unsigned short count = 0; do { if (count++ == 0) { // do this every 256 loops if(port == 1) mmcsdr_str_stp_clk_2 |= 0x06; else mmcsdr_str_stp_clk |= 0x06; } } while(!_MMCSD_IsRun(port));}/****************************************************************************** * Function Name: _MMCSD_StopClk * * Input: * * Value Returned: * * Description: * *Modification History: * 30 DEC,2001, Initial version. Yiwei Zhao ******************************************************************************/void _MMCSD_StopClk(int port){ unsigned short count = 0; do { if (count++ == 0) { // do this every 256 loops if(port == 1) mmcsdr_str_stp_clk_2 |= 0x05; else mmcsdr_str_stp_clk |= 0x05; } }while(_MMCSD_IsRun(port));}/****************************************************************************** * Function Name: _MMCSD_GetResponses * * Input: * * Value Returned: * * Description: * *Modification History: * 30 DEC,2001, Initial version. Yiwei Zhao ******************************************************************************/void _MMCSD_GetResponses(MMCSD_Responses *pRS, u8 rsType,int port){ int i; u16 rs; u32 temp; if(rsType==MMCSDB_R1) { pRS->status=0; if(port == 1) temp=(u32)mmcsdr_res_fifo_2; else temp=(u32)mmcsdr_res_fifo; rs=(u16)temp; pRS->status|=((u32)rs&0x00FF)<<24; if(port == 1) temp=(u32)mmcsdr_res_fifo_2; else temp=(u32)mmcsdr_res_fifo; rs=(u16)temp; pRS->status|=((u32)rs)<<8; if(port == 1) temp=(u32)mmcsdr_res_fifo_2; else temp=(u32)mmcsdr_res_fifo; rs=(u16)temp; pRS->status|=(rs&0xFF00)>>8; } else if(rsType==MMCSDB_R3) { pRS->OCR=0; if(port == 1) temp=(u32)mmcsdr_res_fifo_2; else temp=(u32)mmcsdr_res_fifo; rs=(u16)temp; temp=rs&0x00FF; pRS->OCR|=temp<<24; if(port == 1) temp=(u32)mmcsdr_res_fifo_2; else temp=(u32)mmcsdr_res_fifo; rs=(u16)temp; pRS->OCR|=((u32)rs)<<8; if(port == 1) temp=(u32)mmcsdr_res_fifo_2; else temp=(u32)mmcsdr_res_fifo; rs=(u16)temp; pRS->OCR|=(rs&0xFF00)>>8; } else { for(i=0;i<16;) { if(port == 1) temp=(u32)mmcsdr_res_fifo_2; else temp=(u32)mmcsdr_res_fifo; rs=(u16)temp; pRS->CSD[i] = (rs&0xFF00)>>8; i++; pRS->CSD[i] = (rs&0x00FF); i++; } } }/****************************************************************************** * Function Name: _MMCSD_SetBlockLenReg * * Input: * size: size of the block. * * Value Returned: * * * Description: * this routine sets the size of a block * *Modification History: * 30 DEC,2001, Initial version. Yiwei Zhao ******************************************************************************/void _MMCSD_SetBlockLenReg(u16 size,u32 port){ if(port == 1) mmcsdr_blk_len_2=size; else mmcsdr_blk_len=size;}/****************************************************************************** * Function Name: _MMCSD_SetNumberOfBlockReg * * Input: * * num: Number of block * * Value Returned: * * * Description: * this routine sets number of the blocks. * *Modification History: * 30 DEC,2001, Initial version. Yiwei Zhao ******************************************************************************/void _MMCSD_SetNumberOfBlockReg(u16 num,u32 port){ if(port == 1) mmcsdr_nob_2=num; else mmcsdr_nob=num;}/****************************************************************************** * Function Name: _MMCSD_ClockSet * * Input: * * speed: if speed == oxff, set the highest speed. * * Value Returned: * * * Description: * this routine set clock rate. * *Modification History: * 30 DEC,2001, Initial version. Yiwei Zhao ******************************************************************************/void _MMCSD_ClockSet(u32 prescaler,u8 clk,int port){ _MMCSD_StopClk(port);#ifdef CONFIG_ARCH_MX1ADS prescaler = prescaler&0x07; clk = clk&0x07; mmcsdr_clk_rate=(prescaler<<3)|clk;#endif#ifdef CONFIG_ARCH_MX2ADS prescaler = prescaler&0x0f; clk = clk&0xfff; if(port == 1) mmcsdr_clk_rate_2=(prescaler<<4)|clk; else mmcsdr_clk_rate=(prescaler<<4)|clk;#endif }void _MMCSD_SetClk(int mode,int port){#ifdef CONFIG_ARCH_MX1ADS if(mode == MMCSD_HIGH_SPEED) { if(cur_perclk2<20) { _MMCSD_ClockSet(0,0); } else { _MMCSD_ClockSet(cur_perclk2/20-1,1); } } else { _MMCSD_ClockSet(7,7); }#endif#ifdef CONFIG_ARCH_MX2ADS if(mode == MMCSD_HIGH_SPEED) { if(cur_perclk2<20) { _MMCSD_ClockSet(0,1,port); } else { _MMCSD_ClockSet(0,cur_perclk2/20+1,port); } } else { _MMCSD_ClockSet(8,0xa,port);//if perclk2 is about 20M } TRACE("clkrate=0x%x ,perclk2=0x%x \n",mmcsdr_clk_rate,cur_perclk2);#endif }/****************************************************************************** * Function Name: _MMCSD_PinConfig * * Input: * * Value Returned: * * Description: * this routine sets GPIO registers. * *Modification History: * 30 DEC,2001, Initial version. Yiwei Zhao ******************************************************************************/static void _MMCSD_get_cur_perclk2(void){#ifdef CONFIG_ARCH_MX1ADS cur_perclk2 = *(u32 *)CRM_PCDR; cur_perclk2 = (cur_perclk2&0x000000F0)>>4; cur_perclk2 = 96/(cur_perclk2+1);#endif#ifdef CONFIG_ARCH_MX2ADS cur_perclk2 = _reg_CRM_PCDR; cur_perclk2 = (cur_perclk2&0x03c00000)>>22; cur_perclk2 = 128/(cur_perclk2+1); #endif}void _MMCSD_PinConfig(void){ _MMCSD_get_cur_perclk2();#ifdef CONFIG_ARCH_MX1ADS *(u32 *)DBMX1_GIUS_B &= 0xFFFFC0FF; *(u32 *)DBMX1_GPR_B &= 0xFFFFC0FF; *(u32 *)DBMX1_PUEN_B |= 0x00003f00;#endif#ifdef CONFIG_ARCH_MX2ADS _reg_GPIO_DDIR(GPIOE) |= 0x00fc0000;//0x3f000000; _reg_GPIO_GIUS(GPIOE) &= 0xff03ffff; _reg_GPIO_GPR(GPIOE) &= 0xff03ffff; _reg_GPIO_PUEN(GPIOE) |= 0x00fc0000; //add for SD2 pb4~pb9 pb7-dat3,pb9-clk _reg_GPIO_DDIR(GPIOB) |= 0x000003f0; _reg_GPIO_GIUS(GPIOB) &= ~0x000003f0; _reg_GPIO_GPR(GPIOB) &= ~0x000003f0; _reg_GPIO_PUEN(GPIOB) |= 0x000003f0;#endif }void _MMCSD_64M_MMC_PinConfig(void){ _MMCSD_get_cur_perclk2();#ifdef CONFIG_ARCH_MX2ADS //pin pe18~23,18,19,20,22 up, 21-dat3,23-clk _reg_GPIO_DDIR(GPIOE) |= 0x00fc0000; _reg_GPIO_GIUS(GPIOE) &= 0xff03ffff; _reg_GPIO_GPR(GPIOE) &= 0xff03ffff; _reg_GPIO_PUEN(GPIOE) |= 0x005c0000;// _reg_GPIO_PUEN(GPIOE) &= 0xff5fffff; //add for SD2 pb4~pb9 pb7-dat3,pb9-clk _reg_GPIO_DDIR(GPIOB) |= 0x000003f0; _reg_GPIO_GIUS(GPIOB) &= ~0x000003f0; _reg_GPIO_GPR(GPIOB) &= ~0x000003f0; _reg_GPIO_PUEN(GPIOB) |= 0x00000170; _reg_GPIO_PUEN(GPIOB) &= 0xfffffd7f; #endif //pb8~13, 11-dat3,12-clk,13-cmd#ifdef CONFIG_ARCH_MX1ADS *(u32 *)DBMX1_DDIR_B |= 0x00003F00; // Enable SDHC's port to Output *(u32 *)DBMX1_GIUS_B &= 0xFFFFC0FF; *(u32 *)DBMX1_GPR_B &= 0xFFFFC0FF; *(u32 *)DBMX1_PUEN_B |= 0x00003700; *(u32 *)DBMX1_PUEN_B &=0xfffff7ff;//Karen modify it for MMC test #endif}/************************************************put content to STR_STP_CLK U32 Clk_en = set the clk to start or stop 0x6: start MMC clk 0x5: stop MMC clk************************************************/void Start_Stop_Clk(u32 Clk_en,int port){ //when the clk is STARTED check whether the MMC is enable and reset is not set if(((Clk_en&0x2)!=0)&&((Clk_en&0x8)==0)&&((Clk_en&0x4)!=0)) { if(port == 1) { mmcsdr_str_stp_clk_2 &= ~MMCSD_CLOCK_MASK; mmcsdr_str_stp_clk_2 |= Clk_en; while ( ((mmcsdr_status_2)&0x100) == 0 );//check the status if the clock do not start } else { mmcsdr_str_stp_clk &= ~MMCSD_CLOCK_MASK; mmcsdr_str_stp_clk |= Clk_en; while ( ((mmcsdr_status)&0x100) == 0 );//check the status if the clock do not start } } //when the clk is STOPPED, check whether the MMC is enable and reset is not set else if(((Clk_en&0x1)!=0)&&((Clk_en&0x8)==0)&&((Clk_en&0x4)!=0)) { if(port == 1) { mmcsdr_str_stp_clk_2 &= ~MMCSD_CLOCK_MASK; mmcsdr_str_stp_clk_2 |= Clk_en; while ( ((mmcsdr_status_2) & 0x100) != 0 );//check the status if the clock is still running } else { mmcsdr_str_stp_clk &= ~MMCSD_CLOCK_MASK; mmcsdr_str_stp_clk |= Clk_en; while ( ((mmcsdr_status) & 0x100) != 0 );//check the status if the clock is still running } } //reset or enable the syste else { if(port == 1) { mmcsdr_str_stp_clk_2 &= ~MMCSD_CLOCK_MASK; mmcsdr_str_stp_clk_2 |= Clk_en; } else { mmcsdr_str_stp_clk &= ~MMCSD_CLOCK_MASK; mmcsdr_str_stp_clk |= Clk_en; } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -