memory.c 9.5 KB
Newer Older
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
/*
 * Carsten Langgaard, carstenl@mips.com
 * Copyright (C) 1999,2000 MIPS Technologies, Inc.  All rights reserved.
 * Portions copyright (C) 2009 Cisco Systems, Inc.
 *
 *  This program is free software; you can distribute it and/or modify it
 *  under the terms of the GNU General Public License (Version 2) as
 *  published by the Free Software Foundation.
 *
 *  This program is distributed in the hope it will be useful, but WITHOUT
 *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 *  for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
 *
 * Apparently originally from arch/mips/malta-memory.c. Modified to work
 * with the PowerTV bootloader.
 */
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/bootmem.h>
#include <linux/pfn.h>
#include <linux/string.h>

#include <asm/bootinfo.h>
#include <asm/page.h>
#include <asm/sections.h>

#include <asm/mips-boards/prom.h>
33 34
#include <asm/mach-powertv/asic.h>
#include <asm/mach-powertv/ioremap.h>
35 36 37 38 39 40

#include "init.h"

/* Memory constants */
#define KIBIBYTE(n)		((n) * 1024)	/* Number of kibibytes */
#define MEBIBYTE(n)		((n) * KIBIBYTE(1024)) /* Number of mebibytes */
41
#define DEFAULT_MEMSIZE		MEBIBYTE(128)	/* If no memsize provided */
42

43 44
#define BLDR_SIZE	KIBIBYTE(256)		/* Memory reserved for bldr */
#define RV_SIZE		MEBIBYTE(4)		/* Size of reset vector */
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 153 154 155 156 157 158 159 160 161 162
#define LOW_MEM_END	0x20000000		/* Highest low memory address */
#define BLDR_ALIAS	0x10000000		/* Bootloader address */
#define RV_PHYS		0x1fc00000		/* Reset vector address */
#define LOW_RAM_END	RV_PHYS			/* End of real RAM in low mem */

/*
 * Very low-level conversion from processor physical address to device
 * DMA address for the first bank of memory.
 */
#define PHYS_TO_DMA(paddr)	((paddr) + (CONFIG_LOW_RAM_DMA - LOW_RAM_ALIAS))

unsigned long ptv_memsize;

/*
 * struct low_mem_reserved - Items in low memmory that are reserved
 * @start:	Physical address of item
 * @size:	Size, in bytes, of this item
 * @is_aliased:	True if this is RAM aliased from another location. If false,
 *		it is something other than aliased RAM and the RAM in the
 *		unaliased address is still visible outside of low memory.
 */
struct low_mem_reserved {
	phys_addr_t	start;
	phys_addr_t	size;
	bool		is_aliased;
};

/*
 * Must be in ascending address order
 */
struct low_mem_reserved low_mem_reserved[] = {
	{BLDR_ALIAS, BLDR_SIZE, true},	/* Bootloader RAM */
	{RV_PHYS, RV_SIZE, false},	/* Reset vector */
};

/*
 * struct mem_layout - layout of a piece of the system RAM
 * @phys:	Physical address of the start of this piece of RAM. This is the
 *		address at which both the processor and I/O devices see the
 *		RAM.
 * @alias:	Alias of this piece of memory in order to make it appear in
 *		the low memory part of the processor's address space. I/O
 *		devices don't see anything here.
 * @size:	Size, in bytes, of this piece of RAM
 */
struct mem_layout {
	phys_addr_t	phys;
	phys_addr_t	alias;
	phys_addr_t	size;
};

/*
 * struct mem_layout_list - list descriptor for layouts of system RAM pieces
 * @family:	Specifies the family being described
 * @n:		Number of &struct mem_layout elements
 * @layout:	Pointer to the list of &mem_layout structures
 */
struct mem_layout_list {
	enum family_type	family;
	size_t			n;
	struct mem_layout	*layout;
};

static struct mem_layout f1500_layout[] = {
	{0x20000000, 0x10000000, MEBIBYTE(256)},
};

