1. 程式人生 > >qspi flash驅動開發記錄

qspi flash驅動開發記錄

目錄

畢業也有兩年了,從大一接觸嵌入式以來快六年了,這六年學到的東西也有很多。以前都是看別人的部落格,自有寫部落格想法以來也有一段時間,此部落格作為部落格的開端,接下來的工作學習中會把所見所學記錄在部落格中。希望以後能夠多寫部落格,很多疏漏的地方還望大家指正,共同進步

驅動概括

以前在學校大多數嵌入式都是裸機跑起來,驅動非常簡單;然後就是一些簡單的嵌入式作業系統,比如說freeRtos,這些也都是裸機的驅動;linux驅動就比較複雜,有它自己的驅動框架,並且這個框架十分龐大。這個linux驅動程式就是:

裸機驅動 + linux驅動框架

即按照linux框架來組織驅動程式,所以學好裸機驅動之後,就需要畫大功夫去學習linux驅動框架

驅動框架演變

1,裝置和驅動在一起

裝置相關的資訊,比如暫存器地址、大小等資訊都是在一個原始檔中;以韋東山視訊中最簡單的led程式為例耦合性比較強。

2,裝置和驅動分離

裝置和驅動分離開來,裝置資訊放在一個檔案中,驅動程式放在一個檔案中;兩個檔案分別載入,在核心啟動的時候根據名字匹配,匹配成功後就呼叫probe()函式,進行相關的初始化。

3,裝置樹的引入

由於之前的裝置和驅動都是編譯進核心中,且沒修改一下裝置地址就需要重新編譯一下核心。並且平臺資訊太亂,所以後面就把裝置資訊單獨放到一個檔案中以文字的形式組織起來。並且單獨編譯,不與核心一起編譯

裝置樹

1)前面的匯流排裝置驅動模型中,硬體資源來自於leds_dev.c裡面的資訊,這樣會導致不同的板子,會新增不同的硬體資源資訊,造成核心的臃腫。
2)使用裝置樹後,核心不再包含硬體的描述,硬體描述放在單獨的DTS裡面,然後編譯成二進位制的DTB,在U-Boot啟動的時候載入進去,然後核心進行解析。
3)DTS、DTC和DTB之間的關係:
DTS經過DTC編譯得到DTB,DTB通過DTC反編譯得到DTS.
4)ARM中,所有的DTS檔案放在arch/arm/boot/dts目錄中,為了簡化,將Soc公用部分提取了出來作為dtsi,類似標頭檔案。
5)DTC編譯工具的原始碼在scripts/dtc目錄中,編譯核心時,編譯核心時,需要使能才能將原始碼編譯成工具,對應於scripts/dtc/Makefile中"hostprogs-y:=dtc"。Ubuntu也可直接安裝DTC工具:

例:

