2021-02-22

jacinto 内核驱动 – 5

3.2.2.13 OSPI / QSPI
介绍
八进制串行外设接口(OSPI)是一个具有x8 IO线的SPI模块。四串行外围接口(QSPI)有x4 IO线。这些控制器主要用于接口八进制或四倍SPI flashes。OSPjI向后兼容QSPI。这些模块也可以在双(x2)和单(x1)模式下工作。
TI soc上的OSPI和QSPI控制器支持内存映射IO接口,这为访问外部SPI闪存的数据提供了直接接口,从而简化了软件需求。这些控制器只在主模式下工作。
支持设备
在各种TI soc上有两种OSPI/QSPI控制器IPs的变体。下表提供了不同TI soc的驱动程序和功能的映射:

SoC Family	capability	Driver
AM437x	QSPI	drivers/spi/spi-ti-qspi.c
DRA7xx/AM57xx	QSPI	drivers/spi/spi-ti-qspi.c
66AK2Gx	QSPI	drivers/mtd/spi-nor/cadence-quadspi.c
AM654/J721e	1x OSPI, 1x QSPI	

drivers/mtd/spi-nor/cadence-quadspi.c
驱动程序功能
OSPI控制器支持八进制配置的双数据速率(DDR)模式,其中数据可以在时钟的两个边缘读取。
注意
驱动程序不支持八进制或四进制模式写入。
内存映射读取支持
一旦控制器配置为内存映射模式,整个闪存就可以作为SoC特定地址的内存区域使用。可以使用普通的memcpy()(或mem-to-mem dma copy)访问此区域。控制器硬件将通过SPI总线与SPI闪存进行内部通信,并获取请求的数据。此模式提供最佳吞吐量,是SDK中的默认模式。
支持的SPI模式
spi-ti-qspi.c驱动程序支持特定SoC的TRM表“SPI时钟模式定义”中定义的所有时钟和极性模式。但是请确保选择的模式是由设备的时钟要求支持的,根据设备的数据表。
cadence-quadspi.c驱动程序只支持标准SPI模式0。
DMA的支持
驱动程序在从闪存读取时在OSPI/QSPI内存映射端口上使用mem-to-mem DMA复制,以获得最大吞吐量和减少CPU负载。
驱动程序的体系结构
下图显示了QSPI驱动程序栈:

在这里插入图片描述

图3.1 QSPI驱动程序软件栈
QSPI驱动程序既可以通过mtd子系统访问SPI flash设备,也可以通过SPI框架访问通用SPI设备(比如SPI触摸屏)。
OSPI驱动程序堆栈如下图所示:

在这里插入图片描述

图3.2 OSPI驱动程序软件栈
OSPI不支持与非闪存SPI从机接口。
驱动程序配置
源位置
QSPI驱动程序的源文件可以在Linux内核源代码树下的drivers/spi/spi-ti-qspi.c中找到。
OSPI驱动程序位于Linux内核源代码树下的drivers/mtd/spi-nor/cadence-quadspi.c。此驱动程序还支持同一IP的QSPI版本。
内核配置选项
驱动程序可以内置到内核中,也可以作为模块编译并动态加载到内核中。

启用OSPI/QSPI驱动配置
访问OSPI/QSPI flash需要启用以下功能: 在内核中通过menuconfig配置的TI QSPI控制器驱动程序,SPI NOR框架和MTD M25P80通用串行flash驱动程序。
请注意
缺省情况下,SDK映像中启用了OSPI/QSPI驱动程序及其依赖项。所以在这种情况下可以跳过这一节。
启动Linux内核配置工具:
$ make menuconfig ARCH=arm
启用QSPI控制器驱动程序:

Device Drivers  --->
 [*] SPI support  --->
   <*>   DRA7xxx QSPI controller support

要启用SPI NOR框架:

Device Drivers  --->
  <*> Memory Technology Device (MTD) support  --->
    <*>   SPI-NOR device support  --->

要启用M25P80通用SPI闪存驱动程序:

Device Drivers  --->
  <*> Memory Technology Device (MTD) support  --->
    Self-contained MTD device drivers  --->
      <*> Support most SPI Flash chips (AT26DF, M25P, W25X, ...)

要启用cadence-quadspi驱动程序:

Device Drivers  --->
  <*> Memory Technology Device (MTD) support  --->
    <*>   SPI-NOR device support  --->
      <*>   Cadence Quad SPI controller

要将它们作为模块启用,请将<*>设为。
启用UBIFS文件系统支持:

File systems  --->
  [*] Miscellaneous filesystems  --->
    <*>   UBIFS file system support

DT配置
有关spi-ti-qspi控制器驱动程序的DT绑定及其用法,请参阅内核源树下的文档Documentation/devicetree/bindings/spi/ti_qspi.txt。
关于cadence-quadspi控制器,请参阅文档Documentation/devicetree/bindings/mtd/cadence-quadspi.txt了解DT绑定及其用法。
要配置OSPI/QSPI flash分区和flash相关的DT绑定,请参考文档Documentation/devicetree/bindings/mtd/jedec,spi-nor.txt and Documentation/devicetree/bindings/mtd/partition.txt。
驱动程序使用
请注意
尽管在硬件级别上OSPI和QSPI是不同的,但从Linux的观点来看,OSPI和QSPI都是以相同的方式进行管理的,并作为/dev/mtdX设备公开给用户空间。因此,即使OSPI和QSPI底层使用不同的驱动程序,对最终用户来说实际上也没有什么区别。因此,本节适用于OSPI和QSPI。
请注意
在J721E EVM上,在单板上电访问OSPI flash时,SW3.1开关应处于OFF位置。
根据需要使用modprobe加载QSPI或OSPI模块(这将处理依赖并加载这些模块):

