diff options
Diffstat (limited to 'arch/x86/cpu/tangier/sdram.c')
-rw-r--r-- | arch/x86/cpu/tangier/sdram.c | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/arch/x86/cpu/tangier/sdram.c b/arch/x86/cpu/tangier/sdram.c new file mode 100644 index 0000000..5743077 --- /dev/null +++ b/arch/x86/cpu/tangier/sdram.c @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/e820.h> +#include <asm/global_data.h> +#include <asm/sfi.h> + +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) + error("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) { + error("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; + } + + error("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; +} |