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