2.调试问题
2.1 uboot
2.1.1 dts解析报错
【问题现象】
Uboot命令行执行sf probe提示error。
(1)Invalid bus 0 (err=-19)
(2)Error: subnode with SPI flash config missing!
(3)fdtdec_get_addr_size_auto_noparent: fdtdec_get_addr_size_auto_parent: na=2, ns=2, fdtdec_get_addr_size_fixed: reg: (not enough data:
expected >= 8 cells, got 4 cells)
【问题原因】
以上错误信息均由dts配置引起,包括qspi需要配置别名,qspi需要配置flash芯片子节点,地址配置需要按照指定的cell长度等,修复后的正确配置如下。
[uboot\arch\arm\dts\tsm_tx511.dtsi]
qspi: spi@f0d9e000 {
compatible = "cdns,qspi-nor";
reg = <0x0 0xf0d9e000 0x0 0x1000>,
<0x0 0xe0000000 0x0 0x10000000>;
num-cs = <4>;
cdns,fifo-depth = <256>;
cdns,fifo-width = <4>;
};
[uboot\arch\arm\dts\tsm_tx511_fpga.dts]
aliases {
spi0 = &qspi;
};
&qspi {
status = "okay";
flash@0 {
compatible = "jedec,spi-nor";
spi-max-frequency = <108000000>; /* Based on DC1 spec */
};
};
2.1.2 ahb访问异常
【问题现象】
sf probe或者手动访问ahb触发异常。
=> md.l 0xe0000000 8
e0000000:"Synchronous Abort" handler, esr 0x96000006
elr: 0000000001036a78 lr : 00000000010369d4 (reloc)
elr: 000000003ffada78 lr : 000000003ffad9d4
x0 : 0000000000000009 x1 : 0000000000000000
x2 : 000000000000003a x3 : 00000000f0d8a000
x4 : 00000000e0000000 x5 : 000000003f3fec88
x6 : 000000003f3ff1e8 x7 : 000000003ffc15a0
x8 : 0000000000000004 x9 : 0000000000000004
x10: 0000000000000044 x11: 00000000000186a0
x12: 000000000001869f x13: 0000000000000021
x14: 0000000000000008 x15: 000000003f3fec88
x16: 000000003ff99be8 x17: 0000000000000040
x18: 000000003f3ffde0 x19: 0000000000000008
x20: 00000000e0000000 x21: 00000000e0000000
x22: 000000003ffc0e66 x23: 0000000000000008
x24: 0000000000000004 x25: 000000003ffc0000
x26: 0000000000000004 x27: 0000000000000004
x28: 0000000000000000 x29: 000000003f3ff160
Code: 12800000 17ffffce 7100137f 540001e1 (b9400081)
Resetting CPU ...
【问题原因】
MMU表项配置OSPI的ahb地址少了个0,软件访问的AHB地址未找到物理地址,触发异常。
uboot\arch\arm\mach-tsm\cpu.c
2.1.3 32MB Flash读内容为0x0
【问题现象】
16MB的Flash读内容正常,但32MB的Flash读取内容为0x0。
=> sf read 0x8000000 0 0x1000
device 0 offset 0x0, size 0x1000
cadence_qspi_apb_chipselect : chipselect 0 decode 0
SF: 4096 bytes @ 0x0 Read: OK
=> md.b 0x8000000 10
08000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
=>
【问题原因】
大于16MB的Flash采用4 byte地址访问,此时需要改用4 byte模式下的Read指令。指令替换在spi_nor_scan()->spi_nor_set_4byte_opcodes()中执行。spi-nor-ids.c中的白名单数组配置中对于大于16MB的芯片需配上SPI_NOR_4B_OPCODES标志。
白名单配置修改。
16MB Flash和32MB Flash Read指令对比,前者使用3 byte 模式的0x0b,后者使用4byte模式的0xc。
2.1.4 QSPI QE无法保存
【问题现象】
从QSPI FLASH启动,ATF阶段已经配置过QE使能位,到uboot或者内核阶段再读status寄存器,应该读到使能标志,但每次重启后,uboot/内核驱动调用quad_enable()之前读到的QE都为0。
【问题原因】
uboot/内核驱动在调用quad_enable()之前会调用write_sr(nor, 0)。这里虽然只写了status寄存器的一个byte,但是在SPI模式cs拉高后会清掉QE。该现象目前仅在gd25lq128出现,非普遍现象,非问题。
2.2 kernel
2.2.1INDAC read死循环
【问题现象】
uboot驱动采用DAC模式访问,内核驱动采用INDAC模式访问。Uboot驱动采用轮询方式,内核驱动阶段采用中断方式,读写操作与中断有交互。正常读写流程发起后会等待中断调用complete()进行同步,以执行下一步处理。
出问题时中断未触发,且cpu反复读SRAM,但是CQSPI_REG_SDRAMLEVEL寄存器指示SRAM中始终有数据,一直未被读走,导致软件陷入死循环。
【问题原因】
中断配置,trigger address配置有误。
手册里ospi_int中断号为78,dts中原先配置interrupts = <0 78 0>,内核起来后体现为中断号110,边沿触发。实际上中断号应减去32,改为SPI中断开始的中断号,触发方式改为电平触发。
修改后的中断配置,
qspi: spi@f0d9e000 {
interrupt-parent = <&gic>;
interrupts = <0 46 4>;
}
root@(none):/# cat /proc/interrupts | grep spi
CPU0 CPU1
9: 1 0 GIC-0 78 Level f0d9e000.spi
INDAC方式下CQSPI_REG_INDIRECTTRIGGER(1Ch)写入INDAC模式访问的基地址,该寄存器需配置为AHB的物理地址0xe0000000,这样当内核驱动读该地址时才会触发INDAC访问。否则如果AHB访问地址不在INDAC地址区间内,则该访问一直由DAC执行,由此导致INDAC模式使用的SRAM中数据未被取走。
2.2.2 OSPI 1-1-8模式读取内容错位
【问题现象】
1-1-1模式下发的Rd指令为0x0c,1-1-8模式下的Rd指令为0x8b。读到的数据为8Byte之后的内容,有错位。
【问题原因】
类似问题2.1.3,内核驱动版本比较老,
spi_nor_scan()->spi_nor_set_4byte_opcodes()->spi_nor_convert_3to4_read()对1-1-8模式支持不全。从新内核版本移植1-1-8模式下4byte的指令之后,1-1-8读指令切换为SPINOR_OP_READ_1_1_8_4B(0x7c),后读数据内容ok,问题解决。
注意对于Giga芯片,并下发SPINOR_OP_EN4B命令进入4byte模式,而仅仅是使用4byte的读指令。
3. 代码流程
见uboot_sf_flow.emmx。
4.调试命令
4.1 uboot
(1) sf probe [[bus:]cs] [hz] [mode]
- init flash device on given SPI bus and chip select
(2) sf read addr offset|partition len
- read `len' bytes starting at `offset' or from start of mtd `partition'to memory at `addr'
(3) sf write addr offset|partition len
- write `len' bytes from memory at `addr' to flash at `offset' or to start of mtd `partition'
(4) sf erase offset|partition [+]len
- erase `len' bytes from `offset' or from start of mtd `partition' `+len' round up `len' to block size
(5) sf test offset len
- run a very basic destructive test
sf probe mode字段说明
mode字段定义 uboot/include/spi.h
示例:
1线模式
sf probe 0:0 1000000 0x3
8线模式
sf probe 0:0 1000000 0x8103
4线模式
sf probe 0:0 1000000 0x2103
4.2 kernel
4.2.1 mtd_debug
# mtd_debug
usage: mtd_debug info <device>
mtd_debug read <device> <offset> <len> <dest-filename>
mtd_debug write <device> <offset> <len> <source-filename>
mtd_debug erase <device> <offset> <len>
示例:
# mtd_debug erase /dev/mtd1 0 0x100000
Erased 1048576 bytes from address 0x00000000 in flash
# mtd_debug read /dev/mtd1 0 0x5000 /tmp/rd_1.bin
Copied 20480 bytes from address 0x00000000 in flash to /tmp/rd_1.bin
# hexdump -C /tmp/rd_1.bin
00000000 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
*
00005000
#
4.2.2 sysfs
(1) cat /sys/cdns_qspi/cqspidbg
dump寄存器或者驱动控制块
(2) echo readreg <offset> > /sys/cdns_qspi/cqspidbg
读寄存器
(3) echo writereg <offset> <value> > /sys/cdns_qspi/cqspidbg
写寄存器
(4) echo readid 0 > /sys/cdns_qspi/cqspidbg
读devid
(5) echo readstatus 0 > /sys/cdns_qspi/cqspidbg
读status/config/flag寄存器
(6) echo erase <offset> <length> > /sys/cdns_qspi/cqspidbg
擦除指定偏移和长度的sector区域
(7) echo readdata <offset> <length> > /sys/cdns_qspi/cqspidbg
从指定偏移位置读指定长度的内容到临时文件
(8) echo writedata <offset> <length> <pattern> > /sys/cdns_qspi/cqspidbg
向指定偏移位置写入指定长度的内容,具体内容由pattern决定