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 19 DECLARE_GLOBAL_DATA_PTR; 20 21 static 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 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 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 163 int 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 192 int 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 return -ENOENT; 203 204 if (fdtdec_get_int_array(blob, node, "memory-map", reg, 2)) 205 return -FDT_ERR_NOTFOUND; 206 entry->base = reg[0]; 207 208 /* Find the place where we put the MRC cache */ 209 mrc_node = fdt_subnode_offset(blob, node, "rw-mrc-cache"); 210 if (mrc_node < 0) 211 return -EPERM; 212 213 if (fdtdec_get_int_array(blob, mrc_node, "reg", reg, 2)) 214 return -FDT_ERR_NOTFOUND; 215 entry->offset = reg[0]; 216 entry->length = reg[1]; 217 218 if (devp) { 219 ret = uclass_get_device_by_of_offset(UCLASS_SPI_FLASH, node, 220 devp); 221 debug("ret = %d\n", ret); 222 if (ret) 223 return ret; 224 } 225 226 return 0; 227 } 228 229 int mrccache_save(void) 230 { 231 struct mrc_data_container *data; 232 struct mrc_region entry; 233 struct udevice *sf; 234 int ret; 235 236 if (!gd->arch.mrc_output_len) 237 return 0; 238 debug("Saving %d bytes of MRC output data to SPI flash\n", 239 gd->arch.mrc_output_len); 240 241 ret = mrccache_get_region(&sf, &entry); 242 if (ret) 243 goto err_entry; 244 data = (struct mrc_data_container *)gd->arch.mrc_output; 245 ret = mrccache_update(sf, &entry, data); 246 if (!ret) { 247 debug("Saved MRC data with checksum %04x\n", data->checksum); 248 } else if (ret == -EEXIST) { 249 debug("MRC data is the same as last time, skipping save\n"); 250 ret = 0; 251 } 252 253 err_entry: 254 if (ret) 255 debug("%s: Failed: %d\n", __func__, ret); 256 return ret; 257 } 258