/include/ “skeleton.dtsi”
/ {
compatible = “xlnx,zynq-7000”;

cpus {
	#address-cells = <1>;
	#size-cells = <0>;

	[email protected] {
		compatible = "arm,cortex-a9";
		device_type = "cpu";
		reg = <0>;
		clocks = <&clkc 3>;
		clock-latency = <1000>;
		cpu0-supply = <&regulator_vccpint>;
		operating-points = <
			/* kHz    uV */
			666667  1000000
			333334  1000000
		>;
	};

	[email protected] {
		compatible = "arm,cortex-a9";
		device_type = "cpu";
		reg = <1>;
		clocks = <&clkc 3>;
	};
};

pmu {
	compatible = "arm,cortex-a9-pmu";
	interrupts = <0 5 4>, <0 6 4>;
	interrupt-parent = <&intc>;
	reg = < 0xf8891000 0x1000 0xf8893000 0x1000 >;
};

regulator_vccpint: [email protected] {
	compatible = "regulator-fixed";
	regulator-name = "VCCPINT";
	regulator-min-microvolt = <1000000>;
	regulator-max-microvolt = <1000000>;
	regulator-boot-on;
	regulator-always-on;
};

amba: amba {
	compatible = "simple-bus";
	#address-cells = <1>;
	#size-cells = <1>;
	interrupt-parent = <&intc>;
	ranges;

	adc: [email protected] {
		compatible = "xlnx,zynq-xadc-1.00.a";
		reg = <0xf8007100 0x20>;
		interrupts = <0 7 4>;
		interrupt-parent = <&intc>;
		clocks = <&clkc 12>;
	};

	can0: [email protected] {
		compatible = "xlnx,zynq-can-1.0";
		status = "disabled";
		clocks = <&clkc 19>, <&clkc 36>;
		clock-names = "can_clk", "pclk";
		reg = <0xe0008000 0x1000>;
		interrupts = <0 28 4>;
		interrupt-parent = <&intc>;
		tx-fifo-depth = <0x40>;
		rx-fifo-depth = <0x40>;
	};

	can1: [email protected] {
		compatible = "xlnx,zynq-can-1.0";
		status = "disabled";
		clocks = <&clkc 20>, <&clkc 37>;
		clock-names = "can_clk", "pclk";
		reg = <0xe0009000 0x1000>;
		interrupts = <0 51 4>;
		interrupt-parent = <&intc>;
		tx-fifo-depth = <0x40>;
		rx-fifo-depth = <0x40>;
	};

	gpio0: [email protected] {
		compatible = "xlnx,zynq-gpio-1.0";
		#gpio-cells = <2>;
		#interrupt-cells = <2>;
		clocks = <&clkc 42>;
		gpio-controller;
		interrupt-controller;
		interrupt-parent = <&intc>;
		interrupts = <0 20 4>;
		reg = <0xe000a000 0x1000>;
	};

	i2c0: [email protected] {
		compatible = "cdns,i2c-r1p10";
		status = "disabled";
		clocks = <&clkc 38>;
		interrupt-parent = <&intc>;
		interrupts = <0 25 4>;
		reg = <0xe0004000 0x1000>;
		#address-cells = <1>;
		#size-cells = <0>;
	};

	i2c1: [email protected] {
		compatible = "cdns,i2c-r1p10";
		status = "disabled";
		clocks = <&clkc 39>;
		interrupt-parent = <&intc>;
		interrupts = <0 48 4>;
		reg = <0xe0005000 0x1000>;
		#address-cells = <1>;
		#size-cells = <0>;
	};

	intc: [email protected] {
		compatible = "arm,cortex-a9-gic";
		#interrupt-cells = <3>;
		interrupt-controller;
		reg = <0xF8F01000 0x1000>,
		      <0xF8F00100 0x100>;
	};

	L2: [email protected] {
		compatible = "arm,pl310-cache";
		reg = <0xF8F02000 0x1000>;
		interrupts = <0 2 4>;
		arm,data-latency = <3 2 2>;
		arm,tag-latency = <2 2 2>;
		cache-unified;
		cache-level = <2>;
	};

	mc: [email protected] {
		compatible = "xlnx,zynq-ddrc-a05";
		reg = <0xf8006000 0x1000>;
	};

	ocmc: [email protected] {
		compatible = "xlnx,zynq-ocmc-1.0";
		interrupt-parent = <&intc>;
		interrupts = <0 3 4>;
		reg = <0xf800c000 0x1000>;
	};

	uart0: [email protected] {
		compatible = "xlnx,xuartps", "cdns,uart-r1p8";
		status = "disabled";
		clocks = <&clkc 23>, <&clkc 40>;
		clock-names = "uart_clk", "pclk";
		reg = <0xE0000000 0x1000>;
		interrupts = <0 27 4>;
	};

	uart1: [email protected] {
		compatible = "xlnx,xuartps", "cdns,uart-r1p8";
		status = "disabled";
		clocks = <&clkc 24>, <&clkc 41>;
		clock-names = "uart_clk", "pclk";
		reg = <0xE0001000 0x1000>;
		interrupts = <0 50 4>;
	};

	spi0: [email protected] {
		compatible = "xlnx,zynq-spi-r1p6";
		reg = <0xe0006000 0x1000>;
		status = "disabled";
		interrupt-parent = <&intc>;
		interrupts = <0 26 4>;
		clocks = <&clkc 25>, <&clkc 34>;
		clock-names = "ref_clk", "pclk";
		#address-cells = <1>;
		#size-cells = <0>;
	};

	spi1: [email protected] {
		compatible = "xlnx,zynq-spi-r1p6";
		reg = <0xe0007000 0x1000>;
		status = "disabled";
		interrupt-parent = <&intc>;
		interrupts = <0 49 4>;
		clocks = <&clkc 26>, <&clkc 35>;
		clock-names = "ref_clk", "pclk";
		#address-cells = <1>;
		#size-cells = <0>;
	};

	qspi: [email protected] {
		clock-names = "ref_clk", "pclk";
		clocks = <&clkc 10>, <&clkc 43>;
		compatible = "xlnx,zynq-qspi-1.0";
		status = "disabled";
		interrupt-parent = <&intc>;
		interrupts = <0 19 4>;
		reg = <0xe000d000 0x1000>;
		#address-cells = <1>;
		#size-cells = <0>;
	};

	smcc: [email protected] {
		#address-cells = <1>;
		#size-cells = <1>;
		status = "disabled";
		clock-names = "memclk", "aclk";
		clocks = <&clkc 11>, <&clkc 44>;
		compatible = "arm,pl353-smc-r2p1";
		interrupt-parent = <&intc>;
		interrupts = <0 18 4>;
		ranges ;
		reg = <0xe000e000 0x1000>;
		nand0: [email protected] {
			status = "disabled";
			compatible = "arm,pl353-nand-r2p1";
			reg = <0xe1000000 0x1000000>;
			#address-cells = <0x1>;
			#size-cells = <0x1>;
		};
		nor0: [email protected] {
			status = "disabled";
			compatible = "cfi-flash";
			reg = <0xe2000000 0x2000000>;
			#address-cells = <1>;
			#size-cells = <1>;
		};
	};

	gem0: [email protected] {
		compatible = "cdns,zynq-gem", "cdns,gem";
		reg = <0xe000b000 0x1000>;
		status = "disabled";
		interrupts = <0 22 4>;
		clocks = <&clkc 30>, <&clkc 30>, <&clkc 13>;
		clock-names = "pclk", "hclk", "tx_clk";
		#address-cells = <1>;
		#size-cells = <0>;
	};

	gem1: [email protected] {
		compatible = "cdns,zynq-gem", "cdns,gem";
		reg = <0xe000c000 0x1000>;
		status = "disabled";
		interrupts = <0 45 4>;
		clocks = <&clkc 31>, <&clkc 31>, <&clkc 14>;
		clock-names = "pclk", "hclk", "tx_clk";
		#address-cells = <1>;
		#size-cells = <0>;
	};

	sdhci0: [email protected] {
		compatible = "arasan,sdhci-8.9a";
		status = "disabled";
		clock-names = "clk_xin", "clk_ahb";
		clocks = <&clkc 21>, <&clkc 32>;
		interrupt-parent = <&intc>;
		interrupts = <0 24 4>;
		reg = <0xe0100000 0x1000>;
	};

	sdhci1: [email protected] {
		compatible = "arasan,sdhci-8.9a";
		status = "disabled";
		clock-names = "clk_xin", "clk_ahb";
		clocks = <&clkc 22>, <&clkc 33>;
		interrupt-parent = <&intc>;
		interrupts = <0 47 4>;
		reg = <0xe0101000 0x1000>;
	};

	slcr: [email protected] {
		#address-cells = <1>;
		#size-cells = <1>;
		compatible = "xlnx,zynq-slcr", "syscon", "simple-bus";
		reg = <0xF8000000 0x1000>;
		ranges;
		clkc: [email protected] {
			#clock-cells = <1>;
			compatible = "xlnx,ps7-clkc";
			fclk-enable = <0xf>;
			clock-output-names = "armpll", "ddrpll", "iopll", "cpu_6or4x",
					"cpu_3or2x", "cpu_2x", "cpu_1x", "ddr2x", "ddr3x",
					"dci", "lqspi", "smc", "pcap", "gem0", "gem1",
					"fclk0", "fclk1", "fclk2", "fclk3", "can0", "can1",
					"sdio0", "sdio1", "uart0", "uart1", "spi0", "spi1",
					"dma", "usb0_aper", "usb1_aper", "gem0_aper",
					"gem1_aper", "sdio0_aper", "sdio1_aper",
					"spi0_aper", "spi1_aper", "can0_aper", "can1_aper",
					"i2c0_aper", "i2c1_aper", "uart0_aper", "uart1_aper",
					"gpio_aper", "lqspi_aper", "smc_aper", "swdt",
					"dbg_trc", "dbg_apb";
			reg = <0x100 0x100>;
		};

		rstc: [email protected] {
			compatible = "xlnx,zynq-reset";
			reg = <0x200 0x48>;
			#reset-cells = <1>;
			syscon = <&slcr>;
		};

		pinctrl0: [email protected] {
			compatible = "xlnx,pinctrl-zynq";
			reg = <0x700 0x200>;
			syscon = <&slcr>;
		};
	};

	dmac_s: [email protected] {
		compatible = "arm,pl330", "arm,primecell";
		reg = <0xf8003000 0x1000>;
		interrupt-parent = <&intc>;
		interrupt-names = "abort", "dma0", "dma1", "dma2", "dma3",
			"dma4", "dma5", "dma6", "dma7";
		interrupts = <0 13 4>,
				<0 14 4>, <0 15 4>,
				<0 16 4>, <0 17 4>,
				<0 40 4>, <0 41 4>,
				<0 42 4>, <0 43 4>;
		#dma-cells = <1>;
		#dma-channels = <8>;
		#dma-requests = <4>;
		clocks = <&clkc 27>;
		clock-names = "apb_pclk";
	};

	devcfg: [email protected] {
		clock-names = "ref_clk", "fclk0", "fclk1", "fclk2", "fclk3";
		clocks = <&clkc 12>, <&clkc 15>, <&clkc 16>, <&clkc 17>, <&clkc 18>;
		compatible = "xlnx,zynq-devcfg-1.0";
		interrupt-parent = <&intc>;
		interrupts = <0 8 4>;
		reg = <0xf8007000 0x100>;
		syscon = <&slcr>;
	};

	efuse: [email protected] {
		compatible = "xlnx,zynq-efuse";
		reg = <0xf800d000 0x20>;
	};

	global_timer: [email protected] {
		compatible = "arm,cortex-a9-global-timer";
		reg = <0xf8f00200 0x20>;
		interrupts = <1 11 0x301>;
		interrupt-parent = <&intc>;
		clocks = <&clkc 4>;
	};

	ttc0: [email protected] {
		interrupt-parent = <&intc>;
		interrupts = <0 10 4>, <0 11 4>, <0 12 4>;
		compatible = "cdns,ttc";
		clocks = <&clkc 6>;
		reg = <0xF8001000 0x1000>;
	};

	ttc1: [email protected] {
		interrupt-parent = <&intc>;
		interrupts = <0 37 4>, <0 38 4>, <0 39 4>;
		compatible = "cdns,ttc";
		clocks = <&clkc 6>;
		reg = <0xF8002000 0x1000>;
	};

	scutimer: [email protected] {
		interrupt-parent = <&intc>;
		interrupts = <1 13 0x301>;
		compatible = "arm,cortex-a9-twd-timer";
		reg = <0xf8f00600 0x20>;
		clocks = <&clkc 4>;
	};

	usb0: [email protected] {
		compatible =  "xlnx,zynq-usb-1.00.a", "chipidea,usb2";
		status = "disabled";
		clocks = <&clkc 28>;
		interrupt-parent = <&intc>;
		interrupts = <0 21 4>;
		reg = <0xe0002000 0x1000>;
		phy_type = "ulpi";
	};

	usb1: [email protected] {
		compatible =  "xlnx,zynq-usb-1.00.a", "chipidea,usb2";
		status = "disabled";
		clocks = <&clkc 29>;
		interrupt-parent = <&intc>;
		interrupts = <0 44 4>;
		reg = <0xe0003000 0x1000>;
		phy_type = "ulpi";
	};

	watchdog0: [email protected] {
		clocks = <&clkc 45>;
		compatible = "cdns,wdt-r1p2";
		interrupt-parent = <&intc>;
		interrupts = <0 9 1>;
		reg = <0xf8005000 0x1000>;
		timeout-sec = <10>;
	};
};

};

