aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/core/of_access.c38
-rw-r--r--drivers/core/ofnode.c62
-rw-r--r--drivers/core/read.c21
-rw-r--r--drivers/gpio/gpio-uclass.c18
-rw-r--r--drivers/gpio/sandbox.c5
-rw-r--r--drivers/misc/usb251xb.c20
-rw-r--r--drivers/nvme/nvme.c8
-rw-r--r--drivers/pinctrl/pinctrl_stm32.c8
-rw-r--r--drivers/rng/Kconfig1
-rw-r--r--drivers/rng/optee_rng.c7
-rw-r--r--drivers/tee/optee/Kconfig8
-rw-r--r--drivers/tee/optee/core.c174
-rw-r--r--drivers/virtio/virtio_pci_modern.c2
13 files changed, 341 insertions, 31 deletions
diff --git a/drivers/core/of_access.c b/drivers/core/of_access.c
index a52f5a6b18..df007e642b 100644
--- a/drivers/core/of_access.c
+++ b/drivers/core/of_access.c
@@ -488,6 +488,44 @@ static void *of_find_property_value_of_size(const struct device_node *np,
return prop->value;
}
+int of_read_u8(const struct device_node *np, const char *propname, u8 *outp)
+{
+ const u8 *val;
+
+ debug("%s: %s: ", __func__, propname);
+ if (!np)
+ return -EINVAL;
+ val = of_find_property_value_of_size(np, propname, sizeof(*outp));
+ if (IS_ERR(val)) {
+ debug("(not found)\n");
+ return PTR_ERR(val);
+ }
+
+ *outp = *val;
+ debug("%#x (%d)\n", *outp, *outp);
+
+ return 0;
+}
+
+int of_read_u16(const struct device_node *np, const char *propname, u16 *outp)
+{
+ const __be16 *val;
+
+ debug("%s: %s: ", __func__, propname);
+ if (!np)
+ return -EINVAL;
+ val = of_find_property_value_of_size(np, propname, sizeof(*outp));
+ if (IS_ERR(val)) {
+ debug("(not found)\n");
+ return PTR_ERR(val);
+ }
+
+ *outp = be16_to_cpup(val);
+ debug("%#x (%d)\n", *outp, *outp);
+
+ return 0;
+}
+
int of_read_u32(const struct device_node *np, const char *propname, u32 *outp)
{
return of_read_u32_index(np, propname, 0, outp);
diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c
index 45ea84e9fb..42f3c09a51 100644
--- a/drivers/core/ofnode.c
+++ b/drivers/core/ofnode.c
@@ -31,6 +31,68 @@ bool ofnode_name_eq(ofnode node, const char *name)
return (strlen(name) == len) && !strncmp(node_name, name, len);
}
+int ofnode_read_u8(ofnode node, const char *propname, u8 *outp)
+{
+ const u8 *cell;
+ int len;
+
+ assert(ofnode_valid(node));
+ debug("%s: %s: ", __func__, propname);
+
+ if (ofnode_is_np(node))
+ return of_read_u8(ofnode_to_np(node), propname, outp);
+
+ cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname,
+ &len);
+ if (!cell || len < sizeof(*cell)) {
+ debug("(not found)\n");
+ return -EINVAL;
+ }
+ *outp = *cell;
+ debug("%#x (%d)\n", *outp, *outp);
+
+ return 0;
+}
+
+u8 ofnode_read_u8_default(ofnode node, const char *propname, u8 def)
+{
+ assert(ofnode_valid(node));
+ ofnode_read_u8(node, propname, &def);
+
+ return def;
+}
+
+int ofnode_read_u16(ofnode node, const char *propname, u16 *outp)
+{
+ const fdt16_t *cell;
+ int len;
+
+ assert(ofnode_valid(node));
+ debug("%s: %s: ", __func__, propname);
+
+ if (ofnode_is_np(node))
+ return of_read_u16(ofnode_to_np(node), propname, outp);
+
+ cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname,
+ &len);
+ if (!cell || len < sizeof(*cell)) {
+ debug("(not found)\n");
+ return -EINVAL;
+ }
+ *outp = be16_to_cpup(cell);
+ debug("%#x (%d)\n", *outp, *outp);
+
+ return 0;
+}
+
+u16 ofnode_read_u16_default(ofnode node, const char *propname, u16 def)
+{
+ assert(ofnode_valid(node));
+ ofnode_read_u16(node, propname, &def);
+
+ return def;
+}
+
int ofnode_read_u32(ofnode node, const char *propname, u32 *outp)
{
return ofnode_read_u32_index(node, propname, 0, outp);
diff --git a/drivers/core/read.c b/drivers/core/read.c
index c73508d276..07ab8ab41c 100644
--- a/drivers/core/read.c
+++ b/drivers/core/read.c
@@ -13,6 +13,27 @@
#include <asm/io.h>
#include <linux/ioport.h>
+int dev_read_u8(const struct udevice *dev, const char *propname, u8 *outp)
+{
+ return ofnode_read_u8(dev_ofnode(dev), propname, outp);
+}
+
+u8 dev_read_u8_default(const struct udevice *dev, const char *propname, u8 def)
+{
+ return ofnode_read_u8_default(dev_ofnode(dev), propname, def);
+}
+
+int dev_read_u16(const struct udevice *dev, const char *propname, u16 *outp)
+{
+ return ofnode_read_u16(dev_ofnode(dev), propname, outp);
+}
+
+u16 dev_read_u16_default(const struct udevice *dev, const char *propname,
+ u16 def)
+{
+ return ofnode_read_u16_default(dev_ofnode(dev), propname, def);
+}
+
int dev_read_u32(const struct udevice *dev, const char *propname, u32 *outp)
{
return ofnode_read_u32(dev_ofnode(dev), propname, outp);
diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c
index 0ed32b7217..a00880e446 100644
--- a/drivers/gpio/gpio-uclass.c
+++ b/drivers/gpio/gpio-uclass.c
@@ -884,26 +884,31 @@ int gpio_get_status(struct udevice *dev, int offset, char *buf, int buffsize)
const struct dm_gpio_ops *ops = gpio_get_ops(dev);
struct gpio_dev_priv *priv;
char *str = buf;
+ const char *label;
int func;
int ret;
int len;
+ bool used;
BUILD_BUG_ON(GPIOF_COUNT != ARRAY_SIZE(gpio_function));
*buf = 0;
priv = dev_get_uclass_priv(dev);
- ret = gpio_get_raw_function(dev, offset, NULL);
+ ret = gpio_get_raw_function(dev, offset, &label);
if (ret < 0)
return ret;
func = ret;
len = snprintf(str, buffsize, "%s%d: %s",
priv->bank_name ? priv->bank_name : "",
offset, gpio_function[func]);
- if (func == GPIOF_INPUT || func == GPIOF_OUTPUT ||
- func == GPIOF_UNUSED) {
- const char *label;
- bool used;
+ switch (func) {
+ case GPIOF_FUNC:
+ snprintf(str + len, buffsize - len, " %s", label ? label : "");
+ break;
+ case GPIOF_INPUT:
+ case GPIOF_OUTPUT:
+ case GPIOF_UNUSED:
ret = ops->get_value(dev, offset);
if (ret < 0)
return ret;
@@ -911,8 +916,9 @@ int gpio_get_status(struct udevice *dev, int offset, char *buf, int buffsize)
snprintf(str + len, buffsize - len, ": %d [%c]%s%s",
ret,
used ? 'x' : ' ',
- used ? " " : "",
+ label ? " " : "",
label ? label : "");
+ break;
}
return 0;
diff --git a/drivers/gpio/sandbox.c b/drivers/gpio/sandbox.c
index 106b2a7b27..305f9a6ff6 100644
--- a/drivers/gpio/sandbox.c
+++ b/drivers/gpio/sandbox.c
@@ -196,6 +196,8 @@ static int sb_gpio_get_function(struct udevice *dev, unsigned offset)
return GPIOF_OUTPUT;
if (get_gpio_flag(dev, offset, GPIOD_IS_IN))
return GPIOF_INPUT;
+ if (get_gpio_flag(dev, offset, GPIOD_IS_AF))
+ return GPIOF_FUNC;
return GPIOF_INPUT; /*GPIO is not configurated */
}
@@ -219,6 +221,9 @@ static int sb_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
if (args->args[1] & GPIO_OUT_ACTIVE)
desc->flags |= GPIOD_IS_OUT_ACTIVE;
+ if (args->args[1] & GPIO_AF)
+ desc->flags |= GPIOD_IS_AF;
+
return 0;
}
diff --git a/drivers/misc/usb251xb.c b/drivers/misc/usb251xb.c
index 077edc2504..a78ad1843a 100644
--- a/drivers/misc/usb251xb.c
+++ b/drivers/misc/usb251xb.c
@@ -400,14 +400,14 @@ static int usb251xb_of_to_plat(struct udevice *dev)
}
}
- if (dev_read_u32(dev, "vendor-id", &hub->vendor_id))
- hub->vendor_id = USB251XB_DEF_VENDOR_ID;
+ hub->vendor_id = dev_read_u16_default(dev, "vendor-id",
+ USB251XB_DEF_VENDOR_ID);
- if (dev_read_u32(dev, "product-id", &hub->product_id))
- hub->product_id = data->product_id;
+ hub->product_id = dev_read_u16_default(dev, "product-id",
+ data->product_id);
- if (dev_read_u32(dev, "device-id", &hub->device_id))
- hub->device_id = USB251XB_DEF_DEVICE_ID;
+ hub->device_id = dev_read_u16_default(dev, "device-id",
+ USB251XB_DEF_DEVICE_ID);
hub->conf_data1 = USB251XB_DEF_CONFIG_DATA_1;
if (dev_read_bool(dev, "self-powered")) {
@@ -513,11 +513,11 @@ static int usb251xb_of_to_plat(struct udevice *dev)
if (!dev_read_u32(dev, "power-on-time-ms", &property_u32))
hub->power_on_time = min_t(u8, property_u32 / 2, 255);
- if (dev_read_u32(dev, "language-id", &hub->lang_id))
- hub->lang_id = USB251XB_DEF_LANGUAGE_ID;
+ hub->lang_id = dev_read_u16_default(dev, "language-id",
+ USB251XB_DEF_LANGUAGE_ID);
- if (!dev_read_u32(dev, "boost-up", &hub->boost_up))
- hub->boost_up = USB251XB_DEF_BOOST_UP;
+ hub->boost_up = dev_read_u8_default(dev, "boost-up",
+ USB251XB_DEF_BOOST_UP);
cproperty_char = dev_read_string(dev, "manufacturer");
strlcpy(str, cproperty_char ? : USB251XB_DEF_MANUFACTURER_STRING,
diff --git a/drivers/nvme/nvme.c b/drivers/nvme/nvme.c
index a305305885..31cf700633 100644
--- a/drivers/nvme/nvme.c
+++ b/drivers/nvme/nvme.c
@@ -72,7 +72,7 @@ static int nvme_setup_prps(struct nvme_dev *dev, u64 *prp2,
}
nprps = DIV_ROUND_UP(length, page_size);
- num_pages = DIV_ROUND_UP(nprps, prps_per_page);
+ num_pages = DIV_ROUND_UP(nprps - 1, prps_per_page - 1);
if (nprps > dev->prp_entry_num) {
free(dev->prp_pool);
@@ -85,13 +85,13 @@ static int nvme_setup_prps(struct nvme_dev *dev, u64 *prp2,
printf("Error: malloc prp_pool fail\n");
return -ENOMEM;
}
- dev->prp_entry_num = prps_per_page * num_pages;
+ dev->prp_entry_num = num_pages * (prps_per_page - 1) + 1;
}
prp_pool = dev->prp_pool;
i = 0;
while (nprps) {
- if (i == ((page_size >> 3) - 1)) {
+ if ((i == (prps_per_page - 1)) && nprps > 1) {
*(prp_pool + i) = cpu_to_le64((ulong)prp_pool +
page_size);
i = 0;
@@ -104,7 +104,7 @@ static int nvme_setup_prps(struct nvme_dev *dev, u64 *prp2,
*prp2 = (ulong)dev->prp_pool;
flush_dcache_range((ulong)dev->prp_pool, (ulong)dev->prp_pool +
- dev->prp_entry_num * sizeof(u64));
+ num_pages * page_size);
return 0;
}
diff --git a/drivers/pinctrl/pinctrl_stm32.c b/drivers/pinctrl/pinctrl_stm32.c
index 990cd19286..b755fa42b4 100644
--- a/drivers/pinctrl/pinctrl_stm32.c
+++ b/drivers/pinctrl/pinctrl_stm32.c
@@ -257,10 +257,12 @@ static int stm32_pinctrl_probe(struct udevice *dev)
return 0;
}
-static int stm32_gpio_config(struct gpio_desc *desc,
+static int stm32_gpio_config(ofnode node,
+ struct gpio_desc *desc,
const struct stm32_gpio_ctl *ctl)
{
struct stm32_gpio_priv *priv = dev_get_priv(desc->dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(desc->dev);
struct stm32_gpio_regs *regs = priv->regs;
struct stm32_pinctrl_priv *ctrl_priv;
int ret;
@@ -291,6 +293,8 @@ static int stm32_gpio_config(struct gpio_desc *desc,
index = desc->offset;
clrsetbits_le32(&regs->otyper, OTYPE_MSK << index, ctl->otype << index);
+ uc_priv->name[desc->offset] = strdup(ofnode_get_name(node));
+
hwspinlock_unlock(&ctrl_priv->hws);
return 0;
@@ -385,7 +389,7 @@ static int stm32_pinctrl_config(ofnode node)
if (rv)
return rv;
desc.offset = gpio_dsc.pin;
- rv = stm32_gpio_config(&desc, &gpio_ctl);
+ rv = stm32_gpio_config(node, &desc, &gpio_ctl);
log_debug("rv = %d\n\n", rv);
if (rv)
return rv;
diff --git a/drivers/rng/Kconfig b/drivers/rng/Kconfig
index 16143681da..5dcf68176a 100644
--- a/drivers/rng/Kconfig
+++ b/drivers/rng/Kconfig
@@ -41,6 +41,7 @@ config RNG_NPCM
config RNG_OPTEE
bool "OP-TEE based Random Number Generator support"
depends on DM_RNG && OPTEE
+ default y if OPTEE_SERVICE_DISCOVERY
help
This driver provides support for the OP-TEE based Random Number
Generator on ARM SoCs where hardware entropy sources are not
diff --git a/drivers/rng/optee_rng.c b/drivers/rng/optee_rng.c
index aa8ce864d3..410dfc053f 100644
--- a/drivers/rng/optee_rng.c
+++ b/drivers/rng/optee_rng.c
@@ -11,6 +11,9 @@
#include <dm/device.h>
#include <dm/device_compat.h>
#include <linux/sizes.h>
+#include <tee/optee_service.h>
+
+#define DRIVER_NAME "optee-rng"
#define TEE_ERROR_HEALTH_TEST_FAIL 0x00000001
@@ -35,6 +38,8 @@
#define TA_HWRNG_UUID { 0xab7a617c, 0xb8e7, 0x4d8f, \
{ 0x83, 0x01, 0xd0, 0x9b, 0x61, 0x03, 0x6b, 0x64 } }
+OPTEE_SERVICE_DRIVER(optee_rng, TA_HWRNG_UUID, DRIVER_NAME);
+
/** open_session_ta_hwrng() - Open session with hwrng Trusted App
*
* @dev: device
@@ -177,7 +182,7 @@ static const struct dm_rng_ops optee_rng_ops = {
};
U_BOOT_DRIVER(optee_rng) = {
- .name = "optee-rng",
+ .name = DRIVER_NAME,
.id = UCLASS_RNG,
.ops = &optee_rng_ops,
.probe = optee_rng_probe,
diff --git a/drivers/tee/optee/Kconfig b/drivers/tee/optee/Kconfig
index d03028070b..9dc65b0501 100644
--- a/drivers/tee/optee/Kconfig
+++ b/drivers/tee/optee/Kconfig
@@ -37,6 +37,14 @@ config OPTEE_TA_SCP03
help
Enables support for controlling (enabling, provisioning) the
Secure Channel Protocol 03 operation in the OP-TEE SCP03 TA.
+
+config OPTEE_SERVICE_DISCOVERY
+ bool "OP-TEE service discovery"
+ default y
+ help
+ This implements automated driver binding of OP-TEE service drivers by
+ requesting OP-TEE firmware to enumerate its hosted services.
+
endmenu
endif
diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c
index a89d62aaf0..9240277579 100644
--- a/drivers/tee/optee/core.c
+++ b/drivers/tee/optee/core.c
@@ -14,6 +14,7 @@
#include <linux/arm-smccc.h>
#include <linux/err.h>
#include <linux/io.h>
+#include <tee/optee_service.h>
#include "optee_smc.h"
#include "optee_msg.h"
@@ -22,6 +23,25 @@
#define PAGELIST_ENTRIES_PER_PAGE \
((OPTEE_MSG_NONCONTIG_PAGE_SIZE / sizeof(u64)) - 1)
+/*
+ * PTA_DEVICE_ENUM interface exposed by OP-TEE to discover enumerated services
+ */
+#define PTA_DEVICE_ENUM { 0x7011a688, 0xddde, 0x4053, \
+ { 0xa5, 0xa9, 0x7b, 0x3c, 0x4d, 0xdf, 0x13, 0xb8 } }
+/*
+ * PTA_CMD_GET_DEVICES - List services without supplicant dependencies
+ *
+ * [out] memref[0]: List of the UUIDs of service enumerated by OP-TEE
+ */
+#define PTA_CMD_GET_DEVICES 0x0
+
+/*
+ * PTA_CMD_GET_DEVICES_SUPP - List services depending on tee supplicant
+ *
+ * [out] memref[0]: List of the UUIDs of service enumerated by OP-TEE
+ */
+#define PTA_CMD_GET_DEVICES_SUPP 0x1
+
typedef void (optee_invoke_fn)(unsigned long, unsigned long, unsigned long,
unsigned long, unsigned long, unsigned long,
unsigned long, unsigned long,
@@ -42,6 +62,134 @@ struct rpc_param {
u32 a7;
};
+static struct optee_service *find_service_driver(const struct tee_optee_ta_uuid *uuid)
+{
+ struct optee_service *service;
+ u8 loc_uuid[TEE_UUID_LEN];
+ size_t service_cnt, idx;
+
+ service_cnt = ll_entry_count(struct optee_service, optee_service);
+ service = ll_entry_start(struct optee_service, optee_service);
+
+ for (idx = 0; idx < service_cnt; idx++, service++) {
+ tee_optee_ta_uuid_to_octets(loc_uuid, &service->uuid);
+ if (!memcmp(uuid, loc_uuid, sizeof(uuid)))
+ return service;
+ }
+
+ return NULL;
+}
+
+static int bind_service_list(struct udevice *dev, struct tee_shm *service_list, size_t count)
+{
+ const struct tee_optee_ta_uuid *service_uuid = (const void *)service_list->addr;
+ struct optee_service *service;
+ size_t idx;
+ int ret;
+
+ for (idx = 0; idx < count; idx++) {
+ service = find_service_driver(service_uuid + idx);
+ if (!service)
+ continue;
+
+ ret = device_bind_driver(dev, service->driver_name, service->driver_name, NULL);
+ if (ret) {
+ dev_warn(dev, "%s was not bound: %d, ignored\n", service->driver_name, ret);
+ continue;
+ }
+ }
+
+ return 0;
+}
+
+static int __enum_services(struct udevice *dev, struct tee_shm *shm, size_t *shm_size, u32 tee_sess)
+{
+ struct tee_invoke_arg arg = { };
+ struct tee_param param = { };
+ int ret = 0;
+
+ arg.func = PTA_CMD_GET_DEVICES;
+ arg.session = tee_sess;
+
+ /* Fill invoke cmd params */
+ param.attr = TEE_PARAM_ATTR_TYPE_MEMREF_OUTPUT;
+ param.u.memref.shm = shm;
+ param.u.memref.size = *shm_size;
+
+ ret = tee_invoke_func(dev, &arg, 1, &param);
+ if (ret || (arg.ret && arg.ret != TEE_ERROR_SHORT_BUFFER)) {
+ dev_err(dev, "PTA_CMD_GET_DEVICES invoke function err: 0x%x\n", arg.ret);
+ return -EINVAL;
+ }
+
+ *shm_size = param.u.memref.size;
+
+ return 0;
+}
+
+static int enum_services(struct udevice *dev, struct tee_shm **shm, size_t *count, u32 tee_sess)
+{
+ size_t shm_size = 0;
+ int ret;
+
+ ret = __enum_services(dev, NULL, &shm_size, tee_sess);
+ if (ret)
+ return ret;
+
+ ret = tee_shm_alloc(dev, shm_size, 0, shm);
+ if (ret) {
+ dev_err(dev, "Failed to allocated shared memory: %d\n", ret);
+ return ret;
+ }
+
+ ret = __enum_services(dev, *shm, &shm_size, tee_sess);
+ if (!ret)
+ *count = shm_size / sizeof(struct tee_optee_ta_uuid);
+
+ return ret;
+}
+
+static int open_enum_session(struct udevice *dev, u32 *tee_sess)
+{
+ const struct tee_optee_ta_uuid pta_uuid = PTA_DEVICE_ENUM;
+ struct tee_open_session_arg arg = { };
+ int ret;
+
+ tee_optee_ta_uuid_to_octets(arg.uuid, &pta_uuid);
+
+ ret = tee_open_session(dev, &arg, 0, NULL);
+ if (ret || arg.ret) {
+ if (!ret)
+ ret = -EIO;
+ return ret;
+ }
+
+ *tee_sess = arg.session;
+
+ return 0;
+}
+
+static int bind_service_drivers(struct udevice *dev)
+{
+ struct tee_shm *service_list = NULL;
+ size_t service_count;
+ u32 tee_sess;
+ int ret;
+
+ ret = open_enum_session(dev, &tee_sess);
+ if (ret)
+ return ret;
+
+ ret = enum_services(dev, &service_list, &service_count, tee_sess);
+ if (!ret)
+ ret = bind_service_list(dev, service_list, service_count);
+
+ tee_shm_free(service_list);
+ tee_close_session(dev, tee_sess);
+
+ return ret;
+}
+
/**
* reg_pair_to_ptr() - Make a pointer of 2 32-bit values
* @reg0: High bits of the pointer
@@ -638,11 +786,18 @@ static int optee_of_to_plat(struct udevice *dev)
return 0;
}
+static int optee_bind(struct udevice *dev)
+{
+ if (IS_ENABLED(CONFIG_OPTEE_SERVICE_DISCOVERY))
+ dev_or_flags(dev, DM_FLAG_PROBE_AFTER_BIND);
+
+ return 0;
+}
+
static int optee_probe(struct udevice *dev)
{
struct optee_pdata *pdata = dev_get_plat(dev);
u32 sec_caps;
- struct udevice *child;
int ret;
if (!is_optee_api(pdata->invoke_fn)) {
@@ -668,12 +823,16 @@ static int optee_probe(struct udevice *dev)
return -ENOENT;
}
- /*
- * in U-Boot, the discovery of TA on the TEE bus is not supported:
- * only bind the drivers associated to the supported OP-TEE TA
- */
- if (IS_ENABLED(CONFIG_RNG_OPTEE)) {
- ret = device_bind_driver(dev, "optee-rng", "optee-rng", &child);
+ if (IS_ENABLED(CONFIG_OPTEE_SERVICE_DISCOVERY)) {
+ ret = bind_service_drivers(dev);
+ if (ret)
+ return ret;
+ } else if (IS_ENABLED(CONFIG_RNG_OPTEE)) {
+ /*
+ * Discovery of TAs on the TEE bus is not supported in U-Boot:
+ * only bind the drivers associated to the supported OP-TEE TA
+ */
+ ret = device_bind_driver(dev, "optee-rng", "optee-rng", NULL);
if (ret)
return ret;
}
@@ -692,6 +851,7 @@ U_BOOT_DRIVER(optee) = {
.of_match = optee_match,
.of_to_plat = optee_of_to_plat,
.probe = optee_probe,
+ .bind = optee_bind,
.ops = &optee_ops,
.plat_auto = sizeof(struct optee_pdata),
.priv_auto = sizeof(struct optee_private),
diff --git a/drivers/virtio/virtio_pci_modern.c b/drivers/virtio/virtio_pci_modern.c
index 880a12cc28..cfde4007f5 100644
--- a/drivers/virtio/virtio_pci_modern.c
+++ b/drivers/virtio/virtio_pci_modern.c
@@ -466,7 +466,7 @@ static void __iomem *virtio_pci_map_capability(struct udevice *udev,
unsigned long mask =
PCI_REGION_TYPE | PCI_REGION_SYS_MEMORY | PCI_REGION_RO;
unsigned long flags = PCI_REGION_MEM;
- u8 *p = dm_pci_map_bar(udev, PCI_BASE_ADDRESS_0 + cap->bar, cap->offset,
+ u8 *p = dm_pci_map_bar(udev, PCI_BASE_ADDRESS_0 + 4 * cap->bar, cap->offset,
cap->length, mask, flags);
return (void __iomem *)p;