android uboot boot 区别,uboot fastboot原理

66b52468c121889b900d4956032f1009.png

8种机械键盘轴体对比

本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选?

本文介绍了fastboot协议,在uboot中如何配置支持fastboot,uboot中fastboot的实现流程以及fastboot命令如何使用。

fastboot简介

1、fastboot协议是一种通过USB或以太网与引导加载程序通信的机制。 它的设计非常简单,可以在各种设备和运行Linux,macOS或Windows的主机上使用。主要是PC机通过fastboot协议与bootloader通信。

我们可以理解在uboot中运行fastboot的为客户端,在PC端(ubuntu)运行fastboot的为服务器端,两者之间的通信走fastboot协议。

e4a287a94f48aa4fcd51f5adadba14ef.png

2、fastboot协议最基本的要求:2个bulk端点(BULK IN/OUT),可以通过USB枚举信息看到详细的信息:查看usb设备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

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69[email protected]:~ lsusb -d 0525:a4a5 -v

Bus 001 Device 006: ID 0525:a4a5 Netchip Technology, Inc. Pocketbook Pro 903

Device Descriptor:

bLength 18

bDescriptorType 1

bcdUSB 2.00

bDeviceClass 0 (Defined at Interface level)

bDeviceSubClass 0

bDeviceProtocol 0

bMaxPacketSize0 64

idVendor 0x0525 Netchip Technology, Inc.

idProduct 0xa4a5 Pocketbook Pro 903

bcdDevice 2.21

iManufacturer 1 FSL

iProduct 2 USB download gadget

iSerial 3 0d123198538fcadc

bNumConfigurations 1

Configuration Descriptor:

bLength 9

bDescriptorType 2

wTotalLength 32

bNumInterfaces 1

bConfigurationValue 1

iConfiguration 2 USB download gadget

bmAttributes 0xc0

Self Powered

MaxPower 2mA

Interface Descriptor:

bLength 9

bDescriptorType 4

bInterfaceNumber 0

bAlternateSetting 0

bNumEndpoints 2

bInterfaceClass 255 Vendor Specific Class

bInterfaceSubClass 66

bInterfaceProtocol 3

iInterface 4 Android Fastboot

Endpoint Descriptor:

bLength 7

bDescriptorType 5

bEndpointAddress 0x81 EP 1 IN

bmAttributes 2

Transfer Type Bulk

Synch Type None

Usage Type Data

wMaxPacketSize 0x0200 1x 512 bytes

bInterval 0

Endpoint Descriptor:

bLength 7

bDescriptorType 5

bEndpointAddress 0x02 EP 2 OUT

bmAttributes 2

Transfer Type Bulk

Synch Type None

Usage Type Data

wMaxPacketSize 0x0200 1x 512 bytes

bInterval 0

Device Qualifier (for other device speed):

bLength 10

bDescriptorType 6

bcdUSB 2.00

bDeviceClass 0 (Defined at Interface level)

bDeviceSubClass 0

bDeviceProtocol 0

bMaxPacketSize0 64

bNumConfigurations 1

Device Status: 0x0001

Self PoweredUSB full-speed最大包为64Bytes,high-speed最大包为512Bytes;

该协议完全由主机驱动和同步(与多通道,双向,异步ADB协议不同)。

uboot配置fastboot协议

关于fastboot相关宏的解释,可以参考cmd/fastboot/Kconfig文件。下面说一下在uboot中配置支持fastboot。

1、uboot中已实现对fastboot协议的支持:drivers/usb/gadget/fastboot.c:fastboot usb function源码;

doc/README.android-fastboot:fastboot使能说明文档;

doc/README.android-fastboot-protocol:fastboot协议说明文档;

2、uboot中要使能fastboot,需要在板级配置打开以下的宏:使能fastboot1

2

3

4CONFIG_FASTBOOT

CONFIG_USB_FUNCTION_FASTBOOT

CONFIG_CMD_FASTBOOT

CONFIG_ANDROID_BOOT_IMAGE

uboot在命令行中可以通过fastboot命令进入fastboot模式。

3、使能fastboot usb gadget

因为fastboot协议是基于usb gadget,所以需要打开或配置以下几个宏:配置usb gadget1

2

3

4CONFIG_USB_GADGET_DOWNLOAD

CONFIG_USB_GADGET_VENDOR_NUM

CONFIG_USB_GADGET_PRODUCT_NUM

CONFIG_USB_GADGET_MANUFACTURER

这里面指定的VID和PID必须要在fastboot client中能找到,如果没有,也可以用ubuntu fastboot命令的以下选项指定设备。fastboot命令指定特定的设备1

