AN889の日記

組込みエンジニアのブログ

【U-Boot】QUICC EngineファームウェアのSPIフラッシュからのロード

NXP(旧 Freescale)製PowerPC(以下、PPC)プロセッサのPowerQUICCシリーズは、QUICC Engineと呼ばれるファームウェア(以下、FW)を使って各種通信コントローラーを実装できます。
このFWイメージのロードですが、PPCブートローダーであるU-Bootに実装されてます。
https://github.com/nxp-qoriq/u-boot/blob/LSDK-19.09-update-311219/drivers/qe/qe.c
qe_init() です。
が、良く見ると、NORフラッシュのメモリーマップされたアドレスからのロードのみとなっています。
ブートデバイスにSPIフラッシュを使う場合、FWイメージもSPIフラッシュ上に置くと思います。で、CONFIG_SYS_QE_FW_ADDR にそのアドレスを指定すれば良いと思ってましたが、この実装ではロードされません。
そこで、SPIフラッシュからロードされるようパッチを作ったので公開します。

U-Bootの最新バージョンでもSPIフラッシュからのロードに非対応なので、NXPに対応するよう代理店経由で依頼しましたが、NXPからの回答は「その予定はない」とのつれないものでした。

FMAN(Frame Manager)と呼ばれるFWのロードはSPIフラッシュにも対応してるんですけどね...。
https://github.com/nxp-qoriq/u-boot/blob/LSDK-19.09-update-311219/drivers/net/fm/fm.c
fm_init_common() です。



diff --git a/drivers/qe/qe.c b/drivers/qe/qe.c
index 70d02d3..6710680 100644
--- a/drivers/qe/qe.c
+++ b/drivers/qe/qe.c
@@ -15,6 +15,8 @@
 #include <fsl_qe.h>
 #include <mmc.h>
 #include <environment.h>
+#include <spi.h>
+#include <spi_flash.h>
 
 #ifdef CONFIG_ARCH_LS1021A
 #include <asm/arch/immap_ls102xa.h>
@@ -202,19 +204,46 @@ void qe_init(uint qe_base)
 #else
 void qe_init(uint qe_base)
 {
+	void *addr = NULL;
+
 	/* Init the QE IMMR base */
 	qe_immr = (qe_map_t *)qe_base;
 
-#ifdef CONFIG_SYS_QE_FMAN_FW_IN_NOR
-	/*
-	 * Upload microcode to IRAM for those SOCs which do not have ROM in QE.
-	 */
-	qe_upload_firmware((const void *)CONFIG_SYS_QE_FW_ADDR);
+#if defined(CONFIG_SYS_QE_FMAN_FW_IN_NOR)
+	addr = (void *)CONFIG_SYS_QE_FW_ADDR;
+#elif defined(CONFIG_SYS_QE_FW_IN_SPIFLASH)
+	struct spi_nor *nor;
+	int ret = 0;
+
+	addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH);
+
+# ifdef CONFIG_DM_SPI_FLASH
+	struct udevice *new;
 
-	/* enable the microcode in IRAM */
-	out_be32(&qe_immr->iram.iready,QE_IRAM_READY);
+	/* speed and mode will be read from DT */
+	ret = spi_flash_probe_bus_cs(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS, 0, 0, &new);
+	nor = dev_get_uclass_priv(new);
+# else
+	nor = spi_flash_probe(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS, CONFIG_ENV_SPI_MAX_HZ, CONFIG_ENV_SPI_MODE);
+# endif
+
+	if (!nor)
+		printf("SF: probe for qe firmware failed\n");
+	else {
+		ret = spi_flash_read(nor, CONFIG_SYS_QE_FW_ADDR, CONFIG_SYS_QE_FMAN_FW_LENGTH, addr);
+		if (ret)
+			printf("SF: read for qe firmware failed\n");
+		spi_flash_free(nor);
+	}
 #endif
 
+	if (addr) {
+		/* Upload microcode to IRAM for those SOCs which do not have ROM in QE. */
+		qe_upload_firmware((const void *)addr);
+		/* enable the microcode in IRAM */
+		out_be32(&qe_immr->iram.iready,QE_IRAM_READY);
+	}
+
 	gd->arch.mp_alloc_base = QE_DATAONLY_BASE;
 	gd->arch.mp_alloc_top = gd->arch.mp_alloc_base + QE_DATAONLY_SIZE;