如何在uboot中添加驱动程序

如何在uboot中添加驱动程序,第1张

Author:杨正date:2016.9.21

目的

在u-boot中添加驱动程序。

详派肆细举例介绍

在uboot中 *** 作寄存器,实现对gpio及外围设备的控制有两种方法,一种是直接在arch/arm/lib/board.c中添加对寄存器的 *** 作代码,如:

#define muxctrl_reg50x200f0014#define GPIO6_DIR 0x201a0400#define GPIO6_1_DATA0x201a0008 #define GPIO6_1 (1 <<1)#define readl(addr) (*(volatile unsigned int*)(addr))#define writel(val, addr) ((*(volatile unsigned int *) (addr)) = (val)) int clear_irled(void){unsigned int reg_valreg_val = writel(0, muxctrl_reg5)// set gpio modereg_val = readl(GPIO6_DIR) reg_val |= GPIO6_1 writel(reg_val, GPIO6_DIR)reg_val = readl(GPIO6_1_DATA) reg_val &= ~GPIO6_1 writel(reg_val, GPIO6_1_DATA)return 0}void start_armboot (void){init_fnc_t **init_fnc_ptr char *s#ifdef CONFIG_HAS_SLAVEchar *e#endif#if defined(CONFIG_VFD) || defined(CONFIG_LCD)unsigned long addr#endif #ifdef CONFIG_HI3516A // defined in the include/configs/hi3516a.hclear_irled() // clear ir led, add by yangzheng 2016.9.21#endif

来尘纤轿自CODE的代码片

snippet_file_0.txt

另一种方法:

1、在driver/下新建hi_gpio目录,如:

[yangzheng@centos6 hi_gpio]$ ls

hi_gpio.c Makefile

hi_gpio.c内容如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

[yangzheng@centos6 hi_gpio]$ cat hi_gpio.c/********************************************************************************** Copyright: (C) 2016 Yang Zheng<竖轿[email protected]> * All rights reserved.** Filename: hi_gpio.c*Description: This file* *Version: 1.0.0(09/21/2016~)* Author: Yang Zheng [email protected]>* ChangeLog: 1, Release initial version on "09/21/2016 05:41:41 PM"* ********************************************************************************/#include<common.h>#define readl(addr) (*(volatile unsigned int *) (addr))#define writel(val, addr) (*(volatile unsigned int *) (addr) = (val)) #define muxctrl_reg5 0x200f0014#define GPIO6_DIR 0x201a0400#define GPIO6_1_DATA0x201a0008#define GPIO6_1 1 <<1#define REG_SET 1#define REG_CLR 0 #ifdef DEBUG#define DPRINTF(args...) printf(args)#else#define DPRINTF(args...)#endif int clear_irled(void){unsigned int reg_valreg_val = writel(REG_CLR, muxctrl_reg5)// set gpio modereg_val = readl(GPIO6_DIR) reg_val |= GPIO6_1 writel(reg_val, GPIO6_DIR)writel(REG_CLR, GPIO6_1_DATA) DPRINTF("clear ir led...\n")return 0}

来自CODE的代码片

snippet_file_0.txt

Makefile如下(可以拷贝driver目录下的各模块模板):

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

[yangzheng@centos6 hi_gpio]$ cat Makefile## Copyright 2000-2008# Wolfgang Denk, DENX Software Engineering, [email protected].## See file CREDITS for list of people who contributed to this# project.## This program is free softwareyou can redistribute it and/or# modify it under the terms of the GNU General Public License as# published by the Free Software Foundationeither version 2 of# the License, or (at your option) any later version.## This program is distributed in the hope that it will be useful,# but WITHOUT ANY WARRANTYwithout even the implied warranty of# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the# GNU General Public License for more details.## You should have received a copy of the GNU General Public License# along with this programif not, write to the Free Software# Foundation, Inc., 59 Temple Place, Suite 330, Boston,# MA 02111-1307 USA# include $(TOPDIR)/config.mk LIB := $(obj)libhi_gpio.a COBJS-$(CONFIG_HI3516A_GPIO)+= hi_gpio.o COBJS := $(COBJS-y)SRCS:= $(COBJS:.o=.c)OBJS:= $(addprefix $(obj),$(COBJS)) all:$(LIB) $(LIB): $(obj).depend $(OBJS)$(AR) $(ARFLAGS) $@ $(OBJS) ######################################################################### # defines $(obj).depend targetinclude $(SRCTREE)/rules.mk sinclude $(obj).depend ########################################################################

来自CODE的代码片

snippet_file_0.txt

2、在顶层Makefile添加如下代码:

LIBS += drivers/hi_gpio/libhi_gpio.a

3、在include/configs/hi3516a.h中添加如下代码:

#define CONFIG_HI3516A_GPIO

在include下增加hi_gpio.h文件,内容如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