$modprobe spi-ti-qspi
$modprobe cadence-quadspi

这应该为DT中或通过命令行参数定义的每个分区创建/dev/mtdX条目。MTD抽象了所有类型的flash,因此OSPI和QSPI都显示为MTD设备。要查看系统中运行的所有MTD分区,请执行以下操作:
$cat /proc/mtd
下面是一个输出示例(名称取决于DT或通过命令行参数传递的内容):

dev:    size   erasesize  name
mtd0: 00080000 00010000 "QSPI.U_BOOT"
mtd1: 00080000 00010000 "QSPI.U_BOOT.backup"
mtd2: 00010000 00010000 "QSPI.U-BOOT-SPL_OS"
mtd3: 00010000 00010000 "QSPI.U_BOOT_ENV"
mtd4: 00010000 00010000 "QSPI.U-BOOT-ENV.backup"
mtd5: 00800000 00010000 "QSPI.KERNEL"
mtd6: 036d0000 00010000 "QSPI.FILESYSTEM"

测试
使用mtd-utils

$ cat /proc/mtd       /*应该列出QSPI分区*/
$ flash_erase  /dev/mtd6 0 0  /* Erase整个/dev/mtd6 */
$ dd if=/dev/random of=tmp_write.txt bs=1 count=num  /* num=写入闪存的字节数*/
$ mtd_debug write /dev/mtd6 0 num tmp_write.txt  /*写入闪存的字节数*/
$ mtd_debug read /dev/mtd6 0 num tmp_read.txt /* /*读取到要闪存的字节数*/
$ diff tmp_read.txt tmp_write.txt /*应为空*/
使用 dd 命令
$ cat /proc/mtd       /*应该列出QSPI分区*/
$ flash_erase  /dev/mtd6 0 0  /* Erase整个/dev/mtd6 */
$ dd if=/dev/random of=tmp_write.txt bs=1 count=num  /* num=写入闪存的字节数*/
$ dd if=tmp_write.txt of=/dev/mtd6 bs=num count=1 /*写入闪存的字节数*/
$ dd if=/dev/mtd6 of=tmp_read.txt bs=num count=1  /*读取到要闪存的字节数*/
$ diff tmp_read.txt tmp_write.txt /*应为空*/
在flash上使用UBIFS

确保在内核中启用了UBIFS文件系统(有关更多信息,请参阅本节).

root~# ubiformat /dev/mtd9
ubiformat: mtd9 (nor), size 23199744 bytes (22.1 MiB), 354 eraseblocks of 65536 bytes (64.0 KiB), min. I/O size 1 bytes
libscan: scanning eraseblock 353 -- 100 % complete
ubiformat: 354 eraseblocks are supposedly empty
ubiformat: formatting eraseblock 353 -- 100 % complete
root:~# ubiattach -p /dev/mtd9
[  270.874428] ubi0: attaching mtd9
[  270.914131] ubi0: scanning is finished
[  270.921788] ubi0: attached mtd9 (name "QSPI.file-system", size 22 MiB)
[  270.928405] ubi0: PEB size: 65536 bytes (64 KiB), LEB size: 65408 bytes
[  270.935210] ubi0: min./max. I/O unit sizes: 1/256, sub-page size 1
[  270.941491] ubi0: VID header offset: 64 (aligned 64), data offset: 128
[  270.948102] ubi0: good PEBs: 354, bad PEBs: 0, corrupted PEBs: 0
[  270.954215] ubi0: user volume: 0, internal volumes: 1, max. volumes count: 128
[  270.961602] ubi0: max/mean erase counter: 0/0, WL threshold: 4096, image sequence number: 2077421476
[  270.970887] ubi0: available PEBs: 350, total reserved PEBs: 4, PEBs reserved for bad PEB handling: 0
[  270.980204] ubi0: background thread "ubi_bgt0d" started, PID 863
UBI device number 0, total 354 LEBs (23154432 bytes, 22.1 MiB), available 350 LEBs (22892800 bytes, 21.8 MiB), LEB size 65408 bytes (63.9 KiB)
root:~# ubimkvol /dev/ubi0 -N flash_fs -s 20MiB
Volume ID 0, size 321 LEBs (20995968 bytes, 20.0 MiB), LEB size 65408 bytes (63.9 KiB), dynamic, name "flash_fs", alignment 1
root:~# mkdir /mnt/flash
root:~# mount -t ubifs ubi0:flash_fs /mnt/flash/
[  326.002602] UBIFS (ubi0:0): default file-system created
[  326.008309] UBIFS (ubi0:0): background thread "ubifs_bgt0_0" started, PID 866
[  326.027530] UBIFS (ubi0:0): UBIFS: mounted UBI device 0, volume 0, name "flash_fs"
[  326.035157] UBIFS (ubi0:0): LEB size: 65408 bytes (63 KiB), min./max. I/O unit sizes: 8 bytes/256 bytes
[  326.044615] UBIFS (ubi0:0): FS size: 20341888 bytes (19 MiB, 311 LEBs), journal size 1046528 bytes (0 MiB, 16 LEBs)
[  326.055123] UBIFS (ubi0:0): reserved for root: 960797 bytes (938 KiB)
[  326.061610] UBIFS (ubi0:0): media format: w4/r0 (latest is w4/r0), UUID 828AA98E-3A51-4B35-AD50-9E90144AD4C7, small LPT model
root:~#

