1/*	$NetBSD: cats_machdep.c,v 1.94 2023/04/20 08:28:03 skrll Exp $	*/
2
3/*
4 * Copyright (c) 1997,1998 Mark Brinicombe.
5 * Copyright (c) 1997,1998 Causality Limited.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by Mark Brinicombe
19 *	for the NetBSD Project.
20 * 4. The name of the company nor the name of the author may be used to
21 *    endorse or promote products derived from this software without specific
22 *    prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
25 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
28 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * Machine dependent functions for kernel setup for EBSA285 core architecture
37 * using cyclone firmware
38 *
39 * Created      : 24/11/97
40 */
41
42#include <sys/cdefs.h>
43__KERNEL_RCSID(0, "$NetBSD: cats_machdep.c,v 1.94 2023/04/20 08:28:03 skrll Exp $");
44
45#include "opt_arm_debug.h"
46#include "opt_cats.h"
47#include "opt_ddb.h"
48#include "opt_modular.h"
49
50#include "isadma.h"
51
52#include <sys/param.h>
53#include <sys/device.h>
54#include <sys/systm.h>
55#include <sys/kernel.h>
56#include <sys/exec.h>
57#include <sys/proc.h>
58#include <sys/msgbuf.h>
59#include <sys/reboot.h>
60#include <sys/termios.h>
61#include <sys/ksyms.h>
62#include <sys/cpu.h>
63#include <sys/intr.h>
64
65#include <dev/cons.h>
66
67#include <machine/db_machdep.h>
68#include <ddb/db_sym.h>
69#include <ddb/db_extern.h>
70
71#include <machine/bootconfig.h>
72#define	_ARM32_BUS_DMA_PRIVATE
73#include <sys/bus.h>
74#include <arm/locore.h>
75#include <arm/undefined.h>
76#include <arm/arm32/machdep.h>
77
78#include <machine/cyclone_boot.h>
79#include <arm/footbridge/dc21285mem.h>
80#include <arm/footbridge/dc21285reg.h>
81
82#include "ksyms.h"
83#include "opt_ableelf.h"
84
85#include "isa.h"
86#if NISA > 0
87#include <dev/isa/isareg.h>
88#include <dev/isa/isavar.h>
89#endif
90
91#ifdef VERBOSE_INIT_ARM
92#define VPRINTF(...)	printf(__VA_ARGS__)
93#else
94#define VPRINTF(...)	__nothing
95#endif
96
97/* Kernel text starts at the base of the kernel address space. */
98#define	KERNEL_TEXT_BASE	(KERNEL_BASE + 0x00000000)
99#define	KERNEL_VM_BASE		(KERNEL_BASE + 0x01000000)
100
101/*
102 * The range 0xf1000000 - 0xfcffffff is available for kernel VM space
103 * Footbridge registers and I/O mappings occupy 0xfd000000 - 0xffffffff
104 */
105
106/*
107 * Size of available KVM space, note that growkernel will grow into this.
108 */
109#define KERNEL_VM_SIZE	0x0c000000
110
111/*
112 * Address to call from cpu_reset() to reset the machine.
113 * This is machine architecture dependent as it varies depending
114 * on where the ROM appears when you turn the MMU off.
115 */
116
117u_int dc21285_fclk = FCLK;
118
119struct ebsaboot ebsabootinfo;
120BootConfig bootconfig;		/* Boot config storage */
121static char bootargs[MAX_BOOT_STRING + 1];
122char *boot_args = NULL;
123char *boot_file = NULL;
124
125/* Prototypes */
126
127void consinit(void);
128
129int fcomcnattach(u_int iobase, int rate, tcflag_t cflag);
130int fcomcndetach(void);
131
132static void process_kernel_args(const char *);
133extern void configure(void);
134
135/* A load of console goo. */
136#include "vga.h"
137#if (NVGA > 0)
138#include <dev/ic/mc6845reg.h>
139#include <dev/ic/pcdisplayvar.h>
140#include <dev/ic/vgareg.h>
141#include <dev/ic/vgavar.h>
142#endif
143
144#include "pckbc.h"
145#if (NPCKBC > 0)
146#include <dev/ic/i8042reg.h>
147#include <dev/ic/pckbcvar.h>
148#endif
149
150#include "com.h"
151#if (NCOM > 0)
152#include <dev/ic/comreg.h>
153#include <dev/ic/comvar.h>
154#ifndef CONCOMADDR
155#define CONCOMADDR 0x3f8
156#endif
157#endif
158
159#ifndef CONSDEVNAME
160#define CONSDEVNAME "vga"
161#endif
162
163#define CONSPEED B38400
164#ifndef CONSPEED
165#define CONSPEED B9600	/* TTYDEF_SPEED */
166#endif
167#ifndef CONMODE
168#define CONMODE ((TTYDEF_CFLAG & ~(CSIZE | CSTOPB | PARENB)) | CS8) /* 8N1 */
169#endif
170
171int comcnspeed = CONSPEED;
172int comcnmode = CONMODE;
173
174static const struct pmap_devmap cats_devmap[] = {
175	/* Map 1MB for CSR space */
176	DEVMAP_ENTRY(DC21285_ARMCSR_VBASE,
177		     DC21285_ARMCSR_BASE,
178		     DC21285_ARMCSR_VSIZE),
179
180	/* Map 1MB for fast cache cleaning space */
181	DEVMAP_ENTRY(DC21285_CACHE_FLUSH_VBASE,
182		     DC21285_SA_CACHE_FLUSH_BASE,
183		     DC21285_CACHE_FLUSH_VSIZE),
184
185	/* Map 1MB for PCI IO space */
186	DEVMAP_ENTRY(DC21285_PCI_IO_VBASE,
187		     DC21285_PCI_IO_BASE,
188		     DC21285_PCI_IO_VSIZE),
189
190	/* Map 1MB for PCI IACK space */
191	DEVMAP_ENTRY(DC21285_PCI_IACK_VBASE,
192		     DC21285_PCI_IACK_SPECIAL,
193		     DC21285_PCI_IACK_VSIZE),
194
195	/* Map 16MB of type 1 PCI config access */
196	DEVMAP_ENTRY(DC21285_PCI_TYPE_1_CONFIG_VBASE,
197		     DC21285_PCI_TYPE_1_CONFIG,
198		     DC21285_PCI_TYPE_1_CONFIG_VSIZE),
199
200	/* Map 16MB of type 0 PCI config access */
201	DEVMAP_ENTRY(DC21285_PCI_TYPE_0_CONFIG_VBASE,
202		     DC21285_PCI_TYPE_0_CONFIG,
203		     DC21285_PCI_TYPE_0_CONFIG_VSIZE),
204
205	/* Map 1MB of 32 bit PCI address space for ISA MEM accesses via PCI */
206	DEVMAP_ENTRY(DC21285_PCI_ISA_MEM_VBASE,
207		     DC21285_PCI_MEM_BASE,
208		     DC21285_PCI_ISA_MEM_VSIZE),
209
210	DEVMAP_ENTRY_END
211};
212
213#define MAX_PHYSMEM 4
214static struct boot_physmem cats_physmem[MAX_PHYSMEM];
215int ncats_physmem = 0;
216
217extern struct bus_space footbridge_pci_io_bs_tag;
218extern struct bus_space footbridge_pci_mem_bs_tag;
219void footbridge_pci_bs_tag_init(void);
220
221/*
222 * vaddr_t initarm(struct ebsaboot *bootinfo)
223 *
224 * Initial entry point on startup. This gets called before main() is
225 * entered.
226 * It should be responsible for setting up everything that must be
227 * in place when main is called.
228 * This includes
229 *   Taking a copy of the boot configuration structure.
230 *   Initialising the physical console so characters can be printed.
231 *   Setting up page tables for the kernel
232 *   Relocating the kernel to the bottom of physical memory
233 */
234
235vaddr_t
236initarm(void *arm_bootargs)
237{
238	struct ebsaboot *bootinfo = arm_bootargs;
239	extern u_int cpu_get_control(void);
240
241	/*
242	 * Heads up ... Setup the CPU / MMU / TLB functions
243	 */
244	set_cpufuncs();
245
246	/* Copy the boot configuration structure */
247	ebsabootinfo = *bootinfo;
248
249	if (ebsabootinfo.bt_fclk >= 50000000
250	    && ebsabootinfo.bt_fclk <= 66000000)
251		dc21285_fclk = ebsabootinfo.bt_fclk;
252
253	/* Fake bootconfig structure for the benefit of pmap.c */
254	/* XXX must make the memory description h/w independent */
255	bootconfig.dramblocks = 1;
256	bootconfig.dram[0].address = ebsabootinfo.bt_memstart;
257	bootconfig.dram[0].pages = (ebsabootinfo.bt_memend
258	    - ebsabootinfo.bt_memstart) / PAGE_SIZE;
259
260	/*
261	 * Initialise the diagnostic serial console
262	 * This allows a means of generating output during initarm().
263	 * Once all the memory map changes are complete we can call consinit()
264	 * and not have to worry about things moving.
265	 */
266	pmap_devmap_bootstrap((vaddr_t)ebsabootinfo.bt_l1, cats_devmap);
267
268#ifdef FCOM_INIT_ARM
269	fcomcnattach(DC21285_ARMCSR_VBASE, comcnspeed, comcnmode);
270#endif
271
272	/* Talk to the user */
273	printf("NetBSD/cats booting ...\n");
274
275	if (ebsabootinfo.bt_magic != BT_MAGIC_NUMBER_EBSA
276	    && ebsabootinfo.bt_magic != BT_MAGIC_NUMBER_CATS)
277		panic("Incompatible magic number %#x passed in boot args",
278		    ebsabootinfo.bt_magic);
279
280	/* output the incoming bootinfo */
281	VPRINTF("bootinfo @ %p\n", arm_bootargs);
282	VPRINTF("bt_magic    = 0x%08x\n", ebsabootinfo.bt_magic);
283	VPRINTF("bt_vargp    = 0x%08x\n", ebsabootinfo.bt_vargp);
284	VPRINTF("bt_pargp    = 0x%08x\n", ebsabootinfo.bt_pargp);
285	VPRINTF("bt_args @ %p, contents = \"%s\"\n", ebsabootinfo.bt_args, ebsabootinfo.bt_args);
286	VPRINTF("bt_l1       = %p\n", ebsabootinfo.bt_l1);
287
288	VPRINTF("bt_memstart = 0x%08x\n", ebsabootinfo.bt_memstart);
289	VPRINTF("bt_memend   = 0x%08x\n", ebsabootinfo.bt_memend);
290	VPRINTF("bt_memavail = 0x%08x\n", ebsabootinfo.bt_memavail);
291	VPRINTF("bt_fclk     = 0x%08x\n", ebsabootinfo.bt_fclk);
292	VPRINTF("bt_pciclk   = 0x%08x\n", ebsabootinfo.bt_pciclk);
293	VPRINTF("bt_vers     = 0x%08x\n", ebsabootinfo.bt_vers);
294	VPRINTF("bt_features = 0x%08x\n", ebsabootinfo.bt_features);
295
296	/*
297	 * Examine the boot args string for options we need to know about
298	 * now.
299	 */
300	process_kernel_args(ebsabootinfo.bt_args);
301
302	psize_t ram_size = ebsabootinfo.bt_memend - ebsabootinfo.bt_memstart;
303	/*
304	 * If MEMSIZE specified less than what we really have, limit ourselves
305	 * to that.
306	*/
307#ifdef MEMSIZE
308	if (ram_size == 0 || ram_size > (unsigned)MEMSIZE * 1024 * 1024)
309		ram_size = (unsigned)MEMSIZE * 1024 * 1024;
310	VPRINTF("ram_size = 0x%x\n", (int)ram_size);
311#else
312	KASSERTMSG(ram_size > 0, "RAM size unknown and MEMSIZE undefined");
313#endif
314
315#ifdef __HAVE_MM_MD_DIRECT_MAPPED_PHYS
316	const bool mapallmem_p = true;
317
318#ifndef PMAP_NEED_ALLOC_POOLPAGE
319	if (ram_size > KERNEL_VM_BASE - KERNEL_BASE) {
320		printf("%s: dropping RAM size from %luMB to %uMB\n",
321		    __func__, (unsigned long) (ram_size >> 20),
322		    (KERNEL_VM_BASE - KERNEL_BASE) >> 20);
323		ram_size = KERNEL_VM_BASE - KERNEL_BASE;
324        }
325#endif
326#else
327        const bool mapallmem_p = false;
328#endif
329
330	printf("ram_size = 0x%08lx\n", ram_size);
331
332	arm32_bootmem_init(ebsabootinfo.bt_memstart, ram_size,
333	    ebsabootinfo.bt_memstart);
334
335	/*
336	 * The free block after the kernel from arm32_bootmem_init doesn't
337	 * account for bt_memavail.  Adjust for this.
338	 */
339	extern struct bootmem_info bootmem_info;
340	struct bootmem_info * const bmi = &bootmem_info;
341
342	pv_addr_t *pv0 = &bmi->bmi_freeblocks[0];
343	KASSERTMSG(pv0->pv_pa == bmi->bmi_kernelend,
344	    "pv_pa %#lx kernelend %#lx", pv0->pv_pa, bmi->bmi_kernelend);
345
346	pv0->pv_pa = ebsabootinfo.bt_memavail;
347	pv0->pv_va = KERN_PHYSTOV(pv0->pv_pa);
348	pv0->pv_size = bmi->bmi_end - pv0->pv_pa;
349
350	printf("First freeblock adjusted to: %lx -> %lx\n", pv0->pv_pa,
351	    pv0->pv_pa + pv0->pv_size - 1);
352
353	arm32_kernel_vm_init(KERNEL_VM_BASE, ARM_VECTORS_LOW, 0, cats_devmap,
354	    mapallmem_p);
355
356	printf("init subsystems: patch ");
357
358	/*
359	 * PATCH PATCH ...
360	 *
361	 * Fixup the first word of the kernel to be the instruction
362	 * add pc, pc, #0x41000000
363	 *
364	 * This traps the case where the CPU core resets due to bus contention
365	 * on a prototype CATS system and will reboot into the firmware.
366	 */
367	*((u_int *)KERNEL_TEXT_BASE) = 0xe28ff441;
368
369#if NISA > 0
370	/* Initialise the ISA subsystem early ... */
371	isa_footbridge_init(DC21285_PCI_IO_VBASE, DC21285_PCI_ISA_MEM_VBASE);
372#endif
373
374	footbridge_pci_bs_tag_init();
375
376	printf("busses done.\n");
377
378	/* Map the boot arguments page */
379	if (ebsabootinfo.bt_vargp != vector_page) {
380		pmap_map_entry(kernel_l1pt.pv_va, ebsabootinfo.bt_vargp,
381		    ebsabootinfo.bt_pargp, VM_PROT_READ, PTE_CACHE);
382	}
383
384	printf("Doing freeblocks: %d\n", bmi->bmi_nfreeblocks);
385
386	for (size_t i = 0; i < bmi->bmi_nfreeblocks; i++) {
387		pv_addr_t * const pv = &bmi->bmi_freeblocks[i];
388		paddr_t start = pv->pv_pa;
389		paddr_t end = pv->pv_pa + pv->pv_size;
390		struct boot_physmem *bp;
391#if NISADMA > 0
392		paddr_t istart, isize;
393		extern struct arm32_dma_range *footbridge_isa_dma_ranges;
394		extern int footbridge_isa_dma_nranges;
395#endif
396
397		VPRINTF("%zu: 0x08%lx -> 0x08%lx\n", i, start, end - 1);
398
399#if NISADMA > 0
400		if (arm32_dma_range_intersect(footbridge_isa_dma_ranges,
401		   footbridge_isa_dma_nranges, start, end - start,
402		   &istart, &isize)) {
403			/*
404			 * Place the pages that intersect with the
405			 * ISA DMA range onto the ISA DMA free list.
406			 */
407			VPRINTF("    ISADMA 0x08%lx -> 0x%08lx\n", istart,
408			    istart + isize - 1);
409			bp = &cats_physmem[ncats_physmem++];
410			KASSERT(ncats_physmem < MAX_PHYSMEM);
411			bp->bp_start = atop(istart);
412			bp->bp_pages = atop(isize);
413			bp->bp_freelist = VM_FREELIST_ISADMA;
414
415			/*
416			 * Load the pieces that come before the
417			 * intersection onto the default free list.
418			 */
419			if (start < istart) {
420				VPRINTF("    BEFORE 0x08%lx -> 0x08%lx\n",
421				    start, istart - 1);
422				bp = &cats_physmem[ncats_physmem++];
423				KASSERT(ncats_physmem < MAX_PHYSMEM);
424				bp->bp_start = atop(start);
425				bp->bp_pages = atop(istart - start);
426				bp->bp_freelist = VM_FREELIST_DEFAULT;
427			}
428
429			/*
430			 * Load the pieces that come after the
431			 * intersection onto the default free list.
432			 */
433			if ((istart + isize) < end) {
434				VPRINTF("     AFTER 0x%08lx -> 0x%08lx\n",
435				    (istart + isize), end - 1);
436				bp = &cats_physmem[ncats_physmem++];
437				KASSERT(ncats_physmem < MAX_PHYSMEM);
438				bp->bp_start = atop(istart + isize);
439				bp->bp_pages = atop(end - (istart + isize));
440				bp->bp_freelist = VM_FREELIST_DEFAULT;
441			}
442		} else {
443			bp = &cats_physmem[ncats_physmem++];
444			KASSERT(ncats_physmem < MAX_PHYSMEM);
445			bp->bp_start = atop(start);
446			bp->bp_pages = atop(end - start);
447			bp->bp_freelist = VM_FREELIST_DEFAULT;
448		}
449#else /* NISADMA > 0 */
450		bp = &cats_physmem[ncats_physmem++];
451		KASSERT(ncats_physmem < MAX_PHYSMEM);
452		bp->bp_start = atop(start);
453		bp->bp_pages = atop(end - start);
454		bp->bp_freelist = VM_FREELIST_DEFAULT;
455#endif /* NISADMA > 0 */
456	}
457
458	cpu_reset_address_paddr = DC21285_ROM_BASE;
459
460	/* initarm_common returns the new stack pointer address */
461	vaddr_t sp;
462	sp = initarm_common(KERNEL_VM_BASE, KERNEL_VM_SIZE, cats_physmem,
463	    ncats_physmem);
464
465	/* Setup the IRQ system */
466	printf("init subsystems: irq ");
467	footbridge_intr_init();
468
469	printf("done.\n");
470
471#ifdef FCOM_INIT_ARM
472	fcomcndetach();
473#endif
474
475#ifdef DDB
476	if (boothowto & RB_KDB)
477		Debugger();
478#endif
479
480	/*
481	 * XXX this should only be done in main() but it useful to
482	 * have output earlier ...
483	 */
484	consinit();
485
486	return sp;
487}
488
489static void
490process_kernel_args(const char *loader_args)
491{
492	char *args;
493	boothowto = 0;
494
495	/* Make a local copy of the bootargs */
496	strncpy(bootargs, loader_args, MAX_BOOT_STRING);
497
498	args = bootargs;
499	boot_file = bootargs;
500
501	/* Skip the kernel image filename */
502	while (*args != ' ' && *args != 0)
503		++args;
504
505	if (*args != 0)
506		*args++ = 0;
507
508	while (*args == ' ')
509		++args;
510
511	boot_args = args;
512
513	printf("bootfile: %s\n", boot_file);
514	printf("bootargs: %s\n", boot_args);
515
516	parse_mi_bootargs(boot_args);
517}
518
519void
520consinit(void)
521{
522	static int consinit_called = 0;
523	const char *console = CONSDEVNAME;
524
525	if (consinit_called != 0)
526		return;
527
528	consinit_called = 1;
529
530	get_bootconf_option(boot_args, "console", BOOTOPT_TYPE_STRING,
531	    &console);
532
533	if (strncmp(console, "fcom", 4) == 0
534	    || strncmp(console, "diag", 4) == 0)
535		fcomcnattach(DC21285_ARMCSR_VBASE, comcnspeed, comcnmode);
536#if (NVGA > 0)
537	else if (strncmp(console, "vga", 3) == 0) {
538		vga_cnattach(&footbridge_pci_io_bs_tag,
539		    &footbridge_pci_mem_bs_tag, - 1, 0);
540#if (NPCKBC > 0)
541		pckbc_cnattach(&isa_io_bs_tag, IO_KBD, KBCMDP, PCKBC_KBD_SLOT,
542		    0);
543#endif	/* NPCKBC */
544	}
545#endif	/* NVGA */
546#if (NCOM > 0)
547	else if (strncmp(console, "com", 3) == 0) {
548		if (comcnattach(&isa_io_bs_tag, CONCOMADDR, comcnspeed,
549		    COM_FREQ, COM_TYPE_NORMAL, comcnmode))
550			panic("can't init serial console @%x", CONCOMADDR);
551	}
552#endif
553	/* Don't know what console was requested so use the fall back. */
554	else
555		fcomcnattach(DC21285_ARMCSR_VBASE, comcnspeed, comcnmode);
556}
557
558/* End of cats_machdep.c */
559