资讯
HOME
资讯
正文内容
Nand更新boot Steam Deck掌机升级固态硬盘保姆级教程
发布时间 : 2024-11-24
作者 : 小编
访问数量 : 23
扫码分享至微信

Steam Deck掌机升级固态硬盘保姆级教程

如果觉得手游粗糙的画面无法直视,且又想随时随地玩3A大作,那么x86掌机就是非常不错的选择,但它们配备的固态硬盘容量最高通常只有512GB,而游戏动辄几十个GB,所以升级更高容量的硬盘就成为玩家们的必备技能。上期我们为大家带来了ROG掌机升级硬盘和更新系统的教程,今天带来的是Steam Deck掌机升级硬盘和更新系统的保姆级教程。

1 拆机更换硬盘

Steam Deck的拆机略显麻烦,如果你动手能力在线且有数码产品的拆装经验,这应该就不是问题了。首先拧下机身后面所有的螺丝,记得放好不要丢了。

后盖与机身之间有一圈的卡扣固定,用拆机的塑料撬片沿着机身中间的缝隙走上半圈即可将其分离,然后小心的将后盖取下。

Steam Deck的固态硬盘隐藏在散热风扇左侧的这块硕大的金属屏蔽罩下方,需要将其拆下。不过屏蔽罩的固定方式比较简单,只用了螺丝,而不是卡扣或者直接焊在主板上,先把屏蔽罩周围的螺丝拧下放好。

这个铝箔贴下面还藏了一颗螺丝,揭开就能看到,将其拧下收好。

取下金属屏蔽罩后,可以看到固态硬盘的位置靠近机身的下方,外面套着简易的铝箔散热套。由于这台Steam Deck已经被更换了固态硬盘,所以我们拆出来的并非是原装盘,而是一块2230规格的第三方产品,512GB的容量也确实有升级的必要。

我们用来扩容的固态硬盘型为西部数据全新推出的WD_BLACK SN770M,这是西部数据专为小型便携设备推出的消费级2230规格固态硬盘,有500GB、1TB和2TB三种容量可选。从产品命名看,可认为是大家非常熟悉的WD_BLACK SN770的“mini”版本。

虽然身形“mini”,但黑色PCB和正面的WD_BLACK风格标签,依然透着“黑盘”的强大气场。标签标识了产品型号、容量、和SN编码等信息,3.3V1.8A的电源规格可算出其最大功率为5.94W,对于移动设备的续航还算友好。

WD_BLACK SN770M采用单面设计,背面没有任何元器件,并丝印各种认证的标识,不仅发热量相对低一些,而且对于一些空间局促的设备也有着不错的兼容性。

移去正面贴纸,就可以看到WD_BLACK SN770M的全部电子元器件,布局非常紧凑,采用当下流行的DRAM-Less无缓存方案,主控芯片为闪迪20-82-10082-A1,核心存储元件为112层堆叠的闪迪Bisc5 3D TLC NAND颗粒,整体规格与WD_BLACK SN770M基本一致。

在上机之前,我们先在其他的PC平台对WD_BLACK SN770M 1TB做一个简单直观的测试。Crystal Disk Mark显示,它的顺序读写速度达到了5223.7MB/s和4994.93MB/s,均超过产品标称速度,符合中端PCIe4.0的性能,对于SteamDeck原配产品可以说较大的性能提升。

把简易的铝箔散热套套在WD_BLACK SN770M 1TB上并安装到SteamDeck中,然后把金属屏蔽罩装回并拧好所有的螺丝,最后再装上后盖拧上螺丝固定。

2 制作系统恢复盘

由于全新的固态硬盘没有系统,接下来就是将SteamDeck的SteamOS系统恢复到其中。SteamOS系统恢复包在Steam官网中的“客服”页面下载。传送门在此

下载完Steam OS系统恢复包后,再准备一个8GB以上的U盘,使用Rufus这款软件将系统释放到U盘。选择好镜像文件点击“开始”,待进度条100%就完成了系统盘的制作。需要注意的是,Rufus在恢复操作的时候会将U盘格式化,记得提前备份好里面的文件。

3 Steam OS系统恢复实战

安装好固态硬盘后就可以执行系统的恢复操作了。由于Steam Deck只有一个USB Type-C接口,如果是USB-A接口的普通U盘就需要搭配Type-C扩展坞。连接好系统恢复U盘,按住音量“减”再按电源开机,就会进入EFI系统引导界面,在Boot Manager中选择EFI USB Device,也就是我们的U盘。

接下来系统会自动引导到系统恢复界面,其实就是个带GUI的Linux系统,双击桌面上的Reimage Steam Deck。

在出现的命令行终端页面会弹出一个对话框,点击Proceed就会将新装的固态硬盘重新分区格式化,并将系统恢复其中。

命令行终端会自动进行文件拷贝等操作,完成后会弹出对话框,点击Proceed后系统就会重新启动。

重新启动后先会出现选择语言和系统的时区,这时候就可以拔掉U盘了。

然后会出现链接WiFi的SSID选择界面,选择一个已知的并输入密钥。

接下来就会出现系统恢复的进度条,然后就是稍显漫长的等待,记得一定要为Steam Deck充满电,或者插上充电器,不要被剩余时间骗了。如果进度条不动且没有下载的速度显示,就按住电源键关机,然后重新开机重复上述步骤,或者尝试将语言设置为英语,直至出现有下载速度。

进度条走完后系统会再次重启,然后会再次出现选择语言和地区,这次我们可以选择简体中文和标准时间了。

接下来会让你再次连接WiFi并输入密码。

当通过网络连接互联网检测后,点Continue。

接下来会出现Steam登录界面,输入自己的Steam账号登录。

再跳过一些系统的操作提示,就能进入Steam OS的系统主页了。

按一下Steam按钮或点一下屏幕左下角的菜单,就会出现Steam的菜单,选择“库”即可查看自己已经拥有的游戏,也可去“商店”购买新游戏。

选择一个游戏点击“安装”,然后等待即可。

升级完了硬盘,又下载了游戏,自然要体验一番。以《皇牌空战7:未知空域》和《尘埃4》为例,启动后进入游戏和载入场景都非常迅速,游戏中操作更是如行云流水,没有任何的卡顿。

以上就是Steam Deck升级固态硬盘的全部过程,按照我们的步骤来其实还是非常简单的,快来跟教程一起搞起来吧。

(8397639)

「正点原子Linux连载」第三十三章U-Boot移植(二)

1)实验平台:正点原子Linux开发板

2)摘自《正点原子 I.MX6U嵌入式Linux驱动开发指南 关注官方微信号公众号,获取更多资料:正点原子

33.2.7 网络驱动修改

1、I.MX6U-ALPHA开发板网络简介

