1 /* $NetBSD: sunxi_platform.c,v 1.46 2022/06/28 05:19:03 skrll Exp $ */ 2 3 /*- 4 * Copyright (c) 2017 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 <sys/cdefs.h> 34 __KERNEL_RCSID(0, "$NetBSD: sunxi_platform.c,v 1.46 2022/06/28 05:19:03 skrll Exp $"); 35 36 #include <sys/param.h> 37 #include <sys/bus.h> 38 #include <sys/cpu.h> 39 #include <sys/device.h> 40 #include <sys/termios.h> 41 42 #include <dev/fdt/fdtvar.h> 43 #include <arm/fdt/arm_fdtvar.h> 44 45 #include <uvm/uvm_extern.h> 46 47 #include <machine/bootconfig.h> 48 #include <arm/cpufunc.h> 49 50 #include <arm/cortex/gtmr_var.h> 51 #include <arm/cortex/gic_reg.h> 52 53 #include <dev/ic/ns16550reg.h> 54 #include <dev/ic/comreg.h> 55 56 #include <arm/arm/psci.h> 57 #include <arm/fdt/psci_fdtvar.h> 58 59 #include <arm/sunxi/sunxi_platform.h> 60 61 #if defined(SOC_SUNXI_MC) 62 #include <arm/sunxi/sunxi_mc_smp.h> 63 #endif 64 65 #include <libfdt.h> 66 67 #define SUNXI_REF_FREQ 24000000 68 69 #define SUN4I_TIMER_BASE 0x01c20c00 70 #define SUN4I_TIMER_SIZE 0x90 71 #define SUN4I_TIMER_1_CTRL 0x20 72 #define SUN4I_TIMER_1_CTRL_CLK_SRC __BITS(3,2) 73 #define SUN4I_TIMER_1_CTRL_CLK_SRC_OSC24M 1 74 #define SUN4I_TIMER_1_CTRL_RELOAD __BIT(1) 75 #define SUN4I_TIMER_1_CTRL_EN __BIT(0) 76 #define SUN4I_TIMER_1_INTV_VALUE 0x24 77 #define SUN4I_TIMER_1_VAL 0x28 78 79 #define SUN4I_WDT_BASE 0x01c20c90 80 #define SUN4I_WDT_SIZE 0x10 81 #define SUN4I_WDT_CTRL 0x00 82 #define SUN4I_WDT_CTRL_KEY (0x333 << 1) 83 #define SUN4I_WDT_CTRL_RESTART __BIT(0) 84 #define SUN4I_WDT_MODE 0x04 85 #define SUN4I_WDT_MODE_RST_EN __BIT(1) 86 #define SUN4I_WDT_MODE_EN __BIT(0) 87 88 #define SUN6I_WDT_BASE 0x01c20ca0 89 #define SUN6I_WDT_SIZE 0x20 90 #define SUN6I_WDT_CFG 0x14 91 #define SUN6I_WDT_CFG_SYS __BIT(0) 92 #define SUN6I_WDT_MODE 0x18 93 #define SUN6I_WDT_MODE_EN __BIT(0) 94 95 #define SUN9I_WDT_BASE 0x06000ca0 96 #define SUN9I_WDT_SIZE 0x20 97 #define SUN9I_WDT_CFG 0x14 98 #define SUN9I_WDT_CFG_SYS __BIT(0) 99 #define SUN9I_WDT_MODE 0x18 100 #define SUN9I_WDT_MODE_EN __BIT(0) 101 102 #define SUN50I_H6_WDT_BASE 0x01c20ca0 103 #define SUN50I_H6_WDT_SIZE 0x20 104 #define SUN50I_H6_WDT_CFG 0x14 105 #define SUN50I_H6_WDT_CFG_SYS __BIT(0) 106 #define SUN50I_H6_WDT_MODE 0x18 107 #define SUN50I_H6_WDT_MODE_EN __BIT(0) 108 109 extern struct arm32_bus_dma_tag arm_generic_dma_tag; 110 extern struct bus_space arm_generic_bs_tag; 111 112 #define sunxi_dma_tag arm_generic_dma_tag 113 #define sunxi_bs_tag arm_generic_bs_tag 114 115 static bus_space_handle_t reset_bsh; 116 117 static const struct pmap_devmap * 118 sunxi_platform_devmap(void) 119 { 120 static const struct pmap_devmap devmap[] = { 121 DEVMAP_ENTRY(SUNXI_CORE_VBASE, 122 SUNXI_CORE_PBASE, 123 SUNXI_CORE_SIZE), 124 DEVMAP_ENTRY_END 125 }; 126 127 return devmap; 128 } 129 130 #define SUNXI_MC_CPU_VBASE (SUNXI_CORE_VBASE + SUNXI_CORE_SIZE) 131 #define SUNXI_MC_CPU_PBASE 0x01700000 132 #define SUNXI_MC_CPU_SIZE 0x00100000 133 134 static const struct pmap_devmap * 135 sun8i_a83t_platform_devmap(void) 136 { 137 static const struct pmap_devmap devmap[] = { 138 DEVMAP_ENTRY(SUNXI_CORE_VBASE, 139 SUNXI_CORE_PBASE, 140 SUNXI_CORE_SIZE), 141 DEVMAP_ENTRY(SUNXI_MC_CPU_VBASE, 142 SUNXI_MC_CPU_PBASE, 143 SUNXI_MC_CPU_SIZE), 144 DEVMAP_ENTRY_END 145 }; 146 147 return devmap; 148 } 149 150 #define SUN9I_A80_PRCM_VBASE (SUNXI_MC_CPU_VBASE + SUNXI_MC_CPU_PBASE) 151 #define SUN9I_A80_PRCM_PBASE 0x08000000 152 #define SUN9I_A80_PRCM_SIZE 0x00100000 153 154 static const struct pmap_devmap * 155 sun9i_a80_platform_devmap(void) 156 { 157 static const struct pmap_devmap devmap[] = { 158 DEVMAP_ENTRY(SUNXI_CORE_VBASE, 159 SUNXI_CORE_PBASE, 160 SUNXI_CORE_SIZE), 161 DEVMAP_ENTRY(SUNXI_MC_CPU_VBASE, 162 SUNXI_MC_CPU_PBASE, 163 SUNXI_MC_CPU_SIZE), 164 DEVMAP_ENTRY(SUN9I_A80_PRCM_VBASE, 165 SUN9I_A80_PRCM_PBASE, 166 SUN9I_A80_PRCM_SIZE), 167 DEVMAP_ENTRY_END 168 }; 169 170 return devmap; 171 } 172 173 174 static void 175 sunxi_platform_init_attach_args(struct fdt_attach_args *faa) 176 { 177 faa->faa_bst = &sunxi_bs_tag; 178 faa->faa_dmat = &sunxi_dma_tag; 179 } 180 181 void sunxi_platform_early_putchar(char); 182 183 void __noasan 184 sunxi_platform_early_putchar(char c) 185 { 186 #ifdef CONSADDR 187 #define CONSADDR_VA ((CONSADDR - SUNXI_CORE_PBASE) + SUNXI_CORE_VBASE) 188 volatile uint32_t *uartaddr = cpu_earlydevice_va_p() ? 189 (volatile uint32_t *)CONSADDR_VA : 190 (volatile uint32_t *)CONSADDR; 191 192 while ((le32toh(uartaddr[com_lsr]) & LSR_TXRDY) == 0) 193 ; 194 195 uartaddr[com_data] = htole32(c); 196 #endif 197 } 198 199 static void 200 sunxi_platform_device_register(device_t self, void *aux) 201 { 202 prop_dictionary_t prop = device_properties(self); 203 int val; 204 205 if (device_is_a(self, "rgephy")) { 206 /* Pine64+ and NanoPi NEO Plus2 gigabit ethernet workaround */ 207 static const struct device_compatible_entry compat_data[] = { 208 { .compat = "pine64,pine64-plus" }, 209 { .compat = "friendlyarm,nanopi-neo-plus2" }, 210 DEVICE_COMPAT_EOL 211 }; 212 if (of_compatible_match(OF_finddevice("/"), compat_data)) { 213 prop_dictionary_set_bool(prop, "no-rx-delay", true); 214 } 215 } 216 217 if (device_is_a(self, "armgtmr")) { 218 /* Allwinner A64 has an unstable architectural timer */ 219 static const struct device_compatible_entry compat_data[] = { 220 { .compat = "allwinner,sun50i-a64" }, 221 /* Cubietruck Plus triggers this problem as well. */ 222 { .compat = "allwinner,sun8i-a83t" }, 223 DEVICE_COMPAT_EOL 224 }; 225 if (of_compatible_match(OF_finddevice("/"), compat_data)) { 226 prop_dictionary_set_bool(prop, "sun50i-a64-unstable-timer", true); 227 } 228 } 229 230 if (device_is_a(self, "sunxidrm") || device_is_a(self, "dwhdmi")) { 231 if (get_bootconf_option(boot_args, "nomodeset", BOOTOPT_TYPE_BOOLEAN, &val)) 232 if (val) 233 prop_dictionary_set_bool(prop, "disabled", true); 234 } 235 236 if (device_is_a(self, "sun50ia64ccu0")) { 237 if (get_bootconf_option(boot_args, "nomodeset", BOOTOPT_TYPE_BOOLEAN, &val)) 238 if (val) 239 prop_dictionary_set_bool(prop, "nomodeset", true); 240 } 241 242 if (device_is_a(self, "com")) { 243 static const struct device_compatible_entry compat_data[] = { 244 { .compat = "allwinner,sun4i-a10", .value = 64 }, 245 { .compat = "allwinner,sun5i-a13", .value = 64 }, 246 { .compat = "allwinner,sun6i-a31", .value = 64 }, 247 { .compat = "allwinner,sun7i-a20", .value = 64 }, 248 { .compat = "allwinner,sun8i-h2-plus", .value = 64 }, 249 { .compat = "allwinner,sun8i-h3", .value = 64 }, 250 { .compat = "allwinner,sun8i-a83t", .value = 64 }, 251 { .compat = "allwinner,sun9i-a80", .value = 64 }, 252 { .compat = "allwinner,sun50i-a64", .value = 64 }, 253 { .compat = "allwinner,sun50i-h5", .value = 64 }, 254 { .compat = "allwinner,sun50i-h6", .value = 256 }, 255 DEVICE_COMPAT_EOL 256 }; 257 const struct device_compatible_entry *dce = 258 of_compatible_lookup(OF_finddevice("/"), compat_data); 259 if (dce != NULL) 260 prop_dictionary_set_uint(prop, "fifolen", dce->value); 261 } 262 } 263 264 static u_int 265 sunxi_platform_uart_freq(void) 266 { 267 return SUNXI_REF_FREQ; 268 } 269 270 static void 271 sunxi_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 static void 298 sun4i_platform_bootstrap(void) 299 { 300 bus_space_tag_t bst = &sunxi_bs_tag; 301 302 sunxi_platform_bootstrap(); 303 bus_space_map(bst, SUN4I_WDT_BASE, SUN4I_WDT_SIZE, 0, &reset_bsh); 304 } 305 306 static void 307 sun6i_platform_bootstrap(void) 308 { 309 bus_space_tag_t bst = &sunxi_bs_tag; 310 311 sunxi_platform_bootstrap(); 312 bus_space_map(bst, SUN6I_WDT_BASE, SUN6I_WDT_SIZE, 0, &reset_bsh); 313 } 314 315 static void 316 sun9i_platform_bootstrap(void) 317 { 318 bus_space_tag_t bst = &sunxi_bs_tag; 319 320 sunxi_platform_bootstrap(); 321 bus_space_map(bst, SUN9I_WDT_BASE, SUN9I_WDT_SIZE, 0, &reset_bsh); 322 } 323 324 static void 325 sun50i_h6_platform_bootstrap(void) 326 { 327 bus_space_tag_t bst = &sunxi_bs_tag; 328 329 sunxi_platform_bootstrap(); 330 bus_space_map(bst, SUN50I_H6_WDT_BASE, SUN50I_H6_WDT_SIZE, 0, &reset_bsh); 331 } 332 333 #if defined(SOC_SUNXI_MC) 334 static int 335 cpu_enable_sun8i_a83t(int phandle) 336 { 337 uint64_t mpidr; 338 339 fdtbus_get_reg64(phandle, 0, &mpidr, NULL); 340 341 return sun8i_a83t_smp_enable(mpidr); 342 } 343 ARM_CPU_METHOD(sun8i_a83t, "allwinner,sun8i-a83t-smp", cpu_enable_sun8i_a83t); 344 345 static int 346 cpu_enable_sun9i_a80(int phandle) 347 { 348 uint64_t mpidr; 349 350 fdtbus_get_reg64(phandle, 0, &mpidr, NULL); 351 352 return sun9i_a80_smp_enable(mpidr); 353 } 354 ARM_CPU_METHOD(sun9i_a80, "allwinner,sun9i-a80-smp", cpu_enable_sun9i_a80); 355 #endif 356 357 static void 358 sun4i_platform_reset(void) 359 { 360 bus_space_tag_t bst = &sunxi_bs_tag; 361 362 bus_space_write_4(bst, reset_bsh, SUN4I_WDT_CTRL, 363 SUN4I_WDT_CTRL_KEY | SUN4I_WDT_CTRL_RESTART); 364 for (;;) { 365 bus_space_write_4(bst, reset_bsh, SUN4I_WDT_MODE, 366 SUN4I_WDT_MODE_EN | SUN4I_WDT_MODE_RST_EN); 367 } 368 } 369 370 static void 371 sun4i_platform_delay(u_int n) 372 { 373 static bus_space_tag_t bst = &sunxi_bs_tag; 374 static bus_space_handle_t bsh = 0; 375 const long incs_per_us = SUNXI_REF_FREQ / 1000000; 376 long ticks = n * incs_per_us; 377 uint32_t cur, prev; 378 379 if (bsh == 0) { 380 bus_space_map(bst, SUN4I_TIMER_BASE, SUN4I_TIMER_SIZE, 0, &bsh); 381 382 /* Enable Timer 1 */ 383 bus_space_write_4(bst, bsh, SUN4I_TIMER_1_INTV_VALUE, ~0U); 384 bus_space_write_4(bst, bsh, SUN4I_TIMER_1_CTRL, 385 SUN4I_TIMER_1_CTRL_EN | 386 SUN4I_TIMER_1_CTRL_RELOAD | 387 __SHIFTIN(SUN4I_TIMER_1_CTRL_CLK_SRC_OSC24M, 388 SUN4I_TIMER_1_CTRL_CLK_SRC)); 389 } 390 391 prev = ~bus_space_read_4(bst, bsh, SUN4I_TIMER_1_VAL); 392 while (ticks > 0) { 393 cur = ~bus_space_read_4(bst, bsh, SUN4I_TIMER_1_VAL); 394 if (cur > prev) 395 ticks -= (cur - prev); 396 else 397 ticks -= (~0U - cur + prev); 398 prev = cur; 399 } 400 } 401 402 static void 403 sun6i_platform_reset(void) 404 { 405 bus_space_tag_t bst = &sunxi_bs_tag; 406 407 bus_space_write_4(bst, reset_bsh, SUN6I_WDT_CFG, SUN6I_WDT_CFG_SYS); 408 bus_space_write_4(bst, reset_bsh, SUN6I_WDT_MODE, SUN6I_WDT_MODE_EN); 409 } 410 411 static void 412 sun9i_platform_reset(void) 413 { 414 bus_space_tag_t bst = &sunxi_bs_tag; 415 416 bus_space_write_4(bst, reset_bsh, SUN9I_WDT_CFG, SUN9I_WDT_CFG_SYS); 417 bus_space_write_4(bst, reset_bsh, SUN9I_WDT_MODE, SUN9I_WDT_MODE_EN); 418 } 419 420 static void 421 sun50i_h6_platform_reset(void) 422 { 423 bus_space_tag_t bst = &sunxi_bs_tag; 424 425 bus_space_write_4(bst, reset_bsh, SUN50I_H6_WDT_CFG, SUN50I_H6_WDT_CFG_SYS); 426 bus_space_write_4(bst, reset_bsh, SUN50I_H6_WDT_MODE, SUN50I_H6_WDT_MODE_EN); 427 } 428 429 static const struct arm_platform sun4i_platform = { 430 .ap_devmap = sunxi_platform_devmap, 431 .ap_bootstrap = sun4i_platform_bootstrap, 432 .ap_init_attach_args = sunxi_platform_init_attach_args, 433 .ap_device_register = sunxi_platform_device_register, 434 .ap_reset = sun4i_platform_reset, 435 .ap_delay = sun4i_platform_delay, 436 .ap_uart_freq = sunxi_platform_uart_freq, 437 }; 438 439 ARM_PLATFORM(sun4i_a10, "allwinner,sun4i-a10", &sun4i_platform); 440 441 static const struct arm_platform sun5i_platform = { 442 .ap_devmap = sunxi_platform_devmap, 443 .ap_bootstrap = sun4i_platform_bootstrap, 444 .ap_init_attach_args = sunxi_platform_init_attach_args, 445 .ap_device_register = sunxi_platform_device_register, 446 .ap_reset = sun4i_platform_reset, 447 .ap_delay = sun4i_platform_delay, 448 .ap_uart_freq = sunxi_platform_uart_freq, 449 }; 450 451 ARM_PLATFORM(sun5i_a13, "allwinner,sun5i-a13", &sun5i_platform); 452 ARM_PLATFORM(sun5i_gr8, "nextthing,gr8", &sun5i_platform); 453 454 static const struct arm_platform sun6i_platform = { 455 .ap_devmap = sunxi_platform_devmap, 456 .ap_bootstrap = sun6i_platform_bootstrap, 457 .ap_init_attach_args = sunxi_platform_init_attach_args, 458 .ap_device_register = sunxi_platform_device_register, 459 .ap_reset = sun6i_platform_reset, 460 .ap_delay = gtmr_delay, 461 .ap_uart_freq = sunxi_platform_uart_freq, 462 .ap_mpstart = arm_fdt_cpu_mpstart, 463 }; 464 465 ARM_PLATFORM(sun6i_a31, "allwinner,sun6i-a31", &sun6i_platform); 466 467 static const struct arm_platform sun7i_platform = { 468 .ap_devmap = sunxi_platform_devmap, 469 .ap_bootstrap = sun4i_platform_bootstrap, 470 .ap_init_attach_args = sunxi_platform_init_attach_args, 471 .ap_device_register = sunxi_platform_device_register, 472 .ap_reset = sun4i_platform_reset, 473 .ap_delay = sun4i_platform_delay, 474 .ap_uart_freq = sunxi_platform_uart_freq, 475 .ap_mpstart = arm_fdt_cpu_mpstart, 476 }; 477 478 ARM_PLATFORM(sun7i_a20, "allwinner,sun7i-a20", &sun7i_platform); 479 480 static const struct arm_platform sun8i_platform = { 481 .ap_devmap = sunxi_platform_devmap, 482 .ap_bootstrap = sun6i_platform_bootstrap, 483 .ap_init_attach_args = sunxi_platform_init_attach_args, 484 .ap_device_register = sunxi_platform_device_register, 485 .ap_reset = sun6i_platform_reset, 486 .ap_delay = gtmr_delay, 487 .ap_uart_freq = sunxi_platform_uart_freq, 488 .ap_mpstart = arm_fdt_cpu_mpstart, 489 }; 490 491 ARM_PLATFORM(sun8i_h2plus, "allwinner,sun8i-h2-plus", &sun8i_platform); 492 ARM_PLATFORM(sun8i_h3, "allwinner,sun8i-h3", &sun8i_platform); 493 ARM_PLATFORM(sun8i_v3s, "allwinner,sun8i-v3s", &sun8i_platform); 494 495 static const struct arm_platform sun8i_a83t_platform = { 496 .ap_devmap = sun8i_a83t_platform_devmap, 497 .ap_bootstrap = sun6i_platform_bootstrap, 498 .ap_init_attach_args = sunxi_platform_init_attach_args, 499 .ap_device_register = sunxi_platform_device_register, 500 .ap_reset = sun6i_platform_reset, 501 .ap_delay = gtmr_delay, 502 .ap_uart_freq = sunxi_platform_uart_freq, 503 .ap_mpstart = arm_fdt_cpu_mpstart, 504 }; 505 506 ARM_PLATFORM(sun8i_a83t, "allwinner,sun8i-a83t", &sun8i_a83t_platform); 507 508 static const struct arm_platform sun9i_platform = { 509 .ap_devmap = sun9i_a80_platform_devmap, 510 .ap_bootstrap = sun9i_platform_bootstrap, 511 .ap_init_attach_args = sunxi_platform_init_attach_args, 512 .ap_device_register = sunxi_platform_device_register, 513 .ap_reset = sun9i_platform_reset, 514 .ap_delay = gtmr_delay, 515 .ap_uart_freq = sunxi_platform_uart_freq, 516 .ap_mpstart = arm_fdt_cpu_mpstart, 517 }; 518 519 ARM_PLATFORM(sun9i_a80, "allwinner,sun9i-a80", &sun9i_platform); 520 521 static const struct arm_platform sun50i_platform = { 522 .ap_devmap = sunxi_platform_devmap, 523 .ap_bootstrap = sun6i_platform_bootstrap, 524 .ap_init_attach_args = sunxi_platform_init_attach_args, 525 .ap_device_register = sunxi_platform_device_register, 526 .ap_reset = sun6i_platform_reset, 527 .ap_delay = gtmr_delay, 528 .ap_uart_freq = sunxi_platform_uart_freq, 529 .ap_mpstart = arm_fdt_cpu_mpstart, 530 }; 531 532 ARM_PLATFORM(sun50i_a64, "allwinner,sun50i-a64", &sun50i_platform); 533 ARM_PLATFORM(sun50i_h5, "allwinner,sun50i-h5", &sun50i_platform); 534 535 static const struct arm_platform sun50i_h6_platform = { 536 .ap_devmap = sunxi_platform_devmap, 537 .ap_bootstrap = sun50i_h6_platform_bootstrap, 538 .ap_init_attach_args = sunxi_platform_init_attach_args, 539 .ap_device_register = sunxi_platform_device_register, 540 .ap_reset = sun50i_h6_platform_reset, 541 .ap_delay = gtmr_delay, 542 .ap_uart_freq = sunxi_platform_uart_freq, 543 .ap_mpstart = arm_fdt_cpu_mpstart, 544 }; 545 546 ARM_PLATFORM(sun50i_h6, "allwinner,sun50i-h6", &sun50i_h6_platform); 547