static struct mem_layout f4500_layout[] = {
	{0x40000000, 0x10000000, MEBIBYTE(256)},
	{0x20000000, 0x20000000, MEBIBYTE(32)},
};

static struct mem_layout f8500_layout[] = {
	{0x40000000, 0x10000000, MEBIBYTE(256)},
	{0x20000000, 0x20000000, MEBIBYTE(32)},
	{0x30000000, 0x30000000, MEBIBYTE(32)},
};

static struct mem_layout fx600_layout[] = {
	{0x20000000, 0x10000000, MEBIBYTE(256)},
	{0x60000000, 0x60000000, MEBIBYTE(128)},
};

static struct mem_layout_list layout_list[] = {
	{FAMILY_1500, ARRAY_SIZE(f1500_layout), f1500_layout},
	{FAMILY_1500VZE, ARRAY_SIZE(f1500_layout), f1500_layout},
	{FAMILY_1500VZF, ARRAY_SIZE(f1500_layout), f1500_layout},
	{FAMILY_4500, ARRAY_SIZE(f4500_layout), f4500_layout},
	{FAMILY_8500, ARRAY_SIZE(f8500_layout), f8500_layout},
	{FAMILY_8500RNG, ARRAY_SIZE(f8500_layout), f8500_layout},
	{FAMILY_4600, ARRAY_SIZE(fx600_layout), fx600_layout},
	{FAMILY_4600VZA, ARRAY_SIZE(fx600_layout), fx600_layout},
	{FAMILY_8600, ARRAY_SIZE(fx600_layout), fx600_layout},
	{FAMILY_8600VZB, ARRAY_SIZE(fx600_layout), fx600_layout},
};

/* If we can't determine the layout, use this */
static struct mem_layout default_layout[] = {
	{0x20000000, 0x10000000, MEBIBYTE(128)},
};

/**
 * register_non_ram - register low memory not available for RAM usage
 */
static __init void register_non_ram(void)
{
	int i;

	for (i = 0; i < ARRAY_SIZE(low_mem_reserved); i++)
		add_memory_region(low_mem_reserved[i].start,
			low_mem_reserved[i].size, BOOT_MEM_RESERVED);
}

/**
 * get_memsize - get the size of memory as a single bank
 */
static phys_addr_t get_memsize(void)
163
{
164 165
	static char cmdline[COMMAND_LINE_SIZE] __initdata;
	phys_addr_t memsize = 0;
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
	char *memsize_str;
	char *ptr;

	/* Check the command line first for a memsize directive */
	strcpy(cmdline, arcs_cmdline);
	ptr = strstr(cmdline, "memsize=");
	if (ptr && (ptr != cmdline) && (*(ptr - 1) != ' '))
		ptr = strstr(ptr, " memsize=");

	if (ptr) {
		memsize = memparse(ptr + 8, &ptr);
	} else {
		/* otherwise look in the environment */
		memsize_str = prom_getenv("memsize");

		if (memsize_str != NULL) {
			pr_info("prom memsize = %s\n", memsize_str);
			memsize = simple_strtol(memsize_str, NULL, 0);
		}

		if (memsize == 0) {
			if (_prom_memsize != 0) {
				memsize = _prom_memsize;
189
				pr_info("_prom_memsize = 0x%x\n", memsize);
190 191
				/* add in memory that the bootloader doesn't
				 * report */
192
				memsize += BLDR_SIZE;
193 194 195
			} else {
				memsize = DEFAULT_MEMSIZE;
				pr_info("Memsize not passed by bootloader, "
196
					"defaulting to 0x%x\n", memsize);
197 198 199 200
			}
		}
	}

201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
	return memsize;
}

/**
 * register_low_ram - register an aliased section of RAM
 * @p:		Alias address of memory
 * @n:		Number of bytes in this section of memory
 *
 * Returns the number of bytes registered
 *
 */