现在您可以通过/mnt/flash/访问文件系统。
3.2.2.14. SPI
介绍
•串行接口
•同步
•主从配置(驱动程序仅支持主模式)
•数据交换-DMA/PIO
SOC特定信息

SoC Family	Driver
AM335x	McSPI
AM437x	McSPI
DRA7x	McSPI
66AK2Gx	McSPI
66AK2Lx	Davinci
66AK2Hx	Davinci
66AK2E	Davinci

功能不支持
下面列出了Linux驱动程序不支持的特性。注意,这并不是一个详尽的列表,只是考虑了SoC中的SPI外设能够提供的功能,但目前Linux驱动程序不支持这些功能。
•不支持spi从模式
内核配置
要启用的特定外设驱动程序取决于所使用的SoC。
使McSPI驱动

Device Drivers  --->
   [*] SPI support
      [*] McSPI driver for OMAP
Enabling DaVinci Driver
Device Drivers  --->
   [*] SPI support
      [*] Texas Instruments DaVinci/DA8x/OMAP-L/AM1x SoC SPI controller

SPI驱动程序用例
有许多驱动程序可以用来与各种硬件交互。从基于SPI的RTC到基于SPI的GPIO扩展器。在内核源代码中可以找到驱动程序及其文档的列表。下面的部分试图提供关于位于TI evms上的基于SPI的芯片的信息。
闪存
请注意
本节不要与通过QSPI/OSPI模块的闪存混淆。
带SPI Flash单板

EVM 	Part #	Flash Size
AM335x ICE EVM	W25Q64	8 MB
K2E EVM	N25Q128A11ESF40F	16 MB
K2HK EVM	N25Q128A11ESF40F	16 MB
K2L EVM	N25Q128A11ESF40F	16 MB

内核配置

Device Drivers  --->
   <*> Memory Technology Device (MTD) support  --->
       Self-contained MTD device drivers  --->
         <*> Support most SPI Flash chips (AT26DF, M25P, W25X, ...)

读/写Flash
确定SPI NOR分区MTD标识符
在内核中,计算特定SPI或分区的mtd设备号很简单。用户只需查看mtd设备的列表及其名称。下面的命令将提供此信息:
cat /proc/mtd
下面是在AM571x IDK EVM上执行的输出示例.

dev:    size   erasesize  name
mtd0: 00040000 00010000 "QSPI.SPL"
mtd1: 00100000 00010000 "QSPI.u-boot"
mtd2: 00080000 00010000 "QSPI.u-boot-spl-os"
mtd3: 00010000 00010000 "QSPI.u-boot-env"
mtd4: 00010000 00010000 "QSPI.u-boot-env.backup1"
mtd5: 00800000 00010000 "QSPI.kernel"
mtd6: 01620000 00010000 "QSPI.file-system"

请注意,这些分区的名称、大小(十六进制)和偏移量(十六进制)在特定板的设备树文件中确定。
擦除
可以使用以下命令擦除NOR分区:

flash_erase /dev/mtdX 0 0

其中X是分区号。
读/写
使用EVM上为SPI闪存提供的MTD接口来验证SPI驱动程序接口。
下面的步骤将8KiB从/dev/mtd2分区(u-boot env)复制到/dev/mtd4分区,并将8KiB映像从/dev/mtd4读取到一个文件并检查md5sum。test.img and test1.img 的md5sum应该相同。

cd /tmp
dd if=/dev/mtd2 of=test.img bs=8k count=1
md5sum test.img
flash_eraseall /dev/mtd4
dd if=test.img of=/dev/mtd4 bs=8k count=1
dd if=/dev/mtd4 of=test1.img bs=8k count=1
md5sum test1.img

Linux用户空间接口
如果不存在预先制作的SPI驱动程序,或者用户需要一种简单的方法来发送和接收SPI消息,则可以使用spidev驱动程序。Spidev提供了一种用户空间可访问的方式来与SPI接口通信。关于spidev驱动程序的最新文档可以在这里找到。
Spidev允许用户用各种编程语言与spi接口交互,这些语言可以与内核ioctl通信。
内核配置

Device Drivers  --->
   [*] SPI support
      <*> User mode SPI device driver support

设备树
下面是用户用于启用spidev驱动程序的设备树设置示例。与外设的大多数驱动程序一样,spidev驱动程序被列为主SPI外设驱动程序的子节点.

&spi1 {
        status = "okay";
        pinctrl-names = "default";
        pinctrl-0 = <&spi1_pins_s0>;
        spidev@1 {
                spi-max-frequency = <24000000>;
                reg = <0>;
                compatible = "rohm,dh2228fv";
        };
};

