]> git.ipfire.org Git - thirdparty/u-boot.git/blob - common/memsize.c
Merge tag 'u-boot-dfu-20240606' of https://source.denx.de/u-boot/custodians/u-boot-dfu
[thirdparty/u-boot.git] / common / memsize.c
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 <common.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
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 */
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
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 }