aboutsummaryrefslogtreecommitdiffstats
path: root/arch/xtensa
diff options
context:
space:
mode:
authorMax Filippov <jcmvbkbc@gmail.com>2012-11-03 16:30:13 -0400
committerChris Zankel <chris@zankel.net>2012-12-19 00:10:23 -0500
commitda844a81779e2bb263eca4ecb1046541fdb11cf8 (patch)
tree22f332194e7c13b1b4e2f9715c047722d0dd958a /arch/xtensa
parent2206d5dd9a785a74afc6981f2b13b7a4d4da6f31 (diff)
xtensa: add device trees support
Device trees allow specification of hardware topology and device parameters at runtime instead of hard-coding them in platform setup code. This allows running single binary kernel on a range of compatible boards. New boot parameters tag BP_TAG_FDT is allocated and a pointer to flat device tree is passed in it. Note that current interrupt mapping scheme uses single cell for interrupt identification. That means that IRQ numbers used in DTS must be CPU internal IRQ numbers, not external. It is possible to extend interrupt identification to two cells, and use second cell to tell external IRQ numbers form internal. That would allow to use single DTS on multiple boards with different mapping of external IRQ numbers. Signed-off-by: Max Filippov <jcmvbkbc@gmail.com> Signed-off-by: Chris Zankel <chris@zankel.net>
Diffstat (limited to 'arch/xtensa')
-rw-r--r--arch/xtensa/Kconfig11
-rw-r--r--arch/xtensa/Makefile7
-rw-r--r--arch/xtensa/boot/Makefile11
-rw-r--r--arch/xtensa/include/asm/bootparam.h1
-rw-r--r--arch/xtensa/include/asm/prom.h6
-rw-r--r--arch/xtensa/kernel/irq.c10
-rw-r--r--arch/xtensa/kernel/setup.c143
7 files changed, 164 insertions, 25 deletions
diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig
index 1816abc5c8d5..8ceb5b2ffbb1 100644
--- a/arch/xtensa/Kconfig
+++ b/arch/xtensa/Kconfig
@@ -178,6 +178,17 @@ config CMDLINE
178 time by entering them here. As a minimum, you should specify the 178 time by entering them here. As a minimum, you should specify the
179 memory size and the root device (e.g., mem=64M root=/dev/nfs). 179 memory size and the root device (e.g., mem=64M root=/dev/nfs).
180 180
181config USE_OF
182 bool "Flattened Device Tree support"
183 select OF
184 select OF_EARLY_FLATTREE
185 help
186 Include support for flattened device tree machine descriptions.
187
188config BUILTIN_DTB
189 string "DTB to build into the kernel image"
190 depends on OF
191
181source "mm/Kconfig" 192source "mm/Kconfig"
182 193
183source "drivers/pcmcia/Kconfig" 194source "drivers/pcmcia/Kconfig"
diff --git a/arch/xtensa/Makefile b/arch/xtensa/Makefile
index ab63c9beb930..227f658fc2b9 100644
--- a/arch/xtensa/Makefile
+++ b/arch/xtensa/Makefile
@@ -79,6 +79,10 @@ core-y += $(buildvar) $(buildplf)
79 79
80libs-y += arch/xtensa/lib/ $(LIBGCC) 80libs-y += arch/xtensa/lib/ $(LIBGCC)
81 81
82ifneq ($(CONFIG_BUILTIN_DTB),"")
83core-y += arch/xtensa/boot/
84endif
85
82boot := arch/xtensa/boot 86boot := arch/xtensa/boot
83 87
84all: zImage 88all: zImage
@@ -88,6 +92,9 @@ bzImage : zImage
88zImage: vmlinux 92zImage: vmlinux
89 $(Q)$(MAKE) $(build)=$(boot) $@ 93 $(Q)$(MAKE) $(build)=$(boot) $@
90 94
95%.dtb:
96 $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
97
91define archhelp 98define archhelp
92 @echo '* zImage - Compressed kernel image (arch/xtensa/boot/images/zImage.*)' 99 @echo '* zImage - Compressed kernel image (arch/xtensa/boot/images/zImage.*)'
93endef 100endef
diff --git a/arch/xtensa/boot/Makefile b/arch/xtensa/boot/Makefile
index ff974fc2935b..cb5ff4dbdf88 100644
--- a/arch/xtensa/boot/Makefile
+++ b/arch/xtensa/boot/Makefile
@@ -25,6 +25,17 @@ bootdir-$(CONFIG_XTENSA_PLATFORM_ISS) += boot-elf
25bootdir-$(CONFIG_XTENSA_PLATFORM_XT2000) += boot-redboot boot-elf boot-uboot 25bootdir-$(CONFIG_XTENSA_PLATFORM_XT2000) += boot-redboot boot-elf boot-uboot
26 26
27 27
28BUILTIN_DTB := $(patsubst "%",%,$(CONFIG_BUILTIN_DTB)).dtb.o
29ifneq ($(CONFIG_BUILTIN_DTB),"")
30obj-y += $(BUILTIN_DTB)
31endif
32
33# Rule to build device tree blobs
34$(obj)/%.dtb: $(src)/dts/%.dts FORCE
35 $(call if_changed_dep,dtc)
36
37clean-files := *.dtb.S
38
28zImage Image: $(bootdir-y) 39zImage Image: $(bootdir-y)
29 40
30$(bootdir-y): $(addprefix $(obj)/,$(subdir-y)) \ 41$(bootdir-y): $(addprefix $(obj)/,$(subdir-y)) \
diff --git a/arch/xtensa/include/asm/bootparam.h b/arch/xtensa/include/asm/bootparam.h
index 9983f2c1b7ee..057077e96c98 100644
--- a/arch/xtensa/include/asm/bootparam.h
+++ b/arch/xtensa/include/asm/bootparam.h
@@ -22,6 +22,7 @@
22#define BP_TAG_MEMORY 0x1003 /* memory addr and size (bp_meminfo) */ 22#define BP_TAG_MEMORY 0x1003 /* memory addr and size (bp_meminfo) */
23#define BP_TAG_SERIAL_BAUSRATE 0x1004 /* baud rate of current console. */ 23#define BP_TAG_SERIAL_BAUSRATE 0x1004 /* baud rate of current console. */
24#define BP_TAG_SERIAL_PORT 0x1005 /* serial device of current console */ 24#define BP_TAG_SERIAL_PORT 0x1005 /* serial device of current console */
25#define BP_TAG_FDT 0x1006 /* flat device tree addr */
25 26
26#define BP_TAG_FIRST 0x7B0B /* first tag with a version number */ 27#define BP_TAG_FIRST 0x7B0B /* first tag with a version number */
27#define BP_TAG_LAST 0x7E0B /* last tag */ 28#define BP_TAG_LAST 0x7E0B /* last tag */
diff --git a/arch/xtensa/include/asm/prom.h b/arch/xtensa/include/asm/prom.h
new file mode 100644
index 000000000000..f3d7cd2c0de7
--- /dev/null
+++ b/arch/xtensa/include/asm/prom.h
@@ -0,0 +1,6 @@
1#ifndef _XTENSA_ASM_PROM_H
2#define _XTENSA_ASM_PROM_H
3
4#define HAVE_ARCH_DEVTREE_FIXUPS
5
6#endif /* _XTENSA_ASM_PROM_H */
diff --git a/arch/xtensa/kernel/irq.c b/arch/xtensa/kernel/irq.c
index e90d78211195..6f4f9749cff7 100644
--- a/arch/xtensa/kernel/irq.c
+++ b/arch/xtensa/kernel/irq.c
@@ -19,6 +19,7 @@
19#include <linux/irq.h> 19#include <linux/irq.h>
20#include <linux/kernel_stat.h> 20#include <linux/kernel_stat.h>
21#include <linux/irqdomain.h> 21#include <linux/irqdomain.h>
22#include <linux/of.h>
22 23
23#include <asm/uaccess.h> 24#include <asm/uaccess.h>
24#include <asm/platform.h> 25#include <asm/platform.h>
@@ -199,8 +200,17 @@ void __init init_IRQ(void)
199 cached_irq_mask = 0; 200 cached_irq_mask = 0;
200 set_sr(~0, intclear); 201 set_sr(~0, intclear);
201 202
203#ifdef CONFIG_OF
204 /* The interrupt controller device node is mandatory */
205 intc = of_find_compatible_node(NULL, NULL, "xtensa,pic");
206 BUG_ON(!intc);
207
208 root_domain = irq_domain_add_linear(intc, NR_IRQS,
209 &xtensa_irq_domain_ops, NULL);
210#else
202 root_domain = irq_domain_add_legacy(intc, NR_IRQS, 0, 0, 211 root_domain = irq_domain_add_legacy(intc, NR_IRQS, 0, 0,
203 &xtensa_irq_domain_ops, NULL); 212 &xtensa_irq_domain_ops, NULL);
213#endif
204 irq_set_default_host(root_domain); 214 irq_set_default_host(root_domain);
205 215
206 variant_init_irq(); 216 variant_init_irq();
diff --git a/arch/xtensa/kernel/setup.c b/arch/xtensa/kernel/setup.c
index 45217617c60d..64d80e4b0bd4 100644
--- a/arch/xtensa/kernel/setup.c
+++ b/arch/xtensa/kernel/setup.c
@@ -22,6 +22,11 @@
22#include <linux/bootmem.h> 22#include <linux/bootmem.h>
23#include <linux/kernel.h> 23#include <linux/kernel.h>
24 24
25#ifdef CONFIG_OF
26#include <linux/of_fdt.h>
27#include <linux/of_platform.h>
28#endif
29
25#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE) 30#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
26# include <linux/console.h> 31# include <linux/console.h>
27#endif 32#endif
@@ -65,6 +70,11 @@ int initrd_is_mapped = 0;
65extern int initrd_below_start_ok; 70extern int initrd_below_start_ok;
66#endif 71#endif
67 72
73#ifdef CONFIG_OF
74extern u32 __dtb_start[];
75void *dtb_start = __dtb_start;
76#endif
77
68unsigned char aux_device_present; 78unsigned char aux_device_present;
69extern unsigned long loops_per_jiffy; 79extern unsigned long loops_per_jiffy;
70 80
@@ -84,6 +94,8 @@ extern void init_mmu(void);
84static inline void init_mmu(void) { } 94static inline void init_mmu(void) { }
85#endif 95#endif
86 96
97extern int mem_reserve(unsigned long, unsigned long, int);
98extern void bootmem_init(void);
87extern void zones_init(void); 99extern void zones_init(void);
88 100
89/* 101/*
@@ -105,28 +117,33 @@ typedef struct tagtable {
105 117
106/* parse current tag */ 118/* parse current tag */
107 119
108static int __init parse_tag_mem(const bp_tag_t *tag) 120static int __init add_sysmem_bank(unsigned long type, unsigned long start,
121 unsigned long end)
109{ 122{
110 meminfo_t *mi = (meminfo_t*)(tag->data);
111
112 if (mi->type != MEMORY_TYPE_CONVENTIONAL)
113 return -1;
114
115 if (sysmem.nr_banks >= SYSMEM_BANKS_MAX) { 123 if (sysmem.nr_banks >= SYSMEM_BANKS_MAX) {
116 printk(KERN_WARNING 124 printk(KERN_WARNING
117 "Ignoring memory bank 0x%08lx size %ldKB\n", 125 "Ignoring memory bank 0x%08lx size %ldKB\n",
118 (unsigned long)mi->start, 126 start, end - start);
119 (unsigned long)mi->end - (unsigned long)mi->start);
120 return -EINVAL; 127 return -EINVAL;
121 } 128 }
122 sysmem.bank[sysmem.nr_banks].type = mi->type; 129 sysmem.bank[sysmem.nr_banks].type = type;
123 sysmem.bank[sysmem.nr_banks].start = PAGE_ALIGN(mi->start); 130 sysmem.bank[sysmem.nr_banks].start = PAGE_ALIGN(start);
124 sysmem.bank[sysmem.nr_banks].end = mi->end & PAGE_MASK; 131 sysmem.bank[sysmem.nr_banks].end = end & PAGE_MASK;
125 sysmem.nr_banks++; 132 sysmem.nr_banks++;
126 133
127 return 0; 134 return 0;
128} 135}
129 136
137static int __init parse_tag_mem(const bp_tag_t *tag)
138{
139 meminfo_t *mi = (meminfo_t *)(tag->data);
140
141 if (mi->type != MEMORY_TYPE_CONVENTIONAL)
142 return -1;
143
144 return add_sysmem_bank(mi->type, mi->start, mi->end);
145}
146
130__tagtable(BP_TAG_MEMORY, parse_tag_mem); 147__tagtable(BP_TAG_MEMORY, parse_tag_mem);
131 148
132#ifdef CONFIG_BLK_DEV_INITRD 149#ifdef CONFIG_BLK_DEV_INITRD
@@ -143,12 +160,31 @@ static int __init parse_tag_initrd(const bp_tag_t* tag)
143 160
144__tagtable(BP_TAG_INITRD, parse_tag_initrd); 161__tagtable(BP_TAG_INITRD, parse_tag_initrd);
145 162
163#ifdef CONFIG_OF
164
165static int __init parse_tag_fdt(const bp_tag_t *tag)
166{
167 dtb_start = (void *)(tag->data[0]);
168 return 0;
169}
170
171__tagtable(BP_TAG_FDT, parse_tag_fdt);
172
173void __init early_init_dt_setup_initrd_arch(unsigned long start,
174 unsigned long end)
175{
176 initrd_start = (void *)__va(start);
177 initrd_end = (void *)__va(end);
178 initrd_below_start_ok = 1;
179}
180
181#endif /* CONFIG_OF */
182
146#endif /* CONFIG_BLK_DEV_INITRD */ 183#endif /* CONFIG_BLK_DEV_INITRD */
147 184
148static int __init parse_tag_cmdline(const bp_tag_t* tag) 185static int __init parse_tag_cmdline(const bp_tag_t* tag)
149{ 186{
150 strncpy(command_line, (char*)(tag->data), COMMAND_LINE_SIZE); 187 strlcpy(command_line, (char *)(tag->data), COMMAND_LINE_SIZE);
151 command_line[COMMAND_LINE_SIZE - 1] = '\0';
152 return 0; 188 return 0;
153} 189}
154 190
@@ -186,6 +222,58 @@ static int __init parse_bootparam(const bp_tag_t* tag)
186 return 0; 222 return 0;
187} 223}
188 224
225#ifdef CONFIG_OF
226
227void __init early_init_dt_add_memory_arch(u64 base, u64 size)
228{
229 size &= PAGE_MASK;
230 add_sysmem_bank(MEMORY_TYPE_CONVENTIONAL, base, base + size);
231}
232
233void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
234{
235 return __alloc_bootmem(size, align, 0);
236}
237
238void __init early_init_devtree(void *params)
239{
240 /* Setup flat device-tree pointer */
241 initial_boot_params = params;
242
243 /* Retrieve various informations from the /chosen node of the
244 * device-tree, including the platform type, initrd location and
245 * size, TCE reserve, and more ...
246 */
247 if (!command_line[0])
248 of_scan_flat_dt(early_init_dt_scan_chosen, command_line);
249
250 /* Scan memory nodes and rebuild MEMBLOCKs */
251 of_scan_flat_dt(early_init_dt_scan_root, NULL);
252 if (sysmem.nr_banks == 0)
253 of_scan_flat_dt(early_init_dt_scan_memory, NULL);
254}
255
256static void __init copy_devtree(void)
257{
258 void *alloc = early_init_dt_alloc_memory_arch(
259 be32_to_cpu(initial_boot_params->totalsize), 0);
260 if (alloc) {
261 memcpy(alloc, initial_boot_params,
262 be32_to_cpu(initial_boot_params->totalsize));
263 initial_boot_params = alloc;
264 }
265}
266
267static int __init xtensa_device_probe(void)
268{
269 of_platform_populate(NULL, NULL, NULL, NULL);
270 return 0;
271}
272
273device_initcall(xtensa_device_probe);
274
275#endif /* CONFIG_OF */
276
189/* 277/*
190 * Initialize architecture. (Early stage) 278 * Initialize architecture. (Early stage)
191 */ 279 */
@@ -194,14 +282,14 @@ void __init init_arch(bp_tag_t *bp_start)
194{ 282{
195 sysmem.nr_banks = 0; 283 sysmem.nr_banks = 0;
196 284
197#ifdef CONFIG_CMDLINE_BOOL
198 strcpy(command_line, default_command_line);
199#endif
200
201 /* Parse boot parameters */ 285 /* Parse boot parameters */
202 286
203 if (bp_start) 287 if (bp_start)
204 parse_bootparam(bp_start); 288 parse_bootparam(bp_start);
289
290#ifdef CONFIG_OF
291 early_init_devtree(dtb_start);
292#endif
205 293
206 if (sysmem.nr_banks == 0) { 294 if (sysmem.nr_banks == 0) {
207 sysmem.nr_banks = 1; 295 sysmem.nr_banks = 1;
@@ -210,6 +298,11 @@ void __init init_arch(bp_tag_t *bp_start)
210 + PLATFORM_DEFAULT_MEM_SIZE; 298 + PLATFORM_DEFAULT_MEM_SIZE;
211 } 299 }
212 300
301#ifdef CONFIG_CMDLINE_BOOL
302 if (!command_line[0])
303 strlcpy(command_line, default_command_line, COMMAND_LINE_SIZE);
304#endif
305
213 /* Early hook for platforms */ 306 /* Early hook for platforms */
214 307
215 platform_init(bp_start); 308 platform_init(bp_start);
@@ -355,11 +448,7 @@ void __init check_s32c1i(void)
355 448
356void __init setup_arch(char **cmdline_p) 449void __init setup_arch(char **cmdline_p)
357{ 450{
358 extern int mem_reserve(unsigned long, unsigned long, int); 451 strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
359 extern void bootmem_init(void);
360
361 memcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
362 boot_command_line[COMMAND_LINE_SIZE-1] = '\0';
363 *cmdline_p = command_line; 452 *cmdline_p = command_line;
364 453
365 check_s32c1i(); 454 check_s32c1i();
@@ -395,8 +484,12 @@ void __init setup_arch(char **cmdline_p)
395 484
396 bootmem_init(); 485 bootmem_init();
397 486
398 platform_setup(cmdline_p); 487#ifdef CONFIG_OF
488 copy_devtree();
489 unflatten_device_tree();
490#endif
399 491
492 platform_setup(cmdline_p);
400 493
401 paging_init(); 494 paging_init();
402 zones_init(); 495 zones_init();