2

3

4-s specify device serial number

or path to device port

-i specify a custom USB vendor id

-p specify product name

4、配置缓冲区地址和大小

fastboot需要一块大的内存区域用来下载,需要配置CONFIG_FASTBOOT_BUF_ADDR缓冲区的起始地址以及CONFIG_FASTBOOT_BUF_SIZE大小,这两个值决定了你可以通过fastboot烧写多大的镜像。配置缓冲区地址和大小1

2CONFIG_FASTBOOT_BUF_ADDR=0x82800000

CONFIG_FASTBOOT_BUF_SIZE=0x40000000

5、配置fastboot flash命令的支持

如果想要通过fastboot flash命令烧写到flash上,必须打开CONFIG_FASTBOOT_FLASH相关的配置。比如我板子上使用的是eMMC,必须使能如下的宏:配置支持flash1

2

3CONFIG_FASTBOOT_FLASH=y

CONFIG_FASTBOOT_FLASH_MMC=y

CONFIG_FASTBOOT_FLASH_MMC_DEV=0

uboot中fastboot的实现流程

imx8 uuu基于fastboot协议进行镜像的烧写,以下的分析基于NXP提供的4.14.98_ga版本。

uboot中fastboot命令cmd/fastboot.c1

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

49

50static int (cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])

{

int controller_index;

char *usb_controller;

int ret;

if (argc < 2)

return CMD_RET_USAGE;

usb_controller = argv[1];

controller_index = simple_strtoul(usb_controller, NULL, 0);

controller_index = CONFIG_FASTBOOT_USB_DEV;

#endif

ret = board_usb_init(controller_index, USB_INIT_DEVICE);

if (ret) {

pr_err("USB init failed: %d", ret);

return CMD_RET_FAILURE;

}

g_dnl_clear_detach();

ret = g_dnl_register("usb_dnl_fastboot");

if (ret)

return ret;

if (!g_dnl_board_usb_cable_connected()) {

puts("rUSB cable not detected.n"

"Command exit.n");

ret = CMD_RET_FAILURE;

goto exit;

}

while (1) {

if (g_dnl_detach())

break;

if (ctrlc())

break;

usb_gadget_handle_interrupts(controller_index);

}

ret = CMD_RET_SUCCESS;

exit:

g_dnl_unregister();

g_dnl_clear_detach();

board_usb_cleanup(controller_index, USB_INIT_DEVICE);

return ret;

}

1、首先在uboot命令行执行fastboot x,指定第x个usb controller,使用这个controller进行通信,如果没有,默认使用CONFIG_FASTBOOT_USB_DEV指定的usb controller;

2、然后调用board_usb_init()函数做usb device controller的初始化,这个函数在board/freescale/imx8qxp_mek.c中定义。在NXP的BSP中,这个函数如果没有打开CONFIG_USB_CDNS3_GADGET的话就是个空函数。

为什么呢?我的理解是NXP使用imx uuu是使用usb0(chipidea)做为下载口,当将板子设置为SDP模式,rom code就会去初始化usb0 controller,并且配置为hid设备。因此,如果在SDP模式下,usb0 controller就无需初始化了。

3、调用g_dnl_register()函数注册一个名为usb_dnl_fastboot的usb复合设备。drivers/usb/gadget/g_dnl.c1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19* NOTICE:

* Registering via USB function name won't be necessary after rewriting

* g_dnl to support multiple USB functions.

*/

int g_dnl_register(const char *name)

{

int ret;

debug("%s: g_dnl_driver.name = %sn", __func__, name);

g_dnl_driver.name = name;

ret = usb_composite_register(&g_dnl_driver);

if (ret) {

printf("%s: failed!, error: %dn", __func__, ret);

return ret;

}

return 0;

}

在这个文件中配置了设备描述符等信息以及绑定function。

uboot中的这一套usb composite framework与kernel的一样,后续将会出一个关于这个框架的文章。可以看看我之前的文章Androidadb驱动实现原理 关于usb复合设备的注册是大同小异的。

在这个复合设备中,会依次查找绑定的usb function。在drivers/usb/gadget/f_fastboot.c中调用了DECLARE_GADGET_BIND_CALLBACK(usb_dnl_fastboot, fastboot_add);,这就将fastboot的usb function与g_dnl的usb composite device绑定起来了。drivers/usb/gadget/g_dnl.c1

2

3

4

5

6

7

8

9

10

11

12

13static int g_dnl_do_config(struct usb_configuration *c)

