diff options
author | Tom Rini <trini@konsulko.com> | 2021-02-18 08:06:26 -0500 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2021-02-18 08:06:26 -0500 |
commit | 56f1bcc4b7fbca8789cef90c30f201f5b3fff757 (patch) | |
tree | d587eafbc09d7ec51a9b12dca023ddce60507876 | |
parent | 496f49464d90b564da5f1a2f4eecb5553e01edf9 (diff) | |
parent | 0059ef0be903a1f0a9afe5259fb2e0874f78a8ac (diff) | |
download | u-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
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, ®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), @@ -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); |