• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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