
On Fri, 2020-04-24 at 18:50 +0200, Sylwester Nawrocki wrote:
This patch adds basic driver for the Broadcom STB PCIe host controller. The code is based on Linux upstream driver (pcie-brcmstb.c) with MSI handling removed. The inbound access memory region is not currently parsed from dma-ranges DT property and a fixed 4GB region is used.
The patch has been tested on RPI4 board, i.e. on BCM2711 SoC with VL805 USB Host Controller.
Signed-off-by: Nicolas Saenz Julienne nsaenzjulienne@suse.de Signed-off-by: Sylwester Nawrocki s.nawrocki@samsung.com
Changes since RFC:
- reworked to align with current Linux mainline version and u-boot driver by Nicolas Saenz Julienne
[...]
- /*
* TODO: Use the base address and size(s) provided in the dma-ranges
* property.
*/
- rc_bar2_offset = 0;
- rc_bar2_size = 1ULL << 32;
From experience this works fine, although it highly depends on how DMA memory is handled in u-boot.
For example, in arm64 Linux, DMA memory was allocated from ZONE_DMA32, which would return memory smaller than 4GB. This was not good enough for bcm2711b0 -- revision b0 of rpi4's SoC, so far the most common out there -- which has an internal wiring bug that prevents PCIe from accessing memory higher than 3GB (RPi4 might have up to 4GB). So we had to introduce a ZONE_DMA, which covers the lower GB of memory, in order to allocate suitable DMA memory for PCI and other DMA limited devices.
While playing around with u-boot's xHCI I saw that all memory is allocated is located in the lower 1GB. But never got to look into why. I'm curious to know if someone knows how's that handled in u-boot. Ultimately, depending on how it works, we might be able to just disregard dma-ranges altogether.
For some extra context xhci_malloc() gets its memory from memalign(). And it's not clear to me how that function decides which memory to use.
- tmp = lower_32_bits(rc_bar2_offset);
- u32p_replace_bits(&tmp, brcm_pcie_encode_ibar_size(rc_bar2_size),
PCIE_MISC_RC_BAR2_CONFIG_LO_SIZE_MASK);
- writel(tmp, base + PCIE_MISC_RC_BAR2_CONFIG_LO);
- writel(upper_32_bits(rc_bar2_offset),
base + PCIE_MISC_RC_BAR2_CONFIG_HI);
- scb_size_val = rc_bar2_size ?
ilog2(rc_bar2_size) - 15 : 0xf; /* 0xf is 1GB */
- tmp = readl(base + PCIE_MISC_MISC_CTRL);
- u32p_replace_bits(&tmp, scb_size_val,
PCIE_MISC_MISC_CTRL_SCB0_SIZE_MASK);
- writel(tmp, base + PCIE_MISC_MISC_CTRL);
[...]
Regards, Nicolas