1 /* $NetBSD: meson_platform.c,v 1.13 2019/08/13 09:56:08 skrll Exp $ */ 2 3 /*- 4 * Copyright (c) 2019 Jared McNeill <jmcneill@invisible.ca> 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 ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * 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 29 #include "opt_soc.h" 30 #include "opt_multiprocessor.h" 31 #include "opt_console.h" 32 33 #include "arml2cc.h" 34 35 #include <sys/cdefs.h> 36 __KERNEL_RCSID(0, "$NetBSD: meson_platform.c,v 1.13 2019/08/13 09:56:08 skrll Exp $"); 37 38 #include <sys/param.h> 39 #include <sys/bus.h> 40 #include <sys/cpu.h> 41 #include <sys/device.h> 42 #include <sys/termios.h> 43 44 #include <dev/fdt/fdtvar.h> 45 #include <arm/fdt/arm_fdtvar.h> 46 47 #include <uvm/uvm_extern.h> 48 49 #include <machine/bootconfig.h> 50 #include <arm/cpufunc.h> 51 52 #include <arm/cortex/a9tmr_var.h> 53 #include <arm/cortex/gtmr_var.h> 54 #include <arm/cortex/pl310_var.h> 55 #include <arm/cortex/scu_reg.h> 56 57 #include <arm/amlogic/meson_uart.h> 58 59 #include <evbarm/fdt/platform.h> 60 #include <evbarm/fdt/machdep.h> 61 62 #include <net/if_ether.h> 63 64 #include <libfdt.h> 65 66 #define MESON_CORE_APB3_VBASE KERNEL_IO_VBASE 67 #define MESON_CORE_APB3_PBASE 0xc0000000 68 #define MESON_CORE_APB3_SIZE 0x01400000 69 70 #define MESON_CBUS_OFFSET 0x01100000 71 72 #define MESON8B_WATCHDOG_BASE 0xc1109900 73 #define MESON8B_WATCHDOG_SIZE 0x8 74 #define MESON8B_WATCHDOG_TC 0x00 75 #define MESON8B_WATCHDOG_TC_CPUS __BITS(27,24) 76 #define MESON8B_WATCHDOG_TC_ENABLE __BIT(19) 77 #define MESON8B_WATCHDOG_TC_TCNT __BITS(15,0) 78 #define MESON8B_WATCHDOG_RESET 0x04 79 #define MESON8B_WATCHDOG_RESET_COUNT __BITS(15,0) 80 81 #define MESONGX_WATCHDOG_BASE 0xc11098d0 82 #define MESONGX_WATCHDOG_SIZE 0x10 83 #define MESONGX_WATCHDOG_CNTL 0x00 84 #define MESONGX_WATCHDOG_CNTL_CLK_EN __BIT(24) 85 #define MESONGX_WATCHDOG_CNTL_SYS_RESET_N_EN __BIT(21) 86 #define MESONGX_WATCHDOG_CNTL_WDOG_EN __BIT(18) 87 #define MESONGX_WATCHDOG_CNTL1 0x04 88 #define MESONGX_WATCHDOG_TCNT 0x08 89 #define MESONGX_WATCHDOG_TCNT_COUNT __BITS(15,0) 90 #define MESONGX_WATCHDOG_RESET 0x0c 91 92 #define MESON8B_ARM_VBASE (MESON_CORE_APB3_VBASE + MESON_CORE_APB3_SIZE) 93 #define MESON8B_ARM_PBASE 0xc4200000 94 #define MESON8B_ARM_SIZE 0x00200000 95 #define MESON8B_ARM_PL310_BASE 0x00000000 96 #define MESON8B_ARM_SCU_BASE 0x00100000 97 98 #define MESON8B_AOBUS_VBASE (MESON8B_ARM_VBASE + MESON8B_ARM_SIZE) 99 #define MESON8B_AOBUS_PBASE 0xc8000000 100 #define MESON8B_AOBUS_SIZE 0x00200000 101 #define MESON8B_AOBUS_RTI_OFFSET 0x00100000 102 103 #define MESON_AOBUS_PWR_CTRL0_REG 0xe0 104 #define MESON_AOBUS_PWR_CTRL1_REG 0xe4 105 #define MESON_AOBUS_PWR_MEM_PD0_REG 0xf4 106 107 #define MESON_CBUS_CPU_CLK_CNTL_REG 0x419c 108 109 110 #define MESON8B_SRAM_VBASE (MESON8B_AOBUS_VBASE + MESON8B_AOBUS_SIZE) 111 #define MESON8B_SRAM_PBASE 0xd9000000 112 #define MESON8B_SRAM_SIZE 0x00200000 /* 0x10000 rounded up */ 113 114 #define MESON8B_SRAM_CPUCONF_OFFSET 0x1ff80 115 #define MESON8B_SRAM_CPUCONF_CTRL_REG 0x00 116 #define MESON8B_SRAM_CPUCONF_CPU_ADDR_REG(n) (0x04 * (n)) 117 118 119 extern struct arm32_bus_dma_tag arm_generic_dma_tag; 120 extern struct bus_space arm_generic_bs_tag; 121 extern struct bus_space arm_generic_a4x_bs_tag; 122 123 #define meson_dma_tag arm_generic_dma_tag 124 #define meson_bs_tag arm_generic_bs_tag 125 #define meson_a4x_bs_tag arm_generic_a4x_bs_tag 126 127 static const struct pmap_devmap * 128 meson_platform_devmap(void) 129 { 130 static const struct pmap_devmap devmap[] = { 131 DEVMAP_ENTRY(MESON_CORE_APB3_VBASE, 132 MESON_CORE_APB3_PBASE, 133 MESON_CORE_APB3_SIZE), 134 DEVMAP_ENTRY(MESON8B_ARM_VBASE, 135 MESON8B_ARM_PBASE, 136 MESON8B_ARM_SIZE), 137 DEVMAP_ENTRY(MESON8B_AOBUS_VBASE, 138 MESON8B_AOBUS_PBASE, 139 MESON8B_AOBUS_SIZE), 140 DEVMAP_ENTRY(MESON8B_SRAM_VBASE, 141 MESON8B_SRAM_PBASE, 142 MESON8B_SRAM_SIZE), 143 DEVMAP_ENTRY_END 144 }; 145 146 return devmap; 147 } 148 149 static void 150 meson_platform_init_attach_args(struct fdt_attach_args *faa) 151 { 152 faa->faa_bst = &meson_bs_tag; 153 faa->faa_a4x_bst = &meson_a4x_bs_tag; 154 faa->faa_dmat = &meson_dma_tag; 155 } 156 157 void meson_platform_early_putchar(char); 158 159 void 160 meson_platform_early_putchar(char c) 161 { 162 #ifdef CONSADDR 163 #define CONSADDR_VA ((CONSADDR - MESON8B_AOBUS_PBASE) + MESON8B_AOBUS_VBASE) 164 volatile uint32_t *uartaddr = cpu_earlydevice_va_p() ? 165 (volatile uint32_t *)CONSADDR_VA : 166 (volatile uint32_t *)CONSADDR; 167 int timo = 150000; 168 169 while ((uartaddr[UART_STATUS_REG/4] & UART_STATUS_TX_EMPTY) == 0) { 170 if (--timo == 0) 171 break; 172 } 173 174 uartaddr[UART_WFIFO_REG/4] = c; 175 176 while ((uartaddr[UART_STATUS_REG/4] & UART_STATUS_TX_EMPTY) == 0) { 177 if (--timo == 0) 178 break; 179 } 180 #endif 181 } 182 183 static void 184 meson_platform_device_register(device_t self, void *aux) 185 { 186 prop_dictionary_t dict = device_properties(self); 187 188 if (device_is_a(self, "awge") && device_unit(self) == 0) { 189 uint8_t enaddr[ETHER_ADDR_LEN]; 190 if (get_bootconf_option(boot_args, "awge0.mac-address", 191 BOOTOPT_TYPE_MACADDR, enaddr)) { 192 prop_data_t pd = prop_data_create_data(enaddr, 193 sizeof(enaddr)); 194 prop_dictionary_set(dict, "mac-address", pd); 195 prop_object_release(pd); 196 } 197 } 198 199 if (device_is_a(self, "mesonfb")) { 200 int scale, depth; 201 202 if (get_bootconf_option(boot_args, "fb.scale", 203 BOOTOPT_TYPE_INT, &scale) && scale > 0) { 204 prop_dictionary_set_uint32(dict, "scale", scale); 205 } 206 if (get_bootconf_option(boot_args, "fb.depth", 207 BOOTOPT_TYPE_INT, &depth)) { 208 prop_dictionary_set_uint32(dict, "depth", depth); 209 } 210 } 211 } 212 213 #if defined(SOC_MESON8B) 214 #define MESON8B_BOOTINFO_REG 0xd901ff04 215 static int 216 meson8b_get_boot_id(void) 217 { 218 static int boot_id = -1; 219 bus_space_tag_t bst = &arm_generic_bs_tag; 220 bus_space_handle_t bsh; 221 222 if (boot_id == -1) { 223 if (bus_space_map(bst, MESON8B_BOOTINFO_REG, 4, 0, &bsh) != 0) 224 return -1; 225 226 boot_id = (int)bus_space_read_4(bst, bsh, 0); 227 228 bus_space_unmap(bst, bsh, 4); 229 } 230 231 return boot_id; 232 } 233 234 static void 235 meson8b_platform_device_register(device_t self, void *aux) 236 { 237 device_t parent = device_parent(self); 238 char *ptr; 239 240 if (device_is_a(self, "ld") && 241 device_is_a(parent, "sdmmc") && 242 (device_is_a(device_parent(parent), "mesonsdhc") || 243 device_is_a(device_parent(parent), "mesonsdio"))) { 244 245 const int boot_id = meson8b_get_boot_id(); 246 const bool has_rootdev = get_bootconf_option(boot_args, "root", BOOTOPT_TYPE_STRING, &ptr) != 0; 247 248 if (!has_rootdev) { 249 char rootarg[64]; 250 snprintf(rootarg, sizeof(rootarg), " root=%sa", device_xname(self)); 251 252 /* Assume that SDIO is used for SD cards and SDHC is used for eMMC */ 253 if (device_is_a(device_parent(parent), "mesonsdhc") && boot_id == 0) 254 strcat(boot_args, rootarg); 255 else if (device_is_a(device_parent(parent), "mesonsdio") && boot_id != 0) 256 strcat(boot_args, rootarg); 257 } 258 } 259 260 meson_platform_device_register(self, aux); 261 } 262 #endif 263 264 static u_int 265 meson_platform_uart_freq(void) 266 { 267 return 0; 268 } 269 270 static void 271 meson_platform_bootstrap(void) 272 { 273 arm_fdt_cpu_bootstrap(); 274 275 void *fdt_data = __UNCONST(fdtbus_get_data()); 276 const int chosen_off = fdt_path_offset(fdt_data, "/chosen"); 277 if (chosen_off < 0) 278 return; 279 280 if (match_bootconf_option(boot_args, "console", "fb")) { 281 const int framebuffer_off = 282 fdt_path_offset(fdt_data, "/chosen/framebuffer"); 283 if (framebuffer_off >= 0) { 284 const char *status = fdt_getprop(fdt_data, 285 framebuffer_off, "status", NULL); 286 if (status == NULL || strncmp(status, "ok", 2) == 0) { 287 fdt_setprop_string(fdt_data, chosen_off, 288 "stdout-path", "/chosen/framebuffer"); 289 } 290 } 291 } else if (match_bootconf_option(boot_args, "console", "serial")) { 292 fdt_setprop_string(fdt_data, chosen_off, 293 "stdout-path", "serial0:115200n8"); 294 } 295 } 296 297 #if defined(SOC_MESON8B) 298 static void 299 meson8b_platform_bootstrap(void) 300 { 301 302 #if NARML2CC > 0 303 const bus_space_handle_t pl310_bh = MESON8B_ARM_VBASE + MESON8B_ARM_PL310_BASE; 304 arml2cc_init(&arm_generic_bs_tag, pl310_bh, 0); 305 #endif 306 307 meson_platform_bootstrap(); 308 } 309 310 static void 311 meson8b_platform_reset(void) 312 { 313 bus_space_tag_t bst = &meson_bs_tag; 314 bus_space_handle_t bsh; 315 316 bus_space_map(bst, MESON8B_WATCHDOG_BASE, MESON8B_WATCHDOG_SIZE, 0, &bsh); 317 318 bus_space_write_4(bst, bsh, MESON8B_WATCHDOG_TC, 319 MESON8B_WATCHDOG_TC_CPUS | MESON8B_WATCHDOG_TC_ENABLE | __SHIFTIN(0xfff, MESON8B_WATCHDOG_TC_TCNT)); 320 bus_space_write_4(bst, bsh, MESON8B_WATCHDOG_RESET, 0); 321 322 for (;;) { 323 __asm("wfi"); 324 } 325 } 326 327 static void 328 meson8b_mpinit_delay(u_int n) 329 { 330 for (volatile int i = 0; i < n; i++) 331 ; 332 } 333 334 static int 335 cpu_enable_meson8b(int phandle) 336 { 337 const bus_addr_t cbar = armreg_cbar_read(); 338 bus_space_tag_t bst = &arm_generic_bs_tag; 339 340 const bus_space_handle_t scu_bsh = 341 cbar - MESON8B_ARM_PBASE + MESON8B_ARM_VBASE; 342 const bus_space_handle_t cpuconf_bsh = 343 MESON8B_SRAM_VBASE + MESON8B_SRAM_CPUCONF_OFFSET; 344 const bus_space_handle_t ao_bsh = 345 MESON8B_AOBUS_VBASE + MESON8B_AOBUS_RTI_OFFSET; 346 const bus_space_handle_t cbus_bsh = 347 MESON_CORE_APB3_VBASE + MESON_CBUS_OFFSET; 348 uint32_t pwr_sts, pwr_cntl0, pwr_cntl1, cpuclk, mempd0; 349 uint64_t mpidr; 350 351 fdtbus_get_reg64(phandle, 0, &mpidr, NULL); 352 353 const u_int cpuno = __SHIFTOUT(mpidr, MPIDR_AFF0); 354 355 bus_space_write_4(bst, cpuconf_bsh, MESON8B_SRAM_CPUCONF_CPU_ADDR_REG(cpuno), 356 KERN_VTOPHYS((vaddr_t)cpu_mpstart)); 357 358 pwr_sts = bus_space_read_4(bst, scu_bsh, SCU_CPU_PWR_STS); 359 pwr_sts &= ~(3 << (8 * cpuno)); 360 bus_space_write_4(bst, scu_bsh, SCU_CPU_PWR_STS, pwr_sts); 361 362 pwr_cntl0 = bus_space_read_4(bst, ao_bsh, MESON_AOBUS_PWR_CTRL0_REG); 363 pwr_cntl0 &= ~((3 << 18) << ((cpuno - 1) * 2)); 364 bus_space_write_4(bst, ao_bsh, MESON_AOBUS_PWR_CTRL0_REG, pwr_cntl0); 365 366 meson8b_mpinit_delay(5000); 367 368 cpuclk = bus_space_read_4(bst, cbus_bsh, MESON_CBUS_CPU_CLK_CNTL_REG); 369 cpuclk |= (1 << (24 + cpuno)); 370 bus_space_write_4(bst, cbus_bsh, MESON_CBUS_CPU_CLK_CNTL_REG, cpuclk); 371 372 mempd0 = bus_space_read_4(bst, ao_bsh, MESON_AOBUS_PWR_MEM_PD0_REG); 373 mempd0 &= ~((uint32_t)(0xf << 28) >> ((cpuno - 1) * 4)); 374 bus_space_write_4(bst, ao_bsh, MESON_AOBUS_PWR_MEM_PD0_REG, mempd0); 375 376 pwr_cntl1 = bus_space_read_4(bst, ao_bsh, MESON_AOBUS_PWR_CTRL1_REG); 377 pwr_cntl1 &= ~((3 << 4) << ((cpuno - 1) * 2)); 378 bus_space_write_4(bst, ao_bsh, MESON_AOBUS_PWR_CTRL1_REG, pwr_cntl1); 379 380 meson8b_mpinit_delay(10000); 381 382 for (;;) { 383 pwr_cntl1 = bus_space_read_4(bst, ao_bsh, 384 MESON_AOBUS_PWR_CTRL1_REG) & ((1 << 17) << (cpuno - 1)); 385 if (pwr_cntl1) 386 break; 387 meson8b_mpinit_delay(10000); 388 } 389 390 pwr_cntl0 = bus_space_read_4(bst, ao_bsh, MESON_AOBUS_PWR_CTRL0_REG); 391 pwr_cntl0 &= ~(1 << cpuno); 392 bus_space_write_4(bst, ao_bsh, MESON_AOBUS_PWR_CTRL0_REG, pwr_cntl0); 393 394 cpuclk = bus_space_read_4(bst, cbus_bsh, MESON_CBUS_CPU_CLK_CNTL_REG); 395 cpuclk &= ~(1 << (24 + cpuno)); 396 bus_space_write_4(bst, cbus_bsh, MESON_CBUS_CPU_CLK_CNTL_REG, cpuclk); 397 398 bus_space_write_4(bst, cpuconf_bsh, MESON8B_SRAM_CPUCONF_CPU_ADDR_REG(cpuno), 399 KERN_VTOPHYS((vaddr_t)cpu_mpstart)); 400 401 uint32_t ctrl = bus_space_read_4(bst, cpuconf_bsh, MESON8B_SRAM_CPUCONF_CTRL_REG); 402 ctrl |= __BITS(cpuno,0); 403 bus_space_write_4(bst, cpuconf_bsh, MESON8B_SRAM_CPUCONF_CTRL_REG, ctrl); 404 405 return 0; 406 } 407 408 ARM_CPU_METHOD(meson8b, "amlogic,meson8b-smp", cpu_enable_meson8b); 409 410 static int 411 meson8b_mpstart(void) 412 { 413 int ret = 0; 414 const bus_addr_t cbar = armreg_cbar_read(); 415 bus_space_tag_t bst = &arm_generic_bs_tag; 416 417 if (cbar == 0) 418 return ret; 419 420 const bus_space_handle_t scu_bsh = 421 cbar - MESON8B_ARM_PBASE + MESON8B_ARM_VBASE; 422 423 const uint32_t scu_cfg = bus_space_read_4(bst, scu_bsh, SCU_CFG); 424 const u_int ncpus = (scu_cfg & SCU_CFG_CPUMAX) + 1; 425 426 if (ncpus < 2) 427 return ret; 428 429 /* 430 * Invalidate all SCU cache tags. That is, for all cores (0-3) 431 */ 432 bus_space_write_4(bst, scu_bsh, SCU_INV_ALL_REG, 0xffff); 433 434 uint32_t scu_ctl = bus_space_read_4(bst, scu_bsh, SCU_CTL); 435 scu_ctl |= SCU_CTL_SCU_ENA; 436 bus_space_write_4(bst, scu_bsh, SCU_CTL, scu_ctl); 437 438 armv7_dcache_wbinv_all(); 439 440 ret = arm_fdt_cpu_mpstart(); 441 return ret; 442 } 443 444 static const struct arm_platform meson8b_platform = { 445 .ap_devmap = meson_platform_devmap, 446 .ap_bootstrap = meson8b_platform_bootstrap, 447 .ap_init_attach_args = meson_platform_init_attach_args, 448 .ap_device_register = meson8b_platform_device_register, 449 .ap_reset = meson8b_platform_reset, 450 .ap_delay = a9ptmr_delay, 451 .ap_uart_freq = meson_platform_uart_freq, 452 .ap_mpstart = meson8b_mpstart, 453 }; 454 455 ARM_PLATFORM(meson8b, "amlogic,meson8b", &meson8b_platform); 456 #endif /* SOC_MESON8B */ 457 458 #if defined(SOC_MESONGX) 459 static void 460 mesongx_platform_reset(void) 461 { 462 bus_space_tag_t bst = &meson_bs_tag; 463 bus_space_handle_t bsh; 464 uint32_t val; 465 466 bus_space_map(bst, MESONGX_WATCHDOG_BASE, MESONGX_WATCHDOG_SIZE, 0, &bsh); 467 468 val = MESONGX_WATCHDOG_CNTL_SYS_RESET_N_EN | 469 MESONGX_WATCHDOG_CNTL_WDOG_EN | 470 MESONGX_WATCHDOG_CNTL_CLK_EN; 471 bus_space_write_4(bst, bsh, MESONGX_WATCHDOG_CNTL, val); 472 473 bus_space_write_4(bst, bsh, MESONGX_WATCHDOG_TCNT, 1); 474 475 bus_space_write_4(bst, bsh, MESONGX_WATCHDOG_RESET, 0); 476 477 for (;;) { 478 __asm("wfi"); 479 } 480 } 481 482 static const struct arm_platform mesongx_platform = { 483 .ap_devmap = meson_platform_devmap, 484 .ap_bootstrap = meson_platform_bootstrap, 485 .ap_init_attach_args = meson_platform_init_attach_args, 486 .ap_device_register = meson_platform_device_register, 487 .ap_reset = mesongx_platform_reset, 488 .ap_delay = gtmr_delay, 489 .ap_uart_freq = meson_platform_uart_freq, 490 .ap_mpstart = arm_fdt_cpu_mpstart, 491 }; 492 493 #if defined(SOC_MESONGXBB) 494 ARM_PLATFORM(mesongxbb, "amlogic,meson-gxbb", &mesongx_platform); 495 #endif /* SOC_MESONGXBB */ 496 #if defined(SOC_MESONGXL) 497 ARM_PLATFORM(mesongxl, "amlogic,meson-gxl", &mesongx_platform); 498 #endif /* SOC_MESONGXL */ 499 #endif /* SOC_MESONGX */ 500