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 13DECLARE_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 32static 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 */ 46long 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 119phys_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