1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (c) 2017 Intel Corporation 4 */ 5 6 #include <common.h> 7 #include <asm/e820.h> 8 #include <asm/global_data.h> 9 #include <asm/sfi.h> 10 11 DECLARE_GLOBAL_DATA_PTR; 12 13 /* 14 * SFI tables are part of the first stage bootloader. 15 * 16 * U-Boot finds the System Table by searching 16-byte boundaries between 17 * physical address 0x000E0000 and 0x000FFFFF. U-Boot shall search this region 18 * starting at the low address and shall stop searching when the 1st valid SFI 19 * System Table is found. 20 */ 21 #define SFI_BASE_ADDR 0x000E0000 22 #define SFI_LENGTH 0x00020000 23 #define SFI_TABLE_LENGTH 16 24 25 static int sfi_table_check(struct sfi_table_header *sbh) 26 { 27 char chksum = 0; 28 char *pos = (char *)sbh; 29 u32 i; 30 31 if (sbh->len < SFI_TABLE_LENGTH) 32 return -ENXIO; 33 34 if (sbh->len > SFI_LENGTH) 35 return -ENXIO; 36 37 for (i = 0; i < sbh->len; i++) 38 chksum += *pos++; 39 40 if (chksum) 41 pr_err("sfi: Invalid checksum\n"); 42 43 /* Checksum is OK if zero */ 44 return chksum ? -EILSEQ : 0; 45 } 46 47 static int sfi_table_is_type(struct sfi_table_header *sbh, const char *signature) 48 { 49 return !strncmp(sbh->sig, signature, SFI_SIGNATURE_SIZE) && 50 !sfi_table_check(sbh); 51 } 52 53 static struct sfi_table_simple *sfi_get_table_by_sig(unsigned long addr, 54 const char *signature) 55 { 56 struct sfi_table_simple *sb; 57 u32 i; 58 59 for (i = 0; i < SFI_LENGTH; i += SFI_TABLE_LENGTH) { 60 sb = (struct sfi_table_simple *)(addr + i); 61 if (sfi_table_is_type(&sb->header, signature)) 62 return sb; 63 } 64 65 return NULL; 66 } 67 68 static struct sfi_table_simple *sfi_search_mmap(void) 69 { 70 struct sfi_table_header *sbh; 71 struct sfi_table_simple *sb; 72 u32 sys_entry_cnt; 73 u32 i; 74 75 /* Find SYST table */ 76 sb = sfi_get_table_by_sig(SFI_BASE_ADDR, SFI_SIG_SYST); 77 if (!sb) { 78 pr_err("sfi: failed to locate SYST table\n"); 79 return NULL; 80 } 81 82 sys_entry_cnt = (sb->header.len - sizeof(*sbh)) / 8; 83 84 /* Search through each SYST entry for MMAP table */ 85 for (i = 0; i < sys_entry_cnt; i++) { 86 sbh = (struct sfi_table_header *)(unsigned long)sb->pentry[i]; 87 88 if (sfi_table_is_type(sbh, SFI_SIG_MMAP)) 89 return (struct sfi_table_simple *)sbh; 90 } 91 92 pr_err("sfi: failed to locate SFI MMAP table\n"); 93 return NULL; 94 } 95 96 #define sfi_for_each_mentry(i, sb, mentry) \ 97 for (i = 0, mentry = (struct sfi_mem_entry *)sb->pentry; \ 98 i < SFI_GET_NUM_ENTRIES(sb, struct sfi_mem_entry); \ 99 i++, mentry++) \ 100 101 static unsigned int sfi_setup_e820(unsigned int max_entries, 102 struct e820_entry *entries) 103 { 104 struct sfi_table_simple *sb; 105 struct sfi_mem_entry *mentry; 106 unsigned long long start, end, size; 107 int type, total = 0; 108 u32 i; 109 110 sb = sfi_search_mmap(); 111 if (!sb) 112 return 0; 113 114 sfi_for_each_mentry(i, sb, mentry) { 115 start = mentry->phys_start; 116 size = mentry->pages << 12; 117 end = start + size; 118 119 if (start > end) 120 continue; 121 122 /* translate SFI mmap type to E820 map type */ 123 switch (mentry->type) { 124 case SFI_MEM_CONV: 125 type = E820_RAM; 126 break; 127 case SFI_MEM_UNUSABLE: 128 case SFI_RUNTIME_SERVICE_DATA: 129 continue; 130 default: 131 type = E820_RESERVED; 132 } 133 134 if (total == E820MAX) 135 break; 136 entries[total].addr = start; 137 entries[total].size = size; 138 entries[total].type = type; 139 140 total++; 141 } 142 143 return total; 144 } 145 146 static int sfi_get_bank_size(void) 147 { 148 struct sfi_table_simple *sb; 149 struct sfi_mem_entry *mentry; 150 int bank = 0; 151 u32 i; 152 153 sb = sfi_search_mmap(); 154 if (!sb) 155 return 0; 156 157 sfi_for_each_mentry(i, sb, mentry) { 158 if (mentry->type != SFI_MEM_CONV) 159 continue; 160 161 gd->bd->bi_dram[bank].start = mentry->phys_start; 162 gd->bd->bi_dram[bank].size = mentry->pages << 12; 163 bank++; 164 } 165 166 return bank; 167 } 168 169 static phys_size_t sfi_get_ram_size(void) 170 { 171 struct sfi_table_simple *sb; 172 struct sfi_mem_entry *mentry; 173 phys_size_t ram = 0; 174 u32 i; 175 176 sb = sfi_search_mmap(); 177 if (!sb) 178 return 0; 179 180 sfi_for_each_mentry(i, sb, mentry) { 181 if (mentry->type != SFI_MEM_CONV) 182 continue; 183 184 ram += mentry->pages << 12; 185 } 186 187 debug("sfi: RAM size %llu\n", ram); 188 return ram; 189 } 190 191 unsigned int install_e820_map(unsigned int max_entries, 192 struct e820_entry *entries) 193 { 194 return sfi_setup_e820(max_entries, entries); 195 } 196 197 int dram_init_banksize(void) 198 { 199 sfi_get_bank_size(); 200 return 0; 201 } 202 203 int dram_init(void) 204 { 205 gd->ram_size = sfi_get_ram_size(); 206 return 0; 207 } 208