Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 571b7e69 authored by Paul Burton's avatar Paul Burton Committed by Ralf Baechle
Browse files

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: default avatarPaul Burton <paul.burton@imgtec.com>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/16181/


Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
parent efe4a1ac
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -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.
+1 −0
Original line number Diff line number Diff line
@@ -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
+4 −174
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#include <asm/fw/fw.h>
#include <asm/io.h>
#include <asm/machine.h>
#include <asm/yamon-dt.h>

#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);

+190 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 Imagination Technologies
 * Author: Paul Burton <paul.burton@imgtec.com>
 *
 * 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 <linux/bug.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/libfdt.h>
#include <linux/printk.h>

#include <asm/fw/fw.h>

__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;
}
+48 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 Imagination Technologies
 * Author: Paul Burton <paul.burton@imgtec.com>
 *
 * 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.
 */

#ifndef __MIPS_ASM_YAMON_DT_H__
#define __MIPS_ASM_YAMON_DT_H__

/**
 * yamon_dt_append_cmdline() - Append YAMON-provided command line to /chosen
 * @fdt: the FDT blob
 *
 * Write the YAMON-provided command line to the bootargs property of the
 * /chosen node in @fdt.
 *
 * Return: 0 on success, else -errno
 */
extern __init int yamon_dt_append_cmdline(void *fdt);

/**
 * yamon_dt_append_memory() - Append YAMON-provided memory info to /memory
 * @fdt: the FDT blob
 *
 * Generate a /memory node in @fdt based upon memory size information provided
 * by YAMON in its environment.
 *
 * Return: 0 on success, else -errno
 */
extern __init int yamon_dt_append_memory(void *fdt);

/**
 * yamon_dt_serial_config() - Append YAMON-provided serial config to /chosen
 * @fdt: the FDT blob
 *
 * Generate a stdout-path property in the /chosen node of @fdt, based upon
 * information provided in the YAMON environment about the UART configuration
 * of the system.
 *
 * Return: 0 on success, else -errno
 */
extern __init int yamon_dt_serial_config(void *fdt);

#endif /* __MIPS_ASM_YAMON_DT_H__ */