qspi flash預備知識

由於在工作中使用的事xilinx 的zynq平臺,公司的產品也是基於此平臺,以後的驅動學習也是基於此平臺。

zynq qspi flash controller介紹

1,概括
控制器有三種操作模式:I/O模式;線性地址模式;原始的SPI模式。
(1)在I/O模式,使用flash裝置協議來互動;軟體使用四個TXD暫存器來寫flash命令以及資料,通過讀RXD暫存器來接受flash資料。
(2)線性地址模式使用一個裝置子集來減少軟體開銷,在I/O模式下需要軟體需要去讀取flash儲存器。線性模式使用硬體去處理給flash儲存器的命令以及控制flash裝置到AXI介面的資料流傳輸。這個控制器讓AXI介面訪問flash 儲存器像訪問ROM儲存器一樣。
(3)原始spi模式:QSPI控制器表現的跟普通SPI控制器一樣。
1.1,特點

  • 線性地址模式傳輸的32-bit AXI介面
  • I/O模式傳輸的32-bit APB介面
  • 可程式設計的來自micron和spansion公司的flash儲存器匯流排協議。
  • 普通spi模式以及可擴充套件的效能:1x,2x,4x,8x I/O寬度
  • 靈活的I/O
    • 單 SS 4位flash儲存器介面模式
    • 雙 SS 8位並行1/O儲存器介面模式
    • 雙SS 4位堆疊I/O儲存器模式
    • 單SS,原始SPI模式
  • 每個裝置16MB地址(兩個裝置32MB)
  • 裝置容量高達128Mb
  • I/O 模式(flash控制和資料)
    • 軟體處理指令以及管理flash操作
    • FIFO控制中斷
    • 63-word接受fifo,63-word傳送fifo
  • 線性地址模式(可執行的讀訪問)
    • 儲存器的讀與寫是通過控制器來執行的
    • 多達4個讀請求的AXI portbuffer
    • AXI遞增和封裝地址函式

