Merge branch 'master' of git://git.denx.de/u-boot-socfpga
[oweals/u-boot.git] / arch / x86 / lib / mrccache.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * From coreboot src/southbridge/intel/bd82x6x/mrccache.c
4  *
5  * Copyright (C) 2014 Google Inc.
6  * Copyright (C) 2015 Bin Meng <bmeng.cn@gmail.com>
7  */
8
9 #include <common.h>
10 #include <dm.h>
11 #include <errno.h>
12 #include <fdtdec.h>
13 #include <net.h>
14 #include <spi.h>
15 #include <spi_flash.h>
16 #include <asm/mrccache.h>
17
18 DECLARE_GLOBAL_DATA_PTR;
19
20 static uint mrc_block_size(uint data_size)
21 {
22         uint mrc_size = sizeof(struct mrc_data_container) + data_size;
23
24         return ALIGN(mrc_size, MRC_DATA_ALIGN);
25 }
26
27 static struct mrc_data_container *next_mrc_block(
28         struct mrc_data_container *cache)
29 {
30         /* MRC data blocks are aligned within the region */
31         u8 *region_ptr = (u8 *)cache;
32
33         region_ptr += mrc_block_size(cache->data_size);
34
35         return (struct mrc_data_container *)region_ptr;
36 }
37
38 static int is_mrc_cache(struct mrc_data_container *cache)
39 {
40         return cache && (cache->signature == MRC_DATA_SIGNATURE);
41 }
42
43 struct 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  */
88 static 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
109 int 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                 debug("%s: Cache data not valid\n", __func__);
119                 return -EINVAL;
120         }
121
122         /* Find the last used block */
123         base_addr = entry->base + entry->offset;
124         debug("Updating MRC cache data\n");
125         cache = mrccache_find_current(entry);
126         if (cache && (cache->data_size == cur->data_size) &&
127             (!memcmp(cache, cur, cache->data_size + sizeof(*cur)))) {
128                 debug("MRC data in flash is up to date. No update\n");
129                 return -EEXIST;
130         }
131
132         /* Move to the next block, which will be the first unused block */
133         if (cache)
134                 cache = find_next_mrc_cache(entry, cache);
135
136         /*
137          * If we have got to the end, erase the entire mrc-cache area and start
138          * again at block 0.
139          */
140         if (!cache) {
141                 debug("Erasing the MRC cache region of %x bytes at %x\n",
142                       entry->length, entry->offset);
143
144                 ret = spi_flash_erase_dm(sf, entry->offset, entry->length);
145                 if (ret) {
146                         debug("Failed to erase flash region\n");
147                         return ret;
148                 }
149                 cache = (struct mrc_data_container *)base_addr;
150         }
151
152         /* Write the data out */
153         offset = (ulong)cache - base_addr + entry->offset;
154         debug("Write MRC cache update to flash at %lx\n", offset);
155         ret = spi_flash_write_dm(sf, offset, cur->data_size + sizeof(*cur),
156                                  cur);
157         if (ret) {
158                 debug("Failed to write to SPI flash\n");
159                 return ret;
160         }
161
162         return 0;
163 }
164
165 static void mrccache_setup(void *data)
166 {
167         struct mrc_data_container *cache = data;
168         u16 checksum;
169
170         cache->signature = MRC_DATA_SIGNATURE;
171         cache->data_size = gd->arch.mrc_output_len;
172         checksum = compute_ip_checksum(gd->arch.mrc_output, cache->data_size);
173         debug("Saving %d bytes for MRC output data, checksum %04x\n",
174               cache->data_size, checksum);
175         cache->checksum = checksum;
176         cache->reserved = 0;
177         memcpy(cache->data, gd->arch.mrc_output, cache->data_size);
178
179         /* gd->arch.mrc_output now points to the container */
180         gd->arch.mrc_output = (char *)cache;
181 }
182
183 int mrccache_reserve(void)
184 {
185         if (!gd->arch.mrc_output_len)
186                 return 0;
187
188         /* adjust stack pointer to store pure cache data plus the header */
189         gd->start_addr_sp -= (gd->arch.mrc_output_len + MRC_DATA_HEADER_SIZE);
190         mrccache_setup((void *)gd->start_addr_sp);
191
192         gd->start_addr_sp &= ~0xf;
193
194         return 0;
195 }
196
197 int mrccache_get_region(struct udevice **devp, struct mrc_region *entry)
198 {
199         const void *blob = gd->fdt_blob;
200         int node, mrc_node;
201         u32 reg[2];
202         int ret;
203
204         /* Find the flash chip within the SPI controller node */
205         node = fdtdec_next_compatible(blob, 0, COMPAT_GENERIC_SPI_FLASH);
206         if (node < 0) {
207                 debug("%s: Cannot find SPI flash\n", __func__);
208                 return -ENOENT;
209         }
210
211         if (fdtdec_get_int_array(blob, node, "memory-map", reg, 2)) {
212                 debug("%s: Cannot find memory map\n", __func__);
213                 return -EINVAL;
214         }
215         entry->base = reg[0];
216
217         /* Find the place where we put the MRC cache */
218         mrc_node = fdt_subnode_offset(blob, node, "rw-mrc-cache");
219         if (mrc_node < 0) {
220                 debug("%s: Cannot find node\n", __func__);
221                 return -EPERM;
222         }
223
224         if (fdtdec_get_int_array(blob, mrc_node, "reg", reg, 2)) {
225                 debug("%s: Cannot find address\n", __func__);
226                 return -EINVAL;
227         }
228         entry->offset = reg[0];
229         entry->length = reg[1];
230
231         if (devp) {
232                 ret = uclass_get_device_by_of_offset(UCLASS_SPI_FLASH, node,
233                                                      devp);
234                 debug("ret = %d\n", ret);
235                 if (ret)
236                         return ret;
237         }
238
239         return 0;
240 }
241
242 int mrccache_save(void)
243 {
244         struct mrc_data_container *data;
245         struct mrc_region entry;
246         struct udevice *sf;
247         int ret;
248
249         if (!gd->arch.mrc_output_len)
250                 return 0;
251         debug("Saving %d bytes of MRC output data to SPI flash\n",
252               gd->arch.mrc_output_len);
253
254         ret = mrccache_get_region(&sf, &entry);
255         if (ret)
256                 goto err_entry;
257         data  = (struct mrc_data_container *)gd->arch.mrc_output;
258         ret = mrccache_update(sf, &entry, data);
259         if (!ret) {
260                 debug("Saved MRC data with checksum %04x\n", data->checksum);
261         } else if (ret == -EEXIST) {
262                 debug("MRC data is the same as last time, skipping save\n");
263                 ret = 0;
264         }
265
266 err_entry:
267         if (ret)
268                 debug("%s: Failed: %d\n", __func__, ret);
269         return ret;
270 }
271
272 int mrccache_spl_save(void)
273 {
274         void *data;
275         int size;
276
277         size = gd->arch.mrc_output_len + MRC_DATA_HEADER_SIZE;
278         data = malloc(size);
279         if (!data)
280                 return log_msg_ret("Allocate MRC cache block", -ENOMEM);
281         mrccache_setup(data);
282         gd->arch.mrc_output = data;
283
284         return mrccache_save();
285 }