Skip to content

Commit da844a8

Browse files
jcmvbkbcczankel
authored andcommitted
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 <[email protected]> Signed-off-by: Chris Zankel <[email protected]>
1 parent 2206d5d commit da844a8

File tree

7 files changed

+164
-25
lines changed

7 files changed

+164
-25
lines changed

arch/xtensa/Kconfig

+11
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,17 @@ config CMDLINE
178178
time by entering them here. As a minimum, you should specify the
179179
memory size and the root device (e.g., mem=64M root=/dev/nfs).
180180

181+
config 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+
188+
config BUILTIN_DTB
189+
string "DTB to build into the kernel image"
190+
depends on OF
191+
181192
source "mm/Kconfig"
182193

183194
source "drivers/pcmcia/Kconfig"

arch/xtensa/Makefile

+7
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ core-y += $(buildvar) $(buildplf)
7979

8080
libs-y += arch/xtensa/lib/ $(LIBGCC)
8181

82+
ifneq ($(CONFIG_BUILTIN_DTB),"")
83+
core-y += arch/xtensa/boot/
84+
endif
85+
8286
boot := arch/xtensa/boot
8387

8488
all: zImage
@@ -88,6 +92,9 @@ bzImage : zImage
8892
zImage: vmlinux
8993
$(Q)$(MAKE) $(build)=$(boot) $@
9094

95+
%.dtb:
96+
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
97+
9198
define archhelp
9299
@echo '* zImage - Compressed kernel image (arch/xtensa/boot/images/zImage.*)'
93100
endef

arch/xtensa/boot/Makefile

+11
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,17 @@ bootdir-$(CONFIG_XTENSA_PLATFORM_ISS) += boot-elf
2525
bootdir-$(CONFIG_XTENSA_PLATFORM_XT2000) += boot-redboot boot-elf boot-uboot
2626

2727

28+
BUILTIN_DTB := $(patsubst "%",%,$(CONFIG_BUILTIN_DTB)).dtb.o
29+
ifneq ($(CONFIG_BUILTIN_DTB),"")
30+
obj-y += $(BUILTIN_DTB)
31+
endif
32+
33+
# Rule to build device tree blobs
34+
$(obj)/%.dtb: $(src)/dts/%.dts FORCE
35+
$(call if_changed_dep,dtc)
36+
37+
clean-files := *.dtb.S
38+
2839
zImage Image: $(bootdir-y)
2940

3041
$(bootdir-y): $(addprefix $(obj)/,$(subdir-y)) \

arch/xtensa/include/asm/bootparam.h

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#define BP_TAG_MEMORY 0x1003 /* memory addr and size (bp_meminfo) */
2323
#define BP_TAG_SERIAL_BAUSRATE 0x1004 /* baud rate of current console. */
2424
#define BP_TAG_SERIAL_PORT 0x1005 /* serial device of current console */
25+
#define BP_TAG_FDT 0x1006 /* flat device tree addr */
2526

2627
#define BP_TAG_FIRST 0x7B0B /* first tag with a version number */
2728
#define BP_TAG_LAST 0x7E0B /* last tag */

arch/xtensa/include/asm/prom.h

+6
Original file line numberDiff line numberDiff line change
@@ -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 */

arch/xtensa/kernel/irq.c

+10
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <linux/irq.h>
2020
#include <linux/kernel_stat.h>
2121
#include <linux/irqdomain.h>
22+
#include <linux/of.h>
2223

2324
#include <asm/uaccess.h>
2425
#include <asm/platform.h>
@@ -199,8 +200,17 @@ void __init init_IRQ(void)
199200
cached_irq_mask = 0;
200201
set_sr(~0, intclear);
201202

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
202211
root_domain = irq_domain_add_legacy(intc, NR_IRQS, 0, 0,
203212
&xtensa_irq_domain_ops, NULL);
213+
#endif
204214
irq_set_default_host(root_domain);
205215

206216
variant_init_irq();

arch/xtensa/kernel/setup.c

+118-25
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@
2222
#include <linux/bootmem.h>
2323
#include <linux/kernel.h>
2424

25+
#ifdef CONFIG_OF
26+
#include <linux/of_fdt.h>
27+
#include <linux/of_platform.h>
28+
#endif
29+
2530
#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
2631
# include <linux/console.h>
2732
#endif
@@ -65,6 +70,11 @@ int initrd_is_mapped = 0;
6570
extern int initrd_below_start_ok;
6671
#endif
6772

73+
#ifdef CONFIG_OF
74+
extern u32 __dtb_start[];
75+
void *dtb_start = __dtb_start;
76+
#endif
77+
6878
unsigned char aux_device_present;
6979
extern unsigned long loops_per_jiffy;
7080

@@ -84,6 +94,8 @@ extern void init_mmu(void);
8494
static inline void init_mmu(void) { }
8595
#endif
8696

97+
extern int mem_reserve(unsigned long, unsigned long, int);
98+
extern void bootmem_init(void);
8799
extern void zones_init(void);
88100

