Skip to content

Commit

Permalink
xtensa: add device trees support
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
jcmvbkbc authored and czankel committed Dec 19, 2012
1 parent 2206d5d commit da844a8
Show file tree
Hide file tree
Showing 7 changed files with 164 additions and 25 deletions.
11 changes: 11 additions & 0 deletions arch/xtensa/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,17 @@ config CMDLINE
time by entering them here. As a minimum, you should specify the
memory size and the root device (e.g., mem=64M root=/dev/nfs).

config USE_OF
bool "Flattened Device Tree support"
select OF
select OF_EARLY_FLATTREE
help
Include support for flattened device tree machine descriptions.

config BUILTIN_DTB
string "DTB to build into the kernel image"
depends on OF

source "mm/Kconfig"

source "drivers/pcmcia/Kconfig"
Expand Down
7 changes: 7 additions & 0 deletions arch/xtensa/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ core-y += $(buildvar) $(buildplf)

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

ifneq ($(CONFIG_BUILTIN_DTB),"")
core-y += arch/xtensa/boot/
endif

boot := arch/xtensa/boot

all: zImage
Expand All @@ -88,6 +92,9 @@ bzImage : zImage
zImage: vmlinux
$(Q)$(MAKE) $(build)=$(boot) $@

%.dtb:
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@

define archhelp
@echo '* zImage - Compressed kernel image (arch/xtensa/boot/images/zImage.*)'
endef
Expand Down
11 changes: 11 additions & 0 deletions arch/xtensa/boot/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,17 @@ bootdir-$(CONFIG_XTENSA_PLATFORM_ISS) += boot-elf
bootdir-$(CONFIG_XTENSA_PLATFORM_XT2000) += boot-redboot boot-elf boot-uboot


BUILTIN_DTB := $(patsubst "%",%,$(CONFIG_BUILTIN_DTB)).dtb.o
ifneq ($(CONFIG_BUILTIN_DTB),"")
obj-y += $(BUILTIN_DTB)
endif

# Rule to build device tree blobs
$(obj)/%.dtb: $(src)/dts/%.dts FORCE
$(call if_changed_dep,dtc)

clean-files := *.dtb.S

zImage Image: $(bootdir-y)

$(bootdir-y): $(addprefix $(obj)/,$(subdir-y)) \
Expand Down
1 change: 1 addition & 0 deletions arch/xtensa/include/asm/bootparam.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#define BP_TAG_MEMORY 0x1003 /* memory addr and size (bp_meminfo) */
#define BP_TAG_SERIAL_BAUSRATE 0x1004 /* baud rate of current console. */
#define BP_TAG_SERIAL_PORT 0x1005 /* serial device of current console */
#define BP_TAG_FDT 0x1006 /* flat device tree addr */

#define BP_TAG_FIRST 0x7B0B /* first tag with a version number */
#define BP_TAG_LAST 0x7E0B /* last tag */
Expand Down
6 changes: 6 additions & 0 deletions arch/xtensa/include/asm/prom.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#ifndef _XTENSA_ASM_PROM_H
#define _XTENSA_ASM_PROM_H

#define HAVE_ARCH_DEVTREE_FIXUPS

#endif /* _XTENSA_ASM_PROM_H */
10 changes: 10 additions & 0 deletions arch/xtensa/kernel/irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <linux/irq.h>
#include <linux/kernel_stat.h>
#include <linux/irqdomain.h>
#include <linux/of.h>

#include <asm/uaccess.h>
#include <asm/platform.h>
Expand Down Expand Up @@ -199,8 +200,17 @@ void __init init_IRQ(void)
cached_irq_mask = 0;
set_sr(~0, intclear);

#ifdef CONFIG_OF
/* The interrupt controller device node is mandatory */
intc = of_find_compatible_node(NULL, NULL, "xtensa,pic");
BUG_ON(!intc);

root_domain = irq_domain_add_linear(intc, NR_IRQS,
&xtensa_irq_domain_ops, NULL);
#else
root_domain = irq_domain_add_legacy(intc, NR_IRQS, 0, 0,
&xtensa_irq_domain_ops, NULL);
#endif
irq_set_default_host(root_domain);

variant_init_irq();
Expand Down
143 changes: 118 additions & 25 deletions arch/xtensa/kernel/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@
#include <linux/bootmem.h>
#include <linux/kernel.h>

#ifdef CONFIG_OF
#include <linux/of_fdt.h>
#include <linux/of_platform.h>
#endif

#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
# include <linux/console.h>
#endif
Expand Down Expand Up @@ -65,6 +70,11 @@ int initrd_is_mapped = 0;
extern int initrd_below_start_ok;
#endif

#ifdef CONFIG_OF
extern u32 __dtb_start[];
void *dtb_start = __dtb_start;
#endif

unsigned char aux_device_present;
extern unsigned long loops_per_jiffy;

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

extern int mem_reserve(unsigned long, unsigned long, int);
extern void bootmem_init(void);
extern void zones_init(void);

/*
Expand All @@ -105,28 +117,33 @@ typedef struct tagtable {

/* parse current tag */

