Plattformreferenz RK-KF-YF-020 (CN) / RK-KF-YF-075 (EN) V3.7.0 für aufgeführte SoCs und Linux-4.4/4.19+-BSPs; jede Funktion prüfen. Konkrete ArmSoM-/SDK-Unterstützung unbestätigt, keine Hardwarevalidierung. SoC, Kernel, Patches, Controller, IOMUX, Spannungen und Verdrahtung prüfen. Befehle/Ergebnisse sind Herstellerbeispiele, keine ArmSoM-Messungen. Alle vier Sprachen folgen der chinesischen technischen Basis mit englischen Ergänzungen. Abweichende Codebeispiele stehen separat am Ende. ZH nutzt chinesische, EN/RU/DE englische Originalbilder.
1. Rockchip-SPI-Eigenschaften
SPI (serial peripheral interface), Linux-4.4-Treiber: standardmäßig Motorola SPI; 8/16 Bit; programmierbarer Takt; vier Modi; ein bis zwei CS je Controller. Im Slave nur SPI_CS0N als CS-Eingang, während Übertragung nicht auf GPIO umschalten und kein CS1N-Ersatz. Linux 4.19 ergänzt Framework-Unterstützung für Slave und Master.
1.1 SPI-Schnittstellenrate
| SOC | Master Mode Interface maximum speed |
Slave Mode Interface maximum speed |
|---|---|---|
| RK3506 | 50MHz | 50MHz |
| RV1126B | 50MHz/25MHz/20MHz | 50MHz/25MHz/20MHz |
| RV1106B/RV1103B | 50MHz | 33MHz |
| RK3576 | 50MHz | 33MHz |
| RK3562 | 50MHz | 33MHz |
| RK3528 | 50MHz | 33MHz |
| RV1106/RV1103 | 50MHz | 33MHz |
| RK3588 | 50MHz | 33MHz |
| RV1126/RV1109 | 50MHz | 16MHz |
| RK3568 | 50MHz | 33MHz |
| RK1808 | 50MHz | 16MHz |
| RK3308 | 50MHz | 16MHz |
| Others | 50MHz | 16MHz |
Maximalrate theoretisch, abhängig vom PCB und zu messen. PLL-Teilung erreicht eventuell nicht exakt den Grenzwert; höchste erreichbare Rate gilt. RV1126B: spi1m1 bis 50MHz, spi0m0 bis 25MHz, andere bis 20MHz.
2. Kernelsoftware
2.1 Quellcodepfade
drivers/spi/spi.c spi驱动框架
drivers/spi/spi-rockchip.c rk spi各接⼝实现
drivers/spi/spi-rockchip-slave.c rk spi slave各接⼝实现
drivers/spi/spidev.c 创建spi设备节点,⽤⼾态使⽤。
drivers/spi/spi-rockchip-test.c spi测试驱动,需要⾃⼰⼿动添加到Makefile编译
Documentation/spi/spidev_test.c ⽤⼾态spi测试⼯具
2.2 SPI konfigurieren: RK als Master
Kernelkonfiguration
Device Drivers --->
[*] SPI support --->
<*> Rockchip SPI controller driver
DTS-Knoten
&spi1 { //引⽤spi 控制器节点
status = "okay";
//assigned-clocks = <CLK_SPI1>; //默认不⽤配置,CLK_SPIn 请从 soc 对应的 dtsi ⾥确认
//assigned-clock-rates = <200000000>; //默认不⽤配置,SPI 设备⼯作时钟值
//dma-names; //默认不⽤配置,关闭 DMA ⽀持,仅⽀持 IRQ 传输
//rockchip,poll-only; //默认不⽤配置,开启后强制使⽤ CPU 传输,仅⽀持 master mode 下配置
//rx-sample-delay-ns = <10>; //默认不⽤配置,读采样延时,详细参考 “常⻅问 题”“延时采样时钟配置⽅案” 章节
//rockchip,autosuspend-delay-ms = <500>; //默认不⽤配置,Runtime PM autosuspend 延 时,详细参考 “SPI 传输速率及 CPU 负载优化”
//rockchip,rt; //默认不⽤配置,将spi数据传输进程放到 SCHED_FIFO类中,其优先级为50
spi_test@10 {
compatible ="rockchip,spi_test_bus1_cs0"; //与驱动对应的名字
reg = <0>; //⽚选0或者1
spi-cpha; //设置 CPHA = 1,不配置则为 0
spi-cpol; //设置 CPOL = 1,不配置则为 0
spi-lsb-first; //IO 先传输 lsb
spi-max-frequency = <24000000>; //spi clk输出的时钟频率,不超过50M
status = "okay"; //使能设备节点
};
};
spi-max-frequency ist der Ausgangstakt nach Teilung von spiclk assigned-clock-rates. Der interne Teiler ist gerade und mindestens 2: spiclk assigned-clock-rates >= 2*spi-max-frequency. Für IO 50MHz assigned-clock-rates = <100000000>, spi-max-frequency = <50000000>. PLL wählt den nächsten Wert nicht über 100MHz; Teilung durch 2 ergibt etwa 50MHz. spiclk nicht unter 24M setzen.
2.3 SPI konfigurieren: RK als Slave
spi-rockchip-slave.c empfohlen. Folgenden Patch in der SDK-Version prüfen:
commit 10cbf3c2c93fca6e5ec6c99b5bdb319ca0494d45
Author: Jon Lin <jon.lin@rock-chips.com>
Date: Tue Nov 21 10:58:57 2023 +0800
spi: rockchip-slave: Add code
1.Implement one msg mechanism
2.Support SRAM extension by dts rockchip,sram property
Change-Id: I0fccc5d4347294488b5382ad3ba5ae72b35610f2
Signed-Off-By: Jon Lin <jon.lin@rock-chips.com>
Falls fehlend: Redmine → FAE → Dokumente → Entwicklungskonfiguration → SPI. Kernelkonfiguration:
Device Drivers --->
[*] SPI support --->
[*] SPI slave protocol handlers
[*] Rockchip SPI Slave controller driver
DTS-Knoten:
&spi1 {
compatible = "rockchip,spi-slave"; //优先使⽤ SPI slave 专⽤驱动
status = "okay";
//ready-gpios = <&gpio1 RK_PD2 GPIO_ACTIVE_LOW>;//建议配置,SPI slave 完成传输配置的信号,详细 参考“内核 SPI Slave 软件”章节
//rockchip,cs-inactive-disable; //默认不⽤配置,当 SPI master 时序 tod_cs (Clk Rise To CS Rise Time) 超过多个 io 时钟周期,应开启配置来屏蔽检测 cs 释放动作
slave { //按照框架要求,SPI slave ⼦节点的命名需以 "slave" 开始
compatible ="rockchip,spi_test_bus1_cs0";
reg = <0>; //⽚选仅⽀持 0
spi-cpha; //设置 CPHA = 1,不配置则为 0
spi-cpol; //设置 CPOL = 1,不配置则为 0
spi-lsb-first; //IO 先传输 lsb
status = "okay"; //使能设备节点
};
};
RK SPI aktiviert DMA standardmäßig; im Slave nicht deaktivieren. Übersteigt die Länge den Controllerpuffer, wird DMA gegen verspätete Interruptbearbeitung eingesetzt.
2.4 SPI-Slave-Hinweise
2.4.1 Performance-Modus empfohlen
Oberhalb folgender Master-Raten performance aktivieren, damit DRAM-Taktwechsel keinen Überlauf verursachen: bits_per_word = 8btis bei IO > 5MHz; 16btis bei > 10MHz. Beispiel:
diff --git a/drivers/spi/spi-rockchip-test.c b/drivers/spi/spi-rockchip-test.c
index 544d6038919a..c1037153ff86 100644
--- a/drivers/spi/spi-rockchip-test.c
+++ b/drivers/spi/spi-rockchip-test.c
@@ -36,6 +36,8 @@
#include <linux/platform_data/spi-rockchip.h>
#include <linux/uaccess.h>
#include <linux/syscalls.h>
+#include <soc/rockchip/rockchip-system-status.h>
+#include <dt-bindings/soc/rockchip-system-status.h>
#define MAX_SPI_DEV_NUM 10
#define SPI_MAX_SPEED_HZ 12000000 @@ -242,8 +244,10 @@ static ssize_t spi_test_write(struct file *file,
}
start_time = ktime_get();
+ rockchip_set_system_status(SYS_STATUS_PERFORMANCE);
for (i = 0; i < times; i++)
spi_read_slt(id, rxbuf, size);
+ rockchip_clear_system_status(SYS_STATUS_PERFORMANCE);
end_time = ktime_get();
cost_time = ktime_sub(end_time, start_time);
us = ktime_to_us(cost_time);
Alle Slave-Transfers möglichst in performance. set/clear kostet Zeit; auf Anwendungsebene setzen, nicht häufig aufrufen. Bei Überlauf kann Slave DMA nicht abschließen und bleibt blockiert; SPI->SPI_RISR prüfen.
2.4.2 16bits empfohlen
FIFO-Kapazität ausnutzen: 16bits und mindestens burst 2 beschleunigen Slave-DMA und vermeiden Rückstau durch zu langsamen Transport.
2.4.3 Weitere Hinweise
Zuerst Slave-Lesen, dann Master-Schreiben starten, sonst schreibt Master vor Slave-Bereitschaft. Ebenso Slave-Schreiben vor Master-Lesen: Slave läuft erst mit Master-clk, Master sendet/empfängt sofort. Auf Basis Kapitel 3 zuerst Slave echo write 0 1 16 > /dev/spi_misc_test, dann Master echo read 0 1 16 > /dev/spi_misc_test.
2.5 SPI-Gerätetreiber
Treiberregistrierung:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/spi/spi.h>
static int spi_test_probe(struct spi_device *spi)
{
int ret;
if(!spi)
return -ENOMEM;
spi->bits_per_word= 8;
ret= spi_setup(spi);
if(ret < 0) {
dev_err(&spi->dev,"ERR: fail to setup spi\n");
return-1;
}
return ret;
}
static int spi_test_remove(struct spi_device *spi)
{
printk("%s\n",__func__);
return 0;
}
static const struct of_device_id spi_test_dt_match[]= {
{.compatible = "rockchip,spi_test_bus1_cs0", },
{.compatible = "rockchip,spi_test_bus1_cs1", },
{},
};
MODULE_DEVICE_TABLE(of, spi_test_dt_match);
static struct spi_driver spi_test_driver = {
.driver = {
.name = "spi_test",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(spi_test_dt_match),
},
.probe = spi_test_probe,
.remove = spi_test_remove,
};
static int __init spi_test_init(void)
{
int ret = 0;
ret = spi_register_driver(&spi_test_driver);
return ret;
}
module_init(spi_test_init);
static void __exit spi_test_exit(void)
{
return spi_unregister_driver(&spi_test_driver);
}
module_exit(spi_test_exit);
SPI-Lesen/-Schreiben: include/linux/spi/spi.h, einige Beispiele unten.
static inline int
spi_write(struct spi_device *spi,const void *buf, size_t len)
static inline int
spi_read(struct spi_device *spi,void *buf, size_t len)
static inline int
spi_write_and_read(structspi_device *spi, const void *tx_buf, void *rx_buf, size_t len)
2.6 SPI im Benutzerraum
User mode greift aus Userspace auf SPI zu und erleichtert Peripherietreiber ohne Kerneländerung. Kernelkonfiguration:
Device Drivers --->
[*] SPI support --->
[*] User mode SPI device driver support
DTS-Konfiguration:
&spi0 {
status = "okay";
max-freq = <50000000>;
spi_test@0 {
compatible = "rockchip,spidev";
reg = <0>;
spi-max-frequency = <5000000>;
};
};
Nach Registrierung erscheint etwa /dev/spidev1.1. Beispiele: Linux 4.4 Documentation/spi/spidev_test.c; Linux 4.19+ tools/spi/spidev_test.c. Nach Kernelbuild dort die Standard-SPI-Anwendung kompilieren:
make CROSS_COMPILE=~/path-to-toolchain/gcc-xxxxx-toolchain/bin/xxxx-linux-gnu- # 选择 kernel 所⽤ CROSS_COMPILE
SPI-Slave nach entsprechendem Abschnitt möglich; DTS-Unterknoten muss “rockchip,spidev” bleiben.
2.7 cs-gpios-Unterstützung
cs-gpios in spi-bus erweitert CS über GPIO. Siehe Documentation/devicetree/bindings/spi/spi-bus.txt.
2.7.1 Linux 4.4
Zusätzliche Patches beim RK-Ingenieur anfordern.
2.7.2 Linux 4.19 und neuer
Beispiel SPI1: GPIO0_C4 als spi1_cs2n. cs-gpio setzen und im SPI referenzieren:
diff --git a/arch/arm/boot/dts/rv1126-evb-v10.dtsi b/arch/arm/boot/dts/rv1126-evb-v10.dtsi
index 144e9edf1831..c17ac362289e 100644
--- a/arch/arm/boot/dts/rv1126-evb-v10.dtsi
+++ b/arch/arm/boot/dts/rv1126-evb-v10.dtsi
&pinctrl {
...
+
+ spi1 {
+ spi1_cs0n: spi1-cs1n {
+ rockchip,pins =
+ <0 RK_PC2 RK_FUNC_GPIO &pcfg_pull_up_drv_level_0>;
+ };
+ spi1_cs1n: spi1-cs1n {
+ rockchip,pins =
+ <0 RK_PC3 RK_FUNC_GPIO &pcfg_pull_up_drv_level_0>;
+ };
+ spi1_cs2n: spi1-cs2n {
+ rockchip,pins =
+ <0 RK_PC4 RK_FUNC_GPIO &pcfg_pull_up_drv_level_0>;
+ };
+ };
};
diff --git a/arch/arm/boot/dts/rv1126.dtsi b/arch/arm/boot/dts/rv1126.dtsi
index 351bc668ea42..986a85f13832 100644
--- a/arch/arm/boot/dts/rv1126.dtsi
+++ b/arch/arm/boot/dts/rv1126.dtsi
spi1: spi@ff5b0000 {
compatible = "rockchip,rv1126-spi", "rockchip,rk3066-spi";
reg = <0xff5b0000 0x1000>;
interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
clocks = <&cru CLK_SPI1>, <&cru PCLK_SPI1>;
clock-names = "spiclk", "apb_pclk";
dmas = <&dmac 3>, <&dmac 2>;
dma-names = "tx", "rx";
pinctrl-names = "default", "high_speed";
- pinctrl-0 = <&spi1m0_clk &spi1m0_cs0n &spi1m0_cs1n &spi1m0_miso &spi1m0_mosi>;
- pinctrl-1 = <&spi1m0_clk_hs &spi1m0_cs0n &spi1m0_cs1n &spi1m0_miso_hs &spi1m0_mosi_hs>;
+ pinctrl-0 = <&spi1m0_clk &spi1_cs0n &spi1_cs1n &spi1_cs2n &spi1m0_miso &spi1m0_mosi>;
+ pinctrl-1 = <&spi1m0_clk_hs &spi1_cs0n &spi1_cs1n &spi1_cs2n &spi1m0_miso_hs &spi1m0_mosi_hs>
status = "disabled";
};
CS im SPI neu zuweisen:
+&spi1 {
+ status = "okay";
+ max-freq = <48000000>;
+ cs-gpios = <&gpio0 RK_PC2 GPIO_ACTIVE_LOW>, <&gpio0 RK_PC3 GPIO_ACTIVE_LOW>, <&gpio0 RK_PC4 GPIO_ACTIVE_LOW>;
spi_test@0 {
compatible = "rockchip,spi_test_bus1_cs0";
...
+ spi_test@2 {
+ compatible = "rockchip,spi_test_bus1_cs2";
+ id = <2>;
+ reg = <0x2>;
+ spi-cpha;
+ spi-cpol;
+ spi-lsb-first;
+ spi-max-frequency = <16000000>;
+ };
};
Für cs-gpio-Erweiterung müssen alle CS GPIO-Funktion und cs-gpios verwenden.
3. Kernel-Testsoftware
3.1 Quellcodepfade
drivers/spi/spi-rockchip-test.c
3.2 SPI-Testgerät konfigurieren
Kernelpatch:
需要⼿动添加编译:
drivers/spi/Makefile
+obj-y += spi-rockchip-test.o
DTS:
&spi0 {
status = "okay";
spi_test@0 {
compatible = "rockchip,spi_test_bus0_cs0";
id = <0>; //这个属性spi-rockchip-test.c⽤来区分不 同的spi从设备的
reg = <0>; //chip select 0:cs0 1:cs1
spi-max-frequency = <24000000>; //spi output clock
};
spi_test@1 {
compatible = "rockchip,spi_test_bus0_cs1";
id = <1>;
reg = <1>;
spi-max-frequency = <24000000>;
};
};
Treiberprotokoll:
[ 0.457137]
rockchip_spi_test_probe:name=spi_test_bus0_cs0,bus_num=0,cs=0,mode=11,speed=16000000
[ 0.457308]
rockchip_spi_test_probe:name=spi_test_bus0_cs1,bus_num=0,cs=1,mode=11,speed=16000000
3.3 Testbefehle
echo write 0 10 255 > /dev/spi_misc_test
echo write 0 10 255 init.rc > /dev/spi_misc_test
echo read 0 10 255 > /dev/spi_misc_test
echo loop 0 10 255 > /dev/spi_misc_test
echo setspeed 0 1000000 > /dev/spi_misc_test
Format: echo Typ id Schleifen Länge > /dev/spi_misc_test; echo setspeed id Frequenz_Hz > /dev/spi_misc_test. Tests bei Bedarf anpassen.
4. Kernel-SPI-Slave-Software
4.1 Einführung
SPI-Master/Slave nutzen normalerweise ein Protokoll, etwa SPI NOR mit JEDEC SDFP (Quellenschreibweise). RK liefert mangels allgemeinem Schema ein Protokoll-/Treiberbeispiel. Linux-Grenze: Transferqueue und hohe Priorität nach Aufwecken garantieren wegen Scheduling keine Echtzeit. RK-Slave muss jede Übertragung neu konfigurieren; ein Sideband-ready informiert den Master. GPIO-IRQ auf fallende Flanke empfohlen. ready-gpios-Ablauf: 1) Slave ruft spi_sync; 2) gibt GPIO_SLV_READY aus; 3) Master bestätigt Bereitschaft und startet; 4) genügend Master-clk schließen die Übertragung ab.

