From 571b7e69f7f775c531ffaf73ae476b1e46150f41 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 2 Jun 2017 12:29:51 -0700 Subject: MIPS: generic/yamon-dt: Pull YAMON DT shim code out of SEAD-3 board In preparation for supporting other YAMON-using boards (Malta) & sharing code to translate information from YAMON into device tree properties, pull the code doing so for the kernel command line, system memory & serial configuration out of the SEAD-3 board code. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/16181/ Signed-off-by: Ralf Baechle --- arch/mips/generic/Kconfig | 8 ++ arch/mips/generic/Makefile | 1 + arch/mips/generic/board-sead3.c | 178 +------------------------------------ arch/mips/generic/yamon-dt.c | 190 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 203 insertions(+), 174 deletions(-) create mode 100644 arch/mips/generic/yamon-dt.c (limited to 'arch/mips/generic') diff --git a/arch/mips/generic/Kconfig b/arch/mips/generic/Kconfig index a606b3f9196c..446b7c68133d 100644 --- a/arch/mips/generic/Kconfig +++ b/arch/mips/generic/Kconfig @@ -9,9 +9,17 @@ config LEGACY_BOARDS kernel is booted without being provided with an FDT via the UHI boot protocol. +config YAMON_DT_SHIM + bool + help + Select this from your board if the board uses the YAMON bootloader + and you wish to include code which helps translate various + YAMON-provided environment variables into a device tree properties. + config LEGACY_BOARD_SEAD3 bool "Support MIPS SEAD-3 boards" select LEGACY_BOARDS + select YAMON_DT_SHIM help Enable this to include support for booting on MIPS SEAD-3 FPGA-based development boards, which boot using a legacy boot protocol. diff --git a/arch/mips/generic/Makefile b/arch/mips/generic/Makefile index acb9b6d62b16..56b3ea565ed9 100644 --- a/arch/mips/generic/Makefile +++ b/arch/mips/generic/Makefile @@ -12,5 +12,6 @@ obj-y += init.o obj-y += irq.o obj-y += proc.o +obj-$(CONFIG_YAMON_DT_SHIM) += yamon-dt.o obj-$(CONFIG_LEGACY_BOARD_SEAD3) += board-sead3.o obj-$(CONFIG_KEXEC) += kexec.o diff --git a/arch/mips/generic/board-sead3.c b/arch/mips/generic/board-sead3.c index f4ae0584a33b..63fdc98738ba 100644 --- a/arch/mips/generic/board-sead3.c +++ b/arch/mips/generic/board-sead3.c @@ -17,6 +17,7 @@ #include #include #include +#include #define SEAD_CONFIG CKSEG1ADDR(0x1b100110) #define SEAD_CONFIG_GIC_PRESENT BIT(1) @@ -33,98 +34,6 @@ static __init bool sead3_detect(void) return (rev & MIPS_REVISION_MACHINE) == MIPS_REVISION_MACHINE_SEAD3; } -static __init int append_cmdline(void *fdt) -{ - int err, chosen_off; - - /* find or add chosen node */ - chosen_off = fdt_path_offset(fdt, "/chosen"); - if (chosen_off == -FDT_ERR_NOTFOUND) - chosen_off = fdt_path_offset(fdt, "/chosen@0"); - if (chosen_off == -FDT_ERR_NOTFOUND) - chosen_off = fdt_add_subnode(fdt, 0, "chosen"); - if (chosen_off < 0) { - pr_err("Unable to find or add DT chosen node: %d\n", - chosen_off); - return chosen_off; - } - - err = fdt_setprop_string(fdt, chosen_off, "bootargs", fw_getcmdline()); - if (err) { - pr_err("Unable to set bootargs property: %d\n", err); - return err; - } - - return 0; -} - -static __init int append_memory(void *fdt) -{ - unsigned long phys_memsize, memsize; - __be32 mem_array[2]; - int err, mem_off; - char *var; - - /* find memory size from the bootloader environment */ - var = fw_getenv("memsize"); - if (var) { - err = kstrtoul(var, 0, &phys_memsize); - if (err) { - pr_err("Failed to read memsize env variable '%s'\n", - var); - return -EINVAL; - } - } else { - pr_warn("The bootloader didn't provide memsize: defaulting to 32MB\n"); - phys_memsize = 32 << 20; - } - - /* default to using all available RAM */ - memsize = phys_memsize; - - /* allow the user to override the usable memory */ - var = strstr(arcs_cmdline, "memsize="); - if (var) - memsize = memparse(var + strlen("memsize="), NULL); - - /* if the user says there's more RAM than we thought, believe them */ - phys_memsize = max_t(unsigned long, phys_memsize, memsize); - - /* find or add a memory node */ - mem_off = fdt_path_offset(fdt, "/memory"); - if (mem_off == -FDT_ERR_NOTFOUND) - mem_off = fdt_add_subnode(fdt, 0, "memory"); - if (mem_off < 0) { - pr_err("Unable to find or add memory DT node: %d\n", mem_off); - return mem_off; - } - - err = fdt_setprop_string(fdt, mem_off, "device_type", "memory"); - if (err) { - pr_err("Unable to set memory node device_type: %d\n", err); - return err; - } - - mem_array[0] = 0; - mem_array[1] = cpu_to_be32(phys_memsize); - err = fdt_setprop(fdt, mem_off, "reg", mem_array, sizeof(mem_array)); - if (err) { - pr_err("Unable to set memory regs property: %d\n", err); - return err; - } - - mem_array[0] = 0; - mem_array[1] = cpu_to_be32(memsize); - err = fdt_setprop(fdt, mem_off, "linux,usable-memory", - mem_array, sizeof(mem_array)); - if (err) { - pr_err("Unable to set linux,usable-memory property: %d\n", err); - return err; - } - - return 0; -} - static __init int remove_gic(void *fdt) { const unsigned int cpu_ehci_int = 2; @@ -214,85 +123,6 @@ static __init int remove_gic(void *fdt) return 0; } -static __init int serial_config(void *fdt) -{ - const char *yamontty, *mode_var; - char mode_var_name[9], path[18], parity; - unsigned int uart, baud, stop_bits; - bool hw_flow; - int chosen_off, err; - - yamontty = fw_getenv("yamontty"); - if (!yamontty || !strcmp(yamontty, "tty0")) { - uart = 0; - } else if (!strcmp(yamontty, "tty1")) { - uart = 1; - } else { - pr_warn("yamontty environment variable '%s' invalid\n", - yamontty); - uart = 0; - } - - baud = stop_bits = 0; - parity = 0; - hw_flow = false; - - snprintf(mode_var_name, sizeof(mode_var_name), "modetty%u", uart); - mode_var = fw_getenv(mode_var_name); - if (mode_var) { - while (mode_var[0] >= '0' && mode_var[0] <= '9') { - baud *= 10; - baud += mode_var[0] - '0'; - mode_var++; - } - if (mode_var[0] == ',') - mode_var++; - if (mode_var[0]) - parity = mode_var[0]; - if (mode_var[0] == ',') - mode_var++; - if (mode_var[0]) - stop_bits = mode_var[0] - '0'; - if (mode_var[0] == ',') - mode_var++; - if (!strcmp(mode_var, "hw")) - hw_flow = true; - } - - if (!baud) - baud = 38400; - - if (parity != 'e' && parity != 'n' && parity != 'o') - parity = 'n'; - - if (stop_bits != 7 && stop_bits != 8) - stop_bits = 8; - - WARN_ON(snprintf(path, sizeof(path), "uart%u:%u%c%u%s", - uart, baud, parity, stop_bits, - hw_flow ? "r" : "") >= sizeof(path)); - - /* find or add chosen node */ - chosen_off = fdt_path_offset(fdt, "/chosen"); - if (chosen_off == -FDT_ERR_NOTFOUND) - chosen_off = fdt_path_offset(fdt, "/chosen@0"); - if (chosen_off == -FDT_ERR_NOTFOUND) - chosen_off = fdt_add_subnode(fdt, 0, "chosen"); - if (chosen_off < 0) { - pr_err("Unable to find or add DT chosen node: %d\n", - chosen_off); - return chosen_off; - } - - err = fdt_setprop_string(fdt, chosen_off, "stdout-path", path); - if (err) { - pr_err("Unable to set stdout-path property: %d\n", err); - return err; - } - - return 0; -} - static __init const void *sead3_fixup_fdt(const void *fdt, const void *match_data) { @@ -311,11 +141,11 @@ static __init const void *sead3_fixup_fdt(const void *fdt, if (err) panic("Unable to open FDT: %d", err); - err = append_cmdline(fdt_buf); + err = yamon_dt_append_cmdline(fdt_buf); if (err) panic("Unable to patch FDT: %d", err); - err = append_memory(fdt_buf); + err = yamon_dt_append_memory(fdt_buf); if (err) panic("Unable to patch FDT: %d", err); @@ -323,7 +153,7 @@ static __init const void *sead3_fixup_fdt(const void *fdt, if (err) panic("Unable to patch FDT: %d", err); - err = serial_config(fdt_buf); + err = yamon_dt_serial_config(fdt_buf); if (err) panic("Unable to patch FDT: %d", err); diff --git a/arch/mips/generic/yamon-dt.c b/arch/mips/generic/yamon-dt.c new file mode 100644 index 000000000000..9a0c8da5a796 --- /dev/null +++ b/arch/mips/generic/yamon-dt.c @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2016 Imagination Technologies + * Author: Paul Burton + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#define pr_fmt(fmt) "yamon-dt: " fmt + +#include +#include +#include +#include +#include + +#include + +__init int yamon_dt_append_cmdline(void *fdt) +{ + int err, chosen_off; + + /* find or add chosen node */ + chosen_off = fdt_path_offset(fdt, "/chosen"); + if (chosen_off == -FDT_ERR_NOTFOUND) + chosen_off = fdt_path_offset(fdt, "/chosen@0"); + if (chosen_off == -FDT_ERR_NOTFOUND) + chosen_off = fdt_add_subnode(fdt, 0, "chosen"); + if (chosen_off < 0) { + pr_err("Unable to find or add DT chosen node: %d\n", + chosen_off); + return chosen_off; + } + + err = fdt_setprop_string(fdt, chosen_off, "bootargs", fw_getcmdline()); + if (err) { + pr_err("Unable to set bootargs property: %d\n", err); + return err; + } + + return 0; +} + +__init int yamon_dt_append_memory(void *fdt) +{ + unsigned long phys_memsize, memsize; + __be32 mem_array[2]; + int err, mem_off; + char *var; + + /* find memory size from the bootloader environment */ + var = fw_getenv("memsize"); + if (var) { + err = kstrtoul(var, 0, &phys_memsize); + if (err) { + pr_err("Failed to read memsize env variable '%s'\n", + var); + return -EINVAL; + } + } else { + pr_warn("The bootloader didn't provide memsize: defaulting to 32MB\n"); + phys_memsize = 32 << 20; + } + + /* default to using all available RAM */ + memsize = phys_memsize; + + /* allow the user to override the usable memory */ + var = strstr(arcs_cmdline, "memsize="); + if (var) + memsize = memparse(var + strlen("memsize="), NULL); + + /* if the user says there's more RAM than we thought, believe them */ + phys_memsize = max_t(unsigned long, phys_memsize, memsize); + + /* find or add a memory node */ + mem_off = fdt_path_offset(fdt, "/memory"); + if (mem_off == -FDT_ERR_NOTFOUND) + mem_off = fdt_add_subnode(fdt, 0, "memory"); + if (mem_off < 0) { + pr_err("Unable to find or add memory DT node: %d\n", mem_off); + return mem_off; + } + + err = fdt_setprop_string(fdt, mem_off, "device_type", "memory"); + if (err) { + pr_err("Unable to set memory node device_type: %d\n", err); + return err; + } + + mem_array[0] = 0; + mem_array[1] = cpu_to_be32(phys_memsize); + err = fdt_setprop(fdt, mem_off, "reg", mem_array, sizeof(mem_array)); + if (err) { + pr_err("Unable to set memory regs property: %d\n", err); + return err; + } + + mem_array[0] = 0; + mem_array[1] = cpu_to_be32(memsize); + err = fdt_setprop(fdt, mem_off, "linux,usable-memory", + mem_array, sizeof(mem_array)); + if (err) { + pr_err("Unable to set linux,usable-memory property: %d\n", err); + return err; + } + + return 0; +} + +__init int yamon_dt_serial_config(void *fdt) +{ + const char *yamontty, *mode_var; + char mode_var_name[9], path[18], parity; + unsigned int uart, baud, stop_bits; + bool hw_flow; + int chosen_off, err; + + yamontty = fw_getenv("yamontty"); + if (!yamontty || !strcmp(yamontty, "tty0")) { + uart = 0; + } else if (!strcmp(yamontty, "tty1")) { + uart = 1; + } else { + pr_warn("yamontty environment variable '%s' invalid\n", + yamontty); + uart = 0; + } + + baud = stop_bits = 0; + parity = 0; + hw_flow = false; + + snprintf(mode_var_name, sizeof(mode_var_name), "modetty%u", uart); + mode_var = fw_getenv(mode_var_name); + if (mode_var) { + while (mode_var[0] >= '0' && mode_var[0] <= '9') { + baud *= 10; + baud += mode_var[0] - '0'; + mode_var++; + } + if (mode_var[0] == ',') + mode_var++; + if (mode_var[0]) + parity = mode_var[0]; + if (mode_var[0] == ',') + mode_var++; + if (mode_var[0]) + stop_bits = mode_var[0] - '0'; + if (mode_var[0] == ',') + mode_var++; + if (!strcmp(mode_var, "hw")) + hw_flow = true; + } + + if (!baud) + baud = 38400; + + if (parity != 'e' && parity != 'n' && parity != 'o') + parity = 'n'; + + if (stop_bits != 7 && stop_bits != 8) + stop_bits = 8; + + WARN_ON(snprintf(path, sizeof(path), "uart%u:%u%c%u%s", + uart, baud, parity, stop_bits, + hw_flow ? "r" : "") >= sizeof(path)); + + /* find or add chosen node */ + chosen_off = fdt_path_offset(fdt, "/chosen"); + if (chosen_off == -FDT_ERR_NOTFOUND) + chosen_off = fdt_path_offset(fdt, "/chosen@0"); + if (chosen_off == -FDT_ERR_NOTFOUND) + chosen_off = fdt_add_subnode(fdt, 0, "chosen"); + if (chosen_off < 0) { + pr_err("Unable to find or add DT chosen node: %d\n", + chosen_off); + return chosen_off; + } + + err = fdt_setprop_string(fdt, chosen_off, "stdout-path", path); + if (err) { + pr_err("Unable to set stdout-path property: %d\n", err); + return err; + } + + return 0; +} -- cgit v1.2.3 From f41d2430bbd6b64ee934915a1856fa406677d55e Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 2 Jun 2017 12:29:52 -0700 Subject: MIPS: generic/yamon-dt: Support > 256MB of RAM YAMON can expose more than 256MB of RAM to Linux on Malta by passing an ememsize environment variable with the full size, but the kernel then needs to be careful to choose the corresponding physical memory regions, avoiding the IO memory window. This is platform dependent, and on Malta it also depends on the memory layout which varies between system controllers. Extend yamon_dt_amend_memory() to generically handle this by taking [e]memsize bytes of memory from an array of memory regions passed in as a new parameter. Board code provides this array as appropriate depending on its own memory map. [paul.burton@imgtec.com: SEAD-3 supports 384MB DDR from 0] Signed-off-by: James Hogan Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/16182/ Signed-off-by: Ralf Baechle --- arch/mips/generic/board-sead3.c | 17 +++++++- arch/mips/generic/yamon-dt.c | 92 +++++++++++++++++++++++++++++++--------- arch/mips/include/asm/yamon-dt.h | 22 ++++++++-- 3 files changed, 106 insertions(+), 25 deletions(-) (limited to 'arch/mips/generic') diff --git a/arch/mips/generic/board-sead3.c b/arch/mips/generic/board-sead3.c index 63fdc98738ba..97186a3a5d21 100644 --- a/arch/mips/generic/board-sead3.c +++ b/arch/mips/generic/board-sead3.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -26,6 +27,15 @@ #define MIPS_REVISION_MACHINE (0xf << 4) #define MIPS_REVISION_MACHINE_SEAD3 (0x4 << 4) +/* + * Maximum 384MB RAM at physical address 0, preceding any I/O. + */ +static struct yamon_mem_region mem_regions[] __initdata = { + /* start size */ + { 0, SZ_256M + SZ_128M }, + {} +}; + static __init bool sead3_detect(void) { uint32_t rev; @@ -34,6 +44,11 @@ static __init bool sead3_detect(void) return (rev & MIPS_REVISION_MACHINE) == MIPS_REVISION_MACHINE_SEAD3; } +static __init int append_memory(void *fdt) +{ + return yamon_dt_append_memory(fdt, mem_regions); +} + static __init int remove_gic(void *fdt) { const unsigned int cpu_ehci_int = 2; @@ -145,7 +160,7 @@ static __init const void *sead3_fixup_fdt(const void *fdt, if (err) panic("Unable to patch FDT: %d", err); - err = yamon_dt_append_memory(fdt_buf); + err = append_memory(fdt_buf); if (err) panic("Unable to patch FDT: %d", err); diff --git a/arch/mips/generic/yamon-dt.c b/arch/mips/generic/yamon-dt.c index 9a0c8da5a796..8e36a5baaa7e 100644 --- a/arch/mips/generic/yamon-dt.c +++ b/arch/mips/generic/yamon-dt.c @@ -17,6 +17,9 @@ #include #include +#include + +#define MAX_MEM_ARRAY_ENTRIES 2 __init int yamon_dt_append_cmdline(void *fdt) { @@ -43,23 +46,64 @@ __init int yamon_dt_append_cmdline(void *fdt) return 0; } -__init int yamon_dt_append_memory(void *fdt) +static unsigned int __init gen_fdt_mem_array( + const struct yamon_mem_region *regions, + __be32 *mem_array, + unsigned int max_entries, + unsigned long memsize) +{ + const struct yamon_mem_region *mr; + unsigned long size; + unsigned int entries = 0; + + for (mr = regions; mr->size && memsize; ++mr) { + if (entries >= max_entries) { + pr_warn("Number of regions exceeds max %u\n", + max_entries); + break; + } + + /* How much of the remaining RAM fits in the next region? */ + size = min_t(unsigned long, memsize, mr->size); + memsize -= size; + + /* Emit a memory region */ + *(mem_array++) = cpu_to_be32(mr->start); + *(mem_array++) = cpu_to_be32(size); + ++entries; + + /* Discard the next mr->discard bytes */ + memsize -= min_t(unsigned long, memsize, mr->discard); + } + return entries; +} + +__init int yamon_dt_append_memory(void *fdt, + const struct yamon_mem_region *regions) { unsigned long phys_memsize, memsize; - __be32 mem_array[2]; - int err, mem_off; - char *var; + __be32 mem_array[2 * MAX_MEM_ARRAY_ENTRIES]; + unsigned int mem_entries; + int i, err, mem_off; + char *var, param_name[10], *var_names[] = { + "ememsize", "memsize", + }; /* find memory size from the bootloader environment */ - var = fw_getenv("memsize"); - if (var) { + for (i = 0; i < ARRAY_SIZE(var_names); i++) { + var = fw_getenv(var_names[i]); + if (!var) + continue; + err = kstrtoul(var, 0, &phys_memsize); - if (err) { - pr_err("Failed to read memsize env variable '%s'\n", - var); - return -EINVAL; - } - } else { + if (!err) + break; + + pr_warn("Failed to read the '%s' env variable '%s'\n", + var_names[i], var); + } + + if (!phys_memsize) { pr_warn("The bootloader didn't provide memsize: defaulting to 32MB\n"); phys_memsize = 32 << 20; } @@ -68,9 +112,14 @@ __init int yamon_dt_append_memory(void *fdt) memsize = phys_memsize; /* allow the user to override the usable memory */ - var = strstr(arcs_cmdline, "memsize="); - if (var) - memsize = memparse(var + strlen("memsize="), NULL); + for (i = 0; i < ARRAY_SIZE(var_names); i++) { + snprintf(param_name, sizeof(param_name), "%s=", var_names[i]); + var = strstr(arcs_cmdline, param_name); + if (!var) + continue; + + memsize = memparse(var + strlen(param_name), NULL); + } /* if the user says there's more RAM than we thought, believe them */ phys_memsize = max_t(unsigned long, phys_memsize, memsize); @@ -90,18 +139,19 @@ __init int yamon_dt_append_memory(void *fdt) return err; } - mem_array[0] = 0; - mem_array[1] = cpu_to_be32(phys_memsize); - err = fdt_setprop(fdt, mem_off, "reg", mem_array, sizeof(mem_array)); + mem_entries = gen_fdt_mem_array(regions, mem_array, + MAX_MEM_ARRAY_ENTRIES, phys_memsize); + err = fdt_setprop(fdt, mem_off, "reg", + mem_array, mem_entries * 2 * sizeof(mem_array[0])); if (err) { pr_err("Unable to set memory regs property: %d\n", err); return err; } - mem_array[0] = 0; - mem_array[1] = cpu_to_be32(memsize); + mem_entries = gen_fdt_mem_array(regions, mem_array, + MAX_MEM_ARRAY_ENTRIES, memsize); err = fdt_setprop(fdt, mem_off, "linux,usable-memory", - mem_array, sizeof(mem_array)); + mem_array, mem_entries * 2 * sizeof(mem_array[0])); if (err) { pr_err("Unable to set linux,usable-memory property: %d\n", err); return err; diff --git a/arch/mips/include/asm/yamon-dt.h b/arch/mips/include/asm/yamon-dt.h index 3f3367de4836..485cfe3e45e1 100644 --- a/arch/mips/include/asm/yamon-dt.h +++ b/arch/mips/include/asm/yamon-dt.h @@ -11,6 +11,20 @@ #ifndef __MIPS_ASM_YAMON_DT_H__ #define __MIPS_ASM_YAMON_DT_H__ +#include + +/** + * struct yamon_mem_region - Represents a contiguous range of physical RAM. + * @start: Start physical address. + * @size: Maximum size of region. + * @discard: Length of additional memory to discard after the region. + */ +struct yamon_mem_region { + phys_addr_t start; + phys_addr_t size; + phys_addr_t discard; +}; + /** * yamon_dt_append_cmdline() - Append YAMON-provided command line to /chosen * @fdt: the FDT blob @@ -24,14 +38,16 @@ extern __init int yamon_dt_append_cmdline(void *fdt); /** * yamon_dt_append_memory() - Append YAMON-provided memory info to /memory - * @fdt: the FDT blob + * @fdt: the FDT blob + * @regions: zero size terminated array of physical memory regions * * Generate a /memory node in @fdt based upon memory size information provided - * by YAMON in its environment. + * by YAMON in its environment and the @regions array. * * Return: 0 on success, else -errno */ -extern __init int yamon_dt_append_memory(void *fdt); +extern __init int yamon_dt_append_memory(void *fdt, + const struct yamon_mem_region *regions); /** * yamon_dt_serial_config() - Append YAMON-provided serial config to /chosen -- cgit v1.2.3 From c3d62fc6a058d1024f3ad0525a251e9d6c5203ed Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 2 Jun 2017 12:29:53 -0700 Subject: MIPS: generic/yamon-dt: Use serial* rather than uart* aliases Name aliases in the SEAD-3 device tree serial0 & serial1, rather than uart0 & uart1. This allows the core serial code to make use of the aliases to ensure that the UARTs are consistently numbered as expected rather than having the numbering depend upon probe order. When translating YAMON-provided serial configuration to a device tree stdout-path property adjust accordingly, such that we continue to reference a valid alias. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/16183/ Signed-off-by: Ralf Baechle --- arch/mips/boot/dts/mti/sead3.dts | 6 +++--- arch/mips/generic/yamon-dt.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'arch/mips/generic') diff --git a/arch/mips/boot/dts/mti/sead3.dts b/arch/mips/boot/dts/mti/sead3.dts index 1bf58f841bbb..f327791cbcb5 100644 --- a/arch/mips/boot/dts/mti/sead3.dts +++ b/arch/mips/boot/dts/mti/sead3.dts @@ -14,12 +14,12 @@ interrupt-parent = <&gic>; chosen { - stdout-path = "uart1:115200"; + stdout-path = "serial1:115200"; }; aliases { - uart0 = &uart0; - uart1 = &uart1; + serial0 = &uart0; + serial1 = &uart1; }; cpus { diff --git a/arch/mips/generic/yamon-dt.c b/arch/mips/generic/yamon-dt.c index 8e36a5baaa7e..6077bca9b364 100644 --- a/arch/mips/generic/yamon-dt.c +++ b/arch/mips/generic/yamon-dt.c @@ -163,7 +163,7 @@ __init int yamon_dt_append_memory(void *fdt, __init int yamon_dt_serial_config(void *fdt) { const char *yamontty, *mode_var; - char mode_var_name[9], path[18], parity; + char mode_var_name[9], path[20], parity; unsigned int uart, baud, stop_bits; bool hw_flow; int chosen_off, err; @@ -214,7 +214,7 @@ __init int yamon_dt_serial_config(void *fdt) if (stop_bits != 7 && stop_bits != 8) stop_bits = 8; - WARN_ON(snprintf(path, sizeof(path), "uart%u:%u%c%u%s", + WARN_ON(snprintf(path, sizeof(path), "serial%u:%u%c%u%s", uart, baud, parity, stop_bits, hw_flow ? "r" : "") >= sizeof(path)); -- cgit v1.2.3 From e889dfca12ce95cdeaa50f66d1f33ad8fed4ca58 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 2 Jun 2017 12:29:54 -0700 Subject: MIPS: generic: Abstract FDT fixup application Introduce an apply_mips_fdt_fixups() function which can apply fixups to an FDT based upon an array of fixup descriptions. This abstracts that functionality such that legacy board code can apply FDT fixups without requiring lots of duplication. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/16184/ Signed-off-by: Ralf Baechle --- arch/mips/generic/board-sead3.c | 33 +++++++++++---------------------- arch/mips/generic/init.c | 27 +++++++++++++++++++++++++++ arch/mips/include/asm/machine.h | 31 +++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 22 deletions(-) (limited to 'arch/mips/generic') diff --git a/arch/mips/generic/board-sead3.c b/arch/mips/generic/board-sead3.c index 97186a3a5d21..39e11bd249cf 100644 --- a/arch/mips/generic/board-sead3.c +++ b/arch/mips/generic/board-sead3.c @@ -138,6 +138,14 @@ static __init int remove_gic(void *fdt) return 0; } +static const struct mips_fdt_fixup sead3_fdt_fixups[] __initconst = { + { yamon_dt_append_cmdline, "append command line" }, + { append_memory, "append memory" }, + { remove_gic, "remove GIC when not present" }, + { yamon_dt_serial_config, "append serial configuration" }, + { }, +}; + static __init const void *sead3_fixup_fdt(const void *fdt, const void *match_data) { @@ -152,29 +160,10 @@ static __init const void *sead3_fixup_fdt(const void *fdt, fw_init_cmdline(); - err = fdt_open_into(fdt, fdt_buf, sizeof(fdt_buf)); - if (err) - panic("Unable to open FDT: %d", err); - - err = yamon_dt_append_cmdline(fdt_buf); - if (err) - panic("Unable to patch FDT: %d", err); - - err = append_memory(fdt_buf); - if (err) - panic("Unable to patch FDT: %d", err); - - err = remove_gic(fdt_buf); - if (err) - panic("Unable to patch FDT: %d", err); - - err = yamon_dt_serial_config(fdt_buf); - if (err) - panic("Unable to patch FDT: %d", err); - - err = fdt_pack(fdt_buf); + err = apply_mips_fdt_fixups(fdt_buf, sizeof(fdt_buf), + fdt, sead3_fdt_fixups); if (err) - panic("Unable to pack FDT: %d\n", err); + panic("Unable to fixup FDT: %d", err); return fdt_buf; } diff --git a/arch/mips/generic/init.c b/arch/mips/generic/init.c index 4af619215410..4a9a1edbfb29 100644 --- a/arch/mips/generic/init.c +++ b/arch/mips/generic/init.c @@ -122,6 +122,33 @@ void __init device_tree_init(void) err = register_up_smp_ops(); } +int __init apply_mips_fdt_fixups(void *fdt_out, size_t fdt_out_size, + const void *fdt_in, + const struct mips_fdt_fixup *fixups) +{ + int err; + + err = fdt_open_into(fdt_in, fdt_out, fdt_out_size); + if (err) { + pr_err("Failed to open FDT\n"); + return err; + } + + for (; fixups->apply; fixups++) { + err = fixups->apply(fdt_out); + if (err) { + pr_err("Failed to apply FDT fixup \"%s\"\n", + fixups->description); + return err; + } + } + + err = fdt_pack(fdt_out); + if (err) + pr_err("Failed to pack FDT\n"); + return err; +} + void __init plat_time_init(void) { struct device_node *np; diff --git a/arch/mips/include/asm/machine.h b/arch/mips/include/asm/machine.h index 6b444cd9526f..ecb6c7335484 100644 --- a/arch/mips/include/asm/machine.h +++ b/arch/mips/include/asm/machine.h @@ -60,4 +60,35 @@ mips_machine_is_compatible(const struct mips_machine *mach, const void *fdt) return NULL; } +/** + * struct mips_fdt_fixup - Describe a fixup to apply to an FDT + * @apply: applies the fixup to @fdt, returns zero on success else -errno + * @description: a short description of the fixup + * + * Describes a fixup applied to an FDT blob by the @apply function. The + * @description field provides a short description of the fixup intended for + * use in error messages if the @apply function returns non-zero. + */ +struct mips_fdt_fixup { + int (*apply)(void *fdt); + const char *description; +}; + +/** + * apply_mips_fdt_fixups() - apply fixups to an FDT blob + * @fdt_out: buffer in which to place the fixed-up FDT + * @fdt_out_size: the size of the @fdt_out buffer + * @fdt_in: the FDT blob + * @fixups: pointer to an array of fixups to be applied + * + * Loop through the array of fixups pointed to by @fixups, calling the apply + * function on each until either one returns an error or we reach the end of + * the list as indicated by an entry with a NULL apply field. + * + * Return: zero on success, else -errno + */ +extern int __init apply_mips_fdt_fixups(void *fdt_out, size_t fdt_out_size, + const void *fdt_in, + const struct mips_fdt_fixup *fixups); + #endif /* __MIPS_ASM_MACHINE_H__ */ -- cgit v1.2.3 From fbdc674ba33c3791b315a546019e570e3e94e599 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 2 Jun 2017 12:29:57 -0700 Subject: MIPS: SEAD-3: Set interrupt-parent per-device, not at root node The SEAD-3 board may be configured with or without a MIPS Global Interrupt Controller (GIC). Because of this we have a device tree with a default case of a GIC present, and code to fixup the device tree based upon a configuration register that indicates the presence of the GIC. In order to keep this DT fixup code simple, the interrupt-parent property was specified at the root node of the SEAD-3 DT, allowing the fixup code to simply change this property to the phandle of the CPU interrupt controller if a GIC is not present & affect all interrupt-using devices at once. This however causes a problem if we do have a GIC & the device tree is used as-is, because the interrupt-parent property of the root node applies to the CPU interrupt controller node. This causes a cycle when of_irq_init() attempts to probe interrupt controllers in order and boots fail due to a lack of configured interrupts, with this message printed on the kernel console: [ 0.000000] OF: of_irq_init: children remain, but no parents Fix this by removing the interrupt-parent property from the DT root node & instead setting it for each device which uses interrupts, ensuring that the CPU interrupt controller node has no interrupt-parent & allowing of_irq_init() to identify it as the root interrupt controller. Signed-off-by: Paul Burton Reported-by: Keng Koh Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/16187/ Signed-off-by: Ralf Baechle --- arch/mips/boot/dts/mti/sead3.dts | 5 ++++- arch/mips/generic/board-sead3.c | 26 ++++++++++++++++++++------ 2 files changed, 24 insertions(+), 7 deletions(-) (limited to 'arch/mips/generic') diff --git a/arch/mips/boot/dts/mti/sead3.dts b/arch/mips/boot/dts/mti/sead3.dts index f327791cbcb5..cabe256f9a68 100644 --- a/arch/mips/boot/dts/mti/sead3.dts +++ b/arch/mips/boot/dts/mti/sead3.dts @@ -11,7 +11,6 @@ #size-cells = <1>; compatible = "mti,sead-3"; model = "MIPS SEAD-3"; - interrupt-parent = <&gic>; chosen { stdout-path = "serial1:115200"; @@ -60,6 +59,7 @@ compatible = "generic-ehci"; reg = <0x1b200000 0x1000>; + interrupt-parent = <&gic>; interrupts = <0>; /* GIC 0 or CPU 6 */ has-transaction-translator; @@ -222,6 +222,7 @@ clock-frequency = <14745600>; + interrupt-parent = <&gic>; interrupts = <3>; /* GIC 3 or CPU 4 */ no-loopback-test; @@ -236,6 +237,7 @@ clock-frequency = <14745600>; + interrupt-parent = <&gic>; interrupts = <2>; /* GIC 2 or CPU 4 */ no-loopback-test; @@ -246,6 +248,7 @@ reg = <0x1f010000 0x10000>; reg-io-width = <4>; + interrupt-parent = <&gic>; interrupts = <0>; /* GIC 0 or CPU 6 */ phy-mode = "mii"; diff --git a/arch/mips/generic/board-sead3.c b/arch/mips/generic/board-sead3.c index 39e11bd249cf..f109a6b9fdd0 100644 --- a/arch/mips/generic/board-sead3.c +++ b/arch/mips/generic/board-sead3.c @@ -87,14 +87,16 @@ static __init int remove_gic(void *fdt) return -EINVAL; } - err = fdt_setprop_u32(fdt, 0, "interrupt-parent", cpu_phandle); - if (err) { - pr_err("unable to set root interrupt-parent: %d\n", err); - return err; - } - uart_off = fdt_node_offset_by_compatible(fdt, -1, "ns16550a"); while (uart_off >= 0) { + err = fdt_setprop_u32(fdt, uart_off, "interrupt-parent", + cpu_phandle); + if (err) { + pr_warn("unable to set UART interrupt-parent: %d\n", + err); + return err; + } + err = fdt_setprop_u32(fdt, uart_off, "interrupts", cpu_uart_int); if (err) { @@ -117,6 +119,12 @@ static __init int remove_gic(void *fdt) return eth_off; } + err = fdt_setprop_u32(fdt, eth_off, "interrupt-parent", cpu_phandle); + if (err) { + pr_err("unable to set ethernet interrupt-parent: %d\n", err); + return err; + } + err = fdt_setprop_u32(fdt, eth_off, "interrupts", cpu_eth_int); if (err) { pr_err("unable to set ethernet interrupts property: %d\n", err); @@ -129,6 +137,12 @@ static __init int remove_gic(void *fdt) return ehci_off; } + err = fdt_setprop_u32(fdt, ehci_off, "interrupt-parent", cpu_phandle); + if (err) { + pr_err("unable to set EHCI interrupt-parent: %d\n", err); + return err; + } + err = fdt_setprop_u32(fdt, ehci_off, "interrupts", cpu_ehci_int); if (err) { pr_err("unable to set EHCI interrupts property: %d\n", err); -- cgit v1.2.3 From 6e62a888029b4adbbc55894eaa8b929221113948 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Sat, 17 Jun 2017 13:52:49 -0700 Subject: MIPS: generic: Support MIPS Boston development boards Add support for the MIPS Boston development board to generic kernels, which essentially amounts to: - Adding the device tree source for the MIPS Boston board. - Adding a Kconfig fragment which enables the appropriate drivers for the MIPS Boston board. With these changes in place generic kernels will support the board by default, and kernels with only the drivers needed for Boston enabled can be configured by setting BOARDS=boston during configuration. For example: $ make ARCH=mips 64r6el_defconfig BOARDS=boston Signed-off-by: Paul Burton Reviewed-by: James Hogan Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/16485/ Signed-off-by: Ralf Baechle --- MAINTAINERS | 2 + arch/mips/boot/dts/img/Makefile | 2 + arch/mips/boot/dts/img/boston.dts | 224 ++++++++++++++++++++++++++ arch/mips/configs/generic/board-boston.config | 48 ++++++ arch/mips/generic/Kconfig | 12 ++ arch/mips/generic/vmlinux.its.S | 25 +++ 6 files changed, 313 insertions(+) create mode 100644 arch/mips/boot/dts/img/boston.dts create mode 100644 arch/mips/configs/generic/board-boston.config (limited to 'arch/mips/generic') diff --git a/MAINTAINERS b/MAINTAINERS index 5513b85dd60e..d034eb8031fa 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8509,6 +8509,8 @@ M: Paul Burton L: linux-mips@linux-mips.org S: Maintained F: Documentation/devicetree/bindings/clock/img,boston-clock.txt +F: arch/mips/boot/dts/img/boston.dts +F: arch/mips/configs/generic/board-boston.config F: drivers/clk/imgtec/clk-boston.c F: include/dt-bindings/clock/boston-clock.h diff --git a/arch/mips/boot/dts/img/Makefile b/arch/mips/boot/dts/img/Makefile index c178cf56f5b8..3d70958d0f5a 100644 --- a/arch/mips/boot/dts/img/Makefile +++ b/arch/mips/boot/dts/img/Makefile @@ -1,3 +1,5 @@ +dtb-$(CONFIG_FIT_IMAGE_FDT_BOSTON) += boston.dtb + dtb-$(CONFIG_MACH_PISTACHIO) += pistachio_marduk.dtb obj-$(CONFIG_MACH_PISTACHIO) += pistachio_marduk.dtb.o diff --git a/arch/mips/boot/dts/img/boston.dts b/arch/mips/boot/dts/img/boston.dts new file mode 100644 index 000000000000..53bfa29a7093 --- /dev/null +++ b/arch/mips/boot/dts/img/boston.dts @@ -0,0 +1,224 @@ +/dts-v1/; + +#include +#include +#include +#include + +/ { + #address-cells = <1>; + #size-cells = <1>; + compatible = "img,boston"; + + chosen { + stdout-path = "uart0:115200"; + }; + + aliases { + uart0 = &uart0; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "img,mips"; + reg = <0>; + clocks = <&clk_boston BOSTON_CLK_CPU>; + }; + }; + + memory@0 { + device_type = "memory"; + reg = <0x00000000 0x10000000>; + }; + + pci0: pci@10000000 { + compatible = "xlnx,axi-pcie-host-1.00.a"; + device_type = "pci"; + reg = <0x10000000 0x2000000>; + + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + + interrupt-parent = <&gic>; + interrupts = ; + + ranges = <0x02000000 0 0x40000000 + 0x40000000 0 0x40000000>; + + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &pci0_intc 1>, + <0 0 0 2 &pci0_intc 2>, + <0 0 0 3 &pci0_intc 3>, + <0 0 0 4 &pci0_intc 4>; + + pci0_intc: interrupt-controller { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; + }; + + pci1: pci@12000000 { + compatible = "xlnx,axi-pcie-host-1.00.a"; + device_type = "pci"; + reg = <0x12000000 0x2000000>; + + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + + interrupt-parent = <&gic>; + interrupts = ; + + ranges = <0x02000000 0 0x20000000 + 0x20000000 0 0x20000000>; + + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &pci1_intc 1>, + <0 0 0 2 &pci1_intc 2>, + <0 0 0 3 &pci1_intc 3>, + <0 0 0 4 &pci1_intc 4>; + + pci1_intc: interrupt-controller { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; + }; + + pci2: pci@14000000 { + compatible = "xlnx,axi-pcie-host-1.00.a"; + device_type = "pci"; + reg = <0x14000000 0x2000000>; + + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + + interrupt-parent = <&gic>; + interrupts = ; + + ranges = <0x02000000 0 0x16000000 + 0x16000000 0 0x100000>; + + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &pci2_intc 1>, + <0 0 0 2 &pci2_intc 2>, + <0 0 0 3 &pci2_intc 3>, + <0 0 0 4 &pci2_intc 4>; + + pci2_intc: interrupt-controller { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; + + pci2_root@0,0,0 { + compatible = "pci10ee,7021"; + reg = <0x00000000 0 0 0 0>; + + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + + eg20t_bridge@1,0,0 { + compatible = "pci8086,8800"; + reg = <0x00010000 0 0 0 0>; + + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + + eg20t_mac@2,0,1 { + compatible = "pci8086,8802"; + reg = <0x00020100 0 0 0 0>; + phy-reset-gpios = <&eg20t_gpio 6 + GPIO_ACTIVE_LOW>; + }; + + eg20t_gpio: eg20t_gpio@2,0,2 { + compatible = "pci8086,8803"; + reg = <0x00020200 0 0 0 0>; + + gpio-controller; + #gpio-cells = <2>; + }; + + eg20t_i2c@2,12,2 { + compatible = "pci8086,8817"; + reg = <0x00026200 0 0 0 0>; + + #address-cells = <1>; + #size-cells = <0>; + + rtc@0x68 { + compatible = "st,m41t81s"; + reg = <0x68>; + }; + }; + }; + }; + }; + + gic: interrupt-controller@16120000 { + compatible = "mti,gic"; + reg = <0x16120000 0x20000>; + + interrupt-controller; + #interrupt-cells = <3>; + + timer { + compatible = "mti,gic-timer"; + interrupts = ; + clocks = <&clk_boston BOSTON_CLK_CPU>; + }; + }; + + cdmm@16140000 { + compatible = "mti,mips-cdmm"; + reg = <0x16140000 0x8000>; + }; + + cpc@16200000 { + compatible = "mti,mips-cpc"; + reg = <0x16200000 0x8000>; + }; + + plat_regs: system-controller@17ffd000 { + compatible = "img,boston-platform-regs", "syscon"; + reg = <0x17ffd000 0x1000>; + + clk_boston: clock { + compatible = "img,boston-clock"; + #clock-cells = <1>; + }; + }; + + reboot: syscon-reboot { + compatible = "syscon-reboot"; + regmap = <&plat_regs>; + offset = <0x10>; + mask = <0x10>; + }; + + uart0: uart@17ffe000 { + compatible = "ns16550a"; + reg = <0x17ffe000 0x1000>; + reg-shift = <2>; + + interrupt-parent = <&gic>; + interrupts = ; + + clocks = <&clk_boston BOSTON_CLK_SYS>; + }; + + lcd: lcd@17fff000 { + compatible = "img,boston-lcd"; + reg = <0x17fff000 0x8>; + }; +}; diff --git a/arch/mips/configs/generic/board-boston.config b/arch/mips/configs/generic/board-boston.config new file mode 100644 index 000000000000..19560a45b683 --- /dev/null +++ b/arch/mips/configs/generic/board-boston.config @@ -0,0 +1,48 @@ +CONFIG_FIT_IMAGE_FDT_BOSTON=y + +CONFIG_ATA=y +CONFIG_SATA_AHCI=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y + +CONFIG_AUXDISPLAY=y +CONFIG_IMG_ASCII_LCD=y + +CONFIG_COMMON_CLK_BOSTON=y + +CONFIG_DMADEVICES=y +CONFIG_PCH_DMA=y + +CONFIG_GPIOLIB=y +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_PCH=y + +CONFIG_I2C=y +CONFIG_I2C_EG20T=y + +CONFIG_MMC=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PCI=y + +CONFIG_NETDEVICES=y +CONFIG_PCH_GBE=y + +CONFIG_PCI=y +CONFIG_PCI_MSI=y +CONFIG_PCIE_XILINX=y + +CONFIG_PCH_PHUB=y + +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_M41T80=y + +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_OF_PLATFORM=y + +CONFIG_SPI=y +CONFIG_SPI_TOPCLIFF_PCH=y + +CONFIG_USB=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_OHCI_HCD=y diff --git a/arch/mips/generic/Kconfig b/arch/mips/generic/Kconfig index 446b7c68133d..51ffbbaddee2 100644 --- a/arch/mips/generic/Kconfig +++ b/arch/mips/generic/Kconfig @@ -16,6 +16,8 @@ config YAMON_DT_SHIM and you wish to include code which helps translate various YAMON-provided environment variables into a device tree properties. +comment "Legacy (non-UHI/non-FIT) Boards" + config LEGACY_BOARD_SEAD3 bool "Support MIPS SEAD-3 boards" select LEGACY_BOARDS @@ -24,4 +26,14 @@ config LEGACY_BOARD_SEAD3 Enable this to include support for booting on MIPS SEAD-3 FPGA-based development boards, which boot using a legacy boot protocol. +comment "FIT/UHI Boards" + +config FIT_IMAGE_FDT_BOSTON + bool "Include FDT for MIPS Boston boards" + help + Enable this to include the FDT for the MIPS Boston development board + from Imagination Technologies in the FIT kernel image. You should + enable this if you wish to boot on a MIPS Boston board, as it is + expected by the bootloader. + endif diff --git a/arch/mips/generic/vmlinux.its.S b/arch/mips/generic/vmlinux.its.S index f67fbf1c8541..3390e2f80b80 100644 --- a/arch/mips/generic/vmlinux.its.S +++ b/arch/mips/generic/vmlinux.its.S @@ -29,3 +29,28 @@ }; }; }; + +#ifdef CONFIG_FIT_IMAGE_FDT_BOSTON +/ { + images { + fdt@boston { + description = "img,boston Device Tree"; + data = /incbin/("boot/dts/img/boston.dtb"); + type = "flat_dt"; + arch = "mips"; + compression = "none"; + hash@0 { + algo = "sha1"; + }; + }; + }; + + configurations { + conf@boston { + description = "Boston Linux kernel"; + kernel = "kernel@0"; + fdt = "fdt@boston"; + }; + }; +}; +#endif /* CONFIG_FIT_IMAGE_FDT_BOSTON */ -- cgit v1.2.3