int mrccache_update(struct udevice *sf, struct mrc_region *entry, struct mrc_data_container *cur) { struct mrc_data_container *cache; ulong offset; ulong base_addr; int ret; if (!is_mrc_cache(cur)) return -EINVAL; /* Find the last used block */ base_addr = entry->base + entry->offset; debug("Updating MRC cache data\n"); cache = mrccache_find_current(entry); if (cache && (cache->data_size == cur->data_size) && (!memcmp(cache, cur, cache->data_size + sizeof(*cur)))) { debug("MRC data in flash is up to date. No update\n"); return -EEXIST; } /* Move to the next block, which will be the first unused block */ if (cache) cache = find_next_mrc_cache(entry, cache); /* * If we have got to the end, erase the entire mrc-cache area and start * again at block 0. */ if (!cache) { debug("Erasing the MRC cache region of %x bytes at %x\n", entry->length, entry->offset); ret = spi_flash_erase_dm(sf, entry->offset, entry->length); if (ret) { debug("Failed to erase flash region\n"); return ret; } cache = (struct mrc_data_container *)base_addr; } /* Write the data out */ offset = (ulong)cache - base_addr + entry->offset; debug("Write MRC cache update to flash at %lx\n", offset); ret = spi_flash_write_dm(sf, offset, cur->data_size + sizeof(*cur), cur); if (ret) { debug("Failed to write to SPI flash\n"); return ret; } return 0; }
static void update_mrc_cache(void *unused) { printk(BIOS_DEBUG, "Updating MRC cache data.\n"); struct mrc_data_container *current = cbmem_find(CBMEM_ID_MRCDATA); struct mrc_data_container *cache, *cache_base; u32 cache_size; if (!current) { printk(BIOS_ERR, "No MRC cache in cbmem. Can't update flash.\n"); return; } if (current->mrc_data_size == -1) { printk(BIOS_ERR, "MRC cache data in cbmem invalid.\n"); return; } cache_size = get_mrc_cache_region(&cache_base); if (cache_base == NULL) { printk(BIOS_ERR, "%s: could not find MRC cache area\n", __func__); return; } /* * we need to: */ // 0. compare MRC data to last mrc-cache block (exit if same) cache = find_current_mrc_cache_local(cache_base, cache_size); if (cache && (cache->mrc_data_size == current->mrc_data_size) && (memcmp(cache, current, cache->mrc_data_size) == 0)) { printk(BIOS_DEBUG, "MRC data in flash is up to date. No update.\n"); return; } // 1. use spi_flash_probe() to find the flash, then spi_init(); struct spi_flash *flash = spi_flash_probe(0, 0); if (!flash) { printk(BIOS_DEBUG, "Could not find SPI device\n"); return; } // 2. look up the first unused block if (cache) cache = find_next_mrc_cache(cache_base, cache, cache_size); /* * 3. if no such place exists, erase entire mrc-cache range & use * block 0. First time around the erase is not needed, but this is a * small overhead for simpler code. */ if (!cache) { printk(BIOS_DEBUG, "Need to erase the MRC cache region of %d bytes at %p\n", cache_size, cache_base); flash->erase(flash, to_flash_offset(flash, cache_base), cache_size); /* we will start at the beginning again */ cache = cache_base; } // 4. write mrc data with flash->write() printk(BIOS_DEBUG, "Finally: write MRC cache update to flash at %p\n", cache); flash->write(flash, to_flash_offset(flash, cache), current->mrc_data_size + sizeof(*current), current); }