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
}

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

55 56 57 58 59 60 61
#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;
62
	const __be32 *addr;
63

64
	pr_debug("search \"serial\", depth: %d, uname: %s\n", depth, uname);
65 66 67 68 69 70 71 72

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

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

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

/* 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);
}
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111

/* 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);
112
	return be32_to_cpu(addr); /* return address */
113 114 115 116 117 118 119
}

/* 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);
}
120 121 122 123 124 125 126 127 128 129 130 131 132
#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 ...
	 */
133
	of_scan_flat_dt(early_init_dt_scan_chosen, cmd_line);
134

Y
Yinghai Lu 已提交
135 136
	/* Scan memory nodes and rebuild MEMBLOCKs */
	memblock_init();
137 138 139 140 141 142 143
	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 已提交
144
	memblock_analyze();
145

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

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

151 152 153 154 155 156 157 158 159 160
#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

161 162 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
/*******
 *
 * 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