zynq_platform.c revision 1.7
11.7Sjmcneill/* $NetBSD: zynq_platform.c,v 1.7 2022/10/27 08:49:08 jmcneill 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.7Sjmcneill__KERNEL_RCSID(0, "$NetBSD: zynq_platform.c,v 1.7 2022/10/27 08:49:08 jmcneill 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.1Sskrll#include <arm/fdt/arm_fdtvar.h> 471.1Sskrll 481.1Sskrll#include <uvm/uvm_extern.h> 491.1Sskrll 501.1Sskrll#include <machine/bootconfig.h> 511.1Sskrll 521.1Sskrll#include <arm/cortex/a9tmr_var.h> 531.7Sjmcneill#include <arm/cortex/scu_reg.h> 541.1Sskrll#include <arm/xilinx/zynq_uartreg.h> 551.1Sskrll 561.1Sskrll#include <evbarm/fdt/platform.h> 571.1Sskrll 581.1Sskrll#include <libfdt.h> 591.1Sskrll 601.1Sskrll#include <arm/cortex/pl310_var.h> 611.1Sskrll 621.7Sjmcneill#include <arm/arm32/machdep.h> 631.7Sjmcneill 641.1Sskrll#define ZYNQ_REF_FREQ 24000000 651.1Sskrll#define ZYNQ7000_DDR_PBASE 0x00000000 661.1Sskrll#define ZYNQ7000_DDR_SIZE 0x40000000 671.1Sskrll 681.1Sskrll#define ZYNQ_IOREG_VBASE KERNEL_IO_VBASE 691.1Sskrll#define ZYNQ_IOREG_PBASE 0xe0000000 701.1Sskrll#define ZYNQ_IOREG_SIZE 0x00200000 711.1Sskrll 721.1Sskrll#define ZYNQ_GPV_VBASE (ZYNQ_IOREG_VBASE + ZYNQ_IOREG_SIZE) 731.1Sskrll#define ZYNQ_GPV_PBASE 0xf8900000 741.1Sskrll#define ZYNQ_GPV_SIZE 0x00100000 751.1Sskrll 761.1Sskrll#define ZYNQ_ARMCORE_VBASE (ZYNQ_GPV_VBASE + ZYNQ_GPV_SIZE) 771.1Sskrll#define ZYNQ_ARMCORE_PBASE 0xf8f00000 781.1Sskrll#define ZYNQ_ARMCORE_SIZE 0x00003000 791.1Sskrll 801.7Sjmcneill#define ZYNQ_ARMCORE_SCU_BASE 0x00000000 811.7Sjmcneill#define ZYNQ_ARMCORE_L2C_BASE 0x00002000 821.7Sjmcneill 831.7Sjmcneill#define ZYNQ7000_CPU1_ENTRY 0xfffffff0 841.7Sjmcneill#define ZYNQ7000_CPU1_ENTRY_SZ 4 851.7Sjmcneill 861.1Sskrllextern struct bus_space arm_generic_bs_tag; 871.1Sskrllextern struct arm32_bus_dma_tag arm_generic_dma_tag; 881.1Sskrll 891.1Sskrllvoid zynq_platform_early_putchar(char); 901.1Sskrll 911.1Sskrllstatic const struct pmap_devmap * 921.1Sskrllzynq_platform_devmap(void) 931.1Sskrll{ 941.1Sskrll static const struct pmap_devmap devmap[] = { 951.1Sskrll DEVMAP_ENTRY(ZYNQ_IOREG_VBASE, 961.1Sskrll ZYNQ_IOREG_PBASE, 971.1Sskrll ZYNQ_IOREG_SIZE), 981.1Sskrll DEVMAP_ENTRY(ZYNQ_GPV_VBASE, 991.1Sskrll ZYNQ_GPV_PBASE, 1001.1Sskrll ZYNQ_GPV_SIZE), 1011.1Sskrll DEVMAP_ENTRY(ZYNQ_ARMCORE_VBASE, 1021.1Sskrll ZYNQ_ARMCORE_PBASE, 1031.1Sskrll ZYNQ_ARMCORE_SIZE), 1041.1Sskrll DEVMAP_ENTRY_END 1051.1Sskrll }; 1061.1Sskrll 1071.1Sskrll return devmap; 1081.1Sskrll} 1091.1Sskrll 1101.1Sskrllstatic void 1111.1Sskrllzynq_platform_init_attach_args(struct fdt_attach_args *faa) 1121.1Sskrll{ 1131.1Sskrll faa->faa_bst = &arm_generic_bs_tag; 1141.1Sskrll faa->faa_dmat = &arm_generic_dma_tag; 1151.1Sskrll} 1161.1Sskrll 1171.2Sskrllvoid __noasan 1181.1Sskrllzynq_platform_early_putchar(char c) 1191.1Sskrll{ 1201.1Sskrll#ifdef CONSADDR 1211.1Sskrll#define CONSADDR_VA ((CONSADDR - ZYNQ_IOREG_PBASE) + ZYNQ_IOREG_VBASE) 1221.1Sskrll volatile uint32_t *uartaddr = cpu_earlydevice_va_p() ? 1231.1Sskrll (volatile uint32_t *)CONSADDR_VA : 1241.1Sskrll (volatile uint32_t *)CONSADDR; 1251.1Sskrll 1261.1Sskrll /* QEMU needs CR_TXEN to be set and CR_TXDIS to be unset */ 1271.1Sskrll uartaddr[UART_CONTROL / 4] = CR_TXEN; 1281.1Sskrll while ((le32toh(uartaddr[UART_CHNL_INT_STS / 4]) & STS_TEMPTY) == 0) 1291.1Sskrll ; 1301.1Sskrll 1311.1Sskrll uartaddr[UART_TX_RX_FIFO / 4] = htole32(c); 1321.1Sskrll#endif 1331.1Sskrll} 1341.1Sskrll 1351.1Sskrllstatic void 1361.1Sskrllzynq_platform_device_register(device_t dev, void *aux) 1371.1Sskrll{ 1381.1Sskrll} 1391.1Sskrll 1401.1Sskrllstatic u_int 1411.1Sskrllzynq_platform_uart_freq(void) 1421.1Sskrll{ 1431.1Sskrll return ZYNQ_REF_FREQ; 1441.1Sskrll} 1451.1Sskrll 1461.7Sjmcneill#ifdef MULTIPROCESSOR 1471.7Sjmcneillstatic int 1481.7Sjmcneillzynq_platform_mpstart(void) 1491.7Sjmcneill{ 1501.7Sjmcneill bus_space_tag_t bst = &arm_generic_bs_tag; 1511.7Sjmcneill bus_space_handle_t bsh; 1521.7Sjmcneill uint32_t val; 1531.7Sjmcneill int error; 1541.7Sjmcneill u_int i; 1551.7Sjmcneill 1561.7Sjmcneill /* Invalidate all SCU cache tags and enable SCU. */ 1571.7Sjmcneill bsh = ZYNQ_ARMCORE_VBASE + ZYNQ_ARMCORE_SCU_BASE; 1581.7Sjmcneill bus_space_write_4(bst, bsh, SCU_INV_ALL_REG, 0xffff); 1591.7Sjmcneill val = bus_space_read_4(bst, bsh, SCU_CTL); 1601.7Sjmcneill bus_space_write_4(bst, bsh, SCU_CTL, val | SCU_CTL_SCU_ENA); 1611.7Sjmcneill armv7_dcache_wbinv_all(); 1621.7Sjmcneill 1631.7Sjmcneill /* Write start address for CPU1. */ 1641.7Sjmcneill error = bus_space_map(bst, ZYNQ7000_CPU1_ENTRY, 1651.7Sjmcneill ZYNQ7000_CPU1_ENTRY_SZ, 0, &bsh); 1661.7Sjmcneill if (error) { 1671.7Sjmcneill panic("%s: Couldn't map OCM: %d", __func__, error); 1681.7Sjmcneill } 1691.7Sjmcneill bus_space_write_4(bst, bsh, 0, KERN_VTOPHYS((vaddr_t)cpu_mpstart)); 1701.7Sjmcneill bus_space_unmap(bst, bsh, ZYNQ7000_CPU1_ENTRY_SZ); 1711.7Sjmcneill 1721.7Sjmcneill dsb(sy); 1731.7Sjmcneill sev(); 1741.7Sjmcneill 1751.7Sjmcneill const u_int cpuindex = 1; 1761.7Sjmcneill for (i = 0x10000000; i > 0; i--) { 1771.7Sjmcneill if (cpu_hatched_p(cpuindex)) { 1781.7Sjmcneill break; 1791.7Sjmcneill } 1801.7Sjmcneill } 1811.7Sjmcneill if (i == 0) { 1821.7Sjmcneill aprint_error("cpu%d: WARNING: AP failed to start\n", 1831.7Sjmcneill cpuindex); 1841.7Sjmcneill return EIO; 1851.7Sjmcneill } 1861.7Sjmcneill 1871.7Sjmcneill return 0; 1881.7Sjmcneill} 1891.7Sjmcneill#endif 1901.7Sjmcneill 1911.1Sskrll#define ZYNQ_ARM_PL310_BASE ZYNQ_ARMCORE_VBASE + ZYNQ_ARMCORE_L2C_BASE 1921.1Sskrll 1931.1Sskrllstatic void 1941.1Sskrllzynq_platform_bootstrap(void) 1951.1Sskrll{ 1961.1Sskrll#if NARML2CC > 0 1971.1Sskrll const bus_space_handle_t pl310_bh = ZYNQ_ARM_PL310_BASE; 1981.1Sskrll arml2cc_init(&arm_generic_bs_tag, pl310_bh, 0); 1991.1Sskrll#endif 2001.1Sskrll 2011.1Sskrll arm_fdt_cpu_bootstrap(); 2021.1Sskrll 2031.1Sskrll void *fdt_data = __UNCONST(fdtbus_get_data()); 2041.1Sskrll const int chosen_off = fdt_path_offset(fdt_data, "/chosen"); 2051.1Sskrll if (chosen_off < 0) 2061.1Sskrll return; 2071.1Sskrll 2081.1Sskrll if (match_bootconf_option(boot_args, "console", "fb")) { 2091.1Sskrll const int framebuffer_off = 2101.1Sskrll fdt_path_offset(fdt_data, "/chosen/framebuffer"); 2111.1Sskrll if (framebuffer_off >= 0) { 2121.1Sskrll const char *status = fdt_getprop(fdt_data, 2131.1Sskrll framebuffer_off, "status", NULL); 2141.1Sskrll if (status == NULL || strncmp(status, "ok", 2) == 0) { 2151.1Sskrll fdt_setprop_string(fdt_data, chosen_off, 2161.1Sskrll "stdout-path", "/chosen/framebuffer"); 2171.1Sskrll } 2181.1Sskrll } 2191.1Sskrll } else if (match_bootconf_option(boot_args, "console", "serial")) { 2201.1Sskrll fdt_setprop_string(fdt_data, chosen_off, 2211.1Sskrll "stdout-path", "serial0:115200n8"); 2221.1Sskrll } 2231.1Sskrll} 2241.1Sskrll 2251.1Sskrllstatic void 2261.1Sskrllzynq_platform_reset(void) 2271.1Sskrll{ 2281.1Sskrll 2291.1Sskrll} 2301.1Sskrll 2311.1Sskrllstatic const struct arm_platform zynq_platform = { 2321.1Sskrll .ap_devmap = zynq_platform_devmap, 2331.1Sskrll .ap_bootstrap = zynq_platform_bootstrap, 2341.1Sskrll .ap_init_attach_args = zynq_platform_init_attach_args, 2351.1Sskrll .ap_device_register = zynq_platform_device_register, 2361.1Sskrll .ap_reset = zynq_platform_reset, 2371.1Sskrll .ap_delay = a9tmr_delay, 2381.1Sskrll .ap_uart_freq = zynq_platform_uart_freq, 2391.7Sjmcneill#ifdef MULTIPROCESSOR 2401.7Sjmcneill .ap_mpstart = zynq_platform_mpstart, 2411.1Sskrll#endif 2421.1Sskrll}; 2431.1Sskrll 2441.1Sskrll 2451.1SskrllARM_PLATFORM(zynq, "xlnx,zynq-7000", &zynq_platform); 246