140084ac3SKyle Evans /*- 240084ac3SKyle Evans * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 340084ac3SKyle Evans * 440084ac3SKyle Evans * Copyright (c) 2019 Kyle Evans <kevans@FreeBSD.org> 540084ac3SKyle Evans * 640084ac3SKyle Evans * Redistribution and use in source and binary forms, with or without 740084ac3SKyle Evans * modification, are permitted provided that the following conditions 840084ac3SKyle Evans * are met: 940084ac3SKyle Evans * 1. Redistributions of source code must retain the above copyright 1040084ac3SKyle Evans * notice, this list of conditions and the following disclaimer. 1140084ac3SKyle Evans * 2. Redistributions in binary form must reproduce the above copyright 1240084ac3SKyle Evans * notice, this list of conditions and the following disclaimer in the 1340084ac3SKyle Evans * documentation and/or other materials provided with the distribution. 1440084ac3SKyle Evans * 1540084ac3SKyle Evans * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1640084ac3SKyle Evans * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1740084ac3SKyle Evans * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1840084ac3SKyle Evans * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1940084ac3SKyle Evans * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2040084ac3SKyle Evans * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2140084ac3SKyle Evans * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2240084ac3SKyle Evans * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2340084ac3SKyle Evans * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2440084ac3SKyle Evans * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2540084ac3SKyle Evans * SUCH DAMAGE. 2640084ac3SKyle Evans * 2740084ac3SKyle Evans * $FreeBSD$ 2840084ac3SKyle Evans */ 2940084ac3SKyle Evans 3040084ac3SKyle Evans #include <sys/cdefs.h> 3140084ac3SKyle Evans __FBSDID("$FreeBSD$"); 3240084ac3SKyle Evans 3340084ac3SKyle Evans /* 3440084ac3SKyle Evans * This file contains facilities for runtime determination of address space 3540084ac3SKyle Evans * mappings for use in DMA/mailbox interactions. This is only used for the 3640084ac3SKyle Evans * arm64 SoC because the 32-bit SoC used the same mappings. 3740084ac3SKyle Evans */ 3840084ac3SKyle Evans #if defined (__aarch64__) 3940084ac3SKyle Evans #include "opt_soc.h" 4040084ac3SKyle Evans #endif 4140084ac3SKyle Evans 4240084ac3SKyle Evans #include <sys/types.h> 4340084ac3SKyle Evans #include <sys/systm.h> 4440084ac3SKyle Evans 4540084ac3SKyle Evans #include <dev/ofw/openfirm.h> 4640084ac3SKyle Evans #include <dev/ofw/ofw_bus.h> 4740084ac3SKyle Evans #include <dev/ofw/ofw_bus_subr.h> 4840084ac3SKyle Evans 4940084ac3SKyle Evans #include <machine/bus.h> 5040084ac3SKyle Evans 5140084ac3SKyle Evans #include <arm/broadcom/bcm2835/bcm2835_vcbus.h> 5240084ac3SKyle Evans 5340084ac3SKyle Evans /* 5440084ac3SKyle Evans * This structure describes mappings that need to take place when transforming 5540084ac3SKyle Evans * ARM core addresses into vcbus addresses for use with the DMA/mailbox 5640084ac3SKyle Evans * interfaces. Currently, we only deal with peripheral/SDRAM address spaces 5740084ac3SKyle Evans * here. 5840084ac3SKyle Evans * 5940084ac3SKyle Evans * The SDRAM address space is consistently mapped starting at 0 and extends to 6040084ac3SKyle Evans * the size of the installed SDRAM. 6140084ac3SKyle Evans * 6240084ac3SKyle Evans * Peripherals are mapped further up at spots that vary per-SOC. 6340084ac3SKyle Evans */ 6440084ac3SKyle Evans struct bcm283x_memory_mapping { 6540084ac3SKyle Evans vm_paddr_t armc_start; 6640084ac3SKyle Evans vm_paddr_t armc_size; 6740084ac3SKyle Evans vm_paddr_t vcbus_start; 6840084ac3SKyle Evans }; 6940084ac3SKyle Evans 705910fe02SKyle Evans #ifdef SOC_BCM2835 7140084ac3SKyle Evans static struct bcm283x_memory_mapping bcm2835_memmap[] = { 7240084ac3SKyle Evans { 7340084ac3SKyle Evans /* SDRAM */ 7440084ac3SKyle Evans .armc_start = 0x00000000, 7540084ac3SKyle Evans .armc_size = BCM2835_ARM_IO_BASE, 7640084ac3SKyle Evans .vcbus_start = BCM2835_VCBUS_SDRAM_BASE, 7740084ac3SKyle Evans }, 7840084ac3SKyle Evans { 7940084ac3SKyle Evans /* Peripherals */ 8040084ac3SKyle Evans .armc_start = BCM2835_ARM_IO_BASE, 8140084ac3SKyle Evans .armc_size = BCM28XX_ARM_IO_SIZE, 8240084ac3SKyle Evans .vcbus_start = BCM2835_VCBUS_IO_BASE, 8340084ac3SKyle Evans }, 8440084ac3SKyle Evans { 0, 0, 0 }, 8540084ac3SKyle Evans }; 8640084ac3SKyle Evans #endif 8740084ac3SKyle Evans 885910fe02SKyle Evans #ifdef SOC_BCM2836 895910fe02SKyle Evans static struct bcm283x_memory_mapping bcm2836_memmap[] = { 905910fe02SKyle Evans { 915910fe02SKyle Evans /* SDRAM */ 925910fe02SKyle Evans .armc_start = 0x00000000, 935910fe02SKyle Evans .armc_size = BCM2836_ARM_IO_BASE, 945910fe02SKyle Evans .vcbus_start = BCM2836_VCBUS_SDRAM_BASE, 955910fe02SKyle Evans }, 965910fe02SKyle Evans { 975910fe02SKyle Evans /* Peripherals */ 985910fe02SKyle Evans .armc_start = BCM2836_ARM_IO_BASE, 995910fe02SKyle Evans .armc_size = BCM28XX_ARM_IO_SIZE, 1005910fe02SKyle Evans .vcbus_start = BCM2836_VCBUS_IO_BASE, 1015910fe02SKyle Evans }, 1025910fe02SKyle Evans { 0, 0, 0 }, 1035910fe02SKyle Evans }; 1045910fe02SKyle Evans #endif 1055910fe02SKyle Evans 10640084ac3SKyle Evans #ifdef SOC_BRCM_BCM2837 10740084ac3SKyle Evans static struct bcm283x_memory_mapping bcm2837_memmap[] = { 10840084ac3SKyle Evans { 10940084ac3SKyle Evans /* SDRAM */ 11040084ac3SKyle Evans .armc_start = 0x00000000, 11140084ac3SKyle Evans .armc_size = BCM2837_ARM_IO_BASE, 11240084ac3SKyle Evans .vcbus_start = BCM2837_VCBUS_SDRAM_BASE, 11340084ac3SKyle Evans }, 11440084ac3SKyle Evans { 11540084ac3SKyle Evans /* Peripherals */ 11640084ac3SKyle Evans .armc_start = BCM2837_ARM_IO_BASE, 11740084ac3SKyle Evans .armc_size = BCM28XX_ARM_IO_SIZE, 11840084ac3SKyle Evans .vcbus_start = BCM2837_VCBUS_IO_BASE, 11940084ac3SKyle Evans }, 12040084ac3SKyle Evans { 0, 0, 0 }, 12140084ac3SKyle Evans }; 12240084ac3SKyle Evans #endif 12340084ac3SKyle Evans 12440084ac3SKyle Evans #ifdef SOC_BRCM_BCM2838 12540084ac3SKyle Evans 12640084ac3SKyle Evans /* 12740084ac3SKyle Evans * The BCM2838 supports up to 4GB of SDRAM, but unfortunately we can still only 12840084ac3SKyle Evans * map the first 1GB into the "legacy master view" (vcbus) address space. Thus, 12940084ac3SKyle Evans * peripherals can still only access the lower end of SDRAM. For this reason, 13040084ac3SKyle Evans * we also capture the main-peripheral busdma restriction below. 13140084ac3SKyle Evans */ 13240084ac3SKyle Evans static struct bcm283x_memory_mapping bcm2838_memmap[] = { 13340084ac3SKyle Evans { 13440084ac3SKyle Evans /* SDRAM */ 13540084ac3SKyle Evans .armc_start = 0x00000000, 13640084ac3SKyle Evans .armc_size = 0x40000000, 13740084ac3SKyle Evans .vcbus_start = BCM2838_VCBUS_SDRAM_BASE, 13840084ac3SKyle Evans }, 13940084ac3SKyle Evans { 14040084ac3SKyle Evans /* Main peripherals */ 14140084ac3SKyle Evans .armc_start = BCM2838_ARM_IO_BASE, 14240084ac3SKyle Evans .armc_size = BCM28XX_ARM_IO_SIZE, 14340084ac3SKyle Evans .vcbus_start = BCM2838_VCBUS_IO_BASE, 14440084ac3SKyle Evans }, 14540084ac3SKyle Evans { 0, 0, 0 }, 14640084ac3SKyle Evans }; 14740084ac3SKyle Evans #endif 14840084ac3SKyle Evans 14940084ac3SKyle Evans static struct bcm283x_memory_soc_cfg { 15040084ac3SKyle Evans struct bcm283x_memory_mapping *memmap; 15140084ac3SKyle Evans const char *soc_compat; 15240084ac3SKyle Evans bus_addr_t busdma_lowaddr; 15340084ac3SKyle Evans } bcm283x_memory_configs[] = { 15440084ac3SKyle Evans #ifdef SOC_BCM2835 15532a44e1eSKyle Evans /* Legacy */ 15632a44e1eSKyle Evans { 15732a44e1eSKyle Evans .memmap = bcm2835_memmap, 15832a44e1eSKyle Evans .soc_compat = "raspberrypi,model-b", 15932a44e1eSKyle Evans .busdma_lowaddr = BUS_SPACE_MAXADDR_32BIT, 16032a44e1eSKyle Evans }, 16132a44e1eSKyle Evans /* Modern */ 16240084ac3SKyle Evans { 16340084ac3SKyle Evans .memmap = bcm2835_memmap, 16440084ac3SKyle Evans .soc_compat = "brcm,bcm2835", 16540084ac3SKyle Evans .busdma_lowaddr = BUS_SPACE_MAXADDR_32BIT, 16640084ac3SKyle Evans }, 16740084ac3SKyle Evans #endif 16840084ac3SKyle Evans #ifdef SOC_BCM2836 16932a44e1eSKyle Evans /* Legacy */ 17032a44e1eSKyle Evans { 17132a44e1eSKyle Evans .memmap = bcm2836_memmap, 17232a44e1eSKyle Evans .soc_compat = "brcm,bcm2709", 17332a44e1eSKyle Evans .busdma_lowaddr = BUS_SPACE_MAXADDR_32BIT, 17432a44e1eSKyle Evans }, 17532a44e1eSKyle Evans /* Modern */ 17640084ac3SKyle Evans { 1775910fe02SKyle Evans .memmap = bcm2836_memmap, 17840084ac3SKyle Evans .soc_compat = "brcm,bcm2836", 17940084ac3SKyle Evans .busdma_lowaddr = BUS_SPACE_MAXADDR_32BIT, 18040084ac3SKyle Evans }, 18140084ac3SKyle Evans 18240084ac3SKyle Evans #endif 18340084ac3SKyle Evans #ifdef SOC_BRCM_BCM2837 18440084ac3SKyle Evans { 18540084ac3SKyle Evans .memmap = bcm2837_memmap, 18640084ac3SKyle Evans .soc_compat = "brcm,bcm2837", 18740084ac3SKyle Evans .busdma_lowaddr = BUS_SPACE_MAXADDR_32BIT, 18840084ac3SKyle Evans }, 18940084ac3SKyle Evans #endif 19040084ac3SKyle Evans #ifdef SOC_BRCM_BCM2838 19140084ac3SKyle Evans { 19240084ac3SKyle Evans .memmap = bcm2838_memmap, 193ba78f78fSKyle Evans .soc_compat = "brcm,bcm2711", 194ba78f78fSKyle Evans .busdma_lowaddr = BCM2838_PERIPH_MAXADDR, 195ba78f78fSKyle Evans }, 196ba78f78fSKyle Evans { 197ba78f78fSKyle Evans .memmap = bcm2838_memmap, 19840084ac3SKyle Evans .soc_compat = "brcm,bcm2838", 19940084ac3SKyle Evans .busdma_lowaddr = BCM2838_PERIPH_MAXADDR, 20040084ac3SKyle Evans }, 20140084ac3SKyle Evans #endif 20240084ac3SKyle Evans }; 20340084ac3SKyle Evans 20440084ac3SKyle Evans static struct bcm283x_memory_soc_cfg *booted_soc_memcfg; 20540084ac3SKyle Evans 20640084ac3SKyle Evans static struct bcm283x_memory_soc_cfg * 20740084ac3SKyle Evans bcm283x_get_current_memcfg(void) 20840084ac3SKyle Evans { 20940084ac3SKyle Evans phandle_t root; 21040084ac3SKyle Evans int i; 21140084ac3SKyle Evans 21240084ac3SKyle Evans /* We'll cache it once we decide, because it won't change per-boot. */ 21340084ac3SKyle Evans if (booted_soc_memcfg != NULL) 21440084ac3SKyle Evans return (booted_soc_memcfg); 21540084ac3SKyle Evans 21640084ac3SKyle Evans KASSERT(nitems(bcm283x_memory_configs) != 0, 21740084ac3SKyle Evans ("No SOC memory configurations enabled!")); 21840084ac3SKyle Evans 21940084ac3SKyle Evans root = OF_finddevice("/"); 22040084ac3SKyle Evans for (i = 0; i < nitems(bcm283x_memory_configs); ++i) { 22140084ac3SKyle Evans booted_soc_memcfg = &bcm283x_memory_configs[i]; 222*d2ccf385SKyle Evans if (bootverbose) 22340084ac3SKyle Evans printf("Checking root against %s\n", 22440084ac3SKyle Evans booted_soc_memcfg->soc_compat); 22540084ac3SKyle Evans if (ofw_bus_node_is_compatible(root, 22640084ac3SKyle Evans booted_soc_memcfg->soc_compat)) 22740084ac3SKyle Evans return (booted_soc_memcfg); 22840084ac3SKyle Evans } 22940084ac3SKyle Evans 23040084ac3SKyle Evans /* 23140084ac3SKyle Evans * The kernel doesn't fit the board; we can't really make a reasonable 23240084ac3SKyle Evans * guess, as these SOC are different enough that something will blow up 23340084ac3SKyle Evans * later. 23440084ac3SKyle Evans */ 23540084ac3SKyle Evans panic("No suitable SOC memory configuration found."); 23640084ac3SKyle Evans } 23740084ac3SKyle Evans 23840084ac3SKyle Evans #define BCM283X_MEMMAP_ISTERM(ent) \ 23940084ac3SKyle Evans ((ent)->armc_start == 0 && (ent)->armc_size == 0 && \ 24040084ac3SKyle Evans (ent)->vcbus_start == 0) 24140084ac3SKyle Evans 24240084ac3SKyle Evans vm_paddr_t 24340084ac3SKyle Evans bcm283x_armc_to_vcbus(vm_paddr_t pa) 24440084ac3SKyle Evans { 24540084ac3SKyle Evans struct bcm283x_memory_soc_cfg *cfg; 24640084ac3SKyle Evans struct bcm283x_memory_mapping *map, *ment; 24740084ac3SKyle Evans 24840084ac3SKyle Evans /* Guaranteed not NULL if we haven't panicked yet. */ 24940084ac3SKyle Evans cfg = bcm283x_get_current_memcfg(); 25040084ac3SKyle Evans map = cfg->memmap; 25140084ac3SKyle Evans for (ment = map; !BCM283X_MEMMAP_ISTERM(ment); ++ment) { 25240084ac3SKyle Evans if (pa >= ment->armc_start && 25340084ac3SKyle Evans pa < ment->armc_start + ment->armc_size) { 25440084ac3SKyle Evans return (pa - ment->armc_start) + ment->vcbus_start; 25540084ac3SKyle Evans } 25640084ac3SKyle Evans } 25740084ac3SKyle Evans 25840084ac3SKyle Evans /* 25940084ac3SKyle Evans * Assume 1:1 mapping for anything else, but complain about it on 26040084ac3SKyle Evans * verbose boots. 26140084ac3SKyle Evans */ 26240084ac3SKyle Evans if (bootverbose) 26340084ac3SKyle Evans printf("bcm283x_vcbus: No armc -> vcbus mapping found: %jx\n", 26440084ac3SKyle Evans (uintmax_t)pa); 26540084ac3SKyle Evans return (pa); 26640084ac3SKyle Evans } 26740084ac3SKyle Evans 26840084ac3SKyle Evans vm_paddr_t 26940084ac3SKyle Evans bcm283x_vcbus_to_armc(vm_paddr_t vca) 27040084ac3SKyle Evans { 27140084ac3SKyle Evans struct bcm283x_memory_soc_cfg *cfg; 27240084ac3SKyle Evans struct bcm283x_memory_mapping *map, *ment; 27340084ac3SKyle Evans 27440084ac3SKyle Evans /* Guaranteed not NULL if we haven't panicked yet. */ 27540084ac3SKyle Evans cfg = bcm283x_get_current_memcfg(); 27640084ac3SKyle Evans map = cfg->memmap; 27740084ac3SKyle Evans for (ment = map; !BCM283X_MEMMAP_ISTERM(ment); ++ment) { 27840084ac3SKyle Evans if (vca >= ment->vcbus_start && 27940084ac3SKyle Evans vca < ment->vcbus_start + ment->armc_size) { 28040084ac3SKyle Evans return (vca - ment->vcbus_start) + ment->armc_start; 28140084ac3SKyle Evans } 28240084ac3SKyle Evans } 28340084ac3SKyle Evans 28440084ac3SKyle Evans /* 28540084ac3SKyle Evans * Assume 1:1 mapping for anything else, but complain about it on 28640084ac3SKyle Evans * verbose boots. 28740084ac3SKyle Evans */ 28840084ac3SKyle Evans if (bootverbose) 28940084ac3SKyle Evans printf("bcm283x_vcbus: No vcbus -> armc mapping found: %jx\n", 29040084ac3SKyle Evans (uintmax_t)vca); 29140084ac3SKyle Evans return (vca); 29240084ac3SKyle Evans } 29340084ac3SKyle Evans 29440084ac3SKyle Evans bus_addr_t 29540084ac3SKyle Evans bcm283x_dmabus_peripheral_lowaddr(void) 29640084ac3SKyle Evans { 29740084ac3SKyle Evans struct bcm283x_memory_soc_cfg *cfg; 29840084ac3SKyle Evans 29940084ac3SKyle Evans cfg = bcm283x_get_current_memcfg(); 30040084ac3SKyle Evans return (cfg->busdma_lowaddr); 30140084ac3SKyle Evans } 302