netwinder_machdep.c revision 1.41
11.41Schris/* $NetBSD: netwinder_machdep.c,v 1.41 2002/11/03 21:43:33 chris Exp $ */ 21.1Smatt 31.1Smatt/* 41.1Smatt * Copyright (c) 1997,1998 Mark Brinicombe. 51.1Smatt * Copyright (c) 1997,1998 Causality Limited. 61.1Smatt * All rights reserved. 71.1Smatt * 81.1Smatt * Redistribution and use in source and binary forms, with or without 91.1Smatt * modification, are permitted provided that the following conditions 101.1Smatt * are met: 111.1Smatt * 1. Redistributions of source code must retain the above copyright 121.1Smatt * notice, this list of conditions and the following disclaimer. 131.1Smatt * 2. Redistributions in binary form must reproduce the above copyright 141.1Smatt * notice, this list of conditions and the following disclaimer in the 151.1Smatt * documentation and/or other materials provided with the distribution. 161.1Smatt * 3. All advertising materials mentioning features or use of this software 171.1Smatt * must display the following acknowledgement: 181.1Smatt * This product includes software developed by Mark Brinicombe 191.1Smatt * for the NetBSD Project. 201.1Smatt * 4. The name of the company nor the name of the author may be used to 211.1Smatt * endorse or promote products derived from this software without specific 221.1Smatt * prior written permission. 231.1Smatt * 241.1Smatt * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 251.1Smatt * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 261.1Smatt * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 271.1Smatt * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 281.1Smatt * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 291.1Smatt * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 301.1Smatt * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 311.1Smatt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 321.1Smatt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 331.1Smatt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 341.1Smatt * SUCH DAMAGE. 351.1Smatt * 361.1Smatt * Machine dependant functions for kernel setup for EBSA285 core architecture 371.1Smatt * using Netwinder firmware 381.1Smatt * 391.1Smatt * Created : 24/11/97 401.1Smatt */ 411.1Smatt 421.1Smatt#include "opt_ddb.h" 431.1Smatt#include "opt_pmap_debug.h" 441.1Smatt 451.33Sthorpej#include "isadma.h" 461.33Sthorpej 471.1Smatt#include <sys/param.h> 481.1Smatt#include <sys/device.h> 491.1Smatt#include <sys/systm.h> 501.1Smatt#include <sys/kernel.h> 511.1Smatt#include <sys/exec.h> 521.1Smatt#include <sys/proc.h> 531.1Smatt#include <sys/msgbuf.h> 541.1Smatt#include <sys/reboot.h> 551.1Smatt#include <sys/termios.h> 561.1Smatt 571.1Smatt#include <dev/cons.h> 581.1Smatt 591.1Smatt#include <machine/db_machdep.h> 601.1Smatt#include <ddb/db_sym.h> 611.1Smatt#include <ddb/db_extern.h> 621.1Smatt 631.38Sthorpej#include <arm/arm32/machdep.h> 641.38Sthorpej 651.1Smatt#include <machine/bootconfig.h> 661.34Sthorpej#define _ARM32_BUS_DMA_PRIVATE 671.1Smatt#include <machine/bus.h> 681.1Smatt#include <machine/cpu.h> 691.1Smatt#include <machine/frame.h> 701.9Smatt#include <machine/intr.h> 711.14Sthorpej#include <arm/undefined.h> 721.1Smatt 731.1Smatt#include <machine/netwinder_boot.h> 741.3Schris#include <arm/footbridge/dc21285mem.h> 751.3Schris#include <arm/footbridge/dc21285reg.h> 761.1Smatt 771.1Smatt#include "opt_ipkdb.h" 781.1Smatt 791.1Smatt#include "isa.h" 801.1Smatt#if NISA > 0 811.1Smatt#include <dev/isa/isareg.h> 821.1Smatt#include <dev/isa/isavar.h> 831.1Smatt#endif 841.1Smatt 851.8Smattstatic bus_space_handle_t isa_base = (bus_space_handle_t) DC21285_PCI_IO_VBASE; 861.8Smatt 871.31Sthorpejbs_protos(generic); 881.8Smatt 891.31Sthorpej#define ISA_GETBYTE(r) generic_bs_r_1(0, isa_base, (r)) 901.31Sthorpej#define ISA_PUTBYTE(r,v) generic_bs_w_1(0, isa_base, (r), (v)) 911.8Smatt 921.1Smatt/* 931.1Smatt * Address to call from cpu_reset() to reset the machine. 941.1Smatt * This is machine architecture dependant as it varies depending 951.1Smatt * on where the ROM appears when you turn the MMU off. 961.1Smatt */ 971.27Sthorpejstatic void netwinder_reset(void); 981.8Smattu_int cpu_reset_address = (u_int) netwinder_reset; 991.1Smatt 1001.8Smattu_int dc21285_fclk = 63750000; 1011.1Smatt 1021.1Smatt/* Define various stack sizes in pages */ 1031.1Smatt#define IRQ_STACK_SIZE 1 1041.1Smatt#define ABT_STACK_SIZE 1 1051.1Smatt#ifdef IPKDB 1061.1Smatt#define UND_STACK_SIZE 2 1071.1Smatt#else 1081.1Smatt#define UND_STACK_SIZE 1 1091.1Smatt#endif 1101.1Smatt 1111.1Smattstruct nwbootinfo nwbootinfo; 1121.1SmattBootConfig bootconfig; /* Boot config storage */ 1131.1Smattstatic char bootargs[MAX_BOOT_STRING + 1]; 1141.1Smattchar *boot_args = NULL; 1151.1Smattchar *boot_file = NULL; 1161.1Smatt 1171.1Smattvm_offset_t physical_start; 1181.1Smattvm_offset_t physical_freestart; 1191.1Smattvm_offset_t physical_freeend; 1201.1Smattvm_offset_t physical_end; 1211.1Smattu_int free_pages; 1221.1Smattvm_offset_t pagetables_start; 1231.1Smattint physmem = 0; 1241.1Smatt 1251.1Smatt/*int debug_flags;*/ 1261.1Smatt#ifndef PMAP_STATIC_L1S 1271.1Smattint max_processes = 64; /* Default number */ 1281.1Smatt#endif /* !PMAP_STATIC_L1S */ 1291.1Smatt 1301.1Smatt/* Physical and virtual addresses for some global pages */ 1311.1Smattpv_addr_t systempage; 1321.1Smattpv_addr_t irqstack; 1331.1Smattpv_addr_t undstack; 1341.1Smattpv_addr_t abtstack; 1351.1Smattpv_addr_t kernelstack; 1361.1Smatt 1371.1Smattvm_offset_t msgbufphys; 1381.1Smatt 1391.1Smattextern u_int data_abort_handler_address; 1401.1Smattextern u_int prefetch_abort_handler_address; 1411.1Smattextern u_int undefined_handler_address; 1421.1Smatt 1431.1Smatt#ifdef PMAP_DEBUG 1441.1Smattextern int pmap_debug_level; 1451.1Smatt#endif 1461.1Smatt 1471.1Smatt#define KERNEL_PT_SYS 0 /* Page table for mapping proc0 zero page */ 1481.1Smatt#define KERNEL_PT_KERNEL 1 /* Page table for mapping kernel */ 1491.1Smatt#define KERNEL_PT_VMDATA 2 /* Page tables for mapping kernel VM */ 1501.24Schris#define KERNEL_PT_VMDATA_NUM 4 /* start with 16MB of KVM */ 1511.1Smatt#define NUM_KERNEL_PTS (KERNEL_PT_VMDATA + KERNEL_PT_VMDATA_NUM) 1521.1Smatt 1531.21Sthorpejpv_addr_t kernel_pt_table[NUM_KERNEL_PTS]; 1541.1Smatt 1551.1Smattstruct user *proc0paddr; 1561.1Smatt 1571.1Smatt/* Prototypes */ 1581.1Smatt 1591.1Smattvoid consinit __P((void)); 1601.1Smatt 1611.1Smattint fcomcnattach __P((u_int iobase, int rate,tcflag_t cflag)); 1621.1Smattint fcomcndetach __P((void)); 1631.1Smatt 1641.1Smattvoid process_kernel_args __P((char *)); 1651.1Smattvoid data_abort_handler __P((trapframe_t *frame)); 1661.1Smattvoid prefetch_abort_handler __P((trapframe_t *frame)); 1671.1Smattvoid undefinedinstruction_bounce __P((trapframe_t *frame)); 1681.1Smattextern void configure __P((void)); 1691.1Smattextern void parse_mi_bootargs __P((char *args)); 1701.1Smattextern void dumpsys __P((void)); 1711.1Smatt 1721.1Smatt/* A load of console goo. */ 1731.1Smatt#include "vga.h" 1741.1Smatt#if (NVGA > 0) 1751.1Smatt#include <dev/ic/mc6845reg.h> 1761.1Smatt#include <dev/ic/pcdisplayvar.h> 1771.1Smatt#include <dev/ic/vgareg.h> 1781.1Smatt#include <dev/ic/vgavar.h> 1791.1Smatt#endif 1801.1Smatt 1811.1Smatt#include "pckbc.h" 1821.1Smatt#if (NPCKBC > 0) 1831.1Smatt#include <dev/ic/i8042reg.h> 1841.1Smatt#include <dev/ic/pckbcvar.h> 1851.1Smatt#endif 1861.1Smatt 1871.1Smatt#include "com.h" 1881.1Smatt#if (NCOM > 0) 1891.1Smatt#include <dev/ic/comreg.h> 1901.1Smatt#include <dev/ic/comvar.h> 1911.1Smatt#ifndef CONCOMADDR 1921.1Smatt#define CONCOMADDR 0x3f8 1931.1Smatt#endif 1941.1Smatt#endif 1951.1Smatt 1961.1Smatt#ifndef CONSDEVNAME 1971.1Smatt#define CONSDEVNAME "com" 1981.1Smatt#endif 1991.1Smatt 2001.1Smatt#define CONSPEED B115200 2011.1Smatt#ifndef CONSPEED 2021.1Smatt#define CONSPEED B9600 /* TTYDEF_SPEED */ 2031.1Smatt#endif 2041.1Smatt#ifndef CONMODE 2051.1Smatt#define CONMODE ((TTYDEF_CFLAG & ~(CSIZE | CSTOPB | PARENB)) | CS8) /* 8N1 */ 2061.1Smatt#endif 2071.1Smatt 2081.1Smattint comcnspeed = CONSPEED; 2091.1Smattint comcnmode = CONMODE; 2101.1Smatt 2111.1Smattextern struct consdev kcomcons; 2121.1Smattstatic void kcomcnputc(dev_t, int); 2131.1Smatt 2141.1Smatt/* 2151.1Smatt * void cpu_reboot(int howto, char *bootstr) 2161.1Smatt * 2171.1Smatt * Reboots the system 2181.1Smatt * 2191.1Smatt * Deal with any syncing, unmounting, dumping and shutdown hooks, 2201.1Smatt * then reset the CPU. 2211.1Smatt */ 2221.1Smatt 2231.1Smattvoid 2241.1Smattcpu_reboot(howto, bootstr) 2251.1Smatt int howto; 2261.1Smatt char *bootstr; 2271.1Smatt{ 2281.1Smatt#ifdef DIAGNOSTIC 2291.1Smatt /* info */ 2301.1Smatt printf("boot: howto=%08x curproc=%p\n", howto, curproc); 2311.1Smatt#endif 2321.1Smatt 2331.1Smatt /* 2341.1Smatt * If we are still cold then hit the air brakes 2351.1Smatt * and crash to earth fast 2361.1Smatt */ 2371.1Smatt if (cold) { 2381.1Smatt doshutdownhooks(); 2391.1Smatt printf("The operating system has halted.\n"); 2401.1Smatt printf("Please press any key to reboot.\n\n"); 2411.1Smatt cngetc(); 2421.1Smatt printf("rebooting...\n"); 2431.1Smatt cpu_reset(); 2441.1Smatt /*NOTREACHED*/ 2451.1Smatt } 2461.1Smatt 2471.1Smatt /* Disable console buffering */ 2481.1Smatt/* cnpollc(1);*/ 2491.1Smatt 2501.1Smatt /* 2511.1Smatt * If RB_NOSYNC was not specified sync the discs. 2521.1Smatt * Note: Unless cold is set to 1 here, syslogd will die during the unmount. 2531.1Smatt * It looks like syslogd is getting woken up only to find that it cannot 2541.1Smatt * page part of the binary in as the filesystem has been unmounted. 2551.1Smatt */ 2561.1Smatt if (!(howto & RB_NOSYNC)) 2571.1Smatt bootsync(); 2581.1Smatt 2591.1Smatt /* Say NO to interrupts */ 2601.1Smatt splhigh(); 2611.1Smatt 2621.1Smatt /* Do a dump if requested. */ 2631.1Smatt if ((howto & (RB_DUMP | RB_HALT)) == RB_DUMP) 2641.1Smatt dumpsys(); 2651.1Smatt 2661.1Smatt /* Run any shutdown hooks */ 2671.1Smatt doshutdownhooks(); 2681.1Smatt 2691.1Smatt /* Make sure IRQ's are disabled */ 2701.1Smatt IRQdisable; 2711.1Smatt 2721.1Smatt if (howto & RB_HALT) { 2731.1Smatt printf("The operating system has halted.\n"); 2741.1Smatt printf("Please press any key to reboot.\n\n"); 2751.1Smatt cngetc(); 2761.1Smatt } 2771.1Smatt 2781.1Smatt printf("rebooting...\n"); 2791.1Smatt cpu_reset(); 2801.1Smatt /*NOTREACHED*/ 2811.1Smatt} 2821.1Smatt 2831.8Smattstatic void 2841.8Smattnetwinder_reset(void) 2851.8Smatt{ 2861.8Smatt ISA_PUTBYTE(0x370, 0x07); /* Select Logical Dev 7 (GPIO) */ 2871.8Smatt ISA_PUTBYTE(0x371, 0x07); 2881.8Smatt ISA_PUTBYTE(0x370, 0xe6); /* Select GP16 Control Reg */ 2891.8Smatt ISA_PUTBYTE(0x371, 0x00); /* Make GP16 an output */ 2901.8Smatt ISA_PUTBYTE(0x338, 0xc4); /* Set GP17/GP16 & GP12 */ 2911.8Smatt} 2921.8Smatt 2931.1Smatt/* 2941.1Smatt * Mapping table for core kernel memory. This memory is mapped at init 2951.1Smatt * time with section mappings. 2961.1Smatt */ 2971.1Smattstruct l1_sec_map { 2981.1Smatt vm_offset_t va; 2991.1Smatt vm_offset_t pa; 3001.1Smatt vm_size_t size; 3011.16Sthorpej vm_prot_t prot; 3021.16Sthorpej int cache; 3031.1Smatt} l1_sec_table[] = { 3041.1Smatt /* Map 1MB for CSR space */ 3051.1Smatt { DC21285_ARMCSR_VBASE, DC21285_ARMCSR_BASE, 3061.16Sthorpej DC21285_ARMCSR_VSIZE, VM_PROT_READ|VM_PROT_WRITE, 3071.16Sthorpej PTE_NOCACHE }, 3081.16Sthorpej 3091.1Smatt /* Map 1MB for fast cache cleaning space */ 3101.4Schris { DC21285_CACHE_FLUSH_VBASE, DC21285_SA_CACHE_FLUSH_BASE, 3111.16Sthorpej DC21285_CACHE_FLUSH_VSIZE, VM_PROT_READ|VM_PROT_WRITE, 3121.16Sthorpej PTE_CACHE }, 3131.16Sthorpej 3141.1Smatt /* Map 1MB for PCI IO space */ 3151.1Smatt { DC21285_PCI_IO_VBASE, DC21285_PCI_IO_BASE, 3161.16Sthorpej DC21285_PCI_IO_VSIZE, VM_PROT_READ|VM_PROT_WRITE, 3171.16Sthorpej PTE_NOCACHE }, 3181.16Sthorpej 3191.1Smatt /* Map 1MB for PCI IACK space */ 3201.1Smatt { DC21285_PCI_IACK_VBASE, DC21285_PCI_IACK_SPECIAL, 3211.16Sthorpej DC21285_PCI_IACK_VSIZE, VM_PROT_READ|VM_PROT_WRITE, 3221.16Sthorpej PTE_NOCACHE }, 3231.16Sthorpej 3241.1Smatt /* Map 16MB of type 1 PCI config access */ 3251.1Smatt { DC21285_PCI_TYPE_1_CONFIG_VBASE, DC21285_PCI_TYPE_1_CONFIG, 3261.16Sthorpej DC21285_PCI_TYPE_1_CONFIG_VSIZE, VM_PROT_READ|VM_PROT_WRITE, 3271.16Sthorpej PTE_NOCACHE }, 3281.16Sthorpej 3291.1Smatt /* Map 16MB of type 0 PCI config access */ 3301.1Smatt { DC21285_PCI_TYPE_0_CONFIG_VBASE, DC21285_PCI_TYPE_0_CONFIG, 3311.16Sthorpej DC21285_PCI_TYPE_0_CONFIG_VSIZE, VM_PROT_READ|VM_PROT_WRITE, 3321.16Sthorpej PTE_NOCACHE }, 3331.16Sthorpej 3341.1Smatt /* Map 1MB of 32 bit PCI address space for ISA MEM accesses via PCI */ 3351.1Smatt { DC21285_PCI_ISA_MEM_VBASE, DC21285_PCI_MEM_BASE, 3361.16Sthorpej DC21285_PCI_ISA_MEM_VSIZE, VM_PROT_READ|VM_PROT_WRITE, 3371.16Sthorpej PTE_NOCACHE }, 3381.16Sthorpej 3391.16Sthorpej { 0, 0, 0, 0, 0 } 3401.1Smatt}; 3411.1Smatt 3421.1Smatt/* 3431.38Sthorpej * u_int initarm(...); 3441.1Smatt * 3451.1Smatt * Initial entry point on startup. This gets called before main() is 3461.1Smatt * entered. 3471.6Swiz * It should be responsible for setting up everything that must be 3481.1Smatt * in place when main is called. 3491.1Smatt * This includes 3501.1Smatt * Taking a copy of the boot configuration structure. 3511.1Smatt * Initialising the physical console so characters can be printed. 3521.1Smatt * Setting up page tables for the kernel 3531.1Smatt * Relocating the kernel to the bottom of physical memory 3541.1Smatt */ 3551.1Smatt 3561.1Smattu_int 3571.38Sthorpejinitarm(void *arg) 3581.1Smatt{ 3591.1Smatt int loop; 3601.1Smatt int loop1; 3611.1Smatt u_int l1pagetable; 3621.27Sthorpej extern char _end[]; 3631.1Smatt pv_addr_t kernel_l1pt; 3641.1Smatt pv_addr_t kernel_ptpt; 3651.1Smatt 3661.27Sthorpej /* 3671.27Sthorpej * Set up a diagnostic console so we can see what's going 3681.27Sthorpej * on. 3691.27Sthorpej */ 3701.1Smatt cn_tab = &kcomcons; 3711.27Sthorpej 3721.27Sthorpej /* Talk to the user */ 3731.27Sthorpej printf("\nNetBSD/netwinder booting ...\n"); 3741.27Sthorpej 3751.1Smatt /* 3761.1Smatt * Heads up ... Setup the CPU / MMU / TLB functions 3771.1Smatt */ 3781.1Smatt if (set_cpufuncs()) 3791.1Smatt panic("cpu not recognized!"); 3801.1Smatt 3811.27Sthorpej /* 3821.27Sthorpej * We are currently running with the MMU enabled and the 3831.27Sthorpej * entire address space mapped VA==PA, except for the 3841.27Sthorpej * first 64MB of RAM is also double-mapped at 0xf0000000. 3851.27Sthorpej * There is an L1 page table at 0x00008000. 3861.27Sthorpej * 3871.27Sthorpej * We also have the 21285's PCI I/O space mapped where 3881.27Sthorpej * we expect it. 3891.27Sthorpej */ 3901.27Sthorpej 3911.27Sthorpej printf("initarm: Configuring system ...\n"); 3921.27Sthorpej 3931.28Sthorpej /* 3941.28Sthorpej * Copy out the boot info passed by the firmware. Note that 3951.28Sthorpej * early versions of NeTTrom fill this in with bogus values, 3961.28Sthorpej * so we need to sanity check it. 3971.28Sthorpej */ 3981.28Sthorpej memcpy(&nwbootinfo, (caddr_t)(KERNEL_BASE + 0x100), 3991.28Sthorpej sizeof(nwbootinfo)); 4001.28Sthorpej#ifdef VERBOSE_INIT_ARM 4011.28Sthorpej printf("NeTTrom boot info:\n"); 4021.28Sthorpej printf("\tpage size = 0x%08lx\n", nwbootinfo.bi_pagesize); 4031.28Sthorpej printf("\tnpages = %ld (0x%08lx)\n", nwbootinfo.bi_nrpages, 4041.28Sthorpej nwbootinfo.bi_nrpages); 4051.28Sthorpej printf("\trootdev = 0x%08lx\n", nwbootinfo.bi_rootdev); 4061.28Sthorpej printf("\tcmdline = %s\n", nwbootinfo.bi_cmdline); 4071.28Sthorpej#endif 4081.28Sthorpej if (nwbootinfo.bi_nrpages != 0x02000 && 4091.28Sthorpej nwbootinfo.bi_nrpages != 0x04000 && 4101.28Sthorpej nwbootinfo.bi_nrpages != 0x08000 && 4111.28Sthorpej nwbootinfo.bi_nrpages != 0x10000) { 4121.28Sthorpej nwbootinfo.bi_pagesize = 0xdeadbeef; 4131.28Sthorpej nwbootinfo.bi_nrpages = 0x01000; /* 16MB */ 4141.28Sthorpej nwbootinfo.bi_rootdev = 0; 4151.28Sthorpej } 4161.28Sthorpej 4171.1Smatt /* Fake bootconfig structure for the benefit of pmap.c */ 4181.1Smatt /* XXX must make the memory description h/w independant */ 4191.1Smatt bootconfig.dramblocks = 1; 4201.1Smatt bootconfig.dram[0].address = 0; 4211.28Sthorpej bootconfig.dram[0].pages = nwbootinfo.bi_nrpages; 4221.1Smatt 4231.1Smatt /* 4241.27Sthorpej * Set up the variables that define the availablilty of 4251.27Sthorpej * physical memory. 4261.27Sthorpej * 4271.27Sthorpej * Since the NetWinder NeTTrom doesn't load ELF symbols 4281.27Sthorpej * for us, we can safely assume that everything after end[] 4291.27Sthorpej * is free. We start there and allocate upwards. 4301.1Smatt */ 4311.27Sthorpej physical_start = bootconfig.dram[0].address; 4321.27Sthorpej physical_end = physical_start + (bootconfig.dram[0].pages * NBPG); 4331.1Smatt 4341.27Sthorpej physical_freestart = ((((vaddr_t) _end) + PGOFSET) & ~PGOFSET) - 4351.27Sthorpej KERNEL_BASE; 4361.27Sthorpej physical_freeend = physical_end; 4371.27Sthorpej free_pages = (physical_freeend - physical_freestart) / NBPG; 4381.1Smatt 4391.27Sthorpej#ifdef VERBOSE_INIT_ARM 4401.27Sthorpej printf("freestart = 0x%08lx, free_pages = %d (0x%x)\n", 4411.27Sthorpej physical_freestart, free_pages, free_pages); 4421.1Smatt#endif 4431.1Smatt 4441.1Smatt physmem = (physical_end - physical_start) / NBPG; 4451.1Smatt 4461.1Smatt /* Tell the user about the memory */ 4471.1Smatt printf("physmemory: %d pages at 0x%08lx -> 0x%08lx\n", physmem, 4481.1Smatt physical_start, physical_end - 1); 4491.1Smatt 4501.1Smatt /* 4511.27Sthorpej * Okay, we need to allocate some fixed page tables to get the 4521.27Sthorpej * kernel going. We allocate one page directory and a number 4531.27Sthorpej * of page tables and store the physical addresses in the 4541.27Sthorpej * kernel_pt_table array. 4551.1Smatt * 4561.27Sthorpej * The kernel page directory must be on a 16K boundary. The page 4571.27Sthorpej * tables must be on 4K boundaries. What we do is allocate the 4581.27Sthorpej * page directory on the first 16K boundary that we encounter, 4591.27Sthorpej * and the page tables on 4K boundaries otherwise. Since we 4601.27Sthorpej * allocate at least 3 L2 page tables, we are guaranteed to 4611.27Sthorpej * encounter at least one 16K aligned region. 4621.1Smatt */ 4631.1Smatt 4641.1Smatt#ifdef VERBOSE_INIT_ARM 4651.1Smatt printf("Allocating page tables\n"); 4661.1Smatt#endif 4671.1Smatt 4681.1Smatt /* Define a macro to simplify memory allocation */ 4691.1Smatt#define valloc_pages(var, np) \ 4701.1Smatt alloc_pages((var).pv_pa, (np)); \ 4711.1Smatt (var).pv_va = KERNEL_BASE + (var).pv_pa - physical_start; 4721.1Smatt 4731.1Smatt#define alloc_pages(var, np) \ 4741.1Smatt (var) = physical_freestart; \ 4751.1Smatt physical_freestart += ((np) * NBPG); \ 4761.1Smatt free_pages -= (np); \ 4771.1Smatt memset((char *)(var), 0, ((np) * NBPG)); 4781.1Smatt 4791.1Smatt loop1 = 0; 4801.1Smatt kernel_l1pt.pv_pa = 0; 4811.1Smatt for (loop = 0; loop <= NUM_KERNEL_PTS; ++loop) { 4821.1Smatt /* Are we 16KB aligned for an L1 ? */ 4831.30Sthorpej if ((physical_freestart & (L1_TABLE_SIZE - 1)) == 0 4841.1Smatt && kernel_l1pt.pv_pa == 0) { 4851.30Sthorpej valloc_pages(kernel_l1pt, L1_TABLE_SIZE / NBPG); 4861.1Smatt } else { 4871.21Sthorpej alloc_pages(kernel_pt_table[loop1].pv_pa, 4881.30Sthorpej L2_TABLE_SIZE / NBPG); 4891.21Sthorpej kernel_pt_table[loop1].pv_va = 4901.21Sthorpej kernel_pt_table[loop1].pv_pa; 4911.1Smatt ++loop1; 4921.1Smatt } 4931.1Smatt } 4941.1Smatt 4951.1Smatt /* This should never be able to happen but better confirm that. */ 4961.30Sthorpej if (!kernel_l1pt.pv_pa || (kernel_l1pt.pv_pa & (L1_TABLE_SIZE-1)) != 0) 4971.37Sprovos panic("initarm: Failed to align the kernel page directory"); 4981.1Smatt 4991.1Smatt /* 5001.1Smatt * Allocate a page for the system page mapped to V0x00000000 5011.1Smatt * This page will just contain the system vectors and can be 5021.1Smatt * shared by all processes. 5031.1Smatt */ 5041.1Smatt alloc_pages(systempage.pv_pa, 1); 5051.1Smatt 5061.1Smatt /* Allocate a page for the page table to map kernel page tables*/ 5071.30Sthorpej valloc_pages(kernel_ptpt, L2_TABLE_SIZE / NBPG); 5081.1Smatt 5091.1Smatt /* Allocate stacks for all modes */ 5101.1Smatt valloc_pages(irqstack, IRQ_STACK_SIZE); 5111.1Smatt valloc_pages(abtstack, ABT_STACK_SIZE); 5121.1Smatt valloc_pages(undstack, UND_STACK_SIZE); 5131.1Smatt valloc_pages(kernelstack, UPAGES); 5141.1Smatt 5151.1Smatt#ifdef VERBOSE_INIT_ARM 5161.27Sthorpej printf("IRQ stack: p0x%08lx v0x%08lx\n", irqstack.pv_pa, 5171.27Sthorpej irqstack.pv_va); 5181.27Sthorpej printf("ABT stack: p0x%08lx v0x%08lx\n", abtstack.pv_pa, 5191.27Sthorpej abtstack.pv_va); 5201.27Sthorpej printf("UND stack: p0x%08lx v0x%08lx\n", undstack.pv_pa, 5211.27Sthorpej undstack.pv_va); 5221.27Sthorpej printf("SVC stack: p0x%08lx v0x%08lx\n", kernelstack.pv_pa, 5231.27Sthorpej kernelstack.pv_va); 5241.1Smatt#endif 5251.1Smatt 5261.1Smatt alloc_pages(msgbufphys, round_page(MSGBUFSIZE) / NBPG); 5271.1Smatt 5281.1Smatt /* 5291.1Smatt * Ok we have allocated physical pages for the primary kernel 5301.1Smatt * page tables 5311.1Smatt */ 5321.1Smatt 5331.1Smatt#ifdef VERBOSE_INIT_ARM 5341.27Sthorpej printf("Creating L1 page table at 0x%08lx\n", kernel_l1pt.pv_pa); 5351.1Smatt#endif 5361.1Smatt 5371.1Smatt /* 5381.1Smatt * Now we start consturction of the L1 page table 5391.1Smatt * We start by mapping the L2 page tables into the L1. 5401.1Smatt * This means that we can replace L1 mappings later on if necessary 5411.1Smatt */ 5421.1Smatt l1pagetable = kernel_l1pt.pv_pa; 5431.1Smatt 5441.1Smatt /* Map the L2 pages tables in the L1 page table */ 5451.18Sthorpej pmap_link_l2pt(l1pagetable, 0x00000000, 5461.21Sthorpej &kernel_pt_table[KERNEL_PT_SYS]); 5471.18Sthorpej pmap_link_l2pt(l1pagetable, KERNEL_BASE, 5481.21Sthorpej &kernel_pt_table[KERNEL_PT_KERNEL]); 5491.1Smatt for (loop = 0; loop < KERNEL_PT_VMDATA_NUM; ++loop) 5501.18Sthorpej pmap_link_l2pt(l1pagetable, KERNEL_VM_BASE + loop * 0x00400000, 5511.21Sthorpej &kernel_pt_table[KERNEL_PT_VMDATA + loop]); 5521.27Sthorpej pmap_link_l2pt(l1pagetable, PTE_BASE, &kernel_ptpt); 5531.24Schris 5541.24Schris /* update the top of the kernel VM */ 5551.26Sthorpej pmap_curmaxkvaddr = 5561.26Sthorpej KERNEL_VM_BASE + (KERNEL_PT_VMDATA_NUM * 0x00400000); 5571.1Smatt 5581.1Smatt#ifdef VERBOSE_INIT_ARM 5591.1Smatt printf("Mapping kernel\n"); 5601.1Smatt#endif 5611.1Smatt 5621.1Smatt /* Now we fill in the L2 pagetable for the kernel static code/data */ 5631.27Sthorpej { 5641.27Sthorpej /* 5651.27Sthorpej * The kernel starts in the first 1MB of RAM, and we'd 5661.27Sthorpej * like to use a section mapping for text, so we'll just 5671.27Sthorpej * map from KERNEL_BASE to etext[] to _end[]. 5681.27Sthorpej */ 5691.1Smatt 5701.27Sthorpej extern char etext[]; 5711.27Sthorpej size_t textsize = (uintptr_t) etext - KERNEL_BASE; 5721.27Sthorpej size_t totalsize = (uintptr_t) _end - KERNEL_BASE; 5731.2Smatt u_int logical; 5741.7Smatt 5751.27Sthorpej textsize = (textsize + PGOFSET) & ~PGOFSET; 5761.27Sthorpej totalsize = (totalsize + PGOFSET) & ~PGOFSET; 5771.27Sthorpej 5781.7Smatt textsize = textsize & ~PGOFSET; 5791.7Smatt totalsize = (totalsize + PGOFSET) & ~PGOFSET; 5801.27Sthorpej 5811.27Sthorpej logical = 0; /* offset into RAM */ 5821.27Sthorpej 5831.27Sthorpej logical += pmap_map_chunk(l1pagetable, KERNEL_BASE + logical, 5841.27Sthorpej physical_start + logical, textsize, 5851.19Sthorpej VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); 5861.27Sthorpej logical += pmap_map_chunk(l1pagetable, KERNEL_BASE + logical, 5871.27Sthorpej physical_start + logical, totalsize - textsize, 5881.19Sthorpej VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); 5891.7Smatt } 5901.1Smatt 5911.1Smatt#ifdef VERBOSE_INIT_ARM 5921.1Smatt printf("Constructing L2 page tables\n"); 5931.1Smatt#endif 5941.1Smatt 5951.1Smatt /* Map the stack pages */ 5961.21Sthorpej pmap_map_chunk(l1pagetable, irqstack.pv_va, irqstack.pv_pa, 5971.21Sthorpej IRQ_STACK_SIZE * NBPG, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); 5981.21Sthorpej pmap_map_chunk(l1pagetable, abtstack.pv_va, abtstack.pv_pa, 5991.21Sthorpej ABT_STACK_SIZE * NBPG, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); 6001.21Sthorpej pmap_map_chunk(l1pagetable, undstack.pv_va, undstack.pv_pa, 6011.21Sthorpej UND_STACK_SIZE * NBPG, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); 6021.21Sthorpej pmap_map_chunk(l1pagetable, kernelstack.pv_va, kernelstack.pv_pa, 6031.21Sthorpej UPAGES * NBPG, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); 6041.19Sthorpej 6051.21Sthorpej pmap_map_chunk(l1pagetable, kernel_l1pt.pv_va, kernel_l1pt.pv_pa, 6061.35Sthorpej L1_TABLE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); 6071.1Smatt 6081.1Smatt /* Map the page table that maps the kernel pages */ 6091.23Sthorpej pmap_map_entry(l1pagetable, kernel_ptpt.pv_va, kernel_ptpt.pv_pa, 6101.17Sthorpej VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE); 6111.1Smatt 6121.1Smatt /* 6131.1Smatt * Map entries in the page table used to map PTE's 6141.1Smatt * Basically every kernel page table gets mapped here 6151.1Smatt */ 6161.1Smatt /* The -2 is slightly bogus, it should be -log2(sizeof(pt_entry_t)) */ 6171.22Sthorpej pmap_map_entry(l1pagetable, 6181.25Sthorpej PTE_BASE + (KERNEL_BASE >> (PGSHIFT-2)), 6191.21Sthorpej kernel_pt_table[KERNEL_PT_KERNEL].pv_pa, 6201.36Sthorpej VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); 6211.22Sthorpej pmap_map_entry(l1pagetable, 6221.25Sthorpej PTE_BASE + (PTE_BASE >> (PGSHIFT-2)), 6231.17Sthorpej kernel_ptpt.pv_pa, 6241.17Sthorpej VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE); 6251.22Sthorpej pmap_map_entry(l1pagetable, 6261.25Sthorpej PTE_BASE + (0x00000000 >> (PGSHIFT-2)), 6271.21Sthorpej kernel_pt_table[KERNEL_PT_SYS].pv_pa, 6281.36Sthorpej VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); 6291.1Smatt for (loop = 0; loop < KERNEL_PT_VMDATA_NUM; ++loop) 6301.22Sthorpej pmap_map_entry(l1pagetable, 6311.25Sthorpej PTE_BASE + ((KERNEL_VM_BASE + 6321.1Smatt (loop * 0x00400000)) >> (PGSHIFT-2)), 6331.21Sthorpej kernel_pt_table[KERNEL_PT_VMDATA + loop].pv_pa, 6341.36Sthorpej VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); 6351.1Smatt 6361.29Sthorpej /* Map the vector page. */ 6371.29Sthorpej pmap_map_entry(l1pagetable, vector_page, systempage.pv_pa, 6381.17Sthorpej VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); 6391.1Smatt 6401.27Sthorpej /* 6411.27Sthorpej * Map devices we can map w/ section mappings. 6421.27Sthorpej */ 6431.1Smatt loop = 0; 6441.1Smatt while (l1_sec_table[loop].size) { 6451.1Smatt vm_size_t sz; 6461.1Smatt 6471.1Smatt#ifdef VERBOSE_INIT_ARM 6481.1Smatt printf("%08lx -> %08lx @ %08lx\n", l1_sec_table[loop].pa, 6491.1Smatt l1_sec_table[loop].pa + l1_sec_table[loop].size - 1, 6501.1Smatt l1_sec_table[loop].va); 6511.1Smatt#endif 6521.30Sthorpej for (sz = 0; sz < l1_sec_table[loop].size; sz += L1_S_SIZE) 6531.16Sthorpej pmap_map_section(l1pagetable, 6541.16Sthorpej l1_sec_table[loop].va + sz, 6551.1Smatt l1_sec_table[loop].pa + sz, 6561.16Sthorpej l1_sec_table[loop].prot, 6571.16Sthorpej l1_sec_table[loop].cache); 6581.1Smatt ++loop; 6591.1Smatt } 6601.1Smatt 6611.1Smatt /* 6621.1Smatt * Now we have the real page tables in place so we can switch to them. 6631.27Sthorpej * Once this is done we will be running with the REAL kernel page 6641.27Sthorpej * tables. 6651.1Smatt */ 6661.1Smatt 6671.1Smatt /* Switch tables */ 6681.1Smatt#ifdef VERBOSE_INIT_ARM 6691.27Sthorpej printf("freestart = 0x%08lx, free_pages = %d (0x%x)\n", 6701.1Smatt physical_freestart, free_pages, free_pages); 6711.1Smatt printf("switching to new L1 page table @%#lx...", kernel_l1pt.pv_pa); 6721.1Smatt#endif 6731.1Smatt 6741.1Smatt setttb(kernel_l1pt.pv_pa); 6751.1Smatt 6761.1Smatt#ifdef VERBOSE_INIT_ARM 6771.1Smatt printf("done!\n"); 6781.1Smatt#endif 6791.1Smatt 6801.1Smatt /* 6811.1Smatt * XXX this should only be done in main() but it useful to 6821.1Smatt * have output earlier ... 6831.1Smatt */ 6841.1Smatt consinit(); 6851.1Smatt 6861.1Smatt#ifdef VERBOSE_INIT_ARM 6871.1Smatt printf("bootstrap done.\n"); 6881.1Smatt#endif 6891.1Smatt 6901.29Sthorpej arm32_vector_init(ARM_VECTORS_LOW, ARM_VEC_ALL); 6911.1Smatt 6921.1Smatt /* 6931.1Smatt * Pages were allocated during the secondary bootstrap for the 6941.1Smatt * stacks for different CPU modes. 6951.1Smatt * We must now set the r13 registers in the different CPU modes to 6961.1Smatt * point to these stacks. 6971.1Smatt * Since the ARM stacks use STMFD etc. we must set r13 to the top end 6981.1Smatt * of the stack memory. 6991.1Smatt */ 7001.1Smatt printf("init subsystems: stacks "); 7011.1Smatt 7021.1Smatt set_stackptr(PSR_IRQ32_MODE, irqstack.pv_va + IRQ_STACK_SIZE * NBPG); 7031.1Smatt set_stackptr(PSR_ABT32_MODE, abtstack.pv_va + ABT_STACK_SIZE * NBPG); 7041.1Smatt set_stackptr(PSR_UND32_MODE, undstack.pv_va + UND_STACK_SIZE * NBPG); 7051.1Smatt 7061.1Smatt /* 7071.1Smatt * Well we should set a data abort handler. 7081.27Sthorpej * Once things get going this will change as we will need a proper 7091.27Sthorpej * handler. 7101.1Smatt * Until then we will use a handler that just panics but tells us 7111.1Smatt * why. 7121.1Smatt * Initialisation of the vectors will just panic on a data abort. 7131.1Smatt * This just fills in a slighly better one. 7141.1Smatt */ 7151.1Smatt printf("vectors "); 7161.1Smatt data_abort_handler_address = (u_int)data_abort_handler; 7171.1Smatt prefetch_abort_handler_address = (u_int)prefetch_abort_handler; 7181.1Smatt undefined_handler_address = (u_int)undefinedinstruction_bounce; 7191.1Smatt 7201.1Smatt /* Initialise the undefined instruction handlers */ 7211.1Smatt printf("undefined "); 7221.1Smatt undefined_init(); 7231.1Smatt 7241.33Sthorpej /* Load memory into UVM. */ 7251.33Sthorpej printf("page "); 7261.33Sthorpej uvm_setpagesize(); /* initialize PAGE_SIZE-dependent variables */ 7271.33Sthorpej 7281.33Sthorpej /* XXX Always one RAM block -- nuke the loop. */ 7291.33Sthorpej for (loop = 0; loop < bootconfig.dramblocks; loop++) { 7301.33Sthorpej paddr_t start = (paddr_t)bootconfig.dram[loop].address; 7311.33Sthorpej paddr_t end = start + (bootconfig.dram[loop].pages * NBPG); 7321.33Sthorpej#if NISADMA > 0 7331.33Sthorpej paddr_t istart, isize; 7341.34Sthorpej extern struct arm32_dma_range *footbridge_isa_dma_ranges; 7351.34Sthorpej extern int footbridge_isa_dma_nranges; 7361.33Sthorpej#endif 7371.33Sthorpej 7381.33Sthorpej if (start < physical_freestart) 7391.33Sthorpej start = physical_freestart; 7401.33Sthorpej if (end > physical_freeend) 7411.33Sthorpej end = physical_freeend; 7421.33Sthorpej 7431.33Sthorpej#if 0 7441.33Sthorpej printf("%d: %lx -> %lx\n", loop, start, end - 1); 7451.33Sthorpej#endif 7461.33Sthorpej 7471.33Sthorpej#if NISADMA > 0 7481.34Sthorpej if (arm32_dma_range_intersect(footbridge_isa_dma_ranges, 7491.34Sthorpej footbridge_isa_dma_nranges, 7501.34Sthorpej start, end - start, 7511.34Sthorpej &istart, &isize)) { 7521.33Sthorpej /* 7531.33Sthorpej * Place the pages that intersect with the 7541.33Sthorpej * ISA DMA range onto the ISA DMA free list. 7551.33Sthorpej */ 7561.33Sthorpej#if 0 7571.33Sthorpej printf(" ISADMA 0x%lx -> 0x%lx\n", istart, 7581.33Sthorpej istart + isize - 1); 7591.33Sthorpej#endif 7601.33Sthorpej uvm_page_physload(atop(istart), 7611.33Sthorpej atop(istart + isize), atop(istart), 7621.33Sthorpej atop(istart + isize), VM_FREELIST_ISADMA); 7631.33Sthorpej 7641.33Sthorpej /* 7651.33Sthorpej * Load the pieces that come before the 7661.33Sthorpej * intersection onto the default free list. 7671.33Sthorpej */ 7681.33Sthorpej if (start < istart) { 7691.33Sthorpej#if 0 7701.33Sthorpej printf(" BEFORE 0x%lx -> 0x%lx\n", 7711.33Sthorpej start, istart - 1); 7721.33Sthorpej#endif 7731.33Sthorpej uvm_page_physload(atop(start), 7741.33Sthorpej atop(istart), atop(start), 7751.33Sthorpej atop(istart), VM_FREELIST_DEFAULT); 7761.33Sthorpej } 7771.33Sthorpej 7781.33Sthorpej /* 7791.33Sthorpej * Load the pieces that come after the 7801.33Sthorpej * intersection onto the default free list. 7811.33Sthorpej */ 7821.33Sthorpej if ((istart + isize) < end) { 7831.33Sthorpej#if 0 7841.33Sthorpej printf(" AFTER 0x%lx -> 0x%lx\n", 7851.33Sthorpej (istart + isize), end - 1); 7861.33Sthorpej#endif 7871.33Sthorpej uvm_page_physload(atop(istart + isize), 7881.33Sthorpej atop(end), atop(istart + isize), 7891.33Sthorpej atop(end), VM_FREELIST_DEFAULT); 7901.33Sthorpej } 7911.33Sthorpej } else { 7921.33Sthorpej uvm_page_physload(atop(start), atop(end), 7931.33Sthorpej atop(start), atop(end), VM_FREELIST_DEFAULT); 7941.33Sthorpej } 7951.33Sthorpej#else /* NISADMA > 0 */ 7961.33Sthorpej uvm_page_physload(atop(start), atop(end), 7971.33Sthorpej atop(start), atop(end), VM_FREELIST_DEFAULT); 7981.33Sthorpej#endif /* NISADMA > 0 */ 7991.33Sthorpej } 8001.33Sthorpej 8011.1Smatt /* Boot strap pmap telling it where the kernel page table is */ 8021.1Smatt printf("pmap "); 8031.1Smatt pmap_bootstrap((pd_entry_t *)kernel_l1pt.pv_va, kernel_ptpt); 8041.1Smatt 8051.1Smatt /* Setup the IRQ system */ 8061.1Smatt printf("irq "); 8071.41Schris footbridge_intr_init(); 8081.1Smatt printf("done.\n"); 8091.28Sthorpej 8101.28Sthorpej /* 8111.28Sthorpej * Warn the user if the bootinfo was bogus. We already 8121.28Sthorpej * faked up some safe values. 8131.28Sthorpej */ 8141.28Sthorpej if (nwbootinfo.bi_pagesize == 0xdeadbeef) 8151.28Sthorpej printf("WARNING: NeTTrom boot info corrupt\n"); 8161.1Smatt 8171.1Smatt#ifdef IPKDB 8181.1Smatt /* Initialise ipkdb */ 8191.1Smatt ipkdb_init(); 8201.1Smatt if (boothowto & RB_KDB) 8211.1Smatt ipkdb_connect(0); 8221.1Smatt#endif 8231.1Smatt 8241.1Smatt#ifdef DDB 8251.1Smatt db_machine_init(); 8261.12Sthorpej 8271.12Sthorpej /* Firmware doesn't load symbols. */ 8281.12Sthorpej ddb_init(0, NULL, NULL); 8291.1Smatt 8301.1Smatt if (boothowto & RB_KDB) 8311.1Smatt Debugger(); 8321.1Smatt#endif 8331.1Smatt 8341.1Smatt /* We return the new stack pointer address */ 8351.1Smatt return(kernelstack.pv_va + USPACE_SVC_STACK_TOP); 8361.1Smatt} 8371.1Smatt 8381.1Smattvoid 8391.1Smattprocess_kernel_args(args) 8401.1Smatt char *args; 8411.1Smatt{ 8421.1Smatt 8431.1Smatt boothowto = 0; 8441.1Smatt 8451.1Smatt /* Make a local copy of the bootargs */ 8461.1Smatt strncpy(bootargs, args, MAX_BOOT_STRING); 8471.1Smatt 8481.1Smatt args = bootargs; 8491.1Smatt boot_file = bootargs; 8501.1Smatt 8511.1Smatt /* Skip the kernel image filename */ 8521.1Smatt while (*args != ' ' && *args != 0) 8531.1Smatt ++args; 8541.1Smatt 8551.1Smatt if (*args != 0) 8561.1Smatt *args++ = 0; 8571.1Smatt 8581.1Smatt while (*args == ' ') 8591.1Smatt ++args; 8601.1Smatt 8611.1Smatt boot_args = args; 8621.1Smatt 8631.1Smatt printf("bootfile: %s\n", boot_file); 8641.1Smatt printf("bootargs: %s\n", boot_args); 8651.1Smatt 8661.1Smatt parse_mi_bootargs(boot_args); 8671.1Smatt} 8681.1Smatt 8691.1Smattextern struct bus_space footbridge_pci_io_bs_tag; 8701.1Smattextern struct bus_space footbridge_pci_mem_bs_tag; 8711.1Smattvoid footbridge_pci_bs_tag_init __P((void)); 8721.1Smatt 8731.1Smattvoid 8741.1Smattconsinit(void) 8751.1Smatt{ 8761.1Smatt static int consinit_called = 0; 8771.1Smatt char *console = CONSDEVNAME; 8781.1Smatt 8791.1Smatt if (consinit_called != 0) 8801.1Smatt return; 8811.1Smatt 8821.1Smatt consinit_called = 1; 8831.1Smatt 8841.1Smatt#if NISA > 0 8851.1Smatt /* Initialise the ISA subsystem early ... */ 8861.40Schris isa_footbridge_init(DC21285_PCI_IO_VBASE, DC21285_PCI_ISA_MEM_VBASE); 8871.1Smatt#endif 8881.1Smatt 8891.1Smatt footbridge_pci_bs_tag_init(); 8901.1Smatt 8911.1Smatt if (strncmp(console, "vga", 3) == 0) { 8921.1Smatt#if (NVGA > 0) 8931.1Smatt vga_cnattach(&footbridge_pci_io_bs_tag, 8941.1Smatt &footbridge_pci_mem_bs_tag, - 1, 0); 8951.1Smatt#if (NPCKBC > 0) 8961.1Smatt pckbc_cnattach(&isa_io_bs_tag, IO_KBD, KBCMDP, PCKBC_KBD_SLOT); 8971.1Smatt#endif /* NPCKBC */ 8981.1Smatt#else 8991.1Smatt panic("vga console not configured"); 9001.1Smatt#endif /* NVGA */ 9011.1Smatt } else { 9021.1Smatt#if (NCOM > 0) 9031.1Smatt if (comcnattach(&isa_io_bs_tag, CONCOMADDR, comcnspeed, 9041.1Smatt COM_FREQ, comcnmode)) 9051.1Smatt panic("can't init serial console @%x", CONCOMADDR); 9061.1Smatt#else 9071.1Smatt panic("serial console @%x not configured", CONCOMADDR); 9081.1Smatt#endif 9091.1Smatt } 9101.1Smatt} 9111.1Smatt 9121.1Smattstatic bus_space_handle_t kcom_base = (bus_space_handle_t) (DC21285_PCI_IO_VBASE + CONCOMADDR); 9131.1Smatt 9141.31Sthorpej#define KCOM_GETBYTE(r) generic_bs_r_1(0, kcom_base, (r)) 9151.31Sthorpej#define KCOM_PUTBYTE(r,v) generic_bs_w_1(0, kcom_base, (r), (v)) 9161.1Smatt 9171.1Smattstatic int 9181.1Smattkcomcngetc(dev_t dev) 9191.1Smatt{ 9201.1Smatt int stat, c; 9211.1Smatt 9221.1Smatt /* block until a character becomes available */ 9231.1Smatt while (!ISSET(stat = KCOM_GETBYTE(com_lsr), LSR_RXRDY)) 9241.1Smatt ; 9251.1Smatt 9261.1Smatt c = KCOM_GETBYTE(com_data); 9271.1Smatt stat = KCOM_GETBYTE(com_iir); 9281.1Smatt return c; 9291.1Smatt} 9301.1Smatt 9311.1Smatt/* 9321.1Smatt * Console kernel output character routine. 9331.1Smatt */ 9341.1Smattstatic void 9351.1Smattkcomcnputc(dev_t dev, int c) 9361.1Smatt{ 9371.1Smatt int timo; 9381.1Smatt 9391.1Smatt /* wait for any pending transmission to finish */ 9401.1Smatt timo = 150000; 9411.1Smatt while (!ISSET(KCOM_GETBYTE(com_lsr), LSR_TXRDY) && --timo) 9421.1Smatt continue; 9431.1Smatt 9441.1Smatt KCOM_PUTBYTE(com_data, c); 9451.1Smatt 9461.1Smatt /* wait for this transmission to complete */ 9471.1Smatt timo = 1500000; 9481.1Smatt while (!ISSET(KCOM_GETBYTE(com_lsr), LSR_TXRDY) && --timo) 9491.1Smatt continue; 9501.1Smatt} 9511.1Smatt 9521.1Smattstatic void 9531.1Smattkcomcnpollc(dev_t dev, int on) 9541.1Smatt{ 9551.1Smatt} 9561.1Smatt 9571.1Smattstruct consdev kcomcons = { 9581.1Smatt NULL, NULL, kcomcngetc, kcomcnputc, kcomcnpollc, NULL, 9591.1Smatt NODEV, CN_NORMAL 9601.1Smatt}; 961