详细解析mini2440uboot移植.docx
《详细解析mini2440uboot移植.docx》由会员分享,可在线阅读,更多相关《详细解析mini2440uboot移植.docx(17页珍藏版)》请在冰豆网上搜索。
详细解析mini2440uboot移植
下面会对每一个步骤详细解答,包括为什么这样做?
版本用的是u-boot-2008.10。
我们选择一般都是寻找最相近的进行移植,首先应该考虑选择MCU(微型控制芯片)一样的开发板,如果没有这类存在,就退而求其次,选择MPU(微型处理芯片,即IP核)一样的开发板。
在uboot中没有支持S3C2440(MCU)的开发板,就考虑MPU,S3C2440是arm920t的IP核,所以选择相近的,锁定目标smdk2410开发板,它是以arm920t为核心,三星公司开发的一块开发板。
选定目标之后就可以开始移植了。
第一步:
移植一般从最顶层文件开始,最顶层当然是Makefile了,从它开始编译的。
打开Makefile后找到下面这行字:
(最左边的是行数,这个在同类版本中有一些出入,大家找到关键词就行了)
2625smdk2400_config:
unconfig:
2626@$(MKCONFIG)$(@:
_config=)armarm920tsmdk2400NULLs3c24x0
2627
2628smdk2410_config:
unconfig
2629@$(MKCONFIG)$(@:
_config=)armarm920tsmdk2410NULLs3c24x0
2630
2631SX1_config:
unconfig
2632@$(MKCONFIG)$(@:
_config=)armarm925tsx1
这几行有什么用呢?
定义开发板的名字和其他相关信息,以smdk2410为例,即:
arm:
cpu架构;
arm920t:
cpu的核;
smdk2410:
开发板的名字;
NULL:
开发者,这里没有,也可写上你想取的名字;
S3C24X0:
片上系统(Soc);
现在我们就可以知道哪些可以修改,哪些不用修改了。
这里没有对我们想要移植的开发板的支持,所以应该加上,改成如下:
(红色字为修改的):
2625smdk2400_config:
unconfig:
2626@$(MKCONFIG)$(@:
_config=)armarm920tsmdk2400NULLs3c24x0
2627
2628smdk2410_config:
unconfig
2629@$(MKCONFIG)$(@:
_config=)armarm920tsmdk2410NULLs3c24x0
2630/*modifiedbymike,weletitsupportthedevelopedboardofMINI2440*/
2631MINI2440_config:
unconfig
2632@$(MKCONFIG)$(@:
_config=)armarm920tMINI2410NULLs3c24x0
2633
2634SX1_config:
unconfig
2635@$(MKCONFIG)$(@:
_config=)armarm925tsx1
这里注意一点,如果你取名为MINI2440,那么以后涉及开发板的名字时(接下去的会讲到)就必须以这个名字,而且是必须是大写的,否则编译时会找不到相应的文件。
修改完顶层文件后就开始修改其他与顶层文件不在同一层的文件了,我们知道uboot中很多都不需要修改,不同的大部分在于cpu以及board这两个目录中,为什么呢?
因为一个关于cpu架构,一个关于开发板类型的。
比如smdk2410在board中就有自己的目录,所以新建的这个开发板就得在board中也有自己的目录,这个待会再讲。
那么cpu呢?
这里面有自己的各种核,比如arm920t,powerPC,x86等,接下去修改的便是arm920t这个目录,让这个IP核也支持它的产品S3C2440。
第二步:
进入/cpu/arm920t/start.S,这是一个很重要的文件,我们根据链接脚本可以看出,程序执行都是从这个文件开始执行的。
我们讲一下,当在编译前,我们不是一般都会执行这个命令:
makesmdk2410_config,这意味着待会编译时就只会讲与smdk2410有关的文件链接一起,所以其他不相关的不会参与编译。
那么这个start.S里面有哪些内容需要修改呢?
我们查看文件不难发现,里面有对S3C2410的支持,那么S3C2410与S3C2440很类似,所以修改的地方就不多了,只是添加上一些宏定义而已,源代码如下:
136#ifdefined(CONFIG_S3C2400)||defined(CONFIG_S3C2410)
137/*turnoffthewatchdog*/
138
138#ifdefined(CONFIG_S3C2400)
140#definepWTCON0x15300000
141#defineINTMSK0x14400008/*Interupt-Controllerbaseaddresses*/
142#defineCLKDIVN0x14800014/*clockdivisorregister*/
143#else
144#definepWTCON0x53000000
145#defineINTMSK0x4A000008/*Interupt-Controllerbaseaddresses*/
146#defineINTSUBMSK0x4A00001C
147#defineCLKDIVN0x4C000014/*clockdivisorregister*/
148#endif
149
150ldrr0,=pWTCON
151movr1,#0x0
152strr1,[r0]
153
154/*
155*maskallIRQsbysettingallbitsintheINTMR-default
156*/
157movr1,#0xffffffff
158ldrr0,=INTMSK
159strr1,[r0]
160#ifdefined(CONFIG_S3C2410)
161ldrr1,=0x3ff
162ldrr0,=INTSUBMSK
163strr1,[r0]
164#endif
165
166/*FCLK:
HCLK:
PCLK=1:
2:
4*/
167/*defaultFCLKis120MHz!
*/
168ldrr0,=CLKDIVN
169movr1,#3
170strr1,[r0]
171#endif/*CONFIG_S3C2400||CONFIG_S3C2410*/
现在修改这些代码如下:
135/*modifiedbyMike,addthe2440,closethewatchdog*/
136#ifdefined(CONFIG_S3C2400)||defined(CONFIG_S3C2410)||defined(CONFIG_S3C2440)
137/*turnoffthewatchdog*/
138
139#ifdefined(CONFIG_S3C2400)
140#definepWTCON0x15300000
141#defineINTMSK0x14400008/*Interupt-Controllerbaseaddresses*/
142#defineCLKDIVN0x14800014/*clockdivisorregister*/
143#else
144#definepWTCON0x53000000
145#defineINTMSK0x4A000008/*Interupt-Controllerbaseaddresses*/
146#defineINTSUBMSK0x4A00001C
147#defineCLKDIVN0x4C000014/*clockdivisorregister*/
148#endif
149
150#defineCLK_CTL_BASE0x4C000000
151#defineMDIV_4050x7f<<12
152#definePSDIV_4050x21
153#defineUPLL_MDIV_480x38<<12
154#defineUPLL_PSDIV_480x22
155#defineMDIV_2000xa1<<12
156#definePSDIV_2000x31
157#endif
158
159ldrr0,=pWTCON
160movr1,#0x0
161strr1,[r0]
162
163/*
164*maskallIRQsbysettingallbitsintheINTMR-default
165*/
166movr1,#0xffffffff
167ldrr0,=INTMSK
168strr1,[r0]
169#ifdefined(CONFIG_S3C2410)
170ldrr1,=0x3ff
171ldrr0,=INTSUBMSK
172strr1,[r0]
173#endif
174
175#ifdefined(CONFIG_S3C2440)
176ldrr1,=0x7fff
177ldrr0,=INTSUBMSK
178strr1,[r0]
179#endif
180/*modifytheclock*/
181#ifdefined(CONFIG_S3C2440)
182/*FCLK:
HCLK:
PCLK=1:
4:
8*/
183
184ldrr0,=CLKDIVN
185movr1,#5
186strr1,[r0]
187mrcp15,0,r1,c1,c0,0/*readctrlregister*/
188orrr1,r1,#0xc0000000/*Asynchronous*/
189mcrp15,0,r1,c1,c0,0/*writectrlregister*/
190
191/*now,thecpuclockis405MHz*/
192movr1,#CLK_CTL_BASE
193
194movr2,#UPLL_MDIV_48/*UPLL*/
195addr2,r2,#UPLL_PSDIV_48
196strr2,[r1,#0x08]/*writeUPLLfirst,48MHz*/
197
198movr2,#MDIV_405/*MPLL405MHz*/
199addr2,r2,#PSDIV_405/*MPLL405MHz*/
200strr2,[r1,#0x04]/*MPLLCON*/
201#else
202
203/*FCLK:
HCLK:
PCLK=1:
2:
4*/
204ldrr0,=CLKDIVN
205movr1,#3
206strr1,[r0]
207
208mrcp15,0,r1,c1,c0,0/*readctrlregister*/
209orrr1,r1,#0xc0000000/*Asynchronous*/
210mcrp15,0,r1,c1,c0,0/*writectrlregister*/
211
212/*now,cpuclockis202.8MHz*/
213movr1,#CLK_CTL_BASE
214
215movr2,#MDIV_200/*MPLL200MHz*/
216addr2,r2,#PSDIV_200/*MPLL405MHz*/
217strr2,[r1,#0X04]/*MPLLCON*/
218
219#endif/*CONFIG_S3C2400||CONFIG_S3C2410||CONFIG_S3C2440*/
现在我们详细讲解为什么这么改?
以便以后自己移植新的系统会修改!
!
修改136行是因为让编译时支持S3C2440,这跟#ifdefined有关,关于这个关键词不会的话自行查找C语言的书。
我们可以略掉S3C2400的语句,144行定义watchdog的寄存器地址,由于S3C2440与S3C2410这一寄存器地址一样,所以无需修改的。
关于这个寄存器见S3C2440手册462页。
除了这个一样之外还有相同的是INTMSK、INTSUBMSK、CLKDIVN,分别在S3C2440手册的388、395、58页。
从150行定义的都是根据实际需要修改的。
因为我们要求将S3C2440设置为主频405MHz。
150行是定义寄存器基址,即从0x4c000000开始,MPLL寄存器是0x4c000004,UPLL寄存器是0x4c000008,所以有后面的“196strr2,[r1,#0x08]”与“200strr2,[r1,#0x04]”,即将r2寄存器的值传给r1偏移8(或者4)后的地址的存储器。
这是定义CLK_CTL_BASE的用意。
那么r2里面存的是什么值呢?
首先194行与195行的“movr2,#UPLL_MDIV_48“”addr2,r2,#UPLL_PSDIV_48“,根据上面对UPLL_MDIV_48与
UPLL_PSDIV_48的定义,可以看出MDIV=64,为什么要那样定义呢?
我们知道64是0x38,将其左移12位便是和UPLL寄存器定义的一样,那么UPLL_PSDIV_48则是PDIV和SDIV的组合,这样就构成了UPLL寄存器的值,然后我们计算一下,这里注意一点,UPLL与MPLL的计算公式不一样的(前提是2440,如果是2410那么两者是一样的)。
UPLL=((MIDV+8)*Fin)/((PDIV+2)*2SDIV)=48MHz。
所以要这样写。
同理MPLL与此类似,只是公式有点不一样,MPLL=(2*(MIDV+8)*Fin)/((PDIV+2)*2SDIV)=405MHz。
详细见S3C2440手册的235页第7部分“clock&powermanagement“。
注意这里并没有出现这两个公式,具体是在/cpu/arm920t/s3c24x0/speed.c函数中出现,这会在后面修改。
对于201行~217行的设置是对于没有定义S3C2440的例外情况,其方法与前面讲的类似,本可以不要的,这里加上方便以后移植。
再回过头来看175行,这里是为了设置INTSUBMSK寄存器,查看S3C2440手册395页可知,该寄存器15位可用且初始值都为1,所以赋值0x7fff。
接下去设置分频比,同样查看S3C2440手册246页的分频比设置,由表可知,1:
4:
8对应的HDIVN是2(占用CLKDIVN的[2:
1]),PDIVN是1(占用CLKDIVN的[0]),所以是0x5。
这就是对于这段修改的全部解析!
!
!
!
!
!
至于187行~189行的则是些约定俗成的语句,不解析了。
第三步:
现在跳出start.S函数,进入/cpu/arm920t/s3c24x0/interrupts.c函数。
这个函数是实现中断相关信息的。
改动之处1:
源代码如下:
33#ifdefined(CONFIG_S3C2400)||defined(CONFIG_S3C2410)||defined(CONFIG_TRAB)
34
35#include
36#ifdefined(CONFIG_S3C2400)
37#include
38#elifdefined(CONFIG_S3C2410)
39#include
40#endif
修改后的:
33#ifdefined(CONFIG_S3C2400)||defined(CONFIG_S3C2410)||defined(CONFIG_TRAB)||defined(CONFIG_S3C2440)
34
35#include
36#ifdefined(CONFIG_S3C2400)
37#include
38#elifdefined(CONFIG_S3C2410)||defined(CONFIG_S3C2440)
39#include
40#endif
这些就不细说了,两个改动是为了包含arm920t.h和s3c2410.h这两个头文件。
改动之处2:
源代码:
177#ifdefined(CONFIG_SMDK2400)||defined(CONFIG_TRAB)
178tbclk=timer_load_val*100;
179#elifdefined(CONFIG_SBC2410X)||\
180defined(CONFIG_SMDK2410)||\
181defined(CONFIG_VCMA9)
182tbclk=CFG_HZ;
183#else
改动之后:
177#ifdefined(CONFIG_SMDK2400)||defined(CONFIG_TRAB)
178tbclk=timer_load_val*100;
179#elifdefined(CONFIG_SBC2410X)||\
180defined(CONFIG_SMDK2410)||\
181defined(CONFIG_MINI2440)||\
182defined(CONFIG_VCMA9)
183tbclk=CFG_HZ;
184#else
第四步:
修改/cpu/arm920t/s3c24x0/speed.c函数,改动之处1:
源代码如下:
33#ifdefined(CONFIG_S3C2400)||defined(CONFIG_S3C2410)||defined(CONFIG_TRAB)
34
35#ifdefined(CONFIG_S3C2400)
36#include
37#elifdefined(CONFIG_S3C2410)
38#include
39#endif
修改之后如下:
f
33#ifdefined(CONFIG_S3C2400)||defined(CONFIG_S3C2410)||defined(CONFIG_S3C2440)||defined(CONFIG_TRAB)
34
35#ifdefined(CONFIG_S3C2400)
36#include
37#elifdefined(CONFIG_S3C2410)||defined(CONFIG_S3C2440)
38#include
39#endif
同样是添加定义支持2440,不解析了。
改动之处2:
便是我们上次提到修改MPLL与UPLL公式的地方。
源代码:
66m=((r&0xFF000)>>12)+8;
67p=((r&0x003F0)>>4)+2;
68s=r&0x3;
69
70return((CONFIG_SYS_CLK_FREQ*m)/(p<
上面代码仅仅支持2410的,所以我们要添加上2440的计算方法,改动如下:
66m=((r&0xFF000)>>12)+8;
67p=((r&0x003F0)>>4)+2;
68s=r&0x3;
69#ifdefined(CONFIG_S3C2440)
70if(pllreg==MPLL)
71return((CONFIG_SYS_CLK_FREQ*m*2)/(p<
72elseif(pllreg==UPLL)
73#endif
74return((CONFIG_SYS_CLK_FREQ*m)/(p<
上面66行、67行、68行的r是指MPLLCON(UPLLCON),m、p、s是根据我们S3C2440手册的238页的计算公式得来的,接下去的71行便是MPLL的频率计算公式。
你可能会问,那UPLL怎么没有公式呢?
那是有的,在74行便定义了。
因为它的计算与2410一样,就无需画蛇添足了!
由此可见,linux内核是相当简练的!
改动之处3:
在get_HCLK(void)函数内修改HCLK的计算,源代码:
82S3C24X0_CLOCK_POWER*constclk_power=S3C24X0_GetBase_CLOCK_POWER();
83
84return((clk_power->CLKDIVN&0x2)?
get_FCLK()/2:
get_FCLK());
这是仅仅针对2410的,所以我们要添加定义2440的,改动如下:
82S3C24X0_CLOCK_POWER*constclk_power=S3C24X0_GetBase_CLOCK_POWER();
83
84#ifdefined(CONFIG_S3C2440)
85if(clk_power->CLKDIVN&0x6)
86{
87if((clk_power->CLKDIVN&0x6)==2)
88return(get_FCLK()/2);
89if((clk_power->CLKDIVN&0x6)==6)
90return((clk_power->CAMDIVN&0x100)?
get_FCLK()/6:
get_FCLK()/3);
91if((clk_power->CLKDIVN&0x6)==4)
92return((clk_power->CAMDIVN&0x200)?
get_FCLK()/8:
get_FCLK()/4);
93return(get_FCLK());
94}
95elsereturn((clk_power->CLKDIVN&0x2)?
get_FCLK()/2:
get_FCLK());
96#endif
什么意思呢?
就是如果定义了S3C2440的话,如果CLKDIVN的[2:
1]不为0的话,那么进入判断语句中。
首先如果CLKDIVN与0x6位与等于2的话,就可以知道HCLK=FCLK/2,接下去的分析都是遵循S3C2440手册242页的一个表,这里转换成编程语言,你会发现这转换的技巧很经典!
!
最后是如果CLKDIVN的[2:
1]为0的话就执行另外