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