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