I.MX6UL/ULL内部有个以太网MAC外设,也就是ENET,需要外接一个PHY芯片来实现网络通信功能,也就是内部MAC+外部PHY芯片的方案。大家可能听过DM9000这个网络芯片,在一些没有内部MAC的CPU中,比如三星的2440,4412等,就会采用DM9000来实现联网功能。DM9000提供了一个类似SRAM的访问接口,主控CPU通过这个接口即可与DM9000进行通信,DM9000就是一个MAC+PHY芯片。这个方案就相当于外部MAC+外部PHY,那么I.MX6U这样的内部MAC+PHY芯片与DM9000方案比有什么优势吗?那优势大了去了!首先就是通信效率和速度,一般CPU内部的MAC是带有一个专用DMA的,专门用于处理网络数据包,采用SRAM来读写DM9000的速度是压根就没法和内部MAC+外部PHY芯片的速度比。采用外部DM9000完全是无奈之举,谁让2440,4412这些芯片内部没有以太网外设呢,现在又想用有线网络,没有办法只能找个DM9000的方案。从这里也可以看出,三星的2440、4412这些芯片设计之初就不是给工业产品用的,他们是给消费类电子使用的,比如手机、平板等,手机或平板要上网,可以通过WIFI或者4G,我是没有见过哪个手机或者平板上网是要接根网线的。正点原子的I.MX6U-ALPHA开发板也可以通过WIFI或者4G上网,这个是后话了。

I.MX6UL/ULL有两个网络接口ENET1和ENET2,正点原子的I.MX6U-ALPHA开发板提供了这两个网络接口,其中ENET1和ENET2都使用LAN8720A作为PHY芯片。NXP官方的I.MX6ULL EVK开发板使用KSZ8081这颗PHY芯片,LAN8720A相比KSZ8081具有体积小、外围器件少、价格便宜等优点。直接使用KSZ8081固然可以,但是我们在实际的产品中不一定会使用KSZ8081,有时候为了降低成本会选择其他的PHY芯片,这个时候就有个问题:换了PHY芯片以后网络驱动怎么办?为此,正点原子的I.MX6U-ALPHA开发板将ENET1和ENET2的PHY换为了LAN8720A,这样就可以给大家讲解更换PHY芯片以后如何调整网络驱动,使网络工作正常。

I.MX6U-ALPHA开发板ENET1的网络原理图如图33.2.7.1所示:

图33.2.7.1 ENET1原理图

ENET1的网络PHY芯片为LAN8720A,通过RMII接口与I.MX6ULL相连,正点原子I.MX6U-ALPHA开发板的ENET1引脚与NXP官方的I.MX6ULL EVK开发板基本一样,唯独复位引脚不同。从图33.2.7.1可以看出,正点原子I.MX6U-ALPHA开发板的ENET1复位引脚ENET1_RST接到了I.M6ULL的SNVS_TAMPER7这个引脚上。

LAN8720A内部是有寄存器的,I.MX6ULL会读取LAN8720内部寄存器来判断当前的物理链接状态、连接速度(10M还是100M)和双工状态(半双工还是全双工)。I.MX6ULL通过MDIO接口来读取PHY芯片的内部寄存器,MDIO接口有两个引脚,ENET_MDC和ENET_MDIO, ENET_MDC提供时钟,ENET_MDIO进行数据传输。一个MIDO接口可以管理32个PHY芯片,同一个MDIO接口下的这些PHY使用不同的器件地址来做区分,MIDO接口通过不同的器件地址即可访问到相应的PHY芯片。I.MX6U-ALPHA开发板ENET1上连接的LAN8720A器件地址为0X0,所示我们要修改ENET1网络驱动的话重点就三点:

①、ENET1复位引脚初始化。

②、LAN8720A的器件ID。

③、LAN8720驱动

再来看一下ENET2的原理图,如图33.2.7.2所示:

图33.2.7.2 ENET2原理图

关于ENET2网络驱动的修改也注意一下三点:

①、ENET2的复位引脚,从图33.2.7.2可以看出,ENET2的复位引脚ENET2_RST接到了I.MX6ULL的SNVS_TAMPER8上。

②、ENET2所使用的PHY芯片器件地址,从图33.2.7.2可以看出,PHY器件地址为0X1。

③、LAN8720驱动,ENET1和ENET2都使用的LAN8720,所以驱动肯定是一样的。

2、网络PHY地址修改

首先修改uboot中的ENET1和ENET2的PHY地址和驱动,打开mx6ull_alientek_emmc.h这个文件,找到如下代码:

示例代码33.2.7.1 网络默认ID配置参数

325 #ifdef CONFIG_CMD_NET

326 #define CONFIG_CMD_PING

327 #define CONFIG_CMD_DHCP

328 #define CONFIG_CMD_MII

329 #define CONFIG_FEC_MXC

330 #define CONFIG_MII

331 #define CONFIG_FEC_ENET_DEV 1

332

333 #if( CONFIG_FEC_ENET_DEV == 0)

334 #define IMX_FEC_BASE ENET_BASE_ADDR

335 #define CONFIG_FEC_MXC_PHYADDR 0x2

336 #define CONFIG_FEC_XCV_TYPE RMII

337 #elif ( CONFIG_FEC_ENET_DEV == 1)

338 #define IMX_FEC_BASE ENET2_BASE_ADDR

339 #define CONFIG_FEC_MXC_PHYADDR 0x1

340 #define CONFIG_FEC_XCV_TYPE RMII

341 #endif

342 #define CONFIG_ETHPRIME "FEC"

343

344 #define CONFIG_PHYLIB

345 #define CONFIG_PHY_MICREL

346 #endif

第331行的宏CONFIG_FEC_ENET_DEV用于选择使用哪个网口,默认为1,也就是选择ENET2。第335行为ENET1的PHY地址,默认是0X2,第339行为ENET2的PHY地址,默认为0x1。根据前面的分析可知,正点原子的I.MX6U-ALPHA开发板ENET1的PHY地址为0X0,ENET2的PHY地址为0X1,所以需要将第335行的宏CONFIG_FEC_MXC_PHYADDR改为0x0。

第345行定了一个宏CONFIG_PHY_MICREL,此宏用于使能uboot中Micrel公司的PHY驱动,KSZ8081这颗PHY芯片就是Micrel公司生产的,不过Micrel已经被Microchip收购了。如果要使用LAN8720A,那么就得将CONFIG_PHY_MICREL改为CONFIG_PHY_SMSC,也就是使能uboot中的SMSC公司中的PHY驱动,因为LAN8720A就是SMSC公司生产的。所以示例代码33.2.7.1有三处要修改:

①、修改ENET1网络PHY的地址。

②、修改ENET2网络PHY的地址。

③、使能SMSC公司的PHY驱动。

修改后的网络PHY地址参数如下所示:

示例代码33.2.7.2 网络PHY地址配置参数

325 #ifdef CONFIG_CMD_NET

326 #define CONFIG_CMD_PING

327 #define CONFIG_CMD_DHCP

328 #define CONFIG_CMD_MII

329 #define CONFIG_FEC_MXC

330 #define CONFIG_MII

331 #define CONFIG_FEC_ENET_DEV 1

332

333 #if( CONFIG_FEC_ENET_DEV == 0)

334 #define IMX_FEC_BASE ENET_BASE_ADDR

335 #define CONFIG_FEC_MXC_PHYADDR 0x0

336 #define CONFIG_FEC_XCV_TYPE RMII

337 #elif ( CONFIG_FEC_ENET_DEV == 1)

338 #define IMX_FEC_BASE ENET2_BASE_ADDR

339 #define CONFIG_FEC_MXC_PHYADDR 0x1

340 #define CONFIG_FEC_XCV_TYPE RMII

341 #endif

342 #define CONFIG_ETHPRIME "FEC"

343

344 #define CONFIG_PHYLIB

345 #define CONFIG_PHY_SMSC

346 #endif

3、删除uboot中74LV595的驱动代码

uboot中网络PHY芯片地址修改完成以后就是网络复位引脚的驱动修改了,打开mx6ull_alientek_emmc.c,找到如下代码:

示例代码33.2.7.3 74LV595引脚

#define IOX_SDI IMX_GPIO_NR(5, 10)

#define IOX_STCP IMX_GPIO_NR(5, 7)

#define IOX_SHCP IMX_GPIO_NR(5, 11)

#define IOX_OE IMX_GPIO_NR(5, 8)

示例代码33.2.7.3中以IOX开头的宏定义是74LV595的相关GPIO,因为NXP官方I.MX6ULL EVK开发板使用74LV595来扩展IO,两个网络的复位引脚就是由74LV595来控制的。正点原子的I.MX6U-ALPHA开发板并没有使用74LV595,因此我们将示例代码33.2.6.6中的代码删除掉,替换为如下所示代码:

示例代码33.2.7.4 修改后的网络引脚

#define ENET1_RESET IMX_GPIO_NR(5, 7)

#define ENET2_RESET IMX_GPIO_NR(5, 8)

ENET1的复位引脚连接到SNVS_TAMPER7上,对应GPIO5_IO07,ENET2的复位引脚连接到SNVS_TAMPER8上,对应GPIO5_IO08。

继续在mx6ull_alientek_emmc.c中找到如下代码:

示例代码33.2.7.5 74LV595引脚配置

static iomux_v3_cfg_t const iox_pads[]={

/* IOX_SDI */

MX6_PAD_BOOT_MODE0__GPIO5_IO10 | MUX_PAD_CTRL( NO_PAD_CTRL),

/* IOX_SHCP */

MX6_PAD_BOOT_MODE1__GPIO5_IO11 | MUX_PAD_CTRL( NO_PAD_CTRL),

/* IOX_STCP */

MX6_PAD_SNVS_TAMPER7__GPIO5_IO07 | MUX_PAD_CTRL( NO_PAD_CTRL),

/* IOX_nOE */

MX6_PAD_SNVS_TAMPER8__GPIO5_IO08 | MUX_PAD_CTRL( NO_PAD_CTRL),

};

同理,示例代码33.2.7.5是74LV595的IO配置参数结构体,将其删除掉。继续在mx6ull_alientek_emmc.c中找到函数iox74lv_init,如下所示:

示例代码33.2.7.6 74LV595初始化函数

staticvoid iox74lv_init( void)

{

int i;

gpio_direction_output( IOX_OE, 0);

for( i = 7; i >= 0; i--){

gpio_direction_output( IOX_SHCP, 0);

gpio_direction_output( IOX_SDI, seq[ qn_output[ i]][ 0]);

udelay( 500);

gpio_direction_output( IOX_SHCP, 1);

udelay( 500);

}

......

/*

* shift register will be output to pins

*/

gpio_direction_output( IOX_STCP, 1);

};

void iox74lv_set( int index)

{

int i;

for( i = 7; i >= 0; i--){

gpio_direction_output( IOX_SHCP, 0);

if( i == index)

gpio_direction_output( IOX_SDI, seq[ qn_output[ i]][ 0]);

else

gpio_direction_output( IOX_SDI, seq[ qn_output[ i]][ 1]);

udelay( 500);

gpio_direction_output( IOX_SHCP, 1);

udelay( 500);

}

......

/*

* shift register will be output to pins

*/

gpio_direction_output( IOX_STCP, 1);

};

iox74lv_init函数是74LV595的初始化函数,iox74lv_set函数用于控制74LV595的IO输出电平,将这两个函数全部删除掉!

在mx6ull_alientek_emmc.c中找到board_init函数,此函数是板子初始化函数,会被board_init_r调用,board_init函数内容如下:

示例代码33.2.7.7 board_init函数

int board_init( void)

{

......

imx_iomux_v3_setup_multiple_pads( iox_pads, ARRAY_SIZE( iox_pads));

iox74lv_init();

......

return 0;

}

board_init会调用imx_iomux_v3_setup_multiple_pads和iox74lv_init这两个函数来初始化74lv595的GPIO,将这两行删除掉。至此,mx6ull_alientek_emmc.c中关于74LV595芯片的驱动代码都删除掉了,接下来就是添加I.MX6U-ALPHA开发板两个网络复位引脚了。

4、添加I.MX6U-ALPHA开发板网络复位引脚驱动

在mx6ull_alientek_emmc.c中找到如下所示代码:

示例代码33.2.7.8 默认网络IO结构体数组

640static iomux_v3_cfg_t const fec1_pads[]={

641 MX6_PAD_GPIO1_IO06__ENET1_MDIO | MUX_PAD_CTRL( MDIO_PAD_CTRL),

642 MX6_PAD_GPIO1_IO07__ENET1_MDC | MUX_PAD_CTRL( ENET_PAD_CTRL),

......

649 MX6_PAD_ENET1_RX_ER__ENET1_RX_ER | MUX_PAD_CTRL( ENET_PAD_CTRL),

650 MX6_PAD_ENET1_RX_EN__ENET1_RX_EN | MUX_PAD_CTRL( ENET_PAD_CTRL),

651};

652

653static iomux_v3_cfg_t const fec2_pads[]={

654 MX6_PAD_GPIO1_IO06__ENET2_MDIO | MUX_PAD_CTRL( MDIO_PAD_CTRL),

655 MX6_PAD_GPIO1_IO07__ENET2_MDC | MUX_PAD_CTRL( ENET_PAD_CTRL),

......

664 MX6_PAD_ENET2_RX_EN__ENET2_RX_EN | MUX_PAD_CTRL( ENET_PAD_CTRL),

665 MX6_PAD_ENET2_RX_ER__ENET2_RX_ER | MUX_PAD_CTRL( ENET_PAD_CTRL),

666};

结构体数组fec1_pads和fec2_pads是ENET1和ENET2这两个网口的IO配置参数,在这两个数组中添加两个网口的复位IO配置参数,完成以后如下所示:

示例代码33.2.7.9 添加网络复位IO后的结构体数组

640static iomux_v3_cfg_t const fec1_pads[]={

641 MX6_PAD_GPIO1_IO06__ENET1_MDIO | MUX_PAD_CTRL( MDIO_PAD_CTRL),

642 MX6_PAD_GPIO1_IO07__ENET1_MDC | MUX_PAD_CTRL( ENET_PAD_CTRL),

......

649 MX6_PAD_ENET1_RX_ER__ENET1_RX_ER | MUX_PAD_CTRL( ENET_PAD_CTRL),

650 MX6_PAD_ENET1_RX_EN__ENET1_RX_EN | MUX_PAD_CTRL( ENET_PAD_CTRL),

651 MX6_PAD_SNVS_TAMPER7__GPIO5_IO07 | MUX_PAD_CTRL( NO_PAD_CTRL),

652};

653

654static iomux_v3_cfg_t const fec2_pads[]={

655 MX6_PAD_GPIO1_IO06__ENET2_MDIO | MUX_PAD_CTRL( MDIO_PAD_CTRL),

656 MX6_PAD_GPIO1_IO07__ENET2_MDC | MUX_PAD_CTRL( ENET_PAD_CTRL),

......

665 MX6_PAD_ENET2_RX_EN__ENET2_RX_EN | MUX_PAD_CTRL( ENET_PAD_CTRL),

666 MX6_PAD_ENET2_RX_ER__ENET2_RX_ER | MUX_PAD_CTRL( ENET_PAD_CTRL),

667 MX6_PAD_SNVS_TAMPER8__GPIO5_IO08 | MUX_PAD_CTRL( NO_PAD_CTRL),

668};

示例代码33.2.7.9中,第651行和667行分别是ENET1和ENET2的复位IO配置参数。继续在文件mx6ull_alientek_emmc.c中找到函数setup_iomux_fec,此函数默认代码如下:

示例代码33.2.7.10 setup_iomux_fec函数默认代码

668staticvoid setup_iomux_fec( int fec_id)

669{

670if( fec_id == 0)

671 imx_iomux_v3_setup_multiple_pads( fec1_pads,

672 ARRAY_SIZE( fec1_pads));

673else

674 imx_iomux_v3_setup_multiple_pads( fec2_pads,

675 ARRAY_SIZE( fec2_pads));

676}

函数setup_iomux_fec就是根据fec1_pads和fec2_pads这两个网络IO配置数组来初始化I.MX6ULL的网络IO。我们需要在其中添加网络复位IO的初始化代码,并且复位一下PHY芯片,修改后的setup_iomux_fec函数如下:

示例代码33.2.7.11 修改后的setup_iomux_fec函数

668staticvoid setup_iomux_fec( int fec_id)

669{

670if( fec_id == 0)

671{

672

673 imx_iomux_v3_setup_multiple_pads( fec1_pads,

674 ARRAY_SIZE( fec1_pads));

675

676 gpio_direction_output( ENET1_RESET, 1);

677 gpio_set_value( ENET1_RESET, 0);

678 mdelay( 20);

679 gpio_set_value( ENET1_RESET, 1);

680}

681else

682{

683 imx_iomux_v3_setup_multiple_pads( fec2_pads,

684 ARRAY_SIZE( fec2_pads));

685 gpio_direction_output( ENET2_RESET, 1);

686 gpio_set_value( ENET2_RESET, 0);

687 mdelay( 20);

688 gpio_set_value( ENET2_RESET, 1);

689}

690}

示例代码33.2.7.11中第676行~679行和第685行~688行分别对应ENET1和ENET2的复位IO初始化,将这两个IO设置为输出并且硬件复位一下LAN8720A,这个硬件复位很重要!否则可能导致uboot无法识别LAN8720A。

5、修改drivers/net/phy/phy.c文件中的函数genphy_update_link

大功基本上告成,还差最后一步,uboot中的LAN8720A驱动有点问题,打开文件drivers/net/phy/phy.c,找到函数genphy_update_link,这是个通用PHY驱动函数,此函数用于更新PHY的连接状态和速度。使用LAN8720A的时候需要在此函数中添加一些代码,修改后的函数genphy_update_link如下所示:

示例代码33.2.7.12 修改后的genphy_update_link函数

221int genphy_update_link( struct phy_device * phydev)

222{

223unsignedint mii_reg;

224

225 #ifdef CONFIG_PHY_SMSC

226staticint lan8720_flag = 0;

227int bmcr_reg = 0;

228if( lan8720_flag == 0){

229 bmcr_reg = phy_read( phydev, MDIO_DEVAD_NONE, MII_BMCR);

230 phy_write( phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);

231while( phy_read( phydev, MDIO_DEVAD_NONE, MII_BMCR)& 0X8000){

232 udelay( 100);

233}

234 phy_write( phydev, MDIO_DEVAD_NONE, MII_BMCR, bmcr_reg);

235 lan8720_flag = 1;

236}

237 #endif

238

239/*

240 * Wait if the link is up, and autonegotiation is in progress

241 * (ie - we're capable and it's not done)

242 */

243 mii_reg = phy_read( phydev, MDIO_DEVAD_NONE, MII_BMSR);

......

291

292return 0;

293}

225行~237行就是新添加的代码,为条件编译代码段,只有使用SMSC公司的PHY这段代码才会执行(目前只测试了LAN8720A,SMSC公司其他的芯片还未测试)。第229行读取LAN8720A的BMCR寄存器(寄存器地址为0),此寄存器为LAN8720A的配置寄存器,这里先读取此寄存器的默认值并保存起来。230行向寄存器BMCR寄存器写入BMCR_RESET(值为0X8000),因为BMCR的bit15是软件复位控制位,因此230行就是软件复位LAN8720A,复位完成以后此位会自动清零。第231~233行等待LAN8720A软件复位完成,也就是判断BMCR的bit15位是否为1,为1的话表示还没有复位完成。第234行重新向BMCR寄存器写入以前的值,也就是229行读出的那个值。

至此网络的复位引脚驱动修改完成,重新编译uboot,然后将u-boot.bin烧写到SD卡中并启动,uboot启动信息如图33.2.7.3所示:

图33.2.7.3 uboot启动信息

从图33.2.6.4中可以看到"Net:FEC1"这一行,提示当前使用的FEC1这个网口,也就是ENET2。在uboot中使用网络之前要先设置几个环境变量,命令如下:

setenv ipaddr 192.168.1.55 //开发板IP地址

setenv ethaddr 00:04:9f:04:d2:35 //开发板网卡MAC地址

setenv gatewayip 192.168.1.1 //开发板默认网关

setenv netmask 255.255.255.0 //开发板子网掩码

setenv serverip 192.168.1.250 //服务器地址,也就是Ubuntu地址

saveenv //保存环境变量

设置好环境变量以后就可以在uboot中使用网络了,用网线将I.MX6U-ALPHA上的ENET2与电脑或者路由器连接起来,保证开发板和电脑在同一个网段内,通过ping命令来测试一下网络连接,命令如下:

ping 192.168.1.250

结果如图33.2.7.4所示:

图33.2.7.4 ping命令测试

从图33.2.7.4可以看出,有"host 192.168.1.250 is alive"这句,说明ping主机成功,说明ENET2网络工作正常。再来测试一下ENET1的网络是否正常工作,打开mx6ull_alientek_emmc.h,将CONFIG_FEC_ENET_DEV改为0,然后重新编译一下uboot并烧写到SD卡中重启。重启开发板,uboot输出信息如图33.2.7.5所示:

图33.2.7.5 uboot启动信息

从图33.2.7.5可以出,有"Net:FEC0"这一行,说明当前使用的FEC0这个网卡,也就是ENET1,同样的ping一下主机,结果如图33.2.7.5所示:

图33.2.7.6 ping命令测试

从图33.2.7.6可以看出,ping主机也成功,说明ENET1网络也工作正常,至此,I.MX6U-ALPHA开发板的两个网络都工作正常了,建议大家将ENET2设置为uboot的默认网卡!也就是将宏CONFIG_FEC_ENET_DEV设置为1。

33.2.8 其他需要修改的地方

在uboot启动信息中会有"Board: MX6ULL 14x14 EVK"这一句,也就是说板子名字为"MX6ULL 14x14 EVK",要将其改为我们所使用的板子名字,比如"MX6ULL ALIENTEK EMMC"或者"MX6ULL ALIENTEK NAND"。打开文件mx6ull_alientek_emmc.c,找到函数checkboard,将其改为如下所示内容:

示例代码33.2.8.1 修改后的checkboard函数

int checkboard( void)

{

if( is_mx6ull_9x9_evk())

puts( "Board: MX6ULL 9x9 EVK\n");

else

puts( "Board: MX6ULL ALIENTEK EMMC\n");

return 0;

}

修改完成以后重新编译uboot并烧写到SD卡中验证,uboot启动信息如图33.2.8.1所示:

图33.2.8.1 uboot启动信息

从图33.2.8.1可以看出,Board变成了"MX6ULL ALIENTEK EMMC"。至此uboot的驱动部分就修改完成了,uboot移植也完成了,uboot的最终目的就是启动Linux内核,所以需要通过启动Linux内核来判断uboot移植是否成功。在启动Linux内核之前我们先来学习两个重要的环境变量bootcmd和bootargs。

33.3 bootcmd和bootargs环境变量

uboot中有两个非常重要的环境变量bootcmd和bootargs,接下来看一下这两个环境变量。bootcmd和bootagrs是采用类似shell脚本语言编写的,里面有很多的变量引用,这些变量其实都是环境变量,有很多是NXP自己定义的。文件mx6ull_alientek_emmc.h中的宏CONFIG_EXTRA_ENV_SETTINGS保存着这些环境变量的默认值,内容如下:

示例代码33.3.1.1 宏CONFIG_EXTRA_ENV_SETTINGS默认值

113 #if defined( CONFIG_SYS_BOOT_NAND)

114 #define CONFIG_EXTRA_ENV_SETTINGS \

115 CONFIG_MFG_ENV_SETTINGS \

116"panel=TFT43AB\0" \

117"fdt_addr=0x83000000\0" \

118"fdt_high=0xffffffff\0" \

......

126"bootz ${loadaddr} - ${fdt_addr}\0"

127

128 #else

129 #define CONFIG_EXTRA_ENV_SETTINGS \

130 CONFIG_MFG_ENV_SETTINGS \

131"script=boot.scr\0" \

132"image=zImage\0" \

133"console=ttymxc0\0" \

134"fdt_high=0xffffffff\0" \

135"initrd_high=0xffffffff\0" \

136"fdt_file=undefined\0" \

......

194"findfdt="\

195"if test $fdt_file = undefined; then " \

196"if test $board_name = EVK && test $board_rev = 9X9; then " \

197"setenv fdt_file imx6ull-9x9-evk.dtb; fi; " \

198"if test $board_name = EVK && test $board_rev = 14X14; then " \

199"setenv fdt_file imx6ull-14x14-evk.dtb; fi; " \

200"if test $fdt_file = undefined; then " \

201"echo WARNING: Could not determine dtb to use; fi; " \

202"fi;\0" \

宏CONFIG_EXTRA_ENV_SETTINGS是个条件编译语句,使用NAND和EMMC的时候宏CONFIG_EXTRA_ENV_SETTINGS的值是不同的。

33.3.1 环境变量bootcmd

bootcmd在前面已经说了很多次了,bootcmd保存着uboot默认命令,uboot倒计时结束以后就会执行bootcmd中的命令。这些命令一般都是用来启动Linux内核的,比如读取EMMC或者NAND Flash中的Linux内核镜像文件和设备树文件到DRAM中,然后启动Linux内核。可以在uboot启动以后进入命令行设置bootcmd环境变量的值。如果EMMC或者NAND中没有保存bootcmd的值,那么uboot就会使用默认的值,板子第一次运行uboot的时候都会使用默认值来设置bootcmd环境变量。打开文件include/env_default.h,在此文件中有如下所示内容:

示例代码33.3.1.1 默认环境变量

