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...\n\r");

#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;

}

相关文章

Bootstrip HTML 查询搜索常用格式模版 &lt;form class=&...
如何在按钮上加红色数字 您可以使用Bootstrap的badge组件来在...
要让两个按钮左右排列,你可以使用 Bootstrap 的网格系统将它...
是的,可以将status设置为布尔类型,这样可以在前端使用复选...
前端工程师一般用的是Bootstrap的框架而不是样式,样式一般自...
起步导入:<linkrel="stylesheet"href="b...