diff options
author | Masahiro Yamada <yamada.masahiro@socionext.com> | 2019-07-10 20:07:42 +0900 |
---|---|---|
committer | Masahiro Yamada <yamada.masahiro@socionext.com> | 2019-07-10 22:42:03 +0900 |
commit | 34ded875067306961a684186cf23227b58802b28 (patch) | |
tree | 401ab1652c9f5a4df1ffe5756345d923110e720c | |
parent | 739ba41d5a0964a9bc0d5705055ddb706d7e070d (diff) |
ARM: uniphier: detect register base addresses run-time
Until the last SoC, the register addresses have been hard-coded because
they are always constant. For a planned new SoC, the register bases
will be completely changed. I insist on supporting multiple SoCs/boards
by a single defconfig (uniphier_v8_defconfig) since duplicating similar
defconfig files is a maintenance burden. The base addresses must be
fixed-up at run-time somehow.
Previously, the board init code identified the SoC by reading out the
SG_REVISION register. This is much easier than parsing DT.
You cannot do it any more because the base address of SG will be
changed. The SG_REVISION register exists to read out the SoC ID, but
you never know its address before identifying the SoC. Oh well.
So, the possible solution is to parse the DT, and find out the node
with "*-soc-glue" compatible string. Then, sg_base is set to the value
of the "reg" property. The sc_base is set up likewise.
It is worth noting a pit-fall. Having sc_base and sg_base in the global
scope will make the life easier, but the global variables are poorly
supported before the relocation. In fact, the .bss section overwraps
with DT. Allocating them in the .bss section would break DT. So, I gave
dummy initializers to assign them in the .data section.
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
-rw-r--r-- | arch/arm/mach-uniphier/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/mach-uniphier/base-address.c | 67 | ||||
-rw-r--r-- | arch/arm/mach-uniphier/base-address.h | 18 | ||||
-rw-r--r-- | arch/arm/mach-uniphier/cpu-info.c | 6 | ||||
-rw-r--r-- | arch/arm/mach-uniphier/sc64-regs.h | 2 | ||||
-rw-r--r-- | arch/arm/mach-uniphier/sg-regs.h | 4 |
6 files changed, 97 insertions, 1 deletions
diff --git a/arch/arm/mach-uniphier/Makefile b/arch/arm/mach-uniphier/Makefile index caa79d1e53..115af244cd 100644 --- a/arch/arm/mach-uniphier/Makefile +++ b/arch/arm/mach-uniphier/Makefile @@ -13,6 +13,7 @@ else obj-$(CONFIG_DISPLAY_CPUINFO) += cpu-info.o obj-y += dram_init.o obj-y += board_init.o +obj-$(CONFIG_ARCH_UNIPHIER_V8_MULTI) += base-address.o obj-$(CONFIG_BOARD_LATE_INIT) += board_late_init.o ifndef CONFIG_SYSRESET obj-y += reset.o diff --git a/arch/arm/mach-uniphier/base-address.c b/arch/arm/mach-uniphier/base-address.c new file mode 100644 index 0000000000..5ee742e363 --- /dev/null +++ b/arch/arm/mach-uniphier/base-address.c @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright (C) 2019 Socionext Inc. +// Author: Masahiro Yamada <yamada.masahiro@socionext.com> + +#include <common.h> +#include <dm/of.h> +#include <fdt_support.h> +#include <linux/io.h> +#include <linux/libfdt.h> +#include <linux/sizes.h> +#include <asm/global_data.h> + +#include "base-address.h" +#include "sc64-regs.h" +#include "sg-regs.h" + +/* + * Dummy initializers are needed to allocate these to .data section instead of + * .bss section. The .bss section is unusable before relocation because the + * .bss section and DT share the same address. Without the initializers, + * DT would be broken. + */ +void __iomem *sc_base = (void *)0xdeadbeef; +void __iomem *sg_base = (void *)0xdeadbeef; + +static u64 uniphier_base_address_get(const char *compat_tail) +{ + DECLARE_GLOBAL_DATA_PTR; + const void *fdt = gd->fdt_blob; + int offset, len, i; + const char *str; + + for (offset = fdt_next_node(fdt, 0, NULL); + offset >= 0; + offset = fdt_next_node(fdt, offset, NULL)) { + for (i = 0; + (str = fdt_stringlist_get(fdt, offset, "compatible", i, &len)); + i++) { + if (!memcmp(compat_tail, + str + len - strlen(compat_tail), + strlen(compat_tail))) + return fdt_get_base_address(fdt, offset); + } + } + + return OF_BAD_ADDR; +} + +int uniphier_base_address_init(void) +{ + u64 base; + + base = uniphier_base_address_get("-soc-glue"); + if (base == OF_BAD_ADDR) + return -EINVAL; + + sg_base = ioremap(base, SZ_8K); + + base = uniphier_base_address_get("-sysctrl"); + if (base == OF_BAD_ADDR) + return -EINVAL; + + sc_base = ioremap(base, SZ_64K); + + return 0; +} diff --git a/arch/arm/mach-uniphier/base-address.h b/arch/arm/mach-uniphier/base-address.h new file mode 100644 index 0000000000..6158ce7d66 --- /dev/null +++ b/arch/arm/mach-uniphier/base-address.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2019 Socionext Inc. + */ + +#ifndef __UNIPHIER_BASE_ADDRESS_H +#define __UNIPHIER_BASE_ADDRESS_H + +#ifdef CONFIG_ARCH_UNIPHIER_V8_MULTI +int uniphier_base_address_init(void); +#else +static inline int uniphier_base_address_init(void) +{ + return 0; +} +#endif + +#endif /* __UNIPHIER_BASE_ADDRESS_H */ diff --git a/arch/arm/mach-uniphier/cpu-info.c b/arch/arm/mach-uniphier/cpu-info.c index 9f5f5051b3..6a7b203a44 100644 --- a/arch/arm/mach-uniphier/cpu-info.c +++ b/arch/arm/mach-uniphier/cpu-info.c @@ -10,11 +10,17 @@ #include <linux/io.h> #include <linux/printk.h> +#include "base-address.h" #include "soc-info.h" int print_cpuinfo(void) { unsigned int id, model, rev, required_model = 1, required_rev = 1; + int ret; + + ret = uniphier_base_address_init(); + if (ret) + return ret; id = uniphier_get_soc_id(); model = uniphier_get_soc_model(); diff --git a/arch/arm/mach-uniphier/sc64-regs.h b/arch/arm/mach-uniphier/sc64-regs.h index 1f3b41a336..fdcca232b6 100644 --- a/arch/arm/mach-uniphier/sc64-regs.h +++ b/arch/arm/mach-uniphier/sc64-regs.h @@ -11,7 +11,7 @@ #ifndef __ASSEMBLY__ #include <linux/compiler.h> -#define sc_base ((void __iomem *)SC_BASE) +extern void __iomem *sc_base; #endif #define SC_BASE 0x61840000 diff --git a/arch/arm/mach-uniphier/sg-regs.h b/arch/arm/mach-uniphier/sg-regs.h index cba02d1f4a..f47d101949 100644 --- a/arch/arm/mach-uniphier/sg-regs.h +++ b/arch/arm/mach-uniphier/sg-regs.h @@ -12,8 +12,12 @@ #ifndef __ASSEMBLY__ #include <linux/compiler.h> +#ifdef CONFIG_ARCH_UNIPHIER_V8_MULTI +extern void __iomem *sg_base; +#else #define sg_base ((void __iomem *)SG_BASE) #endif +#endif /* __ASSEMBLY__ */ /* Base Address */ #define SG_BASE 0x5f800000 |