/* * Copyright (c) 2017 Intel Corporation * * SPDX-License-Identifier: GPL-2.0+ */ #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 sfi_setup_e820(unsigned max_entries, struct e820entry *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 install_e820_map(unsigned max_entries, struct e820entry *entries) { return sfi_setup_e820(max_entries, entries); } int dram_init_banksize(void) { sfi_get_bank_size(); return 0; } int dram_init(void) { gd->ram_size = sfi_get_ram_size(); return 0; }