一个x86平台的spi flash驱动移植笔记

最近一个项目,要用到flash存放一些数据,要内核支持。于是又要去移植。
其实,这个项目的合作方式我一直不喜欢,但言语轻微。起初我也不断地提意见,但看了几次的结果后,觉得不提也罢。对于开发人员来说,合作最主要的一点,就是支持力度,至于双赢那些话,我们这层面的人不会关注。这个项目的支持力度一直不给力,要资料也是三番四次的问。

说回这个flash驱动,厂家给的资料只有一个SPI接口的原理图,然后就是flash的手册以及Soc(前面文章多少也提过,这个Soc是Intel的一款芯片)的手册,——就没有然后了。我一开始还对厂家抱有幻想,以为会给demo,谁知后面催的时候却给了人家flash自家写的简单操作demo。关键一点,这个flash同时也存储着BIOS的代码。连我们自己可用的地址范围也是问了好几次才告知。经过自己好几天(其实前后加起来,有2周了)的折腾,加上厂家的支持,最终还是解决了问题,把驱动移植完了。个中滋味,着实难受。
那个flash芯片的操作,其实Linux也支持了。我天真地以为,只要把flash的id填写在那个文件里面就可以了,编译后启动,发现毫无反应。一查才知道,原来没有SPI主机控制器。以前移植某仪器公司的芯片,人家已经实现了主机控制器,所以很容易整合到内核中。现在却不同了。但找遍了内核的配置,没发现有那个Soc类似的控制器代码。于是慌了,问厂家,结果没信息。
于是又在网络上找,经过无序的google搜索,找到一个叫The Chromium Projects的东西,里面有那个SOC的代码。原来这个东西是来自另一个叫coreboot的项目,而coreboot里面有些代码又来自flashroom。无论如何,终于找到一个可以参考的工程了。于是就将里面的spi有关的代码移植到内核中。
为了方便调用,直接用KO的方式在系统运行时加载卸载。在初始化SPI时,发现里面是使用PCI来查询设备的,但coreboot的PCI的代码又不能用于内核,于是又上网了解PCI的知识。对于PCI,一直只闻其名,并没有真正接触过,所以看到直接写一个地址到0xCF8就能拿从0xCFC读取到数据时,从而判断出PCI信息的时候,还是很惊讶的。
解决PCI配置空间的问题后,可以正常找到PCI设备了,接着,加载后内核崩溃,查了好久,才发现是writel的问题,原来内核和coreboot的writel参数是相反的。改正后,可以读取flash的ID的,尝试读取flash的数据,看到有部分不是0xff,初步认为正常——不过,写到flash中的BIOS代码,完全不知道是怎么回事。后来测试写操作,这时又忘记了要先擦除才能写,又耗了一些时间。但写却不成功。擦除倒是正常,有一次测试中,把地址改为0,但忘记注释掉擦除函数,结果把flash的第1个扇区擦除了——这块板子就这样被我搞废了。
我想过可能是写保护的原因,周末利用点时间看看手册,再看看coreboot的代码,发现SPI控制器里面有几个寄存器是可以设置的,于是把代码整理出来,自以为找到了解决方法了。周一来测试,发现情况依旧:还是不能写,写保护还是没法去掉。于是继续查手册,发现几个寄存器的描述中有提到某些位一旦置1后,就不能再写了——而这些位就是锁就是锁住了另外的寄存器。于是猜测是BIOS做了什么事情锁住了寄存器。与此同时,知道了x86中的SMM、SMI这些名词,去网上了解一下资料。得出的结论是:现在这种情况,无法进入SMM,无法改寄存器,无法写flash。然后将测试及疑问发邮件问厂家,我们的最终目的是如何在Linux中使用flash,而不管什么模式什么保护。厂家回复说没在Linux下搞过,只搞过BIOS,然后给出参考步骤,第一步就是禁止写保护功能——而这,正是我们无法做到的一点。
此时,直接进坑了,无法解决。
第二天,厂家给出一个新的BIOS固件,叫我们升级试试。然后我试了,结果成功了!可以正常写了!我直接在flash中写上了惯用的“F”开头的语句。那一刻,很是激动。
最终的解决方法是直接参考coreboot的代码,然后自己封装一个platform设备,调用ioctl来实现读、写、擦除。而不管内核提供的SPI构架。
——一个人奋斗好几天,结果人家一更新bios,就解决了。再次用耗时的教训证明:合作,支持力度十分重要。

后记:
其实这次算是侥幸的了,感谢强大的开源社区!实然也为自己的能力感到羞耻。
想起大学的毕业设计,也是搞了很久,实然找到一个开源的不知是德国人还是法国人写的库(里面的注释还是靠着google翻译才有点看懂),然后就直接拿来用了,然后就解决问题了。
刚来公司时,也是因为一个问题搞了很久,那是一个周末,租房断网,自己拿着公司的本本,去一个同学那里上网继续解决。实然也找到一个类似的模块,又解决了问题。——那天,顶着大太阳走了好远的路。
同时,发现在公司干活或多或少都有坑,或是大坑,或是小坑。
有一次,因为一个接口小板的问题导致一个模块出错,看了半天程序也没找出问题,后来不要接口小板就OK了。又有一次一个IIC驱动问题,查了半天,原来是某仪器他家芯片的BUG,后来也是找技术支持才解决问题。
仅以此文记念那些日子!

2015.1.4补:
1、文中提及的coreboot主页为:http://www.coreboot.org/
2、一个讨论coreboot的论坛,里面有讨论本文提到的CPU:http://www.biosren.com/forum-92-1.html

李迟,2014年11月21日