1/*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2006 Wojciech A. Koszek <wkoszek@FreeBSD.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * 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 copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $FreeBSD$ 29 */ 30#include <sys/cdefs.h> 31__FBSDID("$FreeBSD$"); 32 33#include "opt_ddb.h" 34 35#include <sys/param.h> 36#include <sys/conf.h> 37#include <sys/kernel.h> 38#include <sys/systm.h> 39#include <sys/imgact.h> 40#include <sys/bio.h> 41#include <sys/buf.h> 42#include <sys/bus.h> 43#include <sys/cpu.h> 44#include <sys/cons.h> 45#include <sys/exec.h> 46#include <sys/ucontext.h> 47#include <sys/proc.h> 48#include <sys/kdb.h> 49#include <sys/ptrace.h> 50#include <sys/reboot.h> 51#include <sys/signalvar.h> 52#include <sys/sysent.h> 53#include <sys/sysproto.h> 54#include <sys/user.h> 55 56#include <vm/vm.h> 57#include <vm/vm_object.h> 58#include <vm/vm_page.h> 59 60#include <machine/clock.h> 61#include <machine/cpu.h> 62#include <machine/cpuregs.h> 63#include <machine/hwfunc.h> 64#include <machine/md_var.h> 65#include <machine/pmap.h> 66#include <machine/trap.h> 67 68#ifdef TICK_USE_YAMON_FREQ 69#include <mips/malta/yamon.h> 70#endif 71 72#ifdef TICK_USE_MALTA_RTC 73#include <mips/mips4k/malta/maltareg.h> 74#include <dev/mc146818/mc146818reg.h> 75#include <isa/rtc.h> 76#endif 77 78#include <mips/malta/maltareg.h> 79 80extern int *edata; 81extern int *end; 82 83void lcd_init(void); 84void lcd_puts(char *); 85void malta_reset(void); 86 87/* 88 * Temporary boot environment used at startup. 89 */ 90static char boot1_env[4096]; 91 92/* 93 * Offsets to MALTA LCD characters. 94 */ 95static int malta_lcd_offs[] = { 96 MALTA_ASCIIPOS0, 97 MALTA_ASCIIPOS1, 98 MALTA_ASCIIPOS2, 99 MALTA_ASCIIPOS3, 100 MALTA_ASCIIPOS4, 101 MALTA_ASCIIPOS5, 102 MALTA_ASCIIPOS6, 103 MALTA_ASCIIPOS7 104}; 105 106void 107platform_cpu_init() 108{ 109 /* Nothing special */ 110} 111 112/* 113 * Put character to Malta LCD at given position. 114 */ 115static void 116malta_lcd_putc(int pos, char c) 117{ 118 void *addr; 119 char *ch; 120 121 if (pos < 0 || pos > 7) 122 return; 123 addr = (void *)(MALTA_ASCII_BASE + malta_lcd_offs[pos]); 124 ch = (char *)MIPS_PHYS_TO_KSEG0(addr); 125 *ch = c; 126} 127 128/* 129 * Print given string on LCD. 130 */ 131static void 132malta_lcd_print(char *str) 133{ 134 int i; 135 136 if (str == NULL) 137 return; 138 139 for (i = 0; *str != '\0'; i++, str++) 140 malta_lcd_putc(i, *str); 141} 142 143void 144lcd_init(void) 145{ 146 malta_lcd_print("FreeBSD_"); 147} 148 149void 150lcd_puts(char *s) 151{ 152 malta_lcd_print(s); 153} 154 155#ifdef TICK_USE_MALTA_RTC 156static __inline uint8_t 157rtcin(uint8_t addr) 158{ 159 160 *((volatile uint8_t *) 161 MIPS_PHYS_TO_KSEG1(MALTA_PCI0_ADDR(MALTA_RTCADR))) = addr; 162 return (*((volatile uint8_t *) 163 MIPS_PHYS_TO_KSEG1(MALTA_PCI0_ADDR(MALTA_RTCDAT)))); 164} 165 166static __inline void 167writertc(uint8_t addr, uint8_t val) 168{ 169 170 *((volatile uint8_t *) 171 MIPS_PHYS_TO_KSEG1(MALTA_PCI0_ADDR(MALTA_RTCADR))) = addr; 172 *((volatile uint8_t *) 173 MIPS_PHYS_TO_KSEG1(MALTA_PCI0_ADDR(MALTA_RTCDAT))) = val; 174} 175#endif 176 177static void 178mips_init(unsigned long memsize, uint64_t ememsize) 179{ 180 int i; 181 182 for (i = 0; i < PHYS_AVAIL_ENTRIES; i++) { 183 phys_avail[i] = 0; 184 } 185 186 /* 187 * memsize is the amount of RAM available below 256MB. 188 * ememsize is the total amount of RAM available. 189 * 190 * The second bank starts at 0x90000000. 191 */ 192 193 /* phys_avail regions are in bytes */ 194 phys_avail[0] = MIPS_KSEG0_TO_PHYS(kernel_kseg0_end); 195 phys_avail[1] = memsize; 196 dump_avail[0] = 0; 197 dump_avail[1] = phys_avail[1]; 198 199 /* Only specify the extended region if it's set */ 200 if (ememsize > memsize) { 201 phys_avail[2] = 0x90000000; 202 phys_avail[3] = 0x90000000 + (ememsize - memsize); 203 dump_avail[2] = phys_avail[2]; 204 dump_avail[3] = phys_avail[3]; 205 } 206 207 /* XXX realmem assigned in the caller of mips_init() */ 208 physmem = realmem; 209 210 init_param1(); 211 init_param2(physmem); 212 mips_cpu_init(); 213 pmap_bootstrap(); 214 mips_proc0_init(); 215 mutex_init(); 216 kdb_init(); 217#ifdef KDB 218 if (boothowto & RB_KDB) 219 kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger"); 220#endif 221} 222 223/* 224 * Perform a board-level soft-reset. 225 * Note that this is not emulated by gxemul. 226 */ 227void 228platform_reset(void) 229{ 230 char *c; 231 232 c = (char *)MIPS_PHYS_TO_KSEG0(MALTA_SOFTRES); 233 *c = MALTA_GORESET; 234} 235 236static uint64_t 237malta_cpu_freq(void) 238{ 239 uint64_t platform_counter_freq = 0; 240 241#if defined(TICK_USE_YAMON_FREQ) 242 /* 243 * If we are running on a board which uses YAMON firmware, 244 * then query CPU pipeline clock from the syscon object. 245 * If unsuccessful, use hard-coded default. 246 */ 247 platform_counter_freq = yamon_getcpufreq(); 248 249#elif defined(TICK_USE_MALTA_RTC) 250 /* 251 * If we are running on a board with the MC146818 RTC, 252 * use it to determine CPU pipeline clock frequency. 253 */ 254 u_int64_t counterval[2]; 255 256 /* Set RTC to binary mode. */ 257 writertc(RTC_STATUSB, (rtcin(RTC_STATUSB) | RTCSB_BCD)); 258 259 /* Busy-wait for falling edge of RTC update. */ 260 while (((rtcin(RTC_STATUSA) & RTCSA_TUP) == 0)) 261 ; 262 while (((rtcin(RTC_STATUSA)& RTCSA_TUP) != 0)) 263 ; 264 counterval[0] = mips_rd_count(); 265 266 /* Busy-wait for falling edge of RTC update. */ 267 while (((rtcin(RTC_STATUSA) & RTCSA_TUP) == 0)) 268 ; 269 while (((rtcin(RTC_STATUSA)& RTCSA_TUP) != 0)) 270 ; 271 counterval[1] = mips_rd_count(); 272 273 platform_counter_freq = counterval[1] - counterval[0]; 274#endif 275 276 if (platform_counter_freq == 0) 277 platform_counter_freq = MIPS_DEFAULT_HZ; 278 279 return (platform_counter_freq); 280} 281 282void 283platform_start(__register_t a0, __register_t a1, __register_t a2, 284 __register_t a3) 285{ 286 vm_offset_t kernend; 287 uint64_t platform_counter_freq; 288 int argc = a0; 289 int32_t *argv = (int32_t*)a1; 290 int32_t *envp = (int32_t*)a2; 291 unsigned int memsize = a3; 292 uint64_t ememsize = 0; 293 int i; 294 295 /* clear the BSS and SBSS segments */ 296 kernend = (vm_offset_t)&end; 297 memset(&edata, 0, kernend - (vm_offset_t)(&edata)); 298 299 mips_postboot_fixup(); 300 301 mips_pcpu0_init(); 302 platform_counter_freq = malta_cpu_freq(); 303 mips_timer_early_init(platform_counter_freq); 304 init_static_kenv(boot1_env, sizeof(boot1_env)); 305 306 cninit(); 307 printf("entry: platform_start()\n"); 308 309 bootverbose = 1; 310 311 /* 312 * YAMON uses 32bit pointers to strings so 313 * convert them to proper type manually 314 */ 315 316 if (bootverbose) { 317 printf("cmd line: "); 318 for (i = 0; i < argc; i++) 319 printf("%s ", (char*)(intptr_t)argv[i]); 320 printf("\n"); 321 } 322 323 if (bootverbose) 324 printf("envp:\n"); 325 326 /* 327 * Parse the environment for things like ememsize. 328 */ 329 for (i = 0; envp[i]; i += 2) { 330 const char *a, *v; 331 332 a = (char *)(intptr_t)envp[i]; 333 v = (char *)(intptr_t)envp[i+1]; 334 335 if (bootverbose) 336 printf("\t%s = %s\n", a, v); 337 338 if (strcmp(a, "ememsize") == 0) { 339 ememsize = strtoul(v, NULL, 0); 340 } 341 } 342 343 if (bootverbose) { 344 printf("memsize = %llu (0x%08x)\n", 345 (unsigned long long) memsize, memsize); 346 printf("ememsize = %llu\n", (unsigned long long) ememsize); 347 348#ifdef __mips_o32 349 /* 350 * For O32 phys_avail[] can't address memory beyond 2^32, 351 * so cap extended memory to 2GB minus one page. 352 */ 353 if (ememsize >= 2ULL * 1024 * 1024 * 1024) 354 ememsize = 2ULL * 1024 * 1024 * 1024 - PAGE_SIZE; 355#endif 356 } 357 358 /* 359 * For <= 256MB RAM amounts, ememsize should equal memsize. 360 * For > 256MB RAM amounts it's the total RAM available; 361 * split between two banks. 362 * 363 * XXX TODO: just push realmem assignment into mips_init() ? 364 */ 365 realmem = btoc(ememsize); 366 mips_init(memsize, ememsize); 367 368 mips_timer_init_params(platform_counter_freq, 0); 369} 370