xref: /OK3568_Linux_fs/u-boot/arch/arm/mach-rockchip/vendor.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * (C) Copyright 2008-2017 Fuzhou Rockchip Electronics Co., Ltd
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun #include <common.h>
8*4882a593Smuzhiyun #include <malloc.h>
9*4882a593Smuzhiyun #include <asm/arch/vendor.h>
10*4882a593Smuzhiyun #include <boot_rkimg.h>
11*4882a593Smuzhiyun #include <nand.h>
12*4882a593Smuzhiyun #include <part.h>
13*4882a593Smuzhiyun #include <fdt_support.h>
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun /* tag for vendor check */
16*4882a593Smuzhiyun #define VENDOR_TAG		0x524B5644
17*4882a593Smuzhiyun /* The Vendor partition contains the number of Vendor blocks */
18*4882a593Smuzhiyun #define MTD_VENDOR_PART_NUM	1
19*4882a593Smuzhiyun #define NAND_VENDOR_PART_NUM	2
20*4882a593Smuzhiyun #define VENDOR_PART_NUM		4
21*4882a593Smuzhiyun /* align to 64 bytes */
22*4882a593Smuzhiyun #define VENDOR_BTYE_ALIGN	0x3F
23*4882a593Smuzhiyun #define VENDOR_BLOCK_SIZE	512
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun #define PAGE_ALGIN_SIZE		(4096uL)
26*4882a593Smuzhiyun #define PAGE_ALGIN_MASK		(~(PAGE_ALGIN_SIZE - 1))
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun /* --- Emmc define --- */
29*4882a593Smuzhiyun /* Starting address of the Vendor in memory. */
30*4882a593Smuzhiyun #define EMMC_VENDOR_PART_OFFSET		(1024 * 7)
31*4882a593Smuzhiyun /*
32*4882a593Smuzhiyun  * The number of memory blocks used by each
33*4882a593Smuzhiyun  * Vendor structure(128 * 512B = 64KB)
34*4882a593Smuzhiyun  */
35*4882a593Smuzhiyun #define EMMC_VENDOR_PART_BLKS		128
36*4882a593Smuzhiyun /* The maximum number of items in each Vendor block */
37*4882a593Smuzhiyun #define EMMC_VENDOR_ITEM_NUM		126
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun /* --- Spi Nand/SLC/MLC large capacity case define --- */
40*4882a593Smuzhiyun /* The Vendor partition contains the number of Vendor blocks */
41*4882a593Smuzhiyun #define NAND_VENDOR_PART_OFFSET		0
42*4882a593Smuzhiyun /*
43*4882a593Smuzhiyun  * The number of memory blocks used by each
44*4882a593Smuzhiyun  * Vendor structure(8 * 512B = 4KB)
45*4882a593Smuzhiyun  */
46*4882a593Smuzhiyun #define NAND_VENDOR_PART_BLKS		128
47*4882a593Smuzhiyun /* The maximum number of items in each Vendor block */
48*4882a593Smuzhiyun #define NAND_VENDOR_ITEM_NUM		126
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun /* --- Spi/Spi Nand/SLC/MLC small capacity case define --- */
51*4882a593Smuzhiyun /* The Vendor partition contains the number of Vendor blocks */
52*4882a593Smuzhiyun #define	FLASH_VENDOR_PART_OFFSET	8
53*4882a593Smuzhiyun /*
54*4882a593Smuzhiyun  * The number of memory blocks used by each
55*4882a593Smuzhiyun  * Vendor structure(8 * 512B = 4KB)
56*4882a593Smuzhiyun  */
57*4882a593Smuzhiyun #define FLASH_VENDOR_PART_BLKS		8
58*4882a593Smuzhiyun /* The maximum number of items in each Vendor block */
59*4882a593Smuzhiyun #define FLASH_VENDOR_ITEM_NUM		62
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun /* Vendor uinit test define */
62*4882a593Smuzhiyun int vendor_storage_test(void);
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun struct vendor_hdr {
65*4882a593Smuzhiyun 	u32	tag;
66*4882a593Smuzhiyun 	u32	version;
67*4882a593Smuzhiyun 	u16	next_index;
68*4882a593Smuzhiyun 	u16	item_num;
69*4882a593Smuzhiyun 	u16	free_offset; /* Free space offset */
70*4882a593Smuzhiyun 	u16	free_size; /* Free space size */
71*4882a593Smuzhiyun };
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun /*
74*4882a593Smuzhiyun  * Different types of Flash vendor info are different.
75*4882a593Smuzhiyun  * EMMC:EMMC_VENDOR_PART_BLKS * BLOCK_SIZE(512) = 64KB;
76*4882a593Smuzhiyun  * Spi Nor/Spi Nand/SLC/MLC: FLASH_VENDOR_PART_BLKS *
77*4882a593Smuzhiyun  * BLOCK_SIZE(512) = 4KB.
78*4882a593Smuzhiyun  * hash: For future expansion.
79*4882a593Smuzhiyun  * version2: Together with hdr->version, it is used to
80*4882a593Smuzhiyun  * ensure the current Vendor block content integrity.
81*4882a593Smuzhiyun  *   (version2 == hdr->version):Data valid;
82*4882a593Smuzhiyun  *   (version2 != hdr->version):Data invalid.
83*4882a593Smuzhiyun  */
84*4882a593Smuzhiyun struct vendor_info {
85*4882a593Smuzhiyun 	struct vendor_hdr *hdr;
86*4882a593Smuzhiyun 	struct vendor_item *item;
87*4882a593Smuzhiyun 	u8 *data;
88*4882a593Smuzhiyun 	u32 *hash;
89*4882a593Smuzhiyun 	u32 *version2;
90*4882a593Smuzhiyun };
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun struct mtd_flash_info {
93*4882a593Smuzhiyun 	u32 part_offset;
94*4882a593Smuzhiyun 	u32 part_size;
95*4882a593Smuzhiyun 	u32 blk_offset;
96*4882a593Smuzhiyun 	u32 page_offset;
97*4882a593Smuzhiyun 	u32 version;
98*4882a593Smuzhiyun 	u32 ops_size;
99*4882a593Smuzhiyun 	u32 blk_size;
100*4882a593Smuzhiyun };
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun /*
103*4882a593Smuzhiyun  * Calculate the offset of each field for emmc.
104*4882a593Smuzhiyun  * Emmc vendor info size: 64KB
105*4882a593Smuzhiyun  */
106*4882a593Smuzhiyun #define EMMC_VENDOR_INFO_SIZE	(EMMC_VENDOR_PART_BLKS * VENDOR_BLOCK_SIZE)
107*4882a593Smuzhiyun #define EMMC_VENDOR_DATA_OFFSET	(sizeof(struct vendor_hdr) + EMMC_VENDOR_ITEM_NUM * sizeof(struct vendor_item))
108*4882a593Smuzhiyun #define EMMC_VENDOR_HASH_OFFSET (EMMC_VENDOR_INFO_SIZE - 8)
109*4882a593Smuzhiyun #define EMMC_VENDOR_VERSION2_OFFSET (EMMC_VENDOR_INFO_SIZE - 4)
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun /*
112*4882a593Smuzhiyun  * Calculate the offset of each field for spi nand/slc/mlc large capacity case.
113*4882a593Smuzhiyun  * Flash vendor info size: 4KB
114*4882a593Smuzhiyun  */
115*4882a593Smuzhiyun #define NAND_VENDOR_INFO_SIZE	(NAND_VENDOR_PART_BLKS * VENDOR_BLOCK_SIZE)
116*4882a593Smuzhiyun #define NAND_VENDOR_DATA_OFFSET	(sizeof(struct vendor_hdr) + NAND_VENDOR_ITEM_NUM * sizeof(struct vendor_item))
117*4882a593Smuzhiyun #define NAND_VENDOR_HASH_OFFSET (NAND_VENDOR_INFO_SIZE - 8)
118*4882a593Smuzhiyun #define NAND_VENDOR_VERSION2_OFFSET (NAND_VENDOR_INFO_SIZE - 4)
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun /*
121*4882a593Smuzhiyun  * Calculate the offset of each field for spi nor/spi nand/slc/mlc large small capacity case.
122*4882a593Smuzhiyun  * Flash vendor info size: 4KB
123*4882a593Smuzhiyun  */
124*4882a593Smuzhiyun #define FLASH_VENDOR_INFO_SIZE	(FLASH_VENDOR_PART_BLKS * VENDOR_BLOCK_SIZE)
125*4882a593Smuzhiyun #define FLASH_VENDOR_DATA_OFFSET (sizeof(struct vendor_hdr) + FLASH_VENDOR_ITEM_NUM * sizeof(struct vendor_item))
126*4882a593Smuzhiyun #define FLASH_VENDOR_HASH_OFFSET (FLASH_VENDOR_INFO_SIZE - 8)
127*4882a593Smuzhiyun #define FLASH_VENDOR_VERSION2_OFFSET (FLASH_VENDOR_INFO_SIZE - 4)
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun /* vendor info */
130*4882a593Smuzhiyun static struct vendor_info vendor_info;
131*4882a593Smuzhiyun /* The storage type of the device */
132*4882a593Smuzhiyun static int bootdev_type;
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun #ifdef CONFIG_MTD_BLK
135*4882a593Smuzhiyun static struct mtd_flash_info s_flash_info;
136*4882a593Smuzhiyun static const char *vendor_mtd_name = "vnvm";
137*4882a593Smuzhiyun #endif
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun /* vendor private read write ops*/
140*4882a593Smuzhiyun static	int (*_flash_read)(struct blk_desc *dev_desc,
141*4882a593Smuzhiyun 			   u32 sec,
142*4882a593Smuzhiyun 			   u32 n_sec,
143*4882a593Smuzhiyun 			   void *buffer);
144*4882a593Smuzhiyun static	int (*_flash_write)(struct blk_desc *dev_desc,
145*4882a593Smuzhiyun 			    u32 sec,
146*4882a593Smuzhiyun 			    u32 n_sec,
147*4882a593Smuzhiyun 			    void *buffer);
148*4882a593Smuzhiyun 
flash_vendor_dev_ops_register(int (* read)(struct blk_desc * dev_desc,u32 sec,u32 n_sec,void * p_data),int (* write)(struct blk_desc * dev_desc,u32 sec,u32 n_sec,void * p_data))149*4882a593Smuzhiyun int flash_vendor_dev_ops_register(int (*read)(struct blk_desc *dev_desc,
150*4882a593Smuzhiyun 					      u32 sec,
151*4882a593Smuzhiyun 					      u32 n_sec,
152*4882a593Smuzhiyun 					      void *p_data),
153*4882a593Smuzhiyun 				  int (*write)(struct blk_desc *dev_desc,
154*4882a593Smuzhiyun 					       u32 sec,
155*4882a593Smuzhiyun 					       u32 n_sec,
156*4882a593Smuzhiyun 					       void *p_data))
157*4882a593Smuzhiyun {
158*4882a593Smuzhiyun 	if (!_flash_read) {
159*4882a593Smuzhiyun 		_flash_read = read;
160*4882a593Smuzhiyun 		_flash_write = write;
161*4882a593Smuzhiyun 		return 0;
162*4882a593Smuzhiyun 	}
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	return -EPERM;
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun #ifdef CONFIG_MTD_BLK
mtd_vendor_storage_init(struct blk_desc * dev_desc)168*4882a593Smuzhiyun static int mtd_vendor_storage_init(struct blk_desc *dev_desc)
169*4882a593Smuzhiyun {
170*4882a593Smuzhiyun 	struct mtd_info *mtd = (struct mtd_info *)dev_desc->bdev->priv;
171*4882a593Smuzhiyun 	disk_partition_t vnvm_part_info;
172*4882a593Smuzhiyun 	void *buf = vendor_info.hdr;
173*4882a593Smuzhiyun 	int ret, offset;
174*4882a593Smuzhiyun 	int part_num, bad_block_size;
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	memset(&vnvm_part_info, 0x0, sizeof(vnvm_part_info));
177*4882a593Smuzhiyun 	part_num = part_get_info_by_name(dev_desc, vendor_mtd_name, &vnvm_part_info);
178*4882a593Smuzhiyun 	if (part_num < 0)
179*4882a593Smuzhiyun 		return -EIO;
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	s_flash_info.part_offset = (u32)vnvm_part_info.start;
182*4882a593Smuzhiyun 	s_flash_info.part_size = (u32)vnvm_part_info.size;
183*4882a593Smuzhiyun 	s_flash_info.page_offset = 0;
184*4882a593Smuzhiyun 	s_flash_info.blk_offset = 0;
185*4882a593Smuzhiyun 	s_flash_info.version = 0;
186*4882a593Smuzhiyun 	/* SPI Nor unified to Support 64KB erase block */
187*4882a593Smuzhiyun 	if (dev_desc->devnum == BLK_MTD_SPI_NOR)
188*4882a593Smuzhiyun 		s_flash_info.blk_size = 0x80;
189*4882a593Smuzhiyun 	else
190*4882a593Smuzhiyun 		s_flash_info.blk_size = mtd->erasesize >> 9;
191*4882a593Smuzhiyun 	s_flash_info.ops_size = roundup(FLASH_VENDOR_INFO_SIZE, mtd->writesize) >> 9;
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 	/* scan bad block and calculate the real size can be used */
194*4882a593Smuzhiyun 	bad_block_size = 0;
195*4882a593Smuzhiyun 	for (offset = 0; offset < s_flash_info.part_size; offset += s_flash_info.blk_size) {
196*4882a593Smuzhiyun 		if (mtd_block_isbad(mtd, (s_flash_info.part_offset + offset) << 9))
197*4882a593Smuzhiyun 			bad_block_size += s_flash_info.blk_size;
198*4882a593Smuzhiyun 	}
199*4882a593Smuzhiyun 	s_flash_info.part_size -= bad_block_size;
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	for (offset = 0; offset < s_flash_info.part_size; offset += s_flash_info.blk_size) {
202*4882a593Smuzhiyun 		ret = blk_dread(dev_desc, s_flash_info.part_offset + offset,
203*4882a593Smuzhiyun 				FLASH_VENDOR_INFO_SIZE >> 9,
204*4882a593Smuzhiyun 				(u8 *)buf);
205*4882a593Smuzhiyun 		debug("%s: read %x version = %x\n", __func__,
206*4882a593Smuzhiyun 		      s_flash_info.part_offset + offset,
207*4882a593Smuzhiyun 		      vendor_info.hdr->version);
208*4882a593Smuzhiyun 		if (ret == (FLASH_VENDOR_INFO_SIZE >> 9) && vendor_info.hdr->tag == VENDOR_TAG &&
209*4882a593Smuzhiyun 		    vendor_info.hdr->version == *vendor_info.version2) {
210*4882a593Smuzhiyun 			if (vendor_info.hdr->version > s_flash_info.version) {
211*4882a593Smuzhiyun 				s_flash_info.version = vendor_info.hdr->version;
212*4882a593Smuzhiyun 				s_flash_info.blk_offset = offset;
213*4882a593Smuzhiyun 			}
214*4882a593Smuzhiyun 		}
215*4882a593Smuzhiyun 	}
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun 	debug("%s: s_flash_info.version = %x %x\n", __func__, s_flash_info.version, s_flash_info.blk_offset);
218*4882a593Smuzhiyun 	if (s_flash_info.version) {
219*4882a593Smuzhiyun 		for (offset = s_flash_info.blk_size  - s_flash_info.ops_size;
220*4882a593Smuzhiyun 		     offset >= 0;
221*4882a593Smuzhiyun 		     offset -= s_flash_info.ops_size) {
222*4882a593Smuzhiyun 			ret = blk_dread(dev_desc, s_flash_info.part_offset +
223*4882a593Smuzhiyun 					s_flash_info.blk_offset + offset,
224*4882a593Smuzhiyun 					1,
225*4882a593Smuzhiyun 					(u8 *)buf);
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 			/* the page is not programmed */
228*4882a593Smuzhiyun 			if (ret == 1 && vendor_info.hdr->tag == 0xFFFFFFFF)
229*4882a593Smuzhiyun 				continue;
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 			/* point to the next free page */
232*4882a593Smuzhiyun 			if (s_flash_info.page_offset < offset)
233*4882a593Smuzhiyun 				s_flash_info.page_offset = offset + s_flash_info.ops_size;
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun 			if (ret != 1 || vendor_info.hdr->tag != VENDOR_TAG)
236*4882a593Smuzhiyun 				continue;
237*4882a593Smuzhiyun 			ret = blk_dread(dev_desc, s_flash_info.part_offset +
238*4882a593Smuzhiyun 					s_flash_info.blk_offset + offset,
239*4882a593Smuzhiyun 					FLASH_VENDOR_INFO_SIZE >> 9,
240*4882a593Smuzhiyun 					(u8 *)buf);
241*4882a593Smuzhiyun 			debug("%s: read %x version = %x\n", __func__,
242*4882a593Smuzhiyun 			      s_flash_info.part_offset + s_flash_info.blk_offset  + offset,
243*4882a593Smuzhiyun 			      vendor_info.hdr->version);
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 			if (ret == (FLASH_VENDOR_INFO_SIZE >> 9)  && vendor_info.hdr->tag == VENDOR_TAG &&
246*4882a593Smuzhiyun 			    vendor_info.hdr->version == *vendor_info.version2) {
247*4882a593Smuzhiyun 				s_flash_info.version = vendor_info.hdr->version;
248*4882a593Smuzhiyun 				break;
249*4882a593Smuzhiyun 			}
250*4882a593Smuzhiyun 		}
251*4882a593Smuzhiyun 	} else {
252*4882a593Smuzhiyun 		memset((u8 *)vendor_info.hdr, 0, FLASH_VENDOR_INFO_SIZE);
253*4882a593Smuzhiyun 		vendor_info.hdr->version = 1;
254*4882a593Smuzhiyun 		vendor_info.hdr->tag = VENDOR_TAG;
255*4882a593Smuzhiyun 		vendor_info.hdr->free_size =
256*4882a593Smuzhiyun 			((u32)(size_t)vendor_info.hash
257*4882a593Smuzhiyun 			- (u32)(size_t)vendor_info.data);
258*4882a593Smuzhiyun 		*vendor_info.version2 = vendor_info.hdr->version;
259*4882a593Smuzhiyun 	}
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 	return 0;
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun 
mtd_vendor_write(struct blk_desc * dev_desc,u32 sec,u32 n_sec,void * buf)264*4882a593Smuzhiyun static int mtd_vendor_write(struct blk_desc *dev_desc,
265*4882a593Smuzhiyun 			    u32 sec,
266*4882a593Smuzhiyun 			    u32 n_sec,
267*4882a593Smuzhiyun 			    void *buf)
268*4882a593Smuzhiyun {
269*4882a593Smuzhiyun 	int ret, count = 0, err = 0;
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun re_write:
272*4882a593Smuzhiyun 	debug("[Vendor INFO]:%s page_offset=0x%x count = %x\n", __func__, s_flash_info.part_offset +
273*4882a593Smuzhiyun 	      s_flash_info.blk_offset + s_flash_info.page_offset, count);
274*4882a593Smuzhiyun 	if (s_flash_info.page_offset >= s_flash_info.blk_size) {
275*4882a593Smuzhiyun 		s_flash_info.blk_offset += s_flash_info.blk_size;
276*4882a593Smuzhiyun 		if (s_flash_info.blk_offset >= s_flash_info.part_size)
277*4882a593Smuzhiyun 			s_flash_info.blk_offset = 0;
278*4882a593Smuzhiyun 		s_flash_info.page_offset = 0;
279*4882a593Smuzhiyun 		/*
280*4882a593Smuzhiyun 		 * The spi NOR driver only erase 4KB while write data, and here need to
281*4882a593Smuzhiyun 		 * erase one block for vendor storage request.
282*4882a593Smuzhiyun 		 */
283*4882a593Smuzhiyun 		blk_derase(dev_desc, s_flash_info.part_offset + s_flash_info.blk_offset, s_flash_info.blk_size);
284*4882a593Smuzhiyun 	}
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 	dev_desc->op_flag |= BLK_MTD_CONT_WRITE;
287*4882a593Smuzhiyun 	ret = blk_dwrite(dev_desc, s_flash_info.part_offset +
288*4882a593Smuzhiyun 			 s_flash_info.blk_offset + s_flash_info.page_offset,
289*4882a593Smuzhiyun 			 FLASH_VENDOR_INFO_SIZE >> 9,
290*4882a593Smuzhiyun 			 (u8 *)buf);
291*4882a593Smuzhiyun 	dev_desc->op_flag &= ~(BLK_MTD_CONT_WRITE);
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 	s_flash_info.page_offset += s_flash_info.ops_size;
294*4882a593Smuzhiyun 	if (ret != (FLASH_VENDOR_INFO_SIZE >> 9)) {
295*4882a593Smuzhiyun 		err++;
296*4882a593Smuzhiyun 		if (err > 3)
297*4882a593Smuzhiyun 			return -EIO;
298*4882a593Smuzhiyun 		goto re_write;
299*4882a593Smuzhiyun 	}
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 	count++;
302*4882a593Smuzhiyun 	/* write 2 copies for reliability */
303*4882a593Smuzhiyun 	if (count < 2)
304*4882a593Smuzhiyun 		goto re_write;
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun 	return ret;
307*4882a593Smuzhiyun }
308*4882a593Smuzhiyun #endif
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun /**********************************************************/
311*4882a593Smuzhiyun /*              vendor API implementation                 */
312*4882a593Smuzhiyun /**********************************************************/
vendor_ops(u8 * buffer,u32 addr,u32 n_sec,int write)313*4882a593Smuzhiyun static int vendor_ops(u8 *buffer, u32 addr, u32 n_sec, int write)
314*4882a593Smuzhiyun {
315*4882a593Smuzhiyun 	struct blk_desc *dev_desc;
316*4882a593Smuzhiyun 	unsigned int lba = 0;
317*4882a593Smuzhiyun 	int ret = 0;
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun 	dev_desc = rockchip_get_bootdev();
320*4882a593Smuzhiyun 	if (!dev_desc) {
321*4882a593Smuzhiyun 		printf("%s: dev_desc is NULL!\n", __func__);
322*4882a593Smuzhiyun 		return -ENODEV;
323*4882a593Smuzhiyun 	}
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun 	if (dev_desc->if_type == IF_TYPE_NVME || dev_desc->if_type == IF_TYPE_SCSI) {
326*4882a593Smuzhiyun 		dev_desc = blk_get_devnum_by_type(IF_TYPE_MTD, BLK_MTD_SPI_NOR);
327*4882a593Smuzhiyun 		if (!dev_desc) {
328*4882a593Smuzhiyun 			printf("%s: dev_desc is NULL!\n", __func__);
329*4882a593Smuzhiyun 			return -ENODEV;
330*4882a593Smuzhiyun 		}
331*4882a593Smuzhiyun 	}
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun 	/* Get the offset address according to the device type */
334*4882a593Smuzhiyun 	switch (dev_desc->if_type) {
335*4882a593Smuzhiyun 	case IF_TYPE_MMC:
336*4882a593Smuzhiyun 		/*
337*4882a593Smuzhiyun 		 * The location of VendorStorage in Flash is shown in the
338*4882a593Smuzhiyun 		 * following figure. The starting address of the VendorStorage
339*4882a593Smuzhiyun 		 * partition offset is 3.5MB(EMMC_VENDOR_PART_OFFSET*BLOCK_SIZE(512)),
340*4882a593Smuzhiyun 		 * and the partition size is 256KB.
341*4882a593Smuzhiyun 		 * ----------------------------------------------------
342*4882a593Smuzhiyun 		 * |   3.5MB    |  VendorStorage  |                   |
343*4882a593Smuzhiyun 		 * ----------------------------------------------------
344*4882a593Smuzhiyun 		 */
345*4882a593Smuzhiyun 		lba = EMMC_VENDOR_PART_OFFSET;
346*4882a593Smuzhiyun 		debug("[Vendor INFO]:VendorStorage offset address=0x%x\n", lba);
347*4882a593Smuzhiyun 		break;
348*4882a593Smuzhiyun 	case IF_TYPE_RKNAND:
349*4882a593Smuzhiyun 	case IF_TYPE_SPINAND:
350*4882a593Smuzhiyun 		/*
351*4882a593Smuzhiyun 		 * The location of VendorStorage in Flash is shown in the
352*4882a593Smuzhiyun 		 * following figure. The starting address of the VendorStorage
353*4882a593Smuzhiyun 		 * partition offset is 0KB in FTL vendor block,
354*4882a593Smuzhiyun 		 * and the partition size is 128KB.
355*4882a593Smuzhiyun 		 * ----------------------------------------------------
356*4882a593Smuzhiyun 		 * |  VendorStorage  |                     |
357*4882a593Smuzhiyun 		 * ----------------------------------------------------
358*4882a593Smuzhiyun 		 */
359*4882a593Smuzhiyun 		lba = NAND_VENDOR_PART_OFFSET;
360*4882a593Smuzhiyun 		debug("[Vendor INFO]:VendorStorage offset address=0x%x\n", lba);
361*4882a593Smuzhiyun 		break;
362*4882a593Smuzhiyun 	case IF_TYPE_SPINOR:
363*4882a593Smuzhiyun 		/*
364*4882a593Smuzhiyun 		 * The location of VendorStorage in Flash is shown in the
365*4882a593Smuzhiyun 		 * following figure. The starting address of the VendorStorage
366*4882a593Smuzhiyun 		 * partition offset is 4KB (FLASH_VENDOR_PART_OFFSET * BLOCK_SIZE),
367*4882a593Smuzhiyun 		 * and the partition size is 16KB.
368*4882a593Smuzhiyun 		 * ----------------------------------------------------
369*4882a593Smuzhiyun 		 * |   4KB    |  VendorStorage  |                     |
370*4882a593Smuzhiyun 		 * ----------------------------------------------------
371*4882a593Smuzhiyun 		 */
372*4882a593Smuzhiyun 		lba = FLASH_VENDOR_PART_OFFSET;
373*4882a593Smuzhiyun 		debug("[Vendor INFO]:VendorStorage offset address=0x%x\n", lba);
374*4882a593Smuzhiyun 		break;
375*4882a593Smuzhiyun #ifdef CONFIG_MTD_BLK
376*4882a593Smuzhiyun 	case IF_TYPE_MTD:
377*4882a593Smuzhiyun 		/*
378*4882a593Smuzhiyun 		 * The location of VendorStorage in NAND FLASH or SPI NAND partition "vnvm"
379*4882a593Smuzhiyun 		 * is shown in the following figure. The partition size is at least  4
380*4882a593Smuzhiyun 		 * NAND FLASH blocks.
381*4882a593Smuzhiyun 		 * ----------------------------------------------------
382*4882a593Smuzhiyun 		 * |   .....    |  vnvm  |  .......                   |
383*4882a593Smuzhiyun 		 * ----------------------------------------------------
384*4882a593Smuzhiyun 		 */
385*4882a593Smuzhiyun 		lba = 0;
386*4882a593Smuzhiyun 		break;
387*4882a593Smuzhiyun #endif
388*4882a593Smuzhiyun 	default:
389*4882a593Smuzhiyun 		printf("[Vendor ERROR]:Boot device type is invalid!\n");
390*4882a593Smuzhiyun 		return -ENODEV;
391*4882a593Smuzhiyun 	}
392*4882a593Smuzhiyun 	if (write) {
393*4882a593Smuzhiyun 		if (_flash_write)
394*4882a593Smuzhiyun 			ret = _flash_write(dev_desc, lba + addr, n_sec, buffer);
395*4882a593Smuzhiyun 		else
396*4882a593Smuzhiyun 			ret = blk_dwrite(dev_desc, lba + addr, n_sec, buffer);
397*4882a593Smuzhiyun 	} else {
398*4882a593Smuzhiyun 		if (_flash_read)
399*4882a593Smuzhiyun 			ret = _flash_read(dev_desc, lba + addr, n_sec, buffer);
400*4882a593Smuzhiyun 		else
401*4882a593Smuzhiyun 			ret = blk_dread(dev_desc, lba + addr, n_sec, buffer);
402*4882a593Smuzhiyun 	}
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 	debug("[Vendor INFO]:op=%s, ret=%d\n", write ? "write" : "read", ret);
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun 	return ret;
407*4882a593Smuzhiyun }
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun /*
410*4882a593Smuzhiyun  * The VendorStorage partition is divided into four parts
411*4882a593Smuzhiyun  * (vendor 0-3) and its structure is shown in the following figure.
412*4882a593Smuzhiyun  * The init function is used to select the latest and valid vendor.
413*4882a593Smuzhiyun  *
414*4882a593Smuzhiyun  * |******************** FLASH ********************|
415*4882a593Smuzhiyun  * -------------------------------------------------
416*4882a593Smuzhiyun  * |  vendor0  |  vendor1  |  vendor2  |  vendor3  |
417*4882a593Smuzhiyun  * -------------------------------------------------
418*4882a593Smuzhiyun  * Notices:
419*4882a593Smuzhiyun  *   1. "version" and "version2" are used to verify that the vendor
420*4882a593Smuzhiyun  *      is valid (equal is valid).
421*4882a593Smuzhiyun  *   2. the "version" value is larger, indicating that the current
422*4882a593Smuzhiyun  *      verndor data is new.
423*4882a593Smuzhiyun  */
vendor_storage_init(void)424*4882a593Smuzhiyun int vendor_storage_init(void)
425*4882a593Smuzhiyun {
426*4882a593Smuzhiyun 	int ret = 0;
427*4882a593Smuzhiyun 	int ret_size;
428*4882a593Smuzhiyun 	u8 *buffer;
429*4882a593Smuzhiyun 	u32 size, i;
430*4882a593Smuzhiyun 	u32 max_ver = 0;
431*4882a593Smuzhiyun 	u32 max_index = 0;
432*4882a593Smuzhiyun 	u16 data_offset, hash_offset, part_num;
433*4882a593Smuzhiyun 	u16 version2_offset, part_size;
434*4882a593Smuzhiyun 	struct blk_desc *dev_desc;
435*4882a593Smuzhiyun 
436*4882a593Smuzhiyun 	dev_desc = rockchip_get_bootdev();
437*4882a593Smuzhiyun 	if (!dev_desc) {
438*4882a593Smuzhiyun 		printf("[Vendor ERROR]:Invalid boot device type(%d)\n",
439*4882a593Smuzhiyun 		       bootdev_type);
440*4882a593Smuzhiyun 		return -ENODEV;
441*4882a593Smuzhiyun 	}
442*4882a593Smuzhiyun 
443*4882a593Smuzhiyun 	if (dev_desc->if_type == IF_TYPE_NVME || dev_desc->if_type == IF_TYPE_SCSI) {
444*4882a593Smuzhiyun 		dev_desc = blk_get_devnum_by_type(IF_TYPE_MTD, BLK_MTD_SPI_NOR);
445*4882a593Smuzhiyun 		if (!dev_desc) {
446*4882a593Smuzhiyun 			printf("%s: dev_desc is NULL!\n", __func__);
447*4882a593Smuzhiyun 			return -ENODEV;
448*4882a593Smuzhiyun 		}
449*4882a593Smuzhiyun 	}
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 	switch (dev_desc->if_type) {
452*4882a593Smuzhiyun 	case IF_TYPE_MMC:
453*4882a593Smuzhiyun 		size = EMMC_VENDOR_INFO_SIZE;
454*4882a593Smuzhiyun 		part_size = EMMC_VENDOR_PART_BLKS;
455*4882a593Smuzhiyun 		data_offset = EMMC_VENDOR_DATA_OFFSET;
456*4882a593Smuzhiyun 		hash_offset = EMMC_VENDOR_HASH_OFFSET;
457*4882a593Smuzhiyun 		version2_offset = EMMC_VENDOR_VERSION2_OFFSET;
458*4882a593Smuzhiyun 		part_num = VENDOR_PART_NUM;
459*4882a593Smuzhiyun 		break;
460*4882a593Smuzhiyun 	case IF_TYPE_RKNAND:
461*4882a593Smuzhiyun 	case IF_TYPE_SPINAND:
462*4882a593Smuzhiyun 		size = NAND_VENDOR_INFO_SIZE;
463*4882a593Smuzhiyun 		part_size = NAND_VENDOR_PART_BLKS;
464*4882a593Smuzhiyun 		data_offset = NAND_VENDOR_DATA_OFFSET;
465*4882a593Smuzhiyun 		hash_offset = NAND_VENDOR_HASH_OFFSET;
466*4882a593Smuzhiyun 		version2_offset = NAND_VENDOR_VERSION2_OFFSET;
467*4882a593Smuzhiyun 		part_num = NAND_VENDOR_PART_NUM;
468*4882a593Smuzhiyun 		break;
469*4882a593Smuzhiyun 	case IF_TYPE_SPINOR:
470*4882a593Smuzhiyun 		size = FLASH_VENDOR_INFO_SIZE;
471*4882a593Smuzhiyun 		part_size = FLASH_VENDOR_PART_BLKS;
472*4882a593Smuzhiyun 		data_offset = FLASH_VENDOR_DATA_OFFSET;
473*4882a593Smuzhiyun 		hash_offset = FLASH_VENDOR_HASH_OFFSET;
474*4882a593Smuzhiyun 		version2_offset = FLASH_VENDOR_VERSION2_OFFSET;
475*4882a593Smuzhiyun 		part_num = VENDOR_PART_NUM;
476*4882a593Smuzhiyun 		break;
477*4882a593Smuzhiyun #ifdef CONFIG_MTD_BLK
478*4882a593Smuzhiyun 	case IF_TYPE_MTD:
479*4882a593Smuzhiyun 		size = FLASH_VENDOR_INFO_SIZE;
480*4882a593Smuzhiyun 		part_size = FLASH_VENDOR_PART_BLKS;
481*4882a593Smuzhiyun 		data_offset = FLASH_VENDOR_DATA_OFFSET;
482*4882a593Smuzhiyun 		hash_offset = FLASH_VENDOR_HASH_OFFSET;
483*4882a593Smuzhiyun 		version2_offset = FLASH_VENDOR_VERSION2_OFFSET;
484*4882a593Smuzhiyun 		part_num = MTD_VENDOR_PART_NUM;
485*4882a593Smuzhiyun 		_flash_write = mtd_vendor_write;
486*4882a593Smuzhiyun 		break;
487*4882a593Smuzhiyun #endif
488*4882a593Smuzhiyun 	default:
489*4882a593Smuzhiyun 		debug("[Vendor ERROR]:Boot device type is invalid!\n");
490*4882a593Smuzhiyun 		ret = -ENODEV;
491*4882a593Smuzhiyun 		break;
492*4882a593Smuzhiyun 	}
493*4882a593Smuzhiyun 	/* Invalid bootdev type */
494*4882a593Smuzhiyun 	if (ret)
495*4882a593Smuzhiyun 		return ret;
496*4882a593Smuzhiyun 
497*4882a593Smuzhiyun 	/* Initialize */
498*4882a593Smuzhiyun 	bootdev_type = dev_desc->if_type;
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun 	/* Always use, no need to release, align to page size for kerenl reserved memory */
501*4882a593Smuzhiyun 	buffer = (u8 *)memalign(PAGE_ALGIN_SIZE, size);
502*4882a593Smuzhiyun 	if (!buffer) {
503*4882a593Smuzhiyun 		printf("[Vendor ERROR]:Malloc failed!\n");
504*4882a593Smuzhiyun 		ret = -ENOMEM;
505*4882a593Smuzhiyun 		goto out;
506*4882a593Smuzhiyun 	}
507*4882a593Smuzhiyun 
508*4882a593Smuzhiyun 	/* Pointer initialization */
509*4882a593Smuzhiyun 	vendor_info.hdr = (struct vendor_hdr *)buffer;
510*4882a593Smuzhiyun 	vendor_info.item = (struct vendor_item *)(buffer + sizeof(struct vendor_hdr));
511*4882a593Smuzhiyun 	vendor_info.data = buffer + data_offset;
512*4882a593Smuzhiyun 	vendor_info.hash = (u32 *)(buffer + hash_offset);
513*4882a593Smuzhiyun 	vendor_info.version2 = (u32 *)(buffer + version2_offset);
514*4882a593Smuzhiyun 
515*4882a593Smuzhiyun #ifdef CONFIG_MTD_BLK
516*4882a593Smuzhiyun 	if (dev_desc->if_type == IF_TYPE_MTD) {
517*4882a593Smuzhiyun 		ret = mtd_vendor_storage_init(dev_desc);
518*4882a593Smuzhiyun 		goto out;
519*4882a593Smuzhiyun 	}
520*4882a593Smuzhiyun #endif
521*4882a593Smuzhiyun 
522*4882a593Smuzhiyun 	/* Find valid and up-to-date one from (vendor0 - vendor3) */
523*4882a593Smuzhiyun 	for (i = 0; i < part_num; i++) {
524*4882a593Smuzhiyun 		ret_size = vendor_ops((u8 *)vendor_info.hdr,
525*4882a593Smuzhiyun 				      part_size * i, part_size, 0);
526*4882a593Smuzhiyun 		if (ret_size != part_size) {
527*4882a593Smuzhiyun 			ret = -EIO;
528*4882a593Smuzhiyun 			goto out;
529*4882a593Smuzhiyun 		}
530*4882a593Smuzhiyun 
531*4882a593Smuzhiyun 		if ((vendor_info.hdr->tag == VENDOR_TAG) &&
532*4882a593Smuzhiyun 		    (*(vendor_info.version2) == vendor_info.hdr->version)) {
533*4882a593Smuzhiyun 			if (max_ver < vendor_info.hdr->version) {
534*4882a593Smuzhiyun 				max_index = i;
535*4882a593Smuzhiyun 				max_ver = vendor_info.hdr->version;
536*4882a593Smuzhiyun 			}
537*4882a593Smuzhiyun 		}
538*4882a593Smuzhiyun 	}
539*4882a593Smuzhiyun 
540*4882a593Smuzhiyun 	if (max_ver) {
541*4882a593Smuzhiyun 		debug("[Vendor INFO]:max_ver=%d, vendor_id=%d.\n", max_ver, max_index);
542*4882a593Smuzhiyun 		/*
543*4882a593Smuzhiyun 		 * Keep vendor_info the same as the largest
544*4882a593Smuzhiyun 		 * version of vendor
545*4882a593Smuzhiyun 		 */
546*4882a593Smuzhiyun 		if (max_index != (part_num - 1)) {
547*4882a593Smuzhiyun 			ret_size = vendor_ops((u8 *)vendor_info.hdr,
548*4882a593Smuzhiyun 					       part_size * max_index, part_size, 0);
549*4882a593Smuzhiyun 			if (ret_size != part_size) {
550*4882a593Smuzhiyun 				ret = -EIO;
551*4882a593Smuzhiyun 				goto out;
552*4882a593Smuzhiyun 			}
553*4882a593Smuzhiyun 		}
554*4882a593Smuzhiyun 	} else {
555*4882a593Smuzhiyun 		debug("[Vendor INFO]:Reset vendor info...\n");
556*4882a593Smuzhiyun 		memset((u8 *)vendor_info.hdr, 0, size);
557*4882a593Smuzhiyun 		vendor_info.hdr->version = 1;
558*4882a593Smuzhiyun 		vendor_info.hdr->tag = VENDOR_TAG;
559*4882a593Smuzhiyun 		/* data field length */
560*4882a593Smuzhiyun 		vendor_info.hdr->free_size =
561*4882a593Smuzhiyun 			((u32)(size_t)vendor_info.hash
562*4882a593Smuzhiyun 			- (u32)(size_t)vendor_info.data);
563*4882a593Smuzhiyun 		*(vendor_info.version2) = vendor_info.hdr->version;
564*4882a593Smuzhiyun 	}
565*4882a593Smuzhiyun 	debug("[Vendor INFO]:ret=%d.\n", ret);
566*4882a593Smuzhiyun 
567*4882a593Smuzhiyun out:
568*4882a593Smuzhiyun 	if (ret)
569*4882a593Smuzhiyun 		bootdev_type = 0;
570*4882a593Smuzhiyun 
571*4882a593Smuzhiyun 	return ret;
572*4882a593Smuzhiyun }
573*4882a593Smuzhiyun 
vendor_storage_fixup(void * blob)574*4882a593Smuzhiyun void vendor_storage_fixup(void *blob)
575*4882a593Smuzhiyun {
576*4882a593Smuzhiyun 	unsigned long size;
577*4882a593Smuzhiyun 	unsigned long start;
578*4882a593Smuzhiyun 	ulong offset;
579*4882a593Smuzhiyun 
580*4882a593Smuzhiyun 	/* init vendor storage */
581*4882a593Smuzhiyun 	if (!bootdev_type) {
582*4882a593Smuzhiyun 		if (vendor_storage_init() < 0)
583*4882a593Smuzhiyun 			return;
584*4882a593Smuzhiyun 	}
585*4882a593Smuzhiyun 
586*4882a593Smuzhiyun 	offset = fdt_node_offset_by_compatible(blob, 0, "rockchip,vendor-storage-rm");
587*4882a593Smuzhiyun 	if (offset >= 0) {
588*4882a593Smuzhiyun 		start = (unsigned long)vendor_info.hdr;
589*4882a593Smuzhiyun 		size = (unsigned long)((void *)vendor_info.version2 - (void *)vendor_info.hdr);
590*4882a593Smuzhiyun 		size += 4;
591*4882a593Smuzhiyun 		fdt_update_reserved_memory(blob, "rockchip,vendor-storage-rm",
592*4882a593Smuzhiyun 					   (u64)start,
593*4882a593Smuzhiyun 					   (u64)size);
594*4882a593Smuzhiyun 	}
595*4882a593Smuzhiyun }
596*4882a593Smuzhiyun 
597*4882a593Smuzhiyun /*
598*4882a593Smuzhiyun  * @id: item id, first 4 id is occupied:
599*4882a593Smuzhiyun  *	VENDOR_SN_ID
600*4882a593Smuzhiyun  *	VENDOR_WIFI_MAC_ID
601*4882a593Smuzhiyun  *	VENDOR_LAN_MAC_ID
602*4882a593Smuzhiyun  *	VENDOR_BLUETOOTH_ID
603*4882a593Smuzhiyun  * @pbuf: read data buffer;
604*4882a593Smuzhiyun  * @size: read bytes;
605*4882a593Smuzhiyun  *
606*4882a593Smuzhiyun  * return: bytes equal to @size is success, other fail;
607*4882a593Smuzhiyun  */
vendor_storage_read(u16 id,void * pbuf,u16 size)608*4882a593Smuzhiyun int vendor_storage_read(u16 id, void *pbuf, u16 size)
609*4882a593Smuzhiyun {
610*4882a593Smuzhiyun 	int ret = 0;
611*4882a593Smuzhiyun 	u32 i;
612*4882a593Smuzhiyun 	u16 offset;
613*4882a593Smuzhiyun 	struct vendor_item *item;
614*4882a593Smuzhiyun 
615*4882a593Smuzhiyun 	/* init vendor storage */
616*4882a593Smuzhiyun 	if (!bootdev_type) {
617*4882a593Smuzhiyun 		ret = vendor_storage_init();
618*4882a593Smuzhiyun 		if (ret < 0)
619*4882a593Smuzhiyun 			return ret;
620*4882a593Smuzhiyun 	}
621*4882a593Smuzhiyun 
622*4882a593Smuzhiyun 	item = vendor_info.item;
623*4882a593Smuzhiyun 	for (i = 0; i < vendor_info.hdr->item_num; i++) {
624*4882a593Smuzhiyun 		if ((item + i)->id == id) {
625*4882a593Smuzhiyun 			debug("[Vendor INFO]:Find the matching item, id=%d\n", id);
626*4882a593Smuzhiyun 			/* Correct the size value */
627*4882a593Smuzhiyun 			if (size > (item + i)->size)
628*4882a593Smuzhiyun 				size = (item + i)->size;
629*4882a593Smuzhiyun 			offset = (item + i)->offset;
630*4882a593Smuzhiyun 			memcpy(pbuf, (vendor_info.data + offset), size);
631*4882a593Smuzhiyun 			return size;
632*4882a593Smuzhiyun 		}
633*4882a593Smuzhiyun 	}
634*4882a593Smuzhiyun 	debug("[Vendor ERROR]:No matching item, id=%d\n", id);
635*4882a593Smuzhiyun 
636*4882a593Smuzhiyun 	return -EINVAL;
637*4882a593Smuzhiyun }
638*4882a593Smuzhiyun 
639*4882a593Smuzhiyun /*
640*4882a593Smuzhiyun  * @id: item id, first 4 id is occupied:
641*4882a593Smuzhiyun  *	VENDOR_SN_ID
642*4882a593Smuzhiyun  *	VENDOR_WIFI_MAC_ID
643*4882a593Smuzhiyun  *	VENDOR_LAN_MAC_ID
644*4882a593Smuzhiyun  *	VENDOR_BLUETOOTH_ID
645*4882a593Smuzhiyun  * @pbuf: write data buffer;
646*4882a593Smuzhiyun  * @size: write bytes;
647*4882a593Smuzhiyun  *
648*4882a593Smuzhiyun  * return: bytes equal to @size is success, other fail;
649*4882a593Smuzhiyun  */
vendor_storage_write(u16 id,void * pbuf,u16 size)650*4882a593Smuzhiyun int vendor_storage_write(u16 id, void *pbuf, u16 size)
651*4882a593Smuzhiyun {
652*4882a593Smuzhiyun 	int cnt, ret = 0;
653*4882a593Smuzhiyun 	u32 i, next_index, align_size;
654*4882a593Smuzhiyun 	struct vendor_item *item;
655*4882a593Smuzhiyun 	u16 part_size, max_item_num, offset, part_num;
656*4882a593Smuzhiyun 
657*4882a593Smuzhiyun 	/* init vendor storage */
658*4882a593Smuzhiyun 	if (!bootdev_type) {
659*4882a593Smuzhiyun 		ret = vendor_storage_init();
660*4882a593Smuzhiyun 		if (ret < 0)
661*4882a593Smuzhiyun 			return ret;
662*4882a593Smuzhiyun 	}
663*4882a593Smuzhiyun 
664*4882a593Smuzhiyun 	switch (bootdev_type) {
665*4882a593Smuzhiyun 	case IF_TYPE_MMC:
666*4882a593Smuzhiyun 		part_size = EMMC_VENDOR_PART_BLKS;
667*4882a593Smuzhiyun 		max_item_num = EMMC_VENDOR_ITEM_NUM;
668*4882a593Smuzhiyun 		part_num = VENDOR_PART_NUM;
669*4882a593Smuzhiyun 		break;
670*4882a593Smuzhiyun 	case IF_TYPE_RKNAND:
671*4882a593Smuzhiyun 	case IF_TYPE_SPINAND:
672*4882a593Smuzhiyun 		part_size = NAND_VENDOR_PART_BLKS;
673*4882a593Smuzhiyun 		max_item_num = NAND_VENDOR_ITEM_NUM;
674*4882a593Smuzhiyun 		part_num = NAND_VENDOR_PART_NUM;
675*4882a593Smuzhiyun 		break;
676*4882a593Smuzhiyun 	case IF_TYPE_SPINOR:
677*4882a593Smuzhiyun 		part_size = FLASH_VENDOR_PART_BLKS;
678*4882a593Smuzhiyun 		max_item_num = FLASH_VENDOR_ITEM_NUM;
679*4882a593Smuzhiyun 		part_num = VENDOR_PART_NUM;
680*4882a593Smuzhiyun 		break;
681*4882a593Smuzhiyun #ifdef CONFIG_MTD_BLK
682*4882a593Smuzhiyun 	case IF_TYPE_MTD:
683*4882a593Smuzhiyun 		part_size = FLASH_VENDOR_PART_BLKS;
684*4882a593Smuzhiyun 		max_item_num = FLASH_VENDOR_ITEM_NUM;
685*4882a593Smuzhiyun 		part_num = MTD_VENDOR_PART_NUM;
686*4882a593Smuzhiyun 		break;
687*4882a593Smuzhiyun #endif
688*4882a593Smuzhiyun 	default:
689*4882a593Smuzhiyun 		ret = -ENODEV;
690*4882a593Smuzhiyun 		break;
691*4882a593Smuzhiyun 	}
692*4882a593Smuzhiyun 	/* Invalid bootdev? */
693*4882a593Smuzhiyun 	if (ret < 0)
694*4882a593Smuzhiyun 		return ret;
695*4882a593Smuzhiyun 
696*4882a593Smuzhiyun 	next_index = vendor_info.hdr->next_index;
697*4882a593Smuzhiyun 	/* algin to 64 bytes*/
698*4882a593Smuzhiyun 	align_size = (size + VENDOR_BTYE_ALIGN) & (~VENDOR_BTYE_ALIGN);
699*4882a593Smuzhiyun 	if (size > align_size)
700*4882a593Smuzhiyun 		return -EINVAL;
701*4882a593Smuzhiyun 
702*4882a593Smuzhiyun 	item = vendor_info.item;
703*4882a593Smuzhiyun 	/* If item already exist, update the item data */
704*4882a593Smuzhiyun 	for (i = 0; i < vendor_info.hdr->item_num; i++) {
705*4882a593Smuzhiyun 		if ((item + i)->id == id) {
706*4882a593Smuzhiyun 			debug("[Vendor INFO]:Find the matching item, id=%d\n", id);
707*4882a593Smuzhiyun 			offset = (item + i)->offset;
708*4882a593Smuzhiyun 			memcpy((vendor_info.data + offset), pbuf, size);
709*4882a593Smuzhiyun 			(item + i)->size = size;
710*4882a593Smuzhiyun 			vendor_info.hdr->version++;
711*4882a593Smuzhiyun 			*(vendor_info.version2) = vendor_info.hdr->version;
712*4882a593Smuzhiyun 			vendor_info.hdr->next_index++;
713*4882a593Smuzhiyun 			if (vendor_info.hdr->next_index >= part_num)
714*4882a593Smuzhiyun 				vendor_info.hdr->next_index = 0;
715*4882a593Smuzhiyun 			cnt = vendor_ops((u8 *)vendor_info.hdr, part_size * next_index, part_size, 1);
716*4882a593Smuzhiyun 			return (cnt == part_size) ? size : -EIO;
717*4882a593Smuzhiyun 		}
718*4882a593Smuzhiyun 	}
719*4882a593Smuzhiyun 	/*
720*4882a593Smuzhiyun 	 * If item does not exist, and free size is enough,
721*4882a593Smuzhiyun 	 * creat a new one
722*4882a593Smuzhiyun 	 */
723*4882a593Smuzhiyun 	if ((vendor_info.hdr->item_num < max_item_num) &&
724*4882a593Smuzhiyun 	    (vendor_info.hdr->free_size >= align_size)) {
725*4882a593Smuzhiyun 		debug("[Vendor INFO]:Create new Item, id=%d\n", id);
726*4882a593Smuzhiyun 		item = vendor_info.item + vendor_info.hdr->item_num;
727*4882a593Smuzhiyun 		item->id = id;
728*4882a593Smuzhiyun 		item->offset = vendor_info.hdr->free_offset;
729*4882a593Smuzhiyun 		item->size = size;
730*4882a593Smuzhiyun 
731*4882a593Smuzhiyun 		vendor_info.hdr->free_offset += align_size;
732*4882a593Smuzhiyun 		vendor_info.hdr->free_size -= align_size;
733*4882a593Smuzhiyun 		memcpy((vendor_info.data + item->offset), pbuf, size);
734*4882a593Smuzhiyun 		vendor_info.hdr->item_num++;
735*4882a593Smuzhiyun 		vendor_info.hdr->version++;
736*4882a593Smuzhiyun 		vendor_info.hdr->next_index++;
737*4882a593Smuzhiyun 		*(vendor_info.version2) = vendor_info.hdr->version;
738*4882a593Smuzhiyun 		if (vendor_info.hdr->next_index >= part_num)
739*4882a593Smuzhiyun 			vendor_info.hdr->next_index = 0;
740*4882a593Smuzhiyun 
741*4882a593Smuzhiyun 		cnt = vendor_ops((u8 *)vendor_info.hdr, part_size * next_index, part_size, 1);
742*4882a593Smuzhiyun 		return (cnt == part_size) ? size : -EIO;
743*4882a593Smuzhiyun 	}
744*4882a593Smuzhiyun 	debug("[Vendor ERROR]:Vendor has no space left!\n");
745*4882a593Smuzhiyun 
746*4882a593Smuzhiyun 	return -ENOMEM;
747*4882a593Smuzhiyun }
748*4882a593Smuzhiyun 
749*4882a593Smuzhiyun /**********************************************************/
750*4882a593Smuzhiyun /*              vendor API uinit test                      */
751*4882a593Smuzhiyun /**********************************************************/
752*4882a593Smuzhiyun /* Reset the vendor storage space to the initial state */
vendor_test_reset(void)753*4882a593Smuzhiyun static void vendor_test_reset(void)
754*4882a593Smuzhiyun {
755*4882a593Smuzhiyun 	u16 i, part_size, part_num;
756*4882a593Smuzhiyun 	u32 size;
757*4882a593Smuzhiyun 
758*4882a593Smuzhiyun 	switch (bootdev_type) {
759*4882a593Smuzhiyun 	case IF_TYPE_MMC:
760*4882a593Smuzhiyun 		size = EMMC_VENDOR_INFO_SIZE;
761*4882a593Smuzhiyun 		part_size = EMMC_VENDOR_PART_BLKS;
762*4882a593Smuzhiyun 		part_num = VENDOR_PART_NUM;
763*4882a593Smuzhiyun 		break;
764*4882a593Smuzhiyun 	case IF_TYPE_RKNAND:
765*4882a593Smuzhiyun 	case IF_TYPE_SPINAND:
766*4882a593Smuzhiyun 		size = NAND_VENDOR_INFO_SIZE;
767*4882a593Smuzhiyun 		part_size = NAND_VENDOR_PART_BLKS;
768*4882a593Smuzhiyun 		part_num = NAND_VENDOR_PART_NUM;
769*4882a593Smuzhiyun 		break;
770*4882a593Smuzhiyun 	case IF_TYPE_SPINOR:
771*4882a593Smuzhiyun 		size = FLASH_VENDOR_INFO_SIZE;
772*4882a593Smuzhiyun 		part_size = FLASH_VENDOR_PART_BLKS;
773*4882a593Smuzhiyun 		part_num = VENDOR_PART_NUM;
774*4882a593Smuzhiyun 		break;
775*4882a593Smuzhiyun 	default:
776*4882a593Smuzhiyun 		size = 0;
777*4882a593Smuzhiyun 		part_size = 0;
778*4882a593Smuzhiyun 		break;
779*4882a593Smuzhiyun 	}
780*4882a593Smuzhiyun 	/* Invalid bootdev? */
781*4882a593Smuzhiyun 	if (!size)
782*4882a593Smuzhiyun 		return;
783*4882a593Smuzhiyun 
784*4882a593Smuzhiyun 	memset((u8 *)vendor_info.hdr, 0, size);
785*4882a593Smuzhiyun 	vendor_info.hdr->version = 1;
786*4882a593Smuzhiyun 	vendor_info.hdr->tag = VENDOR_TAG;
787*4882a593Smuzhiyun 	/* data field length */
788*4882a593Smuzhiyun 	vendor_info.hdr->free_size = (unsigned long)vendor_info.hash -
789*4882a593Smuzhiyun 				     (unsigned long)vendor_info.data;
790*4882a593Smuzhiyun 	*(vendor_info.version2) = vendor_info.hdr->version;
791*4882a593Smuzhiyun 	/* write to flash. */
792*4882a593Smuzhiyun 	for (i = 0; i < part_num; i++)
793*4882a593Smuzhiyun 		vendor_ops((u8 *)vendor_info.hdr, part_size * i, part_size, 1);
794*4882a593Smuzhiyun }
795*4882a593Smuzhiyun 
796*4882a593Smuzhiyun /*
797*4882a593Smuzhiyun  * A total of four tests
798*4882a593Smuzhiyun  * 1.All items test.
799*4882a593Smuzhiyun  * 2.Overrides the maximum number of items test.
800*4882a593Smuzhiyun  * 3.Single Item memory overflow test.
801*4882a593Smuzhiyun  * 4.Total memory overflow test.
802*4882a593Smuzhiyun  */
vendor_storage_test(void)803*4882a593Smuzhiyun int vendor_storage_test(void)
804*4882a593Smuzhiyun {
805*4882a593Smuzhiyun 	u16 id, size, j, item_num;
806*4882a593Smuzhiyun 	u32 total_size;
807*4882a593Smuzhiyun 	u8 *buffer = NULL;
808*4882a593Smuzhiyun 	int ret = 0;
809*4882a593Smuzhiyun 
810*4882a593Smuzhiyun 	if (!bootdev_type) {
811*4882a593Smuzhiyun 		ret = vendor_storage_init();
812*4882a593Smuzhiyun 		if (ret) {
813*4882a593Smuzhiyun 			printf("%s: vendor storage init failed, ret=%d\n",
814*4882a593Smuzhiyun 			       __func__, ret);
815*4882a593Smuzhiyun 			return ret;
816*4882a593Smuzhiyun 		}
817*4882a593Smuzhiyun 	}
818*4882a593Smuzhiyun 
819*4882a593Smuzhiyun 	/*
820*4882a593Smuzhiyun 	 * Calculate the maximum number of items and the maximum
821*4882a593Smuzhiyun 	 * allocable memory for each item.
822*4882a593Smuzhiyun 	 */
823*4882a593Smuzhiyun 	switch (bootdev_type) {
824*4882a593Smuzhiyun 	case IF_TYPE_MMC:
825*4882a593Smuzhiyun 		item_num = EMMC_VENDOR_ITEM_NUM;
826*4882a593Smuzhiyun 		total_size = (unsigned long)vendor_info.hash -
827*4882a593Smuzhiyun 			     (unsigned long)vendor_info.data;
828*4882a593Smuzhiyun 		size = total_size / item_num;
829*4882a593Smuzhiyun 		break;
830*4882a593Smuzhiyun 	case IF_TYPE_RKNAND:
831*4882a593Smuzhiyun 	case IF_TYPE_SPINAND:
832*4882a593Smuzhiyun 		item_num = NAND_VENDOR_ITEM_NUM;
833*4882a593Smuzhiyun 		total_size = (unsigned long)vendor_info.hash -
834*4882a593Smuzhiyun 			     (unsigned long)vendor_info.data;
835*4882a593Smuzhiyun 		size = total_size / item_num;
836*4882a593Smuzhiyun 		break;
837*4882a593Smuzhiyun 	case IF_TYPE_SPINOR:
838*4882a593Smuzhiyun 	case IF_TYPE_MTD:
839*4882a593Smuzhiyun 		item_num = FLASH_VENDOR_ITEM_NUM;
840*4882a593Smuzhiyun 		total_size = (unsigned long)vendor_info.hash -
841*4882a593Smuzhiyun 			     (unsigned long)vendor_info.data;
842*4882a593Smuzhiyun 		size = total_size / item_num;
843*4882a593Smuzhiyun 		break;
844*4882a593Smuzhiyun 	default:
845*4882a593Smuzhiyun 		item_num = 0;
846*4882a593Smuzhiyun 		total_size = 0;
847*4882a593Smuzhiyun 		size = 0;
848*4882a593Smuzhiyun 		break;
849*4882a593Smuzhiyun 	}
850*4882a593Smuzhiyun 	/* Invalid bootdev? */
851*4882a593Smuzhiyun 	if (!total_size)
852*4882a593Smuzhiyun 		return -ENODEV;
853*4882a593Smuzhiyun 	/* 64 bytes are aligned and rounded down */
854*4882a593Smuzhiyun 	if (size > 64)
855*4882a593Smuzhiyun 		size = (size / 64) * 64;
856*4882a593Smuzhiyun 	/* malloc memory */
857*4882a593Smuzhiyun 	buffer = (u8 *)malloc(size);
858*4882a593Smuzhiyun 	if (!buffer) {
859*4882a593Smuzhiyun 		printf("[Vendor Test]:Malloc failed(size=%d)!\n", size);
860*4882a593Smuzhiyun 		return -ENOMEM;
861*4882a593Smuzhiyun 	}
862*4882a593Smuzhiyun 	printf("[Vendor Test]:Test Start...\n");
863*4882a593Smuzhiyun 	printf("[Vendor Test]:Before Test, Vendor Resetting.\n");
864*4882a593Smuzhiyun 	if (bootdev_type != IF_TYPE_MTD)
865*4882a593Smuzhiyun 		vendor_test_reset();
866*4882a593Smuzhiyun 
867*4882a593Smuzhiyun 	/* FIRST TEST: test all items can be used correctly */
868*4882a593Smuzhiyun 	printf("[Vendor Test]:<All Items Used> Test Start...\n");
869*4882a593Smuzhiyun 	printf("[Vendor Test]:item_num=%d, size=%d.\n", item_num, size);
870*4882a593Smuzhiyun 	/*
871*4882a593Smuzhiyun 	 * Write data, then read the data, and compare the
872*4882a593Smuzhiyun 	 * data consistency
873*4882a593Smuzhiyun 	 */
874*4882a593Smuzhiyun 	for (id = 0; id < item_num; id++) {
875*4882a593Smuzhiyun 		memset(buffer, id, size);
876*4882a593Smuzhiyun 		ret = vendor_storage_write(id, buffer, size);
877*4882a593Smuzhiyun 		if (ret < 0) {
878*4882a593Smuzhiyun 			printf("[Vendor Test]:vendor write failed(id=%d)!\n", id);
879*4882a593Smuzhiyun 			free(buffer);
880*4882a593Smuzhiyun 			return ret;
881*4882a593Smuzhiyun 		}
882*4882a593Smuzhiyun 	}
883*4882a593Smuzhiyun 	/* Read data */
884*4882a593Smuzhiyun 	for (id = 0; id < item_num; id++) {
885*4882a593Smuzhiyun 		memset(buffer, 0, size);
886*4882a593Smuzhiyun 		ret = vendor_storage_read(id, buffer, size);
887*4882a593Smuzhiyun 		if (ret < 0) {
888*4882a593Smuzhiyun 			printf("[Vendor Test]:vendor read failed(id=%d)!\n", id);
889*4882a593Smuzhiyun 			free(buffer);
890*4882a593Smuzhiyun 			return ret;
891*4882a593Smuzhiyun 		}
892*4882a593Smuzhiyun 		/* check data Correctness */
893*4882a593Smuzhiyun 		for (j = 0; j < size; j++) {
894*4882a593Smuzhiyun 			if (*(buffer + j) != id) {
895*4882a593Smuzhiyun 				printf("[Vendor Test]:Unexpected error occurs(id=%d)\n", id);
896*4882a593Smuzhiyun 				printf("the data content is:\n");
897*4882a593Smuzhiyun 				print_buffer(0, buffer, 1, size, 16);
898*4882a593Smuzhiyun 
899*4882a593Smuzhiyun 				free(buffer);
900*4882a593Smuzhiyun 				return -1;
901*4882a593Smuzhiyun 			}
902*4882a593Smuzhiyun 		}
903*4882a593Smuzhiyun 		debug("\t#id=%03d success,data=0x%02x,size=%d.\n", id, *buffer, size);
904*4882a593Smuzhiyun 	}
905*4882a593Smuzhiyun 	printf("[Vendor Test]:<All Items Used> Test End,States:OK\n");
906*4882a593Smuzhiyun 
907*4882a593Smuzhiyun 	printf("[Vendor Test]:<All Items Used> re init,States:OK\n");
908*4882a593Smuzhiyun 	ret = vendor_storage_init();
909*4882a593Smuzhiyun 	/* Read data */
910*4882a593Smuzhiyun 	for (id = 0; id < item_num; id++) {
911*4882a593Smuzhiyun 		memset(buffer, 0, size);
912*4882a593Smuzhiyun 		ret = vendor_storage_read(id, buffer, size);
913*4882a593Smuzhiyun 		if (ret < 0) {
914*4882a593Smuzhiyun 			printf("[Vendor Test]:vendor read failed(id=%d)!\n", id);
915*4882a593Smuzhiyun 			free(buffer);
916*4882a593Smuzhiyun 			return ret;
917*4882a593Smuzhiyun 		}
918*4882a593Smuzhiyun 		/* check data Correctness */
919*4882a593Smuzhiyun 		for (j = 0; j < size; j++) {
920*4882a593Smuzhiyun 			if (*(buffer + j) != id) {
921*4882a593Smuzhiyun 				printf("[Vendor Test]:Unexpected error occurs(id=%d)\n", id);
922*4882a593Smuzhiyun 				printf("the data content is:\n");
923*4882a593Smuzhiyun 				print_buffer(0, buffer, 1, size, 16);
924*4882a593Smuzhiyun 
925*4882a593Smuzhiyun 				free(buffer);
926*4882a593Smuzhiyun 				return -1;
927*4882a593Smuzhiyun 			}
928*4882a593Smuzhiyun 		}
929*4882a593Smuzhiyun 		debug("\t#id=%03d success,data=0x%02x,size=%d.\n", id, *buffer, size);
930*4882a593Smuzhiyun 	}
931*4882a593Smuzhiyun 	printf("[Vendor Test]:<All Items Used> Test End,States:OK\n");
932*4882a593Smuzhiyun #ifdef CONFIG_MTD_BLK
933*4882a593Smuzhiyun 	if (bootdev_type == IF_TYPE_MTD)
934*4882a593Smuzhiyun 		return 0;
935*4882a593Smuzhiyun #endif
936*4882a593Smuzhiyun 	/*
937*4882a593Smuzhiyun 	 * SECOND TEST: Overrides the maximum number of items to see if the
938*4882a593Smuzhiyun 	 * return value matches the expectation
939*4882a593Smuzhiyun 	 */
940*4882a593Smuzhiyun 	printf("[Vendor Test]:<Overflow Items Cnt> Test Start...\n");
941*4882a593Smuzhiyun 	/* Any id value that was not used before */
942*4882a593Smuzhiyun 	id = item_num;
943*4882a593Smuzhiyun 	printf("[Vendor Test]:id=%d, size=%d.\n", id, size);
944*4882a593Smuzhiyun 	ret = vendor_storage_write(id, buffer, size);
945*4882a593Smuzhiyun 	if (ret == -ENOMEM)
946*4882a593Smuzhiyun 		printf("[Vendor Test]:<Overflow Items Cnt> Test End,States:OK\n");
947*4882a593Smuzhiyun 	else
948*4882a593Smuzhiyun 		printf("[Vendor Test]:<Overflow Items Cnt> Test End,States:Failed\n");
949*4882a593Smuzhiyun 
950*4882a593Smuzhiyun 	/* free buffer, remalloc later */
951*4882a593Smuzhiyun 	free(buffer);
952*4882a593Smuzhiyun 	buffer = NULL;
953*4882a593Smuzhiyun 	/*
954*4882a593Smuzhiyun 	 * remalloc memory and recalculate size to test memory overflow
955*4882a593Smuzhiyun 	 * (1) item_num > 10: Memory is divided into 10 blocks,
956*4882a593Smuzhiyun 	 * 11th memory will overflow.
957*4882a593Smuzhiyun 	 * (2) 10 > item_num > 1: Memory is divided into item_num-1
958*4882a593Smuzhiyun 	 * blocks. item_num block, memory will overflow.
959*4882a593Smuzhiyun 	 * (3) item_num = 1: size = total_size + 512 Bytes, The first
960*4882a593Smuzhiyun 	 * block, memory will overflow.
961*4882a593Smuzhiyun 	 * The reason to do so is to minimize the size of the memory,
962*4882a593Smuzhiyun 	 * making malloc easier to perform successfully.
963*4882a593Smuzhiyun 	 */
964*4882a593Smuzhiyun 	item_num = (item_num > 10) ? 10 : (item_num - 1);
965*4882a593Smuzhiyun 	size = item_num ? (total_size / item_num) : (total_size + 512);
966*4882a593Smuzhiyun 	size = (size + VENDOR_BTYE_ALIGN) & (~VENDOR_BTYE_ALIGN);
967*4882a593Smuzhiyun 	/* Find item_num value that can make the memory overflow */
968*4882a593Smuzhiyun 	for (id = 0; id <= item_num; id++) {
969*4882a593Smuzhiyun 		if (((id + 1) * size) > total_size) {
970*4882a593Smuzhiyun 			item_num = id;
971*4882a593Smuzhiyun 			break;
972*4882a593Smuzhiyun 		}
973*4882a593Smuzhiyun 	}
974*4882a593Smuzhiyun 	/* malloc */
975*4882a593Smuzhiyun 	buffer = (u8 *)malloc(size);
976*4882a593Smuzhiyun 	if (buffer == NULL) {
977*4882a593Smuzhiyun 		printf("[Vendor Test]:Malloc failed(size=%d)!\n", size);
978*4882a593Smuzhiyun 		return -ENOMEM;
979*4882a593Smuzhiyun 	}
980*4882a593Smuzhiyun 
981*4882a593Smuzhiyun 	/* THIRD TEST: Single Item memory overflow test */
982*4882a593Smuzhiyun 	printf("[Vendor Test]:<Single Item Memory Overflow> Test Start...\n");
983*4882a593Smuzhiyun 	/* The value can be arbitrary */
984*4882a593Smuzhiyun 	memset(buffer, 'a', size);
985*4882a593Smuzhiyun 	/* Any id value that was used before */
986*4882a593Smuzhiyun 	id = 0;
987*4882a593Smuzhiyun 	printf("[Vendor Test]:id=%d, size=%d.\n", id, size);
988*4882a593Smuzhiyun 	ret = vendor_storage_write(id, buffer, size);
989*4882a593Smuzhiyun 	if (ret == size)
990*4882a593Smuzhiyun 		printf("[Vendor Test]:<Single Item Memory Overflow> Test End, States:OK\n");
991*4882a593Smuzhiyun 	else
992*4882a593Smuzhiyun 		printf("[Vendor Test]:<Single Item Memory Overflow> Test End, States:Failed\n");
993*4882a593Smuzhiyun 
994*4882a593Smuzhiyun 	/* FORTH TEST: Total memory overflow test */
995*4882a593Smuzhiyun 	printf("[Vendor Test]:<Total memory overflow> Test Start...\n");
996*4882a593Smuzhiyun 	printf("[Vendor Test]:item_num=%d, size=%d.\n", item_num, size);
997*4882a593Smuzhiyun 
998*4882a593Smuzhiyun 	vendor_test_reset();
999*4882a593Smuzhiyun 	for (id = 0; id < item_num; id++) {
1000*4882a593Smuzhiyun 		memset(buffer, id, size);
1001*4882a593Smuzhiyun 		ret = vendor_storage_write(id, buffer, size);
1002*4882a593Smuzhiyun 		if (ret < 0) {
1003*4882a593Smuzhiyun 			if ((id == item_num) && (ret == -ENOMEM)) {
1004*4882a593Smuzhiyun 				printf("[Vendor Test]:<Total memory overflow> Test End, States:OK\n");
1005*4882a593Smuzhiyun 				break;
1006*4882a593Smuzhiyun 			} else {
1007*4882a593Smuzhiyun 				printf("[Vendor Test]:<Total memory overflow> Test End, States:Failed\n");
1008*4882a593Smuzhiyun 				break;
1009*4882a593Smuzhiyun 			}
1010*4882a593Smuzhiyun 		}
1011*4882a593Smuzhiyun 		debug("\t#id=%03d success,data=0x%02x,size=%d.\n", id, *buffer, size);
1012*4882a593Smuzhiyun 	}
1013*4882a593Smuzhiyun 
1014*4882a593Smuzhiyun 	/* Test end */
1015*4882a593Smuzhiyun 	printf("[Vendor Test]:After Test, Vendor Resetting...\n");
1016*4882a593Smuzhiyun 	vendor_test_reset();
1017*4882a593Smuzhiyun 	printf("[Vendor Test]:Test End.\n");
1018*4882a593Smuzhiyun 	free(buffer);
1019*4882a593Smuzhiyun 
1020*4882a593Smuzhiyun 	return 0;
1021*4882a593Smuzhiyun }
1022