static int __init parse_tag_mem(const bp_tag_t *tag)
static int __init add_sysmem_bank(unsigned long type, unsigned long start,
unsigned long end)
{
meminfo_t *mi = (meminfo_t*)(tag->data);

if (mi->type != MEMORY_TYPE_CONVENTIONAL)
return -1;

if (sysmem.nr_banks >= SYSMEM_BANKS_MAX) {
printk(KERN_WARNING
"Ignoring memory bank 0x%08lx size %ldKB\n",
(unsigned long)mi->start,
(unsigned long)mi->end - (unsigned long)mi->start);
"Ignoring memory bank 0x%08lx size %ldKB\n",
start, end - start);
return -EINVAL;
}
sysmem.bank[sysmem.nr_banks].type = mi->type;
sysmem.bank[sysmem.nr_banks].start = PAGE_ALIGN(mi->start);
sysmem.bank[sysmem.nr_banks].end = mi->end & PAGE_MASK;
sysmem.bank[sysmem.nr_banks].type = type;
sysmem.bank[sysmem.nr_banks].start = PAGE_ALIGN(start);
sysmem.bank[sysmem.nr_banks].end = end & PAGE_MASK;
sysmem.nr_banks++;

return 0;
}

static int __init parse_tag_mem(const bp_tag_t *tag)
{
meminfo_t *mi = (meminfo_t *)(tag->data);

if (mi->type != MEMORY_TYPE_CONVENTIONAL)
return -1;

return add_sysmem_bank(mi->type, mi->start, mi->end);
}

__tagtable(BP_TAG_MEMORY, parse_tag_mem);

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

__tagtable(BP_TAG_INITRD, parse_tag_initrd);

#ifdef CONFIG_OF

static int __init parse_tag_fdt(const bp_tag_t *tag)
{
dtb_start = (void *)(tag->data[0]);
return 0;
}

__tagtable(BP_TAG_FDT, parse_tag_fdt);

void __init early_init_dt_setup_initrd_arch(unsigned long start,
unsigned long end)
{
initrd_start = (void *)__va(start);
initrd_end = (void *)__va(end);
initrd_below_start_ok = 1;
}

#endif /* CONFIG_OF */

#endif /* CONFIG_BLK_DEV_INITRD */

static int __init parse_tag_cmdline(const bp_tag_t* tag)
{
strncpy(command_line, (char*)(tag->data), COMMAND_LINE_SIZE);
command_line[COMMAND_LINE_SIZE - 1] = '\0';
strlcpy(command_line, (char *)(tag->data), COMMAND_LINE_SIZE);
return 0;
}

Expand Down Expand Up @@ -186,6 +222,58 @@ static int __init parse_bootparam(const bp_tag_t* tag)
return 0;
}

#ifdef CONFIG_OF

void __init early_init_dt_add_memory_arch(u64 base, u64 size)
{
size &= PAGE_MASK;
add_sysmem_bank(MEMORY_TYPE_CONVENTIONAL, base, base + size);
}

void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
{
return __alloc_bootmem(size, align, 0);
}

void __init early_init_devtree(void *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 ...
*/
if (!command_line[0])
of_scan_flat_dt(early_init_dt_scan_chosen, command_line);

/* Scan memory nodes and rebuild MEMBLOCKs */
of_scan_flat_dt(early_init_dt_scan_root, NULL);
if (sysmem.nr_banks == 0)
of_scan_flat_dt(early_init_dt_scan_memory, NULL);
}

static void __init copy_devtree(void)
{
void *alloc = early_init_dt_alloc_memory_arch(
be32_to_cpu(initial_boot_params->totalsize), 0);
if (alloc) {
memcpy(alloc, initial_boot_params,
be32_to_cpu(initial_boot_params->totalsize));
initial_boot_params = alloc;
}
}

static int __init xtensa_device_probe(void)
{
of_platform_populate(NULL, NULL, NULL, NULL);
return 0;
}

device_initcall(xtensa_device_probe);

#endif /* CONFIG_OF */

/*
* Initialize architecture. (Early stage)
*/
Expand All @@ -194,14 +282,14 @@ void __init init_arch(bp_tag_t *bp_start)
{
sysmem.nr_banks = 0;

#ifdef CONFIG_CMDLINE_BOOL
strcpy(command_line, default_command_line);
#endif

/* Parse boot parameters */

if (bp_start)
parse_bootparam(bp_start);
parse_bootparam(bp_start);

#ifdef CONFIG_OF
early_init_devtree(dtb_start);
#endif

if (sysmem.nr_banks == 0) {
sysmem.nr_banks = 1;
Expand All @@ -210,6 +298,11 @@ void __init init_arch(bp_tag_t *bp_start)
+ PLATFORM_DEFAULT_MEM_SIZE;
}

#ifdef CONFIG_CMDLINE_BOOL
if (!command_line[0])
strlcpy(command_line, default_command_line, COMMAND_LINE_SIZE);
#endif

/* Early hook for platforms */

platform_init(bp_start);
Expand Down Expand Up @@ -355,11 +448,7 @@ void __init check_s32c1i(void)

void __init setup_arch(char **cmdline_p)
{
extern int mem_reserve(unsigned long, unsigned long, int);
extern void bootmem_init(void);

memcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
boot_command_line[COMMAND_LINE_SIZE-1] = '\0';
strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
*cmdline_p = command_line;

check_s32c1i();
Expand Down Expand Up @@ -395,8 +484,12 @@ void __init setup_arch(char **cmdline_p)

bootmem_init();

platform_setup(cmdline_p);
#ifdef CONFIG_OF
copy_devtree();
unflatten_device_tree();
#endif

platform_setup(cmdline_p);

paging_init();
zones_init();
Expand Down

0 comments on commit da844a8

Please sign in to comment.