xref: /OK3568_Linux_fs/u-boot/arch/x86/lib/mrccache.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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