uboot/arch/x86/cpu/tangier/sdram.c
<<
>>
Prefs
   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
  11DECLARE_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
  25static 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
  47static 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
  53static 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
  68static 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
 101static 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
 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 int install_e820_map(unsigned int max_entries,
 192                              struct e820_entry *entries)
 193{
 194        return sfi_setup_e820(max_entries, entries);
 195}
 196
 197int dram_init_banksize(void)
 198{
 199        sfi_get_bank_size();
 200        return 0;
 201}
 202
 203int dram_init(void)
 204{
 205        gd->ram_size = sfi_get_ram_size();
 206        return 0;
 207}
 208