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