•注意,SPI子节点的reg属性通常用于指示与特定驱动程序通信时要使用的芯片选择。
测试应用程序
在内核源代码中,./tools/spi/spidev_test.c是内核中的一个测试应用程序,它可以交叉编译以显示一个与spi外围设备交互的C应用程序。
3.2.2.15 NAND
介绍
NAND闪存设备的TI基础设施
TI的SoC通过片上GPMC(通用内存控制器)接口或AEMIF(取决于SoC)与NAND闪存设备接口。
对于包含GPMC的设备:NAND设备保护其数据所需的ECC算法由两个独立的硬件引擎管理:
•GPMC ECC引擎:用于在写入和读取NAND设备时计算ECC校验和。
•ELM ECC引擎:用于在读取NAND设备时定位和解码ECC错误。
与NAND相关的重要驱动程序可以进一步分为以下子组件。
对于所有设备:
•NAND子系统:MTD子系统中与NAND闪存设备接口的协议驱动程序。
对于K2L和K2E:
•AEMIF驱动程序:AEMIF引擎的控制器驱动程序
对于所有其他SOC:
•GPMC驱动程序:GPMC引擎的控制器驱动程序
•ELM驱动器(适用于SoC):ELM引擎的控制器驱动器。
支持的功能
GPMC NAND驱动程序支持:
•NAND设备具有:
•总线宽度=x8 | x16
•页面大小=2048 | 4096
•块大小=128k | 256k
•1位Hamming、BCH4、BCH8和BCH16 ECC方案。
•针对不同用例和应用程序的各种传输模式(如轮询、轮询预取、IRQ和DMA)。
•NAND引导支持使用NAND-I2C引导模式的自定义非ONFI兼容NAND设备(请参阅处理器TRM中有关初始化的章节)。
•子页写入
访问NAND闪存分区
Linux
在内核中,通过mtd设备访问NAND分区。而不是通过名称或偏移量来引用分区,用户只需以其mtd设备路径的形式指定所涉及的NAND分区。通常格式为/dev/mtdX,其中X为mtd设备号。
确定NAND分区的MTD标识符
在内核中,计算特定NAND分区的mtd设备号很简单。用户只需要查看mtd设备列表及其名称。下面的命令将提供这些信息:
cat /proc/mtd
下面可以看到在DRA71x EVM上执行的输出示例。

dev:    size   erasesize  name
mtd0: 00010000 00010000 "QSPI.SPL"
mtd1: 00010000 00010000 "QSPI.SPL.backup1"
mtd2: 00010000 00010000 "QSPI.SPL.backup2"
mtd3: 00010000 00010000 "QSPI.SPL.backup3"
mtd4: 00100000 00010000 "QSPI.u-boot"
mtd5: 00080000 00010000 "QSPI.u-boot-spl-os"
mtd6: 00010000 00010000 "QSPI.u-boot-env"
mtd7: 00010000 00010000 "QSPI.u-boot-env.backup1"
mtd8: 00800000 00010000 "QSPI.kernel"
mtd9: 01620000 00010000 "QSPI.file-system"
mtd10: 00020000 00020000 "NAND.SPL"
mtd11: 00020000 00020000 "NAND.SPL.backup1"
mtd12: 00020000 00020000 "NAND.SPL.backup2"
mtd13: 00020000 00020000 "NAND.SPL.backup3"
mtd14: 00040000 00020000 "NAND.u-boot-spl-os"
mtd15: 00100000 00020000 "NAND.u-boot"
mtd16: 00020000 00020000 "NAND.u-boot-env"
mtd17: 00020000 00020000 "NAND.u-boot-env.backup1"
mtd18: 00800000 00020000 "NAND.kernel"
mtd19: 0f600000 00020000 "NAND.file-system"

如上所示,mtd设备列表可能不仅包括NAND分区,而且还列出了创建mtd设备的其他外围设备。从上面可以看出,如果用户希望访问NAND中的文件系统分区,那么他们使用/dev/mtd19来引用该分区。这些分区的名称、大小(十六进制)和偏移量(十六进制)在特定板的设备树文件中确定。
擦除、读写
对于以下各节,重要的是要记住用与特定NAND分区相关联的mtd设备替换mtdX,如以上各节所述。
擦除
擦除NAND分区可以使用以下命令执行:
flash_erase /dev/mtdX 0 0
写入
写一个NAND分区通常有两个步骤。在一个位级别上写NAND只能从1到0改变一个位。这是有问题的,因为在写入新数据时,经常需要将许多位从1更改为0,同时也需要将一些位从0更改为1。解决这个问题的唯一方法是在写入之前删除NAND分区。这是因为擦除将分区中的所有位都设置为1。因此,当执行原始的NAND写时,确保您首先擦除分区,否则您将在写或读操作期间经历大量的NAND ECC错误。
写入NAND分区的命令如下:

nandwrite -p /dev/mtdX <filename>

符号应替换为要写入的文件的文件路径。

可通过运行以下命令读取NAND:

nanddump /dev/mtdX -f <filename>

符号应替换为要创建的文件名,该文件包含NAND分区的内容。请注意,上面的命令在默认情况下将NAND分区的全部内容保存到一个文件中。如果您只对转储的特定数量的数据感兴趣,可以将其他参数传递给实用程序。
命令行分区
在某些情况下,设备树中定义的分区可能不够或不正确。请注意,一旦在设备树中定义了分区并出现在主线内核版本中,就不能更改分区,因为这会中断NAND闪存上已有数据的用户,并升级到新的内核和设备树。如果不受此问题的影响,可以选择使用命令行覆盖从设备树传递的分区信息。
在TI内核版本中,MTD命令行分区支持构建为模块。要使用它,在内核命令行中添加如下内容(使用bootargs U-Boot变量传递)