1.2,系統圖
系統圖
線性地址模式下的地址對映和裝置匹配

當只連線一個裝置的時候直接地址操作對映是從FC000000到最大FCFFFFFF(16MB)。連線兩個裝置的地址對映取決於儲存器裝置以及I/O配置。在兩個裝置系統中,QSPI裝置需要來自相同的供應商,這樣他們的協議才會是一樣的。
八位並行I/O模式也需要裝置具有相同的容量,地址操作對映是從FC000000到最大FDFFFFFF(32MB)
四位stacked I/O模式,裝置可以有不通的容量,但是必須是相同的協議。如果使用了兩個不通容量的裝置,xilinx推薦使用一個128Mb的裝置在低地址。這種模式下,QSPI 0 是前16MB,QSPI是後16MB。如果第一裝置小於16MB,那麼在兩個裝置之間就會有地址空缺
模組框圖
在這裡插入圖片描述

1.4 操作限制
當只連線一個裝置時,必須連線在QSPI0,當使用兩個裝置時,兩個裝置必須是一樣的(相同的供應商、相同的協議)
QSPI控制器的MIO引腳與NOR/NAND的控制器引腳是衝突的,當QSPI被使用的時候NOR/NAND介面就不能被使用

2,功能描述
QSPI flash控制器既可以工作在I/O模式下也可以工作線上性地址模式。對於讀取資料,控制器在I/O模式以及線性地址模式都支援singal、dual以及quad讀模式。對於寫入資料,signal和quad模式是在I/O模式下支援,而線上性地址模式下不支援寫入資料。
2.1,操作模式
在這裡插入圖片描述
在I/O模式下,軟體可以通過設定對應的暫存器位來選擇各種操作方式。線上性地址模式下,控制器執行左右必要的讀資料管理,軟體使用就跟ROM一樣

