blob: 2c83092ebcdf0de19797226eed910ef9cdd946df [file] [log] [blame]
Patrick Rudolphbd4bcab2019-06-30 22:12:15 +02001/*
2 * This file is part of the coreboot project.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <types.h>
15#include <symbols.h>
16#include <device/mmio.h>
17#include <ramdetect.h>
18#include <console/console.h>
19
20#define OVERLAP(a, b, s, e) ((b) > (s) && (a) < (e))
21
Asami Doi06993ee2019-08-07 13:40:53 +090022int __weak probe_mb(const uintptr_t dram_start, const uintptr_t size)
Patrick Rudolphbd4bcab2019-06-30 22:12:15 +020023{
24 uintptr_t addr = dram_start + (size * MiB) - sizeof(uint32_t);
25 static const uint32_t patterns[] = {
26 0x55aa55aa,
27 0x12345678
28 };
29 void *ptr = (void *) addr;
30 size_t i;
31
32 /* Don't accidentally clober oneself. */
33 if (OVERLAP(addr, addr + sizeof(uint32_t), (uintptr_t)_program, (uintptr_t) _eprogram))
34 return 1;
35
36 uint32_t old = read32(ptr);
37 for (i = 0; i < ARRAY_SIZE(patterns); i++) {
38 write32(ptr, patterns[i]);
39 if (read32(ptr) != patterns[i])
40 break;
41 }
42
43 write32(ptr, old);
44 return i == ARRAY_SIZE(patterns);
45}
46
47/* - 20 as probe_size is in MiB, - 1 as i is signed */
48#define MAX_ADDRESSABLE_SPACE (sizeof(size_t) * 8 - 20 - 1)
49
50/* Probe an area if it's read/writable. */
51size_t probe_ramsize(const uintptr_t dram_start, const size_t probe_size)
52{
53 ssize_t i;
54 size_t msb = 0;
55 size_t discovered = 0;
56
57 static size_t saved_result;
58 if (saved_result)
59 return saved_result;
60
61 /* Find the MSB + 1. */
62 size_t tmp = probe_size;
63 do {
64 msb++;
65 } while (tmp >>= 1);
66
67 /* Limit search to accessible address space */
68 msb = MIN(msb, MAX_ADDRESSABLE_SPACE);
69
70 /* Compact binary search. */
71 for (i = msb; i >= 0; i--)
72 if (probe_mb(dram_start, (discovered | (1ULL << i))))
73 discovered |= (1ULL << i);
74
75 saved_result = discovered;
76 printk(BIOS_DEBUG, "RAMDETECT: Found %zu MiB RAM\n", discovered);
77 return discovered;
78}