setenv bootargs ${bootargs} cmdlinepart.mtdparts=davinci-nand.0:1m(image)ro,-(free-space)

注意,如果分区名中有空格,MTD命令行将解析中断。所以用“free-space”而不是“free space”。将davinci nand.0更改为正确的设备名称。通常可以从dmesgoutput中找到要使用的名称
在“davinci-nand.0”上创建2个MTD分区:
您还可以在内核使用旧分区引导后设置新分区。如果已经探测到NAND驱动程序,则需要重新探测它。比如:

$ modprobe -r davinci_nand
$ modprobe cmdlinepart mtdparts="davinci-nand.0:2m(image)ro,-(free space)"
$ modprobe davinci_nand

此处的davinci和模块名称可能需要根据您使用的SoC进行更改。
U-boot
有关NAND引导以及从NAND引导内核和文件系统的信息,请参阅U-boot User Guide NAND部分。
基于NAND的文件系统
所需软件
构建UBI文件系统依赖于两个应用程序。Ubinize和mkfs.ubifs文件它们都是由Ubuntu的mtd-utils包(apt-get-install-mtd-utils)提供的。下面的说明基于mtd-utils的1.5.0版本,尽管更新的版本可能可以工作。
构建UBI文件系统
在构建UBI文件系统时,您需要有一个目录,该目录包含您计划用于文件系统的确切文件和目录布局。这类似于将文件系统复制到SD卡上以进行引导的文件和目录布局。重要的是,您的文件系统大小要小于NAND中的文件系统分区。
接下来需要一个名为ubinize.cfg的文件。下面包含了你应该使用的ubinize.cfg的确切内容。但是, 请用您选择的名称替换
ubinize.cfg 内容:

[ubifs]
 mode=ubi
 image=<name>.ubifs
 vol_id=0
 vol_type=dynamic
 vol_name=rootfs
 vol_flags=autoresize

要构建ubi文件系统,只需要以下两个命令。下面的符号应该替换为您想要转换为ubifs的目录的路径。符号应该用创建ubinize.cfg时使用的相同值替换。请确保您使用了相同的;通过两个命令和ubinize.cfg。符号和特定于电路板。根据所使用的TI EVM,将这些值替换为下表中的值。
执行命令:

mkfs.ubifs -r <directory path> -o <name>.ubifs <MKUBIFS ARGS>
ubinize -o <name>.ubi <UBINIZE ARGS> ubinize.cfg

一旦这些命令被执行.ubi可以被编程到NAND的指定文件系统分区中

Board Name	MKUBIFS Args	UBINIZE Args
AM335X GP EVM	-F -m 2048 -e 126976 -c 5600	-m 2048 -p 128KiB -s 512 -O 2048
AM437x GP EVM	-F -m 4096 -e 253952 -c 2650	-m 4096 -p 256KiB -s 4096 -O 4096
K2E EVM	-F -m 2048 -e 126976 -c 3856	-m 2048 -p 128KiB -s 2048 -O 2048
K2L EVM	-F -m 4096 -e 253952 -c 1926	-m 4096 -p 256KiB -s 4096 -O 4096
K2G EVM	-F -m 4096 -e 253952 -c 1926	-m 4096 -p 256KiB -s 4096 -O 4096
DRA71x EVM	-F -m 2048 -e 126976 -c 8192	-m 2048 -p 128KiB -s 512 -O 2048

Table:用于构建UBI文件系统映像的参数表
电路板特定配置
下表给出了各种EVM板上存在的NAND设备的详细信息

EVM	NAND Part #	Size	Bus-Widt h	Block-Si ze (KB)	Page-Siz e (KB)	OOB-Size (bytes)	ECC Scheme	Hardware
AM335x GP	MT29F2G0 8AB	256 MB	8	128	2	64	BCH 8	GPMC
AM437x GP	MT29F4G0 8AB	512 MB	8	256	4	224	BCH 16	GPMC
AM437x EPOS	MT29F4G0 8AB	512 MB	8	256	4	224	BCH 16	GPMC
DRA71x	MT29F2G1 6AADWP:D	256 MB	16	128	2	64	BCH 8	GPMC
K2G	MT29F2G1 6ABAFAWP :F	512 MB	16	128	2	64	BCH 16	GPMC
K2E	MT29F4G0 8ABBDAH4 D	1 GB	8	128	2	64	TBD	AEMIF
K2L	MT29F16G 08ADBCAH 4:C	512 MB	8	256	4	224	TBD	AEMIF |
表:NAND闪存规范摘要

AM43xx GP EVM
在这个板上,NAND闪存数据线与eMMC混合,因此eMMC或NAND都可以同时启用。默认情况下,启用NAND。
AM43xx EPOS EVM
在该电路板上,NAND闪存控制线与QSPI混合,因此一次可以使用NAND或QSPI-NOR。默认情况下,启用NAND。
DRA71x EVM
在电路板上,NAND闪存信号在NAND、NOR和视频输出信号之间进行多路复用。因此,要使信号正确多路复用,使NAND工作,必须打开引脚1(左侧第一个引脚)并关闭引脚2。切勿同时打开针脚1和针脚2。这样做可能会损坏电路板或SoC。
注意
除了为NAND引导设置正确的引导模式(SYSBOOT[5:0])之外,还要确保总线宽度(SYSBOOT[13])和多路复用设备(SYSBOOT[12:11])的设置与TRM中给出的一致。
配置(特定于GPMC)
如何在Linux内核中启用OMAP NAND驱动程序?
OMAP NAND驱动程序可以通过Linux内核配置工具启用/禁用。启用以下配置以启用MTD支持以及MTD nand驱动程序支持

