11.93Sandvar/* $NetBSD: netwinder_machdep.c,v 1.93 2024/02/21 23:23:06 andvar 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.75Swiz * Machine dependent 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.93Sandvar__KERNEL_RCSID(0, "$NetBSD: netwinder_machdep.c,v 1.93 2024/02/21 23:23:06 andvar Exp $"); 441.1Smatt 451.1Smatt#include "opt_ddb.h" 461.1Smatt 471.81Smatt#define _ARM32_BUS_DMA_PRIVATE 481.81Smatt 491.81Smatt#include "isa.h" 501.81Smatt#include "isadma.h" 511.81Smatt#include "igsfb.h" 521.81Smatt#include "pckbc.h" 531.81Smatt#include "com.h" 541.81Smatt#include "ksyms.h" 551.81Smatt 561.1Smatt#include <sys/param.h> 571.1Smatt#include <sys/device.h> 581.1Smatt#include <sys/systm.h> 591.1Smatt#include <sys/kernel.h> 601.1Smatt#include <sys/exec.h> 611.1Smatt#include <sys/proc.h> 621.1Smatt#include <sys/msgbuf.h> 631.1Smatt#include <sys/reboot.h> 641.1Smatt#include <sys/termios.h> 651.46Sragge#include <sys/ksyms.h> 661.81Smatt#include <sys/bus.h> 671.81Smatt#include <sys/cpu.h> 681.81Smatt#include <sys/intr.h> 691.1Smatt 701.44Sthorpej#include <uvm/uvm_extern.h> 711.44Sthorpej 721.1Smatt#include <dev/cons.h> 731.1Smatt 741.1Smatt#if NISA > 0 751.1Smatt#include <dev/isa/isareg.h> 761.1Smatt#include <dev/isa/isavar.h> 771.1Smatt#endif 781.1Smatt 791.55Suwe#if NIGSFB > 0 801.55Suwe#include <dev/pci/pcivar.h> 811.55Suwe#include <dev/pci/igsfb_pcivar.h> 821.55Suwe#endif 831.55Suwe 841.55Suwe#if NPCKBC > 0 851.55Suwe#include <dev/ic/i8042reg.h> 861.55Suwe#include <dev/ic/pckbcvar.h> 871.55Suwe#endif 881.55Suwe 891.55Suwe#include <dev/ic/comreg.h> 901.55Suwe#include <dev/ic/comvar.h> 911.55Suwe 921.81Smatt#include <machine/db_machdep.h> 931.81Smatt#include <ddb/db_sym.h> 941.81Smatt#include <ddb/db_extern.h> 951.81Smatt 961.81Smatt#include <arm/arm32/machdep.h> 971.81Smatt 981.81Smatt#include <machine/bootconfig.h> 991.81Smatt#include <arm/locore.h> 1001.81Smatt#include <arm/undefined.h> 1011.81Smatt 1021.81Smatt#include <machine/netwinder_boot.h> 1031.81Smatt#include <arm/footbridge/dc21285mem.h> 1041.81Smatt#include <arm/footbridge/dc21285reg.h> 1051.81Smatt 1061.46Sragge 1071.8Smattstatic bus_space_handle_t isa_base = (bus_space_handle_t) DC21285_PCI_IO_VBASE; 1081.8Smatt 1091.31Sthorpejbs_protos(generic); 1101.8Smatt 1111.31Sthorpej#define ISA_GETBYTE(r) generic_bs_r_1(0, isa_base, (r)) 1121.31Sthorpej#define ISA_PUTBYTE(r,v) generic_bs_w_1(0, isa_base, (r), (v)) 1131.8Smatt 1141.27Sthorpejstatic void netwinder_reset(void); 1151.1Smatt 1161.8Smattu_int dc21285_fclk = 63750000; 1171.1Smatt 1181.1Smattstruct nwbootinfo nwbootinfo; 1191.1SmattBootConfig bootconfig; /* Boot config storage */ 1201.1Smattstatic char bootargs[MAX_BOOT_STRING + 1]; 1211.1Smattchar *boot_args = NULL; 1221.1Smattchar *boot_file = NULL; 1231.1Smatt 1241.83Smattvaddr_t physical_start; 1251.83Smattvaddr_t physical_freestart; 1261.83Smattvaddr_t physical_freeend; 1271.83Smattvaddr_t physical_end; 1281.1Smattu_int free_pages; 1291.83Smattvaddr_t pagetables_start; 1301.1Smatt 1311.1Smatt/*int debug_flags;*/ 1321.1Smatt#ifndef PMAP_STATIC_L1S 1331.1Smattint max_processes = 64; /* Default number */ 1341.1Smatt#endif /* !PMAP_STATIC_L1S */ 1351.1Smatt 1361.83Smattpaddr_t msgbufphys; 1371.1Smatt 1381.1Smatt#define KERNEL_PT_SYS 0 /* Page table for mapping proc0 zero page */ 1391.1Smatt#define KERNEL_PT_KERNEL 1 /* Page table for mapping kernel */ 1401.1Smatt#define KERNEL_PT_VMDATA 2 /* Page tables for mapping kernel VM */ 1411.24Schris#define KERNEL_PT_VMDATA_NUM 4 /* start with 16MB of KVM */ 1421.1Smatt#define NUM_KERNEL_PTS (KERNEL_PT_VMDATA + KERNEL_PT_VMDATA_NUM) 1431.1Smatt 1441.21Sthorpejpv_addr_t kernel_pt_table[NUM_KERNEL_PTS]; 1451.50Sthorpej 1461.50Sthorpej#define KERNEL_VM_BASE (KERNEL_BASE + 0x01000000) 1471.51Sthorpej/* 1481.51Sthorpej * The range 0xf1000000 - 0xfcffffff is available for kernel VM space 1491.51Sthorpej * Footbridge registers and I/O mappings occupy 0xfd000000 - 0xffffffff 1501.51Sthorpej */ 1511.55Suwe#if NIGSFB > 0 1521.55Suwe/* XXX: uwe: map 16 megs at 0xfc000000 for igsfb(4) */ 1531.55Suwe#define KERNEL_VM_SIZE 0x0B000000 1541.55Suwe#else 1551.51Sthorpej#define KERNEL_VM_SIZE 0x0C000000 1561.55Suwe#endif 1571.1Smatt 1581.1Smatt/* Prototypes */ 1591.1Smatt 1601.53Suwevoid consinit(void); 1611.53Suwevoid process_kernel_args(char *); 1621.53Suwevoid data_abort_handler(trapframe_t *); 1631.53Suwevoid prefetch_abort_handler(trapframe_t *); 1641.53Suwevoid undefinedinstruction_bounce(trapframe_t *); 1651.1Smatt 1661.1Smatt 1671.1Smatt/* A load of console goo. */ 1681.55Suwe#ifndef CONSDEVNAME 1691.55Suwe# if (NIGSFB > 0) && (NPCKBC > 0) 1701.55Suwe# define CONSDEVNAME "igsfb" 1711.55Suwe# elif NCOM > 0 1721.55Suwe# define CONSDEVNAME "com" 1731.55Suwe# else 1741.55Suwe# error CONSDEVNAME not defined and no known console device configured 1751.55Suwe# endif 1761.55Suwe#endif /* !CONSDEVNAME */ 1771.1Smatt 1781.1Smatt#ifndef CONCOMADDR 1791.1Smatt#define CONCOMADDR 0x3f8 1801.1Smatt#endif 1811.1Smatt 1821.55Suwe#ifndef CONSPEED 1831.55Suwe#define CONSPEED B115200 /* match NeTTrom */ 1841.1Smatt#endif 1851.1Smatt 1861.1Smatt#ifndef CONMODE 1871.1Smatt#define CONMODE ((TTYDEF_CFLAG & ~(CSIZE | CSTOPB | PARENB)) | CS8) /* 8N1 */ 1881.1Smatt#endif 1891.1Smatt 1901.1Smattint comcnspeed = CONSPEED; 1911.1Smattint comcnmode = CONMODE; 1921.1Smatt 1931.1Smattextern struct consdev kcomcons; 1941.1Smattstatic void kcomcnputc(dev_t, int); 1951.1Smatt 1961.55Suwe#if NIGSFB > 0 1971.55Suwe/* XXX: uwe */ 1981.55Suwe#define IGS_PCI_MEM_VBASE 0xfc000000 1991.55Suwe#define IGS_PCI_MEM_VSIZE 0x01000000 2001.55Suwe#define IGS_PCI_MEM_BASE 0x08000000 2011.55Suwe 2021.55Suweextern struct arm32_pci_chipset footbridge_pci_chipset; 2031.55Suweextern struct bus_space footbridge_pci_io_bs_tag; 2041.55Suweextern struct bus_space footbridge_pci_mem_bs_tag; 2051.55Suweextern void footbridge_pci_bs_tag_init(void); 2061.55Suwe 2071.55Suwe/* standard methods */ 2081.55Suweextern bs_map_proto(footbridge_mem); 2091.55Suweextern bs_unmap_proto(footbridge_mem); 2101.55Suwe 2111.55Suwe/* our hooks */ 2121.55Suwestatic bs_map_proto(nw_footbridge_mem); 2131.55Suwestatic bs_unmap_proto(nw_footbridge_mem); 2141.55Suwe#endif 2151.55Suwe 2161.55Suwe 2171.1Smatt/* 2181.1Smatt * void cpu_reboot(int howto, char *bootstr) 2191.1Smatt * 2201.1Smatt * Reboots the system 2211.1Smatt * 2221.1Smatt * Deal with any syncing, unmounting, dumping and shutdown hooks, 2231.1Smatt * then reset the CPU. 2241.1Smatt */ 2251.1Smatt 2261.1Smattvoid 2271.53Suwecpu_reboot(int howto, char *bootstr) 2281.1Smatt{ 2291.1Smatt#ifdef DIAGNOSTIC 2301.1Smatt /* info */ 2311.42Sthorpej printf("boot: howto=%08x curlwp=%p\n", howto, curlwp); 2321.1Smatt#endif 2331.1Smatt 2341.1Smatt /* 2351.1Smatt * If we are still cold then hit the air brakes 2361.1Smatt * and crash to earth fast 2371.1Smatt */ 2381.1Smatt if (cold) { 2391.1Smatt doshutdownhooks(); 2401.67Sdyoung pmf_system_shutdown(boothowto); 2411.1Smatt printf("The operating system has halted.\n"); 2421.1Smatt printf("Please press any key to reboot.\n\n"); 2431.1Smatt cngetc(); 2441.1Smatt printf("rebooting...\n"); 2451.1Smatt cpu_reset(); 2461.1Smatt /*NOTREACHED*/ 2471.1Smatt } 2481.1Smatt 2491.1Smatt /* Disable console buffering */ 2501.1Smatt/* cnpollc(1);*/ 2511.1Smatt 2521.1Smatt /* 2531.1Smatt * If RB_NOSYNC was not specified sync the discs. 2541.53Suwe * Note: Unless cold is set to 1 here, syslogd will die during 2551.53Suwe * the unmount. It looks like syslogd is getting woken up 2561.53Suwe * only to find that it cannot page part of the binary in as 2571.53Suwe * the filesystem has been unmounted. 2581.1Smatt */ 2591.1Smatt if (!(howto & RB_NOSYNC)) 2601.1Smatt bootsync(); 2611.1Smatt 2621.1Smatt /* Say NO to interrupts */ 2631.1Smatt splhigh(); 2641.1Smatt 2651.1Smatt /* Do a dump if requested. */ 2661.1Smatt if ((howto & (RB_DUMP | RB_HALT)) == RB_DUMP) 2671.1Smatt dumpsys(); 2681.89Sskrll 2691.1Smatt /* Run any shutdown hooks */ 2701.1Smatt doshutdownhooks(); 2711.1Smatt 2721.67Sdyoung pmf_system_shutdown(boothowto); 2731.67Sdyoung 2741.1Smatt /* Make sure IRQ's are disabled */ 2751.1Smatt IRQdisable; 2761.1Smatt 2771.1Smatt if (howto & RB_HALT) { 2781.1Smatt printf("The operating system has halted.\n"); 2791.1Smatt printf("Please press any key to reboot.\n\n"); 2801.1Smatt cngetc(); 2811.1Smatt } 2821.1Smatt 2831.1Smatt printf("rebooting...\n"); 2841.1Smatt cpu_reset(); 2851.1Smatt /*NOTREACHED*/ 2861.1Smatt} 2871.1Smatt 2881.52Suwe/* 2891.52Suwe * NB: this function runs with MMU disabled! 2901.52Suwe */ 2911.8Smattstatic void 2921.8Smattnetwinder_reset(void) 2931.8Smatt{ 2941.52Suwe register u_int base = DC21285_PCI_IO_BASE; 2951.52Suwe 2961.52Suwe#define PUTBYTE(reg, val) \ 2971.52Suwe *((volatile u_int8_t *)(base + (reg))) = (val) 2981.52Suwe 2991.52Suwe PUTBYTE(0x338, 0x84); /* Red led(GP17), fan on(GP12) */ 3001.52Suwe PUTBYTE(0x370, 0x87); /* Enter the extended function mode */ 3011.52Suwe PUTBYTE(0x370, 0x87); /* (need to write the magic twice) */ 3021.52Suwe PUTBYTE(0x370, 0x07); /* Select Logical Device Number reg */ 3031.52Suwe PUTBYTE(0x371, 0x07); /* Select Logical Device 7 (GPIO) */ 3041.52Suwe PUTBYTE(0x370, 0xe6); /* Select GP16 Control Reg */ 3051.52Suwe PUTBYTE(0x371, 0x00); /* Make GP16 an output */ 3061.52Suwe PUTBYTE(0x338, 0xc4); /* RESET(GP16), red led, fan on */ 3071.8Smatt} 3081.8Smatt 3091.1Smatt/* 3101.1Smatt * Mapping table for core kernel memory. This memory is mapped at init 3111.1Smatt * time with section mappings. 3121.1Smatt */ 3131.1Smattstruct l1_sec_map { 3141.82Smatt vaddr_t va; 3151.82Smatt vaddr_t pa; 3161.82Smatt vsize_t size; 3171.16Sthorpej vm_prot_t prot; 3181.16Sthorpej int cache; 3191.1Smatt} l1_sec_table[] = { 3201.1Smatt /* Map 1MB for CSR space */ 3211.1Smatt { DC21285_ARMCSR_VBASE, DC21285_ARMCSR_BASE, 3221.16Sthorpej DC21285_ARMCSR_VSIZE, VM_PROT_READ|VM_PROT_WRITE, 3231.16Sthorpej PTE_NOCACHE }, 3241.16Sthorpej 3251.1Smatt /* Map 1MB for fast cache cleaning space */ 3261.4Schris { DC21285_CACHE_FLUSH_VBASE, DC21285_SA_CACHE_FLUSH_BASE, 3271.16Sthorpej DC21285_CACHE_FLUSH_VSIZE, VM_PROT_READ|VM_PROT_WRITE, 3281.16Sthorpej PTE_CACHE }, 3291.16Sthorpej 3301.1Smatt /* Map 1MB for PCI IO space */ 3311.1Smatt { DC21285_PCI_IO_VBASE, DC21285_PCI_IO_BASE, 3321.16Sthorpej DC21285_PCI_IO_VSIZE, VM_PROT_READ|VM_PROT_WRITE, 3331.16Sthorpej PTE_NOCACHE }, 3341.16Sthorpej 3351.1Smatt /* Map 1MB for PCI IACK space */ 3361.1Smatt { DC21285_PCI_IACK_VBASE, DC21285_PCI_IACK_SPECIAL, 3371.16Sthorpej DC21285_PCI_IACK_VSIZE, VM_PROT_READ|VM_PROT_WRITE, 3381.16Sthorpej PTE_NOCACHE }, 3391.16Sthorpej 3401.1Smatt /* Map 16MB of type 1 PCI config access */ 3411.1Smatt { DC21285_PCI_TYPE_1_CONFIG_VBASE, DC21285_PCI_TYPE_1_CONFIG, 3421.16Sthorpej DC21285_PCI_TYPE_1_CONFIG_VSIZE, VM_PROT_READ|VM_PROT_WRITE, 3431.16Sthorpej PTE_NOCACHE }, 3441.16Sthorpej 3451.1Smatt /* Map 16MB of type 0 PCI config access */ 3461.1Smatt { DC21285_PCI_TYPE_0_CONFIG_VBASE, DC21285_PCI_TYPE_0_CONFIG, 3471.16Sthorpej DC21285_PCI_TYPE_0_CONFIG_VSIZE, VM_PROT_READ|VM_PROT_WRITE, 3481.16Sthorpej PTE_NOCACHE }, 3491.16Sthorpej 3501.1Smatt /* Map 1MB of 32 bit PCI address space for ISA MEM accesses via PCI */ 3511.1Smatt { DC21285_PCI_ISA_MEM_VBASE, DC21285_PCI_MEM_BASE, 3521.16Sthorpej DC21285_PCI_ISA_MEM_VSIZE, VM_PROT_READ|VM_PROT_WRITE, 3531.16Sthorpej PTE_NOCACHE }, 3541.16Sthorpej 3551.55Suwe#if NIGSFB > 0 3561.55Suwe /* XXX: uwe: Map 16MB of PCI address space for CyberPro as console */ 3571.55Suwe { IGS_PCI_MEM_VBASE, DC21285_PCI_MEM_BASE + IGS_PCI_MEM_BASE, 3581.55Suwe IGS_PCI_MEM_VSIZE, VM_PROT_READ|VM_PROT_WRITE, 3591.55Suwe PTE_NOCACHE }, 3601.55Suwe#endif 3611.55Suwe 3621.16Sthorpej { 0, 0, 0, 0, 0 } 3631.1Smatt}; 3641.1Smatt 3651.1Smatt/* 3661.88Sskrll * vaddr_t initarm(...); 3671.1Smatt * 3681.1Smatt * Initial entry point on startup. This gets called before main() is 3691.1Smatt * entered. 3701.6Swiz * It should be responsible for setting up everything that must be 3711.1Smatt * in place when main is called. 3721.1Smatt * This includes 3731.1Smatt * Taking a copy of the boot configuration structure. 3741.1Smatt * Initialising the physical console so characters can be printed. 3751.1Smatt * Setting up page tables for the kernel 3761.1Smatt * Relocating the kernel to the bottom of physical memory 3771.1Smatt */ 3781.1Smatt 3791.88Sskrllvaddr_t 3801.38Sthorpejinitarm(void *arg) 3811.1Smatt{ 3821.1Smatt int loop; 3831.1Smatt int loop1; 3841.1Smatt u_int l1pagetable; 3851.27Sthorpej extern char _end[]; 3861.1Smatt 3871.27Sthorpej /* 3881.52Suwe * Turn the led off, then turn it yellow. 3891.52Suwe * 0x80 - red; 0x04 - fan; 0x02 - green. 3901.52Suwe */ 3911.52Suwe ISA_PUTBYTE(0x338, 0x04); 3921.52Suwe ISA_PUTBYTE(0x338, 0x86); 3931.52Suwe 3941.52Suwe /* 3951.27Sthorpej * Set up a diagnostic console so we can see what's going 3961.27Sthorpej * on. 3971.27Sthorpej */ 3981.1Smatt cn_tab = &kcomcons; 3991.27Sthorpej 4001.27Sthorpej /* Talk to the user */ 4011.27Sthorpej printf("\nNetBSD/netwinder booting ...\n"); 4021.27Sthorpej 4031.1Smatt /* 4041.1Smatt * Heads up ... Setup the CPU / MMU / TLB functions 4051.1Smatt */ 4061.1Smatt if (set_cpufuncs()) 4071.57Swiz panic("CPU not recognized!"); 4081.1Smatt 4091.27Sthorpej /* 4101.27Sthorpej * We are currently running with the MMU enabled and the 4111.27Sthorpej * entire address space mapped VA==PA, except for the 4121.27Sthorpej * first 64MB of RAM is also double-mapped at 0xf0000000. 4131.27Sthorpej * There is an L1 page table at 0x00008000. 4141.27Sthorpej * 4151.27Sthorpej * We also have the 21285's PCI I/O space mapped where 4161.27Sthorpej * we expect it. 4171.27Sthorpej */ 4181.27Sthorpej 4191.27Sthorpej printf("initarm: Configuring system ...\n"); 4201.27Sthorpej 4211.28Sthorpej /* 4221.28Sthorpej * Copy out the boot info passed by the firmware. Note that 4231.28Sthorpej * early versions of NeTTrom fill this in with bogus values, 4241.28Sthorpej * so we need to sanity check it. 4251.28Sthorpej */ 4261.64Schristos memcpy(&nwbootinfo, (void *)(KERNEL_BASE + 0x100), 4271.28Sthorpej sizeof(nwbootinfo)); 4281.28Sthorpej#ifdef VERBOSE_INIT_ARM 4291.28Sthorpej printf("NeTTrom boot info:\n"); 4301.28Sthorpej printf("\tpage size = 0x%08lx\n", nwbootinfo.bi_pagesize); 4311.28Sthorpej printf("\tnpages = %ld (0x%08lx)\n", nwbootinfo.bi_nrpages, 4321.28Sthorpej nwbootinfo.bi_nrpages); 4331.28Sthorpej printf("\trootdev = 0x%08lx\n", nwbootinfo.bi_rootdev); 4341.28Sthorpej printf("\tcmdline = %s\n", nwbootinfo.bi_cmdline); 4351.28Sthorpej#endif 4361.28Sthorpej if (nwbootinfo.bi_nrpages != 0x02000 && 4371.28Sthorpej nwbootinfo.bi_nrpages != 0x04000 && 4381.28Sthorpej nwbootinfo.bi_nrpages != 0x08000 && 4391.28Sthorpej nwbootinfo.bi_nrpages != 0x10000) { 4401.28Sthorpej nwbootinfo.bi_pagesize = 0xdeadbeef; 4411.28Sthorpej nwbootinfo.bi_nrpages = 0x01000; /* 16MB */ 4421.28Sthorpej nwbootinfo.bi_rootdev = 0; 4431.28Sthorpej } 4441.28Sthorpej 4451.1Smatt /* Fake bootconfig structure for the benefit of pmap.c */ 4461.63Swiz /* XXX must make the memory description h/w independent */ 4471.1Smatt bootconfig.dramblocks = 1; 4481.1Smatt bootconfig.dram[0].address = 0; 4491.28Sthorpej bootconfig.dram[0].pages = nwbootinfo.bi_nrpages; 4501.1Smatt 4511.1Smatt /* 4521.91Sandvar * Set up the variables that define the availability of 4531.27Sthorpej * physical memory. 4541.27Sthorpej * 4551.27Sthorpej * Since the NetWinder NeTTrom doesn't load ELF symbols 4561.27Sthorpej * for us, we can safely assume that everything after end[] 4571.27Sthorpej * is free. We start there and allocate upwards. 4581.1Smatt */ 4591.27Sthorpej physical_start = bootconfig.dram[0].address; 4601.44Sthorpej physical_end = physical_start + (bootconfig.dram[0].pages * PAGE_SIZE); 4611.1Smatt 4621.27Sthorpej physical_freestart = ((((vaddr_t) _end) + PGOFSET) & ~PGOFSET) - 4631.27Sthorpej KERNEL_BASE; 4641.27Sthorpej physical_freeend = physical_end; 4651.44Sthorpej free_pages = (physical_freeend - physical_freestart) / PAGE_SIZE; 4661.1Smatt 4671.27Sthorpej#ifdef VERBOSE_INIT_ARM 4681.27Sthorpej printf("freestart = 0x%08lx, free_pages = %d (0x%x)\n", 4691.27Sthorpej physical_freestart, free_pages, free_pages); 4701.1Smatt#endif 4711.1Smatt 4721.44Sthorpej physmem = (physical_end - physical_start) / PAGE_SIZE; 4731.1Smatt 4741.1Smatt /* Tell the user about the memory */ 4751.93Sandvar printf("physmemory: 0x%"PRIxPSIZE" pages at 0x%08lx -> 0x%08lx\n", 4761.93Sandvar physmem, physical_start, physical_end - 1); 4771.1Smatt 4781.1Smatt /* 4791.27Sthorpej * Okay, we need to allocate some fixed page tables to get the 4801.27Sthorpej * kernel going. We allocate one page directory and a number 4811.27Sthorpej * of page tables and store the physical addresses in the 4821.27Sthorpej * kernel_pt_table array. 4831.1Smatt * 4841.27Sthorpej * The kernel page directory must be on a 16K boundary. The page 4851.27Sthorpej * tables must be on 4K boundaries. What we do is allocate the 4861.27Sthorpej * page directory on the first 16K boundary that we encounter, 4871.27Sthorpej * and the page tables on 4K boundaries otherwise. Since we 4881.27Sthorpej * allocate at least 3 L2 page tables, we are guaranteed to 4891.27Sthorpej * encounter at least one 16K aligned region. 4901.1Smatt */ 4911.1Smatt 4921.1Smatt#ifdef VERBOSE_INIT_ARM 4931.1Smatt printf("Allocating page tables\n"); 4941.1Smatt#endif 4951.1Smatt 4961.1Smatt /* Define a macro to simplify memory allocation */ 4971.1Smatt#define valloc_pages(var, np) \ 4981.1Smatt alloc_pages((var).pv_pa, (np)); \ 4991.1Smatt (var).pv_va = KERNEL_BASE + (var).pv_pa - physical_start; 5001.1Smatt 5011.1Smatt#define alloc_pages(var, np) \ 5021.1Smatt (var) = physical_freestart; \ 5031.44Sthorpej physical_freestart += ((np) * PAGE_SIZE);\ 5041.1Smatt free_pages -= (np); \ 5051.44Sthorpej memset((char *)(var), 0, ((np) * PAGE_SIZE)); 5061.1Smatt 5071.1Smatt loop1 = 0; 5081.1Smatt for (loop = 0; loop <= NUM_KERNEL_PTS; ++loop) { 5091.1Smatt /* Are we 16KB aligned for an L1 ? */ 5101.30Sthorpej if ((physical_freestart & (L1_TABLE_SIZE - 1)) == 0 5111.1Smatt && kernel_l1pt.pv_pa == 0) { 5121.44Sthorpej valloc_pages(kernel_l1pt, L1_TABLE_SIZE / PAGE_SIZE); 5131.1Smatt } else { 5141.45Sthorpej valloc_pages(kernel_pt_table[loop1], 5151.45Sthorpej L2_TABLE_SIZE / PAGE_SIZE); 5161.1Smatt ++loop1; 5171.1Smatt } 5181.1Smatt } 5191.1Smatt 5201.1Smatt /* This should never be able to happen but better confirm that. */ 5211.30Sthorpej if (!kernel_l1pt.pv_pa || (kernel_l1pt.pv_pa & (L1_TABLE_SIZE-1)) != 0) 5221.37Sprovos panic("initarm: Failed to align the kernel page directory"); 5231.1Smatt 5241.1Smatt /* 5251.1Smatt * Allocate a page for the system page mapped to V0x00000000 5261.1Smatt * This page will just contain the system vectors and can be 5271.1Smatt * shared by all processes. 5281.1Smatt */ 5291.1Smatt alloc_pages(systempage.pv_pa, 1); 5301.1Smatt 5311.1Smatt /* Allocate stacks for all modes */ 5321.1Smatt valloc_pages(irqstack, IRQ_STACK_SIZE); 5331.1Smatt valloc_pages(abtstack, ABT_STACK_SIZE); 5341.1Smatt valloc_pages(undstack, UND_STACK_SIZE); 5351.1Smatt valloc_pages(kernelstack, UPAGES); 5361.1Smatt 5371.1Smatt#ifdef VERBOSE_INIT_ARM 5381.27Sthorpej printf("IRQ stack: p0x%08lx v0x%08lx\n", irqstack.pv_pa, 5391.89Sskrll irqstack.pv_va); 5401.27Sthorpej printf("ABT stack: p0x%08lx v0x%08lx\n", abtstack.pv_pa, 5411.89Sskrll abtstack.pv_va); 5421.27Sthorpej printf("UND stack: p0x%08lx v0x%08lx\n", undstack.pv_pa, 5431.89Sskrll undstack.pv_va); 5441.27Sthorpej printf("SVC stack: p0x%08lx v0x%08lx\n", kernelstack.pv_pa, 5451.89Sskrll kernelstack.pv_va); 5461.1Smatt#endif 5471.1Smatt 5481.44Sthorpej alloc_pages(msgbufphys, round_page(MSGBUFSIZE) / PAGE_SIZE); 5491.1Smatt 5501.1Smatt /* 5511.1Smatt * Ok we have allocated physical pages for the primary kernel 5521.1Smatt * page tables 5531.1Smatt */ 5541.1Smatt 5551.1Smatt#ifdef VERBOSE_INIT_ARM 5561.27Sthorpej printf("Creating L1 page table at 0x%08lx\n", kernel_l1pt.pv_pa); 5571.1Smatt#endif 5581.1Smatt 5591.1Smatt /* 5601.92Sandvar * Now we start construction of the L1 page table 5611.1Smatt * We start by mapping the L2 page tables into the L1. 5621.1Smatt * This means that we can replace L1 mappings later on if necessary 5631.1Smatt */ 5641.1Smatt l1pagetable = kernel_l1pt.pv_pa; 5651.1Smatt 5661.1Smatt /* Map the L2 pages tables in the L1 page table */ 5671.18Sthorpej pmap_link_l2pt(l1pagetable, 0x00000000, 5681.21Sthorpej &kernel_pt_table[KERNEL_PT_SYS]); 5691.18Sthorpej pmap_link_l2pt(l1pagetable, KERNEL_BASE, 5701.21Sthorpej &kernel_pt_table[KERNEL_PT_KERNEL]); 5711.1Smatt for (loop = 0; loop < KERNEL_PT_VMDATA_NUM; ++loop) 5721.18Sthorpej pmap_link_l2pt(l1pagetable, KERNEL_VM_BASE + loop * 0x00400000, 5731.21Sthorpej &kernel_pt_table[KERNEL_PT_VMDATA + loop]); 5741.24Schris 5751.24Schris /* update the top of the kernel VM */ 5761.26Sthorpej pmap_curmaxkvaddr = 5771.26Sthorpej KERNEL_VM_BASE + (KERNEL_PT_VMDATA_NUM * 0x00400000); 5781.1Smatt 5791.1Smatt#ifdef VERBOSE_INIT_ARM 5801.1Smatt printf("Mapping kernel\n"); 5811.1Smatt#endif 5821.1Smatt 5831.1Smatt /* Now we fill in the L2 pagetable for the kernel static code/data */ 5841.27Sthorpej { 5851.27Sthorpej /* 5861.27Sthorpej * The kernel starts in the first 1MB of RAM, and we'd 5871.27Sthorpej * like to use a section mapping for text, so we'll just 5881.27Sthorpej * map from KERNEL_BASE to etext[] to _end[]. 5891.27Sthorpej */ 5901.1Smatt 5911.27Sthorpej extern char etext[]; 5921.27Sthorpej size_t textsize = (uintptr_t) etext - KERNEL_BASE; 5931.27Sthorpej size_t totalsize = (uintptr_t) _end - KERNEL_BASE; 5941.2Smatt u_int logical; 5951.7Smatt 5961.27Sthorpej textsize = (textsize + PGOFSET) & ~PGOFSET; 5971.27Sthorpej totalsize = (totalsize + PGOFSET) & ~PGOFSET; 5981.27Sthorpej 5991.7Smatt textsize = textsize & ~PGOFSET; 6001.7Smatt totalsize = (totalsize + PGOFSET) & ~PGOFSET; 6011.27Sthorpej 6021.27Sthorpej logical = 0; /* offset into RAM */ 6031.27Sthorpej 6041.27Sthorpej logical += pmap_map_chunk(l1pagetable, KERNEL_BASE + logical, 6051.27Sthorpej physical_start + logical, textsize, 6061.19Sthorpej VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); 6071.27Sthorpej logical += pmap_map_chunk(l1pagetable, KERNEL_BASE + logical, 6081.27Sthorpej physical_start + logical, totalsize - textsize, 6091.19Sthorpej VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); 6101.7Smatt } 6111.1Smatt 6121.1Smatt#ifdef VERBOSE_INIT_ARM 6131.1Smatt printf("Constructing L2 page tables\n"); 6141.1Smatt#endif 6151.1Smatt 6161.1Smatt /* Map the stack pages */ 6171.21Sthorpej pmap_map_chunk(l1pagetable, irqstack.pv_va, irqstack.pv_pa, 6181.44Sthorpej IRQ_STACK_SIZE * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); 6191.21Sthorpej pmap_map_chunk(l1pagetable, abtstack.pv_va, abtstack.pv_pa, 6201.44Sthorpej ABT_STACK_SIZE * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); 6211.21Sthorpej pmap_map_chunk(l1pagetable, undstack.pv_va, undstack.pv_pa, 6221.44Sthorpej UND_STACK_SIZE * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); 6231.21Sthorpej pmap_map_chunk(l1pagetable, kernelstack.pv_va, kernelstack.pv_pa, 6241.44Sthorpej UPAGES * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); 6251.19Sthorpej 6261.45Sthorpej pmap_map_chunk(l1pagetable, kernel_l1pt.pv_va, kernel_l1pt.pv_pa, 6271.45Sthorpej L1_TABLE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_PAGETABLE); 6281.45Sthorpej 6291.45Sthorpej for (loop = 0; loop < NUM_KERNEL_PTS; ++loop) { 6301.45Sthorpej pmap_map_chunk(l1pagetable, kernel_pt_table[loop].pv_va, 6311.45Sthorpej kernel_pt_table[loop].pv_pa, L2_TABLE_SIZE, 6321.45Sthorpej VM_PROT_READ|VM_PROT_WRITE, PTE_PAGETABLE); 6331.45Sthorpej } 6341.1Smatt 6351.29Sthorpej /* Map the vector page. */ 6361.29Sthorpej pmap_map_entry(l1pagetable, vector_page, systempage.pv_pa, 6371.17Sthorpej VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); 6381.1Smatt 6391.27Sthorpej /* 6401.27Sthorpej * Map devices we can map w/ section mappings. 6411.27Sthorpej */ 6421.1Smatt loop = 0; 6431.1Smatt while (l1_sec_table[loop].size) { 6441.82Smatt vsize_t sz; 6451.1Smatt 6461.1Smatt#ifdef VERBOSE_INIT_ARM 6471.1Smatt printf("%08lx -> %08lx @ %08lx\n", l1_sec_table[loop].pa, 6481.1Smatt l1_sec_table[loop].pa + l1_sec_table[loop].size - 1, 6491.1Smatt l1_sec_table[loop].va); 6501.1Smatt#endif 6511.30Sthorpej for (sz = 0; sz < l1_sec_table[loop].size; sz += L1_S_SIZE) 6521.16Sthorpej pmap_map_section(l1pagetable, 6531.16Sthorpej l1_sec_table[loop].va + sz, 6541.1Smatt l1_sec_table[loop].pa + sz, 6551.16Sthorpej l1_sec_table[loop].prot, 6561.16Sthorpej l1_sec_table[loop].cache); 6571.1Smatt ++loop; 6581.1Smatt } 6591.1Smatt 6601.1Smatt /* 6611.1Smatt * Now we have the real page tables in place so we can switch to them. 6621.27Sthorpej * Once this is done we will be running with the REAL kernel page 6631.27Sthorpej * tables. 6641.1Smatt */ 6651.1Smatt 6661.1Smatt /* Switch tables */ 6671.1Smatt#ifdef VERBOSE_INIT_ARM 6681.27Sthorpej printf("freestart = 0x%08lx, free_pages = %d (0x%x)\n", 6691.1Smatt physical_freestart, free_pages, free_pages); 6701.1Smatt printf("switching to new L1 page table @%#lx...", kernel_l1pt.pv_pa); 6711.1Smatt#endif 6721.1Smatt 6731.45Sthorpej cpu_domains((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT); 6741.79Smatt cpu_setttb(kernel_l1pt.pv_pa, true); 6751.45Sthorpej cpu_domains(DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)); 6761.45Sthorpej 6771.45Sthorpej /* 6781.45Sthorpej * Moved from cpu_startup() as data_abort_handler() references 6791.45Sthorpej * this during uvm init 6801.45Sthorpej */ 6811.73Srmind uvm_lwp_setuarea(&lwp0, kernelstack.pv_va); 6821.1Smatt 6831.1Smatt#ifdef VERBOSE_INIT_ARM 6841.1Smatt printf("done!\n"); 6851.1Smatt#endif 6861.1Smatt 6871.1Smatt /* 6881.1Smatt * XXX this should only be done in main() but it useful to 6891.1Smatt * have output earlier ... 6901.1Smatt */ 6911.1Smatt consinit(); 6921.1Smatt 6931.1Smatt#ifdef VERBOSE_INIT_ARM 6941.1Smatt printf("bootstrap done.\n"); 6951.1Smatt#endif 6961.1Smatt 6971.29Sthorpej arm32_vector_init(ARM_VECTORS_LOW, ARM_VEC_ALL); 6981.1Smatt 6991.1Smatt /* 7001.1Smatt * Pages were allocated during the secondary bootstrap for the 7011.1Smatt * stacks for different CPU modes. 7021.1Smatt * We must now set the r13 registers in the different CPU modes to 7031.1Smatt * point to these stacks. 7041.1Smatt * Since the ARM stacks use STMFD etc. we must set r13 to the top end 7051.1Smatt * of the stack memory. 7061.1Smatt */ 7071.1Smatt printf("init subsystems: stacks "); 7081.1Smatt 7091.44Sthorpej set_stackptr(PSR_IRQ32_MODE, 7101.44Sthorpej irqstack.pv_va + IRQ_STACK_SIZE * PAGE_SIZE); 7111.44Sthorpej set_stackptr(PSR_ABT32_MODE, 7121.44Sthorpej abtstack.pv_va + ABT_STACK_SIZE * PAGE_SIZE); 7131.44Sthorpej set_stackptr(PSR_UND32_MODE, 7141.44Sthorpej undstack.pv_va + UND_STACK_SIZE * PAGE_SIZE); 7151.1Smatt 7161.1Smatt /* 7171.1Smatt * Well we should set a data abort handler. 7181.27Sthorpej * Once things get going this will change as we will need a proper 7191.27Sthorpej * handler. 7201.1Smatt * Until then we will use a handler that just panics but tells us 7211.1Smatt * why. 7221.1Smatt * Initialisation of the vectors will just panic on a data abort. 7231.58Sabs * This just fills in a slightly better one. 7241.1Smatt */ 7251.1Smatt printf("vectors "); 7261.1Smatt data_abort_handler_address = (u_int)data_abort_handler; 7271.1Smatt prefetch_abort_handler_address = (u_int)prefetch_abort_handler; 7281.1Smatt undefined_handler_address = (u_int)undefinedinstruction_bounce; 7291.1Smatt 7301.1Smatt /* Initialise the undefined instruction handlers */ 7311.1Smatt printf("undefined "); 7321.1Smatt undefined_init(); 7331.1Smatt 7341.33Sthorpej /* Load memory into UVM. */ 7351.33Sthorpej printf("page "); 7361.84Scherry uvm_md_init(); 7371.33Sthorpej 7381.33Sthorpej /* XXX Always one RAM block -- nuke the loop. */ 7391.33Sthorpej for (loop = 0; loop < bootconfig.dramblocks; loop++) { 7401.33Sthorpej paddr_t start = (paddr_t)bootconfig.dram[loop].address; 7411.44Sthorpej paddr_t end = start + (bootconfig.dram[loop].pages * PAGE_SIZE); 7421.33Sthorpej#if NISADMA > 0 7431.33Sthorpej paddr_t istart, isize; 7441.34Sthorpej extern struct arm32_dma_range *footbridge_isa_dma_ranges; 7451.34Sthorpej extern int footbridge_isa_dma_nranges; 7461.33Sthorpej#endif 7471.33Sthorpej 7481.33Sthorpej if (start < physical_freestart) 7491.33Sthorpej start = physical_freestart; 7501.33Sthorpej if (end > physical_freeend) 7511.33Sthorpej end = physical_freeend; 7521.33Sthorpej 7531.33Sthorpej#if 0 7541.33Sthorpej printf("%d: %lx -> %lx\n", loop, start, end - 1); 7551.33Sthorpej#endif 7561.33Sthorpej 7571.33Sthorpej#if NISADMA > 0 7581.34Sthorpej if (arm32_dma_range_intersect(footbridge_isa_dma_ranges, 7591.34Sthorpej footbridge_isa_dma_nranges, 7601.34Sthorpej start, end - start, 7611.34Sthorpej &istart, &isize)) { 7621.33Sthorpej /* 7631.33Sthorpej * Place the pages that intersect with the 7641.33Sthorpej * ISA DMA range onto the ISA DMA free list. 7651.33Sthorpej */ 7661.33Sthorpej#if 0 7671.33Sthorpej printf(" ISADMA 0x%lx -> 0x%lx\n", istart, 7681.33Sthorpej istart + isize - 1); 7691.33Sthorpej#endif 7701.33Sthorpej uvm_page_physload(atop(istart), 7711.33Sthorpej atop(istart + isize), atop(istart), 7721.33Sthorpej atop(istart + isize), VM_FREELIST_ISADMA); 7731.33Sthorpej 7741.33Sthorpej /* 7751.33Sthorpej * Load the pieces that come before the 7761.33Sthorpej * intersection onto the default free list. 7771.33Sthorpej */ 7781.33Sthorpej if (start < istart) { 7791.33Sthorpej#if 0 7801.33Sthorpej printf(" BEFORE 0x%lx -> 0x%lx\n", 7811.33Sthorpej start, istart - 1); 7821.33Sthorpej#endif 7831.33Sthorpej uvm_page_physload(atop(start), 7841.33Sthorpej atop(istart), atop(start), 7851.33Sthorpej atop(istart), VM_FREELIST_DEFAULT); 7861.33Sthorpej } 7871.33Sthorpej 7881.33Sthorpej /* 7891.33Sthorpej * Load the pieces that come after the 7901.33Sthorpej * intersection onto the default free list. 7911.33Sthorpej */ 7921.33Sthorpej if ((istart + isize) < end) { 7931.33Sthorpej#if 0 7941.33Sthorpej printf(" AFTER 0x%lx -> 0x%lx\n", 7951.33Sthorpej (istart + isize), end - 1); 7961.33Sthorpej#endif 7971.33Sthorpej uvm_page_physload(atop(istart + isize), 7981.33Sthorpej atop(end), atop(istart + isize), 7991.33Sthorpej atop(end), VM_FREELIST_DEFAULT); 8001.33Sthorpej } 8011.33Sthorpej } else { 8021.33Sthorpej uvm_page_physload(atop(start), atop(end), 8031.33Sthorpej atop(start), atop(end), VM_FREELIST_DEFAULT); 8041.33Sthorpej } 8051.33Sthorpej#else /* NISADMA > 0 */ 8061.33Sthorpej uvm_page_physload(atop(start), atop(end), 8071.33Sthorpej atop(start), atop(end), VM_FREELIST_DEFAULT); 8081.33Sthorpej#endif /* NISADMA > 0 */ 8091.33Sthorpej } 8101.33Sthorpej 8111.86Sskrll /* Boot strap pmap telling it where managed kernel virtual memory is */ 8121.1Smatt printf("pmap "); 8131.66Smatt pmap_bootstrap(KERNEL_VM_BASE, KERNEL_VM_BASE + KERNEL_VM_SIZE); 8141.1Smatt 8151.52Suwe /* Now that pmap is inited, we can set cpu_reset_address */ 8161.78Smatt cpu_reset_address_paddr = vtophys((vaddr_t)netwinder_reset); 8171.52Suwe 8181.1Smatt /* Setup the IRQ system */ 8191.1Smatt printf("irq "); 8201.41Schris footbridge_intr_init(); 8211.1Smatt printf("done.\n"); 8221.28Sthorpej 8231.28Sthorpej /* 8241.28Sthorpej * Warn the user if the bootinfo was bogus. We already 8251.28Sthorpej * faked up some safe values. 8261.28Sthorpej */ 8271.28Sthorpej if (nwbootinfo.bi_pagesize == 0xdeadbeef) 8281.28Sthorpej printf("WARNING: NeTTrom boot info corrupt\n"); 8291.1Smatt 8301.46Sragge#ifdef DDB 8311.46Sragge db_machine_init(); 8321.1Smatt if (boothowto & RB_KDB) 8331.1Smatt Debugger(); 8341.1Smatt#endif 8351.52Suwe 8361.52Suwe /* Turn the led green */ 8371.52Suwe ISA_PUTBYTE(0x338, 0x06); 8381.1Smatt 8391.1Smatt /* We return the new stack pointer address */ 8401.87Sskrll return kernelstack.pv_va + USPACE_SVC_STACK_TOP; 8411.1Smatt} 8421.1Smatt 8431.1Smattvoid 8441.53Suweprocess_kernel_args(char *args) 8451.1Smatt{ 8461.1Smatt 8471.1Smatt boothowto = 0; 8481.1Smatt 8491.1Smatt /* Make a local copy of the bootargs */ 8501.1Smatt strncpy(bootargs, args, MAX_BOOT_STRING); 8511.1Smatt 8521.1Smatt args = bootargs; 8531.1Smatt boot_file = bootargs; 8541.1Smatt 8551.1Smatt /* Skip the kernel image filename */ 8561.1Smatt while (*args != ' ' && *args != 0) 8571.1Smatt ++args; 8581.1Smatt 8591.1Smatt if (*args != 0) 8601.1Smatt *args++ = 0; 8611.1Smatt 8621.1Smatt while (*args == ' ') 8631.1Smatt ++args; 8641.1Smatt 8651.1Smatt boot_args = args; 8661.1Smatt 8671.1Smatt printf("bootfile: %s\n", boot_file); 8681.1Smatt printf("bootargs: %s\n", boot_args); 8691.1Smatt 8701.1Smatt parse_mi_bootargs(boot_args); 8711.1Smatt} 8721.1Smatt 8731.1Smattvoid 8741.1Smattconsinit(void) 8751.1Smatt{ 8761.1Smatt static int consinit_called = 0; 8771.59She const char *console = CONSDEVNAME; 8781.1Smatt 8791.1Smatt if (consinit_called != 0) 8801.1Smatt return; 8811.1Smatt 8821.1Smatt consinit_called = 1; 8831.1Smatt 8841.55Suwe#ifdef DIAGNOSTIC 8851.55Suwe printf("consinit(\"%s\")\n", console); 8861.55Suwe#endif 8871.55Suwe 8881.1Smatt#if NISA > 0 8891.1Smatt /* Initialise the ISA subsystem early ... */ 8901.40Schris isa_footbridge_init(DC21285_PCI_IO_VBASE, DC21285_PCI_ISA_MEM_VBASE); 8911.1Smatt#endif 8921.1Smatt 8931.55Suwe if (strncmp(console, "igsfb", 5) == 0) { 8941.55Suwe#if NIGSFB > 0 8951.55Suwe int res; 8961.55Suwe 8971.55Suwe footbridge_pci_bs_tag_init(); 8981.1Smatt 8991.55Suwe /* 9001.55Suwe * XXX: uwe: special case mapping for the igsfb memory space. 9011.89Sskrll * 9021.55Suwe * The problem with this is that when footbridge is 9031.55Suwe * attached during normal autoconfiguration the bus 9041.55Suwe * space tags will be reinited and these hooks lost. 9051.55Suwe * However, since igsfb(4) don't unmap memory during 9061.55Suwe * normal operation, this is ok. But if the igsfb is 9071.55Suwe * configured but is not a console, we waste 16M of 9081.55Suwe * kernel VA space. 9091.55Suwe */ 9101.55Suwe footbridge_pci_mem_bs_tag.bs_map = nw_footbridge_mem_bs_map; 9111.55Suwe footbridge_pci_mem_bs_tag.bs_unmap = nw_footbridge_mem_bs_unmap; 9121.55Suwe 9131.55Suwe igsfb_pci_cnattach(&footbridge_pci_io_bs_tag, 9141.55Suwe &footbridge_pci_mem_bs_tag, 9151.55Suwe &footbridge_pci_chipset, 9161.55Suwe 0, 8, 0); 9171.55Suwe#if NPCKBC > 0 9181.55Suwe res = pckbc_cnattach(&isa_io_bs_tag, 9191.80Sjdc IO_KBD, KBCMDP, PCKBC_KBD_SLOT, 0); 9201.55Suwe if (res) 9211.55Suwe printf("pckbc_cnattach: %d!\n", res); 9221.55Suwe#endif 9231.1Smatt#else 9241.55Suwe panic("igsfb console not configured"); 9251.55Suwe#endif /* NIGSFB */ 9261.1Smatt } else { 9271.55Suwe#ifdef DIAGNOSTIC 9281.55Suwe if (strncmp(console, "com", 3) != 0) { 9291.55Suwe printf("consinit: unknown CONSDEVNAME=\"%s\"," 9301.55Suwe " falling back to \"com\"\n", console); 9311.55Suwe } 9321.55Suwe#endif 9331.55Suwe#if NCOM > 0 9341.1Smatt if (comcnattach(&isa_io_bs_tag, CONCOMADDR, comcnspeed, 9351.55Suwe COM_FREQ, COM_TYPE_NORMAL, comcnmode)) 9361.1Smatt panic("can't init serial console @%x", CONCOMADDR); 9371.1Smatt#else 9381.55Suwe panic("serial console @%x not configured", CONCOMADDR); 9391.55Suwe#endif 9401.55Suwe } 9411.55Suwe} 9421.55Suwe 9431.55Suwe 9441.55Suwe#if NIGSFB > 0 9451.55Suwestatic int 9461.70Sdslnw_footbridge_mem_bs_map(void *t, bus_addr_t bpa, bus_size_t size, int cacheable, bus_space_handle_t *bshp) 9471.55Suwe{ 9481.55Suwe bus_addr_t startpa, endpa; 9491.55Suwe 9501.92Sandvar /* Round the allocation to page boundaries */ 9511.55Suwe startpa = trunc_page(bpa); 9521.55Suwe endpa = round_page(bpa + size); 9531.55Suwe 9541.55Suwe /* 9551.55Suwe * Check for mappings of the igsfb(4) memory space as we have 9561.55Suwe * this space already mapped. 9571.55Suwe */ 9581.55Suwe if (startpa >= IGS_PCI_MEM_BASE 9591.55Suwe && endpa < (IGS_PCI_MEM_BASE + IGS_PCI_MEM_VSIZE)) { 9601.55Suwe /* Store the bus space handle */ 9611.55Suwe *bshp = IGS_PCI_MEM_VBASE 9621.55Suwe + (bpa - IGS_PCI_MEM_BASE); 9631.55Suwe#ifdef DEBUG 9641.55Suwe printf("nw/mem_bs_map: %08x+%08x: %08x..%08x -> %08x\n", 9651.55Suwe (u_int32_t)bpa, (u_int32_t)size, 9661.55Suwe (u_int32_t)startpa, (u_int32_t)endpa, 9671.55Suwe (u_int32_t)*bshp); 9681.1Smatt#endif 9691.55Suwe return 0; 9701.1Smatt } 9711.55Suwe 9721.55Suwe return (footbridge_mem_bs_map(t, bpa, size, cacheable, bshp)); 9731.1Smatt} 9741.55Suwe 9751.55Suwe 9761.55Suwestatic void 9771.70Sdslnw_footbridge_mem_bs_unmap(void *t, bus_space_handle_t bsh, bus_size_t size) 9781.55Suwe{ 9791.55Suwe 9801.55Suwe /* 9811.55Suwe * Check for mappings of the igsfb(4) memory space as we have 9821.55Suwe * this space already mapped. 9831.55Suwe */ 9841.55Suwe if (bsh >= IGS_PCI_MEM_VBASE 9851.55Suwe && bsh < (IGS_PCI_MEM_VBASE + IGS_PCI_MEM_VSIZE)) { 9861.55Suwe#ifdef DEBUG 9871.55Suwe printf("nw/bs_unmap: 0x%08x\n", (u_int32_t)bsh); 9881.55Suwe#endif 9891.55Suwe return; 9901.55Suwe } 9911.55Suwe 9921.55Suwe footbridge_mem_bs_unmap(t, bsh, size); 9931.55Suwe} 9941.55Suwe#endif /* NIGSFB */ 9951.55Suwe 9961.1Smatt 9971.1Smattstatic bus_space_handle_t kcom_base = (bus_space_handle_t) (DC21285_PCI_IO_VBASE + CONCOMADDR); 9981.1Smatt 9991.31Sthorpej#define KCOM_GETBYTE(r) generic_bs_r_1(0, kcom_base, (r)) 10001.31Sthorpej#define KCOM_PUTBYTE(r,v) generic_bs_w_1(0, kcom_base, (r), (v)) 10011.1Smatt 10021.1Smattstatic int 10031.1Smattkcomcngetc(dev_t dev) 10041.1Smatt{ 10051.1Smatt int stat, c; 10061.1Smatt 10071.1Smatt /* block until a character becomes available */ 10081.1Smatt while (!ISSET(stat = KCOM_GETBYTE(com_lsr), LSR_RXRDY)) 10091.1Smatt ; 10101.1Smatt 10111.1Smatt c = KCOM_GETBYTE(com_data); 10121.1Smatt stat = KCOM_GETBYTE(com_iir); 10131.1Smatt return c; 10141.1Smatt} 10151.1Smatt 10161.1Smatt/* 10171.1Smatt * Console kernel output character routine. 10181.1Smatt */ 10191.1Smattstatic void 10201.1Smattkcomcnputc(dev_t dev, int c) 10211.1Smatt{ 10221.1Smatt int timo; 10231.1Smatt 10241.1Smatt /* wait for any pending transmission to finish */ 10251.1Smatt timo = 150000; 10261.1Smatt while (!ISSET(KCOM_GETBYTE(com_lsr), LSR_TXRDY) && --timo) 10271.1Smatt continue; 10281.1Smatt 10291.1Smatt KCOM_PUTBYTE(com_data, c); 10301.1Smatt 10311.1Smatt /* wait for this transmission to complete */ 10321.1Smatt timo = 1500000; 10331.1Smatt while (!ISSET(KCOM_GETBYTE(com_lsr), LSR_TXRDY) && --timo) 10341.1Smatt continue; 10351.1Smatt} 10361.1Smatt 10371.1Smattstatic void 10381.1Smattkcomcnpollc(dev_t dev, int on) 10391.1Smatt{ 10401.1Smatt} 10411.1Smatt 10421.1Smattstruct consdev kcomcons = { 10431.1Smatt NULL, NULL, kcomcngetc, kcomcnputc, kcomcnpollc, NULL, 10441.43She NULL, NULL, NODEV, CN_NORMAL 10451.1Smatt}; 1046