sniprom.c
3.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
/*
* Big Endian PROM code for SNI RM machines
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 2005-2006 Florian Lohoff (flo@rfc822.org)
* Copyright (C) 2005-2006 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/console.h>
#include <asm/addrspace.h>
#include <asm/sni.h>
#include <asm/mipsprom.h>
#include <asm/mipsregs.h>
#include <asm/bootinfo.h>
/* special SNI prom calls */
/*
* This does not exist in all proms - SINIX compares
* the prom env variable "version" against "2.0008"
* or greater. If lesser it tries to probe interesting
* registers
*/
#define PROM_GET_MEMCONF 58
#define PROM_GET_HWCONF 61
#define PROM_VEC (u64 *)CKSEG1ADDR(0x1fc00000)
#define PROM_ENTRY(x) (PROM_VEC + (x))
#define ___prom_putchar ((int *(*)(int))PROM_ENTRY(PROM_PUTCHAR))
#define ___prom_getenv ((char *(*)(char *))PROM_ENTRY(PROM_GETENV))
#define ___prom_get_memconf ((void (*)(void *))PROM_ENTRY(PROM_GET_MEMCONF))
#define ___prom_get_hwconf ((u32 (*)(void))PROM_ENTRY(PROM_GET_HWCONF))
#ifdef CONFIG_64BIT
/* O32 stack has to be 8-byte aligned. */
static u64 o32_stk[4096];
#define O32_STK &o32_stk[sizeof(o32_stk)]
#define __PROM_O32(fun, arg) fun arg __asm__(#fun); \
__asm__(#fun " = call_o32")
int __PROM_O32(__prom_putchar, (int *(*)(int), void *, int));
char *__PROM_O32(__prom_getenv, (char *(*)(char *), void *, char *));
void __PROM_O32(__prom_get_memconf, (void (*)(void *), void *, void *));
u32 __PROM_O32(__prom_get_hwconf, (u32 (*)(void), void *));
#define _prom_putchar(x) __prom_putchar(___prom_putchar, O32_STK, x)
#define _prom_getenv(x) __prom_getenv(___prom_getenv, O32_STK, x)
#define _prom_get_memconf(x) __prom_get_memconf(___prom_get_memconf, O32_STK, x)
#define _prom_get_hwconf() __prom_get_hwconf(___prom_get_hwconf, O32_STK)
#else
#define _prom_putchar(x) ___prom_putchar(x)
#define _prom_getenv(x) ___prom_getenv(x)
#define _prom_get_memconf(x) ___prom_get_memconf(x)
#define _prom_get_hwconf(x) ___prom_get_hwconf(x)
#endif
void prom_putchar(char c)
{
_prom_putchar(c);
}
char *prom_getenv(char *s)
{
return _prom_getenv(s);
}
void *prom_get_hwconf(void)
{
u32 hwconf = _prom_get_hwconf();
if (hwconf == 0xffffffff)
return NULL;
return (void *)CKSEG1ADDR(hwconf);
}
void __init prom_free_prom_memory(void)
{
}
/*
* /proc/cpuinfo system type
*
*/
char *system_type = "Unknown";
const char *get_system_type(void)
{
return system_type;
}
static void __init sni_mem_init(void)
{
int i, memsize;
struct membank {
u32 size;
u32 base;
u32 size2;
u32 pad1;
u32 pad2;
} memconf[8];
int brd_type = *(unsigned char *)SNI_IDPROM_BRDTYPE;
/* MemSIZE from prom in 16MByte chunks */
memsize = *((unsigned char *) SNI_IDPROM_MEMSIZE) * 16;
pr_debug("IDProm memsize: %u MByte\n", memsize);
/* get memory bank layout from prom */
_prom_get_memconf(&memconf);
pr_debug("prom_get_mem_conf memory configuration:\n");
for (i = 0; i < 8 && memconf[i].size; i++) {
if (brd_type == SNI_BRD_PCI_TOWER ||
brd_type == SNI_BRD_PCI_TOWER_CPLUS) {
if (memconf[i].base >= 0x20000000 &&
memconf[i].base < 0x30000000)
memconf[i].base -= 0x20000000;
}
pr_debug("Bank%d: %08x @ %08x\n", i,
memconf[i].size, memconf[i].base);
add_memory_region(memconf[i].base, memconf[i].size,
BOOT_MEM_RAM);
}
}
void __init prom_init(void)
{
int argc = fw_arg0;
u32 *argv = (u32 *)CKSEG0ADDR(fw_arg1);
int i;
sni_mem_init();
/* copy prom cmdline parameters to kernel cmdline */
for (i = 1; i < argc; i++) {
strcat(arcs_cmdline, (char *)CKSEG0ADDR(argv[i]));
if (i < (argc - 1))
strcat(arcs_cmdline, " ");
}
}