[yangzheng@centos6 u-boot-2010.06]$ cat include/hi_gpio.h/******************************************************************************** * Copyright: (C) 2016 Yang [email protected]>* All rights reserved. * * Filename: hi_gpio.h *Description: This head file is control hisi gpio * *Version: 1.0.0(09/21/2016~) * Author: Yang Zheng [email protected]>* ChangeLog: 1, Release initial version on "09/21/2016 06:09:49 PM" * ********************************************************************************/#ifndef __HI_GPIO_H__#define __HI_GPIO_H__ extern int clear_irled(void)#endif

来自CODE的代码片

snippet_file_0.txt

4、在arch/arm/lib/board.c 里面调用即可,如:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

[yangzheng@centos6 u-boot-2010.06]$ vim arch/arm/lib/board.c void start_armboot (void){init_fnc_t **init_fnc_ptr char *s#ifdef CONFIG_HAS_SLAVEchar *e#endif#if defined(CONFIG_VFD) || defined(CONFIG_LCD)unsigned long addr#endif #ifdef CONFIG_HI3516A_GPIO clear_irled() // clear ir led, add by yangzheng 2016.9.21#endif……

来自CODE的代码片

snippet_file_0.txt

重新编译即可,调试uboot的方法:

如果设备有网口,可用tftp服务下载:

sf probe 0

mw.b 82000000 ff 0x80000

tftp 82000000 u-boot.bin

Go 82000000

如果没有网口,可用串口下载:

sf probe 0

mw.b 82000000 ff 0x80000

loady 82000000 u-boot.bin

go 82000000

1. 首先,介绍以下有关Uboot的命令定义。

每个命令都是通过U_BOOT_CMD宏来定义的。这个宏定义了一个相关的结构体,文件是uboot/include/command.h,结构体为cmd_tbl_s。

具体的命令定义为:

#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \

cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage, help}

U_BOOT_CMD(name,maxargs,repeatable,command,"usage","help")

name: is the name of the commad. THIS IS NOT a string.

maxargs: the maximumn numbers of arguments this function takes

command: Function pointer (*cmd)(struct cmd_tbl_s *, int, int, char *[])

usage: Short description. This is a string

help:long description. This is a string

每一个 U-Boot 命令有一个结构体来描述。结构体包含的成员变量:命令名称、最大参,数个数、重复数、命令执行函数、用法、帮助。

而相关命令的具体执行在uboot/common/cmd_xxxx.c文件中实现的。

接着,以我自己添加的MYTEST命令为桥碰例子,讲述添加命令的过程。

1)在对应的开发板配置文件中,添加相应命令的宏定义。如:在uboot/include/configs/mx25_3stack.h文件中,添加#define CONFIG_CMD_MYTEST。

当然,也可以在uboot/include/config_cmd_default.h文件中,添加该命令的宏定义。

2)在uboot/common/目录下,建立相应的命令执行文件,如cmd_mytest.c,注意命名的规范,必须是cmd_xxx.c才行。

里面的内容也是又格式要求的,如函数的格式,必须汪轮指定参数困消信的;还有相应结尾部分的U_BOOT_CMD定义部分,使不能缺省的。如果命令不需要跟参数,则把maxargs设置为1即可了。

在U_BOOT_CMD中指明的命令执行函数,在该函数中,就是我们要设计的命令 *** 作内容。也就是说,这部分完成的我们定制的命令的功能的。还有,要在uboot/comman/Makefile文件中,加入生成相应的.o文件才可以的。

3)重新编译uboot文件,会在uboot/common/中,生成相应的.o文件。将生成的uboot下载到开发板后,通过终端可以看到我们加入的命令。在终端中输入问号或者help命令即可。执行该命令,只学要输入命令的名字,在回车就可以运行了。

通过在uboot中加入命令,可以完成我们的一些特定的 *** 作,实现调试和测试目的等。

本人用的android平台用的bootloader用的是uboot,貌似大多数手持设备平台都不用这个,因为功能过于强大用不上,反而显得太复杂了。不知道这个平台开发者是怎么想的。既然用了那就来分析一下,顺便修改一下其中的几个小问题,以符合我们的要求。

uboot等同于其他所有的bootloader程序,从根本上讲是一个稍复杂的裸机程序,是最底层的东西,要分析裸机程序我们要从它的连接文件开始。连 接文件(.lds文件)定义了程序编译之后整个连接过程,这样我们就可以找到这个程序的第一句汇编代码,进而来下一步分析。uboot的链接文件代码在 android\bootable\bootloader\uboot-imx\u-boot.lds

[cpp] view plaincopy

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") //文件输出格式

OUTPUT_ARCH(arm)

ENTRY(_start) //首地址标示符

SECTIONS

{

. = 0x00000000 //其实地址0

. = ALIGN(4) //4字节对齐

.text ://代码段

{

board/freescale/mx6q_sabresd/flash_header.o (.text.flasheader) //第一个文件是board/freescale/mx6q_sabresd/flash_header.o

cpu/arm_cortexa8/start.o //第二个cpu/arm_cortexa8/start.o

board/freescale/mx6q_sabresd/libmx6q_sabresd.a (.text)

lib_arm/libarm.a (.text)

net/libnet.a (.text)

drivers/mtd/libmtd.a (.text)

drivers/mmc/libmmc.a (.text)

. = DEFINED(env_offset) ? env_offset : .

common/env_embedded.o(.text)

*(.text) //剩余的所有代码

}

. = ALIGN(4)

.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } //readonly data 段

