// Topic:终于松了口气,说说这周我调试Sate210 android下DM9000 驱动的吐槽经历
//作者:gooogleman
//版权:gooogleman
//发布日期:2012.05.05 23:00
//最后修改:2012.05.06 19:00
// 原文地址:http://blog.csdn.net/gooogleman/article/details/7538560
//注意事项:商业网站未经作者同意不能转载,并且不能删除文章的任何部分,否则追究责任!
//-------------------------------------------------------------------------------------------------
终于摸着门道了,先贴点资料,等下再整理。
嘿嘿,昨晚Sate210 DM9000 网卡终于可以上网了,我一直开着Sate210 ,连续上网,看电影不停的在线播放在线视频,经过一天一夜,工作表现还是良好,我终于放心了。这次我比较happy,经过这次的调试移植,感觉自己从wince转型android开发问题不会太大了,三个月后我有信心可以更上一层楼,现在我的研发激情和刚毕业的那阵子差不了多少,现在认识那么多人,这么多android前辈指导我,我想我应该进步会更快一点。
四月中旬,接到一个客户需求,需要帮他在Sate210 上调试好android的wifi,于是我就安排android工程师去做这个事情。因为这个S5pv210 的marvell8787 wifi模块我们已经做过成熟的产品,所以花了一天左右的时间就移植到Sate210 上去了。不过客户的需求总是在变,过了一周客户说他要改成用DM9000 了,wifi要当做备选,我也满口的答应了,因为我的Sate210 wince6.0 下的DM9000 驱动 早就工作很稳定的,我曾经连续一周不关机,网络依然使用正常,所以我觉得在android下只是一个小case ,对一个合格的android工程师来说一点困难都不会有。但是幸运的事情总是很少发生在我身上,我们android工程师调试了一周,也搞不定,他开始还反问我wince驱动是否真的正常工作?为什么这个网卡int 引脚老是高电平的?!导致我们Sate210 用作网卡中断的XEINT0 在不停的中断,一旦插入网线Sate210 就死机了。后来android工程师折腾的实在也没有方向了,就暂时放下这个android DM9000 驱动,去搞Sate210 android4.0 移植了,再后来很快到了5.1 劳动节,android驱动工程师家里有事情,就请假一周回老家去了,但是5.1 的时候客户给我电话,问我这个android2.3 下的dm9000 是否搞好了,我给他说了目前的情况,这位老兄也比较理解,只是催我尽快搞,他要做底板PCB了。我着急啊,于是我这个android菜鸟决定自己看看,抱着试试的态度去解决这个android dm9000 驱动问题。
首先比较了三星官方开发板的dm9000 驱动和我sate210 驱动比较,发现一个字符都没有差异,看来这个都是开源的好处,到处都有代码可用。
然后再看kernel_v210\arch\arm\plat-s5p 下的devs.c文件,发现还是用官方电路图的XEINT9
/* DM9000 registrations */
#ifdef CONFIG_DM9000
static struct resource s5p_dm9000_resources[] = {
[0] = {
.start = S5P_PA_DM9000,
.end = S5P_PA_DM9000,
.flags = IORESOURCE_MEM,
},
[1] = {
#if defined(CONFIG_DM9000_16BIT)
.start = S5P_PA_DM9000 + 4,
.end = S5P_PA_DM9000 + 4,
.flags = IORESOURCE_MEM,
#else
.start = S5P_PA_DM9000 + 1,
.end = S5P_PA_DM9000 + 1,
.flags = IORESOURCE_MEM,
#endif
},
[2] = {
.start = IRQ_EINT9,
.end = IRQ_EINT9,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
}
};
而我的电路图是EINT0,电路图如下
所以我应该把IRQ_EINT9换成IRQ_EINT0 ,cmd 我接的是Xm0ADDR2,根据DM9000 数据手册
DM9000的访问地址主要是由CMD和CS#这两个端口的连接方式来确定的,CS#是DM9000的片选引脚,CMD引脚在芯片手册中描述如下:
CMD pin :
Command Type
When high, the access of this command cycle is DATA port
When low, the access of this command cycle is INDEX port
所以下面的这个部分不用改,刚好和我的硬件对应上
.start = S5P_PA_DM9000 + 4,
.end = S5P_PA_DM9000 + 4,
这个不用改。这里要说一下题外话,一些人对.end = S5P_PA_DM9000 + 4这个有疑惑,一些人会用.end = S5P_PA_DM9000 + 7 这个值,这里我来说一下我的理解,我觉得.end = S5P_PA_DM9000 + 4, 以及.end = S5P_PA_DM9000 + 7, 一样在Sate210 上能用,因为这个.end = S5P_PA_DM9000 + 4, 只是地址空间长短的问题,这个dm9000 只要指向data port 地址已经足够,如果.end = S5P_PA_DM9000 + 7 也只是浪费内存空间。
并且我的DM9000 的CS 连接到S5pv210 的Xm0CSn1 总线上,属于SROM 的bank1
那么根据S5pv210 的内存 布局(MEMORY ADDRESS MAP )如图
Sate210 dm9000 index port和data port 地址分别是
index port:0x88000000
data port :0x88000004
让我们来看看 S5P_PA_DM9000 的值是多少,如果不符合我们上述的标准,我们就要修改。
arch/arm/mach-s5pv210/include/mach/map.h 下有
#define S5PV210_PA_DM9000 (0x88000300)
#define S5P_PA_DM9000 S5PV210_PA_DM9000
居然是0x88000300 怎么回事呢?一般来说都会选择0x88000000 ,我认为这里替换成0x88000000也不会有关系的,因为真正决定DM9000 相关地址的不是这个“3”.不管怎么样,试了再说了。
果然,改成#define S5PV210_PA_DM9000 (0x88000000) 也和原来的结果一样,一旦插上网线就不停的产生DM9000 中断,这个说明改成
#define S5PV210_PA_DM9000 (0x88000300)和#define S5PV210_PA_DM9000(0x88000000) 是一样的。
为什么会不停的打印中断呢?是我的中断没设置对?除了上面
.start = IRQ_EINT0,
.end = IRQ_EINT0,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
的难道还有别的设置要设置的?
但是据我学习android 驱动的这段日子,这个配置已经足够了,因为IRQ_REQUEST 这个函数是会去调用中断号去下层配置的。这个在S5pv210 的矩阵键盘驱动我已经看清楚明白。
为了证实我的想法,我飞线DM9000 到XEINT4 去,把中断改成
.start = IRQ_EINT4,
.end = IRQ_EINT4,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
神奇啊,Sate210 居然可以上网了,我改成XEINT2,XEINT9,XEINT5 都一样。就是改成XEINT0 就会插上网线就死机。这时候我感觉到这个应该不是dm9000 驱动和配置的问题,而是android下S5pv210 的IRQ中断向量寄存器的部分的程序问题,难道是三星的BUG?!我的天啊,这种事情我们遇到太多了,只要我们不参考三星官网的原理图设计,我们就会很吃亏,很久才能解决本来轻而易举的问题。于是我我又邀请做android的高手朋友帮我看代码,他们帮我远程协助搞到晚上一点钟,也没查出结果,后来师弟还说周日要赶过来帮我调试,让我感动的不知道如何是好,要知道我这是商业行为,对于师弟这种帮助,我感觉不知道怎么办。我知道他成天加班,并且人还不在广州,太远了,不太合适,把人家周末给抢夺了,我还是不想劳驾师弟过来帮我解决。于是我更加卖力的看代码,找到irq 部分的代码来看,两眼冒火了,就是没找出问题所在,我越看越兴奋,看的不舍得下班回家,这种状态我清晰的记得我当年刚毕业学wince就是这么样子的,我好开心,我的状态终于回来了。
非常悲剧,又看了一晚上,还是没看出什么眉目,后来实在无奈了,拿出三星官方开发板的原理图来看看,发现有个惊人的信息:XEINT0 标了一个名字PSHOLD,这是啥玩意?看原理图只是三个插针,看三星官方开发板,上面挂着跳线帽,什么玩意啊,也没接什么东西。师弟晚上又在QQ问我:找到没有?我说貌似有点眉目,后来他说实在没办法的时候就看看手册。于是我去看了一下查XEINT0 的字眼,S5pv210 压根没有,我查找GPH 等字眼的时候才看到,于是用XEINT[0]去查找手册,惊人的一页出现了:
4.10.5.8 MISC Register (PS_HOLD_CONTROL, R/W, Address = 0xE010_E81C)
PS_HOLD_CONTROL Bit Description Initial State
Reserved [31:12] Reserved 0x00005
Reserved [11:10] Reserved 0
DIR [9] Direction (0: input, 1: output) 1
DATA [8] Driving value (0:low, 1:high) 0
Reserved [7:1] Reserved 0x00
PS_HOLD_OUT_EN [0] XEINT[0] pad is controlled by this register values and
values of control registers for XEINT[0] of GPIO
chapter is ignored when this field is ‘1’.
(0: disable, 1: enable)
0
PS_HOLD (muxed with XEINT[0]) pin value is kept up in any power mode. This register is in alive region and reset
by XnRESET or power off only.
CONFIDENTIA
——幸好英文不是很差,一看就知道我错在哪里了,哎,手册没看详细的下场,这个问题其实很简单啊。
这上面说的意思就是S5pv210 的XEINT[0]引脚有复用功能的,这个引脚是一个非常特殊的引脚PS_HOLD 其实就是S5pv210 用来控制PMIC的,在任何S5pv210 处于任何电源模式下,这个引脚都能保持住我们给他设置的电平。
果然啊,在mach-smdk110.c 下有
static void smdkc110_power_off(void)
{
/* PS_HOLD output High --> Low */
writel(readl(S5PV210_PS_HOLD_CONTROL_REG) & 0xFFFFFEFF,
S5PV210_PS_HOLD_CONTROL_REG);
while (1);
}
在uboot下也有
/* To hold max8698 output before releasing power on switch,
* set PS_HOLD signal to high
*/
ldr r0, =0xE010E81C /* PS_HOLD_CONTROL register */
ldr r1, =0x00005301 /* PS_HOLD output high */
str r1, [r0]
uboot已经把 这个XEINT[0]引脚设置成PS_HOLD 功能,并让他一直输出高电平。
难怪我在devs.c 里面设置XEINT[0] 是高电平触发中断的时候他会不停的中断!原来如此! 不过有一点我疑问了,居然是设置成PS_HOLD 功能了,为什么XEINT[0] 中断功能还有效呢?这不是坑人吗?fuck 三星!搞死我了。
现在我知道怎么解决了,在 smdkc110_dm9000_set(void) 函数加上:
static void __init smdkc110_dm9000_set(void)
{
unsigned int tmp;
writel(readl(S5PV210_PS_HOLD_CONTROL_REG) & 0x5000,S5PV210_PS_HOLD_CONTROL_REG);
tmp = ((0<<28)|(3<<24)|(7<<16)|(1<<12)|(3<<8)|(6<<4)|(0<<0));
__raw_writel(tmp, (S5P_SROM_BW+0x08));//Bank1
tmp = __raw_readl(S5P_SROM_BW);
tmp &= ~(0xf << 4);
tmp |= (0x1 << 4);
tmp |= (0x2 << 4);
__raw_writel(tmp, S5P_SROM_BW);
tmp = __raw_readl(S5PV210_MP01CON);
tmp &= ~(0xf << 4);
tmp |= (2 << 4);
__raw_writel(tmp, S5PV210_MP01CON);
}
重新make ,然后fastboot 烧写Sate210 zImage,发现DM9000 的中断慢下来了。
进入系统,打开uc 浏览器,O(∩_∩)O哈哈哈~终于可以上网了,连续不关机一天一夜,还是稳定的上网,看来稳定性还是不错的。自从这个Sate210 android DM9000 驱动调试告一段路。
这是我这个android菜鸟首次单独解决这种bug ,非常高兴,写下这种吐槽调试经历,给自己做个纪念。欢迎广大网友丢砖头指导我,偶一定会再接再厉。