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 7040084ac3SKyle Evans #if defined(SOC_BCM2835) || defined(SOC_BCM2836) 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 8840084ac3SKyle Evans #ifdef SOC_BRCM_BCM2837 8940084ac3SKyle Evans static struct bcm283x_memory_mapping bcm2837_memmap[] = { 9040084ac3SKyle Evans { 9140084ac3SKyle Evans /* SDRAM */ 9240084ac3SKyle Evans .armc_start = 0x00000000, 9340084ac3SKyle Evans .armc_size = BCM2837_ARM_IO_BASE, 9440084ac3SKyle Evans .vcbus_start = BCM2837_VCBUS_SDRAM_BASE, 9540084ac3SKyle Evans }, 9640084ac3SKyle Evans { 9740084ac3SKyle Evans /* Peripherals */ 9840084ac3SKyle Evans .armc_start = BCM2837_ARM_IO_BASE, 9940084ac3SKyle Evans .armc_size = BCM28XX_ARM_IO_SIZE, 10040084ac3SKyle Evans .vcbus_start = BCM2837_VCBUS_IO_BASE, 10140084ac3SKyle Evans }, 10240084ac3SKyle Evans { 0, 0, 0 }, 10340084ac3SKyle Evans }; 10440084ac3SKyle Evans #endif 10540084ac3SKyle Evans 10640084ac3SKyle Evans #ifdef SOC_BRCM_BCM2838 10740084ac3SKyle Evans 10840084ac3SKyle Evans /* 10940084ac3SKyle Evans * The BCM2838 supports up to 4GB of SDRAM, but unfortunately we can still only 11040084ac3SKyle Evans * map the first 1GB into the "legacy master view" (vcbus) address space. Thus, 11140084ac3SKyle Evans * peripherals can still only access the lower end of SDRAM. For this reason, 11240084ac3SKyle Evans * we also capture the main-peripheral busdma restriction below. 11340084ac3SKyle Evans */ 11440084ac3SKyle Evans static struct bcm283x_memory_mapping bcm2838_memmap[] = { 11540084ac3SKyle Evans { 11640084ac3SKyle Evans /* SDRAM */ 11740084ac3SKyle Evans .armc_start = 0x00000000, 11840084ac3SKyle Evans .armc_size = 0x40000000, 11940084ac3SKyle Evans .vcbus_start = BCM2838_VCBUS_SDRAM_BASE, 12040084ac3SKyle Evans }, 12140084ac3SKyle Evans { 12240084ac3SKyle Evans /* Main peripherals */ 12340084ac3SKyle Evans .armc_start = BCM2838_ARM_IO_BASE, 12440084ac3SKyle Evans .armc_size = BCM28XX_ARM_IO_SIZE, 12540084ac3SKyle Evans .vcbus_start = BCM2838_VCBUS_IO_BASE, 12640084ac3SKyle Evans }, 12740084ac3SKyle Evans { 0, 0, 0 }, 12840084ac3SKyle Evans }; 12940084ac3SKyle Evans #endif 13040084ac3SKyle Evans 13140084ac3SKyle Evans static struct bcm283x_memory_soc_cfg { 13240084ac3SKyle Evans struct bcm283x_memory_mapping *memmap; 13340084ac3SKyle Evans const char *soc_compat; 13440084ac3SKyle Evans bus_addr_t busdma_lowaddr; 13540084ac3SKyle Evans } bcm283x_memory_configs[] = { 13640084ac3SKyle Evans #ifdef SOC_BCM2835 13740084ac3SKyle Evans { 13840084ac3SKyle Evans .memmap = bcm2835_memmap, 13940084ac3SKyle Evans .soc_compat = "brcm,bcm2835", 14040084ac3SKyle Evans .busdma_lowaddr = BUS_SPACE_MAXADDR_32BIT, 14140084ac3SKyle Evans }, 14240084ac3SKyle Evans #endif 14340084ac3SKyle Evans #ifdef SOC_BCM2836 14440084ac3SKyle Evans { 14540084ac3SKyle Evans .memmap = bcm2835_memmap, 14640084ac3SKyle Evans .soc_compat = "brcm,bcm2836", 14740084ac3SKyle Evans .busdma_lowaddr = BUS_SPACE_MAXADDR_32BIT, 14840084ac3SKyle Evans }, 14940084ac3SKyle Evans 15040084ac3SKyle Evans #endif 15140084ac3SKyle Evans #ifdef SOC_BRCM_BCM2837 15240084ac3SKyle Evans { 15340084ac3SKyle Evans .memmap = bcm2837_memmap, 15440084ac3SKyle Evans .soc_compat = "brcm,bcm2837", 15540084ac3SKyle Evans .busdma_lowaddr = BUS_SPACE_MAXADDR_32BIT, 15640084ac3SKyle Evans }, 15740084ac3SKyle Evans #endif 15840084ac3SKyle Evans #ifdef SOC_BRCM_BCM2838 15940084ac3SKyle Evans { 16040084ac3SKyle Evans .memmap = bcm2838_memmap, 161*ba78f78fSKyle Evans .soc_compat = "brcm,bcm2711", 162*ba78f78fSKyle Evans .busdma_lowaddr = BCM2838_PERIPH_MAXADDR, 163*ba78f78fSKyle Evans }, 164*ba78f78fSKyle Evans { 165*ba78f78fSKyle Evans .memmap = bcm2838_memmap, 16640084ac3SKyle Evans .soc_compat = "brcm,bcm2838", 16740084ac3SKyle Evans .busdma_lowaddr = BCM2838_PERIPH_MAXADDR, 16840084ac3SKyle Evans }, 16940084ac3SKyle Evans #endif 17040084ac3SKyle Evans }; 17140084ac3SKyle Evans 17240084ac3SKyle Evans static struct bcm283x_memory_soc_cfg *booted_soc_memcfg; 17340084ac3SKyle Evans 17440084ac3SKyle Evans static struct bcm283x_memory_soc_cfg * 17540084ac3SKyle Evans bcm283x_get_current_memcfg(void) 17640084ac3SKyle Evans { 17740084ac3SKyle Evans phandle_t root; 17840084ac3SKyle Evans int i; 17940084ac3SKyle Evans 18040084ac3SKyle Evans /* We'll cache it once we decide, because it won't change per-boot. */ 18140084ac3SKyle Evans if (booted_soc_memcfg != NULL) 18240084ac3SKyle Evans return (booted_soc_memcfg); 18340084ac3SKyle Evans 18440084ac3SKyle Evans KASSERT(nitems(bcm283x_memory_configs) != 0, 18540084ac3SKyle Evans ("No SOC memory configurations enabled!")); 18640084ac3SKyle Evans 18740084ac3SKyle Evans root = OF_finddevice("/"); 18840084ac3SKyle Evans for (i = 0; i < nitems(bcm283x_memory_configs); ++i) { 18940084ac3SKyle Evans booted_soc_memcfg = &bcm283x_memory_configs[i]; 19040084ac3SKyle Evans printf("Checking root against %s\n", 19140084ac3SKyle Evans booted_soc_memcfg->soc_compat); 19240084ac3SKyle Evans if (ofw_bus_node_is_compatible(root, 19340084ac3SKyle Evans booted_soc_memcfg->soc_compat)) 19440084ac3SKyle Evans return (booted_soc_memcfg); 19540084ac3SKyle Evans } 19640084ac3SKyle Evans 19740084ac3SKyle Evans /* 19840084ac3SKyle Evans * The kernel doesn't fit the board; we can't really make a reasonable 19940084ac3SKyle Evans * guess, as these SOC are different enough that something will blow up 20040084ac3SKyle Evans * later. 20140084ac3SKyle Evans */ 20240084ac3SKyle Evans panic("No suitable SOC memory configuration found."); 20340084ac3SKyle Evans } 20440084ac3SKyle Evans 20540084ac3SKyle Evans #define BCM283X_MEMMAP_ISTERM(ent) \ 20640084ac3SKyle Evans ((ent)->armc_start == 0 && (ent)->armc_size == 0 && \ 20740084ac3SKyle Evans (ent)->vcbus_start == 0) 20840084ac3SKyle Evans 20940084ac3SKyle Evans vm_paddr_t 21040084ac3SKyle Evans bcm283x_armc_to_vcbus(vm_paddr_t pa) 21140084ac3SKyle Evans { 21240084ac3SKyle Evans struct bcm283x_memory_soc_cfg *cfg; 21340084ac3SKyle Evans struct bcm283x_memory_mapping *map, *ment; 21440084ac3SKyle Evans 21540084ac3SKyle Evans /* Guaranteed not NULL if we haven't panicked yet. */ 21640084ac3SKyle Evans cfg = bcm283x_get_current_memcfg(); 21740084ac3SKyle Evans map = cfg->memmap; 21840084ac3SKyle Evans for (ment = map; !BCM283X_MEMMAP_ISTERM(ment); ++ment) { 21940084ac3SKyle Evans if (pa >= ment->armc_start && 22040084ac3SKyle Evans pa < ment->armc_start + ment->armc_size) { 22140084ac3SKyle Evans return (pa - ment->armc_start) + ment->vcbus_start; 22240084ac3SKyle Evans } 22340084ac3SKyle Evans } 22440084ac3SKyle Evans 22540084ac3SKyle Evans /* 22640084ac3SKyle Evans * Assume 1:1 mapping for anything else, but complain about it on 22740084ac3SKyle Evans * verbose boots. 22840084ac3SKyle Evans */ 22940084ac3SKyle Evans if (bootverbose) 23040084ac3SKyle Evans printf("bcm283x_vcbus: No armc -> vcbus mapping found: %jx\n", 23140084ac3SKyle Evans (uintmax_t)pa); 23240084ac3SKyle Evans return (pa); 23340084ac3SKyle Evans } 23440084ac3SKyle Evans 23540084ac3SKyle Evans vm_paddr_t 23640084ac3SKyle Evans bcm283x_vcbus_to_armc(vm_paddr_t vca) 23740084ac3SKyle Evans { 23840084ac3SKyle Evans struct bcm283x_memory_soc_cfg *cfg; 23940084ac3SKyle Evans struct bcm283x_memory_mapping *map, *ment; 24040084ac3SKyle Evans 24140084ac3SKyle Evans /* Guaranteed not NULL if we haven't panicked yet. */ 24240084ac3SKyle Evans cfg = bcm283x_get_current_memcfg(); 24340084ac3SKyle Evans map = cfg->memmap; 24440084ac3SKyle Evans for (ment = map; !BCM283X_MEMMAP_ISTERM(ment); ++ment) { 24540084ac3SKyle Evans if (vca >= ment->vcbus_start && 24640084ac3SKyle Evans vca < ment->vcbus_start + ment->armc_size) { 24740084ac3SKyle Evans return (vca - ment->vcbus_start) + ment->armc_start; 24840084ac3SKyle Evans } 24940084ac3SKyle Evans } 25040084ac3SKyle Evans 25140084ac3SKyle Evans /* 25240084ac3SKyle Evans * Assume 1:1 mapping for anything else, but complain about it on 25340084ac3SKyle Evans * verbose boots. 25440084ac3SKyle Evans */ 25540084ac3SKyle Evans if (bootverbose) 25640084ac3SKyle Evans printf("bcm283x_vcbus: No vcbus -> armc mapping found: %jx\n", 25740084ac3SKyle Evans (uintmax_t)vca); 25840084ac3SKyle Evans return (vca); 25940084ac3SKyle Evans } 26040084ac3SKyle Evans 26140084ac3SKyle Evans bus_addr_t 26240084ac3SKyle Evans bcm283x_dmabus_peripheral_lowaddr(void) 26340084ac3SKyle Evans { 26440084ac3SKyle Evans struct bcm283x_memory_soc_cfg *cfg; 26540084ac3SKyle Evans 26640084ac3SKyle Evans cfg = bcm283x_get_current_memcfg(); 26740084ac3SKyle Evans return (cfg->busdma_lowaddr); 26840084ac3SKyle Evans } 269