Abbildung des englischen Originals (p.19)
Zwei Pakete: ctrl = 2B cmd, 2B addr (Slave-application-buffer-Versatz), 4B data (meist Länge des Folgepakets); data packet. Zwei Transfers: ctrl nur ein ctrl packet; data zwei SPI-Transfers, ctrl dann data. spidev_rkslv hat SPI_OBJ_APP_RAM_SIZE Bytes Puffer; 2B addr adressiert dessen Versatz. Wichtiger Patch:
commit d2fef34977c1a7aab3837d29ac8dc3b5378a2754 (HEAD -> develop-4.19)
Author: Jon Lin <jon.lin@rock-chips.com>
Date: Wed Dec 20 12:02:14 2023 +0800
spi: spidev_rkslv: Support dynamic adjustment of system performance
If the DRAM frequency conversion jitters during the transmission process,
it will cause the DMA to be unable to transport SPI FIFO data in a timely
manner, resulting in FIFO overflow/underflow.
Clear performance status for short cmd packet and Set the performance
status for data packet.
Change-Id: I65532ba309677a8d98c8277875a3bd358ca44e44
Signed-off-by: Jon Lin <jon.lin@rock-chips.com>
SDK auf Patch prüfen; sonst Redmine → FAE → Dokumente → Entwicklungskonfiguration → SPI. Quellen:
drivers/spi/spidev-rkslv.c
drivers/spi/spidev-rkmst.c
Quellenbeschreibung: drivers/spi/spidev-rkslv.c:
static int spidev_rkslv_ctrl_receiver_thread(void *p) //建⽴线程,线程内重复发 起传输
{
while (1)
spidev_rkslv_xfer(spidev);
}
static int spidev_rkslv_xfer(struct spidev_rkslv_data *spidev) //传输⼊⼝
{
spidev_slv_read(spidev, spidev->ctrlbuf, SPI_OBJ_CTRL_MSG_SIZE); //1 ctrl packet,获取 并解析传输类型
switch (ctrl->cmd) { //1 data packet,根据 传输类型,定义 data packet 并完成收发
case SPI_OBJ_CTRL_CMD_INIT:
/* to-do */
case SPI_OBJ_CTRL_CMD_READ:
/* to-do */
case SPI_OBJ_CTRL_CMD_WRITE:
/* to-do */
case SPI_OBJ_CTRL_CMD_DUPLEX:
/* to-do */
}
}
static const struct file_operations spidev_rkslv_misc_fops = {} //注册 misc device 测试接⼝
drivers/spi/spidev-rkmst.c:
static int spidev_rkmst_xfer(struct spidev_rkmst_data *spidev, void *tx, void *rx, u16 addr,
u32 len) //传输⼊⼝
{
spidev_rkmst_ctrl(spidev, cmd, addr, len); //1 ctrl packet,定 义传输类型
switch (cmd) { //1 data packet,根 据传输类型,定义 data packet 并完成收发
case SPI_OBJ_CTRL_CMD_READ:
/* to-do */
case SPI_OBJ_CTRL_CMD_WRITE:
/* to-do */
case SPI_OBJ_CTRL_CMD_DUPLEX:
/* to-do */
}
}
static const struct file_operations spidev_rkmst_misc_fops = {} //注册 misc device 测试接⼝
Anwendung implementieren

