11.12Sthorpej/* $NetBSD: zynq_platform.c,v 1.12 2025/09/06 21:02:41 thorpej Exp $ */ 21.1Sskrll 31.1Sskrll/*- 41.1Sskrll * Copyright (c) 2019 The NetBSD Foundation, Inc. 51.1Sskrll * All rights reserved. 61.1Sskrll * 71.1Sskrll * This code is derived from software contributed to The NetBSD Foundation 81.1Sskrll * by Nick Hudson 91.1Sskrll * 101.1Sskrll * Redistribution and use in source and binary forms, with or without 111.1Sskrll * modification, are permitted provided that the following conditions 121.1Sskrll * are met: 131.1Sskrll * 1. Redistributions of source code must retain the above copyright 141.1Sskrll * notice, this list of conditions and the following disclaimer. 151.1Sskrll * 2. Redistributions in binary form must reproduce the above copyright 161.1Sskrll * notice, this list of conditions and the following disclaimer in the 171.1Sskrll * documentation and/or other materials provided with the distribution. 181.1Sskrll * 191.1Sskrll * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 201.1Sskrll * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 211.1Sskrll * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 221.1Sskrll * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 231.1Sskrll * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 241.1Sskrll * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 251.1Sskrll * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 261.1Sskrll * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 271.1Sskrll * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 281.1Sskrll * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 291.1Sskrll * POSSIBILITY OF SUCH DAMAGE. 301.1Sskrll */ 311.1Sskrll 321.1Sskrll#include "opt_console.h" 331.1Sskrll#include "opt_soc.h" 341.1Sskrll 351.1Sskrll#include "arml2cc.h" 361.1Sskrll 371.1Sskrll#include <sys/cdefs.h> 381.12Sthorpej__KERNEL_RCSID(0, "$NetBSD: zynq_platform.c,v 1.12 2025/09/06 21:02:41 thorpej Exp $"); 391.1Sskrll 401.1Sskrll#include <sys/param.h> 411.1Sskrll#include <sys/bus.h> 421.1Sskrll#include <sys/cpu.h> 431.1Sskrll#include <sys/device.h> 441.1Sskrll 451.1Sskrll#include <dev/fdt/fdtvar.h> 461.12Sthorpej#include <dev/fdt/fdt_platform.h> 471.1Sskrll#include <arm/fdt/arm_fdtvar.h> 481.1Sskrll 491.1Sskrll#include <uvm/uvm_extern.h> 501.1Sskrll 511.1Sskrll#include <machine/bootconfig.h> 521.1Sskrll 531.1Sskrll#include <arm/cortex/a9tmr_var.h> 541.7Sjmcneill#include <arm/cortex/scu_reg.h> 551.1Sskrll#include <arm/xilinx/zynq_uartreg.h> 561.1Sskrll 571.1Sskrll#include <evbarm/fdt/platform.h> 581.1Sskrll 591.1Sskrll#include <libfdt.h> 601.1Sskrll 611.1Sskrll#include <arm/cortex/pl310_var.h> 621.1Sskrll 631.7Sjmcneill#include <arm/arm32/machdep.h> 641.7Sjmcneill 651.1Sskrll#define ZYNQ_REF_FREQ 24000000 661.1Sskrll#define ZYNQ7000_DDR_PBASE 0x00000000 671.1Sskrll#define ZYNQ7000_DDR_SIZE 0x40000000 681.1Sskrll 691.1Sskrll#define ZYNQ_IOREG_VBASE KERNEL_IO_VBASE 701.1Sskrll#define ZYNQ_IOREG_PBASE 0xe0000000 711.1Sskrll#define ZYNQ_IOREG_SIZE 0x00200000 721.1Sskrll 731.10Sjmcneill#define ZYNQ_SLCR_VBASE (ZYNQ_IOREG_VBASE + ZYNQ_IOREG_SIZE) 741.10Sjmcneill#define ZYNQ_SLCR_PBASE 0xf8000000 751.10Sjmcneill#define ZYNQ_SLCR_SIZE 0x00100000 761.10Sjmcneill 771.10Sjmcneill#define ZYNQ_GPV_VBASE (ZYNQ_SLCR_VBASE + ZYNQ_SLCR_SIZE) 781.1Sskrll#define ZYNQ_GPV_PBASE 0xf8900000 791.1Sskrll#define ZYNQ_GPV_SIZE 0x00100000 801.1Sskrll 811.1Sskrll#define ZYNQ_ARMCORE_VBASE (ZYNQ_GPV_VBASE + ZYNQ_GPV_SIZE) 821.1Sskrll#define ZYNQ_ARMCORE_PBASE 0xf8f00000 831.9Sjmcneill#define ZYNQ_ARMCORE_SIZE 0x00100000 841.1Sskrll 851.8Sjmcneill#define ZYNQ_OCM_VBASE (ZYNQ_ARMCORE_VBASE + ZYNQ_ARMCORE_SIZE) 861.8Sjmcneill#define ZYNQ_OCM_PBASE 0xfff00000 871.8Sjmcneill#define ZYNQ_OCM_SIZE 0x00100000 881.8Sjmcneill 891.7Sjmcneill#define ZYNQ_ARMCORE_SCU_BASE 0x00000000 901.7Sjmcneill#define ZYNQ_ARMCORE_L2C_BASE 0x00002000 911.7Sjmcneill 921.7Sjmcneill#define ZYNQ7000_CPU1_ENTRY 0xfffffff0 931.7Sjmcneill#define ZYNQ7000_CPU1_ENTRY_SZ 4 941.7Sjmcneill 951.10Sjmcneill/* SLCR registers */ 961.10Sjmcneill#define SLCR_UNLOCK 0x008 971.10Sjmcneill#define UNLOCK_KEY 0xdf0d 981.10Sjmcneill#define PSS_RST_CTRL 0x200 991.10Sjmcneill#define SOFT_RST __BIT(0) 1001.10Sjmcneill 1011.1Sskrllextern struct bus_space arm_generic_bs_tag; 1021.1Sskrllextern struct arm32_bus_dma_tag arm_generic_dma_tag; 1031.1Sskrll 1041.1Sskrllvoid zynq_platform_early_putchar(char); 1051.1Sskrll 1061.1Sskrllstatic const struct pmap_devmap * 1071.1Sskrllzynq_platform_devmap(void) 1081.1Sskrll{ 1091.1Sskrll static const struct pmap_devmap devmap[] = { 1101.1Sskrll DEVMAP_ENTRY(ZYNQ_IOREG_VBASE, 1111.1Sskrll ZYNQ_IOREG_PBASE, 1121.1Sskrll ZYNQ_IOREG_SIZE), 1131.10Sjmcneill DEVMAP_ENTRY(ZYNQ_SLCR_VBASE, 1141.10Sjmcneill ZYNQ_SLCR_PBASE, 1151.10Sjmcneill ZYNQ_SLCR_SIZE), 1161.1Sskrll DEVMAP_ENTRY(ZYNQ_GPV_VBASE, 1171.1Sskrll ZYNQ_GPV_PBASE, 1181.1Sskrll ZYNQ_GPV_SIZE), 1191.1Sskrll DEVMAP_ENTRY(ZYNQ_ARMCORE_VBASE, 1201.1Sskrll ZYNQ_ARMCORE_PBASE, 1211.1Sskrll ZYNQ_ARMCORE_SIZE), 1221.8Sjmcneill DEVMAP_ENTRY(ZYNQ_OCM_VBASE, 1231.8Sjmcneill ZYNQ_OCM_PBASE, 1241.8Sjmcneill ZYNQ_OCM_SIZE), 1251.1Sskrll DEVMAP_ENTRY_END 1261.1Sskrll }; 1271.1Sskrll 1281.1Sskrll return devmap; 1291.1Sskrll} 1301.1Sskrll 1311.1Sskrllstatic void 1321.1Sskrllzynq_platform_init_attach_args(struct fdt_attach_args *faa) 1331.1Sskrll{ 1341.1Sskrll faa->faa_bst = &arm_generic_bs_tag; 1351.1Sskrll faa->faa_dmat = &arm_generic_dma_tag; 1361.1Sskrll} 1371.1Sskrll 1381.2Sskrllvoid __noasan 1391.1Sskrllzynq_platform_early_putchar(char c) 1401.1Sskrll{ 1411.1Sskrll#ifdef CONSADDR 1421.1Sskrll#define CONSADDR_VA ((CONSADDR - ZYNQ_IOREG_PBASE) + ZYNQ_IOREG_VBASE) 1431.1Sskrll volatile uint32_t *uartaddr = cpu_earlydevice_va_p() ? 1441.1Sskrll (volatile uint32_t *)CONSADDR_VA : 1451.1Sskrll (volatile uint32_t *)CONSADDR; 1461.1Sskrll 1471.1Sskrll /* QEMU needs CR_TXEN to be set and CR_TXDIS to be unset */ 1481.1Sskrll uartaddr[UART_CONTROL / 4] = CR_TXEN; 1491.1Sskrll while ((le32toh(uartaddr[UART_CHNL_INT_STS / 4]) & STS_TEMPTY) == 0) 1501.1Sskrll ; 1511.1Sskrll 1521.1Sskrll uartaddr[UART_TX_RX_FIFO / 4] = htole32(c); 1531.1Sskrll#endif 1541.1Sskrll} 1551.1Sskrll 1561.1Sskrllstatic void 1571.1Sskrllzynq_platform_device_register(device_t dev, void *aux) 1581.1Sskrll{ 1591.1Sskrll} 1601.1Sskrll 1611.1Sskrllstatic u_int 1621.1Sskrllzynq_platform_uart_freq(void) 1631.1Sskrll{ 1641.1Sskrll return ZYNQ_REF_FREQ; 1651.1Sskrll} 1661.1Sskrll 1671.7Sjmcneill#ifdef MULTIPROCESSOR 1681.7Sjmcneillstatic int 1691.7Sjmcneillzynq_platform_mpstart(void) 1701.7Sjmcneill{ 1711.7Sjmcneill bus_space_tag_t bst = &arm_generic_bs_tag; 1721.7Sjmcneill bus_space_handle_t bsh; 1731.7Sjmcneill uint32_t val; 1741.7Sjmcneill int error; 1751.7Sjmcneill u_int i; 1761.7Sjmcneill 1771.7Sjmcneill /* Invalidate all SCU cache tags and enable SCU. */ 1781.7Sjmcneill bsh = ZYNQ_ARMCORE_VBASE + ZYNQ_ARMCORE_SCU_BASE; 1791.7Sjmcneill bus_space_write_4(bst, bsh, SCU_INV_ALL_REG, 0xffff); 1801.7Sjmcneill val = bus_space_read_4(bst, bsh, SCU_CTL); 1811.7Sjmcneill bus_space_write_4(bst, bsh, SCU_CTL, val | SCU_CTL_SCU_ENA); 1821.7Sjmcneill armv7_dcache_wbinv_all(); 1831.7Sjmcneill 1841.7Sjmcneill /* Write start address for CPU1. */ 1851.7Sjmcneill error = bus_space_map(bst, ZYNQ7000_CPU1_ENTRY, 1861.7Sjmcneill ZYNQ7000_CPU1_ENTRY_SZ, 0, &bsh); 1871.7Sjmcneill if (error) { 1881.7Sjmcneill panic("%s: Couldn't map OCM: %d", __func__, error); 1891.7Sjmcneill } 1901.7Sjmcneill bus_space_write_4(bst, bsh, 0, KERN_VTOPHYS((vaddr_t)cpu_mpstart)); 1911.7Sjmcneill bus_space_unmap(bst, bsh, ZYNQ7000_CPU1_ENTRY_SZ); 1921.7Sjmcneill 1931.7Sjmcneill dsb(sy); 1941.7Sjmcneill sev(); 1951.7Sjmcneill 1961.7Sjmcneill const u_int cpuindex = 1; 1971.7Sjmcneill for (i = 0x10000000; i > 0; i--) { 1981.7Sjmcneill if (cpu_hatched_p(cpuindex)) { 1991.7Sjmcneill break; 2001.7Sjmcneill } 2011.7Sjmcneill } 2021.7Sjmcneill if (i == 0) { 2031.7Sjmcneill aprint_error("cpu%d: WARNING: AP failed to start\n", 2041.7Sjmcneill cpuindex); 2051.7Sjmcneill return EIO; 2061.7Sjmcneill } 2071.7Sjmcneill 2081.7Sjmcneill return 0; 2091.7Sjmcneill} 2101.7Sjmcneill#endif 2111.7Sjmcneill 2121.1Sskrll#define ZYNQ_ARM_PL310_BASE ZYNQ_ARMCORE_VBASE + ZYNQ_ARMCORE_L2C_BASE 2131.1Sskrll 2141.1Sskrllstatic void 2151.1Sskrllzynq_platform_bootstrap(void) 2161.1Sskrll{ 2171.1Sskrll#if NARML2CC > 0 2181.1Sskrll const bus_space_handle_t pl310_bh = ZYNQ_ARM_PL310_BASE; 2191.1Sskrll arml2cc_init(&arm_generic_bs_tag, pl310_bh, 0); 2201.1Sskrll#endif 2211.1Sskrll 2221.1Sskrll arm_fdt_cpu_bootstrap(); 2231.1Sskrll 2241.1Sskrll void *fdt_data = __UNCONST(fdtbus_get_data()); 2251.1Sskrll const int chosen_off = fdt_path_offset(fdt_data, "/chosen"); 2261.1Sskrll if (chosen_off < 0) 2271.1Sskrll return; 2281.1Sskrll 2291.1Sskrll if (match_bootconf_option(boot_args, "console", "fb")) { 2301.1Sskrll const int framebuffer_off = 2311.1Sskrll fdt_path_offset(fdt_data, "/chosen/framebuffer"); 2321.1Sskrll if (framebuffer_off >= 0) { 2331.1Sskrll const char *status = fdt_getprop(fdt_data, 2341.1Sskrll framebuffer_off, "status", NULL); 2351.1Sskrll if (status == NULL || strncmp(status, "ok", 2) == 0) { 2361.1Sskrll fdt_setprop_string(fdt_data, chosen_off, 2371.1Sskrll "stdout-path", "/chosen/framebuffer"); 2381.1Sskrll } 2391.1Sskrll } 2401.1Sskrll } else if (match_bootconf_option(boot_args, "console", "serial")) { 2411.1Sskrll fdt_setprop_string(fdt_data, chosen_off, 2421.1Sskrll "stdout-path", "serial0:115200n8"); 2431.1Sskrll } 2441.1Sskrll} 2451.1Sskrll 2461.1Sskrllstatic void 2471.1Sskrllzynq_platform_reset(void) 2481.1Sskrll{ 2491.10Sjmcneill bus_space_tag_t bst = &arm_generic_bs_tag; 2501.10Sjmcneill bus_space_handle_t bsh = ZYNQ_SLCR_VBASE; 2511.1Sskrll 2521.10Sjmcneill bus_space_write_4(bst, bsh, SLCR_UNLOCK, UNLOCK_KEY); 2531.10Sjmcneill bus_space_write_4(bst, bsh, PSS_RST_CTRL, SOFT_RST); 2541.1Sskrll} 2551.1Sskrll 2561.11Sskrllstatic const struct fdt_platform zynq_platform = { 2571.11Sskrll .fp_devmap = zynq_platform_devmap, 2581.11Sskrll .fp_bootstrap = zynq_platform_bootstrap, 2591.11Sskrll .fp_init_attach_args = zynq_platform_init_attach_args, 2601.11Sskrll .fp_device_register = zynq_platform_device_register, 2611.11Sskrll .fp_reset = zynq_platform_reset, 2621.11Sskrll .fp_delay = a9tmr_delay, 2631.11Sskrll .fp_uart_freq = zynq_platform_uart_freq, 2641.7Sjmcneill#ifdef MULTIPROCESSOR 2651.11Sskrll .fp_mpstart = zynq_platform_mpstart, 2661.1Sskrll#endif 2671.1Sskrll}; 2681.1Sskrll 2691.1Sskrll 2701.11SskrllFDT_PLATFORM(zynq, "xlnx,zynq-7000", &zynq_platform); 271