uboot/arch/x86/lib/mrccache.c
<<
>>
Prefs
   1/*
   2 * From coreboot src/southbridge/intel/bd82x6x/mrccache.c
   3 *
   4 * Copyright (C) 2014 Google Inc.
   5 * Copyright (C) 2015 Bin Meng <bmeng.cn@gmail.com>
   6 *
   7 * SPDX-License-Identifier:     GPL-2.0
   8 */
   9
  10#include <common.h>
  11#include <dm.h>
  12#include <errno.h>
  13#include <fdtdec.h>
  14#include <net.h>
  15#include <spi.h>
  16#include <spi_flash.h>
  17#include <asm/mrccache.h>
  18
  19DECLARE_GLOBAL_DATA_PTR;
  20
  21static struct mrc_data_container *next_mrc_block(
  22        struct mrc_data_container *cache)
  23{
  24        /* MRC data blocks are aligned within the region */
  25        u32 mrc_size = sizeof(*cache) + cache->data_size;
  26        u8 *region_ptr = (u8 *)cache;
  27
  28        if (mrc_size & (MRC_DATA_ALIGN - 1UL)) {
  29                mrc_size &= ~(MRC_DATA_ALIGN - 1UL);
  30                mrc_size += MRC_DATA_ALIGN;
  31        }
  32
  33        region_ptr += mrc_size;
  34
  35        return (struct mrc_data_container *)region_ptr;
  36}
  37
  38static int is_mrc_cache(struct mrc_data_container *cache)
  39{
  40        return cache && (cache->signature == MRC_DATA_SIGNATURE);
  41}
  42
  43struct mrc_data_container *mrccache_find_current(struct mrc_region *entry)
  44{
  45        struct mrc_data_container *cache, *next;
  46        ulong base_addr, end_addr;
  47        uint id;
  48
  49        base_addr = entry->base + entry->offset;
  50        end_addr = base_addr + entry->length;
  51        cache = NULL;
  52
  53        /* Search for the last filled entry in the region */
  54        for (id = 0, next = (struct mrc_data_container *)base_addr;
  55             is_mrc_cache(next);
  56             id++) {
  57                cache = next;
  58                next = next_mrc_block(next);
  59                if ((ulong)next >= end_addr)
  60                        break;
  61        }
  62
  63        if (id-- == 0) {
  64                debug("%s: No valid MRC cache found.\n", __func__);
  65                return NULL;
  66        }
  67
  68        /* Verify checksum */
  69        if (cache->checksum != compute_ip_checksum(cache->data,
  70                                                   cache->data_size)) {
  71                printf("%s: MRC cache checksum mismatch\n", __func__);
  72                return NULL;
  73        }
  74
  75        debug("%s: picked entry %u from cache block\n", __func__, id);
  76
  77        return cache;
  78}
  79
  80/**
  81 * find_next_mrc_cache() - get next cache entry
  82 *
  83 * @entry:      MRC cache flash area
  84 * @cache:      Entry to start from
  85 *
  86 * @return next cache entry if found, NULL if we got to the end
  87 */
  88static struct mrc_data_container *find_next_mrc_cache(struct mrc_region *entry,
  89                struct mrc_data_container *cache)
  90{
  91        ulong base_addr, end_addr;
  92
  93        base_addr = entry->base + entry->offset;
  94        end_addr = base_addr + entry->length;
  95
  96        cache = next_mrc_block(cache);
  97        if ((ulong)cache >= end_addr) {
  98                /* Crossed the boundary */
  99                cache = NULL;
 100                debug("%s: no available entries found\n", __func__);
 101        } else {
 102                debug("%s: picked next entry from cache block at %p\n",
 103                      __func__, cache);
 104        }
 105
 106        return cache;
 107}
 108
 109int mrccache_update(struct udevice *sf, struct mrc_region *entry,
 110                    struct mrc_data_container *cur)
 111{
 112        struct mrc_data_container *cache;
 113        ulong offset;
 114        ulong base_addr;
 115        int ret;
 116
 117        if (!is_mrc_cache(cur))
 118                return -EINVAL;
 119
 120        /* Find the last used block */
 121        base_addr = entry->base + entry->offset;
 122        debug("Updating MRC cache data\n");
 123        cache = mrccache_find_current(entry);
 124        if (cache && (cache->data_size == cur->data_size) &&
 125            (!memcmp(cache, cur, cache->data_size + sizeof(*cur)))) {
 126                debug("MRC data in flash is up to date. No update\n");
 127                return -EEXIST;
 128        }
 129
 130        /* Move to the next block, which will be the first unused block */
 131        if (cache)
 132                cache = find_next_mrc_cache(entry, cache);
 133
 134        /*
 135         * If we have got to the end, erase the entire mrc-cache area and start
 136         * again at block 0.
 137         */
 138        if (!cache) {
 139                debug("Erasing the MRC cache region of %x bytes at %x\n",
 140                      entry->length, entry->offset);
 141
 142                ret = spi_flash_erase_dm(sf, entry->offset, entry->length);
 143                if (ret) {
 144                        debug("Failed to erase flash region\n");
 145                        return ret;
 146                }
 147                cache = (struct mrc_data_container *)base_addr;
 148        }
 149
 150        /* Write the data out */
 151        offset = (ulong)cache - base_addr + entry->offset;
 152        debug("Write MRC cache update to flash at %lx\n", offset);
 153        ret = spi_flash_write_dm(sf, offset, cur->data_size + sizeof(*cur),
 154                                 cur);
 155        if (ret) {
 156                debug("Failed to write to SPI flash\n");
 157                return ret;
 158        }
 159
 160        return 0;
 161}
 162
 163int mrccache_reserve(void)
 164{
 165        struct mrc_data_container *cache;
 166        u16 checksum;
 167
 168        if (!gd->arch.mrc_output_len)
 169                return 0;
 170
 171        /* adjust stack pointer to store pure cache data plus the header */
 172        gd->start_addr_sp -= (gd->arch.mrc_output_len + MRC_DATA_HEADER_SIZE);
 173        cache = (struct mrc_data_container *)gd->start_addr_sp;
 174
 175        cache->signature = MRC_DATA_SIGNATURE;
 176        cache->data_size = gd->arch.mrc_output_len;
 177        checksum = compute_ip_checksum(gd->arch.mrc_output, cache->data_size);
 178        debug("Saving %d bytes for MRC output data, checksum %04x\n",
 179              cache->data_size, checksum);
 180        cache->checksum = checksum;
 181        cache->reserved = 0;
 182        memcpy(cache->data, gd->arch.mrc_output, cache->data_size);
 183
 184        /* gd->arch.mrc_output now points to the container */
 185        gd->arch.mrc_output = (char *)cache;
 186
 187        gd->start_addr_sp &= ~0xf;
 188
 189        return 0;
 190}
 191
 192int mrccache_get_region(struct udevice **devp, struct mrc_region *entry)
 193{
 194        const void *blob = gd->fdt_blob;
 195        int node, mrc_node;
 196        u32 reg[2];
 197        int ret;
 198
 199        /* Find the flash chip within the SPI controller node */
 200        node = fdtdec_next_compatible(blob, 0, COMPAT_GENERIC_SPI_FLASH);
 201        if (node < 0) {
 202                debug("%s: Cannot find SPI flash\n", __func__);
 203                return -ENOENT;
 204        }
 205
 206        if (fdtdec_get_int_array(blob, node, "memory-map", reg, 2))
 207                return -EINVAL;
 208        entry->base = reg[0];
 209
 210        /* Find the place where we put the MRC cache */
 211        mrc_node = fdt_subnode_offset(blob, node, "rw-mrc-cache");
 212        if (mrc_node < 0)
 213                return -EPERM;
 214
 215        if (fdtdec_get_int_array(blob, mrc_node, "reg", reg, 2))
 216                return -EINVAL;
 217        entry->offset = reg[0];
 218        entry->length = reg[1];
 219
 220        if (devp) {
 221                ret = uclass_get_device_by_of_offset(UCLASS_SPI_FLASH, node,
 222                                                     devp);
 223                debug("ret = %d\n", ret);
 224                if (ret)
 225                        return ret;
 226        }
 227
 228        return 0;
 229}
 230
 231int mrccache_save(void)
 232{
 233        struct mrc_data_container *data;
 234        struct mrc_region entry;
 235        struct udevice *sf;
 236        int ret;
 237
 238        if (!gd->arch.mrc_output_len)
 239                return 0;
 240        debug("Saving %d bytes of MRC output data to SPI flash\n",
 241              gd->arch.mrc_output_len);
 242
 243        ret = mrccache_get_region(&sf, &entry);
 244        if (ret)
 245                goto err_entry;
 246        data  = (struct mrc_data_container *)gd->arch.mrc_output;
 247        ret = mrccache_update(sf, &entry, data);
 248        if (!ret) {
 249                debug("Saved MRC data with checksum %04x\n", data->checksum);
 250        } else if (ret == -EEXIST) {
 251                debug("MRC data is the same as last time, skipping save\n");
 252                ret = 0;
 253        }
 254
 255err_entry:
 256        if (ret)
 257                debug("%s: Failed: %d\n", __func__, ret);
 258        return ret;
 259}
 260