1/* $NetBSD: machdep.c,v 1.17 2024/03/05 14:15:30 thorpej Exp $ */ 2 3/*- 4 * Copyright (c) 2014 Michael Lorenz 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include <sys/cdefs.h> 30__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.17 2024/03/05 14:15:30 thorpej Exp $"); 31 32#include "opt_ddb.h" 33#include "opt_kgdb.h" 34#include "opt_modular.h" 35#include "opt_multiprocessor.h" 36 37#include <sys/param.h> 38#include <sys/boot_flag.h> 39#include <sys/device.h> 40#include <sys/kernel.h> 41#include <sys/kcore.h> 42#include <sys/ksyms.h> 43#include <sys/mount.h> 44#include <sys/reboot.h> 45#include <sys/cpu.h> 46#include <sys/bus.h> 47#include <sys/mutex.h> 48 49#include <uvm/uvm_extern.h> 50 51#include <dev/cons.h> 52 53#include "ksyms.h" 54 55#if NKSYMS || defined(DDB) || defined(MODULAR) 56#include <mips/db_machdep.h> 57#include <ddb/db_extern.h> 58#endif 59 60#include <mips/cache.h> 61#include <mips/locore.h> 62#include <mips/cpuregs.h> 63 64#include <mips/ingenic/ingenic_coreregs.h> 65#include <mips/ingenic/ingenic_regs.h> 66#include <mips/ingenic/ingenic_var.h> 67 68#include "opt_ingenic.h" 69 70/* Maps for VM objects. */ 71struct vm_map *phys_map = NULL; 72 73int maxmem; /* max memory per process */ 74 75int mem_cluster_cnt; 76phys_ram_seg_t mem_clusters[VM_PHYSSEG_MAX]; 77 78void mach_init(void); /* XXX */ 79void ingenic_reset(void); 80 81void ingenic_putchar_init(void); 82void ingenic_puts(const char *); 83void ingenic_com_cnattach(void); 84 85#ifdef MULTIPROCESSOR 86kmutex_t ingenic_ipi_lock; 87#endif 88 89/* Currently the Ingenic kernels (CI20) only support little endian boards */ 90CTASSERT(_BYTE_ORDER == _LITTLE_ENDIAN); 91 92static void 93cal_timer(void) 94{ 95 uint32_t cntfreq; 96 volatile uint32_t junk; 97 98 /* 99 * The manual seems to imply that EXCCLK is 12MHz, although in real 100 * life it appears to be 48MHz. Either way, we want a 12MHz counter. 101 */ 102 curcpu()->ci_cpu_freq = 1200000000; /* for now */ 103 cntfreq = 12000000; /* EXTCLK / 4 */ 104 105 curcpu()->ci_cctr_freq = cntfreq; 106 curcpu()->ci_cycles_per_hz = (cntfreq + hz / 2) / hz; 107 108 /* Compute number of cycles per 1us (1/MHz). 0.5MHz is for roundup. */ 109 curcpu()->ci_divisor_delay = ((cntfreq + 500000) / 1000000); 110 111 /* actually start the counter now */ 112 /* stop OS timer */ 113 writereg(JZ_TC_TECR, TESR_OST); 114 /* zero everything */ 115 writereg(JZ_OST_CTRL, 0); 116 writereg(JZ_OST_CNT_LO, 0); 117 writereg(JZ_OST_CNT_HI, 0); 118 writereg(JZ_OST_DATA, 0xffffffff); 119 /* use EXTCLK, don't reset */ 120 writereg(JZ_OST_CTRL, OSTC_EXT_EN | OSTC_MODE | OSTC_DIV_4); 121 /* start the timer */ 122 writereg(JZ_TC_TESR, TESR_OST); 123 /* make sure the timer actually runs */ 124 junk = readreg(JZ_OST_CNT_LO); 125 do {} while (junk == readreg(JZ_OST_CNT_LO)); 126} 127 128#ifdef MULTIPROCESSOR 129static void 130ingenic_cpu_init(struct cpu_info *ci) 131{ 132 uint32_t reg; 133 134 /* enable IPIs for this core */ 135 reg = mips_cp0_corereim_read(); 136 if (cpu_index(ci) == 1) { 137 reg |= REIM_MIRQ1_M; 138 } else 139 reg |= REIM_MIRQ0_M; 140 mips_cp0_corereim_write(reg); 141 printf("%s %d %08x\n", __func__, cpu_index(ci), reg); 142} 143 144static int 145ingenic_send_ipi(struct cpu_info *ci, int tag) 146{ 147 uint32_t msg; 148 149 msg = 1 << tag; 150 151 mutex_enter(&ingenic_ipi_lock); 152 if (kcpuset_isset(cpus_running, cpu_index(ci))) { 153 if (cpu_index(ci) == 0) { 154 mips_cp0_corembox_write(msg, 0); 155 } else { 156 mips_cp0_corembox_write(msg, 1); 157 } 158 } 159 mutex_exit(&ingenic_ipi_lock); 160 return 0; 161} 162#endif /* MULTIPROCESSOR */ 163 164void 165mach_init(void) 166{ 167 void *kernend; 168 uint32_t memsize; 169 extern char edata[], end[]; /* XXX */ 170 171 /* clear the BSS segment */ 172 kernend = (void *)mips_round_page(end); 173 174 memset(edata, 0, (char *)kernend - edata); 175 176 /* setup early console */ 177 ingenic_putchar_init(); 178 179 /* set CPU model info for sysctl_hw */ 180 cpu_setmodel("Ingenic XBurst"); 181 mips_vector_init(NULL, false); 182 cal_timer(); 183 uvm_md_init(); 184 /* 185 * Look at arguments passed to us and compute boothowto. 186 */ 187 boothowto = RB_AUTOBOOT; 188#ifdef KADB 189 boothowto |= RB_KDB; 190#endif 191 192 /* 193 * Determine the memory size. 194 * 195 * Note: Reserve the first page! That's where the trap 196 * vectors are located. 197 */ 198 memsize = 0x40000000; 199 200 printf("Memory size: 0x%08x\n", memsize); 201 physmem = btoc(memsize); 202 203 /* 204 * memory is at 0x20000000 with first 256MB mirrored to 0x00000000 so 205 * we can see them through KSEG* 206 * assume 1GB for now, the SoC can theoretically support up to 3GB 207 */ 208 mem_clusters[0].start = PAGE_SIZE; 209 mem_clusters[0].size = 0x10000000 - PAGE_SIZE; 210 mem_clusters[1].start = 0x30000000; 211 mem_clusters[1].size = 0x30000000; 212 mem_cluster_cnt = 2; 213 214 /* 215 * Load the available pages into the VM system. 216 */ 217 mips_page_physload(MIPS_KSEG0_START, (vaddr_t)kernend, 218 mem_clusters, mem_cluster_cnt, NULL, 0); 219 220 /* 221 * Initialize message buffer (at end of core). 222 */ 223 mips_init_msgbuf(); 224 225 /* 226 * Initialize the virtual memory system. 227 */ 228 pmap_bootstrap(); 229 230 /* 231 * Allocate uarea page for lwp0 and set it. 232 */ 233 mips_init_lwp0_uarea(); 234 235#ifdef MULTIPROCESSOR 236 mutex_init(&ingenic_ipi_lock, MUTEX_DEFAULT, IPL_HIGH); 237 mips_locoresw.lsw_send_ipi = ingenic_send_ipi; 238 mips_locoresw.lsw_cpu_init = ingenic_cpu_init; 239#endif 240 241 apbus_init(); 242 /* 243 * Initialize debuggers, and break into them, if appropriate. 244 */ 245#ifdef DDB 246 if (boothowto & RB_KDB) 247 Debugger(); 248#endif 249} 250 251void 252consinit(void) 253{ 254 /* 255 * Everything related to console initialization is done 256 * in mach_init(). 257 */ 258 apbus_init(); 259 ingenic_com_cnattach(); 260} 261 262void 263cpu_startup(void) 264{ 265 cpu_startup_common(); 266} 267 268void 269cpu_reboot(int howto, char *bootstr) 270{ 271 static int waittime = -1; 272 273 /* Take a snapshot before clobbering any registers. */ 274 savectx(curpcb); 275 276 /* If "always halt" was specified as a boot flag, obey. */ 277 if (boothowto & RB_HALT) 278 howto |= RB_HALT; 279 280 boothowto = howto; 281 282 /* If system is cold, just halt. */ 283 if (cold) { 284 boothowto |= RB_HALT; 285 goto haltsys; 286 } 287 288 if ((boothowto & RB_NOSYNC) == 0 && waittime < 0) { 289 waittime = 0; 290 291 /* 292 * Synchronize the disks.... 293 */ 294 vfs_shutdown(); 295 } 296 297 /* Disable interrupts. */ 298 splhigh(); 299 300 if (boothowto & RB_DUMP) 301 dumpsys(); 302 303haltsys: 304 /* Run any shutdown hooks. */ 305 doshutdownhooks(); 306 307 pmf_system_shutdown(boothowto); 308 309#if 0 310 if ((boothowto & RB_POWERDOWN) == RB_POWERDOWN) 311 if (board && board->ab_poweroff) 312 board->ab_poweroff(); 313#endif 314 315 /* 316 * Firmware may autoboot (depending on settings), and we cannot pass 317 * flags to it (at least I haven't figured out how to yet), so 318 * we "pseudo-halt" now. 319 */ 320 if (boothowto & RB_HALT) { 321 printf("\n"); 322 printf("The operating system has halted.\n"); 323 printf("Please press any key to reboot.\n\n"); 324 cnpollc(1); /* For proper keyboard command handling */ 325 cngetc(); 326 cnpollc(0); 327 } 328 329 printf("resetting board...\n\n"); 330 mips_icache_sync_all(); 331 mips_dcache_wbinv_all(); 332 ingenic_reset(); 333 __asm volatile("jr %0" :: "r"(MIPS_RESET_EXC_VEC)); 334 printf("Oops, back from reset\n\nSpinning..."); 335 for (;;) 336 /* spin forever */ ; /* XXX */ 337 /*NOTREACHED*/ 338} 339 340void 341ingenic_reset(void) 342{ 343 /* 344 * for now, provoke a watchdog reset in about a second, so UART buffers 345 * have a fighting chance to flush before we pull the plug 346 */ 347 writereg(JZ_WDOG_TCER, 0); /* disable watchdog */ 348 writereg(JZ_WDOG_TCNT, 0); /* reset counter */ 349 writereg(JZ_WDOG_TDR, 128); /* wait for ~1s */ 350 writereg(JZ_WDOG_TCSR, TCSR_RTC_EN | TCSR_DIV_256); 351 writereg(JZ_WDOG_TCER, TCER_ENABLE); /* fire! */ 352} 353