zynq_platform.c revision 1.8
11.8Sjmcneill/* $NetBSD: zynq_platform.c,v 1.8 2022/10/27 20:37:10 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.8Sjmcneill__KERNEL_RCSID(0, "$NetBSD: zynq_platform.c,v 1.8 2022/10/27 20:37:10 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.8Sjmcneill#define ZYNQ_OCM_VBASE (ZYNQ_ARMCORE_VBASE + ZYNQ_ARMCORE_SIZE) 811.8Sjmcneill#define ZYNQ_OCM_PBASE 0xfff00000 821.8Sjmcneill#define ZYNQ_OCM_SIZE 0x00100000 831.8Sjmcneill 841.7Sjmcneill#define ZYNQ_ARMCORE_SCU_BASE 0x00000000 851.7Sjmcneill#define ZYNQ_ARMCORE_L2C_BASE 0x00002000 861.7Sjmcneill 871.7Sjmcneill#define ZYNQ7000_CPU1_ENTRY 0xfffffff0 881.7Sjmcneill#define ZYNQ7000_CPU1_ENTRY_SZ 4 891.7Sjmcneill 901.1Sskrllextern struct bus_space arm_generic_bs_tag; 911.1Sskrllextern struct arm32_bus_dma_tag arm_generic_dma_tag; 921.1Sskrll 931.1Sskrllvoid zynq_platform_early_putchar(char); 941.1Sskrll 951.1Sskrllstatic const struct pmap_devmap * 961.1Sskrllzynq_platform_devmap(void) 971.1Sskrll{ 981.1Sskrll static const struct pmap_devmap devmap[] = { 991.1Sskrll DEVMAP_ENTRY(ZYNQ_IOREG_VBASE, 1001.1Sskrll ZYNQ_IOREG_PBASE, 1011.1Sskrll ZYNQ_IOREG_SIZE), 1021.1Sskrll DEVMAP_ENTRY(ZYNQ_GPV_VBASE, 1031.1Sskrll ZYNQ_GPV_PBASE, 1041.1Sskrll ZYNQ_GPV_SIZE), 1051.1Sskrll DEVMAP_ENTRY(ZYNQ_ARMCORE_VBASE, 1061.1Sskrll ZYNQ_ARMCORE_PBASE, 1071.1Sskrll ZYNQ_ARMCORE_SIZE), 1081.8Sjmcneill DEVMAP_ENTRY(ZYNQ_OCM_VBASE, 1091.8Sjmcneill ZYNQ_OCM_PBASE, 1101.8Sjmcneill ZYNQ_OCM_SIZE), 1111.1Sskrll DEVMAP_ENTRY_END 1121.1Sskrll }; 1131.1Sskrll 1141.1Sskrll return devmap; 1151.1Sskrll} 1161.1Sskrll 1171.1Sskrllstatic void 1181.1Sskrllzynq_platform_init_attach_args(struct fdt_attach_args *faa) 1191.1Sskrll{ 1201.1Sskrll faa->faa_bst = &arm_generic_bs_tag; 1211.1Sskrll faa->faa_dmat = &arm_generic_dma_tag; 1221.1Sskrll} 1231.1Sskrll 1241.2Sskrllvoid __noasan 1251.1Sskrllzynq_platform_early_putchar(char c) 1261.1Sskrll{ 1271.1Sskrll#ifdef CONSADDR 1281.1Sskrll#define CONSADDR_VA ((CONSADDR - ZYNQ_IOREG_PBASE) + ZYNQ_IOREG_VBASE) 1291.1Sskrll volatile uint32_t *uartaddr = cpu_earlydevice_va_p() ? 1301.1Sskrll (volatile uint32_t *)CONSADDR_VA : 1311.1Sskrll (volatile uint32_t *)CONSADDR; 1321.1Sskrll 1331.1Sskrll /* QEMU needs CR_TXEN to be set and CR_TXDIS to be unset */ 1341.1Sskrll uartaddr[UART_CONTROL / 4] = CR_TXEN; 1351.1Sskrll while ((le32toh(uartaddr[UART_CHNL_INT_STS / 4]) & STS_TEMPTY) == 0) 1361.1Sskrll ; 1371.1Sskrll 1381.1Sskrll uartaddr[UART_TX_RX_FIFO / 4] = htole32(c); 1391.1Sskrll#endif 1401.1Sskrll} 1411.1Sskrll 1421.1Sskrllstatic void 1431.1Sskrllzynq_platform_device_register(device_t dev, void *aux) 1441.1Sskrll{ 1451.1Sskrll} 1461.1Sskrll 1471.1Sskrllstatic u_int 1481.1Sskrllzynq_platform_uart_freq(void) 1491.1Sskrll{ 1501.1Sskrll return ZYNQ_REF_FREQ; 1511.1Sskrll} 1521.1Sskrll 1531.7Sjmcneill#ifdef MULTIPROCESSOR 1541.7Sjmcneillstatic int 1551.7Sjmcneillzynq_platform_mpstart(void) 1561.7Sjmcneill{ 1571.7Sjmcneill bus_space_tag_t bst = &arm_generic_bs_tag; 1581.7Sjmcneill bus_space_handle_t bsh; 1591.7Sjmcneill uint32_t val; 1601.7Sjmcneill int error; 1611.7Sjmcneill u_int i; 1621.7Sjmcneill 1631.7Sjmcneill /* Invalidate all SCU cache tags and enable SCU. */ 1641.7Sjmcneill bsh = ZYNQ_ARMCORE_VBASE + ZYNQ_ARMCORE_SCU_BASE; 1651.7Sjmcneill bus_space_write_4(bst, bsh, SCU_INV_ALL_REG, 0xffff); 1661.7Sjmcneill val = bus_space_read_4(bst, bsh, SCU_CTL); 1671.7Sjmcneill bus_space_write_4(bst, bsh, SCU_CTL, val | SCU_CTL_SCU_ENA); 1681.7Sjmcneill armv7_dcache_wbinv_all(); 1691.7Sjmcneill 1701.7Sjmcneill /* Write start address for CPU1. */ 1711.7Sjmcneill error = bus_space_map(bst, ZYNQ7000_CPU1_ENTRY, 1721.7Sjmcneill ZYNQ7000_CPU1_ENTRY_SZ, 0, &bsh); 1731.7Sjmcneill if (error) { 1741.7Sjmcneill panic("%s: Couldn't map OCM: %d", __func__, error); 1751.7Sjmcneill } 1761.7Sjmcneill bus_space_write_4(bst, bsh, 0, KERN_VTOPHYS((vaddr_t)cpu_mpstart)); 1771.7Sjmcneill bus_space_unmap(bst, bsh, ZYNQ7000_CPU1_ENTRY_SZ); 1781.7Sjmcneill 1791.7Sjmcneill dsb(sy); 1801.7Sjmcneill sev(); 1811.7Sjmcneill 1821.7Sjmcneill const u_int cpuindex = 1; 1831.7Sjmcneill for (i = 0x10000000; i > 0; i--) { 1841.7Sjmcneill if (cpu_hatched_p(cpuindex)) { 1851.7Sjmcneill break; 1861.7Sjmcneill } 1871.7Sjmcneill } 1881.7Sjmcneill if (i == 0) { 1891.7Sjmcneill aprint_error("cpu%d: WARNING: AP failed to start\n", 1901.7Sjmcneill cpuindex); 1911.7Sjmcneill return EIO; 1921.7Sjmcneill } 1931.7Sjmcneill 1941.7Sjmcneill return 0; 1951.7Sjmcneill} 1961.7Sjmcneill#endif 1971.7Sjmcneill 1981.1Sskrll#define ZYNQ_ARM_PL310_BASE ZYNQ_ARMCORE_VBASE + ZYNQ_ARMCORE_L2C_BASE 1991.1Sskrll 2001.1Sskrllstatic void 2011.1Sskrllzynq_platform_bootstrap(void) 2021.1Sskrll{ 2031.1Sskrll#if NARML2CC > 0 2041.1Sskrll const bus_space_handle_t pl310_bh = ZYNQ_ARM_PL310_BASE; 2051.1Sskrll arml2cc_init(&arm_generic_bs_tag, pl310_bh, 0); 2061.1Sskrll#endif 2071.1Sskrll 2081.1Sskrll arm_fdt_cpu_bootstrap(); 2091.1Sskrll 2101.1Sskrll void *fdt_data = __UNCONST(fdtbus_get_data()); 2111.1Sskrll const int chosen_off = fdt_path_offset(fdt_data, "/chosen"); 2121.1Sskrll if (chosen_off < 0) 2131.1Sskrll return; 2141.1Sskrll 2151.1Sskrll if (match_bootconf_option(boot_args, "console", "fb")) { 2161.1Sskrll const int framebuffer_off = 2171.1Sskrll fdt_path_offset(fdt_data, "/chosen/framebuffer"); 2181.1Sskrll if (framebuffer_off >= 0) { 2191.1Sskrll const char *status = fdt_getprop(fdt_data, 2201.1Sskrll framebuffer_off, "status", NULL); 2211.1Sskrll if (status == NULL || strncmp(status, "ok", 2) == 0) { 2221.1Sskrll fdt_setprop_string(fdt_data, chosen_off, 2231.1Sskrll "stdout-path", "/chosen/framebuffer"); 2241.1Sskrll } 2251.1Sskrll } 2261.1Sskrll } else if (match_bootconf_option(boot_args, "console", "serial")) { 2271.1Sskrll fdt_setprop_string(fdt_data, chosen_off, 2281.1Sskrll "stdout-path", "serial0:115200n8"); 2291.1Sskrll } 2301.1Sskrll} 2311.1Sskrll 2321.1Sskrllstatic void 2331.1Sskrllzynq_platform_reset(void) 2341.1Sskrll{ 2351.1Sskrll 2361.1Sskrll} 2371.1Sskrll 2381.1Sskrllstatic const struct arm_platform zynq_platform = { 2391.1Sskrll .ap_devmap = zynq_platform_devmap, 2401.1Sskrll .ap_bootstrap = zynq_platform_bootstrap, 2411.1Sskrll .ap_init_attach_args = zynq_platform_init_attach_args, 2421.1Sskrll .ap_device_register = zynq_platform_device_register, 2431.1Sskrll .ap_reset = zynq_platform_reset, 2441.1Sskrll .ap_delay = a9tmr_delay, 2451.1Sskrll .ap_uart_freq = zynq_platform_uart_freq, 2461.7Sjmcneill#ifdef MULTIPROCESSOR 2471.7Sjmcneill .ap_mpstart = zynq_platform_mpstart, 2481.1Sskrll#endif 2491.1Sskrll}; 2501.1Sskrll 2511.1Sskrll 2521.1SskrllARM_PLATFORM(zynq, "xlnx,zynq-7000", &zynq_platform); 253