1/* $NetBSD: machdep.c,v 1.27 2024/03/05 14:15:30 thorpej Exp $ */ 2 3/*- 4 * Copyright (c) 2007 Ruslan Ermilov and Vsevolod Lobko. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or 8 * without modification, are permitted provided that the following 9 * conditions are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above 13 * copyright notice, this list of conditions and the following 14 * disclaimer in the documentation and/or other materials provided 15 * with the distribution. 16 * 3. The names of the authors may not be used to endorse or promote 17 * products derived from this software without specific prior 18 * written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY 21 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 23 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 25 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 27 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 29 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 30 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 31 * OF SUCH DAMAGE. 32 */ 33 34/* 35 * Copyright (c) 1988 University of Utah. 36 * Copyright (c) 1992, 1993 37 * The Regents of the University of California. All rights reserved. 38 * 39 * This code is derived from software contributed to Berkeley by 40 * the Systems Programming Group of the University of Utah Computer 41 * Science Department, The Mach Operating System project at 42 * Carnegie-Mellon University and Ralph Campbell. 43 * 44 * Redistribution and use in source and binary forms, with or without 45 * modification, are permitted provided that the following conditions 46 * are met: 47 * 1. Redistributions of source code must retain the above copyright 48 * notice, this list of conditions and the following disclaimer. 49 * 2. Redistributions in binary form must reproduce the above copyright 50 * notice, this list of conditions and the following disclaimer in the 51 * documentation and/or other materials provided with the distribution. 52 * 3. Neither the name of the University nor the names of its contributors 53 * may be used to endorse or promote products derived from this software 54 * without specific prior written permission. 55 * 56 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 57 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 58 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 59 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 60 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 61 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 62 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 63 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 64 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 65 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 66 * SUCH DAMAGE. 67 * 68 * @(#)machdep.c 8.3 (Berkeley) 1/12/94 69 * from: Utah Hdr: machdep.c 1.63 91/04/24 70 */ 71 72#include <sys/cdefs.h> 73__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.27 2024/03/05 14:15:30 thorpej Exp $"); 74 75#include "opt_ddb.h" 76#include "opt_kgdb.h" 77 78#include "opt_memsize.h" 79#include "opt_modular.h" 80#include "opt_ethaddr.h" 81 82#include "opt_pci.h" 83#include "pci.h" 84 85#include <sys/param.h> 86#include <sys/boot_flag.h> 87#include <sys/buf.h> 88#include <sys/device.h> 89#include <sys/kcore.h> 90#include <sys/kernel.h> 91#include <sys/ksyms.h> 92#include <sys/mount.h> 93#include <sys/reboot.h> 94#include <sys/systm.h> 95#include <sys/termios.h> 96#include <sys/cpu.h> 97 98#include <net/if.h> 99#include <net/if_ether.h> 100 101#include <uvm/uvm_extern.h> 102 103#include <dev/cons.h> 104 105#include "ksyms.h" 106 107#if NKSYMS || defined(DDB) || defined(MODULAR) 108#include <mips/db_machdep.h> 109#include <ddb/db_extern.h> 110#endif 111 112#include <mips/cache.h> 113#include <mips/locore.h> 114 115#include <mips/adm5120/include/adm5120reg.h> 116#include <mips/adm5120/include/adm5120var.h> 117#include <mips/adm5120/include/adm5120_extiovar.h> 118#include <mips/adm5120/include/adm5120_obiovar.h> 119#include <mips/adm5120/include/adm5120_mainbusvar.h> 120#include <mips/adm5120/include/adm5120_pcivar.h> 121#include <mips/adm5120/dev/uart.h> 122 123#ifndef MEMSIZE 124#define MEMSIZE 4 * 1024 * 1024 125#endif /* !MEMSIZE */ 126 127/* Maps for VM objects. */ 128struct vm_map *phys_map = NULL; 129 130int maxmem; /* max memory per process */ 131 132int mem_cluster_cnt; 133phys_ram_seg_t mem_clusters[VM_PHYSSEG_MAX]; 134 135struct adm5120_config adm5120_configuration; 136 137void adm5120_setcpufreq(void); 138 139void 140adm5120_setcpufreq(void) 141{ 142 uint32_t v, freq; 143 144 v = SW_READ(SW_CODE_REG); 145 switch (v & CLKS_MASK) { 146 case CLKS_175MHZ: 147 freq = 175 * 1000 * 1000; 148 break; 149 case CLKS_200MHZ: 150 freq = 200 * 1000 * 1000; 151 break; 152 default: 153 panic("adm5120: cannot determine CPU clock speed"); 154 } 155 156 curcpu()->ci_cpu_freq = freq; 157 curcpu()->ci_cycles_per_hz = (freq + hz / 2) / hz / 2; 158 curcpu()->ci_divisor_delay = ((freq + 500000) / 1000000) / 2; 159} 160 161void mach_init(int, char **, void *, void *); /* XXX */ 162 163static void 164copy_args(int argc, char **argv) 165{ 166 struct adm5120_config *admc = &adm5120_configuration; 167 int i; 168 char *buf; 169 size_t buflen, rc; 170 171 buf = admc->args; 172 buflen = sizeof(admc->args); 173 174 if (argc >= __arraycount(admc->argv)) 175 panic("%s: too many boot args\n", __func__); 176 177 for (i = 0; buflen > 0 && i < argc && argv[i] != NULL; i++) { 178 admc->argv[i] = buf; 179 if ((rc = strlcpy(buf, argv[i], buflen)) >= buflen) 180 panic("%s: boot args too long\n", __func__); 181 182 buf += rc; 183 buflen -= rc; 184 *buf++ = '\0'; 185 buflen--; 186 } 187 if (i < argc) 188 panic("%s: boot args too long\n", __func__); 189 190 admc->argc = argc; 191} 192 193static void 194parse_args(prop_dictionary_t properties, int argc, char **argv, 195 uint32_t *memsizep) 196{ 197 char buf[32]; 198 char *key, *val, *valend; 199 unsigned long tmp; 200 int i; 201 uint8_t enaddr[ETHER_ADDR_LEN]; 202 203 if (memsizep != NULL) 204 *memsizep = MEMSIZE; 205 206 for (i = 0; i < argc && argv[i] != NULL; i++) { 207 if (strlcpy(buf, argv[i], sizeof(buf)) >= sizeof(buf)) 208 goto err; 209 val = buf; 210 key = strsep(&val, "="); 211 if (val == NULL) 212 goto err; 213 if (strcmp(key, "mem") == 0) { 214 tmp = strtoul(val, &valend, 10); 215 if (val == valend || *valend != 'M') 216 goto err; 217 if (memsizep != NULL) 218 *memsizep = tmp * 1024 * 1024; 219 } else if (strcmp(key, "HZ") == 0) 220 ; 221 else if (strcmp(key, "gpio") == 0) { 222 prop_number_t pn; 223 224 tmp = strtoul(val, &valend, 10); 225 if (val == valend || *valend != '\0') 226 goto err; 227 if (properties == NULL) 228 continue; 229 pn = prop_number_create_unsigned_integer(tmp); 230 if (pn == NULL) { 231 printf( 232 "%s: prop_number_create_unsigned_integer\n", 233 __func__); 234 continue; 235 } 236 if (!prop_dictionary_set(properties, "initial-gpio", 237 pn)) { 238 printf("%s: prop_dictionary_set(gpio)\n", 239 __func__); 240 } 241 prop_object_release(pn); 242 } else if (strcmp(key, "kmac") == 0) { 243 prop_data_t pd; 244 245 (void)ether_aton_r(enaddr, sizeof(enaddr), val); 246 if (properties == NULL) 247 continue; 248 pd = prop_data_create_data(enaddr, sizeof(enaddr)); 249 if (pd == NULL) { 250 printf("%s: prop_data_create_data\n", __func__); 251 continue; 252 } 253 if (!prop_dictionary_set(properties, "mac-address", pd)) { 254 printf("%s: prop_dictionary_set(mac)\n", 255 __func__); 256 } 257 prop_object_release(pd); 258 } else if (strcmp(key, "board") == 0) 259 printf("Routerboard %s\n", val); 260 else if (strcmp(key, "boot") == 0) 261 ; 262 continue; 263 err: 264 printf("bad argv[%d] (%s)\n", i, argv[i]); 265 } 266} 267 268void 269mach_init(int argc, char **argv, void *a2, void *a3) 270{ 271 struct adm5120_config *admc = &adm5120_configuration; 272 uint32_t memsize; 273 vaddr_t kernend; 274 275 extern char edata[], end[]; /* XXX */ 276 277 /* clear the BSS segment */ 278 kernend = mips_round_page(end); 279 memset(edata, 0, kernend - (vaddr_t)edata); 280 281 /* set CPU model info for sysctl_hw */ 282 cpu_setmodel("Infineon ADM5120"); 283 284 /* 285 * Set up the exception vectors and CPU-specific function 286 * vectors early on. We need the wbflush() vector set up 287 * before comcnattach() is called (or at least before the 288 * first printf() after that is called). 289 * Sets up mips_cpu_flags that may be queried by other 290 * functions called during startup. 291 * Also clears the I+D caches. 292 */ 293 mips_vector_init(NULL, false); 294 295 uvm_md_init(); 296 297 adm5120_setcpufreq(); 298 299 /* 300 * Initialize bus space tags. 301 */ 302 obio_bus_mem_init(&admc->obio_space, admc); 303 extio_bus_mem_init(&admc->extio_space, admc); 304#if NPCI > 0 305 pciio_bus_mem_init(&admc->pciio_space, admc); 306 pcimem_bus_mem_init(&admc->pcimem_space, admc); 307#endif 308 309 /* 310 * Initialize bus DMA tag. 311 */ 312 obio_dma_init(&admc->obio_dmat); 313 314 /* 315 * Attach serial console. 316 */ 317 uart_cnattach(); 318 319 /* 320 * Look at arguments passed to us and compute boothowto. 321 */ 322 boothowto = RB_AUTOBOOT; 323#ifdef KADB 324 boothowto |= RB_KDB; 325#endif 326 327 parse_args(NULL, argc, argv, &memsize); 328 329 /* 330 * Determine the memory size. 331 * 332 * Note: Reserve the first page! That's where the trap 333 * vectors are located. 334 */ 335 336#if 0 337 if (GET_MEMSIZE(memsize) == 0) { 338 uint32_t val; 339 340 /* This does not seem to work... --dyoung */ 341 val = SW_READ(SW_MEMCONT_REG); 342 printf("SW_MEMCONT_REG: 0x%08" PRIx32 "\n", val); 343 switch (val & SDRAM_SIZE_MASK) { 344 case SDRAM_SIZE_4MBYTES: 345 memsize = 4 * 1024 * 1024; 346 break; 347 case SDRAM_SIZE_8MBYTES: 348 memsize = 8 * 1024 * 1024; 349 break; 350 case SDRAM_SIZE_16MBYTES: 351 memsize = 16 * 1024 * 1024; 352 break; 353 case SDRAM_SIZE_64MBYTES: 354 memsize = 64 * 1024 * 1024; 355 break; 356 case SDRAM_SIZE_128MBYTES: 357 memsize = 128 * 1024 * 1024; 358 break; 359 default: 360 panic("adm5120: cannot determine memory size"); 361 } 362 } 363#endif 364 365 physmem = btoc(memsize); 366 367 mem_clusters[mem_cluster_cnt].start = PAGE_SIZE; 368 mem_clusters[mem_cluster_cnt].size = 369 memsize - mem_clusters[mem_cluster_cnt].start; 370 mem_cluster_cnt++; 371 372 /* 373 * Load the rest of the available pages into the VM system. 374 */ 375 mips_page_physload(MIPS_KSEG0_START, (vaddr_t) kernend, 376 mem_clusters, mem_cluster_cnt, NULL, 0); 377 378 /* 379 * Initialize message buffer (at end of core). 380 */ 381 mips_init_msgbuf(); 382 383 /* 384 * Initialize the virtual memory system. 385 */ 386 pmap_bootstrap(); 387 388 /* 389 * Allocate uarea page for lwp0 and set it. 390 */ 391 mips_init_lwp0_uarea(); 392 393 /* 394 * Initialize debuggers, and break into them, if appropriate. 395 */ 396#ifdef DDB 397 if (boothowto & RB_KDB) 398 Debugger(); 399#endif 400 401 copy_args(argc, argv); 402} 403 404void 405consinit(void) 406{ 407 408 /* 409 * Everything related to console initialization is done 410 * in mach_init(). 411 */ 412} 413 414void 415cpu_startup(void) 416{ 417 struct adm5120_config *admc = &adm5120_configuration; 418 419 if ((admc->properties = prop_dictionary_create()) == NULL) 420 printf("%s: prop_dictionary_create\n", __func__); 421 parse_args(admc->properties, admc->argc, admc->argv, NULL); 422 423 cpu_startup_common(); 424} 425 426void 427cpu_reboot(int howto, char *bootstr) 428{ 429 static int waittime = -1; 430 431 /* Take a snapshot before clobbering any registers. */ 432 savectx(curpcb); 433 434 /* If "always halt" was specified as a boot flag, obey. */ 435 if (boothowto & RB_HALT) 436 howto |= RB_HALT; 437 438 boothowto = howto; 439 440 /* If system is cold, just halt. */ 441 if (cold) { 442 boothowto |= RB_HALT; 443 goto haltsys; 444 } 445 446 if ((boothowto & RB_NOSYNC) == 0 && waittime < 0) { 447 waittime = 0; 448 449 /* 450 * Synchronize the disks.... 451 */ 452 vfs_shutdown(); 453 } 454 455 /* Disable interrupts. */ 456 splhigh(); 457 458 if (boothowto & RB_DUMP) 459 dumpsys(); 460 461 haltsys: 462 /* Run any shutdown hooks. */ 463 doshutdownhooks(); 464 465 pmf_system_shutdown(boothowto); 466 467 /* 468 * Routerboard BIOS may autoboot, so "pseudo-halt". 469 */ 470 if (boothowto & RB_HALT) { 471 printf("\n"); 472 printf("The operating system has halted.\n"); 473 printf("Please press any key to reboot.\n\n"); 474 cnpollc(1); /* For proper keyboard command handling */ 475 cngetc(); 476 cnpollc(0); 477 } 478 479 printf("resetting board...\n\n"); 480 mips_icache_sync_all(); 481 mips_dcache_wbinv_all(); 482 SW_WRITE(SW_SFTRES_REG, 0); /* reset */ 483 for (;;) 484 /* spin forever */ ; /* XXX */ 485 /*NOTREACHED*/ 486} 487