自己写bootloader之OK6410

发布者:legend9最新更新时间:2018-10-11 来源: eefocus关键字:bootloader  OK6410 手机看文章 扫描二维码
随时随地手机看文章

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中,内核才能挂载文件系统成功。


关键字:bootloader  OK6410 引用地址:自己写bootloader之OK6410

上一篇:OK6410启动自动挂载nfs文件系统
下一篇:OK6410裸机之LCD调色板

推荐阅读最新更新时间:2024-03-16 16:15

第30章 STM32F429的系统bootloader之串口IAP固件升级
30.1 初学者重要提示 学习本章节前,务必优先学习第28章。 本章用到的相关软件和文档下载:http://www.armbbs.cn/forum.php?mod=viewthread&tid=96573 。 本章节的串口IAP下载软件使用STM32CubeProg,此软件实现了之前的DfuSe,STLINK小软件和Flashloader三合一,并且支持外部EEPROM,NOR Flash,SPI Flash,NAND Flash等烧写,也支持OTA编程。 使用系统bootloader做串口IAP升级时,MicroUSB接口不要接线到电脑端,因为这会导致系统bootloader工作在USB DFU模式,无法再使用串口I
[单片机]
第30章 STM32F429的系统<font color='red'>bootloader</font>之串口IAP固件升级
mc9s08dz60添加BootLoader实现CANboot下载更新功能
为了以后项目升级方便的需要,在原始程序添加CanBoot下载功能; 1、 把Bootloader安排在高地址区间 (比如0xEE00~0xFFAF),然后固化NVC寄存器的值,将这块Flash区域保护起来; 2、中断向量的搬移,将原来0xFFC0所对应的中断向量搬移到0xEDC0; Bootloader的代码无非就是启动、查找用户程序入口,跳转至用户程序,从用户程序跳转至bootloader,与上位机通信(UART或者CAN),擦除Flash,写入Flash等功能; 具体操作就是修改两部分; 1、修改Project.prm文件,重新划分分区。我划分的分区如下所示: SEGMENTS /* Here all RAM/RO
[单片机]
基于AVR-BootLoader,通过霜蝉远程串口可实现单片机的远程升级
最近一直利用业余时间写自己的“基于AVR-BootLoader”,启发是由于一次在ourAVR论坛看到了绍子阳的bootloader,联想到公司在用AVR MCU,但每次升级程序都要花费很大的力气车马劳顿的跑到工程现场,而且很多机器还安装在国外,为了升级一次程序发费了很多的人力物力财力,加上公司的机器目前大部分都配有远程监控系统,所以本人决定写一个具有自有产权的“AVR-BootLoader”。 特别说明:本“AVR-BootLoad”软件代码属上海霜蝉版权所有,在此贡献发布,仅限于个人免费使用不得用于商业用途,本人也不保证代码的严谨性,如在升级中出现任何问题与本人无关,本人已测试过Atmega64A与Atmega12
[单片机]
基于AVR-<font color='red'>BootLoader</font>,通过霜蝉远程串口可实现单片机的远程升级
一种新颖Bootloader设计方案
本文基于Microchip公司的MPLAB软件开发环境设计了一种新颖的 Bootloader ,并配套编写了PC机端上位机界面程序。其特点是控制灵活,使用便利,系统升级安全可靠。   1 Bootloader的实现   1.1 Bootloader的操作模式   Bootloader在单片机上电/复位后、用户程序之前先运行,运行后判断当前是否需要进入升级状态。如果不需要升级,就直接运行原有的程序;如果需要升级,首先擦除旧的程序,然后从串口接收用户程序,同时写入Flash中。Bootloader有2种操作模式:   ①启动加载模式,也称为“内核启动”模式。即Bootloader从目标机上的某个固态存储设备上将操作系统加载
[单片机]
一种新颖<font color='red'>Bootloader</font>设计方案
OK6410之USB设备驱动程序
usb.c源码: // 参考drivers/hid/usbhid/usbmouse.c #include linux/kernel.h #include linux/slab.h #include linux/module.h #include linux/init.h #include linux/usb/input.h #include linux/hid.h #include linux/input.h static struct input_dev *mk_dev; static int len; static char *buf; static dma_addr_t buf_phys; static str
[单片机]
ATMEL系列MCU在线升级bootloader固件源码及操作过程
前几天出差,无意间问了大家是否需要bootloader实现在线升级,需要的还是比较多,在这里我就把我实现过程与大家分享,并我的bootloader固件给大家参考。我在mage和xmage上都实现过,不过我使用的RS485,所以固件里面也是RS485的,大家使用RS232的话,把RS485的控制去掉就可以了,RS232实现起来比RS485简单,因为RS232是全双工的。 我开发使用的环境是Atmel Studio 6.2,这个看大家习惯,环境主要就是实现可执行文件。bootloader固件都是C语言 实现,相信大家都能看明白,这里就直接上传bootloader固件源码。bootloader固件是需要仿真器等设备下载到设备中的。
[单片机]
ATMEL系列MCU在线升级<font color='red'>bootloader</font>固件源码及操作过程
OK6410开发板裸机DS18B20驱动
相信玩过51的童鞋应该都玩过DS18B20吧,虽然用在ARM11上面,但是操作还是一样,多了一点就是读写IO前需要切换IO方向,其实51在读取之前需要切换到高电平的,这个一般由编译器完成的, /************************************************************************************************************* * 文件名: ds18b20.c * 功能: S3C6410 DS18B20驱动 * 作者: cp1300@139.com * 创建时间: 2012年9月17日22:45 * 最后修改时间:
[单片机]
基于S3C44B0X的U-Boot分析与移植
1.引言 嵌入式系统一般指非PC系统,它包括硬件和软件两部分。硬件包括处理器/微处理器、存储器及外设器件和I/O端口等。软件部分包括Bootloader、操作系统(OS)和应用程序。嵌入式系统的硬件和软件都必须高效率地设计、量体裁衣、去除冗余,这样才能在具体应用中实现更高的处理性能。其中,Bootloader是基于特定硬件平台来实现的,负责硬件的初始化、嵌入式系统的引导加载等工作,是嵌入式系统开发中的一个重要环节。嵌入式开发的硬件平台是根据应用需要定制的,因此不存在一个通用的Bootloader。U-Boot是一个支持多种CPU体系结构的 Bootloader。本文就是针对在自制开发板上实现U-Boot的移植。 2.U-Boo
[单片机]
基于S3C44B0X的U-Boot分析与移植
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved