移植前的准备

下载 android_uboot_smdkv210.tar.bz2 这个文件,找不到可以去公众号回复

下载|三星uboot

开始移植

本人使用的开发板是九鼎的 x210,在三星 uboot 的主 Makefile 中找到了类似的 smdkv210 的相关配置,因为这些配置都差不多,就随便选择了 smdkv210single_config

在 make smdkv210single_config; make 执行之后进行 SD 卡烧录

源码中的 SD 卡烧录脚本 sd_fusing.sh 在本人的电脑上运行有问题,需要将 21 行开始的代码进行修改如下

1
2
3
4
5
6
7
8
9
10
11
// line 19
if [ $1 = $reader_type1 ]
then
# partition1="$11"
# partition2="$12"
# partition3="$13"
# partition4="$14"
partition1="$*1"
partition2="$*2"
partition3="$*3"
partition4="$*4"

在烧录后发现,串口没有信息输出,但是开发板供电锁存成功

开发板供电锁存是在 lowlevel_init.S 中进行的

可以判定 lowlevel_init.S 中有问题,需要进行修改

启动第一阶段

在 lowlevel_init.S 中发现了一段代码对开发板上不存在的 PMIC 的初始化,在注释后串口成功打印 'OK'

1
2
/* init PMIC chip */
// bl PMIC_InitIp

uboot 开始进入启动第二阶段,通过串口输出信息可以看出,虽然 uboot 启动成功,但是很多配置信息是错误的

时钟配置

系统时钟是通过 lowlevel_init.S 中的 system_clock_init 进行的

由于三星在移植 uboot 时已经设置好系统时钟了,相关的时钟配置也都以宏的方式定义在 smdkv210single.h 文件中了

所以时钟这一块不用自己操心

ddr 配置

在 uboot 启动信息中发现串口输出的信息中,DRAM 大小和开发板的不符合

1
DRAM:    1 G

在 smdkv210single.h 文件中找到 ddr 的相关的配置

将 ddr 的地址更改为 0x30000000 (改了可以让两个 ddr 的地址连续),更改 ddr 的大小

1
2
3
4
5
6
7
8
9
10
11
// #define MEMORY_BASE_ADDRESS	0x20000000
#define MEMORY_BASE_ADDRESS 0x30000000
...
#define CONFIG_NR_DRAM_BANKS 2 /* we have 2 bank of DRAM */
// #define SDRAM_BANK_SIZE 0x20000000 /* 512 MB */
#define SDRAM_BANK_SIZE 0x10000000 /* 256 MB */
#define PHYS_SDRAM_1 MEMORY_BASE_ADDRESS /* SDRAM Bank #1 */
#define PHYS_SDRAM_1_SIZE SDRAM_BANK_SIZE
#define PHYS_SDRAM_2 (MEMORY_BASE_ADDRESS + SDRAM_BANK_SIZE) /* SDRAM Bank #2 */
#define PHYS_SDRAM_2_SIZE SDRAM_BANK_SIZE
...

然后是修改 ddr 的初始化参数

1
2
// #define DMC0_MEMCONFIG_0	0x20E01323	// MemConfig0	256MB config, 8 banks,Mapping Method[12:15]0:linear, 1:linterleaved, 2:Mixed
#define DMC0_MEMCONFIG_0 0x30F01323 // MemConfig0 256MB config, 8 banks,Mapping Method[12:15]0:linear, 1:linterleaved, 2:Mixed

ddr 的相关寄存器配置可以参考 S5PV210_UM_REV1.1.pdf

从图中可以看到,[31:24] 控制 AXI 基地址,因为我们设置 ddr 的基地址为 0x30000000 ,所以这里设置为 0x30。[23:16] 控制 AXI 基地址掩码,置1时有效,可以使基地址范围变为 0x3000_0000 ~ 0x37FF_FFFF,所以这里设置为 0xF0

修改虚拟地址到物理地址的映射

修改 board/samsung/smdkc110/smdkc110.c 的 virt_to_phy_smdkc110 函数

1
2
3
4
5
6
7
ulong virt_to_phy_smdkc110(ulong addr)
{
if ((0xc0000000 <= addr) && (addr < 0xd0000000))
// return (addr - 0xc0000000 + 0x20000000);
return (addr - 0xc0000000 + 0x30000000);
...
}

SD/MMC 配置

在 uboot 打印信息中看不到 SD/MMC 的大小,报下面的错误

unrecognised EXT_CSD structure version 7

通过报错信息的搜索,可以将问题定位到 drivers/mmc/mmc.c 中

1
2
3
4
5
6
7
// if (ext_csd_struct > 5) {
if (ext_csd_struct > 7) {
printf("unrecognised EXT_CSD structure "
"version %d\n", ext_csd_struct);
err = -1;
goto out;
}

将原先的判断 version 的版本改大点就可以了

为了通过 SD 卡启动,还需要将下面的代码修改

1
2
// mmc = find_mmc_device(0); // iNand
mmc = find_mmc_device(1); // SD

网卡芯片配置

开发板使用的网卡芯片为 DM9000 ,通过总线结构与开发板 SOC 相连,通过 SOC 的 SROM 控制器进行控制

这样的好处是可以直接通过地址访问网卡芯片内部的寄存器。访问方式是通过网卡芯片的基地址加上网卡芯片内部寄存器的偏移地址完成的

通过原理图观察可以知道 DM9000 与 SOC 之间通信的总线是 16 位的。 DM9000 的 CMD 引脚接到了 SOC 的 ADDR2 上, DM9000 数据命令总线复用,通过 CMD 进行判断是数据还是命令

CS 片选引脚接到了 SOC 的 CSn1 上,代表者使用的是 SROM bank1,因此 DM9000 的总线基地址为 0x88000000

我们需要做的配置也就是初始化网卡而已,驱动都是统一的

定位到板级初始化代码 board/samsung/smdkc110/smdkc110.c 中

dm9000_pre_init 进行了 DM9000 的初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
static void dm9000_pre_init(void)
{
unsigned int tmp;

#if defined(DM9000_16BIT_DATA)
// SROM_BW_REG &= ~(0xf << 20);
// SROM_BW_REG |= (0<<23) | (0<<22) | (0<<21) | (1<<20);
SROM_BW_REG &= ~(0xf << 4); // 更改为 SROM bank1 ,寄存器信息参考下图
SROM_BW_REG |= (1<<7) | (1<<6) | (1<<5) | (1<<4);

#else
SROM_BW_REG &= ~(0xf << 20);
SROM_BW_REG |= (0<<19) | (0<<18) | (0<<16);
#endif
// SROM_BC5_REG = ((0<<28)|(1<<24)|(5<<16)|(1<<12)|(4<<8)|(6<<4)|(0<<0));
SROM_BC1_REG = ((0<<28)|(1<<24)|(5<<16)|(1<<12)|(4<<8)|(6<<4)|(0<<0)); // SROM bank1 对应的 Bank Control Register

tmp = MP01CON_REG; // 更改片选引脚,寄存器信息参考下图
// tmp &=~(0xf<<20);
// tmp |=(2<<20);
tmp &=~(0xf<<4);
tmp |=(2<<4);
MP01CON_REG = tmp;
}

上面的代码就是按照板上具体情况配置,下面两个图是上面修改的寄存器的信息

SROM bank1
SROM bank1
CSn1
CSn1

基地址的配置

1
2
3
4
5
6
7
8
9
10
11
#ifdef CONFIG_DRIVER_DM9000
// #define CONFIG_DM9000_BASE (0xA8000000)
#define CONFIG_DM9000_BASE (0x88000300)
#define DM9000_IO (CONFIG_DM9000_BASE)
#if defined(DM9000_16BIT_DATA)
// #define DM9000_DATA (CONFIG_DM9000_BASE+2)
#define DM9000_DATA (CONFIG_DM9000_BASE+4)
#else
#define DM9000_DATA (CONFIG_DM9000_BASE+1)
#endif
#endif

上面也有提到,不同的 SROM BANK ,它们的基地址都是不同的,这里需要配置

之所以这里的基地址需要增加一个 0x300 的偏移,看到朱有鹏说可能是新版的 DM9000C 内部寄存器存在 0x300 的偏移

移植到此结束

移植后遇见的问题

uboot tftp 下载失败

TFTP error: 'File not found' (1)

在 uboot 中使用 tftp 下载镜像时,一直报上面的错误,但是在电脑上测试是可以正常下载的

后来在网上找到了原因,是 tftp 服务器是配置问题

按下面的步骤重新配置 tftp 服务器就可以正常下载了

1
2
3
4
5
6
7
8
9
10
11
12
13
// https://stackoverflow.com/questions/41616266/tftp-error-file-not-found
1, try to install tftpd-hpa

2, config tftpd-hpa
$ sudo vi /etc/default/tftpd-hpa

TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/tftpboot"
TFTP_ADDRESS="0.0.0.0:69"
TFTP_OPTIONS="-l -c -s"

3, start tftp server
$ sudo service tftpd-hpa restart

Kernel panic

Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)

解决这个问题需要设置 bootargs,可以通过更改配置头文件中的 CONFIG_BOOTARGS 完成。我这块开发板的配置如下:

console=ttySAC2,115200 root=/dev/mmcblk0p2 rw init=/linuxrc rootfstype=ext3

分别简单的介绍下这些参数的意义

console=

这个参数告诉内核将信息输出到什么地方。本开发板的配置为 串口2,波特率115200

root=

这告诉内核使用什么设备作为根文件系统。本开发板的配置为 SD 卡设备

如果需要通过 NFS 启动,可以这样设置

1
root=/dev/nfs

rw

这告诉内核将根文件系统挂载为读/写。

init=

这指定内核启动起来后,进入系统中运行的第一个脚本

rootfstype=

这用来指明文件系统的类型。

参考资料