162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Big Endian PROM code for SNI RM machines
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
562306a36Sopenharmony_ci * License.  See the file "COPYING" in the main directory of this archive
662306a36Sopenharmony_ci * for more details.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Copyright (C) 2005-2006 Florian Lohoff (flo@rfc822.org)
962306a36Sopenharmony_ci * Copyright (C) 2005-2006 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/kernel.h>
1362306a36Sopenharmony_ci#include <linux/init.h>
1462306a36Sopenharmony_ci#include <linux/memblock.h>
1562306a36Sopenharmony_ci#include <linux/string.h>
1662306a36Sopenharmony_ci#include <linux/console.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include <asm/addrspace.h>
1962306a36Sopenharmony_ci#include <asm/sni.h>
2062306a36Sopenharmony_ci#include <asm/mipsprom.h>
2162306a36Sopenharmony_ci#include <asm/mipsregs.h>
2262306a36Sopenharmony_ci#include <asm/bootinfo.h>
2362306a36Sopenharmony_ci#include <asm/setup.h>
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci/* special SNI prom calls */
2662306a36Sopenharmony_ci/*
2762306a36Sopenharmony_ci * This does not exist in all proms - SINIX compares
2862306a36Sopenharmony_ci * the prom env variable "version" against "2.0008"
2962306a36Sopenharmony_ci * or greater. If lesser it tries to probe interesting
3062306a36Sopenharmony_ci * registers
3162306a36Sopenharmony_ci */
3262306a36Sopenharmony_ci#define PROM_GET_MEMCONF	58
3362306a36Sopenharmony_ci#define PROM_GET_HWCONF		61
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#define PROM_VEC		(u64 *)CKSEG1ADDR(0x1fc00000)
3662306a36Sopenharmony_ci#define PROM_ENTRY(x)		(PROM_VEC + (x))
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#define ___prom_putchar		((int *(*)(int))PROM_ENTRY(PROM_PUTCHAR))
3962306a36Sopenharmony_ci#define ___prom_getenv		((char *(*)(char *))PROM_ENTRY(PROM_GETENV))
4062306a36Sopenharmony_ci#define ___prom_get_memconf	((void (*)(void *))PROM_ENTRY(PROM_GET_MEMCONF))
4162306a36Sopenharmony_ci#define ___prom_get_hwconf	((u32 (*)(void))PROM_ENTRY(PROM_GET_HWCONF))
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci#ifdef CONFIG_64BIT
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci/* O32 stack has to be 8-byte aligned. */
4662306a36Sopenharmony_cistatic u64 o32_stk[4096];
4762306a36Sopenharmony_ci#define O32_STK	  (&o32_stk[ARRAY_SIZE(o32_stk)])
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci#define __PROM_O32(fun, arg) fun arg __asm__(#fun); \
5062306a36Sopenharmony_ci				     __asm__(#fun " = call_o32")
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ciint   __PROM_O32(__prom_putchar, (int *(*)(int), void *, int));
5362306a36Sopenharmony_cichar *__PROM_O32(__prom_getenv, (char *(*)(char *), void *, char *));
5462306a36Sopenharmony_civoid  __PROM_O32(__prom_get_memconf, (void (*)(void *), void *, void *));
5562306a36Sopenharmony_ciu32   __PROM_O32(__prom_get_hwconf, (u32 (*)(void), void *));
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci#define _prom_putchar(x)     __prom_putchar(___prom_putchar, O32_STK, x)
5862306a36Sopenharmony_ci#define _prom_getenv(x)	     __prom_getenv(___prom_getenv, O32_STK, x)
5962306a36Sopenharmony_ci#define _prom_get_memconf(x) __prom_get_memconf(___prom_get_memconf, O32_STK, x)
6062306a36Sopenharmony_ci#define _prom_get_hwconf()   __prom_get_hwconf(___prom_get_hwconf, O32_STK)
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci#else
6362306a36Sopenharmony_ci#define _prom_putchar(x)     ___prom_putchar(x)
6462306a36Sopenharmony_ci#define _prom_getenv(x)	     ___prom_getenv(x)
6562306a36Sopenharmony_ci#define _prom_get_memconf(x) ___prom_get_memconf(x)
6662306a36Sopenharmony_ci#define _prom_get_hwconf(x)  ___prom_get_hwconf(x)
6762306a36Sopenharmony_ci#endif
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_civoid prom_putchar(char c)
7062306a36Sopenharmony_ci{
7162306a36Sopenharmony_ci	_prom_putchar(c);
7262306a36Sopenharmony_ci}
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cichar *prom_getenv(char *s)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	return _prom_getenv(s);
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_civoid *prom_get_hwconf(void)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	u32 hwconf = _prom_get_hwconf();
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	if (hwconf == 0xffffffff)
8562306a36Sopenharmony_ci		return NULL;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	return (void *)CKSEG1ADDR(hwconf);
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci/*
9162306a36Sopenharmony_ci * /proc/cpuinfo system type
9262306a36Sopenharmony_ci *
9362306a36Sopenharmony_ci */
9462306a36Sopenharmony_cichar *system_type = "Unknown";
9562306a36Sopenharmony_ciconst char *get_system_type(void)
9662306a36Sopenharmony_ci{
9762306a36Sopenharmony_ci	return system_type;
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistatic void __init sni_mem_init(void)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	int i, memsize;
10362306a36Sopenharmony_ci	struct membank {
10462306a36Sopenharmony_ci		u32		size;
10562306a36Sopenharmony_ci		u32		base;
10662306a36Sopenharmony_ci		u32		size2;
10762306a36Sopenharmony_ci		u32		pad1;
10862306a36Sopenharmony_ci		u32		pad2;
10962306a36Sopenharmony_ci	} memconf[8];
11062306a36Sopenharmony_ci	int brd_type = *(unsigned char *)SNI_IDPROM_BRDTYPE;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	/* MemSIZE from prom in 16MByte chunks */
11462306a36Sopenharmony_ci	memsize = *((unsigned char *) SNI_IDPROM_MEMSIZE) * 16;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	pr_debug("IDProm memsize: %u MByte\n", memsize);
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	/* get memory bank layout from prom */
11962306a36Sopenharmony_ci	_prom_get_memconf(&memconf);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	pr_debug("prom_get_mem_conf memory configuration:\n");
12262306a36Sopenharmony_ci	for (i = 0; i < 8 && memconf[i].size; i++) {
12362306a36Sopenharmony_ci		if (brd_type == SNI_BRD_PCI_TOWER ||
12462306a36Sopenharmony_ci		    brd_type == SNI_BRD_PCI_TOWER_CPLUS) {
12562306a36Sopenharmony_ci			if (memconf[i].base >= 0x20000000 &&
12662306a36Sopenharmony_ci			    memconf[i].base <  0x30000000)
12762306a36Sopenharmony_ci				memconf[i].base -= 0x20000000;
12862306a36Sopenharmony_ci		}
12962306a36Sopenharmony_ci		pr_debug("Bank%d: %08x @ %08x\n", i,
13062306a36Sopenharmony_ci			memconf[i].size, memconf[i].base);
13162306a36Sopenharmony_ci		memblock_add(memconf[i].base, memconf[i].size);
13262306a36Sopenharmony_ci	}
13362306a36Sopenharmony_ci}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_civoid __init prom_init(void)
13662306a36Sopenharmony_ci{
13762306a36Sopenharmony_ci	int argc = fw_arg0;
13862306a36Sopenharmony_ci	u32 *argv = (u32 *)CKSEG0ADDR(fw_arg1);
13962306a36Sopenharmony_ci	int i;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	sni_mem_init();
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	/* copy prom cmdline parameters to kernel cmdline */
14462306a36Sopenharmony_ci	for (i = 1; i < argc; i++) {
14562306a36Sopenharmony_ci		strcat(arcs_cmdline, (char *)CKSEG0ADDR(argv[i]));
14662306a36Sopenharmony_ci		if (i < (argc - 1))
14762306a36Sopenharmony_ci			strcat(arcs_cmdline, " ");
14862306a36Sopenharmony_ci	}
14962306a36Sopenharmony_ci}
150