1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * From coreboot src/southbridge/intel/bd82x6x/mrccache.c
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (C) 2014 Google Inc.
5*4882a593Smuzhiyun * Copyright (C) 2015 Bin Meng <bmeng.cn@gmail.com>
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include <common.h>
11*4882a593Smuzhiyun #include <dm.h>
12*4882a593Smuzhiyun #include <errno.h>
13*4882a593Smuzhiyun #include <fdtdec.h>
14*4882a593Smuzhiyun #include <net.h>
15*4882a593Smuzhiyun #include <spi.h>
16*4882a593Smuzhiyun #include <spi_flash.h>
17*4882a593Smuzhiyun #include <asm/mrccache.h>
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
20*4882a593Smuzhiyun
next_mrc_block(struct mrc_data_container * cache)21*4882a593Smuzhiyun static struct mrc_data_container *next_mrc_block(
22*4882a593Smuzhiyun struct mrc_data_container *cache)
23*4882a593Smuzhiyun {
24*4882a593Smuzhiyun /* MRC data blocks are aligned within the region */
25*4882a593Smuzhiyun u32 mrc_size = sizeof(*cache) + cache->data_size;
26*4882a593Smuzhiyun u8 *region_ptr = (u8 *)cache;
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun if (mrc_size & (MRC_DATA_ALIGN - 1UL)) {
29*4882a593Smuzhiyun mrc_size &= ~(MRC_DATA_ALIGN - 1UL);
30*4882a593Smuzhiyun mrc_size += MRC_DATA_ALIGN;
31*4882a593Smuzhiyun }
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun region_ptr += mrc_size;
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun return (struct mrc_data_container *)region_ptr;
36*4882a593Smuzhiyun }
37*4882a593Smuzhiyun
is_mrc_cache(struct mrc_data_container * cache)38*4882a593Smuzhiyun static int is_mrc_cache(struct mrc_data_container *cache)
39*4882a593Smuzhiyun {
40*4882a593Smuzhiyun return cache && (cache->signature == MRC_DATA_SIGNATURE);
41*4882a593Smuzhiyun }
42*4882a593Smuzhiyun
mrccache_find_current(struct mrc_region * entry)43*4882a593Smuzhiyun struct mrc_data_container *mrccache_find_current(struct mrc_region *entry)
44*4882a593Smuzhiyun {
45*4882a593Smuzhiyun struct mrc_data_container *cache, *next;
46*4882a593Smuzhiyun ulong base_addr, end_addr;
47*4882a593Smuzhiyun uint id;
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun base_addr = entry->base + entry->offset;
50*4882a593Smuzhiyun end_addr = base_addr + entry->length;
51*4882a593Smuzhiyun cache = NULL;
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun /* Search for the last filled entry in the region */
54*4882a593Smuzhiyun for (id = 0, next = (struct mrc_data_container *)base_addr;
55*4882a593Smuzhiyun is_mrc_cache(next);
56*4882a593Smuzhiyun id++) {
57*4882a593Smuzhiyun cache = next;
58*4882a593Smuzhiyun next = next_mrc_block(next);
59*4882a593Smuzhiyun if ((ulong)next >= end_addr)
60*4882a593Smuzhiyun break;
61*4882a593Smuzhiyun }
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun if (id-- == 0) {
64*4882a593Smuzhiyun debug("%s: No valid MRC cache found.\n", __func__);
65*4882a593Smuzhiyun return NULL;
66*4882a593Smuzhiyun }
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun /* Verify checksum */
69*4882a593Smuzhiyun if (cache->checksum != compute_ip_checksum(cache->data,
70*4882a593Smuzhiyun cache->data_size)) {
71*4882a593Smuzhiyun printf("%s: MRC cache checksum mismatch\n", __func__);
72*4882a593Smuzhiyun return NULL;
73*4882a593Smuzhiyun }
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun debug("%s: picked entry %u from cache block\n", __func__, id);
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun return cache;
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun /**
81*4882a593Smuzhiyun * find_next_mrc_cache() - get next cache entry
82*4882a593Smuzhiyun *
83*4882a593Smuzhiyun * @entry: MRC cache flash area
84*4882a593Smuzhiyun * @cache: Entry to start from
85*4882a593Smuzhiyun *
86*4882a593Smuzhiyun * @return next cache entry if found, NULL if we got to the end
87*4882a593Smuzhiyun */
find_next_mrc_cache(struct mrc_region * entry,struct mrc_data_container * cache)88*4882a593Smuzhiyun static struct mrc_data_container *find_next_mrc_cache(struct mrc_region *entry,
89*4882a593Smuzhiyun struct mrc_data_container *cache)
90*4882a593Smuzhiyun {
91*4882a593Smuzhiyun ulong base_addr, end_addr;
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun base_addr = entry->base + entry->offset;
94*4882a593Smuzhiyun end_addr = base_addr + entry->length;
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun cache = next_mrc_block(cache);
97*4882a593Smuzhiyun if ((ulong)cache >= end_addr) {
98*4882a593Smuzhiyun /* Crossed the boundary */
99*4882a593Smuzhiyun cache = NULL;
100*4882a593Smuzhiyun debug("%s: no available entries found\n", __func__);
101*4882a593Smuzhiyun } else {
102*4882a593Smuzhiyun debug("%s: picked next entry from cache block at %p\n",
103*4882a593Smuzhiyun __func__, cache);
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun return cache;
107*4882a593Smuzhiyun }
108*4882a593Smuzhiyun
mrccache_update(struct udevice * sf,struct mrc_region * entry,struct mrc_data_container * cur)109*4882a593Smuzhiyun int mrccache_update(struct udevice *sf, struct mrc_region *entry,
110*4882a593Smuzhiyun struct mrc_data_container *cur)
111*4882a593Smuzhiyun {
112*4882a593Smuzhiyun struct mrc_data_container *cache;
113*4882a593Smuzhiyun ulong offset;
114*4882a593Smuzhiyun ulong base_addr;
115*4882a593Smuzhiyun int ret;
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun if (!is_mrc_cache(cur))
118*4882a593Smuzhiyun return -EINVAL;
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun /* Find the last used block */
121*4882a593Smuzhiyun base_addr = entry->base + entry->offset;
122*4882a593Smuzhiyun debug("Updating MRC cache data\n");
123*4882a593Smuzhiyun cache = mrccache_find_current(entry);
124*4882a593Smuzhiyun if (cache && (cache->data_size == cur->data_size) &&
125*4882a593Smuzhiyun (!memcmp(cache, cur, cache->data_size + sizeof(*cur)))) {
126*4882a593Smuzhiyun debug("MRC data in flash is up to date. No update\n");
127*4882a593Smuzhiyun return -EEXIST;
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun /* Move to the next block, which will be the first unused block */
131*4882a593Smuzhiyun if (cache)
132*4882a593Smuzhiyun cache = find_next_mrc_cache(entry, cache);
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun /*
135*4882a593Smuzhiyun * If we have got to the end, erase the entire mrc-cache area and start
136*4882a593Smuzhiyun * again at block 0.
137*4882a593Smuzhiyun */
138*4882a593Smuzhiyun if (!cache) {
139*4882a593Smuzhiyun debug("Erasing the MRC cache region of %x bytes at %x\n",
140*4882a593Smuzhiyun entry->length, entry->offset);
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun ret = spi_flash_erase_dm(sf, entry->offset, entry->length);
143*4882a593Smuzhiyun if (ret) {
144*4882a593Smuzhiyun debug("Failed to erase flash region\n");
145*4882a593Smuzhiyun return ret;
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun cache = (struct mrc_data_container *)base_addr;
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun /* Write the data out */
151*4882a593Smuzhiyun offset = (ulong)cache - base_addr + entry->offset;
152*4882a593Smuzhiyun debug("Write MRC cache update to flash at %lx\n", offset);
153*4882a593Smuzhiyun ret = spi_flash_write_dm(sf, offset, cur->data_size + sizeof(*cur),
154*4882a593Smuzhiyun cur);
155*4882a593Smuzhiyun if (ret) {
156*4882a593Smuzhiyun debug("Failed to write to SPI flash\n");
157*4882a593Smuzhiyun return ret;
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun return 0;
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun
mrccache_reserve(void)163*4882a593Smuzhiyun int mrccache_reserve(void)
164*4882a593Smuzhiyun {
165*4882a593Smuzhiyun struct mrc_data_container *cache;
166*4882a593Smuzhiyun u16 checksum;
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun if (!gd->arch.mrc_output_len)
169*4882a593Smuzhiyun return 0;
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun /* adjust stack pointer to store pure cache data plus the header */
172*4882a593Smuzhiyun gd->start_addr_sp -= (gd->arch.mrc_output_len + MRC_DATA_HEADER_SIZE);
173*4882a593Smuzhiyun cache = (struct mrc_data_container *)gd->start_addr_sp;
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun cache->signature = MRC_DATA_SIGNATURE;
176*4882a593Smuzhiyun cache->data_size = gd->arch.mrc_output_len;
177*4882a593Smuzhiyun checksum = compute_ip_checksum(gd->arch.mrc_output, cache->data_size);
178*4882a593Smuzhiyun debug("Saving %d bytes for MRC output data, checksum %04x\n",
179*4882a593Smuzhiyun cache->data_size, checksum);
180*4882a593Smuzhiyun cache->checksum = checksum;
181*4882a593Smuzhiyun cache->reserved = 0;
182*4882a593Smuzhiyun memcpy(cache->data, gd->arch.mrc_output, cache->data_size);
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun /* gd->arch.mrc_output now points to the container */
185*4882a593Smuzhiyun gd->arch.mrc_output = (char *)cache;
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun gd->start_addr_sp &= ~0xf;
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun return 0;
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun
mrccache_get_region(struct udevice ** devp,struct mrc_region * entry)192*4882a593Smuzhiyun int mrccache_get_region(struct udevice **devp, struct mrc_region *entry)
193*4882a593Smuzhiyun {
194*4882a593Smuzhiyun const void *blob = gd->fdt_blob;
195*4882a593Smuzhiyun int node, mrc_node;
196*4882a593Smuzhiyun u32 reg[2];
197*4882a593Smuzhiyun int ret;
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun /* Find the flash chip within the SPI controller node */
200*4882a593Smuzhiyun node = fdtdec_next_compatible(blob, 0, COMPAT_GENERIC_SPI_FLASH);
201*4882a593Smuzhiyun if (node < 0) {
202*4882a593Smuzhiyun debug("%s: Cannot find SPI flash\n", __func__);
203*4882a593Smuzhiyun return -ENOENT;
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun if (fdtdec_get_int_array(blob, node, "memory-map", reg, 2))
207*4882a593Smuzhiyun return -EINVAL;
208*4882a593Smuzhiyun entry->base = reg[0];
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun /* Find the place where we put the MRC cache */
211*4882a593Smuzhiyun mrc_node = fdt_subnode_offset(blob, node, "rw-mrc-cache");
212*4882a593Smuzhiyun if (mrc_node < 0)
213*4882a593Smuzhiyun return -EPERM;
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun if (fdtdec_get_int_array(blob, mrc_node, "reg", reg, 2))
216*4882a593Smuzhiyun return -EINVAL;
217*4882a593Smuzhiyun entry->offset = reg[0];
218*4882a593Smuzhiyun entry->length = reg[1];
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun if (devp) {
221*4882a593Smuzhiyun ret = uclass_get_device_by_of_offset(UCLASS_SPI_FLASH, node,
222*4882a593Smuzhiyun devp);
223*4882a593Smuzhiyun debug("ret = %d\n", ret);
224*4882a593Smuzhiyun if (ret)
225*4882a593Smuzhiyun return ret;
226*4882a593Smuzhiyun }
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun return 0;
229*4882a593Smuzhiyun }
230*4882a593Smuzhiyun
mrccache_save(void)231*4882a593Smuzhiyun int mrccache_save(void)
232*4882a593Smuzhiyun {
233*4882a593Smuzhiyun struct mrc_data_container *data;
234*4882a593Smuzhiyun struct mrc_region entry;
235*4882a593Smuzhiyun struct udevice *sf;
236*4882a593Smuzhiyun int ret;
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun if (!gd->arch.mrc_output_len)
239*4882a593Smuzhiyun return 0;
240*4882a593Smuzhiyun debug("Saving %d bytes of MRC output data to SPI flash\n",
241*4882a593Smuzhiyun gd->arch.mrc_output_len);
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun ret = mrccache_get_region(&sf, &entry);
244*4882a593Smuzhiyun if (ret)
245*4882a593Smuzhiyun goto err_entry;
246*4882a593Smuzhiyun data = (struct mrc_data_container *)gd->arch.mrc_output;
247*4882a593Smuzhiyun ret = mrccache_update(sf, &entry, data);
248*4882a593Smuzhiyun if (!ret) {
249*4882a593Smuzhiyun debug("Saved MRC data with checksum %04x\n", data->checksum);
250*4882a593Smuzhiyun } else if (ret == -EEXIST) {
251*4882a593Smuzhiyun debug("MRC data is the same as last time, skipping save\n");
252*4882a593Smuzhiyun ret = 0;
253*4882a593Smuzhiyun }
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun err_entry:
256*4882a593Smuzhiyun if (ret)
257*4882a593Smuzhiyun debug("%s: Failed: %d\n", __func__, ret);
258*4882a593Smuzhiyun return ret;
259*4882a593Smuzhiyun }
260