| 1 | /* |
| 2 | * Procedures for creating, accessing and interpreting the device tree. |
| 3 | * |
| 4 | * Paul Mackerras August 1996. |
| 5 | * Copyright (C) 1996-2005 Paul Mackerras. |
| 6 | * |
| 7 | * Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner. |
| 8 | * {engebret|bergner}@us.ibm.com |
| 9 | * |
| 10 | * This program is free software; you can redistribute it and/or |
| 11 | * modify it under the terms of the GNU General Public License |
| 12 | * as published by the Free Software Foundation; either version |
| 13 | * 2 of the License, or (at your option) any later version. |
| 14 | */ |
| 15 | |
| 16 | #include <stdarg.h> |
| 17 | #include <linux/export.h> |
| 18 | #include <linux/kernel.h> |
| 19 | #include <linux/string.h> |
| 20 | #include <linux/init.h> |
| 21 | #include <linux/threads.h> |
| 22 | #include <linux/spinlock.h> |
| 23 | #include <linux/types.h> |
| 24 | #include <linux/pci.h> |
| 25 | #include <linux/stringify.h> |
| 26 | #include <linux/delay.h> |
| 27 | #include <linux/initrd.h> |
| 28 | #include <linux/bitops.h> |
| 29 | #include <linux/kexec.h> |
| 30 | #include <linux/debugfs.h> |
| 31 | #include <linux/irq.h> |
| 32 | #include <linux/memblock.h> |
| 33 | #include <linux/of_fdt.h> |
| 34 | |
| 35 | #include <asm/prom.h> |
| 36 | #include <asm/page.h> |
| 37 | #include <asm/processor.h> |
| 38 | #include <asm/irq.h> |
| 39 | #include <linux/io.h> |
| 40 | #include <asm/mmu.h> |
| 41 | #include <asm/pgtable.h> |
| 42 | #include <asm/sections.h> |
| 43 | #include <asm/pci-bridge.h> |
| 44 | |
| 45 | #ifdef CONFIG_EARLY_PRINTK |
| 46 | static const char *stdout; |
| 47 | |
| 48 | static int __init early_init_dt_scan_chosen_serial(unsigned long node, |
| 49 | const char *uname, int depth, void *data) |
| 50 | { |
| 51 | int l; |
| 52 | const char *p; |
| 53 | |
| 54 | pr_debug("%s: depth: %d, uname: %s\n", __func__, depth, uname); |
| 55 | |
| 56 | if (depth == 1 && (strcmp(uname, "chosen") == 0 || |
| 57 | strcmp(uname, "chosen@0") == 0)) { |
| 58 | p = of_get_flat_dt_prop(node, "linux,stdout-path", &l); |
| 59 | if (p != NULL && l > 0) |
| 60 | stdout = p; /* store pointer to stdout-path */ |
| 61 | } |
| 62 | |
| 63 | if (stdout && strstr(stdout, uname)) { |
| 64 | p = of_get_flat_dt_prop(node, "compatible", &l); |
| 65 | pr_debug("Compatible string: %s\n", p); |
| 66 | |
| 67 | if ((strncmp(p, "xlnx,xps-uart16550", 18) == 0) || |
| 68 | (strncmp(p, "xlnx,axi-uart16550", 18) == 0)) { |
| 69 | unsigned int addr; |
| 70 | |
| 71 | *(u32 *)data = UART16550; |
| 72 | |
| 73 | addr = *(u32 *)of_get_flat_dt_prop(node, "reg", &l); |
| 74 | addr += *(u32 *)of_get_flat_dt_prop(node, |
| 75 | "reg-offset", &l); |
| 76 | /* clear register offset */ |
| 77 | return be32_to_cpu(addr) & ~3; |
| 78 | } |
| 79 | if ((strncmp(p, "xlnx,xps-uartlite", 17) == 0) || |
| 80 | (strncmp(p, "xlnx,opb-uartlite", 17) == 0) || |
| 81 | (strncmp(p, "xlnx,axi-uartlite", 17) == 0) || |
| 82 | (strncmp(p, "xlnx,mdm", 8) == 0)) { |
| 83 | const unsigned int *addrp; |
| 84 | |
| 85 | *(u32 *)data = UARTLITE; |
| 86 | |
| 87 | addrp = of_get_flat_dt_prop(node, "reg", &l); |
| 88 | return be32_to_cpup(addrp); /* return address */ |
| 89 | } |
| 90 | } |
| 91 | return 0; |
| 92 | } |
| 93 | |
| 94 | /* this function is looking for early console - Microblaze specific */ |
| 95 | int __init of_early_console(void *version) |
| 96 | { |
| 97 | return of_scan_flat_dt(early_init_dt_scan_chosen_serial, version); |
| 98 | } |
| 99 | #endif |
| 100 | |
| 101 | void __init early_init_devtree(void *params) |
| 102 | { |
| 103 | pr_debug(" -> early_init_devtree(%p)\n", params); |
| 104 | |
| 105 | early_init_dt_scan(params); |
| 106 | if (!strlen(boot_command_line)) |
| 107 | strlcpy(boot_command_line, cmd_line, COMMAND_LINE_SIZE); |
| 108 | |
| 109 | parse_early_param(); |
| 110 | |
| 111 | memblock_allow_resize(); |
| 112 | |
| 113 | pr_debug("Phys. mem: %lx\n", (unsigned long) memblock_phys_mem_size()); |
| 114 | |
| 115 | pr_debug(" <- early_init_devtree()\n"); |
| 116 | } |