zynq_platform.c revision 1.7
1/*	$NetBSD: zynq_platform.c,v 1.7 2022/10/27 08:49:08 jmcneill 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.7 2022/10/27 08:49:08 jmcneill 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 <arm/fdt/arm_fdtvar.h>
47
48#include <uvm/uvm_extern.h>
49
50#include <machine/bootconfig.h>
51
52#include <arm/cortex/a9tmr_var.h>
53#include <arm/cortex/scu_reg.h>
54#include <arm/xilinx/zynq_uartreg.h>
55
56#include <evbarm/fdt/platform.h>
57
58#include <libfdt.h>
59
60#include <arm/cortex/pl310_var.h>
61
62#include <arm/arm32/machdep.h>
63
64#define	ZYNQ_REF_FREQ	24000000
65#define	ZYNQ7000_DDR_PBASE	0x00000000
66#define	ZYNQ7000_DDR_SIZE	0x40000000
67
68#define	ZYNQ_IOREG_VBASE	KERNEL_IO_VBASE
69#define	ZYNQ_IOREG_PBASE	0xe0000000
70#define ZYNQ_IOREG_SIZE		0x00200000
71
72#define ZYNQ_GPV_VBASE		(ZYNQ_IOREG_VBASE + ZYNQ_IOREG_SIZE)
73#define ZYNQ_GPV_PBASE		0xf8900000
74#define ZYNQ_GPV_SIZE		0x00100000
75
76#define ZYNQ_ARMCORE_VBASE	(ZYNQ_GPV_VBASE + ZYNQ_GPV_SIZE)
77#define ZYNQ_ARMCORE_PBASE	0xf8f00000
78#define ZYNQ_ARMCORE_SIZE	0x00003000
79
80#define	ZYNQ_ARMCORE_SCU_BASE	0x00000000
81#define	ZYNQ_ARMCORE_L2C_BASE	0x00002000
82
83#define	ZYNQ7000_CPU1_ENTRY	0xfffffff0
84#define	ZYNQ7000_CPU1_ENTRY_SZ	4
85
86extern struct bus_space arm_generic_bs_tag;
87extern struct arm32_bus_dma_tag arm_generic_dma_tag;
88
89void zynq_platform_early_putchar(char);
90
91static const struct pmap_devmap *
92zynq_platform_devmap(void)
93{
94	static const struct pmap_devmap devmap[] = {
95		DEVMAP_ENTRY(ZYNQ_IOREG_VBASE,
96			     ZYNQ_IOREG_PBASE,
97			     ZYNQ_IOREG_SIZE),
98		DEVMAP_ENTRY(ZYNQ_GPV_VBASE,
99			     ZYNQ_GPV_PBASE,
100			     ZYNQ_GPV_SIZE),
101		DEVMAP_ENTRY(ZYNQ_ARMCORE_VBASE,
102			     ZYNQ_ARMCORE_PBASE,
103			     ZYNQ_ARMCORE_SIZE),
104		DEVMAP_ENTRY_END
105	};
106
107	return devmap;
108}
109
110static void
111zynq_platform_init_attach_args(struct fdt_attach_args *faa)
112{
113	faa->faa_bst = &arm_generic_bs_tag;
114	faa->faa_dmat = &arm_generic_dma_tag;
115}
116
117void __noasan
118zynq_platform_early_putchar(char c)
119{
120#ifdef CONSADDR
121#define CONSADDR_VA     ((CONSADDR - ZYNQ_IOREG_PBASE) + ZYNQ_IOREG_VBASE)
122	volatile uint32_t *uartaddr = cpu_earlydevice_va_p() ?
123	    (volatile uint32_t *)CONSADDR_VA :
124	    (volatile uint32_t *)CONSADDR;
125
126	/* QEMU needs CR_TXEN to be set and CR_TXDIS to be unset */
127	uartaddr[UART_CONTROL / 4] = CR_TXEN;
128	while ((le32toh(uartaddr[UART_CHNL_INT_STS / 4]) & STS_TEMPTY) == 0)
129		;
130
131	uartaddr[UART_TX_RX_FIFO / 4] = htole32(c);
132#endif
133}
134
135static void
136zynq_platform_device_register(device_t dev, void *aux)
137{
138}
139
140static u_int
141zynq_platform_uart_freq(void)
142{
143	return ZYNQ_REF_FREQ;
144}
145
146#ifdef MULTIPROCESSOR
147static int
148zynq_platform_mpstart(void)
149{
150	bus_space_tag_t bst = &arm_generic_bs_tag;
151	bus_space_handle_t bsh;
152	uint32_t val;
153	int error;
154	u_int i;
155
156	/* Invalidate all SCU cache tags and enable SCU. */
157	bsh = ZYNQ_ARMCORE_VBASE + ZYNQ_ARMCORE_SCU_BASE;
158	bus_space_write_4(bst, bsh, SCU_INV_ALL_REG, 0xffff);
159	val = bus_space_read_4(bst, bsh, SCU_CTL);
160	bus_space_write_4(bst, bsh, SCU_CTL, val | SCU_CTL_SCU_ENA);
161	armv7_dcache_wbinv_all();
162
163	/* Write start address for CPU1. */
164	error = bus_space_map(bst, ZYNQ7000_CPU1_ENTRY,
165	    ZYNQ7000_CPU1_ENTRY_SZ, 0, &bsh);
166	if (error) {
167		panic("%s: Couldn't map OCM: %d", __func__, error);
168	}
169	bus_space_write_4(bst, bsh, 0, KERN_VTOPHYS((vaddr_t)cpu_mpstart));
170	bus_space_unmap(bst, bsh, ZYNQ7000_CPU1_ENTRY_SZ);
171
172	dsb(sy);
173	sev();
174
175	const u_int cpuindex = 1;
176	for (i = 0x10000000; i > 0; i--) {
177		if (cpu_hatched_p(cpuindex)) {
178			break;
179		}
180	}
181	if (i == 0) {
182		aprint_error("cpu%d: WARNING: AP failed to start\n",
183		    cpuindex);
184		return EIO;
185	}
186
187	return 0;
188}
189#endif
190
191#define ZYNQ_ARM_PL310_BASE	ZYNQ_ARMCORE_VBASE + ZYNQ_ARMCORE_L2C_BASE
192
193static void
194zynq_platform_bootstrap(void)
195{
196#if NARML2CC > 0
197	const bus_space_handle_t pl310_bh = ZYNQ_ARM_PL310_BASE;
198	arml2cc_init(&arm_generic_bs_tag, pl310_bh, 0);
199#endif
200
201	arm_fdt_cpu_bootstrap();
202
203	void *fdt_data = __UNCONST(fdtbus_get_data());
204	const int chosen_off = fdt_path_offset(fdt_data, "/chosen");
205	if (chosen_off < 0)
206		return;
207
208	if (match_bootconf_option(boot_args, "console", "fb")) {
209		const int framebuffer_off =
210		    fdt_path_offset(fdt_data, "/chosen/framebuffer");
211		if (framebuffer_off >= 0) {
212			const char *status = fdt_getprop(fdt_data,
213			    framebuffer_off, "status", NULL);
214			if (status == NULL || strncmp(status, "ok", 2) == 0) {
215				fdt_setprop_string(fdt_data, chosen_off,
216				    "stdout-path", "/chosen/framebuffer");
217			}
218		}
219	} else if (match_bootconf_option(boot_args, "console", "serial")) {
220		fdt_setprop_string(fdt_data, chosen_off,
221		    "stdout-path", "serial0:115200n8");
222	}
223}
224
225static void
226zynq_platform_reset(void)
227{
228
229}
230
231static const struct arm_platform zynq_platform = {
232	.ap_devmap = zynq_platform_devmap,
233	.ap_bootstrap = zynq_platform_bootstrap,
234	.ap_init_attach_args = zynq_platform_init_attach_args,
235	.ap_device_register = zynq_platform_device_register,
236	.ap_reset = zynq_platform_reset,
237	.ap_delay = a9tmr_delay,
238	.ap_uart_freq = zynq_platform_uart_freq,
239#ifdef MULTIPROCESSOR
240	.ap_mpstart = zynq_platform_mpstart,
241#endif
242};
243
244
245ARM_PLATFORM(zynq, "xlnx,zynq-7000", &zynq_platform);
246