{

const char *s = c->cdev->driver->name;

struct g_dnl_bind_callback *callback = g_dnl_bind_callback_first();

debug("%s: configuration: 0x%p composite dev: 0x%pn",

__func__, c, c->cdev);

for (; callback != g_dnl_bind_callback_end(); callback++)

if (!strcmp(s, callback->usb_function_name))

return callback->fptr(c);

return -ENODEV;

}include/g_dnl.h1

2

3

4

5

6

7

8

9

10

11/*

* @usb_fname: unescaped USB function name

* @callback_ptr: bind callback, one per function name

*/

#define DECLARE_GADGET_BIND_CALLBACK(usb_fname, callback_ptr)

ll_entry_declare(struct g_dnl_bind_callback,

__usb_function_name_##usb_fname,

g_dnl_bind_callbacks) = {

.usb_function_name = #usb_fname,

.fptr = callback_ptr

}

4、在这之后就进入while(1)的循环,如果碰到g_dnl驱动卸载掉或者ctrl + c就跳出,否则调用usb_gadget_handle_interrupts()处理usb中断(我这里使用到的是chipidea udc)。至此,当你在uboot命令行执行fastboot 1后,接下来全部都是在处理usb ep的中断,也就是处理PC端发送过来的指令。drivers/usb/gadget/ci_udc.c1

2

3

4

5

6

7

8

9

10int usb_gadget_handle_interrupts(int index)

{

u32 value;

struct ci_udc *udc = (struct ci_udc *)controller.ctrl->hcor;

value = readl(&udc->usbsts);

if (value)

udc_irq();

return value;

}

更一般的,这里指就是usb endpoint的中断。具体的,就是处理fastbootusb function中指定的usb endpoint的中断。其中rx_handler_command()函数用来处理PC端发送过来的数据,fastboot_complete()用来处理板子发送给PC端的数据。drivers/usb/gadget/f_fastboot.c1

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

29static int fastboot_set_alt(struct usb_function *f,

unsigned interface, unsigned alt)

{

......

f_fb->out_req = fastboot_start_ep(f_fb->out_ep);

if (!f_fb->out_req) {

puts("failed to alloc out reqn");

ret = -EINVAL;

goto err;

}

f_fb->out_req->complete = rx_handler_command;

d = fb_ep_desc(gadget, &fs_ep_in, &hs_ep_in, &ss_ep_in);

ret = usb_ep_enable(f_fb->in_ep, d);

if (ret) {

puts("failed to enable in epn");

goto err;

}

f_fb->in_req = fastboot_start_ep(f_fb->in_ep);

if (!f_fb->in_req) {

puts("failed alloc req inn");

ret = -EINVAL;

goto err;

}

f_fb->in_req->complete = fastboot_complete;

......

}

fastboot支持的参数

在前面,我们说到rx_handler_command()函数用来处理PC端发送过来的数据,其中cmd_dispatch_info[]数组定义了一系列fastboot所支持的参数列表以及对应的处理函数。drivers/usb/gadget/f_fastboot.c1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26static const struct cmd_dispatch_info cmd_dispatch_info[] = {

#ifdef CONFIG_FSL_FASTBOOT

{

.cmd = "reboot-bootloader",

.cb = cb_reboot_bootloader,

},

{

.cmd = "upload",

.cb = cb_upload,

},

{

.cmd = "get_staged",

.cb = cb_upload,

},

#ifdef CONFIG_FASTBOOT_LOCK

{

.cmd = "flashing",

.cb = cb_flashing,

},

{

.cmd = "oem",

.cb = cb_flashing,

},

#endif

......

}

fastboot环境变量配置

前面我们说过,需要配置CONFIG_FASTBOOT_BUF_ADDR缓冲区的起始地址以及CONFIG_FASTBOOT_BUF_SIZE大小,这个其实是为了配置一个名为fastboot_buffer的环境变量。drivers/usb/gadget/f_fastboot.c1

2

3

4

5

6

7

8static void parameters_setup(void)

{

interface.nand_block_size = 0;

interface.transfer_buffer =

(unsigned char *)env_get_ulong("fastboot_buffer", 16, CONFIG_FASTBOOT_BUF_ADDR);

interface.transfer_buffer_size =

CONFIG_FASTBOOT_BUF_SIZE;

}

uuu进入fastboot模式

CONFIG_MFG_ENV_SETTINGS_DEFAULT中会执行fastboot 0进入fastboot下载模式,等待与PC之间的通信。include/configs/imx_env.h1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18#define CONFIG_MFG_ENV_SETTINGS_DEFAULT

"mfgtool_args=setenv bootargs console=${console},${baudrate} "

"rdinit=/linuxrc "

"clk_ignore_unused "

"