static __init phys_addr_t register_low_ram(phys_addr_t p, phys_addr_t n)
{
	phys_addr_t s;
	int i;
	phys_addr_t orig_n;

	orig_n = n;

	BUG_ON(p + n > RV_PHYS);

	for (i = 0; n != 0 && i < ARRAY_SIZE(low_mem_reserved); i++) {
		phys_addr_t start;
		phys_addr_t size;

		start = low_mem_reserved[i].start;
		size = low_mem_reserved[i].size;

		/* Handle memory before this low memory section */
		if (p < start) {
			phys_addr_t s;
			s = min(n, start - p);
			add_memory_region(p, s, BOOT_MEM_RAM);
			p += s;
			n -= s;
		}

		/* Handle the low memory section itself. If it's aliased,
		 * we reduce the number of byes left, but if not, the RAM
		 * is available elsewhere and we don't reduce the number of
		 * bytes remaining. */
		if (p == start) {
			if (low_mem_reserved[i].is_aliased) {
				s = min(n, size);
				n -= s;
				p += s;
			} else
				p += n;
		}
250 251
	}

252 253 254
	return orig_n - n;
}

255
/*
256 257 258 259 260
 * register_ram - register real RAM
 * @p:	Address of memory as seen by devices
 * @alias:	If the memory is seen at an additional address by the processor,
 *		this will be the address, otherwise it is the same as @p.
 * @n:		Number of bytes in this section of memory
261
 */
262 263 264
static __init void register_ram(phys_addr_t p, phys_addr_t alias,
	phys_addr_t n)
{
265
	/*
266 267
	 * If some or all of this memory has an alias, break it into the
	 * aliased and non-aliased portion.
268
	 */
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
	if (p != alias) {
		phys_addr_t alias_size;
		phys_addr_t registered;

		alias_size = min(n, LOW_RAM_END - alias);
		registered = register_low_ram(alias, alias_size);
		ioremap_add_map(alias, p, n);
		n -= registered;
		p += registered;
	}

#ifdef CONFIG_HIGHMEM
	if (n != 0) {
		add_memory_region(p, n, BOOT_MEM_RAM);
		ioremap_add_map(p, p, n);
	}
#endif
}

/**
 * register_address_space - register things in the address space
 * @memsize:	Number of bytes of RAM installed
 *
 * Takes the given number of bytes of RAM and registers as many of the regions,
 * or partial regions, as it can. So, the default configuration might have
 * two regions with 256 MiB each. If the memsize passed in on the command line
 * is 384 MiB, it will register the first region with 256 MiB and the second
 * with 128 MiB.
 */
static __init void register_address_space(phys_addr_t memsize)
{
	int i;
	phys_addr_t size;
	size_t n;
	struct mem_layout *layout;
	enum family_type family;

306
	/*
307 308
	 * Register all of the things that aren't available to the kernel as
	 * memory.
309
	 */
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338
	register_non_ram();

	/* Find the appropriate memory description */
	family = platform_get_family();

	for (i = 0; i < ARRAY_SIZE(layout_list); i++) {
		if (layout_list[i].family == family)
			break;
	}

	if (i == ARRAY_SIZE(layout_list)) {
		n = ARRAY_SIZE(default_layout);
		layout = default_layout;
	} else {
		n = layout_list[i].n;
		layout = layout_list[i].layout;
	}

	for (i = 0; memsize != 0 && i < n; i++) {
		size = min(memsize, layout[i].size);
		register_ram(layout[i].phys, layout[i].alias, size);
		memsize -= size;
	}
}

void __init prom_meminit(void)
{
	ptv_memsize = get_memsize();
	register_address_space(ptv_memsize);
339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354
}

void __init prom_free_prom_memory(void)
{
	unsigned long addr;
	int i;

	for (i = 0; i < boot_mem_map.nr_map; i++) {
		if (boot_mem_map.map[i].type != BOOT_MEM_ROM_DATA)
			continue;

		addr = boot_mem_map.map[i].addr;
		free_init_pages("prom memory",
				addr, addr + boot_mem_map.map[i].size);
	}
}