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