xref: /rk3399_rockchip-uboot/drivers/usb/gadget/f_rockusb.c (revision a1b07e70833e1cdf40d400a1060374e5e7623878)
1f16e43f8SFrank Wang /*
2f16e43f8SFrank Wang  * Copyright 2017 Rockchip Electronics Co., Ltd
3f16e43f8SFrank Wang  * Frank Wang <frank.wang@rock-chips.com>
4f16e43f8SFrank Wang  *
5f16e43f8SFrank Wang  * SPDX-License-Identifier:	GPL-2.0+
6f16e43f8SFrank Wang  */
7f16e43f8SFrank Wang 
8866d7966SJoseph Chen #include <asm/io.h>
92122174dSWu Liangqing #include <android_avb/avb_ops_user.h>
102122174dSWu Liangqing #include <android_avb/rk_avb_ops_user.h>
11866d7966SJoseph Chen #include <asm/arch/boot_mode.h>
12829f2b85SFrank Wang #include <asm/arch/chip_info.h>
13d4cce25eSYifeng Zhao #include <asm/arch/rk_atags.h>
14dfbf26e8STony Xu #include <write_keybox.h>
15e66d4537SJon Lin #include <linux/mtd/mtd.h>
16850ced9dSHisping Lin #include <optee_include/OpteeClientInterface.h>
178168f857SYifeng Zhao #include <dm.h>
188168f857SYifeng Zhao #include <misc.h>
194d2787f5SJon Lin #include <mmc.h>
201b375c35SYifeng Zhao #include <scsi.h>
214d2787f5SJon Lin #include <stdlib.h>
228c6654f1SJon Lin #include <usbplug.h>
230d0c3248SFrank Wang 
240d0c3248SFrank Wang #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION
250d0c3248SFrank Wang #include <asm/arch/vendor.h>
260d0c3248SFrank Wang #endif
27f16e43f8SFrank Wang #include <rockusb.h>
28f16e43f8SFrank Wang 
29f16e43f8SFrank Wang #define ROCKUSB_INTERFACE_CLASS	0xff
30f16e43f8SFrank Wang #define ROCKUSB_INTERFACE_SUB_CLASS	0x06
31f16e43f8SFrank Wang #define ROCKUSB_INTERFACE_PROTOCOL	0x05
32f16e43f8SFrank Wang 
33e66d4537SJon Lin #define ROCKCHIP_FLASH_BLOCK_SIZE	1024
34e66d4537SJon Lin #define ROCKCHIP_FLASH_PAGE_SIZE	4
35e66d4537SJon Lin 
36f16e43f8SFrank Wang static struct usb_interface_descriptor rkusb_intf_desc = {
37f16e43f8SFrank Wang 	.bLength		= USB_DT_INTERFACE_SIZE,
38f16e43f8SFrank Wang 	.bDescriptorType	= USB_DT_INTERFACE,
39f16e43f8SFrank Wang 	.bInterfaceNumber	= 0x00,
40f16e43f8SFrank Wang 	.bAlternateSetting	= 0x00,
41f16e43f8SFrank Wang 	.bNumEndpoints		= 0x02,
42f16e43f8SFrank Wang 	.bInterfaceClass	= ROCKUSB_INTERFACE_CLASS,
43f16e43f8SFrank Wang 	.bInterfaceSubClass	= ROCKUSB_INTERFACE_SUB_CLASS,
44f16e43f8SFrank Wang 	.bInterfaceProtocol	= ROCKUSB_INTERFACE_PROTOCOL,
45f16e43f8SFrank Wang };
46f16e43f8SFrank Wang 
47f16e43f8SFrank Wang static struct usb_descriptor_header *rkusb_fs_function[] = {
48f16e43f8SFrank Wang 	(struct usb_descriptor_header *)&rkusb_intf_desc,
49f16e43f8SFrank Wang 	(struct usb_descriptor_header *)&fsg_fs_bulk_in_desc,
50f16e43f8SFrank Wang 	(struct usb_descriptor_header *)&fsg_fs_bulk_out_desc,
51f16e43f8SFrank Wang 	NULL,
52f16e43f8SFrank Wang };
53f16e43f8SFrank Wang 
54f16e43f8SFrank Wang static struct usb_descriptor_header *rkusb_hs_function[] = {
55f16e43f8SFrank Wang 	(struct usb_descriptor_header *)&rkusb_intf_desc,
56f16e43f8SFrank Wang 	(struct usb_descriptor_header *)&fsg_hs_bulk_in_desc,
57f16e43f8SFrank Wang 	(struct usb_descriptor_header *)&fsg_hs_bulk_out_desc,
58f16e43f8SFrank Wang 	NULL,
59f16e43f8SFrank Wang };
60f16e43f8SFrank Wang 
6126dd3474SWilliam Wu static struct usb_descriptor_header *rkusb_ss_function[] = {
6226dd3474SWilliam Wu 	(struct usb_descriptor_header *)&rkusb_intf_desc,
6326dd3474SWilliam Wu 	(struct usb_descriptor_header *)&fsg_ss_bulk_in_desc,
6426dd3474SWilliam Wu 	(struct usb_descriptor_header *)&fsg_ss_bulk_in_comp_desc,
6526dd3474SWilliam Wu 	(struct usb_descriptor_header *)&fsg_ss_bulk_out_desc,
6626dd3474SWilliam Wu 	(struct usb_descriptor_header *)&fsg_ss_bulk_out_comp_desc,
6726dd3474SWilliam Wu 	NULL,
6826dd3474SWilliam Wu };
6926dd3474SWilliam Wu 
70f16e43f8SFrank Wang struct rk_flash_info {
71f16e43f8SFrank Wang 	u32	flash_size;
72f16e43f8SFrank Wang 	u16	block_size;
73f16e43f8SFrank Wang 	u8	page_size;
74f16e43f8SFrank Wang 	u8	ecc_bits;
75f16e43f8SFrank Wang 	u8	access_time;
76f16e43f8SFrank Wang 	u8	manufacturer;
77f16e43f8SFrank Wang 	u8	flash_mask;
78f16e43f8SFrank Wang } __packed;
79f16e43f8SFrank Wang 
805b081643SFrank Wang static int rkusb_rst_code; /* The subcode in reset command (0xFF) */
815b081643SFrank Wang 
82f16e43f8SFrank Wang int g_dnl_bind_fixup(struct usb_device_descriptor *dev, const char *name)
83f16e43f8SFrank Wang {
84ba437c8cSFrank Wang 	if (IS_RKUSB_UMS_DNL(name)) {
85c0acb0f2SFrank Wang 		/* Fix to Rockchip's VID and PID */
86ba437c8cSFrank Wang 		dev->idVendor  = __constant_cpu_to_le16(0x2207);
87ba437c8cSFrank Wang 		dev->idProduct = __constant_cpu_to_le16(CONFIG_ROCKUSB_G_DNL_PID);
88ba437c8cSFrank Wang 
89f16e43f8SFrank Wang 		/* Enumerate as a loader device */
9095424692SJoseph Chen #if defined(CONFIG_SUPPORT_USBPLUG)
9195424692SJoseph Chen 		dev->bcdUSB = cpu_to_le16(0x0200);
9295424692SJoseph Chen #else
93f16e43f8SFrank Wang 		dev->bcdUSB = cpu_to_le16(0x0201);
9495424692SJoseph Chen #endif
95c0acb0f2SFrank Wang 	} else if (!strncmp(name, "usb_dnl_fastboot", 16)) {
96c0acb0f2SFrank Wang 		/* Fix to Google's VID and PID */
97c0acb0f2SFrank Wang 		dev->idVendor  = __constant_cpu_to_le16(0x18d1);
98c0acb0f2SFrank Wang 		dev->idProduct = __constant_cpu_to_le16(0xd00d);
99ca422507SYifeng Zhao 	} else if (!strncmp(name, "usb_dnl_dfu", 11)) {
100ca422507SYifeng Zhao 		/* Fix to Rockchip's VID and PID for DFU */
101ca422507SYifeng Zhao 		dev->idVendor  = cpu_to_le16(0x2207);
102ca422507SYifeng Zhao 		dev->idProduct = cpu_to_le16(0x0107);
1030a076251SFrank Wang 	} else if (!strncmp(name, "usb_dnl_ums", 11)) {
1040a076251SFrank Wang 		dev->idVendor  = cpu_to_le16(0x2207);
1050a076251SFrank Wang 		dev->idProduct = cpu_to_le16(0x0010);
106ba437c8cSFrank Wang 	}
107f16e43f8SFrank Wang 
108f16e43f8SFrank Wang 	return 0;
109f16e43f8SFrank Wang }
110f16e43f8SFrank Wang 
111f16e43f8SFrank Wang __maybe_unused
112f16e43f8SFrank Wang static inline void dump_cbw(struct fsg_bulk_cb_wrap *cbw)
113f16e43f8SFrank Wang {
114f16e43f8SFrank Wang 	assert(!cbw);
115f16e43f8SFrank Wang 
116f16e43f8SFrank Wang 	debug("%s:\n", __func__);
117f16e43f8SFrank Wang 	debug("Signature %x\n", cbw->Signature);
118f16e43f8SFrank Wang 	debug("Tag %x\n", cbw->Tag);
119f16e43f8SFrank Wang 	debug("DataTransferLength %x\n", cbw->DataTransferLength);
120f16e43f8SFrank Wang 	debug("Flags %x\n", cbw->Flags);
121f16e43f8SFrank Wang 	debug("LUN %x\n", cbw->Lun);
122f16e43f8SFrank Wang 	debug("Length %x\n", cbw->Length);
123f16e43f8SFrank Wang 	debug("OptionCode %x\n", cbw->CDB[0]);
124f16e43f8SFrank Wang 	debug("SubCode %x\n", cbw->CDB[1]);
125f16e43f8SFrank Wang 	debug("SectorAddr %x\n", get_unaligned_be32(&cbw->CDB[2]));
126f16e43f8SFrank Wang 	debug("BlkSectors %x\n\n", get_unaligned_be16(&cbw->CDB[7]));
127f16e43f8SFrank Wang }
128f16e43f8SFrank Wang 
129f16e43f8SFrank Wang static int rkusb_check_lun(struct fsg_common *common)
130f16e43f8SFrank Wang {
131f16e43f8SFrank Wang 	struct fsg_lun *curlun;
132f16e43f8SFrank Wang 
133f16e43f8SFrank Wang 	/* Check the LUN */
134f16e43f8SFrank Wang 	if (common->lun >= 0 && common->lun < common->nluns) {
135f16e43f8SFrank Wang 		curlun = &common->luns[common->lun];
136f16e43f8SFrank Wang 		if (common->cmnd[0] != SC_REQUEST_SENSE) {
137f16e43f8SFrank Wang 			curlun->sense_data = SS_NO_SENSE;
138f16e43f8SFrank Wang 			curlun->info_valid = 0;
139f16e43f8SFrank Wang 		}
140f16e43f8SFrank Wang 	} else {
141f16e43f8SFrank Wang 		curlun = NULL;
142f16e43f8SFrank Wang 		common->bad_lun_okay = 0;
143f16e43f8SFrank Wang 
144f16e43f8SFrank Wang 		/*
145f16e43f8SFrank Wang 		 * INQUIRY and REQUEST SENSE commands are explicitly allowed
146f16e43f8SFrank Wang 		 * to use unsupported LUNs; all others may not.
147f16e43f8SFrank Wang 		 */
148f16e43f8SFrank Wang 		if (common->cmnd[0] != SC_INQUIRY &&
149f16e43f8SFrank Wang 		    common->cmnd[0] != SC_REQUEST_SENSE) {
150f16e43f8SFrank Wang 			debug("unsupported LUN %d\n", common->lun);
151f16e43f8SFrank Wang 			return -EINVAL;
152f16e43f8SFrank Wang 		}
153f16e43f8SFrank Wang 	}
154f16e43f8SFrank Wang 
155f16e43f8SFrank Wang 	return 0;
156f16e43f8SFrank Wang }
157f16e43f8SFrank Wang 
158f16e43f8SFrank Wang static void __do_reset(struct usb_ep *ep, struct usb_request *req)
159f16e43f8SFrank Wang {
1605b081643SFrank Wang 	u32 boot_flag = BOOT_NORMAL;
1615b081643SFrank Wang 
1625b081643SFrank Wang 	if (rkusb_rst_code == 0x03)
1635b081643SFrank Wang 		boot_flag = BOOT_BROM_DOWNLOAD;
1645b081643SFrank Wang 
1655b081643SFrank Wang 	rkusb_rst_code = 0; /* restore to default */
1665b081643SFrank Wang 	writel(boot_flag, (void *)CONFIG_ROCKCHIP_BOOT_MODE_REG);
167866d7966SJoseph Chen 
168f16e43f8SFrank Wang 	do_reset(NULL, 0, 0, NULL);
169f16e43f8SFrank Wang }
170f16e43f8SFrank Wang 
171f16e43f8SFrank Wang static int rkusb_do_reset(struct fsg_common *common,
172f16e43f8SFrank Wang 			  struct fsg_buffhd *bh)
173f16e43f8SFrank Wang {
174f16e43f8SFrank Wang 	common->data_size_from_cmnd = common->cmnd[4];
175f16e43f8SFrank Wang 	common->residue = 0;
176f16e43f8SFrank Wang 	bh->inreq->complete = __do_reset;
177f16e43f8SFrank Wang 	bh->state = BUF_STATE_EMPTY;
178f16e43f8SFrank Wang 
1795b081643SFrank Wang 	rkusb_rst_code = !common->cmnd[1] ? 0xff : common->cmnd[1];
180f16e43f8SFrank Wang 	return 0;
181f16e43f8SFrank Wang }
182f16e43f8SFrank Wang 
18336c87911Swilliam.wu __weak bool rkusb_usb3_capable(void)
18436c87911Swilliam.wu {
18536c87911Swilliam.wu 	return false;
18636c87911Swilliam.wu }
18736c87911Swilliam.wu 
18836c87911Swilliam.wu static int rkusb_do_switch_to_usb3(struct fsg_common *common,
18936c87911Swilliam.wu 				   struct fsg_buffhd *bh)
19036c87911Swilliam.wu {
19136c87911Swilliam.wu 	g_dnl_set_serialnumber((char *)&common->cmnd[1]);
19236c87911Swilliam.wu 	rkusb_switch_to_usb3_enable(true);
19336c87911Swilliam.wu 	bh->state = BUF_STATE_EMPTY;
19436c87911Swilliam.wu 
19536c87911Swilliam.wu 	return 0;
19636c87911Swilliam.wu }
19736c87911Swilliam.wu 
198f16e43f8SFrank Wang static int rkusb_do_test_unit_ready(struct fsg_common *common,
199f16e43f8SFrank Wang 				    struct fsg_buffhd *bh)
200f16e43f8SFrank Wang {
2017eb64117SJon Lin 	struct blk_desc *desc = &ums[common->lun].block_dev;
20218188f57SWilliam Wu 	u32 usb_trb_size;
20318188f57SWilliam Wu 	u16 residue;
2047eb64117SJon Lin 
2057eb64117SJon Lin 	if ((desc->if_type == IF_TYPE_MTD && desc->devnum == BLK_MTD_SPI_NOR) ||
2067eb64117SJon Lin 	    desc->if_type == IF_TYPE_SPINOR)
20718188f57SWilliam Wu 		residue = 0x03; /* 128KB Max block xfer for SPI Nor */
20818188f57SWilliam Wu 	else if (common->cmnd[1] == 0xf7 && FSG_BUFLEN >= 0x400000)
20918188f57SWilliam Wu 		residue = 0x0a; /* Max block xfer for USB DWC3 */
2107eb64117SJon Lin 	else
21118188f57SWilliam Wu 		residue = 0x06; /* Max block xfer support from host */
2127eb64117SJon Lin 
21318188f57SWilliam Wu 	usb_trb_size = (1 << residue) * 4096;
21418188f57SWilliam Wu 	common->usb_trb_size = min(usb_trb_size, FSG_BUFLEN);
21518188f57SWilliam Wu 	common->residue = residue << 24;
216f16e43f8SFrank Wang 	common->data_dir = DATA_DIR_NONE;
217f16e43f8SFrank Wang 	bh->state = BUF_STATE_EMPTY;
218f16e43f8SFrank Wang 
219f16e43f8SFrank Wang 	return 0;
220f16e43f8SFrank Wang }
221f16e43f8SFrank Wang 
222f16e43f8SFrank Wang static int rkusb_do_read_flash_id(struct fsg_common *common,
223f16e43f8SFrank Wang 				  struct fsg_buffhd *bh)
224f16e43f8SFrank Wang {
225f16e43f8SFrank Wang 	u8 *buf = (u8 *)bh->buf;
226e0023032SKever Yang 	u32 len = 5;
227d7386f60SFrank Wang 	enum if_type type = ums[common->lun].block_dev.if_type;
228afc6362aSJon Lin 	u32 devnum = ums[common->lun].block_dev.devnum;
229afc6362aSJon Lin 	const char *str;
230f16e43f8SFrank Wang 
231afc6362aSJon Lin 	switch (type) {
232afc6362aSJon Lin 	case IF_TYPE_MMC:
233afc6362aSJon Lin 		str = "EMMC ";
234afc6362aSJon Lin 		break;
235afc6362aSJon Lin 	case IF_TYPE_RKNAND:
236afc6362aSJon Lin 		str = "NAND ";
237afc6362aSJon Lin 		break;
238afc6362aSJon Lin 	case IF_TYPE_MTD:
239afc6362aSJon Lin 		if (devnum == BLK_MTD_SPI_NAND)
240afc6362aSJon Lin 			str ="SNAND";
241afc6362aSJon Lin 		else if (devnum == BLK_MTD_NAND)
242afc6362aSJon Lin 			str = "NAND ";
243d7386f60SFrank Wang 		else
244afc6362aSJon Lin 			str = "NOR  ";
245afc6362aSJon Lin 		break;
246afc6362aSJon Lin 	default:
247afc6362aSJon Lin 		str = "UNKN "; /* unknown */
248afc6362aSJon Lin 		break;
249afc6362aSJon Lin 	}
250afc6362aSJon Lin 
251afc6362aSJon Lin 	memcpy((void *)&buf[0], str, len);
252f16e43f8SFrank Wang 
253f16e43f8SFrank Wang 	/* Set data xfer size */
254f16e43f8SFrank Wang 	common->residue = common->data_size_from_cmnd = len;
255e0023032SKever Yang 	common->data_size = len;
256f16e43f8SFrank Wang 
257f16e43f8SFrank Wang 	return len;
258f16e43f8SFrank Wang }
259f16e43f8SFrank Wang 
260f16e43f8SFrank Wang static int rkusb_do_test_bad_block(struct fsg_common *common,
261f16e43f8SFrank Wang 				   struct fsg_buffhd *bh)
262f16e43f8SFrank Wang {
263f16e43f8SFrank Wang 	u8 *buf = (u8 *)bh->buf;
264e0023032SKever Yang 	u32 len = 64;
265f16e43f8SFrank Wang 
266f16e43f8SFrank Wang 	memset((void *)&buf[0], 0, len);
267f16e43f8SFrank Wang 
268f16e43f8SFrank Wang 	/* Set data xfer size */
269f16e43f8SFrank Wang 	common->residue = common->data_size_from_cmnd = len;
270e0023032SKever Yang 	common->data_size = len;
271f16e43f8SFrank Wang 
272f16e43f8SFrank Wang 	return len;
273f16e43f8SFrank Wang }
274f16e43f8SFrank Wang 
275f16e43f8SFrank Wang static int rkusb_do_read_flash_info(struct fsg_common *common,
276f16e43f8SFrank Wang 				    struct fsg_buffhd *bh)
277f16e43f8SFrank Wang {
278e66d4537SJon Lin 	struct blk_desc *desc = &ums[common->lun].block_dev;
279f16e43f8SFrank Wang 	u8 *buf = (u8 *)bh->buf;
280d23ec8c4SKever Yang 	u32 len = sizeof(struct rk_flash_info);
281f16e43f8SFrank Wang 	struct rk_flash_info finfo = {
282e66d4537SJon Lin 		.block_size = ROCKCHIP_FLASH_BLOCK_SIZE,
283f16e43f8SFrank Wang 		.ecc_bits = 0,
284e66d4537SJon Lin 		.page_size = ROCKCHIP_FLASH_PAGE_SIZE,
285f16e43f8SFrank Wang 		.access_time = 40,
286f16e43f8SFrank Wang 		.manufacturer = 0,
287f16e43f8SFrank Wang 		.flash_mask = 0
288f16e43f8SFrank Wang 	};
289f16e43f8SFrank Wang 
2900aca89f2SYifeng Zhao 	/* Set the raw block size for tools to creat GPT with 4K block size */
2910aca89f2SYifeng Zhao 	if (desc->rawblksz == 0x1000)
2920aca89f2SYifeng Zhao 		finfo.manufacturer = 208;
2930aca89f2SYifeng Zhao 
294e66d4537SJon Lin 	finfo.flash_size = (u32)desc->lba;
295e66d4537SJon Lin 
296e66d4537SJon Lin 	if (desc->if_type == IF_TYPE_MTD &&
297e66d4537SJon Lin 	    (desc->devnum == BLK_MTD_NAND ||
298e66d4537SJon Lin 	    desc->devnum == BLK_MTD_SPI_NAND)) {
299e66d4537SJon Lin 		struct mtd_info *mtd = (struct mtd_info *)desc->bdev->priv;
300e66d4537SJon Lin 
301e66d4537SJon Lin 		if (mtd) {
302e66d4537SJon Lin 			finfo.block_size = mtd->erasesize >> 9;
303e66d4537SJon Lin 			finfo.page_size = mtd->writesize >> 9;
30426b169f6SJon Lin #ifdef CONFIG_SUPPORT_USBPLUG
30526b169f6SJon Lin 			/* Using 4KB pagesize as 2KB for idblock */
30626b169f6SJon Lin 			if (finfo.page_size == 8 && desc->devnum == BLK_MTD_SPI_NAND)
30726b169f6SJon Lin 				finfo.page_size |= (4 << 4);
30826b169f6SJon Lin #endif
309e66d4537SJon Lin 		}
310e66d4537SJon Lin 	}
311e66d4537SJon Lin 
31265a0fed9SJon Lin 	if (desc->if_type == IF_TYPE_MTD && desc->devnum == BLK_MTD_SPI_NOR) {
31365a0fed9SJon Lin 		/* RV1126/RK3308 mtd spinor keep the former upgrade mode */
31465a0fed9SJon Lin #if !defined(CONFIG_ROCKCHIP_RV1126) && !defined(CONFIG_ROCKCHIP_RK3308)
315b8e5601dSJon Lin 		finfo.block_size = 0x80; /* Aligned to 64KB */
31665a0fed9SJon Lin #else
31765a0fed9SJon Lin 		finfo.block_size = ROCKCHIP_FLASH_BLOCK_SIZE;
31865a0fed9SJon Lin #endif
31965a0fed9SJon Lin 	}
32065a0fed9SJon Lin 
321e66d4537SJon Lin 	debug("Flash info: block_size= %x page_size= %x\n", finfo.block_size,
322e66d4537SJon Lin 	      finfo.page_size);
323e66d4537SJon Lin 
324f16e43f8SFrank Wang 	if (finfo.flash_size)
325f16e43f8SFrank Wang 		finfo.flash_mask = 1;
326f16e43f8SFrank Wang 
327f16e43f8SFrank Wang 	memset((void *)&buf[0], 0, len);
328f16e43f8SFrank Wang 	memcpy((void *)&buf[0], (void *)&finfo, len);
329f16e43f8SFrank Wang 
330f16e43f8SFrank Wang 	/* Set data xfer size */
331f16e43f8SFrank Wang 	common->residue = common->data_size_from_cmnd = len;
332d23ec8c4SKever Yang         /* legacy upgrade_tool does not set correct transfer size */
333d23ec8c4SKever Yang 	common->data_size = len;
334f16e43f8SFrank Wang 
335f16e43f8SFrank Wang 	return len;
336f16e43f8SFrank Wang }
337f16e43f8SFrank Wang 
338829f2b85SFrank Wang static int rkusb_do_get_chip_info(struct fsg_common *common,
339829f2b85SFrank Wang 				  struct fsg_buffhd *bh)
340829f2b85SFrank Wang {
341829f2b85SFrank Wang 	u8 *buf = (u8 *)bh->buf;
342829f2b85SFrank Wang 	u32 len = common->data_size;
343829f2b85SFrank Wang 	u32 chip_info[4];
344829f2b85SFrank Wang 
345829f2b85SFrank Wang 	memset((void *)chip_info, 0, sizeof(chip_info));
346829f2b85SFrank Wang 	rockchip_rockusb_get_chip_info(chip_info);
347829f2b85SFrank Wang 
348829f2b85SFrank Wang 	memset((void *)&buf[0], 0, len);
349829f2b85SFrank Wang 	memcpy((void *)&buf[0], (void *)chip_info, len);
350829f2b85SFrank Wang 
351829f2b85SFrank Wang 	/* Set data xfer size */
352829f2b85SFrank Wang 	common->residue = common->data_size_from_cmnd = len;
353829f2b85SFrank Wang 
354829f2b85SFrank Wang 	return len;
355829f2b85SFrank Wang }
356829f2b85SFrank Wang 
357f16e43f8SFrank Wang static int rkusb_do_lba_erase(struct fsg_common *common,
358f16e43f8SFrank Wang 			      struct fsg_buffhd *bh)
359f16e43f8SFrank Wang {
360f16e43f8SFrank Wang 	struct fsg_lun *curlun = &common->luns[common->lun];
361f16e43f8SFrank Wang 	u32 lba, amount;
362f16e43f8SFrank Wang 	loff_t file_offset;
363f16e43f8SFrank Wang 	int rc;
364f16e43f8SFrank Wang 
365f16e43f8SFrank Wang 	lba = get_unaligned_be32(&common->cmnd[2]);
366f16e43f8SFrank Wang 	if (lba >= curlun->num_sectors) {
367f16e43f8SFrank Wang 		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
368f16e43f8SFrank Wang 		rc = -EINVAL;
369f16e43f8SFrank Wang 		goto out;
370f16e43f8SFrank Wang 	}
371f16e43f8SFrank Wang 
372f16e43f8SFrank Wang 	file_offset = ((loff_t) lba) << 9;
373f16e43f8SFrank Wang 	amount = get_unaligned_be16(&common->cmnd[7]) << 9;
374f16e43f8SFrank Wang 	if (unlikely(amount == 0)) {
375f16e43f8SFrank Wang 		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
376f16e43f8SFrank Wang 		rc = -EIO;
377f16e43f8SFrank Wang 		goto out;
378f16e43f8SFrank Wang 	}
379f16e43f8SFrank Wang 
380f16e43f8SFrank Wang 	/* Perform the erase */
381f16e43f8SFrank Wang 	rc = ums[common->lun].erase_sector(&ums[common->lun],
382f16e43f8SFrank Wang 			       file_offset / SECTOR_SIZE,
383f16e43f8SFrank Wang 			       amount / SECTOR_SIZE);
384f16e43f8SFrank Wang 	if (!rc) {
385f16e43f8SFrank Wang 		curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
386f16e43f8SFrank Wang 		rc = -EIO;
387f16e43f8SFrank Wang 	}
388f16e43f8SFrank Wang 
389f16e43f8SFrank Wang out:
390f16e43f8SFrank Wang 	common->data_dir = DATA_DIR_NONE;
391f16e43f8SFrank Wang 	bh->state = BUF_STATE_EMPTY;
392f16e43f8SFrank Wang 
393f16e43f8SFrank Wang 	return rc;
394f16e43f8SFrank Wang }
395f16e43f8SFrank Wang 
396e66d4537SJon Lin static int rkusb_do_erase_force(struct fsg_common *common,
397e66d4537SJon Lin 				struct fsg_buffhd *bh)
398e66d4537SJon Lin {
399e66d4537SJon Lin 	struct blk_desc *desc = &ums[common->lun].block_dev;
400e66d4537SJon Lin 	struct fsg_lun *curlun = &common->luns[common->lun];
401e66d4537SJon Lin 	u16 block_size = ROCKCHIP_FLASH_BLOCK_SIZE;
402e66d4537SJon Lin 	u32 lba, amount;
403e66d4537SJon Lin 	loff_t file_offset;
404e66d4537SJon Lin 	int rc;
405e66d4537SJon Lin 
406e66d4537SJon Lin 	lba = get_unaligned_be32(&common->cmnd[2]);
407e66d4537SJon Lin 	if (lba >= curlun->num_sectors) {
408e66d4537SJon Lin 		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
409e66d4537SJon Lin 		rc = -EINVAL;
410e66d4537SJon Lin 		goto out;
411e66d4537SJon Lin 	}
412e66d4537SJon Lin 
413e66d4537SJon Lin 	if (desc->if_type == IF_TYPE_MTD &&
414e66d4537SJon Lin 	    (desc->devnum == BLK_MTD_NAND ||
415e66d4537SJon Lin 	    desc->devnum == BLK_MTD_SPI_NAND)) {
416e66d4537SJon Lin 		struct mtd_info *mtd = (struct mtd_info *)desc->bdev->priv;
417e66d4537SJon Lin 
418e66d4537SJon Lin 		if (mtd)
419e66d4537SJon Lin 			block_size = mtd->erasesize >> 9;
420e66d4537SJon Lin 	}
421e66d4537SJon Lin 
422e66d4537SJon Lin 	file_offset = ((loff_t)lba) * block_size;
423e66d4537SJon Lin 	amount = get_unaligned_be16(&common->cmnd[7]) * block_size;
424e66d4537SJon Lin 
425e66d4537SJon Lin 	debug("%s lba= %x, nsec= %x\n", __func__, lba,
426e66d4537SJon Lin 	      (u32)get_unaligned_be16(&common->cmnd[7]));
427e66d4537SJon Lin 
428e66d4537SJon Lin 	if (unlikely(amount == 0)) {
429e66d4537SJon Lin 		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
430e66d4537SJon Lin 		rc = -EIO;
431e66d4537SJon Lin 		goto out;
432e66d4537SJon Lin 	}
433e66d4537SJon Lin 
434e66d4537SJon Lin 	/* Perform the erase */
435e66d4537SJon Lin 	rc = ums[common->lun].erase_sector(&ums[common->lun],
436e66d4537SJon Lin 					   file_offset,
437e66d4537SJon Lin 					   amount);
438e66d4537SJon Lin 	if (!rc) {
439e66d4537SJon Lin 		curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
440e66d4537SJon Lin 		rc = -EIO;
441e66d4537SJon Lin 	}
442e66d4537SJon Lin 
443e66d4537SJon Lin out:
444e66d4537SJon Lin 	common->data_dir = DATA_DIR_NONE;
445e66d4537SJon Lin 	bh->state = BUF_STATE_EMPTY;
446e66d4537SJon Lin 
447e66d4537SJon Lin 	return rc;
448e66d4537SJon Lin }
449e66d4537SJon Lin 
4500d0c3248SFrank Wang #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION
4510d0c3248SFrank Wang static int rkusb_do_vs_write(struct fsg_common *common)
4520d0c3248SFrank Wang {
4530d0c3248SFrank Wang 	struct fsg_lun		*curlun = &common->luns[common->lun];
4540d0c3248SFrank Wang 	u16			type = get_unaligned_be16(&common->cmnd[4]);
4550d0c3248SFrank Wang 	struct vendor_item	*vhead;
4560d0c3248SFrank Wang 	struct fsg_buffhd	*bh;
4570d0c3248SFrank Wang 	void			*data;
4580d0c3248SFrank Wang 	int			rc;
4590d0c3248SFrank Wang 
4600d0c3248SFrank Wang 	if (common->data_size >= (u32)65536) {
4610d0c3248SFrank Wang 		/* _MUST_ small than 64K */
4620d0c3248SFrank Wang 		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
4630d0c3248SFrank Wang 		return -EINVAL;
4640d0c3248SFrank Wang 	}
4650d0c3248SFrank Wang 
4660d0c3248SFrank Wang 	common->residue         = common->data_size;
4670d0c3248SFrank Wang 	common->usb_amount_left = common->data_size;
4680d0c3248SFrank Wang 
4690d0c3248SFrank Wang 	/* Carry out the file writes */
4700d0c3248SFrank Wang 	if (unlikely(common->data_size == 0))
4710d0c3248SFrank Wang 		return -EIO; /* No data to write */
4720d0c3248SFrank Wang 
4730d0c3248SFrank Wang 	for (;;) {
4740d0c3248SFrank Wang 		if (common->usb_amount_left > 0) {
4750d0c3248SFrank Wang 			/* Wait for the next buffer to become available */
4760d0c3248SFrank Wang 			bh = common->next_buffhd_to_fill;
4770d0c3248SFrank Wang 			if (bh->state != BUF_STATE_EMPTY)
4780d0c3248SFrank Wang 				goto wait;
4790d0c3248SFrank Wang 
4800d0c3248SFrank Wang 			/* Request the next buffer */
4810d0c3248SFrank Wang 			common->usb_amount_left      -= common->data_size;
4820d0c3248SFrank Wang 			bh->outreq->length	     = common->data_size;
4830d0c3248SFrank Wang 			bh->bulk_out_intended_length = common->data_size;
4840d0c3248SFrank Wang 			bh->outreq->short_not_ok     = 1;
4850d0c3248SFrank Wang 
4860d0c3248SFrank Wang 			START_TRANSFER_OR(common, bulk_out, bh->outreq,
4870d0c3248SFrank Wang 					  &bh->outreq_busy, &bh->state)
4880d0c3248SFrank Wang 				/*
4890d0c3248SFrank Wang 				 * Don't know what to do if
4900d0c3248SFrank Wang 				 * common->fsg is NULL
4910d0c3248SFrank Wang 				 */
4920d0c3248SFrank Wang 				return -EIO;
4930d0c3248SFrank Wang 			common->next_buffhd_to_fill = bh->next;
4940d0c3248SFrank Wang 		} else {
4950d0c3248SFrank Wang 			/* Then, wait for the data to become available */
4960d0c3248SFrank Wang 			bh = common->next_buffhd_to_drain;
4970d0c3248SFrank Wang 			if (bh->state != BUF_STATE_FULL)
4980d0c3248SFrank Wang 				goto wait;
4990d0c3248SFrank Wang 
5000d0c3248SFrank Wang 			common->next_buffhd_to_drain = bh->next;
5010d0c3248SFrank Wang 			bh->state = BUF_STATE_EMPTY;
5020d0c3248SFrank Wang 
5030d0c3248SFrank Wang 			/* Did something go wrong with the transfer? */
5040d0c3248SFrank Wang 			if (bh->outreq->status != 0) {
5050d0c3248SFrank Wang 				curlun->sense_data = SS_COMMUNICATION_FAILURE;
5060d0c3248SFrank Wang 				curlun->info_valid = 1;
5070d0c3248SFrank Wang 				break;
5080d0c3248SFrank Wang 			}
5090d0c3248SFrank Wang 
5100d0c3248SFrank Wang 			/* Perform the write */
5110d0c3248SFrank Wang 			vhead = (struct vendor_item *)bh->buf;
5120d0c3248SFrank Wang 			data  = bh->buf + sizeof(struct vendor_item);
5130d0c3248SFrank Wang 
5140d0c3248SFrank Wang 			if (!type) {
51570990948SYifeng Zhao 				#ifndef CONFIG_SUPPORT_USBPLUG
516420ee9d5SJoseph Chen 				if (vhead->id == HDCP_14_HDMI_ID ||
51778dcc928SZhang Yubing 				    vhead->id == HDCP_14_HDMIRX_ID ||
51878dcc928SZhang Yubing 				    vhead->id == HDCP_14_DP_ID) {
519420ee9d5SJoseph Chen 					rc = vendor_handle_hdcp(vhead);
520420ee9d5SJoseph Chen 					if (rc < 0) {
521420ee9d5SJoseph Chen 						curlun->sense_data = SS_WRITE_ERROR;
522420ee9d5SJoseph Chen 						return -EIO;
523420ee9d5SJoseph Chen 					}
524420ee9d5SJoseph Chen 				}
52570990948SYifeng Zhao 				#endif
526420ee9d5SJoseph Chen 
5270d0c3248SFrank Wang 				/* Vendor storage */
5280d0c3248SFrank Wang 				rc = vendor_storage_write(vhead->id,
5290d0c3248SFrank Wang 							  (char __user *)data,
5300d0c3248SFrank Wang 							  vhead->size);
53119652be0SFrank Wang 				if (rc < 0) {
53219652be0SFrank Wang 					curlun->sense_data = SS_WRITE_ERROR;
5330d0c3248SFrank Wang 					return -EIO;
53419652be0SFrank Wang 				}
5352122174dSWu Liangqing 			} else if (type == 1) {
5360d0c3248SFrank Wang 				/* RPMB */
5376f0347c8Stony.xu 				rc =
5386f0347c8Stony.xu 				write_keybox_to_secure_storage((u8 *)data,
5396f0347c8Stony.xu 							       vhead->size);
54019652be0SFrank Wang 				if (rc < 0) {
54119652be0SFrank Wang 					curlun->sense_data = SS_WRITE_ERROR;
5426f0347c8Stony.xu 					return -EIO;
5430d0c3248SFrank Wang 				}
5442122174dSWu Liangqing 			} else if (type == 2) {
5452122174dSWu Liangqing 				/* security storage */
5462122174dSWu Liangqing #ifdef CONFIG_RK_AVB_LIBAVB_USER
5472122174dSWu Liangqing 				debug("%s call rk_avb_write_perm_attr %d, %d\n",
5482122174dSWu Liangqing 				      __func__, vhead->id, vhead->size);
5492122174dSWu Liangqing 				rc = rk_avb_write_perm_attr(vhead->id,
5502122174dSWu Liangqing 							    (char __user *)data,
5512122174dSWu Liangqing 							    vhead->size);
5522122174dSWu Liangqing 				if (rc < 0) {
5532122174dSWu Liangqing 					curlun->sense_data = SS_WRITE_ERROR;
5542122174dSWu Liangqing 					return -EIO;
5552122174dSWu Liangqing 				}
5562122174dSWu Liangqing #else
5572122174dSWu Liangqing 				printf("Please enable CONFIG_RK_AVB_LIBAVB_USER\n");
5582122174dSWu Liangqing #endif
559850ced9dSHisping Lin 			} else if (type == 3) {
560850ced9dSHisping Lin 				/* efuse or otp*/
561850ced9dSHisping Lin #ifdef CONFIG_OPTEE_CLIENT
562850ced9dSHisping Lin 				if (memcmp(data, "TAEK", 4) == 0) {
563850ced9dSHisping Lin 					if (vhead->size - 8 != 32) {
564850ced9dSHisping Lin 						printf("check ta encryption key size fail!\n");
565850ced9dSHisping Lin 						curlun->sense_data = SS_WRITE_ERROR;
566850ced9dSHisping Lin 						return -EIO;
567850ced9dSHisping Lin 					}
568850ced9dSHisping Lin 					if (trusty_write_ta_encryption_key((uint32_t *)(data + 8), 8) != 0) {
569850ced9dSHisping Lin 						printf("trusty_write_ta_encryption_key error!");
570850ced9dSHisping Lin 						curlun->sense_data = SS_WRITE_ERROR;
571850ced9dSHisping Lin 						return -EIO;
572850ced9dSHisping Lin 					}
573a43611afSHisping Lin 				} else if (memcmp(data, "EHUK", 4) == 0) {
574a43611afSHisping Lin 					if (vhead->size - 8 != 32) {
575a43611afSHisping Lin 						printf("check oem huk size fail!\n");
576a43611afSHisping Lin 						curlun->sense_data = SS_WRITE_ERROR;
577a43611afSHisping Lin 						return -EIO;
578a43611afSHisping Lin 					}
579a43611afSHisping Lin 					if (trusty_write_oem_huk((uint32_t *)(data + 8), 8) != 0) {
580a43611afSHisping Lin 						printf("trusty_write_oem_huk error!");
581a43611afSHisping Lin 						curlun->sense_data = SS_WRITE_ERROR;
582a43611afSHisping Lin 						return -EIO;
583a43611afSHisping Lin 					}
584005bd059SHisping Lin 				} else if (memcmp(data, "ENDA", 4) == 0) {
585005bd059SHisping Lin 					if (vhead->size - 8 != 16) {
586005bd059SHisping Lin 						printf("check oem encrypt data size fail!\n");
587005bd059SHisping Lin 						curlun->sense_data = SS_WRITE_ERROR;
588005bd059SHisping Lin 						return -EIO;
589005bd059SHisping Lin 					}
590005bd059SHisping Lin 					if (trusty_write_oem_encrypt_data((uint32_t *)(data + 8), 4) != 0) {
591005bd059SHisping Lin 						printf("trusty_write_oem_encrypt_data error!");
592005bd059SHisping Lin 						curlun->sense_data = SS_WRITE_ERROR;
593005bd059SHisping Lin 						return -EIO;
594005bd059SHisping Lin 					}
5951dd9b2ceSHisping Lin 				} else if (memcmp(data, "OTPK", 4) == 0) {
5961dd9b2ceSHisping Lin 					uint32_t key_len = vhead->size - 9;
5971dd9b2ceSHisping Lin 					uint8_t key_id = *((uint8_t *)data + 8);
5981dd9b2ceSHisping Lin 					if (key_len != 16 && key_len != 24 && key_len != 32) {
5991dd9b2ceSHisping Lin 						printf("check oem otp key size fail!\n");
6001dd9b2ceSHisping Lin 						curlun->sense_data = SS_WRITE_ERROR;
6011dd9b2ceSHisping Lin 						return -EIO;
6021dd9b2ceSHisping Lin 					}
6031dd9b2ceSHisping Lin 					if (trusty_write_oem_otp_key(key_id, (uint8_t *)(data + 9), key_len) != 0) {
6041dd9b2ceSHisping Lin 						printf("trusty_write_oem_huk error!");
6051dd9b2ceSHisping Lin 						curlun->sense_data = SS_WRITE_ERROR;
6061dd9b2ceSHisping Lin 						return -EIO;
6071dd9b2ceSHisping Lin 					}
608850ced9dSHisping Lin 				} else {
609850ced9dSHisping Lin 					printf("Unknown tag\n");
610850ced9dSHisping Lin 					curlun->sense_data = SS_WRITE_ERROR;
611850ced9dSHisping Lin 					return -EIO;
612850ced9dSHisping Lin 				}
613850ced9dSHisping Lin #else
614850ced9dSHisping Lin 				printf("Please enable CONFIG_OPTEE_CLIENT\n");
615850ced9dSHisping Lin #endif
6162122174dSWu Liangqing 			} else {
6172122174dSWu Liangqing 				return -EINVAL;
61819652be0SFrank Wang 			}
6190d0c3248SFrank Wang 
6200d0c3248SFrank Wang 			common->residue -= common->data_size;
6210d0c3248SFrank Wang 
6220d0c3248SFrank Wang 			/* Did the host decide to stop early? */
6230d0c3248SFrank Wang 			if (bh->outreq->actual != bh->outreq->length)
6240d0c3248SFrank Wang 				common->short_packet_received = 1;
6250d0c3248SFrank Wang 			break; /* Command done */
6260d0c3248SFrank Wang 		}
6270d0c3248SFrank Wang wait:
6280d0c3248SFrank Wang 		/* Wait for something to happen */
6290d0c3248SFrank Wang 		rc = sleep_thread(common);
6300d0c3248SFrank Wang 		if (rc)
6310d0c3248SFrank Wang 			return rc;
6320d0c3248SFrank Wang 	}
6330d0c3248SFrank Wang 
6340d0c3248SFrank Wang 	return -EIO; /* No default reply */
6350d0c3248SFrank Wang }
6360d0c3248SFrank Wang 
6370d0c3248SFrank Wang static int rkusb_do_vs_read(struct fsg_common *common)
6380d0c3248SFrank Wang {
6390d0c3248SFrank Wang 	struct fsg_lun		*curlun = &common->luns[common->lun];
6400d0c3248SFrank Wang 	u16			type = get_unaligned_be16(&common->cmnd[4]);
6410d0c3248SFrank Wang 	struct vendor_item	*vhead;
6420d0c3248SFrank Wang 	struct fsg_buffhd	*bh;
6430d0c3248SFrank Wang 	void			*data;
6440d0c3248SFrank Wang 	int			rc;
6450d0c3248SFrank Wang 
6460d0c3248SFrank Wang 	if (common->data_size >= (u32)65536) {
6470d0c3248SFrank Wang 		/* _MUST_ small than 64K */
6480d0c3248SFrank Wang 		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
6490d0c3248SFrank Wang 		return -EINVAL;
6500d0c3248SFrank Wang 	}
6510d0c3248SFrank Wang 
6520d0c3248SFrank Wang 	common->residue         = common->data_size;
6530d0c3248SFrank Wang 	common->usb_amount_left = common->data_size;
6540d0c3248SFrank Wang 
6550d0c3248SFrank Wang 	/* Carry out the file reads */
6560d0c3248SFrank Wang 	if (unlikely(common->data_size == 0))
6570d0c3248SFrank Wang 		return -EIO; /* No default reply */
6580d0c3248SFrank Wang 
6590d0c3248SFrank Wang 	for (;;) {
6600d0c3248SFrank Wang 		/* Wait for the next buffer to become available */
6610d0c3248SFrank Wang 		bh = common->next_buffhd_to_fill;
6620d0c3248SFrank Wang 		while (bh->state != BUF_STATE_EMPTY) {
6630d0c3248SFrank Wang 			rc = sleep_thread(common);
6640d0c3248SFrank Wang 			if (rc)
6650d0c3248SFrank Wang 				return rc;
6660d0c3248SFrank Wang 		}
6670d0c3248SFrank Wang 
6680d0c3248SFrank Wang 		memset(bh->buf, 0, FSG_BUFLEN);
6690d0c3248SFrank Wang 		vhead = (struct vendor_item *)bh->buf;
6700d0c3248SFrank Wang 		data  = bh->buf + sizeof(struct vendor_item);
6710d0c3248SFrank Wang 		vhead->id = get_unaligned_be16(&common->cmnd[2]);
6720d0c3248SFrank Wang 
6730d0c3248SFrank Wang 		if (!type) {
6740d0c3248SFrank Wang 			/* Vendor storage */
6750d0c3248SFrank Wang 			rc = vendor_storage_read(vhead->id,
6760d0c3248SFrank Wang 						 (char __user *)data,
6770d0c3248SFrank Wang 						 common->data_size);
67819652be0SFrank Wang 			if (!rc) {
67919652be0SFrank Wang 				curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
6800d0c3248SFrank Wang 				return -EIO;
68119652be0SFrank Wang 			}
6820d0c3248SFrank Wang 			vhead->size = rc;
6832122174dSWu Liangqing 		} else if (type == 1) {
6840d0c3248SFrank Wang 			/* RPMB */
685700a3668STony Xu 			rc =
686700a3668STony Xu 			read_raw_data_from_secure_storage((u8 *)data,
687700a3668STony Xu 							  common->data_size);
68819652be0SFrank Wang 			if (!rc) {
68919652be0SFrank Wang 				curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
690700a3668STony Xu 				return -EIO;
69119652be0SFrank Wang 			}
692700a3668STony Xu 			vhead->size = rc;
6932122174dSWu Liangqing 		} else if (type == 2) {
6942122174dSWu Liangqing 			/* security storage */
6952122174dSWu Liangqing #ifdef CONFIG_RK_AVB_LIBAVB_USER
6962122174dSWu Liangqing 			rc = rk_avb_read_perm_attr(vhead->id,
6972122174dSWu Liangqing 						   (char __user *)data,
6982122174dSWu Liangqing 						   vhead->size);
6992122174dSWu Liangqing 			if (rc < 0)
7002122174dSWu Liangqing 				return -EIO;
7012122174dSWu Liangqing 			vhead->size = rc;
7022122174dSWu Liangqing #else
7032122174dSWu Liangqing 			printf("Please enable CONFIG_RK_AVB_LIBAVB_USER!\n");
7042122174dSWu Liangqing #endif
70547c8f13dSHisping Lin 		} else if (type == 3) {
70647c8f13dSHisping Lin 			/* efuse or otp*/
70747c8f13dSHisping Lin #ifdef CONFIG_OPTEE_CLIENT
70847c8f13dSHisping Lin 			if (vhead->id == 120) {
70947c8f13dSHisping Lin 				u8 value;
71047c8f13dSHisping Lin 				char *written_str = "key is written!";
71147c8f13dSHisping Lin 				char *not_written_str = "key is not written!";
71247c8f13dSHisping Lin 				if (trusty_ta_encryption_key_is_written(&value) != 0) {
71347c8f13dSHisping Lin 					printf("trusty_ta_encryption_key_is_written error!");
71447c8f13dSHisping Lin 					return -EIO;
71547c8f13dSHisping Lin 				}
71647c8f13dSHisping Lin 				if (value) {
71747c8f13dSHisping Lin 					memcpy(data, written_str, strlen(written_str));
71847c8f13dSHisping Lin 					vhead->size = strlen(written_str);
71947c8f13dSHisping Lin 				} else {
72047c8f13dSHisping Lin 					memcpy(data, not_written_str, strlen(not_written_str));
72147c8f13dSHisping Lin 					vhead->size = strlen(not_written_str);
72247c8f13dSHisping Lin 				}
72347c8f13dSHisping Lin 			} else {
72447c8f13dSHisping Lin 				printf("Unknown tag\n");
72547c8f13dSHisping Lin 				return -EIO;
72647c8f13dSHisping Lin 			}
72747c8f13dSHisping Lin #else
72847c8f13dSHisping Lin 			printf("Please enable CONFIG_OPTEE_CLIENT\n");
72947c8f13dSHisping Lin #endif
7302122174dSWu Liangqing 		} else {
7312122174dSWu Liangqing 			return -EINVAL;
7320d0c3248SFrank Wang 		}
7330d0c3248SFrank Wang 
7340d0c3248SFrank Wang 		common->residue   -= common->data_size;
7350d0c3248SFrank Wang 		bh->inreq->length = common->data_size;
7360d0c3248SFrank Wang 		bh->state         = BUF_STATE_FULL;
7370d0c3248SFrank Wang 
7380d0c3248SFrank Wang 		break; /* No more left to read */
7390d0c3248SFrank Wang 	}
7400d0c3248SFrank Wang 
7410d0c3248SFrank Wang 	return -EIO; /* No default reply */
7420d0c3248SFrank Wang }
7430d0c3248SFrank Wang #endif
7440d0c3248SFrank Wang 
7454d2787f5SJon Lin static int rkusb_do_switch_storage(struct fsg_common *common)
7464d2787f5SJon Lin {
7474d2787f5SJon Lin 	enum if_type type, cur_type = ums[common->lun].block_dev.if_type;
7484d2787f5SJon Lin 	int devnum, cur_devnum = ums[common->lun].block_dev.devnum;
7494d2787f5SJon Lin 	struct blk_desc *block_dev;
7504d2787f5SJon Lin 	u32 media = BOOT_TYPE_UNKNOWN;
7514d2787f5SJon Lin 
7524d2787f5SJon Lin 	media = 1 << common->cmnd[1];
7534d2787f5SJon Lin 
7544d2787f5SJon Lin 	switch (media) {
75522c2f449SJon Lin #ifdef CONFIG_MMC
7564d2787f5SJon Lin 	case BOOT_TYPE_EMMC:
7574d2787f5SJon Lin 		type = IF_TYPE_MMC;
7584d2787f5SJon Lin 		devnum = 0;
7594d2787f5SJon Lin 		mmc_initialize(gd->bd);
7604d2787f5SJon Lin 		break;
76122c2f449SJon Lin #endif
7624d2787f5SJon Lin 	case BOOT_TYPE_MTD_BLK_NAND:
7634d2787f5SJon Lin 		type = IF_TYPE_MTD;
7644d2787f5SJon Lin 		devnum = 0;
7654d2787f5SJon Lin 		break;
7664d2787f5SJon Lin 	case BOOT_TYPE_MTD_BLK_SPI_NAND:
7674d2787f5SJon Lin 		type = IF_TYPE_MTD;
7684d2787f5SJon Lin 		devnum = 1;
7694d2787f5SJon Lin 		break;
7704d2787f5SJon Lin 	case BOOT_TYPE_MTD_BLK_SPI_NOR:
7714d2787f5SJon Lin 		type = IF_TYPE_MTD;
7724d2787f5SJon Lin 		devnum = 2;
7734d2787f5SJon Lin 		break;
7741b375c35SYifeng Zhao #if defined(CONFIG_SCSI) && defined(CONFIG_CMD_SCSI) && (defined(CONFIG_AHCI) || defined(CONFIG_UFS))
7751b375c35SYifeng Zhao 	case BOOT_TYPE_SATA:
7761b375c35SYifeng Zhao 		type = IF_TYPE_SCSI;
7771b375c35SYifeng Zhao 		devnum = 0;
7781b375c35SYifeng Zhao 		break;
7791b375c35SYifeng Zhao #endif
7804d2787f5SJon Lin 	default:
7814d2787f5SJon Lin 		printf("Bootdev 0x%x is not support\n", media);
7824d2787f5SJon Lin 		return -ENODEV;
7834d2787f5SJon Lin 	}
7844d2787f5SJon Lin 
7854d2787f5SJon Lin 	if (cur_type == type && cur_devnum == devnum)
7864d2787f5SJon Lin 		return 0;
7874d2787f5SJon Lin 
7888c6654f1SJon Lin #if CONFIG_IS_ENABLED(SUPPORT_USBPLUG)
7898c6654f1SJon Lin 	block_dev = usbplug_blk_get_devnum_by_type(type, devnum);
7908c6654f1SJon Lin #else
7914d2787f5SJon Lin 	block_dev = blk_get_devnum_by_type(type, devnum);
7928c6654f1SJon Lin #endif
7934d2787f5SJon Lin 	if (!block_dev) {
7944d2787f5SJon Lin 		printf("Bootdev if_type=%d num=%d toggle fail\n", type, devnum);
7954d2787f5SJon Lin 		return -ENODEV;
7964d2787f5SJon Lin 	}
7974d2787f5SJon Lin 
798*a1b07e70SYifeng Zhao 	common->luns[common->lun].num_sectors = block_dev->lba;
7994d2787f5SJon Lin 	ums[common->lun].num_sectors = block_dev->lba;
8004d2787f5SJon Lin 	ums[common->lun].block_dev = *block_dev;
8014d2787f5SJon Lin 
8024d2787f5SJon Lin 	printf("RKUSB: LUN %d, dev %d, hwpart %d, sector %#x, count %#x\n",
8034d2787f5SJon Lin 	       0,
8044d2787f5SJon Lin 	       ums[common->lun].block_dev.devnum,
8054d2787f5SJon Lin 	       ums[common->lun].block_dev.hwpart,
8064d2787f5SJon Lin 	       ums[common->lun].start_sector,
8074d2787f5SJon Lin 	       ums[common->lun].num_sectors);
8084d2787f5SJon Lin 
8094d2787f5SJon Lin 	return 0;
8104d2787f5SJon Lin }
8114d2787f5SJon Lin 
812d4cce25eSYifeng Zhao static int rkusb_do_get_storage_info(struct fsg_common *common,
813d4cce25eSYifeng Zhao 				     struct fsg_buffhd *bh)
814d4cce25eSYifeng Zhao {
815d4cce25eSYifeng Zhao 	enum if_type type = ums[common->lun].block_dev.if_type;
816d4cce25eSYifeng Zhao 	int devnum = ums[common->lun].block_dev.devnum;
817d4cce25eSYifeng Zhao 	u32 media = BOOT_TYPE_UNKNOWN;
818d4cce25eSYifeng Zhao 	u32 len = common->data_size;
819d4cce25eSYifeng Zhao 	u8 *buf = (u8 *)bh->buf;
820d4cce25eSYifeng Zhao 
821d4cce25eSYifeng Zhao 	if (len > 4)
822d4cce25eSYifeng Zhao 		len = 4;
823d4cce25eSYifeng Zhao 
824d4cce25eSYifeng Zhao 	switch (type) {
825d4cce25eSYifeng Zhao 	case IF_TYPE_MMC:
826d4cce25eSYifeng Zhao 		media = BOOT_TYPE_EMMC;
827d4cce25eSYifeng Zhao 		break;
828d4cce25eSYifeng Zhao 
829d4cce25eSYifeng Zhao 	case IF_TYPE_SD:
830d4cce25eSYifeng Zhao 		media = BOOT_TYPE_SD0;
831d4cce25eSYifeng Zhao 		break;
832d4cce25eSYifeng Zhao 
833d4cce25eSYifeng Zhao 	case IF_TYPE_MTD:
834d4cce25eSYifeng Zhao 		if (devnum == BLK_MTD_SPI_NAND)
835d4cce25eSYifeng Zhao 			media = BOOT_TYPE_MTD_BLK_SPI_NAND;
836d4cce25eSYifeng Zhao 		else if (devnum == BLK_MTD_NAND)
837d4cce25eSYifeng Zhao 			media = BOOT_TYPE_NAND;
838d4cce25eSYifeng Zhao 		else
839d4cce25eSYifeng Zhao 			media = BOOT_TYPE_MTD_BLK_SPI_NOR;
840d4cce25eSYifeng Zhao 		break;
841d4cce25eSYifeng Zhao 
842d4cce25eSYifeng Zhao 	case IF_TYPE_SCSI:
843d4cce25eSYifeng Zhao 		media = BOOT_TYPE_SATA;
844d4cce25eSYifeng Zhao 		break;
845d4cce25eSYifeng Zhao 
846d4cce25eSYifeng Zhao 	case IF_TYPE_RKNAND:
847d4cce25eSYifeng Zhao 		media = BOOT_TYPE_NAND;
848d4cce25eSYifeng Zhao 		break;
8492daa60eeSJon Lin 
8502daa60eeSJon Lin 	case IF_TYPE_NVME:
8512daa60eeSJon Lin 		media = BOOT_TYPE_PCIE;
8522daa60eeSJon Lin 		break;
8532daa60eeSJon Lin 
854d4cce25eSYifeng Zhao 	default:
855d4cce25eSYifeng Zhao 		break;
856d4cce25eSYifeng Zhao 	}
857d4cce25eSYifeng Zhao 
858d4cce25eSYifeng Zhao 	memcpy((void *)&buf[0], (void *)&media, len);
859d4cce25eSYifeng Zhao 	common->residue = len;
860d4cce25eSYifeng Zhao 	common->data_size_from_cmnd = len;
861d4cce25eSYifeng Zhao 
862d4cce25eSYifeng Zhao 	return len;
863d4cce25eSYifeng Zhao }
864d4cce25eSYifeng Zhao 
865f16e43f8SFrank Wang static int rkusb_do_read_capacity(struct fsg_common *common,
866f16e43f8SFrank Wang 				  struct fsg_buffhd *bh)
867f16e43f8SFrank Wang {
868f16e43f8SFrank Wang 	u8 *buf = (u8 *)bh->buf;
869f16e43f8SFrank Wang 	u32 len = common->data_size;
870d015bf41SFrank Wang 	enum if_type type = ums[common->lun].block_dev.if_type;
871e66d4537SJon Lin 	int devnum = ums[common->lun].block_dev.devnum;
872f16e43f8SFrank Wang 
873f16e43f8SFrank Wang 	/*
874f16e43f8SFrank Wang 	 * bit[0]: Direct LBA, 0: Disabled;
8750d0c3248SFrank Wang 	 * bit[1]: Vendor Storage API, 0: Disabed (default);
876d015bf41SFrank Wang 	 * bit[2]: First 4M Access, 0: Disabled;
8770d0c3248SFrank Wang 	 * bit[3]: Read LBA On, 0: Disabed (default);
8780d0c3248SFrank Wang 	 * bit[4]: New Vendor Storage API, 0: Disabed;
879d4cce25eSYifeng Zhao 	 * bit[5]: Read uart data from ram
880d4cce25eSYifeng Zhao 	 * bit[6]: Read IDB config
881d4cce25eSYifeng Zhao 	 * bit[7]: Read SecureMode
882d4cce25eSYifeng Zhao 	 * bit[8]: New IDB feature
883d4cce25eSYifeng Zhao 	 * bit[9]: Get storage media info
8848168f857SYifeng Zhao 	 * bit[10]: LBAwrite Parity
8858168f857SYifeng Zhao 	 * bit[11]: Read Otp Data
8868168f857SYifeng Zhao 	 * bit[12]: usb3 download
8878168f857SYifeng Zhao 	 * bit[13]: Write OTP proof
8888168f857SYifeng Zhao 	 * bit[14]: Write Cipher Key
8898168f857SYifeng Zhao 	 * bit[15:63}: Reserved.
890f16e43f8SFrank Wang 	 */
891f16e43f8SFrank Wang 	memset((void *)&buf[0], 0, len);
8922daa60eeSJon Lin 	if (type == IF_TYPE_MMC || type == IF_TYPE_SD || type == IF_TYPE_NVME)
8930d0c3248SFrank Wang 		buf[0] = BIT(0) | BIT(2) | BIT(4);
8940d0c3248SFrank Wang 	else
8950d0c3248SFrank Wang 		buf[0] = BIT(0) | BIT(4);
896f16e43f8SFrank Wang 
897e66d4537SJon Lin 	if (type == IF_TYPE_MTD &&
898e66d4537SJon Lin 	    (devnum == BLK_MTD_NAND ||
899e66d4537SJon Lin 	    devnum == BLK_MTD_SPI_NAND))
900e66d4537SJon Lin 		buf[0] |= (1 << 6);
901e66d4537SJon Lin 
90265a0fed9SJon Lin #if !defined(CONFIG_ROCKCHIP_RV1126) && !defined(CONFIG_ROCKCHIP_RK3308)
90365a0fed9SJon Lin 	if (type == IF_TYPE_MTD && devnum == BLK_MTD_SPI_NOR)
90465a0fed9SJon Lin 		buf[0] |= (1 << 6);
90565a0fed9SJon Lin #endif
90665a0fed9SJon Lin 
9070b97a2cbSJoseph Chen #if defined(CONFIG_ROCKCHIP_NEW_IDB)
908007849d8SYifeng Zhao 	buf[1] = BIT(0);
909007849d8SYifeng Zhao #endif
9102c0c66c1SYifeng Zhao 	buf[1] |= BIT(1); /* Switch Storage */
9112c0c66c1SYifeng Zhao 	buf[1] |= BIT(2); /* LBAwrite Parity */
912d4cce25eSYifeng Zhao 
91336c87911Swilliam.wu 	if (rkusb_usb3_capable() && !rkusb_force_usb2_enabled())
9143c7547fcSWilliam Wu 		buf[1] |= BIT(4);
91536c87911Swilliam.wu 	else
9163c7547fcSWilliam Wu 		buf[1] &= ~BIT(4);
91736c87911Swilliam.wu 
9188168f857SYifeng Zhao #ifdef CONFIG_ROCKCHIP_OTP
9198168f857SYifeng Zhao 	buf[1] |= BIT(3); /* Read Otp Data */
9208168f857SYifeng Zhao 	buf[1] |= BIT(5); /* Write OTP proof */
9218168f857SYifeng Zhao 	buf[1] |= BIT(6); /* Write Cipher Key */
9228168f857SYifeng Zhao #endif
9238168f857SYifeng Zhao 
924f16e43f8SFrank Wang 	/* Set data xfer size */
925e66d4537SJon Lin 	common->residue = len;
926e66d4537SJon Lin 	common->data_size_from_cmnd = len;
927f16e43f8SFrank Wang 
928f16e43f8SFrank Wang 	return len;
929f16e43f8SFrank Wang }
930f16e43f8SFrank Wang 
9318168f857SYifeng Zhao #ifdef CONFIG_ROCKCHIP_OTP
9328168f857SYifeng Zhao static int rkusb_do_read_otp(struct fsg_common *common,
9338168f857SYifeng Zhao 			       struct fsg_buffhd *bh)
9348168f857SYifeng Zhao {
9358168f857SYifeng Zhao 	u32 len = common->data_size;
9368168f857SYifeng Zhao 	u32 type = common->cmnd[1];
9378168f857SYifeng Zhao 	u8 *buf = (u8 *)bh->buf;
9388168f857SYifeng Zhao 	struct udevice *dev;
9398168f857SYifeng Zhao 
9408168f857SYifeng Zhao 	buf[0] = 0;
9418168f857SYifeng Zhao 	if (type == 0) { /* soc uuid */
9428168f857SYifeng Zhao 		if (!uclass_get_device_by_driver(UCLASS_MISC, DM_GET_DRIVER(rockchip_otp), &dev)) {
9438168f857SYifeng Zhao 			if (!misc_read(dev, CFG_CPUID_OFFSET, (void *)&buf[1], len))
9448168f857SYifeng Zhao 				buf[0] = len;
9458168f857SYifeng Zhao 		}
9468168f857SYifeng Zhao 	}
9478168f857SYifeng Zhao 
9488168f857SYifeng Zhao 	common->residue = len;
9498168f857SYifeng Zhao 	common->data_size_from_cmnd = len;
9508168f857SYifeng Zhao 
9518168f857SYifeng Zhao 	return len;
9528168f857SYifeng Zhao }
9538168f857SYifeng Zhao #endif
9548168f857SYifeng Zhao 
955d23ec8c4SKever Yang static void rkusb_fixup_cbwcb(struct fsg_common *common,
956d23ec8c4SKever Yang 			      struct fsg_buffhd *bh)
957d23ec8c4SKever Yang {
958d23ec8c4SKever Yang 	struct usb_request      *req = bh->outreq;
959d23ec8c4SKever Yang 	struct fsg_bulk_cb_wrap *cbw = req->buf;
960d23ec8c4SKever Yang 
961d23ec8c4SKever Yang 	/* FIXME cbw.DataTransferLength was not set by Upgrade Tool */
962d23ec8c4SKever Yang 	common->data_size = le32_to_cpu(cbw->DataTransferLength);
963d23ec8c4SKever Yang 	if (common->data_size == 0) {
964d23ec8c4SKever Yang 		common->data_size =
965d23ec8c4SKever Yang 		get_unaligned_be16(&common->cmnd[7]) << 9;
966d23ec8c4SKever Yang 		printf("Trasfer Length NOT set, please use new version tool\n");
967d23ec8c4SKever Yang 		debug("%s %d, cmnd1 %x\n", __func__,
968d23ec8c4SKever Yang 		      get_unaligned_be16(&common->cmnd[7]),
969d23ec8c4SKever Yang 		      get_unaligned_be16(&common->cmnd[1]));
970d23ec8c4SKever Yang 	}
971d23ec8c4SKever Yang 	if (cbw->Flags & USB_BULK_IN_FLAG)
972d23ec8c4SKever Yang 		common->data_dir = DATA_DIR_TO_HOST;
973d23ec8c4SKever Yang 	else
974d23ec8c4SKever Yang 		common->data_dir = DATA_DIR_FROM_HOST;
975d23ec8c4SKever Yang 
976d23ec8c4SKever Yang 	/* Not support */
977d23ec8c4SKever Yang 	common->cmnd[1] = 0;
978d23ec8c4SKever Yang }
979d23ec8c4SKever Yang 
980f16e43f8SFrank Wang static int rkusb_cmd_process(struct fsg_common *common,
981f16e43f8SFrank Wang 			     struct fsg_buffhd *bh, int *reply)
982f16e43f8SFrank Wang {
983f16e43f8SFrank Wang 	struct usb_request	*req = bh->outreq;
984f16e43f8SFrank Wang 	struct fsg_bulk_cb_wrap	*cbw = req->buf;
985f16e43f8SFrank Wang 	int rc;
986f16e43f8SFrank Wang 
987f16e43f8SFrank Wang 	dump_cbw(cbw);
988f16e43f8SFrank Wang 
989f16e43f8SFrank Wang 	if (rkusb_check_lun(common)) {
990f16e43f8SFrank Wang 		*reply = -EINVAL;
991f16e43f8SFrank Wang 		return RKUSB_RC_ERROR;
992f16e43f8SFrank Wang 	}
993f16e43f8SFrank Wang 
994f16e43f8SFrank Wang 	switch (common->cmnd[0]) {
995f16e43f8SFrank Wang 	case RKUSB_TEST_UNIT_READY:
996f16e43f8SFrank Wang 		*reply = rkusb_do_test_unit_ready(common, bh);
997f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
998f16e43f8SFrank Wang 		break;
999f16e43f8SFrank Wang 
1000f16e43f8SFrank Wang 	case RKUSB_READ_FLASH_ID:
1001f16e43f8SFrank Wang 		*reply = rkusb_do_read_flash_id(common, bh);
1002f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
1003f16e43f8SFrank Wang 		break;
1004f16e43f8SFrank Wang 
1005f16e43f8SFrank Wang 	case RKUSB_TEST_BAD_BLOCK:
1006f16e43f8SFrank Wang 		*reply = rkusb_do_test_bad_block(common, bh);
1007f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
1008f16e43f8SFrank Wang 		break;
1009f16e43f8SFrank Wang 
1010e66d4537SJon Lin 	case RKUSB_ERASE_10_FORCE:
1011e66d4537SJon Lin 		*reply = rkusb_do_erase_force(common, bh);
1012e66d4537SJon Lin 		rc = RKUSB_RC_FINISHED;
1013e66d4537SJon Lin 		break;
1014e66d4537SJon Lin 
1015f16e43f8SFrank Wang 	case RKUSB_LBA_READ_10:
10165fb597c2SKever Yang 		rkusb_fixup_cbwcb(common, bh);
1017f16e43f8SFrank Wang 		common->cmnd[0] = SC_READ_10;
1018f16e43f8SFrank Wang 		common->cmnd[1] = 0; /* Not support */
1019f16e43f8SFrank Wang 		rc = RKUSB_RC_CONTINUE;
1020f16e43f8SFrank Wang 		break;
1021f16e43f8SFrank Wang 
1022f16e43f8SFrank Wang 	case RKUSB_LBA_WRITE_10:
10235fb597c2SKever Yang 		rkusb_fixup_cbwcb(common, bh);
1024f16e43f8SFrank Wang 		common->cmnd[0] = SC_WRITE_10;
1025f16e43f8SFrank Wang 		common->cmnd[1] = 0; /* Not support */
1026f16e43f8SFrank Wang 		rc = RKUSB_RC_CONTINUE;
1027f16e43f8SFrank Wang 		break;
1028f16e43f8SFrank Wang 
1029f16e43f8SFrank Wang 	case RKUSB_READ_FLASH_INFO:
1030f16e43f8SFrank Wang 		*reply = rkusb_do_read_flash_info(common, bh);
1031f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
1032f16e43f8SFrank Wang 		break;
1033f16e43f8SFrank Wang 
1034829f2b85SFrank Wang 	case RKUSB_GET_CHIP_VER:
1035829f2b85SFrank Wang 		*reply = rkusb_do_get_chip_info(common, bh);
1036829f2b85SFrank Wang 		rc = RKUSB_RC_FINISHED;
1037829f2b85SFrank Wang 		break;
1038829f2b85SFrank Wang 
1039f16e43f8SFrank Wang 	case RKUSB_LBA_ERASE:
1040f16e43f8SFrank Wang 		*reply = rkusb_do_lba_erase(common, bh);
1041f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
1042f16e43f8SFrank Wang 		break;
1043f16e43f8SFrank Wang 
10440d0c3248SFrank Wang #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION
10450d0c3248SFrank Wang 	case RKUSB_VS_WRITE:
10460d0c3248SFrank Wang 		*reply = rkusb_do_vs_write(common);
10470d0c3248SFrank Wang 		rc = RKUSB_RC_FINISHED;
10480d0c3248SFrank Wang 		break;
10490d0c3248SFrank Wang 
10500d0c3248SFrank Wang 	case RKUSB_VS_READ:
10510d0c3248SFrank Wang 		*reply = rkusb_do_vs_read(common);
10520d0c3248SFrank Wang 		rc = RKUSB_RC_FINISHED;
10530d0c3248SFrank Wang 		break;
10540d0c3248SFrank Wang #endif
10554d2787f5SJon Lin 	case RKUSB_SWITCH_STORAGE:
10564d2787f5SJon Lin 		*reply = rkusb_do_switch_storage(common);
10574d2787f5SJon Lin 		rc = RKUSB_RC_FINISHED;
10584d2787f5SJon Lin 		break;
1059d4cce25eSYifeng Zhao 	case RKUSB_GET_STORAGE_MEDIA:
1060d4cce25eSYifeng Zhao 		*reply = rkusb_do_get_storage_info(common, bh);
1061d4cce25eSYifeng Zhao 		rc = RKUSB_RC_FINISHED;
1062d4cce25eSYifeng Zhao 		break;
10630d0c3248SFrank Wang 
1064f16e43f8SFrank Wang 	case RKUSB_READ_CAPACITY:
1065f16e43f8SFrank Wang 		*reply = rkusb_do_read_capacity(common, bh);
1066f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
1067f16e43f8SFrank Wang 		break;
1068f16e43f8SFrank Wang 
106936c87911Swilliam.wu 	case RKUSB_SWITCH_USB3:
107036c87911Swilliam.wu 		*reply = rkusb_do_switch_to_usb3(common, bh);
107136c87911Swilliam.wu 		rc = RKUSB_RC_FINISHED;
107236c87911Swilliam.wu 		break;
107336c87911Swilliam.wu 
1074f16e43f8SFrank Wang 	case RKUSB_RESET:
1075f16e43f8SFrank Wang 		*reply = rkusb_do_reset(common, bh);
1076f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
1077f16e43f8SFrank Wang 		break;
1078f16e43f8SFrank Wang 
10798168f857SYifeng Zhao #ifdef CONFIG_ROCKCHIP_OTP
10808168f857SYifeng Zhao 	case RKUSB_READ_OTP_DATA:
10818168f857SYifeng Zhao 		*reply = rkusb_do_read_otp(common, bh);
10828168f857SYifeng Zhao 		rc = RKUSB_RC_FINISHED;
10838168f857SYifeng Zhao 		break;
10848168f857SYifeng Zhao #endif
10858168f857SYifeng Zhao 
1086f16e43f8SFrank Wang 	case RKUSB_READ_10:
1087f16e43f8SFrank Wang 	case RKUSB_WRITE_10:
1088e0023032SKever Yang 		printf("CMD Not support, pls use new version Tool\n");
1089e0023032SKever Yang 	case RKUSB_SET_DEVICE_ID:
1090f16e43f8SFrank Wang 	case RKUSB_ERASE_10:
1091f16e43f8SFrank Wang 	case RKUSB_WRITE_SPARE:
1092f16e43f8SFrank Wang 	case RKUSB_READ_SPARE:
1093f16e43f8SFrank Wang 	case RKUSB_GET_VERSION:
1094f16e43f8SFrank Wang 	case RKUSB_ERASE_SYS_DISK:
1095f16e43f8SFrank Wang 	case RKUSB_SDRAM_READ_10:
1096f16e43f8SFrank Wang 	case RKUSB_SDRAM_WRITE_10:
1097f16e43f8SFrank Wang 	case RKUSB_SDRAM_EXECUTE:
1098f16e43f8SFrank Wang 	case RKUSB_LOW_FORMAT:
1099f16e43f8SFrank Wang 	case RKUSB_SET_RESET_FLAG:
1100f16e43f8SFrank Wang 	case RKUSB_SPI_READ_10:
1101f16e43f8SFrank Wang 	case RKUSB_SPI_WRITE_10:
1102f16e43f8SFrank Wang 		/* Fall through */
1103f16e43f8SFrank Wang 	default:
1104f16e43f8SFrank Wang 		rc = RKUSB_RC_UNKNOWN_CMND;
1105f16e43f8SFrank Wang 		break;
1106f16e43f8SFrank Wang 	}
1107f16e43f8SFrank Wang 
1108f16e43f8SFrank Wang 	return rc;
1109f16e43f8SFrank Wang }
1110f16e43f8SFrank Wang 
11112c0c66c1SYifeng Zhao int rkusb_do_check_parity(struct fsg_common *common)
11122c0c66c1SYifeng Zhao {
11132c0c66c1SYifeng Zhao 	int ret = 0, rc;
11142c0c66c1SYifeng Zhao 	u32 parity, i, usb_parity, lba, len;
11152c0c66c1SYifeng Zhao 	static u32 usb_check_buffer[1024 * 256];
11162c0c66c1SYifeng Zhao 
11172c0c66c1SYifeng Zhao 	usb_parity = common->cmnd[9] | (common->cmnd[10] << 8) |
11182c0c66c1SYifeng Zhao 			(common->cmnd[11] << 16) | (common->cmnd[12] << 24);
11192c0c66c1SYifeng Zhao 
11202c0c66c1SYifeng Zhao 	if (common->cmnd[0] == SC_WRITE_10 && (usb_parity)) {
11212c0c66c1SYifeng Zhao 		lba = get_unaligned_be32(&common->cmnd[2]);
11222c0c66c1SYifeng Zhao 		len = common->data_size_from_cmnd >> 9;
11232c0c66c1SYifeng Zhao 		rc = blk_dread(&ums[common->lun].block_dev, lba, len, usb_check_buffer);
11242c0c66c1SYifeng Zhao 		parity = 0x000055aa;
11252c0c66c1SYifeng Zhao 		for (i = 0; i < len * 128; i++)
11262c0c66c1SYifeng Zhao 			parity += usb_check_buffer[i];
11272c0c66c1SYifeng Zhao 		if (!rc || parity != usb_parity)
11282c0c66c1SYifeng Zhao 			common->phase_error = 1;
11292c0c66c1SYifeng Zhao 	}
11302c0c66c1SYifeng Zhao 
11312c0c66c1SYifeng Zhao 	return ret;
11322c0c66c1SYifeng Zhao }
11332c0c66c1SYifeng Zhao 
1134f16e43f8SFrank Wang DECLARE_GADGET_BIND_CALLBACK(rkusb_ums_dnl, fsg_add);
1135