xref: /freebsd/sys/arm/broadcom/bcm2835/bcm2835_vcbus.c (revision d2ccf385fd7a988c622a0869a8f7dbbc77dcd729)
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