在本文中,咱们将介绍关于spi-mem Linux内核框架的工做,该框架将容许在SPI NOR设备和常规SPI设备以及SPI NAND设备上复用SPI控制器驱动程序。html
在过去,SPI是一个简单的协议,总线上的全部设备只共享3根信号线:linux
另外每一个设备有一个独立信号线,用于选择咱们想要通讯的设备:git
但随后SPI存储出现了。它从较小且相对较慢的SPI NORs开始,如dataflash、EEPROMs和SRAMs,而后逐渐发展到较大的SPI NORs和SPI NANDs。像往常同样,当涉及处处理存储时,咱们但愿获得最佳性能表现。SPI总线的限制很快成为瓶颈,所以供应商决定添加更多的I/O线路,并使 MISO/MOSI 线能够双向通讯。如今咱们看到SPI控制器支持最多8路I/O。这就是业内所说的DualSPI QuadSPI和OctoSPI。c#
为了在主从设备的数据传输中用上全部的I/O线,必须有某种主从设备之间的协议,这样双方才能知道,什么时候能够在I/O线上收发数据,应该使用多少根I/O线等。这些由一组从设备预约义的操做规定了如何进行,主设备必须遵循这组操做的规定,进入特定的发送或接收状态。SPI存储器操做一般包括:api
请注意,虽然这个协议倾向于被用于存储设备,但并无什么能限制它只能用于存储设备,若是一些FPGA使用相同的协议来操做非存储设备,我也不会感到惊讶。架构
Linux支持双线SPI和四线SPI模式已经有一段时间了(v3.12), SPI设备驱动程序能够为每一个SPI传输指定I/O通道的数量。使用这种方式,对SPI存储的操做能够被分为屡次SPI传输,每次SPI传输使用预约义数量的I/O通道进行传输。框架
这种方式能够正常工做,直到一些IP供应商决定让它们的SPI控制器更加智能,嵌入某种高级接口,能够在单个的步骤中执行SPI存储器的操做,而不是使用分开的屡次传输操做。(事实上,大多数SPI控制器甚至比这更加智能,能够容许你直接将SPI存储映射到CPU的地址空间,但让咱们先把这种状况留待之后处理吧)。在这种状况下,咱们须要赋予SPI控制器更多的控制权,这样它就能够决定具体该作什么,而没必要从一组分散的SPI传输命令中,重建SPI存储器操做。ide
当时的决定是,将这些控制器专门用于一个任务,控制SPI NORs(当时这是惟一会用到双线和四线模式的状况),SPI NOR框架就是为此而建立的。函数
因为这个决定,咱们如今在Linux中有一个SPI NOR框架用于链接SPI NOR控制器驱动和SPI NOR的逻辑代码(spi-nor 子系统),同时咱们有常规的SPI控制器驱动,能够进行基础的SPI传输(spi 子系统)。然而,从硬件的角度看,能为SPI NOR提供特殊特性的SPI控制器,通常也拥有进行基本传输的能力,便可用于控制常规的SPI设备。不幸的是,基于当前的spi-nor 子系统和spi 子系统是分裂开来的状况,若是一个SPI控制器被spi-nor子系统的驱动支持了,它将没法被用于与spi子系统中的常规设备进行通讯。性能
做为一个针对这个问题的部分的解决方案,->spi_flash_read()操做被添加到结构体 spi_controller中,这容许spi子系统中的常规spi控制器驱动提供一个较优的方式,来从SPI NOR存储中读取数据,这种方式被通用SPI NOR驱动m25p80所使用。然而,这个解决方案是部分的,由于它只优化了读取,而且仅限于SPI NORs。
在当前的架构中,咱们有
咱们以前已经看到,基于SPI NOR框架,SPI NOR存储器已经获得了适当的支持。但NORs 并不是SPI总线上惟一的存储设备,SPI NANDs 正在变得愈来愈流行。
Peter Pan提出了一个遵循SPI NOR模型的,用于支持SPI NAND设备的框架: SPI控制器必须实现SPI NAND控制器接口才能控制SPI NAND。可是当咱们更深刻地参与到这个开发中时,咱们很快意识到沿着这条路走会有多么麻烦,由于这意味着,若是SPI控制器想要同时控制两种设备,就必须同时实现SPI NOR和SPI NAND接口。当SPI NVRAM或任何其余类型的存储制造商决定采用SPI总线时,将会发生什么?再添加一个SPI控制器必须实现的接口?这听起来不是个好主意。
所以咱们决定用另外的方式解决这个问题,尝试找出SPI NANDs和SPI NORs的共同点。SPI NORs和SPI NANDs 指令集不一样,行为和约束也不一样(主要是因为NOR和NAND自己的不一样),但当与设备交互时,都遵循一样的SPI存储器操做语义,这也是高级控制器都在尝试优化的部分。
SPI 存储器层只是提供一种方式给SPI控制器驱动,用于传递高级SPI存储器操做,而不是让它们处理SPI传输细节并自行尝试优化它们。这一样简化了SPI存储器驱动,由于它们只须要按照SPI存储器规范发送SPI存储器操做指令,不须要关心复杂的、不断发展的、依赖具体存储器的接口。
有了这个新的架构,SPI NOR和SPI NAND均可以基于相同的SPI控制器驱动进行支持了。m25p80驱动将被修改为,使用spi-mem接口,取代具备局限性的->spi_flash_read()接口。目前,咱们仍然有专用的SPI NOR控制器驱动,但最终目标是移除它们,并将它们移植为 drivers/spi 下的普通SPI控制器驱动。很是欢迎这方面的帮助和贡献。
SPI存储器的API 由 include/linux/spi/spi-mem.h 描述。
但愿使用SPI存储器API的SPI设备驱动程序,应该将本身声明为spi_mem_drivers,并实现->probe()和->remove()函数。
它们将被传入一个spi_mem对象,它只是一个围绕spi_device对象的简单包装,咱们引入一个不一样的对象的缘由是,咱们但愿可以拓展spi_mem对象,并在须要时附加更多的信息(例如存储器类型,存储器组织方式和其余的高级SPI控制器可能须要的信息)。
当驱动想要执行SPI存储器操做时,它将填充spi_mem_op结构并调用spi_mem_exec_op()。另外,可使用spi_mem_supports_op(),测试一个SPI控制器是否支持特定的存储器操做,使用spi_mem_adjust_op_size(),获取控制器支持的最大传输大小,并尝试拆分数据传输以免超出限制。
如今让咱们看下控制器端。一个但愿优化SPI存储器操做的SPI控制器,能够实现spi_mem_ops接口,该接口包含三个直接对应用户API的方法:
注意,当spi_mem_ops 没有实现时,core层将经过建立由多个SPI传输组成的SPI消息,来添加对该特性的通用支持,就像之前通用SPI NOR控制器驱动程序(名为m25p80)所作的那样。
如你所见,这些API很是直截了当,因此但愿有更多的SPI存储器驱动可以转换为使用它,而不是手动建立包含多个SPI传输的SPI消息。
一部分已经被贡献出去并合并,计划成为Linux 4.18的一部分:
先进的SPI控制器不只可以优化SPI存储器操做的执行,它们能够进一步将全部存储器访问的复杂性隐藏起来,提供一个直接映射的IOMEM区域,对此区域的访问会自动在总线上触发SPI存储器操做,为你完成数据的收发,这样的行为就像一个链接在并行的内存总线上的内存。能够想象,这将容许更高的吞吐量和更少的用于SPI存储器操做管理的CPU时间,但这同时也是一个难以经过常规的方式进行支持的功能。咱们已经在linux-mtd邮件列表上发布了一个支持这种直接映射功能的建议。
如前所述,另外一个具备挑战性的主题是,将全部的SPI NOR控制器驱动转换为基于SPI mem模型,以便全部的QSPI控制器都真正表现为SPI控制器而非SPI NOR控制器。这可能须要一些时间,由于目前在driver/mtd/spi-nor 下有10个驱动,咱们只知道其中2个被转换为了SPI mem方法(fsl-quadspi和atmel-quadspi)。
本文地址 http://www.javashuo.com/article/p-bkcyefib-ea.html
译自 https://bootlin.com/blog/spi-mem-bringing-some-consistency-to-the-spi-memory-ecosystem/
原做者 Boris Brezillon