Abbildung des englischen Originals (p.21)
Slave-Software ist Protokoll-/Treiberreferenz; Kunden müssen Produktanforderungen auf dem Slave-application-buffer selbst definieren.
4.2 SPI-Slave-Testgerät konfigurieren
defconfig:
CONFIG_SPI_SLAVE_ROCKCHIP_OBJ=y
Slave-DTS-Beispiel:
&spi1 {
compatible = "rockchip,spi-slave";
status = "okay";
rockchip,cs-inactive-disable; //RK 内部互联使⽤ RK Linux SPI master 驱动,tod_cs 较⻓
ready-gpios = <&gpio1 RK_PD3 GPIO_ACTIVE_LOW>; //请设置为实际所⽤ GPIO
slave {
compatible = "rockchip,spi-obj-slave";
reg = <0x0>;
spi-cpha;
spi-cpol;
spi-lsb-first;
spi-max-frequency = <50000000>;
};
};
Master-DTS-Beispiel:
&spi0 {
status = "okay";
spi_test@00 {
compatible = "rockchip,spi-obj-master";
reg = <0x0>;
spi-cpha;
spi-cpol;
spi-lsb-first;
spi-max-frequency = <16000000>;
ready-gpios = <&gpio1 RK_PD2 GPIO_ACTIVE_LOW>; //请设置为实际所⽤ GPIO
};
};
4.3 Testbefehle
Master: Einzelpakettest
echo cmd addr length > /dev/spidev_rkmst_misc
cmd: read/write/duplex.
addr: Versatz im entfernten Slave-Puffer, Bytes, nur dezimal. length: data-packet-Länge, Bytes, nur dezimal. Beispiel:
echo write 128 128 > /dev/spidev_rkmst_misc
echo read 128 128 > /dev/spidev_rkmst_misc
echo duplex 128 128 > /dev/spidev_rkmst_misc
Master-Autotest
echo autotest length loops compare > /dev/spidev_rkmst_misc
autotest fest vorgeben: erst Vollduplex, dann Lesen/Schreiben mit Ratenanzeige. Slave-Versatz standardmäßig 0. length: Bytes, dezimal; loops: Lastzyklen; compare: 1 prüfen, 0 nicht prüfen (etwa Dauersignal). Beispiel:
echo autotest 1024 64 1 > /dev/spidev_rkmst_misc
Slave-Test
echo appmem 0 256 > ./dev/spidev_rkslv_misc #打印 application buffer 数据
echo verbose 1 > ./dev/spidev_rkslv_misc #开启传输传输过程 debug log,echo verbose 0 关 闭打印
5. Häufige Fragen
5.1 Kein SPI-Signal
Treiberstart und IOMUX aller vier Pins prüfen. Bei TX müssen TX-Wellenform, CLK-Takt und CS low vorhanden sein. Bei hoher Frequenz Treiberstärke erhöhen. Fehlen folgende UART-Schlüsselwörter, ist DMA aktiviert:
[ 0.457137] Failed to request TX DMA channel
[ 0.457237] Failed to request RX DMA channel
5.2 SPI-Anwendung entwickeln
Vor Entwicklung Schnittstelle wählen: eigener Treiber nach SPI Device Driver, etwa drivers/spi/spi-rockchip-test.c; spidev-Anwendung nach User mode SPI device.
5.3 Abtastverzögerung
Bei hoher SPI-Rate kann Peripherie-Ausgangsverzögerung Master-Lesen stören. RSD aktivieren: 0/1/2/3, Einheit ein spi_clk cycle. rx-sample-delay wird auf nächsten gültigen RSD gerundet. Bei 200MHz, 5ns Periode: 0/5/10/15ns; 12ns ergibt 10ns.
5.4 Übertragungsverfahren
Master unterstützt IRQ/DMA/CPU, Slave IRQ/DMA. Standard: IRQ bei Länge < FIFO, DMA bei >= FIFO; FIFO meist 64 bei Kernel 4.19+. Master kombiniert lassen, DMA für IRQ deaktivieren oder rockchip,poll-only für CPU setzen. Slave-Modus nicht änderbar. Unter FIFO-Länge erzeugt ein Transfer einen Interrupt.
Bei >= FIFO und IRQ liegt die Schwelle bei halbem FIFO, meist 32 Einträgen; ungefähr items / 32 Interrupts. DMA erzeugt keinen SPI-Controller-Interrupt, sondern einen DMA-Abschlusscallback.
5.5 SPI-Rate und CPU-Last optimieren
Niedrige Rate und hohe CPU-Last kommen oft von kleinen häufigen Transfers: SPI-Thread-, Interrupt- (Modus prüfen) und CPU-Idle-Scheduling. Empfehlungen:
- Auto runtime mit 500ms Verzögerung aktivieren, per Messung anpassen; rockchip,autosuspend-delay-ms in DTS.
- CPU senken: IRQ kann günstiger als DMA sein; Patch unten.
- Bei DMA TX-Watermark ändern, um CPU-Wartezeit auf FIFO-Abschluss im Callback zu senken. Patches unten. Auf IRQ wechseln:
diff --git a/arch/arm/boot/dts/rv1126-evb-v10.dtsi b/arch/arm/boot/dts/rv1126-evb-v10.dtsi
index 86dd23482d97..2cea93d2423f 100644
--- a/arch/arm/boot/dts/rv1126-evb-v10.dtsi
+++ b/arch/arm/boot/dts/rv1126-evb-v10.dtsi
@@ -1367,6 +1367,7 @@
status = "okay";
max-freq = <48000000>;
cs-gpios = <0>, <0>, <&gpio0 RK_PC4 GPIO_ACTIVE_LOW>;
+ dma-names;
spi_test@00 {
SPI-Watermark ändern:
diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index 27fd6f671b12..bd0fa8c5f8c3 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -616,7 +616,8 @@ static void rockchip_spi_config(struct rockchip_spi *rs,
else
writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_RXFTLR);
- writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_DMATDLR);
+ // writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_DMATDLR);
+ writel_relaxed(11, rs->regs + ROCKCHIP_SPI_DMATDLR);
writel_relaxed(rockchip_spi_calc_burst_size(xfer->len / rs->n_bytes) - 1,
rs->regs + ROCKCHIP_SPI_DMARDLR);
writel_relaxed(dmacr, rs->regs + ROCKCHIP_SPI_DMACR);
Quellenunterschiede: englische Beispiele und Hinweis
Folgende englische Beispiele unterscheiden sich in Kommentaren, Umbrüchen oder Inhalt. Sie bleiben zur Nachvollziehbarkeit, nicht als austauschbare Konfigurationen. Englischer Schlusshinweis: Patches gelten für Rockchip SPI und RV1126-EVB-V10 DTS; andere Systeme benötigen Anpassung. Chinesische Angaben zu gerader Teilung, PLL-Abrundung und Blockieren ohne Rückkehr bei Überlauf gelten; das widersprüchliche “block and exit” wird nicht übernommen.
EN p.8 / source unit 38
drivers/spi/spi.c /* SPI Driver framework */
drivers/spi/spi-rockchip.c /* RK SPI Slave implement of interface */
drivers/spi/spi-rockchip-slave.c /* RK SPI Slave implement of interface */
drivers/spi/spidev.c /* Create SPI device node for using */
EN p.9 / source unit 39
drivers/spi/spi-rockchip-test.c /* SPI test driver, it needs to add to Makefile compiler manually. */
Documentation/spi/spidev_test.c /* SPI test tool in user state */
EN p.9 / source unit 44
&spi1 { //Quote SPI controller node
status = "okay";
//assigned-clocks = <CLK_SPI1>; //Not configured by default, depend on soc dtsi
//assigned-clock-rates = <200000000>;//Not configured by default, spi controller work clock
//dma-names; //Not configured by default, turn off DMA support, only supports IRQ transmission
//rockchip,poll-only; //Not configured by default, turn to use CPU transmission, only master mode supported
//rx-sample-delay-ns = <10>; //Not configured by default, Read sampling delay. Please refer to "FAQ" and "Delay sampling clock configuration" for details
//rockchip, autosuspend-delay-ms = <500>; //Not configured by default, Runtime PM autosuspend delay, refer to "SPI Transfer Rate and CPU Usage Optimization Directions" for details.
//rockchip,rt; //Not configured by default,Place SPI data transfer process into SCHED_FIFO, its priority is 50
spi_test@10 {
compatible ="rockchip,spi_test_bus1_cs0"; //The name corresponding to the driver
reg = <0>; //Chip select 0 or 1
spi-cpha; //If configure it, cpha is 1
spi-cpol; //If configure it,cpol is 1, the clk pin remains high level.
spi-lsb-first; //IO firstly transfer lsb
status = "okay"; //Enable device node
spi-max-frequency = <24000000>; //This is clock frequency of SPI clk output,witch does not exceed 50M.
};
};
EN p.10 / source unit 53
&spi1 {
compatible = "rockchip,spi-slave"; //priority use SPI slave dedicated driver
status = "okay";
//ready-gpios = <&gpio1 RK_PD2 GPIO_ACTIVE_LOW>;//recommend configuring, SPI slave complete transmission flag, refer to "kernel SPI Slave Software" chapter
//rockchip,cs-inactive-disable; //default do not configure, when SPI master timing tod_cs (Clock Rise To CS Rise Time) is over multiple io clock cycles, should open config to detect cs release action
slave { //according to framework requirement, SPI slave sub node's name should start with "slave"
compatible ="rockchip,spi_test_bus1_cs0";
reg = <0>; //only support single chip select
EN p.11 / source unit 54
spi-cpha; //set CPHA = 1, do not configure otherwise
spi-cpol; //set CPOL = 1, do not configure otherwise
spi-lsb-first; //IO Input lsb first
status = "okay"; //enable device node
};
};
EN p.14 / source unit 78
make CROSS_COMPILE=~/path-to-toolchain/gcc-xxxxx-toolchain/bin/xxxx-linux-gnu- # Choose kernel toolchain
EN p.17 / source unit 98
&spi0 {
status = "okay";
spi_test@0 {
compatible = "rockchip,spi_test_bus0_cs0";
id = <0>; //This attribute is used to distinguish different SPI slave devices in "spi-rockchip-test.c".
reg = <0>; //chip select 0:cs0 1:cs1
spi-max-frequency = <24000000>; //spi output clock
};
spi_test@1 {
compatible = "rockchip,spi_test_bus0_cs1";
id = <1>;
reg = <1>;
spi-max-frequency = <24000000>;
};
};
EN p.20 / source unit 115
static int spidev_rkslv_ctrl_receiver_thread(void *p) //Establish a thread and repeatedly initiate transfers within the thread
{
while (1)
spidev_rkslv_xfer(spidev);
}
static int spidev_rkslv_xfer(struct spidev_rkslv_data *spidev) //Transmission entrance
{
spidev_slv_read(spidev, spidev->ctrlbuf, SPI_OBJ_CTRL_MSG_SIZE); //1 ctrl packet to obtain and parse the transmission type
switch (ctrl->cmd) { //1 data packet, define data packets based on the transmission type and complete sending and receiving
case SPI_OBJ_CTRL_CMD_INIT:
/* to-do */
case SPI_OBJ_CTRL_CMD_READ:
/* to-do */
case SPI_OBJ_CTRL_CMD_WRITE:
/* to-do */
case SPI_OBJ_CTRL_CMD_DUPLEX:
/* to-do */
}
}
static const struct file_operations spidev_rkslv_misc_fops = {} //Register misc device test interface
EN p.20 / source unit 117
static int spidev_rkmst_xfer(struct spidev_rkmst_data *spidev, void *tx, void *rx, u16 addr,
u32 len) //Transmission entrance
{
spidev_rkmst_ctrl(spidev, cmd, addr, len); //1 ctrl packet, defining the transmission type
switch (cmd) { //1 data packet, define data packets based on the transmission type and complete sending and receiving
case SPI_OBJ_CTRL_CMD_READ:
/* to-do */
case SPI_OBJ_CTRL_CMD_WRITE:
/* to-do */
case SPI_OBJ_CTRL_CMD_DUPLEX:
/* to-do */
}
}
static const struct file_operations spidev_rkmst_misc_fops = {} //Register misc device test interface
EN p.21 / source unit 125
&spi1 {
status = "okay";
spi-slave;
rockchip,cs-inactive-disable; //RK internal interconnection using RK Linux SPI master driver, and the tod_cs takes a long time
ready-gpios = <&gpio1 RK_PD3 GPIO_ACTIVE_LOW>; //Please set to the actual GPIO used
slave {
compatible = "rockchip,spi-obj-slave";
reg = <0x0>;
spi-cpha;
spi-cpol;
spi-lsb-first;
spi-max-frequency = <50000000>;
};
};
EN p.22 / source unit 127
&spi0 {
status = "okay";
spi_test@00 {
compatible = "rockchip,spi-obj-master";
reg = <0x0>;
spi-cpha;
spi-cpol;
spi-lsb-first;
spi-max-frequency = <16000000>;
ready-gpios = <&gpio1 RK_PD2 GPIO_ACTIVE_LOW>;
};
};
EN p.23 / source unit 138
echo appmem 0 256 > ./dev/spidev_rkslv_misc #Print application buffer data
echo verbose 1 > ./dev/spidev_rkslv_misc #Enable the transmission process debug log,
echo verbose 0, and close printing
