]> git.sur5r.net Git - u-boot/blob - arch/x86/cpu/ivybridge/mrccache.c
x86: Tidy up the 64-bit calling code
[u-boot] / arch / x86 / cpu / ivybridge / mrccache.c
1 /*
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
18 static 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
33 static 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  */
42 struct 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  */
87 static 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
108 int mrccache_update(struct udevice *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_dm(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_dm(sf, offset, cur->data_size + sizeof(*cur),
150                                  cur);
151         if (ret) {
152                 debug("Failed to write to SPI flash\n");
153                 return ret;
154         }
155
156         return 0;
157 }