xref: /netbsd-src/sys/arch/cats/cats/cats_machdep.c (revision 3864cb2a6e81782f6a0c6979b833790316db47a0)
1 /*	$NetBSD: cats_machdep.c,v 1.96 2024/10/21 13:37:07 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.96 2024/10/21 13:37:07 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 
117 u_int dc21285_fclk = FCLK;
118 
119 struct ebsaboot ebsabootinfo;
120 BootConfig bootconfig;		/* Boot config storage */
121 static char bootargs[MAX_BOOT_STRING + 1];
122 char *boot_args = NULL;
123 char *boot_file = NULL;
124 
125 /* Prototypes */
126 
127 void consinit(void);
128 
129 int fcomcnattach(u_int iobase, int rate, tcflag_t cflag);
130 int fcomcndetach(void);
131 
132 static void process_kernel_args(const char *);
133 extern 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 
171 int comcnspeed = CONSPEED;
172 int comcnmode = CONMODE;
173 
174 static 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
214 static struct boot_physmem cats_physmem[MAX_PHYSMEM];
215 int ncats_physmem = 0;
216 
217 extern struct bus_space footbridge_pci_io_bs_tag;
218 extern struct bus_space footbridge_pci_mem_bs_tag;
219 void 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 
235 vaddr_t
236 initarm(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 	if (ram_size > KERNEL_VM_BASE - KERNEL_BASE) {
319 		printf("%s: dropping RAM size from %luMB to %uMB\n",
320 		    __func__, (unsigned long) (ram_size >> 20),
321 		    (KERNEL_VM_BASE - KERNEL_BASE) >> 20);
322 		ram_size = KERNEL_VM_BASE - KERNEL_BASE;
323         }
324 #else
325         const bool mapallmem_p = false;
326 #endif
327 
328 	printf("ram_size = 0x%08lx\n", ram_size);
329 
330 	arm32_bootmem_init(ebsabootinfo.bt_memstart, ram_size,
331 	    ebsabootinfo.bt_memstart);
332 
333 	/*
334 	 * The free block after the kernel from arm32_bootmem_init doesn't
335 	 * account for bt_memavail.  Adjust for this.
336 	 */
337 	extern struct bootmem_info bootmem_info;
338 	struct bootmem_info * const bmi = &bootmem_info;
339 
340 	pv_addr_t *pv0 = &bmi->bmi_freeblocks[0];
341 	KASSERTMSG(pv0->pv_pa == bmi->bmi_kernelend,
342 	    "pv_pa %#lx kernelend %#lx", pv0->pv_pa, bmi->bmi_kernelend);
343 
344 	pv0->pv_pa = ebsabootinfo.bt_memavail;
345 	pv0->pv_va = KERN_PHYSTOV(pv0->pv_pa);
346 	pv0->pv_size = bmi->bmi_end - pv0->pv_pa;
347 
348 	printf("First freeblock adjusted to: %lx -> %lx\n", pv0->pv_pa,
349 	    pv0->pv_pa + pv0->pv_size - 1);
350 
351 	arm32_kernel_vm_init(KERNEL_VM_BASE, ARM_VECTORS_LOW, 0, cats_devmap,
352 	    mapallmem_p);
353 
354 	printf("init subsystems: patch ");
355 
356 	/*
357 	 * PATCH PATCH ...
358 	 *
359 	 * Fixup the first word of the kernel to be the instruction
360 	 * add pc, pc, #0x41000000
361 	 *
362 	 * This traps the case where the CPU core resets due to bus contention
363 	 * on a prototype CATS system and will reboot into the firmware.
364 	 */
365 	*((u_int *)KERNEL_TEXT_BASE) = 0xe28ff441;
366 
367 #if NISA > 0
368 	/* Initialise the ISA subsystem early ... */
369 	isa_footbridge_init(DC21285_PCI_IO_VBASE, DC21285_PCI_ISA_MEM_VBASE);
370 #endif
371 
372 	footbridge_pci_bs_tag_init();
373 
374 	printf("busses done.\n");
375 
376 	/* Map the boot arguments page */
377 	if (ebsabootinfo.bt_vargp != vector_page) {
378 		pmap_map_entry(kernel_l1pt.pv_va, ebsabootinfo.bt_vargp,
379 		    ebsabootinfo.bt_pargp, VM_PROT_READ, PTE_CACHE);
380 	}
381 
382 	printf("Doing freeblocks: %d\n", bmi->bmi_nfreeblocks);
383 
384 	for (size_t i = 0; i < bmi->bmi_nfreeblocks; i++) {
385 		pv_addr_t * const pv = &bmi->bmi_freeblocks[i];
386 		paddr_t start = pv->pv_pa;
387 		paddr_t end = pv->pv_pa + pv->pv_size;
388 		struct boot_physmem *bp;
389 #if NISADMA > 0
390 		paddr_t istart, isize;
391 		extern struct arm32_dma_range *footbridge_isa_dma_ranges;
392 		extern int footbridge_isa_dma_nranges;
393 #endif
394 
395 		VPRINTF("%zu: 0x08%lx -> 0x08%lx\n", i, start, end - 1);
396 
397 #if NISADMA > 0
398 		if (arm32_dma_range_intersect(footbridge_isa_dma_ranges,
399 		   footbridge_isa_dma_nranges, start, end - start,
400 		   &istart, &isize)) {
401 			/*
402 			 * Place the pages that intersect with the
403 			 * ISA DMA range onto the ISA DMA free list.
404 			 */
405 			VPRINTF("    ISADMA 0x08%lx -> 0x%08lx\n", istart,
406 			    istart + isize - 1);
407 			bp = &cats_physmem[ncats_physmem++];
408 			KASSERT(ncats_physmem < MAX_PHYSMEM);
409 			bp->bp_start = atop(istart);
410 			bp->bp_pages = atop(isize);
411 			bp->bp_freelist = VM_FREELIST_ISADMA;
412 
413 			/*
414 			 * Load the pieces that come before the
415 			 * intersection onto the default free list.
416 			 */
417 			if (start < istart) {
418 				VPRINTF("    BEFORE 0x08%lx -> 0x08%lx\n",
419 				    start, istart - 1);
420 				bp = &cats_physmem[ncats_physmem++];
421 				KASSERT(ncats_physmem < MAX_PHYSMEM);
422 				bp->bp_start = atop(start);
423 				bp->bp_pages = atop(istart - start);
424 				bp->bp_freelist = VM_FREELIST_DEFAULT;
425 			}
426 
427 			/*
428 			 * Load the pieces that come after the
429 			 * intersection onto the default free list.
430 			 */
431 			if ((istart + isize) < end) {
432 				VPRINTF("     AFTER 0x%08lx -> 0x%08lx\n",
433 				    (istart + isize), end - 1);
434 				bp = &cats_physmem[ncats_physmem++];
435 				KASSERT(ncats_physmem < MAX_PHYSMEM);
436 				bp->bp_start = atop(istart + isize);
437 				bp->bp_pages = atop(end - (istart + isize));
438 				bp->bp_freelist = VM_FREELIST_DEFAULT;
439 			}
440 		} else {
441 			bp = &cats_physmem[ncats_physmem++];
442 			KASSERT(ncats_physmem < MAX_PHYSMEM);
443 			bp->bp_start = atop(start);
444 			bp->bp_pages = atop(end - start);
445 			bp->bp_freelist = VM_FREELIST_DEFAULT;
446 		}
447 #else /* NISADMA > 0 */
448 		bp = &cats_physmem[ncats_physmem++];
449 		KASSERT(ncats_physmem < MAX_PHYSMEM);
450 		bp->bp_start = atop(start);
451 		bp->bp_pages = atop(end - start);
452 		bp->bp_freelist = VM_FREELIST_DEFAULT;
453 #endif /* NISADMA > 0 */
454 	}
455 
456 	cpu_reset_address_paddr = DC21285_ROM_BASE;
457 
458 	/* initarm_common returns the new stack pointer address */
459 	vaddr_t sp;
460 	sp = initarm_common(KERNEL_VM_BASE, KERNEL_VM_SIZE, cats_physmem,
461 	    ncats_physmem);
462 
463 	/* Setup the IRQ system */
464 	printf("init subsystems: irq ");
465 	footbridge_intr_init();
466 
467 	printf("done.\n");
468 
469 #ifdef FCOM_INIT_ARM
470 	fcomcndetach();
471 #endif
472 
473 #ifdef DDB
474 	if (boothowto & RB_KDB)
475 		Debugger();
476 #endif
477 
478 	/*
479 	 * XXX this should only be done in main() but it useful to
480 	 * have output earlier ...
481 	 */
482 	consinit();
483 
484 	return sp;
485 }
486 
487 static void
488 process_kernel_args(const char *loader_args)
489 {
490 	char *args;
491 	boothowto = 0;
492 
493 	/* Make a local copy of the bootargs */
494 	strncpy(bootargs, loader_args, MAX_BOOT_STRING);
495 
496 	args = bootargs;
497 	boot_file = bootargs;
498 
499 	/* Skip the kernel image filename */
500 	while (*args != ' ' && *args != 0)
501 		++args;
502 
503 	if (*args != 0)
504 		*args++ = 0;
505 
506 	while (*args == ' ')
507 		++args;
508 
509 	boot_args = args;
510 
511 	printf("bootfile: %s\n", boot_file);
512 	printf("bootargs: %s\n", boot_args);
513 
514 	parse_mi_bootargs(boot_args);
515 }
516 
517 void
518 consinit(void)
519 {
520 	static int consinit_called = 0;
521 	const char *console = CONSDEVNAME;
522 
523 	if (consinit_called != 0)
524 		return;
525 
526 	consinit_called = 1;
527 
528 	get_bootconf_option(boot_args, "console", BOOTOPT_TYPE_STRING,
529 	    &console);
530 
531 	if (strncmp(console, "fcom", 4) == 0
532 	    || strncmp(console, "diag", 4) == 0)
533 		fcomcnattach(DC21285_ARMCSR_VBASE, comcnspeed, comcnmode);
534 #if (NVGA > 0)
535 	else if (strncmp(console, "vga", 3) == 0) {
536 		vga_cnattach(&footbridge_pci_io_bs_tag,
537 		    &footbridge_pci_mem_bs_tag, - 1, 0);
538 #if (NPCKBC > 0)
539 		pckbc_cnattach(&isa_io_bs_tag, IO_KBD, KBCMDP, PCKBC_KBD_SLOT,
540 		    0);
541 #endif	/* NPCKBC */
542 	}
543 #endif	/* NVGA */
544 #if (NCOM > 0)
545 	else if (strncmp(console, "com", 3) == 0) {
546 		if (comcnattach(&isa_io_bs_tag, CONCOMADDR, comcnspeed,
547 		    COM_FREQ, COM_TYPE_NORMAL, comcnmode))
548 			panic("can't init serial console @%x", CONCOMADDR);
549 	}
550 #endif
551 	/* Don't know what console was requested so use the fall back. */
552 	else
553 		fcomcnattach(DC21285_ARMCSR_VBASE, comcnspeed, comcnmode);
554 }
555 
556 /* End of cats_machdep.c */
557