89101
/*
@@ -105,28 +117,33 @@ typedef struct tagtable {
105117

106118
/* parse current tag */
107119

108-
static int __init parse_tag_mem(const bp_tag_t *tag)
120+
static int __init add_sysmem_bank(unsigned long type, unsigned long start,
121+
unsigned long end)
109122
{
110-
meminfo_t *mi = (meminfo_t*)(tag->data);
111-
112-
if (mi->type != MEMORY_TYPE_CONVENTIONAL)
113-
return -1;
114-
115123
if (sysmem.nr_banks >= SYSMEM_BANKS_MAX) {
116124
printk(KERN_WARNING
117-
"Ignoring memory bank 0x%08lx size %ldKB\n",
118-
(unsigned long)mi->start,
119-
(unsigned long)mi->end - (unsigned long)mi->start);
125+
"Ignoring memory bank 0x%08lx size %ldKB\n",
126+
start, end - start);
120127
return -EINVAL;
121128
}
122-
sysmem.bank[sysmem.nr_banks].type = mi->type;
123-
sysmem.bank[sysmem.nr_banks].start = PAGE_ALIGN(mi->start);
124-
sysmem.bank[sysmem.nr_banks].end = mi->end & PAGE_MASK;
129+
sysmem.bank[sysmem.nr_banks].type = type;
130+
sysmem.bank[sysmem.nr_banks].start = PAGE_ALIGN(start);
131+
sysmem.bank[sysmem.nr_banks].end = end & PAGE_MASK;
125132
sysmem.nr_banks++;
126133

127134
return 0;
128135
}
129136

137+
static 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+
130147
__tagtable(BP_TAG_MEMORY, parse_tag_mem);
131148

132149
#ifdef CONFIG_BLK_DEV_INITRD
@@ -143,12 +160,31 @@ static int __init parse_tag_initrd(const bp_tag_t* tag)
143160

144161
__tagtable(BP_TAG_INITRD, parse_tag_initrd);
145162

163+
#ifdef CONFIG_OF
164+
165+
static 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+
173+
void __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+
146183
#endif /* CONFIG_BLK_DEV_INITRD */
147184

148185
static int __init parse_tag_cmdline(const bp_tag_t* tag)
149186
{
150-
strncpy(command_line, (char*)(tag->data), COMMAND_LINE_SIZE);
151-
command_line[COMMAND_LINE_SIZE - 1] = '\0';
187+
strlcpy(command_line, (char *)(tag->data), COMMAND_LINE_SIZE);
152188
return 0;
153189
}
154190

@@ -186,6 +222,58 @@ static int __init parse_bootparam(const bp_tag_t* tag)
186222
return 0;
187223
}
188224

225+
#ifdef CONFIG_OF
226+
227+
void __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+
233+
void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
234+
{
235+
return __alloc_bootmem(size, align, 0);
236+
}
237+
238+
void __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+
256+
static 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+
267+
static int __init xtensa_device_probe(void)
268+
{
269+
of_platform_populate(NULL, NULL, NULL, NULL);
270+
return 0;
271+
}
272+
273+
device_initcall(xtensa_device_probe);
274+
275+
#endif /* CONFIG_OF */
276+
189277
/*
190278
* Initialize architecture. (Early stage)
191279
*/
@@ -194,14 +282,14 @@ void __init init_arch(bp_tag_t *bp_start)
194282
{
195283
sysmem.nr_banks = 0;
196284

197-
#ifdef CONFIG_CMDLINE_BOOL
198-
strcpy(command_line, default_command_line);
199-
#endif
200-
201285
/* Parse boot parameters */
202286

203287
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
205293

206294
if (sysmem.nr_banks == 0) {
207295
sysmem.nr_banks = 1;
@@ -210,6 +298,11 @@ void __init init_arch(bp_tag_t *bp_start)
210298
+ PLATFORM_DEFAULT_MEM_SIZE;
211299
}
212300

301+
#ifdef CONFIG_CMDLINE_BOOL
302+
if (!command_line[0])
303+
strlcpy(command_line, default_command_line, COMMAND_LINE_SIZE);
304+
#endif
305+
213306
/* Early hook for platforms */
214307

215308
platform_init(bp_start);
@@ -355,11 +448,7 @@ void __init check_s32c1i(void)
355448

356449
void __init setup_arch(char **cmdline_p)
357450
{
358-
extern int mem_reserve(unsigned long, unsigned long, int);
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';
451+
strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
363452
*cmdline_p = command_line;
364453

365454
check_s32c1i();
@@ -395,8 +484,12 @@ void __init setup_arch(char **cmdline_p)
395484

396485
bootmem_init();
397486

398-
platform_setup(cmdline_p);
487+
#ifdef CONFIG_OF
488+
copy_devtree();
489+
unflatten_device_tree();
490+
#endif
399491

492+
platform_setup(cmdline_p);
400493

401494
paging_init();
402495
zones_init();

0 commit comments

Comments
 (0)