18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci *
38c2ecf20Sopenharmony_ci * BRIEF MODULE DESCRIPTION
48c2ecf20Sopenharmony_ci *    PROM library initialisation code, supports YAMON and U-Boot.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright 2000-2001, 2006, 2008 MontaVista Software Inc.
78c2ecf20Sopenharmony_ci * Author: MontaVista Software, Inc. <source@mvista.com>
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * This file was derived from Carsten Langgaard's
108c2ecf20Sopenharmony_ci * arch/mips/mips-boards/xx files.
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci * Carsten Langgaard, carstenl@mips.com
138c2ecf20Sopenharmony_ci * Copyright (C) 1999,2000 MIPS Technologies, Inc.  All rights reserved.
148c2ecf20Sopenharmony_ci *
158c2ecf20Sopenharmony_ci *  This program is free software; you can redistribute  it and/or modify it
168c2ecf20Sopenharmony_ci *  under  the terms of  the GNU General  Public License as published by the
178c2ecf20Sopenharmony_ci *  Free Software Foundation;  either version 2 of the  License, or (at your
188c2ecf20Sopenharmony_ci *  option) any later version.
198c2ecf20Sopenharmony_ci *
208c2ecf20Sopenharmony_ci *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
218c2ecf20Sopenharmony_ci *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
228c2ecf20Sopenharmony_ci *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
238c2ecf20Sopenharmony_ci *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
248c2ecf20Sopenharmony_ci *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
258c2ecf20Sopenharmony_ci *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
268c2ecf20Sopenharmony_ci *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
278c2ecf20Sopenharmony_ci *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
288c2ecf20Sopenharmony_ci *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
298c2ecf20Sopenharmony_ci *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
308c2ecf20Sopenharmony_ci *
318c2ecf20Sopenharmony_ci *  You should have received a copy of the  GNU General Public License along
328c2ecf20Sopenharmony_ci *  with this program; if not, write  to the Free Software Foundation, Inc.,
338c2ecf20Sopenharmony_ci *  675 Mass Ave, Cambridge, MA 02139, USA.
348c2ecf20Sopenharmony_ci */
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci#include <linux/init.h>
378c2ecf20Sopenharmony_ci#include <linux/kernel.h>
388c2ecf20Sopenharmony_ci#include <linux/memblock.h>
398c2ecf20Sopenharmony_ci#include <linux/sizes.h>
408c2ecf20Sopenharmony_ci#include <linux/string.h>
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci#include <asm/bootinfo.h>
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ciint prom_argc;
458c2ecf20Sopenharmony_cichar **prom_argv;
468c2ecf20Sopenharmony_cichar **prom_envp;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_civoid __init prom_init_cmdline(void)
498c2ecf20Sopenharmony_ci{
508c2ecf20Sopenharmony_ci	int i;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	for (i = 1; i < prom_argc; i++) {
538c2ecf20Sopenharmony_ci		strlcat(arcs_cmdline, prom_argv[i], COMMAND_LINE_SIZE);
548c2ecf20Sopenharmony_ci		if (i < (prom_argc - 1))
558c2ecf20Sopenharmony_ci			strlcat(arcs_cmdline, " ", COMMAND_LINE_SIZE);
568c2ecf20Sopenharmony_ci	}
578c2ecf20Sopenharmony_ci}
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cichar *prom_getenv(char *envname)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	/*
628c2ecf20Sopenharmony_ci	 * Return a pointer to the given environment variable.
638c2ecf20Sopenharmony_ci	 * YAMON uses "name", "value" pairs, while U-Boot uses "name=value".
648c2ecf20Sopenharmony_ci	 */
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	char **env = prom_envp;
678c2ecf20Sopenharmony_ci	int i = strlen(envname);
688c2ecf20Sopenharmony_ci	int yamon = (*env && strchr(*env, '=') == NULL);
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	while (*env) {
718c2ecf20Sopenharmony_ci		if (yamon) {
728c2ecf20Sopenharmony_ci			if (strcmp(envname, *env++) == 0)
738c2ecf20Sopenharmony_ci				return *env;
748c2ecf20Sopenharmony_ci		} else if (strncmp(envname, *env, i) == 0 && (*env)[i] == '=')
758c2ecf20Sopenharmony_ci			return *env + i + 1;
768c2ecf20Sopenharmony_ci		env++;
778c2ecf20Sopenharmony_ci	}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	return NULL;
808c2ecf20Sopenharmony_ci}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_civoid __init prom_init(void)
838c2ecf20Sopenharmony_ci{
848c2ecf20Sopenharmony_ci	unsigned char *memsize_str;
858c2ecf20Sopenharmony_ci	unsigned long memsize;
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	prom_argc = (int)fw_arg0;
888c2ecf20Sopenharmony_ci	prom_argv = (char **)fw_arg1;
898c2ecf20Sopenharmony_ci	prom_envp = (char **)fw_arg2;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	prom_init_cmdline();
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	memsize_str = prom_getenv("memsize");
948c2ecf20Sopenharmony_ci	if (!memsize_str || kstrtoul(memsize_str, 0, &memsize))
958c2ecf20Sopenharmony_ci		memsize = SZ_64M; /* minimum memsize is 64MB RAM */
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	memblock_add(0, memsize);
988c2ecf20Sopenharmony_ci}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_cistatic inline unsigned char str2hexnum(unsigned char c)
1018c2ecf20Sopenharmony_ci{
1028c2ecf20Sopenharmony_ci	if (c >= '0' && c <= '9')
1038c2ecf20Sopenharmony_ci		return c - '0';
1048c2ecf20Sopenharmony_ci	if (c >= 'a' && c <= 'f')
1058c2ecf20Sopenharmony_ci		return c - 'a' + 10;
1068c2ecf20Sopenharmony_ci	if (c >= 'A' && c <= 'F')
1078c2ecf20Sopenharmony_ci		return c - 'A' + 10;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	return 0; /* foo */
1108c2ecf20Sopenharmony_ci}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_cistatic inline void str2eaddr(unsigned char *ea, unsigned char *str)
1138c2ecf20Sopenharmony_ci{
1148c2ecf20Sopenharmony_ci	int i;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	for (i = 0; i < 6; i++) {
1178c2ecf20Sopenharmony_ci		unsigned char num;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci		if ((*str == '.') || (*str == ':'))
1208c2ecf20Sopenharmony_ci			str++;
1218c2ecf20Sopenharmony_ci		num  = str2hexnum(*str++) << 4;
1228c2ecf20Sopenharmony_ci		num |= str2hexnum(*str++);
1238c2ecf20Sopenharmony_ci		ea[i] = num;
1248c2ecf20Sopenharmony_ci	}
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ciint __init prom_get_ethernet_addr(char *ethernet_addr)
1288c2ecf20Sopenharmony_ci{
1298c2ecf20Sopenharmony_ci	char *ethaddr_str;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	/* Check the environment variables first */
1328c2ecf20Sopenharmony_ci	ethaddr_str = prom_getenv("ethaddr");
1338c2ecf20Sopenharmony_ci	if (!ethaddr_str) {
1348c2ecf20Sopenharmony_ci		/* Check command line */
1358c2ecf20Sopenharmony_ci		ethaddr_str = strstr(arcs_cmdline, "ethaddr=");
1368c2ecf20Sopenharmony_ci		if (!ethaddr_str)
1378c2ecf20Sopenharmony_ci			return -1;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci		ethaddr_str += strlen("ethaddr=");
1408c2ecf20Sopenharmony_ci	}
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	str2eaddr(ethernet_addr, ethaddr_str);
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	return 0;
1458c2ecf20Sopenharmony_ci}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_civoid __init prom_free_prom_memory(void)
1488c2ecf20Sopenharmony_ci{
1498c2ecf20Sopenharmony_ci}
150