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,IMG_SIZE, JUMP_ADDR);

#endif

       /*Load from Norflash in RAM */

#ifdef CFG_NORFLASH//不执行暂不分析,主要是从不同的flash中加载UBOOT到SDRAM

       load_norflash(IMG_ADDRESS,IMG_SIZE, 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, IMG_ADDRESS,IMG_SIZE, 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), 0, PIO_DEFAULT, PIO_PERIPH_A},

              {"TXD", AT91C_PIN_PB(15), 0, PIO_DEFAULT, PIO_PERIPH_A},

#endif

              {(char *) 0, 0, 0, PIO_DEFAULT, PIO_PERIPH_A},

       };//此结构体初始化为空,调试阶段有使用价值

       /* 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, const unsigned int value)

{

       writel(value, 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;

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值