162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * The simple platform -- for booting when firmware doesn't supply a device 462306a36Sopenharmony_ci * tree or any platform configuration information. 562306a36Sopenharmony_ci * All data is extracted from an embedded device tree 662306a36Sopenharmony_ci * blob. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Authors: Scott Wood <scottwood@freescale.com> 962306a36Sopenharmony_ci * Grant Likely <grant.likely@secretlab.ca> 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * Copyright (c) 2007 Freescale Semiconductor, Inc. 1262306a36Sopenharmony_ci * Copyright (c) 2008 Secret Lab Technologies Ltd. 1362306a36Sopenharmony_ci */ 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include "ops.h" 1662306a36Sopenharmony_ci#include "types.h" 1762306a36Sopenharmony_ci#include "io.h" 1862306a36Sopenharmony_ci#include "stdio.h" 1962306a36Sopenharmony_ci#include <libfdt.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ciBSS_STACK(4*1024); 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ciextern int platform_specific_init(void) __attribute__((weak)); 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_civoid platform_init(unsigned long r3, unsigned long r4, unsigned long r5, 2662306a36Sopenharmony_ci unsigned long r6, unsigned long r7) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci const u32 *na, *ns, *reg, *timebase; 2962306a36Sopenharmony_ci u64 memsize64; 3062306a36Sopenharmony_ci int node, size, i; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci /* Make sure FDT blob is sane */ 3362306a36Sopenharmony_ci if (fdt_check_header(_dtb_start) != 0) 3462306a36Sopenharmony_ci fatal("Invalid device tree blob\n"); 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci /* Find the #address-cells and #size-cells properties */ 3762306a36Sopenharmony_ci node = fdt_path_offset(_dtb_start, "/"); 3862306a36Sopenharmony_ci if (node < 0) 3962306a36Sopenharmony_ci fatal("Cannot find root node\n"); 4062306a36Sopenharmony_ci na = fdt_getprop(_dtb_start, node, "#address-cells", &size); 4162306a36Sopenharmony_ci if (!na || (size != 4)) 4262306a36Sopenharmony_ci fatal("Cannot find #address-cells property"); 4362306a36Sopenharmony_ci ns = fdt_getprop(_dtb_start, node, "#size-cells", &size); 4462306a36Sopenharmony_ci if (!ns || (size != 4)) 4562306a36Sopenharmony_ci fatal("Cannot find #size-cells property"); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci /* Find the memory range */ 4862306a36Sopenharmony_ci node = fdt_node_offset_by_prop_value(_dtb_start, -1, "device_type", 4962306a36Sopenharmony_ci "memory", sizeof("memory")); 5062306a36Sopenharmony_ci if (node < 0) 5162306a36Sopenharmony_ci fatal("Cannot find memory node\n"); 5262306a36Sopenharmony_ci reg = fdt_getprop(_dtb_start, node, "reg", &size); 5362306a36Sopenharmony_ci if (size < (*na+*ns) * sizeof(u32)) 5462306a36Sopenharmony_ci fatal("cannot get memory range\n"); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci /* Only interested in memory based at 0 */ 5762306a36Sopenharmony_ci for (i = 0; i < *na; i++) 5862306a36Sopenharmony_ci if (*reg++ != 0) 5962306a36Sopenharmony_ci fatal("Memory range is not based at address 0\n"); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci /* get the memsize and truncate it to under 4G on 32 bit machines */ 6262306a36Sopenharmony_ci memsize64 = 0; 6362306a36Sopenharmony_ci for (i = 0; i < *ns; i++) 6462306a36Sopenharmony_ci memsize64 = (memsize64 << 32) | *reg++; 6562306a36Sopenharmony_ci if (sizeof(void *) == 4 && memsize64 >= 0x100000000ULL) 6662306a36Sopenharmony_ci memsize64 = 0xffffffff; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci /* finally, setup the timebase */ 6962306a36Sopenharmony_ci node = fdt_node_offset_by_prop_value(_dtb_start, -1, "device_type", 7062306a36Sopenharmony_ci "cpu", sizeof("cpu")); 7162306a36Sopenharmony_ci if (!node) 7262306a36Sopenharmony_ci fatal("Cannot find cpu node\n"); 7362306a36Sopenharmony_ci timebase = fdt_getprop(_dtb_start, node, "timebase-frequency", &size); 7462306a36Sopenharmony_ci if (timebase && (size == 4)) 7562306a36Sopenharmony_ci timebase_period_ns = 1000000000 / *timebase; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci /* Now we have the memory size; initialize the heap */ 7862306a36Sopenharmony_ci simple_alloc_init(_end, memsize64 - (unsigned long)_end, 32, 64); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci /* prepare the device tree and find the console */ 8162306a36Sopenharmony_ci fdt_init(_dtb_start); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci if (platform_specific_init) 8462306a36Sopenharmony_ci platform_specific_init(); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci serial_console_init(); 8762306a36Sopenharmony_ci} 88