14 env_t environment __PPCENV__ ={

15 ENV_CRC, /* CRC Sum */

16 #ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT

171, /* Flags: valid */

18 #endif

19{

20 #elif defined( DEFAULT_ENV_INSTANCE_STATIC)

21staticchar default_environment[]={

22 #else

23const uchar default_environment[]={

24 #endif

25 #ifdef CONFIG_ENV_CALLBACK_LIST_DEFAULT

26 ENV_CALLBACK_VAR "=" CONFIG_ENV_CALLBACK_LIST_DEFAULT "\0"

27 #endif

28 #ifdef CONFIG_ENV_FLAGS_LIST_DEFAULT

29 ENV_FLAGS_VAR "=" CONFIG_ENV_FLAGS_LIST_DEFAULT "\0"

30 #endif

31 #ifdef CONFIG_BOOTARGS

32"bootargs=" CONFIG_BOOTARGS "\0"

33 #endif

34 #ifdef CONFIG_BOOTCOMMAND

35"bootcmd=" CONFIG_BOOTCOMMAND "\0"

36 #endif

37 #ifdef CONFIG_RAMBOOTCOMMAND

38"ramboot=" CONFIG_RAMBOOTCOMMAND "\0"

39 #endif

40 #ifdef CONFIG_NFSBOOTCOMMAND

41"nfsboot=" CONFIG_NFSBOOTCOMMAND "\0"

42 #endif

43 #if defined( CONFIG_BOOTDELAY)&&( CONFIG_BOOTDELAY >= 0)

44"bootdelay=" __stringify( CONFIG_BOOTDELAY) "\0"

45 #endif

46 #if defined( CONFIG_BAUDRATE)&&( CONFIG_BAUDRATE >= 0)

47"baudrate=" __stringify( CONFIG_BAUDRATE) "\0"

48 #endif

49 #ifdef CONFIG_LOADS_ECHO

50"loads_echo=" __stringify( CONFIG_LOADS_ECHO) "\0"

51 #endif

52 #ifdef CONFIG_ETHPRIME

53"ethprime=" CONFIG_ETHPRIME "\0"

54 #endif

55 #ifdef CONFIG_IPADDR

56"ipaddr=" __stringify( CONFIG_IPADDR) "\0"

57 #endif

58 #ifdef CONFIG_SERVERIP

59"serverip=" __stringify( CONFIG_SERVERIP) "\0"

60 #endif

61 #ifdef CONFIG_SYS_AUTOLOAD

62"autoload=" CONFIG_SYS_AUTOLOAD "\0"

63 #endif

64 #ifdef CONFIG_PREBOOT

65"preboot=" CONFIG_PREBOOT "\0"

66 #endif

67 #ifdef CONFIG_ROOTPATH

68"rootpath=" CONFIG_ROOTPATH "\0"

69 #endif

70 #ifdef CONFIG_GATEWAYIP

71"gatewayip=" __stringify( CONFIG_GATEWAYIP) "\0"

72 #endif

73 #ifdef CONFIG_NETMASK

74"netmask=" __stringify( CONFIG_NETMASK) "\0"

75 #endif

76 #ifdef CONFIG_HOSTNAME

77"hostname=" __stringify( CONFIG_HOSTNAME) "\0"

78 #endif

79 #ifdef CONFIG_BOOTFILE

80"bootfile=" CONFIG_BOOTFILE "\0"

81 #endif

82 #ifdef CONFIG_LOADADDR

83"loadaddr=" __stringify( CONFIG_LOADADDR) "\0"

84 #endif

85 #ifdef CONFIG_CLOCKS_IN_MHZ

86"clocks_in_mhz=1\0"

87 #endif

88 #if defined( CONFIG_PCI_BOOTDELAY)&&( CONFIG_PCI_BOOTDELAY > 0)

89"pcidelay=" __stringify( CONFIG_PCI_BOOTDELAY) "\0"

90 #endif

91 #ifdef CONFIG_ENV_VARS_UBOOT_CONFIG

92"arch=" CONFIG_SYS_ARCH "\0"

93"cpu=" CONFIG_SYS_CPU "\0"

94"board=" CONFIG_SYS_BOARD "\0"

95"board_name=" CONFIG_SYS_BOARD "\0"

96 #ifdef CONFIG_SYS_VENDOR

97"vendor=" CONFIG_SYS_VENDOR "\0"

98 #endif

99 #ifdef CONFIG_SYS_SOC

100"soc=" CONFIG_SYS_SOC "\0"

101 #endif

102 #endif

103 #ifdef CONFIG_EXTRA_ENV_SETTINGS

104 CONFIG_EXTRA_ENV_SETTINGS

105 #endif

106"\0"

107 #ifdef DEFAULT_ENV_INSTANCE_EMBEDDED

108}

109 #endif

110};

environment是个env_t类型的变量,env_t类型如下:

示例代码33.3.1.2 env_t结构体

156typedef struct environment_s {

157uint32_t crc; /* CRC32 over data bytes */

158 #ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT

159unsignedchar flags; /* active/obsolete flags */

160 #endif

161unsignedchar data[ ENV_SIZE]; /* Environment data */

162} env_t

env_t结构体中的crc为CRC值,flags是标志位,data数组就是环境变量值。因此,environment就是用来保存默认环境变量的,在示例代码33.3.1.1中指定了很多环境变量的默认值,比如bootcmd的默认值就是CONFIG_BOOTCOMMAND,bootargs的默认值就是CONFIG_BOOTARGS。我们可以在mx6ull_alientek_emmc.h文件中通过设置宏CONFIG_BOOTCOMMAND来设置bootcmd的默认值,NXP官方设置的CONFIG_BOOTCOMMAND值如下:

示例代码33.3.1.3 CONFIG_BOOTCOMMAND默认值

204 #define CONFIG_BOOTCOMMAND \

205"run findfdt;" \

206"mmc dev ${mmcdev};" \

207"mmc dev ${mmcdev}; if mmc rescan; then " \

208"if run loadbootscript; then " \

209"run bootscript; " \

210"else " \

211"if run loadimage; then " \

212"run mmcboot; " \

213"else run netboot; " \

214"fi; " \

215"fi; " \

216"else run netboot; fi"

看起来很复杂的样子!因为uboot使用了类似shell脚本语言的方式来编写的,我们一行一行来分析。

第205行,runfindfdt;使用的是uboot的run命令来运行findfdt,findfdt是NXP自行添加的环境变量。findfdt是用来查找开发板对应的设备树文件(.dtb)。IMX6ULL EVK的设备树文件为imx6ull-14x14-evk.dtb,findfdt内容如下:

"findfdt="\

"if test $fdt_file = undefined; then " \

"if test $board_name = EVK && test $board_rev = 9X9; then " \

"setenv fdt_file imx6ull-9x9-evk.dtb; fi; " \

"if test $board_name = EVK && test $board_rev = 14X14; then " \

"setenv fdt_file imx6ull-14x14-evk.dtb; fi; " \

"if test $fdt_file = undefined; then " \

"echo WARNING: Could not determine dtb to use; fi; " \

"fi;\0" \

findfdt里面用到的变量有fdt_file,board_name,board_rev,这三个变量内容如下:

fdt_file=undefined,board_name=EVK,board_rev=14X14

findfdt做的事情就是判断,fdt_file是否为undefined,如果fdt_file为undefined的话那就要根据板子信息得出所需的.dtb文件名。此时fdt_file为undefined,所以根据board_name和board_rev来判断实际所需的.dtb文件,如果board_name为EVK并且board_rev=9x9的话fdt_file就为imx6ull-9x9-evk.dtb。如果board_name为EVK并且board_rev=14x14的话fdt_file就设置为imx6ull-14x14-evk.dtb。因此IMX6ULL EVK板子的设备树文件就是imx6ull-14x14-evk.dtb,

因此runfindfdt的结果就是设置fdt_file为imx6ull-14x14-evk.dtb。

第206行,mmc dev ${mmcdev}用于切换mmc设备,mmcdev为1,因此这行代码就是:mmcdev1,也就是切换到EMMC上。

第207行,先执行mmc dev ${mmcdev}切换到EMMC上,然后使用命令mmcrescan扫描看有没有SD卡或者EMMC存在,如果没有的话就直接跳到216行,执行runnetboot,netboot也是一个自定义的环境变量,这个变量是从网络启动Linux的。如果mmc设备存在的话就从mmc设备启动。

第208行,运行loadbootscript环境变量,此环境变量内容如下:

loadbootscript=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${script};

其中mmcdev=1,mmcpart=1,loadaddr=0x80800000,script= boot.scr,因此展开以后就是:

loadbootscript=fatload mmc 1:1 0x80800000 boot.scr;

loadbootscript就是从mmc1的分区1中读取文件boot.src到DRAM的0X80800000处。但是mmc1的分区1中没有boot.src这个文件,可以使用命令"lsmmc 1:1"查看一下mmc1分区1中的所有文件,看看有没有boot.src这个文件。

第209行,如果加载boot.src文件成功的话就运行bootscript环境变量,bootscript的内容如下:

bootscript=echo Running bootscript from mmc ...;

source

因为boot.src文件不存在,所以bootscript也就不会运行。

第211行,如果loadbootscript没有找到boot.src的话就运行环境变量loadimage,环境变量loadimage内容如下:

loadimage=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${image}

其中mmcdev=1,mmcpart=1,loadaddr=0x80800000,image =zImage,展开以后就是:

loadimage=fatload mmc 1:1 0x80800000 zImage

可以看出loadimage就是从mmc1的分区中读取zImage到内存的0X80800000处,而mmc1的分区1中存在zImage。

第212行,加载linux镜像文件zImage成功以后就运行环境变量mmcboot,否则的话运行netboot环境变量。mmcboot环境变量如下:

示例代码33.3.1.4 mmcboot环境变量

154"mmcboot=echo Booting from mmc ...; " \

155"run mmcargs; " \

156"if test ${boot_fdt} = yes || test ${boot_fdt} = try; then " \

157"if run loadfdt; then " \

158"bootz ${loadaddr} - ${fdt_addr}; " \

159"else " \

160"if test ${boot_fdt} = try; then " \

161"bootz; " \

162"else " \

163"echo WARN: Cannot load the DT; " \

164"fi; " \

165"fi; " \

166"else " \

167"bootz; " \

168"fi;\0" \

第154行,输出信息"Booting from mmc ..."。

第155行,运行环境变量mmcargs,mmcargs用来设置bootargs,后面分析bootargs的时候在学习。

第156行,判断boot_fdt是否为yes或者try,根据uboot输出的环境变量信息可知boot_fdt=try。因此会执行157行的语句。

第157行,运行环境变量loadfdt,环境变量loadfdt定义如下:

loadfdt=fatload mmc ${mmcdev}:${mmcpart} ${fdt_addr} ${fdt_file}

展开以后就是:

loadfdt=fatload mmc 1:1 0x83000000 imx6ull-14x14-evk.dtb

因此loadfdt的作用就是从mmc1的分区1中读取imx6ull-14x14-evk.dtb文件并放到0x83000000处。

第158行,如果读取.dtb文件成功的话那就调用命令bootz启动linux,调用方法如下:

bootz ${loadaddr} - ${fdt_addr};

展开就是:

bootz 0x80800000 - 0x83000000 (注意'-'前后要有空格)

至此Linux内核启动,如此复杂的设置就是为了从EMMC中读取zImage镜像文件和设备树文件。经过分析,浓缩出来的仅仅是4行精华:

mmcdev 1 //切换到EMMC

fatload mmc 1:1 0x80800000 zImage //读取zImage到0x80800000处

fatload mmc 1:1 0x83000000 imx6ull-14x14-evk.dtb //读取设备树到0x83000000处

bootz 0x80800000 - 0x83000000 //启动Linux

NXP官方将CONFIG_BOOTCOMMAND写的这么复杂只有一个目的:为了兼容多个板子,所以写了个很复杂的脚本。当我们明确知道我们所使用的板子的时候就可以大幅简化宏CONFIG_BOOTCOMMAND的设置,比如我们要从EMMC启动,那么宏CONFIG_BOOTCOMMAND就可简化为:

#define CONFIG_BOOTCOMMAND \

"mmc dev 1;" \

"fatload mmc 1:1 0x80800000 zImage;" \

"fatload mmc 1:1 0x83000000 imx6ull-alientek-emmc.dtb;" \

"bootz 0x80800000 - 0x83000000;"

或者可以直接在uboot中设置bootcmd的值,这个值就是保存到EMMC中的,命令如下:

setenv bootcmd 'mmc dev 1; fatload mmc 1:1 80800000 zImage; fatload mmc 1:1 83000000 imx6ull-alientek-emmc.dtb; bootz 80800000 - 83000000;'

33.3.2 环境变量bootargs

bootargs保存着uboot传递给Linux内核的参数,在上一小节讲解bootcmd的时候说过,bootargs环境变量是由mmcargs设置的,mmcargs环境变量如下:

mmcargs=setenv bootargs console=${console},${baudrate} root=${mmcroot}

其中console=ttymxc0,baudrate=115200,mmcroot=/dev/mmcblk1p2 rootwait rw,因此将mmcargs展开以后就是:

mmcargs=setenv bootargs console= ttymxc0, 115200 root= /dev/mmcblk1p2 rootwait rw

可以看出环境变量mmcargs就是设置bootargs的值为"console= ttymxc0, 115200 root= /dev/mmcblk1p2 rootwait rw",bootargs就是设置了很多的参数的值,这些参数Linux内核会使用到,常用的参数有:

1、console

console用来设置linux终端(或者叫控制台),也就是通过什么设备来和Linux进行交互,是串口还是LCD屏幕?如果是串口的话应该是串口几等等。一般设置串口作为Linux终端,这样我们就可以在电脑上通过SecureCRT来和linux交互了。这里设置console为ttymxc0,因为linux启动以后I.MX6ULL的串口1在linux下的设备文件就是/dev/ttymxc0,在Linux下,一切皆文件。

ttymxc0后面有个",115200",这是设置串口的波特率,console=ttymxc0,115200综合起来就是设置ttymxc0(也就是串口1)作为Linux的终端,并且串口波特率设置为115200。

2、root

root用来设置根文件系统的位置,root=/dev/mmcblk1p2用于指明根文件系统存放在mmcblk1设备的分区2中。EMMC版本的核心板启动linux以后会存在/dev/mmcblk0、/dev/mmcblk1、/dev/mmcblk0p1、/dev/mmcblk0p2、/dev/mmcblk1p1和/dev/mmcblk1p2这样的文件,其中/dev/mmcblkx(x=0~n)表示mmc设备,而/dev/mmcblkxpy(x=0~n,y=1~n)表示mmc设备x的分区y。在I.MX6U-ALPHA开发板中/dev/mmcblk1表示EMMC,而/dev/mmcblk1p2表示EMMC的分区2。

root后面有"rootwaitrw",rootwait表示等待mmc设备初始化完成以后再挂载,否则的话mmc设备还没初始化完成就挂载根文件系统会出错的。rw表示根文件系统是可以读写的,不加rw的话可能无法在根文件系统中进行写操作,只能进行读操作。

3、rootfstype

此选项一般配置root一起使用,rootfstype用于指定根文件系统类型,如果根文件系统为ext格式的话此选项无所谓。如果根文件系统是yaffs、jffs或ubifs的话就需要设置此选项,指定根文件系统的类型。

bootargs常设置的选项就这三个,后面遇到其他选项的话再讲解。

33.4 uboot启动Linux测试

uboot已经移植好了,bootcmd和bootargs这两个重要的环境变量也讲解了,接下来就要测试一下uboot能不能完成它的工作:启动Linux内核。我们测试两种启动Linux内核的方法,一种是直接从EMMC启动,一种是从网络启动。

33.4.1 从EMMC启动Linux系统

从EMMC启动也就是将编译出来的Linux镜像文件zImage和设备树文件保存在EMMC中,uboot从EMMC中读取这两个文件并启动,这个是我们产品最终的启动方式。但是我们目前还没有讲解如何移植linux和设备树文件,以及如何将zImage和设备树文件保存到EMMC中。不过大家拿到手的I.MX6U-ALPHA开发板(EMMC版本)已经将zImage文件和设备树文件烧写到了EMMC中,所以我们可以直接读取来测试。先检查一下EMMC的分区1中有没有zImage文件和设备树文件,输入命令"lsmmc 1:1",结果如图33.4.1.1所示:

图33.4.1.1 EMMC分区1文件

从图33.4.1.1中可以看出,此时EMMC分区1中存在zimage和imx6ull-alientek-emmc.dtb这两个文件,所以我们可以测试新移植的uboot能不能启动linux内核。设置bootargs和bootcmd这两个环境变量,设置如下:

setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw'

setenv bootcmd 'mmc dev 1; fatload mmc 1:1 80800000 zImage; fatload mmc 1:1 83000000 imx6ull-alientek-emmc.dtb; bootz 80800000 - 83000000;'

saveenv

设置好以后直接输入boot,或者runbootcmd即可启动Linux内核,如果Linux内核启动成功的话就会输出如图33.4.1.2所示的启动信息:

图33.4.1.2 linux内核启动成功

33.4.2 从网络启动Linux系统

从网络启动linux系统的唯一目的就是为了调试!不管是为了调试linux系统还是linux下的驱动。每次修改linux系统文件或者linux下的某个驱动以后都要将其烧写到EMMC中去测试,这样太麻烦了。我们可以设置linux从网络启动,也就是将linux镜像文件和根文件系统都放到Ubuntu下某个指定的文件夹中,这样每次重新编译linux内核或者某个linux驱动以后只需要使用cp命令将其拷贝到这个指定的文件夹中即可,这样就不用需要频繁的烧写EMMC,这样就加快了开发速度。我们可以通过nfs或者tftp从Ubuntu中下载zImage和设备树文件,根文件系统的话也可以通过nfs挂载,不过本小节我们不讲解如何通过nfs挂载根文件系统,这个在讲解根文件系统移植的时候再讲解。这里我们使用tftp从Ubuntu中下载zImage和设备树文件,前提是要将zImage和设备树文件放到Ubuntu下的tftp目录中,具体方法在30.4.4小节讲解tftp命令的时候已经详细的介绍过了。

设置bootargs和bootcmd这两个环境变量,设置如下:

setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw'

setenv bootcmd 'tftp 80800000 zImage; tftp 83000000 imx6ull-alientek-emmc.dtb; bootz 80800000 - 83000000'

saveenv

一开始是通过tftp下载zImage和imx6ull-alientek-emmc.dtb这两个文件,过程如下图33.4.1.3所示:

图33.4.1.3 下载过程

下载完成以后就是启动Linux内核,启动过程如图33.4.1.4所示:

图33.4.1.5 Linux启动过程

uboot移植到此结束,简单总结一下uboot移植的过程:

①、不管是购买的开发板还是自己做的开发板,基本都是参考半导体厂商的dmeo板,而半导体厂商会在他们自己的开发板上移植好uboot、linuxkernel和systemfs等,最终制作好BSP包提供给用户。我们可以在官方提供的BSP包的基础上添加我们的板子,也就是俗称的移植。

②、我们购买的开发板或者自己做的板子一般都不会原封不动的照抄半导体厂商的demo板,都会根据实际的情况来做修改,既然有修改就必然涉及到uboot下驱动的移植。

③、一般uboot中需要解决串口、NAND、EMMC或SD卡、网络和LCD驱动,因为uboot的主要目的就是启动Linux内核,所以不需要考虑太多的外设驱动。

④、在uboot中添加自己的板子信息,根据自己板子的实际情况来修改uboot中的驱动

相关问答

wii怎么备份 NAND ?

裝成Boot2的效果最大,可以裝就裝吧。NAND只能備份到SD/SDHC卡,備份檔案大小約600MB。目前可以裝成Boot2的BootMii確實是最好的防磚工具。DVDx讓你使用Wii播放D...

...苹果标志时上方出现一系列英文,均以[ NAND ]开头的。-ZOL问答

[NAND]_FindFlashMediaAndkeepout:601physicalnandblockoffset1[NAND]start:356this0x97ba2400PROV...

【makefile中的@$是什么意思?OBJS_BOOTPACK=bootpack.objnas...

[回答]$@:代表规则中的目标文件名.如果目标是一个文档(Linux中,一般称.a文件为文档),那么它代表这个文档的文件名.在多目标的模式规则中,它代表的是哪个触...

怎么修改weblogic console登陆的用户名和密码-ZOL问答

第四步:备份你的config.xml和boot.properties文件,为了避免修改操作失误;如果没办法回复到修改密码前的那种状态,那只能建议你重配Domain了.第五步:修改boot...

为什么手机储存卡会自动格式化?-ZOL问答

特别是大容量的内存卡用的是NANDFLASH材质,寿命缩短不说,还会增加坏块,也就是...电脑开机进不了boot怎么处理6768浏览笔记本键盘打斜线怎么打出来的啊?5回...

我给电脑装个固态硬盘,能兼容吗?-ZOL问答

单面布置NANDFlash颗粒的厚度为2.75mm,双面颗粒的厚度是3.85mm,对mSATA来说体...开机F1进入BOIS,——BOOT——HARDDISK——(一般按+—或者F5/F6)将S...

四月有什么数码产品值得入手?

阳春三月是每年各家新品频发的时候,特别是手机类别,各家都希望借着新机在上半年有好的市场表现,至于PCDIY方面,虽然相对淡定很多,但也有让人亮眼的产品。为...

 悲怆交响曲  水原有纱 
王经理: 180-0000-0000(微信同号)
10086@qq.com
北京海淀区西三旗街道国际大厦08A座
©2024  上海羊羽卓进出口贸易有限公司  版权所有.All Rights Reserved.  |  程序由Z-BlogPHP强力驱动
网站首页
电话咨询
微信号

QQ

在线咨询真诚为您提供专业解答服务

热线

188-0000-0000
专属服务热线

微信

二维码扫一扫微信交流
顶部