- add iProc RNG2000 driver for RPi4
- add support for CM4 and RPi400 -----BEGIN PGP SIGNATURE----- iQJGBAABCAAwFiEEUdvKHhzqrUYPB/u8L21+TfbCqH4FAmAuZAQSHG1icnVnZ2Vy QHN1c2UuY29tAAoJEC9tfk32wqh+LPYP/AsL1NVEkENP5DBxJdvwsCBc1KjAt2MP Pt0VvRaOmL1mkkngHtLMenS3oVwVrmop1fyGcccMvI8oQtEwWbNHlvAsapza/Abt jxiOJikeiV0ks7LiZyHpbREDYfsD1kkQgCa8P67h0JXtiTINBKfvm9NwpNlp1asV w6XYPF6tT+3ebnMd1sUGfOpt2mjHgRWbLGkyTSPn93zfFmK8EVQA2tj3iv45843z VAAMYsg39EIQs0AF1cmW5J4OM3EHG3cyWjl+sp0MJBHm7MOWLlqSeTWIMBn7CmHd 2fOkFLkYcxy+dH/yiF4sZSXlAYLPNu2usDgws9SOCJtE8Rc4C7spGagKU2hG8vV+ r9djoXBmJk5sOEm16BzL86E+I3i8mt8pgiKqfimGQBNro7bJ0B4o0DmN9Y1D2Pyo RAgxTlfGGIcHxeuphbdXRz1rKOVMkbzgZGOeNJ169Jigd+ypzpr2eAKjokNqUhX6 oC9gUVZ4shLCyCCLsmKIE0gVhAlVW7myLyI4i6rdX4LN9CZmBZ3eInFXhh3P4qOH 5V0Z9Lmv4xQVfEmu2rfK61U7CRu/hV1fAI9DFhrVKuISFxamvV3DMT7ZGtOZm5sO GV6QurT6FZW8fqTBuN483Xjcxm/oBFDlO9n3lOYtUaU7NADwXq4J1rVlxO7wJ//z Y0tLVtxoK+g/ =r4d8 -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
56f1bcc4b7
|
@ -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";
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
};
|
|
@ -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);
|
||||
|
||||
/*
|
||||
|
|
|
@ -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[] = {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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" },
|
||||
{ }
|
||||
};
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
|
@ -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);
|
Loading…
Reference in New Issue