xref: /freebsd/sys/arm/broadcom/bcm2835/bcm2835_vcbus.c (revision 685dc743dc3b5645e34836464128e1c0558b404b)
140084ac3SKyle Evans /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
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 
2840084ac3SKyle Evans #include <sys/cdefs.h>
2940084ac3SKyle Evans /*
3040084ac3SKyle Evans  * This file contains facilities for runtime determination of address space
3140084ac3SKyle Evans  * mappings for use in DMA/mailbox interactions.  This is only used for the
3240084ac3SKyle Evans  * arm64 SoC because the 32-bit SoC used the same mappings.
3340084ac3SKyle Evans  */
3440084ac3SKyle Evans 
3540084ac3SKyle Evans #include <sys/types.h>
3640084ac3SKyle Evans #include <sys/systm.h>
3740084ac3SKyle Evans 
3840084ac3SKyle Evans #include <dev/ofw/openfirm.h>
3940084ac3SKyle Evans #include <dev/ofw/ofw_bus.h>
4040084ac3SKyle Evans #include <dev/ofw/ofw_bus_subr.h>
4140084ac3SKyle Evans 
4240084ac3SKyle Evans #include <machine/bus.h>
4340084ac3SKyle Evans 
4440084ac3SKyle Evans #include <arm/broadcom/bcm2835/bcm2835_vcbus.h>
4540084ac3SKyle Evans 
4640084ac3SKyle Evans /*
4740084ac3SKyle Evans  * This structure describes mappings that need to take place when transforming
4840084ac3SKyle Evans  * ARM core addresses into vcbus addresses for use with the DMA/mailbox
4940084ac3SKyle Evans  * interfaces.  Currently, we only deal with peripheral/SDRAM address spaces
5040084ac3SKyle Evans  * here.
5140084ac3SKyle Evans  *
5240084ac3SKyle Evans  * The SDRAM address space is consistently mapped starting at 0 and extends to
5340084ac3SKyle Evans  * the size of the installed SDRAM.
5440084ac3SKyle Evans  *
5540084ac3SKyle Evans  * Peripherals are mapped further up at spots that vary per-SOC.
5640084ac3SKyle Evans  */
5740084ac3SKyle Evans struct bcm283x_memory_mapping {
5840084ac3SKyle Evans 	vm_paddr_t	armc_start;
5940084ac3SKyle Evans 	vm_paddr_t	armc_size;
6040084ac3SKyle Evans 	vm_paddr_t	vcbus_start;
6140084ac3SKyle Evans };
6240084ac3SKyle Evans 
6340084ac3SKyle Evans static struct bcm283x_memory_mapping bcm2835_memmap[] = {
6440084ac3SKyle Evans 	{
6540084ac3SKyle Evans 		/* SDRAM */
6640084ac3SKyle Evans 		.armc_start = 0x00000000,
6740084ac3SKyle Evans 		.armc_size = BCM2835_ARM_IO_BASE,
6840084ac3SKyle Evans 		.vcbus_start = BCM2835_VCBUS_SDRAM_BASE,
6940084ac3SKyle Evans 	},
7040084ac3SKyle Evans 	{
7140084ac3SKyle Evans 		/* Peripherals */
7240084ac3SKyle Evans 		.armc_start = BCM2835_ARM_IO_BASE,
7340084ac3SKyle Evans 		.armc_size  = BCM28XX_ARM_IO_SIZE,
7440084ac3SKyle Evans 		.vcbus_start = BCM2835_VCBUS_IO_BASE,
7540084ac3SKyle Evans 	},
7640084ac3SKyle Evans 	{ 0, 0, 0 },
7740084ac3SKyle Evans };
7840084ac3SKyle Evans 
795910fe02SKyle Evans static struct bcm283x_memory_mapping bcm2836_memmap[] = {
805910fe02SKyle Evans 	{
815910fe02SKyle Evans 		/* SDRAM */
825910fe02SKyle Evans 		.armc_start = 0x00000000,
835910fe02SKyle Evans 		.armc_size = BCM2836_ARM_IO_BASE,
845910fe02SKyle Evans 		.vcbus_start = BCM2836_VCBUS_SDRAM_BASE,
855910fe02SKyle Evans 	},
865910fe02SKyle Evans 	{
875910fe02SKyle Evans 		/* Peripherals */
885910fe02SKyle Evans 		.armc_start = BCM2836_ARM_IO_BASE,
895910fe02SKyle Evans 		.armc_size  = BCM28XX_ARM_IO_SIZE,
905910fe02SKyle Evans 		.vcbus_start = BCM2836_VCBUS_IO_BASE,
915910fe02SKyle Evans 	},
925910fe02SKyle Evans 	{ 0, 0, 0 },
935910fe02SKyle Evans };
945910fe02SKyle Evans 
9540084ac3SKyle Evans static struct bcm283x_memory_mapping bcm2837_memmap[] = {
9640084ac3SKyle Evans 	{
9740084ac3SKyle Evans 		/* SDRAM */
9840084ac3SKyle Evans 		.armc_start = 0x00000000,
9940084ac3SKyle Evans 		.armc_size = BCM2837_ARM_IO_BASE,
10040084ac3SKyle Evans 		.vcbus_start = BCM2837_VCBUS_SDRAM_BASE,
10140084ac3SKyle Evans 	},
10240084ac3SKyle Evans 	{
10340084ac3SKyle Evans 		/* Peripherals */
10440084ac3SKyle Evans 		.armc_start = BCM2837_ARM_IO_BASE,
10540084ac3SKyle Evans 		.armc_size  = BCM28XX_ARM_IO_SIZE,
10640084ac3SKyle Evans 		.vcbus_start = BCM2837_VCBUS_IO_BASE,
10740084ac3SKyle Evans 	},
10840084ac3SKyle Evans 	{ 0, 0, 0 },
10940084ac3SKyle Evans };
11040084ac3SKyle Evans 
11140084ac3SKyle Evans /*
11240084ac3SKyle Evans  * The BCM2838 supports up to 4GB of SDRAM, but unfortunately we can still only
11340084ac3SKyle Evans  * map the first 1GB into the "legacy master view" (vcbus) address space.  Thus,
11440084ac3SKyle Evans  * peripherals can still only access the lower end of SDRAM.  For this reason,
11540084ac3SKyle Evans  * we also capture the main-peripheral busdma restriction below.
11640084ac3SKyle Evans  */
11740084ac3SKyle Evans static struct bcm283x_memory_mapping bcm2838_memmap[] = {
11840084ac3SKyle Evans 	{
11940084ac3SKyle Evans 		/* SDRAM */
12040084ac3SKyle Evans 		.armc_start = 0x00000000,
12140084ac3SKyle Evans 		.armc_size = 0x40000000,
12240084ac3SKyle Evans 		.vcbus_start = BCM2838_VCBUS_SDRAM_BASE,
12340084ac3SKyle Evans 	},
12440084ac3SKyle Evans 	{
12540084ac3SKyle Evans 		/* Main peripherals */
12640084ac3SKyle Evans 		.armc_start = BCM2838_ARM_IO_BASE,
12740084ac3SKyle Evans 		.armc_size = BCM28XX_ARM_IO_SIZE,
12840084ac3SKyle Evans 		.vcbus_start = BCM2838_VCBUS_IO_BASE,
12940084ac3SKyle Evans 	},
13040084ac3SKyle Evans 	{ 0, 0, 0 },
13140084ac3SKyle Evans };
13240084ac3SKyle Evans 
13340084ac3SKyle Evans static struct bcm283x_memory_soc_cfg {
13440084ac3SKyle Evans 	struct bcm283x_memory_mapping	*memmap;
13540084ac3SKyle Evans 	const char			*soc_compat;
13640084ac3SKyle Evans 	bus_addr_t			 busdma_lowaddr;
13740084ac3SKyle Evans } bcm283x_memory_configs[] = {
13832a44e1eSKyle Evans 	/* Legacy */
13932a44e1eSKyle Evans 	{
14032a44e1eSKyle Evans 		.memmap = bcm2835_memmap,
14132a44e1eSKyle Evans 		.soc_compat = "raspberrypi,model-b",
14232a44e1eSKyle Evans 		.busdma_lowaddr = BUS_SPACE_MAXADDR_32BIT,
14332a44e1eSKyle Evans 	},
14432a44e1eSKyle Evans 	/* Modern */
14540084ac3SKyle Evans 	{
14640084ac3SKyle Evans 		.memmap = bcm2835_memmap,
14740084ac3SKyle Evans 		.soc_compat = "brcm,bcm2835",
14840084ac3SKyle Evans 		.busdma_lowaddr = BUS_SPACE_MAXADDR_32BIT,
14940084ac3SKyle Evans 	},
15032a44e1eSKyle Evans 	/* Legacy */
15132a44e1eSKyle Evans 	{
15232a44e1eSKyle Evans 		.memmap = bcm2836_memmap,
15332a44e1eSKyle Evans 		.soc_compat = "brcm,bcm2709",
15432a44e1eSKyle Evans 		.busdma_lowaddr = BUS_SPACE_MAXADDR_32BIT,
15532a44e1eSKyle Evans 	},
15632a44e1eSKyle Evans 	/* Modern */
15740084ac3SKyle Evans 	{
1585910fe02SKyle Evans 		.memmap = bcm2836_memmap,
15940084ac3SKyle Evans 		.soc_compat = "brcm,bcm2836",
16040084ac3SKyle Evans 		.busdma_lowaddr = BUS_SPACE_MAXADDR_32BIT,
16140084ac3SKyle Evans 	},
16240084ac3SKyle Evans 	{
16340084ac3SKyle Evans 		.memmap = bcm2837_memmap,
16440084ac3SKyle Evans 		.soc_compat = "brcm,bcm2837",
16540084ac3SKyle Evans 		.busdma_lowaddr = BUS_SPACE_MAXADDR_32BIT,
16640084ac3SKyle Evans 	},
16740084ac3SKyle Evans 	{
16840084ac3SKyle Evans 		.memmap = bcm2838_memmap,
169ba78f78fSKyle Evans 		.soc_compat = "brcm,bcm2711",
170ba78f78fSKyle Evans 		.busdma_lowaddr = BCM2838_PERIPH_MAXADDR,
171ba78f78fSKyle Evans 	},
172ba78f78fSKyle Evans 	{
173ba78f78fSKyle Evans 		.memmap = bcm2838_memmap,
17440084ac3SKyle Evans 		.soc_compat = "brcm,bcm2838",
17540084ac3SKyle Evans 		.busdma_lowaddr = BCM2838_PERIPH_MAXADDR,
17640084ac3SKyle Evans 	},
17740084ac3SKyle Evans };
17840084ac3SKyle Evans 
17940084ac3SKyle Evans static struct bcm283x_memory_soc_cfg *booted_soc_memcfg;
18040084ac3SKyle Evans 
18140084ac3SKyle Evans static struct bcm283x_memory_soc_cfg *
bcm283x_get_current_memcfg(void)18240084ac3SKyle Evans bcm283x_get_current_memcfg(void)
18340084ac3SKyle Evans {
18440084ac3SKyle Evans 	phandle_t root;
18540084ac3SKyle Evans 	int i;
18640084ac3SKyle Evans 
18740084ac3SKyle Evans 	/* We'll cache it once we decide, because it won't change per-boot. */
18840084ac3SKyle Evans 	if (booted_soc_memcfg != NULL)
18940084ac3SKyle Evans 		return (booted_soc_memcfg);
19040084ac3SKyle Evans 
19140084ac3SKyle Evans 	KASSERT(nitems(bcm283x_memory_configs) != 0,
19240084ac3SKyle Evans 	    ("No SOC memory configurations enabled!"));
19340084ac3SKyle Evans 
19440084ac3SKyle Evans 	root = OF_finddevice("/");
19540084ac3SKyle Evans 	for (i = 0; i < nitems(bcm283x_memory_configs); ++i) {
19640084ac3SKyle Evans 		booted_soc_memcfg = &bcm283x_memory_configs[i];
197d2ccf385SKyle Evans 		if (bootverbose)
19840084ac3SKyle Evans 			printf("Checking root against %s\n",
19940084ac3SKyle Evans 			    booted_soc_memcfg->soc_compat);
20040084ac3SKyle Evans 		if (ofw_bus_node_is_compatible(root,
20140084ac3SKyle Evans 		    booted_soc_memcfg->soc_compat))
20240084ac3SKyle Evans 			return (booted_soc_memcfg);
20340084ac3SKyle Evans 	}
20440084ac3SKyle Evans 
20540084ac3SKyle Evans 	/*
20640084ac3SKyle Evans 	 * The kernel doesn't fit the board; we can't really make a reasonable
20740084ac3SKyle Evans 	 * guess, as these SOC are different enough that something will blow up
20840084ac3SKyle Evans 	 * later.
20940084ac3SKyle Evans 	 */
21040084ac3SKyle Evans 	panic("No suitable SOC memory configuration found.");
21140084ac3SKyle Evans }
21240084ac3SKyle Evans 
21340084ac3SKyle Evans #define	BCM283X_MEMMAP_ISTERM(ent)	\
21440084ac3SKyle Evans     ((ent)->armc_start == 0 && (ent)->armc_size == 0 && \
21540084ac3SKyle Evans     (ent)->vcbus_start == 0)
21640084ac3SKyle Evans 
21740084ac3SKyle Evans vm_paddr_t
bcm283x_armc_to_vcbus(vm_paddr_t pa)21840084ac3SKyle Evans bcm283x_armc_to_vcbus(vm_paddr_t pa)
21940084ac3SKyle Evans {
22040084ac3SKyle Evans 	struct bcm283x_memory_soc_cfg *cfg;
22140084ac3SKyle Evans 	struct bcm283x_memory_mapping *map, *ment;
22240084ac3SKyle Evans 
22340084ac3SKyle Evans 	/* Guaranteed not NULL if we haven't panicked yet. */
22440084ac3SKyle Evans 	cfg = bcm283x_get_current_memcfg();
22540084ac3SKyle Evans 	map = cfg->memmap;
22640084ac3SKyle Evans 	for (ment = map; !BCM283X_MEMMAP_ISTERM(ment); ++ment) {
22740084ac3SKyle Evans 		if (pa >= ment->armc_start &&
22840084ac3SKyle Evans 		    pa < ment->armc_start + ment->armc_size) {
22940084ac3SKyle Evans 			return (pa - ment->armc_start) + ment->vcbus_start;
23040084ac3SKyle Evans 		}
23140084ac3SKyle Evans 	}
23240084ac3SKyle Evans 
23340084ac3SKyle Evans 	/*
23440084ac3SKyle Evans 	 * Assume 1:1 mapping for anything else, but complain about it on
23540084ac3SKyle Evans 	 * verbose boots.
23640084ac3SKyle Evans 	 */
23740084ac3SKyle Evans 	if (bootverbose)
23840084ac3SKyle Evans 		printf("bcm283x_vcbus: No armc -> vcbus mapping found: %jx\n",
23940084ac3SKyle Evans 		    (uintmax_t)pa);
24040084ac3SKyle Evans 	return (pa);
24140084ac3SKyle Evans }
24240084ac3SKyle Evans 
24340084ac3SKyle Evans vm_paddr_t
bcm283x_vcbus_to_armc(vm_paddr_t vca)24440084ac3SKyle Evans bcm283x_vcbus_to_armc(vm_paddr_t vca)
24540084ac3SKyle Evans {
24640084ac3SKyle Evans 	struct bcm283x_memory_soc_cfg *cfg;
24740084ac3SKyle Evans 	struct bcm283x_memory_mapping *map, *ment;
24840084ac3SKyle Evans 
24940084ac3SKyle Evans 	/* Guaranteed not NULL if we haven't panicked yet. */
25040084ac3SKyle Evans 	cfg = bcm283x_get_current_memcfg();
25140084ac3SKyle Evans 	map = cfg->memmap;
25240084ac3SKyle Evans 	for (ment = map; !BCM283X_MEMMAP_ISTERM(ment); ++ment) {
25340084ac3SKyle Evans 		if (vca >= ment->vcbus_start &&
25440084ac3SKyle Evans 		    vca < ment->vcbus_start + ment->armc_size) {
25540084ac3SKyle Evans 			return (vca - ment->vcbus_start) + ment->armc_start;
25640084ac3SKyle Evans 		}
25740084ac3SKyle Evans 	}
25840084ac3SKyle Evans 
25940084ac3SKyle Evans 	/*
26040084ac3SKyle Evans 	 * Assume 1:1 mapping for anything else, but complain about it on
26140084ac3SKyle Evans 	 * verbose boots.
26240084ac3SKyle Evans 	 */
26340084ac3SKyle Evans 	if (bootverbose)
26440084ac3SKyle Evans 		printf("bcm283x_vcbus: No vcbus -> armc mapping found: %jx\n",
26540084ac3SKyle Evans 		    (uintmax_t)vca);
26640084ac3SKyle Evans 	return (vca);
26740084ac3SKyle Evans }
26840084ac3SKyle Evans 
26940084ac3SKyle Evans bus_addr_t
bcm283x_dmabus_peripheral_lowaddr(void)27040084ac3SKyle Evans bcm283x_dmabus_peripheral_lowaddr(void)
27140084ac3SKyle Evans {
27240084ac3SKyle Evans 	struct bcm283x_memory_soc_cfg *cfg;
27340084ac3SKyle Evans 
27440084ac3SKyle Evans 	cfg = bcm283x_get_current_memcfg();
27540084ac3SKyle Evans 	return (cfg->busdma_lowaddr);
27640084ac3SKyle Evans }
277