about summary refs log tree commit diff
path: root/pkgs/misc/uboot
diff options
context:
space:
mode:
authorBernardo Meurer <bernardo@meurer.org>2022-04-26 13:04:46 -0700
committerBernardo Meurer <bernardo@meurer.org>2022-04-26 15:22:36 -0700
commit323f123f6afee22cc0c642988a12285ba0f11b3a (patch)
tree42509dbee250035ff5530a2fa3b6ce574c86d4f6 /pkgs/misc/uboot
parentca0c9279ab2471bd8bf67681fb57fe33adbccb27 (diff)
downloadnixlib-323f123f6afee22cc0c642988a12285ba0f11b3a.tar
nixlib-323f123f6afee22cc0c642988a12285ba0f11b3a.tar.gz
nixlib-323f123f6afee22cc0c642988a12285ba0f11b3a.tar.bz2
nixlib-323f123f6afee22cc0c642988a12285ba0f11b3a.tar.lz
nixlib-323f123f6afee22cc0c642988a12285ba0f11b3a.tar.xz
nixlib-323f123f6afee22cc0c642988a12285ba0f11b3a.tar.zst
nixlib-323f123f6afee22cc0c642988a12285ba0f11b3a.zip
ubootRaspberryCM4_64bit: add all NVME patches
Diffstat (limited to 'pkgs/misc/uboot')
-rw-r--r--pkgs/misc/uboot/default.nix7
-rw-r--r--pkgs/misc/uboot/rpi-cm4/0001-drivers-bcm283x-don-t-explicitly-disable-init.patch54
-rw-r--r--pkgs/misc/uboot/rpi-cm4/0002-drivers-bcm283x-allow-to-spawn-any-PL011-UART.patch68
-rw-r--r--pkgs/misc/uboot/rpi-cm4/0003-nvme-improve-readability-of-nvme_setup_prps.patch51
-rw-r--r--pkgs/misc/uboot/rpi-cm4/0004-Revert-nvme-Correct-the-prps-per-page-calculation-me.patch44
-rw-r--r--pkgs/misc/uboot/rpi-cm4/0004-nvme-Use-pointer-for-CPU-addressed-buffers.patch263
-rw-r--r--pkgs/misc/uboot/rpi-cm4/0005-nvme-translate-virtual-addresses-into-the-bus-s-addr.patch198
7 files changed, 685 insertions, 0 deletions
diff --git a/pkgs/misc/uboot/default.nix b/pkgs/misc/uboot/default.nix
index 70fb54d4078e..d231dcef8979 100644
--- a/pkgs/misc/uboot/default.nix
+++ b/pkgs/misc/uboot/default.nix
@@ -432,7 +432,14 @@ in {
     '';
     extraPatches = [
       ./rpi-cm4/0003-rpi-add-NVMe-to-boot-order.patch
+      ./rpi-cm4/0004-Revert-nvme-Correct-the-prps-per-page-calculation-me.patch
       ./rpi-cm4/0005-usb-xhci-brcm-Make-driver-compatible-with-downstream.patch
+
+      ./rpi-cm4/0001-drivers-bcm283x-don-t-explicitly-disable-init.patch
+      ./rpi-cm4/0002-drivers-bcm283x-allow-to-spawn-any-PL011-UART.patch
+      ./rpi-cm4/0003-nvme-improve-readability-of-nvme_setup_prps.patch
+      ./rpi-cm4/0004-nvme-Use-pointer-for-CPU-addressed-buffers.patch
+      ./rpi-cm4/0005-nvme-translate-virtual-addresses-into-the-bus-s-addr.patch
     ];
   };
 
