1 /*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * PROM library functions for acquiring/using memory descriptors given to
7 * us from the YAMON.
8 *
9 * Copyright (C) 1999,2000,2012 MIPS Technologies, Inc.
10 * All rights reserved.
11 * Authors: Carsten Langgaard <carstenl@mips.com>
12 * Steven J. Hill <sjhill@mips.com>
13 */
14 #include <linux/init.h>
15 #include <linux/bootmem.h>
16 #include <linux/string.h>
17
18 #include <asm/bootinfo.h>
19 #include <asm/sections.h>
20 #include <asm/fw/fw.h>
21
22 static fw_memblock_t mdesc[FW_MAX_MEMBLOCKS];
23
24 #ifdef DEBUG
25 static char *mtypes[3] = {
26 "Dont use memory",
27 "YAMON PROM memory",
28 "Free memmory",
29 "Memory in use",
30 };
31 #endif
32
33 /* determined physical memory size, not overridden by command line args */
34 unsigned long physical_memsize = 0L;
35 static unsigned newMapType;
36
prom_getmdesc(void)37 static inline fw_memblock_t * __init prom_getmdesc(void)
38 {
39 char *memsize_str;
40 char *ememsize_str;
41 unsigned long memsize = 0;
42 unsigned long ememsize = 0;
43 char *ptr;
44 static char cmdline[COMMAND_LINE_SIZE] __initdata;
45
46 /* otherwise look in the environment */
47 memsize_str = fw_getenv("memsize");
48 #ifdef DEBUG
49 pr_debug("prom_memsize = %s\n", memsize_str);
50 #endif
51 if (memsize_str)
52 memsize = simple_strtol(memsize_str, NULL, 0);
53 ememsize_str = fw_getenv("ememsize");
54 #ifdef DEBUG
55 pr_debug("fw_ememsize = %s\n", ememsize_str);
56 #endif
57 if (ememsize_str)
58 ememsize = simple_strtol(ememsize_str, NULL, 0);
59
60 if ((!memsize) && !ememsize) {
61 printk(KERN_WARNING
62 "memsize not set in boot prom, set to default (32Mb)\n");
63 physical_memsize = 0x02000000;
64 } else {
65 physical_memsize = ememsize;
66 if (!physical_memsize)
67 physical_memsize = memsize;
68 }
69
70 #ifdef CONFIG_CPU_BIG_ENDIAN
71 /* SOC-it swaps, or perhaps doesn't swap, when DMA'ing the last
72 word of physical memory */
73 physical_memsize -= PAGE_SIZE;
74 #endif
75
76 memsize = 0;
77 /* Check the command line for a memsize directive that overrides
78 the physical/default amount */
79 strcpy(cmdline, arcs_cmdline);
80 ptr = strstr(cmdline, " memsize=");
81 if (ptr && (ptr != cmdline))
82 memsize = memparse(ptr + 9, &ptr);
83 ptr = strstr(cmdline, " ememsize=");
84 if (ptr && (ptr != cmdline))
85 memsize = memparse(ptr + 10, &ptr);
86 if (!memsize) {
87 ptr = strstr(cmdline, "memsize=");
88 if (ptr && (ptr != cmdline))
89 memsize = memparse(ptr + 8, &ptr);
90 ptr = strstr(cmdline, "ememsize=");
91 if (ptr && (ptr != cmdline))
92 memsize = memparse(ptr + 9, &ptr);
93 }
94 if (!memsize)
95 memsize = physical_memsize;
96
97 if ((memsize == 0x10000000) && !ememsize)
98 if ((!ptr) || (ptr == cmdline)) {
99 printk("YAMON reports memsize=256M but doesn't report ememsize option\n");
100 printk("If you install > 256MB memory, upgrade YAMON or use boot option memsize=XXXM\n");
101 }
102 newMapType = *((unsigned int *)CKSEG1ADDR(0xbf403004));
103 printk("System Controller register = %0x\n",newMapType);
104 newMapType &= 0x100; /* extract map type bit */
105 #ifdef CONFIG_EVA_OLD_MALTA_MAP
106 if (newMapType)
107 panic("Malta board has new memory map layout but kernel is configured for legacy map\n");
108 #endif
109 #if (!defined(CONFIG_PHYS_ADDR_T_64BIT)) && !defined(CONFIG_HIGHMEM)
110 /* Don't use last 64KB - it is just for macros arithmetics overflow */
111 /* It is assumed that HIGHMEM lowmem map follows this rule too */
112 if (((unsigned long long)PHYS_OFFSET + (unsigned long long)memsize) > 0xffff0000ULL)
113 memsize = 0xffff0000ULL - (unsigned long long)PHYS_OFFSET;
114 #endif
115
116 memset(mdesc, 0, sizeof(mdesc));
117
118 mdesc[0].type = fw_dontuse;
119 mdesc[0].base = PHYS_OFFSET;
120 mdesc[0].size = 0x00001000;
121
122 mdesc[1].type = fw_code;
123 mdesc[1].base = mdesc[0].base + 0x00001000UL;
124 mdesc[1].size = 0x000ef000;
125
126 /*
127 * The area 0x000f0000-0x000fffff is allocated for BIOS memory by the
128 * south bridge and PCI access always forwarded to the ISA Bus and
129 * BIOSCS# is always generated.
130 * This mean that this area can't be used as DMA memory for PCI
131 * devices.
132 */
133 mdesc[2].type = fw_dontuse;
134 mdesc[2].base = mdesc[0].base + 0x000f0000UL;
135 mdesc[2].size = 0x00010000;
136
137 mdesc[3].type = fw_inuse;
138 mdesc[3].base = mdesc[0].base + 0x00100000UL;
139 mdesc[3].size = CPHYSADDR(PFN_ALIGN((unsigned long)&_end)) - 0x00100000UL;
140
141 /* this code assumes that PAGE_OFFSET == 0 and PHYS_OFFSET == n*512MB */
142 if ((memsize > 0x20000000) && !PHYS_OFFSET) {
143 /* first 256MB */
144 mdesc[4].type = fw_free;
145 mdesc[4].base = mdesc[0].base + CPHYSADDR(PFN_ALIGN(&_end));
146 mdesc[4].size = mdesc[0].base + 0x10000000 - CPHYSADDR(mdesc[4].base);
147
148 /* I/O hole ... */
149
150 /* the rest of memory (256MB behind hole is lost) */
151 mdesc[5].type = fw_free;
152 mdesc[5].base = mdesc[0].base + 0x20000000;
153 mdesc[5].size = memsize - 0x20000000;
154 } else {
155 /* limit to 256MB, exclude I/O hole */
156 if (!PHYS_OFFSET)
157 memsize = (memsize > 0x10000000)? 0x10000000 : memsize;
158
159 mdesc[4].type = fw_free;
160 mdesc[4].base = mdesc[0].base + CPHYSADDR(PFN_ALIGN(&_end));
161 mdesc[4].size = memsize - CPHYSADDR(mdesc[4].base);
162 }
163
164 return &mdesc[0];
165 }
166
167 #ifdef CONFIG_EVA
168 #ifndef CONFIG_EVA_OLD_MALTA_MAP
prom_mem_check(int niocu)169 void __init prom_mem_check(int niocu)
170 {
171 if (!newMapType) {
172 if (niocu && mdesc[5].size) {
173 printk(KERN_WARNING "Malta board has legacy memory map + IOCU, but kernel is configured for new map layout, restrict memsize to 256MB\n");
174 boot_mem_map.nr_map--;
175 }
176 }
177 }
178 #endif /* !CONFIG_EVA_OLD_MALTA_MAP */
179 #endif /* CONFIG_EVA */
180
fw_memtype_classify(unsigned int type)181 static int __init fw_memtype_classify(unsigned int type)
182 {
183 switch (type) {
184 case fw_free:
185 return BOOT_MEM_RAM;
186 case fw_code:
187 return BOOT_MEM_ROM_DATA;
188 case fw_inuse:
189 return BOOT_MEM_INUSE;
190 default:
191 return BOOT_MEM_RESERVED;
192 }
193 }
194
fw_getmdesc(void)195 fw_memblock_t __init *fw_getmdesc(void)
196 {
197 fw_memblock_t *p;
198
199 p = prom_getmdesc();
200 return p;
201 }
202
fw_meminit(void)203 void __init fw_meminit(void)
204 {
205 fw_memblock_t *p;
206
207 #ifdef DEBUG
208 pr_debug("YAMON MEMORY DESCRIPTOR dump:\n");
209 p = fw_getmdesc();
210
211 while (p->size) {
212 int i = 0;
213 pr_debug("[%d,%p]: base<%08lx> size<%x> type<%s>\n",
214 i, p, p->base, p->size, mtypes[p->type]);
215 p++;
216 i++;
217 }
218 #endif
219 p = fw_getmdesc();
220
221 while (p->size) {
222 long type;
223 unsigned long base, size;
224
225 type = fw_memtype_classify(p->type);
226 base = p->base;
227 size = p->size;
228
229 add_memory_region(base, size, type);
230 p++;
231 }
232 }
233
prom_free_prom_memory(void)234 void __init prom_free_prom_memory(void)
235 {
236 unsigned long addr;
237 int i;
238
239 for (i = 0; i < boot_mem_map.nr_map; i++) {
240 if (boot_mem_map.map[i].type != BOOT_MEM_ROM_DATA)
241 continue;
242
243 addr = boot_mem_map.map[i].addr;
244 free_init_pages("YAMON memory",
245 addr, addr + boot_mem_map.map[i].size);
246 }
247 }
248