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