xref: /rk3399_rockchip-uboot/arch/arm/mach-rockchip/vendor.c (revision 5baddfb2d29fa96ba14d02812ae8beefb36b3c7b)
191441457Sfrancis.fan /*
291441457Sfrancis.fan  * (C) Copyright 2008-2017 Fuzhou Rockchip Electronics Co., Ltd
391441457Sfrancis.fan  *
491441457Sfrancis.fan  * SPDX-License-Identifier:	GPL-2.0+
591441457Sfrancis.fan  */
691441457Sfrancis.fan 
791441457Sfrancis.fan #include <common.h>
891441457Sfrancis.fan #include <malloc.h>
991441457Sfrancis.fan #include <asm/arch/vendor.h>
105bd6dc27SKever Yang #include <boot_rkimg.h>
111da937e7SYifeng Zhao #include <nand.h>
121da937e7SYifeng Zhao #include <part.h>
132a217cf1SYifeng Zhao #include <fdt_support.h>
1470990948SYifeng Zhao #include <usbplug.h>
1591441457Sfrancis.fan 
1691441457Sfrancis.fan /* tag for vendor check */
1791441457Sfrancis.fan #define VENDOR_TAG		0x524B5644
1891441457Sfrancis.fan /* The Vendor partition contains the number of Vendor blocks */
191da937e7SYifeng Zhao #define MTD_VENDOR_PART_NUM	1
203628f4d0SDingqiang Lin #define NAND_VENDOR_PART_NUM	2
2191441457Sfrancis.fan #define VENDOR_PART_NUM		4
2291441457Sfrancis.fan /* align to 64 bytes */
2391441457Sfrancis.fan #define VENDOR_BTYE_ALIGN	0x3F
2491441457Sfrancis.fan #define VENDOR_BLOCK_SIZE	512
2591441457Sfrancis.fan 
262a217cf1SYifeng Zhao #define PAGE_ALGIN_SIZE		(4096uL)
272a217cf1SYifeng Zhao #define PAGE_ALGIN_MASK		(~(PAGE_ALGIN_SIZE - 1))
282a217cf1SYifeng Zhao 
2991441457Sfrancis.fan /* --- Emmc define --- */
3091441457Sfrancis.fan /* Starting address of the Vendor in memory. */
3191441457Sfrancis.fan #define EMMC_VENDOR_PART_OFFSET		(1024 * 7)
3291441457Sfrancis.fan /*
3391441457Sfrancis.fan  * The number of memory blocks used by each
3491441457Sfrancis.fan  * Vendor structure(128 * 512B = 64KB)
3591441457Sfrancis.fan  */
3691441457Sfrancis.fan #define EMMC_VENDOR_PART_BLKS		128
3791441457Sfrancis.fan /* The maximum number of items in each Vendor block */
3891441457Sfrancis.fan #define EMMC_VENDOR_ITEM_NUM		126
3991441457Sfrancis.fan 
403628f4d0SDingqiang Lin /* --- Spi Nand/SLC/MLC large capacity case define --- */
413628f4d0SDingqiang Lin /* The Vendor partition contains the number of Vendor blocks */
423628f4d0SDingqiang Lin #define NAND_VENDOR_PART_OFFSET		0
433628f4d0SDingqiang Lin /*
443628f4d0SDingqiang Lin  * The number of memory blocks used by each
453628f4d0SDingqiang Lin  * Vendor structure(8 * 512B = 4KB)
463628f4d0SDingqiang Lin  */
473628f4d0SDingqiang Lin #define NAND_VENDOR_PART_BLKS		128
483628f4d0SDingqiang Lin /* The maximum number of items in each Vendor block */
493628f4d0SDingqiang Lin #define NAND_VENDOR_ITEM_NUM		126
503628f4d0SDingqiang Lin 
513628f4d0SDingqiang Lin /* --- Spi/Spi Nand/SLC/MLC small capacity case define --- */
5291441457Sfrancis.fan /* The Vendor partition contains the number of Vendor blocks */
5391441457Sfrancis.fan #define	FLASH_VENDOR_PART_OFFSET	8
5491441457Sfrancis.fan /*
5591441457Sfrancis.fan  * The number of memory blocks used by each
5691441457Sfrancis.fan  * Vendor structure(8 * 512B = 4KB)
5791441457Sfrancis.fan  */
5891441457Sfrancis.fan #define FLASH_VENDOR_PART_BLKS		8
5991441457Sfrancis.fan /* The maximum number of items in each Vendor block */
6091441457Sfrancis.fan #define FLASH_VENDOR_ITEM_NUM		62
6191441457Sfrancis.fan 
6291441457Sfrancis.fan /* Vendor uinit test define */
6391441457Sfrancis.fan int vendor_storage_test(void);
6491441457Sfrancis.fan 
6591441457Sfrancis.fan struct vendor_hdr {
6691441457Sfrancis.fan 	u32	tag;
6791441457Sfrancis.fan 	u32	version;
6891441457Sfrancis.fan 	u16	next_index;
6991441457Sfrancis.fan 	u16	item_num;
7091441457Sfrancis.fan 	u16	free_offset; /* Free space offset */
7191441457Sfrancis.fan 	u16	free_size; /* Free space size */
7291441457Sfrancis.fan };
7391441457Sfrancis.fan 
7491441457Sfrancis.fan /*
7591441457Sfrancis.fan  * Different types of Flash vendor info are different.
7691441457Sfrancis.fan  * EMMC:EMMC_VENDOR_PART_BLKS * BLOCK_SIZE(512) = 64KB;
7791441457Sfrancis.fan  * Spi Nor/Spi Nand/SLC/MLC: FLASH_VENDOR_PART_BLKS *
7891441457Sfrancis.fan  * BLOCK_SIZE(512) = 4KB.
7991441457Sfrancis.fan  * hash: For future expansion.
8091441457Sfrancis.fan  * version2: Together with hdr->version, it is used to
8191441457Sfrancis.fan  * ensure the current Vendor block content integrity.
8291441457Sfrancis.fan  *   (version2 == hdr->version):Data valid;
8391441457Sfrancis.fan  *   (version2 != hdr->version):Data invalid.
8491441457Sfrancis.fan  */
8591441457Sfrancis.fan struct vendor_info {
8691441457Sfrancis.fan 	struct vendor_hdr *hdr;
8791441457Sfrancis.fan 	struct vendor_item *item;
8891441457Sfrancis.fan 	u8 *data;
8991441457Sfrancis.fan 	u32 *hash;
9091441457Sfrancis.fan 	u32 *version2;
9191441457Sfrancis.fan };
923628f4d0SDingqiang Lin 
931e5036b9SJon Lin struct mtd_flash_info {
941da937e7SYifeng Zhao 	u32 part_offset;
951da937e7SYifeng Zhao 	u32 part_size;
961da937e7SYifeng Zhao 	u32 blk_offset;
971da937e7SYifeng Zhao 	u32 page_offset;
981da937e7SYifeng Zhao 	u32 version;
991da937e7SYifeng Zhao 	u32 ops_size;
1001da937e7SYifeng Zhao 	u32 blk_size;
1011da937e7SYifeng Zhao };
1021da937e7SYifeng Zhao 
10391441457Sfrancis.fan /*
10491441457Sfrancis.fan  * Calculate the offset of each field for emmc.
10591441457Sfrancis.fan  * Emmc vendor info size: 64KB
10691441457Sfrancis.fan  */
10791441457Sfrancis.fan #define EMMC_VENDOR_INFO_SIZE	(EMMC_VENDOR_PART_BLKS * VENDOR_BLOCK_SIZE)
10891441457Sfrancis.fan #define EMMC_VENDOR_DATA_OFFSET	(sizeof(struct vendor_hdr) + EMMC_VENDOR_ITEM_NUM * sizeof(struct vendor_item))
10991441457Sfrancis.fan #define EMMC_VENDOR_HASH_OFFSET (EMMC_VENDOR_INFO_SIZE - 8)
11091441457Sfrancis.fan #define EMMC_VENDOR_VERSION2_OFFSET (EMMC_VENDOR_INFO_SIZE - 4)
1113628f4d0SDingqiang Lin 
11291441457Sfrancis.fan /*
1133628f4d0SDingqiang Lin  * Calculate the offset of each field for spi nand/slc/mlc large capacity case.
1143628f4d0SDingqiang Lin  * Flash vendor info size: 4KB
1153628f4d0SDingqiang Lin  */
1163628f4d0SDingqiang Lin #define NAND_VENDOR_INFO_SIZE	(NAND_VENDOR_PART_BLKS * VENDOR_BLOCK_SIZE)
1173628f4d0SDingqiang Lin #define NAND_VENDOR_DATA_OFFSET	(sizeof(struct vendor_hdr) + NAND_VENDOR_ITEM_NUM * sizeof(struct vendor_item))
1183628f4d0SDingqiang Lin #define NAND_VENDOR_HASH_OFFSET (NAND_VENDOR_INFO_SIZE - 8)
1193628f4d0SDingqiang Lin #define NAND_VENDOR_VERSION2_OFFSET (NAND_VENDOR_INFO_SIZE - 4)
1203628f4d0SDingqiang Lin 
1213628f4d0SDingqiang Lin /*
1223628f4d0SDingqiang Lin  * Calculate the offset of each field for spi nor/spi nand/slc/mlc large small capacity case.
12391441457Sfrancis.fan  * Flash vendor info size: 4KB
12491441457Sfrancis.fan  */
12591441457Sfrancis.fan #define FLASH_VENDOR_INFO_SIZE	(FLASH_VENDOR_PART_BLKS * VENDOR_BLOCK_SIZE)
12691441457Sfrancis.fan #define FLASH_VENDOR_DATA_OFFSET (sizeof(struct vendor_hdr) + FLASH_VENDOR_ITEM_NUM * sizeof(struct vendor_item))
12791441457Sfrancis.fan #define FLASH_VENDOR_HASH_OFFSET (FLASH_VENDOR_INFO_SIZE - 8)
12891441457Sfrancis.fan #define FLASH_VENDOR_VERSION2_OFFSET (FLASH_VENDOR_INFO_SIZE - 4)
12991441457Sfrancis.fan 
13091441457Sfrancis.fan /* vendor info */
13191441457Sfrancis.fan static struct vendor_info vendor_info;
13291441457Sfrancis.fan /* The storage type of the device */
13391441457Sfrancis.fan static int bootdev_type;
13491441457Sfrancis.fan 
1351da937e7SYifeng Zhao #ifdef CONFIG_MTD_BLK
1361e5036b9SJon Lin static struct mtd_flash_info s_flash_info;
1371da937e7SYifeng Zhao static const char *vendor_mtd_name = "vnvm";
1381da937e7SYifeng Zhao #endif
1391da937e7SYifeng Zhao 
1403628f4d0SDingqiang Lin /* vendor private read write ops*/
1413628f4d0SDingqiang Lin static	int (*_flash_read)(struct blk_desc *dev_desc,
1423628f4d0SDingqiang Lin 			   u32 sec,
1433628f4d0SDingqiang Lin 			   u32 n_sec,
1443628f4d0SDingqiang Lin 			   void *buffer);
1453628f4d0SDingqiang Lin static	int (*_flash_write)(struct blk_desc *dev_desc,
1463628f4d0SDingqiang Lin 			    u32 sec,
1473628f4d0SDingqiang Lin 			    u32 n_sec,
1483628f4d0SDingqiang Lin 			    void *buffer);
1493628f4d0SDingqiang Lin 
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))1503628f4d0SDingqiang Lin int flash_vendor_dev_ops_register(int (*read)(struct blk_desc *dev_desc,
1513628f4d0SDingqiang Lin 					      u32 sec,
1523628f4d0SDingqiang Lin 					      u32 n_sec,
1533628f4d0SDingqiang Lin 					      void *p_data),
1543628f4d0SDingqiang Lin 				  int (*write)(struct blk_desc *dev_desc,
1553628f4d0SDingqiang Lin 					       u32 sec,
1563628f4d0SDingqiang Lin 					       u32 n_sec,
1573628f4d0SDingqiang Lin 					       void *p_data))
1583628f4d0SDingqiang Lin {
1593628f4d0SDingqiang Lin 	if (!_flash_read) {
1603628f4d0SDingqiang Lin 		_flash_read = read;
1613628f4d0SDingqiang Lin 		_flash_write = write;
1623628f4d0SDingqiang Lin 		return 0;
1633628f4d0SDingqiang Lin 	}
1643628f4d0SDingqiang Lin 
1653628f4d0SDingqiang Lin 	return -EPERM;
1663628f4d0SDingqiang Lin }
1673628f4d0SDingqiang Lin 
1681da937e7SYifeng Zhao #ifdef CONFIG_MTD_BLK
mtd_vendor_storage_init(struct blk_desc * dev_desc)1691da937e7SYifeng Zhao static int mtd_vendor_storage_init(struct blk_desc *dev_desc)
1701da937e7SYifeng Zhao {
1711da937e7SYifeng Zhao 	struct mtd_info *mtd = (struct mtd_info *)dev_desc->bdev->priv;
1721da937e7SYifeng Zhao 	disk_partition_t vnvm_part_info;
1731da937e7SYifeng Zhao 	void *buf = vendor_info.hdr;
1741da937e7SYifeng Zhao 	int ret, offset;
1751da937e7SYifeng Zhao 	int part_num, bad_block_size;
1761da937e7SYifeng Zhao 
1771da937e7SYifeng Zhao 	memset(&vnvm_part_info, 0x0, sizeof(vnvm_part_info));
1781da937e7SYifeng Zhao 	part_num = part_get_info_by_name(dev_desc, vendor_mtd_name, &vnvm_part_info);
1791da937e7SYifeng Zhao 	if (part_num < 0)
1801da937e7SYifeng Zhao 		return -EIO;
1811da937e7SYifeng Zhao 
1821e5036b9SJon Lin 	s_flash_info.part_offset = (u32)vnvm_part_info.start;
1831e5036b9SJon Lin 	s_flash_info.part_size = (u32)vnvm_part_info.size;
1841e5036b9SJon Lin 	s_flash_info.page_offset = 0;
1851e5036b9SJon Lin 	s_flash_info.blk_offset = 0;
1861e5036b9SJon Lin 	s_flash_info.version = 0;
1871e5036b9SJon Lin 	/* SPI Nor unified to Support 64KB erase block */
1881e5036b9SJon Lin 	if (dev_desc->devnum == BLK_MTD_SPI_NOR)
1891e5036b9SJon Lin 		s_flash_info.blk_size = 0x80;
1901e5036b9SJon Lin 	else
1911e5036b9SJon Lin 		s_flash_info.blk_size = mtd->erasesize >> 9;
1921e5036b9SJon Lin 	s_flash_info.ops_size = roundup(FLASH_VENDOR_INFO_SIZE, mtd->writesize) >> 9;
1931da937e7SYifeng Zhao 
1941da937e7SYifeng Zhao 	/* scan bad block and calculate the real size can be used */
1951da937e7SYifeng Zhao 	bad_block_size = 0;
1961e5036b9SJon Lin 	for (offset = 0; offset < s_flash_info.part_size; offset += s_flash_info.blk_size) {
1971e5036b9SJon Lin 		if (mtd_block_isbad(mtd, (s_flash_info.part_offset + offset) << 9))
1981e5036b9SJon Lin 			bad_block_size += s_flash_info.blk_size;
1991da937e7SYifeng Zhao 	}
2001e5036b9SJon Lin 	s_flash_info.part_size -= bad_block_size;
2011da937e7SYifeng Zhao 
2021e5036b9SJon Lin 	for (offset = 0; offset < s_flash_info.part_size; offset += s_flash_info.blk_size) {
2031e5036b9SJon Lin 		ret = blk_dread(dev_desc, s_flash_info.part_offset + offset,
2041da937e7SYifeng Zhao 				FLASH_VENDOR_INFO_SIZE >> 9,
2051da937e7SYifeng Zhao 				(u8 *)buf);
2061da937e7SYifeng Zhao 		debug("%s: read %x version = %x\n", __func__,
2071e5036b9SJon Lin 		      s_flash_info.part_offset + offset,
2081da937e7SYifeng Zhao 		      vendor_info.hdr->version);
2091da937e7SYifeng Zhao 		if (ret == (FLASH_VENDOR_INFO_SIZE >> 9) && vendor_info.hdr->tag == VENDOR_TAG &&
2101da937e7SYifeng Zhao 		    vendor_info.hdr->version == *vendor_info.version2) {
2111e5036b9SJon Lin 			if (vendor_info.hdr->version > s_flash_info.version) {
2121e5036b9SJon Lin 				s_flash_info.version = vendor_info.hdr->version;
2131e5036b9SJon Lin 				s_flash_info.blk_offset = offset;
2141da937e7SYifeng Zhao 			}
2151da937e7SYifeng Zhao 		}
2161da937e7SYifeng Zhao 	}
2171da937e7SYifeng Zhao 
2181e5036b9SJon Lin 	debug("%s: s_flash_info.version = %x %x\n", __func__, s_flash_info.version, s_flash_info.blk_offset);
2191e5036b9SJon Lin 	if (s_flash_info.version) {
2201e5036b9SJon Lin 		for (offset = s_flash_info.blk_size  - s_flash_info.ops_size;
2211da937e7SYifeng Zhao 		     offset >= 0;
2221e5036b9SJon Lin 		     offset -= s_flash_info.ops_size) {
2231e5036b9SJon Lin 			ret = blk_dread(dev_desc, s_flash_info.part_offset +
2241e5036b9SJon Lin 					s_flash_info.blk_offset + offset,
2251da937e7SYifeng Zhao 					1,
2261da937e7SYifeng Zhao 					(u8 *)buf);
2271da937e7SYifeng Zhao 
228b1c0e43cSYifeng Zhao 			/* the page is not programmed */
2291da937e7SYifeng Zhao 			if (ret == 1 && vendor_info.hdr->tag == 0xFFFFFFFF)
2301da937e7SYifeng Zhao 				continue;
2311da937e7SYifeng Zhao 
232b1c0e43cSYifeng Zhao 			/* point to the next free page */
2331e5036b9SJon Lin 			if (s_flash_info.page_offset < offset)
234b1c0e43cSYifeng Zhao 				s_flash_info.page_offset = offset + s_flash_info.ops_size;
2351da937e7SYifeng Zhao 
2361da937e7SYifeng Zhao 			if (ret != 1 || vendor_info.hdr->tag != VENDOR_TAG)
2371da937e7SYifeng Zhao 				continue;
2381e5036b9SJon Lin 			ret = blk_dread(dev_desc, s_flash_info.part_offset +
2391e5036b9SJon Lin 					s_flash_info.blk_offset + offset,
2401da937e7SYifeng Zhao 					FLASH_VENDOR_INFO_SIZE >> 9,
2411da937e7SYifeng Zhao 					(u8 *)buf);
2421da937e7SYifeng Zhao 			debug("%s: read %x version = %x\n", __func__,
2431e5036b9SJon Lin 			      s_flash_info.part_offset + s_flash_info.blk_offset  + offset,
2441da937e7SYifeng Zhao 			      vendor_info.hdr->version);
2451da937e7SYifeng Zhao 
2461da937e7SYifeng Zhao 			if (ret == (FLASH_VENDOR_INFO_SIZE >> 9)  && vendor_info.hdr->tag == VENDOR_TAG &&
2471da937e7SYifeng Zhao 			    vendor_info.hdr->version == *vendor_info.version2) {
2481e5036b9SJon Lin 				s_flash_info.version = vendor_info.hdr->version;
2491da937e7SYifeng Zhao 				break;
2501da937e7SYifeng Zhao 			}
2511da937e7SYifeng Zhao 		}
2521da937e7SYifeng Zhao 	} else {
2531da937e7SYifeng Zhao 		memset((u8 *)vendor_info.hdr, 0, FLASH_VENDOR_INFO_SIZE);
2541da937e7SYifeng Zhao 		vendor_info.hdr->version = 1;
2551da937e7SYifeng Zhao 		vendor_info.hdr->tag = VENDOR_TAG;
2561da937e7SYifeng Zhao 		vendor_info.hdr->free_size =
2571da937e7SYifeng Zhao 			((u32)(size_t)vendor_info.hash
2581da937e7SYifeng Zhao 			- (u32)(size_t)vendor_info.data);
2591da937e7SYifeng Zhao 		*vendor_info.version2 = vendor_info.hdr->version;
2601da937e7SYifeng Zhao 	}
2611da937e7SYifeng Zhao 
2621da937e7SYifeng Zhao 	return 0;
2631da937e7SYifeng Zhao }
2641da937e7SYifeng Zhao 
mtd_vendor_write(struct blk_desc * dev_desc,u32 sec,u32 n_sec,void * buf)2651da937e7SYifeng Zhao static int mtd_vendor_write(struct blk_desc *dev_desc,
2661da937e7SYifeng Zhao 			    u32 sec,
2671da937e7SYifeng Zhao 			    u32 n_sec,
2681da937e7SYifeng Zhao 			    void *buf)
2691da937e7SYifeng Zhao {
2701da937e7SYifeng Zhao 	int ret, count = 0, err = 0;
2711da937e7SYifeng Zhao 
2721da937e7SYifeng Zhao re_write:
2731e5036b9SJon Lin 	debug("[Vendor INFO]:%s page_offset=0x%x count = %x\n", __func__, s_flash_info.part_offset +
2741e5036b9SJon Lin 	      s_flash_info.blk_offset + s_flash_info.page_offset, count);
2751e5036b9SJon Lin 	if (s_flash_info.page_offset >= s_flash_info.blk_size) {
2761e5036b9SJon Lin 		s_flash_info.blk_offset += s_flash_info.blk_size;
2771e5036b9SJon Lin 		if (s_flash_info.blk_offset >= s_flash_info.part_size)
2781e5036b9SJon Lin 			s_flash_info.blk_offset = 0;
2791e5036b9SJon Lin 		s_flash_info.page_offset = 0;
280b523ac97SYifeng Zhao 		/*
281b523ac97SYifeng Zhao 		 * The spi NOR driver only erase 4KB while write data, and here need to
282b523ac97SYifeng Zhao 		 * erase one block for vendor storage request.
283b523ac97SYifeng Zhao 		 */
284b523ac97SYifeng Zhao 		blk_derase(dev_desc, s_flash_info.part_offset + s_flash_info.blk_offset, s_flash_info.blk_size);
2851da937e7SYifeng Zhao 	}
2861da937e7SYifeng Zhao 
2871e5036b9SJon Lin 	dev_desc->op_flag |= BLK_MTD_CONT_WRITE;
2881e5036b9SJon Lin 	ret = blk_dwrite(dev_desc, s_flash_info.part_offset +
2891e5036b9SJon Lin 			 s_flash_info.blk_offset + s_flash_info.page_offset,
2901da937e7SYifeng Zhao 			 FLASH_VENDOR_INFO_SIZE >> 9,
2911da937e7SYifeng Zhao 			 (u8 *)buf);
2921e5036b9SJon Lin 	dev_desc->op_flag &= ~(BLK_MTD_CONT_WRITE);
2931da937e7SYifeng Zhao 
2941e5036b9SJon Lin 	s_flash_info.page_offset += s_flash_info.ops_size;
2951da937e7SYifeng Zhao 	if (ret != (FLASH_VENDOR_INFO_SIZE >> 9)) {
2961da937e7SYifeng Zhao 		err++;
2971da937e7SYifeng Zhao 		if (err > 3)
2981da937e7SYifeng Zhao 			return -EIO;
2991da937e7SYifeng Zhao 		goto re_write;
3001da937e7SYifeng Zhao 	}
3011da937e7SYifeng Zhao 
3021da937e7SYifeng Zhao 	count++;
3031da937e7SYifeng Zhao 	/* write 2 copies for reliability */
3041da937e7SYifeng Zhao 	if (count < 2)
3051da937e7SYifeng Zhao 		goto re_write;
3061da937e7SYifeng Zhao 
3071da937e7SYifeng Zhao 	return ret;
3081da937e7SYifeng Zhao }
3091da937e7SYifeng Zhao #endif
3101da937e7SYifeng Zhao 
31191441457Sfrancis.fan /**********************************************************/
31291441457Sfrancis.fan /*              vendor API implementation                 */
31391441457Sfrancis.fan /**********************************************************/
vendor_ops(u8 * buffer,u32 addr,u32 n_sec,int write)31491441457Sfrancis.fan static int vendor_ops(u8 *buffer, u32 addr, u32 n_sec, int write)
31591441457Sfrancis.fan {
3165bd6dc27SKever Yang 	struct blk_desc *dev_desc;
31791441457Sfrancis.fan 	unsigned int lba = 0;
31891441457Sfrancis.fan 	int ret = 0;
31991441457Sfrancis.fan 
3205bd6dc27SKever Yang 	dev_desc = rockchip_get_bootdev();
3216651d4c0SJason Zhu 	if (!dev_desc) {
3226651d4c0SJason Zhu 		printf("%s: dev_desc is NULL!\n", __func__);
3236651d4c0SJason Zhu 		return -ENODEV;
3246651d4c0SJason Zhu 	}
325efcfb227SYifeng Zhao 
326*5baddfb2SYifeng Zhao 	if (dev_desc->if_type == IF_TYPE_NVME || (dev_desc->if_type == IF_TYPE_SCSI && dev_desc->rawblksz == 512)) {
327efcfb227SYifeng Zhao 		dev_desc = blk_get_devnum_by_type(IF_TYPE_MTD, BLK_MTD_SPI_NOR);
328efcfb227SYifeng Zhao 		if (!dev_desc) {
329efcfb227SYifeng Zhao 			printf("%s: dev_desc is NULL!\n", __func__);
330efcfb227SYifeng Zhao 			return -ENODEV;
331efcfb227SYifeng Zhao 		}
332efcfb227SYifeng Zhao 	}
333efcfb227SYifeng Zhao 
33491441457Sfrancis.fan 	/* Get the offset address according to the device type */
3355bd6dc27SKever Yang 	switch (dev_desc->if_type) {
3365bd6dc27SKever Yang 	case IF_TYPE_MMC:
337*5baddfb2SYifeng Zhao 	case IF_TYPE_SCSI:
33891441457Sfrancis.fan 		/*
33991441457Sfrancis.fan 		 * The location of VendorStorage in Flash is shown in the
34091441457Sfrancis.fan 		 * following figure. The starting address of the VendorStorage
3413628f4d0SDingqiang Lin 		 * partition offset is 3.5MB(EMMC_VENDOR_PART_OFFSET*BLOCK_SIZE(512)),
34291441457Sfrancis.fan 		 * and the partition size is 256KB.
34391441457Sfrancis.fan 		 * ----------------------------------------------------
34491441457Sfrancis.fan 		 * |   3.5MB    |  VendorStorage  |                   |
34591441457Sfrancis.fan 		 * ----------------------------------------------------
34691441457Sfrancis.fan 		 */
34791441457Sfrancis.fan 		lba = EMMC_VENDOR_PART_OFFSET;
348dce239c7SJoseph Chen 		debug("[Vendor INFO]:VendorStorage offset address=0x%x\n", lba);
34991441457Sfrancis.fan 		break;
3505bd6dc27SKever Yang 	case IF_TYPE_RKNAND:
3515bd6dc27SKever Yang 	case IF_TYPE_SPINAND:
35291441457Sfrancis.fan 		/*
35391441457Sfrancis.fan 		 * The location of VendorStorage in Flash is shown in the
35491441457Sfrancis.fan 		 * following figure. The starting address of the VendorStorage
3553628f4d0SDingqiang Lin 		 * partition offset is 0KB in FTL vendor block,
3563628f4d0SDingqiang Lin 		 * and the partition size is 128KB.
3573628f4d0SDingqiang Lin 		 * ----------------------------------------------------
3583628f4d0SDingqiang Lin 		 * |  VendorStorage  |                     |
3593628f4d0SDingqiang Lin 		 * ----------------------------------------------------
3603628f4d0SDingqiang Lin 		 */
3613628f4d0SDingqiang Lin 		lba = NAND_VENDOR_PART_OFFSET;
3623628f4d0SDingqiang Lin 		debug("[Vendor INFO]:VendorStorage offset address=0x%x\n", lba);
3633628f4d0SDingqiang Lin 		break;
3643628f4d0SDingqiang Lin 	case IF_TYPE_SPINOR:
3653628f4d0SDingqiang Lin 		/*
3663628f4d0SDingqiang Lin 		 * The location of VendorStorage in Flash is shown in the
3673628f4d0SDingqiang Lin 		 * following figure. The starting address of the VendorStorage
3683628f4d0SDingqiang Lin 		 * partition offset is 4KB (FLASH_VENDOR_PART_OFFSET * BLOCK_SIZE),
36991441457Sfrancis.fan 		 * and the partition size is 16KB.
37091441457Sfrancis.fan 		 * ----------------------------------------------------
37191441457Sfrancis.fan 		 * |   4KB    |  VendorStorage  |                     |
37291441457Sfrancis.fan 		 * ----------------------------------------------------
37391441457Sfrancis.fan 		 */
37491441457Sfrancis.fan 		lba = FLASH_VENDOR_PART_OFFSET;
375dce239c7SJoseph Chen 		debug("[Vendor INFO]:VendorStorage offset address=0x%x\n", lba);
37691441457Sfrancis.fan 		break;
3771da937e7SYifeng Zhao #ifdef CONFIG_MTD_BLK
3781da937e7SYifeng Zhao 	case IF_TYPE_MTD:
3791da937e7SYifeng Zhao 		/*
3801da937e7SYifeng Zhao 		 * The location of VendorStorage in NAND FLASH or SPI NAND partition "vnvm"
3811da937e7SYifeng Zhao 		 * is shown in the following figure. The partition size is at least  4
3821da937e7SYifeng Zhao 		 * NAND FLASH blocks.
3831da937e7SYifeng Zhao 		 * ----------------------------------------------------
3841da937e7SYifeng Zhao 		 * |   .....    |  vnvm  |  .......                   |
3851da937e7SYifeng Zhao 		 * ----------------------------------------------------
3861da937e7SYifeng Zhao 		 */
3871da937e7SYifeng Zhao 		lba = 0;
3881da937e7SYifeng Zhao 		break;
3891da937e7SYifeng Zhao #endif
39091441457Sfrancis.fan 	default:
391dce239c7SJoseph Chen 		printf("[Vendor ERROR]:Boot device type is invalid!\n");
3921203ea63SJason Zhu 		return -ENODEV;
39391441457Sfrancis.fan 	}
3943628f4d0SDingqiang Lin 	if (write) {
3953628f4d0SDingqiang Lin 		if (_flash_write)
3963628f4d0SDingqiang Lin 			ret = _flash_write(dev_desc, lba + addr, n_sec, buffer);
3973628f4d0SDingqiang Lin 		else
3985bd6dc27SKever Yang 			ret = blk_dwrite(dev_desc, lba + addr, n_sec, buffer);
3993628f4d0SDingqiang Lin 	} else {
4003628f4d0SDingqiang Lin 		if (_flash_read)
4013628f4d0SDingqiang Lin 			ret = _flash_read(dev_desc, lba + addr, n_sec, buffer);
40291441457Sfrancis.fan 		else
4035bd6dc27SKever Yang 			ret = blk_dread(dev_desc, lba + addr, n_sec, buffer);
4043628f4d0SDingqiang Lin 	}
4053628f4d0SDingqiang Lin 
406dce239c7SJoseph Chen 	debug("[Vendor INFO]:op=%s, ret=%d\n", write ? "write" : "read", ret);
40791441457Sfrancis.fan 
40891441457Sfrancis.fan 	return ret;
40991441457Sfrancis.fan }
41091441457Sfrancis.fan 
41191441457Sfrancis.fan /*
41291441457Sfrancis.fan  * The VendorStorage partition is divided into four parts
41391441457Sfrancis.fan  * (vendor 0-3) and its structure is shown in the following figure.
41491441457Sfrancis.fan  * The init function is used to select the latest and valid vendor.
41591441457Sfrancis.fan  *
41691441457Sfrancis.fan  * |******************** FLASH ********************|
41791441457Sfrancis.fan  * -------------------------------------------------
41891441457Sfrancis.fan  * |  vendor0  |  vendor1  |  vendor2  |  vendor3  |
41991441457Sfrancis.fan  * -------------------------------------------------
42091441457Sfrancis.fan  * Notices:
42191441457Sfrancis.fan  *   1. "version" and "version2" are used to verify that the vendor
42291441457Sfrancis.fan  *      is valid (equal is valid).
42391441457Sfrancis.fan  *   2. the "version" value is larger, indicating that the current
42491441457Sfrancis.fan  *      verndor data is new.
42591441457Sfrancis.fan  */
vendor_storage_init(void)42691441457Sfrancis.fan int vendor_storage_init(void)
42791441457Sfrancis.fan {
42891441457Sfrancis.fan 	int ret = 0;
429143a7f24SJoseph Chen 	int ret_size;
43091441457Sfrancis.fan 	u8 *buffer;
43191441457Sfrancis.fan 	u32 size, i;
43291441457Sfrancis.fan 	u32 max_ver = 0;
43391441457Sfrancis.fan 	u32 max_index = 0;
4343628f4d0SDingqiang Lin 	u16 data_offset, hash_offset, part_num;
43591441457Sfrancis.fan 	u16 version2_offset, part_size;
4365bd6dc27SKever Yang 	struct blk_desc *dev_desc;
43791441457Sfrancis.fan 
4385bd6dc27SKever Yang 	dev_desc = rockchip_get_bootdev();
4395bd6dc27SKever Yang 	if (!dev_desc) {
440dce239c7SJoseph Chen 		printf("[Vendor ERROR]:Invalid boot device type(%d)\n",
44191441457Sfrancis.fan 		       bootdev_type);
44291441457Sfrancis.fan 		return -ENODEV;
44391441457Sfrancis.fan 	}
44491441457Sfrancis.fan 
445*5baddfb2SYifeng Zhao 	if (dev_desc->if_type == IF_TYPE_NVME || (dev_desc->if_type == IF_TYPE_SCSI && dev_desc->rawblksz == 512)) {
446efcfb227SYifeng Zhao 		dev_desc = blk_get_devnum_by_type(IF_TYPE_MTD, BLK_MTD_SPI_NOR);
447efcfb227SYifeng Zhao 		if (!dev_desc) {
448efcfb227SYifeng Zhao 			printf("%s: dev_desc is NULL!\n", __func__);
449efcfb227SYifeng Zhao 			return -ENODEV;
450efcfb227SYifeng Zhao 		}
451efcfb227SYifeng Zhao 	}
452efcfb227SYifeng Zhao 
4535bd6dc27SKever Yang 	switch (dev_desc->if_type) {
4545bd6dc27SKever Yang 	case IF_TYPE_MMC:
455*5baddfb2SYifeng Zhao 	case IF_TYPE_SCSI:
45691441457Sfrancis.fan 		size = EMMC_VENDOR_INFO_SIZE;
45791441457Sfrancis.fan 		part_size = EMMC_VENDOR_PART_BLKS;
45891441457Sfrancis.fan 		data_offset = EMMC_VENDOR_DATA_OFFSET;
45991441457Sfrancis.fan 		hash_offset = EMMC_VENDOR_HASH_OFFSET;
46091441457Sfrancis.fan 		version2_offset = EMMC_VENDOR_VERSION2_OFFSET;
4613628f4d0SDingqiang Lin 		part_num = VENDOR_PART_NUM;
46291441457Sfrancis.fan 		break;
4635bd6dc27SKever Yang 	case IF_TYPE_RKNAND:
4645bd6dc27SKever Yang 	case IF_TYPE_SPINAND:
4653628f4d0SDingqiang Lin 		size = NAND_VENDOR_INFO_SIZE;
4663628f4d0SDingqiang Lin 		part_size = NAND_VENDOR_PART_BLKS;
4673628f4d0SDingqiang Lin 		data_offset = NAND_VENDOR_DATA_OFFSET;
4683628f4d0SDingqiang Lin 		hash_offset = NAND_VENDOR_HASH_OFFSET;
4693628f4d0SDingqiang Lin 		version2_offset = NAND_VENDOR_VERSION2_OFFSET;
4703628f4d0SDingqiang Lin 		part_num = NAND_VENDOR_PART_NUM;
4713628f4d0SDingqiang Lin 		break;
4723628f4d0SDingqiang Lin 	case IF_TYPE_SPINOR:
47391441457Sfrancis.fan 		size = FLASH_VENDOR_INFO_SIZE;
47491441457Sfrancis.fan 		part_size = FLASH_VENDOR_PART_BLKS;
47591441457Sfrancis.fan 		data_offset = FLASH_VENDOR_DATA_OFFSET;
47691441457Sfrancis.fan 		hash_offset = FLASH_VENDOR_HASH_OFFSET;
47791441457Sfrancis.fan 		version2_offset = FLASH_VENDOR_VERSION2_OFFSET;
4783628f4d0SDingqiang Lin 		part_num = VENDOR_PART_NUM;
47991441457Sfrancis.fan 		break;
4801da937e7SYifeng Zhao #ifdef CONFIG_MTD_BLK
4811da937e7SYifeng Zhao 	case IF_TYPE_MTD:
4821da937e7SYifeng Zhao 		size = FLASH_VENDOR_INFO_SIZE;
4831da937e7SYifeng Zhao 		part_size = FLASH_VENDOR_PART_BLKS;
4841da937e7SYifeng Zhao 		data_offset = FLASH_VENDOR_DATA_OFFSET;
4851da937e7SYifeng Zhao 		hash_offset = FLASH_VENDOR_HASH_OFFSET;
4861da937e7SYifeng Zhao 		version2_offset = FLASH_VENDOR_VERSION2_OFFSET;
4871da937e7SYifeng Zhao 		part_num = MTD_VENDOR_PART_NUM;
4881da937e7SYifeng Zhao 		_flash_write = mtd_vendor_write;
4891da937e7SYifeng Zhao 		break;
4901da937e7SYifeng Zhao #endif
49191441457Sfrancis.fan 	default:
492dce239c7SJoseph Chen 		debug("[Vendor ERROR]:Boot device type is invalid!\n");
49391441457Sfrancis.fan 		ret = -ENODEV;
49491441457Sfrancis.fan 		break;
49591441457Sfrancis.fan 	}
49691441457Sfrancis.fan 	/* Invalid bootdev type */
49791441457Sfrancis.fan 	if (ret)
49891441457Sfrancis.fan 		return ret;
49972c2cf15SJoseph Chen 
50072c2cf15SJoseph Chen 	/* Initialize */
50172c2cf15SJoseph Chen 	bootdev_type = dev_desc->if_type;
50272c2cf15SJoseph Chen 
5038b5c4985SYifeng Zhao 	/* Always use, no need to release, align to page size for kerenl reserved memory */
5048b5c4985SYifeng Zhao 	buffer = (u8 *)memalign(PAGE_ALGIN_SIZE, size);
50591441457Sfrancis.fan 	if (!buffer) {
506dce239c7SJoseph Chen 		printf("[Vendor ERROR]:Malloc failed!\n");
507ea89190dSJon Lin 		ret = -ENOMEM;
508ea89190dSJon Lin 		goto out;
50991441457Sfrancis.fan 	}
5102a217cf1SYifeng Zhao 
51191441457Sfrancis.fan 	/* Pointer initialization */
51291441457Sfrancis.fan 	vendor_info.hdr = (struct vendor_hdr *)buffer;
51391441457Sfrancis.fan 	vendor_info.item = (struct vendor_item *)(buffer + sizeof(struct vendor_hdr));
51491441457Sfrancis.fan 	vendor_info.data = buffer + data_offset;
51591441457Sfrancis.fan 	vendor_info.hash = (u32 *)(buffer + hash_offset);
51691441457Sfrancis.fan 	vendor_info.version2 = (u32 *)(buffer + version2_offset);
51791441457Sfrancis.fan 
5181da937e7SYifeng Zhao #ifdef CONFIG_MTD_BLK
519ea89190dSJon Lin 	if (dev_desc->if_type == IF_TYPE_MTD) {
520ea89190dSJon Lin 		ret = mtd_vendor_storage_init(dev_desc);
521ea89190dSJon Lin 		goto out;
522ea89190dSJon Lin 	}
5231da937e7SYifeng Zhao #endif
5241da937e7SYifeng Zhao 
52591441457Sfrancis.fan 	/* Find valid and up-to-date one from (vendor0 - vendor3) */
5263628f4d0SDingqiang Lin 	for (i = 0; i < part_num; i++) {
527143a7f24SJoseph Chen 		ret_size = vendor_ops((u8 *)vendor_info.hdr,
528143a7f24SJoseph Chen 				      part_size * i, part_size, 0);
529143a7f24SJoseph Chen 		if (ret_size != part_size) {
530143a7f24SJoseph Chen 			ret = -EIO;
531143a7f24SJoseph Chen 			goto out;
532143a7f24SJoseph Chen 		}
53391441457Sfrancis.fan 
53491441457Sfrancis.fan 		if ((vendor_info.hdr->tag == VENDOR_TAG) &&
53591441457Sfrancis.fan 		    (*(vendor_info.version2) == vendor_info.hdr->version)) {
53691441457Sfrancis.fan 			if (max_ver < vendor_info.hdr->version) {
53791441457Sfrancis.fan 				max_index = i;
53891441457Sfrancis.fan 				max_ver = vendor_info.hdr->version;
53991441457Sfrancis.fan 			}
54091441457Sfrancis.fan 		}
54191441457Sfrancis.fan 	}
542143a7f24SJoseph Chen 
54391441457Sfrancis.fan 	if (max_ver) {
544dce239c7SJoseph Chen 		debug("[Vendor INFO]:max_ver=%d, vendor_id=%d.\n", max_ver, max_index);
54591441457Sfrancis.fan 		/*
54691441457Sfrancis.fan 		 * Keep vendor_info the same as the largest
54791441457Sfrancis.fan 		 * version of vendor
54891441457Sfrancis.fan 		 */
5493628f4d0SDingqiang Lin 		if (max_index != (part_num - 1)) {
550143a7f24SJoseph Chen 			ret_size = vendor_ops((u8 *)vendor_info.hdr,
551143a7f24SJoseph Chen 					       part_size * max_index, part_size, 0);
552143a7f24SJoseph Chen 			if (ret_size != part_size) {
553143a7f24SJoseph Chen 				ret = -EIO;
554143a7f24SJoseph Chen 				goto out;
555143a7f24SJoseph Chen 			}
55672c2cf15SJoseph Chen 		}
55791441457Sfrancis.fan 	} else {
558dce239c7SJoseph Chen 		debug("[Vendor INFO]:Reset vendor info...\n");
55991441457Sfrancis.fan 		memset((u8 *)vendor_info.hdr, 0, size);
56091441457Sfrancis.fan 		vendor_info.hdr->version = 1;
56191441457Sfrancis.fan 		vendor_info.hdr->tag = VENDOR_TAG;
56291441457Sfrancis.fan 		/* data field length */
56334826408SJason Zhu 		vendor_info.hdr->free_size =
56434826408SJason Zhu 			((u32)(size_t)vendor_info.hash
56534826408SJason Zhu 			- (u32)(size_t)vendor_info.data);
56691441457Sfrancis.fan 		*(vendor_info.version2) = vendor_info.hdr->version;
56791441457Sfrancis.fan 	}
568dce239c7SJoseph Chen 	debug("[Vendor INFO]:ret=%d.\n", ret);
56991441457Sfrancis.fan 
570143a7f24SJoseph Chen out:
571ea89190dSJon Lin 	if (ret)
572ea89190dSJon Lin 		bootdev_type = 0;
573ea89190dSJon Lin 
57491441457Sfrancis.fan 	return ret;
57591441457Sfrancis.fan }
57691441457Sfrancis.fan 
vendor_storage_fixup(void * blob)5772a217cf1SYifeng Zhao void vendor_storage_fixup(void *blob)
5782a217cf1SYifeng Zhao {
5792a217cf1SYifeng Zhao 	unsigned long size;
5802a217cf1SYifeng Zhao 	unsigned long start;
58161ad2ee7SJoseph Chen 	int offset;
5822a217cf1SYifeng Zhao 
5832a217cf1SYifeng Zhao 	/* init vendor storage */
5842a217cf1SYifeng Zhao 	if (!bootdev_type) {
5852a217cf1SYifeng Zhao 		if (vendor_storage_init() < 0)
5862a217cf1SYifeng Zhao 			return;
5872a217cf1SYifeng Zhao 	}
5882a217cf1SYifeng Zhao 
5892a217cf1SYifeng Zhao 	offset = fdt_node_offset_by_compatible(blob, 0, "rockchip,vendor-storage-rm");
5902a217cf1SYifeng Zhao 	if (offset >= 0) {
5912a217cf1SYifeng Zhao 		start = (unsigned long)vendor_info.hdr;
5922a217cf1SYifeng Zhao 		size = (unsigned long)((void *)vendor_info.version2 - (void *)vendor_info.hdr);
5932a217cf1SYifeng Zhao 		size += 4;
5942a217cf1SYifeng Zhao 		fdt_update_reserved_memory(blob, "rockchip,vendor-storage-rm",
5952a217cf1SYifeng Zhao 					   (u64)start,
5962a217cf1SYifeng Zhao 					   (u64)size);
5972a217cf1SYifeng Zhao 	}
5982a217cf1SYifeng Zhao }
5992a217cf1SYifeng Zhao 
60072c2cf15SJoseph Chen /*
60172c2cf15SJoseph Chen  * @id: item id, first 4 id is occupied:
60272c2cf15SJoseph Chen  *	VENDOR_SN_ID
60372c2cf15SJoseph Chen  *	VENDOR_WIFI_MAC_ID
60472c2cf15SJoseph Chen  *	VENDOR_LAN_MAC_ID
60572c2cf15SJoseph Chen  *	VENDOR_BLUETOOTH_ID
60672c2cf15SJoseph Chen  * @pbuf: read data buffer;
60772c2cf15SJoseph Chen  * @size: read bytes;
60872c2cf15SJoseph Chen  *
60972c2cf15SJoseph Chen  * return: bytes equal to @size is success, other fail;
61072c2cf15SJoseph Chen  */
vendor_storage_read(u16 id,void * pbuf,u16 size)61191441457Sfrancis.fan int vendor_storage_read(u16 id, void *pbuf, u16 size)
61291441457Sfrancis.fan {
61391441457Sfrancis.fan 	int ret = 0;
61491441457Sfrancis.fan 	u32 i;
61591441457Sfrancis.fan 	u16 offset;
61691441457Sfrancis.fan 	struct vendor_item *item;
61791441457Sfrancis.fan 
61891441457Sfrancis.fan 	/* init vendor storage */
61991441457Sfrancis.fan 	if (!bootdev_type) {
62091441457Sfrancis.fan 		ret = vendor_storage_init();
6211203ea63SJason Zhu 		if (ret < 0)
62291441457Sfrancis.fan 			return ret;
62391441457Sfrancis.fan 	}
62491441457Sfrancis.fan 
62591441457Sfrancis.fan 	item = vendor_info.item;
62691441457Sfrancis.fan 	for (i = 0; i < vendor_info.hdr->item_num; i++) {
62791441457Sfrancis.fan 		if ((item + i)->id == id) {
628dce239c7SJoseph Chen 			debug("[Vendor INFO]:Find the matching item, id=%d\n", id);
62991441457Sfrancis.fan 			/* Correct the size value */
63091441457Sfrancis.fan 			if (size > (item + i)->size)
63191441457Sfrancis.fan 				size = (item + i)->size;
63291441457Sfrancis.fan 			offset = (item + i)->offset;
63391441457Sfrancis.fan 			memcpy(pbuf, (vendor_info.data + offset), size);
63491441457Sfrancis.fan 			return size;
63591441457Sfrancis.fan 		}
63691441457Sfrancis.fan 	}
637dce239c7SJoseph Chen 	debug("[Vendor ERROR]:No matching item, id=%d\n", id);
63891441457Sfrancis.fan 
63991441457Sfrancis.fan 	return -EINVAL;
64091441457Sfrancis.fan }
64191441457Sfrancis.fan 
64272c2cf15SJoseph Chen /*
64372c2cf15SJoseph Chen  * @id: item id, first 4 id is occupied:
64472c2cf15SJoseph Chen  *	VENDOR_SN_ID
64572c2cf15SJoseph Chen  *	VENDOR_WIFI_MAC_ID
64672c2cf15SJoseph Chen  *	VENDOR_LAN_MAC_ID
64772c2cf15SJoseph Chen  *	VENDOR_BLUETOOTH_ID
64872c2cf15SJoseph Chen  * @pbuf: write data buffer;
64972c2cf15SJoseph Chen  * @size: write bytes;
65072c2cf15SJoseph Chen  *
65172c2cf15SJoseph Chen  * return: bytes equal to @size is success, other fail;
65272c2cf15SJoseph Chen  */
vendor_storage_write(u16 id,void * pbuf,u16 size)65391441457Sfrancis.fan int vendor_storage_write(u16 id, void *pbuf, u16 size)
65491441457Sfrancis.fan {
655fc00e536SYifeng Zhao 	u32 i, j, next_index, align_size, alloc_size, next_size;
6563628f4d0SDingqiang Lin 	u16 part_size, max_item_num, offset, part_num;
657fc00e536SYifeng Zhao 	struct vendor_item *item;
658fc00e536SYifeng Zhao 	int cnt, ret = 0;
65991441457Sfrancis.fan 
66091441457Sfrancis.fan 	/* init vendor storage */
66191441457Sfrancis.fan 	if (!bootdev_type) {
66291441457Sfrancis.fan 		ret = vendor_storage_init();
6631203ea63SJason Zhu 		if (ret < 0)
66491441457Sfrancis.fan 			return ret;
66591441457Sfrancis.fan 	}
66691441457Sfrancis.fan 
66791441457Sfrancis.fan 	switch (bootdev_type) {
6685bd6dc27SKever Yang 	case IF_TYPE_MMC:
669*5baddfb2SYifeng Zhao 	case IF_TYPE_SCSI:
67091441457Sfrancis.fan 		part_size = EMMC_VENDOR_PART_BLKS;
67191441457Sfrancis.fan 		max_item_num = EMMC_VENDOR_ITEM_NUM;
6723628f4d0SDingqiang Lin 		part_num = VENDOR_PART_NUM;
67391441457Sfrancis.fan 		break;
6745bd6dc27SKever Yang 	case IF_TYPE_RKNAND:
6755bd6dc27SKever Yang 	case IF_TYPE_SPINAND:
6763628f4d0SDingqiang Lin 		part_size = NAND_VENDOR_PART_BLKS;
6773628f4d0SDingqiang Lin 		max_item_num = NAND_VENDOR_ITEM_NUM;
6783628f4d0SDingqiang Lin 		part_num = NAND_VENDOR_PART_NUM;
6793628f4d0SDingqiang Lin 		break;
6803628f4d0SDingqiang Lin 	case IF_TYPE_SPINOR:
68191441457Sfrancis.fan 		part_size = FLASH_VENDOR_PART_BLKS;
68291441457Sfrancis.fan 		max_item_num = FLASH_VENDOR_ITEM_NUM;
6833628f4d0SDingqiang Lin 		part_num = VENDOR_PART_NUM;
68491441457Sfrancis.fan 		break;
6851da937e7SYifeng Zhao #ifdef CONFIG_MTD_BLK
6861da937e7SYifeng Zhao 	case IF_TYPE_MTD:
6871da937e7SYifeng Zhao 		part_size = FLASH_VENDOR_PART_BLKS;
6881da937e7SYifeng Zhao 		max_item_num = FLASH_VENDOR_ITEM_NUM;
6891da937e7SYifeng Zhao 		part_num = MTD_VENDOR_PART_NUM;
6901da937e7SYifeng Zhao 		break;
6911da937e7SYifeng Zhao #endif
69291441457Sfrancis.fan 	default:
69391441457Sfrancis.fan 		ret = -ENODEV;
69491441457Sfrancis.fan 		break;
69591441457Sfrancis.fan 	}
69691441457Sfrancis.fan 	/* Invalid bootdev? */
6971203ea63SJason Zhu 	if (ret < 0)
69891441457Sfrancis.fan 		return ret;
69991441457Sfrancis.fan 
70091441457Sfrancis.fan 	next_index = vendor_info.hdr->next_index;
70191441457Sfrancis.fan 	/* algin to 64 bytes*/
70291441457Sfrancis.fan 	align_size = (size + VENDOR_BTYE_ALIGN) & (~VENDOR_BTYE_ALIGN);
70391441457Sfrancis.fan 	if (size > align_size)
70491441457Sfrancis.fan 		return -EINVAL;
70591441457Sfrancis.fan 
70691441457Sfrancis.fan 	item = vendor_info.item;
70791441457Sfrancis.fan 	/* If item already exist, update the item data */
70891441457Sfrancis.fan 	for (i = 0; i < vendor_info.hdr->item_num; i++) {
70991441457Sfrancis.fan 		if ((item + i)->id == id) {
710fc00e536SYifeng Zhao 			alloc_size = ((item + i)->size + VENDOR_BTYE_ALIGN) & (~VENDOR_BTYE_ALIGN);
711fc00e536SYifeng Zhao 			if (size > alloc_size) {
712fc00e536SYifeng Zhao 				if (vendor_info.hdr->free_size < align_size)
713fc00e536SYifeng Zhao 					return -EINVAL;
714fc00e536SYifeng Zhao 				debug("[Vendor INFO]:Find the matching item, id=%d and resize\n", id);
715fc00e536SYifeng Zhao 				offset = (item + i)->offset;
716fc00e536SYifeng Zhao 				for (j = i; j < vendor_info.hdr->item_num - 1; j++) {
717fc00e536SYifeng Zhao 					(item + j)->id = (item + j + 1)->id;
718fc00e536SYifeng Zhao 					(item + j)->size = (item + j + 1)->size;
719fc00e536SYifeng Zhao 					(item + j)->offset = offset;
720fc00e536SYifeng Zhao 
721fc00e536SYifeng Zhao 					next_size = ((item + j + 1)->size + VENDOR_BTYE_ALIGN) & (~VENDOR_BTYE_ALIGN);
722fc00e536SYifeng Zhao 					memcpy((vendor_info.data + offset),
723fc00e536SYifeng Zhao 					       (vendor_info.data + (item + j + 1)->offset),
724fc00e536SYifeng Zhao 					       next_size);
725fc00e536SYifeng Zhao 					offset += next_size;
726fc00e536SYifeng Zhao 				}
727fc00e536SYifeng Zhao 				(item + j)->id = id;
728fc00e536SYifeng Zhao 				(item + j)->offset = offset;
729fc00e536SYifeng Zhao 				(item + j)->size = size;
730fc00e536SYifeng Zhao 				memcpy((vendor_info.data + offset), pbuf, size);
731fc00e536SYifeng Zhao 				vendor_info.hdr->free_offset = offset + align_size;
732fc00e536SYifeng Zhao 				vendor_info.hdr->free_size -= align_size - alloc_size;
733fc00e536SYifeng Zhao 			} else {
734dce239c7SJoseph Chen 				debug("[Vendor INFO]:Find the matching item, id=%d\n", id);
73591441457Sfrancis.fan 				offset = (item + i)->offset;
73691441457Sfrancis.fan 				memcpy((vendor_info.data + offset), pbuf, size);
73791441457Sfrancis.fan 				(item + i)->size = size;
738fc00e536SYifeng Zhao 			}
73991441457Sfrancis.fan 			vendor_info.hdr->version++;
74091441457Sfrancis.fan 			*(vendor_info.version2) = vendor_info.hdr->version;
74191441457Sfrancis.fan 			vendor_info.hdr->next_index++;
7423628f4d0SDingqiang Lin 			if (vendor_info.hdr->next_index >= part_num)
74391441457Sfrancis.fan 				vendor_info.hdr->next_index = 0;
74472c2cf15SJoseph Chen 			cnt = vendor_ops((u8 *)vendor_info.hdr, part_size * next_index, part_size, 1);
74572c2cf15SJoseph Chen 			return (cnt == part_size) ? size : -EIO;
74691441457Sfrancis.fan 		}
74791441457Sfrancis.fan 	}
74891441457Sfrancis.fan 	/*
74991441457Sfrancis.fan 	 * If item does not exist, and free size is enough,
75091441457Sfrancis.fan 	 * creat a new one
75191441457Sfrancis.fan 	 */
75291441457Sfrancis.fan 	if ((vendor_info.hdr->item_num < max_item_num) &&
75391441457Sfrancis.fan 	    (vendor_info.hdr->free_size >= align_size)) {
754dce239c7SJoseph Chen 		debug("[Vendor INFO]:Create new Item, id=%d\n", id);
75591441457Sfrancis.fan 		item = vendor_info.item + vendor_info.hdr->item_num;
75691441457Sfrancis.fan 		item->id = id;
75791441457Sfrancis.fan 		item->offset = vendor_info.hdr->free_offset;
75891441457Sfrancis.fan 		item->size = size;
75991441457Sfrancis.fan 
76091441457Sfrancis.fan 		vendor_info.hdr->free_offset += align_size;
76191441457Sfrancis.fan 		vendor_info.hdr->free_size -= align_size;
76291441457Sfrancis.fan 		memcpy((vendor_info.data + item->offset), pbuf, size);
76391441457Sfrancis.fan 		vendor_info.hdr->item_num++;
76491441457Sfrancis.fan 		vendor_info.hdr->version++;
76591441457Sfrancis.fan 		vendor_info.hdr->next_index++;
76691441457Sfrancis.fan 		*(vendor_info.version2) = vendor_info.hdr->version;
7673628f4d0SDingqiang Lin 		if (vendor_info.hdr->next_index >= part_num)
76891441457Sfrancis.fan 			vendor_info.hdr->next_index = 0;
76991441457Sfrancis.fan 
77072c2cf15SJoseph Chen 		cnt = vendor_ops((u8 *)vendor_info.hdr, part_size * next_index, part_size, 1);
77172c2cf15SJoseph Chen 		return (cnt == part_size) ? size : -EIO;
77291441457Sfrancis.fan 	}
773dce239c7SJoseph Chen 	debug("[Vendor ERROR]:Vendor has no space left!\n");
77491441457Sfrancis.fan 
77591441457Sfrancis.fan 	return -ENOMEM;
77691441457Sfrancis.fan }
77791441457Sfrancis.fan 
77891441457Sfrancis.fan /**********************************************************/
77991441457Sfrancis.fan /*              vendor API uinit test                      */
78091441457Sfrancis.fan /**********************************************************/
78191441457Sfrancis.fan /* Reset the vendor storage space to the initial state */
vendor_test_reset(void)782143a7f24SJoseph Chen static void vendor_test_reset(void)
78391441457Sfrancis.fan {
7843628f4d0SDingqiang Lin 	u16 i, part_size, part_num;
78591441457Sfrancis.fan 	u32 size;
78691441457Sfrancis.fan 
78791441457Sfrancis.fan 	switch (bootdev_type) {
7885bd6dc27SKever Yang 	case IF_TYPE_MMC:
789*5baddfb2SYifeng Zhao 	case IF_TYPE_SCSI:
79091441457Sfrancis.fan 		size = EMMC_VENDOR_INFO_SIZE;
79191441457Sfrancis.fan 		part_size = EMMC_VENDOR_PART_BLKS;
7923628f4d0SDingqiang Lin 		part_num = VENDOR_PART_NUM;
79391441457Sfrancis.fan 		break;
7945bd6dc27SKever Yang 	case IF_TYPE_RKNAND:
7955bd6dc27SKever Yang 	case IF_TYPE_SPINAND:
7963628f4d0SDingqiang Lin 		size = NAND_VENDOR_INFO_SIZE;
7973628f4d0SDingqiang Lin 		part_size = NAND_VENDOR_PART_BLKS;
7983628f4d0SDingqiang Lin 		part_num = NAND_VENDOR_PART_NUM;
7993628f4d0SDingqiang Lin 		break;
8003628f4d0SDingqiang Lin 	case IF_TYPE_SPINOR:
80191441457Sfrancis.fan 		size = FLASH_VENDOR_INFO_SIZE;
80291441457Sfrancis.fan 		part_size = FLASH_VENDOR_PART_BLKS;
8033628f4d0SDingqiang Lin 		part_num = VENDOR_PART_NUM;
80491441457Sfrancis.fan 		break;
80591441457Sfrancis.fan 	default:
80691441457Sfrancis.fan 		size = 0;
80791441457Sfrancis.fan 		part_size = 0;
80891441457Sfrancis.fan 		break;
80991441457Sfrancis.fan 	}
81091441457Sfrancis.fan 	/* Invalid bootdev? */
81191441457Sfrancis.fan 	if (!size)
81291441457Sfrancis.fan 		return;
81391441457Sfrancis.fan 
81491441457Sfrancis.fan 	memset((u8 *)vendor_info.hdr, 0, size);
81591441457Sfrancis.fan 	vendor_info.hdr->version = 1;
81691441457Sfrancis.fan 	vendor_info.hdr->tag = VENDOR_TAG;
81791441457Sfrancis.fan 	/* data field length */
818426b906cSJoseph Chen 	vendor_info.hdr->free_size = (unsigned long)vendor_info.hash -
819426b906cSJoseph Chen 				     (unsigned long)vendor_info.data;
82091441457Sfrancis.fan 	*(vendor_info.version2) = vendor_info.hdr->version;
82191441457Sfrancis.fan 	/* write to flash. */
8223628f4d0SDingqiang Lin 	for (i = 0; i < part_num; i++)
82391441457Sfrancis.fan 		vendor_ops((u8 *)vendor_info.hdr, part_size * i, part_size, 1);
82491441457Sfrancis.fan }
82591441457Sfrancis.fan 
82691441457Sfrancis.fan /*
82791441457Sfrancis.fan  * A total of four tests
82891441457Sfrancis.fan  * 1.All items test.
82991441457Sfrancis.fan  * 2.Overrides the maximum number of items test.
83091441457Sfrancis.fan  * 3.Single Item memory overflow test.
83191441457Sfrancis.fan  * 4.Total memory overflow test.
83291441457Sfrancis.fan  */
vendor_storage_test(void)83391441457Sfrancis.fan int vendor_storage_test(void)
83491441457Sfrancis.fan {
83591441457Sfrancis.fan 	u16 id, size, j, item_num;
83691441457Sfrancis.fan 	u32 total_size;
83791441457Sfrancis.fan 	u8 *buffer = NULL;
83891441457Sfrancis.fan 	int ret = 0;
83991441457Sfrancis.fan 
840143a7f24SJoseph Chen 	if (!bootdev_type) {
841143a7f24SJoseph Chen 		ret = vendor_storage_init();
842143a7f24SJoseph Chen 		if (ret) {
843143a7f24SJoseph Chen 			printf("%s: vendor storage init failed, ret=%d\n",
844143a7f24SJoseph Chen 			       __func__, ret);
845143a7f24SJoseph Chen 			return ret;
846143a7f24SJoseph Chen 		}
847143a7f24SJoseph Chen 	}
848143a7f24SJoseph Chen 
84991441457Sfrancis.fan 	/*
85091441457Sfrancis.fan 	 * Calculate the maximum number of items and the maximum
85191441457Sfrancis.fan 	 * allocable memory for each item.
85291441457Sfrancis.fan 	 */
85391441457Sfrancis.fan 	switch (bootdev_type) {
8545bd6dc27SKever Yang 	case IF_TYPE_MMC:
855*5baddfb2SYifeng Zhao 	case IF_TYPE_SCSI:
85691441457Sfrancis.fan 		item_num = EMMC_VENDOR_ITEM_NUM;
857426b906cSJoseph Chen 		total_size = (unsigned long)vendor_info.hash -
858426b906cSJoseph Chen 			     (unsigned long)vendor_info.data;
85991441457Sfrancis.fan 		size = total_size / item_num;
86091441457Sfrancis.fan 		break;
8615bd6dc27SKever Yang 	case IF_TYPE_RKNAND:
8625bd6dc27SKever Yang 	case IF_TYPE_SPINAND:
8633628f4d0SDingqiang Lin 		item_num = NAND_VENDOR_ITEM_NUM;
8643628f4d0SDingqiang Lin 		total_size = (unsigned long)vendor_info.hash -
8653628f4d0SDingqiang Lin 			     (unsigned long)vendor_info.data;
8663628f4d0SDingqiang Lin 		size = total_size / item_num;
8673628f4d0SDingqiang Lin 		break;
8683628f4d0SDingqiang Lin 	case IF_TYPE_SPINOR:
8691da937e7SYifeng Zhao 	case IF_TYPE_MTD:
87091441457Sfrancis.fan 		item_num = FLASH_VENDOR_ITEM_NUM;
871426b906cSJoseph Chen 		total_size = (unsigned long)vendor_info.hash -
872426b906cSJoseph Chen 			     (unsigned long)vendor_info.data;
87391441457Sfrancis.fan 		size = total_size / item_num;
87491441457Sfrancis.fan 		break;
87591441457Sfrancis.fan 	default:
876ac408c8eSJoseph Chen 		item_num = 0;
87791441457Sfrancis.fan 		total_size = 0;
878ae973818SJeffy Chen 		size = 0;
87991441457Sfrancis.fan 		break;
88091441457Sfrancis.fan 	}
88191441457Sfrancis.fan 	/* Invalid bootdev? */
88291441457Sfrancis.fan 	if (!total_size)
88391441457Sfrancis.fan 		return -ENODEV;
88491441457Sfrancis.fan 	/* 64 bytes are aligned and rounded down */
8851da937e7SYifeng Zhao 	if (size > 64)
88691441457Sfrancis.fan 		size = (size / 64) * 64;
88791441457Sfrancis.fan 	/* malloc memory */
88891441457Sfrancis.fan 	buffer = (u8 *)malloc(size);
88991441457Sfrancis.fan 	if (!buffer) {
89091441457Sfrancis.fan 		printf("[Vendor Test]:Malloc failed(size=%d)!\n", size);
89191441457Sfrancis.fan 		return -ENOMEM;
89291441457Sfrancis.fan 	}
89391441457Sfrancis.fan 	printf("[Vendor Test]:Test Start...\n");
89491441457Sfrancis.fan 	printf("[Vendor Test]:Before Test, Vendor Resetting.\n");
8951da937e7SYifeng Zhao 	if (bootdev_type != IF_TYPE_MTD)
89691441457Sfrancis.fan 		vendor_test_reset();
89791441457Sfrancis.fan 
89891441457Sfrancis.fan 	/* FIRST TEST: test all items can be used correctly */
89991441457Sfrancis.fan 	printf("[Vendor Test]:<All Items Used> Test Start...\n");
9001da937e7SYifeng Zhao 	printf("[Vendor Test]:item_num=%d, size=%d.\n", item_num, size);
90191441457Sfrancis.fan 	/*
90291441457Sfrancis.fan 	 * Write data, then read the data, and compare the
90391441457Sfrancis.fan 	 * data consistency
90491441457Sfrancis.fan 	 */
90591441457Sfrancis.fan 	for (id = 0; id < item_num; id++) {
90691441457Sfrancis.fan 		memset(buffer, id, size);
90791441457Sfrancis.fan 		ret = vendor_storage_write(id, buffer, size);
9081203ea63SJason Zhu 		if (ret < 0) {
90991441457Sfrancis.fan 			printf("[Vendor Test]:vendor write failed(id=%d)!\n", id);
91091441457Sfrancis.fan 			free(buffer);
91191441457Sfrancis.fan 			return ret;
91291441457Sfrancis.fan 		}
91391441457Sfrancis.fan 	}
91491441457Sfrancis.fan 	/* Read data */
91591441457Sfrancis.fan 	for (id = 0; id < item_num; id++) {
91691441457Sfrancis.fan 		memset(buffer, 0, size);
91791441457Sfrancis.fan 		ret = vendor_storage_read(id, buffer, size);
91872c2cf15SJoseph Chen 		if (ret < 0) {
91991441457Sfrancis.fan 			printf("[Vendor Test]:vendor read failed(id=%d)!\n", id);
92091441457Sfrancis.fan 			free(buffer);
92191441457Sfrancis.fan 			return ret;
92291441457Sfrancis.fan 		}
92391441457Sfrancis.fan 		/* check data Correctness */
92491441457Sfrancis.fan 		for (j = 0; j < size; j++) {
92591441457Sfrancis.fan 			if (*(buffer + j) != id) {
92691441457Sfrancis.fan 				printf("[Vendor Test]:Unexpected error occurs(id=%d)\n", id);
92791441457Sfrancis.fan 				printf("the data content is:\n");
92891441457Sfrancis.fan 				print_buffer(0, buffer, 1, size, 16);
92991441457Sfrancis.fan 
93091441457Sfrancis.fan 				free(buffer);
93191441457Sfrancis.fan 				return -1;
93291441457Sfrancis.fan 			}
93391441457Sfrancis.fan 		}
93491441457Sfrancis.fan 		debug("\t#id=%03d success,data=0x%02x,size=%d.\n", id, *buffer, size);
93591441457Sfrancis.fan 	}
93691441457Sfrancis.fan 	printf("[Vendor Test]:<All Items Used> Test End,States:OK\n");
93791441457Sfrancis.fan 
9381da937e7SYifeng Zhao 	printf("[Vendor Test]:<All Items Used> re init,States:OK\n");
9391da937e7SYifeng Zhao 	ret = vendor_storage_init();
9401da937e7SYifeng Zhao 	/* Read data */
9411da937e7SYifeng Zhao 	for (id = 0; id < item_num; id++) {
9421da937e7SYifeng Zhao 		memset(buffer, 0, size);
9431da937e7SYifeng Zhao 		ret = vendor_storage_read(id, buffer, size);
9441da937e7SYifeng Zhao 		if (ret < 0) {
9451da937e7SYifeng Zhao 			printf("[Vendor Test]:vendor read failed(id=%d)!\n", id);
9461da937e7SYifeng Zhao 			free(buffer);
9471da937e7SYifeng Zhao 			return ret;
9481da937e7SYifeng Zhao 		}
9491da937e7SYifeng Zhao 		/* check data Correctness */
9501da937e7SYifeng Zhao 		for (j = 0; j < size; j++) {
9511da937e7SYifeng Zhao 			if (*(buffer + j) != id) {
9521da937e7SYifeng Zhao 				printf("[Vendor Test]:Unexpected error occurs(id=%d)\n", id);
9531da937e7SYifeng Zhao 				printf("the data content is:\n");
9541da937e7SYifeng Zhao 				print_buffer(0, buffer, 1, size, 16);
9551da937e7SYifeng Zhao 
9561da937e7SYifeng Zhao 				free(buffer);
9571da937e7SYifeng Zhao 				return -1;
9581da937e7SYifeng Zhao 			}
9591da937e7SYifeng Zhao 		}
9601da937e7SYifeng Zhao 		debug("\t#id=%03d success,data=0x%02x,size=%d.\n", id, *buffer, size);
9611da937e7SYifeng Zhao 	}
9621da937e7SYifeng Zhao 	printf("[Vendor Test]:<All Items Used> Test End,States:OK\n");
9631da937e7SYifeng Zhao #ifdef CONFIG_MTD_BLK
9641da937e7SYifeng Zhao 	if (bootdev_type == IF_TYPE_MTD)
9651da937e7SYifeng Zhao 		return 0;
9661da937e7SYifeng Zhao #endif
96791441457Sfrancis.fan 	/*
96891441457Sfrancis.fan 	 * SECOND TEST: Overrides the maximum number of items to see if the
96991441457Sfrancis.fan 	 * return value matches the expectation
97091441457Sfrancis.fan 	 */
97191441457Sfrancis.fan 	printf("[Vendor Test]:<Overflow Items Cnt> Test Start...\n");
97291441457Sfrancis.fan 	/* Any id value that was not used before */
97391441457Sfrancis.fan 	id = item_num;
97491441457Sfrancis.fan 	printf("[Vendor Test]:id=%d, size=%d.\n", id, size);
97591441457Sfrancis.fan 	ret = vendor_storage_write(id, buffer, size);
97691441457Sfrancis.fan 	if (ret == -ENOMEM)
97791441457Sfrancis.fan 		printf("[Vendor Test]:<Overflow Items Cnt> Test End,States:OK\n");
97891441457Sfrancis.fan 	else
97991441457Sfrancis.fan 		printf("[Vendor Test]:<Overflow Items Cnt> Test End,States:Failed\n");
98091441457Sfrancis.fan 
98191441457Sfrancis.fan 	/* free buffer, remalloc later */
98291441457Sfrancis.fan 	free(buffer);
98391441457Sfrancis.fan 	buffer = NULL;
98491441457Sfrancis.fan 	/*
98591441457Sfrancis.fan 	 * remalloc memory and recalculate size to test memory overflow
98691441457Sfrancis.fan 	 * (1) item_num > 10: Memory is divided into 10 blocks,
98791441457Sfrancis.fan 	 * 11th memory will overflow.
98891441457Sfrancis.fan 	 * (2) 10 > item_num > 1: Memory is divided into item_num-1
98991441457Sfrancis.fan 	 * blocks. item_num block, memory will overflow.
99091441457Sfrancis.fan 	 * (3) item_num = 1: size = total_size + 512 Bytes, The first
99191441457Sfrancis.fan 	 * block, memory will overflow.
99291441457Sfrancis.fan 	 * The reason to do so is to minimize the size of the memory,
99391441457Sfrancis.fan 	 * making malloc easier to perform successfully.
99491441457Sfrancis.fan 	 */
99591441457Sfrancis.fan 	item_num = (item_num > 10) ? 10 : (item_num - 1);
99691441457Sfrancis.fan 	size = item_num ? (total_size / item_num) : (total_size + 512);
99791441457Sfrancis.fan 	size = (size + VENDOR_BTYE_ALIGN) & (~VENDOR_BTYE_ALIGN);
99891441457Sfrancis.fan 	/* Find item_num value that can make the memory overflow */
99991441457Sfrancis.fan 	for (id = 0; id <= item_num; id++) {
100091441457Sfrancis.fan 		if (((id + 1) * size) > total_size) {
100191441457Sfrancis.fan 			item_num = id;
100291441457Sfrancis.fan 			break;
100391441457Sfrancis.fan 		}
100491441457Sfrancis.fan 	}
100591441457Sfrancis.fan 	/* malloc */
100691441457Sfrancis.fan 	buffer = (u8 *)malloc(size);
100791441457Sfrancis.fan 	if (buffer == NULL) {
100891441457Sfrancis.fan 		printf("[Vendor Test]:Malloc failed(size=%d)!\n", size);
100991441457Sfrancis.fan 		return -ENOMEM;
101091441457Sfrancis.fan 	}
101191441457Sfrancis.fan 
101291441457Sfrancis.fan 	/* THIRD TEST: Single Item memory overflow test */
101391441457Sfrancis.fan 	printf("[Vendor Test]:<Single Item Memory Overflow> Test Start...\n");
101491441457Sfrancis.fan 	/* The value can be arbitrary */
101591441457Sfrancis.fan 	memset(buffer, 'a', size);
101691441457Sfrancis.fan 	/* Any id value that was used before */
101791441457Sfrancis.fan 	id = 0;
101891441457Sfrancis.fan 	printf("[Vendor Test]:id=%d, size=%d.\n", id, size);
101991441457Sfrancis.fan 	ret = vendor_storage_write(id, buffer, size);
10201203ea63SJason Zhu 	if (ret == size)
102191441457Sfrancis.fan 		printf("[Vendor Test]:<Single Item Memory Overflow> Test End, States:OK\n");
102291441457Sfrancis.fan 	else
102391441457Sfrancis.fan 		printf("[Vendor Test]:<Single Item Memory Overflow> Test End, States:Failed\n");
102491441457Sfrancis.fan 
102591441457Sfrancis.fan 	/* FORTH TEST: Total memory overflow test */
102691441457Sfrancis.fan 	printf("[Vendor Test]:<Total memory overflow> Test Start...\n");
102791441457Sfrancis.fan 	printf("[Vendor Test]:item_num=%d, size=%d.\n", item_num, size);
102891441457Sfrancis.fan 
102991441457Sfrancis.fan 	vendor_test_reset();
10303628f4d0SDingqiang Lin 	for (id = 0; id < item_num; id++) {
103191441457Sfrancis.fan 		memset(buffer, id, size);
103291441457Sfrancis.fan 		ret = vendor_storage_write(id, buffer, size);
10331203ea63SJason Zhu 		if (ret < 0) {
103491441457Sfrancis.fan 			if ((id == item_num) && (ret == -ENOMEM)) {
103591441457Sfrancis.fan 				printf("[Vendor Test]:<Total memory overflow> Test End, States:OK\n");
103691441457Sfrancis.fan 				break;
103791441457Sfrancis.fan 			} else {
103891441457Sfrancis.fan 				printf("[Vendor Test]:<Total memory overflow> Test End, States:Failed\n");
103991441457Sfrancis.fan 				break;
104091441457Sfrancis.fan 			}
104191441457Sfrancis.fan 		}
104291441457Sfrancis.fan 		debug("\t#id=%03d success,data=0x%02x,size=%d.\n", id, *buffer, size);
104391441457Sfrancis.fan 	}
104491441457Sfrancis.fan 
104591441457Sfrancis.fan 	/* Test end */
104691441457Sfrancis.fan 	printf("[Vendor Test]:After Test, Vendor Resetting...\n");
104791441457Sfrancis.fan 	vendor_test_reset();
104891441457Sfrancis.fan 	printf("[Vendor Test]:Test End.\n");
104991441457Sfrancis.fan 	free(buffer);
105091441457Sfrancis.fan 
105191441457Sfrancis.fan 	return 0;
105291441457Sfrancis.fan }
1053