prom.c 5.0 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
/*
 * Procedures for creating, accessing and interpreting the device tree.
 *
 * Paul Mackerras	August 1996.
 * Copyright (C) 1996-2005 Paul Mackerras.
 *
 *  Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
 *    {engebret|bergner}@us.ibm.com
 *
 *      This program is free software; you can redistribute it and/or
 *      modify it under the terms of the GNU General Public License
 *      as published by the Free Software Foundation; either version
 *      2 of the License, or (at your option) any later version.
 */

#include <stdarg.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/init.h>
#include <linux/threads.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/stringify.h>
#include <linux/delay.h>
#include <linux/initrd.h>
#include <linux/bitops.h>
#include <linux/module.h>
#include <linux/kexec.h>
#include <linux/debugfs.h>
#include <linux/irq.h>
Y
Yinghai Lu 已提交
32
#include <linux/memblock.h>
33 34 35 36 37 38 39 40 41 42 43 44

#include <asm/prom.h>
#include <asm/page.h>
#include <asm/processor.h>
#include <asm/irq.h>
#include <linux/io.h>
#include <asm/system.h>
#include <asm/mmu.h>
#include <asm/pgtable.h>
#include <asm/sections.h>
#include <asm/pci-bridge.h>

45
void __init early_init_dt_add_memory_arch(u64 base, u64 size)
46
{
Y
Yinghai Lu 已提交
47
	memblock_add(base, size);
48 49
}

J
Jeremy Kerr 已提交
50 51
u64 __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
{
Y
Yinghai Lu 已提交
52
	return memblock_alloc(size, align);
J
Jeremy Kerr 已提交
53 54
}

55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
#ifdef CONFIG_EARLY_PRINTK
/* MS this is Microblaze specifig function */
static int __init early_init_dt_scan_serial(unsigned long node,
				const char *uname, int depth, void *data)
{
	unsigned long l;
	char *p;
	int *addr;

	pr_debug("search \"chosen\", depth: %d, uname: %s\n", depth, uname);

/* find all serial nodes */
	if (strncmp(uname, "serial", 6) != 0)
		return 0;

	early_init_dt_check_for_initrd(node);

/* find compatible node with uartlite */
	p = of_get_flat_dt_prop(node, "compatible", &l);
	if ((strncmp(p, "xlnx,xps-uartlite", 17) != 0) &&
75 76
			(strncmp(p, "xlnx,opb-uartlite", 17) != 0) &&
			(strncmp(p, "xlnx,axi-uartlite", 17) != 0))
77 78 79
		return 0;

	addr = of_get_flat_dt_prop(node, "reg", &l);
80
	return be32_to_cpup(addr); /* return address */
81 82 83 84 85 86 87
}

/* this function is looking for early uartlite console - Microblaze specific */
int __init early_uartlite_console(void)
{
	return of_scan_flat_dt(early_init_dt_scan_serial, NULL);
}
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113

/* MS this is Microblaze specifig function */
static int __init early_init_dt_scan_serial_full(unsigned long node,
				const char *uname, int depth, void *data)
{
	unsigned long l;
	char *p;
	unsigned int addr;

	pr_debug("search \"chosen\", depth: %d, uname: %s\n", depth, uname);

/* find all serial nodes */
	if (strncmp(uname, "serial", 6) != 0)
		return 0;

	early_init_dt_check_for_initrd(node);

/* find compatible node with uartlite */
	p = of_get_flat_dt_prop(node, "compatible", &l);

	if ((strncmp(p, "xlnx,xps-uart16550", 18) != 0) &&
		(strncmp(p, "xlnx,axi-uart16550", 18) != 0))
		return 0;

	addr = *(u32 *)of_get_flat_dt_prop(node, "reg", &l);
	addr += *(u32 *)of_get_flat_dt_prop(node, "reg-offset", &l);
114
	return be32_to_cpu(addr); /* return address */
115 116 117 118 119 120 121
}

/* this function is looking for early uartlite console - Microblaze specific */
int __init early_uart16550_console(void)
{
	return of_scan_flat_dt(early_init_dt_scan_serial_full, NULL);
}
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
#endif

void __init early_init_devtree(void *params)
{
	pr_debug(" -> early_init_devtree(%p)\n", params);

	/* Setup flat device-tree pointer */
	initial_boot_params = params;

	/* Retrieve various informations from the /chosen node of the
	 * device-tree, including the platform type, initrd location and
	 * size, TCE reserve, and more ...
	 */
	of_scan_flat_dt(early_init_dt_scan_chosen, NULL);

Y
Yinghai Lu 已提交
137 138
	/* Scan memory nodes and rebuild MEMBLOCKs */
	memblock_init();
139 140 141 142 143 144 145
	of_scan_flat_dt(early_init_dt_scan_root, NULL);
	of_scan_flat_dt(early_init_dt_scan_memory, NULL);

	/* Save command line for /proc/cmdline and then parse parameters */
	strlcpy(boot_command_line, cmd_line, COMMAND_LINE_SIZE);
	parse_early_param();

Y
Yinghai Lu 已提交
146
	memblock_analyze();
147

Y
Yinghai Lu 已提交
148
	pr_debug("Phys. mem: %lx\n", (unsigned long) memblock_phys_mem_size());
149 150 151 152

	pr_debug(" <- early_init_devtree()\n");
}

153 154 155 156 157 158 159 160 161 162
#ifdef CONFIG_BLK_DEV_INITRD
void __init early_init_dt_setup_initrd_arch(unsigned long start,
		unsigned long end)
{
	initrd_start = (unsigned long)__va(start);
	initrd_end = (unsigned long)__va(end);
	initrd_below_start_ok = 1;
}
#endif

163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
/*******
 *
 * New implementation of the OF "find" APIs, return a refcounted
 * object, call of_node_put() when done.  The device tree and list
 * are protected by a rw_lock.
 *
 * Note that property management will need some locking as well,
 * this isn't dealt with yet.
 *
 *******/

#if defined(CONFIG_DEBUG_FS) && defined(DEBUG)
static struct debugfs_blob_wrapper flat_dt_blob;

static int __init export_flat_device_tree(void)
{
	struct dentry *d;

	flat_dt_blob.data = initial_boot_params;
	flat_dt_blob.size = initial_boot_params->totalsize;

	d = debugfs_create_blob("flat-device-tree", S_IFREG | S_IRUSR,
				of_debugfs_root, &flat_dt_blob);
	if (!d)
		return 1;

	return 0;
}
device_initcall(export_flat_device_tree);
#endif