2.1,I/O模式
在I/O模式下,命令和資料的指令是根據QSPI的協議通過軟體來實現的。這個不同格式的命令是排列好的,其中包括指令和資料,之後通過重複寫TXD暫存器來把這些命令傳遞到TxFIFO中去。這個傳輸邏輯電路按照QSPI介面的說明連載TxFIFO的內容,然後傳送資料到flash儲存器,當傳輸邏輯在傳輸資料的時候也會採集接受的資料,並儲存在TxFIFO中。
在讀取命令的情況下,資料在命令和地址之後被傳遞,這個MIO在傳輸邏輯的控制下在恰當的時候從輸出轉變為輸入。資料移位到RxFIFO中既有有效資料也有無用的資料
軟體需要過濾RxFIFO的原始資料來獲得有用的資料,控制器即修改軟體寫入指令得到資料也不修改讀取命令返回的資料。
控制器支援小段模式,最小位元組的最小位首先被傳遞。
資料流控制
I/O模式下載資料傳輸中不同種資料流控制。使用者需要選擇自動模式還是手動模式,通過控制 config_reg.MANSTARTEN (Man_start_com).在手動模式下,使用者能夠進一步懸著手動或者自動晶片選擇,通過控制Config_reg.SSFORCE (Manaual_CS).宣告晶片選擇訊號在命令流的開始階段。在CS有效之後,DO資料是給flash 儲存器的命令
在自動模式下,整個傳輸序列,包括晶片使能引腳的控制都是硬體自動完成的。期間不需要軟體的參與。通過寫TxD資料到TxFIFO之後,傳輸立刻開始,晶片選擇自動有效。當TxFIFO空之後傳輸完成,晶片選擇訊號自動無效。在這個模式下,為了實現連續的資料傳輸,軟體寫TxFIFO的速率必須大於等於MIO傳輸資料的速率。這將是困難的,因為讀取RXD資料和寫TXD資料是在APB時鐘的速率下。
在手動模式下,使用者控制資料的傳輸。在這種情況下,軟體需要些整個傳輸佇列到TxFIFO直到TxFIFO滿了。通過寫Man_start_en位,控制器開始工作,使能CS,開始吧TxFIFO移出,同時移入資料到RxFIFO,正確的控制MIO的輸入/輸出狀態,傳輸整個對流直到TxFIFO為空然後使CS無效,每個命令最大的資料佇列受TxFIFO深度的影響是252bytes。
在手動模式下,使用者可以在通過控制開始傳輸之外控制晶片使能、軟體之後寫入傳輸佇列,軟體使能CS,但是在傳輸完成之後,CS在TxFIFO空了之後不會使能無效。軟體可以繼續填寫之前沒有寫完的命令資料到TxFIFO中。這種方法消除了前面的單個命令長度的限制可以單次傳輸非常多的資料。在一個命令傳輸完成之後通過寫Manual_CS位來軟體失能CS訊號。
** I/O模式傳輸暫存器(TXD)**
軟體寫flash 裝置需要的資料流,根據QSPI裝置廠商的說明。控制器有4個32-bit只寫暫存器,這些暫存器用來寫命令資料去獲得狀態或者讀寫儲存器中的資料,Qspi TXD暫存器的寫入形式如下圖示所示,寫這四個暫存器最後都會寫入到TxFIFO當中去
使用者必須在一下連續訪問中清空TxFIFO
*TXD0 to TXD1/TXD2/TXD3
*TXD1 to TXD0/TXD1/TXD2/TXD3
*TXD2 to TXD0/TXD1/TXD2/TXD3
*TXD3 to TXD0/TXD1/TXD2/TXD3
對於TXD0到TXD0訪問,您不需要清空FIFO
在這裡插入圖片描述
FIFO讀寫
TxFIFO和RxFIFO共用同一個時鐘。因此,對於每byte包括命令和地址資料從TxFIFO中移出,TxFIFO就會同時移入。
為了從QSPI讀取資料,軟體需要寫對應的命令,地址、模式(當時Quad或者Dual I/O模式)以及QSPI flash儲存器需要的虛擬間隔週期到TxFIFO中。另外,軟體必須要寫入另外的dummy資料,這些多餘的dummy資料為了提供資料移位到RxFIFO所需要的時鐘。
2.4 I/O模式考慮
TxFiFO中斷狀態暫存器在資料真正可讀之前就只為置位。在讀取這個狀態暫存器的延時時間裡,資料就變得正真可讀。
在讀命令中,軟體必須往TxFIFO中寫入dummy資料來從裝置中讀取資料,在自動模式下,如果TxFIFO為空,QSPI控制器就會失能CS。為了接受資料,軟體必須傳送讀命令和地址資料給裝置。
2.5,線性地址模式
線性地址模式自動實現QSPI命令轉換。
線上性地址模式下,這個flash memoy子系統像一個自讀儲存器
2.6,不支援的裝置
有些自定義的協議在這裡沒有被支援
2.7,支援的讀寫命令
Supports commands that transfers address one bit per rising edge of SCK and return data 1, 2, or 4 bits of data per rising edge of SCK. These commands are called Read or Fast Read for 1-bit data; Dual Output Read for 2-bit data, and Quad Output for 4-bit data.
Supports commands that transfer both address and data 2 or 4 bits per rising edge of SCK. These are called Dual I/O for 2-bit and Quad I/O for 4-bit.
在這裡插入圖片描述

