162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci *
362306a36Sopenharmony_ci * BRIEF MODULE DESCRIPTION
462306a36Sopenharmony_ci *    PROM library initialisation code, supports YAMON and U-Boot.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright 2000-2001, 2006, 2008 MontaVista Software Inc.
762306a36Sopenharmony_ci * Author: MontaVista Software, Inc. <source@mvista.com>
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * This file was derived from Carsten Langgaard's
1062306a36Sopenharmony_ci * arch/mips/mips-boards/xx files.
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci * Carsten Langgaard, carstenl@mips.com
1362306a36Sopenharmony_ci * Copyright (C) 1999,2000 MIPS Technologies, Inc.  All rights reserved.
1462306a36Sopenharmony_ci *
1562306a36Sopenharmony_ci *  This program is free software; you can redistribute  it and/or modify it
1662306a36Sopenharmony_ci *  under  the terms of  the GNU General  Public License as published by the
1762306a36Sopenharmony_ci *  Free Software Foundation;  either version 2 of the  License, or (at your
1862306a36Sopenharmony_ci *  option) any later version.
1962306a36Sopenharmony_ci *
2062306a36Sopenharmony_ci *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
2162306a36Sopenharmony_ci *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
2262306a36Sopenharmony_ci *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
2362306a36Sopenharmony_ci *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
2462306a36Sopenharmony_ci *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2562306a36Sopenharmony_ci *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
2662306a36Sopenharmony_ci *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
2762306a36Sopenharmony_ci *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
2862306a36Sopenharmony_ci *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2962306a36Sopenharmony_ci *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3062306a36Sopenharmony_ci *
3162306a36Sopenharmony_ci *  You should have received a copy of the  GNU General Public License along
3262306a36Sopenharmony_ci *  with this program; if not, write  to the Free Software Foundation, Inc.,
3362306a36Sopenharmony_ci *  675 Mass Ave, Cambridge, MA 02139, USA.
3462306a36Sopenharmony_ci */
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#include <linux/init.h>
3762306a36Sopenharmony_ci#include <linux/kernel.h>
3862306a36Sopenharmony_ci#include <linux/memblock.h>
3962306a36Sopenharmony_ci#include <linux/sizes.h>
4062306a36Sopenharmony_ci#include <linux/string.h>
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci#include <asm/bootinfo.h>
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ciint prom_argc;
4562306a36Sopenharmony_cichar **prom_argv;
4662306a36Sopenharmony_cichar **prom_envp;
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_civoid __init prom_init_cmdline(void)
4962306a36Sopenharmony_ci{
5062306a36Sopenharmony_ci	int i;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	for (i = 1; i < prom_argc; i++) {
5362306a36Sopenharmony_ci		strlcat(arcs_cmdline, prom_argv[i], COMMAND_LINE_SIZE);
5462306a36Sopenharmony_ci		if (i < (prom_argc - 1))
5562306a36Sopenharmony_ci			strlcat(arcs_cmdline, " ", COMMAND_LINE_SIZE);
5662306a36Sopenharmony_ci	}
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cichar *prom_getenv(char *envname)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	/*
6262306a36Sopenharmony_ci	 * Return a pointer to the given environment variable.
6362306a36Sopenharmony_ci	 * YAMON uses "name", "value" pairs, while U-Boot uses "name=value".
6462306a36Sopenharmony_ci	 */
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	char **env = prom_envp;
6762306a36Sopenharmony_ci	int i = strlen(envname);
6862306a36Sopenharmony_ci	int yamon = (*env && strchr(*env, '=') == NULL);
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	while (*env) {
7162306a36Sopenharmony_ci		if (yamon) {
7262306a36Sopenharmony_ci			if (strcmp(envname, *env++) == 0)
7362306a36Sopenharmony_ci				return *env;
7462306a36Sopenharmony_ci		} else if (strncmp(envname, *env, i) == 0 && (*env)[i] == '=')
7562306a36Sopenharmony_ci			return *env + i + 1;
7662306a36Sopenharmony_ci		env++;
7762306a36Sopenharmony_ci	}
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	return NULL;
8062306a36Sopenharmony_ci}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_civoid __init prom_init(void)
8362306a36Sopenharmony_ci{
8462306a36Sopenharmony_ci	unsigned char *memsize_str;
8562306a36Sopenharmony_ci	unsigned long memsize;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	prom_argc = (int)fw_arg0;
8862306a36Sopenharmony_ci	prom_argv = (char **)fw_arg1;
8962306a36Sopenharmony_ci	prom_envp = (char **)fw_arg2;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	prom_init_cmdline();
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	memsize_str = prom_getenv("memsize");
9462306a36Sopenharmony_ci	if (!memsize_str || kstrtoul(memsize_str, 0, &memsize))
9562306a36Sopenharmony_ci		memsize = SZ_64M; /* minimum memsize is 64MB RAM */
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	memblock_add(0, memsize);
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistatic inline unsigned char str2hexnum(unsigned char c)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	if (c >= '0' && c <= '9')
10362306a36Sopenharmony_ci		return c - '0';
10462306a36Sopenharmony_ci	if (c >= 'a' && c <= 'f')
10562306a36Sopenharmony_ci		return c - 'a' + 10;
10662306a36Sopenharmony_ci	if (c >= 'A' && c <= 'F')
10762306a36Sopenharmony_ci		return c - 'A' + 10;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	return 0; /* foo */
11062306a36Sopenharmony_ci}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_cistatic inline void str2eaddr(unsigned char *ea, unsigned char *str)
11362306a36Sopenharmony_ci{
11462306a36Sopenharmony_ci	int i;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	for (i = 0; i < 6; i++) {
11762306a36Sopenharmony_ci		unsigned char num;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci		if ((*str == '.') || (*str == ':'))
12062306a36Sopenharmony_ci			str++;
12162306a36Sopenharmony_ci		num  = str2hexnum(*str++) << 4;
12262306a36Sopenharmony_ci		num |= str2hexnum(*str++);
12362306a36Sopenharmony_ci		ea[i] = num;
12462306a36Sopenharmony_ci	}
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ciint __init prom_get_ethernet_addr(char *ethernet_addr)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	char *ethaddr_str;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	/* Check the environment variables first */
13262306a36Sopenharmony_ci	ethaddr_str = prom_getenv("ethaddr");
13362306a36Sopenharmony_ci	if (!ethaddr_str) {
13462306a36Sopenharmony_ci		/* Check command line */
13562306a36Sopenharmony_ci		ethaddr_str = strstr(arcs_cmdline, "ethaddr=");
13662306a36Sopenharmony_ci		if (!ethaddr_str)
13762306a36Sopenharmony_ci			return -1;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci		ethaddr_str += strlen("ethaddr=");
14062306a36Sopenharmony_ci	}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	str2eaddr(ethernet_addr, ethaddr_str);
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	return 0;
14562306a36Sopenharmony_ci}
146