blob: 0f1a64b26847a603fc92ccbd2e62ccc8206a7bd1 [file] [log] [blame]
Simon Glass428dfa42015-01-19 22:16:14 -07001/*
2 * From Coreboot src/southbridge/intel/bd82x6x/mrccache.c
3 *
4 * Copyright (C) 2014 Google Inc.
5 *
6 * SPDX-License-Identifier: GPL-2.0
7 */
8
9#include <common.h>
10#include <errno.h>
11#include <fdtdec.h>
12#include <net.h>
13#include <spi.h>
14#include <spi_flash.h>
15#include <asm/arch/mrccache.h>
16#include <asm/arch/sandybridge.h>
17
18static struct mrc_data_container *next_mrc_block(
19 struct mrc_data_container *mrc_cache)
20{
21 /* MRC data blocks are aligned within the region */
22 u32 mrc_size = sizeof(*mrc_cache) + mrc_cache->data_size;
23 if (mrc_size & (MRC_DATA_ALIGN - 1UL)) {
24 mrc_size &= ~(MRC_DATA_ALIGN - 1UL);
25 mrc_size += MRC_DATA_ALIGN;
26 }
27
28 u8 *region_ptr = (u8 *)mrc_cache;
29 region_ptr += mrc_size;
30 return (struct mrc_data_container *)region_ptr;
31}
32
33static int is_mrc_cache(struct mrc_data_container *cache)
34{
35 return cache && (cache->signature == MRC_DATA_SIGNATURE);
36}
37
38/*
39 * Find the largest index block in the MRC cache. Return NULL if none is
40 * found.
41 */
42struct mrc_data_container *mrccache_find_current(struct fmap_entry *entry)
43{
44 struct mrc_data_container *cache, *next;
45 ulong base_addr, end_addr;
46 uint id;
47
48 base_addr = (1ULL << 32) - CONFIG_ROM_SIZE + entry->offset;
49 end_addr = base_addr + entry->length;
50 cache = NULL;
51
52 /* Search for the last filled entry in the region */
53 for (id = 0, next = (struct mrc_data_container *)base_addr;
54 is_mrc_cache(next);
55 id++) {
56 cache = next;
57 next = next_mrc_block(next);
58 if ((ulong)next >= end_addr)
59 break;
60 }
61
62 if (id-- == 0) {
63 debug("%s: No valid MRC cache found.\n", __func__);
64 return NULL;
65 }
66
67 /* Verify checksum */
68 if (cache->checksum != compute_ip_checksum(cache->data,
69 cache->data_size)) {
70 printf("%s: MRC cache checksum mismatch\n", __func__);
71 return NULL;
72 }
73
74 debug("%s: picked entry %u from cache block\n", __func__, id);
75
76 return cache;
77}
78
79/**
80 * find_next_mrc_cache() - get next cache entry
81 *
82 * @entry: MRC cache flash area
83 * @cache: Entry to start from
84 *
85 * @return next cache entry if found, NULL if we got to the end
86 */
87static struct mrc_data_container *find_next_mrc_cache(struct fmap_entry *entry,
88 struct mrc_data_container *cache)
89{
90 ulong base_addr, end_addr;
91
92 base_addr = (1ULL << 32) - CONFIG_ROM_SIZE + entry->offset;
93 end_addr = base_addr + entry->length;
94
95 cache = next_mrc_block(cache);
96 if ((ulong)cache >= end_addr) {
97 /* Crossed the boundary */
98 cache = NULL;
99 debug("%s: no available entries found\n", __func__);
100 } else {
101 debug("%s: picked next entry from cache block at %p\n",
102 __func__, cache);
103 }
104
105 return cache;
106}
107
108int mrccache_update(struct spi_flash *sf, struct fmap_entry *entry,
109 struct mrc_data_container *cur)
110{
111 struct mrc_data_container *cache;
112 ulong offset;
113 ulong base_addr;
114 int ret;
115
116 /* Find the last used block */
117 base_addr = (1ULL << 32) - CONFIG_ROM_SIZE + entry->offset;
118 debug("Updating MRC cache data\n");
119 cache = mrccache_find_current(entry);
120 if (cache && (cache->data_size == cur->data_size) &&
121 (!memcmp(cache, cur, cache->data_size + sizeof(*cur)))) {
122 debug("MRC data in flash is up to date. No update\n");
123 return -EEXIST;
124 }
125
126 /* Move to the next block, which will be the first unused block */
127 if (cache)
128 cache = find_next_mrc_cache(entry, cache);
129
130 /*
131 * If we have got to the end, erase the entire mrc-cache area and start
132 * again at block 0.
133 */
134 if (!cache) {
135 debug("Erasing the MRC cache region of %x bytes at %x\n",
136 entry->length, entry->offset);
137
138 ret = spi_flash_erase(sf, entry->offset, entry->length);
139 if (ret) {
140 debug("Failed to erase flash region\n");
141 return ret;
142 }
143 cache = (struct mrc_data_container *)base_addr;
144 }
145
146 /* Write the data out */
147 offset = (ulong)cache - base_addr + entry->offset;
148 debug("Write MRC cache update to flash at %lx\n", offset);
149 ret = spi_flash_write(sf, offset, cur->data_size + sizeof(*cur), cur);
150 if (ret) {
151 debug("Failed to write to SPI flash\n");
152 return ret;
153 }
154
155 return 0;
156}