// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (c) 2017 Intel Corporation */ #include #include #include #include #include #include DECLARE_GLOBAL_DATA_PTR; /* * SFI tables are part of the first stage bootloader. * * U-Boot finds the System Table by searching 16-byte boundaries between * physical address 0x000E0000 and 0x000FFFFF. U-Boot shall search this region * starting at the low address and shall stop searching when the 1st valid SFI * System Table is found. */ #define SFI_BASE_ADDR 0x000E0000 #define SFI_LENGTH 0x00020000 #define SFI_TABLE_LENGTH 16 static int sfi_table_check(struct sfi_table_header *sbh) { char chksum = 0; char *pos = (char *)sbh; u32 i; if (sbh->len < SFI_TABLE_LENGTH) return -ENXIO; if (sbh->len > SFI_LENGTH) return -ENXIO; for (i = 0; i < sbh->len; i++) chksum += *pos++; if (chksum) pr_err("sfi: Invalid checksum\n"); /* Checksum is OK if zero */ return chksum ? -EILSEQ : 0; } static int sfi_table_is_type(struct sfi_table_header *sbh, const char *signature) { return !strncmp(sbh->sig, signature, SFI_SIGNATURE_SIZE) && !sfi_table_check(sbh); } static struct sfi_table_simple *sfi_get_table_by_sig(unsigned long addr, const char *signature) { struct sfi_table_simple *sb; u32 i; for (i = 0; i < SFI_LENGTH; i += SFI_TABLE_LENGTH) { sb = (struct sfi_table_simple *)(addr + i); if (sfi_table_is_type(&sb->header, signature)) return sb; } return NULL; } static struct sfi_table_simple *sfi_search_mmap(void) { struct sfi_table_header *sbh; struct sfi_table_simple *sb; u32 sys_entry_cnt; u32 i; /* Find SYST table */ sb = sfi_get_table_by_sig(SFI_BASE_ADDR, SFI_SIG_SYST); if (!sb) { pr_err("sfi: failed to locate SYST table\n"); return NULL; } sys_entry_cnt = (sb->header.len - sizeof(*sbh)) / 8; /* Search through each SYST entry for MMAP table */ for (i = 0; i < sys_entry_cnt; i++) { sbh = (struct sfi_table_header *)(unsigned long)sb->pentry[i]; if (sfi_table_is_type(sbh, SFI_SIG_MMAP)) return (struct sfi_table_simple *)sbh; } pr_err("sfi: failed to locate SFI MMAP table\n"); return NULL; } #define sfi_for_each_mentry(i, sb, mentry) \ for (i = 0, mentry = (struct sfi_mem_entry *)sb->pentry; \ i < SFI_GET_NUM_ENTRIES(sb, struct sfi_mem_entry); \ i++, mentry++) \ static unsigned int sfi_setup_e820(unsigned int max_entries, struct e820_entry *entries) { struct sfi_table_simple *sb; struct sfi_mem_entry *mentry; unsigned long long start, end, size; int type, total = 0; u32 i; sb = sfi_search_mmap(); if (!sb) return 0; sfi_for_each_mentry(i, sb, mentry) { start = mentry->phys_start; size = mentry->pages << 12; end = start + size; if (start > end) continue; /* translate SFI mmap type to E820 map type */ switch (mentry->type) { case SFI_MEM_CONV: type = E820_RAM; break; case SFI_MEM_UNUSABLE: case SFI_RUNTIME_SERVICE_DATA: continue; default: type = E820_RESERVED; } if (total == E820MAX) break; entries[total].addr = start; entries[total].size = size; entries[total].type = type; total++; } return total; } static int sfi_get_bank_size(void) { struct sfi_table_simple *sb; struct sfi_mem_entry *mentry; int bank = 0; u32 i; sb = sfi_search_mmap(); if (!sb) return 0; sfi_for_each_mentry(i, sb, mentry) { if (mentry->type != SFI_MEM_CONV) continue; gd->bd->bi_dram[bank].start = mentry->phys_start; gd->bd->bi_dram[bank].size = mentry->pages << 12; bank++; } return bank; } static phys_size_t sfi_get_ram_size(void) { struct sfi_table_simple *sb; struct sfi_mem_entry *mentry; phys_size_t ram = 0; u32 i; sb = sfi_search_mmap(); if (!sb) return 0; sfi_for_each_mentry(i, sb, mentry) { if (mentry->type != SFI_MEM_CONV) continue; ram += mentry->pages << 12; } debug("sfi: RAM size %llu\n", ram); return ram; } unsigned int install_e820_map(unsigned int max_entries, struct e820_entry *entries) { return sfi_setup_e820(max_entries, entries); } /* * This function looks for the highest region of memory lower than 2GB which * has enough space for U-Boot where U-Boot is aligned on a page boundary. It * overrides the default implementation found elsewhere which simply picks the * end of RAM, wherever that may be. The location of the stack, the relocation * address, and how far U-Boot is moved by relocation are set in the global * data structure. */ phys_size_t board_get_usable_ram_top(phys_size_t total_size) { struct sfi_table_simple *sb; struct sfi_mem_entry *mentry; ulong dest_addr = 0; u32 i; sb = sfi_search_mmap(); if (!sb) panic("No available memory found for relocation"); sfi_for_each_mentry(i, sb, mentry) { unsigned long long start, end; if (mentry->type != SFI_MEM_CONV) continue; start = mentry->phys_start; end = start + (mentry->pages << 12); /* Filter memory over 2GB. */ if (end > 0x7fffffffULL) end = 0x80000000ULL; /* Skip this region if it's too small. */ if (end - start < total_size) continue; /* Use this address if it's the largest so far. */ if (end > dest_addr) dest_addr = end; } return dest_addr; } int dram_init_banksize(void) { sfi_get_bank_size(); return 0; } int dram_init(void) { gd->ram_size = sfi_get_ram_size(); return 0; }