18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Big Endian PROM code for SNI RM machines 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 58c2ecf20Sopenharmony_ci * License. See the file "COPYING" in the main directory of this archive 68c2ecf20Sopenharmony_ci * for more details. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Copyright (C) 2005-2006 Florian Lohoff (flo@rfc822.org) 98c2ecf20Sopenharmony_ci * Copyright (C) 2005-2006 Thomas Bogendoerfer (tsbogend@alpha.franken.de) 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/kernel.h> 138c2ecf20Sopenharmony_ci#include <linux/init.h> 148c2ecf20Sopenharmony_ci#include <linux/memblock.h> 158c2ecf20Sopenharmony_ci#include <linux/string.h> 168c2ecf20Sopenharmony_ci#include <linux/console.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <asm/addrspace.h> 198c2ecf20Sopenharmony_ci#include <asm/sni.h> 208c2ecf20Sopenharmony_ci#include <asm/mipsprom.h> 218c2ecf20Sopenharmony_ci#include <asm/mipsregs.h> 228c2ecf20Sopenharmony_ci#include <asm/bootinfo.h> 238c2ecf20Sopenharmony_ci#include <asm/setup.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/* special SNI prom calls */ 268c2ecf20Sopenharmony_ci/* 278c2ecf20Sopenharmony_ci * This does not exist in all proms - SINIX compares 288c2ecf20Sopenharmony_ci * the prom env variable "version" against "2.0008" 298c2ecf20Sopenharmony_ci * or greater. If lesser it tries to probe interesting 308c2ecf20Sopenharmony_ci * registers 318c2ecf20Sopenharmony_ci */ 328c2ecf20Sopenharmony_ci#define PROM_GET_MEMCONF 58 338c2ecf20Sopenharmony_ci#define PROM_GET_HWCONF 61 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#define PROM_VEC (u64 *)CKSEG1ADDR(0x1fc00000) 368c2ecf20Sopenharmony_ci#define PROM_ENTRY(x) (PROM_VEC + (x)) 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#define ___prom_putchar ((int *(*)(int))PROM_ENTRY(PROM_PUTCHAR)) 398c2ecf20Sopenharmony_ci#define ___prom_getenv ((char *(*)(char *))PROM_ENTRY(PROM_GETENV)) 408c2ecf20Sopenharmony_ci#define ___prom_get_memconf ((void (*)(void *))PROM_ENTRY(PROM_GET_MEMCONF)) 418c2ecf20Sopenharmony_ci#define ___prom_get_hwconf ((u32 (*)(void))PROM_ENTRY(PROM_GET_HWCONF)) 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#ifdef CONFIG_64BIT 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci/* O32 stack has to be 8-byte aligned. */ 468c2ecf20Sopenharmony_cistatic u64 o32_stk[4096]; 478c2ecf20Sopenharmony_ci#define O32_STK (&o32_stk[ARRAY_SIZE(o32_stk)]) 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#define __PROM_O32(fun, arg) fun arg __asm__(#fun); \ 508c2ecf20Sopenharmony_ci __asm__(#fun " = call_o32") 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ciint __PROM_O32(__prom_putchar, (int *(*)(int), void *, int)); 538c2ecf20Sopenharmony_cichar *__PROM_O32(__prom_getenv, (char *(*)(char *), void *, char *)); 548c2ecf20Sopenharmony_civoid __PROM_O32(__prom_get_memconf, (void (*)(void *), void *, void *)); 558c2ecf20Sopenharmony_ciu32 __PROM_O32(__prom_get_hwconf, (u32 (*)(void), void *)); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci#define _prom_putchar(x) __prom_putchar(___prom_putchar, O32_STK, x) 588c2ecf20Sopenharmony_ci#define _prom_getenv(x) __prom_getenv(___prom_getenv, O32_STK, x) 598c2ecf20Sopenharmony_ci#define _prom_get_memconf(x) __prom_get_memconf(___prom_get_memconf, O32_STK, x) 608c2ecf20Sopenharmony_ci#define _prom_get_hwconf() __prom_get_hwconf(___prom_get_hwconf, O32_STK) 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci#else 638c2ecf20Sopenharmony_ci#define _prom_putchar(x) ___prom_putchar(x) 648c2ecf20Sopenharmony_ci#define _prom_getenv(x) ___prom_getenv(x) 658c2ecf20Sopenharmony_ci#define _prom_get_memconf(x) ___prom_get_memconf(x) 668c2ecf20Sopenharmony_ci#define _prom_get_hwconf(x) ___prom_get_hwconf(x) 678c2ecf20Sopenharmony_ci#endif 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_civoid prom_putchar(char c) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci _prom_putchar(c); 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cichar *prom_getenv(char *s) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci return _prom_getenv(s); 788c2ecf20Sopenharmony_ci} 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_civoid *prom_get_hwconf(void) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci u32 hwconf = _prom_get_hwconf(); 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci if (hwconf == 0xffffffff) 858c2ecf20Sopenharmony_ci return NULL; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci return (void *)CKSEG1ADDR(hwconf); 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_civoid __init prom_free_prom_memory(void) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci/* 958c2ecf20Sopenharmony_ci * /proc/cpuinfo system type 968c2ecf20Sopenharmony_ci * 978c2ecf20Sopenharmony_ci */ 988c2ecf20Sopenharmony_cichar *system_type = "Unknown"; 998c2ecf20Sopenharmony_ciconst char *get_system_type(void) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci return system_type; 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic void __init sni_mem_init(void) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci int i, memsize; 1078c2ecf20Sopenharmony_ci struct membank { 1088c2ecf20Sopenharmony_ci u32 size; 1098c2ecf20Sopenharmony_ci u32 base; 1108c2ecf20Sopenharmony_ci u32 size2; 1118c2ecf20Sopenharmony_ci u32 pad1; 1128c2ecf20Sopenharmony_ci u32 pad2; 1138c2ecf20Sopenharmony_ci } memconf[8]; 1148c2ecf20Sopenharmony_ci int brd_type = *(unsigned char *)SNI_IDPROM_BRDTYPE; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci /* MemSIZE from prom in 16MByte chunks */ 1188c2ecf20Sopenharmony_ci memsize = *((unsigned char *) SNI_IDPROM_MEMSIZE) * 16; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci pr_debug("IDProm memsize: %u MByte\n", memsize); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci /* get memory bank layout from prom */ 1238c2ecf20Sopenharmony_ci _prom_get_memconf(&memconf); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci pr_debug("prom_get_mem_conf memory configuration:\n"); 1268c2ecf20Sopenharmony_ci for (i = 0; i < 8 && memconf[i].size; i++) { 1278c2ecf20Sopenharmony_ci if (brd_type == SNI_BRD_PCI_TOWER || 1288c2ecf20Sopenharmony_ci brd_type == SNI_BRD_PCI_TOWER_CPLUS) { 1298c2ecf20Sopenharmony_ci if (memconf[i].base >= 0x20000000 && 1308c2ecf20Sopenharmony_ci memconf[i].base < 0x30000000) 1318c2ecf20Sopenharmony_ci memconf[i].base -= 0x20000000; 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci pr_debug("Bank%d: %08x @ %08x\n", i, 1348c2ecf20Sopenharmony_ci memconf[i].size, memconf[i].base); 1358c2ecf20Sopenharmony_ci memblock_add(memconf[i].base, memconf[i].size); 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_civoid __init prom_init(void) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci int argc = fw_arg0; 1428c2ecf20Sopenharmony_ci u32 *argv = (u32 *)CKSEG0ADDR(fw_arg1); 1438c2ecf20Sopenharmony_ci int i; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci sni_mem_init(); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci /* copy prom cmdline parameters to kernel cmdline */ 1488c2ecf20Sopenharmony_ci for (i = 1; i < argc; i++) { 1498c2ecf20Sopenharmony_ci strcat(arcs_cmdline, (char *)CKSEG0ADDR(argv[i])); 1508c2ecf20Sopenharmony_ci if (i < (argc - 1)) 1518c2ecf20Sopenharmony_ci strcat(arcs_cmdline, " "); 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci} 154