U-Boot的作用是引导操作系统,因此U-Boot的移植相对Linux操作系统的移植相对简单,无须考虑太多驱动程序,主要涉及到CPU初始化、SDRAM控制器初始化、Flash驱动程序、串口和网络接口驱动程序。完全从头开始移植一个U-Boot程序工作量是很大的,好在半导体公司一般都提供评估板的板级支持包(Board Support Package,BSP),在其基础上移植可以减少很多工作量。
由于目标板是基于BF536处理器的,而BF536处理器和BF537是兼容的,仅在片内内存配置方面有所不同,所以可以在ADI公司BF537 stamp主板的配置基础上来修改以适应目标板。U-Boot程序中和BF536处理器相关的部分如表4.3所示。
表4.3 U-Boot中BF536处理器相关的目录
板级配置文件存放在“/includes/configs”目录下,对于stamp板而言就是bf537-stamp.h,在其基础上修改以适应BF536目标板。bf537-stamp.h文件内容如下:
/*
* U-boot - Configuration file for BF537 STAMP board
*/
#ifndef __CONFIG_BF537_H__
#define __CONFIG_BF537_H__
#define CFG_LONGHELP 1
#define CONFIG_CMDLINE_EDITING 1
#define CONFIG_BAUDRATE 115200 //定义BF536启动后串口波特率
//PC端的串口设置要与此一致
/* Set default serial console for bf537 */
#define CONFIG_UART_CONSOLE 0 //控制台被定向到串口0
#define CONFIG_BF537 1
#define CONFIG_BOOTDELAY 3 //U-Boot启动后的延时,以秒为单位
/* define CONFIG_BF537_STAMP_LEDCMD to enable LED command*/
/*#define CONFIG_BF537_STAMP_LEDCMD 1*/
/*
* Boot Mode Set
* Blackfin can support several boot modes
*/
#define BF537_BYPASS_BOOT 0x0011 /* 启动模式0 */
#define BF537_PARA_BOOT 0x0012 /* 启动模式1 */
#define BF537_SPI_MASTER_BOOT 0x0014 /* 启动模式3 */
#define BF537_SPI_SLAVE_BOOT 0x0015 /* 启动模式4 */
#define BF537_TWI_MASTER_BOOT 0x0016 /* 启动模式5 */
#define BF537_TWI_SLAVE_BOOT 0x0017 /* 启动模式6 */
#define BF537_UART_BOOT 0x0018 /* 启动模式7 */
/* Define the boot mode */
#define BFIN_BOOT_MODE BF537_BYPASS_BOOT //定义当前的启动模式,旁路片内ROM
//#define BFIN_BOOT_MODE BF537_SPI_MASTER_BOOT
//#define BFIN_BOOT_MODE BF537_UART_BOOT
#define CONFIG_PANIC_HANG 1
#define ADSP_BF534 0x34
#define ADSP_BF536 0x36
#define ADSP_BF537 0x37
#define BFIN_CPU ADSP_BF536 //选择BF536处理器
/* This sets the default state of the cache on U-Boot's boot */
#define CONFIG_ICACHE_ON //使能指令缓存
#define CONFIG_DCACHE_ON //使能数据缓存
/* Define if want to do post memory test */
#undef CONFIG_POST_TEST
/* Define where the uboot will be loaded by on-chip boot rom */
#define APP_ENTRY 0x00001000 //U-Boot的执行地址,指向SDRAM空间
#define CONFIG_RTC_BF533 1
#define CONFIG_BOOT_RETRY_TIME -1
/* CONFIG_CLKIN_HZ is any value in Hz */
#define CONFIG_CLKIN_HZ 25000000 //定义主板外部晶振频率
/* CONFIG_CLKIN_HALF controls what is passed to PLL 0=CLKIN */
/* 1=CLKIN/2 */
#define CONFIG_CLKIN_HALF 0 //外部时钟频率直径输入到PLL
/* CONFIG_PLL_BYPASS controls if the PLL is used 0=don't bypass */
/* 1=bypass PLL */
#define CONFIG_PLL_BYPASS 0 //不旁路PLL
/* CONFIG_VCO_MULT controls what the multiplier of the PLL is. */
/* Values can range from 1-64 */
#define CONFIG_VCO_MULT 16 //VCO频率=16 * 25 = 400 MHz
/* CONFIG_CCLK_DIV controls what the core clock divider is */
/* Values can be 1, 2, 4, or 8 ONLY */
#define CONFIG_CCLK_DIV 1 //内核时钟=VCO频率/CONFIG_CCLK_DIV
/* CONFIG_SCLK_DIV controls what the peripheral clock divider is */
/* Values can range from 1-15 */
#define CONFIG_SCLK_DIV 4 //系统总线频率=VCO/CONFIG_SCLK_DIV
/* CONFIG_SPI_BAUD controls the SPI peripheral clock divider */
/* Values can range from 2-65535 */
/* SCK Frequency = SCLK / (2 * CONFIG_SPI_BAUD) */
#define CONFIG_SPI_BAUD 2
#if (BFIN_BOOT_MODE == BF537_SPI_MASTER_BOOT)
#define CONFIG_SPI_BAUD_INITBLOCK 4
#endif
#if ( CONFIG_CLKIN_HALF == 0 )
#define CONFIG_VCO_HZ ( CONFIG_CLKIN_HZ * CONFIG_VCO_MULT )
#else
#define CONFIG_VCO_HZ (( CONFIG_CLKIN_HZ * CONFIG_VCO_MULT ) / 2 )
#endif
#if (CONFIG_PLL_BYPASS == 0)
#define CONFIG_CCLK_HZ ( CONFIG_VCO_HZ / CONFIG_CCLK_DIV )
#define CONFIG_SCLK_HZ ( CONFIG_VCO_HZ / CONFIG_SCLK_DIV )
#else
#define CONFIG_CCLK_HZ CONFIG_CLKIN_HZ
#define CONFIG_SCLK_HZ CONFIG_CLKIN_HZ
#endif
#if (BFIN_BOOT_MODE == BF537_SPI_MASTER_BOOT)
#if (CONFIG_SCLK_HZ / (2*CONFIG_SPI_BAUD) > 20000000)
#define CONFIG_SPI_FLASH_FAST_READ 1 /* Needed if SPI_CLK > 20 MHz */
#else
#undef CONFIG_SPI_FLASH_FAST_READ
#endif
#endif
#define CONFIG_MEM_SIZE 32 //定义主板SDRAM的容量,以MB为单位
#define CONFIG_MEM_ADD_WDTH 9 //定义SDRAM的列地址宽度
#define CONFIG_MEM_MT48LC16M16A2TG_75 1 //4MB*16*4Bank的SDRAM,频率为133 MHz
//U-Boot以此为依据初始化SDRAM控制器
#define CONFIG_LOADS_ECHO 1
#define CFG_AUTOLOAD "no"
/*
* Network Settings
*/
/* network support */
#if (BFIN_CPU != ADSP_BF534)
#define CONFIG_IPADDR 192.168.1.76 //默认IP地址
#define CONFIG_NETMASK 255.255.255.0 //默认子网掩码
#define CONFIG_GATEWAYIP 192.168.1.1 //默认网关IP地址
#define CONFIG_SERVERIP 192.168.1.126//默认服务器IP地址
#define CONFIG_HOSTNAME BF537
#endif
#define CONFIG_ROOTPATH /romfs
/* Uncomment next line to use fixed MAC address */
//#define CONFIG_ETHADDR 02:80:ad:20:31:e8
/* This is the routine that copies the MAC in Flash to the 'ethaddr'setting */
#define CONFIG_BOOTCOMMAND"run ramboot" //启动后执行的命令
#if (BFIN_BOOT_MODE == BF537_BYPASS_BOOT) && defined
(CONFIG_POST_TEST)
/* 上电自检 */
#define CONFIG_POST ( CFG_POST_MEMORY | \
CFG_POST_UART | \
CFG_POST_FLASH | \
CFG_POST_ETHER | \
CFG_POST_LED | \
CFG_POST_BUTTON)
#else
#undef CONFIG_POST
#endif
#ifdef CONFIG_POST
#define CFG_CMD_POST_DIAG CFG_CMD_DIAG
#define FLASH_START_POST_BLOCK 11 /* Should > = 11 */
#define FLASH_END_POST_BLOCK 71 /* Should < = 71 */
#else
#define CFG_CMD_POST_DIAG 0
#endif
/* CF-CARD IDE-HDD Support */
#if defined(CONFIG_BFIN_CF_IDE) || defined(CONFIG_BFIN_HDD_IDE) ||defined(CONFIG_BFIN_TRUE_IDE)
# define CONFIG_BFIN_IDE 1
# define ADD_IDE_CMD CFG_CMD_IDE
#else
# define ADD_IDE_CMD 0
#endif
/*#define CONFIG_BF537_NAND */ /* Add nand flash support */
#ifdef CONFIG_BF537_NAND
# define ADD_NAND_CMD CFG_CMD_NAND
#else
# define ADD_NAND_CMD 0
#endif
#define CONFIG_NETCONSOLE 1
#define CONFIG_NET_MULTI 1
#if (BFIN_CPU == ADSP_BF534)
#define CONFIG_BFIN_CMD (CONFIG_CMD_DFL &~CFG_CMD_NET)
#else
#define CONFIG_BFIN_CMD (CONFIG_CMD_DFL | CFG_CMD_PING)
#endif
#if ((BFIN_BOOT_MODE == BF537_BYPASS_BOOT) || (BFIN_BOOT_MODE ==BF537_UART_BOOT))
#define CONFIG_COMMANDS (CONFIG_BFIN_CMD| \
CFG_CMD_ELF | \
CFG_CMD_I2C | \
CFG_CMD_CACHE | \
CFG_CMD_JFFS2 | \
CFG_CMD_EEPROM | \
CFG_CMD_DHCP | \
ADD_IDE_CMD | \
ADD_NAND_CMD | \
CFG_CMD_POST_DIAG | \
CFG_CMD_DATE)
#elif (BFIN_BOOT_MODE == BF537_SPI_MASTER_BOOT)
#define CONFIG_COMMANDS (CONFIG_BFIN_CMD| \
CFG_CMD_ELF | \
CFG_CMD_I2C | \
CFG_CMD_CACHE | \
CFG_CMD_JFFS2 | \
CFG_CMD_EEPROM | \
ADD_IDE_CMD | \
CFG_CMD_DATE)
#endif
//引导Linux内核启动时传递给内核的参数
#define CONFIG_BOOTARGS "root=/dev/mtdblock0 rw console=ttyBF0,115200"
#define CONFIG_LOADADDR 0x1000000 //内核的执行地址
#if((BFIN_BOOT_MODE==BF537_BYPASS_BOOT)||(BFIN_BOOT_MODE ==BF537_UART_BOOT))
#if(BFIN_CPU != ADSP_BF534)
#define CONFIG_EXTRA_ENV_SETTINGS \
"ramargs=setenv bootargs root=/dev/mtdblock0 rw
console=ttyBF0,115200\0"\ "nfsargs=setenv bootargs root=/dev/nfs rw " \
"nfsroot=$(serverip):$(rootpath) console=ttyBF0,115200\0" \
"addip=setenv bootargs $(bootargs) " \
"ip=$(ipaddr):$(serverip):$(gatewayip):$(netmask)" \
":$(hostname):eth0:off\0" \
"ramboot=tftpboot $(loadaddr) linux;" \
"run ramargs;run addip;bootelf\0" \
"nfsboot=tftpboot $(loadaddr) linux;" \
"run nfsargs;run addip;bootelf\0" \
"flashboot=bootm 0x20100000\0" \
"update=tftpboot $(loadaddr) u-boot.bin;" \
"protect off 0x20000000 0x2007FFFF;" \
"erase 0x20000000 0x2007FFFF;cp.b 0x1000000 0x20000000
$(filesize)\0" \
""
#else
#define CONFIG_EXTRA_ENV_SETTINGS \
"ramargs=setenv bootargs root=/dev/mtdblock0 rw
console=ttyBF0,115200\0" \
"flashboot=bootm 0x20100000\0"\
""
#endif
#elif (BFIN_BOOT_MODE == BF537_SPI_MASTER_BOOT)
#if (BFIN_CPU != ADSP_BF534)
#define CONFIG_EXTRA_ENV_SETTINGS \
"ramargs=setenv bootargs root=/dev/mtdblock0 rw
console=ttyBF0,115200\0"\"nfsargs=setenv bootargs root=/dev/ nfs rw " \
"nfsroot=$(serverip):$(rootpath) console=ttyBF0,115200\0" \
"addip=setenv bootargs $(bootargs) "\
"ip=$(ipaddr):$(serverip):$(gatewayip):$(netmask)" \
":$(hostname):eth0:off\0" \
"ramboot=tftpboot $(loadaddr) linux;" \
"run ramargs;run addip;bootelf\0" \
"nfsboot=tftpboot $(loadaddr) linux;" \
"run nfsargs;run addip;bootelf\0" \
"flashboot=bootm 0x20100000\0" \
"update=tftpboot $(loadaddr) u-boot.ldr;" \
"eeprom write $(loadaddr) 0x0 $(filesize);\0" \
""
#else
#define CONFIG_EXTRA_ENV_SETTINGS \
"ramargs=setenv bootargs root=/dev/mtdblock0 rw
console=ttyBF0,115200\0"\
"flashboot=bootm 0x20100000\0" \
""
#endif
#endif
/* this must be included AFTER the definition of CONFIG_COMMANDS (if any) */
#include <cmd_confdefs.h>
#if (BFIN_BOOT_MODE == BF537_SPI_MASTER_BOOT)
#if (BFIN_CPU == ADSP_BF534)
#define CFG_PROMPT"serial_bf534> " /* Monitor Command Prompt */
#elif (BFIN_CPU == ADSP_BF536)
#define CFG_PROMPT"serial_bf536> " /* Monitor Command Prompt */
#else
#define CFG_PROMPT"serial_bf537> " /* Monitor Command Prompt */
#endif
#else
#if (BFIN_CPU == ADSP_BF534)
#define CFG_PROMPT"bf534> " /* Monitor Command Prompt */
#elif (BFIN_CPU == ADSP_BF536)
#define CFG_PROMPT"bf536> " /* U-Boot命令行显示的提示符 */
#else
#define CFG_PROMPT"bf537> " /* Monitor Command Prompt */
#endif
#endif
#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
#define CFG_CBSIZE 1024 /* Console I/O Buffer Size */
#else
#define CFG_CBSIZE 256 /* Console I/O Buffer Size */
#endif
#define CFG_MAX_RAM_SIZE (CONFIG_MEM_SIZE * 1024*1024) //最多SDRAM空间
#define CFG_PBSIZE (CFG_CBSIZE+sizeof(CFG_PROMPT)+16)/* Print Buffer Size */
#define CFG_MAXARGS 16 /* max number of command args */
#define CFG_BARGSIZE CFG_CBSIZE /* Boot Argument Buffer Size */ #define CFG_MEMTEST_START 0x0 /* SDRAM的测试起始地址 */
#define CFG_MEMTEST_END ( (CONFIG_MEM_SIZE - 1) * 1024*1024)
#define CFG_LOAD_ADDR CONFIG_LOADADDR /* default load address */
#define CFG_HZ 1000 /* decrementer freq: 10 ms ticks */
#define CFG_BAUDRATE_TABLE { 9600, 19200, 38400, 57600, 115200 }
#define CFG_SDRAM_BASE 0x00000000 //SDRAM起始地址,由片选决定
#define CFG_FLASH_BASE 0x20000000 //Flash起始地址,由片选决定
#define CFG_MONITOR_LEN (256 << 10) //最高位的256 KB被Monitor使用
#define CFG_MONITOR_BASE (CFG_MAX_RAM_SIZE - CFG_MONITOR_LEN)
#define CFG_MALLOC_LEN (128 << 10) /* Reserve 128 KB for malloc() */
//其次的128 KB为malloc使用
#define CFG_MALLOC_BASE (CFG_MONITOR_BASE - CFG_MALLOC_LEN)
#define CFG_GBL_DATA_SIZE 0x4000
//其次全局数据地址
#define CFG_GBL_DATA_ADDR (CFG_MALLOC_BASE - CFG_GBL_DATA_SIZE) //其次系统堆栈地址
#define CONFIG_STACKBASE(CFG_GBL_DATA_ADDR - 4)
#define CFG_BOOTMAPSZ (8 << 20) /* Initial Memory map for
Linux */
#define CFG_MAX_FLASH_BANKS 1 /* max number of memory banks */
#define CFG_MAX_FLASH_SECT 64 /* max number of sectors on one chip */
#if (BFIN_BOOT_MODE == BF537_BYPASS_BOOT) || (BFIN_BOOT_MODE ==
BF537_UART_BOOT) /* for bf537-stamp, uart boot mode still store env in flash */
#define CFG_ENV_IS_IN_FLASH 1 //环境变量是否存储在Flash中
#define CFG_ENV_ADDR 0x20004000 //环境变量的存储地址
#define CFG_ENV_OFFSET (CFG_ENV_ADDR - CFG_FLASH_BASE)
#elif (BFIN_BOOT_MODE == BF537_SPI_MASTER_BOOT)
#define CFG_ENV_IS_IN_EEPROM 1
#define CFG_ENV_OFFSET 0x4000
#define CFG_ENV_HEADER (CFG_ENV_OFFSET + 0x16e) /* 0x12A is the length of LDR file header */
#endif
#define CFG_ENV_SIZE 0x2000
#define CFG_ENV_SECT_SIZE 0x10000 /* Total Size of Environment Sector */
//#if (BFIN_BOOT_MODE == BF537_BYPASS_BOOT)
#define ENV_IS_EMBEDDED
//#endif
/* JFFS Partition offset set */ #define CFG_JFFS2_FIRST_BANK 0
#define CFG_JFFS2_NUM_BANKS 1
/* 512kB reserved for u-boot */
#define CFG_JFFS2_FIRST_SECTOR 15
#define CONFIG_SPI
/*
* Stack sizes
*/
#define CONFIG_STACKSIZE (128*1024) /* regular stack */
#define POLL_MODE 1
#define FLASH_TOT_SECT 32
#define FLASH_SIZE 0x400000 //共4 MB的Flash空间
#define CFG_FLASH_SIZE 0x400000
/*
* Board NAND Infomation
*/
#define CFG_NAND_ADDR 0x20212000
#define CFG_NAND_BASE CFG_NAND_ADDR
#define CFG_MAX_NAND_DEVICE 1
#define SECTORSIZE 512
#define ADDR_COLUMN 1
#define ADDR_PAGE 2
#define ADDR_COLUMN_PAGE 3
#define NAND_ChipID_UNKNOWN 0x00
#define NAND_MAX_FLOORS 1
#define NAND_MAX_CHIPS 1
#define BFIN_NAND_READY PF3
#define NAND_WAIT_READY(nand) \
do { \
int timeout = 0; \
while(!(*pPORTFIO & PF3)) \
if (timeout++ > 100000) \
break; \
} while (0)
#define BFIN_NAND_CLE (1<<2) /* A2 -> Command Enable */
#define BFIN_NAND_ALE (1<<1) /* A1 -> Address Enable */
#define WRITE_NAND_COMMAND(d, adr) do{ *(volatile __u8 *)((unsigned long)adr | BFIN_NAND_CLE) = (__u8)(d); } while(0)
#define WRITE_NAND_ADDRESS(d, adr) do{ *(volatile __u8 *)((unsigned long)adr | BFIN_NAND_ALE) = (__u8)(d); } while(0)
#define WRITE_NAND(d, adr) do{ *(volatile __u8 *)((unsigned long)adr) = (__u8)d; } while(0)
#define READ_NAND(adr) ((volatile unsigned char)(*(volatile __u8
*)(unsigned long)adr))
/*
* Initialize PSD4256 registers for using I2C
*/
#define CONFIG_MISC_INIT_R
#define CFG_BOOTM_LEN 0x2000000 /* Large Image Length,set to 64 Meg */
/*
* I2C settings
* By default PF1 is used as SDA and PF0 as SCL on the Stamp board */
/*#define CONFIG_SOFT_I2C 1*/ /* I2C bit-banged */
#define CONFIG_HARD_I2C 1 /* I2C TWI */
#if defined CONFIG_HARD_I2C
#define CONFIG_TWICLK_KHZ 50
#endif
#if defined CONFIG_SOFT_I2C
/*
* Software (bit-bang) I2C driver configuration */
#define PF_SCL PF0
#define PF_SDA PF1
#define I2C_INIT (*pFIO_DIR |= PF_SCL); asm("ssync;")
#define I2C_ACTIVE (*pFIO_DIR |= PF_SDA); *pFIO_INEN &=
~PF_SDA; asm("ssync;")
#define I2C_TRISTATE (*pFIO_DIR &= ~PF_SDA); *pFIO_INEN|= PF_SDA; asm("ssync;")
#define I2C_READ((volatile)(*pFIO_FLAG_D & PF_SDA) != 0);
asm("ssync;")
#define I2C_SDA(bit) if(bit) { \
*pFIO_FLAG_S = PF_SDA; \
asm("ssync;"); \
} \
else { \
*pFIO_FLAG_C = PF_SDA; \
asm("ssync;"); \
}
#define I2C_SCL(bit) if(bit) { \
*pFIO_FLAG_S = PF_SCL; \
asm("ssync;"); \
} \
else { \
*pFIO_FLAG_C = PF_SCL; \
asm("ssync;"); \
}
#define I2C_DELAY udelay(5) /* 1/4 I2C clock duration */
#endif
#define CFG_I2C_SPEED 50000
#define CFG_I2C_SLAVE 0xFE
//EBIU控制器定义
#define AMGCTLVAL 0xFF
#define AMBCTL0VAL 0x7BB07BB0
#define AMBCTL1VAL 0xFFC27BB0
#define CONFIG_VDSP 1
#ifdef CONFIG_VDSP
#define ET_EXEC_VDSP 0x8
#define SHT_STRTAB_VDSP 0x1
#define ELFSHDRSIZE_VDSP 0x2C
#define VDSP_ENTRY_ADDR 0xFFA00000
#endif
#if defined(CONFIG_BFIN_IDE)
#define CONFIG_DOS_PARTITION 1 /*
* IDE/ATA stuff
*/
#undef CONFIG_IDE_8xx_DIRECT/* no pcmcia interface
required */
#undef CONFIG_IDE_LED /* no led for ide supported */
#undef CONFIG_IDE_RESET/* no reset for ide supported */
#define CFG_IDE_MAXBUS 1/* max. 1 IDE busses */
#define CFG_IDE_MAXDEVICE (CFG_IDE_MAXBUS*1) /* max. 1 drives per IDE bus */
#undef AMBCTL1VAL
#define AMBCTL1VAL 0xFFC3FFC3
#define CONFIG_CF_ATASEL_DIS 0x20311800
#define CONFIG_CF_ATASEL_ENA 0x20311802
#if defined(CONFIG_BFIN_TRUE_IDE)
// Note that these settings aren't for the most part used in include/ata.h
// when all of the ATA registers are setup
#define CFG_ATA_BASE_ADDR 0x2031C000
#define CFG_ATA_IDE0_OFFSET 0x0000
#define CFG_ATA_DATA_OFFSET 0x0020 /* Offset for data I/O */
#define CFG_ATA_REG_OFFSET 0x0020 /* Offset for normal
register accesses */
#define CFG_ATA_ALT_OFFSET 0x001C /* Offset for alternate registers */
#define CFG_ATA_STRIDE 2 /* CF.A0 --> Blackfin.Ax */
#endif /* CONFIG_BFIN_TRUE_IDE */
#if defined(CONFIG_BFIN_CF_IDE) /* USE CompactFlash Storage Card in the common memory space */
#define CFG_ATA_BASE_ADDR 0x20211800
#define CFG_ATA_IDE0_OFFSET 0x0000
#define CFG_ATA_DATA_OFFSET 0x0000 /* Offset for data I/O */
#define CFG_ATA_REG_OFFSET 0x0000 /* Offset for normal
register accesses */
#define CFG_ATA_ALT_OFFSET 0x000E /* Offset for alternate registers */
#define CFG_ATA_STRIDE 1 /* CF.A0 --> Blackfin.Ax */
#endif /* CONFIG_BFIN_CF_IDE */
#if defined(CONFIG_BFIN_HDD_IDE) /* USE TRUE IDE */
#define CFG_ATA_BASE_ADDR 0x20314000
#define CFG_ATA_IDE0_OFFSET 0x0000
#define CFG_ATA_DATA_OFFSET 0x0020 /* Offset for data I/O */
#define CFG_ATA_REG_OFFSET 0x0020 /* Offset for normal
register accesses */
#define CFG_ATA_ALT_OFFSET 0x001C /* Offset for alternate registers */
#define CFG_ATA_STRIDE 2 /* CF.A0 --> Blackfin.A1 */ #undef CONFIG_SCLK_DIV
#define CONFIG_SCLK_DIV 8
#endif /* CONFIG_BFIN_HDD_IDE */
#endif /*CONFIG_BFIN_IDE*/
#endif
可以看到配置文件的主要内容是时钟参数的配置、启动模式的配置、串口参数的配置、Flash配置、SDRAM配置、网络参数配置等,还有一些内容涉及到CF卡、IDE硬盘、I 2 C接口等,不是U-Boot的必须内容,为精简U-Boot的体积可以去掉这些配置。
时钟系统是处理器的脉搏,处理器按照时钟的节拍对数据流进行加工。Blackfin处理器时钟系统的核心是锁相环(Phase Locked Loop,PLL),外部时钟信号进入锁相环,经过倍频后得到压控振荡器频率,然后由这个频率经过分频得到内核时钟CCLK和系统时钟SCLK。内核时钟是Blackfin内核的运行频率,片内SRAM空间的读写操作也是运行在内核频率。系统时钟SCLK为外设存取总线(Peripheral Access Bus,PAB)、DMA总线(DMA Access Bus,DAB)、外部存取总线(External Access Bus,EAB)和外部总线接口单元(External Bus Interface Unit,EBIU)提供时钟。PLL系统结构如图4.1所示。
图4.1 PLL时钟系统结构框图
各种时钟频率的计算公式如下:
VCOCLK =(CLKIN × MSEL[5:0])/(DF + 1),if MSEL[5:0] != 0
VCOCLK =(CLKIN × 64)/(DF + 1),if MSEL[5:0] == 0
VCOCLK = CLKIN,if BYPASS = 1
CCLK = VCOCLK/(2的CSEL[1:0]次方)
SCLK = VCOCLK/SSEL[3:0],SSEL[3:0] != 0
时钟频率的生成是由一组寄存器控制的,主要是控制寄存器PLL_CTRL和PLL分频寄存器PLL_DIV。
PLL_DIV寄存器如图4.2所示。
图4.2 PLL_DIV寄存器
PLL_DIV寄存器定义内核时钟和系统时钟的分频倍数。
PLL_CTRL寄存器如图4.3所示。
图4.3 PLL_CTRL寄存器
PLL_CTRL寄存器控制PLL的行为模式,关系到时钟频率的设置包括DF、BYPASS和MSEL[5:0]。具体作用效果可以参考前面的时钟计算公式。
明白PLL时钟系统的工作原理后,再针对目标板进行设置就很轻松了。BF536处理器要求的外部输入时钟CLKIN的频率范围是10~50 MHz,目标板的晶振是25 MHz,如果要得到400 MHz的主频和100 MHz的系统频率,需要的参数如下:
DF = 0
BYPASS = 0
MSEL[5:0] = 16
CSEL[1:0] = 0
SSEL[3:0] = 4
所以在bf537-stamp.h文件中定义如下:
#define CONFIG_CLKIN_HZ 25000000 //定义主板外部晶振频率#define CONFIG_CLKIN_HALF 0 //DF = 0
#define CONFIG_PLL_BYPASS 0 //BYPASS = 0
#define CONFIG_VCO_MULT 16 //MSEL[5:0] = 16
#define CONFIG_CCLK_DIV 1 //CSEL[1:0] = 0
#define CONFIG_SCLK_DIV 4 //SSEL[3:0] = 4
bf537-stamp.h文件中仅仅是定义这些值,真正地写进寄存器是在/cpu/bf537/init_sdram.S文件中。
注意:BF536处理器PLL寄存器默认设置是10倍倍频,所以在选择外部时钟时要注意不能超过BF536的最高频率的1/10。
串口在嵌入式系统调试中至关重要,尽早地打通串口对调试信息的输出是非常有利的。U-Boot在/cpu/bf537/serial.c文件中定义串口初始化以及串口收/发函数,初始化函数serial_init()在/lib_blackfin/board.c文件中的函数board_init_f()中被调用。在初始化串口之前调用函数init_baudrate()设置串口波特率。串口波特率的宏定义在配置文件中定义。U-Boot默认的波特率是57600 bps,可以在bf537-stamp.h文件中修改该定义为希望的波特率115200 bps,如下:
#define CONFIG_BAUDRATE 115200
BF536处理器的SDRAM控制器最大可支持128 MB的SDRAM,总线宽度可以配置为4位、8位或者16位,下面以32 MB SDRAM HY57V561620为例说明SDRAM的配置。HY57V561620是Hynix公司出品的4×4×16位的SDRAM,总线宽度为16位,包括4个Bank。BF536处理器与HY57V561620的连接包括数据总线D[0:15]、地址总线A[1:19]、SDRAM刷新专用信号SA10、时钟信号SCLK、时钟使能信号SCKE、行锁存信号SRAS、列锁存信号SCAS、写使能信号SWE、片选信号SMS和总线屏蔽信号ABE[1:0]。BF536处理器SDRAM起始地址为0x00000000,因此目标板SDRAM地址范围为0x00000000~0x01ffffff,共32 MB。BF536处理器与HY57V561620的连接电路图如图4.4所示。
图4.4 BF536处理器与HY57V561620的连接图
BF536处理器的SDRAM控制器包括4个寄存器:EBIU_SDRRC、EBIU_SDBCTL、EBIU_SDGCTL、EBIU_SDSTAT,其中前3个寄存器的设置决定SDRAM的工作方式,最后1个寄存器反映控制器的状态。
SDRAM刷新率控制寄存器EBIU_SDRRC如图4.5所示。
图4.5 SDRAM刷新率控制寄存器EBIU_SDRRC
EBIU_SDRRC寄存器包括1个12位的刷新率RDIV[11:0],依照以下公式计算该值:
RDIV = ((fSCLK × tREF) / NRA) – (tRAS + tRP)
其中,fSCLK = 系统总线频率;tREF = SDRAM行刷新时间;NRA = 刷新周期,对于HY57V561620来说,NRA=8192;tRAS = 从存储体激活到预充电之间的时间,以时钟周期为单位;tRP = 存储体从预充电到再次被激活之间的最小时间,以时钟周期为单位。
如果系统总线频率为100 MHz,对于HY57V561620来说,
RDIV = ((100×10^6×64×10^-3) / 8192 – (6 + 3) = 0x304
SDRAM存储体控制寄存器EBIU_SDBCTL如图4.6所示。
图4.6 SDRAM存储体控制寄存器EBIU_SDBCTL
表4.4 EBIU_SDBCTL寄存器定义
对于HY57V561620而言,列地址宽度为9位,容量为32 MB。
SDRAM全局控制寄存器EBIU_SDGCTL 。
EBIU_SDGCTL寄存器决定SDRAM操作的时序,需要配合SDRAM手册进行调整,不同的参数会影响SDRAM的性能,甚至影响是否能够正常工作。
U-Boot对SDRAM的设置体现在三个文件中,首先在配置文件中定义SDRAM容量大小、列地址宽度和型号,其次在mem_init.h中根据前面的定义自动生成EBIU_SDRRC、EBIU_SDBCTL、EBIU_SDGCTL三个寄存器的值,最后在init_sdram.S文件中初始化SDRAM控制器,把上面生成的值写入寄存器。
图4.7 SDRAM全局控制寄存器EBIU_SDGCTL
/include/configs/bf537-stamp.h中的定义:
#define CONFIG_MEM_SIZE 32 //定义主板SDRAM的容量,以MB为单位
#define CONFIG_MEM_ADD_WDTH 9 //定义SDRAM的列地址宽度
//4MB×16×4Bank的SDRAM,频率为133 MHz,与HY57V561620兼容
#define CONFIG_MEM_MT48LC16M16A2TG_75 1
/include/asm-blackfin/mem_init.h中系统时钟为100 MHz时HY57V561620对应的定义:
#define SDRAM_tRP TRP_2
#define SDRAM_tRP_num 2
#define SDRAM_tRAS TRAS_5
#define SDRAM_tRAS_num 5 #define SDRAM_tRCD TRCD_2
#define SDRAM_tWR TWR_2
#define SDRAM_Tref 64
#define SDRAM_NRA 8192
#define SDRAM_CL CL_3
#define SDRAM_SIZE EBSZ_32
#define SDRAM_WIDTH EBCAW_9
#define mem_SDBCTL SDRAM_WIDTH | SDRAM_SIZE | EBE
#define mem_SDRRC ((( CONFIG_SCLK_HZ / 1000) * SDRAM_Tref) / SDRAM_NRA) - (SDRAM_tRAS_num + SDRAM_tRP_num)
#define mem_SDGCTL ( SCTLE | SDRAM_CL | SDRAM_tRAS | SDRAM_tRP |SDRAM_tRCD | SDRAM_tWR | PSS )
/cpu/bf537/init_sdram.S中的设置:
p0.l = lo(EBIU_SDRRC);
p0.h = hi(EBIU_SDRRC);
r0 = mem_SDRRC; //把mem_init.h文件生成的mem_SDRRC,w[p0] = r0.l;//写入EBIU_SDRRC寄存器
ssync;
p0.l = (EBIU_SDBCTL & 0xFFFF);
p0.h = (EBIU_SDBCTL >> 16);
r0 = mem_SDBCTL; //把mem_init.h文件生成的mem_SDBCTL,w[p0] = r0.l; //写入EBIU_SDBCTL寄存器
ssync;
P2.H = hi(EBIU_SDGCTL);
P2.L = lo(EBIU_SDGCTL);
R0 = [P2];
BITCLR (R0, 24); //禁止自我刷新p0.h = hi(EBIU_SDSTAT);
p0.l = lo(EBIU_SDSTAT);
r2.l = w[p0];
cc = bittst(r2,3); //判断SDRAM是否已经启动,如果没有则启动,
否则跳过
if !cc jump skip;
NOP;
BITSET (R0, 23);
skip:
[P2] = R0;
SSYNC;
R0.L = lo(mem_SDGCTL);
R0.H = hi(mem_SDGCTL);
[P2] = R0; //把mem_init.h中生成的值写入寄存器中
EBIU_SDGCTL
SSYNC;
nop;
至此,SDRAM控制器初始化完成,如果采用不同型号和配置的SDRAM存储器,可参考以上步骤修改相关参数。
BF536处理器的异步存储控制器(Asynchronous Memory Controller,AMC)最多支持4个片选信号,每个片选信号可以寻址1 MB的地址空间。4个片选分别是AMS0、AMS1、AMS2和AMS3,其中AMS0支持上电启动。Flash存储器用来存储用户程序,目标板上的Flash存储器选用SST公司的SST39VF3201,该芯片与BF536处理器的连接包括A[1:19]地址总线、D[0:15]共16位数据总线、写使能信号AWE、允许输出信号AOE、片选信号AMS0和复位信号RESET。BF536处理器与Flash芯片的连接电路图如图4.8所示。
图4.8 BF536处理器与SST39VF3201芯片之间的连接电路
用户在U-Boot命令行环境下可以下载并烧写程序、设置环境变量等工作,因此U-Boot涉及到Flash的部分除了异步存储控制器的设置外,还需要编写Flash的擦除、编程等接口程序。
BF536的异步存储控制器不但可以无缝接口Flash设备,还可以连接所有支持以存储器方式访问的设备,如各种外设控制器、SRAM、FPGA等,不同设备需要的不同时序由寄存器参数来调整。异步存储控制器包括4个片选信号AMS[3:0],称之为段。每个段独立寻址,具有独立的时序,最多可以寻址1 MB的地址空间,其中AMS0支持上电启动,4个片选信号的寻址空间如表4.5所示。
表4.5 BF536 AMC寻址空间
AMC的工作模式由3个寄存器决定:全局控制寄存器EBIU_AMGCTL、段控制寄存器EBIU_AMBCTL0和EBIU_AMBCTL1。
EBIU_AMGCTL寄存器如图4.9所示,定义如表4.6所示。
图4.9 EBIU_AMGCTL寄存器
表4.6 EBIU_AMGCTL寄存器定义
(续表)
EBIU_AMBCTL0寄存器如图4.10所示,定义如表4.7所示。
图4.10 EBIU_AMBCTL0寄存器
表4.7 EBIU_AMBCTL0寄存器定义
(续表)
EBIU_AMBCTL1寄存器如图4.11所示,定义如表4.8所示。
图4.11 EBIU_AMBCTL1寄存器
图4.11 EBIU_AMBCTL1寄存器(续)
表4.8 EBIU_AMBCTL1寄存器定义
(续表)
EBIU_AMGCTL寄存器控制全局属性,包括是否使能片选、DMA与CPU的优先级等,EBIU_AMBCTL0和EBIU_AMBCTL1分别控制4个片选段的动作属性,主要是各种操作的时序,不同的时序对读写操作的影响很大,根据所使用的Flash或者其他外设的要求调整时序以达到最佳性能,能够提供系统的吞吐率。BF536处理器在上电时使用默认值初始化寄存器,默认值一般是最大时延,以满足最慢的Flash的启动要求,系统启动后需要重新设置这些寄存器以追求最佳性能。
U-Boot中对Flash的要求体现在以下3个方面:
(1)/include/configs/bf537-stamp.h中的定义。
#define AMGCTLVAL 0xFF
#define AMBCTL0VAL 0xBBC3BBC3
#define AMBCTL1VAL 0x99B39983
(2)/cpu/bf537/start.S中的初始化。
p2.h = (EBIU_AMBCTL1 >> 16);
p2.l = (EBIU_AMBCTL1 & 0xFFFF);
r0.h = (AMBCTL1VAL >> 16);
r0.l = (AMBCTL1VAL & 0xFFFF);
[p2] = r0; //设置EBIU_AMBCTL1寄存器
ssync;
p2.h = (EBIU_AMBCTL0 >> 16);
p2.l = (EBIU_AMBCTL0 & 0xFFFF);
r0.h = (AMBCTL0VAL >> 16);
r0.l = (AMBCTL0VAL & 0xFFFF);
[p2] = r0; //设置EBIU_AMBCTL0寄存器
ssync;
p2.h = (EBIU_AMGCTL >> 16);
p2.l = (EBIU_AMGCTL & 0xffff);
r0 = AMGCTLVAL;
w[p2] = r0; //设置EBIU_AMGCTL寄存器
ssync;
(3)/board/bf536-stamp/flash.c中具体的Flash操作接口函数。
falsh.c文件中定义了Flash操作的接口函数,包括通用函数和底层接口函数,底层接口函数包括get_codes()、write_flash()、read_flash()、poll_toggle_bit()、erase_flash()、erase_block_flash()等函数。用户需要根据SST39VF3201的芯片手册自己实现这些函数,下面以最基本的读写操作来说明接口函数的实现。
#define CFG_FLASH_BASE 0x20000000 //Flash存储器的起始地址
//定义相对偏移量到绝对地址的映射关系
#define sysAddress(offset) ((volatile unsigned short *)(CFG_FLASH_BASE + (offset << 1)))
/***************************************************************************
* Flash写操作接口write_flash()
* 作用:把一个word数据写入指定地址中
* 输入:long nOffset——相对于0x20000000的地址偏移量
* uint16 nValue——要写入的数据,16 bit
* 输出:写成功返回SUCCESS,否则返回 FLASH_FAIL
***************************************************************************/
int write_flash(long nOffset, uint16 nValue)
{
*sysAddress(0x5555) = 0x00AA; // write data 0x00AA to device addr 0x5555
*sysAddress(0x2AAA) = 0x0055; // write data 0x0055 to device addr 0x2AAA
*sysAddress(0x5555) = 0x00A0; // write data 0x00A0 to device addr 0x5555
*sysAddress(nOffset/2) = nValue; // transfer the Uint16 to destination
if(poll_toggle_bit(nOffset) < 0)
return FLASH_FAIL;
return FLASH_SUCCESS;
}
/***************************************************************************
* Flash读操作接口read_flash()
* 作用:把指定地址处的数据读取到给定变量中
* 输入:long nOffset——相对于0x20000000的地址偏移量
* 输出:uint16 *pnValue——要返回的数据,16 bit
***************************************************************************/
int read_flash(long nOffset, uint16 *pnValue)
{
uint16 nValue = 0x0;
nValue = *(sysAddress(nOffset/2));
*pnValue = nValue;
return TRUE;
}