1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2004
4  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5  */
6 
7 #include <config.h>
8 #include <init.h>
9 #include <asm/global_data.h>
10 #include <cpu_func.h>
11 #include <stdint.h>
12 
13 DECLARE_GLOBAL_DATA_PTR;
14 
15 #ifdef CONFIG_SYS_CACHELINE_SIZE
16 # define MEMSIZE_CACHELINE_SIZE CONFIG_SYS_CACHELINE_SIZE
17 #else
18 /* Just use the greatest cache flush alignment requirement I'm aware of */
19 # define MEMSIZE_CACHELINE_SIZE 128
20 #endif
21 
22 #ifdef __PPC__
23 /*
24  * At least on G2 PowerPC cores, sequential accesses to non-existent
25  * memory must be synchronized.
26  */
27 # include <asm/io.h>	/* for sync() */
28 #else
29 # define sync()		/* nothing */
30 #endif
31 
dcache_flush_invalidate(volatile long * p)32 static void dcache_flush_invalidate(volatile long *p)
33 {
34 	uintptr_t start, stop;
35 	start = ALIGN_DOWN((uintptr_t)p, MEMSIZE_CACHELINE_SIZE);
36 	stop = start + MEMSIZE_CACHELINE_SIZE;
37 	flush_dcache_range(start, stop);
38 	invalidate_dcache_range(start, stop);
39 }
40 
41 /*
42  * Check memory range for valid RAM. A simple memory test determines
43  * the actually available RAM size between addresses `base' and
44  * `base + maxsize'.
45  */
get_ram_size(long * base,long maxsize)46 long get_ram_size(long *base, long maxsize)
47 {
48 	volatile long *addr;
49 	long           save[BITS_PER_LONG - 1];
50 	long           save_base;
51 	long           cnt;
52 	long           val;
53 	long           size;
54 	int            i = 0;
55 	int            dcache_en = dcache_status();
56 
57 	for (cnt = (maxsize / sizeof(long)) >> 1; cnt > 0; cnt >>= 1) {
58 		addr = base + cnt;	/* pointer arith! */
59 		sync();
60 		save[i++] = *addr;
61 		sync();
62 		*addr = ~cnt;
63 		if (dcache_en)
64 			dcache_flush_invalidate(addr);
65 	}
66 
67 	addr = base;
68 	sync();
69 	save_base = *addr;
70 	sync();
71 	*addr = 0;
72 
73 	sync();
74 	if (dcache_en)
75 		dcache_flush_invalidate(addr);
76 
77 	if ((val = *addr) != 0) {
78 		/* Restore the original data before leaving the function. */
79 		sync();
80 		*base = save_base;
81 		for (cnt = 1; cnt < maxsize / sizeof(long); cnt <<= 1) {
82 			addr  = base + cnt;
83 			sync();
84 			*addr = save[--i];
85 		}
86 		return (0);
87 	}
88 
89 	for (cnt = 1; cnt < maxsize / sizeof(long); cnt <<= 1) {
90 		addr = base + cnt;	/* pointer arith! */
91 		val = *addr;
92 		*addr = save[--i];
93 		if (val != ~cnt) {
94 			size = cnt * sizeof(long);
95 			/*
96 			 * Restore the original data
97 			 * before leaving the function.
98 			 */
99 			for (cnt <<= 1;
100 			     cnt < maxsize / sizeof(long);
101 			     cnt <<= 1) {
102 				addr  = base + cnt;
103 				*addr = save[--i];
104 			}
105 			/* warning: don't restore save_base in this case,
106 			 * it is already done in the loop because
107 			 * base and base+size share the same physical memory
108 			 * and *base is saved after *(base+size) modification
109 			 * in first loop
110 			 */
111 			return (size);
112 		}
113 	}
114 	*base = save_base;
115 
116 	return (maxsize);
117 }
118 
get_effective_memsize(void)119 phys_size_t __weak get_effective_memsize(void)
120 {
121 	phys_size_t ram_size = gd->ram_size;
122 
123 #ifdef CONFIG_MPC85xx
124 	/*
125 	 * Check for overflow and limit ram size to some representable value.
126 	 * It is required that ram_base + ram_size must be representable by
127 	 * phys_size_t type and must be aligned by direct access, therefore
128 	 * calculate it from last 4kB sector which should work as alignment
129 	 * on any platform.
130 	 */
131 	if (gd->ram_base + ram_size < gd->ram_base)
132 		ram_size = ((phys_size_t)~0xfffULL) - gd->ram_base;
133 #endif
134 
135 #ifndef CFG_MAX_MEM_MAPPED
136 	return ram_size;
137 #else
138 	/* limit stack to what we can reasonable map */
139 	return ((ram_size > CFG_MAX_MEM_MAPPED) ?
140 		CFG_MAX_MEM_MAPPED : ram_size);
141 #endif
142 }
143