From 537f00182ffd276a81dbf9746652fc940151528e Mon Sep 17 00:00:00 2001 From: Matthias Brugger Date: Tue, 15 Dec 2020 10:49:23 +0100 Subject: [PATCH 01/18] rng: Add iProc RNG200 driver Add support for random number generator RNG200. This is for example found on RPi4. Signed-off-by: Matthias Brugger Tested-by: Heinrich Schuchardt Tested-by: Peter Robinson [mb: adapt to new struct driver memebers] Signed-off-by: Matthias Brugger --- drivers/rng/Kconfig | 6 ++ drivers/rng/Makefile | 1 + drivers/rng/iproc_rng200.c | 186 +++++++++++++++++++++++++++++++++++++ 3 files changed, 193 insertions(+) create mode 100644 drivers/rng/iproc_rng200.c 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..de6672e955 --- /dev/null +++ b/drivers/rng/iproc_rng200.c @@ -0,0 +1,186 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright 2020, Matthias Brugger + * + * Driver for Raspberry Pi hardware random number generator + */ + +#include +#include +#include +#include +#include + +#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, +}; From 1613cf506c68ea4361ac6c8287932ba86e5e04a2 Mon Sep 17 00:00:00 2001 From: Matthias Brugger Date: Tue, 15 Dec 2020 10:49:24 +0100 Subject: [PATCH 02/18] config: Enable iProc RNG200 driver in RPi4 configs We find the iProc RNG200 in the Raspberry Pi 4. Add it to all it's config so that it can be used. Signed-off-by: Matthias Brugger Tested-by: Peter Robinson [mb: drop rpi_4_32b_defconfig] Signed-off-by: Matthias Brugger --- configs/rpi_4_defconfig | 2 ++ configs/rpi_arm64_defconfig | 2 ++ drivers/rng/iproc_rng200.c | 1 - 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/configs/rpi_4_defconfig b/configs/rpi_4_defconfig index 2590d0a696..46b6cc3046 100644 --- a/configs/rpi_4_defconfig +++ b/configs/rpi_4_defconfig @@ -36,6 +36,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..b75144036d 100644 --- a/configs/rpi_arm64_defconfig +++ b/configs/rpi_arm64_defconfig @@ -33,6 +33,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/drivers/rng/iproc_rng200.c b/drivers/rng/iproc_rng200.c index de6672e955..f71f285f53 100644 --- a/drivers/rng/iproc_rng200.c +++ b/drivers/rng/iproc_rng200.c @@ -50,7 +50,6 @@ static void iproc_rng200_enable(struct iproc_rng200_platdata *pdata, bool enable val &= ~RNG_CTRL_RNG_RBGEN_ENABLE; writel(val, rng_base + RNG_CTRL_OFFSET); - } static void iproc_rng200_restart(struct iproc_rng200_platdata *pdata) From e3bbc1f74e05b194cfd2193f93f5c9310fbd3252 Mon Sep 17 00:00:00 2001 From: Nicolas Saenz Julienne Date: Thu, 14 Jan 2021 16:49:00 +0100 Subject: [PATCH 03/18] usb: xhci-pci: Add DM_FLAG_OS_PREPARE flag The PCIe bus the controller is connected to might need to be removed prior the handover. Make sure xhci-pci is also removed so as to avoid unexpected timeouts or hangs. Signed-off-by: Nicolas Saenz Julienne Signed-off-by: Matthias Brugger --- drivers/usb/host/xhci-pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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[] = { From 85f3fddbcc2e8282f1c26dcef4684f59490d47ba Mon Sep 17 00:00:00 2001 From: Nicolas Saenz Julienne Date: Thu, 14 Jan 2021 16:49:01 +0100 Subject: [PATCH 04/18] pci: brcmstb: Cleanup controller state before handover Make sure we handover the PCIe controller in a clean state. Some of the devices hanging from the PCIe bus might need to be properly reset through #PERST in order for Linux to be able to initialize them. This is specially important in order to properly initialize Raspberry Pi 4 B and 400's USB chip. Signed-off-by: Nicolas Saenz Julienne Signed-off-by: Matthias Brugger --- drivers/pci/pcie_brcmstb.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/pci/pcie_brcmstb.c b/drivers/pci/pcie_brcmstb.c index dd2a4ef629..54aa02c809 100644 --- a/drivers/pci/pcie_brcmstb.c +++ b/drivers/pci/pcie_brcmstb.c @@ -579,6 +579,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 +636,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, }; From 6b3d18c2cb61e5beefbce2de589fe7707ac78fe3 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Mon, 1 Feb 2021 12:16:33 +0100 Subject: [PATCH 05/18] rpi: limit size of the RAM to the multiple of the MMU_SECTION_SIZE When RPi4 is booted from USB Mass Storage, the firmware reports 947MiB of the ARM memory (948 in case of the standard SD-card boot). This value is not MMU_SECTION_SIZE aligned, so the dram_bank_mmu_setup() skips mapping of the last 1MiB. This later causes u-boot in ARM 32bit mode to freeze, because it relocated itself into that unmapped memory and fails to execute. Fix this by limiting the size of the first bank to the multiple of MMU_SECTION_SIZE. Signed-off-by: Marek Szyprowski Reviewed-by: Nicolas Saenz Julienne Tested-by: Jaehoon Chung Reviewed-by: Jaehoon Chung Signed-off-by: Matthias Brugger --- board/raspberrypi/rpi/rpi.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/board/raspberrypi/rpi/rpi.c b/board/raspberrypi/rpi/rpi.c index 6b1fa5fc14..6a9384f1d6 100644 --- a/board/raspberrypi/rpi/rpi.c +++ b/board/raspberrypi/rpi/rpi.c @@ -268,6 +268,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; } From f10f5362815e363fe6511348fd4077cf171cea3f Mon Sep 17 00:00:00 2001 From: Nicolas Saenz Julienne Date: Tue, 12 Jan 2021 13:55:19 +0100 Subject: [PATCH 06/18] rpi: Add identifier for the new RPi400 The Raspberry Pi Foundation released the new RPi400 which we want to detect, so we can enable Ethernet on it and know the correct device tree file name. Signed-off-by: Nicolas Saenz Julienne Reviewed-by: Peter Robinson Tested-by: Peter Robinson Signed-off-by: Matthias Brugger --- board/raspberrypi/rpi/rpi.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/board/raspberrypi/rpi/rpi.c b/board/raspberrypi/rpi/rpi.c index 6a9384f1d6..772cb40ca9 100644 --- a/board/raspberrypi/rpi/rpi.c +++ b/board/raspberrypi/rpi/rpi.c @@ -157,6 +157,11 @@ 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, + }, }; static const struct rpi_model rpi_models_old_scheme[] = { From 561bce3522bd1df5f6b10fbae5a6ea5c0b131ff9 Mon Sep 17 00:00:00 2001 From: Nicolas Saenz Julienne Date: Tue, 12 Jan 2021 13:55:20 +0100 Subject: [PATCH 07/18] rpi: Add identifier for the new CM4 The Raspberry Pi Foundation released the new Compute Module 4 which we want to detect, so we can enable Ethernet on it and know the correct device tree file name. Note that this sets the Ethernet option to true since the official CM4 IO board has an Ethernet port. But that might not be the case when using custom ones. Signed-off-by: Nicolas Saenz Julienne Reviewed-by: Peter Robinson Tested-by: Peter Robinson Signed-off-by: Matthias Brugger --- board/raspberrypi/rpi/rpi.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/board/raspberrypi/rpi/rpi.c b/board/raspberrypi/rpi/rpi.c index 772cb40ca9..df52a4689f 100644 --- a/board/raspberrypi/rpi/rpi.c +++ b/board/raspberrypi/rpi/rpi.c @@ -162,6 +162,11 @@ static const struct rpi_model rpi_models_new_scheme[] = { 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[] = { From c709243ee0e1c3e1f8aaa750efb5b738493502c7 Mon Sep 17 00:00:00 2001 From: Nicolas Saenz Julienne Date: Tue, 12 Jan 2021 13:55:21 +0100 Subject: [PATCH 08/18] pci: pcie-brcmstb: Fix inbound window configurations So far we've assumed a fixed configuration for inbound windows as we had a single user for this controller. But the controller's DMA constraints were improved starting with BCM2711's B1 revision of the SoC, notably available in CM4 and Pi400. They allow for wider inbound windows. We can now cover the whole address space, whereas before we where limited to the lower 3GB. This information is passed to us through DT's 'dma-ranges' property and it's specially important for us to honor it since some interactions with the board's co-processor assume we're doing so (specifically the XHCI firmware load operation, which is handled by the co-processor after u-boot has correctly configured the PCIe controller). Signed-off-by: Nicolas Saenz Julienne Tested-by: Peter Robinson Signed-off-by: Matthias Brugger --- drivers/pci/pcie_brcmstb.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/pci/pcie_brcmstb.c b/drivers/pci/pcie_brcmstb.c index 54aa02c809..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, ®ion, 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), From 51bdb50904b1ffffc1caa8dd92f5abea78e33a0b Mon Sep 17 00:00:00 2001 From: Nicolas Saenz Julienne Date: Tue, 12 Jan 2021 13:55:22 +0100 Subject: [PATCH 09/18] dm: Introduce xxx_get_dma_range() Add the following functions to get a specific device's DMA ranges: - dev_get_dma_range() - ofnode_get_dma_range() - of_get_dma_range() - fdt_get_dma_range() They are specially useful in oder to be able validate a physical address space range into a bus's and to convert addresses from and to address spaces. Signed-off-by: Nicolas Saenz Julienne Reviewed-by: Simon Glass Tested-by: Peter Robinson Signed-off-by: Matthias Brugger --- common/fdt_support.c | 73 +++++++++++++++++++++++++++++++++++++++ drivers/core/of_addr.c | 78 ++++++++++++++++++++++++++++++++++++++++++ drivers/core/ofnode.c | 9 +++++ drivers/core/read.c | 6 ++++ include/dm/of_addr.h | 17 +++++++++ include/dm/ofnode.h | 16 +++++++++ include/dm/read.h | 21 ++++++++++++ include/fdt_support.h | 14 ++++++++ 8 files changed, 234 insertions(+) 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/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/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 @@ -998,6 +998,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 * 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 @@ -647,6 +647,21 @@ u64 dev_translate_address(const struct udevice *dev, const fdt32_t *in_addr); 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); From 283628c412a2b98bdb22093a732aef4d5668e106 Mon Sep 17 00:00:00 2001 From: Nicolas Saenz Julienne Date: Tue, 12 Jan 2021 13:55:23 +0100 Subject: [PATCH 10/18] dm: test: Add test case for dev_get_dma_ranges() Introduce some new nodes in sandbox's test device-tree and dm tests in order to validate dev_get_dma_range(). Signed-off-by: Nicolas Saenz Julienne Reviewed-by: Simon Glass Tested-by: Peter Robinson Signed-off-by: Matthias Brugger --- arch/sandbox/dts/test.dts | 17 ++++++++++++++ test/dm/Makefile | 1 + test/dm/read.c | 49 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+) create mode 100644 test/dm/read.c diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index e95f4631bf..c135881ac3 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -350,6 +350,23 @@ 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"; + }; + acpi_test1: acpi-test { compatible = "denx,u-boot-acpi-test"; acpi-ssdt-test-data = "ab"; diff --git a/test/dm/Makefile b/test/dm/Makefile index e70e50f402..c363ca47a6 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -15,6 +15,7 @@ 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 ifneq ($(CONFIG_SANDBOX),) obj-$(CONFIG_ACPIGEN) += acpi.o obj-$(CONFIG_ACPIGEN) += acpigen.o 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +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); From 4abf68d57d495674e521b693191be1dcada46ecd Mon Sep 17 00:00:00 2001 From: Nicolas Saenz Julienne Date: Tue, 12 Jan 2021 13:55:24 +0100 Subject: [PATCH 11/18] dm: Introduce DMA constraints into the core device model Calculating the DMA offset between a bus address space and CPU's every time we call phys_to_bus() and bus_to_phys() isn't ideal performance wise, as it implies traversing the device tree from the device's node up to the root. Since this information is static and available before the device's initialization, parse it before the probe call an provide the DMA offset in 'struct udevice' for the address translation code to use it. Signed-off-by: Nicolas Saenz Julienne Reviewed-by: Simon Glass Tested-by: Peter Robinson Signed-off-by: Matthias Brugger --- drivers/core/Kconfig | 10 ++++++++++ drivers/core/device.c | 41 +++++++++++++++++++++++++++++++++++++++++ include/dm/device.h | 13 +++++++++++++ 3 files changed, 64 insertions(+) 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/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) From e88018769cd3ed69d2f1623fe03a02dcb0be073a Mon Sep 17 00:00:00 2001 From: Nicolas Saenz Julienne Date: Tue, 12 Jan 2021 13:55:25 +0100 Subject: [PATCH 12/18] dm: test: Add test case for dev->dma_offset Add test to validate dev->dma_offset is properly set on devices. Signed-off-by: Nicolas Saenz Julienne Reviewed-by: Simon Glass Tested-by: Peter Robinson Signed-off-by: Matthias Brugger --- arch/sandbox/dts/test.dts | 4 ++++ configs/sandbox64_defconfig | 1 + configs/sandbox_defconfig | 1 + configs/sandbox_flattree_defconfig | 1 + configs/sandbox_spl_defconfig | 1 + test/dm/core.c | 30 ++++++++++++++++++++++++++++++ 6 files changed, 38 insertions(+) diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index c135881ac3..d4195b45bb 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -365,6 +365,10 @@ #address-cells = <1>; #size-cells = <1>; compatible = "denx,u-boot-test-bus"; + + subnode@0 { + compatible = "denx,u-boot-fdt-test"; + }; }; acpi_test1: acpi-test { 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/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); From 2a15a25c362bbeddf0c8e6fcfb142321076eb904 Mon Sep 17 00:00:00 2001 From: Nicolas Saenz Julienne Date: Tue, 12 Jan 2021 13:55:26 +0100 Subject: [PATCH 13/18] dm: Introduce dev_phys_to_bus()/dev_bus_to_phys() These functions, instead of relying on hard-coded platform-specific address translations, make use of the DMA constraints provided by the DM core. This allows for per-device translations. We can't yet get rid of the legacy phys_to_bus()/bus_to_phys() implementations as some of its users are not integrated into the device model. Signed-off-by: Nicolas Saenz Julienne Reviewed-by: Simon Glass Reviewed-by: Stefan Roese Tested-by: Peter Robinson Signed-off-by: Matthias Brugger --- include/phys2bus.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) 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 + +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 From 30b20e6b3f041d2a383d5a59303af21108afc1d7 Mon Sep 17 00:00:00 2001 From: Nicolas Saenz Julienne Date: Tue, 12 Jan 2021 13:55:27 +0100 Subject: [PATCH 14/18] dm: test: Add test case for dev_phys_to_bus()/dev_bus_to_phys() By reusing DT nodes already available in sandbox's test DT introduce a test to validate dev_phys_to_bus()/dev_bus_to_phys(). Signed-off-by: Nicolas Saenz Julienne Reviewed-by: Simon Glass Tested-by: Peter Robinson Signed-off-by: Matthias Brugger --- test/dm/Makefile | 1 + test/dm/phys2bus.c | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 test/dm/phys2bus.c diff --git a/test/dm/Makefile b/test/dm/Makefile index c363ca47a6..6275ec56ea 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -16,6 +16,7 @@ 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/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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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); From 1a474559d90a4b4f7acd95050fe759fe52395867 Mon Sep 17 00:00:00 2001 From: Nicolas Saenz Julienne Date: Tue, 12 Jan 2021 13:55:28 +0100 Subject: [PATCH 15/18] xhci: translate virtual addresses into the bus's address space So far we've been content with passing physical addresses when configuring memory addresses into XHCI 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 xhci_virt_to_bus() and xhci_bus_to_virt() to cater with these limitations, and make sure we don't break non DM users. Signed-off-by: Nicolas Saenz Julienne Reviewed-by: Simon Glass Reviewed-by: Stefan Roese Tested-by: Peter Robinson [mb: fix compilation for 32 bit] Signed-off-by: Matthias Brugger fix from nicolas --- drivers/usb/host/xhci-mem.c | 45 +++++++++++++++++++----------------- drivers/usb/host/xhci-ring.c | 13 +++++++---- drivers/usb/host/xhci.c | 4 ++-- include/usb/xhci.h | 20 +++++++++++++++- 4 files changed, 53 insertions(+), 29 deletions(-) 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-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/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 #include #include #include @@ -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_ */ From c89c96d3222ca4f4ecfacd2cbaf560ff5d3d2a2f Mon Sep 17 00:00:00 2001 From: Nicolas Saenz Julienne Date: Tue, 12 Jan 2021 13:55:29 +0100 Subject: [PATCH 16/18] mmc: Introduce mmc_phys_to_bus()/mmc_bus_to_phys() This will allow us to use DM variants of phys_to_bus()/bus_to_phys() when relevant. Signed-off-by: Nicolas Saenz Julienne Reviewed-by: Simon Glass Tested-by: Peter Robinson Signed-off-by: Matthias Brugger --- drivers/mmc/sdhci.c | 10 ++++++---- include/mmc.h | 6 ++++++ 2 files changed, 12 insertions(+), 4 deletions(-) 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/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 */ From 74a9f68f7fbe709dca0b20d39a214ae38834b3e8 Mon Sep 17 00:00:00 2001 From: Nicolas Saenz Julienne Date: Tue, 12 Jan 2021 13:55:30 +0100 Subject: [PATCH 17/18] configs: rpi4: Enable DM_DMA across all RPi4 configurations The DM_DMA option is needed in order to translate physical address into bus addresses on a per-device basis. Signed-off-by: Nicolas Saenz Julienne Reviewed-by: Simon Glass Tested-by: Peter Robinson Signed-off-by: Matthias Brugger --- configs/rpi_4_32b_defconfig | 1 + configs/rpi_4_defconfig | 1 + configs/rpi_arm64_defconfig | 1 + 3 files changed, 3 insertions(+) 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 46b6cc3046..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 diff --git a/configs/rpi_arm64_defconfig b/configs/rpi_arm64_defconfig index b75144036d..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 From 0059ef0be903a1f0a9afe5259fb2e0874f78a8ac Mon Sep 17 00:00:00 2001 From: Nicolas Saenz Julienne Date: Tue, 12 Jan 2021 13:55:31 +0100 Subject: [PATCH 18/18] video: arm: rpi: Add brcm,bcm2711-hdmi0 compatible The 'brcm,bcm2711-hdmi0' compatible string is used on RPi4 instead of 'brcm,bcm2835-hdmi' since the IP core was upgraded (now called VC6 instead of VC4). This has no functional change as far as u-boot driver is concerned. So simply add the compatible string. Signed-off-by: Nicolas Saenz Julienne Tested-by: Peter Robinson Signed-off-by: Matthias Brugger --- drivers/video/bcm2835.c | 1 + 1 file changed, 1 insertion(+) 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" }, { } };