不通的命令下控制器會自動的識別是dual spi還是quad spi。這以外的命令,控制器採用標準的spi時序。

qspi協議介紹

標準SPI
標準的spi有四線,clk,cs,miso,mosi,是一種通用的序列匯流排標準

dual spi
針對flash儲存器,輸入輸出同時工作的全雙工不太實用,所以針對flash controller的dual spi資料線的數量不變,但是可以同時輸入輸出2bit資料,MISO,MOSI即可以作為輸入,也可以作為輸出。加快了資料的傳輸。

quad spi
quad spi 協議是在spi的基礎上把資料線由原來的2根擴充套件為四根,四根可以同時為輸入或者是輸出。一般都是針對quad spi flash來做的控制,加快了資料的傳輸

qspi flash 介紹

有各種命令,包括dual spi 、標準spi、quad spi通訊方式,每個命令對應著一種時序,檢視資料手冊以及主控的資料手冊,完成對應的控制

塊裝置驅動框架介紹

塊裝置概念:塊裝置是指只能以塊為單位進行訪問的裝置,塊的大小一般是512個位元組的整數倍。常見的塊裝置包括flash,SD卡,光碟等

1,塊裝置驅動的系統架構

在這裡插入圖片描述

qspi flash驅動介紹

出現的問題記錄

1. 系統無法軟重啟

a,發現無法軟體重啟,只是把啟動用的flash掛到linux系統中,所以應該是flash導致的。把裝置樹中的flash去掉,就可以正常啟動。接下來通過現象排查是死在那個地方
b,斷電能夠正常起來;在核心中加入列印資訊,發現往軟重啟暫存器裡寫入了重啟命令,猜測系統已經重啟,但是沒有啟動是因為啟動部分的問題。
c,直接外部硬體復位引腳復位也沒有反應,說明系統是在啟動的時候沒有從flash讀取到啟動檔案導致的。
d,猜測應該是flash沒有處在一個初始化的狀態,到時zynq沒法正常的操作。
e,參考開發板,掛在flash能夠正常啟動,對比flash_probe函式,發現兩個函式的區別,一個設定了4位地址模式,一個是三位地址模式,檢視資料手冊,flash預設是3位地址模式,zynq啟動的時候也是以三位地址模式來讀取flash。
f,修改驅動,設定讀寫模式為3位地址模式。