+static int read_seed_from_cmos(struct pei_data *pei_data)
+{
+ u16 c1, c2, checksum, seed_checksum;
+ struct udevice *dev;
+ int ret = 0;
+
+ ret = uclass_get_device(UCLASS_RTC, 0, &dev);
+ if (ret) {
+ debug("Cannot find RTC: err=%d\n", ret);
+ return -ENODEV;
+ }
+
+ /*
+ * Read scrambler seeds from CMOS RAM. We don't want to store them in
+ * SPI flash since they change on every boot and that would wear down
+ * the flash too much. So we store these in CMOS and the large MRC
+ * data in SPI flash.
+ */
+ ret = rtc_read32(dev, CMOS_OFFSET_MRC_SEED, &pei_data->scrambler_seed);
+ if (!ret) {
+ ret = rtc_read32(dev, CMOS_OFFSET_MRC_SEED_S3,
+ &pei_data->scrambler_seed_s3);
+ }
+ if (ret) {
+ debug("Failed to read from RTC %s\n", dev->name);
+ return ret;
+ }
+
+ debug("Read scrambler seed 0x%08x from CMOS 0x%02x\n",
+ pei_data->scrambler_seed, CMOS_OFFSET_MRC_SEED);
+ debug("Read S3 scrambler seed 0x%08x from CMOS 0x%02x\n",
+ pei_data->scrambler_seed_s3, CMOS_OFFSET_MRC_SEED_S3);
+
+ /* Compute seed checksum and compare */
+ c1 = compute_ip_checksum((u8 *)&pei_data->scrambler_seed,
+ sizeof(u32));
+ c2 = compute_ip_checksum((u8 *)&pei_data->scrambler_seed_s3,
+ sizeof(u32));
+ checksum = add_ip_checksums(sizeof(u32), c1, c2);
+
+ seed_checksum = rtc_read8(dev, CMOS_OFFSET_MRC_SEED_CHK);
+ seed_checksum |= rtc_read8(dev, CMOS_OFFSET_MRC_SEED_CHK + 1) << 8;
+
+ if (checksum != seed_checksum) {
+ debug("%s: invalid seed checksum\n", __func__);
+ pei_data->scrambler_seed = 0;
+ pei_data->scrambler_seed_s3 = 0;
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int prepare_mrc_cache(struct pei_data *pei_data)
+{
+ struct mrc_data_container *mrc_cache;
+ struct mrc_region entry;
+ int ret;
+
+ ret = read_seed_from_cmos(pei_data);
+ if (ret)
+ return ret;
+ ret = mrccache_get_region(NULL, &entry);
+ if (ret)
+ return ret;
+ mrc_cache = mrccache_find_current(&entry);
+ if (!mrc_cache)
+ return -ENOENT;
+
+ pei_data->mrc_input = mrc_cache->data;
+ pei_data->mrc_input_len = mrc_cache->data_size;
+ debug("%s: at %p, size %x checksum %04x\n", __func__,
+ pei_data->mrc_input, pei_data->mrc_input_len,
+ mrc_cache->checksum);
+
+ return 0;
+}
+
+static int write_seeds_to_cmos(struct pei_data *pei_data)
+{
+ u16 c1, c2, checksum;
+ struct udevice *dev;
+ int ret = 0;
+
+ ret = uclass_get_device(UCLASS_RTC, 0, &dev);
+ if (ret) {
+ debug("Cannot find RTC: err=%d\n", ret);
+ return -ENODEV;
+ }
+
+ /* Save the MRC seed values to CMOS */
+ rtc_write32(dev, CMOS_OFFSET_MRC_SEED, pei_data->scrambler_seed);
+ debug("Save scrambler seed 0x%08x to CMOS 0x%02x\n",
+ pei_data->scrambler_seed, CMOS_OFFSET_MRC_SEED);
+
+ rtc_write32(dev, CMOS_OFFSET_MRC_SEED_S3, pei_data->scrambler_seed_s3);
+ debug("Save s3 scrambler seed 0x%08x to CMOS 0x%02x\n",
+ pei_data->scrambler_seed_s3, CMOS_OFFSET_MRC_SEED_S3);
+
+ /* Save a simple checksum of the seed values */
+ c1 = compute_ip_checksum((u8 *)&pei_data->scrambler_seed,
+ sizeof(u32));
+ c2 = compute_ip_checksum((u8 *)&pei_data->scrambler_seed_s3,
+ sizeof(u32));
+ checksum = add_ip_checksums(sizeof(u32), c1, c2);
+
+ rtc_write8(dev, CMOS_OFFSET_MRC_SEED_CHK, checksum & 0xff);
+ rtc_write8(dev, CMOS_OFFSET_MRC_SEED_CHK + 1, (checksum >> 8) & 0xff);
+
+ return 0;
+}
+
+/* Use this hook to save our SDRAM parameters */
+int misc_init_r(void)
+{
+ int ret;
+
+ ret = mrccache_save();
+ if (ret)
+ printf("Unable to save MRC data: %d\n", ret);
+
+ return 0;
+}
+