Device Drivers  --->
  <*> Memory Technology Device (MTD) support  --->
            [*]   Command line partition table parsing
            <*>   Direct char device access to MTD devices
            <*>   Caching block device access to MTD devices
            <*>   NAND Device Support  --->
                        <*>    NAND Flash device on OMAP2 and OMAP3
            <*>   Enable UBI - Unsorted block images  --->

传输模式
选择正确的总线传输模式
TI的NAND驱动程序支持将数据传输到外部NAND设备的不同模式。
•“prefetch-polled” 预取轮询模式(默认)
•“polled”轮询模式,不预取
•“prefetch-dma”预取启用DMA模式
•“prefetch-irq”预取开启IRQ模式
传输模式可以通过DT binding <ti,nand-xfer-type>在linux内核中配置,请参阅:Linux kernel_docs @ $LINUX/Documentation/devicetree/bindings/mtd/gpmc-nand.txt文件
DMA与非DMA模式(PIO模式)
与主CPU相比,NAND接口是一个低速接口。这意味着对于大多数CPU频率
如果CPU正在通过轮询读取NAND缓冲区,那么它完全能够以最大速度读取NAND。
当然,这样做的代价是,在轮询NAND时,CPU不能做任何其他事情
增加总体CPU负载。
DMA在一次可以读取大量数据时表现最佳。这是必要的,因为在设置、执行和从DMA请求返回时的开销不是微不足道的,以便为DMA读取/写入尽可能多的数据进行最佳补偿。这提供了一个双重目的,即显著降低操作的CPU负载,同时还具有高性能。
当前Linux中的NAND子系统处理的是一次从NAND读取一个页面。不幸的是,页面大小太小,以至于使用DMA(包括Linux DMA软件堆栈)的开销会对性能产生负面影响。根据2016年初使用DMA进行的nand性能测试,根据SOC,nand读写性能降低了10-20%。然而,当通过同一个NAND测试使用轮询时,cpu负载约为99%。当使用DMA模式时,根据SOC,读取的CPU负载约为35%-54%,写入的CPU负载约为15%-30%。
NAND的性能优化
调整NAND设备信号时序
通过将GPMC信号定时与板上的NAND设备相匹配,可以提高NAND的吞吐量。尽管GPMC信号时序配置与NAND设备数据表中给出的配置不同,但它们可以很容易地根据GPMC控制器功能规范中给出的详细信息推导出来。
•有关GPMC信号时序配置以及如何使用这些配置的详细信息,请参阅TI的处理器TRM
第二章通用存储控制器信号控制部分
•在Linux中,GPMC信号时序配置通过DTB指定。
请参阅kernel_docs $LINUX/Documentation/devicetree/bindings/bus/ti-gpmc.txt文件,一些时序配置如<gpmc,rd-cycle-ns>, <gpmc,wr-cycle-ns>对NAND吞吐量的影响比其他配置更大。
•在U-boot中,GPMC信号时序配置在arch/arm/cpu/armv7/…/… mem.c or mem_common.c的初始化过程中指定。
gpmc_init():: struct gpmc_cfg
调整UBIFS
•在挂载UBIFS时指定-o bulk_read(预读)
•调整Linux虚拟机(虚拟机的内核旋钮)
额外的资源
以下链接将帮助您更好地理解NAND Flash技术.

http://www.linux-mtd.infradead.org/doc/nand.html
https://wiki.linaro.org/Flash%20memory
https://lwn.net/Articles/428584/

3.2.2.16. MMC/SD
3.2.2.16.1. 介绍
多媒体卡高速/SDIO(MMC/SDIO)主机控制器在本地主机(LH)如微处理器单元(MPU)或数字信号处理器(DSP)与MMC、SD®存储卡或SDIO卡之间提供接口,并以最小的LH干预处理MMC/SDIO事务。

MMC/SD驱动程序体系结构
3.2.2.16.2 参考文献

