aboutsummaryrefslogtreecommitdiff
path: root/drivers/misc/mediatek/kernel/mtk_meminfo.c
blob: 917af97ec321b1c4164b7517da0ed87f22c7a379 (plain) (blame)
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
#include <asm/page.h>
#include <asm/setup.h>
#include <linux/module.h>
#include <linux/of_fdt.h>
#include <mach/mtk_memcfg.h>

#ifdef CONFIG_OF
/* return the actual physical DRAM size */
static u64 kernel_mem_sz;
static u64 phone_dram_sz;	/* original phone DRAM size */
static int dt_scan_memory(unsigned long node, const char *uname, int depth, void *data)
{
	char *type = of_get_flat_dt_prop(node, "device_type", NULL);
	int i;
	__be32 *reg, *endp;
	unsigned long l;
	dram_info_t *dram_info;

	/* We are scanning "memory" nodes only */
	if (type == NULL) {
		/*
		 * The longtrail doesn't have a device_type on the
		 * /memory node, so look for the node called /memory@0.
		 */
		if (depth != 1 || strcmp(uname, "memory@0") != 0)
			return 0;
	} else if (strcmp(type, "memory") != 0) {
		return 0;
	}

	/*
	 * Use kernel_mem_sz if phone_dram_sz is not available (workaround)
	 * Projects use device tree should have orig_dram_info entry in their
	 * device tree.
	 * After the porting is done, kernel_mem_sz will be removed.
	 */
	reg = of_get_flat_dt_prop(node, "reg", &l);
	if (reg == NULL)
		return 0;

	endp = reg + (l / sizeof(__be32));
	while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {
		u64 base, size;

		base = dt_mem_next_cell(dt_root_addr_cells, &reg);
		size = dt_mem_next_cell(dt_root_size_cells, &reg);

		if (size == 0)
			continue;

		kernel_mem_sz += size;
	}

	/* orig_dram_info */
	dram_info = (dram_info_t *)of_get_flat_dt_prop(node,
			"orig_dram_info", NULL);
	if (dram_info) {
		for (i = 0; i < dram_info->rank_num; i++)
			phone_dram_sz += dram_info->rank_info[i].size;
	}

	return node;
}

static int __init init_get_max_DRAM_size(void)
{
	if (!phone_dram_sz && !kernel_mem_sz) {
		if (of_scan_flat_dt(dt_scan_memory, NULL)) {
			pr_alert("init_get_max_DRAM_size done. phone_dram_sz: 0x%llx, kernel_mem_sz: 0x%llx\n",
				 (unsigned long long)phone_dram_sz,
				 (unsigned long long)kernel_mem_sz);
		} else {
			pr_err("init_get_max_DRAM_size fail\n");
			BUG();
		}
	}
	return 0;
}

phys_addr_t get_max_DRAM_size(void)
{
	if (!phone_dram_sz && !kernel_mem_sz)
		init_get_max_DRAM_size();
	return phone_dram_sz ? (phys_addr_t)phone_dram_sz : (phys_addr_t)kernel_mem_sz;
}
early_initcall(init_get_max_DRAM_size);
#else
extern phys_addr_t mtk_get_max_DRAM_size(void);
phys_addr_t get_max_DRAM_size(void)
{
	return mtk_get_max_DRAM_size();
}
#endif /* end of CONFIG_OF */
EXPORT_SYMBOL(get_max_DRAM_size);

/*
 * Return the DRAM size used by Linux kernel.
 * In current stage, use phone DRAM size directly
 */
phys_addr_t get_memory_size(void)
{
	return get_max_DRAM_size();
}
EXPORT_SYMBOL(get_memory_size);

phys_addr_t get_phys_offset(void)
{
	return PHYS_OFFSET;
}
EXPORT_SYMBOL(get_phys_offset);