prom.c 5.1 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_scan_chosen_arch(unsigned long node)
46
{
47
	/* No Microblaze specific code here */
48 49
}

50
void __init early_init_dt_add_memory_arch(u64 base, u64 size)
51
{
Y
Yinghai Lu 已提交
52
	memblock_add(base, size);
53 54
}

J
Jeremy Kerr 已提交
55 56
u64 __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
{
Y
Yinghai Lu 已提交
57
	return memblock_alloc(size, align);
J
Jeremy Kerr 已提交
58 59
}

60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
#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) &&
			(strncmp(p, "xlnx,opb-uartlite", 17) != 0))
		return 0;

	addr = of_get_flat_dt_prop(node, "reg", &l);
	return *addr; /* return address */
}

/* 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);
}
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125

/* 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);
	return addr; /* return address */
}

/* 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);
}
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
#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 已提交
141 142
	/* Scan memory nodes and rebuild MEMBLOCKs */
	memblock_init();
143 144 145 146 147 148 149
	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 已提交
150
	memblock_analyze();
151

Y
Yinghai Lu 已提交
152
	pr_debug("Phys. mem: %lx\n", (unsigned long) memblock_phys_mem_size());
153 154 155 156

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

157 158 159 160 161 162 163 164 165 166
#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

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 193 194 195 196
/*******
 *
 * 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