18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * The simple platform -- for booting when firmware doesn't supply a device 48c2ecf20Sopenharmony_ci * tree or any platform configuration information. 58c2ecf20Sopenharmony_ci * All data is extracted from an embedded device tree 68c2ecf20Sopenharmony_ci * blob. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Authors: Scott Wood <scottwood@freescale.com> 98c2ecf20Sopenharmony_ci * Grant Likely <grant.likely@secretlab.ca> 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Copyright (c) 2007 Freescale Semiconductor, Inc. 128c2ecf20Sopenharmony_ci * Copyright (c) 2008 Secret Lab Technologies Ltd. 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include "ops.h" 168c2ecf20Sopenharmony_ci#include "types.h" 178c2ecf20Sopenharmony_ci#include "io.h" 188c2ecf20Sopenharmony_ci#include "stdio.h" 198c2ecf20Sopenharmony_ci#include <libfdt.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ciBSS_STACK(4*1024); 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ciextern int platform_specific_init(void) __attribute__((weak)); 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_civoid platform_init(unsigned long r3, unsigned long r4, unsigned long r5, 268c2ecf20Sopenharmony_ci unsigned long r6, unsigned long r7) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci const u32 *na, *ns, *reg, *timebase; 298c2ecf20Sopenharmony_ci u64 memsize64; 308c2ecf20Sopenharmony_ci int node, size, i; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci /* Make sure FDT blob is sane */ 338c2ecf20Sopenharmony_ci if (fdt_check_header(_dtb_start) != 0) 348c2ecf20Sopenharmony_ci fatal("Invalid device tree blob\n"); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci /* Find the #address-cells and #size-cells properties */ 378c2ecf20Sopenharmony_ci node = fdt_path_offset(_dtb_start, "/"); 388c2ecf20Sopenharmony_ci if (node < 0) 398c2ecf20Sopenharmony_ci fatal("Cannot find root node\n"); 408c2ecf20Sopenharmony_ci na = fdt_getprop(_dtb_start, node, "#address-cells", &size); 418c2ecf20Sopenharmony_ci if (!na || (size != 4)) 428c2ecf20Sopenharmony_ci fatal("Cannot find #address-cells property"); 438c2ecf20Sopenharmony_ci ns = fdt_getprop(_dtb_start, node, "#size-cells", &size); 448c2ecf20Sopenharmony_ci if (!ns || (size != 4)) 458c2ecf20Sopenharmony_ci fatal("Cannot find #size-cells property"); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci /* Find the memory range */ 488c2ecf20Sopenharmony_ci node = fdt_node_offset_by_prop_value(_dtb_start, -1, "device_type", 498c2ecf20Sopenharmony_ci "memory", sizeof("memory")); 508c2ecf20Sopenharmony_ci if (node < 0) 518c2ecf20Sopenharmony_ci fatal("Cannot find memory node\n"); 528c2ecf20Sopenharmony_ci reg = fdt_getprop(_dtb_start, node, "reg", &size); 538c2ecf20Sopenharmony_ci if (size < (*na+*ns) * sizeof(u32)) 548c2ecf20Sopenharmony_ci fatal("cannot get memory range\n"); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci /* Only interested in memory based at 0 */ 578c2ecf20Sopenharmony_ci for (i = 0; i < *na; i++) 588c2ecf20Sopenharmony_ci if (*reg++ != 0) 598c2ecf20Sopenharmony_ci fatal("Memory range is not based at address 0\n"); 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci /* get the memsize and truncate it to under 4G on 32 bit machines */ 628c2ecf20Sopenharmony_ci memsize64 = 0; 638c2ecf20Sopenharmony_ci for (i = 0; i < *ns; i++) 648c2ecf20Sopenharmony_ci memsize64 = (memsize64 << 32) | *reg++; 658c2ecf20Sopenharmony_ci if (sizeof(void *) == 4 && memsize64 >= 0x100000000ULL) 668c2ecf20Sopenharmony_ci memsize64 = 0xffffffff; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci /* finally, setup the timebase */ 698c2ecf20Sopenharmony_ci node = fdt_node_offset_by_prop_value(_dtb_start, -1, "device_type", 708c2ecf20Sopenharmony_ci "cpu", sizeof("cpu")); 718c2ecf20Sopenharmony_ci if (!node) 728c2ecf20Sopenharmony_ci fatal("Cannot find cpu node\n"); 738c2ecf20Sopenharmony_ci timebase = fdt_getprop(_dtb_start, node, "timebase-frequency", &size); 748c2ecf20Sopenharmony_ci if (timebase && (size == 4)) 758c2ecf20Sopenharmony_ci timebase_period_ns = 1000000000 / *timebase; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci /* Now we have the memory size; initialize the heap */ 788c2ecf20Sopenharmony_ci simple_alloc_init(_end, memsize64 - (unsigned long)_end, 32, 64); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci /* prepare the device tree and find the console */ 818c2ecf20Sopenharmony_ci fdt_init(_dtb_start); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci if (platform_specific_init) 848c2ecf20Sopenharmony_ci platform_specific_init(); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci serial_console_init(); 878c2ecf20Sopenharmony_ci} 88