uboot/arch/x86/cpu/tangier/sdram.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2017 Intel Corporation
   3 *
   4 * SPDX-License-Identifier:     GPL-2.0+
   5 */
   6
   7#include <common.h>
   8#include <asm/e820.h>
   9#include <asm/global_data.h>
  10#include <asm/sfi.h>
  11
  12DECLARE_GLOBAL_DATA_PTR;
  13
  14/*
  15 * SFI tables are part of the first stage bootloader.
  16 *
  17 * U-Boot finds the System Table by searching 16-byte boundaries between
  18 * physical address 0x000E0000 and 0x000FFFFF. U-Boot shall search this region
  19 * starting at the low address and shall stop searching when the 1st valid SFI
  20 * System Table is found.
  21 */
  22#define SFI_BASE_ADDR           0x000E0000
  23#define SFI_LENGTH              0x00020000
  24#define SFI_TABLE_LENGTH        16
  25
  26static int sfi_table_check(struct sfi_table_header *sbh)
  27{
  28        char chksum = 0;
  29        char *pos = (char *)sbh;
  30        u32 i;
  31
  32        if (sbh->len < SFI_TABLE_LENGTH)
  33                return -ENXIO;
  34
  35        if (sbh->len > SFI_LENGTH)
  36                return -ENXIO;
  37
  38        for (i = 0; i < sbh->len; i++)
  39                chksum += *pos++;
  40
  41        if (chksum)
  42                pr_err("sfi: Invalid checksum\n");
  43
  44        /* Checksum is OK if zero */
  45        return chksum ? -EILSEQ : 0;
  46}
  47
  48static int sfi_table_is_type(struct sfi_table_header *sbh, const char *signature)
  49{
  50        return !strncmp(sbh->sig, signature, SFI_SIGNATURE_SIZE) &&
  51               !sfi_table_check(sbh);
  52}
  53
  54static struct sfi_table_simple *sfi_get_table_by_sig(unsigned long addr,
  55                                                     const char *signature)
  56{
  57        struct sfi_table_simple *sb;
  58        u32 i;
  59
  60        for (i = 0; i < SFI_LENGTH; i += SFI_TABLE_LENGTH) {
  61                sb = (struct sfi_table_simple *)(addr + i);
  62                if (sfi_table_is_type(&sb->header, signature))
  63                        return sb;
  64        }
  65
  66        return NULL;
  67}
  68
  69static struct sfi_table_simple *sfi_search_mmap(void)
  70{
  71        struct sfi_table_header *sbh;
  72        struct sfi_table_simple *sb;
  73        u32 sys_entry_cnt;
  74        u32 i;
  75
  76        /* Find SYST table */
  77        sb = sfi_get_table_by_sig(SFI_BASE_ADDR, SFI_SIG_SYST);
  78        if (!sb) {
  79                pr_err("sfi: failed to locate SYST table\n");
  80                return NULL;
  81        }
  82
  83        sys_entry_cnt = (sb->header.len - sizeof(*sbh)) / 8;
  84
  85        /* Search through each SYST entry for MMAP table */
  86        for (i = 0; i < sys_entry_cnt; i++) {
  87                sbh = (struct sfi_table_header *)(unsigned long)sb->pentry[i];
  88
  89                if (sfi_table_is_type(sbh, SFI_SIG_MMAP))
  90                        return (struct sfi_table_simple *)sbh;
  91        }
  92
  93        pr_err("sfi: failed to locate SFI MMAP table\n");
  94        return NULL;
  95}
  96
  97#define sfi_for_each_mentry(i, sb, mentry)                              \
  98        for (i = 0, mentry = (struct sfi_mem_entry *)sb->pentry;        \
  99             i < SFI_GET_NUM_ENTRIES(sb, struct sfi_mem_entry);         \
 100             i++, mentry++)                                             \
 101
 102static unsigned sfi_setup_e820(unsigned max_entries, struct e820entry *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
 146static 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
 169static 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
 191unsigned install_e820_map(unsigned max_entries, struct e820entry *entries)
 192{
 193        return sfi_setup_e820(max_entries, entries);
 194}
 195
 196int dram_init_banksize(void)
 197{
 198        sfi_get_bank_size();
 199        return 0;
 200}
 201
 202int dram_init(void)
 203{
 204        gd->ram_size = sfi_get_ram_size();
 205        return 0;
 206}
 207