diff --git a/pkgs/misc/uboot/rpi-cm4/0001-drivers-bcm283x-don-t-explicitly-disable-init.patch b/pkgs/misc/uboot/rpi-cm4/0001-drivers-bcm283x-don-t-explicitly-disable-init.patch
new file mode 100644
index 000000000000..59e7234dde9f
--- /dev/null
+++ b/pkgs/misc/uboot/rpi-cm4/0001-drivers-bcm283x-don-t-explicitly-disable-init.patch
@@ -0,0 +1,54 @@
+From 78704bc154d695ee16fdf8396f4d60b740190014 Mon Sep 17 00:00:00 2001
+Message-Id: <78704bc154d695ee16fdf8396f4d60b740190014.1650924333.git.stefan@agner.ch>
+From: Stefan Agner <stefan@agner.ch>
+Date: Thu, 14 Apr 2022 12:15:26 +0200
+Subject: [PATCH 1/5] drivers: bcm283x: don't explicitly disable init
+
+It seems that the reason why init doesn't succeed is the lack of clock
+support in U-Boot. Setting the default clock of 48MHz for the PL011
+UARTs makes reinitialization work consistently.
+
+Note that for the first UART the "skip-init" is anyways set in the
+device tree. This will only affect probing of UARTs not enabled by
+firmware.
+
+Signed-off-by: Stefan Agner <stefan@agner.ch>
+---
+ drivers/serial/serial_bcm283x_pl011.c | 6 ------
+ include/configs/rpi.h                 | 3 +++
+ 2 files changed, 3 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/serial/serial_bcm283x_pl011.c b/drivers/serial/serial_bcm283x_pl011.c
+index 2d2e970316..182274036c 100644
+--- a/drivers/serial/serial_bcm283x_pl011.c
++++ b/drivers/serial/serial_bcm283x_pl011.c
+@@ -51,12 +51,6 @@ static int bcm283x_pl011_serial_probe(struct udevice *dev)
+ 	if (ret)
+ 		return ret;
+ 
+-	/*
+-	 * TODO: Reinitialization doesn't always work for now, just skip
+-	 *       init always - we know we're already initialized
+-	 */
+-	plat->skip_init = true;
+-
+ 	return pl01x_serial_probe(dev);
+ }
+ 
+diff --git a/include/configs/rpi.h b/include/configs/rpi.h
+index e24c94c7d2..98ba4dc052 100644
+--- a/include/configs/rpi.h
++++ b/include/configs/rpi.h
+@@ -40,6 +40,9 @@
+ #define CONFIG_SYS_BOOTM_LEN		SZ_64M
+ #endif
+ 
++/* Define PL011 default clock */
++#define CONFIG_PL011_CLOCK		48000000
++
+ /* Devices */
+ /* GPIO */
+ #define CONFIG_BCM2835_GPIO
+-- 
+2.36.0
+
diff --git a/pkgs/misc/uboot/rpi-cm4/0002-drivers-bcm283x-allow-to-spawn-any-PL011-UART.patch b/pkgs/misc/uboot/rpi-cm4/0002-drivers-bcm283x-allow-to-spawn-any-PL011-UART.patch
new file mode 100644
index 000000000000..7ce52e15c573
--- /dev/null
+++ b/pkgs/misc/uboot/rpi-cm4/0002-drivers-bcm283x-allow-to-spawn-any-PL011-UART.patch
@@ -0,0 +1,68 @@
+From c2447aa922068cebd9bbaac45acae3d853abf687 Mon Sep 17 00:00:00 2001
+Message-Id: <c2447aa922068cebd9bbaac45acae3d853abf687.1650924333.git.stefan@agner.ch>
+In-Reply-To: <78704bc154d695ee16fdf8396f4d60b740190014.1650924333.git.stefan@agner.ch>
+References: <78704bc154d695ee16fdf8396f4d60b740190014.1650924333.git.stefan@agner.ch>
+From: Stefan Agner <stefan@agner.ch>
+Date: Thu, 14 Apr 2022 12:18:41 +0200
+Subject: [PATCH 2/5] drivers: bcm283x: allow to spawn any PL011 UART
+
+The current code checks pinmux for the first PL011 only. Raspberry Pi 4
+has multiple PL011 UARTs. This code prevents probing of other UARTs in
+case the first PL011 UART is not active.
+
+Furthermore, U-Boot supports pinmuxing, hence the pins should be muxed
+at this point anyway. Drop the check entirly.
+
+This allows to use other UARTs as stdout paths (e.g. stdout-path =
+"serial5:115200n8").
+
+Signed-off-by: Stefan Agner <stefan@agner.ch>
+---
+ drivers/serial/serial_bcm283x_pl011.c | 27 ---------------------------
+ 1 file changed, 27 deletions(-)
+
+diff --git a/drivers/serial/serial_bcm283x_pl011.c b/drivers/serial/serial_bcm283x_pl011.c
+index 182274036c..98628e1ca4 100644
+--- a/drivers/serial/serial_bcm283x_pl011.c
++++ b/drivers/serial/serial_bcm283x_pl011.c
+@@ -11,37 +11,10 @@
+ #include <serial.h>
+ #include "serial_pl01x_internal.h"
+ 
+-/*
+- * Check if this serial device is muxed
+- *
+- * The serial device will only work properly if it has been muxed to the serial
+- * pins by firmware. Check whether that happened here.
+- *
+- * @return true if serial device is muxed, false if not
+- */
+-static bool bcm283x_is_serial_muxed(void)
+-{
+-	int serial_gpio = 15;
+-	struct udevice *dev;
+-
+-	if (uclass_first_device(UCLASS_PINCTRL, &dev) || !dev)
+-		return false;
+-
+-	if (pinctrl_get_gpio_mux(dev, 0, serial_gpio) != BCM2835_GPIO_ALT0)
+-		return false;
+-
+-	return true;
+-}
+-
+ static int bcm283x_pl011_serial_probe(struct udevice *dev)
+ {
+-	struct pl01x_serial_plat *plat = dev_get_plat(dev);
+ 	int ret;
+ 
+-	/* Don't spawn the device if it's not muxed */
+-	if (!bcm283x_is_serial_muxed())
+-		return -ENODEV;
+-
+ 	/*
+ 	 * Read the ofdata here rather than in an of_to_plat() method
+ 	 * since we need the soc simple-bus to be probed so that the 'ranges'
+-- 
+2.36.0
+
diff --git a/pkgs/misc/uboot/rpi-cm4/0003-nvme-improve-readability-of-nvme_setup_prps.patch b/pkgs/misc/uboot/rpi-cm4/0003-nvme-improve-readability-of-nvme_setup_prps.patch
new file mode 100644
index 000000000000..1ca9d0c1253f
--- /dev/null
+++ b/pkgs/misc/uboot/rpi-cm4/0003-nvme-improve-readability-of-nvme_setup_prps.patch
@@ -0,0 +1,51 @@
+From 78924e9cf8c4af0baafcb2e7224bf04ad65276de Mon Sep 17 00:00:00 2001
+Message-Id: <78924e9cf8c4af0baafcb2e7224bf04ad65276de.1650924333.git.stefan@agner.ch>
+In-Reply-To: <78704bc154d695ee16fdf8396f4d60b740190014.1650924333.git.stefan@agner.ch>
+References: <78704bc154d695ee16fdf8396f4d60b740190014.1650924333.git.stefan@agner.ch>
+From: Stefan Agner <stefan@agner.ch>
+Date: Thu, 23 Sep 2021 23:52:44 +0200
+Subject: [PATCH 3/5] nvme: improve readability of nvme_setup_prps()
+
+Improve readability by introducing consts, reuse consts where
+appropriate and adding variables with discriptive name.
+
+Signed-off-by: Stefan Agner <stefan@agner.ch>
+---
+ drivers/nvme/nvme.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/nvme/nvme.c b/drivers/nvme/nvme.c
+index 3bda491e12..1601651449 100644
+--- a/drivers/nvme/nvme.c
++++ b/drivers/nvme/nvme.c
+@@ -76,12 +76,12 @@ static int nvme_wait_ready(struct nvme_dev *dev, bool enabled)
+ static int nvme_setup_prps(struct nvme_dev *dev, u64 *prp2,
+ 			   int total_len, u64 dma_addr)
+ {
+-	u32 page_size = dev->page_size;
++	const u32 page_size = dev->page_size;
++	const u32 prps_per_page = (page_size >> 3) - 1;
+ 	int offset = dma_addr & (page_size - 1);
+ 	u64 *prp_pool;
+ 	int length = total_len;
+ 	int i, nprps;
+-	u32 prps_per_page = (page_size >> 3) - 1;
+ 	u32 num_pages;
+ 
+ 	length -= (page_size - offset);
+@@ -119,9 +119,9 @@ static int nvme_setup_prps(struct nvme_dev *dev, u64 *prp2,
+ 	prp_pool = dev->prp_pool;
+ 	i = 0;
+ 	while (nprps) {
+-		if (i == ((page_size >> 3) - 1)) {
+-			*(prp_pool + i) = cpu_to_le64((ulong)prp_pool +
+-					page_size);
++		if (i == prps_per_page) {
++			u64 next_prp_list = (u64)prp_pool + page_size;
++			*(prp_pool + i) = cpu_to_le64(next_prp_list);
+ 			i = 0;
+ 			prp_pool += page_size;
+ 		}
+-- 
+2.36.0
+
diff --git a/pkgs/misc/uboot/rpi-cm4/0004-Revert-nvme-Correct-the-prps-per-page-calculation-me.patch b/pkgs/misc/uboot/rpi-cm4/0004-Revert-nvme-Correct-the-prps-per-page-calculation-me.patch
new file mode 100644
index 000000000000..2bd7d9e868f0
--- /dev/null
+++ b/pkgs/misc/uboot/rpi-cm4/0004-Revert-nvme-Correct-the-prps-per-page-calculation-me.patch
@@ -0,0 +1,44 @@
+From 3a13ff4eb509e8e80a52ae45c9a5573e745803c3 Mon Sep 17 00:00:00 2001
+Message-Id: <3a13ff4eb509e8e80a52ae45c9a5573e745803c3.1645627172.git.stefan@agner.ch>
+In-Reply-To: <24b77460dbfa2497ceb7a1611bf28b6eb88a1d74.1645627172.git.stefan@agner.ch>
+References: <24b77460dbfa2497ceb7a1611bf28b6eb88a1d74.1645627172.git.stefan@agner.ch>
+From: Stefan Agner <stefan@agner.ch>
+Date: Thu, 23 Sep 2021 23:43:31 +0200
+Subject: [PATCH 4/5] Revert "nvme: Correct the prps per page calculation
+ method"
+
+This reverts commit 859b33c948945f7904f60a2c12a3792d356d51ad.
+
+If there is more than one PRP List the last entry is a pointer to
+the next list. From the NVM Express specification:
+
+"The last entry within a memory page, as indicated by the memory page
+size in the CC.MPS field, shall be a PRP List pointer if there is more
+than a single memory page of data to be transferred."
+
+For the purpose of calculating the number of pages required for PRP
+lists we should always assume that the last entry is required for
+the next PRP list.
+
+Signed-off-by: Stefan Agner <stefan@agner.ch>
+Cc: Wesley Sheng <wesleyshenggit@sina.com>
+---
+ drivers/nvme/nvme.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/nvme/nvme.c b/drivers/nvme/nvme.c
+index 3c529a2fce..3bda491e12 100644
+--- a/drivers/nvme/nvme.c
++++ b/drivers/nvme/nvme.c
+@@ -81,7 +81,7 @@ static int nvme_setup_prps(struct nvme_dev *dev, u64 *prp2,
+ 	u64 *prp_pool;
+ 	int length = total_len;
+ 	int i, nprps;
+-	u32 prps_per_page = page_size >> 3;
++	u32 prps_per_page = (page_size >> 3) - 1;
+ 	u32 num_pages;
+ 
+ 	length -= (page_size - offset);
+-- 
+2.35.1
+
diff --git a/pkgs/misc/uboot/rpi-cm4/0004-nvme-Use-pointer-for-CPU-addressed-buffers.patch b/pkgs/misc/uboot/rpi-cm4/0004-nvme-Use-pointer-for-CPU-addressed-buffers.patch
new file mode 100644
index 000000000000..1a25f4ce1b3a
--- /dev/null
+++ b/pkgs/misc/uboot/rpi-cm4/0004-nvme-Use-pointer-for-CPU-addressed-buffers.patch
@@ -0,0 +1,263 @@
+From e040d976ecbdd8071bbcb73d78e17ababa88c51f Mon Sep 17 00:00:00 2001
+Message-Id: <e040d976ecbdd8071bbcb73d78e17ababa88c51f.1650924333.git.stefan@agner.ch>
+In-Reply-To: <78704bc154d695ee16fdf8396f4d60b740190014.1650924333.git.stefan@agner.ch>
+References: <78704bc154d695ee16fdf8396f4d60b740190014.1650924333.git.stefan@agner.ch>
+From: Stefan Agner <stefan@agner.ch>
+Date: Thu, 23 Sep 2021 23:58:35 +0200
+Subject: [PATCH 4/5] nvme: Use pointer for CPU addressed buffers
+
+Pass buffers which use CPU addressing as void pointers. This aligns with
+DMA APIs which use void pointers as argument. It will avoid unnecessary
+type casts when adding support bus address translations.
+
+Signed-off-by: Stefan Agner <stefan@agner.ch>
+---
+ drivers/nvme/nvme.c      | 50 ++++++++++++++++++++--------------------
+ drivers/nvme/nvme_show.c |  4 ++--
+ include/nvme.h           | 12 +++++-----
+ 3 files changed, 33 insertions(+), 33 deletions(-)
+
+diff --git a/drivers/nvme/nvme.c b/drivers/nvme/nvme.c
+index 1601651449..6ab94ada7e 100644
+--- a/drivers/nvme/nvme.c
++++ b/drivers/nvme/nvme.c
+@@ -74,11 +74,11 @@ static int nvme_wait_ready(struct nvme_dev *dev, bool enabled)
+ }
+ 
+ static int nvme_setup_prps(struct nvme_dev *dev, u64 *prp2,
+-			   int total_len, u64 dma_addr)
++			   int total_len, void *buffer)
+ {
+ 	const u32 page_size = dev->page_size;
+ 	const u32 prps_per_page = (page_size >> 3) - 1;
+-	int offset = dma_addr & (page_size - 1);
++	int offset = (uintptr_t)buffer & (page_size - 1);
+ 	u64 *prp_pool;
+ 	int length = total_len;
+ 	int i, nprps;
+@@ -92,10 +92,10 @@ static int nvme_setup_prps(struct nvme_dev *dev, u64 *prp2,
+ 	}
+ 
+ 	if (length)
+-		dma_addr += (page_size - offset);
++		buffer += (page_size - offset);
+ 
+ 	if (length <= page_size) {
+-		*prp2 = dma_addr;
++		*prp2 = (u64)buffer;
+ 		return 0;
+ 	}
+ 
+@@ -125,11 +125,11 @@ static int nvme_setup_prps(struct nvme_dev *dev, u64 *prp2,
+ 			i = 0;
+ 			prp_pool += page_size;
+ 		}
+-		*(prp_pool + i++) = cpu_to_le64(dma_addr);
+-		dma_addr += page_size;
++		*(prp_pool + i++) = cpu_to_le64((u64)buffer);
++		buffer += page_size;
+ 		nprps--;
+ 	}
+-	*prp2 = (ulong)dev->prp_pool;
++	*prp2 = (u64)dev->prp_pool;
+ 
+ 	flush_dcache_range((ulong)dev->prp_pool, (ulong)dev->prp_pool +
+ 			   dev->prp_entry_num * sizeof(u64));
+@@ -450,42 +450,42 @@ static int nvme_alloc_sq(struct nvme_dev *dev, u16 qid,
+ }
+ 
+ int nvme_identify(struct nvme_dev *dev, unsigned nsid,
+-		  unsigned cns, dma_addr_t dma_addr)
++		  unsigned int cns, void *buffer)
+ {
+ 	struct nvme_command c;
+ 	u32 page_size = dev->page_size;
+-	int offset = dma_addr & (page_size - 1);
++	int offset = (uintptr_t)buffer & (page_size - 1);
+ 	int length = sizeof(struct nvme_id_ctrl);
+ 	int ret;
+ 
+ 	memset(&c, 0, sizeof(c));
+ 	c.identify.opcode = nvme_admin_identify;
+ 	c.identify.nsid = cpu_to_le32(nsid);
+-	c.identify.prp1 = cpu_to_le64(dma_addr);
++	c.identify.prp1 = cpu_to_le64((u64)buffer);
+ 
+ 	length -= (page_size - offset);
+ 	if (length <= 0) {
+ 		c.identify.prp2 = 0;
+ 	} else {
+-		dma_addr += (page_size - offset);
+-		c.identify.prp2 = cpu_to_le64(dma_addr);
++		buffer += (page_size - offset);
++		c.identify.prp2 = cpu_to_le64((u64)buffer);
+ 	}
+ 
+ 	c.identify.cns = cpu_to_le32(cns);
+ 
+-	invalidate_dcache_range(dma_addr,
+-				dma_addr + sizeof(struct nvme_id_ctrl));
++	invalidate_dcache_range((uintptr_t)buffer,
++				(uintptr_t)buffer + sizeof(struct nvme_id_ctrl));
+ 
+ 	ret = nvme_submit_admin_cmd(dev, &c, NULL);
+ 	if (!ret)
+-		invalidate_dcache_range(dma_addr,
+-					dma_addr + sizeof(struct nvme_id_ctrl));
++		invalidate_dcache_range((uintptr_t)buffer,
++					(uintptr_t)buffer + sizeof(struct nvme_id_ctrl));
+ 
+ 	return ret;
+ }
+ 
+ int nvme_get_features(struct nvme_dev *dev, unsigned fid, unsigned nsid,
+-		      dma_addr_t dma_addr, u32 *result)
++		      void *buffer, u32 *result)
+ {
+ 	struct nvme_command c;
+ 	int ret;
+@@ -493,7 +493,7 @@ int nvme_get_features(struct nvme_dev *dev, unsigned fid, unsigned nsid,
+ 	memset(&c, 0, sizeof(c));
+ 	c.features.opcode = nvme_admin_get_features;
+ 	c.features.nsid = cpu_to_le32(nsid);
+-	c.features.prp1 = cpu_to_le64(dma_addr);
++	c.features.prp1 = cpu_to_le64((u64)buffer);
+ 	c.features.fid = cpu_to_le32(fid);
+ 
+ 	ret = nvme_submit_admin_cmd(dev, &c, result);
+@@ -513,13 +513,13 @@ int nvme_get_features(struct nvme_dev *dev, unsigned fid, unsigned nsid,
+ }
+ 
+ int nvme_set_features(struct nvme_dev *dev, unsigned fid, unsigned dword11,
+-		      dma_addr_t dma_addr, u32 *result)
++		      void *buffer, u32 *result)
+ {
+ 	struct nvme_command c;
+ 
+ 	memset(&c, 0, sizeof(c));
+ 	c.features.opcode = nvme_admin_set_features;
+-	c.features.prp1 = cpu_to_le64(dma_addr);
++	c.features.prp1 = cpu_to_le64((u64)buffer);
+ 	c.features.fid = cpu_to_le32(fid);
+ 	c.features.dword11 = cpu_to_le32(dword11);
+ 
+@@ -570,7 +570,7 @@ static int nvme_set_queue_count(struct nvme_dev *dev, int count)
+ 	u32 q_count = (count - 1) | ((count - 1) << 16);
+ 
+ 	status = nvme_set_features(dev, NVME_FEAT_NUM_QUEUES,
+-			q_count, 0, &result);
++			q_count, NULL, &result);
+ 
+ 	if (status < 0)
+ 		return status;
+@@ -622,7 +622,7 @@ static int nvme_get_info_from_identify(struct nvme_dev *dev)
+ 	if (!ctrl)
+ 		return -ENOMEM;
+ 
+-	ret = nvme_identify(dev, 0, 1, (dma_addr_t)(long)ctrl);
++	ret = nvme_identify(dev, 0, 1, ctrl);
+ 	if (ret) {
+ 		free(ctrl);
+ 		return -EIO;
+@@ -708,7 +708,7 @@ static int nvme_blk_probe(struct udevice *udev)
+ 	ns->dev = ndev;
+ 	/* extract the namespace id from the block device name */
+ 	ns->ns_id = trailing_strtol(udev->name);
+-	if (nvme_identify(ndev, ns->ns_id, 0, (dma_addr_t)(long)id)) {
++	if (nvme_identify(ndev, ns->ns_id, 0, id)) {
+ 		free(id);
+ 		return -EIO;
+ 	}
+@@ -743,7 +743,7 @@ static ulong nvme_blk_rw(struct udevice *udev, lbaint_t blknr,
+ 	u64 prp2;
+ 	u64 total_len = blkcnt << desc->log2blksz;
+ 	u64 temp_len = total_len;
+-	uintptr_t temp_buffer = (uintptr_t)buffer;
++	void *temp_buffer = buffer;
+ 
+ 	u64 slba = blknr;
+ 	u16 lbas = 1 << (dev->max_transfer_shift - ns->lba_shift);
+@@ -890,7 +890,7 @@ static int nvme_probe(struct udevice *udev)
+ 		char name[20];
+ 
+ 		memset(id, 0, sizeof(*id));
+-		if (nvme_identify(ndev, i, 0, (dma_addr_t)(long)id)) {
++		if (nvme_identify(ndev, i, 0, id)) {
+ 			ret = -EIO;
+ 			goto free_id;
+ 		}
+diff --git a/drivers/nvme/nvme_show.c b/drivers/nvme/nvme_show.c
+index 15e459da1a..c30adfada5 100644
+--- a/drivers/nvme/nvme_show.c
++++ b/drivers/nvme/nvme_show.c
+@@ -111,14 +111,14 @@ int nvme_print_info(struct udevice *udev)
+ 	ALLOC_CACHE_ALIGN_BUFFER(char, buf_ctrl, sizeof(struct nvme_id_ctrl));
+ 	struct nvme_id_ctrl *ctrl = (struct nvme_id_ctrl *)buf_ctrl;
+ 
+-	if (nvme_identify(dev, 0, 1, (dma_addr_t)(long)ctrl))
++	if (nvme_identify(dev, 0, 1, ctrl))
+ 		return -EIO;
+ 
+ 	print_optional_admin_cmd(le16_to_cpu(ctrl->oacs), ns->devnum);
+ 	print_optional_nvm_cmd(le16_to_cpu(ctrl->oncs), ns->devnum);
+ 	print_format_nvme_attributes(ctrl->fna, ns->devnum);
+ 
+-	if (nvme_identify(dev, ns->ns_id, 0, (dma_addr_t)(long)id))
++	if (nvme_identify(dev, ns->ns_id, 0, id))
+ 		return -EIO;
+ 
+ 	print_formats(id, ns);
+diff --git a/include/nvme.h b/include/nvme.h
+index 2cdf8ce320..8ff823cd81 100644
+--- a/include/nvme.h
++++ b/include/nvme.h
+@@ -18,12 +18,12 @@ struct nvme_dev;
+  * @dev:	NVMe controller device
+  * @nsid:	0 for controller, namespace id for namespace to identify
+  * @cns:	1 for controller, 0 for namespace
+- * @dma_addr:	dma buffer address to store the identify result
++ * @buffer:	dma buffer address to store the identify result
+  * @return:	0 on success, -ETIMEDOUT on command execution timeout,
+  *		-EIO on command execution fails
+  */
+ int nvme_identify(struct nvme_dev *dev, unsigned nsid,
+-		  unsigned cns, dma_addr_t dma_addr);
++		  unsigned int cns, void *buffer);
+ 
+ /**
+  * nvme_get_features - retrieve the attributes of the feature specified
+@@ -33,13 +33,13 @@ int nvme_identify(struct nvme_dev *dev, unsigned nsid,
+  * @dev:	NVMe controller device
+  * @fid:	feature id to provide data
+  * @nsid:	namespace id the command applies to
+- * @dma_addr:	data structure used as part of the specified feature
++ * @buffer:	data structure used as part of the specified feature
+  * @result:	command-specific result in the completion queue entry
+  * @return:	0 on success, -ETIMEDOUT on command execution timeout,
+  *		-EIO on command execution fails
+  */
+ int nvme_get_features(struct nvme_dev *dev, unsigned fid, unsigned nsid,
+-		      dma_addr_t dma_addr, u32 *result);
++		      void *buffer, u32 *result);
+ 
+ /**
+  * nvme_set_features - specify the attributes of the feature indicated
+@@ -49,13 +49,13 @@ int nvme_get_features(struct nvme_dev *dev, unsigned fid, unsigned nsid,
+  * @dev:	NVMe controller device
+  * @fid:	feature id to provide data
+  * @dword11:	command-specific input parameter
+- * @dma_addr:	data structure used as part of the specified feature
++ * @buffer:	data structure used as part of the specified feature
+  * @result:	command-specific result in the completion queue entry
+  * @return:	0 on success, -ETIMEDOUT on command execution timeout,
+  *		-EIO on command execution fails
+  */
+ int nvme_set_features(struct nvme_dev *dev, unsigned fid, unsigned dword11,
+-		      dma_addr_t dma_addr, u32 *result);
++		      void *buffer, u32 *result);
+ 
+ /**
+  * nvme_scan_namespace - scan all namespaces attached to NVMe controllers
+-- 
+2.36.0
+
diff --git a/pkgs/misc/uboot/rpi-cm4/0005-nvme-translate-virtual-addresses-into-the-bus-s-addr.patch b/pkgs/misc/uboot/rpi-cm4/0005-nvme-translate-virtual-addresses-into-the-bus-s-addr.patch
new file mode 100644
index 000000000000..cf25242c6caf
--- /dev/null
+++ b/pkgs/misc/uboot/rpi-cm4/0005-nvme-translate-virtual-addresses-into-the-bus-s-addr.patch
@@ -0,0 +1,198 @@
+From c4736c35141e519d15430660e17c274e142e886d Mon Sep 17 00:00:00 2001
+Message-Id: <c4736c35141e519d15430660e17c274e142e886d.1650924333.git.stefan@agner.ch>
+In-Reply-To: <78704bc154d695ee16fdf8396f4d60b740190014.1650924333.git.stefan@agner.ch>
+References: <78704bc154d695ee16fdf8396f4d60b740190014.1650924333.git.stefan@agner.ch>
+From: Stefan Agner <stefan@agner.ch>
+Date: Fri, 24 Sep 2021 00:27:39 +0200
+Subject: [PATCH 5/5] nvme: translate virtual addresses into the bus's address
+ space
+
+So far we've been content with passing physical/CPU addresses when
+configuring memory addresses into NVMe controllers, but not all
+platforms have buses with transparent mappings. Specifically the
+Raspberry Pi 4 might introduce an offset to memory accesses incoming
+from its PCIe port.
+
+Introduce nvme_virt_to_bus() and nvme_bus_to_virt() to cater with these
+limitations, and make sure we don't break non DM users.
+For devices where PCIe's view of host memory doesn't match the memory
+as seen by the CPU.
+
+A similar change has been introduced for XHCI controller with
+commit 1a474559d90a ("xhci: translate virtual addresses into the bus's
+address space").
+
+Signed-off-by: Stefan Agner <stefan@agner.ch>
+---
+ drivers/nvme/nvme.c | 32 ++++++++++++++++++--------------
+ drivers/nvme/nvme.h | 15 +++++++++++++++
+ 2 files changed, 33 insertions(+), 14 deletions(-)
+
+diff --git a/drivers/nvme/nvme.c b/drivers/nvme/nvme.c
+index 6ab94ada7e..dd190bd654 100644
+--- a/drivers/nvme/nvme.c
++++ b/drivers/nvme/nvme.c
+@@ -95,7 +95,7 @@ static int nvme_setup_prps(struct nvme_dev *dev, u64 *prp2,
+ 		buffer += (page_size - offset);
+ 
+ 	if (length <= page_size) {
+-		*prp2 = (u64)buffer;
++		*prp2 = nvme_virt_to_bus(dev, buffer);
+ 		return 0;
+ 	}
+ 
+@@ -120,16 +120,16 @@ static int nvme_setup_prps(struct nvme_dev *dev, u64 *prp2,
+ 	i = 0;
+ 	while (nprps) {
+ 		if (i == prps_per_page) {
+-			u64 next_prp_list = (u64)prp_pool + page_size;
+-			*(prp_pool + i) = cpu_to_le64(next_prp_list);
++			u64 next = nvme_virt_to_bus(dev, prp_pool + page_size);
++			*(prp_pool + i) = cpu_to_le64(next);
+ 			i = 0;
+ 			prp_pool += page_size;
+ 		}
+-		*(prp_pool + i++) = cpu_to_le64((u64)buffer);
++		*(prp_pool + i++) = cpu_to_le64(nvme_virt_to_bus(dev, buffer));
+ 		buffer += page_size;
+ 		nprps--;
+ 	}
+-	*prp2 = (u64)dev->prp_pool;
++	*prp2 = nvme_virt_to_bus(dev, dev->prp_pool);
+ 
+ 	flush_dcache_range((ulong)dev->prp_pool, (ulong)dev->prp_pool +
+ 			   dev->prp_entry_num * sizeof(u64));
+@@ -356,6 +356,7 @@ static int nvme_configure_admin_queue(struct nvme_dev *dev)
+ 	int result;
+ 	u32 aqa;
+ 	u64 cap = dev->cap;
++	u64 dma_addr;
+ 	struct nvme_queue *nvmeq;
+ 	/* most architectures use 4KB as the page size */
+ 	unsigned page_shift = 12;
+@@ -396,8 +397,10 @@ static int nvme_configure_admin_queue(struct nvme_dev *dev)
+ 	dev->ctrl_config |= NVME_CC_IOSQES | NVME_CC_IOCQES;
+ 
+ 	writel(aqa, &dev->bar->aqa);
+-	nvme_writeq((ulong)nvmeq->sq_cmds, &dev->bar->asq);
+-	nvme_writeq((ulong)nvmeq->cqes, &dev->bar->acq);
++	dma_addr = nvme_virt_to_bus(dev, nvmeq->sq_cmds);
++	nvme_writeq(dma_addr, &dev->bar->asq);
++	dma_addr = nvme_virt_to_bus(dev, nvmeq->cqes);
++	nvme_writeq(dma_addr, &dev->bar->acq);
+ 
+ 	result = nvme_enable_ctrl(dev);
+ 	if (result)
+@@ -423,7 +426,7 @@ static int nvme_alloc_cq(struct nvme_dev *dev, u16 qid,
+ 
+ 	memset(&c, 0, sizeof(c));
+ 	c.create_cq.opcode = nvme_admin_create_cq;
+-	c.create_cq.prp1 = cpu_to_le64((ulong)nvmeq->cqes);
++	c.create_cq.prp1 = cpu_to_le64(nvme_virt_to_bus(dev, nvmeq->cqes));
+ 	c.create_cq.cqid = cpu_to_le16(qid);
+ 	c.create_cq.qsize = cpu_to_le16(nvmeq->q_depth - 1);
+ 	c.create_cq.cq_flags = cpu_to_le16(flags);
+@@ -440,7 +443,7 @@ static int nvme_alloc_sq(struct nvme_dev *dev, u16 qid,
+ 
+ 	memset(&c, 0, sizeof(c));
+ 	c.create_sq.opcode = nvme_admin_create_sq;
+-	c.create_sq.prp1 = cpu_to_le64((ulong)nvmeq->sq_cmds);
++	c.create_sq.prp1 = cpu_to_le64(nvme_virt_to_bus(dev, nvmeq->sq_cmds));
+ 	c.create_sq.sqid = cpu_to_le16(qid);
+ 	c.create_sq.qsize = cpu_to_le16(nvmeq->q_depth - 1);
+ 	c.create_sq.sq_flags = cpu_to_le16(flags);
+@@ -461,14 +464,14 @@ int nvme_identify(struct nvme_dev *dev, unsigned nsid,
+ 	memset(&c, 0, sizeof(c));
+ 	c.identify.opcode = nvme_admin_identify;
+ 	c.identify.nsid = cpu_to_le32(nsid);
+-	c.identify.prp1 = cpu_to_le64((u64)buffer);
++	c.identify.prp1 = cpu_to_le64(nvme_virt_to_bus(dev, buffer));
+ 
+ 	length -= (page_size - offset);
+ 	if (length <= 0) {
+ 		c.identify.prp2 = 0;
+ 	} else {
+ 		buffer += (page_size - offset);
+-		c.identify.prp2 = cpu_to_le64((u64)buffer);
++		c.identify.prp2 = cpu_to_le64(nvme_virt_to_bus(dev, buffer));
+ 	}
+ 
+ 	c.identify.cns = cpu_to_le32(cns);
+@@ -493,7 +496,7 @@ int nvme_get_features(struct nvme_dev *dev, unsigned fid, unsigned nsid,
+ 	memset(&c, 0, sizeof(c));
+ 	c.features.opcode = nvme_admin_get_features;
+ 	c.features.nsid = cpu_to_le32(nsid);
+-	c.features.prp1 = cpu_to_le64((u64)buffer);
++	c.features.prp1 = cpu_to_le64(nvme_virt_to_bus(dev, buffer));
+ 	c.features.fid = cpu_to_le32(fid);
+ 
+ 	ret = nvme_submit_admin_cmd(dev, &c, result);
+@@ -519,7 +522,7 @@ int nvme_set_features(struct nvme_dev *dev, unsigned fid, unsigned dword11,
+ 
+ 	memset(&c, 0, sizeof(c));
+ 	c.features.opcode = nvme_admin_set_features;
+-	c.features.prp1 = cpu_to_le64((u64)buffer);
++	c.features.prp1 = cpu_to_le64(nvme_virt_to_bus(dev, buffer));
+ 	c.features.fid = cpu_to_le32(fid);
+ 	c.features.dword11 = cpu_to_le32(dword11);
+ 
+@@ -776,7 +779,7 @@ static ulong nvme_blk_rw(struct udevice *udev, lbaint_t blknr,
+ 		c.rw.slba = cpu_to_le64(slba);
+ 		slba += lbas;
+ 		c.rw.length = cpu_to_le16(lbas - 1);
+-		c.rw.prp1 = cpu_to_le64(temp_buffer);
++		c.rw.prp1 = cpu_to_le64(nvme_virt_to_bus(dev, temp_buffer));
+ 		c.rw.prp2 = cpu_to_le64(prp2);
+ 		status = nvme_submit_sync_cmd(dev->queues[NVME_IO_Q],
+ 				&c, NULL, IO_TIMEOUT);
+@@ -835,6 +838,7 @@ static int nvme_probe(struct udevice *udev)
+ 	struct nvme_id_ns *id;
+ 
+ 	ndev->instance = trailing_strtol(udev->name);
++	ndev->dev = udev->parent;
+ 
+ 	INIT_LIST_HEAD(&ndev->namespaces);
+ 	ndev->bar = dm_pci_map_bar(udev, PCI_BASE_ADDRESS_0,
+diff --git a/drivers/nvme/nvme.h b/drivers/nvme/nvme.h
+index c6aae4da5d..31e6899bca 100644
+--- a/drivers/nvme/nvme.h
++++ b/drivers/nvme/nvme.h
+@@ -7,8 +7,15 @@
+ #ifndef __DRIVER_NVME_H__
+ #define __DRIVER_NVME_H__
+ 
++#include <phys2bus.h>
+ #include <asm/io.h>
+ 
++#if CONFIG_IS_ENABLED(DM_USB)
++#define nvme_to_dev(_dev)     _dev->dev
++#else
++#define nvme_to_dev(_dev)     NULL
++#endif
++
+ struct nvme_id_power_state {
+ 	__le16			max_power;	/* centiwatts */
+ 	__u8			rsvd2;
+@@ -596,6 +603,9 @@ enum {
+ 
+ /* Represents an NVM Express device. Each nvme_dev is a PCI function. */
+ struct nvme_dev {
++#if CONFIG_IS_ENABLED(DM_USB)
++	struct udevice *dev;
++#endif
+ 	struct list_head node;
+ 	struct nvme_queue **queues;
+ 	u32 __iomem *dbs;
+@@ -635,4 +645,9 @@ struct nvme_ns {
+ 	u8 flbas;
+ };
+ 
++static inline dma_addr_t nvme_virt_to_bus(struct nvme_dev *dev, void *addr)
++{
++	return dev_phys_to_bus(nvme_to_dev(dev), virt_to_phys(addr));
++}
++
+ #endif /* __DRIVER_NVME_H__ */
+-- 
+2.36.0
+