Home | History | Annotate | Line # | Download | only in xilinx
      1 /*	$NetBSD: zynq_platform.c,v 1.13 2025/11/28 08:27:08 skrll Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2019 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Nick Hudson
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include "opt_console.h"
     33 #include "opt_soc.h"
     34 
     35 #include "arml2cc.h"
     36 
     37 #include <sys/cdefs.h>
     38 __KERNEL_RCSID(0, "$NetBSD: zynq_platform.c,v 1.13 2025/11/28 08:27:08 skrll Exp $");
     39 
     40 #include <sys/param.h>
     41 #include <sys/bus.h>
     42 #include <sys/cpu.h>
     43 #include <sys/device.h>
     44 
     45 #include <dev/fdt/fdtvar.h>
     46 #include <dev/fdt/fdt_platform.h>
     47 #include <arm/fdt/arm_fdtvar.h>
     48 
     49 #include <uvm/uvm_extern.h>
     50 
     51 #include <machine/bootconfig.h>
     52 
     53 #include <arm/cortex/a9tmr_var.h>
     54 #include <arm/cortex/scu_reg.h>
     55 #include <arm/xilinx/zynq_uartreg.h>
     56 
     57 #include <evbarm/fdt/platform.h>
     58 
     59 #include <libfdt.h>
     60 
     61 #include <arm/cortex/pl310_var.h>
     62 
     63 #include <arm/arm32/machdep.h>
     64 
     65 #define	ZYNQ_REF_FREQ	24000000
     66 #define	ZYNQ7000_DDR_PBASE	0x00000000
     67 #define	ZYNQ7000_DDR_SIZE	0x40000000
     68 
     69 #define	ZYNQ_IOREG_VBASE	KERNEL_IO_VBASE
     70 #define	ZYNQ_IOREG_PBASE	0xe0000000
     71 #define ZYNQ_IOREG_SIZE		0x00200000
     72 
     73 #define	ZYNQ_SLCR_VBASE		(ZYNQ_IOREG_VBASE + ZYNQ_IOREG_SIZE)
     74 #define	ZYNQ_SLCR_PBASE		0xf8000000
     75 #define	ZYNQ_SLCR_SIZE		0x00100000
     76 
     77 #define ZYNQ_GPV_VBASE		(ZYNQ_SLCR_VBASE + ZYNQ_SLCR_SIZE)
     78 #define ZYNQ_GPV_PBASE		0xf8900000
     79 #define ZYNQ_GPV_SIZE		0x00100000
     80 
     81 #define ZYNQ_ARMCORE_VBASE	(ZYNQ_GPV_VBASE + ZYNQ_GPV_SIZE)
     82 #define ZYNQ_ARMCORE_PBASE	0xf8f00000
     83 #define ZYNQ_ARMCORE_SIZE	0x00100000
     84 
     85 #define	ZYNQ_OCM_VBASE		(ZYNQ_ARMCORE_VBASE + ZYNQ_ARMCORE_SIZE)
     86 #define	ZYNQ_OCM_PBASE		0xfff00000
     87 #define	ZYNQ_OCM_SIZE		0x00100000
     88 
     89 #define	ZYNQ_ARMCORE_SCU_BASE	0x00000000
     90 #define	ZYNQ_ARMCORE_L2C_BASE	0x00002000
     91 
     92 #define	ZYNQ7000_CPU1_ENTRY	0xfffffff0
     93 #define	ZYNQ7000_CPU1_ENTRY_SZ	4
     94 
     95 /* SLCR registers */
     96 #define	SLCR_UNLOCK		0x008
     97 #define	 UNLOCK_KEY		0xdf0d
     98 #define	PSS_RST_CTRL		0x200
     99 #define	 SOFT_RST		__BIT(0)
    100 
    101 extern struct bus_space arm_generic_bs_tag;
    102 extern struct arm32_bus_dma_tag arm_generic_dma_tag;
    103 
    104 void zynq_platform_early_putchar(char);
    105 
    106 static const struct pmap_devmap *
    107 zynq_platform_devmap(void)
    108 {
    109 	static const struct pmap_devmap devmap[] = {
    110 		DEVMAP_ENTRY(ZYNQ_IOREG_VBASE,
    111 			     ZYNQ_IOREG_PBASE,
    112 			     ZYNQ_IOREG_SIZE),
    113 		DEVMAP_ENTRY(ZYNQ_SLCR_VBASE,
    114 			     ZYNQ_SLCR_PBASE,
    115 			     ZYNQ_SLCR_SIZE),
    116 		DEVMAP_ENTRY(ZYNQ_GPV_VBASE,
    117 			     ZYNQ_GPV_PBASE,
    118 			     ZYNQ_GPV_SIZE),
    119 		DEVMAP_ENTRY(ZYNQ_ARMCORE_VBASE,
    120 			     ZYNQ_ARMCORE_PBASE,
    121 			     ZYNQ_ARMCORE_SIZE),
    122 		DEVMAP_ENTRY(ZYNQ_OCM_VBASE,
    123 			     ZYNQ_OCM_PBASE,
    124 			     ZYNQ_OCM_SIZE),
    125 		DEVMAP_ENTRY_END
    126 	};
    127 
    128 	return devmap;
    129 }
    130 
    131 static void
    132 zynq_platform_init_attach_args(struct fdt_attach_args *faa)
    133 {
    134 	faa->faa_bst = &arm_generic_bs_tag;
    135 	faa->faa_dmat = &arm_generic_dma_tag;
    136 }
    137 
    138 void __noasan
    139 zynq_platform_early_putchar(char c)
    140 {
    141 #ifdef CONSADDR
    142 #define CONSADDR_VA     ((CONSADDR - ZYNQ_IOREG_PBASE) + ZYNQ_IOREG_VBASE)
    143 	volatile uint32_t *uartaddr = cpu_earlydevice_va_p() ?
    144 	    (volatile uint32_t *)CONSADDR_VA :
    145 	    (volatile uint32_t *)CONSADDR;
    146 
    147 	/* QEMU needs CR_TXEN to be set and CR_TXDIS to be unset */
    148 	uartaddr[UART_CONTROL / 4] = CR_TXEN;
    149 	while ((le32toh(uartaddr[UART_CHNL_INT_STS / 4]) & STS_TEMPTY) == 0)
    150 		;
    151 
    152 	uartaddr[UART_TX_RX_FIFO / 4] = htole32(c);
    153 #endif
    154 }
    155 
    156 static void
    157 zynq_platform_device_register(device_t dev, void *aux)
    158 {
    159 }
    160 
    161 static u_int
    162 zynq_platform_uart_freq(void)
    163 {
    164 	return ZYNQ_REF_FREQ;
    165 }
    166 
    167 #ifdef MULTIPROCESSOR
    168 static int
    169 zynq_platform_mpstart(void)
    170 {
    171 	bus_space_tag_t bst = &arm_generic_bs_tag;
    172 	bus_space_handle_t bsh;
    173 	uint32_t val;
    174 	int error;
    175 	u_int i;
    176 
    177 	/* Invalidate all SCU cache tags and enable SCU. */
    178 	bsh = ZYNQ_ARMCORE_VBASE + ZYNQ_ARMCORE_SCU_BASE;
    179 	bus_space_write_4(bst, bsh, SCU_INV_ALL_REG, 0xffff);
    180 	val = bus_space_read_4(bst, bsh, SCU_CTL);
    181 	bus_space_write_4(bst, bsh, SCU_CTL, val | SCU_CTL_SCU_ENA);
    182 	armv7_dcache_wbinv_all();
    183 
    184 	/* Write start address for CPU1. */
    185 	error = bus_space_map(bst, ZYNQ7000_CPU1_ENTRY,
    186 	    ZYNQ7000_CPU1_ENTRY_SZ, 0, &bsh);
    187 	if (error) {
    188 		panic("%s: Couldn't map OCM: %d", __func__, error);
    189 	}
    190 	bus_space_write_4(bst, bsh, 0, KERN_VTOPHYS((vaddr_t)cpu_mpstart));
    191 	bus_space_unmap(bst, bsh, ZYNQ7000_CPU1_ENTRY_SZ);
    192 
    193 	dsb(sy);
    194 	sev();
    195 
    196 	const u_int cpuindex = 1;
    197 	for (i = 0x10000000; i > 0; i--) {
    198 		if (cpu_hatched_p(cpuindex)) {
    199 			break;
    200 		}
    201 	}
    202 	if (i == 0) {
    203 		aprint_error("cpu%d: WARNING: AP failed to start\n",
    204 		    cpuindex);
    205 		return EIO;
    206 	}
    207 
    208 	return 0;
    209 }
    210 #endif
    211 
    212 #define ZYNQ_ARM_PL310_BASE	ZYNQ_ARMCORE_VBASE + ZYNQ_ARMCORE_L2C_BASE
    213 
    214 static void
    215 zynq_platform_bootstrap(void)
    216 {
    217 #if NARML2CC > 0
    218 	const bus_space_handle_t pl310_bh = ZYNQ_ARM_PL310_BASE;
    219 	arml2cc_get_cacheinfo(&arm_generic_bs_tag, pl310_bh, 0);
    220 #endif
    221 
    222 	arm_fdt_cpu_bootstrap();
    223 
    224 	void *fdt_data = __UNCONST(fdtbus_get_data());
    225 	const int chosen_off = fdt_path_offset(fdt_data, "/chosen");
    226 	if (chosen_off < 0)
    227 		return;
    228 
    229 	if (match_bootconf_option(boot_args, "console", "fb")) {
    230 		const int framebuffer_off =
    231 		    fdt_path_offset(fdt_data, "/chosen/framebuffer");
    232 		if (framebuffer_off >= 0) {
    233 			const char *status = fdt_getprop(fdt_data,
    234 			    framebuffer_off, "status", NULL);
    235 			if (status == NULL || strncmp(status, "ok", 2) == 0) {
    236 				fdt_setprop_string(fdt_data, chosen_off,
    237 				    "stdout-path", "/chosen/framebuffer");
    238 			}
    239 		}
    240 	} else if (match_bootconf_option(boot_args, "console", "serial")) {
    241 		fdt_setprop_string(fdt_data, chosen_off,
    242 		    "stdout-path", "serial0:115200n8");
    243 	}
    244 }
    245 
    246 static void
    247 zynq_platform_reset(void)
    248 {
    249 	bus_space_tag_t bst = &arm_generic_bs_tag;
    250 	bus_space_handle_t bsh = ZYNQ_SLCR_VBASE;
    251 
    252 	bus_space_write_4(bst, bsh, SLCR_UNLOCK, UNLOCK_KEY);
    253 	bus_space_write_4(bst, bsh, PSS_RST_CTRL, SOFT_RST);
    254 }
    255 
    256 static const struct fdt_platform zynq_platform = {
    257 	.fp_devmap = zynq_platform_devmap,
    258 	.fp_bootstrap = zynq_platform_bootstrap,
    259 	.fp_init_attach_args = zynq_platform_init_attach_args,
    260 	.fp_device_register = zynq_platform_device_register,
    261 	.fp_reset = zynq_platform_reset,
    262 	.fp_delay = a9tmr_delay,
    263 	.fp_uart_freq = zynq_platform_uart_freq,
    264 #ifdef MULTIPROCESSOR
    265 	.fp_mpstart = zynq_platform_mpstart,
    266 #endif
    267 };
    268 
    269 
    270 FDT_PLATFORM(zynq, "xlnx,zynq-7000", &zynq_platform);
    271