Chinaunix首页 | 论坛 | 博客
  • 博客访问: 151802
  • 博文数量: 40
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 908
  • 用 户 组: 普通用户
  • 注册时间: 2013-09-03 11:03
个人简介

学习linux

文章分类
文章存档

2014年(7)

2013年(33)

我的朋友

分类: 嵌入式

2013-09-03 21:00:07

买了一个ok6410的板子,准备开始学习嵌入式linux,同时也想把自己的学习历程记录下来,方便以后看看。有什么问题请各位朋友指教。
bootloader的作用主要就是:先将内核拷贝到RAM,再传递bootargs地址并启动内核。
我主要用的C语音,只有直接操作CPU寄存器才用了一点汇编。

1. arm11的cpu在访问I/O内存之前要先映射一下总线地址:
        mov r0, #0x70000000
        orr r0, r0, #0x13
        mcr p15, 0, r0, c15, c2, 4

2. 关闭看门狗,不然系统会不断重启的:
        ldr r0, =0x7e004000
        mov r1, #0
        str r1, [r0]

3. 其实还要关闭MMU,禁止cache等等,但上电默认如此,就省略了。

4. S3C6410的中断不再是单片机式的跳转指令,而是像X86的使用中断控制器,但首先要设置CPU使用VIC控制器,而不是发生跳转:
        mrc p15, 0, r0, c1, c0, 0
        orr r0, r0, #(1 << 24)
        mcr p15, 0, r0, c1, c0, 0

5. 在调用C程序之前设置好堆栈指针,由于这里使用了ARM的两种模式,管理模式和中断模式,所以两个堆栈指针都要设置:
        (我对ARM架构的多种模式有点不懂,也不知道为什么要用这么多种模式,希望明白的更我讲一下,谢谢)
        ( 改:我后来弄懂了,是为了用户能够系统调用内核,可以见我写的: ARM硬件基础之一  : ) )
        @切换模式来设置中断模式的sp
        mrs r0, cpsr
        bic r0, r0, #0x1f
        orr r0, r0, #0x12
        msr cpsr, r0
        @现在是中断模式
        mov sp, #0x52000000

        @再把模式切换到SVC模式
        mrs r0, cpsr
        bic r0, r0, #0x1f
        orr r0, r0, #0x13
        msr cpsr, r0
        @堆栈8KB
        mov sp, #0x2000

