spi-mem: 爲SPI存儲器生態帶來一些一致性

在本文中,咱們將介紹關於spi-mem Linux內核框架的工做,該框架將容許在SPI NOR設備和常規SPI設備以及SPI NAND設備上覆用SPI控制器驅動程序。html

從SPI到雙線、四線、八線SPI

在過去,SPI是一個簡單的協議,總線上的全部設備只共享3根信號線:linux

  • MISO: Master In Slave Out,主設備輸入從設備輸出線
  • MOSI: Master Out Slave In,主設備輸出從設備輸入線
  • SCLK: Serial Clock,時鐘線

另外每一個設備有一個獨立信號線,用於選擇咱們想要通訊的設備:git

  • SS: Slave Select,從設備選擇線 (有時也稱爲片選線CS,Chip Select)

但隨後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

  • 1字節的操做碼,表示將要進行從操做 (將來將很快會將出現2字節的操做碼,請作好準備)
  • 0-N 字節的地址,其含義取決於操做碼(能夠是絕對內存地址,或其餘含義)
  • 0-N 字節的啞字節,使得從設備有足夠的時間來進入操做碼請求的特定狀態,一樣,啞字節的數量時取決於操做碼的
  • 0-N 字節的輸入或輸出數據,方向是取決於操做碼

請注意,雖然這個協議傾向於被用於存儲設備,但並無什麼能限制它只能用於存儲設備,若是一些FPGA使用相同的協議來操做非存儲設備,我也不會感到驚訝。架構

Linux SPI 生態

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存儲器通信的協議。這個框架依賴於結構體spi_nor中列出的接口,這些接口的實現是:
  • 專用的SPI NOR控制器,支持專用於SPI NORs的高級SPI控制器
  • m25p80驅動,提供一樣的接口,但基於常規SPI控制器驅動,可能具備->spi_flash_read()的優化

是什麼促使咱們提出SPI存儲器接口?

咱們以前已經看到,基於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是什麼樣子的?

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的方法:

  • ->exec_op():執行存儲器操做,若是不支持則返回-ENOTSUPP。
  • ->supports_op(): 檢查這個存儲器操做是否支持。
  • ->adjust_op_size(): 調整存儲器操做的數據傳輸大小,以符合對齊要求和最大FIFO大小的約束。

注意,當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

相關文章
相關標籤/搜索