Index: head/sys/arm/broadcom/bcm2835/bcm2835_dma.c =================================================================== --- head/sys/arm/broadcom/bcm2835/bcm2835_dma.c +++ head/sys/arm/broadcom/bcm2835/bcm2835_dma.c @@ -169,7 +169,7 @@ return; addr = (bus_addr_t*)arg; - *addr = PHYS_TO_VCBUS(segs[0].ds_addr); + *addr = ARMC_TO_VCBUS(segs[0].ds_addr); } static void @@ -247,8 +247,12 @@ if ((reg & bcm_dma_channel_mask) != 0) device_printf(dev, "statuses are not cleared\n"); - /* Allocate DMA chunks control blocks */ - /* p.40 of spec - control block should be 32-bit aligned */ + /* + * Allocate DMA chunks control blocks based on p.40 of the peripheral + * spec - control block should be 32-bit aligned. The DMA controller + * has a full 32-bit register dedicated to this address, so we do not + * need to bother with the per-SoC peripheral restrictions. + */ err = bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, @@ -561,14 +565,9 @@ return (-1); cb = sc->sc_dma_ch[ch].cb; - if (BCM2835_ARM_IS_IO(src)) - cb->src = IO_TO_VCBUS(src); - else - cb->src = PHYS_TO_VCBUS(src); - if (BCM2835_ARM_IS_IO(dst)) - cb->dst = IO_TO_VCBUS(dst); - else - cb->dst = PHYS_TO_VCBUS(dst); + cb->src = ARMC_TO_VCBUS(src); + cb->dst = ARMC_TO_VCBUS(dst); + cb->len = len; bus_dmamap_sync(sc->sc_dma_tag, Index: head/sys/arm/broadcom/bcm2835/bcm2835_ft5406.c =================================================================== --- head/sys/arm/broadcom/bcm2835/bcm2835_ft5406.c +++ head/sys/arm/broadcom/bcm2835/bcm2835_ft5406.c @@ -227,7 +227,7 @@ return; } - touchbuf = VCBUS_TO_PHYS(msg.body.resp.address); + touchbuf = VCBUS_TO_ARMC(msg.body.resp.address); sc->touch_buf = (uint8_t*)pmap_mapdev(touchbuf, FT5406_WINDOW_SIZE); /* 60Hz */ Index: head/sys/arm/broadcom/bcm2835/bcm2835_mbox.c =================================================================== --- head/sys/arm/broadcom/bcm2835/bcm2835_mbox.c +++ head/sys/arm/broadcom/bcm2835/bcm2835_mbox.c @@ -303,7 +303,7 @@ if (err) return; addr = (bus_addr_t *)arg; - *addr = PHYS_TO_VCBUS(segs[0].ds_addr); + *addr = ARMC_TO_VCBUS(segs[0].ds_addr); } static void * @@ -314,7 +314,7 @@ int err; err = bus_dma_tag_create(bus_get_dma_tag(dev), 16, 0, - BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, + bcm283x_dmabus_peripheral_lowaddr(), BUS_SPACE_MAXADDR, NULL, NULL, len, 1, len, 0, NULL, NULL, tag); if (err != 0) { device_printf(dev, "can't create DMA tag\n"); @@ -554,7 +554,7 @@ fb->xoffset = msg.offset.body.resp.x; fb->yoffset = msg.offset.body.resp.y; fb->pitch = msg.pitch.body.resp.pitch; - fb->base = VCBUS_TO_PHYS(msg.buffer.body.resp.fb_address); + fb->base = VCBUS_TO_ARMC(msg.buffer.body.resp.fb_address); fb->size = msg.buffer.body.resp.fb_size; } Index: head/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c =================================================================== --- head/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c +++ head/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c @@ -61,6 +61,7 @@ #ifdef NOTYET #include #endif +#include #define BCM2835_DEFAULT_SDHCI_FREQ 50 #define BCM2838_DEFAULT_SDHCI_FREQ 100 @@ -330,7 +331,7 @@ /* Allocate bus_dma resources. */ err = bus_dma_tag_create(bus_get_dma_tag(dev), - 1, 0, BUS_SPACE_MAXADDR_32BIT, + 1, 0, bcm283x_dmabus_peripheral_lowaddr(), BUS_SPACE_MAXADDR, NULL, NULL, BCM_DMA_MAXSIZE, ALLOCATED_DMA_SEGS, BCM_SDHCI_BUFFER_SIZE, BUS_DMA_ALLOCNOW, NULL, NULL, Index: head/sys/arm/broadcom/bcm2835/bcm2835_vcbus.h =================================================================== --- head/sys/arm/broadcom/bcm2835/bcm2835_vcbus.h +++ head/sys/arm/broadcom/bcm2835/bcm2835_vcbus.h @@ -35,47 +35,40 @@ #ifndef _BCM2835_VCBUS_H_ #define _BCM2835_VCBUS_H_ -/* - * ARM64 define its SOC options in opt_soc.h - */ -#if defined(__aarch64__) -#include "opt_soc.h" -#endif - #define BCM2835_VCBUS_SDRAM_CACHED 0x40000000 -#define BCM2835_VCBUS_IO_BASE 0x7E000000 #define BCM2835_VCBUS_SDRAM_UNCACHED 0xC0000000 -#if defined(SOC_BCM2835) #define BCM2835_ARM_IO_BASE 0x20000000 +#define BCM2835_VCBUS_IO_BASE 0x7E000000 #define BCM2835_VCBUS_SDRAM_BASE BCM2835_VCBUS_SDRAM_CACHED -#else -#define BCM2835_ARM_IO_BASE 0x3f000000 -#define BCM2835_VCBUS_SDRAM_BASE BCM2835_VCBUS_SDRAM_UNCACHED -#endif -#define BCM2835_ARM_IO_SIZE 0x01000000 -/* - * Convert physical address to VC bus address. Should be used - * when submitting address over mailbox interface - */ -#define PHYS_TO_VCBUS(pa) ((pa) + BCM2835_VCBUS_SDRAM_BASE) +#define BCM2837_ARM_IO_BASE 0x3f000000 +#define BCM2837_VCBUS_IO_BASE BCM2835_VCBUS_IO_BASE +#define BCM2837_VCBUS_SDRAM_BASE BCM2835_VCBUS_SDRAM_UNCACHED -/* Check whether pa bellong top IO window */ -#define BCM2835_ARM_IS_IO(pa) (((pa) >= BCM2835_ARM_IO_BASE) && \ - ((pa) < BCM2835_ARM_IO_BASE + BCM2835_ARM_IO_SIZE)) +#define BCM2838_ARM_IO_BASE 0xfe000000 +#define BCM2838_VCBUS_IO_BASE BCM2835_VCBUS_IO_BASE +#define BCM2838_VCBUS_SDRAM_BASE BCM2835_VCBUS_SDRAM_UNCACHED /* - * Convert physical address in IO space to VC bus address. + * Max allowed SDRAM mapping for most peripherals. The Raspberry Pi 4 has more + * than 1 GB of SDRAM, but only the lowest 1 GB is mapped into the "Legacy + * Master view" of the address space accessible by the DMA engine. Technically, + * we can slide this window around to whatever similarly sized range is + * convenient, but this is the most useful window given how busdma(9) works and + * that the window must be reconfigured for all channels in a given DMA engine. + * The DMA lite engine's window can be configured separately from the 30-bit DMA + * engine. */ -#define IO_TO_VCBUS(pa) ((pa - BCM2835_ARM_IO_BASE) + \ - BCM2835_VCBUS_IO_BASE) +#define BCM2838_PERIPH_MAXADDR 0x3fffffff -/* - * Convert address from VC bus space to physical. Should be used - * when address is returned by VC over mailbox interface. e.g. - * framebuffer base - */ -#define VCBUS_TO_PHYS(vca) ((vca) & ~(BCM2835_VCBUS_SDRAM_BASE)) +#define BCM28XX_ARM_IO_SIZE 0x01000000 + +vm_paddr_t bcm283x_armc_to_vcbus(vm_paddr_t pa); +vm_paddr_t bcm283x_vcbus_to_armc(vm_paddr_t vca); +bus_addr_t bcm283x_dmabus_peripheral_lowaddr(void); + +#define ARMC_TO_VCBUS(pa) bcm283x_armc_to_vcbus(pa) +#define VCBUS_TO_ARMC(vca) bcm283x_vcbus_to_armc(vca) #endif /* _BCM2835_VCBUS_H_ */ Index: head/sys/arm/broadcom/bcm2835/bcm2835_vcbus.c =================================================================== --- head/sys/arm/broadcom/bcm2835/bcm2835_vcbus.c +++ head/sys/arm/broadcom/bcm2835/bcm2835_vcbus.c @@ -0,0 +1,263 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2019 Kyle Evans + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * This file contains facilities for runtime determination of address space + * mappings for use in DMA/mailbox interactions. This is only used for the + * arm64 SoC because the 32-bit SoC used the same mappings. + */ +#if defined (__aarch64__) +#include "opt_soc.h" +#endif + +#include +#include + +#include +#include +#include + +#include + +#include + +/* + * This structure describes mappings that need to take place when transforming + * ARM core addresses into vcbus addresses for use with the DMA/mailbox + * interfaces. Currently, we only deal with peripheral/SDRAM address spaces + * here. + * + * The SDRAM address space is consistently mapped starting at 0 and extends to + * the size of the installed SDRAM. + * + * Peripherals are mapped further up at spots that vary per-SOC. + */ +struct bcm283x_memory_mapping { + vm_paddr_t armc_start; + vm_paddr_t armc_size; + vm_paddr_t vcbus_start; +}; + +#if defined(SOC_BCM2835) || defined(SOC_BCM2836) +static struct bcm283x_memory_mapping bcm2835_memmap[] = { + { + /* SDRAM */ + .armc_start = 0x00000000, + .armc_size = BCM2835_ARM_IO_BASE, + .vcbus_start = BCM2835_VCBUS_SDRAM_BASE, + }, + { + /* Peripherals */ + .armc_start = BCM2835_ARM_IO_BASE, + .armc_size = BCM28XX_ARM_IO_SIZE, + .vcbus_start = BCM2835_VCBUS_IO_BASE, + }, + { 0, 0, 0 }, +}; +#endif + +#ifdef SOC_BRCM_BCM2837 +static struct bcm283x_memory_mapping bcm2837_memmap[] = { + { + /* SDRAM */ + .armc_start = 0x00000000, + .armc_size = BCM2837_ARM_IO_BASE, + .vcbus_start = BCM2837_VCBUS_SDRAM_BASE, + }, + { + /* Peripherals */ + .armc_start = BCM2837_ARM_IO_BASE, + .armc_size = BCM28XX_ARM_IO_SIZE, + .vcbus_start = BCM2837_VCBUS_IO_BASE, + }, + { 0, 0, 0 }, +}; +#endif + +#ifdef SOC_BRCM_BCM2838 + +/* + * The BCM2838 supports up to 4GB of SDRAM, but unfortunately we can still only + * map the first 1GB into the "legacy master view" (vcbus) address space. Thus, + * peripherals can still only access the lower end of SDRAM. For this reason, + * we also capture the main-peripheral busdma restriction below. + */ +static struct bcm283x_memory_mapping bcm2838_memmap[] = { + { + /* SDRAM */ + .armc_start = 0x00000000, + .armc_size = 0x40000000, + .vcbus_start = BCM2838_VCBUS_SDRAM_BASE, + }, + { + /* Main peripherals */ + .armc_start = BCM2838_ARM_IO_BASE, + .armc_size = BCM28XX_ARM_IO_SIZE, + .vcbus_start = BCM2838_VCBUS_IO_BASE, + }, + { 0, 0, 0 }, +}; +#endif + +static struct bcm283x_memory_soc_cfg { + struct bcm283x_memory_mapping *memmap; + const char *soc_compat; + bus_addr_t busdma_lowaddr; +} bcm283x_memory_configs[] = { +#ifdef SOC_BCM2835 + { + .memmap = bcm2835_memmap, + .soc_compat = "brcm,bcm2835", + .busdma_lowaddr = BUS_SPACE_MAXADDR_32BIT, + }, +#endif +#ifdef SOC_BCM2836 + { + .memmap = bcm2835_memmap, + .soc_compat = "brcm,bcm2836", + .busdma_lowaddr = BUS_SPACE_MAXADDR_32BIT, + }, + +#endif +#ifdef SOC_BRCM_BCM2837 + { + .memmap = bcm2837_memmap, + .soc_compat = "brcm,bcm2837", + .busdma_lowaddr = BUS_SPACE_MAXADDR_32BIT, + }, +#endif +#ifdef SOC_BRCM_BCM2838 + { + .memmap = bcm2838_memmap, + .soc_compat = "brcm,bcm2838", + .busdma_lowaddr = BCM2838_PERIPH_MAXADDR, + }, +#endif +}; + +static struct bcm283x_memory_soc_cfg *booted_soc_memcfg; + +static struct bcm283x_memory_soc_cfg * +bcm283x_get_current_memcfg(void) +{ + phandle_t root; + int i; + + /* We'll cache it once we decide, because it won't change per-boot. */ + if (booted_soc_memcfg != NULL) + return (booted_soc_memcfg); + + KASSERT(nitems(bcm283x_memory_configs) != 0, + ("No SOC memory configurations enabled!")); + + root = OF_finddevice("/"); + for (i = 0; i < nitems(bcm283x_memory_configs); ++i) { + booted_soc_memcfg = &bcm283x_memory_configs[i]; + printf("Checking root against %s\n", + booted_soc_memcfg->soc_compat); + if (ofw_bus_node_is_compatible(root, + booted_soc_memcfg->soc_compat)) + return (booted_soc_memcfg); + } + + /* + * The kernel doesn't fit the board; we can't really make a reasonable + * guess, as these SOC are different enough that something will blow up + * later. + */ + panic("No suitable SOC memory configuration found."); +} + +#define BCM283X_MEMMAP_ISTERM(ent) \ + ((ent)->armc_start == 0 && (ent)->armc_size == 0 && \ + (ent)->vcbus_start == 0) + +vm_paddr_t +bcm283x_armc_to_vcbus(vm_paddr_t pa) +{ + struct bcm283x_memory_soc_cfg *cfg; + struct bcm283x_memory_mapping *map, *ment; + + /* Guaranteed not NULL if we haven't panicked yet. */ + cfg = bcm283x_get_current_memcfg(); + map = cfg->memmap; + for (ment = map; !BCM283X_MEMMAP_ISTERM(ment); ++ment) { + if (pa >= ment->armc_start && + pa < ment->armc_start + ment->armc_size) { + return (pa - ment->armc_start) + ment->vcbus_start; + } + } + + /* + * Assume 1:1 mapping for anything else, but complain about it on + * verbose boots. + */ + if (bootverbose) + printf("bcm283x_vcbus: No armc -> vcbus mapping found: %jx\n", + (uintmax_t)pa); + return (pa); +} + +vm_paddr_t +bcm283x_vcbus_to_armc(vm_paddr_t vca) +{ + struct bcm283x_memory_soc_cfg *cfg; + struct bcm283x_memory_mapping *map, *ment; + + /* Guaranteed not NULL if we haven't panicked yet. */ + cfg = bcm283x_get_current_memcfg(); + map = cfg->memmap; + for (ment = map; !BCM283X_MEMMAP_ISTERM(ment); ++ment) { + if (vca >= ment->vcbus_start && + vca < ment->vcbus_start + ment->armc_size) { + return (vca - ment->vcbus_start) + ment->armc_start; + } + } + + /* + * Assume 1:1 mapping for anything else, but complain about it on + * verbose boots. + */ + if (bootverbose) + printf("bcm283x_vcbus: No vcbus -> armc mapping found: %jx\n", + (uintmax_t)vca); + return (vca); +} + +bus_addr_t +bcm283x_dmabus_peripheral_lowaddr(void) +{ + struct bcm283x_memory_soc_cfg *cfg; + + cfg = bcm283x_get_current_memcfg(); + return (cfg->busdma_lowaddr); +} Index: head/sys/arm/broadcom/bcm2835/files.bcm283x =================================================================== --- head/sys/arm/broadcom/bcm2835/files.bcm283x +++ head/sys/arm/broadcom/bcm2835/files.bcm283x @@ -14,6 +14,7 @@ arm/broadcom/bcm2835/bcm2835_sdhci.c optional sdhci arm/broadcom/bcm2835/bcm2835_sdhost.c optional sdhci arm/broadcom/bcm2835/bcm2835_spi.c optional bcm2835_spi +arm/broadcom/bcm2835/bcm2835_vcbus.c standard arm/broadcom/bcm2835/bcm2835_vcio.c standard arm/broadcom/bcm2835/bcm2835_wdog.c standard arm/broadcom/bcm2835/bcm283x_dwc_fdt.c optional dwcotg fdt Index: head/sys/conf/files.arm64 =================================================================== --- head/sys/conf/files.arm64 +++ head/sys/conf/files.arm64 @@ -101,6 +101,7 @@ arm/broadcom/bcm2835/bcm2835_sdhci.c optional sdhci soc_brcm_bcm2837 fdt | sdhci soc_brcm_bcm2838 fdt arm/broadcom/bcm2835/bcm2835_sdhost.c optional sdhci soc_brcm_bcm2837 fdt | sdhci soc_brcm_bcm2838 fdt arm/broadcom/bcm2835/bcm2835_spi.c optional bcm2835_spi fdt +arm/broadcom/bcm2835/bcm2835_vcbus.c optional soc_brcm_bcm2837 fdt | soc_brcm_bcm2838 fdt arm/broadcom/bcm2835/bcm2835_vcio.c optional soc_brcm_bcm2837 fdt | soc_brcm_bcm2838 fdt arm/broadcom/bcm2835/bcm2835_wdog.c optional soc_brcm_bcm2837 fdt | soc_brcm_bcm2838 fdt arm/broadcom/bcm2835/bcm2836.c optional soc_brcm_bcm2837 fdt | soc_brcm_bcm2838 fdt