xref: /rk3399_rockchip-uboot/drivers/usb/gadget/f_rockusb.c (revision 8c6654f1c1f6fd59bc4e964e3a4ca1d96fd11f9b)
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>
174d2787f5SJon Lin #include <mmc.h>
184d2787f5SJon Lin #include <stdlib.h>
19*8c6654f1SJon Lin #include <usbplug.h>
200d0c3248SFrank Wang 
210d0c3248SFrank Wang #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION
220d0c3248SFrank Wang #include <asm/arch/vendor.h>
230d0c3248SFrank Wang #endif
24f16e43f8SFrank Wang #include <rockusb.h>
25f16e43f8SFrank Wang 
26f16e43f8SFrank Wang #define ROCKUSB_INTERFACE_CLASS	0xff
27f16e43f8SFrank Wang #define ROCKUSB_INTERFACE_SUB_CLASS	0x06
28f16e43f8SFrank Wang #define ROCKUSB_INTERFACE_PROTOCOL	0x05
29f16e43f8SFrank Wang 
30e66d4537SJon Lin #define ROCKCHIP_FLASH_BLOCK_SIZE	1024
31e66d4537SJon Lin #define ROCKCHIP_FLASH_PAGE_SIZE	4
32e66d4537SJon Lin 
33f16e43f8SFrank Wang static struct usb_interface_descriptor rkusb_intf_desc = {
34f16e43f8SFrank Wang 	.bLength		= USB_DT_INTERFACE_SIZE,
35f16e43f8SFrank Wang 	.bDescriptorType	= USB_DT_INTERFACE,
36f16e43f8SFrank Wang 	.bInterfaceNumber	= 0x00,
37f16e43f8SFrank Wang 	.bAlternateSetting	= 0x00,
38f16e43f8SFrank Wang 	.bNumEndpoints		= 0x02,
39f16e43f8SFrank Wang 	.bInterfaceClass	= ROCKUSB_INTERFACE_CLASS,
40f16e43f8SFrank Wang 	.bInterfaceSubClass	= ROCKUSB_INTERFACE_SUB_CLASS,
41f16e43f8SFrank Wang 	.bInterfaceProtocol	= ROCKUSB_INTERFACE_PROTOCOL,
42f16e43f8SFrank Wang };
43f16e43f8SFrank Wang 
44f16e43f8SFrank Wang static struct usb_descriptor_header *rkusb_fs_function[] = {
45f16e43f8SFrank Wang 	(struct usb_descriptor_header *)&rkusb_intf_desc,
46f16e43f8SFrank Wang 	(struct usb_descriptor_header *)&fsg_fs_bulk_in_desc,
47f16e43f8SFrank Wang 	(struct usb_descriptor_header *)&fsg_fs_bulk_out_desc,
48f16e43f8SFrank Wang 	NULL,
49f16e43f8SFrank Wang };
50f16e43f8SFrank Wang 
51f16e43f8SFrank Wang static struct usb_descriptor_header *rkusb_hs_function[] = {
52f16e43f8SFrank Wang 	(struct usb_descriptor_header *)&rkusb_intf_desc,
53f16e43f8SFrank Wang 	(struct usb_descriptor_header *)&fsg_hs_bulk_in_desc,
54f16e43f8SFrank Wang 	(struct usb_descriptor_header *)&fsg_hs_bulk_out_desc,
55f16e43f8SFrank Wang 	NULL,
56f16e43f8SFrank Wang };
57f16e43f8SFrank Wang 
5826dd3474SWilliam Wu static struct usb_descriptor_header *rkusb_ss_function[] = {
5926dd3474SWilliam Wu 	(struct usb_descriptor_header *)&rkusb_intf_desc,
6026dd3474SWilliam Wu 	(struct usb_descriptor_header *)&fsg_ss_bulk_in_desc,
6126dd3474SWilliam Wu 	(struct usb_descriptor_header *)&fsg_ss_bulk_in_comp_desc,
6226dd3474SWilliam Wu 	(struct usb_descriptor_header *)&fsg_ss_bulk_out_desc,
6326dd3474SWilliam Wu 	(struct usb_descriptor_header *)&fsg_ss_bulk_out_comp_desc,
6426dd3474SWilliam Wu 	NULL,
6526dd3474SWilliam Wu };
6626dd3474SWilliam Wu 
67f16e43f8SFrank Wang struct rk_flash_info {
68f16e43f8SFrank Wang 	u32	flash_size;
69f16e43f8SFrank Wang 	u16	block_size;
70f16e43f8SFrank Wang 	u8	page_size;
71f16e43f8SFrank Wang 	u8	ecc_bits;
72f16e43f8SFrank Wang 	u8	access_time;
73f16e43f8SFrank Wang 	u8	manufacturer;
74f16e43f8SFrank Wang 	u8	flash_mask;
75f16e43f8SFrank Wang } __packed;
76f16e43f8SFrank Wang 
775b081643SFrank Wang static int rkusb_rst_code; /* The subcode in reset command (0xFF) */
785b081643SFrank Wang 
79f16e43f8SFrank Wang int g_dnl_bind_fixup(struct usb_device_descriptor *dev, const char *name)
80f16e43f8SFrank Wang {
81ba437c8cSFrank Wang 	if (IS_RKUSB_UMS_DNL(name)) {
82c0acb0f2SFrank Wang 		/* Fix to Rockchip's VID and PID */
83ba437c8cSFrank Wang 		dev->idVendor  = __constant_cpu_to_le16(0x2207);
84ba437c8cSFrank Wang 		dev->idProduct = __constant_cpu_to_le16(CONFIG_ROCKUSB_G_DNL_PID);
85ba437c8cSFrank Wang 
86f16e43f8SFrank Wang 		/* Enumerate as a loader device */
8795424692SJoseph Chen #if defined(CONFIG_SUPPORT_USBPLUG)
8895424692SJoseph Chen 		dev->bcdUSB = cpu_to_le16(0x0200);
8995424692SJoseph Chen #else
90f16e43f8SFrank Wang 		dev->bcdUSB = cpu_to_le16(0x0201);
9195424692SJoseph Chen #endif
92c0acb0f2SFrank Wang 	} else if (!strncmp(name, "usb_dnl_fastboot", 16)) {
93c0acb0f2SFrank Wang 		/* Fix to Google's VID and PID */
94c0acb0f2SFrank Wang 		dev->idVendor  = __constant_cpu_to_le16(0x18d1);
95c0acb0f2SFrank Wang 		dev->idProduct = __constant_cpu_to_le16(0xd00d);
96ca422507SYifeng Zhao 	} else if (!strncmp(name, "usb_dnl_dfu", 11)) {
97ca422507SYifeng Zhao 		/* Fix to Rockchip's VID and PID for DFU */
98ca422507SYifeng Zhao 		dev->idVendor  = cpu_to_le16(0x2207);
99ca422507SYifeng Zhao 		dev->idProduct = cpu_to_le16(0x0107);
1000a076251SFrank Wang 	} else if (!strncmp(name, "usb_dnl_ums", 11)) {
1010a076251SFrank Wang 		dev->idVendor  = cpu_to_le16(0x2207);
1020a076251SFrank Wang 		dev->idProduct = cpu_to_le16(0x0010);
103ba437c8cSFrank Wang 	}
104f16e43f8SFrank Wang 
105f16e43f8SFrank Wang 	return 0;
106f16e43f8SFrank Wang }
107f16e43f8SFrank Wang 
108f16e43f8SFrank Wang __maybe_unused
109f16e43f8SFrank Wang static inline void dump_cbw(struct fsg_bulk_cb_wrap *cbw)
110f16e43f8SFrank Wang {
111f16e43f8SFrank Wang 	assert(!cbw);
112f16e43f8SFrank Wang 
113f16e43f8SFrank Wang 	debug("%s:\n", __func__);
114f16e43f8SFrank Wang 	debug("Signature %x\n", cbw->Signature);
115f16e43f8SFrank Wang 	debug("Tag %x\n", cbw->Tag);
116f16e43f8SFrank Wang 	debug("DataTransferLength %x\n", cbw->DataTransferLength);
117f16e43f8SFrank Wang 	debug("Flags %x\n", cbw->Flags);
118f16e43f8SFrank Wang 	debug("LUN %x\n", cbw->Lun);
119f16e43f8SFrank Wang 	debug("Length %x\n", cbw->Length);
120f16e43f8SFrank Wang 	debug("OptionCode %x\n", cbw->CDB[0]);
121f16e43f8SFrank Wang 	debug("SubCode %x\n", cbw->CDB[1]);
122f16e43f8SFrank Wang 	debug("SectorAddr %x\n", get_unaligned_be32(&cbw->CDB[2]));
123f16e43f8SFrank Wang 	debug("BlkSectors %x\n\n", get_unaligned_be16(&cbw->CDB[7]));
124f16e43f8SFrank Wang }
125f16e43f8SFrank Wang 
126f16e43f8SFrank Wang static int rkusb_check_lun(struct fsg_common *common)
127f16e43f8SFrank Wang {
128f16e43f8SFrank Wang 	struct fsg_lun *curlun;
129f16e43f8SFrank Wang 
130f16e43f8SFrank Wang 	/* Check the LUN */
131f16e43f8SFrank Wang 	if (common->lun >= 0 && common->lun < common->nluns) {
132f16e43f8SFrank Wang 		curlun = &common->luns[common->lun];
133f16e43f8SFrank Wang 		if (common->cmnd[0] != SC_REQUEST_SENSE) {
134f16e43f8SFrank Wang 			curlun->sense_data = SS_NO_SENSE;
135f16e43f8SFrank Wang 			curlun->info_valid = 0;
136f16e43f8SFrank Wang 		}
137f16e43f8SFrank Wang 	} else {
138f16e43f8SFrank Wang 		curlun = NULL;
139f16e43f8SFrank Wang 		common->bad_lun_okay = 0;
140f16e43f8SFrank Wang 
141f16e43f8SFrank Wang 		/*
142f16e43f8SFrank Wang 		 * INQUIRY and REQUEST SENSE commands are explicitly allowed
143f16e43f8SFrank Wang 		 * to use unsupported LUNs; all others may not.
144f16e43f8SFrank Wang 		 */
145f16e43f8SFrank Wang 		if (common->cmnd[0] != SC_INQUIRY &&
146f16e43f8SFrank Wang 		    common->cmnd[0] != SC_REQUEST_SENSE) {
147f16e43f8SFrank Wang 			debug("unsupported LUN %d\n", common->lun);
148f16e43f8SFrank Wang 			return -EINVAL;
149f16e43f8SFrank Wang 		}
150f16e43f8SFrank Wang 	}
151f16e43f8SFrank Wang 
152f16e43f8SFrank Wang 	return 0;
153f16e43f8SFrank Wang }
154f16e43f8SFrank Wang 
155f16e43f8SFrank Wang static void __do_reset(struct usb_ep *ep, struct usb_request *req)
156f16e43f8SFrank Wang {
1575b081643SFrank Wang 	u32 boot_flag = BOOT_NORMAL;
1585b081643SFrank Wang 
1595b081643SFrank Wang 	if (rkusb_rst_code == 0x03)
1605b081643SFrank Wang 		boot_flag = BOOT_BROM_DOWNLOAD;
1615b081643SFrank Wang 
1625b081643SFrank Wang 	rkusb_rst_code = 0; /* restore to default */
1635b081643SFrank Wang 	writel(boot_flag, (void *)CONFIG_ROCKCHIP_BOOT_MODE_REG);
164866d7966SJoseph Chen 
165f16e43f8SFrank Wang 	do_reset(NULL, 0, 0, NULL);
166f16e43f8SFrank Wang }
167f16e43f8SFrank Wang 
168f16e43f8SFrank Wang static int rkusb_do_reset(struct fsg_common *common,
169f16e43f8SFrank Wang 			  struct fsg_buffhd *bh)
170f16e43f8SFrank Wang {
171f16e43f8SFrank Wang 	common->data_size_from_cmnd = common->cmnd[4];
172f16e43f8SFrank Wang 	common->residue = 0;
173f16e43f8SFrank Wang 	bh->inreq->complete = __do_reset;
174f16e43f8SFrank Wang 	bh->state = BUF_STATE_EMPTY;
175f16e43f8SFrank Wang 
1765b081643SFrank Wang 	rkusb_rst_code = !common->cmnd[1] ? 0xff : common->cmnd[1];
177f16e43f8SFrank Wang 	return 0;
178f16e43f8SFrank Wang }
179f16e43f8SFrank Wang 
18036c87911Swilliam.wu __weak bool rkusb_usb3_capable(void)
18136c87911Swilliam.wu {
18236c87911Swilliam.wu 	return false;
18336c87911Swilliam.wu }
18436c87911Swilliam.wu 
18536c87911Swilliam.wu static int rkusb_do_switch_to_usb3(struct fsg_common *common,
18636c87911Swilliam.wu 				   struct fsg_buffhd *bh)
18736c87911Swilliam.wu {
18836c87911Swilliam.wu 	g_dnl_set_serialnumber((char *)&common->cmnd[1]);
18936c87911Swilliam.wu 	rkusb_switch_to_usb3_enable(true);
19036c87911Swilliam.wu 	bh->state = BUF_STATE_EMPTY;
19136c87911Swilliam.wu 
19236c87911Swilliam.wu 	return 0;
19336c87911Swilliam.wu }
19436c87911Swilliam.wu 
195f16e43f8SFrank Wang static int rkusb_do_test_unit_ready(struct fsg_common *common,
196f16e43f8SFrank Wang 				    struct fsg_buffhd *bh)
197f16e43f8SFrank Wang {
1987eb64117SJon Lin 	struct blk_desc *desc = &ums[common->lun].block_dev;
1997eb64117SJon Lin 
2007eb64117SJon Lin 	if ((desc->if_type == IF_TYPE_MTD && desc->devnum == BLK_MTD_SPI_NOR) ||
2017eb64117SJon Lin 	    desc->if_type == IF_TYPE_SPINOR)
2027eb64117SJon Lin 		common->residue = 0x03 << 24; /* 128KB Max block xfer for SPI Nor */
2037eb64117SJon Lin 	else
204f16e43f8SFrank Wang 		common->residue = 0x06 << 24; /* Max block xfer support from host */
2057eb64117SJon Lin 
206f16e43f8SFrank Wang 	common->data_dir = DATA_DIR_NONE;
207f16e43f8SFrank Wang 	bh->state = BUF_STATE_EMPTY;
208f16e43f8SFrank Wang 
209f16e43f8SFrank Wang 	return 0;
210f16e43f8SFrank Wang }
211f16e43f8SFrank Wang 
212f16e43f8SFrank Wang static int rkusb_do_read_flash_id(struct fsg_common *common,
213f16e43f8SFrank Wang 				  struct fsg_buffhd *bh)
214f16e43f8SFrank Wang {
215f16e43f8SFrank Wang 	u8 *buf = (u8 *)bh->buf;
216e0023032SKever Yang 	u32 len = 5;
217d7386f60SFrank Wang 	enum if_type type = ums[common->lun].block_dev.if_type;
218afc6362aSJon Lin 	u32 devnum = ums[common->lun].block_dev.devnum;
219afc6362aSJon Lin 	const char *str;
220f16e43f8SFrank Wang 
221afc6362aSJon Lin 	switch (type) {
222afc6362aSJon Lin 	case IF_TYPE_MMC:
223afc6362aSJon Lin 		str = "EMMC ";
224afc6362aSJon Lin 		break;
225afc6362aSJon Lin 	case IF_TYPE_RKNAND:
226afc6362aSJon Lin 		str = "NAND ";
227afc6362aSJon Lin 		break;
228afc6362aSJon Lin 	case IF_TYPE_MTD:
229afc6362aSJon Lin 		if (devnum == BLK_MTD_SPI_NAND)
230afc6362aSJon Lin 			str ="SNAND";
231afc6362aSJon Lin 		else if (devnum == BLK_MTD_NAND)
232afc6362aSJon Lin 			str = "NAND ";
233d7386f60SFrank Wang 		else
234afc6362aSJon Lin 			str = "NOR  ";
235afc6362aSJon Lin 		break;
236afc6362aSJon Lin 	default:
237afc6362aSJon Lin 		str = "UNKN "; /* unknown */
238afc6362aSJon Lin 		break;
239afc6362aSJon Lin 	}
240afc6362aSJon Lin 
241afc6362aSJon Lin 	memcpy((void *)&buf[0], str, len);
242f16e43f8SFrank Wang 
243f16e43f8SFrank Wang 	/* Set data xfer size */
244f16e43f8SFrank Wang 	common->residue = common->data_size_from_cmnd = len;
245e0023032SKever Yang 	common->data_size = len;
246f16e43f8SFrank Wang 
247f16e43f8SFrank Wang 	return len;
248f16e43f8SFrank Wang }
249f16e43f8SFrank Wang 
250f16e43f8SFrank Wang static int rkusb_do_test_bad_block(struct fsg_common *common,
251f16e43f8SFrank Wang 				   struct fsg_buffhd *bh)
252f16e43f8SFrank Wang {
253f16e43f8SFrank Wang 	u8 *buf = (u8 *)bh->buf;
254e0023032SKever Yang 	u32 len = 64;
255f16e43f8SFrank Wang 
256f16e43f8SFrank Wang 	memset((void *)&buf[0], 0, len);
257f16e43f8SFrank Wang 
258f16e43f8SFrank Wang 	/* Set data xfer size */
259f16e43f8SFrank Wang 	common->residue = common->data_size_from_cmnd = len;
260e0023032SKever Yang 	common->data_size = len;
261f16e43f8SFrank Wang 
262f16e43f8SFrank Wang 	return len;
263f16e43f8SFrank Wang }
264f16e43f8SFrank Wang 
265f16e43f8SFrank Wang static int rkusb_do_read_flash_info(struct fsg_common *common,
266f16e43f8SFrank Wang 				    struct fsg_buffhd *bh)
267f16e43f8SFrank Wang {
268e66d4537SJon Lin 	struct blk_desc *desc = &ums[common->lun].block_dev;
269f16e43f8SFrank Wang 	u8 *buf = (u8 *)bh->buf;
270d23ec8c4SKever Yang 	u32 len = sizeof(struct rk_flash_info);
271f16e43f8SFrank Wang 	struct rk_flash_info finfo = {
272e66d4537SJon Lin 		.block_size = ROCKCHIP_FLASH_BLOCK_SIZE,
273f16e43f8SFrank Wang 		.ecc_bits = 0,
274e66d4537SJon Lin 		.page_size = ROCKCHIP_FLASH_PAGE_SIZE,
275f16e43f8SFrank Wang 		.access_time = 40,
276f16e43f8SFrank Wang 		.manufacturer = 0,
277f16e43f8SFrank Wang 		.flash_mask = 0
278f16e43f8SFrank Wang 	};
279f16e43f8SFrank Wang 
280e66d4537SJon Lin 	finfo.flash_size = (u32)desc->lba;
281e66d4537SJon Lin 
282e66d4537SJon Lin 	if (desc->if_type == IF_TYPE_MTD &&
283e66d4537SJon Lin 	    (desc->devnum == BLK_MTD_NAND ||
284e66d4537SJon Lin 	    desc->devnum == BLK_MTD_SPI_NAND)) {
285e66d4537SJon Lin 		struct mtd_info *mtd = (struct mtd_info *)desc->bdev->priv;
286e66d4537SJon Lin 
287e66d4537SJon Lin 		if (mtd) {
288e66d4537SJon Lin 			finfo.block_size = mtd->erasesize >> 9;
289e66d4537SJon Lin 			finfo.page_size = mtd->writesize >> 9;
290e66d4537SJon Lin 		}
291e66d4537SJon Lin 	}
292e66d4537SJon Lin 
29365a0fed9SJon Lin 	if (desc->if_type == IF_TYPE_MTD && desc->devnum == BLK_MTD_SPI_NOR) {
29465a0fed9SJon Lin 		/* RV1126/RK3308 mtd spinor keep the former upgrade mode */
29565a0fed9SJon Lin #if !defined(CONFIG_ROCKCHIP_RV1126) && !defined(CONFIG_ROCKCHIP_RK3308)
296b8e5601dSJon Lin 		finfo.block_size = 0x80; /* Aligned to 64KB */
29765a0fed9SJon Lin #else
29865a0fed9SJon Lin 		finfo.block_size = ROCKCHIP_FLASH_BLOCK_SIZE;
29965a0fed9SJon Lin #endif
30065a0fed9SJon Lin 	}
30165a0fed9SJon Lin 
302e66d4537SJon Lin 	debug("Flash info: block_size= %x page_size= %x\n", finfo.block_size,
303e66d4537SJon Lin 	      finfo.page_size);
304e66d4537SJon Lin 
305f16e43f8SFrank Wang 	if (finfo.flash_size)
306f16e43f8SFrank Wang 		finfo.flash_mask = 1;
307f16e43f8SFrank Wang 
308f16e43f8SFrank Wang 	memset((void *)&buf[0], 0, len);
309f16e43f8SFrank Wang 	memcpy((void *)&buf[0], (void *)&finfo, len);
310f16e43f8SFrank Wang 
311f16e43f8SFrank Wang 	/* Set data xfer size */
312f16e43f8SFrank Wang 	common->residue = common->data_size_from_cmnd = len;
313d23ec8c4SKever Yang         /* legacy upgrade_tool does not set correct transfer size */
314d23ec8c4SKever Yang 	common->data_size = len;
315f16e43f8SFrank Wang 
316f16e43f8SFrank Wang 	return len;
317f16e43f8SFrank Wang }
318f16e43f8SFrank Wang 
319829f2b85SFrank Wang static int rkusb_do_get_chip_info(struct fsg_common *common,
320829f2b85SFrank Wang 				  struct fsg_buffhd *bh)
321829f2b85SFrank Wang {
322829f2b85SFrank Wang 	u8 *buf = (u8 *)bh->buf;
323829f2b85SFrank Wang 	u32 len = common->data_size;
324829f2b85SFrank Wang 	u32 chip_info[4];
325829f2b85SFrank Wang 
326829f2b85SFrank Wang 	memset((void *)chip_info, 0, sizeof(chip_info));
327829f2b85SFrank Wang 	rockchip_rockusb_get_chip_info(chip_info);
328829f2b85SFrank Wang 
329829f2b85SFrank Wang 	memset((void *)&buf[0], 0, len);
330829f2b85SFrank Wang 	memcpy((void *)&buf[0], (void *)chip_info, len);
331829f2b85SFrank Wang 
332829f2b85SFrank Wang 	/* Set data xfer size */
333829f2b85SFrank Wang 	common->residue = common->data_size_from_cmnd = len;
334829f2b85SFrank Wang 
335829f2b85SFrank Wang 	return len;
336829f2b85SFrank Wang }
337829f2b85SFrank Wang 
338f16e43f8SFrank Wang static int rkusb_do_lba_erase(struct fsg_common *common,
339f16e43f8SFrank Wang 			      struct fsg_buffhd *bh)
340f16e43f8SFrank Wang {
341f16e43f8SFrank Wang 	struct fsg_lun *curlun = &common->luns[common->lun];
342f16e43f8SFrank Wang 	u32 lba, amount;
343f16e43f8SFrank Wang 	loff_t file_offset;
344f16e43f8SFrank Wang 	int rc;
345f16e43f8SFrank Wang 
346f16e43f8SFrank Wang 	lba = get_unaligned_be32(&common->cmnd[2]);
347f16e43f8SFrank Wang 	if (lba >= curlun->num_sectors) {
348f16e43f8SFrank Wang 		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
349f16e43f8SFrank Wang 		rc = -EINVAL;
350f16e43f8SFrank Wang 		goto out;
351f16e43f8SFrank Wang 	}
352f16e43f8SFrank Wang 
353f16e43f8SFrank Wang 	file_offset = ((loff_t) lba) << 9;
354f16e43f8SFrank Wang 	amount = get_unaligned_be16(&common->cmnd[7]) << 9;
355f16e43f8SFrank Wang 	if (unlikely(amount == 0)) {
356f16e43f8SFrank Wang 		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
357f16e43f8SFrank Wang 		rc = -EIO;
358f16e43f8SFrank Wang 		goto out;
359f16e43f8SFrank Wang 	}
360f16e43f8SFrank Wang 
361f16e43f8SFrank Wang 	/* Perform the erase */
362f16e43f8SFrank Wang 	rc = ums[common->lun].erase_sector(&ums[common->lun],
363f16e43f8SFrank Wang 			       file_offset / SECTOR_SIZE,
364f16e43f8SFrank Wang 			       amount / SECTOR_SIZE);
365f16e43f8SFrank Wang 	if (!rc) {
366f16e43f8SFrank Wang 		curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
367f16e43f8SFrank Wang 		rc = -EIO;
368f16e43f8SFrank Wang 	}
369f16e43f8SFrank Wang 
370f16e43f8SFrank Wang out:
371f16e43f8SFrank Wang 	common->data_dir = DATA_DIR_NONE;
372f16e43f8SFrank Wang 	bh->state = BUF_STATE_EMPTY;
373f16e43f8SFrank Wang 
374f16e43f8SFrank Wang 	return rc;
375f16e43f8SFrank Wang }
376f16e43f8SFrank Wang 
377e66d4537SJon Lin static int rkusb_do_erase_force(struct fsg_common *common,
378e66d4537SJon Lin 				struct fsg_buffhd *bh)
379e66d4537SJon Lin {
380e66d4537SJon Lin 	struct blk_desc *desc = &ums[common->lun].block_dev;
381e66d4537SJon Lin 	struct fsg_lun *curlun = &common->luns[common->lun];
382e66d4537SJon Lin 	u16 block_size = ROCKCHIP_FLASH_BLOCK_SIZE;
383e66d4537SJon Lin 	u32 lba, amount;
384e66d4537SJon Lin 	loff_t file_offset;
385e66d4537SJon Lin 	int rc;
386e66d4537SJon Lin 
387e66d4537SJon Lin 	lba = get_unaligned_be32(&common->cmnd[2]);
388e66d4537SJon Lin 	if (lba >= curlun->num_sectors) {
389e66d4537SJon Lin 		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
390e66d4537SJon Lin 		rc = -EINVAL;
391e66d4537SJon Lin 		goto out;
392e66d4537SJon Lin 	}
393e66d4537SJon Lin 
394e66d4537SJon Lin 	if (desc->if_type == IF_TYPE_MTD &&
395e66d4537SJon Lin 	    (desc->devnum == BLK_MTD_NAND ||
396e66d4537SJon Lin 	    desc->devnum == BLK_MTD_SPI_NAND)) {
397e66d4537SJon Lin 		struct mtd_info *mtd = (struct mtd_info *)desc->bdev->priv;
398e66d4537SJon Lin 
399e66d4537SJon Lin 		if (mtd)
400e66d4537SJon Lin 			block_size = mtd->erasesize >> 9;
401e66d4537SJon Lin 	}
402e66d4537SJon Lin 
403e66d4537SJon Lin 	file_offset = ((loff_t)lba) * block_size;
404e66d4537SJon Lin 	amount = get_unaligned_be16(&common->cmnd[7]) * block_size;
405e66d4537SJon Lin 
406e66d4537SJon Lin 	debug("%s lba= %x, nsec= %x\n", __func__, lba,
407e66d4537SJon Lin 	      (u32)get_unaligned_be16(&common->cmnd[7]));
408e66d4537SJon Lin 
409e66d4537SJon Lin 	if (unlikely(amount == 0)) {
410e66d4537SJon Lin 		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
411e66d4537SJon Lin 		rc = -EIO;
412e66d4537SJon Lin 		goto out;
413e66d4537SJon Lin 	}
414e66d4537SJon Lin 
415e66d4537SJon Lin 	/* Perform the erase */
416e66d4537SJon Lin 	rc = ums[common->lun].erase_sector(&ums[common->lun],
417e66d4537SJon Lin 					   file_offset,
418e66d4537SJon Lin 					   amount);
419e66d4537SJon Lin 	if (!rc) {
420e66d4537SJon Lin 		curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
421e66d4537SJon Lin 		rc = -EIO;
422e66d4537SJon Lin 	}
423e66d4537SJon Lin 
424e66d4537SJon Lin out:
425e66d4537SJon Lin 	common->data_dir = DATA_DIR_NONE;
426e66d4537SJon Lin 	bh->state = BUF_STATE_EMPTY;
427e66d4537SJon Lin 
428e66d4537SJon Lin 	return rc;
429e66d4537SJon Lin }
430e66d4537SJon Lin 
4310d0c3248SFrank Wang #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION
4320d0c3248SFrank Wang static int rkusb_do_vs_write(struct fsg_common *common)
4330d0c3248SFrank Wang {
4340d0c3248SFrank Wang 	struct fsg_lun		*curlun = &common->luns[common->lun];
4350d0c3248SFrank Wang 	u16			type = get_unaligned_be16(&common->cmnd[4]);
4360d0c3248SFrank Wang 	struct vendor_item	*vhead;
4370d0c3248SFrank Wang 	struct fsg_buffhd	*bh;
4380d0c3248SFrank Wang 	void			*data;
4390d0c3248SFrank Wang 	int			rc;
4400d0c3248SFrank Wang 
4410d0c3248SFrank Wang 	if (common->data_size >= (u32)65536) {
4420d0c3248SFrank Wang 		/* _MUST_ small than 64K */
4430d0c3248SFrank Wang 		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
4440d0c3248SFrank Wang 		return -EINVAL;
4450d0c3248SFrank Wang 	}
4460d0c3248SFrank Wang 
4470d0c3248SFrank Wang 	common->residue         = common->data_size;
4480d0c3248SFrank Wang 	common->usb_amount_left = common->data_size;
4490d0c3248SFrank Wang 
4500d0c3248SFrank Wang 	/* Carry out the file writes */
4510d0c3248SFrank Wang 	if (unlikely(common->data_size == 0))
4520d0c3248SFrank Wang 		return -EIO; /* No data to write */
4530d0c3248SFrank Wang 
4540d0c3248SFrank Wang 	for (;;) {
4550d0c3248SFrank Wang 		if (common->usb_amount_left > 0) {
4560d0c3248SFrank Wang 			/* Wait for the next buffer to become available */
4570d0c3248SFrank Wang 			bh = common->next_buffhd_to_fill;
4580d0c3248SFrank Wang 			if (bh->state != BUF_STATE_EMPTY)
4590d0c3248SFrank Wang 				goto wait;
4600d0c3248SFrank Wang 
4610d0c3248SFrank Wang 			/* Request the next buffer */
4620d0c3248SFrank Wang 			common->usb_amount_left      -= common->data_size;
4630d0c3248SFrank Wang 			bh->outreq->length	     = common->data_size;
4640d0c3248SFrank Wang 			bh->bulk_out_intended_length = common->data_size;
4650d0c3248SFrank Wang 			bh->outreq->short_not_ok     = 1;
4660d0c3248SFrank Wang 
4670d0c3248SFrank Wang 			START_TRANSFER_OR(common, bulk_out, bh->outreq,
4680d0c3248SFrank Wang 					  &bh->outreq_busy, &bh->state)
4690d0c3248SFrank Wang 				/*
4700d0c3248SFrank Wang 				 * Don't know what to do if
4710d0c3248SFrank Wang 				 * common->fsg is NULL
4720d0c3248SFrank Wang 				 */
4730d0c3248SFrank Wang 				return -EIO;
4740d0c3248SFrank Wang 			common->next_buffhd_to_fill = bh->next;
4750d0c3248SFrank Wang 		} else {
4760d0c3248SFrank Wang 			/* Then, wait for the data to become available */
4770d0c3248SFrank Wang 			bh = common->next_buffhd_to_drain;
4780d0c3248SFrank Wang 			if (bh->state != BUF_STATE_FULL)
4790d0c3248SFrank Wang 				goto wait;
4800d0c3248SFrank Wang 
4810d0c3248SFrank Wang 			common->next_buffhd_to_drain = bh->next;
4820d0c3248SFrank Wang 			bh->state = BUF_STATE_EMPTY;
4830d0c3248SFrank Wang 
4840d0c3248SFrank Wang 			/* Did something go wrong with the transfer? */
4850d0c3248SFrank Wang 			if (bh->outreq->status != 0) {
4860d0c3248SFrank Wang 				curlun->sense_data = SS_COMMUNICATION_FAILURE;
4870d0c3248SFrank Wang 				curlun->info_valid = 1;
4880d0c3248SFrank Wang 				break;
4890d0c3248SFrank Wang 			}
4900d0c3248SFrank Wang 
4910d0c3248SFrank Wang 			/* Perform the write */
4920d0c3248SFrank Wang 			vhead = (struct vendor_item *)bh->buf;
4930d0c3248SFrank Wang 			data  = bh->buf + sizeof(struct vendor_item);
4940d0c3248SFrank Wang 
4950d0c3248SFrank Wang 			if (!type) {
49670990948SYifeng Zhao 				#ifndef CONFIG_SUPPORT_USBPLUG
497420ee9d5SJoseph Chen 				if (vhead->id == HDCP_14_HDMI_ID ||
49878dcc928SZhang Yubing 				    vhead->id == HDCP_14_HDMIRX_ID ||
49978dcc928SZhang Yubing 				    vhead->id == HDCP_14_DP_ID) {
500420ee9d5SJoseph Chen 					rc = vendor_handle_hdcp(vhead);
501420ee9d5SJoseph Chen 					if (rc < 0) {
502420ee9d5SJoseph Chen 						curlun->sense_data = SS_WRITE_ERROR;
503420ee9d5SJoseph Chen 						return -EIO;
504420ee9d5SJoseph Chen 					}
505420ee9d5SJoseph Chen 				}
50670990948SYifeng Zhao 				#endif
507420ee9d5SJoseph Chen 
5080d0c3248SFrank Wang 				/* Vendor storage */
5090d0c3248SFrank Wang 				rc = vendor_storage_write(vhead->id,
5100d0c3248SFrank Wang 							  (char __user *)data,
5110d0c3248SFrank Wang 							  vhead->size);
51219652be0SFrank Wang 				if (rc < 0) {
51319652be0SFrank Wang 					curlun->sense_data = SS_WRITE_ERROR;
5140d0c3248SFrank Wang 					return -EIO;
51519652be0SFrank Wang 				}
5162122174dSWu Liangqing 			} else if (type == 1) {
5170d0c3248SFrank Wang 				/* RPMB */
5186f0347c8Stony.xu 				rc =
5196f0347c8Stony.xu 				write_keybox_to_secure_storage((u8 *)data,
5206f0347c8Stony.xu 							       vhead->size);
52119652be0SFrank Wang 				if (rc < 0) {
52219652be0SFrank Wang 					curlun->sense_data = SS_WRITE_ERROR;
5236f0347c8Stony.xu 					return -EIO;
5240d0c3248SFrank Wang 				}
5252122174dSWu Liangqing 			} else if (type == 2) {
5262122174dSWu Liangqing 				/* security storage */
5272122174dSWu Liangqing #ifdef CONFIG_RK_AVB_LIBAVB_USER
5282122174dSWu Liangqing 				debug("%s call rk_avb_write_perm_attr %d, %d\n",
5292122174dSWu Liangqing 				      __func__, vhead->id, vhead->size);
5302122174dSWu Liangqing 				rc = rk_avb_write_perm_attr(vhead->id,
5312122174dSWu Liangqing 							    (char __user *)data,
5322122174dSWu Liangqing 							    vhead->size);
5332122174dSWu Liangqing 				if (rc < 0) {
5342122174dSWu Liangqing 					curlun->sense_data = SS_WRITE_ERROR;
5352122174dSWu Liangqing 					return -EIO;
5362122174dSWu Liangqing 				}
5372122174dSWu Liangqing #else
5382122174dSWu Liangqing 				printf("Please enable CONFIG_RK_AVB_LIBAVB_USER\n");
5392122174dSWu Liangqing #endif
540850ced9dSHisping Lin 			} else if (type == 3) {
541850ced9dSHisping Lin 				/* efuse or otp*/
542850ced9dSHisping Lin #ifdef CONFIG_OPTEE_CLIENT
543850ced9dSHisping Lin 				if (memcmp(data, "TAEK", 4) == 0) {
544850ced9dSHisping Lin 					if (vhead->size - 8 != 32) {
545850ced9dSHisping Lin 						printf("check ta encryption key size fail!\n");
546850ced9dSHisping Lin 						curlun->sense_data = SS_WRITE_ERROR;
547850ced9dSHisping Lin 						return -EIO;
548850ced9dSHisping Lin 					}
549850ced9dSHisping Lin 					if (trusty_write_ta_encryption_key((uint32_t *)(data + 8), 8) != 0) {
550850ced9dSHisping Lin 						printf("trusty_write_ta_encryption_key error!");
551850ced9dSHisping Lin 						curlun->sense_data = SS_WRITE_ERROR;
552850ced9dSHisping Lin 						return -EIO;
553850ced9dSHisping Lin 					}
554a43611afSHisping Lin 				} else if (memcmp(data, "EHUK", 4) == 0) {
555a43611afSHisping Lin 					if (vhead->size - 8 != 32) {
556a43611afSHisping Lin 						printf("check oem huk size fail!\n");
557a43611afSHisping Lin 						curlun->sense_data = SS_WRITE_ERROR;
558a43611afSHisping Lin 						return -EIO;
559a43611afSHisping Lin 					}
560a43611afSHisping Lin 					if (trusty_write_oem_huk((uint32_t *)(data + 8), 8) != 0) {
561a43611afSHisping Lin 						printf("trusty_write_oem_huk error!");
562a43611afSHisping Lin 						curlun->sense_data = SS_WRITE_ERROR;
563a43611afSHisping Lin 						return -EIO;
564a43611afSHisping Lin 					}
565850ced9dSHisping Lin 				} else {
566850ced9dSHisping Lin 					printf("Unknown tag\n");
567850ced9dSHisping Lin 					curlun->sense_data = SS_WRITE_ERROR;
568850ced9dSHisping Lin 					return -EIO;
569850ced9dSHisping Lin 				}
570850ced9dSHisping Lin #else
571850ced9dSHisping Lin 				printf("Please enable CONFIG_OPTEE_CLIENT\n");
572850ced9dSHisping Lin #endif
5732122174dSWu Liangqing 			} else {
5742122174dSWu Liangqing 				return -EINVAL;
57519652be0SFrank Wang 			}
5760d0c3248SFrank Wang 
5770d0c3248SFrank Wang 			common->residue -= common->data_size;
5780d0c3248SFrank Wang 
5790d0c3248SFrank Wang 			/* Did the host decide to stop early? */
5800d0c3248SFrank Wang 			if (bh->outreq->actual != bh->outreq->length)
5810d0c3248SFrank Wang 				common->short_packet_received = 1;
5820d0c3248SFrank Wang 			break; /* Command done */
5830d0c3248SFrank Wang 		}
5840d0c3248SFrank Wang wait:
5850d0c3248SFrank Wang 		/* Wait for something to happen */
5860d0c3248SFrank Wang 		rc = sleep_thread(common);
5870d0c3248SFrank Wang 		if (rc)
5880d0c3248SFrank Wang 			return rc;
5890d0c3248SFrank Wang 	}
5900d0c3248SFrank Wang 
5910d0c3248SFrank Wang 	return -EIO; /* No default reply */
5920d0c3248SFrank Wang }
5930d0c3248SFrank Wang 
5940d0c3248SFrank Wang static int rkusb_do_vs_read(struct fsg_common *common)
5950d0c3248SFrank Wang {
5960d0c3248SFrank Wang 	struct fsg_lun		*curlun = &common->luns[common->lun];
5970d0c3248SFrank Wang 	u16			type = get_unaligned_be16(&common->cmnd[4]);
5980d0c3248SFrank Wang 	struct vendor_item	*vhead;
5990d0c3248SFrank Wang 	struct fsg_buffhd	*bh;
6000d0c3248SFrank Wang 	void			*data;
6010d0c3248SFrank Wang 	int			rc;
6020d0c3248SFrank Wang 
6030d0c3248SFrank Wang 	if (common->data_size >= (u32)65536) {
6040d0c3248SFrank Wang 		/* _MUST_ small than 64K */
6050d0c3248SFrank Wang 		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
6060d0c3248SFrank Wang 		return -EINVAL;
6070d0c3248SFrank Wang 	}
6080d0c3248SFrank Wang 
6090d0c3248SFrank Wang 	common->residue         = common->data_size;
6100d0c3248SFrank Wang 	common->usb_amount_left = common->data_size;
6110d0c3248SFrank Wang 
6120d0c3248SFrank Wang 	/* Carry out the file reads */
6130d0c3248SFrank Wang 	if (unlikely(common->data_size == 0))
6140d0c3248SFrank Wang 		return -EIO; /* No default reply */
6150d0c3248SFrank Wang 
6160d0c3248SFrank Wang 	for (;;) {
6170d0c3248SFrank Wang 		/* Wait for the next buffer to become available */
6180d0c3248SFrank Wang 		bh = common->next_buffhd_to_fill;
6190d0c3248SFrank Wang 		while (bh->state != BUF_STATE_EMPTY) {
6200d0c3248SFrank Wang 			rc = sleep_thread(common);
6210d0c3248SFrank Wang 			if (rc)
6220d0c3248SFrank Wang 				return rc;
6230d0c3248SFrank Wang 		}
6240d0c3248SFrank Wang 
6250d0c3248SFrank Wang 		memset(bh->buf, 0, FSG_BUFLEN);
6260d0c3248SFrank Wang 		vhead = (struct vendor_item *)bh->buf;
6270d0c3248SFrank Wang 		data  = bh->buf + sizeof(struct vendor_item);
6280d0c3248SFrank Wang 		vhead->id = get_unaligned_be16(&common->cmnd[2]);
6290d0c3248SFrank Wang 
6300d0c3248SFrank Wang 		if (!type) {
6310d0c3248SFrank Wang 			/* Vendor storage */
6320d0c3248SFrank Wang 			rc = vendor_storage_read(vhead->id,
6330d0c3248SFrank Wang 						 (char __user *)data,
6340d0c3248SFrank Wang 						 common->data_size);
63519652be0SFrank Wang 			if (!rc) {
63619652be0SFrank Wang 				curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
6370d0c3248SFrank Wang 				return -EIO;
63819652be0SFrank Wang 			}
6390d0c3248SFrank Wang 			vhead->size = rc;
6402122174dSWu Liangqing 		} else if (type == 1) {
6410d0c3248SFrank Wang 			/* RPMB */
642700a3668STony Xu 			rc =
643700a3668STony Xu 			read_raw_data_from_secure_storage((u8 *)data,
644700a3668STony Xu 							  common->data_size);
64519652be0SFrank Wang 			if (!rc) {
64619652be0SFrank Wang 				curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
647700a3668STony Xu 				return -EIO;
64819652be0SFrank Wang 			}
649700a3668STony Xu 			vhead->size = rc;
6502122174dSWu Liangqing 		} else if (type == 2) {
6512122174dSWu Liangqing 			/* security storage */
6522122174dSWu Liangqing #ifdef CONFIG_RK_AVB_LIBAVB_USER
6532122174dSWu Liangqing 			rc = rk_avb_read_perm_attr(vhead->id,
6542122174dSWu Liangqing 						   (char __user *)data,
6552122174dSWu Liangqing 						   vhead->size);
6562122174dSWu Liangqing 			if (rc < 0)
6572122174dSWu Liangqing 				return -EIO;
6582122174dSWu Liangqing 			vhead->size = rc;
6592122174dSWu Liangqing #else
6602122174dSWu Liangqing 			printf("Please enable CONFIG_RK_AVB_LIBAVB_USER!\n");
6612122174dSWu Liangqing #endif
66247c8f13dSHisping Lin 		} else if (type == 3) {
66347c8f13dSHisping Lin 			/* efuse or otp*/
66447c8f13dSHisping Lin #ifdef CONFIG_OPTEE_CLIENT
66547c8f13dSHisping Lin 			if (vhead->id == 120) {
66647c8f13dSHisping Lin 				u8 value;
66747c8f13dSHisping Lin 				char *written_str = "key is written!";
66847c8f13dSHisping Lin 				char *not_written_str = "key is not written!";
66947c8f13dSHisping Lin 				if (trusty_ta_encryption_key_is_written(&value) != 0) {
67047c8f13dSHisping Lin 					printf("trusty_ta_encryption_key_is_written error!");
67147c8f13dSHisping Lin 					return -EIO;
67247c8f13dSHisping Lin 				}
67347c8f13dSHisping Lin 				if (value) {
67447c8f13dSHisping Lin 					memcpy(data, written_str, strlen(written_str));
67547c8f13dSHisping Lin 					vhead->size = strlen(written_str);
67647c8f13dSHisping Lin 				} else {
67747c8f13dSHisping Lin 					memcpy(data, not_written_str, strlen(not_written_str));
67847c8f13dSHisping Lin 					vhead->size = strlen(not_written_str);
67947c8f13dSHisping Lin 				}
68047c8f13dSHisping Lin 			} else {
68147c8f13dSHisping Lin 				printf("Unknown tag\n");
68247c8f13dSHisping Lin 				return -EIO;
68347c8f13dSHisping Lin 			}
68447c8f13dSHisping Lin #else
68547c8f13dSHisping Lin 			printf("Please enable CONFIG_OPTEE_CLIENT\n");
68647c8f13dSHisping Lin #endif
6872122174dSWu Liangqing 		} else {
6882122174dSWu Liangqing 			return -EINVAL;
6890d0c3248SFrank Wang 		}
6900d0c3248SFrank Wang 
6910d0c3248SFrank Wang 		common->residue   -= common->data_size;
6920d0c3248SFrank Wang 		bh->inreq->length = common->data_size;
6930d0c3248SFrank Wang 		bh->state         = BUF_STATE_FULL;
6940d0c3248SFrank Wang 
6950d0c3248SFrank Wang 		break; /* No more left to read */
6960d0c3248SFrank Wang 	}
6970d0c3248SFrank Wang 
6980d0c3248SFrank Wang 	return -EIO; /* No default reply */
6990d0c3248SFrank Wang }
7000d0c3248SFrank Wang #endif
7010d0c3248SFrank Wang 
7024d2787f5SJon Lin static int rkusb_do_switch_storage(struct fsg_common *common)
7034d2787f5SJon Lin {
7044d2787f5SJon Lin 	enum if_type type, cur_type = ums[common->lun].block_dev.if_type;
7054d2787f5SJon Lin 	int devnum, cur_devnum = ums[common->lun].block_dev.devnum;
7064d2787f5SJon Lin 	struct blk_desc *block_dev;
7074d2787f5SJon Lin 	u32 media = BOOT_TYPE_UNKNOWN;
7084d2787f5SJon Lin 
7094d2787f5SJon Lin 	media = 1 << common->cmnd[1];
7104d2787f5SJon Lin 
7114d2787f5SJon Lin 	switch (media) {
71222c2f449SJon Lin #ifdef CONFIG_MMC
7134d2787f5SJon Lin 	case BOOT_TYPE_EMMC:
7144d2787f5SJon Lin 		type = IF_TYPE_MMC;
7154d2787f5SJon Lin 		devnum = 0;
7164d2787f5SJon Lin 		mmc_initialize(gd->bd);
7174d2787f5SJon Lin 		break;
71822c2f449SJon Lin #endif
7194d2787f5SJon Lin 	case BOOT_TYPE_MTD_BLK_NAND:
7204d2787f5SJon Lin 		type = IF_TYPE_MTD;
7214d2787f5SJon Lin 		devnum = 0;
7224d2787f5SJon Lin 		break;
7234d2787f5SJon Lin 	case BOOT_TYPE_MTD_BLK_SPI_NAND:
7244d2787f5SJon Lin 		type = IF_TYPE_MTD;
7254d2787f5SJon Lin 		devnum = 1;
7264d2787f5SJon Lin 		break;
7274d2787f5SJon Lin 	case BOOT_TYPE_MTD_BLK_SPI_NOR:
7284d2787f5SJon Lin 		type = IF_TYPE_MTD;
7294d2787f5SJon Lin 		devnum = 2;
7304d2787f5SJon Lin 		break;
7314d2787f5SJon Lin 	default:
7324d2787f5SJon Lin 		printf("Bootdev 0x%x is not support\n", media);
7334d2787f5SJon Lin 		return -ENODEV;
7344d2787f5SJon Lin 	}
7354d2787f5SJon Lin 
7364d2787f5SJon Lin 	if (cur_type == type && cur_devnum == devnum)
7374d2787f5SJon Lin 		return 0;
7384d2787f5SJon Lin 
739*8c6654f1SJon Lin #if CONFIG_IS_ENABLED(SUPPORT_USBPLUG)
740*8c6654f1SJon Lin 	block_dev = usbplug_blk_get_devnum_by_type(type, devnum);
741*8c6654f1SJon Lin #else
7424d2787f5SJon Lin 	block_dev = blk_get_devnum_by_type(type, devnum);
743*8c6654f1SJon Lin #endif
7444d2787f5SJon Lin 	if (!block_dev) {
7454d2787f5SJon Lin 		printf("Bootdev if_type=%d num=%d toggle fail\n", type, devnum);
7464d2787f5SJon Lin 		return -ENODEV;
7474d2787f5SJon Lin 	}
7484d2787f5SJon Lin 
7494d2787f5SJon Lin 	ums[common->lun].num_sectors = block_dev->lba;
7504d2787f5SJon Lin 	ums[common->lun].block_dev = *block_dev;
7514d2787f5SJon Lin 
7524d2787f5SJon Lin 	printf("RKUSB: LUN %d, dev %d, hwpart %d, sector %#x, count %#x\n",
7534d2787f5SJon Lin 	       0,
7544d2787f5SJon Lin 	       ums[common->lun].block_dev.devnum,
7554d2787f5SJon Lin 	       ums[common->lun].block_dev.hwpart,
7564d2787f5SJon Lin 	       ums[common->lun].start_sector,
7574d2787f5SJon Lin 	       ums[common->lun].num_sectors);
7584d2787f5SJon Lin 
7594d2787f5SJon Lin 	return 0;
7604d2787f5SJon Lin }
7614d2787f5SJon Lin 
762d4cce25eSYifeng Zhao static int rkusb_do_get_storage_info(struct fsg_common *common,
763d4cce25eSYifeng Zhao 				     struct fsg_buffhd *bh)
764d4cce25eSYifeng Zhao {
765d4cce25eSYifeng Zhao 	enum if_type type = ums[common->lun].block_dev.if_type;
766d4cce25eSYifeng Zhao 	int devnum = ums[common->lun].block_dev.devnum;
767d4cce25eSYifeng Zhao 	u32 media = BOOT_TYPE_UNKNOWN;
768d4cce25eSYifeng Zhao 	u32 len = common->data_size;
769d4cce25eSYifeng Zhao 	u8 *buf = (u8 *)bh->buf;
770d4cce25eSYifeng Zhao 
771d4cce25eSYifeng Zhao 	if (len > 4)
772d4cce25eSYifeng Zhao 		len = 4;
773d4cce25eSYifeng Zhao 
774d4cce25eSYifeng Zhao 	switch (type) {
775d4cce25eSYifeng Zhao 	case IF_TYPE_MMC:
776d4cce25eSYifeng Zhao 		media = BOOT_TYPE_EMMC;
777d4cce25eSYifeng Zhao 		break;
778d4cce25eSYifeng Zhao 
779d4cce25eSYifeng Zhao 	case IF_TYPE_SD:
780d4cce25eSYifeng Zhao 		media = BOOT_TYPE_SD0;
781d4cce25eSYifeng Zhao 		break;
782d4cce25eSYifeng Zhao 
783d4cce25eSYifeng Zhao 	case IF_TYPE_MTD:
784d4cce25eSYifeng Zhao 		if (devnum == BLK_MTD_SPI_NAND)
785d4cce25eSYifeng Zhao 			media = BOOT_TYPE_MTD_BLK_SPI_NAND;
786d4cce25eSYifeng Zhao 		else if (devnum == BLK_MTD_NAND)
787d4cce25eSYifeng Zhao 			media = BOOT_TYPE_NAND;
788d4cce25eSYifeng Zhao 		else
789d4cce25eSYifeng Zhao 			media = BOOT_TYPE_MTD_BLK_SPI_NOR;
790d4cce25eSYifeng Zhao 		break;
791d4cce25eSYifeng Zhao 
792d4cce25eSYifeng Zhao 	case IF_TYPE_SCSI:
793d4cce25eSYifeng Zhao 		media = BOOT_TYPE_SATA;
794d4cce25eSYifeng Zhao 		break;
795d4cce25eSYifeng Zhao 
796d4cce25eSYifeng Zhao 	case IF_TYPE_RKNAND:
797d4cce25eSYifeng Zhao 		media = BOOT_TYPE_NAND;
798d4cce25eSYifeng Zhao 		break;
7992daa60eeSJon Lin 
8002daa60eeSJon Lin 	case IF_TYPE_NVME:
8012daa60eeSJon Lin 		media = BOOT_TYPE_PCIE;
8022daa60eeSJon Lin 		break;
8032daa60eeSJon Lin 
804d4cce25eSYifeng Zhao 	default:
805d4cce25eSYifeng Zhao 		break;
806d4cce25eSYifeng Zhao 	}
807d4cce25eSYifeng Zhao 
808d4cce25eSYifeng Zhao 	memcpy((void *)&buf[0], (void *)&media, len);
809d4cce25eSYifeng Zhao 	common->residue = len;
810d4cce25eSYifeng Zhao 	common->data_size_from_cmnd = len;
811d4cce25eSYifeng Zhao 
812d4cce25eSYifeng Zhao 	return len;
813d4cce25eSYifeng Zhao }
814d4cce25eSYifeng Zhao 
815f16e43f8SFrank Wang static int rkusb_do_read_capacity(struct fsg_common *common,
816f16e43f8SFrank Wang 				  struct fsg_buffhd *bh)
817f16e43f8SFrank Wang {
818f16e43f8SFrank Wang 	u8 *buf = (u8 *)bh->buf;
819f16e43f8SFrank Wang 	u32 len = common->data_size;
820d015bf41SFrank Wang 	enum if_type type = ums[common->lun].block_dev.if_type;
821e66d4537SJon Lin 	int devnum = ums[common->lun].block_dev.devnum;
822f16e43f8SFrank Wang 
823f16e43f8SFrank Wang 	/*
824f16e43f8SFrank Wang 	 * bit[0]: Direct LBA, 0: Disabled;
8250d0c3248SFrank Wang 	 * bit[1]: Vendor Storage API, 0: Disabed (default);
826d015bf41SFrank Wang 	 * bit[2]: First 4M Access, 0: Disabled;
8270d0c3248SFrank Wang 	 * bit[3]: Read LBA On, 0: Disabed (default);
8280d0c3248SFrank Wang 	 * bit[4]: New Vendor Storage API, 0: Disabed;
829d4cce25eSYifeng Zhao 	 * bit[5]: Read uart data from ram
830d4cce25eSYifeng Zhao 	 * bit[6]: Read IDB config
831d4cce25eSYifeng Zhao 	 * bit[7]: Read SecureMode
832d4cce25eSYifeng Zhao 	 * bit[8]: New IDB feature
833d4cce25eSYifeng Zhao 	 * bit[9]: Get storage media info
834d4cce25eSYifeng Zhao 	 * bit[10:63}: Reserved.
835f16e43f8SFrank Wang 	 */
836f16e43f8SFrank Wang 	memset((void *)&buf[0], 0, len);
8372daa60eeSJon Lin 	if (type == IF_TYPE_MMC || type == IF_TYPE_SD || type == IF_TYPE_NVME)
8380d0c3248SFrank Wang 		buf[0] = BIT(0) | BIT(2) | BIT(4);
8390d0c3248SFrank Wang 	else
8400d0c3248SFrank Wang 		buf[0] = BIT(0) | BIT(4);
841f16e43f8SFrank Wang 
842e66d4537SJon Lin 	if (type == IF_TYPE_MTD &&
843e66d4537SJon Lin 	    (devnum == BLK_MTD_NAND ||
844e66d4537SJon Lin 	    devnum == BLK_MTD_SPI_NAND))
845e66d4537SJon Lin 		buf[0] |= (1 << 6);
846e66d4537SJon Lin 
84765a0fed9SJon Lin #if !defined(CONFIG_ROCKCHIP_RV1126) && !defined(CONFIG_ROCKCHIP_RK3308)
84865a0fed9SJon Lin 	if (type == IF_TYPE_MTD && devnum == BLK_MTD_SPI_NOR)
84965a0fed9SJon Lin 		buf[0] |= (1 << 6);
85065a0fed9SJon Lin #endif
85165a0fed9SJon Lin 
8520b97a2cbSJoseph Chen #if defined(CONFIG_ROCKCHIP_NEW_IDB)
853007849d8SYifeng Zhao 	buf[1] = BIT(0);
854007849d8SYifeng Zhao #endif
8552c0c66c1SYifeng Zhao 	buf[1] |= BIT(1); /* Switch Storage */
8562c0c66c1SYifeng Zhao 	buf[1] |= BIT(2); /* LBAwrite Parity */
857d4cce25eSYifeng Zhao 
85836c87911Swilliam.wu 	if (rkusb_usb3_capable() && !rkusb_force_usb2_enabled())
8593c7547fcSWilliam Wu 		buf[1] |= BIT(4);
86036c87911Swilliam.wu 	else
8613c7547fcSWilliam Wu 		buf[1] &= ~BIT(4);
86236c87911Swilliam.wu 
863f16e43f8SFrank Wang 	/* Set data xfer size */
864e66d4537SJon Lin 	common->residue = len;
865e66d4537SJon Lin 	common->data_size_from_cmnd = len;
866f16e43f8SFrank Wang 
867f16e43f8SFrank Wang 	return len;
868f16e43f8SFrank Wang }
869f16e43f8SFrank Wang 
870d23ec8c4SKever Yang static void rkusb_fixup_cbwcb(struct fsg_common *common,
871d23ec8c4SKever Yang 			      struct fsg_buffhd *bh)
872d23ec8c4SKever Yang {
873d23ec8c4SKever Yang 	struct usb_request      *req = bh->outreq;
874d23ec8c4SKever Yang 	struct fsg_bulk_cb_wrap *cbw = req->buf;
875d23ec8c4SKever Yang 
876d23ec8c4SKever Yang 	/* FIXME cbw.DataTransferLength was not set by Upgrade Tool */
877d23ec8c4SKever Yang 	common->data_size = le32_to_cpu(cbw->DataTransferLength);
878d23ec8c4SKever Yang 	if (common->data_size == 0) {
879d23ec8c4SKever Yang 		common->data_size =
880d23ec8c4SKever Yang 		get_unaligned_be16(&common->cmnd[7]) << 9;
881d23ec8c4SKever Yang 		printf("Trasfer Length NOT set, please use new version tool\n");
882d23ec8c4SKever Yang 		debug("%s %d, cmnd1 %x\n", __func__,
883d23ec8c4SKever Yang 		      get_unaligned_be16(&common->cmnd[7]),
884d23ec8c4SKever Yang 		      get_unaligned_be16(&common->cmnd[1]));
885d23ec8c4SKever Yang 	}
886d23ec8c4SKever Yang 	if (cbw->Flags & USB_BULK_IN_FLAG)
887d23ec8c4SKever Yang 		common->data_dir = DATA_DIR_TO_HOST;
888d23ec8c4SKever Yang 	else
889d23ec8c4SKever Yang 		common->data_dir = DATA_DIR_FROM_HOST;
890d23ec8c4SKever Yang 
891d23ec8c4SKever Yang 	/* Not support */
892d23ec8c4SKever Yang 	common->cmnd[1] = 0;
893d23ec8c4SKever Yang }
894d23ec8c4SKever Yang 
895f16e43f8SFrank Wang static int rkusb_cmd_process(struct fsg_common *common,
896f16e43f8SFrank Wang 			     struct fsg_buffhd *bh, int *reply)
897f16e43f8SFrank Wang {
898f16e43f8SFrank Wang 	struct usb_request	*req = bh->outreq;
899f16e43f8SFrank Wang 	struct fsg_bulk_cb_wrap	*cbw = req->buf;
900f16e43f8SFrank Wang 	int rc;
901f16e43f8SFrank Wang 
902f16e43f8SFrank Wang 	dump_cbw(cbw);
903f16e43f8SFrank Wang 
904f16e43f8SFrank Wang 	if (rkusb_check_lun(common)) {
905f16e43f8SFrank Wang 		*reply = -EINVAL;
906f16e43f8SFrank Wang 		return RKUSB_RC_ERROR;
907f16e43f8SFrank Wang 	}
908f16e43f8SFrank Wang 
909f16e43f8SFrank Wang 	switch (common->cmnd[0]) {
910f16e43f8SFrank Wang 	case RKUSB_TEST_UNIT_READY:
911f16e43f8SFrank Wang 		*reply = rkusb_do_test_unit_ready(common, bh);
912f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
913f16e43f8SFrank Wang 		break;
914f16e43f8SFrank Wang 
915f16e43f8SFrank Wang 	case RKUSB_READ_FLASH_ID:
916f16e43f8SFrank Wang 		*reply = rkusb_do_read_flash_id(common, bh);
917f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
918f16e43f8SFrank Wang 		break;
919f16e43f8SFrank Wang 
920f16e43f8SFrank Wang 	case RKUSB_TEST_BAD_BLOCK:
921f16e43f8SFrank Wang 		*reply = rkusb_do_test_bad_block(common, bh);
922f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
923f16e43f8SFrank Wang 		break;
924f16e43f8SFrank Wang 
925e66d4537SJon Lin 	case RKUSB_ERASE_10_FORCE:
926e66d4537SJon Lin 		*reply = rkusb_do_erase_force(common, bh);
927e66d4537SJon Lin 		rc = RKUSB_RC_FINISHED;
928e66d4537SJon Lin 		break;
929e66d4537SJon Lin 
930f16e43f8SFrank Wang 	case RKUSB_LBA_READ_10:
9315fb597c2SKever Yang 		rkusb_fixup_cbwcb(common, bh);
932f16e43f8SFrank Wang 		common->cmnd[0] = SC_READ_10;
933f16e43f8SFrank Wang 		common->cmnd[1] = 0; /* Not support */
934f16e43f8SFrank Wang 		rc = RKUSB_RC_CONTINUE;
935f16e43f8SFrank Wang 		break;
936f16e43f8SFrank Wang 
937f16e43f8SFrank Wang 	case RKUSB_LBA_WRITE_10:
9385fb597c2SKever Yang 		rkusb_fixup_cbwcb(common, bh);
939f16e43f8SFrank Wang 		common->cmnd[0] = SC_WRITE_10;
940f16e43f8SFrank Wang 		common->cmnd[1] = 0; /* Not support */
941f16e43f8SFrank Wang 		rc = RKUSB_RC_CONTINUE;
942f16e43f8SFrank Wang 		break;
943f16e43f8SFrank Wang 
944f16e43f8SFrank Wang 	case RKUSB_READ_FLASH_INFO:
945f16e43f8SFrank Wang 		*reply = rkusb_do_read_flash_info(common, bh);
946f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
947f16e43f8SFrank Wang 		break;
948f16e43f8SFrank Wang 
949829f2b85SFrank Wang 	case RKUSB_GET_CHIP_VER:
950829f2b85SFrank Wang 		*reply = rkusb_do_get_chip_info(common, bh);
951829f2b85SFrank Wang 		rc = RKUSB_RC_FINISHED;
952829f2b85SFrank Wang 		break;
953829f2b85SFrank Wang 
954f16e43f8SFrank Wang 	case RKUSB_LBA_ERASE:
955f16e43f8SFrank Wang 		*reply = rkusb_do_lba_erase(common, bh);
956f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
957f16e43f8SFrank Wang 		break;
958f16e43f8SFrank Wang 
9590d0c3248SFrank Wang #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION
9600d0c3248SFrank Wang 	case RKUSB_VS_WRITE:
9610d0c3248SFrank Wang 		*reply = rkusb_do_vs_write(common);
9620d0c3248SFrank Wang 		rc = RKUSB_RC_FINISHED;
9630d0c3248SFrank Wang 		break;
9640d0c3248SFrank Wang 
9650d0c3248SFrank Wang 	case RKUSB_VS_READ:
9660d0c3248SFrank Wang 		*reply = rkusb_do_vs_read(common);
9670d0c3248SFrank Wang 		rc = RKUSB_RC_FINISHED;
9680d0c3248SFrank Wang 		break;
9690d0c3248SFrank Wang #endif
9704d2787f5SJon Lin 	case RKUSB_SWITCH_STORAGE:
9714d2787f5SJon Lin 		*reply = rkusb_do_switch_storage(common);
9724d2787f5SJon Lin 		rc = RKUSB_RC_FINISHED;
9734d2787f5SJon Lin 		break;
974d4cce25eSYifeng Zhao 	case RKUSB_GET_STORAGE_MEDIA:
975d4cce25eSYifeng Zhao 		*reply = rkusb_do_get_storage_info(common, bh);
976d4cce25eSYifeng Zhao 		rc = RKUSB_RC_FINISHED;
977d4cce25eSYifeng Zhao 		break;
9780d0c3248SFrank Wang 
979f16e43f8SFrank Wang 	case RKUSB_READ_CAPACITY:
980f16e43f8SFrank Wang 		*reply = rkusb_do_read_capacity(common, bh);
981f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
982f16e43f8SFrank Wang 		break;
983f16e43f8SFrank Wang 
98436c87911Swilliam.wu 	case RKUSB_SWITCH_USB3:
98536c87911Swilliam.wu 		*reply = rkusb_do_switch_to_usb3(common, bh);
98636c87911Swilliam.wu 		rc = RKUSB_RC_FINISHED;
98736c87911Swilliam.wu 		break;
98836c87911Swilliam.wu 
989f16e43f8SFrank Wang 	case RKUSB_RESET:
990f16e43f8SFrank Wang 		*reply = rkusb_do_reset(common, bh);
991f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
992f16e43f8SFrank Wang 		break;
993f16e43f8SFrank Wang 
994f16e43f8SFrank Wang 	case RKUSB_READ_10:
995f16e43f8SFrank Wang 	case RKUSB_WRITE_10:
996e0023032SKever Yang 		printf("CMD Not support, pls use new version Tool\n");
997e0023032SKever Yang 	case RKUSB_SET_DEVICE_ID:
998f16e43f8SFrank Wang 	case RKUSB_ERASE_10:
999f16e43f8SFrank Wang 	case RKUSB_WRITE_SPARE:
1000f16e43f8SFrank Wang 	case RKUSB_READ_SPARE:
1001f16e43f8SFrank Wang 	case RKUSB_GET_VERSION:
1002f16e43f8SFrank Wang 	case RKUSB_ERASE_SYS_DISK:
1003f16e43f8SFrank Wang 	case RKUSB_SDRAM_READ_10:
1004f16e43f8SFrank Wang 	case RKUSB_SDRAM_WRITE_10:
1005f16e43f8SFrank Wang 	case RKUSB_SDRAM_EXECUTE:
1006f16e43f8SFrank Wang 	case RKUSB_LOW_FORMAT:
1007f16e43f8SFrank Wang 	case RKUSB_SET_RESET_FLAG:
1008f16e43f8SFrank Wang 	case RKUSB_SPI_READ_10:
1009f16e43f8SFrank Wang 	case RKUSB_SPI_WRITE_10:
1010f16e43f8SFrank Wang 	case RKUSB_SESSION:
1011f16e43f8SFrank Wang 		/* Fall through */
1012f16e43f8SFrank Wang 	default:
1013f16e43f8SFrank Wang 		rc = RKUSB_RC_UNKNOWN_CMND;
1014f16e43f8SFrank Wang 		break;
1015f16e43f8SFrank Wang 	}
1016f16e43f8SFrank Wang 
1017f16e43f8SFrank Wang 	return rc;
1018f16e43f8SFrank Wang }
1019f16e43f8SFrank Wang 
10202c0c66c1SYifeng Zhao int rkusb_do_check_parity(struct fsg_common *common)
10212c0c66c1SYifeng Zhao {
10222c0c66c1SYifeng Zhao 	int ret = 0, rc;
10232c0c66c1SYifeng Zhao 	u32 parity, i, usb_parity, lba, len;
10242c0c66c1SYifeng Zhao 	static u32 usb_check_buffer[1024 * 256];
10252c0c66c1SYifeng Zhao 
10262c0c66c1SYifeng Zhao 	usb_parity = common->cmnd[9] | (common->cmnd[10] << 8) |
10272c0c66c1SYifeng Zhao 			(common->cmnd[11] << 16) | (common->cmnd[12] << 24);
10282c0c66c1SYifeng Zhao 
10292c0c66c1SYifeng Zhao 	if (common->cmnd[0] == SC_WRITE_10 && (usb_parity)) {
10302c0c66c1SYifeng Zhao 		lba = get_unaligned_be32(&common->cmnd[2]);
10312c0c66c1SYifeng Zhao 		len = common->data_size_from_cmnd >> 9;
10322c0c66c1SYifeng Zhao 		rc = blk_dread(&ums[common->lun].block_dev, lba, len, usb_check_buffer);
10332c0c66c1SYifeng Zhao 		parity = 0x000055aa;
10342c0c66c1SYifeng Zhao 		for (i = 0; i < len * 128; i++)
10352c0c66c1SYifeng Zhao 			parity += usb_check_buffer[i];
10362c0c66c1SYifeng Zhao 		if (!rc || parity != usb_parity)
10372c0c66c1SYifeng Zhao 			common->phase_error = 1;
10382c0c66c1SYifeng Zhao 	}
10392c0c66c1SYifeng Zhao 
10402c0c66c1SYifeng Zhao 	return ret;
10412c0c66c1SYifeng Zhao }
10422c0c66c1SYifeng Zhao 
1043f16e43f8SFrank Wang DECLARE_GADGET_BIND_CALLBACK(rkusb_ums_dnl, fsg_add);
1044