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 <init.h>
   8#include <log.h>
   9#include <asm/e820.h>
  10#include <asm/global_data.h>
  11#include <asm/sfi.h>
  12
  13DECLARE_GLOBAL_DATA_PTR;
  14
  15/*
  16 * SFI tables are part of the first stage bootloader.
  17 *
  18 * U-Boot finds the System Table by searching 16-byte boundaries between
  19 * physical address 0x000E0000 and 0x000FFFFF. U-Boot shall search this region
  20 * starting at the low address and shall stop searching when the 1st valid SFI
  21 * System Table is found.
  22 */
  23#define SFI_BASE_ADDR           0x000E0000
  24#define SFI_LENGTH              0x00020000
  25#define SFI_TABLE_LENGTH        16
  26
  27static int sfi_table_check(struct sfi_table_header *sbh)
  28{
  29        char chksum = 0;
  30        char *pos = (char *)sbh;
  31        u32 i;
  32
  33        if (sbh->len < SFI_TABLE_LENGTH)
  34                return -ENXIO;
  35
  36        if (sbh->len > SFI_LENGTH)
  37                return -ENXIO;
  38
  39        for (i = 0; i < sbh->len; i++)
  40                chksum += *pos++;
  41
  42        if (chksum)
  43                pr_err("sfi: Invalid checksum\n");
  44
  45        /* Checksum is OK if zero */
  46        return chksum ? -EILSEQ : 0;
  47}
  48
  49static int sfi_table_is_type(struct sfi_table_header *sbh, const char *signature)
  50{
  51        return !strncmp(sbh->sig, signature, SFI_SIGNATURE_SIZE) &&
  52               !sfi_table_check(sbh);
  53}
  54
  55static struct sfi_table_simple *sfi_get_table_by_sig(unsigned long addr,
  56                                                     const char *signature)
  57{
  58        struct sfi_table_simple *sb;
  59        u32 i;
  60
  61        for (i = 0; i < SFI_LENGTH; i += SFI_TABLE_LENGTH) {
  62                sb = (struct sfi_table_simple *)(addr + i);
  63                if (sfi_table_is_type(&sb->header, signature))
  64                        return sb;
  65        }
  66
  67        return NULL;
  68}
  69
  70static struct sfi_table_simple *sfi_search_mmap(void)
  71{
  72        struct sfi_table_header *sbh;
  73        struct sfi_table_simple *sb;
  74        u32 sys_entry_cnt;
  75        u32 i;
  76
  77        /* Find SYST table */
  78        sb = sfi_get_table_by_sig(SFI_BASE_ADDR, SFI_SIG_SYST);
  79        if (!sb) {
  80                pr_err("sfi: failed to locate SYST table\n");
  81                return NULL;
  82        }
  83
  84        sys_entry_cnt = (sb->header.len - sizeof(*sbh)) / 8;
  85
  86        /* Search through each SYST entry for MMAP table */
  87        for (i = 0; i < sys_entry_cnt; i++) {
  88                sbh = (struct sfi_table_header *)(unsigned long)sb->pentry[i];
  89
  90                if (sfi_table_is_type(sbh, SFI_SIG_MMAP))
  91                        return (struct sfi_table_simple *)sbh;
  92        }
  93
  94        pr_err("sfi: failed to locate SFI MMAP table\n");
  95        return NULL;
  96}
  97
  98#define sfi_for_each_mentry(i, sb, mentry)                              \
  99        for (i = 0, mentry = (struct sfi_mem_entry *)sb->pentry;        \
 100             i < SFI_GET_NUM_ENTRIES(sb, struct sfi_mem_entry);         \
 101             i++, mentry++)                                             \
 102
 103static unsigned int sfi_setup_e820(unsigned int max_entries,
 104                                   struct e820_entry *entries)
 105{
 106        struct sfi_table_simple *sb;
 107        struct sfi_mem_entry *mentry;
 108        unsigned long long start, end, size;
 109        int type, total = 0;
 110        u32 i;
 111
 112        sb = sfi_search_mmap();
 113        if (!sb)
 114                return 0;
 115
 116        sfi_for_each_mentry(i, sb, mentry) {
 117                start = mentry->phys_start;
 118                size = mentry->pages << 12;
 119                end = start + size;
 120
 121                if (start > end)
 122                        continue;
 123
 124                /* translate SFI mmap type to E820 map type */
 125                switch (mentry->type) {
 126                case SFI_MEM_CONV:
 127                        type = E820_RAM;
 128                        break;
 129                case SFI_MEM_UNUSABLE:
 130                case SFI_RUNTIME_SERVICE_DATA:
 131                        continue;
 132                default:
 133                        type = E820_RESERVED;
 134                }
 135
 136                if (total == E820MAX)
 137                        break;
 138                entries[total].addr = start;
 139                entries[total].size = size;
 140                entries[total].type = type;
 141
 142                total++;
 143        }
 144
 145        return total;
 146}
 147
 148static int sfi_get_bank_size(void)
 149{
 150        struct sfi_table_simple *sb;
 151        struct sfi_mem_entry *mentry;
 152        int bank = 0;
 153        u32 i;
 154
 155        sb = sfi_search_mmap();
 156        if (!sb)
 157                return 0;
 158
 159        sfi_for_each_mentry(i, sb, mentry) {
 160                if (mentry->type != SFI_MEM_CONV)
 161                        continue;
 162
 163                gd->bd->bi_dram[bank].start = mentry->phys_start;
 164                gd->bd->bi_dram[bank].size = mentry->pages << 12;
 165                bank++;
 166        }
 167
 168        return bank;
 169}
 170
 171static phys_size_t sfi_get_ram_size(void)
 172{
 173        struct sfi_table_simple *sb;
 174        struct sfi_mem_entry *mentry;
 175        phys_size_t ram = 0;
 176        u32 i;
 177
 178        sb = sfi_search_mmap();
 179        if (!sb)
 180                return 0;
 181
 182        sfi_for_each_mentry(i, sb, mentry) {
 183                if (mentry->type != SFI_MEM_CONV)
 184                        continue;
 185
 186                ram += mentry->pages << 12;
 187        }
 188
 189        debug("sfi: RAM size %llu\n", ram);
 190        return ram;
 191}
 192
 193unsigned int install_e820_map(unsigned int max_entries,
 194                              struct e820_entry *entries)
 195{
 196        return sfi_setup_e820(max_entries, entries);
 197}
 198
 199/*
 200 * This function looks for the highest region of memory lower than 2GB which
 201 * has enough space for U-Boot where U-Boot is aligned on a page boundary. It
 202 * overrides the default implementation found elsewhere which simply picks the
 203 * end of RAM, wherever that may be. The location of the stack, the relocation
 204 * address, and how far U-Boot is moved by relocation are set in the global
 205 * data structure.
 206 */
 207phys_size_t board_get_usable_ram_top(phys_size_t total_size)
 208{
 209        struct sfi_table_simple *sb;
 210        struct sfi_mem_entry *mentry;
 211        ulong dest_addr = 0;
 212        u32 i;
 213
 214        sb = sfi_search_mmap();
 215        if (!sb)
 216                panic("No available memory found for relocation");
 217
 218        sfi_for_each_mentry(i, sb, mentry) {
 219                unsigned long long start, end;
 220
 221                if (mentry->type != SFI_MEM_CONV)
 222                        continue;
 223
 224                start = mentry->phys_start;
 225                end = start + (mentry->pages << 12);
 226
 227                /* Filter memory over 2GB. */
 228                if (end > 0x7fffffffULL)
 229                        end = 0x80000000ULL;
 230                /* Skip this region if it's too small. */
 231                if (end - start < total_size)
 232                        continue;
 233
 234                /* Use this address if it's the largest so far. */
 235                if (end > dest_addr)
 236                        dest_addr = end;
 237        }
 238
 239        return dest_addr;
 240}
 241
 242int dram_init_banksize(void)
 243{
 244        sfi_get_bank_size();
 245        return 0;
 246}
 247
 248int dram_init(void)
 249{
 250        gd->ram_size = sfi_get_ram_size();
 251        return 0;
 252}
 253