netwinder_machdep.c revision 1.66
11.66Smatt/* $NetBSD: netwinder_machdep.c,v 1.66 2008/04/27 18:58:47 matt 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.56Slukem 421.56Slukem#include <sys/cdefs.h> 431.66Smatt__KERNEL_RCSID(0, "$NetBSD: netwinder_machdep.c,v 1.66 2008/04/27 18:58:47 matt Exp $"); 441.1Smatt 451.1Smatt#include "opt_ddb.h" 461.1Smatt#include "opt_pmap_debug.h" 471.1Smatt 481.1Smatt#include <sys/param.h> 491.1Smatt#include <sys/device.h> 501.1Smatt#include <sys/systm.h> 511.1Smatt#include <sys/kernel.h> 521.1Smatt#include <sys/exec.h> 531.1Smatt#include <sys/proc.h> 541.1Smatt#include <sys/msgbuf.h> 551.1Smatt#include <sys/reboot.h> 561.1Smatt#include <sys/termios.h> 571.46Sragge#include <sys/ksyms.h> 581.1Smatt 591.44Sthorpej#include <uvm/uvm_extern.h> 601.44Sthorpej 611.1Smatt#include <dev/cons.h> 621.1Smatt 631.1Smatt#include <machine/db_machdep.h> 641.1Smatt#include <ddb/db_sym.h> 651.1Smatt#include <ddb/db_extern.h> 661.1Smatt 671.38Sthorpej#include <arm/arm32/machdep.h> 681.38Sthorpej 691.1Smatt#include <machine/bootconfig.h> 701.34Sthorpej#define _ARM32_BUS_DMA_PRIVATE 711.1Smatt#include <machine/bus.h> 721.1Smatt#include <machine/cpu.h> 731.1Smatt#include <machine/frame.h> 741.9Smatt#include <machine/intr.h> 751.14Sthorpej#include <arm/undefined.h> 761.1Smatt 771.1Smatt#include <machine/netwinder_boot.h> 781.3Schris#include <arm/footbridge/dc21285mem.h> 791.3Schris#include <arm/footbridge/dc21285reg.h> 801.1Smatt 811.1Smatt#include "isa.h" 821.55Suwe#include "isadma.h" 831.1Smatt#if NISA > 0 841.1Smatt#include <dev/isa/isareg.h> 851.1Smatt#include <dev/isa/isavar.h> 861.1Smatt#endif 871.1Smatt 881.55Suwe#include "igsfb.h" 891.55Suwe#if NIGSFB > 0 901.55Suwe#include <dev/pci/pcivar.h> 911.55Suwe#include <dev/pci/igsfb_pcivar.h> 921.55Suwe#endif 931.55Suwe 941.55Suwe#include "pckbc.h" 951.55Suwe#if NPCKBC > 0 961.55Suwe#include <dev/ic/i8042reg.h> 971.55Suwe#include <dev/ic/pckbcvar.h> 981.55Suwe#endif 991.55Suwe 1001.55Suwe#include "com.h" 1011.55Suwe#include <dev/ic/comreg.h> 1021.55Suwe#include <dev/ic/comvar.h> 1031.55Suwe 1041.46Sragge#include "ksyms.h" 1051.46Sragge 1061.8Smattstatic bus_space_handle_t isa_base = (bus_space_handle_t) DC21285_PCI_IO_VBASE; 1071.8Smatt 1081.31Sthorpejbs_protos(generic); 1091.8Smatt 1101.31Sthorpej#define ISA_GETBYTE(r) generic_bs_r_1(0, isa_base, (r)) 1111.31Sthorpej#define ISA_PUTBYTE(r,v) generic_bs_w_1(0, isa_base, (r), (v)) 1121.8Smatt 1131.1Smatt/* 1141.1Smatt * Address to call from cpu_reset() to reset the machine. 1151.1Smatt * This is machine architecture dependant as it varies depending 1161.1Smatt * on where the ROM appears when you turn the MMU off. 1171.1Smatt */ 1181.27Sthorpejstatic void netwinder_reset(void); 1191.52Suweu_int cpu_reset_address; 1201.1Smatt 1211.8Smattu_int dc21285_fclk = 63750000; 1221.1Smatt 1231.1Smatt/* Define various stack sizes in pages */ 1241.1Smatt#define IRQ_STACK_SIZE 1 1251.1Smatt#define ABT_STACK_SIZE 1 1261.1Smatt#define UND_STACK_SIZE 1 1271.1Smatt 1281.1Smattstruct nwbootinfo nwbootinfo; 1291.1SmattBootConfig bootconfig; /* Boot config storage */ 1301.1Smattstatic char bootargs[MAX_BOOT_STRING + 1]; 1311.1Smattchar *boot_args = NULL; 1321.1Smattchar *boot_file = NULL; 1331.1Smatt 1341.1Smattvm_offset_t physical_start; 1351.1Smattvm_offset_t physical_freestart; 1361.1Smattvm_offset_t physical_freeend; 1371.1Smattvm_offset_t physical_end; 1381.1Smattu_int free_pages; 1391.1Smattvm_offset_t pagetables_start; 1401.1Smattint physmem = 0; 1411.1Smatt 1421.1Smatt/*int debug_flags;*/ 1431.1Smatt#ifndef PMAP_STATIC_L1S 1441.1Smattint max_processes = 64; /* Default number */ 1451.1Smatt#endif /* !PMAP_STATIC_L1S */ 1461.1Smatt 1471.1Smatt/* Physical and virtual addresses for some global pages */ 1481.1Smattpv_addr_t irqstack; 1491.1Smattpv_addr_t undstack; 1501.1Smattpv_addr_t abtstack; 1511.61Suweextern pv_addr_t kernelstack; /* in arm32_machdep.c */ 1521.1Smatt 1531.1Smattvm_offset_t msgbufphys; 1541.1Smatt 1551.1Smattextern u_int data_abort_handler_address; 1561.1Smattextern u_int prefetch_abort_handler_address; 1571.1Smattextern u_int undefined_handler_address; 1581.1Smatt 1591.1Smatt#ifdef PMAP_DEBUG 1601.1Smattextern int pmap_debug_level; 1611.1Smatt#endif 1621.1Smatt 1631.1Smatt#define KERNEL_PT_SYS 0 /* Page table for mapping proc0 zero page */ 1641.1Smatt#define KERNEL_PT_KERNEL 1 /* Page table for mapping kernel */ 1651.1Smatt#define KERNEL_PT_VMDATA 2 /* Page tables for mapping kernel VM */ 1661.24Schris#define KERNEL_PT_VMDATA_NUM 4 /* start with 16MB of KVM */ 1671.1Smatt#define NUM_KERNEL_PTS (KERNEL_PT_VMDATA + KERNEL_PT_VMDATA_NUM) 1681.1Smatt 1691.21Sthorpejpv_addr_t kernel_pt_table[NUM_KERNEL_PTS]; 1701.50Sthorpej 1711.50Sthorpej#define KERNEL_VM_BASE (KERNEL_BASE + 0x01000000) 1721.51Sthorpej/* 1731.51Sthorpej * The range 0xf1000000 - 0xfcffffff is available for kernel VM space 1741.51Sthorpej * Footbridge registers and I/O mappings occupy 0xfd000000 - 0xffffffff 1751.51Sthorpej */ 1761.55Suwe#if NIGSFB > 0 1771.55Suwe/* XXX: uwe: map 16 megs at 0xfc000000 for igsfb(4) */ 1781.55Suwe#define KERNEL_VM_SIZE 0x0B000000 1791.55Suwe#else 1801.51Sthorpej#define KERNEL_VM_SIZE 0x0C000000 1811.55Suwe#endif 1821.1Smatt 1831.61Suweextern struct user *proc0paddr; /* in arm32_machdep.c */ 1841.1Smatt 1851.1Smatt/* Prototypes */ 1861.1Smatt 1871.53Suwevoid consinit(void); 1881.53Suwevoid process_kernel_args(char *); 1891.53Suwevoid data_abort_handler(trapframe_t *); 1901.53Suwevoid prefetch_abort_handler(trapframe_t *); 1911.53Suwevoid undefinedinstruction_bounce(trapframe_t *); 1921.1Smatt 1931.1Smatt 1941.1Smatt/* A load of console goo. */ 1951.55Suwe#ifndef CONSDEVNAME 1961.55Suwe# if (NIGSFB > 0) && (NPCKBC > 0) 1971.55Suwe# define CONSDEVNAME "igsfb" 1981.55Suwe# elif NCOM > 0 1991.55Suwe# define CONSDEVNAME "com" 2001.55Suwe# else 2011.55Suwe# error CONSDEVNAME not defined and no known console device configured 2021.55Suwe# endif 2031.55Suwe#endif /* !CONSDEVNAME */ 2041.1Smatt 2051.1Smatt#ifndef CONCOMADDR 2061.1Smatt#define CONCOMADDR 0x3f8 2071.1Smatt#endif 2081.1Smatt 2091.55Suwe#ifndef CONSPEED 2101.55Suwe#define CONSPEED B115200 /* match NeTTrom */ 2111.1Smatt#endif 2121.1Smatt 2131.1Smatt#ifndef CONMODE 2141.1Smatt#define CONMODE ((TTYDEF_CFLAG & ~(CSIZE | CSTOPB | PARENB)) | CS8) /* 8N1 */ 2151.1Smatt#endif 2161.1Smatt 2171.1Smattint comcnspeed = CONSPEED; 2181.1Smattint comcnmode = CONMODE; 2191.1Smatt 2201.1Smattextern struct consdev kcomcons; 2211.1Smattstatic void kcomcnputc(dev_t, int); 2221.1Smatt 2231.55Suwe#if NIGSFB > 0 2241.55Suwe/* XXX: uwe */ 2251.55Suwe#define IGS_PCI_MEM_VBASE 0xfc000000 2261.55Suwe#define IGS_PCI_MEM_VSIZE 0x01000000 2271.55Suwe#define IGS_PCI_MEM_BASE 0x08000000 2281.55Suwe 2291.55Suweextern struct arm32_pci_chipset footbridge_pci_chipset; 2301.55Suweextern struct bus_space footbridge_pci_io_bs_tag; 2311.55Suweextern struct bus_space footbridge_pci_mem_bs_tag; 2321.55Suweextern void footbridge_pci_bs_tag_init(void); 2331.55Suwe 2341.55Suwe/* standard methods */ 2351.55Suweextern bs_map_proto(footbridge_mem); 2361.55Suweextern bs_unmap_proto(footbridge_mem); 2371.55Suwe 2381.55Suwe/* our hooks */ 2391.55Suwestatic bs_map_proto(nw_footbridge_mem); 2401.55Suwestatic bs_unmap_proto(nw_footbridge_mem); 2411.55Suwe#endif 2421.55Suwe 2431.55Suwe 2441.1Smatt/* 2451.1Smatt * void cpu_reboot(int howto, char *bootstr) 2461.1Smatt * 2471.1Smatt * Reboots the system 2481.1Smatt * 2491.1Smatt * Deal with any syncing, unmounting, dumping and shutdown hooks, 2501.1Smatt * then reset the CPU. 2511.1Smatt */ 2521.1Smatt 2531.1Smattvoid 2541.53Suwecpu_reboot(int howto, char *bootstr) 2551.1Smatt{ 2561.1Smatt#ifdef DIAGNOSTIC 2571.1Smatt /* info */ 2581.42Sthorpej printf("boot: howto=%08x curlwp=%p\n", howto, curlwp); 2591.1Smatt#endif 2601.1Smatt 2611.1Smatt /* 2621.1Smatt * If we are still cold then hit the air brakes 2631.1Smatt * and crash to earth fast 2641.1Smatt */ 2651.1Smatt if (cold) { 2661.1Smatt doshutdownhooks(); 2671.1Smatt printf("The operating system has halted.\n"); 2681.1Smatt printf("Please press any key to reboot.\n\n"); 2691.1Smatt cngetc(); 2701.1Smatt printf("rebooting...\n"); 2711.1Smatt cpu_reset(); 2721.1Smatt /*NOTREACHED*/ 2731.1Smatt } 2741.1Smatt 2751.1Smatt /* Disable console buffering */ 2761.1Smatt/* cnpollc(1);*/ 2771.1Smatt 2781.1Smatt /* 2791.1Smatt * If RB_NOSYNC was not specified sync the discs. 2801.53Suwe * Note: Unless cold is set to 1 here, syslogd will die during 2811.53Suwe * the unmount. It looks like syslogd is getting woken up 2821.53Suwe * only to find that it cannot page part of the binary in as 2831.53Suwe * the filesystem has been unmounted. 2841.1Smatt */ 2851.1Smatt if (!(howto & RB_NOSYNC)) 2861.1Smatt bootsync(); 2871.1Smatt 2881.1Smatt /* Say NO to interrupts */ 2891.1Smatt splhigh(); 2901.1Smatt 2911.1Smatt /* Do a dump if requested. */ 2921.1Smatt if ((howto & (RB_DUMP | RB_HALT)) == RB_DUMP) 2931.1Smatt dumpsys(); 2941.1Smatt 2951.1Smatt /* Run any shutdown hooks */ 2961.1Smatt doshutdownhooks(); 2971.1Smatt 2981.1Smatt /* Make sure IRQ's are disabled */ 2991.1Smatt IRQdisable; 3001.1Smatt 3011.1Smatt if (howto & RB_HALT) { 3021.1Smatt printf("The operating system has halted.\n"); 3031.1Smatt printf("Please press any key to reboot.\n\n"); 3041.1Smatt cngetc(); 3051.1Smatt } 3061.1Smatt 3071.1Smatt printf("rebooting...\n"); 3081.1Smatt cpu_reset(); 3091.1Smatt /*NOTREACHED*/ 3101.1Smatt} 3111.1Smatt 3121.52Suwe/* 3131.52Suwe * NB: this function runs with MMU disabled! 3141.52Suwe */ 3151.8Smattstatic void 3161.8Smattnetwinder_reset(void) 3171.8Smatt{ 3181.52Suwe register u_int base = DC21285_PCI_IO_BASE; 3191.52Suwe 3201.52Suwe#define PUTBYTE(reg, val) \ 3211.52Suwe *((volatile u_int8_t *)(base + (reg))) = (val) 3221.52Suwe 3231.52Suwe PUTBYTE(0x338, 0x84); /* Red led(GP17), fan on(GP12) */ 3241.52Suwe PUTBYTE(0x370, 0x87); /* Enter the extended function mode */ 3251.52Suwe PUTBYTE(0x370, 0x87); /* (need to write the magic twice) */ 3261.52Suwe PUTBYTE(0x370, 0x07); /* Select Logical Device Number reg */ 3271.52Suwe PUTBYTE(0x371, 0x07); /* Select Logical Device 7 (GPIO) */ 3281.52Suwe PUTBYTE(0x370, 0xe6); /* Select GP16 Control Reg */ 3291.52Suwe PUTBYTE(0x371, 0x00); /* Make GP16 an output */ 3301.52Suwe PUTBYTE(0x338, 0xc4); /* RESET(GP16), red led, fan on */ 3311.8Smatt} 3321.8Smatt 3331.1Smatt/* 3341.1Smatt * Mapping table for core kernel memory. This memory is mapped at init 3351.1Smatt * time with section mappings. 3361.1Smatt */ 3371.1Smattstruct l1_sec_map { 3381.1Smatt vm_offset_t va; 3391.1Smatt vm_offset_t pa; 3401.1Smatt vm_size_t size; 3411.16Sthorpej vm_prot_t prot; 3421.16Sthorpej int cache; 3431.1Smatt} l1_sec_table[] = { 3441.1Smatt /* Map 1MB for CSR space */ 3451.1Smatt { DC21285_ARMCSR_VBASE, DC21285_ARMCSR_BASE, 3461.16Sthorpej DC21285_ARMCSR_VSIZE, VM_PROT_READ|VM_PROT_WRITE, 3471.16Sthorpej PTE_NOCACHE }, 3481.16Sthorpej 3491.1Smatt /* Map 1MB for fast cache cleaning space */ 3501.4Schris { DC21285_CACHE_FLUSH_VBASE, DC21285_SA_CACHE_FLUSH_BASE, 3511.16Sthorpej DC21285_CACHE_FLUSH_VSIZE, VM_PROT_READ|VM_PROT_WRITE, 3521.16Sthorpej PTE_CACHE }, 3531.16Sthorpej 3541.1Smatt /* Map 1MB for PCI IO space */ 3551.1Smatt { DC21285_PCI_IO_VBASE, DC21285_PCI_IO_BASE, 3561.16Sthorpej DC21285_PCI_IO_VSIZE, VM_PROT_READ|VM_PROT_WRITE, 3571.16Sthorpej PTE_NOCACHE }, 3581.16Sthorpej 3591.1Smatt /* Map 1MB for PCI IACK space */ 3601.1Smatt { DC21285_PCI_IACK_VBASE, DC21285_PCI_IACK_SPECIAL, 3611.16Sthorpej DC21285_PCI_IACK_VSIZE, VM_PROT_READ|VM_PROT_WRITE, 3621.16Sthorpej PTE_NOCACHE }, 3631.16Sthorpej 3641.1Smatt /* Map 16MB of type 1 PCI config access */ 3651.1Smatt { DC21285_PCI_TYPE_1_CONFIG_VBASE, DC21285_PCI_TYPE_1_CONFIG, 3661.16Sthorpej DC21285_PCI_TYPE_1_CONFIG_VSIZE, VM_PROT_READ|VM_PROT_WRITE, 3671.16Sthorpej PTE_NOCACHE }, 3681.16Sthorpej 3691.1Smatt /* Map 16MB of type 0 PCI config access */ 3701.1Smatt { DC21285_PCI_TYPE_0_CONFIG_VBASE, DC21285_PCI_TYPE_0_CONFIG, 3711.16Sthorpej DC21285_PCI_TYPE_0_CONFIG_VSIZE, VM_PROT_READ|VM_PROT_WRITE, 3721.16Sthorpej PTE_NOCACHE }, 3731.16Sthorpej 3741.1Smatt /* Map 1MB of 32 bit PCI address space for ISA MEM accesses via PCI */ 3751.1Smatt { DC21285_PCI_ISA_MEM_VBASE, DC21285_PCI_MEM_BASE, 3761.16Sthorpej DC21285_PCI_ISA_MEM_VSIZE, VM_PROT_READ|VM_PROT_WRITE, 3771.16Sthorpej PTE_NOCACHE }, 3781.16Sthorpej 3791.55Suwe#if NIGSFB > 0 3801.55Suwe /* XXX: uwe: Map 16MB of PCI address space for CyberPro as console */ 3811.55Suwe { IGS_PCI_MEM_VBASE, DC21285_PCI_MEM_BASE + IGS_PCI_MEM_BASE, 3821.55Suwe IGS_PCI_MEM_VSIZE, VM_PROT_READ|VM_PROT_WRITE, 3831.55Suwe PTE_NOCACHE }, 3841.55Suwe#endif 3851.55Suwe 3861.16Sthorpej { 0, 0, 0, 0, 0 } 3871.1Smatt}; 3881.1Smatt 3891.1Smatt/* 3901.38Sthorpej * u_int initarm(...); 3911.1Smatt * 3921.1Smatt * Initial entry point on startup. This gets called before main() is 3931.1Smatt * entered. 3941.6Swiz * It should be responsible for setting up everything that must be 3951.1Smatt * in place when main is called. 3961.1Smatt * This includes 3971.1Smatt * Taking a copy of the boot configuration structure. 3981.1Smatt * Initialising the physical console so characters can be printed. 3991.1Smatt * Setting up page tables for the kernel 4001.1Smatt * Relocating the kernel to the bottom of physical memory 4011.1Smatt */ 4021.1Smatt 4031.1Smattu_int 4041.38Sthorpejinitarm(void *arg) 4051.1Smatt{ 4061.1Smatt int loop; 4071.1Smatt int loop1; 4081.1Smatt u_int l1pagetable; 4091.27Sthorpej extern char _end[]; 4101.1Smatt 4111.27Sthorpej /* 4121.52Suwe * Turn the led off, then turn it yellow. 4131.52Suwe * 0x80 - red; 0x04 - fan; 0x02 - green. 4141.52Suwe */ 4151.52Suwe ISA_PUTBYTE(0x338, 0x04); 4161.52Suwe ISA_PUTBYTE(0x338, 0x86); 4171.52Suwe 4181.52Suwe /* 4191.27Sthorpej * Set up a diagnostic console so we can see what's going 4201.27Sthorpej * on. 4211.27Sthorpej */ 4221.1Smatt cn_tab = &kcomcons; 4231.27Sthorpej 4241.27Sthorpej /* Talk to the user */ 4251.27Sthorpej printf("\nNetBSD/netwinder booting ...\n"); 4261.27Sthorpej 4271.1Smatt /* 4281.1Smatt * Heads up ... Setup the CPU / MMU / TLB functions 4291.1Smatt */ 4301.1Smatt if (set_cpufuncs()) 4311.57Swiz panic("CPU not recognized!"); 4321.1Smatt 4331.27Sthorpej /* 4341.27Sthorpej * We are currently running with the MMU enabled and the 4351.27Sthorpej * entire address space mapped VA==PA, except for the 4361.27Sthorpej * first 64MB of RAM is also double-mapped at 0xf0000000. 4371.27Sthorpej * There is an L1 page table at 0x00008000. 4381.27Sthorpej * 4391.27Sthorpej * We also have the 21285's PCI I/O space mapped where 4401.27Sthorpej * we expect it. 4411.27Sthorpej */ 4421.27Sthorpej 4431.27Sthorpej printf("initarm: Configuring system ...\n"); 4441.27Sthorpej 4451.28Sthorpej /* 4461.28Sthorpej * Copy out the boot info passed by the firmware. Note that 4471.28Sthorpej * early versions of NeTTrom fill this in with bogus values, 4481.28Sthorpej * so we need to sanity check it. 4491.28Sthorpej */ 4501.64Schristos memcpy(&nwbootinfo, (void *)(KERNEL_BASE + 0x100), 4511.28Sthorpej sizeof(nwbootinfo)); 4521.28Sthorpej#ifdef VERBOSE_INIT_ARM 4531.28Sthorpej printf("NeTTrom boot info:\n"); 4541.28Sthorpej printf("\tpage size = 0x%08lx\n", nwbootinfo.bi_pagesize); 4551.28Sthorpej printf("\tnpages = %ld (0x%08lx)\n", nwbootinfo.bi_nrpages, 4561.28Sthorpej nwbootinfo.bi_nrpages); 4571.28Sthorpej printf("\trootdev = 0x%08lx\n", nwbootinfo.bi_rootdev); 4581.28Sthorpej printf("\tcmdline = %s\n", nwbootinfo.bi_cmdline); 4591.28Sthorpej#endif 4601.28Sthorpej if (nwbootinfo.bi_nrpages != 0x02000 && 4611.28Sthorpej nwbootinfo.bi_nrpages != 0x04000 && 4621.28Sthorpej nwbootinfo.bi_nrpages != 0x08000 && 4631.28Sthorpej nwbootinfo.bi_nrpages != 0x10000) { 4641.28Sthorpej nwbootinfo.bi_pagesize = 0xdeadbeef; 4651.28Sthorpej nwbootinfo.bi_nrpages = 0x01000; /* 16MB */ 4661.28Sthorpej nwbootinfo.bi_rootdev = 0; 4671.28Sthorpej } 4681.28Sthorpej 4691.1Smatt /* Fake bootconfig structure for the benefit of pmap.c */ 4701.63Swiz /* XXX must make the memory description h/w independent */ 4711.1Smatt bootconfig.dramblocks = 1; 4721.1Smatt bootconfig.dram[0].address = 0; 4731.28Sthorpej bootconfig.dram[0].pages = nwbootinfo.bi_nrpages; 4741.1Smatt 4751.1Smatt /* 4761.27Sthorpej * Set up the variables that define the availablilty of 4771.27Sthorpej * physical memory. 4781.27Sthorpej * 4791.27Sthorpej * Since the NetWinder NeTTrom doesn't load ELF symbols 4801.27Sthorpej * for us, we can safely assume that everything after end[] 4811.27Sthorpej * is free. We start there and allocate upwards. 4821.1Smatt */ 4831.27Sthorpej physical_start = bootconfig.dram[0].address; 4841.44Sthorpej physical_end = physical_start + (bootconfig.dram[0].pages * PAGE_SIZE); 4851.1Smatt 4861.27Sthorpej physical_freestart = ((((vaddr_t) _end) + PGOFSET) & ~PGOFSET) - 4871.27Sthorpej KERNEL_BASE; 4881.27Sthorpej physical_freeend = physical_end; 4891.44Sthorpej free_pages = (physical_freeend - physical_freestart) / PAGE_SIZE; 4901.1Smatt 4911.27Sthorpej#ifdef VERBOSE_INIT_ARM 4921.27Sthorpej printf("freestart = 0x%08lx, free_pages = %d (0x%x)\n", 4931.27Sthorpej physical_freestart, free_pages, free_pages); 4941.1Smatt#endif 4951.1Smatt 4961.44Sthorpej physmem = (physical_end - physical_start) / PAGE_SIZE; 4971.1Smatt 4981.1Smatt /* Tell the user about the memory */ 4991.1Smatt printf("physmemory: %d pages at 0x%08lx -> 0x%08lx\n", physmem, 5001.1Smatt physical_start, physical_end - 1); 5011.1Smatt 5021.1Smatt /* 5031.27Sthorpej * Okay, we need to allocate some fixed page tables to get the 5041.27Sthorpej * kernel going. We allocate one page directory and a number 5051.27Sthorpej * of page tables and store the physical addresses in the 5061.27Sthorpej * kernel_pt_table array. 5071.1Smatt * 5081.27Sthorpej * The kernel page directory must be on a 16K boundary. The page 5091.27Sthorpej * tables must be on 4K boundaries. What we do is allocate the 5101.27Sthorpej * page directory on the first 16K boundary that we encounter, 5111.27Sthorpej * and the page tables on 4K boundaries otherwise. Since we 5121.27Sthorpej * allocate at least 3 L2 page tables, we are guaranteed to 5131.27Sthorpej * encounter at least one 16K aligned region. 5141.1Smatt */ 5151.1Smatt 5161.1Smatt#ifdef VERBOSE_INIT_ARM 5171.1Smatt printf("Allocating page tables\n"); 5181.1Smatt#endif 5191.1Smatt 5201.1Smatt /* Define a macro to simplify memory allocation */ 5211.1Smatt#define valloc_pages(var, np) \ 5221.1Smatt alloc_pages((var).pv_pa, (np)); \ 5231.1Smatt (var).pv_va = KERNEL_BASE + (var).pv_pa - physical_start; 5241.1Smatt 5251.1Smatt#define alloc_pages(var, np) \ 5261.1Smatt (var) = physical_freestart; \ 5271.44Sthorpej physical_freestart += ((np) * PAGE_SIZE);\ 5281.1Smatt free_pages -= (np); \ 5291.44Sthorpej memset((char *)(var), 0, ((np) * PAGE_SIZE)); 5301.1Smatt 5311.1Smatt loop1 = 0; 5321.1Smatt for (loop = 0; loop <= NUM_KERNEL_PTS; ++loop) { 5331.1Smatt /* Are we 16KB aligned for an L1 ? */ 5341.30Sthorpej if ((physical_freestart & (L1_TABLE_SIZE - 1)) == 0 5351.1Smatt && kernel_l1pt.pv_pa == 0) { 5361.44Sthorpej valloc_pages(kernel_l1pt, L1_TABLE_SIZE / PAGE_SIZE); 5371.1Smatt } else { 5381.45Sthorpej valloc_pages(kernel_pt_table[loop1], 5391.45Sthorpej L2_TABLE_SIZE / PAGE_SIZE); 5401.1Smatt ++loop1; 5411.1Smatt } 5421.1Smatt } 5431.1Smatt 5441.1Smatt /* This should never be able to happen but better confirm that. */ 5451.30Sthorpej if (!kernel_l1pt.pv_pa || (kernel_l1pt.pv_pa & (L1_TABLE_SIZE-1)) != 0) 5461.37Sprovos panic("initarm: Failed to align the kernel page directory"); 5471.1Smatt 5481.1Smatt /* 5491.1Smatt * Allocate a page for the system page mapped to V0x00000000 5501.1Smatt * This page will just contain the system vectors and can be 5511.1Smatt * shared by all processes. 5521.1Smatt */ 5531.1Smatt alloc_pages(systempage.pv_pa, 1); 5541.1Smatt 5551.1Smatt /* Allocate stacks for all modes */ 5561.1Smatt valloc_pages(irqstack, IRQ_STACK_SIZE); 5571.1Smatt valloc_pages(abtstack, ABT_STACK_SIZE); 5581.1Smatt valloc_pages(undstack, UND_STACK_SIZE); 5591.1Smatt valloc_pages(kernelstack, UPAGES); 5601.1Smatt 5611.1Smatt#ifdef VERBOSE_INIT_ARM 5621.27Sthorpej printf("IRQ stack: p0x%08lx v0x%08lx\n", irqstack.pv_pa, 5631.27Sthorpej irqstack.pv_va); 5641.27Sthorpej printf("ABT stack: p0x%08lx v0x%08lx\n", abtstack.pv_pa, 5651.27Sthorpej abtstack.pv_va); 5661.27Sthorpej printf("UND stack: p0x%08lx v0x%08lx\n", undstack.pv_pa, 5671.27Sthorpej undstack.pv_va); 5681.27Sthorpej printf("SVC stack: p0x%08lx v0x%08lx\n", kernelstack.pv_pa, 5691.27Sthorpej kernelstack.pv_va); 5701.1Smatt#endif 5711.1Smatt 5721.44Sthorpej alloc_pages(msgbufphys, round_page(MSGBUFSIZE) / PAGE_SIZE); 5731.1Smatt 5741.1Smatt /* 5751.1Smatt * Ok we have allocated physical pages for the primary kernel 5761.1Smatt * page tables 5771.1Smatt */ 5781.1Smatt 5791.1Smatt#ifdef VERBOSE_INIT_ARM 5801.27Sthorpej printf("Creating L1 page table at 0x%08lx\n", kernel_l1pt.pv_pa); 5811.1Smatt#endif 5821.1Smatt 5831.1Smatt /* 5841.1Smatt * Now we start consturction of the L1 page table 5851.1Smatt * We start by mapping the L2 page tables into the L1. 5861.1Smatt * This means that we can replace L1 mappings later on if necessary 5871.1Smatt */ 5881.1Smatt l1pagetable = kernel_l1pt.pv_pa; 5891.1Smatt 5901.1Smatt /* Map the L2 pages tables in the L1 page table */ 5911.18Sthorpej pmap_link_l2pt(l1pagetable, 0x00000000, 5921.21Sthorpej &kernel_pt_table[KERNEL_PT_SYS]); 5931.18Sthorpej pmap_link_l2pt(l1pagetable, KERNEL_BASE, 5941.21Sthorpej &kernel_pt_table[KERNEL_PT_KERNEL]); 5951.1Smatt for (loop = 0; loop < KERNEL_PT_VMDATA_NUM; ++loop) 5961.18Sthorpej pmap_link_l2pt(l1pagetable, KERNEL_VM_BASE + loop * 0x00400000, 5971.21Sthorpej &kernel_pt_table[KERNEL_PT_VMDATA + loop]); 5981.24Schris 5991.24Schris /* update the top of the kernel VM */ 6001.26Sthorpej pmap_curmaxkvaddr = 6011.26Sthorpej KERNEL_VM_BASE + (KERNEL_PT_VMDATA_NUM * 0x00400000); 6021.1Smatt 6031.1Smatt#ifdef VERBOSE_INIT_ARM 6041.1Smatt printf("Mapping kernel\n"); 6051.1Smatt#endif 6061.1Smatt 6071.1Smatt /* Now we fill in the L2 pagetable for the kernel static code/data */ 6081.27Sthorpej { 6091.27Sthorpej /* 6101.27Sthorpej * The kernel starts in the first 1MB of RAM, and we'd 6111.27Sthorpej * like to use a section mapping for text, so we'll just 6121.27Sthorpej * map from KERNEL_BASE to etext[] to _end[]. 6131.27Sthorpej */ 6141.1Smatt 6151.27Sthorpej extern char etext[]; 6161.27Sthorpej size_t textsize = (uintptr_t) etext - KERNEL_BASE; 6171.27Sthorpej size_t totalsize = (uintptr_t) _end - KERNEL_BASE; 6181.2Smatt u_int logical; 6191.7Smatt 6201.27Sthorpej textsize = (textsize + PGOFSET) & ~PGOFSET; 6211.27Sthorpej totalsize = (totalsize + PGOFSET) & ~PGOFSET; 6221.27Sthorpej 6231.7Smatt textsize = textsize & ~PGOFSET; 6241.7Smatt totalsize = (totalsize + PGOFSET) & ~PGOFSET; 6251.27Sthorpej 6261.27Sthorpej logical = 0; /* offset into RAM */ 6271.27Sthorpej 6281.27Sthorpej logical += pmap_map_chunk(l1pagetable, KERNEL_BASE + logical, 6291.27Sthorpej physical_start + logical, textsize, 6301.19Sthorpej VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); 6311.27Sthorpej logical += pmap_map_chunk(l1pagetable, KERNEL_BASE + logical, 6321.27Sthorpej physical_start + logical, totalsize - textsize, 6331.19Sthorpej VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); 6341.7Smatt } 6351.1Smatt 6361.1Smatt#ifdef VERBOSE_INIT_ARM 6371.1Smatt printf("Constructing L2 page tables\n"); 6381.1Smatt#endif 6391.1Smatt 6401.1Smatt /* Map the stack pages */ 6411.21Sthorpej pmap_map_chunk(l1pagetable, irqstack.pv_va, irqstack.pv_pa, 6421.44Sthorpej IRQ_STACK_SIZE * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); 6431.21Sthorpej pmap_map_chunk(l1pagetable, abtstack.pv_va, abtstack.pv_pa, 6441.44Sthorpej ABT_STACK_SIZE * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); 6451.21Sthorpej pmap_map_chunk(l1pagetable, undstack.pv_va, undstack.pv_pa, 6461.44Sthorpej UND_STACK_SIZE * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); 6471.21Sthorpej pmap_map_chunk(l1pagetable, kernelstack.pv_va, kernelstack.pv_pa, 6481.44Sthorpej UPAGES * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); 6491.19Sthorpej 6501.45Sthorpej pmap_map_chunk(l1pagetable, kernel_l1pt.pv_va, kernel_l1pt.pv_pa, 6511.45Sthorpej L1_TABLE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_PAGETABLE); 6521.45Sthorpej 6531.45Sthorpej for (loop = 0; loop < NUM_KERNEL_PTS; ++loop) { 6541.45Sthorpej pmap_map_chunk(l1pagetable, kernel_pt_table[loop].pv_va, 6551.45Sthorpej kernel_pt_table[loop].pv_pa, L2_TABLE_SIZE, 6561.45Sthorpej VM_PROT_READ|VM_PROT_WRITE, PTE_PAGETABLE); 6571.45Sthorpej } 6581.1Smatt 6591.29Sthorpej /* Map the vector page. */ 6601.29Sthorpej pmap_map_entry(l1pagetable, vector_page, systempage.pv_pa, 6611.17Sthorpej VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); 6621.1Smatt 6631.27Sthorpej /* 6641.27Sthorpej * Map devices we can map w/ section mappings. 6651.27Sthorpej */ 6661.1Smatt loop = 0; 6671.1Smatt while (l1_sec_table[loop].size) { 6681.1Smatt vm_size_t sz; 6691.1Smatt 6701.1Smatt#ifdef VERBOSE_INIT_ARM 6711.1Smatt printf("%08lx -> %08lx @ %08lx\n", l1_sec_table[loop].pa, 6721.1Smatt l1_sec_table[loop].pa + l1_sec_table[loop].size - 1, 6731.1Smatt l1_sec_table[loop].va); 6741.1Smatt#endif 6751.30Sthorpej for (sz = 0; sz < l1_sec_table[loop].size; sz += L1_S_SIZE) 6761.16Sthorpej pmap_map_section(l1pagetable, 6771.16Sthorpej l1_sec_table[loop].va + sz, 6781.1Smatt l1_sec_table[loop].pa + sz, 6791.16Sthorpej l1_sec_table[loop].prot, 6801.16Sthorpej l1_sec_table[loop].cache); 6811.1Smatt ++loop; 6821.1Smatt } 6831.1Smatt 6841.1Smatt /* 6851.1Smatt * Now we have the real page tables in place so we can switch to them. 6861.27Sthorpej * Once this is done we will be running with the REAL kernel page 6871.27Sthorpej * tables. 6881.1Smatt */ 6891.1Smatt 6901.1Smatt /* Switch tables */ 6911.1Smatt#ifdef VERBOSE_INIT_ARM 6921.27Sthorpej printf("freestart = 0x%08lx, free_pages = %d (0x%x)\n", 6931.1Smatt physical_freestart, free_pages, free_pages); 6941.1Smatt printf("switching to new L1 page table @%#lx...", kernel_l1pt.pv_pa); 6951.1Smatt#endif 6961.1Smatt 6971.45Sthorpej cpu_domains((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT); 6981.1Smatt setttb(kernel_l1pt.pv_pa); 6991.45Sthorpej cpu_domains(DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)); 7001.45Sthorpej 7011.45Sthorpej /* 7021.45Sthorpej * Moved from cpu_startup() as data_abort_handler() references 7031.45Sthorpej * this during uvm init 7041.45Sthorpej */ 7051.45Sthorpej proc0paddr = (struct user *)kernelstack.pv_va; 7061.45Sthorpej lwp0.l_addr = proc0paddr; 7071.1Smatt 7081.1Smatt#ifdef VERBOSE_INIT_ARM 7091.1Smatt printf("done!\n"); 7101.1Smatt#endif 7111.1Smatt 7121.1Smatt /* 7131.1Smatt * XXX this should only be done in main() but it useful to 7141.1Smatt * have output earlier ... 7151.1Smatt */ 7161.1Smatt consinit(); 7171.1Smatt 7181.1Smatt#ifdef VERBOSE_INIT_ARM 7191.1Smatt printf("bootstrap done.\n"); 7201.1Smatt#endif 7211.1Smatt 7221.29Sthorpej arm32_vector_init(ARM_VECTORS_LOW, ARM_VEC_ALL); 7231.1Smatt 7241.1Smatt /* 7251.1Smatt * Pages were allocated during the secondary bootstrap for the 7261.1Smatt * stacks for different CPU modes. 7271.1Smatt * We must now set the r13 registers in the different CPU modes to 7281.1Smatt * point to these stacks. 7291.1Smatt * Since the ARM stacks use STMFD etc. we must set r13 to the top end 7301.1Smatt * of the stack memory. 7311.1Smatt */ 7321.1Smatt printf("init subsystems: stacks "); 7331.1Smatt 7341.44Sthorpej set_stackptr(PSR_IRQ32_MODE, 7351.44Sthorpej irqstack.pv_va + IRQ_STACK_SIZE * PAGE_SIZE); 7361.44Sthorpej set_stackptr(PSR_ABT32_MODE, 7371.44Sthorpej abtstack.pv_va + ABT_STACK_SIZE * PAGE_SIZE); 7381.44Sthorpej set_stackptr(PSR_UND32_MODE, 7391.44Sthorpej undstack.pv_va + UND_STACK_SIZE * PAGE_SIZE); 7401.1Smatt 7411.1Smatt /* 7421.1Smatt * Well we should set a data abort handler. 7431.27Sthorpej * Once things get going this will change as we will need a proper 7441.27Sthorpej * handler. 7451.1Smatt * Until then we will use a handler that just panics but tells us 7461.1Smatt * why. 7471.1Smatt * Initialisation of the vectors will just panic on a data abort. 7481.58Sabs * This just fills in a slightly better one. 7491.1Smatt */ 7501.1Smatt printf("vectors "); 7511.1Smatt data_abort_handler_address = (u_int)data_abort_handler; 7521.1Smatt prefetch_abort_handler_address = (u_int)prefetch_abort_handler; 7531.1Smatt undefined_handler_address = (u_int)undefinedinstruction_bounce; 7541.1Smatt 7551.1Smatt /* Initialise the undefined instruction handlers */ 7561.1Smatt printf("undefined "); 7571.1Smatt undefined_init(); 7581.1Smatt 7591.33Sthorpej /* Load memory into UVM. */ 7601.33Sthorpej printf("page "); 7611.33Sthorpej uvm_setpagesize(); /* initialize PAGE_SIZE-dependent variables */ 7621.33Sthorpej 7631.33Sthorpej /* XXX Always one RAM block -- nuke the loop. */ 7641.33Sthorpej for (loop = 0; loop < bootconfig.dramblocks; loop++) { 7651.33Sthorpej paddr_t start = (paddr_t)bootconfig.dram[loop].address; 7661.44Sthorpej paddr_t end = start + (bootconfig.dram[loop].pages * PAGE_SIZE); 7671.33Sthorpej#if NISADMA > 0 7681.33Sthorpej paddr_t istart, isize; 7691.34Sthorpej extern struct arm32_dma_range *footbridge_isa_dma_ranges; 7701.34Sthorpej extern int footbridge_isa_dma_nranges; 7711.33Sthorpej#endif 7721.33Sthorpej 7731.33Sthorpej if (start < physical_freestart) 7741.33Sthorpej start = physical_freestart; 7751.33Sthorpej if (end > physical_freeend) 7761.33Sthorpej end = physical_freeend; 7771.33Sthorpej 7781.33Sthorpej#if 0 7791.33Sthorpej printf("%d: %lx -> %lx\n", loop, start, end - 1); 7801.33Sthorpej#endif 7811.33Sthorpej 7821.33Sthorpej#if NISADMA > 0 7831.34Sthorpej if (arm32_dma_range_intersect(footbridge_isa_dma_ranges, 7841.34Sthorpej footbridge_isa_dma_nranges, 7851.34Sthorpej start, end - start, 7861.34Sthorpej &istart, &isize)) { 7871.33Sthorpej /* 7881.33Sthorpej * Place the pages that intersect with the 7891.33Sthorpej * ISA DMA range onto the ISA DMA free list. 7901.33Sthorpej */ 7911.33Sthorpej#if 0 7921.33Sthorpej printf(" ISADMA 0x%lx -> 0x%lx\n", istart, 7931.33Sthorpej istart + isize - 1); 7941.33Sthorpej#endif 7951.33Sthorpej uvm_page_physload(atop(istart), 7961.33Sthorpej atop(istart + isize), atop(istart), 7971.33Sthorpej atop(istart + isize), VM_FREELIST_ISADMA); 7981.33Sthorpej 7991.33Sthorpej /* 8001.33Sthorpej * Load the pieces that come before the 8011.33Sthorpej * intersection onto the default free list. 8021.33Sthorpej */ 8031.33Sthorpej if (start < istart) { 8041.33Sthorpej#if 0 8051.33Sthorpej printf(" BEFORE 0x%lx -> 0x%lx\n", 8061.33Sthorpej start, istart - 1); 8071.33Sthorpej#endif 8081.33Sthorpej uvm_page_physload(atop(start), 8091.33Sthorpej atop(istart), atop(start), 8101.33Sthorpej atop(istart), VM_FREELIST_DEFAULT); 8111.33Sthorpej } 8121.33Sthorpej 8131.33Sthorpej /* 8141.33Sthorpej * Load the pieces that come after the 8151.33Sthorpej * intersection onto the default free list. 8161.33Sthorpej */ 8171.33Sthorpej if ((istart + isize) < end) { 8181.33Sthorpej#if 0 8191.33Sthorpej printf(" AFTER 0x%lx -> 0x%lx\n", 8201.33Sthorpej (istart + isize), end - 1); 8211.33Sthorpej#endif 8221.33Sthorpej uvm_page_physload(atop(istart + isize), 8231.33Sthorpej atop(end), atop(istart + isize), 8241.33Sthorpej atop(end), VM_FREELIST_DEFAULT); 8251.33Sthorpej } 8261.33Sthorpej } else { 8271.33Sthorpej uvm_page_physload(atop(start), atop(end), 8281.33Sthorpej atop(start), atop(end), VM_FREELIST_DEFAULT); 8291.33Sthorpej } 8301.33Sthorpej#else /* NISADMA > 0 */ 8311.33Sthorpej uvm_page_physload(atop(start), atop(end), 8321.33Sthorpej atop(start), atop(end), VM_FREELIST_DEFAULT); 8331.33Sthorpej#endif /* NISADMA > 0 */ 8341.33Sthorpej } 8351.33Sthorpej 8361.1Smatt /* Boot strap pmap telling it where the kernel page table is */ 8371.1Smatt printf("pmap "); 8381.66Smatt pmap_bootstrap(KERNEL_VM_BASE, KERNEL_VM_BASE + KERNEL_VM_SIZE); 8391.1Smatt 8401.52Suwe /* Now that pmap is inited, we can set cpu_reset_address */ 8411.52Suwe cpu_reset_address = (u_int)vtophys((vaddr_t)netwinder_reset); 8421.52Suwe 8431.1Smatt /* Setup the IRQ system */ 8441.1Smatt printf("irq "); 8451.41Schris footbridge_intr_init(); 8461.1Smatt printf("done.\n"); 8471.28Sthorpej 8481.28Sthorpej /* 8491.28Sthorpej * Warn the user if the bootinfo was bogus. We already 8501.28Sthorpej * faked up some safe values. 8511.28Sthorpej */ 8521.28Sthorpej if (nwbootinfo.bi_pagesize == 0xdeadbeef) 8531.28Sthorpej printf("WARNING: NeTTrom boot info corrupt\n"); 8541.1Smatt 8551.46Sragge#if NKSYMS || defined(DDB) || defined(LKM) 8561.12Sthorpej /* Firmware doesn't load symbols. */ 8571.46Sragge ksyms_init(0, NULL, NULL); 8581.46Sragge#endif 8591.1Smatt 8601.46Sragge#ifdef DDB 8611.46Sragge db_machine_init(); 8621.1Smatt if (boothowto & RB_KDB) 8631.1Smatt Debugger(); 8641.1Smatt#endif 8651.52Suwe 8661.52Suwe /* Turn the led green */ 8671.52Suwe ISA_PUTBYTE(0x338, 0x06); 8681.1Smatt 8691.1Smatt /* We return the new stack pointer address */ 8701.1Smatt return(kernelstack.pv_va + USPACE_SVC_STACK_TOP); 8711.1Smatt} 8721.1Smatt 8731.1Smattvoid 8741.53Suweprocess_kernel_args(char *args) 8751.1Smatt{ 8761.1Smatt 8771.1Smatt boothowto = 0; 8781.1Smatt 8791.1Smatt /* Make a local copy of the bootargs */ 8801.1Smatt strncpy(bootargs, args, MAX_BOOT_STRING); 8811.1Smatt 8821.1Smatt args = bootargs; 8831.1Smatt boot_file = bootargs; 8841.1Smatt 8851.1Smatt /* Skip the kernel image filename */ 8861.1Smatt while (*args != ' ' && *args != 0) 8871.1Smatt ++args; 8881.1Smatt 8891.1Smatt if (*args != 0) 8901.1Smatt *args++ = 0; 8911.1Smatt 8921.1Smatt while (*args == ' ') 8931.1Smatt ++args; 8941.1Smatt 8951.1Smatt boot_args = args; 8961.1Smatt 8971.1Smatt printf("bootfile: %s\n", boot_file); 8981.1Smatt printf("bootargs: %s\n", boot_args); 8991.1Smatt 9001.1Smatt parse_mi_bootargs(boot_args); 9011.1Smatt} 9021.1Smatt 9031.1Smattvoid 9041.1Smattconsinit(void) 9051.1Smatt{ 9061.1Smatt static int consinit_called = 0; 9071.59She const char *console = CONSDEVNAME; 9081.1Smatt 9091.1Smatt if (consinit_called != 0) 9101.1Smatt return; 9111.1Smatt 9121.1Smatt consinit_called = 1; 9131.1Smatt 9141.55Suwe#ifdef DIAGNOSTIC 9151.55Suwe printf("consinit(\"%s\")\n", console); 9161.55Suwe#endif 9171.55Suwe 9181.1Smatt#if NISA > 0 9191.1Smatt /* Initialise the ISA subsystem early ... */ 9201.40Schris isa_footbridge_init(DC21285_PCI_IO_VBASE, DC21285_PCI_ISA_MEM_VBASE); 9211.1Smatt#endif 9221.1Smatt 9231.55Suwe if (strncmp(console, "igsfb", 5) == 0) { 9241.55Suwe#if NIGSFB > 0 9251.55Suwe int res; 9261.55Suwe 9271.55Suwe footbridge_pci_bs_tag_init(); 9281.1Smatt 9291.55Suwe /* 9301.55Suwe * XXX: uwe: special case mapping for the igsfb memory space. 9311.55Suwe * 9321.55Suwe * The problem with this is that when footbridge is 9331.55Suwe * attached during normal autoconfiguration the bus 9341.55Suwe * space tags will be reinited and these hooks lost. 9351.55Suwe * However, since igsfb(4) don't unmap memory during 9361.55Suwe * normal operation, this is ok. But if the igsfb is 9371.55Suwe * configured but is not a console, we waste 16M of 9381.55Suwe * kernel VA space. 9391.55Suwe */ 9401.55Suwe footbridge_pci_mem_bs_tag.bs_map = nw_footbridge_mem_bs_map; 9411.55Suwe footbridge_pci_mem_bs_tag.bs_unmap = nw_footbridge_mem_bs_unmap; 9421.55Suwe 9431.55Suwe igsfb_pci_cnattach(&footbridge_pci_io_bs_tag, 9441.55Suwe &footbridge_pci_mem_bs_tag, 9451.55Suwe &footbridge_pci_chipset, 9461.55Suwe 0, 8, 0); 9471.55Suwe#if NPCKBC > 0 9481.55Suwe res = pckbc_cnattach(&isa_io_bs_tag, 9491.55Suwe IO_KBD, KBCMDP, PCKBC_KBD_SLOT); 9501.55Suwe if (res) 9511.55Suwe printf("pckbc_cnattach: %d!\n", res); 9521.55Suwe#endif 9531.1Smatt#else 9541.55Suwe panic("igsfb console not configured"); 9551.55Suwe#endif /* NIGSFB */ 9561.1Smatt } else { 9571.55Suwe#ifdef DIAGNOSTIC 9581.55Suwe if (strncmp(console, "com", 3) != 0) { 9591.55Suwe printf("consinit: unknown CONSDEVNAME=\"%s\"," 9601.55Suwe " falling back to \"com\"\n", console); 9611.55Suwe } 9621.55Suwe#endif 9631.55Suwe#if NCOM > 0 9641.1Smatt if (comcnattach(&isa_io_bs_tag, CONCOMADDR, comcnspeed, 9651.55Suwe COM_FREQ, COM_TYPE_NORMAL, comcnmode)) 9661.1Smatt panic("can't init serial console @%x", CONCOMADDR); 9671.1Smatt#else 9681.55Suwe panic("serial console @%x not configured", CONCOMADDR); 9691.55Suwe#endif 9701.55Suwe } 9711.55Suwe} 9721.55Suwe 9731.55Suwe 9741.55Suwe#if NIGSFB > 0 9751.55Suwestatic int 9761.55Suwenw_footbridge_mem_bs_map(t, bpa, size, cacheable, bshp) 9771.55Suwe void *t; 9781.55Suwe bus_addr_t bpa; 9791.55Suwe bus_size_t size; 9801.55Suwe int cacheable; 9811.55Suwe bus_space_handle_t *bshp; 9821.55Suwe{ 9831.55Suwe bus_addr_t startpa, endpa; 9841.55Suwe 9851.55Suwe /* Round the allocation to page boundries */ 9861.55Suwe startpa = trunc_page(bpa); 9871.55Suwe endpa = round_page(bpa + size); 9881.55Suwe 9891.55Suwe /* 9901.55Suwe * Check for mappings of the igsfb(4) memory space as we have 9911.55Suwe * this space already mapped. 9921.55Suwe */ 9931.55Suwe if (startpa >= IGS_PCI_MEM_BASE 9941.55Suwe && endpa < (IGS_PCI_MEM_BASE + IGS_PCI_MEM_VSIZE)) { 9951.55Suwe /* Store the bus space handle */ 9961.55Suwe *bshp = IGS_PCI_MEM_VBASE 9971.55Suwe + (bpa - IGS_PCI_MEM_BASE); 9981.55Suwe#ifdef DEBUG 9991.55Suwe printf("nw/mem_bs_map: %08x+%08x: %08x..%08x -> %08x\n", 10001.55Suwe (u_int32_t)bpa, (u_int32_t)size, 10011.55Suwe (u_int32_t)startpa, (u_int32_t)endpa, 10021.55Suwe (u_int32_t)*bshp); 10031.1Smatt#endif 10041.55Suwe return 0; 10051.1Smatt } 10061.55Suwe 10071.55Suwe return (footbridge_mem_bs_map(t, bpa, size, cacheable, bshp)); 10081.1Smatt} 10091.55Suwe 10101.55Suwe 10111.55Suwestatic void 10121.55Suwenw_footbridge_mem_bs_unmap(t, bsh, size) 10131.55Suwe void *t; 10141.55Suwe bus_space_handle_t bsh; 10151.55Suwe bus_size_t size; 10161.55Suwe{ 10171.55Suwe 10181.55Suwe /* 10191.55Suwe * Check for mappings of the igsfb(4) memory space as we have 10201.55Suwe * this space already mapped. 10211.55Suwe */ 10221.55Suwe if (bsh >= IGS_PCI_MEM_VBASE 10231.55Suwe && bsh < (IGS_PCI_MEM_VBASE + IGS_PCI_MEM_VSIZE)) { 10241.55Suwe#ifdef DEBUG 10251.55Suwe printf("nw/bs_unmap: 0x%08x\n", (u_int32_t)bsh); 10261.55Suwe#endif 10271.55Suwe return; 10281.55Suwe } 10291.55Suwe 10301.55Suwe footbridge_mem_bs_unmap(t, bsh, size); 10311.55Suwe} 10321.55Suwe#endif /* NIGSFB */ 10331.55Suwe 10341.1Smatt 10351.1Smattstatic bus_space_handle_t kcom_base = (bus_space_handle_t) (DC21285_PCI_IO_VBASE + CONCOMADDR); 10361.1Smatt 10371.31Sthorpej#define KCOM_GETBYTE(r) generic_bs_r_1(0, kcom_base, (r)) 10381.31Sthorpej#define KCOM_PUTBYTE(r,v) generic_bs_w_1(0, kcom_base, (r), (v)) 10391.1Smatt 10401.1Smattstatic int 10411.1Smattkcomcngetc(dev_t dev) 10421.1Smatt{ 10431.1Smatt int stat, c; 10441.1Smatt 10451.1Smatt /* block until a character becomes available */ 10461.1Smatt while (!ISSET(stat = KCOM_GETBYTE(com_lsr), LSR_RXRDY)) 10471.1Smatt ; 10481.1Smatt 10491.1Smatt c = KCOM_GETBYTE(com_data); 10501.1Smatt stat = KCOM_GETBYTE(com_iir); 10511.1Smatt return c; 10521.1Smatt} 10531.1Smatt 10541.1Smatt/* 10551.1Smatt * Console kernel output character routine. 10561.1Smatt */ 10571.1Smattstatic void 10581.1Smattkcomcnputc(dev_t dev, int c) 10591.1Smatt{ 10601.1Smatt int timo; 10611.1Smatt 10621.1Smatt /* wait for any pending transmission to finish */ 10631.1Smatt timo = 150000; 10641.1Smatt while (!ISSET(KCOM_GETBYTE(com_lsr), LSR_TXRDY) && --timo) 10651.1Smatt continue; 10661.1Smatt 10671.1Smatt KCOM_PUTBYTE(com_data, c); 10681.1Smatt 10691.1Smatt /* wait for this transmission to complete */ 10701.1Smatt timo = 1500000; 10711.1Smatt while (!ISSET(KCOM_GETBYTE(com_lsr), LSR_TXRDY) && --timo) 10721.1Smatt continue; 10731.1Smatt} 10741.1Smatt 10751.1Smattstatic void 10761.1Smattkcomcnpollc(dev_t dev, int on) 10771.1Smatt{ 10781.1Smatt} 10791.1Smatt 10801.1Smattstruct consdev kcomcons = { 10811.1Smatt NULL, NULL, kcomcngetc, kcomcnputc, kcomcnpollc, NULL, 10821.43She NULL, NULL, NODEV, CN_NORMAL 10831.1Smatt}; 1084