. = ALIGN(4)

.data : { *(.data) } //所有的readonly data

. = ALIGN(4)

.got : { *(.got) }

. = .

__u_boot_cmd_start = . //u_boot_cmd段,里面是所有uboot命令的一个列表

.u_boot_cmd : { *(.u_boot_cmd) }

__u_boot_cmd_end = .

. = ALIGN(4)

_end_of_copy = .

__bss_start = . //bss段 就是内存数据段

.bss : { *(.bss) }

_end = .

}

从上面的代码可以看出我们编译生成的二进制应用程序组成是:代码段->rodata段->uboot命令列表->bss段。我们启动这个应用程序时候是从,0地址开始的,因此我瞎衫们来看

board/freescale/mx6q_sabresd/flash_header.s这个文件。

这个文件中除了分配内存和宏定义的伪汇编指令以外,真正执行的命令有一条

[cpp] view plaincopy

.section ".text.flasheader", "x"

b _start

.orgCONFIG_FLASH_HEADER_OFFSET

也就是说,这个文件一执行就直接跳歼神扒到_start 位置处。_start 在android\bootable\bootloader\uboot-imx\cpu\arm_cortexa8\ start.S中,因此我们来看这个文件代码

[cpp] view plaincopy

.globl _start

_start: b reset

这里直接跳转的氏昌reset中接下来看

[csharp] view plaincopy

reset:

/*

* set the cpu to SVC32 modecpu设置成32位管理模式

*/

mrs r0, cpsr

bic r0, r0, #0x1f

orr r0, r0, #0xd3

msr cpsr,r0

#if (CONFIG_OMAP34XX) //因为我们的cpu不是ompa的 所以这段不会编译

.............................

#endif

/* the mask ROM code should have PLL and others stable */

#ifndef CONFIG_SKIP_LOWLEVEL_INIT

bl cpu_init_crit

#endif

这里接下来执行cpu_init_crit

[csharp] view plaincopy

/*************************************************************************

*

* CPU_init_critical registers

*

* setup important registers

* setup memory timing

*

*************************************************************************/

cpu_init_crit:

/*

* Invalidate L1 I/D

*/

mov r0, #0 @ set up for MCR

mcr p15, 0, r0, c8, c7, 0 @ invalidate TLBs

mcr p15, 0, r0, c7, c5, 0 @ invalidate icache

/*

* disable MMU stuff and caches //关闭mmu

*/

mrc p15, 0, r0, c1, c0, 0

bic r0, r0, #0x00002000 @ clear bits 13 (--V-)

bic r0, r0, #0x00000007 @ clear bits 2:0 (-CAM)

orr r0, r0, #0x00000002 @ set bit 1 (--A-) Align

orr r0, r0, #0x00000800 @ set bit 12 (Z---) BTB

mcr p15, 0, r0, c1, c0, 0

/*

* Jump to board specific initialization...

* The Mask ROM will have already initialized

* basic memory. Go here to bump up clock rate and handle

* wake up conditions.

*/

mov ip, lr @ persevere link reg across call

bl lowlevel_init @ go setup pll,mux,memory//执行lowlevel_init这个函数代码在

@\bootloader\uboot-imx\board\freescale\mx6q_sabresd\lowlevel_init.S中

@主要对时钟,外部ram,rom等进行了初始化代码不贴了。

mov lr, ip @ restore link

mov pc, lr @ back to my caller

初始化完成后,接下来执行

[csharp] view plaincopy

#ifndef CONFIG_SKIP_RELOCATE_UBOOT

relocate: @ relocate U-Boot to RAM将uboot重新定位到内存中

adr r0, _start @ r0 <- current position of code

ldr r1, _TEXT_BASE @ test if we run from flash or RAM

cmp r0, r1 @ don't reloc during debug测试当前代码是否已经在内存中

beq stack_setup @如果在的话就直接跳转到stack_setup

ldr r2, _armboot_start @如果不在的话,加载_armboot_start地址到r2中。_armboot_start是uboot执行的主体c函数。

ldr r3, _bss_start

sub r2, r3, r2 @ r2 <- size of armboot计算bss_start-armboot_start 保存到R2中,也就是uboot的总大小

add r2, r0, r2 @ r2 <- source end address 计算出uboot代码和rodata地址

copy_loop: @ copy 32 bytes at a time //开始拷贝

ldmia r0!, {r3 - r10} @ copy from source address [r0]

stmia r1!, {r3 - r10} @ copy to target address [r1]

cmp r0, r2 @ until source end addreee [r2]

ble copy_loop

#endif /* CONFIG_SKIP_RELOCATE_UBOOT */


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/tougao/12151412.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-21
下一篇 2023-05-21

发表评论

登录后才能评论

评论列表(0条)

保存