]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
2a5f7f20 | 2 | /* |
d5859255 | 3 | * Copyright (c) 2016-2018, NVIDIA CORPORATION. |
2a5f7f20 SW |
4 | */ |
5 | ||
6 | #include <common.h> | |
7 | #include <fdt_support.h> | |
8 | #include <fdtdec.h> | |
9 | #include <asm/arch/tegra.h> | |
cdcf5558 | 10 | #include <asm/armv8/mmu.h> |
2a5f7f20 | 11 | |
d5859255 SW |
12 | #define SZ_4G 0x100000000ULL |
13 | ||
14 | /* | |
15 | * Size of a region that's large enough to hold the relocated U-Boot and all | |
16 | * other allocations made around it (stack, heap, page tables, etc.) | |
17 | * In practice, running "bdinfo" at the shell prompt, the stack reaches about | |
18 | * 5MB from the address selected for ram_top as of the time of writing, | |
19 | * so a 16MB region should be plenty. | |
20 | */ | |
21 | #define MIN_USABLE_RAM_SIZE SZ_16M | |
22 | /* | |
23 | * The amount of space we expect to require for stack usage. Used to validate | |
24 | * that all reservations fit into the region selected for the relocation target | |
25 | */ | |
26 | #define MIN_USABLE_STACK_SIZE SZ_1M | |
27 | ||
2a5f7f20 SW |
28 | DECLARE_GLOBAL_DATA_PTR; |
29 | ||
30 | extern unsigned long nvtboot_boot_x0; | |
cdcf5558 | 31 | extern struct mm_region tegra_mem_map[]; |
2a5f7f20 SW |
32 | |
33 | /* | |
d5859255 SW |
34 | * These variables are written to before relocation, and hence cannot be |
35 | * in.bss, since .bss overlaps the DTB that's appended to the U-Boot binary. | |
36 | * The section attribute forces this into .data and avoids this issue. This | |
37 | * also has the nice side-effect of the content being valid after relocation. | |
2a5f7f20 | 38 | */ |
d5859255 | 39 | |
d5859255 SW |
40 | /* The number of valid entries in ram_banks[] */ |
41 | static int ram_bank_count __attribute__((section(".data"))); | |
42 | ||
43 | /* | |
44 | * The usable top-of-RAM for U-Boot. This is both: | |
45 | * a) Below 4GB to avoid issues with peripherals that use 32-bit addressing. | |
46 | * b) At the end of a region that has enough space to hold the relocated U-Boot | |
47 | * and all other allocations made around it (stack, heap, page tables, etc.) | |
48 | */ | |
49 | static u64 ram_top __attribute__((section(".data"))); | |
50 | /* The base address of the region of RAM that ends at ram_top */ | |
51 | static u64 region_base __attribute__((section(".data"))); | |
2a5f7f20 SW |
52 | |
53 | int dram_init(void) | |
54 | { | |
55 | unsigned int na, ns; | |
56 | const void *nvtboot_blob = (void *)nvtboot_boot_x0; | |
57 | int node, len, i; | |
58 | const u32 *prop; | |
59 | ||
2a5f7f20 SW |
60 | na = fdtdec_get_uint(nvtboot_blob, 0, "#address-cells", 2); |
61 | ns = fdtdec_get_uint(nvtboot_blob, 0, "#size-cells", 2); | |
62 | ||
63 | node = fdt_path_offset(nvtboot_blob, "/memory"); | |
64 | if (node < 0) { | |
9b643e31 | 65 | pr_err("Can't find /memory node in nvtboot DTB"); |
2a5f7f20 SW |
66 | hang(); |
67 | } | |
68 | prop = fdt_getprop(nvtboot_blob, node, "reg", &len); | |
69 | if (!prop) { | |
9b643e31 | 70 | pr_err("Can't find /memory/reg property in nvtboot DTB"); |
2a5f7f20 SW |
71 | hang(); |
72 | } | |
73 | ||
f6974712 SW |
74 | /* Calculate the true # of base/size pairs to read */ |
75 | len /= 4; /* Convert bytes to number of cells */ | |
76 | len /= (na + ns); /* Convert cells to number of banks */ | |
cdcf5558 SW |
77 | if (len > CONFIG_NR_DRAM_BANKS) |
78 | len = CONFIG_NR_DRAM_BANKS; | |
2a5f7f20 | 79 | |
cdcf5558 | 80 | /* Parse the /memory node, and save useful entries */ |
2a5f7f20 | 81 | gd->ram_size = 0; |
cdcf5558 SW |
82 | ram_bank_count = 0; |
83 | for (i = 0; i < len; i++) { | |
84 | u64 bank_start, bank_end, bank_size, usable_bank_size; | |
d5859255 | 85 | |
cdcf5558 SW |
86 | /* Extract raw memory region data from DTB */ |
87 | bank_start = fdt_read_number(prop, na); | |
2a5f7f20 | 88 | prop += na; |
cdcf5558 | 89 | bank_size = fdt_read_number(prop, ns); |
2a5f7f20 | 90 | prop += ns; |
cdcf5558 SW |
91 | gd->ram_size += bank_size; |
92 | bank_end = bank_start + bank_size; | |
93 | debug("Bank %d: %llx..%llx (+%llx)\n", i, | |
94 | bank_start, bank_end, bank_size); | |
95 | ||
96 | /* | |
97 | * Align the bank to MMU section size. This is not strictly | |
98 | * necessary, since the translation table construction code | |
99 | * handles page granularity without issue. However, aligning | |
100 | * the MMU entries reduces the size and number of levels in the | |
101 | * page table, so is worth it. | |
102 | */ | |
103 | bank_start = ROUND(bank_start, SZ_2M); | |
104 | bank_end = bank_end & ~(SZ_2M - 1); | |
105 | bank_size = bank_end - bank_start; | |
106 | debug(" aligned: %llx..%llx (+%llx)\n", | |
107 | bank_start, bank_end, bank_size); | |
108 | if (bank_end <= bank_start) | |
109 | continue; | |
110 | ||
111 | /* Record data used to create MMU translation tables */ | |
112 | ram_bank_count++; | |
113 | /* Index below is deliberately 1-based to skip MMIO entry */ | |
114 | tegra_mem_map[ram_bank_count].virt = bank_start; | |
115 | tegra_mem_map[ram_bank_count].phys = bank_start; | |
116 | tegra_mem_map[ram_bank_count].size = bank_size; | |
117 | tegra_mem_map[ram_bank_count].attrs = | |
118 | PTE_BLOCK_MEMTYPE(MT_NORMAL) | PTE_BLOCK_INNER_SHARE; | |
119 | ||
120 | /* Determine best bank to relocate U-Boot into */ | |
d5859255 SW |
121 | if (bank_end > SZ_4G) |
122 | bank_end = SZ_4G; | |
123 | debug(" end %llx (usable)\n", bank_end); | |
cdcf5558 | 124 | usable_bank_size = bank_end - bank_start; |
d5859255 SW |
125 | debug(" size %llx (usable)\n", usable_bank_size); |
126 | if ((usable_bank_size >= MIN_USABLE_RAM_SIZE) && | |
127 | (bank_end > ram_top)) { | |
128 | ram_top = bank_end; | |
cdcf5558 | 129 | region_base = bank_start; |
d5859255 SW |
130 | debug("ram top now %llx\n", ram_top); |
131 | } | |
132 | } | |
cdcf5558 SW |
133 | |
134 | /* Ensure memory map contains the desired sentinel entry */ | |
135 | tegra_mem_map[ram_bank_count + 1].virt = 0; | |
136 | tegra_mem_map[ram_bank_count + 1].phys = 0; | |
137 | tegra_mem_map[ram_bank_count + 1].size = 0; | |
138 | tegra_mem_map[ram_bank_count + 1].attrs = 0; | |
139 | ||
140 | /* Error out if a relocation target couldn't be found */ | |
d5859255 SW |
141 | if (!ram_top) { |
142 | pr_err("Can't find a usable RAM top"); | |
143 | hang(); | |
2a5f7f20 SW |
144 | } |
145 | ||
146 | return 0; | |
147 | } | |
148 | ||
76b00aca | 149 | int dram_init_banksize(void) |
2a5f7f20 SW |
150 | { |
151 | int i; | |
152 | ||
d5859255 SW |
153 | if ((gd->start_addr_sp - region_base) < MIN_USABLE_STACK_SIZE) { |
154 | pr_err("Reservations exceed chosen region size"); | |
155 | hang(); | |
156 | } | |
157 | ||
158 | for (i = 0; i < ram_bank_count; i++) { | |
cdcf5558 SW |
159 | gd->bd->bi_dram[i].start = tegra_mem_map[1 + i].virt; |
160 | gd->bd->bi_dram[i].size = tegra_mem_map[1 + i].size; | |
2a5f7f20 | 161 | } |
76b00aca | 162 | |
f6974712 | 163 | #ifdef CONFIG_PCI |
d5859255 | 164 | gd->pci_ram_top = ram_top; |
f6974712 SW |
165 | #endif |
166 | ||
76b00aca | 167 | return 0; |
2a5f7f20 SW |
168 | } |
169 | ||
170 | ulong board_get_usable_ram_top(ulong total_size) | |
171 | { | |
d5859255 | 172 | return ram_top; |
2a5f7f20 | 173 | } |