AT91Bootstrap1.16第二阶段C程序详解之一
Main函数的主要流程: 硬件初始化——》从Dataflash中加载uboot——》返回指定的地址JUMP_ADDR ?本文主要分析:?硬件初始化hw_init() #include "include/part.h" #include "include/main.h" #include "include/debug.h" #include "include/dataflash.h" #include "include/nandflash.h" #include "include/norflash.h" /*------------------------------------------------------------------------------*/ /* Function Name?????? : main??????????????????????????????????????????? */ /* Object????????????? : Main function?????????????????????????????????????? */ /* Input Parameters??? : none??????????????????????????????????????????????? */ /* Output Parameters?? : True?????????????????????????????????????????????? */ /*------------------------------------------------------------------------------*/ int main(void) { /* ================== 1st step: HardwareInitialization ================= */ ?????? /* Performs the hardware initialization*/ #ifdef CFG_HW_INIT ?????? hw_init();硬件初始化执行(WDT.PLLA.MCK.PLLB.CP15.PIO.EBI.MATRIX.SDRAM) #endif /* ==================== 2nd step: Load frommedia ==================== */ ?????? /* Load from Dataflash in RAM */ #ifdef CFG_DATAFLASH? //Dataflash加载到SDRAM中 ?????? load_df(AT91C_SPI_PCS_DATAFLASH,IMG_ADDRESS,IMG_SIZE,JUMP_ADDR); #endif ?????? /*Load from Nandflash in RAM */ #ifdef CFG_NANDFLASH //不执行暂不分析,主要是从不同的flash中加载UBOOT到SDRAM ?????? load_nandflash(IMG_ADDRESS,JUMP_ADDR); #endif ?????? /*Load from Norflash in RAM */ #ifdef CFG_NORFLASH//不执行暂不分析,主要是从不同的flash中加载UBOOT到SDRAM ?????? load_norflash(IMG_ADDRESS,JUMP_ADDR); #endif /* ==================== 3rd step:? Process the Image =================== */ ?????? /* Uncompress the image */ #ifdef GUNZIP //解压缩映像文件,不需要,不执行 ?????? decompress_image((void*)IMG_ADDRESS,(void *)JUMP_ADDR,IMG_SIZE); /*NOT IMPLEMENTED YET */ #endif /* GUNZIP */ /* ==================== 4th step: Start theapplication =================== */ ?????? /* Set linux arguments *///不执行 #ifdef LINUX_ARG//设置启动参数,不需要,因为bootstrap只加载uboot到SDRAM中 ?????? linux_arg(LINUX_ARG);???? /* NOT IMPLEMENTED YET */ #endif /* LINUX_ARG */ ?????? /*Jump to the Image Address */ ?????? returnJUMP_ADDR;//0x23F00000???? /* Final Jump Address */可以自行修改 } 通过对main函数的分析可知启示,在主函数中只有两函数要执行,特定的开发板,那就是: hw_init() 硬件初始化执行 load_df(AT91C_SPI_PCS_DATAFLASH,JUMP_ADDR); Dataflash加载到SDRAM中 对于从不同的flash中加载主要体现在,硬件是否支持哪种启动方式。 Load from Dataflash inRAM Load from Nandflash inRAM Load from Norflash inRAM ????需要有针对性的添加修改,来适应自己的开发板 ? 本次移植使用的是AT的官方demo板子画的,所有只移植从Dataflash加载uboot即可。 ? 以下具体分析这两函数的具体实现: 一硬件初始化void hw_init(void) /*----------------------------------------------------------------------------*/ /* fn??? hw_init???????????????????????????????????????????? ????? */ /* brief This functionperforms very low level HW initialization????? ????? */ /* This function isinvoked as soon as possible during the c_startup??? ????? */ /* The bss segment mustbe initialized????????????????????????????? ????? */ /*----------------------------------------------------------------------------*/ void hw_init(void) { ?????? unsigned int cp15; ?????? /* Configure PIOs */ ?????? const struct pio_desc hw_pio[] = { #ifdef CFG_DEBUG ????????????? {"RXD",AT91C_PIN_PB(14),PIO_DEFAULT,PIO_PERIPH_A}, ????????????? {"TXD",AT91C_PIN_PB(15), #endif ????????????? {(char *) 0, ?????? };//此结构体初始化为空,调试阶段有使用价值 ?????? /* Disable watchdog */ ?????? writel(AT91C_WDTC_WDDIS,AT91C_BASE_WDTC + WDTC_WDMR); //关闭看门狗(0xFFFFFD40+4)=(0x1 << 15) ?????? /* At this stage the main oscillator is supposed to be enabled ?????? ?* PCK = MCK = MOSC *///在这个阶段,主振荡器启用PCK = MCK = MOSC ?????? /* Configure PLLA = MOSC * (PLL_MULA + 1) / PLL_DIVA */ ?????? pmc_cfg_plla(PLLA_SETTINGS,PLL_LOCK_TIMEOUT);//0x2060BF09 ?? ? ? ?/* PCK = PLLA = 2 * MCK */ ?????? pmc_cfg_mck(MCKR_SETTINGS,PLL_LOCK_TIMEOUT); ?????? /* Switch MCK onPLLA output */ ?????? pmc_cfg_mck(MCKR_CSS_SETTINGS,PLL_LOCK_TIMEOUT); ? ? ? ?/* Configure PLLB */ ?????? pmc_cfg_pllb(PLLB_SETTINGS,PLL_LOCK_TIMEOUT); ? ? ? ?/* Configure CP15 */ ?????? cp15 = get_cp15();//将协处理器P15的寄存器中数据传送到ARM处理器寄存器r0中。 ?????? cp15 |= I_CACHE;//set bit 12 (I) I-Cache ?????? set_cp15(cp15);//设置CP15中的寄存器值,禁止指令Cache? ?????? /* Configure the PIO controller */ ?????? pio_setup(hw_pio);//此函数直接跳出,因为hw_pio结构体的第一个元素是0,调试有用? ?????? /* Configure the EBI Slave Slot Cycle to 64 *///简单就是给某个寄存器写入一个值 writel( (readl((AT91C_BASE_MATRIX + MATRIX_SCFG3)) & ~0xFF)| 0x40,(AT91C_BASE_MATRIX+ MATRIX_SCFG3)); //先读出(MATRIX)Base Address+Slave Configuration Register 3 (ebi)寄存器的值,同时将低 //8位清零,再和0x40相与,即置位第7位 01000000? , // writel(X1XXXXXXX,刚刚读出的那个寄存器0xFFFFEE00+0X4C)); //将0XFFFFEE4C寄存器的第7位置1,具体什么功能,查数据手册???????????? #ifdef CFG_DEBUG ?//调试阶段使用,暂不分析 ?????? /* Enable Debugmessages on the DBGU */ ?????? dbg_init(BAUDRATE(MASTER_CLOCK,115200)); ?????? dbg_print("Start AT91Bootstrap...nr"); #endif /* CFG_DEBUG */ #ifdef CFG_SDRAM ?????? /* Initializethe matrix *///简单就是给某个寄存器写入一个值 ?????? writel(readl(AT91C_BASE_CCFG+ CCFG_EBICSA) | AT91C_EBI_CS1A_SDRAMC,AT91C_BASE_CCFG + CCFG_EBICSA); //先读出(CCFG)Base Address+ EBI Chip Select Assignement Register寄存器的值 //再和(0x1<< 1) // (CCFG) Chip Select 1 is assigned to the SDRAM Controller.相或,即置位第//2位 0000 0010? , // writel(XXXXXXX1X,刚刚读出的那个寄存器0xFFFFEF10+0X0C)); //将0XFFFFEF1C寄存器的第2位置1,具体什么功能,查数据手册???????????? ?????? /* Configure SDRAM Controller */ ?????? sdram_init(???? AT91C_SDRAMC_NC_9? | ??????????????????????????? AT91C_SDRAMC_NR_13 | ??????????????????????????? AT91C_SDRAMC_CAS_2 | ??????????????????????????? AT91C_SDRAMC_NB_4_BANKS | ??????????????????????????? AT91C_SDRAMC_DBW_32_BITS | ??????????????????????????? AT91C_SDRAMC_TWR_2 | ??????????????????????????? AT91C_SDRAMC_TRC_7 | ??????????????????????????? AT91C_SDRAMC_TRP_2 | ??????????????????????????? AT91C_SDRAMC_TRCD_2 | ??????????????????????????? AT91C_SDRAMC_TRAS_5 | ??????????????????????????? AT91C_SDRAMC_TXSR_8,??????? ??? /* Control Register*/ ??????????????????????????? (MASTER_CLOCK *7)/1000000,?????? /* Refresh TimerRegister */ ??????????????????????????? AT91C_SDRAMC_MD_SDRAM);?????? /* SDRAM (no low power) */ #endif /* CFG_SDRAM */ } 两个重要宏定义 #define writel(value,address) ?????? (*(volatile unsigned int *)(address)) = (value)?? //向寄存器写入某个值 #define readl(address) ?????? (*(volatile unsigned int *)(address))??????????? //从寄存器中读取 重点分析以下几个子函数: 前3个是关于PLL的配置,最后一个是SDRAM初始化子函数。 /* Write PMC register */ static inline voidwrite_pmc(unsigned int offset,const unsigned int value) { ?????? writel(value,offset + AT91C_BASE_PMC);// (0xFFFFFC00) // (PMC) Base Address } /* Read PMC registers */ static inline unsignedint read_pmc(unsigned int offset) { ?????? return readl(offset + AT91C_BASE_PMC);// (0xFFFFFC00) // (PMC) Base Address } 1//*---------------------------------------------------------------------------- //* fn???pmc_cfg_plla //* brief Configurethe pll frequency to the corresponding value. //*----------------------------------------------------------------------------*/ intpmc_cfg_plla(unsigned int pmc_pllar,unsigned int timeout) { ?????? write_pmc((unsigned int)PMC_PLLAR,pmc_pllar); // pmc_pllar=0x2060BF09写入到偏移(40)PLL A Register的寄存器中 ?????? while ( (timeout--) && !(read_pmc(PMC_SR) & AT91C_PMC_LOCKA) );//延时等待 //若延时未到,则只有在PMC Status Register的(PMC) PLL A Status=0x02状态位是0x2跳出 //即//延时等待PLLA 锁定频率 ?????? return (timeout) ? 0 : (-1); } 2//*---------------------------------------------------------------------------- //* fn??? pmc_cfg_mck //* brief Configurethe main oscillator to the corresponding value. //*----------------------------------------------------------------------------*/ intpmc_cfg_mck(unsigned int pmc_mckr,unsigned int timeout) { ?????? write_pmc(PMC_MCKR,?pmc_mckr); ???????????????????? // pmc_mckr写入到偏移(48) Master ClockRegister的寄存器中 ?????? while ( (timeout--) && !(read_pmc(PMC_SR) & AT91C_PMC_MCKRDY) ); ?//延时等待 Master Clock状态准备就绪 ?????? return (timeout) ? 0 : (-1); } 3 intpmc_cfg_pllb(unsigned int pmc_pllbr,unsigned int timeout) { ?????? write_pmc(PMC_PLLBR,pmc_pllbr); // pmc_pllbr=0x10483F0E写入到偏移(44) // PLL B Register的寄存器中 ?????? while ( (timeout--) && !(read_pmc(PMC_SR) & AT91C_PMC_LOCKB) ); //延时等待PLLB 锁定频率 ?????? return (timeout) ? 0 : (-1); } 4//*---------------------------------------------------------------------------- //* fn??? sdram_init //* brief Initializethe SDRAM Controller //*---------------------------------------------------------------------------- 关于SDRAM初始化的重要子函数 /* Write SDRAMCregister */ static inline voidwrite_sdramc(unsigned int offset,offset + AT91C_BASE_SDRAMC);// 0xFFFFEA00(SDRAMC) Base Address } /* Read SDRAMCregisters */ static inline unsignedint read_sdramc(unsigned int offset) { ?????? return readl(offset + AT91C_BASE_SDRAMC); // 0xFFFFEA00(SDRAMC) Base Address } int sdram_init(unsignedint sdramc_cr,unsigned int sdramc_tr,unsigned char low_power) { ?????? volatile unsigned int i; ?????? /* Performs the hardware initialization */ ?????? sdramc_hw_init();//初始化IO,主要是写两寄存器 ?????? /* CFG Control Register */ ?????? write_sdramc(SDRAMC_CR,sdramc_cr);//主要是设置SDRAM的一些配置参数 ????????????? //将sdramc_cr的值写入到地址偏移SDRAMC_CR的寄存器中 ?????? /* Set MDR Register */ ??? write_sdramc(SDRAMC_MDR,(low_power &0x01)); //(low_power=0 )& 0x01=0 ?????? for (i =0; i< 1000;i++);//延时一段时间,到底是多少时间需要好好弄清楚了呀?????? //修改模式寄存器的值,改变工作模式0x1 write_sdramc(SDRAMC_MR,AT91C_SDRAMC_MODE_NOP_CMD);? // Set NOP // (SDRAMC) Issue a NOP Command at every accesswrite_sdramc(SDRAMC_MR,1 ); writel(0x00000000,AT91C_SDRAM);//Perform NOP? AT91C_SDRAM=0x20000000 //修改模式寄存器的值,改变工作模式0x2 ?????? write_sdramc(SDRAMC_MR,AT91C_SDRAMC_MODE_PRCGALL_CMD); // Set PRCHG AL ?????? writel(0x00000000,AT91C_SDRAM); // Perform PRCHG? AT91C_SDRAM=0x20000000 ?????? for (i =0; i< 10000;i++);//延时多少时间?????? //修改模式寄存器的值,改变工作模式0x4。以下代码实现每次设置工作模式为0x4,然后 //在地址0x20000004 写 0x0000 0001 //在地址0x20000008 写 0x0000 0002? 依次写直到 //在地址0x20000020 写 0x0000 0008? ?????? write_sdramc(SDRAMC_MR,AT91C_SDRAMC_MODE_RFSH_CMD); // Set 1st CBR ?????? writel(0x00000001,AT91C_SDRAM+4);?????????????????? // Perform CBR ?????? write_sdramc(SDRAMC_MR,AT91C_SDRAMC_MODE_RFSH_CMD); // Set 2 CBR ?????? writel(0x00000002,AT91C_SDRAM+8);?????????????????? // Perform CBR ?????? write_sdramc(SDRAMC_MR,AT91C_SDRAMC_MODE_RFSH_CMD); // Set 3 CBR ?????? writel(0x00000003,AT91C_SDRAM+0xc);?????????????? // Perform CBR ?????? write_sdramc(SDRAMC_MR,AT91C_SDRAMC_MODE_RFSH_CMD); // Set 4 CBR ?????? writel(0x00000004,AT91C_SDRAM+0x10);??????????????????? // Perform CBR ?????? write_sdramc(SDRAMC_MR,AT91C_SDRAMC_MODE_RFSH_CMD); // Set 5 CBR ?????? writel(0x00000005,AT91C_SDRAM+0x14);??????????????????? // Perform CBR ?????? write_sdramc(SDRAMC_MR,AT91C_SDRAMC_MODE_RFSH_CMD); // Set 6 CBR ?????? writel(0x00000006,AT91C_SDRAM+0x18);??????????????????? // Perform CBR ?????? write_sdramc(SDRAMC_MR,AT91C_SDRAMC_MODE_RFSH_CMD); // Set 7 CBR ?????? writel(0x00000007,AT91C_SDRAM+0x1C);??????????????????? //Perform CBR ?????? write_sdramc(SDRAMC_MR,AT91C_SDRAMC_MODE_RFSH_CMD); // Set 8 CBR ?????? writel(0x00000008,AT91C_SDRAM+0x20);??????????????????? //Perform CBR //修改模式寄存器的值,改变工作模式0x3, //在地址0x20000024 写 0xcafe dede ?????? write_sdramc(SDRAMC_MR,AT91C_SDRAMC_MODE_LMR_CMD);?? //SetLMR operation ?????? writel(0xcafedede,AT91C_SDRAM+0x24);?????????????? //Perform LMR burst=1,lat=2 //修改刷新时间寄存器的值(MASTER_CLOCK * 7)/1000000,寄存器要填写的值怎么计算? //MASTER_CLOCK???????????? (198656000/2)???? 具体这个值是怎么来的 ?????? write_sdramc(SDRAMC_TR,sdramc_tr);????????????????? // Set Refresh Timer ?//修改模式寄存器的值,改变工作模式0x0, ?????? write_sdramc(SDRAMC_MR,AT91C_SDRAMC_MODE_NORMAL_CMD);? // Set Normalmode ?????? writel(0x00000000,AT91C_SDRAM);?????????????? // Perform Normal mode ?????? return 0; } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |