start.S源码:
.globl _start
_start:
// 硬件相关的设置
// Peri port setup
ldr r0, =0x70000000
orr r0, r0, #0x13
mcr p15,0,r0,c15,c2,4 @ 256M(0x70000000-0x7fffffff)
// 关看门狗
// 往WTCON(0x7E004000)写0
ldr r0, =0x7E004000
mov r1, #0
str r1, [r0]
// 设置栈
ldr sp, =8*1024
// 设置时钟
bl clock_init
bl ddr_init
bl init_uart
// 清BSS
// 把BSS段对应的内存清零
clean_bss:
ldr r0, =bss_start
ldr r1, =bss_end
mov r3, #0
cmp r0, r1
b copy_kernel
clean_loop:
str r3, [r0], #4
cmp r0, r1
bne clean_loop
copy_kernel:
mov r0, #0x200000
ldr r1, =(0x50008000 - 64)
mov r2, #0x500000
bl copykernel2ddr
cmp r0, #0
bne halt
bl set_params
mov r0, #0
ldr r1, =1626
ldr r2, =0x50000100
ldr pc, =0x50008000
halt:
b halt
=====================================================================
clock.S源码:
.globl clock_init
clock_init:
// 1.设置LOCK_TIME
ldr r0, =0x7E00F000 // APLL_LOCK
ldr r1, =0x0000FFFF
str r1, [r0]
str r1, [r0, #4] // MPLL_LOCK
str r1, [r0, #8] // EPLL_LOCK
#define OTHERS 0x7e00f900
@ set async mode // 当CPU时钟 != HCLK时,要设为异步模式
ldr r0, =OTHERS
ldr r1, [r0]
bic r1, #0xc0
str r1, [r0]
loop1: // 等待,直到CPU进入异步模式
ldr r0, =OTHERS
ldr r1, [r0]
and r1, #0xf00
cmp r1, #0
bne loop1
// SYNC667
// MISC_CON[19] = 0
#define ARM_RATIO 0 // ARMCLK = DOUTAPLL / (ARM_RATIO + 1)
#define HCLKX2_RATIO 1 // HCLKX2 = HCLKX2IN / (HCLKX2_RATIO + 1)
#define HCLK_RATIO 1 // HCLK = HCLKX2 / (HCLK_RATIO + 1)
#define PCLK_RATIO 3 // PCLK = HCLKX2 / (PCLK_RATIO + 1)
#define MPLL_RATIO 0 // DOUTMPLL = MOUTMPLL / (MPLL_RATIO + 1)
ldr r0, =0x7E00F020 // CLK_DIV0
ldr r1, =(ARM_RATIO) | (MPLL_RATIO << 4) | (HCLK_RATIO << 8) | (HCLKX2_RATIO << 9) | (PCLK_RATIO << 12)
str r1, [r0]
// 2.配置时钟
// 2.1 配置APLL
// 2.1.1 设置APLL
// 2.1.2 MUXAPLL
// 2.1.3 SYNC667
// 2.1.4 DIVAPLL
#define APLL_CON_VAL ((1<<31) | (266 << 16) | (3 << 8) | (1))
ldr r0, =0x7E00F00C
ldr r1, =APLL_CON_VAL
str r1, [r0] // APLL_CON, FOUTAPL = MDIV * Fin / (PDIV*2^SDIV) = 266*12/(3*2^1) = 532MHz
// 2.2 配置MPLL
// 2.2.1 设置MPLL
// 2.2.2 MUXMPLL
// 2.2.3 SYNCMUX
// 2.2.4 SYNC667
// 2.2.5 HCLKX2_RATIO
// 2.2.6 PCLK_RATIO
#define MPLL_CON_VAL ((1<<31) | (266 << 16) | (3 << 8) | (1))
ldr r0, =0x7E00F010
ldr r1, =MPLL_CON_VAL
str r1, [r0] // MPLL_CON, FOUTMPL = MDIV * Fin / (PDIV*2^SDIV) = 266*12/(3*2^1) = 532MHz
// 3.选择PLL的输出作为时钟源
ldr r0, =0x7E00F01C
ldr r1, =0x03
str r1, [r0]
mov pc, lr
=====================================================================
sdram.c源码:
#include "common.h"
#define MEMCCMD 0x7e001004
#define P1REFRESH 0x7e001010
#define P1CASLAT 0x7e001014
#define MEM_SYS_CFG 0x7e00f120
#define P1MEMCFG 0x7e00100c
#define P1T_DQSS 0x7e001018
#define P1T_MRD 0x7e00101c
#define P1T_RAS 0x7e001020
#define P1T_RC 0x7e001024
#define P1T_RCD 0x7e001028
#define P1T_RFC 0x7e00102c
#define P1T_RP 0x7e001030
#define P1T_RRD 0x7e001034
#define P1T_WR 0x7e001038
#define P1T_WTR 0x7e00103c
#define P1T_XP 0x7e001040
#define P1T_XSR 0x7e001044
#define P1T_ESR 0x7e001048
#define P1MEMCFG2 0X7e00104c
#define P1_chip_0_cfg 0x7e001200
#define P1MEMSTAT 0x7e001000
#define P1MEMCCMD 0x7e001004
#define P1DIRECTCMD 0x7e001008
#define HCLK 133000000
#define nstoclk(ns) (ns/( 1000000000/HCLK)+1)
int ddr_init( void )
{
// tell dramc to configure
set_val( MEMCCMD, 0x4 );
// set refresh period
set_val( P1REFRESH, nstoclk(7800) );
// set timing para
set_val( P1CASLAT, ( 3 << 1 ) );
set_val( P1T_DQSS, 0x1 ); // 0.75 - 1.25
set_val( P1T_MRD, 0x2 );
set_val( P1T_RAS, nstoclk(45) );
set_val( P1T_RC, nstoclk(68) );
u32 trcd = nstoclk( 23 );
set_val( P1T_RCD, trcd | (( trcd - 3 ) << 3 ) );
u32 trfc = nstoclk( 80 );
set_val( P1T_RFC, trfc | ( ( trfc-3 ) << 5 ) );
u32 trp = nstoclk( 23 );
set_val( P1T_RP, trp | ( ( trp - 3 ) << 3 ) );
set_val( P1T_RRD, nstoclk(15) );
set_val( P1T_WR, nstoclk(15) );
set_val( P1T_WTR, 0x7 );
set_val( P1T_XP, 0x2 );
set_val( P1T_XSR, nstoclk(120) );
set_val( P1T_ESR, nstoclk(120) );
// set mem cfg
set_nbit( P1MEMCFG, 0, 3, 0x2 ); // 10 column address
// set_nbit: 把从第bit位开始的一共len位消零,然后把这几位设为val
set_nbit( P1MEMCFG, 3, 3, 0x3 ); // 14 row address
set_zero( P1MEMCFG, 6 ); // A10/AP
set_nbit( P1MEMCFG, 15, 3, 0x2 ); // Burst 4
set_nbit( P1MEMCFG2, 0, 4, 0x5 );
set_2bit( P1MEMCFG2, 6, 0x1 ); // 32 bit
set_nbit( P1MEMCFG2, 8, 3, 0x3 ); // Mobile DDR SDRAM
set_2bit( P1MEMCFG2, 11, 0x1 );
set_one( P1_chip_0_cfg, 16 ); // Bank-Row-Column organization
// memory init
set_val( P1DIRECTCMD, 0xc0000 ); // NOP
set_val( P1DIRECTCMD, 0x000 ); // precharge
set_val( P1DIRECTCMD, 0x40000 ); // auto refresh
set_val( P1DIRECTCMD, 0x40000 ); // auto refresh
set_val( P1DIRECTCMD, 0xa0000 ); // EMRS
set_val( P1DIRECTCMD, 0x80032 ); // MRS
set_val( MEM_SYS_CFG, 0x0 );
// set dramc to "go" status
set_val( P1MEMCCMD, 0x000 );
// wait ready
while( !(( read_val( P1MEMSTAT ) & 0x3 ) == 0x1));
return 0;
}
=====================================================================
nand.c源码:
#define MEM_SYS_CFG (*((volatile unsigned long *)0x7E00F120))
#define NFCONF (*((volatile unsigned long *)0x70200000))
#define NFCONT (*((volatile unsigned long *)0x70200004))
#define NFCMMD (*((volatile unsigned long *)0x70200008))
#define NFADDR (*((volatile unsigned long *)0x7020000C))
#define NFDATA (*((volatile unsigned char *)0x70200010))
#define NFSTAT (*((volatile unsigned long *)0x70200028))
void nand_select(void)
{
NFCONT &= ~(1<<1);
}
void nand_deselect(void)
{
NFCONT |= (1<<1);
}
void nand_cmd(unsigned char cmd)
{
NFCMMD = cmd;
}
void nand_addr(unsigned char addr)
{
NFADDR = addr;
}
unsigned char nand_get_data(void)
{
return NFDATA;
}
void nand_send_data(unsigned char data)
{
NFDATA = data;
}
void wait_ready(void)
{
while ((NFSTAT & 0x1) == 0);
}
void nand_reset(void)
{
// 选中
nand_select();
// 发出0xff命令
nand_cmd(0xff);
// 等待就绪
wait_ready();
// 取消选中
nand_deselect();
}
void nand_init(void)
{
#if 1
#define TACLS 7
#define TWRPH0 7
#define TWRPH1 7
NFCONF &= ~((7<<4) | (7<<8) | (7<<12) | (1<<30));
NFCONF |= ((TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4));
// 使能nand flash controller
NFCONT |= 1;
NFCONT &= ~(1<<16);
nand_reset();
#else
// 让xm0csn2用作nand flash cs0 片选引脚
MEM_SYS_CFG &= ~(1<<1);
// 设置时间参数
#define TACLS 0
#define TWRPH0 1
#define TWRPH1 0
NFCONF &= ~((1<<30) | (7<<12) | (7<<8) | (7<<4));
NFCONF |= ((TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4));
// 使能nand flash controller
NFCONT |= 1;
NFCONT &= ~(1<<16); // 森止soft lock
nand_reset();
#endif
}
void nand_send_addr(unsigned int addr)
{
#if 0
unsigned int page = addr / 2048;
// 这两个地址表示从页内哪里开始
nand_addr(addr & 0xff);
nand_addr((addr >> 8) & 0xff);
// 下面三个地址表示哪一页
nand_addr(page & 0xff);
nand_addr((page >> 8) & 0xff);
nand_addr((page >> 16) & 0xff);
#elif 0
nand_addr(addr & 0xff); // a0~a7
nand_addr((addr >> 8) & 0x7); // 程序的角度: a8~a10
nand_addr((addr >> 11) & 0xff); // 程序的角度: a11~a18
nand_addr((addr >> 19) & 0xff); // 程序的角度: a19~a26
nand_addr((addr >> 27) & 0xff); // 程序的角度: a27~
#elif 1
nand_addr(addr & 0xff); // a0~a7
nand_addr((addr >> 8) & 0x7); // 程序的角度: a8~a11
nand_addr((addr >> 12) & 0xff); // 程序的角度: a12~a19
nand_addr((addr >> 20) & 0xff); // 程序的角度: a20~a27
nand_addr((addr >> 28) & 0x01); // 程序的角度: a28~
#endif
}
int nand_read(unsigned int nand_start, unsigned int ddr_start, unsigned int len)
{
unsigned int addr = nand_start;
int i = nand_start % 4096;
int count = 0;
unsigned char *dest = (unsigned char *)ddr_start;
// 选中芯片
nand_select();
while (count < len)
{
// 发出命令0x00
nand_cmd(0x00);
// 发出地址
nand_send_addr(addr);
// 发出命令0x30
nand_cmd(0x30);
// 等待就绪
wait_ready();
// 读数据
for (; i < 4096 && count < len; i++)
{
dest[count++] = nand_get_data();
addr++;
}
i = 0;
}
// 取消片选
nand_deselect();
return 0;
}
int nand_erase_block(unsigned long addr)
{
int page = addr / 4096;
nand_select();
nand_cmd(0x60);
nand_addr(page & 0xff);
nand_addr((page >> 8) & 0xff);
nand_addr((page >> 16) & 0xff);
nand_cmd(0xd0);
wait_ready();
nand_deselect();
return 0;
}
int nand_write(unsigned int nand_start, unsigned char * buf, unsigned int len)
{
unsigned long count = 0;
unsigned long addr = nand_start;
int i = nand_start % 4096;
nand_select();
while (count < len)
{
nand_cmd(0x80);
nand_send_addr(addr);
for (; i < 4096 && count < len; i++)
{
nand_send_data(buf[count++]);
addr++;
}
nand_cmd(0x10);
wait_ready();
i = 0;
}
nand_deselect();
return 0;
}
int copykernel2ddr(unsigned int nand_start, unsigned int ddr_start, unsigned int len)
{
int ret;
// 初始化nand flash controller
nand_init();
// 读nand flash
ret = nand_read(nand_start, ddr_start, len);
return ret;
}
=====================================================================
params.c源码:
#include "setup.h"
static struct tag *params;
static void setup_start_tag (void)
{
params = (struct tag *)0x50000100;
params->hdr.tag = ATAG_CORE;
params->hdr.size = tag_size (tag_core);
params->u.core.flags = 0;
params->u.core.pagesize = 0;
params->u.core.rootdev = 0;
params = tag_next (params);
}
static void setup_memory_tags (void)
{
params->hdr.tag = ATAG_MEM;
params->hdr.size = tag_size (tag_mem32);
params->u.mem.start = 0x50000000;
params->u.mem.size = 256*1024*1024;
params = tag_next (params);
}
char * strcpy(char * dest,const char *src)
{
char *tmp = dest;
while ((*dest++ = *src++) != '\0')
// nothing ;
return tmp;
}
int strlen(const char * s)
{
const char *sc;
for (sc = s; *sc != '\0'; ++sc)
// nothing ;
return sc - s;
}
static void setup_commandline_tag (void)
{
char *commandline = "noinitrd root=/dev/mtdblock2 init=/linuxrc console=ttySAC0,115200";
params->hdr.tag = ATAG_CMDLINE;
params->hdr.size = (sizeof (struct tag_header) + strlen (commandline) + 1 + 3) >> 2;
strcpy (params->u.cmdline.cmdline, commandline);
params = tag_next (params);
}
static void setup_end_tag (void)
{
params->hdr.tag = ATAG_NONE;
params->hdr.size = 0;
}
void set_params(void)
{
setup_start_tag();
setup_memory_tags();
setup_commandline_tag();
setup_end_tag();
}
=====================================================================
uart.c源码:
#include "s3c6410_regs.h"
//#define ENABLE_FIFO
void init_uart(void)
{
GPACON &= ~0xff;
GPACON |= 0x22;
// ULCON0
ULCON0 = 0x3; // 数据位:8, 无较验, 停止位: 1, 8n1
UCON0 = 0x5 | (1<<9); // 使能UART发送、接收, tx interrupt request type = level
#ifdef ENABLE_FIFO
UFCON0 = 0x07 | (1<<6); // FIFO enable, tx fifo trigger level = 16 bytes
#else
UFCON0 = 0x00; // FIFO disable
#endif
UMCON0 = 0;
// 波特率
// DIV_VAL = (PCLK / (bps x 16 ) ) - 1
// bps = 57600
// DIV_VAL = (66500000 / (115200 x 16 ) ) - 1
// = 35.08
UBRDIV0 = 35;
// x/16 = 0.08
// x = 1
UDIVSLOT0 = 0x1;
}
unsigned char getc(void)
{
#ifdef ENABLE_FIFO
while ((UFSTAT0 & (1<<6)) == 0 && (UFSTAT0 & 0x3f) == 0);
#else
while ((UTRSTAT0 & (1<<0)) == 0);
#endif
return URXH0;
}
=====================================================================
自己写bootloader启动内核,QT文件系统:
测试:把内核源码放到ubuntu先解压:
tar xzf linux-3.0.1-2012-09-23.tar.gz
cd linux-3.0.1-2012-09-23/
make uImage
会在arch/arm/boot/目录下生成uImage文件
把开发板设为SD卡启动,从SD卡启动后按空格键运行SD卡里的u-boot来烧写文件:
tftp 52000000 boot.bin
nand erase 0 200000
nand write 52000000 0 200000
tftp uImage 52000000
nand erase 200000 500000
nand write 52000000 200000 500000
断电把开发板设为nand flash启动,上电等uboot从nand flash中拷贝内核到DDR中再跳到DDR中运行即可看到内核启动信息,要提前用SD卡把QT文件系统烧写到nand flash中,内核才能挂载文件系统成功。
上一篇:OK6410启动自动挂载nfs文件系统
下一篇:OK6410裸机之LCD调色板
推荐阅读最新更新时间:2024-03-16 16:15