13f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski/*
23f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski * Device tree based initialization code for reserved memory.
33f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski *
43f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski * Copyright (c) 2013, The Linux Foundation. All Rights Reserved.
53f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski * Copyright (c) 2013,2014 Samsung Electronics Co., Ltd.
63f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski *		http://www.samsung.com
73f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski * Author: Marek Szyprowski <m.szyprowski@samsung.com>
83f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski * Author: Josh Cartwright <joshc@codeaurora.org>
93f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski *
103f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski * This program is free software; you can redistribute it and/or
113f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski * modify it under the terms of the GNU General Public License as
123f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski * published by the Free Software Foundation; either version 2 of the
133f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski * License or (at your optional) any later version of the license.
143f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski */
153f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski
163f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski#include <linux/err.h>
173f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski#include <linux/of.h>
183f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski#include <linux/of_fdt.h>
193f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski#include <linux/of_platform.h>
203f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski#include <linux/mm.h>
213f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski#include <linux/sizes.h>
223f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski#include <linux/of_reserved_mem.h>
233f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski
243f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski#define MAX_RESERVED_REGIONS	16
253f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowskistatic struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS];
263f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowskistatic int reserved_mem_count;
273f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski
283f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski#if defined(CONFIG_HAVE_MEMBLOCK)
293f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski#include <linux/memblock.h>
303f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowskiint __init __weak early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
313f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	phys_addr_t align, phys_addr_t start, phys_addr_t end, bool nomap,
323f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	phys_addr_t *res_base)
333f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski{
343f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	/*
353f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	 * We use __memblock_alloc_base() because memblock_alloc_base()
363f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	 * panic()s on allocation failure.
373f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	 */
383f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	phys_addr_t base = __memblock_alloc_base(size, align, end);
393f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	if (!base)
403f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski		return -ENOMEM;
413f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski
423f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	/*
433f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	 * Check if the allocated region fits in to start..end window
443f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	 */
453f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	if (base < start) {
463f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski		memblock_free(base, size);
473f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski		return -ENOMEM;
483f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	}
493f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski
503f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	*res_base = base;
513f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	if (nomap)
523f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski		return memblock_remove(base, size);
533f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	return 0;
543f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski}
553f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski#else
563f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowskiint __init __weak early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
573f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	phys_addr_t align, phys_addr_t start, phys_addr_t end, bool nomap,
583f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	phys_addr_t *res_base)
593f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski{
603f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	pr_err("Reserved memory not supported, ignoring region 0x%llx%s\n",
613f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski		  size, nomap ? " (nomap)" : "");
623f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	return -ENOSYS;
633f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski}
643f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski#endif
653f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski
663f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski/**
673f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski * res_mem_save_node() - save fdt node for second pass initialization
683f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski */
693f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowskivoid __init fdt_reserved_mem_save_node(unsigned long node, const char *uname,
703f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski				      phys_addr_t base, phys_addr_t size)
713f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski{
723f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	struct reserved_mem *rmem = &reserved_mem[reserved_mem_count];
733f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski
743f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	if (reserved_mem_count == ARRAY_SIZE(reserved_mem)) {
753f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski		pr_err("Reserved memory: not enough space all defined regions.\n");
763f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski		return;
773f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	}
783f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski
793f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	rmem->fdt_node = node;
803f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	rmem->name = uname;
813f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	rmem->base = base;
823f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	rmem->size = size;
833f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski
843f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	reserved_mem_count++;
853f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	return;
863f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski}
873f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski
883f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski/**
893f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski * res_mem_alloc_size() - allocate reserved memory described by 'size', 'align'
903f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski *			  and 'alloc-ranges' properties
913f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski */
923f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowskistatic int __init __reserved_mem_alloc_size(unsigned long node,
933f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	const char *uname, phys_addr_t *res_base, phys_addr_t *res_size)
943f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski{
953f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	int t_len = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32);
963f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	phys_addr_t start = 0, end = 0;
973f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	phys_addr_t base = 0, align = 0, size;
989d0c4dfedd96ee54fc075b16d02f82499c8cc3a6Rob Herring	int len;
999d0c4dfedd96ee54fc075b16d02f82499c8cc3a6Rob Herring	const __be32 *prop;
1003f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	int nomap;
1013f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	int ret;
1023f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski
1033f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	prop = of_get_flat_dt_prop(node, "size", &len);
1043f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	if (!prop)
1053f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski		return -EINVAL;
1063f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski
1073f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	if (len != dt_root_size_cells * sizeof(__be32)) {
1083f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski		pr_err("Reserved memory: invalid size property in '%s' node.\n",
1093f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski				uname);
1103f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski		return -EINVAL;
1113f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	}
1123f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	size = dt_mem_next_cell(dt_root_size_cells, &prop);
1133f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski
1143f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	nomap = of_get_flat_dt_prop(node, "no-map", NULL) != NULL;
1153f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski
1163f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	prop = of_get_flat_dt_prop(node, "alignment", &len);
1173f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	if (prop) {
1183f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski		if (len != dt_root_addr_cells * sizeof(__be32)) {
1193f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski			pr_err("Reserved memory: invalid alignment property in '%s' node.\n",
1203f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski				uname);
1213f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski			return -EINVAL;
1223f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski		}
1233f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski		align = dt_mem_next_cell(dt_root_addr_cells, &prop);
1243f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	}
1253f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski
1263f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	prop = of_get_flat_dt_prop(node, "alloc-ranges", &len);
1273f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	if (prop) {
1283f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski
1293f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski		if (len % t_len != 0) {
1303f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski			pr_err("Reserved memory: invalid alloc-ranges property in '%s', skipping node.\n",
1313f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski			       uname);
1323f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski			return -EINVAL;
1333f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski		}
1343f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski
1353f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski		base = 0;
1363f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski
1373f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski		while (len > 0) {
1383f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski			start = dt_mem_next_cell(dt_root_addr_cells, &prop);
1393f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski			end = start + dt_mem_next_cell(dt_root_size_cells,
1403f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski						       &prop);
1413f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski
1423f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski			ret = early_init_dt_alloc_reserved_memory_arch(size,
1433f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski					align, start, end, nomap, &base);
1443f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski			if (ret == 0) {
1453f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski				pr_debug("Reserved memory: allocated memory for '%s' node: base %pa, size %ld MiB\n",
1463f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski					uname, &base,
1473f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski					(unsigned long)size / SZ_1M);
1483f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski				break;
1493f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski			}
1503f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski			len -= t_len;
1513f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski		}
1523f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski
1533f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	} else {
1543f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski		ret = early_init_dt_alloc_reserved_memory_arch(size, align,
1553f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski							0, 0, nomap, &base);
1563f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski		if (ret == 0)
1573f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski			pr_debug("Reserved memory: allocated memory for '%s' node: base %pa, size %ld MiB\n",
1583f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski				uname, &base, (unsigned long)size / SZ_1M);
1593f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	}
1603f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski
1613f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	if (base == 0) {
1623f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski		pr_info("Reserved memory: failed to allocate memory for node '%s'\n",
1633f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski			uname);
1643f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski		return -ENOMEM;
1653f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	}
1663f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski
1673f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	*res_base = base;
1683f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	*res_size = size;
1693f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski
1703f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	return 0;
1713f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski}
1723f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski
173f618c4703a14672d27bc2ca5d132a844363d6f5fMarek Szyprowskistatic const struct of_device_id __rmem_of_table_sentinel
174f618c4703a14672d27bc2ca5d132a844363d6f5fMarek Szyprowski	__used __section(__reservedmem_of_table_end);
175f618c4703a14672d27bc2ca5d132a844363d6f5fMarek Szyprowski
176f618c4703a14672d27bc2ca5d132a844363d6f5fMarek Szyprowski/**
177f618c4703a14672d27bc2ca5d132a844363d6f5fMarek Szyprowski * res_mem_init_node() - call region specific reserved memory init code
178f618c4703a14672d27bc2ca5d132a844363d6f5fMarek Szyprowski */
179f618c4703a14672d27bc2ca5d132a844363d6f5fMarek Szyprowskistatic int __init __reserved_mem_init_node(struct reserved_mem *rmem)
180f618c4703a14672d27bc2ca5d132a844363d6f5fMarek Szyprowski{
181f618c4703a14672d27bc2ca5d132a844363d6f5fMarek Szyprowski	extern const struct of_device_id __reservedmem_of_table[];
182f618c4703a14672d27bc2ca5d132a844363d6f5fMarek Szyprowski	const struct of_device_id *i;
183f618c4703a14672d27bc2ca5d132a844363d6f5fMarek Szyprowski
184f618c4703a14672d27bc2ca5d132a844363d6f5fMarek Szyprowski	for (i = __reservedmem_of_table; i < &__rmem_of_table_sentinel; i++) {
185f618c4703a14672d27bc2ca5d132a844363d6f5fMarek Szyprowski		reservedmem_of_init_fn initfn = i->data;
186f618c4703a14672d27bc2ca5d132a844363d6f5fMarek Szyprowski		const char *compat = i->compatible;
187f618c4703a14672d27bc2ca5d132a844363d6f5fMarek Szyprowski
188f618c4703a14672d27bc2ca5d132a844363d6f5fMarek Szyprowski		if (!of_flat_dt_is_compatible(rmem->fdt_node, compat))
189f618c4703a14672d27bc2ca5d132a844363d6f5fMarek Szyprowski			continue;
190f618c4703a14672d27bc2ca5d132a844363d6f5fMarek Szyprowski
1919dd3107576c4bbd40e1c2c8b24d560abf9a7b991Rob Herring		if (initfn(rmem) == 0) {
192f618c4703a14672d27bc2ca5d132a844363d6f5fMarek Szyprowski			pr_info("Reserved memory: initialized node %s, compatible id %s\n",
193f618c4703a14672d27bc2ca5d132a844363d6f5fMarek Szyprowski				rmem->name, compat);
194f618c4703a14672d27bc2ca5d132a844363d6f5fMarek Szyprowski			return 0;
195f618c4703a14672d27bc2ca5d132a844363d6f5fMarek Szyprowski		}
196f618c4703a14672d27bc2ca5d132a844363d6f5fMarek Szyprowski	}
197f618c4703a14672d27bc2ca5d132a844363d6f5fMarek Szyprowski	return -ENOENT;
198f618c4703a14672d27bc2ca5d132a844363d6f5fMarek Szyprowski}
199f618c4703a14672d27bc2ca5d132a844363d6f5fMarek Szyprowski
2003f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski/**
2013f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski * fdt_init_reserved_mem - allocate and init all saved reserved memory regions
2023f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski */
2033f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowskivoid __init fdt_init_reserved_mem(void)
2043f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski{
2053f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	int i;
2063f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	for (i = 0; i < reserved_mem_count; i++) {
2073f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski		struct reserved_mem *rmem = &reserved_mem[i];
2083f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski		unsigned long node = rmem->fdt_node;
2099dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski		int len;
2109dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski		const __be32 *prop;
2113f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski		int err = 0;
2123f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski
2139dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski		prop = of_get_flat_dt_prop(node, "phandle", &len);
2149dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski		if (!prop)
2159dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski			prop = of_get_flat_dt_prop(node, "linux,phandle", &len);
2169dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski		if (prop)
2179dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski			rmem->phandle = of_read_number(prop, len/4);
2189dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski
2193f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski		if (rmem->size == 0)
2203f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski			err = __reserved_mem_alloc_size(node, rmem->name,
2213f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski						 &rmem->base, &rmem->size);
222f618c4703a14672d27bc2ca5d132a844363d6f5fMarek Szyprowski		if (err == 0)
223f618c4703a14672d27bc2ca5d132a844363d6f5fMarek Szyprowski			__reserved_mem_init_node(rmem);
2243f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski	}
2253f0c8206644836e4f10a6b9fc47cda6a9a372f9bMarek Szyprowski}
2269dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski
2279dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowskistatic inline struct reserved_mem *__find_rmem(struct device_node *node)
2289dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski{
2299dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski	unsigned int i;
2309dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski
2319dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski	if (!node->phandle)
2329dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski		return NULL;
2339dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski
2349dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski	for (i = 0; i < reserved_mem_count; i++)
2359dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski		if (reserved_mem[i].phandle == node->phandle)
2369dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski			return &reserved_mem[i];
2379dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski	return NULL;
2389dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski}
2399dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski
2409dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski/**
2419dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski * of_reserved_mem_device_init() - assign reserved memory region to given device
2429dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski *
2439dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski * This function assign memory region pointed by "memory-region" device tree
2449dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski * property to the given device.
2459dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski */
24647f29df7db78ee4fcdb104cf36918d987ddd0278Marek Szyprowskiint of_reserved_mem_device_init(struct device *dev)
2479dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski{
2489dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski	struct reserved_mem *rmem;
2499dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski	struct device_node *np;
25047f29df7db78ee4fcdb104cf36918d987ddd0278Marek Szyprowski	int ret;
2519dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski
2529dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski	np = of_parse_phandle(dev->of_node, "memory-region", 0);
2539dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski	if (!np)
25447f29df7db78ee4fcdb104cf36918d987ddd0278Marek Szyprowski		return -ENODEV;
2559dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski
2569dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski	rmem = __find_rmem(np);
2579dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski	of_node_put(np);
2589dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski
2599dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski	if (!rmem || !rmem->ops || !rmem->ops->device_init)
26047f29df7db78ee4fcdb104cf36918d987ddd0278Marek Szyprowski		return -EINVAL;
26147f29df7db78ee4fcdb104cf36918d987ddd0278Marek Szyprowski
26247f29df7db78ee4fcdb104cf36918d987ddd0278Marek Szyprowski	ret = rmem->ops->device_init(rmem, dev);
26347f29df7db78ee4fcdb104cf36918d987ddd0278Marek Szyprowski	if (ret == 0)
26447f29df7db78ee4fcdb104cf36918d987ddd0278Marek Szyprowski		dev_info(dev, "assigned reserved memory node %s\n", rmem->name);
2659dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski
26647f29df7db78ee4fcdb104cf36918d987ddd0278Marek Szyprowski	return ret;
2679dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski}
2689dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski
2699dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski/**
2709dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski * of_reserved_mem_device_release() - release reserved memory device structures
2719dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski *
2729dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski * This function releases structures allocated for memory region handling for
2739dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski * the given device.
2749dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski */
2759dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowskivoid of_reserved_mem_device_release(struct device *dev)
2769dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski{
2779dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski	struct reserved_mem *rmem;
2789dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski	struct device_node *np;
2799dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski
2809dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski	np = of_parse_phandle(dev->of_node, "memory-region", 0);
2819dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski	if (!np)
2829dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski		return;
2839dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski
2849dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski	rmem = __find_rmem(np);
2859dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski	of_node_put(np);
2869dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski
2879dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski	if (!rmem || !rmem->ops || !rmem->ops->device_release)
2889dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski		return;
2899dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski
2909dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski	rmem->ops->device_release(rmem, dev);
2919dcfee01930e6cc1e84d28c232664f0c19a1f86cMarek Szyprowski}
292