1.	JEDEC eMMC Homepage [http://www.jedec.org/category/technology-focus-area/flash-memory-ssds-ufs-emmc]
  1. SD ORG Homepage [http://www.sdcard.org]
    3.2.2.16.3 缩略词和定义
    Acronym Definition
    MMC 多媒体卡
    HS-MMC 高速 MMC
    SD 安全数字
    SDHC SD 高容量
    SDIO SD Input/Output

表:MMC/SD:缩略词
3.2.2.16.4. 特征
SD/MMC驱动程序支持以下功能:
•支持DMA传输的ADMA
•HS400速度模式
•支持内置和模块模式
•支持ext2/ext3/ext4文件系统
3.2.2.16.5. 支持的高速模式

•sd
Platform	SDR104	DDR50	SDR50	SDR25	SDR12
J721e-EVM	Y	Y	Y	Y	Y
•emmc
Platform	DDR52	HS200	HS400
J721e-EVM	Y	Y	Y

3.2.2.16.6. 驱动程序配置
默认的内核配置支持内核内置的MMC/SD驱动程序。使用TI SDHCI驱动程序。为了成功地为J721E选择SDHCI驱动程序,需要在Linux内核中配置以下选项。
•启用SDHCI支持(CONFIG_MMC_SDHCI)

Device Drivers -->
   MMC/SD/SDIO card support -->
      <*> Secure Digital Host Controller Interface support
•启用SDHCI平台帮助程序
(CONFIG_MMC_SDHCI_PLTFM)
Device Drivers -->
   MMC/SD/SDIO card support -->
      Secure Digital Host Controller Interface support -->
         <*> SDHCI platform and OF driver helper

•为TI设备启用SDHCI控制器

(CONFIG_MMC_SDHCI_AM654)
Device Drivers -->
   MMC/SD/SDIO card support -->
      <*> Support for the SDHCI Controller in TI's AM654 SOCs

3.2.2.17. 通用异步收发器UART
3.2.2.17.1 介绍
本指南涵盖了在drivers/tty/serial/8250/8250_omap.c找到的8250 OMAP串行驱动。它支持在TI的Jacinto 7 soc上找到的UART IP。这些soc有8250兼容的UART ip,因此使用Linux内核的通用8250串行驱动程序框架支持。
本文档适用于内核v4.14及更高版本。
支架的设备
• J721E
3.2.2.17.2 驱动程序功能
驱动程序功能
驱动程序支持以下特性:
•硬件流量控制
•标准波特率高达3M Baud
•DMA支持(AM437x除外)
驱动程序配置
驱动源位置: drivers/tty/serial/8250/8250_omap.c
内核的配置选项

在内核中启用的配置

CONFIG_SERIAL_8250 (8250 core support)
CONFIG_SERIAL_8250_CONSOLE (for console on 8250 UARTs)
CONFIG_SERIAL_8250_DMA (for DMA support)
SERIAL_8250_OMAP (Enable 8250 based driver for TI SoCs)

DT配置示例

From k3-j721e.dtsi
aliases {
        ...
        serial0 = &wkup_uart0;
        serial1 = &mcu_uart0;
        serial2 = &main_uart0;
        serial3 = &main_uart1;
        ...
};
From k3-j721e-main.dtsi
main_uart0: serial@2800000 {
        compatible = "ti,j721e-uart", "ti,am654-uart";
        reg = <0x00 0x02800000 0x00 0x100>;
        reg-shift = <2>;
        reg-io-width = <4>;
        interrupts = <GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>;
        clock-frequency = <48000000>;
        current-speed = <115200>;
        power-domains = <&k3_pds 146 TI_SCI_PD_SHARED>;
        clocks = <&k3_clks 146 0>;
        clock-names = "fclk";
};

main_uart1: serial@2810000 {
        compatible = "ti,j721e-uart", "ti,am654-uart";
        reg = <0x00 0x02810000 0x00 0x100>;
        reg-shift = <2>;
        reg-io-width = <4>;
        interrupts = <GIC_SPI 193 IRQ_TYPE_LEVEL_HIGH>;
        clock-frequency = <48000000>;
        current-speed = <115200>;
        power-domains = <&k3_pds 278 TI_SCI_PD_EXCLUSIVE>;
        clocks = <&k3_clks 278 0>;
        clock-names = "fclk";
};

驱动程序使用
一旦探测到驱动程序,内核就会将每个串行端口公开为一个字符设备文件,供用户空间使用:
/dev/ttySX X-串行端口号(zero indexed)
因此UART0->/dev/ttyS0
从串行端口读取:

cat /dev/ttyS0

写入串行端口:

echo "hello" > /dev/ttyS0

更改串行端口波特率:

stty -F /dev/ttyS0 <baudrate>
stty -F /dev/ttyS0 115200

测试UART通信
要么用流量控制线连接两个UART端口,要么在外部环回模式(RTS-CTS, RX-TX)连接单个UART。内部环回模式不能用于测试UART,因为不能保证HW流控可靠工作.
3.2.2.17.3. 基本外部环回测试

stty -F /dev/ttySX 115200 /* Set baudrate to 115200: */
cat /dev/ttySX &
echo hello > /de/ttySX

这应该在shell上打印“hello”。验证RX-TX外部环回的。
用HW流量控制测试UART通信
确保所有引脚都正确连接(RTS-CTS, RX-TX),并设置了pinmux。克隆以下repo工具来测试串口:
https://github.com/nsekhar/serialcheck
serialcheck编译工具:

~/serialcheck$ gcc -o serialcheck serialcheck.c CROSS_COMPILE=arm-linux-gnueabihf-

serialstats编译工具:

~/serialcheck$ gcc -o serialstats serialstats.c CROSS_COMPILE=arm-linux-gnueabihf-

serialcheck:用于配置UART,然后通过UART发送/接收数据。该工具通过将UART传输过程中观察到的任何不一致与参考文件进行比较来报告。
有关详细信息,请运行:
serialcheck --help
serialstats:打印内核的tty层提供的UART统计信息。
有关详细信息,请运行:
serialstats --help
创建随机文件:
dd if=/dev/urandom of=binary count=1 bs=4096
将随机文件复制到两个节点(TX端和RX端)。
在后台启动serialstats来收集统计/错误:

serialstats -d /dev/ttySX -i 1 &

开始测试(启用HW流量控制3MBaud):
接收节点(-m r):

serialcheck -h -d /dev/ttyS0 -f binary -m r -l 10 -b 3000000

发送节点(-m t):

serialcheck -h -d /dev/ttyS0 -f binary -m t -l 10 -b 3000000

先启动接收端,再启动发送端。这将传输“二进制”文件10次,而另一方将期望该文件传输10次。
一旦程序完成,如果测试成功,双方都应该编写类似的代码。
需要0读取1写入循环10/10

cts: 3 dsr: 0 rng: 0 dcd: 0 rx: 40960 tx: 40960 frame 0 ovr 0 par: 0 brk: 0 buf_ovrr: 0

或者有错误的输出示例:
需要20次读取0次写入Oh oh,位置2273(0x8e1)不一致。
原始样品:

000008b0: 28 b2 18 c9 ec b5 2c b3  3a a1 29 b1 fc 27 20 7f   (.....,.:.)..' .
000008c0: 42 f8 d5 cb d8 52 ec b5  c8 76 d3 4b d2 57 44 6a   B....R...v.K.WDj
000008d0: 40 81 6a 82 27 fd 8d 50  84 70 bc 24 6b 3d 88 fd   @.j.'..P.p.$k=..
000008e0: 9f ac 78 a4 76 9b f9 1c  74 2c d6 79 22 60 c5 de   ..x.v...t,.y"`..
000008f0: 02 9c fb 52 21 4b 40 6f  80 69 2e 80 df 12 ba a0   ...R!K@o.i......
00000900: 75 57 d5 22 33 c0 f3 bc  94 f8 aa 22 9d 02 59 20   uW."3......"..Y

收到样品:

000008b0: 28 b2 18 c9 ec b5 2c b3  3a a1 29 b1 fc 27 20 7f   (.....,.:.)..' .
000008c0: 42 f8 d5 cb d8 52 ec b5  c8 76 d3 4b d2 57 44 6a   B....R...v.K.WDj
000008d0: 40 81 6a 82 27 fd 8d 50  84 70 bc 24 6b 3d 88 fd   @.j.'..P.p.$k=..
000008e0: 9f 00 ac 78 a4 76 9b f9  1c 74 2c d6 79 22 60 c5   ...x.v...t,.y"`.
000008f0: de 02 9c fb 52 21 4b 40  6f 80 69 2e 80 df 12 ba   ....R!K@o.i.....
00000900: a0 75 57 d5 22 33 c0 f3  bc 94 f8 aa 22 9d 02 59   .uW."3......"..Y
loops 54878 / 4294967295

cts: 0 dsr: 0 rng: 0 dcd: 0 rx: 224792017 tx: 223379456 frame 0 ovr 1 par: 0 brk: 0 buf_ovrr: 0

不同计数器的含义
cts:流量控制线被断言的次数
dsr/rng/dcd:对应Modem控制线统计
rx/tx: rx和tx计数器。表示会话中发送/接收的字节数。这里的不匹配表示数据丢失。
frame:帧错误数
ovr: UART HW FIFO超时的次数
par:奇偶校验错误数
brk:接收到中断字符的次数。(有关以上错误的详细信息,请参阅: https://en.wikipedia.org/wiki/Universal_asynchronous_receiver-transmitter)
buf_ovrr:由于内核tty层软件缓冲区溢出而丢失的字节数。
HW流量控制的独立测试
只启动串行检查的TX端:

serialcheck -h -d /dev/ttySX -f binary -m t -l 10 -b 3000000

只在RX端运行serialstats,而不启动RX接收器进程.

serialstats -d /dev/ttySX -i 1

如果cts不为零,且未报告ovr和buf_ovrr,则HW流量控制工作。
注意
•确保在启动TX之前启动RX侧。
•RX端等待100秒后报告超时。确保发送端在100秒前开始发送数据。
•serialcheck工具不支持双工模式(-m d->模拟接收和发送)。解决方法是反向启动第二个发送/接收对。
不同错误的可能原因
Frame error/parity error:主要是由于外部环回连接错误或线路上的信号干扰
overruns:该字段对应于HW FIFO overruns。TI的8250 UART IP支持自动HW流量控制,只要驱动程序在IP中启用了流量控制并连接了RTS-CTS线。溢出表示HW流控制线没有连接,或者没有被用户空间打开(使用serialcheck时通过-h选项)。
buf_ovrr:驱动程序错误或tty ldisc驱动程序错误(默认ldisc为n_tty drivers/tty/n_tty.c)。如果接收器不堪重负,ldisc层有责任调用uart_throttle()函数来避免buf_ovrr。
•另一个测试UART驱动程序的工具是:https: //github.com/cbrake/linux-serial-test
•要探索/使用UART端口的其他特性,请使用termios提供的系统调用。h: http://man7.org/linux/man-pages/man3/termios.3.html
•该文件展示了如何启用HW流量控制、设置波特率和更改其他tty设置的示例:https://github.com/nsekhar/serialcheck/blob/master/serialcheck.c
请注意
对于UART通信,总是建议连接HW流量控制线。此外,软件应该明确地启用HW流量控制。否则将导致数据丢失和数据损坏.

  • 12
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 11
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值