summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2021-02-18 08:06:26 -0500
committerTom Rini <trini@konsulko.com>2021-02-18 08:06:26 -0500
commit56f1bcc4b7fbca8789cef90c30f201f5b3fff757 (patch)
treed587eafbc09d7ec51a9b12dca023ddce60507876
parent496f49464d90b564da5f1a2f4eecb5553e01edf9 (diff)
parent0059ef0be903a1f0a9afe5259fb2e0874f78a8ac (diff)
downloadu-boot-56f1bcc4b7fbca8789cef90c30f201f5b3fff757.tar.gz
Merge tag 'rpi-next-2021.04' of https://gitlab.denx.de/u-boot/custodians/u-boot-raspberrypi
- add iProc RNG2000 driver for RPi4 - add support for CM4 and RPi400
-rw-r--r--arch/sandbox/dts/test.dts21
-rw-r--r--board/raspberrypi/rpi/rpi.c17
-rw-r--r--common/fdt_support.c73
-rw-r--r--configs/rpi_4_32b_defconfig1
-rw-r--r--configs/rpi_4_defconfig3
-rw-r--r--configs/rpi_arm64_defconfig3
-rw-r--r--configs/sandbox64_defconfig1
-rw-r--r--configs/sandbox_defconfig1
-rw-r--r--configs/sandbox_flattree_defconfig1
-rw-r--r--configs/sandbox_spl_defconfig1
-rw-r--r--drivers/core/Kconfig10
-rw-r--r--drivers/core/device.c41
-rw-r--r--drivers/core/of_addr.c78
-rw-r--r--drivers/core/ofnode.c9
-rw-r--r--drivers/core/read.c6
-rw-r--r--drivers/mmc/sdhci.c10
-rw-r--r--drivers/pci/pcie_brcmstb.c32
-rw-r--r--drivers/rng/Kconfig6
-rw-r--r--drivers/rng/Makefile1
-rw-r--r--drivers/rng/iproc_rng200.c185
-rw-r--r--drivers/usb/host/xhci-mem.c45
-rw-r--r--drivers/usb/host/xhci-pci.c2
-rw-r--r--drivers/usb/host/xhci-ring.c13
-rw-r--r--drivers/usb/host/xhci.c4
-rw-r--r--drivers/video/bcm2835.c1
-rw-r--r--include/dm/device.h13
-rw-r--r--include/dm/of_addr.h17
-rw-r--r--include/dm/ofnode.h16
-rw-r--r--include/dm/read.h21
-rw-r--r--include/fdt_support.h14
-rw-r--r--include/mmc.h6
-rw-r--r--include/phys2bus.h17
-rw-r--r--include/usb/xhci.h20
-rw-r--r--test/dm/Makefile2
-rw-r--r--test/dm/core.c30
-rw-r--r--test/dm/phys2bus.c37
-rw-r--r--test/dm/read.c49
37 files changed, 766 insertions, 41 deletions
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index e95f4631bf..d4195b45bb 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -350,6 +350,27 @@
test5-gpios = <&gpio_a 19>;
};
+ mmio-bus@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "denx,u-boot-test-bus";
+ dma-ranges = <0x10000000 0x00000000 0x00040000>;
+
+ subnode@0 {
+ compatible = "denx,u-boot-fdt-test";
+ };
+ };
+
+ mmio-bus@1 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "denx,u-boot-test-bus";
+
+ subnode@0 {
+ compatible = "denx,u-boot-fdt-test";
+ };
+ };
+
acpi_test1: acpi-test {
compatible = "denx,u-boot-acpi-test";
acpi-ssdt-test-data = "ab";
diff --git a/board/raspberrypi/rpi/rpi.c b/board/raspberrypi/rpi/rpi.c
index 6b1fa5fc14..df52a4689f 100644
--- a/board/raspberrypi/rpi/rpi.c
+++ b/board/raspberrypi/rpi/rpi.c
@@ -157,6 +157,16 @@ static const struct rpi_model rpi_models_new_scheme[] = {
DTB_DIR "bcm2711-rpi-4-b.dtb",
true,
},
+ [0x13] = {
+ "400",
+ DTB_DIR "bcm2711-rpi-400.dtb",
+ true,
+ },
+ [0x14] = {
+ "Compute Module 4",
+ DTB_DIR "bcm2711-rpi-cm4.dtb",
+ true,
+ },
};
static const struct rpi_model rpi_models_old_scheme[] = {
@@ -268,6 +278,13 @@ int dram_init(void)
gd->ram_size = msg->get_arm_mem.body.resp.mem_size;
+ /*
+ * In some configurations the memory size returned by VideoCore
+ * is not aligned to the section size, what is mandatory for
+ * the u-boot's memory setup.
+ */
+ gd->ram_size &= ~MMU_SECTION_SIZE;
+
return 0;
}
diff --git a/common/fdt_support.c b/common/fdt_support.c
index 638eca983e..1a1b408607 100644
--- a/common/fdt_support.c
+++ b/common/fdt_support.c
@@ -1344,6 +1344,79 @@ u64 fdt_translate_dma_address(const void *blob, int node_offset,
return __of_translate_address(blob, node_offset, in_addr, "dma-ranges");
}
+int fdt_get_dma_range(const void *blob, int node, phys_addr_t *cpu,
+ dma_addr_t *bus, u64 *size)
+{
+ bool found_dma_ranges = false;
+ struct of_bus *bus_node;
+ const fdt32_t *ranges;
+ int na, ns, pna, pns;
+ int parent = node;
+ int ret = 0;
+ int len;
+
+ /* Find the closest dma-ranges property */
+ while (parent >= 0) {
+ ranges = fdt_getprop(blob, parent, "dma-ranges", &len);
+
+ /* Ignore empty ranges, they imply no translation required */
+ if (ranges && len > 0)
+ break;
+
+ /* Once we find 'dma-ranges', then a missing one is an error */
+ if (found_dma_ranges && !ranges) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (ranges)
+ found_dma_ranges = true;
+
+ parent = fdt_parent_offset(blob, parent);
+ }
+
+ if (!ranges || parent < 0) {
+ debug("no dma-ranges found for node %s\n",
+ fdt_get_name(blob, node, NULL));
+ ret = -ENOENT;
+ goto out;
+ }
+
+ /* switch to that node */
+ node = parent;
+ parent = fdt_parent_offset(blob, node);
+ if (parent < 0) {
+ printf("Found dma-ranges in root node, shoudln't happen\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* Get the address sizes both for the bus and its parent */
+ bus_node = of_match_bus(blob, node);
+ bus_node->count_cells(blob, node, &na, &ns);
+ if (!OF_CHECK_COUNTS(na, ns)) {
+ printf("%s: Bad cell count for %s\n", __FUNCTION__,
+ fdt_get_name(blob, node, NULL));
+ return -EINVAL;
+ goto out;
+ }
+
+ bus_node = of_match_bus(blob, parent);
+ bus_node->count_cells(blob, parent, &pna, &pns);
+ if (!OF_CHECK_COUNTS(pna, pns)) {
+ printf("%s: Bad cell count for %s\n", __FUNCTION__,
+ fdt_get_name(blob, parent, NULL));
+ return -EINVAL;
+ goto out;
+ }
+
+ *bus = fdt_read_number(ranges, na);
+ *cpu = fdt_translate_dma_address(blob, node, ranges + na);
+ *size = fdt_read_number(ranges + na + pna, ns);
+out:
+ return ret;
+}
+
/**
* fdt_node_offset_by_compat_reg: Find a node that matches compatiable and
* who's reg property matches a physical cpu address
diff --git a/configs/rpi_4_32b_defconfig b/configs/rpi_4_32b_defconfig
index 5ddd838fd5..0a5d3ff8cd 100644
--- a/configs/rpi_4_32b_defconfig
+++ b/configs/rpi_4_32b_defconfig
@@ -22,6 +22,7 @@ CONFIG_OF_BOARD=y
CONFIG_ENV_FAT_DEVICE_AND_PART="0:1"
CONFIG_SYS_RELOC_GD_ENV_ADDR=y
CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y
+CONFIG_DM_DMA=y
CONFIG_DFU_MMC=y
CONFIG_DM_KEYBOARD=y
CONFIG_DM_MMC=y
diff --git a/configs/rpi_4_defconfig b/configs/rpi_4_defconfig
index 2590d0a696..cb6ee773e1 100644
--- a/configs/rpi_4_defconfig
+++ b/configs/rpi_4_defconfig
@@ -22,6 +22,7 @@ CONFIG_OF_BOARD=y
CONFIG_ENV_FAT_DEVICE_AND_PART="0:1"
CONFIG_SYS_RELOC_GD_ENV_ADDR=y
CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y
+CONFIG_DM_DMA=y
CONFIG_DFU_MMC=y
CONFIG_DM_KEYBOARD=y
CONFIG_DM_MMC=y
@@ -36,6 +37,8 @@ CONFIG_PCI_BRCMSTB=y
CONFIG_PINCTRL=y
# CONFIG_PINCTRL_GENERIC is not set
CONFIG_DM_RESET=y
+CONFIG_DM_RNG=y
+CONFIG_RNG_IPROC200=y
# CONFIG_REQUIRE_SERIAL_CONSOLE is not set
CONFIG_USB=y
CONFIG_DM_USB=y
diff --git a/configs/rpi_arm64_defconfig b/configs/rpi_arm64_defconfig
index 2639219a1a..4d69026c1d 100644
--- a/configs/rpi_arm64_defconfig
+++ b/configs/rpi_arm64_defconfig
@@ -20,6 +20,7 @@ CONFIG_CMD_FS_UUID=y
CONFIG_OF_BOARD=y
CONFIG_ENV_FAT_DEVICE_AND_PART="0:1"
CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y
+CONFIG_DM_DMA=y
CONFIG_DM_KEYBOARD=y
CONFIG_DM_MMC=y
CONFIG_MMC_SDHCI=y
@@ -33,6 +34,8 @@ CONFIG_PCI_BRCMSTB=y
CONFIG_PINCTRL=y
# CONFIG_PINCTRL_GENERIC is not set
CONFIG_DM_RESET=y
+CONFIG_DM_RNG=y
+CONFIG_RNG_IPROC200=y
# CONFIG_REQUIRE_SERIAL_CONSOLE is not set
CONFIG_USB=y
CONFIG_DM_USB=y
diff --git a/configs/sandbox64_defconfig b/configs/sandbox64_defconfig
index 4e67819559..634c19502c 100644
--- a/configs/sandbox64_defconfig
+++ b/configs/sandbox64_defconfig
@@ -94,6 +94,7 @@ CONFIG_ENV_EXT4_DEVICE_AND_PART="0:0"
CONFIG_BOOTP_SEND_HOSTNAME=y
CONFIG_NETCONSOLE=y
CONFIG_IP_DEFRAG=y
+CONFIG_DM_DMA=y
CONFIG_REGMAP=y
CONFIG_SYSCON=y
CONFIG_DEVRES=y
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index 0c7674efc9..fc1df3114c 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -108,6 +108,7 @@ CONFIG_ENV_EXT4_DEVICE_AND_PART="0:0"
CONFIG_BOOTP_SEND_HOSTNAME=y
CONFIG_NETCONSOLE=y
CONFIG_IP_DEFRAG=y
+CONFIG_DM_DMA=y
CONFIG_REGMAP=y
CONFIG_SYSCON=y
CONFIG_DEVRES=y
diff --git a/configs/sandbox_flattree_defconfig b/configs/sandbox_flattree_defconfig
index 96465c56cf..4401f33f0b 100644
--- a/configs/sandbox_flattree_defconfig
+++ b/configs/sandbox_flattree_defconfig
@@ -75,6 +75,7 @@ CONFIG_ENV_EXT4_DEVICE_AND_PART="0:0"
CONFIG_BOOTP_SEND_HOSTNAME=y
CONFIG_NETCONSOLE=y
CONFIG_IP_DEFRAG=y
+CONFIG_DM_DMA=y
CONFIG_REGMAP=y
CONFIG_SYSCON=y
CONFIG_DEVRES=y
diff --git a/configs/sandbox_spl_defconfig b/configs/sandbox_spl_defconfig
index 61dae34a6a..c0118702a8 100644
--- a/configs/sandbox_spl_defconfig
+++ b/configs/sandbox_spl_defconfig
@@ -95,6 +95,7 @@ CONFIG_BOOTP_SEND_HOSTNAME=y
CONFIG_NETCONSOLE=y
CONFIG_IP_DEFRAG=y
CONFIG_SPL_DM=y
+CONFIG_DM_DMA=y
CONFIG_REGMAP=y
CONFIG_SPL_REGMAP=y
CONFIG_SYSCON=y
diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig
index dbfe51c6e8..00554af499 100644
--- a/drivers/core/Kconfig
+++ b/drivers/core/Kconfig
@@ -129,6 +129,16 @@ config TPL_DM_INLINE_OFNODE
This applies to several ofnode functions (see ofnode.h) which are
seldom used. Inlining them can help reduce code size.
+config DM_DMA
+ bool "Support per-device DMA constraints"
+ depends on DM
+ default n
+ help
+ Enable this to extract per-device DMA constraints, only supported on
+ device-tree systems for now. This is needed in order translate
+ addresses on systems where different buses have different views of
+ the physical address space.
+
config REGMAP
bool "Support register maps"
depends on DM
diff --git a/drivers/core/device.c b/drivers/core/device.c
index 82a0098960..625134921d 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -422,6 +422,43 @@ fail:
return ret;
}
+/**
+ * device_get_dma_constraints() - Populate device's DMA constraints
+ *
+ * Gets a device's DMA constraints from firmware. This information is later
+ * used by drivers to translate physcal addresses to the device's bus address
+ * space. For now only device-tree is supported.
+ *
+ * @dev: Pointer to target device
+ * Return: 0 if OK or if no DMA constraints were found, error otherwise
+ */
+static int device_get_dma_constraints(struct udevice *dev)
+{
+ struct udevice *parent = dev->parent;
+ phys_addr_t cpu = 0;
+ dma_addr_t bus = 0;
+ u64 size = 0;
+ int ret;
+
+ if (!CONFIG_IS_ENABLED(DM_DMA) || !parent || !dev_has_ofnode(parent))
+ return 0;
+
+ /*
+ * We start parsing for dma-ranges from the device's bus node. This is
+ * specially important on nested buses.
+ */
+ ret = dev_get_dma_range(parent, &cpu, &bus, &size);
+ /* Don't return an error if no 'dma-ranges' were found */
+ if (ret && ret != -ENOENT) {
+ dm_warn("%s: failed to get DMA range, %d\n", dev->name, ret);
+ return ret;
+ }
+
+ dev_set_dma_offset(dev, cpu - bus);
+
+ return 0;
+}
+
int device_probe(struct udevice *dev)
{
const struct driver *drv;
@@ -484,6 +521,10 @@ int device_probe(struct udevice *dev)
goto fail;
}
+ ret = device_get_dma_constraints(dev);
+ if (ret)
+ goto fail;
+
ret = uclass_pre_probe_device(dev);
if (ret)
goto fail;
diff --git a/drivers/core/of_addr.c b/drivers/core/of_addr.c
index bbe80136ba..5bc6ca1de0 100644
--- a/drivers/core/of_addr.c
+++ b/drivers/core/of_addr.c
@@ -318,6 +318,84 @@ u64 of_translate_dma_address(const struct device_node *dev, const __be32 *in_add
return __of_translate_address(dev, in_addr, "dma-ranges");
}
+int of_get_dma_range(const struct device_node *dev, phys_addr_t *cpu,
+ dma_addr_t *bus, u64 *size)
+{
+ bool found_dma_ranges = false;
+ struct device_node *parent;
+ struct of_bus *bus_node;
+ int na, ns, pna, pns;
+ const __be32 *ranges;
+ int ret = 0;
+ int len;
+
+ /* Find the closest dma-ranges property */
+ dev = of_node_get(dev);
+ while (dev) {
+ ranges = of_get_property(dev, "dma-ranges", &len);
+
+ /* Ignore empty ranges, they imply no translation required */
+ if (ranges && len > 0)
+ break;
+
+ /* Once we find 'dma-ranges', then a missing one is an error */
+ if (found_dma_ranges && !ranges) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (ranges)
+ found_dma_ranges = true;
+
+ parent = of_get_parent(dev);
+ of_node_put(dev);
+ dev = parent;
+ }
+
+ if (!dev || !ranges) {
+ debug("no dma-ranges found for node %s\n",
+ of_node_full_name(dev));
+ ret = -ENOENT;
+ goto out;
+ }
+
+ /* switch to that node */
+ parent = of_get_parent(dev);
+ if (!parent) {
+ printf("Found dma-ranges in root node, shoudln't happen\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* Get the address sizes both for the bus and its parent */
+ bus_node = of_match_bus((struct device_node*)dev);
+ bus_node->count_cells(dev, &na, &ns);
+ if (!OF_CHECK_COUNTS(na, ns)) {
+ printf("Bad cell count for %s\n", of_node_full_name(dev));
+ return -EINVAL;
+ goto out_parent;
+ }
+
+ bus_node = of_match_bus(parent);
+ bus_node->count_cells(parent, &pna, &pns);
+ if (!OF_CHECK_COUNTS(pna, pns)) {
+ printf("Bad cell count for %s\n", of_node_full_name(parent));
+ return -EINVAL;
+ goto out_parent;
+ }
+
+ *bus = of_read_number(ranges, na);
+ *cpu = of_translate_dma_address(dev, ranges + na);
+ *size = of_read_number(ranges + na + pna, ns);
+
+out_parent:
+ of_node_put(parent);
+out:
+ of_node_put(dev);
+ return ret;
+}
+
+
static int __of_address_to_resource(const struct device_node *dev,
const __be32 *addrp, u64 size, unsigned int flags,
const char *name, struct resource *r)
diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c
index 26c9d04056..fa0bd2a9c4 100644
--- a/drivers/core/ofnode.c
+++ b/drivers/core/ofnode.c
@@ -927,6 +927,15 @@ u64 ofnode_translate_dma_address(ofnode node, const fdt32_t *in_addr)
return fdt_translate_dma_address(gd->fdt_blob, ofnode_to_offset(node), in_addr);
}
+int ofnode_get_dma_range(ofnode node, phys_addr_t *cpu, dma_addr_t *bus, u64 *size)
+{
+ if (ofnode_is_np(node))
+ return of_get_dma_range(ofnode_to_np(node), cpu, bus, size);
+ else
+ return fdt_get_dma_range(gd->fdt_blob, ofnode_to_offset(node),
+ cpu, bus, size);
+}
+
int ofnode_device_is_compatible(ofnode node, const char *compat)
{
if (ofnode_is_np(node))
diff --git a/drivers/core/read.c b/drivers/core/read.c
index 14fd1214d6..4307ca4579 100644
--- a/drivers/core/read.c
+++ b/drivers/core/read.c
@@ -341,6 +341,12 @@ u64 dev_translate_dma_address(const struct udevice *dev, const fdt32_t *in_addr)
return ofnode_translate_dma_address(dev_ofnode(dev), in_addr);
}
+int dev_get_dma_range(const struct udevice *dev, phys_addr_t *cpu,
+ dma_addr_t *bus, u64 *size)
+{
+ return ofnode_get_dma_range(dev_ofnode(dev), cpu, bus, size);
+}
+
int dev_read_alias_highest_id(const char *stem)
{
if (of_live_active())
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index ed0dc17325..5f18d472bd 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -74,6 +74,7 @@ static void sdhci_transfer_pio(struct sdhci_host *host, struct mmc_data *data)
static void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data,
int *is_aligned, int trans_bytes)
{
+ dma_addr_t dma_addr;
unsigned char ctrl;
void *buf;
@@ -104,8 +105,8 @@ static void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data,
mmc_get_dma_dir(data));
if (host->flags & USE_SDMA) {
- sdhci_writel(host, phys_to_bus((ulong)host->start_addr),
- SDHCI_DMA_ADDRESS);
+ dma_addr = dev_phys_to_bus(mmc_to_dev(host->mmc), host->start_addr);
+ sdhci_writel(host, dma_addr, SDHCI_DMA_ADDRESS);
}
#if CONFIG_IS_ENABLED(MMC_SDHCI_ADMA)
else if (host->flags & (USE_ADMA | USE_ADMA64)) {
@@ -163,8 +164,9 @@ static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data)
start_addr &=
~(SDHCI_DEFAULT_BOUNDARY_SIZE - 1);
start_addr += SDHCI_DEFAULT_BOUNDARY_SIZE;
- sdhci_writel(host, phys_to_bus((ulong)start_addr),
- SDHCI_DMA_ADDRESS);
+ start_addr = dev_phys_to_bus(mmc_to_dev(host->mmc),
+ start_addr);
+ sdhci_writel(host, start_addr, SDHCI_DMA_ADDRESS);
}
}
if (timeout-- > 0)
diff --git a/drivers/pci/pcie_brcmstb.c b/drivers/pci/pcie_brcmstb.c
index dd2a4ef629..90225f6779 100644
--- a/drivers/pci/pcie_brcmstb.c
+++ b/drivers/pci/pcie_brcmstb.c
@@ -432,6 +432,7 @@ static int brcm_pcie_probe(struct udevice *dev)
struct pci_controller *hose = dev_get_uclass_priv(ctlr);
struct brcm_pcie *pcie = dev_get_priv(dev);
void __iomem *base = pcie->base;
+ struct pci_region region;
bool ssc_good = false;
int num_out_wins = 0;
u64 rc_bar2_offset, rc_bar2_size;
@@ -468,13 +469,10 @@ static int brcm_pcie_probe(struct udevice *dev)
MISC_CTRL_SCB_ACCESS_EN_MASK |
MISC_CTRL_CFG_READ_UR_MODE_MASK |
MISC_CTRL_MAX_BURST_SIZE_128);
- /*
- * TODO: When support for other SoCs than BCM2711 is added we may
- * need to use the base address and size(s) provided in the dma-ranges
- * property.
- */
- rc_bar2_offset = 0;
- rc_bar2_size = 0xc0000000;
+
+ pci_get_dma_regions(dev, &region, 0);
+ rc_bar2_offset = region.bus_start - region.phys_start;
+ rc_bar2_size = 1ULL << fls64(region.size - 1);
tmp = lower_32_bits(rc_bar2_offset);
u32p_replace_bits(&tmp, brcm_pcie_encode_ibar_size(rc_bar2_size),
@@ -579,6 +577,24 @@ static int brcm_pcie_probe(struct udevice *dev)
return 0;
}
+static int brcm_pcie_remove(struct udevice *dev)
+{
+ struct brcm_pcie *pcie = dev_get_priv(dev);
+ void __iomem *base = pcie->base;
+
+ /* Assert fundamental reset */
+ setbits_le32(base + PCIE_RGR1_SW_INIT_1, RGR1_SW_INIT_1_PERST_MASK);
+
+ /* Turn off SerDes */
+ setbits_le32(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG,
+ PCIE_HARD_DEBUG_SERDES_IDDQ_MASK);
+
+ /* Shutdown bridge */
+ setbits_le32(base + PCIE_RGR1_SW_INIT_1, RGR1_SW_INIT_1_INIT_MASK);
+
+ return 0;
+}
+
static int brcm_pcie_of_to_plat(struct udevice *dev)
{
struct brcm_pcie *pcie = dev_get_priv(dev);
@@ -618,6 +634,8 @@ U_BOOT_DRIVER(pcie_brcm_base) = {
.ops = &brcm_pcie_ops,
.of_match = brcm_pcie_ids,
.probe = brcm_pcie_probe,
+ .remove = brcm_pcie_remove,
.of_to_plat = brcm_pcie_of_to_plat,
.priv_auto = sizeof(struct brcm_pcie),
+ .flags = DM_FLAG_OS_PREPARE,
};
diff --git a/drivers/rng/Kconfig b/drivers/rng/Kconfig
index 11001c8ae7..94915d45b3 100644
--- a/drivers/rng/Kconfig
+++ b/drivers/rng/Kconfig
@@ -46,4 +46,10 @@ config RNG_ROCKCHIP
Enable random number generator for rockchip.This driver is
support rng module of crypto v1 and crypto v2.
+config RNG_IPROC200
+ bool "Broadcom iProc RNG200 random number generator"
+ depends on DM_RNG
+ default n
+ help
+ Enable random number generator for RPI4.
endif
diff --git a/drivers/rng/Makefile b/drivers/rng/Makefile
index 8953406882..39f7ee3f03 100644
--- a/drivers/rng/Makefile
+++ b/drivers/rng/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_RNG_SANDBOX) += sandbox_rng.o
obj-$(CONFIG_RNG_MSM) += msm_rng.o
obj-$(CONFIG_RNG_STM32MP1) += stm32mp1_rng.o
obj-$(CONFIG_RNG_ROCKCHIP) += rockchip_rng.o
+obj-$(CONFIG_RNG_IPROC200) += iproc_rng200.o
diff --git a/drivers/rng/iproc_rng200.c b/drivers/rng/iproc_rng200.c
new file mode 100644
index 0000000000..f71f285f53
--- /dev/null
+++ b/drivers/rng/iproc_rng200.c
@@ -0,0 +1,185 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2020, Matthias Brugger <mbrugger@suse.com>
+ *
+ * Driver for Raspberry Pi hardware random number generator
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <linux/delay.h>
+#include <rng.h>
+#include <asm/io.h>
+
+#define usleep_range(a, b) udelay((b))
+
+#define RNG_CTRL_OFFSET 0x00
+#define RNG_CTRL_RNG_RBGEN_MASK 0x00001FFF
+#define RNG_CTRL_RNG_RBGEN_ENABLE 0x00000001
+#define RNG_CTRL_RNG_RBGEN_DISABLE 0x00000000
+
+#define RNG_SOFT_RESET_OFFSET 0x04
+#define RNG_SOFT_RESET 0x00000001
+
+#define RBG_SOFT_RESET_OFFSET 0x08
+#define RBG_SOFT_RESET 0x00000001
+
+#define RNG_INT_STATUS_OFFSET 0x18
+#define RNG_INT_STATUS_MASTER_FAIL_LOCKOUT_IRQ_MASK 0x80000000
+#define RNG_INT_STATUS_NIST_FAIL_IRQ_MASK 0x00000020
+
+#define RNG_FIFO_DATA_OFFSET 0x20
+
+#define RNG_FIFO_COUNT_OFFSET 0x24
+#define RNG_FIFO_COUNT_RNG_FIFO_COUNT_MASK 0x000000FF
+
+struct iproc_rng200_platdata {
+ fdt_addr_t base;
+};
+
+static void iproc_rng200_enable(struct iproc_rng200_platdata *pdata, bool enable)
+{
+ fdt_addr_t rng_base = pdata->base;
+ u32 val;
+
+ val = readl(rng_base + RNG_CTRL_OFFSET);
+ val &= ~RNG_CTRL_RNG_RBGEN_MASK;
+ if (enable)
+ val |= RNG_CTRL_RNG_RBGEN_ENABLE;
+ else
+ val &= ~RNG_CTRL_RNG_RBGEN_ENABLE;
+
+ writel(val, rng_base + RNG_CTRL_OFFSET);
+}
+
+static void iproc_rng200_restart(struct iproc_rng200_platdata *pdata)
+{
+ fdt_addr_t rng_base = pdata->base;
+ u32 val;
+
+ iproc_rng200_enable(pdata, false);
+
+ /* Clear all interrupt status */
+ writel(0xFFFFFFFFUL, rng_base + RNG_INT_STATUS_OFFSET);
+
+ /* Reset RNG and RBG */
+ val = readl(rng_base + RBG_SOFT_RESET_OFFSET);
+ val |= RBG_SOFT_RESET;
+ writel(val, rng_base + RBG_SOFT_RESET_OFFSET);
+
+ val = readl(rng_base + RNG_SOFT_RESET_OFFSET);
+ val |= RNG_SOFT_RESET;
+ writel(val, rng_base + RNG_SOFT_RESET_OFFSET);
+
+ val = readl(rng_base + RNG_SOFT_RESET_OFFSET);
+ val &= ~RNG_SOFT_RESET;
+ writel(val, rng_base + RNG_SOFT_RESET_OFFSET);
+
+ val = readl(rng_base + RBG_SOFT_RESET_OFFSET);
+ val &= ~RBG_SOFT_RESET;
+ writel(val, rng_base + RBG_SOFT_RESET_OFFSET);
+
+ iproc_rng200_enable(pdata, true);
+}
+
+static int iproc_rng200_read(struct udevice *dev, void *data, size_t len)
+{
+ struct iproc_rng200_platdata *priv = dev_get_plat(dev);
+ char *buf = (char *)data;
+ u32 num_remaining = len;
+ u32 status;
+
+ #define MAX_RESETS_PER_READ 1
+ u32 num_resets = 0;
+
+ while (num_remaining > 0) {
+
+ /* Is RNG sane? If not, reset it. */
+ status = readl(priv->base + RNG_INT_STATUS_OFFSET);
+ if ((status & (RNG_INT_STATUS_MASTER_FAIL_LOCKOUT_IRQ_MASK |
+ RNG_INT_STATUS_NIST_FAIL_IRQ_MASK)) != 0) {
+
+ if (num_resets >= MAX_RESETS_PER_READ)
+ return len - num_remaining;
+
+ iproc_rng200_restart(priv);
+ num_resets++;
+ }
+
+ /* Are there any random numbers available? */
+ if ((readl(priv->base + RNG_FIFO_COUNT_OFFSET) &
+ RNG_FIFO_COUNT_RNG_FIFO_COUNT_MASK) > 0) {
+
+ if (num_remaining >= sizeof(u32)) {
+ /* Buffer has room to store entire word */
+ *(u32 *)buf = readl(priv->base +
+ RNG_FIFO_DATA_OFFSET);
+ buf += sizeof(u32);
+ num_remaining -= sizeof(u32);
+ } else {
+ /* Buffer can only store partial word */
+ u32 rnd_number = readl(priv->base +
+ RNG_FIFO_DATA_OFFSET);
+ memcpy(buf, &rnd_number, num_remaining);
+ buf += num_remaining;
+ num_remaining = 0;
+ }
+
+ } else {
+ /* Can wait, give others chance to run */
+ usleep_range(min(num_remaining * 10, 500U), 500);
+ }
+ }
+
+ return 0;
+}
+
+static int iproc_rng200_probe(struct udevice *dev)
+{
+ struct iproc_rng200_platdata *priv = dev_get_plat(dev);
+
+ iproc_rng200_enable(priv, true);
+
+ return 0;
+}
+
+static int iproc_rng200_remove(struct udevice *dev)
+{
+ struct iproc_rng200_platdata *priv = dev_get_plat(dev);
+
+ iproc_rng200_enable(priv, false);
+
+ return 0;
+}
+
+static int iproc_rng200_ofdata_to_platdata(struct udevice *dev)
+{
+ struct iproc_rng200_platdata *pdata = dev_get_plat(dev);
+
+ pdata->base = dev_read_addr(dev);
+ if (!pdata->base)
+ return -ENODEV;
+
+ return 0;
+}
+
+static const struct dm_rng_ops iproc_rng200_ops = {
+ .read = iproc_rng200_read,
+};
+
+static const struct udevice_id iproc_rng200_rng_match[] = {
+ { .compatible = "brcm,bcm2711-rng200", },
+ { .compatible = "brcm,iproc-rng200", },
+ {},
+};
+
+U_BOOT_DRIVER(iproc_rng200_rng) = {
+ .name = "iproc_rng200-rng",
+ .id = UCLASS_RNG,
+ .of_match = iproc_rng200_rng_match,
+ .ops = &iproc_rng200_ops,
+ .probe = iproc_rng200_probe,
+ .remove = iproc_rng200_remove,
+ .plat_auto = sizeof(struct iproc_rng200_platdata),
+ .of_to_plat = iproc_rng200_ofdata_to_platdata,
+};
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index b002d6f166..83147d51b5 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -110,7 +110,7 @@ static void xhci_scratchpad_free(struct xhci_ctrl *ctrl)
ctrl->dcbaa->dev_context_ptrs[0] = 0;
- free((void *)(uintptr_t)le64_to_cpu(ctrl->scratchpad->sp_array[0]));
+ free(xhci_bus_to_virt(ctrl, le64_to_cpu(ctrl->scratchpad->sp_array[0])));
free(ctrl->scratchpad->sp_array);
free(ctrl->scratchpad);
ctrl->scratchpad = NULL;
@@ -216,8 +216,8 @@ static void *xhci_malloc(unsigned int size)
* @param link_trbs flag to indicate whether to link the trbs or NOT
* @return none
*/
-static void xhci_link_segments(struct xhci_segment *prev,
- struct xhci_segment *next, bool link_trbs)
+static void xhci_link_segments(struct xhci_ctrl *ctrl, struct xhci_segment *prev,
+ struct xhci_segment *next, bool link_trbs)
{
u32 val;
u64 val_64 = 0;
@@ -226,7 +226,7 @@ static void xhci_link_segments(struct xhci_segment *prev,
return;
prev->next = next;
if (link_trbs) {
- val_64 = virt_to_phys(next->trbs);
+ val_64 = xhci_virt_to_bus(ctrl, next->trbs);
prev->trbs[TRBS_PER_SEGMENT-1].link.segment_ptr =
cpu_to_le64(val_64);
@@ -304,7 +304,8 @@ static struct xhci_segment *xhci_segment_alloc(void)
* @param link_trbs flag to indicate whether to link the trbs or NOT
* @return pointer to the newly created RING
*/
-struct xhci_ring *xhci_ring_alloc(unsigned int num_segs, bool link_trbs)
+struct xhci_ring *xhci_ring_alloc(struct xhci_ctrl *ctrl, unsigned int num_segs,
+ bool link_trbs)
{
struct xhci_ring *ring;
struct xhci_segment *prev;
@@ -327,12 +328,12 @@ struct xhci_ring *xhci_ring_alloc(unsigned int num_segs, bool link_trbs)
next = xhci_segment_alloc();
BUG_ON(!next);
- xhci_link_segments(prev, next, link_trbs);
+ xhci_link_segments(ctrl, prev, next, link_trbs);
prev = next;
num_segs--;
}
- xhci_link_segments(prev, ring->first_seg, link_trbs);
+ xhci_link_segments(ctrl, prev, ring->first_seg, link_trbs);
if (link_trbs) {
/* See section 4.9.2.1 and 6.4.4.1 */
prev->trbs[TRBS_PER_SEGMENT-1].link.control |=
@@ -354,6 +355,7 @@ static int xhci_scratchpad_alloc(struct xhci_ctrl *ctrl)
struct xhci_hccr *hccr = ctrl->hccr;
struct xhci_hcor *hcor = ctrl->hcor;
struct xhci_scratchpad *scratchpad;
+ uint64_t val_64;
int num_sp;
uint32_t page_size;
void *buf;
@@ -371,8 +373,9 @@ static int xhci_scratchpad_alloc(struct xhci_ctrl *ctrl)
scratchpad->sp_array = xhci_malloc(num_sp * sizeof(u64));
if (!scratchpad->sp_array)
goto fail_sp2;
- ctrl->dcbaa->dev_context_ptrs[0] =
- cpu_to_le64((uintptr_t)scratchpad->sp_array);
+
+ val_64 = xhci_virt_to_bus(ctrl, scratchpad->sp_array);
+ ctrl->dcbaa->dev_context_ptrs[0] = cpu_to_le64(val_64);
xhci_flush_cache((uintptr_t)&ctrl->dcbaa->dev_context_ptrs[0],
sizeof(ctrl->dcbaa->dev_context_ptrs[0]));
@@ -393,8 +396,8 @@ static int xhci_scratchpad_alloc(struct xhci_ctrl *ctrl)
xhci_flush_cache((uintptr_t)buf, num_sp * page_size);
for (i = 0; i < num_sp; i++) {
- uintptr_t ptr = (uintptr_t)buf + i * page_size;
- scratchpad->sp_array[i] = cpu_to_le64(ptr);
+ val_64 = xhci_virt_to_bus(ctrl, buf + i * page_size);
+ scratchpad->sp_array[i] = cpu_to_le64(val_64);
}
xhci_flush_cache((uintptr_t)scratchpad->sp_array,
@@ -484,9 +487,9 @@ int xhci_alloc_virt_device(struct xhci_ctrl *ctrl, unsigned int slot_id)
}
/* Allocate endpoint 0 ring */
- virt_dev->eps[0].ring = xhci_ring_alloc(1, true);
+ virt_dev->eps[0].ring = xhci_ring_alloc(ctrl, 1, true);
- byte_64 = virt_to_phys(virt_dev->out_ctx->bytes);
+ byte_64 = xhci_virt_to_bus(ctrl, virt_dev->out_ctx->bytes);
/* Point to output device context in dcbaa. */
ctrl->dcbaa->dev_context_ptrs[slot_id] = cpu_to_le64(byte_64);
@@ -522,15 +525,15 @@ int xhci_mem_init(struct xhci_ctrl *ctrl, struct xhci_hccr *hccr,
return -ENOMEM;
}
- val_64 = virt_to_phys(ctrl->dcbaa);
+ val_64 = xhci_virt_to_bus(ctrl, ctrl->dcbaa);
/* Set the pointer in DCBAA register */
xhci_writeq(&hcor->or_dcbaap, val_64);
/* Command ring control pointer register initialization */
- ctrl->cmd_ring = xhci_ring_alloc(1, true);
+ ctrl->cmd_ring = xhci_ring_alloc(ctrl, 1, true);
/* Set the address in the Command Ring Control register */
- trb_64 = virt_to_phys(ctrl->cmd_ring->first_seg->trbs);
+ trb_64 = xhci_virt_to_bus(ctrl, ctrl->cmd_ring->first_seg->trbs);
val_64 = xhci_readq(&hcor->or_crcr);
val_64 = (val_64 & (u64) CMD_RING_RSVD_BITS) |
(trb_64 & (u64) ~CMD_RING_RSVD_BITS) |
@@ -551,7 +554,7 @@ int xhci_mem_init(struct xhci_ctrl *ctrl, struct xhci_hccr *hccr,
ctrl->ir_set = &ctrl->run_regs->ir_set[0];
/* Event ring does not maintain link TRB */
- ctrl->event_ring = xhci_ring_alloc(ERST_NUM_SEGS, false);
+ ctrl->event_ring = xhci_ring_alloc(ctrl, ERST_NUM_SEGS, false);
ctrl->erst.entries = xhci_malloc(sizeof(struct xhci_erst_entry) *
ERST_NUM_SEGS);
@@ -560,8 +563,8 @@ int xhci_mem_init(struct xhci_ctrl *ctrl, struct xhci_hccr *hccr,
for (val = 0, seg = ctrl->event_ring->first_seg;
val < ERST_NUM_SEGS;
val++) {
- trb_64 = virt_to_phys(seg->trbs);
struct xhci_erst_entry *entry = &ctrl->erst.entries[val];
+ trb_64 = xhci_virt_to_bus(ctrl, seg->trbs);
entry->seg_addr = cpu_to_le64(trb_64);
entry->seg_size = cpu_to_le32(TRBS_PER_SEGMENT);
entry->rsvd = 0;
@@ -570,7 +573,7 @@ int xhci_mem_init(struct xhci_ctrl *ctrl, struct xhci_hccr *hccr,
xhci_flush_cache((uintptr_t)ctrl->erst.entries,
ERST_NUM_SEGS * sizeof(struct xhci_erst_entry));
- deq = virt_to_phys(ctrl->event_ring->dequeue);
+ deq = xhci_virt_to_bus(ctrl, ctrl->event_ring->dequeue);
/* Update HC event ring dequeue pointer */
xhci_writeq(&ctrl->ir_set->erst_dequeue,
@@ -585,7 +588,7 @@ int xhci_mem_init(struct xhci_ctrl *ctrl, struct xhci_hccr *hccr,
/* this is the event ring segment table pointer */
val_64 = xhci_readq(&ctrl->ir_set->erst_base);
val_64 &= ERST_PTR_MASK;
- val_64 |= virt_to_phys(ctrl->erst.entries) & ~ERST_PTR_MASK;
+ val_64 |= xhci_virt_to_bus(ctrl, ctrl->erst.entries) & ~ERST_PTR_MASK;
xhci_writeq(&ctrl->ir_set->erst_base, val_64);
@@ -848,7 +851,7 @@ void xhci_setup_addressable_virt_dev(struct xhci_ctrl *ctrl,
/* EP 0 can handle "burst" sizes of 1, so Max Burst Size field is 0 */
ep0_ctx->ep_info2 |= cpu_to_le32(MAX_BURST(0) | ERROR_COUNT(3));
- trb_64 = virt_to_phys(virt_dev->eps[0].ring->first_seg->trbs);
+ trb_64 = xhci_virt_to_bus(ctrl, virt_dev->eps[0].ring->first_seg->trbs);
ep0_ctx->deq = cpu_to_le64(trb_64 | virt_dev->eps[0].ring->cycle_state);
/*
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index 6c5024d3f1..aaa243f291 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -70,7 +70,7 @@ U_BOOT_DRIVER(xhci_pci) = {
.ops = &xhci_usb_ops,
.plat_auto = sizeof(struct usb_plat),
.priv_auto = sizeof(struct xhci_ctrl),
- .flags = DM_FLAG_ALLOC_PRIV_DMA,
+ .flags = DM_FLAG_OS_PREPARE | DM_FLAG_ALLOC_PRIV_DMA,
};
static struct pci_device_id xhci_pci_supported[] = {
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index d6c47d579b..46c137f857 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -275,10 +275,13 @@ void xhci_queue_command(struct xhci_ctrl *ctrl, u8 *ptr, u32 slot_id,
u32 ep_index, trb_type cmd)
{
u32 fields[4];
- u64 val_64 = virt_to_phys(ptr);
+ u64 val_64 = 0;
BUG_ON(prepare_ring(ctrl, ctrl->cmd_ring, EP_STATE_RUNNING));
+ if (ptr)
+ val_64 = xhci_virt_to_bus(ctrl, ptr);
+
fields[0] = lower_32_bits(val_64);
fields[1] = upper_32_bits(val_64);
fields[2] = 0;
@@ -401,7 +404,7 @@ void xhci_acknowledge_event(struct xhci_ctrl *ctrl)
/* Inform the hardware */
xhci_writeq(&ctrl->ir_set->erst_dequeue,
- virt_to_phys(ctrl->event_ring->dequeue) | ERST_EHB);
+ xhci_virt_to_bus(ctrl, ctrl->event_ring->dequeue) | ERST_EHB);
}
/**
@@ -579,7 +582,7 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe,
u64 addr;
int ret;
u32 trb_fields[4];
- u64 val_64 = virt_to_phys(buffer);
+ u64 val_64 = xhci_virt_to_bus(ctrl, buffer);
void *last_transfer_trb_addr;
int available_length;
@@ -724,7 +727,7 @@ again:
}
if ((uintptr_t)(le64_to_cpu(event->trans_event.buffer)) !=
- (uintptr_t)virt_to_phys(last_transfer_trb_addr)) {
+ (uintptr_t)xhci_virt_to_bus(ctrl, last_transfer_trb_addr)) {
available_length -=
(int)EVENT_TRB_LEN(le32_to_cpu(event->trans_event.transfer_len));
xhci_acknowledge_event(ctrl);
@@ -884,7 +887,7 @@ int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe,
if (length > 0) {
if (req->requesttype & USB_DIR_IN)
field |= TRB_DIR_IN;
- buf_64 = virt_to_phys(buffer);
+ buf_64 = xhci_virt_to_bus(ctrl, buffer);
trb_fields[0] = lower_32_bits(buf_64);
trb_fields[1] = upper_32_bits(buf_64);
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 7080f8fabe..d27ac01c83 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -604,7 +604,7 @@ static int xhci_set_configuration(struct usb_device *udev)
ep_ctx[ep_index] = xhci_get_ep_ctx(ctrl, in_ctx, ep_index);
/* Allocate the ep rings */
- virt_dev->eps[ep_index].ring = xhci_ring_alloc(1, true);
+ virt_dev->eps[ep_index].ring = xhci_ring_alloc(ctrl, 1, true);
if (!virt_dev->eps[ep_index].ring)
return -ENOMEM;
@@ -628,7 +628,7 @@ static int xhci_set_configuration(struct usb_device *udev)
cpu_to_le32(MAX_BURST(max_burst) |
ERROR_COUNT(err_count));
- trb_64 = virt_to_phys(virt_dev->eps[ep_index].ring->enqueue);
+ trb_64 = xhci_virt_to_bus(ctrl, virt_dev->eps[ep_index].ring->enqueue);
ep_ctx[ep_index]->deq = cpu_to_le64(trb_64 |
virt_dev->eps[ep_index].ring->cycle_state);
diff --git a/drivers/video/bcm2835.c b/drivers/video/bcm2835.c
index 9326999cd3..c2962932c9 100644
--- a/drivers/video/bcm2835.c
+++ b/drivers/video/bcm2835.c
@@ -52,6 +52,7 @@ static int bcm2835_video_probe(struct udevice *dev)
static const struct udevice_id bcm2835_video_ids[] = {
{ .compatible = "brcm,bcm2835-hdmi" },
+ { .compatible = "brcm,bcm2711-hdmi0" },
{ .compatible = "brcm,bcm2708-fb" },
{ }
};
diff --git a/include/dm/device.h b/include/dm/device.h
index 28533ce0b6..bb9faa0ed9 100644
--- a/include/dm/device.h
+++ b/include/dm/device.h
@@ -159,6 +159,8 @@ enum {
* When CONFIG_DEVRES is enabled, devm_kmalloc() and friends will
* add to this list. Memory so-allocated will be freed
* automatically when the device is removed / unbound
+ * @dma_offset: Offset between the physical address space (CPU's) and the
+ * device's bus address space
*/
struct udevice {
const struct driver *driver;
@@ -183,6 +185,9 @@ struct udevice {
#ifdef CONFIG_DEVRES
struct list_head devres_head;
#endif
+#if CONFIG_IS_ENABLED(DM_DMA)
+ ulong dma_offset;
+#endif
};
/* Maximum sequence number supported */
@@ -224,6 +229,14 @@ static inline ofnode dev_ofnode(const struct udevice *dev)
/* Returns non-zero if the device is active (probed and not removed) */
#define device_active(dev) (dev_get_flags(dev) & DM_FLAG_ACTIVATED)
+#if CONFIG_IS_ENABLED(DM_DMA)
+#define dev_set_dma_offset(_dev, _offset) _dev->dma_offset = _offset
+#define dev_get_dma_offset(_dev) _dev->dma_offset
+#else
+#define dev_set_dma_offset(_dev, _offset)
+#define dev_get_dma_offset(_dev) 0
+#endif
+
static inline int dev_of_offset(const struct udevice *dev)
{
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
diff --git a/include/dm/of_addr.h b/include/dm/of_addr.h
index 3fa1ffce81..ee21d5cf4f 100644
--- a/include/dm/of_addr.h
+++ b/include/dm/of_addr.h
@@ -44,6 +44,23 @@ u64 of_translate_address(const struct device_node *no, const __be32 *in_addr);
*/
u64 of_translate_dma_address(const struct device_node *no, const __be32 *in_addr);
+
+/**
+ * of_get_dma_range() - get dma-ranges for a specific DT node
+ *
+ * Get DMA ranges for a specifc node, this is useful to perform bus->cpu and
+ * cpu->bus address translations
+ *
+ * @param blob Pointer to device tree blob
+ * @param node_offset Node DT offset
+ * @param cpu Pointer to variable storing the range's cpu address
+ * @param bus Pointer to variable storing the range's bus address
+ * @param size Pointer to variable storing the range's size
+ * @return translated DMA address or OF_BAD_ADDR on error
+ */
+int of_get_dma_range(const struct device_node *dev, phys_addr_t *cpu,
+ dma_addr_t *bus, u64 *size);
+
/**
* of_get_address() - obtain an address from a node
*
diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h
index 5318d65035..2c0597c407 100644
--- a/include/dm/ofnode.h
+++ b/include/dm/ofnode.h
@@ -999,6 +999,22 @@ u64 ofnode_translate_address(ofnode node, const fdt32_t *in_addr);
u64 ofnode_translate_dma_address(ofnode node, const fdt32_t *in_addr);
/**
+ * ofnode_get_dma_range() - get dma-ranges for a specific DT node
+ *
+ * Get DMA ranges for a specifc node, this is useful to perform bus->cpu and
+ * cpu->bus address translations
+ *
+ * @param blob Pointer to device tree blob
+ * @param node_offset Node DT offset
+ * @param cpu Pointer to variable storing the range's cpu address
+ * @param bus Pointer to variable storing the range's bus address
+ * @param size Pointer to variable storing the range's size
+ * @return translated DMA address or OF_BAD_ADDR on error
+ */
+int ofnode_get_dma_range(ofnode node, phys_addr_t *cpu, dma_addr_t *bus,
+ u64 *size);
+
+/**
* ofnode_device_is_compatible() - check if the node is compatible with compat
*
* This allows to check whether the node is comaptible with the compat.
diff --git a/include/dm/read.h b/include/dm/read.h
index 97575bcad0..5bf3405614 100644
--- a/include/dm/read.h
+++ b/include/dm/read.h
@@ -648,6 +648,21 @@ u64 dev_translate_dma_address(const struct udevice *dev,
const fdt32_t *in_addr);
/**
+ * dev_get_dma_range() - Get a device's DMA constraints
+ *
+ * Provide the address bases and size of the linear mapping between the CPU and
+ * a device's BUS address space.
+ *
+ * @dev: device giving the context in which to translate the DMA address
+ * @cpu: base address for CPU's view of memory
+ * @bus: base address for BUS's view of memory
+ * @size: size of the address space
+ * @return 0 if ok, negative on error
+ */
+int dev_get_dma_range(const struct udevice *dev, phys_addr_t *cpu,
+ dma_addr_t *bus, u64 *size);
+
+/**
* dev_read_alias_highest_id - Get highest alias id for the given stem
* @stem: Alias stem to be examined
*
@@ -1005,6 +1020,12 @@ static inline u64 dev_translate_dma_address(const struct udevice *dev,
return ofnode_translate_dma_address(dev_ofnode(dev), in_addr);
}
+static inline int dev_get_dma_range(const struct udevice *dev, phys_addr_t *cpu,
+ dma_addr_t *bus, u64 *size)
+{
+ return ofnode_get_dma_range(dev_ofnode(dev), cpu, bus, size);
+}
+
static inline int dev_read_alias_highest_id(const char *stem)
{
if (!CONFIG_IS_ENABLED(OF_LIBFDT) || !gd->fdt_blob)
diff --git a/include/fdt_support.h b/include/fdt_support.h
index dbbac0fb6a..46eb1dbbb2 100644
--- a/include/fdt_support.h
+++ b/include/fdt_support.h
@@ -260,6 +260,20 @@ u64 fdt_translate_address(const void *blob, int node_offset,
u64 fdt_translate_dma_address(const void *blob, int node_offset,
const __be32 *in_addr);
+/**
+ * Get DMA ranges for a specifc node, this is useful to perform bus->cpu and
+ * cpu->bus address translations
+ *
+ * @param blob Pointer to device tree blob
+ * @param node_offset Node DT offset
+ * @param cpu Pointer to variable storing the range's cpu address
+ * @param bus Pointer to variable storing the range's bus address
+ * @param size Pointer to variable storing the range's size
+ * @return translated DMA address or OF_BAD_ADDR on error
+ */
+int fdt_get_dma_range(const void *blob, int node_offset, phys_addr_t *cpu,
+ dma_addr_t *bus, u64 *size);
+
int fdt_node_offset_by_compat_reg(void *blob, const char *compat,
phys_addr_t compat_off);
int fdt_alloc_phandle(void *blob);
diff --git a/include/mmc.h b/include/mmc.h
index 1d377e0281..c12c7a0b5c 100644
--- a/include/mmc.h
+++ b/include/mmc.h
@@ -736,6 +736,12 @@ struct mmc {
u8 hs400_tuning;
};
+#if CONFIG_IS_ENABLED(DM_MMC)
+#define mmc_to_dev(_mmc) _mmc->dev
+#else
+#define mmc_to_dev(_mmc) NULL
+#endif
+
struct mmc_hwpart_conf {
struct {
uint enh_start; /* in 512-byte sectors */
diff --git a/include/phys2bus.h b/include/phys2bus.h
index dc9b8e5a25..866b8b51a8 100644
--- a/include/phys2bus.h
+++ b/include/phys2bus.h
@@ -21,4 +21,21 @@ static inline unsigned long bus_to_phys(unsigned long bus)
}
#endif
+#if CONFIG_IS_ENABLED(DM)
+#include <dm/device.h>
+
+static inline dma_addr_t dev_phys_to_bus(struct udevice *dev, phys_addr_t phys)
+{
+ return phys - dev_get_dma_offset(dev);
+}
+
+static inline phys_addr_t dev_bus_to_phys(struct udevice *dev, dma_addr_t bus)
+{
+ return bus + dev_get_dma_offset(dev);
+}
+#else
+#define dev_phys_to_bus(_, _addr) _addr
+#define dev_bus_to_phys(_, _addr) _addr
+#endif
+
#endif
diff --git a/include/usb/xhci.h b/include/usb/xhci.h
index e1d382369a..8d95e213b0 100644
--- a/include/usb/xhci.h
+++ b/include/usb/xhci.h
@@ -16,6 +16,7 @@
#ifndef HOST_XHCI_H_
#define HOST_XHCI_H_
+#include <phys2bus.h>
#include <reset.h>
#include <asm/types.h>
#include <asm/cache.h>
@@ -1221,6 +1222,12 @@ struct xhci_ctrl {
#define XHCI_MTK_HOST BIT(0)
};
+#if CONFIG_IS_ENABLED(DM_USB)
+#define xhci_to_dev(_ctrl) _ctrl->dev
+#else
+#define xhci_to_dev(_ctrl) NULL
+#endif
+
unsigned long trb_addr(struct xhci_segment *seg, union xhci_trb *trb);
struct xhci_input_control_ctx
*xhci_get_input_control_ctx(struct xhci_container_ctx *ctx);
@@ -1250,7 +1257,8 @@ int xhci_check_maxpacket(struct usb_device *udev);
void xhci_flush_cache(uintptr_t addr, u32 type_len);
void xhci_inval_cache(uintptr_t addr, u32 type_len);
void xhci_cleanup(struct xhci_ctrl *ctrl);
-struct xhci_ring *xhci_ring_alloc(unsigned int num_segs, bool link_trbs);
+struct xhci_ring *xhci_ring_alloc(struct xhci_ctrl *ctrl, unsigned int num_segs,
+ bool link_trbs);
int xhci_alloc_virt_device(struct xhci_ctrl *ctrl, unsigned int slot_id);
int xhci_mem_init(struct xhci_ctrl *ctrl, struct xhci_hccr *hccr,
struct xhci_hcor *hcor);
@@ -1278,4 +1286,14 @@ extern struct dm_usb_ops xhci_usb_ops;
struct xhci_ctrl *xhci_get_ctrl(struct usb_device *udev);
+static inline dma_addr_t xhci_virt_to_bus(struct xhci_ctrl *ctrl, void *addr)
+{
+ return dev_phys_to_bus(xhci_to_dev(ctrl), virt_to_phys(addr));
+}
+
+static inline void *xhci_bus_to_virt(struct xhci_ctrl *ctrl, dma_addr_t addr)
+{
+ return phys_to_virt(dev_bus_to_phys(xhci_to_dev(ctrl), addr));
+}
+
#endif /* HOST_XHCI_H_ */
diff --git a/test/dm/Makefile b/test/dm/Makefile
index e70e50f402..6275ec56ea 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -15,6 +15,8 @@ obj-$(CONFIG_UT_DM) += test-fdt.o
obj-$(CONFIG_UT_DM) += test-uclass.o
obj-$(CONFIG_UT_DM) += core.o
+obj-$(CONFIG_UT_DM) += read.o
+obj-$(CONFIG_UT_DM) += phys2bus.o
ifneq ($(CONFIG_SANDBOX),)
obj-$(CONFIG_ACPIGEN) += acpi.o
obj-$(CONFIG_ACPIGEN) += acpigen.o
diff --git a/test/dm/core.c b/test/dm/core.c
index ce31d86c7d..35ca689d64 100644
--- a/test/dm/core.c
+++ b/test/dm/core.c
@@ -1180,3 +1180,33 @@ static int dm_test_all_have_seq(struct unit_test_state *uts)
return 0;
}
DM_TEST(dm_test_all_have_seq, UT_TESTF_SCAN_PDATA);
+
+static int dm_test_dma_offset(struct unit_test_state *uts)
+{
+ struct udevice *dev;
+ ofnode node;
+
+ /* Make sure the bus's dma-ranges aren't taken into account here */
+ node = ofnode_path("/mmio-bus@0");
+ ut_assert(ofnode_valid(node));
+ ut_assertok(uclass_get_device_by_ofnode(UCLASS_TEST_BUS, node, &dev));
+ ut_asserteq_64(0, dev->dma_offset);
+
+ /* Device behind a bus with dma-ranges */
+ node = ofnode_path("/mmio-bus@0/subnode@0");
+ ut_assert(ofnode_valid(node));
+ ut_assertok(uclass_get_device_by_ofnode(UCLASS_TEST_FDT, node, &dev));
+ ut_asserteq_64(-0x10000000ULL, dev->dma_offset);
+
+ /* This one has no dma-ranges */
+ node = ofnode_path("/mmio-bus@1");
+ ut_assert(ofnode_valid(node));
+ ut_assertok(uclass_get_device_by_ofnode(UCLASS_TEST_BUS, node, &dev));
+ node = ofnode_path("/mmio-bus@1/subnode@0");
+ ut_assert(ofnode_valid(node));
+ ut_assertok(uclass_get_device_by_ofnode(UCLASS_TEST_FDT, node, &dev));
+ ut_asserteq_64(0, dev->dma_offset);
+
+ return 0;
+}
+DM_TEST(dm_test_dma_offset, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
diff --git a/test/dm/phys2bus.c b/test/dm/phys2bus.c
new file mode 100644
index 0000000000..342f2fa8eb
--- /dev/null
+++ b/test/dm/phys2bus.c
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2020 Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <mapmem.h>
+#include <phys2bus.h>
+#include <dm/device.h>
+#include <dm/ofnode.h>
+#include <dm/root.h>
+#include <dm/test.h>
+#include <dm/uclass-internal.h>
+#include <test/ut.h>
+
+static int dm_test_phys_to_bus(struct unit_test_state *uts)
+{
+ struct udevice *dev;
+ ofnode node;
+
+ node = ofnode_path("/mmio-bus@0");
+ ut_assert(ofnode_valid(node));
+ ut_assertok(uclass_get_device_by_ofnode(UCLASS_TEST_BUS, node, &dev));
+ /* In this case it should be transparent, no dma-ranges in parent bus */
+ ut_asserteq_addr((void*)0xfffffULL, (void*)dev_phys_to_bus(dev, 0xfffff));
+ ut_asserteq_addr((void*)0xfffffULL, (void*)(ulong)dev_bus_to_phys(dev, 0xfffff));
+
+ node = ofnode_path("/mmio-bus@0/subnode@0");
+ ut_assert(ofnode_valid(node));
+ ut_assertok(uclass_get_device_by_ofnode(UCLASS_TEST_FDT, node, &dev));
+ ut_asserteq_addr((void*)0x100fffffULL, (void*)dev_phys_to_bus(dev, 0xfffff));
+ ut_asserteq_addr((void*)0xfffffULL, (void*)(ulong)dev_bus_to_phys(dev, 0x100fffff));
+
+ return 0;
+}
+DM_TEST(dm_test_phys_to_bus, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
diff --git a/test/dm/read.c b/test/dm/read.c
new file mode 100644
index 0000000000..7768aa2968
--- /dev/null
+++ b/test/dm/read.c
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2020 Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/device.h>
+#include <dm/ofnode.h>
+#include <dm/root.h>
+#include <dm/test.h>
+#include <dm/uclass-internal.h>
+#include <test/ut.h>
+
+static int dm_test_dma_ranges(struct unit_test_state *uts)
+{
+ struct udevice *dev;
+ phys_addr_t cpu;
+ dma_addr_t bus;
+ ofnode node;
+ u64 size;
+
+ /* dma-ranges are on the device's node */
+ node = ofnode_path("/mmio-bus@0");
+ ut_assert(ofnode_valid(node));
+ ut_assertok(uclass_get_device_by_ofnode(UCLASS_TEST_BUS, node, &dev));
+ ut_assertok(dev_get_dma_range(dev, &cpu, &bus, &size));
+ ut_asserteq_64(0x40000, size);
+ ut_asserteq_64(0x0, cpu);
+ ut_asserteq_64(0x10000000, bus);
+
+ /* dma-ranges are on the bus' node */
+ node = ofnode_path("/mmio-bus@0/subnode@0");
+ ut_assert(ofnode_valid(node));
+ ut_assertok(uclass_get_device_by_ofnode(UCLASS_TEST_FDT, node, &dev));
+ ut_assertok(dev_get_dma_range(dev, &cpu, &bus, &size));
+ ut_asserteq_64(0x40000, size);
+ ut_asserteq_64(0x0, cpu);
+ ut_asserteq_64(0x10000000, bus);
+
+ /* No dma-ranges available */
+ node = ofnode_path("/mmio-bus@1");
+ ut_assert(ofnode_valid(node));
+ ut_assertok(uclass_get_device_by_ofnode(UCLASS_TEST_BUS, node, &dev));
+ ut_asserteq(-ENOENT, dev_get_dma_range(dev, &cpu, &bus, &size));
+
+ return 0;
+}
+DM_TEST(dm_test_dma_ranges, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);