6. 再初始化时钟,初始化Nand Flash,初始化Uart,Led,初始化SDRAM:
        bl    system_clock_init
        bl    uart_asm_init
        bl    nand_asm_init
        bl    led_init        
        bl    ddr_init

        (后面粘上三个主要函数的代码)其实对这些寄存器的访问都可以用C语言就实现的  : (

点击(此处)折叠或打开

  1. .global system_clock_init
  2. system_clock_init:
  3.     ldr    r0, =0x7e00f000

  4.     ldr    r1, [r0, #OTHERS_OFFSET]
  5.     mov    r2, #0x40
  6.     orr    r1, r1, r2
  7.     str    r1, [r0, #OTHERS_OFFSET]

  8.     nop
  9.     nop
  10.     nop
  11.     nop
  12.     nop

  13.     ldr    r2, =0x80
  14.     orr    r1, r1, r2
  15.     str    r1, [r0, #OTHERS_OFFSET]

  16. check_syncack:
  17.     ldr    r1, [r0, #OTHERS_OFFSET]
  18.     ldr    r2, =0xf00
  19.     and    r1, r1, r2
  20.     cmp    r1, #0xf00
  21.     bne    check_syncack

  22.     mov    r1, #0xff00
  23.     orr    r1, r1, #0xff
  24.     str    r1, [r0, #APLL_LOCK_OFFSET]
  25.     str    r1, [r0, #MPLL_LOCK_OFFSET]
  26.     str    r1, [r0, #EPLL_LOCK_OFFSET]
  27. /* CLKUART(=66.5Mhz) = CLKUART_input(532/2=266Mhz) / (UART_RATIO(3)+1) */
  28. /* CLKUART(=50Mhz) = CLKUART_input(400/2=200Mhz) / (UART_RATIO(3)+1) */
  29. /* Now, When you use UART CLK SRC by EXT_UCLK1, We support 532MHz & 400MHz value */

  30.     ldr     r1, [r0, #CLK_DIV2_OFFSET]
  31.     bic    r1, r1, #0x70000
  32.     orr    r1, r1, #0x30000
  33.     str    r1, [r0, #CLK_DIV2_OFFSET]

  34.     ldr     r1, [r0, #CLK_DIV0_OFFSET]    /*Set Clock Divider*/
  35.     bic    r1, r1, #0x30000
  36.     bic    r1, r1, #0xff00
  37.     bic    r1, r1, #0xff
  38.     ldr    r2, =CLK_DIV_VAL
  39.     orr    r1, r1, r2
  40.     str    r1, [r0, #CLK_DIV0_OFFSET]

  41.     ldr    r1, =APLL_VAL
  42.     str    r1, [r0, #APLL_CON_OFFSET]
  43.     ldr    r1, =MPLL_VAL
  44.     str    r1, [r0, #MPLL_CON_OFFSET]

  45.     ldr    r1, =0x80420302            /* FOUT of EPLL is 96MHz *///    66MHz
  46.     str    r1, [r0, #EPLL_CON0_OFFSET]
  47.     ldr    r1, =0x0
  48.     str    r1, [r0, #EPLL_CON1_OFFSET]

  49.     ldr    r1, [r0, #CLK_SRC_OFFSET]    /* APLL, MPLL, EPLL select to Fout */

  50.     ldr    r2, =0x2007

  51.     orr    r1, r1, r2

  52.     str    r1, [r0, #CLK_SRC_OFFSET]

  53.     /* wait at least 200us to stablize all clock */
  54.     mov    r1, #0x10000
  55. 1:    subs    r1, r1, #1
  56.     bne    1b

  57.     /* Synchronization for VIC port */
  58.     ldr    r1, [r0, #OTHERS_OFFSET]
  59.     orr    r1, r1, #0x20
  60.     str    r1, [r0, #OTHERS_OFFSET]

  61.     mov    pc, lr

点击(此处)折叠或打开

  1. .global    nand_asm_init
  2. nand_asm_init:
  3.     ldr    r0, =ELFIN_NAND_BASE
  4.     ldr    r1, [r0, #NFCONF_OFFSET]
  5.     orr    r1, r1, #0x70
  6.     orr    r1, r1, #0x7700
  7.     str r1, [r0, #NFCONF_OFFSET]

  8.     ldr    r1, [r0, #NFCONT_OFFSET]
  9.     orr    r1, r1, #0x03
  10.     str r1, [r0, #NFCONT_OFFSET]

  11.     mov    pc, lr

点击(此处)折叠或打开

  1. #define DDR_READY while((P1MEMSTAT & 3) != 1)

  2. void ddr_time(void);
  3. void ddr_cmd(void);

  4. void ddr_init(void)
  5. {
  6.     //port
  7.     MEM_SYS_CFG &= ~(1 << 7);
  8.     P1MEMCCMD = 0x4;//config mod
  9.     //attribute
  10.     P1MEMCFG = (2 << 15) | (3 << 3) | (2);        //2 SDRAM
  11.     P1MEMCFG2 = (1 << 11) | (3 << 8) | (1 << 6) | (3);
  12.     P1_chip_0_cfg = (1<<16)|(0x50<<8)|(0xf8<<0);    
  13.     //time
  14.     ddr_time();
  15.     //cmd
  16.     ddr_cmd();

  17.     P1MEMCCMD = 0x0;//go mod
  18.     DDR_READY;
  19. }

  20. unsigned int ns_to_clk(unsigned int ns)
  21. {
  22.     return (ns / (1000000000 / 133000000)+1);
  23. }

  24. void ddr_time(void)
  25. {
  26.     P1REFRESH = ns_to_clk(7800);
  27.     P1CASLAT = 3 << 1;
  28.     P1T_DQSS = 1;
  29.     P1T_MRD = 2;
  30.     P1T_RAS = ns_to_clk(50);
  31.     P1T_RC = ns_to_clk(70);
  32.     P1T_RCD = ns_to_clk(25) | ((ns_to_clk(25) - 3) << 3);
  33.     P1T_RFC = ns_to_clk(80) | ((ns_to_clk(80) - 3) << 5);
  34.     P1T_RP = ns_to_clk(25) | ((ns_to_clk(25) - 3) << 3);
  35.     P1T_RRD = ns_to_clk(20);
  36.     P1T_WR = ns_to_clk(20);
  37.     P1T_WTR = 1;
  38.     P1T_XP = 2;
  39.     P1T_XSR = ns_to_clk(120);
  40.     P1T_ESR = ns_to_clk(120);
  41. }

  42. void ddr_cmd(void)
  43. {
  44.     P1DIRECTCMD = 2 << 18;
  45.     P1DIRECTCMD = 0 << 18;
  46.     P1DIRECTCMD = 3 << 18;
  47.     P1DIRECTCMD = 3 << 18;

  48.     P1DIRECTCMD = (2 << 18) | (2 << 16);
  49.     P1DIRECTCMD = (2 << 18) | (0 << 16) | (3 << 4) | 2;
  50. }




    

7. 上面都是在8k的stepping stone里执行的,现在准备工作完成,将代码拷贝到sdram接着上面执行,最好重新设置一下堆栈指针到SDRAM:
        (不过最初代码在nand flash里,启动是stepping stone,但是代码是如何从nand到stepping stone的呢? 不解 :(  )
        (这几天看数据手册,它说有个stepping stone的控制器,可以将代码复制到内部的RAM中执行)
        bl    copy_uboot_to_ram
        ldr    sp,=0x58000000
        @终于进入C程序了
        ldr    pc,=main

8. 到main里就什么都好搞了,首先要开中断,再亮个灯,串口输出hello world,再用LCD显示个logo,玩玩rtc校准时钟:
        enable_irq();
        led_on(0);  
        uart_test();
        lcd_test();
        rtc_timedisp();

9. 接着最重要,将linux内核zImage从nand flash拷贝到SDRAM的0x50008000 :
        copy_kernel_to_ram();

10. 再将bootargs放到0x50000100,这是内核默认了的参数位置,并跳到0x50008000运行启动内核,用一个函数即可完成:
        bootm(0x50008000,"root=/dev/nfs nfsroot=115.156.138.17:/home/nfs ip=115.156.138.18:115.156.138.17:115.156.138.110:255.255.255.0 console=ttySAC0,115200");

11. 内核启动后bootloader任务就完成了,内核会通过NFS挂载根文件系统。
        
阅读(1871) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~